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_SYSMENU))
75 #define IS_SYSTEM_POPUP(MenuInfo) \
76 (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
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_SYSMENU
? 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
)
1261 //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
1262 return lppop
->cyMax
;
1264 //ERR("MGMaxPH SyMax %d\n",GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYBORDER));
1265 return GetSystemMetrics(SM_CYSCREEN
) - GetSystemMetrics(SM_CYBORDER
);
1268 /***********************************************************************
1269 * MenuPopupMenuCalcSize
1271 * Calculate the size of a popup menu.
1273 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1275 ROSMENUITEMINFO lpitem
;
1278 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
1279 BOOL textandbmp
= FALSE
;
1281 MenuInfo
->cxMenu
= MenuInfo
->cyMenu
= 0;
1282 if (MenuInfo
->cItems
== 0)
1284 MenuSetRosMenuInfo(MenuInfo
);
1289 SelectObject( hdc
, hMenuFont
);
1294 MenuInfo
->cxTextAlign
= 0;
1296 MenuInitRosMenuItemInfo(&lpitem
);
1297 //MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem);
1298 while (start
< MenuInfo
->cItems
)
1300 //lpitem = &lppop->items[start];
1302 //if( lpitem.fType & (MF_MENUBREAK | MF_MENUBARBREAK))
1303 // orgX += MENU_COL_SPACE;
1304 orgY
= 2;//MENU_TOP_MARGIN;
1306 maxTab
= maxTabWidth
= 0;
1307 /* Parse items until column break or end of menu */
1308 for (i
= start
; i
< MenuInfo
->cItems
; i
++)//, lpitem++)
1310 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
1312 MenuCleanupRosMenuItemInfo(&lpitem
);
1313 MenuSetRosMenuInfo(MenuInfo
);
1317 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1320 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
1321 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
1323 MenuCleanupRosMenuItemInfo(&lpitem
);
1324 MenuSetRosMenuInfo(MenuInfo
);
1328 maxX
= max(maxX
, lpitem
.Rect
.right
);
1329 orgY
= lpitem
.Rect
.bottom
;
1330 if (IS_STRING_ITEM(lpitem
.fType
) && lpitem
.dxTab
)
1332 maxTab
= max( maxTab
, lpitem
.dxTab
);
1333 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.dxTab
);
1335 if( lpitem
.lpstr
&& lpitem
.hbmpItem
) textandbmp
= TRUE
;
1338 /* Finish the column (set all items to the largest width found) */
1339 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
1342 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
1344 lpitem
.Rect
.right
= maxX
;
1345 if (IS_STRING_ITEM(lpitem
.fType
) && lpitem
.dxTab
)
1347 lpitem
.dxTab
= maxTab
;
1349 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
1353 MenuInfo
->cyMenu
= max(MenuInfo
->cyMenu
, orgY
);
1356 MenuInfo
->cxMenu
= maxX
;
1357 /* if none of the items have both text and bitmap then
1358 * the text and bitmaps are all aligned on the left. If there is at
1359 * least one item with both text and bitmap then bitmaps are
1360 * on the left and texts left aligned with the right hand side
1362 if( !textandbmp
) MenuInfo
->cxTextAlign
= 0;
1364 /* space for 3d border */
1365 MenuInfo
->cyMenu
+= MENU_BOTTOM_MARGIN
;
1366 MenuInfo
->cxMenu
+= 2;
1368 /* Adjust popup height if it exceeds maximum */
1369 maxHeight
= MENU_GetMaxPopupHeight(MenuInfo
);
1370 MenuInfo
->iMaxTop
= MenuInfo
->cyMenu
- MENU_TOP_MARGIN
;
1371 if (MenuInfo
->cyMenu
>= maxHeight
)
1373 MenuInfo
->cyMenu
= maxHeight
;
1374 MenuInfo
->dwArrowsOn
= 1;
1378 MenuInfo
->dwArrowsOn
= 0;
1381 MenuCleanupRosMenuItemInfo(&lpitem
);
1382 MenuSetRosMenuInfo(MenuInfo
);
1383 ReleaseDC( 0, hdc
);
1386 /***********************************************************************
1387 * MenuMenuBarCalcSize
1389 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1390 * height is off by 1 pixel which causes lengthy window relocations when
1391 * active document window is maximized/restored.
1393 * Calculate the size of the menu bar.
1395 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1396 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
1398 ROSMENUITEMINFO ItemInfo
;
1399 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1401 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
1402 if (MenuInfo
->cItems
== 0) return;
1403 TRACE("lprect %p %s\n", lprect
, wine_dbgstr_rect( lprect
));
1404 MenuInfo
->cxMenu
= lprect
->right
- lprect
->left
;
1405 MenuInfo
->cyMenu
= 0;
1406 maxY
= lprect
->top
+ 1;
1410 MenuInfo
->cxTextAlign
= 0;
1412 MenuInitRosMenuItemInfo(&ItemInfo
);
1413 while (start
< MenuInfo
->cItems
)
1415 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1417 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1420 orgX
= lprect
->left
;
1423 /* Parse items until line break or end of menu */
1424 for (i
= start
; i
< MenuInfo
->cItems
; i
++)
1426 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1428 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1430 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1431 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
1432 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1434 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1438 if (ItemInfo
.Rect
.right
> lprect
->right
)
1440 if (i
!= start
) break;
1441 else ItemInfo
.Rect
.right
= lprect
->right
;
1443 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
1444 orgX
= ItemInfo
.Rect
.right
;
1445 if (i
+ 1 < MenuInfo
->cItems
)
1447 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1449 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1455 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1456 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1458 /* Finish the line (set all items to the largest height found) */
1461 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1463 ItemInfo
.Rect
.bottom
= maxY
;
1464 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
1469 start
= i
; /* This works! */
1473 lprect
->bottom
= maxY
;
1474 MenuInfo
->cyMenu
= lprect
->bottom
- lprect
->top
;
1475 MenuSetRosMenuInfo(MenuInfo
);
1479 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1480 /* the last item (if several lines, only move the last line) */
1481 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->cItems
- 1, &ItemInfo
))
1483 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1486 orgY
= ItemInfo
.Rect
.top
;
1487 orgX
= lprect
->right
;
1488 for (i
= MenuInfo
->cItems
- 1; helpPos
<= i
; i
--)
1490 if (i
< helpPos
) break; /* done */
1491 if (ItemInfo
.Rect
.top
!= orgY
) break; /* Other line */
1492 if (orgX
<= ItemInfo
.Rect
.right
) break; /* Too far right already */
1493 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1494 ItemInfo
.Rect
.right
= orgX
;
1495 orgX
= ItemInfo
.Rect
.left
;
1496 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1497 if (helpPos
+ 1 <= i
&&
1498 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1500 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1506 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1509 /***********************************************************************
1510 * MENU_DrawScrollArrows
1512 * Draw scroll arrows.
1515 MENU_DrawScrollArrows(PROSMENUINFO lppop
, HDC hdc
)
1517 HDC hdcMem
= CreateCompatibleDC(hdc
);
1518 HBITMAP hOrigBitmap
;
1519 UINT arrow_bitmap_width
, arrow_bitmap_height
;
1523 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp
), &bmp
);
1524 arrow_bitmap_width
= bmp
.bmWidth
;
1525 arrow_bitmap_height
= bmp
.bmHeight
;
1528 hOrigBitmap
= SelectObject(hdcMem
, get_up_arrow_bitmap());
1530 hOrigBitmap
= SelectObject(hdcMem
, get_up_arrow_inactive_bitmap());
1533 rect
.right
= lppop
->cxMenu
;
1534 rect
.bottom
= arrow_bitmap_height
;
1535 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENU
));
1536 BitBlt(hdc
, (lppop
->cxMenu
- arrow_bitmap_width
) / 2, 0,
1537 arrow_bitmap_width
, arrow_bitmap_height
, hdcMem
, 0, 0, SRCCOPY
);
1538 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
1539 rect
.bottom
= lppop
->cyMenu
;
1540 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENU
));
1541 if (lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
))
1542 SelectObject(hdcMem
, get_down_arrow_bitmap());
1544 SelectObject(hdcMem
, get_down_arrow_inactive_bitmap());
1545 BitBlt(hdc
, (lppop
->cxMenu
- arrow_bitmap_width
) / 2,
1546 lppop
->cyMenu
- arrow_bitmap_height
,
1547 arrow_bitmap_width
, arrow_bitmap_height
, hdcMem
, 0, 0, SRCCOPY
);
1548 SelectObject(hdcMem
, hOrigBitmap
);
1552 /***********************************************************************
1555 * Draws the popup-menu arrow.
1557 static void draw_popup_arrow( HDC hdc
, RECT rect
, UINT arrow_bitmap_width
,
1558 UINT arrow_bitmap_height
)
1560 HDC hdcMem
= CreateCompatibleDC( hdc
);
1561 HBITMAP hOrigBitmap
;
1563 hOrigBitmap
= SelectObject( hdcMem
, get_arrow_bitmap() );
1564 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1565 (rect
.top
+ rect
.bottom
- arrow_bitmap_height
) / 2,
1566 arrow_bitmap_width
, arrow_bitmap_height
,
1567 hdcMem
, 0, 0, SRCCOPY
);
1568 SelectObject( hdcMem
, hOrigBitmap
);
1572 /***********************************************************************
1575 * Draw a single menu item.
1577 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1578 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1582 BOOL flat_menu
= FALSE
;
1584 UINT arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
1585 PWND Wnd
= ValidateHwndNoErr(hWnd
);
1592 GetObjectW( get_arrow_bitmap(), sizeof(bmp
), &bmp
);
1593 arrow_bitmap_width
= bmp
.bmWidth
;
1594 arrow_bitmap_height
= bmp
.bmHeight
;
1597 if (lpitem
->fType
& MF_SYSMENU
)
1599 if ( (Wnd
->style
& WS_MINIMIZE
))
1601 UserGetInsideRectNC(Wnd
, &rect
);
1602 UserDrawSysMenuButton(hWnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1607 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1608 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1612 if (lpitem
->fState
& MF_HILITE
)
1614 if(menuBar
&& !flat_menu
) {
1615 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1616 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1618 if (lpitem
->fState
& MF_GRAYED
)
1619 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1621 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1622 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1627 if (lpitem
->fState
& MF_GRAYED
)
1628 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1630 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1631 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1634 TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem
->Rect
));
1635 rect
= lpitem
->Rect
;
1636 MENU_AdjustMenuItemRect(MenuInfo
, &rect
);
1638 if (lpitem
->fType
& MF_OWNERDRAW
)
1641 ** Experimentation under Windows reveals that an owner-drawn
1642 ** menu is given the rectangle which includes the space it requested
1643 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1644 ** and a popup-menu arrow. This is the value of lpitem->rect.
1645 ** Windows will leave all drawing to the application except for
1646 ** the popup-menu arrow. Windows always draws that itself, after
1647 ** the menu owner has finished drawing.
1651 dis
.CtlType
= ODT_MENU
;
1653 dis
.itemID
= lpitem
->wID
;
1654 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1656 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1657 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
1658 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
1659 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1660 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1661 //if (!(MenuInfo->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL;
1662 //if (MenuInfo->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE;
1663 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1664 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1667 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1668 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1669 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1670 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1672 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1673 /* Draw the popup-menu arrow */
1674 if (lpitem
->hSubMenu
)
1677 CopyRect(&rectTemp, &rect);
1678 rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
1679 DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
1681 draw_popup_arrow( hdc
, rect
, arrow_bitmap_width
, arrow_bitmap_height
);
1686 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1688 if (lpitem
->fState
& MF_HILITE
)
1692 InflateRect (&rect
, -1, -1);
1693 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1694 InflateRect (&rect
, 1, 1);
1695 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1700 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1702 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1706 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1708 SetBkMode( hdc
, TRANSPARENT
);
1710 /* vertical separator */
1711 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1716 rc
.left
-= 3;//MENU_COL_SPACE / 2 + 1;
1718 rc
.bottom
= Height
- 3;
1721 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1722 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1723 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1724 LineTo( hdc
, rc
.left
, rc
.bottom
);
1725 SelectObject( hdc
, oldPen
);
1728 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1731 /* horizontal separator */
1732 if (lpitem
->fType
& MF_SEPARATOR
)
1739 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1742 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1743 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1744 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1745 LineTo( hdc
, rc
.right
, rc
.top
);
1746 SelectObject( hdc
, oldPen
);
1749 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1754 /* helper lines for debugging */
1755 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1756 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1757 SelectObject(hdc
, GetStockObject(DC_PEN
));
1758 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1759 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1760 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1766 INT y
= rect
.top
+ rect
.bottom
;
1768 BOOL checked
= FALSE
;
1769 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1770 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1771 /* Draw the check mark
1774 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1776 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1777 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1778 lpitem
->hbmpUnchecked
;
1779 if (bm
) /* we have a custom bitmap */
1781 HDC hdcMem
= CreateCompatibleDC( hdc
);
1783 SelectObject( hdcMem
, bm
);
1784 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1785 check_bitmap_width
, check_bitmap_height
,
1786 hdcMem
, 0, 0, SRCCOPY
);
1790 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1793 //HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
1794 //HDC hdcMem = CreateCompatibleDC( hdc );
1795 //SelectObject( hdcMem, bm );
1796 //SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height);
1797 CopyRect(&r
, &rect
);
1798 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1799 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1800 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1801 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1802 //BitBlt( hdc, rc.left, (y - r.bottom) / 2, r.right, r.bottom, hdcMem, 0, 0, SRCCOPY );
1803 //DeleteDC( hdcMem );
1804 //DeleteObject( bm );
1808 if ( lpitem
->hbmpItem
)//&& !( checked && (MenuInfo->dwStyle & MNS_CHECKORBMP)))
1811 CopyRect(&bmpRect
, &rect
);
1812 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1813 bmpRect
.left
+= check_bitmap_width
+ 2;
1814 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1817 bmpRect
.right
= bmpRect
.left
+ lpitem
->maxBmpSize
.cx
;
1818 /* some applications make this assumption on the DC's origin */
1819 //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
1820 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
, WndOwner
, odaction
, menuBar
);
1821 //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1824 /* Draw the popup-menu arrow */
1825 if (lpitem
->hSubMenu
)
1828 CopyRect(&rectTemp, &rect);
1829 rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
1830 DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
1832 draw_popup_arrow( hdc
, rect
, arrow_bitmap_width
, arrow_bitmap_height
);
1835 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1836 rect
.left
+= check_bitmap_width
;
1837 rect
.right
-= arrow_bitmap_width
;//check_bitmap_width;
1839 else if( lpitem
->hbmpItem
)
1840 { /* Draw the bitmap */
1843 //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
1844 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
, WndOwner
, odaction
, menuBar
);
1845 //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1848 /* process text if present */
1854 UINT uFormat
= menuBar
?
1855 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1856 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1858 if ((MenuInfo
->dwStyle
& MNS_CHECKORBMP
))
1859 rect
.left
+= max(0, (int)(MenuInfo
->cxTextAlign
- GetSystemMetrics(SM_CXMENUCHECK
)));
1861 rect
.left
+= MenuInfo
->cxTextAlign
;
1863 if ( lpitem
->fState
& MFS_DEFAULT
)
1865 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1869 if( lpitem
->hbmpItem
)
1870 rect
.left
+= lpitem
->maxBmpSize
.cx
;
1871 if( !(lpitem
->hbmpItem
== HBMMENU_CALLBACK
))
1872 rect
.left
+= MenuCharSize
.cx
;
1873 rect
.right
-= MenuCharSize
.cx
;
1874 //rect.left += MENU_BAR_ITEMS_SPACE / 2;
1875 //rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1878 Text
= lpitem
->lpstr
;
1881 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1882 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1886 if(lpitem
->fState
& MF_GRAYED
)
1888 if (!(lpitem
->fState
& MF_HILITE
) )
1890 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1891 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1892 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1893 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1895 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1898 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1900 /* paint the shortcut text */
1901 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1903 if (L
'\t' == Text
[i
])
1905 rect
.left
= lpitem
->dxTab
;
1906 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1910 rect
.right
= lpitem
->dxTab
;
1911 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1914 if (lpitem
->fState
& MF_GRAYED
)
1916 if (!(lpitem
->fState
& MF_HILITE
) )
1918 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1919 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1920 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1921 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1923 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1925 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1929 SelectObject (hdc
, hfontOld
);
1933 /***********************************************************************
1936 * Paint a popup menu.
1938 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1940 HBRUSH hPrevBrush
= 0;
1943 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1945 GetClientRect( hwnd
, &rect
);
1947 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1948 && (SelectObject( hdc
, hMenuFont
)))
1952 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1954 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1957 BOOL flat_menu
= FALSE
;
1958 ROSMENUINFO MenuInfo
;
1959 ROSMENUITEMINFO ItemInfo
;
1961 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1963 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1965 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1967 //TRACE("hmenu %p Style %08x\n", hmenu, menu->dwStyle);
1968 /* draw menu items */
1969 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.cItems
)
1972 MenuInitRosMenuItemInfo(&ItemInfo
);
1974 //for (u = MenuInfo.cItems; u > 0; u--, item++)
1975 for (u
= 0; u
< MenuInfo
.cItems
; u
++)
1977 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1979 HWND WndOwner
= MenuInfo
.spwndNotify
? MenuInfo
.spwndNotify
->head
.h
: NULL
;
1980 MenuDrawMenuItem(hwnd
, &MenuInfo
, WndOwner
, hdc
, &ItemInfo
,
1981 MenuInfo
.cyMenu
, FALSE
, ODA_DRAWENTIRE
);
1984 /* draw scroll arrows */
1985 if (MenuInfo
.dwArrowsOn
)
1987 MENU_DrawScrollArrows(&MenuInfo
, hdc
);
1990 MenuSetRosMenuInfo(&MenuInfo
);
1991 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1995 SelectObject( hdc
, hPrevBrush
);
2000 /***********************************************************************
2003 * Paint a menu bar. Returns the height of the menu bar.
2004 * called from [windows/nonclient.c]
2006 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
2011 HMENU hMenu
= GetMenu(hwnd
);
2013 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
2015 return GetSystemMetrics(SM_CYMENU
);
2020 hfontOld
= SelectObject(hDC
, hMenuFont
);
2022 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
2024 lprect
->bottom
= lprect
->top
+ lppop
.cyMenu
;
2026 if (hfontOld
) SelectObject( hDC
, hfontOld
);
2027 return lppop
.cyMenu
;
2030 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
2033 /***********************************************************************
2036 * Popup menu initialization before WM_ENTERMENULOOP.
2038 static BOOL
MENU_InitPopup( HWND hwndOwner
, HMENU hmenu
, UINT flags
)
2042 ROSMENUINFO MenuInfo
;
2044 TRACE("owner=%p hmenu=%p\n", hwndOwner
, hmenu
);
2046 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
2048 /* store the owner for DrawItem */
2049 if (!IsWindow( hwndOwner
))
2051 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2054 MenuGetRosMenuInfo(&MenuInfo
, menu
->head
.h
);
2055 //menu->hwndOwner = hwndOwner;
2056 MenuInfo
.spwndNotify
= ValidateHwndNoErr( hwndOwner
);
2058 if (flags
& TPM_LAYOUTRTL
)
2059 ex_style
= WS_EX_LAYOUTRTL
;
2061 /* NOTE: In Windows, top menu popup is not owned. */
2062 //menu->hWnd = CreateWindowExW( ex_style, WC_MENU, NULL,
2063 MenuInfo
.Wnd
= CreateWindowExW( ex_style
, WC_MENU
, NULL
,
2064 WS_POPUP
, 0, 0, 0, 0,
2065 hwndOwner
, 0, (HINSTANCE
)GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
2067 MenuSetRosMenuInfo(&MenuInfo
);
2068 if( !menu
->hWnd
) return FALSE
;
2072 /***********************************************************************
2075 * Display a popup menu.
2077 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
2078 INT x
, INT y
, INT xanchor
, INT yanchor
)
2080 ROSMENUINFO MenuInfo
;
2081 ROSMENUITEMINFO ItemInfo
;
2087 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2088 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
2090 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
2091 if (MenuInfo
.iItem
!= NO_SELECTED_ITEM
)
2093 MenuInitRosMenuItemInfo(&ItemInfo
);
2094 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.iItem
, &ItemInfo
))
2096 ItemInfo
.fMask
|= MIIM_STATE
;
2097 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2098 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.iItem
, &ItemInfo
);
2100 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2101 MenuInfo
.iItem
= NO_SELECTED_ITEM
;
2104 //menu->dwArrowsOn = 0;
2105 MenuInfo
.dwArrowsOn
= 0;
2106 MenuSetRosMenuInfo(&MenuInfo
);
2107 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
2109 /* adjust popup menu pos so that it fits within the desktop */
2111 width
= MenuInfo
.cxMenu
+ GetSystemMetrics(SM_CXBORDER
);
2112 height
= MenuInfo
.cyMenu
+ GetSystemMetrics(SM_CYBORDER
);
2114 /* FIXME: should use item rect */
2117 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
2118 info
.cbSize
= sizeof(info
);
2119 GetMonitorInfoW( monitor
, &info
);
2121 if (flags
& TPM_LAYOUTRTL
)
2122 flags
^= TPM_RIGHTALIGN
;
2124 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
2125 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
2127 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
2128 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
2130 if( x
+ width
> info
.rcMonitor
.right
)
2132 if( xanchor
&& x
>= width
- xanchor
)
2133 x
-= width
- xanchor
;
2135 if( x
+ width
> info
.rcMonitor
.right
)
2136 x
= info
.rcMonitor
.right
- width
;
2138 if( x
< info
.rcMonitor
.left
) x
= info
.rcMonitor
.left
;
2140 if( y
+ height
> info
.rcMonitor
.bottom
)
2142 if( yanchor
&& y
>= height
+ yanchor
)
2143 y
-= height
+ yanchor
;
2145 if( y
+ height
> info
.rcMonitor
.bottom
)
2146 y
= info
.rcMonitor
.bottom
- height
;
2148 if( y
< info
.rcMonitor
.top
) y
= info
.rcMonitor
.top
;
2151 top_popup
= MenuInfo
.Wnd
;
2152 top_popup_hmenu
= hmenu
;
2154 /* Display the window */
2156 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, x
, y
, width
, height
,
2157 SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
2158 UpdateWindow( MenuInfo
.Wnd
);
2160 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
2165 /***********************************************************************
2166 * MENU_EnsureMenuItemVisible
2169 MENU_EnsureMenuItemVisible(PROSMENUINFO lppop
, PROSMENUITEMINFO item
, HDC hdc
)
2171 if (lppop
->dwArrowsOn
)
2173 //ITEM *item = &lppop->items[wIndex];
2174 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
2175 UINT nOldPos
= lppop
->iTop
;
2177 UINT arrow_bitmap_height
;
2180 GetClientRect(lppop
->Wnd
, &rc
);
2182 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp
), &bmp
);
2183 arrow_bitmap_height
= bmp
.bmHeight
;
2185 rc
.top
+= arrow_bitmap_height
;
2186 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
2188 nMaxHeight
-= GetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
2189 if (item
->Rect
.bottom
> lppop
->iTop
+ nMaxHeight
)
2191 lppop
->iTop
= item
->Rect
.bottom
- nMaxHeight
;
2192 ScrollWindow(lppop
->Wnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2193 MENU_DrawScrollArrows(lppop
, hdc
);
2195 else if (item
->Rect
.top
- MENU_TOP_MARGIN
< lppop
->iTop
)
2197 lppop
->iTop
= item
->Rect
.top
- MENU_TOP_MARGIN
;
2198 ScrollWindow(lppop
->Wnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2199 MENU_DrawScrollArrows(lppop
, hdc
);
2201 MenuSetRosMenuInfo(lppop
);
2205 /***********************************************************************
2208 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
2209 BOOL sendMenuSelect
, HMENU topmenu
)
2211 ROSMENUITEMINFO ItemInfo
;
2212 ROSMENUINFO TopMenuInfo
;
2215 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
2217 if (!hmenu
|| !hmenu
->cItems
|| !hmenu
->Wnd
) return;
2218 if (hmenu
->iItem
== wIndex
) return;
2219 if (hmenu
->fFlags
& MNF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
2220 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2222 top_popup
= hmenu
->Wnd
;
2223 top_popup_hmenu
= hmenu
->Self
;
2226 SelectObject( hdc
, hMenuFont
);
2228 MenuInitRosMenuItemInfo(&ItemInfo
);
2230 /* Clear previous highlighted item */
2231 if (hmenu
->iItem
!= NO_SELECTED_ITEM
)
2233 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
))
2235 ItemInfo
.fMask
|= MIIM_STATE
;
2236 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2237 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
);
2239 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
2240 hmenu
->cyMenu
, !(hmenu
->fFlags
& MNF_POPUP
),
2244 /* Highlight new item (if any) */
2245 hmenu
->iItem
= wIndex
;
2246 MenuSetRosMenuInfo(hmenu
);
2247 if (hmenu
->iItem
!= NO_SELECTED_ITEM
)
2249 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
))
2251 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
2253 ItemInfo
.fMask
|= MIIM_STATE
;
2254 ItemInfo
.fState
|= MF_HILITE
;
2255 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
);
2256 MENU_EnsureMenuItemVisible(hmenu
, &ItemInfo
, hdc
);
2257 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
2258 &ItemInfo
, hmenu
->cyMenu
, !(hmenu
->fFlags
& MNF_POPUP
), ODA_SELECT
);
2262 WPARAM wParam
= MAKEWPARAM( ItemInfo
.hSubMenu
? wIndex
: ItemInfo
.wID
,
2263 ItemInfo
.fType
| ItemInfo
.fState
|
2264 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
2265 (hmenu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
2267 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) hmenu
->Self
);
2271 else if (sendMenuSelect
)
2276 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
2277 if (pos
!= NO_SELECTED_ITEM
)
2279 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
2280 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
2282 WPARAM wParam
= MAKEWPARAM( Pos
, ItemInfo
.fType
| ItemInfo
.fState
|
2283 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
2284 (TopMenuInfo
.fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
2286 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) topmenu
);
2291 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2292 ReleaseDC(hmenu
->Wnd
, hdc
);
2295 /***********************************************************************
2298 * Moves currently selected item according to the Offset parameter.
2299 * If there is no selection then it should select the last item if
2300 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2302 static void FASTCALL
2303 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
2306 ROSMENUITEMINFO ItemInfo
;
2309 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
2311 /* Prevent looping */
2312 if (0 == MenuInfo
->cItems
|| 0 == Offset
)
2314 else if (Offset
< -1)
2316 else if (Offset
> 1)
2319 MenuInitRosMenuItemInfo(&ItemInfo
);
2321 OrigPos
= MenuInfo
->iItem
;
2322 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
2329 i
= MenuInfo
->iItem
;
2336 /* Clip and wrap around */
2339 i
= MenuInfo
->cItems
- 1;
2341 else if (i
>= MenuInfo
->cItems
)
2345 /* If this is a good candidate; */
2346 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
2347 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2349 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
2350 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2353 } while (i
!= OrigPos
);
2356 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2361 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2363 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2365 PPOPUPMENU pPopupMenu
;
2367 pWnd
= ValidateHwndNoErr(Wnd
);
2372 if (Message
!= WM_NCCREATE
)
2374 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2376 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
2377 pPopupMenu
= HeapAlloc( GetProcessHeap(), 0, sizeof(POPUPMENU
) );
2378 pPopupMenu
->spwndPopupMenu
= pWnd
;
2379 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)pPopupMenu
);
2383 if (pWnd
->fnid
!= FNID_MENU
)
2385 ERR("Wrong window class for Menu!\n");
2388 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
2393 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2399 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
2400 pPopupMenu
->spmenu
= ValidateHandle(cs
->lpCreateParams
, TYPE_MENU
);
2404 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2405 return MA_NOACTIVATE
;
2410 BeginPaint(Wnd
, &ps
);
2411 MenuDrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
->head
.h
);
2416 case WM_PRINTCLIENT
:
2418 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
->head
.h
);
2426 /* zero out global pointer in case resident popup window was destroyed. */
2427 if (Wnd
== top_popup
)
2430 top_popup_hmenu
= NULL
;
2436 HeapFree( GetProcessHeap(), 0, pPopupMenu
);
2437 SetWindowLongPtrW(Wnd
, 0, 0);
2438 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
2445 if (!pPopupMenu
|| !pPopupMenu
->spmenu
)
2447 OutputDebugStringA("no menu to display\n");
2452 pPopupMenu->spmenu = NULL; ///// WTF?
2456 case MM_SETMENUHANDLE
:
2458 PMENU pmenu
= ValidateHandle((HMENU
)wParam
, TYPE_MENU
);
2461 ERR("Bad Menu Handle\n");
2464 pPopupMenu
->spmenu
= pmenu
;
2468 case MM_GETMENUHANDLE
:
2470 return (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? pPopupMenu
->spmenu
->head
.h
: NULL
) : NULL
);
2473 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2481 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2483 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2486 pWnd
= ValidateHwnd(Wnd
);
2491 if (Message
!= WM_NCCREATE
)
2493 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2495 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
2499 if (pWnd
->fnid
!= FNID_MENU
)
2501 ERR("Wrong window class for Menu!\n");
2508 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2514 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
2515 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
2519 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2520 return MA_NOACTIVATE
;
2525 BeginPaint(Wnd
, &ps
);
2526 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
2531 case WM_PRINTCLIENT
:
2533 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
2534 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
2542 /* zero out global pointer in case resident popup window was destroyed. */
2543 if (Wnd
== top_popup
)
2546 top_popup_hmenu
= NULL
;
2552 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
2559 if (0 == GetWindowLongPtrW(Wnd
, 0))
2561 OutputDebugStringA("no menu to display\n");
2566 SetWindowLongPtrW(Wnd
, 0, 0);
2570 case MM_SETMENUHANDLE
:
2571 SetWindowLongPtrW(Wnd
, 0, wParam
);
2574 case MM_GETMENUHANDLE
:
2576 return GetWindowLongPtrW(Wnd
, 0);
2579 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2586 // This breaks some test results. Should handle A2U if called!
2588 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2592 pWnd
= ValidateHwnd(Wnd
);
2593 if (pWnd
&& !pWnd
->fnid
&& Message
!= WM_NCCREATE
)
2595 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
2597 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2603 case WM_MOUSEACTIVATE
:
2605 case WM_PRINTCLIENT
:
2610 case MM_SETMENUHANDLE
:
2611 case MM_GETMENUHANDLE
:
2613 return PopupMenuWndProcW(Wnd
, Message
, wParam
, lParam
);
2616 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
2621 /**********************************************************************
2622 * MENU_ParseResource
2624 * Parse a standard menu resource and add items to the menu.
2625 * Return a pointer to the end of the resource.
2627 * NOTE: flags is equivalent to the mtOption field
2629 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
)
2638 flags
= GET_WORD(res
);
2640 /* remove MF_END flag before passing it to AppendMenu()! */
2641 end
= (flags
& MF_END
);
2642 if(end
) flags
^= MF_END
;
2644 res
+= sizeof(WORD
);
2645 if(!(flags
& MF_POPUP
))
2648 res
+= sizeof(WORD
);
2651 res
+= (strlenW(str
) + 1) * sizeof(WCHAR
);
2653 if (flags
& MF_POPUP
)
2655 hSubMenu
= CreatePopupMenu();
2656 if(!hSubMenu
) return NULL
;
2657 if(!(res
= MENU_ParseResource(res
, hSubMenu
))) return NULL
;
2658 AppendMenuW(hMenu
, flags
, (UINT_PTR
)hSubMenu
, (LPCWSTR
)str
);
2660 else /* Not a popup */
2662 AppendMenuW(hMenu
, flags
, id
, *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2668 /**********************************************************************
2669 * MENUEX_ParseResource
2671 * Parse an extended menu resource and add items to the menu.
2672 * Return a pointer to the end of the resource.
2674 static LPCSTR
MENUEX_ParseResource(LPCSTR res
, HMENU hMenu
)
2681 mii
.cbSize
= sizeof(mii
);
2682 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
2683 mii
.fType
= GET_DWORD(res
);
2684 res
+= sizeof(DWORD
);
2685 mii
.fState
= GET_DWORD(res
);
2686 res
+= sizeof(DWORD
);
2687 mii
.wID
= GET_DWORD(res
);
2688 res
+= sizeof(DWORD
);
2689 resinfo
= GET_WORD(res
);
2690 res
+= sizeof(WORD
);
2691 /* Align the text on a word boundary. */
2692 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2693 mii
.dwTypeData
= (LPWSTR
)res
;
2694 mii
.cch
= strlenW(mii
.dwTypeData
);
2695 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2696 /* Align the following fields on a dword boundary. */
2697 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2699 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2700 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2702 if (resinfo
& 1) /* Pop-up? */
2704 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2705 res
+= sizeof(DWORD
);
2706 mii
.hSubMenu
= CreatePopupMenu();
2709 ERR("CreatePopupMenu failed\n");
2713 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
2715 ERR("MENUEX_ParseResource failed\n");
2716 DestroyMenu(mii
.hSubMenu
);
2719 mii
.fMask
|= MIIM_SUBMENU
;
2721 else if (!mii
.dwTypeData
[0] && !(mii
.fType
& MF_SEPARATOR
))
2723 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
2724 mii
.wID
, mii
.fType
);
2725 mii
.fType
|= MF_SEPARATOR
;
2727 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2728 } while (!(resinfo
& MF_END
));
2733 /***********************************************************************
2734 * DrawMenuBarTemp (USER32.@)
2738 * called by W98SE desk.cpl Control Panel Applet
2740 * Not 100% sure about the param names, but close.
2745 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2747 ROSMENUINFO MenuInfo
;
2748 ROSMENUITEMINFO ItemInfo
;
2750 HFONT FontOld
= NULL
;
2751 BOOL flat_menu
= FALSE
;
2753 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2757 Menu
= GetMenu(Wnd
);
2765 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2767 return GetSystemMetrics(SM_CYMENU
);
2770 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2772 FontOld
= SelectObject(DC
, Font
);
2774 if (0 == MenuInfo
.cyMenu
)
2776 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2779 Rect
->bottom
= Rect
->top
+ MenuInfo
.cyMenu
;
2781 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2783 SelectObject(DC
, GetStockObject(DC_PEN
));
2784 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2785 MoveToEx(DC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2786 LineTo(DC
, Rect
->right
, Rect
->bottom
- 1);
2788 if (0 == MenuInfo
.cItems
)
2790 SelectObject(DC
, FontOld
);
2791 return GetSystemMetrics(SM_CYMENU
);
2794 MenuInitRosMenuItemInfo(&ItemInfo
);
2795 for (i
= 0; i
< MenuInfo
.cItems
; i
++)
2797 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2799 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2800 MenuInfo
.cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2803 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2805 SelectObject(DC
, FontOld
);
2807 return MenuInfo
.cyMenu
;
2811 /***********************************************************************
2814 * Display the sub-menu of the selected item of this menu.
2815 * Return the handle of the submenu, or menu if no submenu to display.
2817 static HMENU FASTCALL
2818 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2821 ROSMENUITEMINFO ItemInfo
;
2822 ROSMENUINFO SubMenuInfo
;
2826 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2828 if (MenuInfo
->iItem
== NO_SELECTED_ITEM
) return MenuInfo
->Self
;
2830 MenuInitRosMenuItemInfo(&ItemInfo
);
2831 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
2833 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2834 return MenuInfo
->Self
;
2837 //item = &menu->rgItems[menu->iItem];
2838 if (!(ItemInfo
.hSubMenu
) || (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2840 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2841 return MenuInfo
->Self
;
2844 /* message must be sent before using item,
2845 because nearly everything may be changed by the application ! */
2847 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2848 if (!(Flags
& TPM_NONOTIFY
))
2850 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2851 MAKELPARAM(MenuInfo
->iItem
, IS_SYSTEM_MENU(MenuInfo
)));
2854 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
2856 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2857 return MenuInfo
->Self
;
2860 //item = &menu->rgItems[menu->iItem];
2861 Rect
= ItemInfo
.Rect
;
2863 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2864 if (!(ItemInfo
.fState
& MF_HILITE
))
2866 if (MenuInfo
->fFlags
& MNF_POPUP
) Dc
= GetDC(MenuInfo
->Wnd
);
2867 else Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2869 SelectObject(Dc
, hMenuFont
);
2870 ItemInfo
.fMask
|= MIIM_STATE
;
2871 ItemInfo
.fState
|= MF_HILITE
;
2872 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2873 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->cyMenu
,
2874 !(MenuInfo
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
2875 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2878 if (!ItemInfo
.Rect
.top
&& !ItemInfo
.Rect
.left
&& !ItemInfo
.Rect
.bottom
&& !ItemInfo
.Rect
.right
)
2879 ItemInfo
.Rect
= Rect
;
2881 ItemInfo
.fMask
|= MIIM_STATE
;
2882 ItemInfo
.fState
|= MF_MOUSESELECT
;
2883 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2885 if (IS_SYSTEM_MENU(MenuInfo
))
2887 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
,
2888 GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2889 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2891 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2892 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
= Rect
.right
;
2893 Rect
.top
= Rect
.bottom
;
2894 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2895 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2899 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2900 if (MenuInfo
->fFlags
& MNF_POPUP
)
2902 RECT rc
= ItemInfo
.Rect
;
2904 MENU_AdjustMenuItemRect(MenuInfo
, &rc
);
2906 /* The first item in the popup menu has to be at the
2907 same y position as the focused menu item */
2908 if(Flags
& TPM_LAYOUTRTL
)
2909 Rect
.left
+= GetSystemMetrics(SM_CXBORDER
);
2911 Rect
.left
+= rc
.right
/*ItemInfo.Rect.right*/ - GetSystemMetrics(SM_CXBORDER
);
2912 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
2913 Rect
.right
= rc
.left
- rc
.right
+ GetSystemMetrics(SM_CXBORDER
);
2914 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
2915 - GetSystemMetrics(SM_CYBORDER
);
2919 if(Flags
& TPM_LAYOUTRTL
)
2920 Rect
.left
+= Rect
.right
- ItemInfo
.Rect
.left
;
2922 Rect
.left
+= ItemInfo
.Rect
.left
;
2923 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2924 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2925 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2929 /* use default alignment for submenus */
2930 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
2932 MENU_InitPopup( WndOwner
, ItemInfo
.hSubMenu
, Flags
);
2934 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->iItem
, Flags
,
2935 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2936 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2938 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2941 Ret
= ItemInfo
.hSubMenu
;
2942 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2947 /**********************************************************************
2950 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2952 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2954 void MENU_EndMenu( HWND hwnd
)
2957 menu
= top_popup_hmenu
? MENU_GetMenu( top_popup_hmenu
) : NULL
;
2958 if (menu
&& ( hwnd
== menu
->hWnd
|| hwnd
== (menu
->spwndNotify
? menu
->spwndNotify
->head
.h
: NULL
)) )
2962 /***********************************************************************
2965 * Hide the sub-popup menus of this menu.
2967 static void FASTCALL
2968 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2969 BOOL SendMenuSelect
, UINT wFlags
)
2971 ROSMENUINFO SubMenuInfo
;
2972 ROSMENUITEMINFO ItemInfo
;
2974 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2976 if (MenuInfo
&& top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->iItem
)
2978 //item = &menu->rgItems[menu->iItem];
2979 MenuInitRosMenuItemInfo(&ItemInfo
);
2980 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2981 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
)
2982 || !(ItemInfo
.hSubMenu
)
2983 || !(ItemInfo
.fState
& MF_MOUSESELECT
))
2985 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2988 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2989 ItemInfo
.fMask
|= MIIM_STATE
;
2990 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2991 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2993 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2994 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2996 DestroyWindow(SubMenuInfo
.Wnd
);
2997 /* Native returns handle to destroyed window */
2998 if (!(wFlags
& TPM_NONOTIFY
))
2999 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
3000 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
3002 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3003 // Fixes todo_wine User32 test menu.c line 2233 GetMenuBarInfo callback....
3005 SubMenuInfo
.Wnd
= NULL
;
3006 MenuSetRosMenuInfo(&SubMenuInfo
);
3012 /***********************************************************************
3013 * MenuSwitchTracking
3015 * Helper function for menu navigation routines.
3017 static void FASTCALL
3018 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
3020 ROSMENUINFO TopMenuInfo
;
3022 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
3024 if ( MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
3025 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
3026 !((PtMenuInfo
->fFlags
| TopMenuInfo
.fFlags
) & MNF_POPUP
) )
3028 /* both are top level menus (system and menu-bar) */
3029 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
3030 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3031 Mt
->TopMenu
= PtMenuInfo
->Self
;
3035 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
3038 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
3041 /***********************************************************************
3042 * MenuExecFocusedItem
3044 * Execute a menu item (for instance when user pressed Enter).
3045 * Return the wID of the executed item. Otherwise, -1 indicating
3046 * that no menu item was executed, -2 if a popup is shown;
3047 * Have to receive the flags for the TrackPopupMenu options to avoid
3048 * sending unwanted message.
3052 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
3054 ROSMENUITEMINFO ItemInfo
;
3057 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
3059 if (0 == MenuInfo
->cItems
|| NO_SELECTED_ITEM
== MenuInfo
->iItem
)
3064 MenuInitRosMenuItemInfo(&ItemInfo
);
3065 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
3067 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3071 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
3073 if (0 == (ItemInfo
.hSubMenu
))
3075 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
3076 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
3078 /* If TPM_RETURNCMD is set you return the id, but
3079 do not send a message to the owner */
3080 if (0 == (Flags
& TPM_RETURNCMD
))
3082 if (0 != (MenuInfo
->fFlags
& MNF_SYSMENU
))
3084 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
3085 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
3089 ROSMENUINFO topmenuI
;
3090 BOOL ret
= MenuGetRosMenuInfo(&topmenuI
, Mt
->TopMenu
);
3091 DWORD dwStyle
= MenuInfo
->dwStyle
| (ret
? topmenuI
.dwStyle
: 0);
3093 if (dwStyle
& MNS_NOTIFYBYPOS
)
3094 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
, MenuInfo
->iItem
, (LPARAM
)MenuInfo
->Self
);
3096 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
3100 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3106 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
3113 /***********************************************************************
3116 * Return TRUE if we can go on with menu tracking.
3118 static BOOL FASTCALL
3119 MENU_ButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
3122 ROSMENUINFO MenuInfo
;
3123 ROSMENUITEMINFO Item
;
3125 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
3129 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
3133 if (IS_SYSTEM_MENU(&MenuInfo
))
3139 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
3141 MenuInitRosMenuItemInfo(&Item
);
3142 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
3144 MenuCleanupRosMenuItemInfo(&Item
);
3148 if (!(Item
.fType
& MF_SEPARATOR
) &&
3149 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
3151 if (MenuInfo
.iItem
!= Index
)
3153 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
3156 /* If the popup menu is not already "popped" */
3157 if (0 == (Item
.fState
& MF_MOUSESELECT
))
3159 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3163 MenuCleanupRosMenuItemInfo(&Item
);
3168 /* else the click was on the menu bar, finish the tracking */
3173 /***********************************************************************
3176 * Return the value of MenuExecFocusedItem if
3177 * the selected item was not a popup. Else open the popup.
3178 * A -1 return value indicates that we go on with menu tracking.
3182 MENU_ButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
3185 ROSMENUINFO MenuInfo
;
3186 ROSMENUITEMINFO ItemInfo
;
3188 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
3193 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
3198 if (! IS_SYSTEM_MENU(&MenuInfo
))
3200 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
3202 MenuInitRosMenuItemInfo(&ItemInfo
);
3203 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
3204 MenuInfo
.iItem
== Id
)
3206 if (0 == (ItemInfo
.hSubMenu
))
3208 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
3209 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3210 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
3212 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3214 /* If we are dealing with the top-level menu */
3215 /* and this is a click on an already "popped" item: */
3216 /* Stop the menu tracking and close the opened submenus */
3217 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
3219 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3223 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3224 MenuInfo
.TimeToHide
= TRUE
;
3225 MenuSetRosMenuInfo(&MenuInfo
);
3231 /***********************************************************************
3234 * Walks menu chain trying to find a menu pt maps to.
3236 static HMENU FASTCALL
3237 MENU_PtMenu(HMENU hMenu
, POINT pt
)
3243 menu
= MENU_GetMenu( hMenu
);
3244 if (!menu
) return NULL
;
3246 /* try subpopup first (if any) */
3247 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3249 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
3250 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3251 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3253 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
3254 ret
= MENU_PtMenu( UserHMGetHandle(pSubMenu
), pt
);
3258 /* check the current window (avoiding WM_HITTEST) */
3261 INT ht
= DefWndNCHitTest(menu
->hWnd
, pt
);
3262 if ( menu
->fFlags
& MNF_POPUP
)
3264 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= hMenu
;
3266 else if (ht
== HTSYSMENU
)
3267 ret
= get_win_sys_menu(menu
->hWnd
);
3268 else if (ht
== HTMENU
)
3269 ret
= GetMenu( menu
->hWnd
);
3274 /***********************************************************************
3277 * Return TRUE if we can go on with menu tracking.
3279 static BOOL FASTCALL
3280 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
3283 ROSMENUINFO MenuInfo
;
3284 ROSMENUITEMINFO ItemInfo
;
3288 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
3292 if (IS_SYSTEM_MENU(&MenuInfo
))
3298 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
3303 Index
= NO_SELECTED_ITEM
;
3306 if (NO_SELECTED_ITEM
== Index
)
3308 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
3309 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3311 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3315 else if (MenuInfo
.iItem
!= Index
)
3317 MenuInitRosMenuItemInfo(&ItemInfo
);
3318 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
3319 !(ItemInfo
.fType
& MF_SEPARATOR
))
3321 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
3322 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
3323 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3325 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3331 /***********************************************************************
3334 * Return the handle of the selected sub-popup menu (if any).
3337 HMENU
MENU_GetSubPopup( HMENU hmenu
)
3342 menu
= MENU_GetMenu( hmenu
);
3344 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3346 //item = &menu->rgItems[menu->iItem];
3347 item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
3348 if (item
) item
= &item
[menu
->iItem
];
3349 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3351 PMENU pSubMenu
= DesktopPtrToUser(item
->spSubMenu
);
3352 return UserHMGetHandle(pSubMenu
);
3357 /***********************************************************************
3360 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3362 static LRESULT FASTCALL
3363 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
, UINT wFlags
)
3365 ROSMENUINFO TopMenuInfo
;
3366 ROSMENUINFO MenuInfo
;
3368 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3370 return (LRESULT
) FALSE
;
3373 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.iItem
)
3374 || (VK_RIGHT
== Vk
&& TopMenuInfo
.iItem
== TopMenuInfo
.cItems
- 1))
3376 MDINEXTMENU NextMenu
;
3381 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
3382 NextMenu
.hmenuNext
= NULL
;
3383 NextMenu
.hwndNext
= NULL
;
3384 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3386 TRACE("%p [%p] -> %p [%p]\n",
3387 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3389 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3391 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
3392 NewWnd
= Mt
->OwnerWnd
;
3393 if (IS_SYSTEM_MENU(&TopMenuInfo
))
3395 /* switch to the menu bar */
3397 if (0 != (Style
& WS_CHILD
)
3398 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
3405 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
3409 Id
= MenuInfo
.cItems
- 1;
3412 else if (0 != (Style
& WS_SYSMENU
))
3414 /* switch to the system menu */
3415 NewMenu
= get_win_sys_menu(NewWnd
);
3422 else /* application returned a new menu to switch to */
3424 NewMenu
= NextMenu
.hmenuNext
;
3425 NewWnd
= NextMenu
.hwndNext
;
3427 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
3429 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
3431 if (0 != (Style
& WS_SYSMENU
)
3432 && get_win_sys_menu(NewWnd
) == NewMenu
)
3434 /* get the real system menu */
3435 NewMenu
= get_win_sys_menu(NewWnd
);
3437 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
3439 /* FIXME: Not sure what to do here;
3440 * perhaps try to track NewMenu as a popup? */
3442 WARN(" -- got confused.\n");
3452 if (NewMenu
!= Mt
->TopMenu
)
3454 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
3456 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3458 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
3462 if (NewWnd
!= Mt
->OwnerWnd
)
3464 Mt
->OwnerWnd
= NewWnd
;
3465 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
); // 1
3466 SetCapture(Mt
->OwnerWnd
); // 2
3469 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
3470 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3472 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
3481 /***********************************************************************
3484 * The idea is not to show the popup if the next input message is
3485 * going to hide it anyway.
3487 static BOOL FASTCALL
3488 MenuSuspendPopup(MTRACKER
* Mt
, UINT uMsg
)
3492 msg
.hwnd
= Mt
->OwnerWnd
;
3494 PeekMessageW( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
); // ported incorrectly since 8317 GvG
3495 //Mt->TrackFlags |= TF_SKIPREMOVE; // This sends TrackMenu into a loop with arrow keys!!!!
3500 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3501 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3503 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3504 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3505 if( msg
.message
== WM_KEYDOWN
&&
3506 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3508 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3514 /* failures go through this */
3515 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3519 /***********************************************************************
3522 * Handle a VK_ESCAPE key event in a menu.
3524 static BOOL FASTCALL
3525 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
3527 BOOL EndMenu
= TRUE
;
3528 ROSMENUINFO MenuInfo
;
3529 HMENU MenuTmp
, MenuPrev
;
3531 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3533 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
3534 && 0 != (MenuInfo
.fFlags
& MNF_POPUP
))
3536 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3538 /* close topmost popup */
3539 while (MenuTmp
!= Mt
->CurrentMenu
)
3542 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3545 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3547 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
3549 Mt
->CurrentMenu
= MenuPrev
;
3557 /***********************************************************************
3560 * Handle a VK_LEFT key event in a menu.
3562 static void FASTCALL
3563 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3565 ROSMENUINFO MenuInfo
;
3566 ROSMENUINFO TopMenuInfo
;
3567 ROSMENUINFO PrevMenuInfo
;
3568 HMENU MenuTmp
, MenuPrev
;
3571 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3573 /* Try to move 1 column left (if possible) */
3574 if ( (PrevCol
= MENU_GetStartOfPrevColumn(Mt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3576 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3578 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3583 /* close topmost popup */
3584 while (MenuTmp
!= Mt
->CurrentMenu
)
3587 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3590 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3594 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3595 Mt
->CurrentMenu
= MenuPrev
;
3597 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3601 if ((MenuPrev
== Mt
->TopMenu
) && !(TopMenuInfo
.fFlags
& MNF_POPUP
))
3603 /* move menu bar selection if no more popups are left */
3605 if (!MenuDoNextMenu(Mt
, VK_LEFT
, Flags
))
3607 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3610 if (MenuPrev
!= MenuTmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3612 /* A sublevel menu was displayed - display the next one
3613 * unless there is another displacement coming up */
3615 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3616 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3618 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3625 /***********************************************************************
3628 * Handle a VK_RIGHT key event in a menu.
3630 static void FASTCALL
MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3633 ROSMENUINFO MenuInfo
;
3634 ROSMENUINFO CurrentMenuInfo
;
3637 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3638 Mt
->CurrentMenu
, Mt
->TopMenu
);
3640 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
)) return;
3641 if ((MenuInfo
.fFlags
& MNF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3643 /* If already displaying a popup, try to display sub-popup */
3645 hmenutmp
= Mt
->CurrentMenu
;
3646 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3648 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3651 /* if subpopup was displayed then we are done */
3652 if (hmenutmp
!= Mt
->CurrentMenu
) return;
3655 /* Check to see if there's another column */
3656 if ( (NextCol
= MENU_GetStartOfNextColumn(Mt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3658 TRACE("Going to %d.\n", NextCol
);
3659 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3661 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3666 if (!(MenuInfo
.fFlags
& MNF_POPUP
)) /* menu bar tracking */
3668 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3670 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3671 hmenutmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3678 /* try to move to the next item */
3679 if ( !MenuDoNextMenu(Mt
, VK_RIGHT
, Flags
))
3680 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3682 if ( hmenutmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3684 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3685 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3687 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3694 /***********************************************************************
3697 * Menu tracking code.
3699 static INT FASTCALL
MenuTrackMenu(HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
3700 HWND hwnd
, const RECT
*lprect
)
3703 ROSMENUINFO MenuInfo
;
3704 ROSMENUITEMINFO ItemInfo
;
3707 INT executedMenuId
= -1;
3710 BOOL enterIdleSent
= FALSE
;
3713 mt
.CurrentMenu
= hmenu
;
3719 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3720 hmenu
, wFlags
, x
, y
, hwnd
, lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3721 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3725 WARN("Invalid menu handle %p\n", hmenu
); // Error already set in IsMenu.
3729 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
))
3734 if (wFlags
& TPM_BUTTONDOWN
)
3736 /* Get the result in order to start the tracking or not */
3737 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
3738 fEndMenu
= !fRemove
;
3741 if (wFlags
& TF_ENDMENU
) fEndMenu
= TRUE
;
3743 /* owner may not be visible when tracking a popup, so use the menu itself */
3744 capture_win
= (wFlags
& TPM_POPUPMENU
) ? MenuInfo
.Wnd
: mt
.OwnerWnd
;
3745 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, capture_win
); // 1
3746 SetCapture(capture_win
); // 2
3750 BOOL ErrorExit
= FALSE
;
3751 menu
= MENU_GetMenu( mt
.CurrentMenu
);
3752 if (!menu
) /* sometimes happens if I do a window manager close */
3755 /* we have to keep the message in the queue until it's
3756 * clear that menu loop is not over yet. */
3760 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3762 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3763 /* remove the message from the queue */
3764 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3769 if (!ValidateHwndNoErr(mt
.OwnerWnd
) || !ValidateHwndNoErr(MenuInfo
.Wnd
))
3771 ErrorExit
= TRUE
; // Do not wait on dead windows, now test_capture_4 works.
3776 HWND win
= MenuInfo
.fFlags
& MNF_POPUP
? MenuInfo
.Wnd
: NULL
;
3777 enterIdleSent
= TRUE
;
3778 SendMessageW( mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3784 if (ErrorExit
) break; // Gracefully dropout.
3786 /* check if EndMenu() tried to cancel us, by posting this message */
3787 if (msg
.message
== WM_CANCELMODE
)
3789 /* we are now out of the loop */
3792 /* remove the message from the queue */
3793 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3795 /* break out of internal loop, ala ESCAPE */
3799 TranslateMessage( &msg
);
3802 if ( (msg
.hwnd
== MenuInfo
.Wnd
) || (msg
.message
!=WM_TIMER
) )
3803 enterIdleSent
=FALSE
;
3806 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3809 * Use the mouse coordinates in lParam instead of those in the MSG
3810 * struct to properly handle synthetic messages. They are already
3811 * in screen coordinates.
3813 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3814 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3816 /* Find a menu for this mouse event */
3817 hmenu
= MENU_PtMenu(mt
.TopMenu
, mt
.Pt
);
3821 /* no WM_NC... messages in captured state */
3823 case WM_RBUTTONDBLCLK
:
3824 case WM_RBUTTONDOWN
:
3825 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3827 case WM_LBUTTONDBLCLK
:
3828 case WM_LBUTTONDOWN
:
3829 /* If the message belongs to the menu, removes it from the queue */
3830 /* Else, end menu tracking */
3831 fRemove
= MENU_ButtonDown(&mt
, hmenu
, wFlags
);
3832 fEndMenu
= !fRemove
;
3836 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3839 /* Check if a menu was selected by the mouse */
3842 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
3843 TRACE("executedMenuId %d\n", executedMenuId
);
3845 /* End the loop if executedMenuId is an item ID */
3846 /* or if the job was done (executedMenuId = 0). */
3847 fEndMenu
= fRemove
= (executedMenuId
!= -1);
3849 /* No menu was selected by the mouse */
3850 /* if the function was called by TrackPopupMenu, continue
3851 with the menu tracking. If not, stop it */
3853 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3858 /* the selected menu item must be changed every time */
3859 /* the mouse moves. */
3862 fEndMenu
|= !MenuMouseMove( &mt
, hmenu
, wFlags
);
3864 } /* switch(msg.message) - mouse */
3866 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
3868 fRemove
= TRUE
; /* Keyboard messages are always removed */
3882 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3884 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
3885 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3890 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3891 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3893 if (!(MenuInfo
.fFlags
& MNF_POPUP
))
3895 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3896 mt
.CurrentMenu
= MenuShowSubPopup(mt
.OwnerWnd
, &MenuInfo
, TRUE
, wFlags
);
3898 else /* otherwise try to move selection */
3899 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
3904 MenuKeyLeft( &mt
, wFlags
);
3908 MenuKeyRight( &mt
, wFlags
);
3912 fEndMenu
= MenuKeyEscape(&mt
, wFlags
);
3918 hi
.cbSize
= sizeof(HELPINFO
);
3919 hi
.iContextType
= HELPINFO_MENUITEM
;
3920 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3922 if (MenuInfo
.iItem
== NO_SELECTED_ITEM
)
3926 MenuInitRosMenuItemInfo(&ItemInfo
);
3927 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3931 hi
.iCtrlId
= ItemInfo
.wID
;
3937 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3940 hi
.hItemHandle
= hmenu
;
3941 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3942 hi
.MousePos
= msg
.pt
;
3943 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
3950 break; /* WM_KEYDOWN */
3957 if (! MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
)) break;
3958 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
3960 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3961 fEndMenu
= (executedMenuId
!= -2);
3965 /* Hack to avoid control chars. */
3966 /* We will find a better way real soon... */
3967 if (msg
.wParam
< 32) break;
3969 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
3970 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
3971 else if (pos
== (UINT
)-1) MessageBeep(0);
3974 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, pos
, TRUE
, 0);
3975 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3976 fEndMenu
= (executedMenuId
!= -2);
3980 } /* switch(msg.message) - kbd */
3984 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3985 DispatchMessageW( &msg
);
3989 if (!fEndMenu
) fRemove
= TRUE
;
3991 /* finally remove message from the queue */
3993 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
3994 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3995 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3998 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3999 SetCapture(NULL
); /* release the capture */
4001 /* If dropdown is still painted and the close box is clicked on
4002 then the menu will be destroyed as part of the DispatchMessage above.
4003 This will then invalidate the menu handle in mt.hTopMenu. We should
4004 check for this first. */
4005 if( IsMenu( mt
.TopMenu
) )
4007 if (IsWindow(mt
.OwnerWnd
))
4009 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
4011 MenuHideSubPopups(mt
.OwnerWnd
, &MenuInfo
, FALSE
, wFlags
);
4013 if (MenuInfo
.fFlags
& MNF_POPUP
)
4015 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4016 DestroyWindow(MenuInfo
.Wnd
);
4017 MenuInfo
.Wnd
= NULL
;
4018 MenuSetRosMenuInfo(&MenuInfo
);
4020 if (!(wFlags
& TPM_NONOTIFY
))
4021 SendMessageW( mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.TopMenu
,
4022 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
4024 MenuSelectItem( mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
4027 SendMessageW( mt
.OwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4030 /* Reset the variable for hiding menu */
4031 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
4033 MenuInfo
.TimeToHide
= FALSE
;
4034 MenuSetRosMenuInfo(&MenuInfo
);
4038 /* The return value is only used by TrackPopupMenu */
4039 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4040 if (executedMenuId
== -1) executedMenuId
= 0;
4041 return executedMenuId
;
4044 /***********************************************************************
4047 static BOOL FASTCALL
MenuInitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
4049 ROSMENUINFO MenuInfo
= {0};
4051 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
4055 /* This makes the menus of applications built with Delphi work.
4056 * It also enables menus to be displayed in more than one window,
4057 * but there are some bugs left that need to be fixed in this case.
4059 if (!bPopup
&& (MenuGetRosMenuInfo(&MenuInfo
, hMenu
)))
4061 MenuInfo
.Wnd
= hWnd
;
4062 MenuSetRosMenuInfo(&MenuInfo
);
4064 //if (!bPopup) menu->hWnd = hWnd;
4067 top_popup
= MenuInfo
.Wnd
;//menu->hWnd;
4068 top_popup_hmenu
= hMenu
;
4073 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4074 if (!(wFlags
& TPM_NONOTIFY
))
4075 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
4077 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
4079 if (!(wFlags
& TPM_NONOTIFY
))
4081 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
4082 /* If an app changed/recreated menu bar entries in WM_INITMENU
4083 * menu sizes will be recalculated once the menu created/shown.
4086 if (!MenuInfo
.cyMenu
)
4088 /* app changed/recreated menu bar entries in WM_INITMENU
4089 Recalculate menu sizes else clicks will not work */
4090 SetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4091 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4096 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4098 MenuInfo
.fFlags
& MNF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
4103 /***********************************************************************
4106 static BOOL FASTCALL
MenuExitTracking(HWND hWnd
, BOOL bPopup
)
4108 TRACE("hwnd=%p\n", hWnd
);
4110 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, hWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4111 SendMessageW( hWnd
, WM_EXITMENULOOP
, bPopup
, 0 );
4114 top_popup_hmenu
= NULL
;
4118 /***********************************************************************
4119 * MenuTrackMouseMenuBar
4121 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4123 VOID
MenuTrackMouseMenuBar( HWND hWnd
, ULONG ht
, POINT pt
)
4125 HMENU hMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( hWnd
) : GetMenu(hWnd
);
4126 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4128 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
4130 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4133 /* map point to parent client coordinates */
4134 HWND Parent
= GetAncestor(hWnd
, GA_PARENT
);
4135 if (Parent
!= GetDesktopWindow())
4137 ScreenToClient(Parent
, &pt
);
4140 MenuInitTracking(hWnd
, hMenu
, FALSE
, wFlags
);
4141 /* fetch the window menu again, it may have changed */
4142 hMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( hWnd
) : GetMenu( hWnd
);
4143 MenuTrackMenu(hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
4144 MenuExitTracking(hWnd
, FALSE
);
4148 /***********************************************************************
4149 * MenuTrackKbdMenuBar
4151 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4153 VOID
MenuTrackKbdMenuBar(HWND hwnd
, UINT wParam
, WCHAR wChar
)
4155 UINT uItem
= NO_SELECTED_ITEM
;
4157 ROSMENUINFO MenuInfo
;
4158 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4160 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
4162 /* find window that has a menu */
4164 while (!((GetWindowLongPtrW( hwnd
, GWL_STYLE
) &
4165 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
4166 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
4168 /* check if we have to track a system menu */
4170 hTrackMenu
= GetMenu( hwnd
);
4171 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
4173 if (!(GetWindowLongPtrW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
4174 hTrackMenu
= get_win_sys_menu(hwnd
);
4176 wParam
|= HTSYSMENU
; /* prevent item lookup */
4179 if (!IsMenu( hTrackMenu
)) return;
4181 MenuInitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
4183 /* fetch the window menu again, it may have changed */
4184 hTrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( hwnd
) : GetMenu( hwnd
);
4186 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
4191 if( wChar
&& wChar
!= ' ' )
4193 uItem
= MENU_FindItemByKey( hwnd
, hTrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4194 if ( uItem
>= (UINT
)(-2) )
4196 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
4197 /* schedule end of menu tracking */
4198 wFlags
|= TF_ENDMENU
;
4203 MenuSelectItem( hwnd
, &MenuInfo
, uItem
, TRUE
, 0 );
4205 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4207 if( uItem
== NO_SELECTED_ITEM
)
4208 MenuMoveSelection( hwnd
, &MenuInfo
, ITEM_NEXT
);
4210 PostMessageW( hwnd
, WM_KEYDOWN
, VK_RETURN
, 0 );
4214 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
4215 MenuExitTracking( hwnd
, FALSE
);
4218 /**********************************************************************
4219 * TrackPopupMenuEx (USER32.@)
4221 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, int x
, int y
,
4222 HWND hWnd
, LPTPMPARAMS lpTpm
)
4227 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p rect %s\n",
4228 hMenu
, wFlags
, x
, y
, hWnd
, lpTpm
,
4229 lpTpm
? wine_dbgstr_rect( &lpTpm
->rcExclude
) : "-" );
4231 /* Parameter check */
4232 /* FIXME: this check is performed several times, here and in the called
4233 functions. That could be optimized */
4234 if (!(menu
= MENU_GetMenu( hMenu
)))
4236 SetLastError( ERROR_INVALID_MENU_HANDLE
);
4240 if (IsWindow(menu
->hWnd
))
4242 SetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4246 if (MENU_InitPopup( hWnd
, hMenu
, wFlags
))
4248 MenuInitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
4250 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4251 if (!(wFlags
& TPM_NONOTIFY
))
4252 SendMessageW(hWnd
, WM_INITMENUPOPUP
, (WPARAM
) hMenu
, 0);
4254 if (MenuShowPopup(hWnd
, hMenu
, 0, wFlags
, x
, y
, 0, 0 ))
4255 ret
= MenuTrackMenu(hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
,
4256 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4257 MenuExitTracking(hWnd
, TRUE
);
4261 ROSMENUINFO MenuInfo
;
4262 if (IsWindow( menu
->hWnd
)) // wine hack around this with their destroy function.
4263 DestroyWindow( menu
->hWnd
); // Fix wrong error return.
4265 MenuGetRosMenuInfo(&MenuInfo
, menu
->head
.h
);
4267 MenuSetRosMenuInfo(&MenuInfo
);
4269 if (!(wFlags
& TPM_NONOTIFY
))
4270 SendMessageW( hWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)hMenu
,
4271 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4277 /**********************************************************************
4278 * TrackPopupMenu (USER32.@)
4280 BOOL WINAPI
TrackPopupMenu( HMENU Menu
, UINT Flags
, int x
, int y
,
4281 int Reserved
, HWND Wnd
, CONST RECT
*Rect
)
4283 return TrackPopupMenuEx( Menu
, Flags
, x
, y
, Wnd
, NULL
);
4286 /**********************************************************************
4289 * Uses flags, id and text ptr, passed by InsertMenu() and
4290 * ModifyMenu() to setup a MenuItemInfo structure.
4292 static void MENU_mnu2mnuii( UINT flags
, UINT_PTR id
, LPCWSTR str
, LPMENUITEMINFOW pmii
, BOOL Unicode
)
4294 RtlZeroMemory( pmii
, sizeof( MENUITEMINFOW
));
4295 pmii
->cbSize
= sizeof( MENUITEMINFOW
);
4296 pmii
->fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
4297 /* setting bitmap clears text and vice versa */
4298 if( IS_STRING_ITEM(flags
)) {
4299 pmii
->fMask
|= MIIM_STRING
| MIIM_BITMAP
;
4301 flags
|= MF_SEPARATOR
;
4302 /* Item beginning with a backspace is a help item */
4303 /* FIXME: wrong place, this is only true in win16 */
4316 LPCSTR NewItemA
= (LPCSTR
) str
;
4317 if (*NewItemA
== '\b')
4321 str
= (LPCWSTR
) NewItemA
;
4323 TRACE("A cch %d\n",strlen(NewItemA
));
4326 pmii
->dwTypeData
= (LPWSTR
)str
;
4327 } else if( flags
& MFT_BITMAP
){
4328 pmii
->fMask
|= MIIM_BITMAP
| MIIM_STRING
;
4329 pmii
->hbmpItem
= (HBITMAP
)str
;
4331 if( flags
& MF_OWNERDRAW
){
4332 pmii
->fMask
|= MIIM_DATA
;
4333 pmii
->dwItemData
= (ULONG_PTR
) str
;
4335 if( flags
& MF_POPUP
&& MENU_GetMenu((HMENU
)id
)) {
4336 pmii
->fMask
|= MIIM_SUBMENU
;
4337 pmii
->hSubMenu
= (HMENU
)id
;
4339 if( flags
& MF_SEPARATOR
) flags
|= MF_GRAYED
| MF_DISABLED
;
4340 pmii
->fState
= flags
& MENUITEMINFO_STATE_MASK
& ~MFS_DEFAULT
;
4341 pmii
->fType
= flags
& MENUITEMINFO_TYPE_MASK
;
4342 pmii
->wID
= (UINT
)id
;
4345 /**********************************************************************
4346 * MENU_NormalizeMenuItemInfoStruct
4348 * Helper for SetMenuItemInfo and InsertMenuItemInfo:
4349 * check, copy and extend the MENUITEMINFO struct from the version that the application
4350 * supplied to the version used by wine source. */
4351 static BOOL
MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW
*pmii_in
,
4352 MENUITEMINFOW
*pmii_out
)
4354 /* do we recognize the size? */
4355 if( !pmii_in
|| (pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) &&
4356 pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) - sizeof( pmii_in
->hbmpItem
)) ) {
4357 SetLastError( ERROR_INVALID_PARAMETER
);
4360 /* copy the fields that we have */
4361 memcpy( pmii_out
, pmii_in
, pmii_in
->cbSize
);
4362 /* if the hbmpItem member is missing then extend */
4363 if( pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
)) {
4364 pmii_out
->cbSize
= sizeof( MENUITEMINFOW
);
4365 pmii_out
->hbmpItem
= NULL
;
4367 /* test for invalid bit combinations */
4368 if( (pmii_out
->fMask
& MIIM_TYPE
&&
4369 pmii_out
->fMask
& (MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
)) ||
4370 (pmii_out
->fMask
& MIIM_FTYPE
&& pmii_out
->fType
& MFT_BITMAP
)) {
4371 ERR("invalid combination of fMask bits used\n");
4372 /* this does not happen on Win9x/ME */
4373 SetLastError( ERROR_INVALID_PARAMETER
);
4376 /* convert old style (MIIM_TYPE) to the new and keep the old one too */
4377 if( pmii_out
->fMask
& MIIM_TYPE
){
4378 pmii_out
->fMask
|= MIIM_FTYPE
;
4379 if( IS_STRING_ITEM(pmii_out
->fType
)){
4380 pmii_out
->fMask
|= MIIM_STRING
;
4381 } else if( (pmii_out
->fType
) & MFT_BITMAP
){
4382 pmii_out
->fMask
|= MIIM_BITMAP
;
4383 pmii_out
->hbmpItem
= UlongToHandle(LOWORD(pmii_out
->dwTypeData
));
4386 if (pmii_out
->fMask
& MIIM_FTYPE
)
4388 pmii_out
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
4389 pmii_out
->fType
|= pmii_in
->fType
& MENUITEMINFO_TYPE_MASK
;
4391 if (pmii_out
->fMask
& MIIM_STATE
)
4392 /* Other menu items having MFS_DEFAULT are not converted
4394 pmii_out
->fState
= pmii_in
->fState
& MENUITEMINFO_STATE_MASK
;
4402 NONCLIENTMETRICSW ncm
;
4404 /* get the menu font */
4405 if(!hMenuFont
|| !hMenuFontBold
)
4407 ncm
.cbSize
= sizeof(ncm
);
4408 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
4410 ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
4414 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
4415 if(hMenuFont
== NULL
)
4417 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
4421 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
4422 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
4423 if(hMenuFontBold
== NULL
)
4425 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
4426 DeleteObject(hMenuFont
);
4440 DeleteObject(hMenuFont
);
4446 DeleteObject(hMenuFontBold
);
4447 hMenuFontBold
= NULL
;
4451 HMENU FASTCALL
MENU_LoadSystemMenu(BOOL mdi
)
4453 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
4457 MENUINFO menuinfo
= {0};
4458 MENUITEMINFOW info
= {0};
4461 // removing space for checkboxes from menu
4462 menuinfo
.cbSize
= sizeof(menuinfo
);
4463 menuinfo
.fMask
= MIM_STYLE
;
4464 GetMenuInfo(hmenu
, &menuinfo
);
4465 menuinfo
.dwStyle
|= MNS_CHECKORBMP
;
4466 SetMenuInfo(hmenu
, &menuinfo
);
4468 // adding bitmaps to menu items
4469 info
.cbSize
= sizeof(info
);
4470 info
.fMask
|= MIIM_BITMAP
;
4471 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
4472 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
4473 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
4474 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
4475 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
4476 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
4477 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
4478 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
4481 AppendMenuW(hmenu
, MF_SEPARATOR
, 0, NULL
);
4482 //LoadStringW(User32Instance, IDS_MDI_NEXT, buf, sizeof(buf)/sizeof(WCHAR));
4483 //AppendMenuW(hmenu, MF_STRING, SC_NEXTWINDOW, buf);
4490 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
4494 // Will be converted to load bitmaps for OBMI!
4496 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
4500 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
4502 PLOADMENU_CALLBACK_ARGUMENTS Common
;
4505 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
4507 Result
= (LRESULT
)LoadMenuW( Common
->hModule
, Common
->InterSource
? MAKEINTRESOURCE(Common
->InterSource
) : (LPCWSTR
)&Common
->MenuName
);
4509 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
4513 /* FUNCTIONS *****************************************************************/
4519 AppendMenuA(HMENU hMenu
,
4521 UINT_PTR uIDNewItem
,
4525 UNICODE_STRING UnicodeString
;
4528 RtlInitUnicodeString(&UnicodeString
, 0);
4530 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
4532 /* copy the text string, it will be one or the other */
4533 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
4535 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
4537 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
4540 mii
.dwTypeData
= UnicodeString
.Buffer
;
4541 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
4545 TRACE("AMA Handle bitmaps\n");
4547 ////// Answer a question, why a -1? To hunt for the end of the item list. Get it, to Append?
4548 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &UnicodeString
);
4549 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
4557 AppendMenuW(HMENU hMenu
,
4559 UINT_PTR uIDNewItem
,
4563 UNICODE_STRING MenuText
;
4566 RtlInitUnicodeString(&MenuText
, 0);
4568 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
4570 /* copy the text string, it will be one or the other */
4571 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
4573 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
4574 mii
.dwTypeData
= MenuText
.Buffer
;
4575 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4577 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &MenuText
);
4585 CheckMenuItem(HMENU hmenu
,
4593 if (!(pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4596 if (!(item
= MENU_FindItem( &hmenu
, &uIDCheckItem
, uCheck
))) return -1;
4598 Ret
= item
->fState
& MFS_CHECKED
;
4599 if ( Ret
== (uCheck
& MFS_CHECKED
)) return Ret
; // Already Checked...
4601 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
4608 CheckMenuRadioItem(HMENU hMenu
,
4616 PITEM mi_first
= NULL
, mi_check
;
4617 HMENU m_first
, m_check
;
4619 mii
.cbSize
= sizeof( mii
);
4621 for (i
= first
; i
<= last
; i
++)
4628 mi_first
= MENU_FindItem(&m_first
, &pos
, bypos
);
4629 if (!mi_first
) continue;
4630 mi_check
= mi_first
;
4636 mi_check
= MENU_FindItem(&m_check
, &pos
, bypos
);
4637 if (!mi_check
) continue;
4640 if (m_first
!= m_check
) continue;
4641 if (mi_check
->fType
== MFT_SEPARATOR
) continue;
4645 if (!(mi_check
->fType
& MFT_RADIOCHECK
) || !(mi_check
->fState
& MFS_CHECKED
))
4647 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
;
4648 mii
.fType
= (mi_check
->fType
& MENUITEMINFO_TYPE_MASK
) | MFT_RADIOCHECK
;
4649 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) | MFS_CHECKED
;
4650 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
4656 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
4657 if (mi_check
->fState
& MFS_CHECKED
)
4659 mii
.fMask
= MIIM_STATE
;
4660 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) & ~MFS_CHECKED
;
4661 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
4675 return NtUserxCreateMenu();
4682 CreatePopupMenu(VOID
)
4685 return NtUserxCreatePopupMenu();
4692 DrawMenuBar(HWND hWnd
)
4694 return NtUserxDrawMenuBar(hWnd
);
4701 EnableMenuItem(HMENU hMenu
,
4705 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4715 guii
.cbSize
= sizeof(GUITHREADINFO
);
4716 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4720 guii
.hwndMenuOwner
!= top_popup
)
4722 ERR("Capture GUI pti hWnd does not match top_popup!\n");
4726 /* if we are in the menu code, and it is active */
4727 if (!fEndMenu
&& top_popup
)
4729 /* terminate the menu handling code */
4732 /* needs to be posted to wakeup the internal menu handler */
4733 /* which will now terminate the menu, in the event that */
4734 /* the main window was minimized, or lost focus, so we */
4735 /* don't end up with an orphaned menu */
4736 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
4741 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
4744 ROSMENUINFO MenuInfo
;
4745 TRACE("(%p, %p, %04x, %04x);\n", hWnd
, hMenu
, wItemID
, wHilite
);
4746 // Force bits to be set call server side....
4747 // This alone works and passes all the menu test_menu_hilitemenuitem tests.
4748 if (!NtUserHiliteMenuItem(hWnd
, hMenu
, wItemID
, wHilite
)) return FALSE
;
4749 // Without the above call we fail 3 out of the wine failed todo tests, see CORE-7967
4751 if (MenuGetRosMenuInfo(&MenuInfo
, hMenu
))
4753 if (MenuInfo
.iItem
== wItemID
) return TRUE
;
4754 MenuHideSubPopups( hWnd
, &MenuInfo
, FALSE
, 0 );
4755 MenuSelectItem( hWnd
, &MenuInfo
, wItemID
, TRUE
, 0 );
4757 return TRUE
; // Always returns TRUE!
4766 PWND Wnd
= ValidateHwnd(hWnd
);
4771 return UlongToHandle(Wnd
->IDMenu
);
4777 BOOL WINAPI
GetMenuBarInfo( HWND hwnd
, LONG idObject
, LONG idItem
, PMENUBARINFO pmbi
)
4780 Ret
= NtUserGetMenuBarInfo( hwnd
, idObject
, idItem
, pmbi
);
4781 // Reason to move to server side!!!!!
4782 if (!Ret
) return Ret
;
4784 pmbi
->fBarFocused
= top_popup_hmenu
== pmbi
->hMenu
;
4787 pmbi
->fFocused
= pmbi
->fBarFocused
;
4797 GetMenuCheckMarkDimensions(VOID
)
4799 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4800 GetSystemMetrics(SM_CYMENUCHECK
)));
4808 GetMenuContextHelpId(HMENU hmenu
)
4811 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4812 return pMenu
->dwContextHelpId
;
4820 GetMenuDefaultItem(HMENU hMenu
,
4826 if (!(pMenu
= ValidateHandle(hMenu
, TYPE_MENU
)))
4829 return IntGetMenuDefaultItem( pMenu
, (BOOL
)fByPos
, gmdiFlags
, &gismc
);
4836 GetMenuInfo(HMENU hmenu
,
4841 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4843 SetLastError(ERROR_INVALID_PARAMETER
);
4847 if (!(pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4850 if (lpcmi
->fMask
& MIM_BACKGROUND
)
4851 lpcmi
->hbrBack
= pMenu
->hbrBack
;
4853 if (lpcmi
->fMask
& MIM_HELPID
)
4854 lpcmi
->dwContextHelpID
= pMenu
->dwContextHelpId
;
4856 if (lpcmi
->fMask
& MIM_MAXHEIGHT
)
4857 lpcmi
->cyMax
= pMenu
->cyMax
;
4859 if (lpcmi
->fMask
& MIM_MENUDATA
)
4860 lpcmi
->dwMenuData
= pMenu
->dwMenuData
;
4862 if (lpcmi
->fMask
& MIM_STYLE
)
4863 lpcmi
->dwStyle
= pMenu
->fFlags
& MNS_STYLE_MASK
;
4872 GetMenuItemCount(HMENU hmenu
)
4875 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4876 return pMenu
->cItems
;
4884 GetMenuItemID(HMENU hMenu
,
4888 if (!(lpmi
= MENU_FindItem(&hMenu
,(UINT
*)&nPos
,MF_BYPOSITION
))) return -1;
4889 if (lpmi
->spSubMenu
) return -1;
4901 LPMENUITEMINFOA lpmii
)
4906 if( lpmii
->cbSize
!= sizeof( mii
) &&
4907 lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
4909 SetLastError( ERROR_INVALID_PARAMETER
);
4912 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
4913 mii
.cbSize
= sizeof( mii
);
4914 ret
= GetMenuItemInfo_common (hmenu
,
4917 (LPMENUITEMINFOW
)&mii
,
4919 mii
.cbSize
= lpmii
->cbSize
;
4920 memcpy( lpmii
, &mii
, mii
.cbSize
);
4932 LPMENUITEMINFOW lpmii
)
4936 if( lpmii
->cbSize
!= sizeof( mii
) && lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
4938 SetLastError( ERROR_INVALID_PARAMETER
);
4941 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
4942 mii
.cbSize
= sizeof( mii
);
4943 ret
= GetMenuItemInfo_common (hMenu
, Item
, bypos
, &mii
, TRUE
);
4944 mii
.cbSize
= lpmii
->cbSize
;
4945 memcpy( lpmii
, &mii
, mii
.cbSize
);
4961 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu
, uId
, uFlags
);
4962 if (!(pItem
= MENU_FindItem( &hMenu
, &uId
, uFlags
))) return -1;
4964 if (!pItem
->Xlpstr
&& pItem
->hbmp
) Type
= MFT_BITMAP
;
4966 if (pItem
->spSubMenu
)
4968 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
4969 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
4970 if (!IsMenu(hsubmenu
)) return (UINT
)-1;
4971 else return (pSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|Type
) & 0xff);
4974 return (pItem
->fType
| pItem
->fState
| Type
);
4991 ////// wine Code, seems to be faster.
4992 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
4994 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
4996 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
4998 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
5002 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
5004 if (!text
) return 0;
5005 if (!lpString
|| !nMaxCount
) return WideCharToMultiByte( CP_ACP
, 0, text
, -1, NULL
, 0, NULL
, NULL
);
5006 if (!WideCharToMultiByte( CP_ACP
, 0, text
, -1, lpString
, nMaxCount
, NULL
, NULL
))
5007 lpString
[nMaxCount
-1] = 0;
5008 TRACE("A returning %s\n", lpString
);
5009 return strlen(lpString
);
5027 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
5029 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
5031 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
5033 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
5037 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
5039 if (!lpString
|| !nMaxCount
) return text
? strlenW(text
) : 0;
5045 lstrcpynW( lpString
, text
, nMaxCount
);
5046 TRACE("W returning %S\n", lpString
);
5047 return strlenW(lpString
);
5060 if (!(pItem
= MENU_FindItem( &hMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
5062 if (pItem
->spSubMenu
)
5064 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
5065 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
5066 if (IsMenu(hsubmenu
)) return hsubmenu
;
5080 return NtUserGetSystemMenu(hWnd
, bRevert
);
5092 UINT_PTR uIDNewItem
,
5096 UNICODE_STRING UnicodeString
;
5099 RtlInitUnicodeString(&UnicodeString
, 0);
5101 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
5103 /* copy the text string, it will be one or the other */
5104 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5106 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5108 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5111 mii
.dwTypeData
= UnicodeString
.Buffer
;
5112 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5116 TRACE("Handle bitmaps\n");
5118 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &UnicodeString
);
5119 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
5132 LPCMENUITEMINFOA lpmii
)
5135 UNICODE_STRING UnicodeString
;
5138 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5140 RtlInitUnicodeString(&UnicodeString
, 0);
5142 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5144 /* copy the text string */
5145 if (((mii
.fMask
& MIIM_STRING
) ||
5146 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5147 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5149 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5151 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5154 mii
.dwTypeData
= UnicodeString
.Buffer
;
5155 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5159 TRACE("Handle bitmaps\n");
5161 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &UnicodeString
);
5162 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
5175 LPCMENUITEMINFOW lpmii
)
5178 UNICODE_STRING MenuText
;
5181 /* while we could just pass 'lpmii' to win32k, we make a copy so that
5182 if a bad user passes bad data, we crash his process instead of the
5185 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5187 RtlInitUnicodeString(&MenuText
, 0);
5189 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5191 /* copy the text string */
5192 if (((mii
.fMask
& MIIM_STRING
) ||
5193 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5194 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5196 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
5197 mii
.dwTypeData
= MenuText
.Buffer
;
5198 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
5200 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &MenuText
);
5213 UINT_PTR uIDNewItem
,
5217 UNICODE_STRING MenuText
;
5220 RtlInitUnicodeString(&MenuText
, 0);
5222 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
5224 /* copy the text string, it will be one or the other */
5225 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5227 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
5228 mii
.dwTypeData
= MenuText
.Buffer
;
5229 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
5231 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &MenuText
);
5243 if (ValidateHandle(Menu
, TYPE_MENU
)) return TRUE
;
5251 LoadMenuA(HINSTANCE hInstance
,
5254 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
5255 if (Resource
== NULL
)
5259 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
5266 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
5268 return(LoadMenuIndirectW(lpMenuTemplate
));
5275 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
5278 WORD version
, offset
;
5279 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
5281 version
= GET_WORD(p
);
5286 case 0: /* standard format is version of 0 */
5287 offset
= GET_WORD(p
);
5288 p
+= sizeof(WORD
) + offset
;
5289 if (!(hMenu
= CreateMenu())) return 0;
5290 if (!MENU_ParseResource(p
, hMenu
))
5296 case 1: /* extended format is version of 1 */
5297 offset
= GET_WORD(p
);
5298 p
+= sizeof(WORD
) + offset
;
5299 if (!(hMenu
= CreateMenu())) return 0;
5300 if (!MENUEX_ParseResource(p
, hMenu
))
5302 DestroyMenu( hMenu
);
5307 ERR("Menu template version %d not supported.\n", version
);
5316 LoadMenuW(HINSTANCE hInstance
,
5319 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
5320 if (Resource
== NULL
)
5324 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
5337 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
5349 UINT_PTR uIDNewItem
,
5353 UNICODE_STRING UnicodeString
;
5356 RtlInitUnicodeString(&UnicodeString
, 0);
5358 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
5360 /* copy the text string, it will be one or the other */
5361 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5363 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5365 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5368 mii
.dwTypeData
= UnicodeString
.Buffer
;
5369 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5373 TRACE("Handle bitmaps\n");
5375 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &UnicodeString
);
5376 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
5389 UINT_PTR uIDNewItem
,
5393 UNICODE_STRING MenuText
;
5396 RtlInitUnicodeString(&MenuText
, 0);
5398 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
5400 /* copy the text string, it will be one or the other */
5401 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5403 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
5404 mii
.dwTypeData
= MenuText
.Buffer
;
5405 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
5409 TRACE("Handle bitmaps\n");
5411 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &MenuText
);
5422 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
5437 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
5439 SetLastError(ERROR_INVALID_PARAMETER
);
5443 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
5444 return NtUserThunkedMenuInfo(hmenu
, (LPCMENUINFO
)&mi
);
5456 HBITMAP hBitmapUnchecked
,
5457 HBITMAP hBitmapChecked
)
5459 MENUITEMINFOW uItem
;
5460 memset ( &uItem
, 0, sizeof(uItem
) );
5461 uItem
.cbSize
= sizeof(MENUITEMINFOW
);
5462 uItem
.fMask
= MIIM_CHECKMARKS
;
5463 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
5464 uItem
.hbmpChecked
= hBitmapChecked
;
5465 return SetMenuItemInfoW(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), &uItem
);
5477 LPCMENUITEMINFOA lpmii
)
5480 UNICODE_STRING UnicodeString
;
5483 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu
, item
, bypos
, lpmii
);
5485 RtlInitUnicodeString(&UnicodeString
, 0);
5487 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5489 * MIIM_STRING == good
5490 * MIIM_TYPE & MFT_STRING == good
5491 * MIIM_STRING & MFT_STRING == good
5492 * MIIM_STRING & MFT_OWNERDRAW == good
5494 if (((mii
.fMask
& MIIM_STRING
) ||
5495 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5496 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5498 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5499 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5501 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5504 mii
.dwTypeData
= UnicodeString
.Buffer
;
5505 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5509 UnicodeString
.Buffer
= NULL
;
5511 Ret
= NtUserThunkedMenuItemInfo(hmenu
, item
, bypos
, FALSE
, &mii
, &UnicodeString
);
5512 if (UnicodeString
.Buffer
!= NULL
) RtlFreeUnicodeString(&UnicodeString
);
5525 LPCMENUITEMINFOW lpmii
)
5527 MENUITEMINFOW MenuItemInfoW
;
5528 UNICODE_STRING UnicodeString
;
5531 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5533 RtlInitUnicodeString(&UnicodeString
, 0);
5535 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &MenuItemInfoW
)) return FALSE
;
5537 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5538 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5539 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5540 && MenuItemInfoW
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)MenuItemInfoW
.dwTypeData
)) )
5542 RtlInitUnicodeString(&UnicodeString
, (PCWSTR
)MenuItemInfoW
.dwTypeData
);
5543 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5545 Ret
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, FALSE
, &MenuItemInfoW
, &UnicodeString
);
5561 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5566 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5569 return NtUserSetSystemMenu(hwnd
, hMenu
);
5573 // Example for the Win32/User32 rewrite.
5574 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5588 return NtUserTrackPopupMenuEx( Menu
,
5593 NULL
); // LPTPMPARAMS is null
5612 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5615 Result
= (ULONG_PTR
)lResult
;
5620 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5639 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5642 Result
= (ULONG_PTR
)lResult
;
5647 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5658 LPCWSTR lpszNewItem
,
5663 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5664 for MF_DELETE. We should check the parameters for all others
5665 MF_* actions also (anybody got a doc on ChangeMenu?).
5668 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5671 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5674 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5677 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5680 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5681 flags
&~ MF_REMOVE
);
5683 default : /* MF_INSERT */
5684 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5701 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5702 for MF_DELETE. We should check the parameters for all others
5703 MF_* actions also (anybody got a doc on ChangeMenu?).
5706 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5709 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5712 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5715 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5718 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5719 flags
&~ MF_REMOVE
);
5721 default : /* MF_INSERT */
5722 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);