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
);
18 WINE_DEFAULT_DEBUG_CHANNEL(menu
);
20 /* internal popup menu window messages */
22 #define MM_SETMENUHANDLE (WM_USER + 0)
23 #define MM_GETMENUHANDLE (WM_USER + 1)
25 /* internal flags for menu tracking */
27 #define TF_ENDMENU 0x10000
28 #define TF_SUSPENDPOPUP 0x20000
29 #define TF_SKIPREMOVE 0x40000
34 /* Internal MenuTrackMenu() flags */
35 #define TPM_INTERNAL 0xF0000000
36 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
37 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
40 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
42 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
44 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
45 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
46 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
48 #define IS_SYSTEM_MENU(MenuInfo) \
49 (0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
51 #define IS_SYSTEM_POPUP(MenuInfo) \
52 (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
54 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
56 /* Use global popup window because there's no way 2 menus can
57 * be tracked at the same time. */
58 static HWND top_popup
;
59 static HMENU top_popup_hmenu
;
61 /* Flag set by EndMenu() to force an exit from menu tracking */
62 static BOOL fEndMenu
= FALSE
;
64 #define MENU_ITEM_HBMP_SPACE (5)
65 #define MENU_BAR_ITEMS_SPACE (12)
66 #define SEPARATOR_HEIGHT (5)
67 #define MENU_TAB_SPACE (8)
72 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
73 HMENU TopMenu
; /* initial menu */
74 HWND OwnerWnd
; /* where notifications are sent */
79 /*********************************************************************
80 * PopupMenu class descriptor
82 const struct builtin_class_descr POPUPMENU_builtin_class
=
85 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
86 (WNDPROC
) NULL
, /* FIXME - procA */
87 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
88 sizeof(MENUINFO
*), /* extra */
89 (LPCWSTR
) IDC_ARROW
, /* cursor */
90 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
94 #define GET_WORD(ptr) (*(WORD *)(ptr))
97 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
100 HFONT hMenuFont
= NULL
;
101 HFONT hMenuFontBold
= NULL
;
103 /* Dimension of the menu bitmaps */
104 static HBITMAP BmpSysMenu
= NULL
;
106 static SIZE MenuCharSize
;
108 /***********************************************************************
111 * Get full information about menu
114 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
116 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
117 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
119 return NtUserMenuInfo(Menu
, MenuInfo
, FALSE
);
122 /***********************************************************************
125 * Set full information about menu
128 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
130 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
131 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
133 return NtUserMenuInfo(MenuInfo
->Self
, MenuInfo
, TRUE
);
136 /***********************************************************************
137 * MenuInitRosMenuItemInfo
139 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
142 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
144 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
145 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
148 /***********************************************************************
149 * MenuGetRosMenuItemInfo
151 * Get full information about a menu item
154 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
156 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
158 if (ItemInfo
->dwTypeData
!= NULL
)
160 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
164 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
165 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
166 ItemInfo
->dwTypeData
= NULL
;
168 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
174 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
177 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0,
178 ItemInfo
->cch
* sizeof(WCHAR
));
179 if (NULL
== ItemInfo
->dwTypeData
)
184 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
189 ItemInfo
->dwTypeData
[ItemInfo
->cch
- 1] = UNICODE_NULL
;
191 ItemInfo
->fMask
= Save_Mask
;
195 /***********************************************************************
196 * MenuSetRosMenuItemInfo
198 * Set selected information about a menu item, need to set the mask bits.
201 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
205 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
206 ItemInfo
->dwTypeData
!= NULL
)
208 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
210 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
215 /***********************************************************************
216 * MenuCleanupRosMenuItemInfo
218 * Cleanup after use of MenuGet/SetRosMenuItemInfo
221 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
223 if (ItemInfo
->dwTypeData
!= NULL
)
225 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
226 ItemInfo
->dwTypeData
= NULL
;
230 /***********************************************************************
231 * MenuGetAllRosMenuItemInfo
233 * Get full information about all menu items
236 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
240 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
241 if (BufSize
== (DWORD
) -1 || BufSize
== 0)
245 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
246 if (NULL
== *ItemInfo
)
251 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
254 /***********************************************************************
255 * MenuCleanupAllRosMenuItemInfo
257 * Cleanup after use of MenuGetAllRosMenuItemInfo
260 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
262 HeapFree(GetProcessHeap(), 0, ItemInfo
);
265 /***********************************************************************
266 * MenuInitSysMenuPopup
268 * Grey the appropriate items in System menu.
270 void FASTCALL
MenuInitSysMenuPopup(HMENU hmenu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
278 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
279 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
280 gray
= ((style
& WS_MAXIMIZE
) != 0);
281 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
282 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
283 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
284 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
285 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
286 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
287 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
288 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
290 /* The menu item must keep its state if it's disabled */
292 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
294 /* Set default menu item */
295 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
296 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
297 else DefItem
= SC_CLOSE
;
299 mii
.cbSize
= sizeof(MENUITEMINFOW
);
300 mii
.fMask
|= MIIM_STATE
;
301 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(hmenu
, DefItem
, FALSE
, &mii
) &&
302 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
))) DefItem
= SC_CLOSE
;
304 SetMenuDefaultItem(hmenu
, DefItem
, MF_BYCOMMAND
);
307 /******************************************************************************
309 * UINT MenuGetStartOfNextColumn(
310 * PROSMENUINFO MenuInfo)
312 *****************************************************************************/
313 static UINT
MenuGetStartOfNextColumn(
314 PROSMENUINFO MenuInfo
)
316 PROSMENUITEMINFO MenuItems
;
319 i
= MenuInfo
->FocusedItem
;
320 if ( i
== NO_SELECTED_ITEM
)
323 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
324 return NO_SELECTED_ITEM
;
326 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
327 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
330 return NO_SELECTED_ITEM
;
333 /******************************************************************************
335 * UINT MenuGetStartOfPrevColumn(
336 * PROSMENUINFO MenuInfo)
338 *****************************************************************************/
340 static UINT FASTCALL
MenuGetStartOfPrevColumn(
341 PROSMENUINFO MenuInfo
)
343 PROSMENUITEMINFO MenuItems
;
346 if (!MenuInfo
->FocusedItem
|| MenuInfo
->FocusedItem
== NO_SELECTED_ITEM
)
347 return NO_SELECTED_ITEM
;
349 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
350 return NO_SELECTED_ITEM
;
352 /* Find the start of the column */
353 for (i
= MenuInfo
->FocusedItem
;
354 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
362 MenuCleanupAllRosMenuItemInfo(MenuItems
);
363 return NO_SELECTED_ITEM
;
366 for (--i
; 0 != i
; --i
)
367 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
370 MenuCleanupAllRosMenuItemInfo(MenuItems
);
371 TRACE("ret %d.\n", i
);
376 /***********************************************************************
379 * Find a Sub menu. Return the position of the submenu, and modifies
380 * *hmenu in case it is found in another sub-menu.
381 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
383 static UINT FASTCALL
MenuFindSubMenu(HMENU
*hmenu
, HMENU hSubTarget
)
387 ROSMENUITEMINFO item
;
388 if (((*hmenu
)==(HMENU
)0xffff) ||
389 (!MenuGetRosMenuInfo(&menu
, *hmenu
)))
390 return NO_SELECTED_ITEM
;
392 MenuInitRosMenuItemInfo(&item
);
393 for (i
= 0; i
< menu
.MenuItemCount
; i
++) {
394 if (! MenuGetRosMenuItemInfo(menu
.Self
, i
, &item
))
396 MenuCleanupRosMenuItemInfo(&item
);
397 return NO_SELECTED_ITEM
;
399 if (!(item
.fType
& MF_POPUP
)) continue;
400 if (item
.hSubMenu
== hSubTarget
) {
401 MenuCleanupRosMenuItemInfo(&item
);
405 HMENU hsubmenu
= item
.hSubMenu
;
406 UINT pos
= MenuFindSubMenu(&hsubmenu
, hSubTarget
);
407 if (pos
!= NO_SELECTED_ITEM
) {
413 MenuCleanupRosMenuItemInfo(&item
);
414 return NO_SELECTED_ITEM
;
417 /***********************************************************************
420 * Load the arrow bitmap. We can't do this from MenuInit since user32
421 * can also be used (and thus initialized) from text-mode.
424 MenuLoadBitmaps(VOID
)
426 /* Load system buttons bitmaps */
427 if (NULL
== BmpSysMenu
)
429 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
433 /***********************************************************************
436 * Draws popup magic glyphs (can be found in system menu).
439 MenuDrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
442 HFONT hFont
, hOldFont
;
448 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
451 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
454 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
457 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
461 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
464 ZeroMemory(&lf
, sizeof(LOGFONTW
));
465 InflateRect(r
, -2, -2);
466 lf
.lfHeight
= r
->bottom
- r
->top
;
468 lf
.lfWeight
= FW_NORMAL
;
469 lf
.lfCharSet
= DEFAULT_CHARSET
;
470 lstrcpy(lf
.lfFaceName
, TEXT("Marlett"));
471 hFont
= CreateFontIndirect(&lf
);
472 /* save font and text color */
473 hOldFont
= SelectObject(dc
, hFont
);
474 clrsave
= GetTextColor(dc
);
475 bkmode
= GetBkMode(dc
);
476 /* set color and drawing mode */
477 SetBkMode(dc
, TRANSPARENT
);
483 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
484 TextOut(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
487 SetTextColor(dc
, GetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
488 /* draw selected symbol */
489 TextOut(dc
, r
->left
, r
->top
, &symbol
, 1);
490 /* restore previous settings */
491 SetTextColor(dc
, clrsave
);
492 SelectObject(dc
, hOldFont
);
493 SetBkMode(dc
, bkmode
);
497 /***********************************************************************
500 * Find the menu item selected by a key press.
501 * Return item id, -1 if none, -2 if we should close the menu.
503 static UINT FASTCALL
MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
504 WCHAR Key
, BOOL ForceMenuChar
)
506 ROSMENUINFO SysMenuInfo
;
507 PROSMENUITEMINFO Items
, ItemInfo
;
511 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
513 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
515 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
517 MenuInfo
= &SysMenuInfo
;
525 if (NULL
!= MenuInfo
)
527 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
535 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
537 if ((ItemInfo
->lpstr
) && NULL
!= ItemInfo
->dwTypeData
)
539 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
542 p
= strchrW(p
+ 2, '&');
544 while (NULL
!= p
&& L
'&' == p
[1]);
545 if (NULL
!= p
&& (toupperW(p
[1]) == Key
))
553 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
554 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
555 if (2 == HIWORD(MenuChar
))
557 return LOWORD(MenuChar
);
559 if (1 == HIWORD(MenuChar
))
568 /***********************************************************************
569 * MenuGetBitmapItemSize
571 * Get the size of a bitmap item.
573 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
, HWND WndOwner
)
576 HBITMAP bmp
= lpitem
->hbmpItem
;
578 size
->cx
= size
->cy
= 0;
580 /* check if there is a magic menu item associated with this item */
581 if (IS_MAGIC_BITMAP(bmp
))
583 switch((INT_PTR
) bmp
)
585 case (INT_PTR
)HBMMENU_CALLBACK
:
587 MEASUREITEMSTRUCT measItem
;
588 measItem
.CtlType
= ODT_MENU
;
590 measItem
.itemID
= lpitem
->wID
;
591 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
592 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
593 measItem
.itemData
= lpitem
->dwItemData
;
594 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
595 size
->cx
= measItem
.itemWidth
;
596 size
->cy
= measItem
.itemHeight
;
601 case (INT_PTR
) HBMMENU_SYSTEM
:
602 if (0 != lpitem
->dwItemData
)
604 bmp
= (HBITMAP
) lpitem
->dwItemData
;
608 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
609 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
610 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
611 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
612 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
613 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
614 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
615 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
616 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
617 /* FIXME: Why we need to subtract these magic values? */
618 /* to make them smaller than the menu bar? */
619 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
620 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
625 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
627 size
->cx
= bm
.bmWidth
;
628 size
->cy
= bm
.bmHeight
;
632 /***********************************************************************
635 * Draw a bitmap item.
637 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
638 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
644 int w
= rect
->right
- rect
->left
;
645 int h
= rect
->bottom
- rect
->top
;
648 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
651 /* Check if there is a magic menu item associated with this item */
652 if (IS_MAGIC_BITMAP(hbmToDraw
))
658 switch ((INT_PTR
)hbmToDraw
)
660 case (INT_PTR
)HBMMENU_SYSTEM
:
661 if (lpitem
->dwTypeData
)
663 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
664 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
668 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
670 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
671 /* only use right half of the bitmap */
672 bmp_xoffset
= bm
.bmWidth
/ 2;
673 bm
.bmWidth
-= bmp_xoffset
;
676 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
677 flags
= DFCS_CAPTIONRESTORE
;
679 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
681 flags
= DFCS_CAPTIONMIN
;
683 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
685 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
687 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
688 flags
= DFCS_CAPTIONCLOSE
;
690 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
691 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
693 case (INT_PTR
)HBMMENU_CALLBACK
:
695 DRAWITEMSTRUCT drawItem
;
697 drawItem
.CtlType
= ODT_MENU
;
699 drawItem
.itemID
= lpitem
->wID
;
700 drawItem
.itemAction
= odaction
;
701 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
702 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
703 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
704 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
705 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
706 drawItem
.hwndItem
= (HWND
)hmenu
;
708 drawItem
.rcItem
= *rect
;
709 drawItem
.itemData
= lpitem
->dwItemData
;
710 /* some applications make this assumption on the DC's origin */
711 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
712 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
713 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
714 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
719 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
720 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
721 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
722 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
723 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
726 InflateRect(&r
, -1, -1);
727 if (0 != (lpitem
->fState
& MF_HILITE
))
729 flags
|= DFCS_PUSHED
;
731 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
735 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
738 hdcMem
= CreateCompatibleDC( hdc
);
739 SelectObject( hdcMem
, bmp
);
741 /* handle fontsize > bitmap_height */
742 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
744 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
745 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
746 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
747 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
751 /***********************************************************************
754 * Calculate the size of the menu item and store it in lpitem->rect.
756 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
757 INT orgX
, INT orgY
, BOOL menuBar
)
760 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
763 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
765 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
767 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
769 if (lpitem
->fType
& MF_OWNERDRAW
)
771 MEASUREITEMSTRUCT mis
;
772 mis
.CtlType
= ODT_MENU
;
774 mis
.itemID
= lpitem
->wID
;
775 mis
.itemData
= lpitem
->dwItemData
;
776 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
778 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
779 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
780 * width of a menufont character to the width of an owner-drawn menu.
782 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
785 /* under at least win95 you seem to be given a standard
786 height for the menu and the height value is ignored */
787 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
789 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
791 TRACE("id=%04lx size=%dx%d\n",
792 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
796 if (lpitem
->fType
& MF_SEPARATOR
)
798 lpitem
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
800 lpitem
->Rect
.right
+= check_bitmap_width
+ MenuCharSize
.cx
;
806 if (lpitem
->hbmpItem
)
811 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
812 /* Keep the size of the bitmap in callback mode to be able
813 * to draw it correctly */
814 lpitem
->Rect
.right
= lpitem
->Rect
.left
+ size
.cx
;
815 if (MenuInfo
->maxBmpSize
.cx
< abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
||
816 MenuInfo
->maxBmpSize
.cy
< abs(size
.cy
))
818 MenuInfo
->maxBmpSize
.cx
= abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
;
819 MenuInfo
->maxBmpSize
.cy
= abs(size
.cy
);
821 MenuSetRosMenuInfo(MenuInfo
);
822 itemheight
= size
.cy
+ 2;
824 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
825 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
826 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
827 lpitem
->dxTab
= lpitem
->Rect
.right
;
828 lpitem
->Rect
.right
+= check_bitmap_width
;
829 } else /* hbmpItem & MenuBar */ {
830 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
831 lpitem
->Rect
.right
+= size
.cx
;
832 if( lpitem
->lpstr
) lpitem
->Rect
.right
+= 2;
833 itemheight
= size
.cy
;
835 /* Special case: Minimize button doesn't have a space behind it. */
836 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
837 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
838 lpitem
->Rect
.right
-= 1;
842 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
843 lpitem
->Rect
.right
+= check_bitmap_width
;
844 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
845 lpitem
->dxTab
= lpitem
->Rect
.right
;
846 lpitem
->Rect
.right
+= check_bitmap_width
;
849 /* it must be a text item - unless it's the system menu */
850 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->lpstr
) {
851 HFONT hfontOld
= NULL
;
852 RECT rc
= lpitem
->Rect
;
853 LONG txtheight
, txtwidth
;
855 if ( lpitem
->fState
& MFS_DEFAULT
) {
856 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
859 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
860 DT_SINGLELINE
|DT_CALCRECT
);
861 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
862 itemheight
= max( max( itemheight
, txtheight
),
863 GetSystemMetrics( SM_CYMENU
) - 1);
864 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
866 if ((p
= strchrW( lpitem
->dwTypeData
, '\t' )) != NULL
) {
869 int n
= (int)( p
- lpitem
->dwTypeData
);
870 /* Item contains a tab (only meaningful in popup menus) */
871 /* get text size before the tab */
872 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, n
, &rc
,
873 DT_SINGLELINE
|DT_CALCRECT
);
874 txtwidth
= rc
.right
- rc
.left
;
875 p
+= 1; /* advance past the Tab */
876 /* get text size after the tab */
877 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
878 DT_SINGLELINE
|DT_CALCRECT
);
879 lpitem
->dxTab
+= txtwidth
;
880 txtheight
= max( txtheight
, tmpheight
);
881 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
882 tmprc
.right
- tmprc
.left
; /* space for the short cut */
884 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
885 DT_SINGLELINE
|DT_CALCRECT
);
886 txtwidth
= rc
.right
- rc
.left
;
887 lpitem
->dxTab
+= txtwidth
;
889 lpitem
->Rect
.right
+= 2 + txtwidth
;
890 itemheight
= max( itemheight
,
891 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
893 if (hfontOld
) SelectObject (hdc
, hfontOld
);
894 } else if( menuBar
) {
895 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
897 lpitem
->Rect
.bottom
+= itemheight
;
898 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
901 /***********************************************************************
902 * MenuPopupMenuCalcSize
904 * Calculate the size of a popup menu.
906 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
908 ROSMENUITEMINFO lpitem
;
911 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
913 MenuInfo
->Width
= MenuInfo
->Height
= 0;
914 if (MenuInfo
->MenuItemCount
== 0)
916 MenuSetRosMenuInfo(MenuInfo
);
921 SelectObject( hdc
, hMenuFont
);
926 MenuInfo
->maxBmpSize
.cx
= 0;
927 MenuInfo
->maxBmpSize
.cy
= 0;
929 MenuInitRosMenuItemInfo(&lpitem
);
930 while (start
< MenuInfo
->MenuItemCount
)
935 maxTab
= maxTabWidth
= 0;
937 /* Parse items until column break or end of menu */
938 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
940 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
942 MenuCleanupRosMenuItemInfo(&lpitem
);
943 MenuSetRosMenuInfo(MenuInfo
);
947 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
949 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
);
950 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
952 MenuCleanupRosMenuItemInfo(&lpitem
);
953 MenuSetRosMenuInfo(MenuInfo
);
956 // Not sure here,, The patch from wine removes this.
957 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
961 maxX
= max(maxX
, lpitem
.Rect
.right
);
962 orgY
= lpitem
.Rect
.bottom
;
963 if ((lpitem
.lpstr
) && lpitem
.dxTab
)
965 maxTab
= max( maxTab
, lpitem
.dxTab
);
966 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.dxTab
);
970 /* Finish the column (set all items to the largest width found) */
971 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
974 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
976 lpitem
.Rect
.right
= maxX
;
977 if ((lpitem
.lpstr
) && 0 != lpitem
.dxTab
)
979 lpitem
.dxTab
= maxTab
;
981 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
985 MenuInfo
->Height
= max(MenuInfo
->Height
, orgY
);
988 MenuInfo
->Width
= maxX
;
990 /* space for 3d border */
991 MenuInfo
->Height
+= 2;
992 MenuInfo
->Width
+= 2;
994 MenuCleanupRosMenuItemInfo(&lpitem
);
995 MenuSetRosMenuInfo(MenuInfo
);
999 /***********************************************************************
1000 * MenuMenuBarCalcSize
1002 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1003 * height is off by 1 pixel which causes lengthy window relocations when
1004 * active document window is maximized/restored.
1006 * Calculate the size of the menu bar.
1008 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1009 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
1011 ROSMENUITEMINFO ItemInfo
;
1012 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1014 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
1015 if (MenuInfo
->MenuItemCount
== 0) return;
1016 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
1017 MenuInfo
->Width
= lprect
->right
- lprect
->left
;
1018 MenuInfo
->Height
= 0;
1019 maxY
= lprect
->top
+ 1;
1023 MenuInfo
->maxBmpSize
.cx
= 0;
1024 MenuInfo
->maxBmpSize
.cy
= 0;
1026 MenuInitRosMenuItemInfo(&ItemInfo
);
1027 while (start
< MenuInfo
->MenuItemCount
)
1029 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1031 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1034 orgX
= lprect
->left
;
1037 /* Parse items until line break or end of menu */
1038 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
1040 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1042 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1044 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1045 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
);
1046 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1048 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1052 if (ItemInfo
.Rect
.right
> lprect
->right
)
1054 if (i
!= start
) break;
1055 else ItemInfo
.Rect
.right
= lprect
->right
;
1057 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
1058 orgX
= ItemInfo
.Rect
.right
;
1059 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1061 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1063 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1069 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1070 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1072 /* Finish the line (set all items to the largest height found) */
1075 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1077 ItemInfo
.Rect
.bottom
= maxY
;
1078 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
1083 start
= i
; /* This works! */
1087 lprect
->bottom
= maxY
;
1088 MenuInfo
->Height
= lprect
->bottom
- lprect
->top
;
1089 MenuSetRosMenuInfo(MenuInfo
);
1093 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1094 /* the last item (if several lines, only move the last line) */
1095 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1097 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1100 orgY
= ItemInfo
.Rect
.top
;
1101 orgX
= lprect
->right
;
1102 for (i
= MenuInfo
->MenuItemCount
- 1; helpPos
<= i
; i
--)
1108 if (ItemInfo
.Rect
.top
!= orgY
)
1110 break; /* Other line */
1112 if (orgX
<= ItemInfo
.Rect
.right
)
1114 break; /* Too far right already */
1116 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1117 ItemInfo
.Rect
.right
= orgX
;
1118 orgX
= ItemInfo
.Rect
.left
;
1119 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1120 if (helpPos
+ 1 <= i
&&
1121 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1123 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1129 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1132 /***********************************************************************
1135 * Draw a single menu item.
1137 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1138 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1142 BOOL flat_menu
= FALSE
;
1144 PWND Wnd
= ValidateHwnd(hWnd
);
1149 if (lpitem
->fType
& MF_SYSMENU
)
1151 if ( (Wnd
->style
& WS_MINIMIZE
))
1153 UserGetInsideRectNC(Wnd
, &rect
);
1154 UserDrawSysMenuButton(hWnd
, hdc
, &rect
,
1155 lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1160 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1161 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1165 if (lpitem
->fState
& MF_HILITE
)
1167 if(menuBar
&& !flat_menu
) {
1168 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1169 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1171 if (lpitem
->fState
& MF_GRAYED
)
1172 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1174 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1175 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1180 if (lpitem
->fState
& MF_GRAYED
)
1181 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1183 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1184 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1187 rect
= lpitem
->Rect
;
1189 if (lpitem
->fType
& MF_OWNERDRAW
)
1192 ** Experimentation under Windows reveals that an owner-drawn
1193 ** menu is given the rectangle which includes the space it requested
1194 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1195 ** and a popup-menu arrow. This is the value of lpitem->rect.
1196 ** Windows will leave all drawing to the application except for
1197 ** the popup-menu arrow. Windows always draws that itself, after
1198 ** the menu owner has finished drawing.
1202 dis
.CtlType
= ODT_MENU
;
1204 dis
.itemID
= lpitem
->wID
;
1205 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1207 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1208 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1209 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1210 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1211 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1214 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1215 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1216 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1217 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1219 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1220 /* Draw the popup-menu arrow */
1221 if (lpitem
->fType
& MF_POPUP
)
1224 CopyRect(&rectTemp
, &rect
);
1225 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1226 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1231 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1233 if (lpitem
->fState
& MF_HILITE
)
1237 InflateRect (&rect
, -1, -1);
1238 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1239 InflateRect (&rect
, 1, 1);
1240 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1245 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1247 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1251 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1253 SetBkMode( hdc
, TRANSPARENT
);
1255 /* vertical separator */
1256 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1263 rc
.bottom
= Height
- 3;
1266 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1267 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1268 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1269 LineTo( hdc
, rc
.left
, rc
.bottom
);
1270 SelectObject( hdc
, oldPen
);
1273 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1276 /* horizontal separator */
1277 if (lpitem
->fType
& MF_SEPARATOR
)
1284 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1287 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1288 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1289 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1290 LineTo( hdc
, rc
.right
, rc
.top
);
1291 SelectObject( hdc
, oldPen
);
1294 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1299 /* helper lines for debugging */
1300 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1301 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1302 SelectObject(hdc
, GetStockObject(DC_PEN
));
1303 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1304 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1305 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1311 INT y
= rect
.top
+ rect
.bottom
;
1313 int checked
= FALSE
;
1314 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1315 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1316 /* Draw the check mark
1319 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1321 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1322 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1323 lpitem
->hbmpUnchecked
;
1324 if (bm
) /* we have a custom bitmap */
1326 HDC hdcMem
= CreateCompatibleDC( hdc
);
1328 SelectObject( hdcMem
, bm
);
1329 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1330 check_bitmap_width
, check_bitmap_height
,
1331 hdcMem
, 0, 0, SRCCOPY
);
1335 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1338 CopyRect(&r
, &rect
);
1339 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1340 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1341 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1342 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1346 if ( lpitem
->hbmpItem
)
1349 CopyRect(&bmpRect
, &rect
);
1350 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1351 bmpRect
.left
+= check_bitmap_width
+ 2;
1352 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1354 bmpRect
.right
= bmpRect
.left
+ MenuInfo
->maxBmpSize
.cx
;
1355 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1358 /* Draw the popup-menu arrow */
1359 if (lpitem
->fType
& MF_POPUP
)
1362 CopyRect(&rectTemp
, &rect
);
1363 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1364 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1367 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1368 rect
.left
+= check_bitmap_width
;
1369 rect
.right
-= check_bitmap_width
;
1371 else if( lpitem
->hbmpItem
)
1372 { /* Draw the bitmap */
1373 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1376 /* process text if present */
1382 UINT uFormat
= menuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
1383 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1385 if(MenuInfo
->dwStyle
& MNS_CHECKORBMP
)
1386 rect
.left
+= max(0, MenuInfo
->maxBmpSize
.cx
- GetSystemMetrics(SM_CXMENUCHECK
));
1388 rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
1390 if ( lpitem
->fState
& MFS_DEFAULT
)
1392 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1396 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1397 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1400 Text
= (PWCHAR
) lpitem
->dwTypeData
;
1403 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1404 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1408 if(lpitem
->fState
& MF_GRAYED
)
1410 if (!(lpitem
->fState
& MF_HILITE
) )
1412 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1413 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1414 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1415 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1417 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1420 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1422 /* paint the shortcut text */
1423 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1425 if (L
'\t' == Text
[i
])
1427 rect
.left
= lpitem
->dxTab
;
1428 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1432 rect
.right
= lpitem
->dxTab
;
1433 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1436 if (lpitem
->fState
& MF_GRAYED
)
1438 if (!(lpitem
->fState
& MF_HILITE
) )
1440 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1441 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1442 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1443 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1445 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1447 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1451 SelectObject (hdc
, hfontOld
);
1455 /***********************************************************************
1458 * Paint a popup menu.
1460 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1462 HBRUSH hPrevBrush
= 0;
1465 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1467 GetClientRect( hwnd
, &rect
);
1469 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1470 && (SelectObject( hdc
, hMenuFont
)))
1474 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1476 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1479 BOOL flat_menu
= FALSE
;
1480 ROSMENUINFO MenuInfo
;
1481 ROSMENUITEMINFO ItemInfo
;
1483 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1485 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1487 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1489 /* draw menu items */
1490 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.MenuItemCount
)
1494 MenuInitRosMenuItemInfo(&ItemInfo
);
1496 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
1498 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1500 MenuDrawMenuItem(hwnd
, &MenuInfo
, MenuInfo
.WndOwner
, hdc
, &ItemInfo
,
1501 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
1505 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1509 SelectObject( hdc
, hPrevBrush
);
1514 /***********************************************************************
1517 * Paint a menu bar. Returns the height of the menu bar.
1518 * called from [windows/nonclient.c]
1520 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1525 HMENU hMenu
= GetMenu(hwnd
);
1527 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
1529 return GetSystemMetrics(SM_CYMENU
);
1534 hfontOld
= SelectObject(hDC
, hMenuFont
);
1536 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
1538 lprect
->bottom
= lprect
->top
+ lppop
.Height
;
1540 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1541 return lppop
.Height
;
1544 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1547 /***********************************************************************
1550 * Display a popup menu.
1552 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
1553 INT x
, INT y
, INT xanchor
, INT yanchor
)
1555 ROSMENUINFO MenuInfo
;
1556 ROSMENUITEMINFO ItemInfo
;
1562 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1563 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1565 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
1566 if (MenuInfo
.FocusedItem
!= NO_SELECTED_ITEM
)
1568 MenuInitRosMenuItemInfo(&ItemInfo
);
1569 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1571 ItemInfo
.fMask
|= MIIM_STATE
;
1572 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1573 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1575 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1576 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1579 /* store the owner for DrawItem */
1580 MenuInfo
.WndOwner
= hwndOwner
;
1581 MenuSetRosMenuInfo(&MenuInfo
);
1583 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
1585 /* adjust popup menu pos so that it fits within the desktop */
1587 width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1588 height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1590 /* FIXME: should use item rect */
1593 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
1594 info
.cbSize
= sizeof(info
);
1595 GetMonitorInfoW( monitor
, &info
);
1597 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
1598 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
1600 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
1601 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
1603 if( x
+ width
> info
.rcMonitor
.right
)
1605 if( xanchor
&& x
>= width
- xanchor
)
1606 x
-= width
- xanchor
;
1608 if( x
+ width
> info
.rcMonitor
.right
)
1609 x
= info
.rcMonitor
.right
- width
;
1611 if( x
< info
.rcMonitor
.left
) x
= info
.rcMonitor
.left
;
1613 if( y
+ height
> info
.rcMonitor
.bottom
)
1615 if( yanchor
&& y
>= height
+ yanchor
)
1616 y
-= height
+ yanchor
;
1618 if( y
+ height
> info
.rcMonitor
.bottom
)
1619 y
= info
.rcMonitor
.bottom
- height
;
1621 if( y
< info
.rcMonitor
.top
) y
= info
.rcMonitor
.top
;
1623 /* NOTE: In Windows, top menu popup is not owned. */
1624 MenuInfo
.Wnd
= CreateWindowExW( 0, WC_MENU
, NULL
,
1625 WS_POPUP
, x
, y
, width
, height
,
1626 hwndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
1627 (LPVOID
) MenuInfo
.Self
);
1628 if ( !MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
)) return FALSE
;
1630 top_popup
= MenuInfo
.Wnd
;
1631 top_popup_hmenu
= hmenu
;
1634 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
1636 /* Display the window */
1638 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1639 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1640 UpdateWindow( MenuInfo
.Wnd
);
1645 /***********************************************************************
1648 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
1649 BOOL sendMenuSelect
, HMENU topmenu
)
1651 ROSMENUITEMINFO ItemInfo
;
1652 ROSMENUINFO TopMenuInfo
;
1655 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1657 if (!hmenu
|| !hmenu
->MenuItemCount
|| !hmenu
->Wnd
) return;
1658 if (hmenu
->FocusedItem
== wIndex
) return;
1659 if (hmenu
->Flags
& MF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
1660 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1662 top_popup
= hmenu
->Wnd
;
1663 top_popup_hmenu
= hmenu
->Self
;
1666 SelectObject( hdc
, hMenuFont
);
1668 MenuInitRosMenuItemInfo(&ItemInfo
);
1670 /* Clear previous highlighted item */
1671 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1673 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1675 ItemInfo
.fMask
|= MIIM_STATE
;
1676 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1677 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1679 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
1680 hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1684 /* Highlight new item (if any) */
1685 hmenu
->FocusedItem
= wIndex
;
1686 MenuSetRosMenuInfo(hmenu
);
1687 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1689 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1691 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
1693 ItemInfo
.fMask
|= MIIM_STATE
;
1694 ItemInfo
.fState
|= MF_HILITE
;
1695 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1696 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
1697 &ItemInfo
, hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1702 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1703 MAKELONG(ItemInfo
.fType
& MF_POPUP
? wIndex
: ItemInfo
.wID
,
1704 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
1705 (hmenu
->Flags
& MF_SYSMENU
)), (LPARAM
) hmenu
->Self
);
1709 else if (sendMenuSelect
) {
1712 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
1713 if (pos
!= NO_SELECTED_ITEM
)
1715 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
1716 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
1718 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1719 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
1721 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
1727 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1728 ReleaseDC(hmenu
->Wnd
, hdc
);
1731 /***********************************************************************
1734 * Moves currently selected item according to the Offset parameter.
1735 * If there is no selection then it should select the last item if
1736 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
1738 static void FASTCALL
1739 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
1742 ROSMENUITEMINFO ItemInfo
;
1745 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
1747 /* Prevent looping */
1748 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
1750 else if (Offset
< -1)
1752 else if (Offset
> 1)
1755 MenuInitRosMenuItemInfo(&ItemInfo
);
1757 OrigPos
= MenuInfo
->FocusedItem
;
1758 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
1765 i
= MenuInfo
->FocusedItem
;
1772 /* Clip and wrap around */
1775 i
= MenuInfo
->MenuItemCount
- 1;
1777 else if (i
>= MenuInfo
->MenuItemCount
)
1781 /* If this is a good candidate; */
1782 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1783 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1785 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1786 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1789 } while (i
!= OrigPos
);
1792 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1796 // This breaks some test results. Should handle A2U if called!
1798 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1800 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1804 pWnd
= ValidateHwnd(Wnd
);
1809 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
1818 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*) lParam
;
1819 SetWindowLongPtrA(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1823 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1824 return MA_NOACTIVATE
;
1829 BeginPaint(Wnd
, &ps
);
1830 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrA(Wnd
, 0));
1835 case WM_PRINTCLIENT
:
1837 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1838 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1846 /* zero out global pointer in case resident popup window was destroyed. */
1847 if (Wnd
== top_popup
)
1850 top_popup_hmenu
= NULL
;
1853 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
1860 if (0 == GetWindowLongPtrA(Wnd
, 0))
1862 OutputDebugStringA("no menu to display\n");
1867 SetWindowLongPtrA(Wnd
, 0, 0);
1871 case MM_SETMENUHANDLE
:
1872 SetWindowLongPtrA(Wnd
, 0, wParam
);
1875 case MM_GETMENUHANDLE
:
1877 return GetWindowLongPtrA(Wnd
, 0);
1880 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1886 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1888 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1889 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
1892 pWnd
= ValidateHwnd(Wnd
);
1897 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
1906 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1907 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1911 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1912 return MA_NOACTIVATE
;
1917 BeginPaint(Wnd
, &ps
);
1918 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1923 case WM_PRINTCLIENT
:
1925 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1926 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1934 /* zero out global pointer in case resident popup window was destroyed. */
1935 if (Wnd
== top_popup
)
1938 top_popup_hmenu
= NULL
;
1941 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
1948 if (0 == GetWindowLongPtrW(Wnd
, 0))
1950 OutputDebugStringA("no menu to display\n");
1955 SetWindowLongPtrW(Wnd
, 0, 0);
1959 case MM_SETMENUHANDLE
:
1960 SetWindowLongPtrW(Wnd
, 0, wParam
);
1963 case MM_GETMENUHANDLE
:
1965 return GetWindowLongPtrW(Wnd
, 0);
1968 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1974 /**********************************************************************
1975 * MENU_ParseResource
1977 * Parse a standard menu resource and add items to the menu.
1978 * Return a pointer to the end of the resource.
1980 * NOTE: flags is equivalent to the mtOption field
1982 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1991 flags
= GET_WORD(res
);
1993 /* remove MF_END flag before passing it to AppendMenu()! */
1994 end
= (flags
& MF_END
);
1995 if(end
) flags
^= MF_END
;
1997 res
+= sizeof(WORD
);
1998 if(!(flags
& MF_POPUP
))
2001 res
+= sizeof(WORD
);
2005 res
+= strlen(str
) + 1;
2007 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
2008 if (flags
& MF_POPUP
)
2010 hSubMenu
= CreatePopupMenu();
2011 if(!hSubMenu
) return NULL
;
2012 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
2015 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
2017 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
2019 else /* Not a popup */
2024 flags
= MF_SEPARATOR
;
2028 if (*(LPCWSTR
)str
== 0)
2029 flags
= MF_SEPARATOR
;
2032 if (flags
& MF_SEPARATOR
)
2034 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
2035 flags
|= MF_GRAYED
| MF_DISABLED
;
2039 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
2041 AppendMenuW(hMenu
, flags
, id
,
2042 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2049 /**********************************************************************
2050 * MENUEX_ParseResource
2052 * Parse an extended menu resource and add items to the menu.
2053 * Return a pointer to the end of the resource.
2055 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
2061 mii
.cbSize
= sizeof(mii
);
2062 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
2063 mii
.fType
= GET_DWORD(res
);
2064 res
+= sizeof(DWORD
);
2065 mii
.fState
= GET_DWORD(res
);
2066 res
+= sizeof(DWORD
);
2067 mii
.wID
= GET_DWORD(res
);
2068 res
+= sizeof(DWORD
);
2069 resinfo
= GET_WORD(res
);
2070 res
+= sizeof(WORD
);
2071 /* Align the text on a word boundary. */
2072 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2073 mii
.dwTypeData
= (LPWSTR
) res
;
2074 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2075 /* Align the following fields on a dword boundary. */
2076 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2078 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2079 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2081 if (resinfo
& 1) { /* Pop-up? */
2082 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2083 res
+= sizeof(DWORD
);
2084 mii
.hSubMenu
= CreatePopupMenu();
2087 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
2088 DestroyMenu(mii
.hSubMenu
);
2091 mii
.fMask
|= MIIM_SUBMENU
;
2092 mii
.fType
|= MF_POPUP
;
2093 mii
.wID
= (UINT
) mii
.hSubMenu
;
2095 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
2097 mii
.fType
|= MF_SEPARATOR
;
2099 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2100 } while (!(resinfo
& MF_END
));
2105 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
2107 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
2108 LRESULT Result
= (LRESULT
)hmenu
;
2109 MENUINFO menuinfo
= {0};
2110 MENUITEMINFOW info
= {0};
2112 // removing space for checkboxes from menu
2113 menuinfo
.cbSize
= sizeof(menuinfo
);
2114 menuinfo
.fMask
= MIM_STYLE
;
2115 GetMenuInfo(hmenu
, &menuinfo
);
2116 menuinfo
.dwStyle
|= MNS_NOCHECK
;
2117 SetMenuInfo(hmenu
, &menuinfo
);
2119 // adding bitmaps to menu items
2120 info
.cbSize
= sizeof(info
);
2121 info
.fMask
|= MIIM_BITMAP
;
2122 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
2123 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
2124 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
2125 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
2126 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
2127 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
2128 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
2129 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
2131 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
2138 NONCLIENTMETRICSW ncm
;
2140 /* get the menu font */
2141 if(!hMenuFont
|| !hMenuFontBold
)
2143 ncm
.cbSize
= sizeof(ncm
);
2144 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
2146 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
2150 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2151 if(hMenuFont
== NULL
)
2153 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
2157 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
2158 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2159 if(hMenuFontBold
== NULL
)
2161 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
2162 DeleteObject(hMenuFont
);
2176 DeleteObject(hMenuFont
);
2182 DeleteObject(hMenuFontBold
);
2183 hMenuFontBold
= NULL
;
2187 /***********************************************************************
2188 * DrawMenuBarTemp (USER32.@)
2192 * called by W98SE desk.cpl Control Panel Applet
2194 * Not 100% sure about the param names, but close.
2199 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2201 ROSMENUINFO MenuInfo
;
2202 ROSMENUITEMINFO ItemInfo
;
2204 HFONT FontOld
= NULL
;
2205 BOOL flat_menu
= FALSE
;
2207 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2211 Menu
= GetMenu(Wnd
);
2219 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2221 return GetSystemMetrics(SM_CYMENU
);
2224 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2226 FontOld
= SelectObject(DC
, Font
);
2228 if (0 == MenuInfo
.Height
)
2230 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2233 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
2235 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2237 SelectObject(DC
, GetStockObject(DC_PEN
));
2238 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2239 MoveToEx(DC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2240 LineTo(DC
, Rect
->right
, Rect
->bottom
- 1);
2242 if (0 == MenuInfo
.MenuItemCount
)
2244 SelectObject(DC
, FontOld
);
2245 return GetSystemMetrics(SM_CYMENU
);
2248 MenuInitRosMenuItemInfo(&ItemInfo
);
2249 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2251 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2253 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2254 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
2257 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2259 SelectObject(DC
, FontOld
);
2261 return MenuInfo
.Height
;
2264 /***********************************************************************
2267 * Display the sub-menu of the selected item of this menu.
2268 * Return the handle of the submenu, or menu if no submenu to display.
2270 static HMENU FASTCALL
2271 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2273 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2275 ROSMENUITEMINFO ItemInfo
;
2276 ROSMENUINFO SubMenuInfo
;
2280 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2282 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2284 return MenuInfo
->Self
;
2287 MenuInitRosMenuItemInfo(&ItemInfo
);
2288 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2290 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2291 return MenuInfo
->Self
;
2293 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2295 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2296 return MenuInfo
->Self
;
2299 /* message must be sent before using item,
2300 because nearly everything may be changed by the application ! */
2302 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2303 if (0 == (Flags
& TPM_NONOTIFY
))
2305 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2306 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2309 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2311 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2312 return MenuInfo
->Self
;
2314 Rect
= ItemInfo
.Rect
;
2316 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2317 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2319 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2321 Dc
= GetDC(MenuInfo
->Wnd
);
2325 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2328 SelectObject(Dc
, hMenuFont
);
2329 ItemInfo
.fMask
|= MIIM_STATE
;
2330 ItemInfo
.fState
|= MF_HILITE
;
2331 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2332 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2333 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2334 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2337 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2338 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2340 ItemInfo
.Rect
= Rect
;
2343 ItemInfo
.fMask
|= MIIM_STATE
;
2344 ItemInfo
.fState
|= MF_MOUSESELECT
;
2345 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2347 if (IS_SYSTEM_MENU(MenuInfo
))
2349 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2350 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2352 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2353 Rect
.top
= Rect
.bottom
;
2354 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2355 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2359 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2360 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2362 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2363 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2364 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2365 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2366 - GetSystemMetrics(SM_CYBORDER
);
2370 Rect
.left
+= ItemInfo
.Rect
.left
;
2371 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2372 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2373 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2377 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
, Flags
,
2378 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2379 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2381 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2384 Ret
= ItemInfo
.hSubMenu
;
2385 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2390 /**********************************************************************
2393 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2395 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2397 void MENU_EndMenu( HWND hwnd
)
2399 ROSMENUINFO MenuInfo
;
2401 if (top_popup_hmenu
)
2402 Ret
= MenuGetRosMenuInfo(&MenuInfo
, top_popup_hmenu
);
2403 if (Ret
&& hwnd
== MenuInfo
.WndOwner
) EndMenu();
2406 /***********************************************************************
2409 * Hide the sub-popup menus of this menu.
2411 static void FASTCALL
2412 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2413 BOOL SendMenuSelect
, UINT wFlags
)
2415 ROSMENUINFO SubMenuInfo
;
2416 ROSMENUITEMINFO ItemInfo
;
2418 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2420 if (NULL
!= MenuInfo
&& NULL
!= top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2422 MenuInitRosMenuItemInfo(&ItemInfo
);
2423 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2424 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2425 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2426 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2428 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2431 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2432 ItemInfo
.fMask
|= MIIM_STATE
;
2433 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2434 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2436 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2437 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2438 DestroyWindow(SubMenuInfo
.Wnd
);
2439 SubMenuInfo
.Wnd
= NULL
;
2440 MenuSetRosMenuInfo(&SubMenuInfo
);
2442 if (!(wFlags
& TPM_NONOTIFY
))
2443 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
2444 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
2449 /***********************************************************************
2450 * MenuSwitchTracking
2452 * Helper function for menu navigation routines.
2454 static void FASTCALL
2455 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
2457 ROSMENUINFO TopMenuInfo
;
2459 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2461 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2462 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2463 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2465 /* both are top level menus (system and menu-bar) */
2466 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2467 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2468 Mt
->TopMenu
= PtMenuInfo
->Self
;
2472 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
2475 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2478 /***********************************************************************
2479 * MenuExecFocusedItem
2481 * Execute a menu item (for instance when user pressed Enter).
2482 * Return the wID of the executed item. Otherwise, -1 indicating
2483 * that no menu item was executed, -2 if a popup is shown;
2484 * Have to receive the flags for the TrackPopupMenu options to avoid
2485 * sending unwanted message.
2489 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2491 ROSMENUITEMINFO ItemInfo
;
2494 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2496 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2501 MenuInitRosMenuItemInfo(&ItemInfo
);
2502 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2504 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2508 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2510 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2512 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2513 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2515 /* If TPM_RETURNCMD is set you return the id, but
2516 do not send a message to the owner */
2517 if (0 == (Flags
& TPM_RETURNCMD
))
2519 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2521 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2522 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2526 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2527 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2528 MenuInfo
->FocusedItem
,
2529 (LPARAM
)MenuInfo
->Self
);
2531 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2535 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2541 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2548 /***********************************************************************
2551 * Return TRUE if we can go on with menu tracking.
2553 static BOOL FASTCALL
2554 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2557 ROSMENUINFO MenuInfo
;
2558 ROSMENUITEMINFO Item
;
2560 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2564 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2568 if (IS_SYSTEM_MENU(&MenuInfo
))
2574 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2576 MenuInitRosMenuItemInfo(&Item
);
2577 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2579 MenuCleanupRosMenuItemInfo(&Item
);
2583 if (!(Item
.fType
& MF_SEPARATOR
) &&
2584 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2586 if (MenuInfo
.FocusedItem
!= Index
)
2588 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2591 /* If the popup menu is not already "popped" */
2592 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2594 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2598 MenuCleanupRosMenuItemInfo(&Item
);
2603 /* else the click was on the menu bar, finish the tracking */
2608 /***********************************************************************
2611 * Return the value of MenuExecFocusedItem if
2612 * the selected item was not a popup. Else open the popup.
2613 * A -1 return value indicates that we go on with menu tracking.
2617 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2620 ROSMENUINFO MenuInfo
;
2621 ROSMENUITEMINFO ItemInfo
;
2623 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2628 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2633 if (! IS_SYSTEM_MENU(&MenuInfo
))
2635 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2637 MenuInitRosMenuItemInfo(&ItemInfo
);
2638 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2639 MenuInfo
.FocusedItem
== Id
)
2641 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2643 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2644 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2645 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2647 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2649 /* If we are dealing with the top-level menu */
2650 /* and this is a click on an already "popped" item: */
2651 /* Stop the menu tracking and close the opened submenus */
2652 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2654 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2658 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2659 MenuInfo
.TimeToHide
= TRUE
;
2660 MenuSetRosMenuInfo(&MenuInfo
);
2666 /***********************************************************************
2669 * Walks menu chain trying to find a menu pt maps to.
2671 static HMENU FASTCALL
2672 MenuPtMenu(HMENU Menu
, POINT Pt
)
2674 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2675 ROSMENUINFO MenuInfo
;
2676 ROSMENUITEMINFO ItemInfo
;
2680 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2685 /* try subpopup first (if any) */
2686 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2688 MenuInitRosMenuItemInfo(&ItemInfo
);
2689 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2690 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2691 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2693 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2696 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2700 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2703 /* check the current window (avoiding WM_HITTEST) */
2704 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2705 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2707 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2712 else if (HTSYSMENU
== Ht
)
2714 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2716 else if (HTMENU
== Ht
)
2718 Ret
= GetMenu(MenuInfo
.Wnd
);
2724 /***********************************************************************
2727 * Return TRUE if we can go on with menu tracking.
2729 static BOOL FASTCALL
2730 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2733 ROSMENUINFO MenuInfo
;
2734 ROSMENUITEMINFO ItemInfo
;
2738 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2742 if (IS_SYSTEM_MENU(&MenuInfo
))
2748 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2753 Index
= NO_SELECTED_ITEM
;
2756 if (NO_SELECTED_ITEM
== Index
)
2758 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2759 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2761 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2765 else if (MenuInfo
.FocusedItem
!= Index
)
2767 MenuInitRosMenuItemInfo(&ItemInfo
);
2768 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2769 !(ItemInfo
.fType
& MF_SEPARATOR
))
2771 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2772 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2773 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2775 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2781 /***********************************************************************
2784 * Return the handle of the selected sub-popup menu (if any).
2786 static HMENU FASTCALL
2787 MenuGetSubPopup(HMENU Menu
)
2789 ROSMENUINFO MenuInfo
;
2790 ROSMENUITEMINFO ItemInfo
;
2792 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2793 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2798 MenuInitRosMenuItemInfo(&ItemInfo
);
2799 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2801 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2804 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2806 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2807 return ItemInfo
.hSubMenu
;
2810 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2814 /***********************************************************************
2817 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2819 static LRESULT FASTCALL
2820 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
, UINT wFlags
)
2822 ROSMENUINFO TopMenuInfo
;
2823 ROSMENUINFO MenuInfo
;
2825 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2827 return (LRESULT
) FALSE
;
2830 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2831 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2833 MDINEXTMENU NextMenu
;
2838 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2839 NextMenu
.hmenuNext
= NULL
;
2840 NextMenu
.hwndNext
= NULL
;
2841 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2843 TRACE("%p [%p] -> %p [%p]\n",
2844 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2846 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2848 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2849 NewWnd
= Mt
->OwnerWnd
;
2850 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2852 /* switch to the menu bar */
2854 if (0 != (Style
& WS_CHILD
)
2855 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2862 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2866 Id
= MenuInfo
.MenuItemCount
- 1;
2869 else if (0 != (Style
& WS_SYSMENU
))
2871 /* switch to the system menu */
2872 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2879 else /* application returned a new menu to switch to */
2881 NewMenu
= NextMenu
.hmenuNext
;
2882 NewWnd
= NextMenu
.hwndNext
;
2884 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2886 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2888 if (0 != (Style
& WS_SYSMENU
)
2889 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2891 /* get the real system menu */
2892 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2894 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2896 /* FIXME: Not sure what to do here;
2897 * perhaps try to track NewMenu as a popup? */
2899 WARN(" -- got confused.\n");
2909 if (NewMenu
!= Mt
->TopMenu
)
2911 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2913 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2915 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2919 if (NewWnd
!= Mt
->OwnerWnd
)
2921 Mt
->OwnerWnd
= NewWnd
;
2922 SetCapture(Mt
->OwnerWnd
);
2923 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
);
2926 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2927 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2929 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2938 /***********************************************************************
2941 * The idea is not to show the popup if the next input message is
2942 * going to hide it anyway.
2944 static BOOL FASTCALL
2945 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
2949 Msg
.hwnd
= Mt
->OwnerWnd
;
2951 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2952 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
2957 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2958 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
2960 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2961 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2962 if (WM_KEYDOWN
== Msg
.message
2963 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
2965 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2972 /* failures go through this */
2973 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
2978 /***********************************************************************
2981 * Handle a VK_ESCAPE key event in a menu.
2983 static BOOL FASTCALL
2984 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
2986 BOOL EndMenu
= TRUE
;
2987 ROSMENUINFO MenuInfo
;
2988 HMENU MenuTmp
, MenuPrev
;
2990 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2992 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
2993 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
2995 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2997 /* close topmost popup */
2998 while (MenuTmp
!= Mt
->CurrentMenu
)
3001 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3004 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3006 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
3008 Mt
->CurrentMenu
= MenuPrev
;
3016 /***********************************************************************
3019 * Handle a VK_LEFT key event in a menu.
3021 static void FASTCALL
3022 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3024 ROSMENUINFO MenuInfo
;
3025 ROSMENUINFO TopMenuInfo
;
3026 ROSMENUINFO PrevMenuInfo
;
3027 HMENU MenuTmp
, MenuPrev
;
3030 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3032 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3037 /* Try to move 1 column left (if possible) */
3038 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
3040 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3042 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3047 /* close topmost popup */
3048 while (MenuTmp
!= Mt
->CurrentMenu
)
3051 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3054 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3058 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3059 Mt
->CurrentMenu
= MenuPrev
;
3061 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3065 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
3067 /* move menu bar selection if no more popups are left */
3069 if (! MenuDoNextMenu(Mt
, VK_LEFT
, Flags
))
3071 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3074 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3076 /* A sublevel menu was displayed - display the next one
3077 * unless there is another displacement coming up */
3079 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3080 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3082 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3089 /***********************************************************************
3092 * Handle a VK_RIGHT key event in a menu.
3094 static void FASTCALL
MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3097 ROSMENUINFO MenuInfo
;
3098 ROSMENUINFO CurrentMenuInfo
;
3101 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3102 Mt
->CurrentMenu
, Mt
->TopMenu
);
3104 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
)) return;
3105 if ((MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3107 /* If already displaying a popup, try to display sub-popup */
3109 hmenutmp
= Mt
->CurrentMenu
;
3110 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3112 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3115 /* if subpopup was displayed then we are done */
3116 if (hmenutmp
!= Mt
->CurrentMenu
) return;
3119 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3124 /* Check to see if there's another column */
3125 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
3127 TRACE("Going to %d.\n", NextCol
);
3128 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3130 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3135 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3137 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3139 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
3140 hmenutmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3147 /* try to move to the next item */
3148 if ( !MenuDoNextMenu(Mt
, VK_RIGHT
, Flags
))
3149 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3151 if ( hmenutmp
|| Mt
->TrackFlags
& TF_SUSPENDPOPUP
)
3153 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3154 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3156 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3163 /***********************************************************************
3166 * Menu tracking code.
3168 static INT FASTCALL
MenuTrackMenu(HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
3169 HWND hwnd
, const RECT
*lprect
)
3172 ROSMENUINFO MenuInfo
;
3173 ROSMENUITEMINFO ItemInfo
;
3175 INT executedMenuId
= -1;
3177 BOOL enterIdleSent
= FALSE
;
3180 mt
.CurrentMenu
= hmenu
;
3186 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
3187 hmenu
, wFlags
, x
, y
, hwnd
, lprect
? lprect
->left
: 0, lprect
? lprect
->top
: 0,
3188 lprect
? lprect
->right
: 0, lprect
? lprect
->bottom
: 0);
3192 WARN("Invalid menu handle %p\n", hmenu
);
3193 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3198 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
))
3203 if (wFlags
& TPM_BUTTONDOWN
)
3205 /* Get the result in order to start the tracking or not */
3206 fRemove
= MenuButtonDown( &mt
, hmenu
, wFlags
);
3207 fEndMenu
= !fRemove
;
3210 SetCapture(mt
.OwnerWnd
);
3211 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, mt
.OwnerWnd
);
3213 FIXME("MenuTrackMenu 1\n");
3216 PVOID menu
= ValidateHandle(mt
.CurrentMenu
, VALIDATE_TYPE_MENU
);
3217 if (!menu
) /* sometimes happens if I do a window manager close */
3220 /* we have to keep the message in the queue until it's
3221 * clear that menu loop is not over yet. */
3225 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3227 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3228 /* remove the message from the queue */
3229 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3235 HWND win
= MenuInfo
.Flags
& MF_POPUP
? MenuInfo
.Wnd
: NULL
;
3236 enterIdleSent
= TRUE
;
3237 SendMessageW( mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) win
);
3241 //FIXME("MenuTrackMenu loop 1\n");
3244 /* check if EndMenu() tried to cancel us, by posting this message */
3245 if (msg
.message
== WM_CANCELMODE
)
3247 /* we are now out of the loop */
3250 /* remove the message from the queue */
3251 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3253 /* break out of internal loop, ala ESCAPE */
3257 TranslateMessage( &msg
);
3260 if ( (msg
.hwnd
== MenuInfo
.Wnd
) || (msg
.message
!=WM_TIMER
) )
3261 enterIdleSent
=FALSE
;
3264 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3267 * Use the mouse coordinates in lParam instead of those in the MSG
3268 * struct to properly handle synthetic messages. They are already
3269 * in screen coordinates.
3271 mt
.Pt
.x
= (short)LOWORD(msg
.lParam
);
3272 mt
.Pt
.y
= (short)HIWORD(msg
.lParam
);
3274 /* Find a menu for this mouse event */
3275 hmenu
= MenuPtMenu(mt
.TopMenu
, mt
.Pt
);
3279 /* no WM_NC... messages in captured state */
3281 case WM_RBUTTONDBLCLK
:
3282 case WM_RBUTTONDOWN
:
3283 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3285 case WM_LBUTTONDBLCLK
:
3286 case WM_LBUTTONDOWN
:
3287 /* If the message belongs to the menu, removes it from the queue */
3288 /* Else, end menu tracking */
3289 fRemove
= MenuButtonDown(&mt
, hmenu
, wFlags
);
3290 fEndMenu
= !fRemove
;
3294 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3297 /* Check if a menu was selected by the mouse */
3300 executedMenuId
= MenuButtonUp( &mt
, hmenu
, wFlags
);
3301 TRACE("executedMenuId %d\n", executedMenuId
);
3303 /* End the loop if executedMenuId is an item ID */
3304 /* or if the job was done (executedMenuId = 0). */
3305 fEndMenu
= fRemove
= (executedMenuId
!= -1);
3307 /* No menu was selected by the mouse */
3308 /* if the function was called by TrackPopupMenu, continue
3309 with the menu tracking. If not, stop it */
3311 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3316 /* the selected menu item must be changed every time */
3317 /* the mouse moves. */
3320 fEndMenu
|= !MenuMouseMove( &mt
, hmenu
, wFlags
);
3322 } /* switch(msg.message) - mouse */
3324 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
3326 fRemove
= TRUE
; /* Keyboard messages are always removed */
3340 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3342 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
,
3343 NO_SELECTED_ITEM
, FALSE
, 0 );
3344 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3345 VK_HOME
== msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3350 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3351 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3353 if (!(MenuInfo
.Flags
& MF_POPUP
))
3355 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3356 mt
.CurrentMenu
= MenuShowSubPopup(mt
.OwnerWnd
, &MenuInfo
, TRUE
, wFlags
);
3358 else /* otherwise try to move selection */
3359 MenuMoveSelection(mt
.OwnerWnd
, &MenuInfo
,
3360 (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
3365 MenuKeyLeft( &mt
, wFlags
);
3369 MenuKeyRight( &mt
, wFlags
);
3373 fEndMenu
= MenuKeyEscape(&mt
, wFlags
);
3379 hi
.cbSize
= sizeof(HELPINFO
);
3380 hi
.iContextType
= HELPINFO_MENUITEM
;
3381 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
))
3383 if (MenuInfo
.FocusedItem
== NO_SELECTED_ITEM
)
3387 MenuInitRosMenuItemInfo(&ItemInfo
);
3388 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3389 MenuInfo
.FocusedItem
,
3392 hi
.iCtrlId
= ItemInfo
.wID
;
3398 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3401 hi
.hItemHandle
= hmenu
;
3402 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3403 hi
.MousePos
= msg
.pt
;
3404 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
3411 break; /* WM_KEYDOWN */
3418 if (! MenuGetRosMenuInfo(&MenuInfo
, mt
.CurrentMenu
)) break;
3419 if (msg
.wParam
== L
'\r' || msg
.wParam
== L
' ')
3421 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3422 fEndMenu
= (executedMenuId
!= -2);
3426 /* Hack to avoid control chars. */
3427 /* We will find a better way real soon... */
3428 if (msg
.wParam
< 32) break;
3430 pos
= MenuFindItemByKey(mt
.OwnerWnd
, &MenuInfo
,
3431 LOWORD(msg
.wParam
), FALSE
);
3432 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
3433 else if (pos
== (UINT
)-1) MessageBeep(0);
3436 MenuSelectItem(mt
.OwnerWnd
, &MenuInfo
, pos
,
3438 executedMenuId
= MenuExecFocusedItem(&mt
, &MenuInfo
, wFlags
);
3439 fEndMenu
= (executedMenuId
!= -2);
3443 } /* switch(msg.message) - kbd */
3447 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3448 DispatchMessageW( &msg
);
3449 //FIXME("MenuTrackMenu loop 2\n");
3453 if (!fEndMenu
) fRemove
= TRUE
;
3455 /* finally remove message from the queue */
3457 if (fRemove
&& !(mt
.TrackFlags
& TF_SKIPREMOVE
) )
3458 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3459 else mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3460 //FIXME("MenuTrackMenu loop 3\n");
3462 FIXME("MenuTrackMenu 2\n");
3464 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3465 SetCapture(NULL
); /* release the capture */
3467 /* If dropdown is still painted and the close box is clicked on
3468 then the menu will be destroyed as part of the DispatchMessage above.
3469 This will then invalidate the menu handle in mt.hTopMenu. We should
3470 check for this first. */
3471 if( IsMenu( mt
.TopMenu
) )
3473 if (IsWindow(mt
.OwnerWnd
))
3475 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3477 MenuHideSubPopups(mt
.OwnerWnd
, &MenuInfo
, FALSE
, wFlags
);
3479 if (MenuInfo
.Flags
& MF_POPUP
)
3481 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
3482 DestroyWindow(MenuInfo
.Wnd
);
3483 MenuInfo
.Wnd
= NULL
;
3485 if (!(MenuInfo
.Flags
& TPM_NONOTIFY
))
3486 SendMessageW( mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.TopMenu
,
3487 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
3490 MenuSelectItem( mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, 0 );
3493 SendMessageW( mt
.OwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0, 0xffff), 0 );
3496 /* Reset the variable for hiding menu */
3497 if (MenuGetRosMenuInfo(&MenuInfo
, mt
.TopMenu
))
3499 MenuInfo
.TimeToHide
= FALSE
;
3500 MenuSetRosMenuInfo(&MenuInfo
);
3504 /* The return value is only used by TrackPopupMenu */
3505 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
3506 if (executedMenuId
== -1) executedMenuId
= 0;
3507 return executedMenuId
;
3510 /***********************************************************************
3513 static BOOL FASTCALL
MenuInitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
3515 ROSMENUINFO MenuInfo
;
3517 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
3521 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
3522 /* This makes the menus of applications built with Delphi work.
3523 * It also enables menus to be displayed in more than one window,
3524 * but there are some bugs left that need to be fixed in this case.
3526 if(MenuInfo
.Self
== hMenu
)
3528 MenuInfo
.Wnd
= hWnd
;
3529 MenuSetRosMenuInfo(&MenuInfo
);
3532 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3533 if (!(wFlags
& TPM_NONOTIFY
))
3534 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
3536 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
3538 if (!(wFlags
& TPM_NONOTIFY
))
3540 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
3541 /* If an app changed/recreated menu bar entries in WM_INITMENU
3542 * menu sizes will be recalculated once the menu created/shown.
3545 if (!MenuInfo
.Height
)
3547 /* app changed/recreated menu bar entries in WM_INITMENU
3548 Recalculate menu sizes else clicks will not work */
3549 SetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3550 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3555 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART
,
3557 MenuInfo
.Flags
& MF_SYSMENU
? OBJID_SYSMENU
: OBJID_MENU
,
3561 /***********************************************************************
3564 static BOOL FASTCALL
MenuExitTracking(HWND hWnd
, BOOL bPopup
)
3566 TRACE("hwnd=%p\n", hWnd
);
3568 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND
, hWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
3569 SendMessageW( hWnd
, WM_EXITMENULOOP
, bPopup
, 0 );
3572 top_popup_hmenu
= NULL
;
3576 /***********************************************************************
3577 * MenuTrackMouseMenuBar
3579 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3581 VOID
MenuTrackMouseMenuBar( HWND hWnd
, ULONG ht
, POINT pt
)
3583 HMENU hMenu
= (ht
== HTSYSMENU
) ? NtUserGetSystemMenu( hWnd
, FALSE
) : GetMenu(hWnd
);
3584 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3586 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
3590 /* map point to parent client coordinates */
3591 HWND Parent
= GetAncestor(hWnd
, GA_PARENT
);
3592 if (Parent
!= GetDesktopWindow())
3594 ScreenToClient(Parent
, &pt
);
3597 MenuInitTracking(hWnd
, hMenu
, FALSE
, wFlags
);
3598 MenuTrackMenu(hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
3599 MenuExitTracking(hWnd
, FALSE
);
3604 /***********************************************************************
3605 * MenuTrackKbdMenuBar
3607 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3609 VOID
MenuTrackKbdMenuBar(HWND hwnd
, UINT wParam
, WCHAR wChar
)
3611 UINT uItem
= NO_SELECTED_ITEM
;
3613 ROSMENUINFO MenuInfo
;
3614 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3616 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
3618 /* find window that has a menu */
3620 while (!((GetWindowLongPtrW( hwnd
, GWL_STYLE
) &
3621 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3622 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
3624 /* check if we have to track a system menu */
3626 hTrackMenu
= GetMenu( hwnd
);
3627 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
3629 if (!(GetWindowLongPtrW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3630 hTrackMenu
= NtUserGetSystemMenu(hwnd
, FALSE
);
3632 wParam
|= HTSYSMENU
; /* prevent item lookup */
3635 if (!IsMenu( hTrackMenu
)) return;
3637 MenuInitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
3639 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3644 if( wChar
&& wChar
!= ' ' )
3646 uItem
= MenuFindItemByKey( hwnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3647 if ( uItem
>= (UINT
)(-2) )
3649 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3650 /* schedule end of menu tracking */
3651 wFlags
|= TF_ENDMENU
;
3656 MenuSelectItem( hwnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3658 if (wParam
& HTSYSMENU
)
3660 /* prevent sysmenu activation for managed windows on Alt down/up */
3661 // if (GetPropA( hwnd, "__wine_x11_managed" ))
3662 wFlags
|= TF_ENDMENU
; /* schedule end of menu tracking */
3666 if( uItem
== NO_SELECTED_ITEM
)
3667 MenuMoveSelection( hwnd
, &MenuInfo
, ITEM_NEXT
);
3669 PostMessageW( hwnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3673 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
3674 MenuExitTracking( hwnd
, FALSE
);
3678 /**********************************************************************
3679 * TrackPopupMenuEx (USER32.@)
3681 BOOL WINAPI
TrackPopupMenuEx( HMENU Menu
, UINT Flags
, int x
, int y
,
3682 HWND Wnd
, LPTPMPARAMS Tpm
)
3685 ROSMENUINFO MenuInfo
;
3689 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3693 MenuGetRosMenuInfo(&MenuInfo
, Menu
);
3694 if (IsWindow(MenuInfo
.Wnd
))
3696 SetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
3700 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
3702 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3703 if (!(Flags
& TPM_NONOTIFY
))
3704 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
3706 if (MenuShowPopup(Wnd
, Menu
, 0, Flags
, x
, y
, 0, 0 ))
3707 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
,
3708 Tpm
? &Tpm
->rcExclude
: NULL
);
3709 MenuExitTracking(Wnd
, TRUE
);
3713 /**********************************************************************
3714 * TrackPopupMenu (USER32.@)
3716 BOOL WINAPI
TrackPopupMenu( HMENU Menu
, UINT Flags
, int x
, int y
,
3717 int Reserved
, HWND Wnd
, CONST RECT
*Rect
)
3719 return TrackPopupMenuEx( Menu
, Flags
, x
, y
, Wnd
, NULL
);
3724 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3725 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3727 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3729 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3730 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3731 * MFT_STRING is replaced by MIIM_STRING.
3732 * (So, I guess we should use MIIM_STRING only for strings?)
3734 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3736 * Based on wine, SetMenuItemInfo_common:
3737 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3738 * it will result in a error.
3739 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3740 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3747 LPMENUITEMINFOW mii
,
3754 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3756 if(Flags
& MF_BITMAP
)
3758 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3759 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3761 if (Flags
& MF_HELP
)
3763 /* increase ident */
3764 mii
->fType
|= MF_HELP
;
3767 else if(Flags
& MF_OWNERDRAW
)
3769 mii
->fType
|= MFT_OWNERDRAW
;
3770 mii
->fMask
|= MIIM_DATA
;
3771 mii
->dwItemData
= (DWORD_PTR
) NewItem
;
3773 else if (Flags
& MF_SEPARATOR
)
3775 mii
->fType
|= MFT_SEPARATOR
;
3776 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3777 Flags
|= MF_GRAYED
|MF_DISABLED
;
3779 else /* Default action MF_STRING. */
3781 /* Item beginning with a backspace is a help item */
3782 if (NewItem
!= NULL
)
3786 if (*NewItem
== '\b')
3788 mii
->fType
|= MF_HELP
;
3794 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3795 if (*NewItemA
== '\b')
3797 mii
->fType
|= MF_HELP
;
3799 NewItem
= (LPCWSTR
) NewItemA
;
3803 if (Flags
& MF_HELP
)
3804 mii
->fType
|= MF_HELP
;
3805 mii
->fMask
|= MIIM_STRING
;
3806 mii
->fType
|= MFT_STRING
; /* Zero */
3807 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3809 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3811 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3815 mii
->fType
|= MFT_SEPARATOR
;
3816 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3817 Flags
|= MF_GRAYED
|MF_DISABLED
;
3821 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3823 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3826 if(Flags
& MF_MENUBREAK
)
3828 mii
->fType
|= MFT_MENUBREAK
;
3830 else if(Flags
& MF_MENUBARBREAK
)
3832 mii
->fType
|= MFT_MENUBARBREAK
;
3835 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3837 if (Flags
& MF_GRAYED
)
3838 mii
->fState
|= MF_GRAYED
;
3840 if (Flags
& MF_DISABLED
)
3841 mii
->fState
|= MF_DISABLED
;
3843 mii
->fMask
|= MIIM_STATE
;
3845 else if (Flags
& MF_HILITE
)
3847 mii
->fState
|= MF_HILITE
;
3848 mii
->fMask
|= MIIM_STATE
;
3850 else /* default state */
3852 mii
->fState
|= MFS_ENABLED
;
3853 mii
->fMask
|= MIIM_STATE
;
3856 if(Flags
& MF_POPUP
)
3858 mii
->fType
|= MF_POPUP
;
3859 mii
->fMask
|= MIIM_SUBMENU
;
3860 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3864 mii
->fMask
|= MIIM_ID
;
3865 mii
->wID
= (UINT
)IDNewItem
;
3871 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
3873 PLOADMENU_CALLBACK_ARGUMENTS Common
;
3876 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
3878 Result
= (LRESULT
)LoadMenuW( Common
->hModule
,
3879 IS_INTRESOURCE(Common
->MenuName
[0]) ?
3880 MAKEINTRESOURCE(Common
->MenuName
[0]) :
3881 (LPCWSTR
)&Common
->MenuName
);
3883 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
3887 /* FUNCTIONS *****************************************************************/
3890 MenuIsStringItem(ULONG TypeData)
3892 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3900 AppendMenuA(HMENU hMenu
,
3902 UINT_PTR uIDNewItem
,
3905 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3914 AppendMenuW(HMENU hMenu
,
3916 UINT_PTR uIDNewItem
,
3919 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3928 CheckMenuItem(HMENU hmenu
,
3932 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3937 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
3940 PROSMENUITEMINFO Items
= NULL
;
3941 UINT cChecked
, cUnchecked
;
3945 if(idFirst
> idLast
)
3948 ItemCount
= GetMenuItemCount(hMenu
);
3950 //mi.cbSize = sizeof(ROSMENUINFO);
3951 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
3954 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
3956 ERR("MenuGetAllRosMenuItemInfo failed\n");
3960 cChecked
= cUnchecked
= 0;
3962 for (i
= 0 ; i
< ItemCount
; i
++)
3965 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
3966 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
3968 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
3970 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
3973 if (uFlags
& MF_BYPOSITION
)
3975 if (i
< idFirst
|| i
> idLast
)
3990 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
3993 if (Items
[i
].wID
== idCheck
)
4007 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
4010 Items
[i
].fType
|= MFT_RADIOCHECK
;
4011 Items
[i
].fState
|= MFS_CHECKED
;
4015 Items
[i
].fState
&= ~MFS_CHECKED
;
4018 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
4020 ERR("MenuSetRosMenuItemInfo failed\n");
4025 HeapFree(GetProcessHeap(), 0, Items
);
4027 *pChecked
+= cChecked
;
4028 *pUnchecked
+= cUnchecked
;
4030 if (cChecked
|| cUnchecked
)
4040 CheckMenuRadioItem(HMENU hmenu
,
4047 UINT cUnchecked
= 0;
4048 UINT cMenuChanged
= 0;
4050 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4053 if (cMenuChanged
> 1)
4060 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4063 return (cChecked
!= 0);
4074 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENU
);
4082 CreatePopupMenu(VOID
)
4085 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENUPOPUP
);
4093 DrawMenuBar(HWND hWnd
)
4095 // return (BOOL)NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_DRAWMENUBAR);
4096 ROSMENUINFO MenuInfo
;
4098 hMenu
= GetMenu(hWnd
);
4101 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4102 MenuInfo
.Height
= 0; // make sure to recalc size
4103 MenuSetRosMenuInfo(&MenuInfo
);
4105 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4106 SWP_NOZORDER
| SWP_FRAMECHANGED
);
4114 EnableMenuItem(HMENU hMenu
,
4118 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4128 guii
.cbSize
= sizeof(GUITHREADINFO
);
4129 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4133 guii
.hwndMenuOwner
!= top_popup
)
4135 ERR("Capture GUI pti hWnd does not match top_popup!\n");
4139 /* if we are in the menu code, and it is active */
4140 if (!fEndMenu
&& top_popup
)
4142 /* terminate the menu handling code */
4145 /* needs to be posted to wakeup the internal menu handler */
4146 /* which will now terminate the menu, in the event that */
4147 /* the main window was minimized, or lost focus, so we */
4148 /* don't end up with an orphaned menu */
4149 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
4161 PWND Wnd
= ValidateHwnd(hWnd
);
4166 return UlongToHandle(Wnd
->IDMenu
);
4174 GetMenuCheckMarkDimensions(VOID
)
4176 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4177 GetSystemMetrics(SM_CYMENUCHECK
)));
4185 GetMenuDefaultItem(HMENU hMenu
,
4189 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4197 GetMenuInfo(HMENU hmenu
,
4203 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4206 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4207 mi
.cbSize
= sizeof(MENUINFO
);
4208 mi
.fMask
= lpcmi
->fMask
;
4210 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4212 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4221 GetMenuItemCount(HMENU Menu
)
4223 ROSMENUINFO MenuInfo
;
4225 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4233 GetMenuItemID(HMENU hMenu
,
4236 ROSMENUITEMINFO mii
;
4238 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4239 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4241 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4246 if (NULL
!= mii
.hSubMenu
)
4267 LPMENUITEMINFOA mii
)
4273 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4274 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4276 SetLastError(ERROR_INVALID_PARAMETER
);
4280 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4282 /* No text requested, just pass on */
4283 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4286 AnsiBuffer
= mii
->dwTypeData
;
4287 Count
= miiW
.cch
= mii
->cch
;
4288 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4289 miiW
.dwTypeData
= 0;
4293 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4294 miiW
.cch
* sizeof(WCHAR
));
4295 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4296 miiW
.dwTypeData
[0] = 0;
4299 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4301 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4305 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4307 if (!AnsiBuffer
|| !Count
)
4309 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4310 mii
->dwTypeData
= AnsiBuffer
;
4311 mii
->cch
= miiW
.cch
;
4315 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4319 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4323 if (Count
> miiW
.cch
)
4325 AnsiBuffer
[miiW
.cch
] = 0;
4327 mii
->cch
= mii
->cch
;
4335 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4336 mii
->dwTypeData
= AnsiBuffer
;
4350 LPMENUITEMINFOW mii
)
4356 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4357 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4359 SetLastError(ERROR_INVALID_PARAMETER
);
4363 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4365 /* No text requested, just pass on */
4366 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4369 String
= mii
->dwTypeData
;
4371 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4372 miiW
.dwTypeData
= 0;
4376 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4377 miiW
.cch
* sizeof(WCHAR
));
4378 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4379 miiW
.dwTypeData
[0] = 0;
4382 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4384 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4388 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4390 if (!String
|| !Count
)
4392 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4393 mii
->dwTypeData
= String
; // may not be zero.
4394 mii
->cch
= miiW
.cch
;
4398 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4400 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4403 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4404 mii
->dwTypeData
= String
;
4405 mii
->cch
= strlenW(String
);
4420 ROSMENUINFO MenuInfo
;
4421 ROSMENUITEMINFO mii
;
4422 memset( &mii
, 0, sizeof(mii
) );
4423 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4424 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4427 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4432 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4436 nSubItems
= MenuInfo
.MenuItemCount
;
4438 /* FIXME - ported from wine, does that work (0xff)? */
4439 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4440 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4442 return (UINT
)-1; /* Invalid submenu */
4445 /* FIXME - ported from wine, does that work? */
4446 return (mii
.fType
| mii
.fState
);
4466 memset( &mii
, 0, sizeof(mii
) );
4467 mii
.dwTypeData
= lpString
;
4468 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4469 mii
.fType
= MFT_STRING
;
4470 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4471 mii
.cch
= nMaxCount
;
4473 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4493 memset( &miiW
, 0, sizeof(miiW
) );
4494 miiW
.dwTypeData
= lpString
;
4495 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4496 miiW
.fType
= MFT_STRING
;
4497 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4498 miiW
.cch
= nMaxCount
;
4500 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4518 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4519 mi
.fMask
= MIIM_SUBMENU
;
4521 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4523 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4540 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4542 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4555 UINT_PTR uIDNewItem
,
4559 memset( &mii
, 0, sizeof(mii
) );
4560 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4561 mii
.fMask
= MIIM_FTYPE
;
4563 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4566 (LPCWSTR
) lpNewItem
,
4569 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4583 LPCMENUITEMINFOA lpmii
)
4586 UNICODE_STRING MenuText
;
4588 BOOL CleanHeap
= FALSE
;
4591 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4592 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4594 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4596 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4598 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4601 /* copy the text string */
4602 if (((mi
.fMask
& MIIM_STRING
) ||
4603 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4604 && mi
.dwTypeData
!= NULL
)
4606 Status
= RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
);
4607 if (!NT_SUCCESS (Status
))
4609 SetLastError (RtlNtStatusToDosError(Status
));
4612 mi
.dwTypeData
= MenuText
.Buffer
;
4613 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4616 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4618 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4633 LPCMENUITEMINFOW lpmii
)
4636 UNICODE_STRING MenuText
;
4639 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4640 if a bad user passes bad data, we crash his process instead of the
4643 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4644 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4646 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4648 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4650 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4653 /* copy the text string */
4654 if (((mi
.fMask
& MIIM_STRING
) ||
4655 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4656 && mi
.dwTypeData
!= NULL
)
4658 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4659 mi
.dwTypeData
= MenuText
.Buffer
;
4660 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4662 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4677 UINT_PTR uIDNewItem
,
4681 memset( &mii
, 0, sizeof(mii
) );
4682 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4683 mii
.fMask
= MIIM_FTYPE
;
4685 MenuSetItemData( &mii
,
4691 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4703 if (ValidateHandle(Menu
, VALIDATE_TYPE_MENU
)) return TRUE
;
4712 LoadMenuA(HINSTANCE hInstance
,
4715 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4716 if (Resource
== NULL
)
4720 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4728 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4730 return(LoadMenuIndirectW(lpMenuTemplate
));
4738 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4741 WORD version
, offset
;
4742 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4744 version
= GET_WORD(p
);
4749 case 0: /* standard format is version of 0 */
4750 offset
= GET_WORD(p
);
4751 p
+= sizeof(WORD
) + offset
;
4752 if (!(hMenu
= CreateMenu())) return 0;
4753 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4759 case 1: /* extended format is version of 1 */
4760 offset
= GET_WORD(p
);
4761 p
+= sizeof(WORD
) + offset
;
4762 if (!(hMenu
= CreateMenu())) return 0;
4763 if (!MENUEX_ParseResource(p
, hMenu
))
4765 DestroyMenu( hMenu
);
4770 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4780 LoadMenuW(HINSTANCE hInstance
,
4783 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4784 if (Resource
== NULL
)
4788 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4802 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4815 UINT_PTR uIDNewItem
,
4819 ROSMENUITEMINFO rmii
;
4821 memset( &mii
, 0, sizeof(mii
) );
4822 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4823 mii
.fMask
= MIIM_FTYPE
;
4825 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4829 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4831 MenuInitRosMenuItemInfo( &rmii
);
4833 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4835 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4836 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4838 MenuCleanupRosMenuItemInfo( &rmii
);
4840 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4843 (LPCWSTR
) lpNewItem
,
4846 return SetMenuItemInfoA( hMnu
,
4848 (BOOL
)(MF_BYPOSITION
& uFlags
),
4862 UINT_PTR uIDNewItem
,
4866 ROSMENUITEMINFO rmii
;
4868 memset ( &mii
, 0, sizeof(mii
) );
4869 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4870 mii
.fMask
= MIIM_FTYPE
;
4872 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4874 mi
.Height
= 0; // Force size recalculation.
4876 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4878 MenuInitRosMenuItemInfo( &rmii
);
4880 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4882 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4883 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4885 MenuCleanupRosMenuItemInfo( &rmii
);
4887 /* Init new data for this menu item */
4888 MenuSetItemData( &mii
,
4894 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4895 return SetMenuItemInfoW( hMnu
,
4897 (BOOL
)(MF_BYPOSITION
& uFlags
),
4909 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4925 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4927 SetLastError(ERROR_INVALID_PARAMETER
);
4931 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4932 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
4945 HBITMAP hBitmapUnchecked
,
4946 HBITMAP hBitmapChecked
)
4948 ROSMENUITEMINFO uItem
;
4949 memset ( &uItem
, 0, sizeof(uItem
) );
4950 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
4952 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
4953 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
4955 if (!hBitmapChecked
&& !hBitmapUnchecked
)
4957 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
4959 else /* Install new bitmaps */
4961 uItem
.hbmpChecked
= hBitmapChecked
;
4962 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
4963 uItem
.fState
|= MF_USECHECKBITMAPS
;
4965 return NtUserMenuItemInfo(hMenu
, uPosition
,
4966 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
4979 LPCMENUITEMINFOA lpmii
)
4981 MENUITEMINFOW MenuItemInfoW
;
4982 UNICODE_STRING UnicodeString
;
4984 ULONG Result
= FALSE
;
4986 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
4988 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4990 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
4991 MenuItemInfoW
.hbmpItem
= NULL
;
4994 * MIIM_STRING == good
4995 * MIIM_TYPE & MFT_STRING == good
4996 * MIIM_STRING & MFT_STRING == good
4997 * MIIM_STRING & MFT_OWNERSRAW == good
4999 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5000 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5001 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5002 && MenuItemInfoW
.dwTypeData
!= NULL
)
5004 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5005 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
5006 (LPSTR
)MenuItemInfoW
.dwTypeData
);
5007 if (!NT_SUCCESS (Status
))
5009 SetLastError (RtlNtStatusToDosError(Status
));
5012 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
5013 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5017 UnicodeString
.Buffer
= NULL
;
5020 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5021 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5023 if (UnicodeString
.Buffer
!= NULL
)
5025 RtlFreeUnicodeString(&UnicodeString
);
5041 LPCMENUITEMINFOW lpmii
)
5043 MENUITEMINFOW MenuItemInfoW
;
5046 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5048 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5050 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5051 MenuItemInfoW
.hbmpItem
= NULL
;
5054 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5055 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5056 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5057 && MenuItemInfoW
.dwTypeData
!= NULL
)
5059 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5061 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5062 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5078 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5083 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5086 return NtUserSetSystemMenu(hwnd
, hMenu
);
5090 // Example for the Win32/User32 rewrite.
5091 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5105 return NtUserTrackPopupMenuEx( Menu
,
5110 NULL
); // LPTPMPARAMS is null
5119 GetMenuContextHelpId(HMENU hmenu
)
5122 mi
.cbSize
= sizeof(ROSMENUINFO
);
5123 mi
.fMask
= MIM_HELPID
;
5125 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5127 return mi
.dwContextHelpID
;
5148 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5151 Result
= (ULONG_PTR
)lResult
;
5156 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5176 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5179 Result
= (ULONG_PTR
)lResult
;
5184 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5195 LPCWSTR lpszNewItem
,
5200 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5201 for MF_DELETE. We should check the parameters for all others
5202 MF_* actions also (anybody got a doc on ChangeMenu?).
5205 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5208 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5211 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5214 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5217 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5218 flags
&~ MF_REMOVE
);
5220 default : /* MF_INSERT */
5221 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5238 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5239 for MF_DELETE. We should check the parameters for all others
5240 MF_* actions also (anybody got a doc on ChangeMenu?).
5243 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5246 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5249 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5252 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5255 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5256 flags
&~ MF_REMOVE
);
5258 default : /* MF_INSERT */
5259 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);