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 2 //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 NULL
, /* FIXME - procA */
111 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
)) )
299 *((WCHAR
*)lpmii
->dwTypeData
) = 0;
301 *((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
->iTop
;
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 (BmpSysMenu
== NULL
)
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
= 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
)
2041 DWORD ex_style
= WS_EX_TOOLWINDOW
;
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
);
2194 //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2196 else if (item
->Rect
.top
- MENU_TOP_MARGIN
< lppop
->iTop
)
2198 lppop
->iTop
= item
->Rect
.top
- MENU_TOP_MARGIN
;
2199 ScrollWindow(lppop
->Wnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2200 MENU_DrawScrollArrows(lppop
, hdc
);
2201 //ERR("Scroll Up iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
2203 MenuSetRosMenuInfo(lppop
);
2207 /***********************************************************************
2210 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
2211 BOOL sendMenuSelect
, HMENU topmenu
)
2213 ROSMENUITEMINFO ItemInfo
;
2214 ROSMENUINFO TopMenuInfo
;
2217 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
2219 if (!hmenu
|| !hmenu
->cItems
|| !hmenu
->Wnd
) return;
2220 if (hmenu
->iItem
== wIndex
) return;
2221 if (hmenu
->fFlags
& MNF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
2222 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2224 top_popup
= hmenu
->Wnd
;
2225 top_popup_hmenu
= hmenu
->Self
;
2228 SelectObject( hdc
, hMenuFont
);
2230 MenuInitRosMenuItemInfo(&ItemInfo
);
2232 /* Clear previous highlighted item */
2233 if (hmenu
->iItem
!= NO_SELECTED_ITEM
)
2235 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
))
2237 ItemInfo
.fMask
|= MIIM_STATE
;
2238 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2239 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
);
2241 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
2242 hmenu
->cyMenu
, !(hmenu
->fFlags
& MNF_POPUP
),
2246 /* Highlight new item (if any) */
2247 hmenu
->iItem
= wIndex
;
2248 MenuSetRosMenuInfo(hmenu
);
2249 if (hmenu
->iItem
!= NO_SELECTED_ITEM
)
2251 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
))
2253 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
2255 ItemInfo
.fMask
|= MIIM_STATE
;
2256 ItemInfo
.fState
|= MF_HILITE
;
2257 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
);
2258 MENU_EnsureMenuItemVisible(hmenu
, &ItemInfo
, hdc
);
2259 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
2260 &ItemInfo
, hmenu
->cyMenu
, !(hmenu
->fFlags
& MNF_POPUP
), ODA_SELECT
);
2264 WPARAM wParam
= MAKEWPARAM( ItemInfo
.hSubMenu
? wIndex
: ItemInfo
.wID
,
2265 ItemInfo
.fType
| ItemInfo
.fState
|
2266 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
2267 (hmenu
->fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
2269 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) hmenu
->Self
);
2273 else if (sendMenuSelect
)
2278 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
2279 if (pos
!= NO_SELECTED_ITEM
)
2281 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
2282 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
2284 WPARAM wParam
= MAKEWPARAM( Pos
, ItemInfo
.fType
| ItemInfo
.fState
|
2285 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
2286 (TopMenuInfo
.fFlags
& MNF_SYSMENU
? MF_SYSMENU
: 0 ) );
2288 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) topmenu
);
2293 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2294 ReleaseDC(hmenu
->Wnd
, hdc
);
2297 /***********************************************************************
2300 * Moves currently selected item according to the Offset parameter.
2301 * If there is no selection then it should select the last item if
2302 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2304 static void FASTCALL
2305 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
2308 ROSMENUITEMINFO ItemInfo
;
2311 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
2313 /* Prevent looping */
2314 if (0 == MenuInfo
->cItems
|| 0 == Offset
)
2316 else if (Offset
< -1)
2318 else if (Offset
> 1)
2321 MenuInitRosMenuItemInfo(&ItemInfo
);
2323 OrigPos
= MenuInfo
->iItem
;
2324 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
2331 i
= MenuInfo
->iItem
;
2338 /* Clip and wrap around */
2341 i
= MenuInfo
->cItems
- 1;
2343 else if (i
>= MenuInfo
->cItems
)
2347 /* If this is a good candidate; */
2348 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
2349 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2351 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
2352 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2355 } while (i
!= OrigPos
);
2358 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2363 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2365 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2367 PPOPUPMENU pPopupMenu
;
2369 pWnd
= ValidateHwndNoErr(Wnd
);
2374 if (Message
!= WM_NCCREATE
)
2376 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2378 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
2379 pPopupMenu
= HeapAlloc( GetProcessHeap(), 0, sizeof(POPUPMENU
) );
2380 pPopupMenu
->spwndPopupMenu
= pWnd
;
2381 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)pPopupMenu
);
2385 if (pWnd
->fnid
!= FNID_MENU
)
2387 ERR("Wrong window class for Menu!\n");
2390 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
2395 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2401 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
2402 pPopupMenu
->spmenu
= ValidateHandle(cs
->lpCreateParams
, TYPE_MENU
);
2406 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2407 return MA_NOACTIVATE
;
2412 BeginPaint(Wnd
, &ps
);
2413 MenuDrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
->head
.h
);
2418 case WM_PRINTCLIENT
:
2420 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
->head
.h
);
2428 /* zero out global pointer in case resident popup window was destroyed. */
2429 if (Wnd
== top_popup
)
2432 top_popup_hmenu
= NULL
;
2438 HeapFree( GetProcessHeap(), 0, pPopupMenu
);
2439 SetWindowLongPtrW(Wnd
, 0, 0);
2440 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
2447 if (!pPopupMenu
|| !pPopupMenu
->spmenu
)
2449 OutputDebugStringA("no menu to display\n");
2454 pPopupMenu->spmenu = NULL; ///// WTF?
2458 case MM_SETMENUHANDLE
:
2460 PMENU pmenu
= ValidateHandle((HMENU
)wParam
, TYPE_MENU
);
2463 ERR("Bad Menu Handle\n");
2466 pPopupMenu
->spmenu
= pmenu
;
2470 case MM_GETMENUHANDLE
:
2472 return (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? pPopupMenu
->spmenu
->head
.h
: NULL
) : NULL
);
2475 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2483 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2485 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2488 pWnd
= ValidateHwnd(Wnd
);
2493 if (Message
!= WM_NCCREATE
)
2495 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2497 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
2501 if (pWnd
->fnid
!= FNID_MENU
)
2503 ERR("Wrong window class for Menu!\n");
2510 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2516 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
2517 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
2521 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2522 return MA_NOACTIVATE
;
2527 BeginPaint(Wnd
, &ps
);
2528 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
2533 case WM_PRINTCLIENT
:
2535 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
2536 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
2544 /* zero out global pointer in case resident popup window was destroyed. */
2545 if (Wnd
== top_popup
)
2548 top_popup_hmenu
= NULL
;
2554 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
2561 if (0 == GetWindowLongPtrW(Wnd
, 0))
2563 OutputDebugStringA("no menu to display\n");
2568 SetWindowLongPtrW(Wnd
, 0, 0);
2572 case MM_SETMENUHANDLE
:
2573 SetWindowLongPtrW(Wnd
, 0, wParam
);
2576 case MM_GETMENUHANDLE
:
2578 return GetWindowLongPtrW(Wnd
, 0);
2581 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2588 // This breaks some test results. Should handle A2U if called!
2590 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2594 pWnd
= ValidateHwnd(Wnd
);
2595 if (pWnd
&& !pWnd
->fnid
&& Message
!= WM_NCCREATE
)
2597 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
2599 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2605 case WM_MOUSEACTIVATE
:
2607 case WM_PRINTCLIENT
:
2612 case MM_SETMENUHANDLE
:
2613 case MM_GETMENUHANDLE
:
2615 return PopupMenuWndProcW(Wnd
, Message
, wParam
, lParam
);
2618 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
2623 /**********************************************************************
2624 * MENU_ParseResource
2626 * Parse a standard menu resource and add items to the menu.
2627 * Return a pointer to the end of the resource.
2629 * NOTE: flags is equivalent to the mtOption field
2631 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
)
2640 flags
= GET_WORD(res
);
2642 /* remove MF_END flag before passing it to AppendMenu()! */
2643 end
= (flags
& MF_END
);
2644 if(end
) flags
^= MF_END
;
2646 res
+= sizeof(WORD
);
2647 if(!(flags
& MF_POPUP
))
2650 res
+= sizeof(WORD
);
2653 res
+= (strlenW(str
) + 1) * sizeof(WCHAR
);
2655 if (flags
& MF_POPUP
)
2657 hSubMenu
= CreatePopupMenu();
2658 if(!hSubMenu
) return NULL
;
2659 if(!(res
= MENU_ParseResource(res
, hSubMenu
))) return NULL
;
2660 AppendMenuW(hMenu
, flags
, (UINT_PTR
)hSubMenu
, (LPCWSTR
)str
);
2662 else /* Not a popup */
2664 AppendMenuW(hMenu
, flags
, id
, *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2670 /**********************************************************************
2671 * MENUEX_ParseResource
2673 * Parse an extended menu resource and add items to the menu.
2674 * Return a pointer to the end of the resource.
2676 static LPCSTR
MENUEX_ParseResource(LPCSTR res
, HMENU hMenu
)
2683 mii
.cbSize
= sizeof(mii
);
2684 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
2685 mii
.fType
= GET_DWORD(res
);
2686 res
+= sizeof(DWORD
);
2687 mii
.fState
= GET_DWORD(res
);
2688 res
+= sizeof(DWORD
);
2689 mii
.wID
= GET_DWORD(res
);
2690 res
+= sizeof(DWORD
);
2691 resinfo
= GET_WORD(res
);
2692 res
+= sizeof(WORD
);
2693 /* Align the text on a word boundary. */
2694 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2695 mii
.dwTypeData
= (LPWSTR
)res
;
2696 mii
.cch
= strlenW(mii
.dwTypeData
);
2697 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2698 /* Align the following fields on a dword boundary. */
2699 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2701 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2702 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2704 if (resinfo
& 1) /* Pop-up? */
2706 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2707 res
+= sizeof(DWORD
);
2708 mii
.hSubMenu
= CreatePopupMenu();
2711 ERR("CreatePopupMenu failed\n");
2715 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
2717 ERR("MENUEX_ParseResource failed\n");
2718 DestroyMenu(mii
.hSubMenu
);
2721 mii
.fMask
|= MIIM_SUBMENU
;
2723 else if (!mii
.dwTypeData
[0] && !(mii
.fType
& MF_SEPARATOR
))
2725 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
2726 mii
.wID
, mii
.fType
);
2727 mii
.fType
|= MF_SEPARATOR
;
2729 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2730 } while (!(resinfo
& MF_END
));
2735 /***********************************************************************
2736 * DrawMenuBarTemp (USER32.@)
2740 * called by W98SE desk.cpl Control Panel Applet
2742 * Not 100% sure about the param names, but close.
2747 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2749 ROSMENUINFO MenuInfo
;
2750 ROSMENUITEMINFO ItemInfo
;
2752 HFONT FontOld
= NULL
;
2753 BOOL flat_menu
= FALSE
;
2755 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2759 Menu
= GetMenu(Wnd
);
2767 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2769 return GetSystemMetrics(SM_CYMENU
);
2772 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2774 FontOld
= SelectObject(DC
, Font
);
2776 if (0 == MenuInfo
.cyMenu
)
2778 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2781 Rect
->bottom
= Rect
->top
+ MenuInfo
.cyMenu
;
2783 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2785 SelectObject(DC
, GetStockObject(DC_PEN
));
2786 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2787 MoveToEx(DC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2788 LineTo(DC
, Rect
->right
, Rect
->bottom
- 1);
2790 if (0 == MenuInfo
.cItems
)
2792 SelectObject(DC
, FontOld
);
2793 return GetSystemMetrics(SM_CYMENU
);
2796 MenuInitRosMenuItemInfo(&ItemInfo
);
2797 for (i
= 0; i
< MenuInfo
.cItems
; i
++)
2799 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2801 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2802 MenuInfo
.cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2805 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2807 SelectObject(DC
, FontOld
);
2809 return MenuInfo
.cyMenu
;
2813 /***********************************************************************
2816 * Display the sub-menu of the selected item of this menu.
2817 * Return the handle of the submenu, or menu if no submenu to display.
2819 static HMENU FASTCALL
2820 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2823 ROSMENUITEMINFO ItemInfo
;
2824 ROSMENUINFO SubMenuInfo
;
2828 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2830 if (MenuInfo
->iItem
== NO_SELECTED_ITEM
) return MenuInfo
->Self
;
2832 MenuInitRosMenuItemInfo(&ItemInfo
);
2833 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
2835 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2836 return MenuInfo
->Self
;
2839 //item = &menu->rgItems[menu->iItem];
2840 if (!(ItemInfo
.hSubMenu
) || (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2842 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2843 return MenuInfo
->Self
;
2846 /* message must be sent before using item,
2847 because nearly everything may be changed by the application ! */
2849 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2850 if (!(Flags
& TPM_NONOTIFY
))
2852 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2853 MAKELPARAM(MenuInfo
->iItem
, IS_SYSTEM_MENU(MenuInfo
)));
2856 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
2858 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2859 return MenuInfo
->Self
;
2862 //item = &menu->rgItems[menu->iItem];
2863 Rect
= ItemInfo
.Rect
;
2865 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2866 if (!(ItemInfo
.fState
& MF_HILITE
))
2868 if (MenuInfo
->fFlags
& MNF_POPUP
) Dc
= GetDC(MenuInfo
->Wnd
);
2869 else Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2871 SelectObject(Dc
, hMenuFont
);
2872 ItemInfo
.fMask
|= MIIM_STATE
;
2873 ItemInfo
.fState
|= MF_HILITE
;
2874 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2875 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->cyMenu
,
2876 !(MenuInfo
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
2877 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2880 if (!ItemInfo
.Rect
.top
&& !ItemInfo
.Rect
.left
&& !ItemInfo
.Rect
.bottom
&& !ItemInfo
.Rect
.right
)
2881 ItemInfo
.Rect
= Rect
;
2883 ItemInfo
.fMask
|= MIIM_STATE
;
2884 ItemInfo
.fState
|= MF_MOUSESELECT
;
2885 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2887 if (IS_SYSTEM_MENU(MenuInfo
))
2889 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
,
2890 GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2891 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2893 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2894 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
= Rect
.right
;
2895 Rect
.top
= Rect
.bottom
;
2896 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2897 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2901 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2902 if (MenuInfo
->fFlags
& MNF_POPUP
)
2904 RECT rc
= ItemInfo
.Rect
;
2906 MENU_AdjustMenuItemRect(MenuInfo
, &rc
);
2908 /* The first item in the popup menu has to be at the
2909 same y position as the focused menu item */
2910 if(Flags
& TPM_LAYOUTRTL
)
2911 Rect
.left
+= GetSystemMetrics(SM_CXBORDER
);
2913 Rect
.left
+= rc
.right
/*ItemInfo.Rect.right*/ - GetSystemMetrics(SM_CXBORDER
);
2914 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
2915 Rect
.right
= rc
.left
- rc
.right
+ GetSystemMetrics(SM_CXBORDER
);
2916 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
2917 - GetSystemMetrics(SM_CYBORDER
);
2921 if(Flags
& TPM_LAYOUTRTL
)
2922 Rect
.left
+= Rect
.right
- ItemInfo
.Rect
.left
;
2924 Rect
.left
+= ItemInfo
.Rect
.left
;
2925 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2926 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2927 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2931 /* use default alignment for submenus */
2932 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
2934 MENU_InitPopup( WndOwner
, ItemInfo
.hSubMenu
, Flags
);
2936 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->iItem
, Flags
,
2937 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2938 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2940 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2943 Ret
= ItemInfo
.hSubMenu
;
2944 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2949 /**********************************************************************
2952 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2954 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2956 void MENU_EndMenu( HWND hwnd
)
2959 menu
= top_popup_hmenu
? MENU_GetMenu( top_popup_hmenu
) : NULL
;
2960 if (menu
&& ( hwnd
== menu
->hWnd
|| hwnd
== (menu
->spwndNotify
? menu
->spwndNotify
->head
.h
: NULL
)) )
2964 /***********************************************************************
2967 * Hide the sub-popup menus of this menu.
2969 static void FASTCALL
2970 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2971 BOOL SendMenuSelect
, UINT wFlags
)
2973 ROSMENUINFO SubMenuInfo
;
2974 ROSMENUITEMINFO ItemInfo
;
2976 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2978 if (MenuInfo
&& top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->iItem
)
2980 //item = &menu->rgItems[menu->iItem];
2981 MenuInitRosMenuItemInfo(&ItemInfo
);
2982 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2983 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
)
2984 || !(ItemInfo
.hSubMenu
)
2985 || !(ItemInfo
.fState
& MF_MOUSESELECT
))
2987 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2990 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2991 ItemInfo
.fMask
|= MIIM_STATE
;
2992 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2993 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2995 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2996 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2998 DestroyWindow(SubMenuInfo
.Wnd
);
2999 /* Native returns handle to destroyed window */
3000 if (!(wFlags
& TPM_NONOTIFY
))
3001 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
3002 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
3004 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3005 // Fixes todo_wine User32 test menu.c line 2233 GetMenuBarInfo callback....
3007 SubMenuInfo
.Wnd
= NULL
;
3008 MenuSetRosMenuInfo(&SubMenuInfo
);
3014 /***********************************************************************
3015 * MenuSwitchTracking
3017 * Helper function for menu navigation routines.
3019 static void FASTCALL
3020 MenuSwitchTracking(MTRACKER
* pmt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
3022 ROSMENUINFO TopMenuInfo
;
3024 TRACE("%x menu=%x 0x%04x\n", pmt
, PtMenuInfo
->Self
, Index
);
3026 if ( MenuGetRosMenuInfo(&TopMenuInfo
, pmt
->TopMenu
) &&
3027 pmt
->TopMenu
!= PtMenuInfo
->Self
&&
3028 !((PtMenuInfo
->fFlags
| TopMenuInfo
.fFlags
) & MNF_POPUP
) )
3030 /* both are top level menus (system and menu-bar) */
3031 MenuHideSubPopups(pmt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
3032 MenuSelectItem(pmt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3033 pmt
->TopMenu
= PtMenuInfo
->Self
;
3037 MenuHideSubPopups(pmt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
3040 MenuSelectItem(pmt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
3043 /***********************************************************************
3044 * MenuExecFocusedItem
3046 * Execute a menu item (for instance when user pressed Enter).
3047 * Return the wID of the executed item. Otherwise, -1 indicating
3048 * that no menu item was executed, -2 if a popup is shown;
3049 * Have to receive the flags for the TrackPopupMenu options to avoid
3050 * sending unwanted message.
3054 MenuExecFocusedItem(MTRACKER
*pmt
, PROSMENUINFO MenuInfo
, UINT Flags
)
3056 ROSMENUITEMINFO ItemInfo
;
3059 TRACE("%p menu=%p\n", pmt
, MenuInfo
);
3061 if (0 == MenuInfo
->cItems
|| NO_SELECTED_ITEM
== MenuInfo
->iItem
)
3066 MenuInitRosMenuItemInfo(&ItemInfo
);
3067 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
3069 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3073 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
3075 if (0 == (ItemInfo
.hSubMenu
))
3077 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
3078 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
3080 /* If TPM_RETURNCMD is set you return the id, but
3081 do not send a message to the owner */
3082 if (0 == (Flags
& TPM_RETURNCMD
))
3084 if (0 != (MenuInfo
->fFlags
& MNF_SYSMENU
))
3086 PostMessageW(pmt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
3087 MAKELPARAM((SHORT
) pmt
->Pt
.x
, (SHORT
) pmt
->Pt
.y
));
3091 ROSMENUINFO topmenuI
;
3092 BOOL ret
= MenuGetRosMenuInfo(&topmenuI
, pmt
->TopMenu
);
3093 DWORD dwStyle
= MenuInfo
->dwStyle
| (ret
? topmenuI
.dwStyle
: 0);
3095 if (dwStyle
& MNS_NOTIFYBYPOS
)
3096 PostMessageW(pmt
->OwnerWnd
, WM_MENUCOMMAND
, MenuInfo
->iItem
, (LPARAM
)MenuInfo
->Self
);
3098 PostMessageW(pmt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
3102 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3108 pmt
->CurrentMenu
= MenuShowSubPopup(pmt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
3115 /***********************************************************************
3118 * Return TRUE if we can go on with menu tracking.
3120 static BOOL FASTCALL
3121 MENU_ButtonDown(MTRACKER
* pmt
, HMENU hPtMenu
, UINT Flags
)
3124 ROSMENUINFO MenuInfo
;
3125 ROSMENUITEMINFO Item
;
3127 TRACE("%x PtMenu=%p\n", pmt
, hPtMenu
);
3129 if (NULL
!= hPtMenu
)
3131 if (! MenuGetRosMenuInfo(&MenuInfo
, hPtMenu
))
3135 if (IS_SYSTEM_MENU(&MenuInfo
))
3141 Index
= NtUserMenuItemFromPoint(pmt
->OwnerWnd
, hPtMenu
, pmt
->Pt
.x
, pmt
->Pt
.y
);
3143 MenuInitRosMenuItemInfo(&Item
);
3144 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(hPtMenu
, Index
, &Item
))
3146 MenuCleanupRosMenuItemInfo(&Item
);
3150 if (!(Item
.fType
& MF_SEPARATOR
) &&
3151 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
3153 if (MenuInfo
.iItem
!= Index
)
3155 MenuSwitchTracking(pmt
, &MenuInfo
, Index
, Flags
);
3158 /* If the popup menu is not already "popped" */
3159 if (!(Item
.fState
& MF_MOUSESELECT
))
3161 pmt
->CurrentMenu
= MenuShowSubPopup(pmt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3164 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
*pmt
, HMENU hPtMenu
, UINT Flags
)
3185 ROSMENUINFO MenuInfo
;
3186 ROSMENUITEMINFO ItemInfo
;
3188 TRACE("%p hmenu=%x\n", pmt
, hPtMenu
);
3193 if (! MenuGetRosMenuInfo(&MenuInfo
, hPtMenu
))
3198 if (! IS_SYSTEM_MENU(&MenuInfo
))
3200 Id
= NtUserMenuItemFromPoint(pmt
->OwnerWnd
, MenuInfo
.Self
, pmt
->Pt
.x
, pmt
->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( pmt
, &MenuInfo
, Flags
);
3209 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3210 if (ExecutedMenuId
== -1 || ExecutedMenuId
== -2) return -1;
3211 return ExecutedMenuId
;
3213 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3215 /* If we are dealing with the menu bar */
3216 /* and this is a click on an already "popped" item: */
3217 /* Stop the menu tracking and close the opened submenus */
3218 if (pmt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
3220 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3224 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3225 if( GetMenu(MenuInfo
.Wnd
) == hPtMenu
)
3227 MenuInfo
.TimeToHide
= TRUE
;
3228 MenuSetRosMenuInfo(&MenuInfo
);
3234 /***********************************************************************
3237 * Walks menu chain trying to find a menu pt maps to.
3239 static HMENU FASTCALL
3240 MENU_PtMenu(HMENU hMenu
, POINT pt
)
3246 menu
= MENU_GetMenu( hMenu
);
3247 if (!menu
) return NULL
;
3249 /* try subpopup first (if any) */
3250 if (menu
->iItem
!= NO_SELECTED_ITEM
)
3252 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
3253 if ( pItem
) pItem
= &pItem
[menu
->iItem
];
3254 if ( pItem
&& pItem
->spSubMenu
&& pItem
->fState
& MF_MOUSESELECT
)
3256 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
3257 ret
= MENU_PtMenu( UserHMGetHandle(pSubMenu
), pt
);
3261 /* check the current window (avoiding WM_HITTEST) */
3264 INT ht
= DefWndNCHitTest(menu
->hWnd
, pt
);
3265 if ( menu
->fFlags
& MNF_POPUP
)
3267 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= hMenu
;
3269 else if (ht
== HTSYSMENU
)
3270 ret
= get_win_sys_menu(menu
->hWnd
);
3271 else if (ht
== HTMENU
)
3272 ret
= GetMenu( menu
->hWnd
);
3277 /***********************************************************************
3280 * Return TRUE if we can go on with menu tracking.
3282 static BOOL FASTCALL
3283 MenuMouseMove(MTRACKER
*pmt
, HMENU PtMenu
, UINT Flags
)
3286 ROSMENUINFO MenuInfo
;
3287 ROSMENUITEMINFO ItemInfo
;
3291 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
3295 if (IS_SYSTEM_MENU(&MenuInfo
))
3301 Index
= NtUserMenuItemFromPoint(pmt
->OwnerWnd
, PtMenu
, pmt
->Pt
.x
, pmt
->Pt
.y
);
3306 Index
= NO_SELECTED_ITEM
;
3309 if (NO_SELECTED_ITEM
== Index
)
3311 if (pmt
->CurrentMenu
== MenuInfo
.Self
||
3312 MenuGetRosMenuInfo(&MenuInfo
, pmt
->CurrentMenu
))
3314 MenuSelectItem(pmt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3315 TRUE
, pmt
->TopMenu
);
3318 else if (MenuInfo
.iItem
!= Index
)
3320 MenuInitRosMenuItemInfo(&ItemInfo
);
3321 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
3322 !(ItemInfo
.fType
& MF_SEPARATOR
))
3324 MenuSwitchTracking(pmt
, &MenuInfo
, Index
, Flags
);
3325 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
3326 pmt
->CurrentMenu
= MenuShowSubPopup(pmt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3328 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3334 /***********************************************************************
3337 * Return the handle of the selected sub-popup menu (if any).
3340 HMENU
MENU_GetSubPopup( HMENU hmenu
)
3345 menu
= MENU_GetMenu( hmenu
);
3347 if ((!menu
) || (menu
->iItem
== NO_SELECTED_ITEM
)) return 0;
3349 //item = &menu->rgItems[menu->iItem];
3350 item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
3351 if (item
) item
= &item
[menu
->iItem
];
3352 if (item
&& (item
->spSubMenu
) && (item
->fState
& MF_MOUSESELECT
))
3354 PMENU pSubMenu
= DesktopPtrToUser(item
->spSubMenu
);
3355 return UserHMGetHandle(pSubMenu
);
3360 /***********************************************************************
3363 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3365 static LRESULT FASTCALL
3366 MenuDoNextMenu(MTRACKER
* pmt
, UINT Vk
, UINT wFlags
)
3368 ROSMENUINFO TopMenuInfo
;
3369 ROSMENUINFO MenuInfo
;
3371 if (! MenuGetRosMenuInfo(&TopMenuInfo
, pmt
->TopMenu
))
3373 return (LRESULT
) FALSE
;
3376 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.iItem
)
3377 || (VK_RIGHT
== Vk
&& TopMenuInfo
.iItem
== TopMenuInfo
.cItems
- 1))
3379 MDINEXTMENU NextMenu
;
3384 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(pmt
->TopMenu
, 0) : pmt
->TopMenu
;
3385 NextMenu
.hmenuNext
= NULL
;
3386 NextMenu
.hwndNext
= NULL
;
3387 SendMessageW(pmt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
3389 TRACE("%p [%p] -> %p [%p]\n",
3390 pmt
->CurrentMenu
, pmt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
3392 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
3394 DWORD Style
= GetWindowLongPtrW(pmt
->OwnerWnd
, GWL_STYLE
);
3395 NewWnd
= pmt
->OwnerWnd
;
3396 if (IS_SYSTEM_MENU(&TopMenuInfo
))
3398 /* switch to the menu bar */
3400 if (0 != (Style
& WS_CHILD
)
3401 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
3408 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
3412 Id
= MenuInfo
.cItems
- 1;
3415 else if (0 != (Style
& WS_SYSMENU
))
3417 /* switch to the system menu */
3418 NewMenu
= get_win_sys_menu(NewWnd
);
3425 else /* application returned a new menu to switch to */
3427 NewMenu
= NextMenu
.hmenuNext
;
3428 NewWnd
= NextMenu
.hwndNext
;
3430 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
3432 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
3434 if (0 != (Style
& WS_SYSMENU
)
3435 && get_win_sys_menu(NewWnd
) == NewMenu
)
3437 /* get the real system menu */
3438 NewMenu
= get_win_sys_menu(NewWnd
);
3440 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
3442 /* FIXME: Not sure what to do here;
3443 * perhaps try to track NewMenu as a popup? */
3445 WARN(" -- got confused.\n");
3455 if (NewMenu
!= pmt
->TopMenu
)
3457 MenuSelectItem(pmt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
3459 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3461 MenuHideSubPopups(pmt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
3465 if (NewWnd
!= pmt
->OwnerWnd
)
3467 pmt
->OwnerWnd
= NewWnd
;
3468 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, pmt
->OwnerWnd
); // 1
3469 SetCapture(pmt
->OwnerWnd
); // 2
3472 pmt
->TopMenu
= pmt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
3473 if (MenuGetRosMenuInfo(&TopMenuInfo
, pmt
->TopMenu
))
3475 MenuSelectItem(pmt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
3484 /***********************************************************************
3487 * The idea is not to show the popup if the next input message is
3488 * going to hide it anyway.
3490 static BOOL FASTCALL
3491 MenuSuspendPopup(MTRACKER
* pmt
, UINT uMsg
)
3495 msg
.hwnd
= pmt
->OwnerWnd
;
3497 PeekMessageW( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
); // ported incorrectly since 8317 GvG
3498 //pmt->TrackFlags |= TF_SKIPREMOVE; // This sends TrackMenu into a loop with arrow keys!!!!
3503 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3504 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
3506 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3507 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3508 if( msg
.message
== WM_KEYDOWN
&&
3509 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
3511 pmt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3517 /* failures go through this */
3518 pmt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3522 /***********************************************************************
3525 * Handle a VK_ESCAPE key event in a menu.
3527 static BOOL FASTCALL
3528 MenuKeyEscape(MTRACKER
*pmt
, UINT Flags
)
3530 BOOL EndMenu
= TRUE
;
3531 ROSMENUINFO MenuInfo
;
3532 HMENU MenuTmp
, MenuPrev
;
3534 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3536 if (MenuGetRosMenuInfo(&MenuInfo
, pmt
->CurrentMenu
)
3537 && 0 != (MenuInfo
.fFlags
& MNF_POPUP
))
3539 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3541 /* close topmost popup */
3542 while (MenuTmp
!= pmt
->CurrentMenu
)
3545 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3548 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3550 MenuHideSubPopups(pmt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
3552 pmt
->CurrentMenu
= MenuPrev
;
3560 /***********************************************************************
3563 * Handle a VK_LEFT key event in a menu.
3565 static void FASTCALL
3566 MenuKeyLeft(MTRACKER
* pmt
, UINT Flags
)
3568 ROSMENUINFO MenuInfo
;
3569 ROSMENUINFO TopMenuInfo
;
3570 ROSMENUINFO PrevMenuInfo
;
3571 HMENU MenuTmp
, MenuPrev
;
3574 MenuPrev
= MenuTmp
= pmt
->TopMenu
;
3576 /* Try to move 1 column left (if possible) */
3577 if ( (PrevCol
= MENU_GetStartOfPrevColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3579 if (MenuGetRosMenuInfo(&MenuInfo
, pmt
->CurrentMenu
))
3581 MenuSelectItem(pmt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3586 /* close topmost popup */
3587 while (MenuTmp
!= pmt
->CurrentMenu
)
3590 MenuTmp
= MENU_GetSubPopup(MenuPrev
);
3593 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3597 MenuHideSubPopups(pmt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3598 pmt
->CurrentMenu
= MenuPrev
;
3600 if (! MenuGetRosMenuInfo(&TopMenuInfo
, pmt
->TopMenu
))
3604 if ((MenuPrev
== pmt
->TopMenu
) && !(TopMenuInfo
.fFlags
& MNF_POPUP
))
3606 /* move menu bar selection if no more popups are left */
3608 if (!MenuDoNextMenu(pmt
, VK_LEFT
, Flags
))
3610 MenuMoveSelection(pmt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3613 if (MenuPrev
!= MenuTmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3615 /* A sublevel menu was displayed - display the next one
3616 * unless there is another displacement coming up */
3618 if (! MenuSuspendPopup(pmt
, WM_KEYDOWN
)
3619 && MenuGetRosMenuInfo(&TopMenuInfo
, pmt
->TopMenu
))
3621 pmt
->CurrentMenu
= MenuShowSubPopup(pmt
->OwnerWnd
, &TopMenuInfo
,
3628 /***********************************************************************
3631 * Handle a VK_RIGHT key event in a menu.
3633 static void FASTCALL
MenuKeyRight(MTRACKER
*pmt
, UINT Flags
)
3636 ROSMENUINFO MenuInfo
;
3637 ROSMENUINFO CurrentMenuInfo
;
3640 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3641 pmt
->CurrentMenu
, pmt
->TopMenu
);
3643 if (! MenuGetRosMenuInfo(&MenuInfo
, pmt
->TopMenu
)) return;
3644 if ((MenuInfo
.fFlags
& MNF_POPUP
) || (pmt
->CurrentMenu
!= pmt
->TopMenu
))
3646 /* If already displaying a popup, try to display sub-popup */
3648 hmenutmp
= pmt
->CurrentMenu
;
3649 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, pmt
->CurrentMenu
))
3651 pmt
->CurrentMenu
= MenuShowSubPopup(pmt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3654 /* if subpopup was displayed then we are done */
3655 if (hmenutmp
!= pmt
->CurrentMenu
) return;
3658 /* Check to see if there's another column */
3659 if ( (NextCol
= MENU_GetStartOfNextColumn(pmt
->CurrentMenu
)) != NO_SELECTED_ITEM
)
3661 TRACE("Going to %d.\n", NextCol
);
3662 if (MenuGetRosMenuInfo(&MenuInfo
, pmt
->CurrentMenu
))
3664 MenuSelectItem(pmt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3669 if (!(MenuInfo
.fFlags
& MNF_POPUP
)) /* menu bar tracking */
3671 if (pmt
->CurrentMenu
!= pmt
->TopMenu
)
3673 MenuHideSubPopups(pmt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3674 hmenutmp
= pmt
->CurrentMenu
= pmt
->TopMenu
;
3681 /* try to move to the next item */
3682 if ( !MenuDoNextMenu(pmt
, VK_RIGHT
, Flags
))
3683 MenuMoveSelection(pmt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3685 if ( hmenutmp
|| pmt
->TrackFlags
& TF_SUSPENDPOPUP
)
3687 if (! MenuSuspendPopup(pmt
, WM_KEYDOWN
)
3688 && MenuGetRosMenuInfo(&MenuInfo
, pmt
->TopMenu
))
3690 pmt
->CurrentMenu
= MenuShowSubPopup(pmt
->OwnerWnd
, &MenuInfo
,
3697 /***********************************************************************
3700 * Menu tracking code.
3702 static INT FASTCALL
MenuTrackMenu(HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
3703 HWND hwnd
, const RECT
*lprect
)
3706 ROSMENUINFO MenuInfo
;
3707 ROSMENUITEMINFO ItemInfo
;
3710 INT executedMenuId
= -1;
3713 BOOL enterIdleSent
= FALSE
;
3716 mt
.CurrentMenu
= hmenu
;
3722 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3723 hmenu
, wFlags
, x
, y
, hwnd
, lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3724 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3728 WARN("Invalid menu handle %p\n", hmenu
); // Error already set in IsMenu.
3732 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
))
3737 if (wFlags
& TPM_BUTTONDOWN
)
3739 /* Get the result in order to start the tracking or not */
3740 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
3741 fEndMenu
= !fRemove
;
3744 if (wFlags
& TF_ENDMENU
) fEndMenu
= TRUE
;
3746 /* owner may not be visible when tracking a popup, so use the menu itself */
3747 capture_win
= (wFlags
& TPM_POPUPMENU
) ? MenuInfo
.Wnd
: mt
.OwnerWnd
;
3748 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, capture_win
); // 1
3749 SetCapture(capture_win
); // 2
3753 BOOL ErrorExit
= FALSE
;
3754 menu
= MENU_GetMenu( mt
.CurrentMenu
);
3755 if (!menu
) /* sometimes happens if I do a window manager close */
3758 /* we have to keep the message in the queue until it's
3759 * clear that menu loop is not over yet. */
3763 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3765 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3766 /* remove the message from the queue */
3767 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3772 if (!ValidateHwndNoErr(mt
.OwnerWnd
) || !ValidateHwndNoErr(MenuInfo
.Wnd
))
3774 ErrorExit
= TRUE
; // Do not wait on dead windows, now test_capture_4 works.
3779 HWND win
= MenuInfo
.fFlags
& MNF_POPUP
? MenuInfo
.Wnd
: NULL
;
3780 enterIdleSent
= TRUE
;
3781 SendMessageW( mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3787 if (ErrorExit
) break; // Gracefully dropout.
3789 /* check if EndMenu() tried to cancel us, by posting this message */
3790 if (msg
.message
== WM_CANCELMODE
)
3792 /* we are now out of the loop */
3795 /* remove the message from the queue */
3796 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3798 /* break out of internal loop, ala ESCAPE */
3802 TranslateMessage( &msg
);
3805 if ( (msg
.hwnd
== MenuInfo
.Wnd
) || (msg
.message
!=WM_TIMER
) )
3806 enterIdleSent
=FALSE
;
3809 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3812 * Use the mouse coordinates in lParam instead of those in the MSG
3813 * struct to properly handle synthetic messages. They are already
3814 * in screen coordinates.
3816 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3817 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3819 /* Find a menu for this mouse event */
3820 hmenu
= MENU_PtMenu(mt
.TopMenu
, mt
.Pt
);
3824 /* no WM_NC... messages in captured state */
3826 case WM_RBUTTONDBLCLK
:
3827 case WM_RBUTTONDOWN
:
3828 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3830 case WM_LBUTTONDBLCLK
:
3831 case WM_LBUTTONDOWN
:
3832 /* If the message belongs to the menu, removes it from the queue */
3833 /* Else, end menu tracking */
3834 fRemove
= MENU_ButtonDown(&mt
, hmenu
, wFlags
);
3835 fEndMenu
= !fRemove
;
3836 if (msg
.message
== WM_LBUTTONDBLCLK
) fEndMenu
= TRUE
; // Must exit or loop forever!
3840 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3843 /* Check if a menu was selected by the mouse */
3846 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
3847 TRACE("executedMenuId %d\n", executedMenuId
);
3849 /* End the loop if executedMenuId is an item ID */
3850 /* or if the job was done (executedMenuId = 0). */
3851 fEndMenu
= fRemove
= (executedMenuId
!= -1);
3853 /* No menu was selected by the mouse */
3854 /* if the function was called by TrackPopupMenu, continue
3855 with the menu tracking. If not, stop it */
3857 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3862 /* the selected menu item must be changed every time */
3863 /* the mouse moves. */
3866 fEndMenu
|= !MenuMouseMove( &mt
, hmenu
, wFlags
);
3868 } /* switch(msg.message) - mouse */
3870 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
3872 fRemove
= TRUE
; /* Keyboard messages are always removed */
3886 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3888 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
3889 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
, VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3894 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3895 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3897 if (!(MenuInfo
.fFlags
& MNF_POPUP
))
3899 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3900 mt
.CurrentMenu
= MenuShowSubPopup(mt
.OwnerWnd
, &MenuInfo
, TRUE
, wFlags
);
3902 else /* otherwise try to move selection */
3903 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
, (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
3908 MenuKeyLeft( &mt
, wFlags
);
3912 MenuKeyRight( &mt
, wFlags
);
3916 fEndMenu
= MenuKeyEscape(&mt
, wFlags
);
3922 hi
.cbSize
= sizeof(HELPINFO
);
3923 hi
.iContextType
= HELPINFO_MENUITEM
;
3924 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3926 if (MenuInfo
.iItem
== NO_SELECTED_ITEM
)
3930 MenuInitRosMenuItemInfo(&ItemInfo
);
3931 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3935 hi
.iCtrlId
= ItemInfo
.wID
;
3941 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3944 hi
.hItemHandle
= hmenu
;
3945 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3946 hi
.MousePos
= msg
.pt
;
3947 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
3954 break; /* WM_KEYDOWN */
3961 if (! MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
)) break;
3962 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
3964 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3965 fEndMenu
= (executedMenuId
!= -2);
3969 /* Hack to avoid control chars. */
3970 /* We will find a better way real soon... */
3971 if (msg
.wParam
< 32) break;
3973 pos
= MENU_FindItemByKey(mt
.OwnerWnd
, mt
.CurrentMenu
, LOWORD(msg
.wParam
), FALSE
);
3974 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
3975 else if (pos
== (UINT
)-1) MessageBeep(0);
3978 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, pos
, TRUE
, 0);
3979 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3980 fEndMenu
= (executedMenuId
!= -2);
3984 } /* switch(msg.message) - kbd */
3988 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3989 DispatchMessageW( &msg
);
3993 if (!fEndMenu
) fRemove
= TRUE
;
3995 /* finally remove message from the queue */
3997 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
3998 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3999 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
4002 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
4003 SetCapture(NULL
); /* release the capture */
4005 /* If dropdown is still painted and the close box is clicked on
4006 then the menu will be destroyed as part of the DispatchMessage above.
4007 This will then invalidate the menu handle in mt.hTopMenu. We should
4008 check for this first. */
4009 if( IsMenu( mt
.TopMenu
) )
4011 if (IsWindow(mt
.OwnerWnd
))
4013 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
4015 MenuHideSubPopups(mt
.OwnerWnd
, &MenuInfo
, FALSE
, wFlags
);
4017 if (MenuInfo
.fFlags
& MNF_POPUP
)
4019 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
4020 DestroyWindow(MenuInfo
.Wnd
);
4021 MenuInfo
.Wnd
= NULL
;
4022 MenuSetRosMenuInfo(&MenuInfo
);
4024 if (!(wFlags
& TPM_NONOTIFY
))
4025 SendMessageW( mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.TopMenu
,
4026 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
4028 MenuSelectItem( mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
4031 SendMessageW( mt
.OwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
4034 /* Reset the variable for hiding menu */
4035 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
4037 MenuInfo
.TimeToHide
= FALSE
;
4038 MenuSetRosMenuInfo(&MenuInfo
);
4042 /* The return value is only used by TrackPopupMenu */
4043 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
4044 if (executedMenuId
== -1) executedMenuId
= 0;
4045 return executedMenuId
;
4048 /***********************************************************************
4051 static BOOL FASTCALL
MenuInitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
4053 ROSMENUINFO MenuInfo
= {0};
4055 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
4057 if (!MenuGetRosMenuInfo(&MenuInfo
, hMenu
)) return FALSE
;
4061 /* This makes the menus of applications built with Delphi work.
4062 * It also enables menus to be displayed in more than one window,
4063 * but there are some bugs left that need to be fixed in this case.
4067 MenuInfo
.Wnd
= hWnd
;
4068 MenuSetRosMenuInfo(&MenuInfo
);
4070 //if (!bPopup) menu->hWnd = hWnd;
4073 top_popup
= MenuInfo
.Wnd
;//menu->hWnd;
4074 top_popup_hmenu
= hMenu
;
4079 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4080 if (!(wFlags
& TPM_NONOTIFY
))
4081 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
4083 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
4085 if (!(wFlags
& TPM_NONOTIFY
))
4087 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
4088 /* If an app changed/recreated menu bar entries in WM_INITMENU
4089 * menu sizes will be recalculated once the menu created/shown.
4092 if (!MenuInfo
.cyMenu
)
4094 /* app changed/recreated menu bar entries in WM_INITMENU
4095 Recalculate menu sizes else clicks will not work */
4096 SetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4097 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4102 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
4104 MenuInfo
.fFlags
& MNF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
4109 /***********************************************************************
4112 static BOOL FASTCALL
MenuExitTracking(HWND hWnd
, BOOL bPopup
)
4114 TRACE("hwnd=%p\n", hWnd
);
4116 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, hWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
4117 SendMessageW( hWnd
, WM_EXITMENULOOP
, bPopup
, 0 );
4120 top_popup_hmenu
= NULL
;
4124 /***********************************************************************
4125 * MenuTrackMouseMenuBar
4127 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4129 VOID
MenuTrackMouseMenuBar( HWND hWnd
, ULONG ht
, POINT pt
)
4131 HMENU hMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( hWnd
) : GetMenu(hWnd
);
4132 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4134 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
4136 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
4139 /* map point to parent client coordinates */
4140 HWND Parent
= GetAncestor(hWnd
, GA_PARENT
);
4141 if (Parent
!= GetDesktopWindow())
4143 ScreenToClient(Parent
, &pt
);
4146 MenuInitTracking(hWnd
, hMenu
, FALSE
, wFlags
);
4147 /* fetch the window menu again, it may have changed */
4148 hMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( hWnd
) : GetMenu( hWnd
);
4149 MenuTrackMenu(hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
4150 MenuExitTracking(hWnd
, FALSE
);
4154 /***********************************************************************
4155 * MenuTrackKbdMenuBar
4157 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4159 VOID
MenuTrackKbdMenuBar(HWND hwnd
, UINT wParam
, WCHAR wChar
)
4161 UINT uItem
= NO_SELECTED_ITEM
;
4163 ROSMENUINFO MenuInfo
;
4164 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
4166 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
4168 /* find window that has a menu */
4170 while (!((GetWindowLongPtrW( hwnd
, GWL_STYLE
) &
4171 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
4172 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
4174 /* check if we have to track a system menu */
4176 hTrackMenu
= GetMenu( hwnd
);
4177 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
4179 if (!(GetWindowLongPtrW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
4180 hTrackMenu
= get_win_sys_menu(hwnd
);
4182 wParam
|= HTSYSMENU
; /* prevent item lookup */
4185 if (!IsMenu( hTrackMenu
)) return;
4187 MenuInitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
4189 /* fetch the window menu again, it may have changed */
4190 hTrackMenu
= (wParam
& HTSYSMENU
) ? get_win_sys_menu( hwnd
) : GetMenu( hwnd
);
4192 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
4197 if( wChar
&& wChar
!= ' ' )
4199 uItem
= MENU_FindItemByKey( hwnd
, hTrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
4200 if ( uItem
>= (UINT
)(-2) )
4202 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
4203 /* schedule end of menu tracking */
4204 wFlags
|= TF_ENDMENU
;
4209 MenuSelectItem( hwnd
, &MenuInfo
, uItem
, TRUE
, 0 );
4211 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
4213 if( uItem
== NO_SELECTED_ITEM
)
4214 MenuMoveSelection( hwnd
, &MenuInfo
, ITEM_NEXT
);
4216 PostMessageW( hwnd
, WM_KEYDOWN
, VK_RETURN
, 0 );
4220 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
4221 MenuExitTracking( hwnd
, FALSE
);
4224 /**********************************************************************
4225 * TrackPopupMenuEx (USER32.@)
4227 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, int x
, int y
,
4228 HWND hWnd
, LPTPMPARAMS lpTpm
)
4233 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p rect %s\n",
4234 hMenu
, wFlags
, x
, y
, hWnd
, lpTpm
,
4235 lpTpm
? wine_dbgstr_rect( &lpTpm
->rcExclude
) : "-" );
4237 /* Parameter check */
4238 /* FIXME: this check is performed several times, here and in the called
4239 functions. That could be optimized */
4240 if (!(menu
= MENU_GetMenu( hMenu
)))
4242 SetLastError( ERROR_INVALID_MENU_HANDLE
);
4246 if (IsWindow(menu
->hWnd
))
4248 SetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
4252 if (MENU_InitPopup( hWnd
, hMenu
, wFlags
))
4254 MenuInitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
4256 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4257 if (!(wFlags
& TPM_NONOTIFY
))
4258 SendMessageW(hWnd
, WM_INITMENUPOPUP
, (WPARAM
) hMenu
, 0);
4260 if (MenuShowPopup(hWnd
, hMenu
, 0, wFlags
, x
, y
, 0, 0 ))
4261 ret
= MenuTrackMenu(hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
,
4262 lpTpm
? &lpTpm
->rcExclude
: NULL
);
4263 MenuExitTracking(hWnd
, TRUE
);
4267 ROSMENUINFO MenuInfo
;
4268 if (IsWindow( menu
->hWnd
)) // wine hack around this with their destroy function.
4269 DestroyWindow( menu
->hWnd
); // Fix wrong error return.
4271 MenuGetRosMenuInfo(&MenuInfo
, menu
->head
.h
);
4273 MenuSetRosMenuInfo(&MenuInfo
);
4275 if (!(wFlags
& TPM_NONOTIFY
))
4276 SendMessageW( hWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)hMenu
,
4277 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
4283 /**********************************************************************
4284 * TrackPopupMenu (USER32.@)
4286 BOOL WINAPI
TrackPopupMenu( HMENU Menu
, UINT Flags
, int x
, int y
,
4287 int Reserved
, HWND Wnd
, CONST RECT
*Rect
)
4289 return TrackPopupMenuEx( Menu
, Flags
, x
, y
, Wnd
, NULL
);
4292 /**********************************************************************
4295 * Uses flags, id and text ptr, passed by InsertMenu() and
4296 * ModifyMenu() to setup a MenuItemInfo structure.
4298 static void MENU_mnu2mnuii( UINT flags
, UINT_PTR id
, LPCWSTR str
, LPMENUITEMINFOW pmii
, BOOL Unicode
)
4300 RtlZeroMemory( pmii
, sizeof( MENUITEMINFOW
));
4301 pmii
->cbSize
= sizeof( MENUITEMINFOW
);
4302 pmii
->fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
4303 /* setting bitmap clears text and vice versa */
4304 if( IS_STRING_ITEM(flags
)) {
4305 pmii
->fMask
|= MIIM_STRING
| MIIM_BITMAP
;
4307 flags
|= MF_SEPARATOR
;
4308 /* Item beginning with a backspace is a help item */
4309 /* FIXME: wrong place, this is only true in win16 */
4322 LPCSTR NewItemA
= (LPCSTR
) str
;
4323 if (*NewItemA
== '\b')
4327 str
= (LPCWSTR
) NewItemA
;
4329 TRACE("A cch %d\n",strlen(NewItemA
));
4332 pmii
->dwTypeData
= (LPWSTR
)str
;
4333 } else if( flags
& MFT_BITMAP
){
4334 pmii
->fMask
|= MIIM_BITMAP
| MIIM_STRING
;
4335 pmii
->hbmpItem
= (HBITMAP
)str
;
4337 if( flags
& MF_OWNERDRAW
){
4338 pmii
->fMask
|= MIIM_DATA
;
4339 pmii
->dwItemData
= (ULONG_PTR
) str
;
4341 if( flags
& MF_POPUP
&& MENU_GetMenu((HMENU
)id
)) {
4342 pmii
->fMask
|= MIIM_SUBMENU
;
4343 pmii
->hSubMenu
= (HMENU
)id
;
4345 if( flags
& MF_SEPARATOR
) flags
|= MF_GRAYED
| MF_DISABLED
;
4346 pmii
->fState
= flags
& MENUITEMINFO_STATE_MASK
& ~MFS_DEFAULT
;
4347 pmii
->fType
= flags
& MENUITEMINFO_TYPE_MASK
;
4348 pmii
->wID
= (UINT
)id
;
4351 /**********************************************************************
4352 * MENU_NormalizeMenuItemInfoStruct
4354 * Helper for SetMenuItemInfo and InsertMenuItemInfo:
4355 * check, copy and extend the MENUITEMINFO struct from the version that the application
4356 * supplied to the version used by wine source. */
4357 static BOOL
MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW
*pmii_in
,
4358 MENUITEMINFOW
*pmii_out
)
4360 /* do we recognize the size? */
4361 if( !pmii_in
|| (pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) &&
4362 pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) - sizeof( pmii_in
->hbmpItem
)) ) {
4363 SetLastError( ERROR_INVALID_PARAMETER
);
4366 /* copy the fields that we have */
4367 memcpy( pmii_out
, pmii_in
, pmii_in
->cbSize
);
4368 /* if the hbmpItem member is missing then extend */
4369 if( pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
)) {
4370 pmii_out
->cbSize
= sizeof( MENUITEMINFOW
);
4371 pmii_out
->hbmpItem
= NULL
;
4373 /* test for invalid bit combinations */
4374 if( (pmii_out
->fMask
& MIIM_TYPE
&&
4375 pmii_out
->fMask
& (MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
)) ||
4376 (pmii_out
->fMask
& MIIM_FTYPE
&& pmii_out
->fType
& MFT_BITMAP
)) {
4377 ERR("invalid combination of fMask bits used\n");
4378 /* this does not happen on Win9x/ME */
4379 SetLastError( ERROR_INVALID_PARAMETER
);
4382 /* convert old style (MIIM_TYPE) to the new and keep the old one too */
4383 if( pmii_out
->fMask
& MIIM_TYPE
){
4384 pmii_out
->fMask
|= MIIM_FTYPE
;
4385 if( IS_STRING_ITEM(pmii_out
->fType
)){
4386 pmii_out
->fMask
|= MIIM_STRING
;
4387 } else if( (pmii_out
->fType
) & MFT_BITMAP
){
4388 pmii_out
->fMask
|= MIIM_BITMAP
;
4389 pmii_out
->hbmpItem
= UlongToHandle(LOWORD(pmii_out
->dwTypeData
));
4392 if (pmii_out
->fMask
& MIIM_FTYPE
)
4394 pmii_out
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
4395 pmii_out
->fType
|= pmii_in
->fType
& MENUITEMINFO_TYPE_MASK
;
4397 if (pmii_out
->fMask
& MIIM_STATE
)
4398 /* Other menu items having MFS_DEFAULT are not converted
4400 pmii_out
->fState
= pmii_in
->fState
& MENUITEMINFO_STATE_MASK
;
4402 if (pmii_out
->fMask
& MIIM_SUBMENU
)
4404 if ((pmii_out
->hSubMenu
!= NULL
) && !IsMenu(pmii_out
->hSubMenu
))
4414 NONCLIENTMETRICSW ncm
;
4416 /* get the menu font */
4417 if(!hMenuFont
|| !hMenuFontBold
)
4419 ncm
.cbSize
= sizeof(ncm
);
4420 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
4422 ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
4426 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
4427 if(hMenuFont
== NULL
)
4429 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
4433 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
4434 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
4435 if(hMenuFontBold
== NULL
)
4437 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
4438 DeleteObject(hMenuFont
);
4452 DeleteObject(hMenuFont
);
4458 DeleteObject(hMenuFontBold
);
4459 hMenuFontBold
= NULL
;
4463 HMENU FASTCALL
MENU_LoadSystemMenu(BOOL mdi
)
4465 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
4469 MENUINFO menuinfo
= {0};
4470 MENUITEMINFOW info
= {0};
4473 // removing space for checkboxes from menu
4474 menuinfo
.cbSize
= sizeof(menuinfo
);
4475 menuinfo
.fMask
= MIM_STYLE
;
4476 GetMenuInfo(hmenu
, &menuinfo
);
4477 menuinfo
.dwStyle
|= MNS_CHECKORBMP
;
4478 SetMenuInfo(hmenu
, &menuinfo
);
4480 // adding bitmaps to menu items
4481 info
.cbSize
= sizeof(info
);
4482 info
.fMask
|= MIIM_BITMAP
;
4483 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
4484 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
4485 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
4486 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
4487 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
4488 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
4489 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
4490 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
4493 AppendMenuW(hmenu
, MF_SEPARATOR
, 0, NULL
);
4494 //LoadStringW(User32Instance, IDS_MDI_NEXT, buf, sizeof(buf)/sizeof(WCHAR));
4495 //AppendMenuW(hmenu, MF_STRING, SC_NEXTWINDOW, buf);
4502 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
4506 // Will be converted to load bitmaps for OBMI!
4508 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
4512 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
4514 PLOADMENU_CALLBACK_ARGUMENTS Common
;
4517 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
4519 Result
= (LRESULT
)LoadMenuW( Common
->hModule
, Common
->InterSource
? MAKEINTRESOURCE(Common
->InterSource
) : (LPCWSTR
)&Common
->MenuName
);
4521 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
4525 /* FUNCTIONS *****************************************************************/
4531 AppendMenuA(HMENU hMenu
,
4533 UINT_PTR uIDNewItem
,
4537 UNICODE_STRING UnicodeString
;
4540 RtlInitUnicodeString(&UnicodeString
, 0);
4542 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
4544 /* copy the text string, it will be one or the other */
4545 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
4547 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
4549 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
4552 mii
.dwTypeData
= UnicodeString
.Buffer
;
4553 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
4557 TRACE("AMA Handle bitmaps\n");
4559 ////// Answer a question, why a -1? To hunt for the end of the item list. Get it, to Append?
4560 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &UnicodeString
);
4561 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
4569 AppendMenuW(HMENU hMenu
,
4571 UINT_PTR uIDNewItem
,
4575 UNICODE_STRING MenuText
;
4578 RtlInitUnicodeString(&MenuText
, 0);
4580 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
4582 /* copy the text string, it will be one or the other */
4583 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
4585 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
4586 mii
.dwTypeData
= MenuText
.Buffer
;
4587 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4589 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &MenuText
);
4597 CheckMenuItem(HMENU hmenu
,
4603 UINT uID
= uIDCheckItem
;
4605 if (!ValidateHandle(hmenu
, TYPE_MENU
))
4608 if (!(item
= MENU_FindItem( &hmenu
, &uID
, uCheck
))) return -1;
4610 Ret
= item
->fState
& MFS_CHECKED
;
4611 if ( Ret
== (uCheck
& MFS_CHECKED
)) return Ret
; // Already Checked...
4613 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
4620 CheckMenuRadioItem(HMENU hMenu
,
4628 PITEM mi_first
= NULL
, mi_check
;
4629 HMENU m_first
, m_check
;
4631 mii
.cbSize
= sizeof( mii
);
4633 for (i
= first
; i
<= last
; i
++)
4640 mi_first
= MENU_FindItem(&m_first
, &pos
, bypos
);
4641 if (!mi_first
) continue;
4642 mi_check
= mi_first
;
4648 mi_check
= MENU_FindItem(&m_check
, &pos
, bypos
);
4649 if (!mi_check
) continue;
4652 if (m_first
!= m_check
) continue;
4653 if (mi_check
->fType
== MFT_SEPARATOR
) continue;
4657 if (!(mi_check
->fType
& MFT_RADIOCHECK
) || !(mi_check
->fState
& MFS_CHECKED
))
4659 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
;
4660 mii
.fType
= (mi_check
->fType
& MENUITEMINFO_TYPE_MASK
) | MFT_RADIOCHECK
;
4661 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) | MFS_CHECKED
;
4662 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
4668 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
4669 if (mi_check
->fState
& MFS_CHECKED
)
4671 mii
.fMask
= MIIM_STATE
;
4672 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) & ~MFS_CHECKED
;
4673 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
4687 return NtUserxCreateMenu();
4694 CreatePopupMenu(VOID
)
4697 return NtUserxCreatePopupMenu();
4704 DrawMenuBar(HWND hWnd
)
4706 return NtUserxDrawMenuBar(hWnd
);
4713 EnableMenuItem(HMENU hMenu
,
4717 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4727 guii
.cbSize
= sizeof(GUITHREADINFO
);
4728 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4732 guii
.hwndMenuOwner
!= top_popup
)
4734 ERR("Capture GUI pti hWnd does not match top_popup!\n");
4738 /* if we are in the menu code, and it is active */
4739 if (!fEndMenu
&& top_popup
)
4741 /* terminate the menu handling code */
4744 /* needs to be posted to wakeup the internal menu handler */
4745 /* which will now terminate the menu, in the event that */
4746 /* the main window was minimized, or lost focus, so we */
4747 /* don't end up with an orphaned menu */
4748 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
4753 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
4756 ROSMENUINFO MenuInfo
;
4757 TRACE("(%p, %p, %04x, %04x);\n", hWnd
, hMenu
, wItemID
, wHilite
);
4758 // Force bits to be set call server side....
4759 // This alone works and passes all the menu test_menu_hilitemenuitem tests.
4760 if (!NtUserHiliteMenuItem(hWnd
, hMenu
, wItemID
, wHilite
)) return FALSE
;
4761 // Without the above call we fail 3 out of the wine failed todo tests, see CORE-7967
4763 if (MenuGetRosMenuInfo(&MenuInfo
, hMenu
))
4765 if (MenuInfo
.iItem
== wItemID
) return TRUE
;
4766 MenuHideSubPopups( hWnd
, &MenuInfo
, FALSE
, 0 );
4767 MenuSelectItem( hWnd
, &MenuInfo
, wItemID
, TRUE
, 0 );
4769 return TRUE
; // Always returns TRUE!
4778 PWND Wnd
= ValidateHwnd(hWnd
);
4783 return UlongToHandle(Wnd
->IDMenu
);
4789 BOOL WINAPI
GetMenuBarInfo( HWND hwnd
, LONG idObject
, LONG idItem
, PMENUBARINFO pmbi
)
4792 Ret
= NtUserGetMenuBarInfo( hwnd
, idObject
, idItem
, pmbi
);
4793 // Reason to move to server side!!!!!
4794 if (!Ret
) return Ret
;
4796 pmbi
->fBarFocused
= top_popup_hmenu
== pmbi
->hMenu
;
4799 pmbi
->fFocused
= pmbi
->fBarFocused
;
4809 GetMenuCheckMarkDimensions(VOID
)
4811 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4812 GetSystemMetrics(SM_CYMENUCHECK
)));
4820 GetMenuContextHelpId(HMENU hmenu
)
4823 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4824 return pMenu
->dwContextHelpId
;
4832 GetMenuDefaultItem(HMENU hMenu
,
4838 if (!(pMenu
= ValidateHandle(hMenu
, TYPE_MENU
)))
4841 return IntGetMenuDefaultItem( pMenu
, (BOOL
)fByPos
, gmdiFlags
, &gismc
);
4848 GetMenuInfo(HMENU hmenu
,
4853 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4855 SetLastError(ERROR_INVALID_PARAMETER
);
4859 if (!(pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4862 if (lpcmi
->fMask
& MIM_BACKGROUND
)
4863 lpcmi
->hbrBack
= pMenu
->hbrBack
;
4865 if (lpcmi
->fMask
& MIM_HELPID
)
4866 lpcmi
->dwContextHelpID
= pMenu
->dwContextHelpId
;
4868 if (lpcmi
->fMask
& MIM_MAXHEIGHT
)
4869 lpcmi
->cyMax
= pMenu
->cyMax
;
4871 if (lpcmi
->fMask
& MIM_MENUDATA
)
4872 lpcmi
->dwMenuData
= pMenu
->dwMenuData
;
4874 if (lpcmi
->fMask
& MIM_STYLE
)
4875 lpcmi
->dwStyle
= pMenu
->fFlags
& MNS_STYLE_MASK
;
4884 GetMenuItemCount(HMENU hmenu
)
4887 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
4888 return pMenu
->cItems
;
4896 GetMenuItemID(HMENU hMenu
,
4900 if (!(lpmi
= MENU_FindItem(&hMenu
,(UINT
*)&nPos
,MF_BYPOSITION
))) return -1;
4901 if (lpmi
->spSubMenu
) return -1;
4913 LPMENUITEMINFOA lpmii
)
4918 if( lpmii
->cbSize
!= sizeof( mii
) &&
4919 lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
4921 SetLastError( ERROR_INVALID_PARAMETER
);
4924 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
4925 mii
.cbSize
= sizeof( mii
);
4926 ret
= GetMenuItemInfo_common (hmenu
,
4929 (LPMENUITEMINFOW
)&mii
,
4931 mii
.cbSize
= lpmii
->cbSize
;
4932 memcpy( lpmii
, &mii
, mii
.cbSize
);
4944 LPMENUITEMINFOW lpmii
)
4948 if( lpmii
->cbSize
!= sizeof( mii
) && lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
4950 SetLastError( ERROR_INVALID_PARAMETER
);
4953 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
4954 mii
.cbSize
= sizeof( mii
);
4955 ret
= GetMenuItemInfo_common (hMenu
, Item
, bypos
, &mii
, TRUE
);
4956 mii
.cbSize
= lpmii
->cbSize
;
4957 memcpy( lpmii
, &mii
, mii
.cbSize
);
4973 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu
, uId
, uFlags
);
4974 if (!(pItem
= MENU_FindItem( &hMenu
, &uId
, uFlags
))) return -1;
4976 if (!pItem
->Xlpstr
&& pItem
->hbmp
) Type
= MFT_BITMAP
;
4978 if (pItem
->spSubMenu
)
4980 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
4981 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
4982 if (!IsMenu(hsubmenu
)) return (UINT
)-1;
4983 else return (pSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|Type
) & 0xff);
4986 return (pItem
->fType
| pItem
->fState
| Type
);
5003 ////// wine Code, seems to be faster.
5004 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
5006 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
5008 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
5010 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
5014 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
5016 if (!text
) return 0;
5017 if (!lpString
|| !nMaxCount
) return WideCharToMultiByte( CP_ACP
, 0, text
, -1, NULL
, 0, NULL
, NULL
);
5018 if (!WideCharToMultiByte( CP_ACP
, 0, text
, -1, lpString
, nMaxCount
, NULL
, NULL
))
5019 lpString
[nMaxCount
-1] = 0;
5020 TRACE("A returning %s\n", lpString
);
5021 return strlen(lpString
);
5039 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
5041 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
5043 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
5045 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
5049 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
5051 if (!lpString
|| !nMaxCount
) return text
? strlenW(text
) : 0;
5057 lstrcpynW( lpString
, text
, nMaxCount
);
5058 TRACE("W returning %S\n", lpString
);
5059 return strlenW(lpString
);
5072 if (!(pItem
= MENU_FindItem( &hMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
5074 if (pItem
->spSubMenu
)
5076 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
5077 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
5078 if (IsMenu(hsubmenu
)) return hsubmenu
;
5092 return NtUserGetSystemMenu(hWnd
, bRevert
);
5104 UINT_PTR uIDNewItem
,
5108 UNICODE_STRING UnicodeString
;
5111 RtlInitUnicodeString(&UnicodeString
, 0);
5113 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
5115 /* copy the text string, it will be one or the other */
5116 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5118 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5120 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5123 mii
.dwTypeData
= UnicodeString
.Buffer
;
5124 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5128 TRACE("Handle bitmaps\n");
5130 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &UnicodeString
);
5131 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
5144 LPCMENUITEMINFOA lpmii
)
5147 UNICODE_STRING UnicodeString
;
5150 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5152 RtlInitUnicodeString(&UnicodeString
, 0);
5154 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5156 /* copy the text string */
5157 if (((mii
.fMask
& MIIM_STRING
) ||
5158 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5159 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5161 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5163 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5166 mii
.dwTypeData
= UnicodeString
.Buffer
;
5167 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5171 TRACE("Handle bitmaps\n");
5173 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &UnicodeString
);
5174 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
5187 LPCMENUITEMINFOW lpmii
)
5190 UNICODE_STRING MenuText
;
5193 /* while we could just pass 'lpmii' to win32k, we make a copy so that
5194 if a bad user passes bad data, we crash his process instead of the
5197 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5199 RtlInitUnicodeString(&MenuText
, 0);
5201 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5203 /* copy the text string */
5204 if (((mii
.fMask
& MIIM_STRING
) ||
5205 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5206 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5208 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
5209 mii
.dwTypeData
= MenuText
.Buffer
;
5210 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
5212 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &MenuText
);
5225 UINT_PTR uIDNewItem
,
5229 UNICODE_STRING MenuText
;
5232 RtlInitUnicodeString(&MenuText
, 0);
5234 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
5236 /* copy the text string, it will be one or the other */
5237 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5239 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
5240 mii
.dwTypeData
= MenuText
.Buffer
;
5241 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
5243 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &MenuText
);
5255 if (ValidateHandle(Menu
, TYPE_MENU
)) return TRUE
;
5263 LoadMenuA(HINSTANCE hInstance
,
5266 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
5267 if (Resource
== NULL
)
5271 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
5278 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
5280 return(LoadMenuIndirectW(lpMenuTemplate
));
5287 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
5290 WORD version
, offset
;
5291 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
5293 version
= GET_WORD(p
);
5298 case 0: /* standard format is version of 0 */
5299 offset
= GET_WORD(p
);
5300 p
+= sizeof(WORD
) + offset
;
5301 if (!(hMenu
= CreateMenu())) return 0;
5302 if (!MENU_ParseResource(p
, hMenu
))
5308 case 1: /* extended format is version of 1 */
5309 offset
= GET_WORD(p
);
5310 p
+= sizeof(WORD
) + offset
;
5311 if (!(hMenu
= CreateMenu())) return 0;
5312 if (!MENUEX_ParseResource(p
, hMenu
))
5314 DestroyMenu( hMenu
);
5319 ERR("Menu template version %d not supported.\n", version
);
5328 LoadMenuW(HINSTANCE hInstance
,
5331 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
5332 if (Resource
== NULL
)
5336 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
5349 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
5361 UINT_PTR uIDNewItem
,
5365 UNICODE_STRING UnicodeString
;
5368 RtlInitUnicodeString(&UnicodeString
, 0);
5370 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
5372 /* copy the text string, it will be one or the other */
5373 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5375 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5377 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5380 mii
.dwTypeData
= UnicodeString
.Buffer
;
5381 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5385 TRACE("Handle bitmaps\n");
5387 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &UnicodeString
);
5388 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
5401 UINT_PTR uIDNewItem
,
5405 UNICODE_STRING MenuText
;
5408 RtlInitUnicodeString(&MenuText
, 0);
5410 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
5412 /* copy the text string, it will be one or the other */
5413 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
5415 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
5416 mii
.dwTypeData
= MenuText
.Buffer
;
5417 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
5421 TRACE("Handle bitmaps\n");
5423 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &MenuText
);
5434 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
5449 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
5451 SetLastError(ERROR_INVALID_PARAMETER
);
5455 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
5456 return NtUserThunkedMenuInfo(hmenu
, (LPCMENUINFO
)&mi
);
5468 HBITMAP hBitmapUnchecked
,
5469 HBITMAP hBitmapChecked
)
5471 MENUITEMINFOW uItem
;
5472 memset ( &uItem
, 0, sizeof(uItem
) );
5473 uItem
.cbSize
= sizeof(MENUITEMINFOW
);
5474 uItem
.fMask
= MIIM_CHECKMARKS
;
5475 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
5476 uItem
.hbmpChecked
= hBitmapChecked
;
5477 return SetMenuItemInfoW(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), &uItem
);
5489 LPCMENUITEMINFOA lpmii
)
5492 UNICODE_STRING UnicodeString
;
5495 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu
, item
, bypos
, lpmii
);
5497 RtlInitUnicodeString(&UnicodeString
, 0);
5499 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
5501 * MIIM_STRING == good
5502 * MIIM_TYPE & MFT_STRING == good
5503 * MIIM_STRING & MFT_STRING == good
5504 * MIIM_STRING & MFT_OWNERDRAW == good
5506 if (((mii
.fMask
& MIIM_STRING
) ||
5507 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
5508 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
5510 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5511 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
5513 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
5516 mii
.dwTypeData
= UnicodeString
.Buffer
;
5517 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5521 UnicodeString
.Buffer
= NULL
;
5523 Ret
= NtUserThunkedMenuItemInfo(hmenu
, item
, bypos
, FALSE
, &mii
, &UnicodeString
);
5524 if (UnicodeString
.Buffer
!= NULL
) RtlFreeUnicodeString(&UnicodeString
);
5537 LPCMENUITEMINFOW lpmii
)
5539 MENUITEMINFOW MenuItemInfoW
;
5540 UNICODE_STRING UnicodeString
;
5543 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
5545 RtlInitUnicodeString(&UnicodeString
, 0);
5547 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &MenuItemInfoW
)) return FALSE
;
5549 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5550 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5551 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5552 && MenuItemInfoW
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)MenuItemInfoW
.dwTypeData
)) )
5554 RtlInitUnicodeString(&UnicodeString
, (PCWSTR
)MenuItemInfoW
.dwTypeData
);
5555 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5557 Ret
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, FALSE
, &MenuItemInfoW
, &UnicodeString
);
5573 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5578 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5581 return NtUserSetSystemMenu(hwnd
, hMenu
);
5585 // Example for the Win32/User32 rewrite.
5586 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5600 return NtUserTrackPopupMenuEx( Menu
,
5605 NULL
); // LPTPMPARAMS is null
5624 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5627 Result
= (ULONG_PTR
)lResult
;
5632 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5651 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5654 Result
= (ULONG_PTR
)lResult
;
5659 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5670 LPCWSTR lpszNewItem
,
5675 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5676 for MF_DELETE. We should check the parameters for all others
5677 MF_* actions also (anybody got a doc on ChangeMenu?).
5680 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5683 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5686 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5689 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5692 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5693 flags
&~ MF_REMOVE
);
5695 default : /* MF_INSERT */
5696 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5713 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5714 for MF_DELETE. We should check the parameters for all others
5715 MF_* actions also (anybody got a doc on ChangeMenu?).
5718 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5721 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5724 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5727 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5730 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5731 flags
&~ MF_REMOVE
);
5733 default : /* MF_INSERT */
5734 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);