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)
531 if ( !ForceMenuChar
)
534 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
536 if ((ItemInfo
->lpstr
) && NULL
!= ItemInfo
->dwTypeData
)
538 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
541 p
= strchrW (p
+ 2, '&');
543 while (p
!= NULL
&& p
[1] == '&');
544 if (p
&& (toupperW(p
[1]) == toupperW(Key
))) return i
;
549 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
550 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
551 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
552 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
557 /***********************************************************************
558 * MenuGetBitmapItemSize
560 * Get the size of a bitmap item.
562 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
, HWND WndOwner
)
565 HBITMAP bmp
= lpitem
->hbmpItem
;
567 size
->cx
= size
->cy
= 0;
569 /* check if there is a magic menu item associated with this item */
570 if (IS_MAGIC_BITMAP(bmp
))
572 switch((INT_PTR
) bmp
)
574 case (INT_PTR
)HBMMENU_CALLBACK
:
576 MEASUREITEMSTRUCT measItem
;
577 measItem
.CtlType
= ODT_MENU
;
579 measItem
.itemID
= lpitem
->wID
;
580 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
581 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
582 measItem
.itemData
= lpitem
->dwItemData
;
583 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
584 size
->cx
= measItem
.itemWidth
;
585 size
->cy
= measItem
.itemHeight
;
590 case (INT_PTR
) HBMMENU_SYSTEM
:
591 if (0 != lpitem
->dwItemData
)
593 bmp
= (HBITMAP
) lpitem
->dwItemData
;
597 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
598 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
599 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
600 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
601 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
602 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
603 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
604 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
605 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
606 /* FIXME: Why we need to subtract these magic values? */
607 /* to make them smaller than the menu bar? */
608 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
609 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
614 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
616 size
->cx
= bm
.bmWidth
;
617 size
->cy
= bm
.bmHeight
;
621 /***********************************************************************
624 * Draw a bitmap item.
626 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
627 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
633 int w
= rect
->right
- rect
->left
;
634 int h
= rect
->bottom
- rect
->top
;
637 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
640 /* Check if there is a magic menu item associated with this item */
641 if (IS_MAGIC_BITMAP(hbmToDraw
))
647 switch ((INT_PTR
)hbmToDraw
)
649 case (INT_PTR
)HBMMENU_SYSTEM
:
650 if (lpitem
->dwTypeData
)
652 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
653 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
657 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
659 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
660 /* only use right half of the bitmap */
661 bmp_xoffset
= bm
.bmWidth
/ 2;
662 bm
.bmWidth
-= bmp_xoffset
;
665 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
666 flags
= DFCS_CAPTIONRESTORE
;
668 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
670 flags
= DFCS_CAPTIONMIN
;
672 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
674 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
676 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
677 flags
= DFCS_CAPTIONCLOSE
;
679 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
680 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
682 case (INT_PTR
)HBMMENU_CALLBACK
:
684 DRAWITEMSTRUCT drawItem
;
686 drawItem
.CtlType
= ODT_MENU
;
688 drawItem
.itemID
= lpitem
->wID
;
689 drawItem
.itemAction
= odaction
;
690 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
691 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
692 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
693 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
694 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
695 drawItem
.hwndItem
= (HWND
)hmenu
;
697 drawItem
.rcItem
= *rect
;
698 drawItem
.itemData
= lpitem
->dwItemData
;
699 /* some applications make this assumption on the DC's origin */
700 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
701 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
702 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
703 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
708 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
709 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
710 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
711 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
712 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
715 InflateRect(&r
, -1, -1);
716 if (0 != (lpitem
->fState
& MF_HILITE
))
718 flags
|= DFCS_PUSHED
;
720 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
724 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
727 hdcMem
= CreateCompatibleDC( hdc
);
728 SelectObject( hdcMem
, bmp
);
730 /* handle fontsize > bitmap_height */
731 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
733 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
734 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
735 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
736 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
740 /***********************************************************************
743 * Calculate the size of the menu item and store it in lpitem->rect.
745 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
746 INT orgX
, INT orgY
, BOOL menuBar
)
749 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
752 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
754 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
756 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
758 if (lpitem
->fType
& MF_OWNERDRAW
)
760 MEASUREITEMSTRUCT mis
;
761 mis
.CtlType
= ODT_MENU
;
763 mis
.itemID
= lpitem
->wID
;
764 mis
.itemData
= lpitem
->dwItemData
;
765 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
767 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
768 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
769 * width of a menufont character to the width of an owner-drawn menu.
771 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
774 /* under at least win95 you seem to be given a standard
775 height for the menu and the height value is ignored */
776 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
778 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
780 TRACE("id=%04lx size=%dx%d\n",
781 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
785 if (lpitem
->fType
& MF_SEPARATOR
)
787 lpitem
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
789 lpitem
->Rect
.right
+= check_bitmap_width
+ MenuCharSize
.cx
;
795 if (lpitem
->hbmpItem
)
800 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
801 /* Keep the size of the bitmap in callback mode to be able
802 * to draw it correctly */
803 lpitem
->Rect
.right
= lpitem
->Rect
.left
+ size
.cx
;
804 if (MenuInfo
->maxBmpSize
.cx
< abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
||
805 MenuInfo
->maxBmpSize
.cy
< abs(size
.cy
))
807 MenuInfo
->maxBmpSize
.cx
= abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
;
808 MenuInfo
->maxBmpSize
.cy
= abs(size
.cy
);
810 MenuSetRosMenuInfo(MenuInfo
);
811 itemheight
= size
.cy
+ 2;
813 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
814 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
815 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
816 lpitem
->dxTab
= lpitem
->Rect
.right
;
817 lpitem
->Rect
.right
+= check_bitmap_width
;
818 } else /* hbmpItem & MenuBar */ {
819 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
820 lpitem
->Rect
.right
+= size
.cx
;
821 if( lpitem
->lpstr
) lpitem
->Rect
.right
+= 2;
822 itemheight
= size
.cy
;
824 /* Special case: Minimize button doesn't have a space behind it. */
825 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
826 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
827 lpitem
->Rect
.right
-= 1;
831 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
832 lpitem
->Rect
.right
+= check_bitmap_width
;
833 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
834 lpitem
->dxTab
= lpitem
->Rect
.right
;
835 lpitem
->Rect
.right
+= check_bitmap_width
;
838 /* it must be a text item - unless it's the system menu */
839 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->lpstr
) {
840 HFONT hfontOld
= NULL
;
841 RECT rc
= lpitem
->Rect
;
842 LONG txtheight
, txtwidth
;
844 if ( lpitem
->fState
& MFS_DEFAULT
) {
845 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
848 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
849 DT_SINGLELINE
|DT_CALCRECT
);
850 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
851 itemheight
= max( max( itemheight
, txtheight
),
852 GetSystemMetrics( SM_CYMENU
) - 1);
853 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
855 if ((p
= strchrW( lpitem
->dwTypeData
, '\t' )) != NULL
) {
858 int n
= (int)( p
- lpitem
->dwTypeData
);
859 /* Item contains a tab (only meaningful in popup menus) */
860 /* get text size before the tab */
861 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, n
, &rc
,
862 DT_SINGLELINE
|DT_CALCRECT
);
863 txtwidth
= rc
.right
- rc
.left
;
864 p
+= 1; /* advance past the Tab */
865 /* get text size after the tab */
866 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
867 DT_SINGLELINE
|DT_CALCRECT
);
868 lpitem
->dxTab
+= txtwidth
;
869 txtheight
= max( txtheight
, tmpheight
);
870 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
871 tmprc
.right
- tmprc
.left
; /* space for the short cut */
873 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
874 DT_SINGLELINE
|DT_CALCRECT
);
875 txtwidth
= rc
.right
- rc
.left
;
876 lpitem
->dxTab
+= txtwidth
;
878 lpitem
->Rect
.right
+= 2 + txtwidth
;
879 itemheight
= max( itemheight
,
880 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
882 if (hfontOld
) SelectObject (hdc
, hfontOld
);
883 } else if( menuBar
) {
884 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
886 lpitem
->Rect
.bottom
+= itemheight
;
887 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
890 /***********************************************************************
891 * MenuPopupMenuCalcSize
893 * Calculate the size of a popup menu.
895 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
897 ROSMENUITEMINFO lpitem
;
900 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
902 MenuInfo
->Width
= MenuInfo
->Height
= 0;
903 if (MenuInfo
->MenuItemCount
== 0)
905 MenuSetRosMenuInfo(MenuInfo
);
910 SelectObject( hdc
, hMenuFont
);
915 MenuInfo
->maxBmpSize
.cx
= 0;
916 MenuInfo
->maxBmpSize
.cy
= 0;
918 MenuInitRosMenuItemInfo(&lpitem
);
919 while (start
< MenuInfo
->MenuItemCount
)
924 maxTab
= maxTabWidth
= 0;
926 /* Parse items until column break or end of menu */
927 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
929 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
931 MenuCleanupRosMenuItemInfo(&lpitem
);
932 MenuSetRosMenuInfo(MenuInfo
);
936 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
938 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
);
939 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
941 MenuCleanupRosMenuItemInfo(&lpitem
);
942 MenuSetRosMenuInfo(MenuInfo
);
945 // Not sure here,, The patch from wine removes this.
946 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
950 maxX
= max(maxX
, lpitem
.Rect
.right
);
951 orgY
= lpitem
.Rect
.bottom
;
952 if ((lpitem
.lpstr
) && lpitem
.dxTab
)
954 maxTab
= max( maxTab
, lpitem
.dxTab
);
955 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.dxTab
);
959 /* Finish the column (set all items to the largest width found) */
960 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
963 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
965 lpitem
.Rect
.right
= maxX
;
966 if ((lpitem
.lpstr
) && 0 != lpitem
.dxTab
)
968 lpitem
.dxTab
= maxTab
;
970 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
974 MenuInfo
->Height
= max(MenuInfo
->Height
, orgY
);
977 MenuInfo
->Width
= maxX
;
979 /* space for 3d border */
980 MenuInfo
->Height
+= 2;
981 MenuInfo
->Width
+= 2;
983 MenuCleanupRosMenuItemInfo(&lpitem
);
984 MenuSetRosMenuInfo(MenuInfo
);
988 /***********************************************************************
989 * MenuMenuBarCalcSize
991 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
992 * height is off by 1 pixel which causes lengthy window relocations when
993 * active document window is maximized/restored.
995 * Calculate the size of the menu bar.
997 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
998 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
1000 ROSMENUITEMINFO ItemInfo
;
1001 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1003 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
1004 if (MenuInfo
->MenuItemCount
== 0) return;
1005 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
1006 MenuInfo
->Width
= lprect
->right
- lprect
->left
;
1007 MenuInfo
->Height
= 0;
1008 maxY
= lprect
->top
+ 1;
1012 MenuInfo
->maxBmpSize
.cx
= 0;
1013 MenuInfo
->maxBmpSize
.cy
= 0;
1015 MenuInitRosMenuItemInfo(&ItemInfo
);
1016 while (start
< MenuInfo
->MenuItemCount
)
1018 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1020 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1023 orgX
= lprect
->left
;
1026 /* Parse items until line break or end of menu */
1027 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
1029 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1031 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1033 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1034 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
);
1035 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1037 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1041 if (ItemInfo
.Rect
.right
> lprect
->right
)
1043 if (i
!= start
) break;
1044 else ItemInfo
.Rect
.right
= lprect
->right
;
1046 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
1047 orgX
= ItemInfo
.Rect
.right
;
1048 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1050 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1052 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1058 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1059 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1061 /* Finish the line (set all items to the largest height found) */
1064 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1066 ItemInfo
.Rect
.bottom
= maxY
;
1067 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
1072 start
= i
; /* This works! */
1076 lprect
->bottom
= maxY
;
1077 MenuInfo
->Height
= lprect
->bottom
- lprect
->top
;
1078 MenuSetRosMenuInfo(MenuInfo
);
1082 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1083 /* the last item (if several lines, only move the last line) */
1084 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1086 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1089 orgY
= ItemInfo
.Rect
.top
;
1090 orgX
= lprect
->right
;
1091 for (i
= MenuInfo
->MenuItemCount
- 1; helpPos
<= i
; i
--)
1097 if (ItemInfo
.Rect
.top
!= orgY
)
1099 break; /* Other line */
1101 if (orgX
<= ItemInfo
.Rect
.right
)
1103 break; /* Too far right already */
1105 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1106 ItemInfo
.Rect
.right
= orgX
;
1107 orgX
= ItemInfo
.Rect
.left
;
1108 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1109 if (helpPos
+ 1 <= i
&&
1110 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1112 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1118 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1121 /***********************************************************************
1124 * Draw a single menu item.
1126 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1127 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1131 BOOL flat_menu
= FALSE
;
1133 PWND Wnd
= ValidateHwnd(hWnd
);
1138 if (lpitem
->fType
& MF_SYSMENU
)
1140 if ( (Wnd
->style
& WS_MINIMIZE
))
1142 UserGetInsideRectNC(Wnd
, &rect
);
1143 UserDrawSysMenuButton(hWnd
, hdc
, &rect
,
1144 lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1149 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1150 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1154 if (lpitem
->fState
& MF_HILITE
)
1156 if(menuBar
&& !flat_menu
) {
1157 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1158 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1160 if (lpitem
->fState
& MF_GRAYED
)
1161 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1163 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1164 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1169 if (lpitem
->fState
& MF_GRAYED
)
1170 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1172 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1173 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1176 rect
= lpitem
->Rect
;
1178 if (lpitem
->fType
& MF_OWNERDRAW
)
1181 ** Experimentation under Windows reveals that an owner-drawn
1182 ** menu is given the rectangle which includes the space it requested
1183 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1184 ** and a popup-menu arrow. This is the value of lpitem->rect.
1185 ** Windows will leave all drawing to the application except for
1186 ** the popup-menu arrow. Windows always draws that itself, after
1187 ** the menu owner has finished drawing.
1191 dis
.CtlType
= ODT_MENU
;
1193 dis
.itemID
= lpitem
->wID
;
1194 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1196 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1197 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1198 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1199 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1200 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1203 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1204 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1205 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1206 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1208 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1209 /* Draw the popup-menu arrow */
1210 if (lpitem
->fType
& MF_POPUP
)
1213 CopyRect(&rectTemp
, &rect
);
1214 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1215 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1220 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1222 if (lpitem
->fState
& MF_HILITE
)
1226 InflateRect (&rect
, -1, -1);
1227 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1228 InflateRect (&rect
, 1, 1);
1229 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1234 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1236 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1240 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1242 SetBkMode( hdc
, TRANSPARENT
);
1244 /* vertical separator */
1245 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1252 rc
.bottom
= Height
- 3;
1255 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1256 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1257 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1258 LineTo( hdc
, rc
.left
, rc
.bottom
);
1259 SelectObject( hdc
, oldPen
);
1262 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1265 /* horizontal separator */
1266 if (lpitem
->fType
& MF_SEPARATOR
)
1273 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1276 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1277 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1278 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1279 LineTo( hdc
, rc
.right
, rc
.top
);
1280 SelectObject( hdc
, oldPen
);
1283 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1288 /* helper lines for debugging */
1289 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1290 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1291 SelectObject(hdc
, GetStockObject(DC_PEN
));
1292 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1293 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1294 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1300 INT y
= rect
.top
+ rect
.bottom
;
1302 int checked
= FALSE
;
1303 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1304 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1305 /* Draw the check mark
1308 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1310 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1311 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1312 lpitem
->hbmpUnchecked
;
1313 if (bm
) /* we have a custom bitmap */
1315 HDC hdcMem
= CreateCompatibleDC( hdc
);
1317 SelectObject( hdcMem
, bm
);
1318 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1319 check_bitmap_width
, check_bitmap_height
,
1320 hdcMem
, 0, 0, SRCCOPY
);
1324 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1327 CopyRect(&r
, &rect
);
1328 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1329 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1330 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1331 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1335 if ( lpitem
->hbmpItem
)
1338 CopyRect(&bmpRect
, &rect
);
1339 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1340 bmpRect
.left
+= check_bitmap_width
+ 2;
1341 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1343 bmpRect
.right
= bmpRect
.left
+ MenuInfo
->maxBmpSize
.cx
;
1344 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1347 /* Draw the popup-menu arrow */
1348 if (lpitem
->fType
& MF_POPUP
)
1351 CopyRect(&rectTemp
, &rect
);
1352 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1353 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1356 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1357 rect
.left
+= check_bitmap_width
;
1358 rect
.right
-= check_bitmap_width
;
1360 else if( lpitem
->hbmpItem
)
1361 { /* Draw the bitmap */
1362 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1365 /* process text if present */
1371 UINT uFormat
= menuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
1372 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1374 if(MenuInfo
->dwStyle
& MNS_CHECKORBMP
)
1375 rect
.left
+= max(0, MenuInfo
->maxBmpSize
.cx
- GetSystemMetrics(SM_CXMENUCHECK
));
1377 rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
1379 if ( lpitem
->fState
& MFS_DEFAULT
)
1381 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1385 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1386 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1389 Text
= (PWCHAR
) lpitem
->dwTypeData
;
1392 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1393 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1397 if(lpitem
->fState
& MF_GRAYED
)
1399 if (!(lpitem
->fState
& MF_HILITE
) )
1401 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1402 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1403 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1404 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1406 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1409 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1411 /* paint the shortcut text */
1412 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1414 if (L
'\t' == Text
[i
])
1416 rect
.left
= lpitem
->dxTab
;
1417 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1421 rect
.right
= lpitem
->dxTab
;
1422 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1425 if (lpitem
->fState
& MF_GRAYED
)
1427 if (!(lpitem
->fState
& MF_HILITE
) )
1429 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1430 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1431 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1432 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1434 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1436 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1440 SelectObject (hdc
, hfontOld
);
1444 /***********************************************************************
1447 * Paint a popup menu.
1449 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1451 HBRUSH hPrevBrush
= 0;
1454 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1456 GetClientRect( hwnd
, &rect
);
1458 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1459 && (SelectObject( hdc
, hMenuFont
)))
1463 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1465 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1468 BOOL flat_menu
= FALSE
;
1469 ROSMENUINFO MenuInfo
;
1470 ROSMENUITEMINFO ItemInfo
;
1472 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1474 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1476 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1478 /* draw menu items */
1479 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.MenuItemCount
)
1483 MenuInitRosMenuItemInfo(&ItemInfo
);
1485 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
1487 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1489 MenuDrawMenuItem(hwnd
, &MenuInfo
, MenuInfo
.WndOwner
, hdc
, &ItemInfo
,
1490 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
1494 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1498 SelectObject( hdc
, hPrevBrush
);
1503 /***********************************************************************
1506 * Paint a menu bar. Returns the height of the menu bar.
1507 * called from [windows/nonclient.c]
1509 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1514 HMENU hMenu
= GetMenu(hwnd
);
1516 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
1518 return GetSystemMetrics(SM_CYMENU
);
1523 hfontOld
= SelectObject(hDC
, hMenuFont
);
1525 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
1527 lprect
->bottom
= lprect
->top
+ lppop
.Height
;
1529 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1530 return lppop
.Height
;
1533 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1536 /***********************************************************************
1539 * Display a popup menu.
1541 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
1542 INT x
, INT y
, INT xanchor
, INT yanchor
)
1544 ROSMENUINFO MenuInfo
;
1545 ROSMENUITEMINFO ItemInfo
;
1551 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1552 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1554 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
1555 if (MenuInfo
.FocusedItem
!= NO_SELECTED_ITEM
)
1557 MenuInitRosMenuItemInfo(&ItemInfo
);
1558 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1560 ItemInfo
.fMask
|= MIIM_STATE
;
1561 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1562 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1564 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1565 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1568 /* store the owner for DrawItem */
1569 if (!IsWindow(hwndOwner
))
1571 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
1574 MenuInfo
.WndOwner
= hwndOwner
;
1575 MenuSetRosMenuInfo(&MenuInfo
);
1577 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
1579 /* adjust popup menu pos so that it fits within the desktop */
1581 width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1582 height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1584 /* FIXME: should use item rect */
1587 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
1588 info
.cbSize
= sizeof(info
);
1589 GetMonitorInfoW( monitor
, &info
);
1591 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
1592 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
1594 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
1595 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
1597 if( x
+ width
> info
.rcMonitor
.right
)
1599 if( xanchor
&& x
>= width
- xanchor
)
1600 x
-= width
- xanchor
;
1602 if( x
+ width
> info
.rcMonitor
.right
)
1603 x
= info
.rcMonitor
.right
- width
;
1605 if( x
< info
.rcMonitor
.left
) x
= info
.rcMonitor
.left
;
1607 if( y
+ height
> info
.rcMonitor
.bottom
)
1609 if( yanchor
&& y
>= height
+ yanchor
)
1610 y
-= height
+ yanchor
;
1612 if( y
+ height
> info
.rcMonitor
.bottom
)
1613 y
= info
.rcMonitor
.bottom
- height
;
1615 if( y
< info
.rcMonitor
.top
) y
= info
.rcMonitor
.top
;
1617 /* NOTE: In Windows, top menu popup is not owned. */
1618 MenuInfo
.Wnd
= CreateWindowExW( 0, WC_MENU
, NULL
,
1619 WS_POPUP
, x
, y
, width
, height
,
1620 hwndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
1621 (LPVOID
) MenuInfo
.Self
);
1622 if ( !MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
)) return FALSE
;
1624 top_popup
= MenuInfo
.Wnd
;
1625 top_popup_hmenu
= hmenu
;
1628 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
1630 /* Display the window */
1632 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1633 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1634 UpdateWindow( MenuInfo
.Wnd
);
1639 /***********************************************************************
1642 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
1643 BOOL sendMenuSelect
, HMENU topmenu
)
1645 ROSMENUITEMINFO ItemInfo
;
1646 ROSMENUINFO TopMenuInfo
;
1649 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1651 if (!hmenu
|| !hmenu
->MenuItemCount
|| !hmenu
->Wnd
) return;
1652 if (hmenu
->FocusedItem
== wIndex
) return;
1653 if (hmenu
->Flags
& MF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
1654 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1656 top_popup
= hmenu
->Wnd
;
1657 top_popup_hmenu
= hmenu
->Self
;
1660 SelectObject( hdc
, hMenuFont
);
1662 MenuInitRosMenuItemInfo(&ItemInfo
);
1664 /* Clear previous highlighted item */
1665 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1667 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1669 ItemInfo
.fMask
|= MIIM_STATE
;
1670 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1671 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1673 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
1674 hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1678 /* Highlight new item (if any) */
1679 hmenu
->FocusedItem
= wIndex
;
1680 MenuSetRosMenuInfo(hmenu
);
1681 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1683 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1685 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
1687 ItemInfo
.fMask
|= MIIM_STATE
;
1688 ItemInfo
.fState
|= MF_HILITE
;
1689 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1690 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
1691 &ItemInfo
, hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1696 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1697 MAKELONG(ItemInfo
.fType
& MF_POPUP
? wIndex
: ItemInfo
.wID
,
1698 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
1699 (hmenu
->Flags
& MF_SYSMENU
)), (LPARAM
) hmenu
->Self
);
1703 else if (sendMenuSelect
) {
1706 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
1707 if (pos
!= NO_SELECTED_ITEM
)
1709 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
1710 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
1712 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1713 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
1715 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
1721 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1722 ReleaseDC(hmenu
->Wnd
, hdc
);
1725 /***********************************************************************
1728 * Moves currently selected item according to the Offset parameter.
1729 * If there is no selection then it should select the last item if
1730 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
1732 static void FASTCALL
1733 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
1736 ROSMENUITEMINFO ItemInfo
;
1739 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
1741 /* Prevent looping */
1742 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
1744 else if (Offset
< -1)
1746 else if (Offset
> 1)
1749 MenuInitRosMenuItemInfo(&ItemInfo
);
1751 OrigPos
= MenuInfo
->FocusedItem
;
1752 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
1759 i
= MenuInfo
->FocusedItem
;
1766 /* Clip and wrap around */
1769 i
= MenuInfo
->MenuItemCount
- 1;
1771 else if (i
>= MenuInfo
->MenuItemCount
)
1775 /* If this is a good candidate; */
1776 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1777 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1779 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1780 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1783 } while (i
!= OrigPos
);
1786 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1790 // This breaks some test results. Should handle A2U if called!
1792 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1797 pWnd
= ValidateHwnd(Wnd
);
1802 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
1806 if (pWnd
->fnid
!= FNID_MENU
)
1808 ERR("Wrong window class for Menu!\n");
1815 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1821 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*) lParam
;
1822 SetWindowLongPtrA(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1826 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1827 return MA_NOACTIVATE
;
1832 BeginPaint(Wnd
, &ps
);
1833 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrA(Wnd
, 0));
1838 case WM_PRINTCLIENT
:
1840 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1841 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1849 /* zero out global pointer in case resident popup window was destroyed. */
1850 if (Wnd
== top_popup
)
1853 top_popup_hmenu
= NULL
;
1859 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
1866 if (0 == GetWindowLongPtrA(Wnd
, 0))
1868 OutputDebugStringA("no menu to display\n");
1873 SetWindowLongPtrA(Wnd
, 0, 0);
1877 case MM_SETMENUHANDLE
:
1878 SetWindowLongPtrA(Wnd
, 0, wParam
);
1881 case MM_GETMENUHANDLE
:
1883 return GetWindowLongPtrA(Wnd
, 0);
1886 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1892 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1894 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
1897 pWnd
= ValidateHwnd(Wnd
);
1902 if (Message
!= WM_NCCREATE
)
1904 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1906 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
1910 if (pWnd
->fnid
!= FNID_MENU
)
1912 ERR("Wrong window class for Menu!\n");
1919 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1925 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1926 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1930 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1931 return MA_NOACTIVATE
;
1936 BeginPaint(Wnd
, &ps
);
1937 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1942 case WM_PRINTCLIENT
:
1944 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1945 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1953 /* zero out global pointer in case resident popup window was destroyed. */
1954 if (Wnd
== top_popup
)
1957 top_popup_hmenu
= NULL
;
1964 if (0 == GetWindowLongPtrW(Wnd
, 0))
1966 OutputDebugStringA("no menu to display\n");
1971 SetWindowLongPtrW(Wnd
, 0, 0);
1975 case MM_SETMENUHANDLE
:
1976 SetWindowLongPtrW(Wnd
, 0, wParam
);
1979 case MM_GETMENUHANDLE
:
1981 return GetWindowLongPtrW(Wnd
, 0);
1984 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1990 /**********************************************************************
1991 * MENU_ParseResource
1993 * Parse a standard menu resource and add items to the menu.
1994 * Return a pointer to the end of the resource.
1996 * NOTE: flags is equivalent to the mtOption field
1998 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
2007 flags
= GET_WORD(res
);
2009 /* remove MF_END flag before passing it to AppendMenu()! */
2010 end
= (flags
& MF_END
);
2011 if(end
) flags
^= MF_END
;
2013 res
+= sizeof(WORD
);
2014 if(!(flags
& MF_POPUP
))
2017 res
+= sizeof(WORD
);
2021 res
+= strlen(str
) + 1;
2023 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
2024 if (flags
& MF_POPUP
)
2026 hSubMenu
= CreatePopupMenu();
2027 if(!hSubMenu
) return NULL
;
2028 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
2031 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
2033 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
2035 else /* Not a popup */
2040 flags
= MF_SEPARATOR
;
2044 if (*(LPCWSTR
)str
== 0)
2045 flags
= MF_SEPARATOR
;
2048 if (flags
& MF_SEPARATOR
)
2050 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
2051 flags
|= MF_GRAYED
| MF_DISABLED
;
2055 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
2057 AppendMenuW(hMenu
, flags
, id
,
2058 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2065 /**********************************************************************
2066 * MENUEX_ParseResource
2068 * Parse an extended menu resource and add items to the menu.
2069 * Return a pointer to the end of the resource.
2071 static LPCSTR
MENUEX_ParseResource(LPCSTR res
, HMENU hMenu
)
2078 mii
.cbSize
= sizeof(mii
);
2079 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
2080 mii
.fType
= GET_DWORD(res
);
2081 res
+= sizeof(DWORD
);
2082 mii
.fState
= GET_DWORD(res
);
2083 res
+= sizeof(DWORD
);
2084 mii
.wID
= GET_DWORD(res
);
2085 res
+= sizeof(DWORD
);
2086 resinfo
= GET_WORD(res
);
2087 res
+= sizeof(WORD
);
2088 /* Align the text on a word boundary. */
2089 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2090 mii
.dwTypeData
= (LPWSTR
)res
;
2091 mii
.cch
= strlenW(mii
.dwTypeData
);
2092 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2093 /* Align the following fields on a dword boundary. */
2094 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2096 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2097 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2099 if (resinfo
& 1) /* Pop-up? */
2101 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2102 res
+= sizeof(DWORD
);
2103 mii
.hSubMenu
= CreatePopupMenu();
2106 ERR("CreatePopupMenu failed\n");
2110 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
2112 ERR("MENUEX_ParseResource failed\n");
2113 DestroyMenu(mii
.hSubMenu
);
2116 mii
.fMask
|= MIIM_SUBMENU
;
2117 mii
.fType
|= MF_POPUP
;
2118 mii
.wID
= (UINT
)mii
.hSubMenu
;
2120 else if (!mii
.dwTypeData
[0])
2121 mii
.fType
|= MF_SEPARATOR
;
2123 if (!InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
))
2124 ERR("InsertMenuItemW failed\n");
2125 } while (!(resinfo
& MF_END
));
2130 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
2132 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
2133 LRESULT Result
= (LRESULT
)hmenu
;
2134 MENUINFO menuinfo
= {0};
2135 MENUITEMINFOW info
= {0};
2137 // removing space for checkboxes from menu
2138 menuinfo
.cbSize
= sizeof(menuinfo
);
2139 menuinfo
.fMask
= MIM_STYLE
;
2140 GetMenuInfo(hmenu
, &menuinfo
);
2141 menuinfo
.dwStyle
|= MNS_NOCHECK
;
2142 SetMenuInfo(hmenu
, &menuinfo
);
2144 // adding bitmaps to menu items
2145 info
.cbSize
= sizeof(info
);
2146 info
.fMask
|= MIIM_BITMAP
;
2147 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
2148 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
2149 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
2150 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
2151 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
2152 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
2153 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
2154 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
2156 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
2163 NONCLIENTMETRICSW ncm
;
2165 /* get the menu font */
2166 if(!hMenuFont
|| !hMenuFontBold
)
2168 ncm
.cbSize
= sizeof(ncm
);
2169 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
2171 ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
2175 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2176 if(hMenuFont
== NULL
)
2178 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
2182 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
2183 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2184 if(hMenuFontBold
== NULL
)
2186 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
2187 DeleteObject(hMenuFont
);
2201 DeleteObject(hMenuFont
);
2207 DeleteObject(hMenuFontBold
);
2208 hMenuFontBold
= NULL
;
2212 /***********************************************************************
2213 * DrawMenuBarTemp (USER32.@)
2217 * called by W98SE desk.cpl Control Panel Applet
2219 * Not 100% sure about the param names, but close.
2224 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2226 ROSMENUINFO MenuInfo
;
2227 ROSMENUITEMINFO ItemInfo
;
2229 HFONT FontOld
= NULL
;
2230 BOOL flat_menu
= FALSE
;
2232 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2236 Menu
= GetMenu(Wnd
);
2244 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2246 return GetSystemMetrics(SM_CYMENU
);
2249 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2251 FontOld
= SelectObject(DC
, Font
);
2253 if (0 == MenuInfo
.Height
)
2255 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2258 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
2260 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2262 SelectObject(DC
, GetStockObject(DC_PEN
));
2263 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2264 MoveToEx(DC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2265 LineTo(DC
, Rect
->right
, Rect
->bottom
- 1);
2267 if (0 == MenuInfo
.MenuItemCount
)
2269 SelectObject(DC
, FontOld
);
2270 return GetSystemMetrics(SM_CYMENU
);
2273 MenuInitRosMenuItemInfo(&ItemInfo
);
2274 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2276 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2278 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2279 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
2282 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2284 SelectObject(DC
, FontOld
);
2286 return MenuInfo
.Height
;
2289 /***********************************************************************
2292 * Display the sub-menu of the selected item of this menu.
2293 * Return the handle of the submenu, or menu if no submenu to display.
2295 static HMENU FASTCALL
2296 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2298 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2300 ROSMENUITEMINFO ItemInfo
;
2301 ROSMENUINFO SubMenuInfo
;
2305 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2307 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2309 return MenuInfo
->Self
;
2312 MenuInitRosMenuItemInfo(&ItemInfo
);
2313 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2315 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2316 return MenuInfo
->Self
;
2318 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2320 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2321 return MenuInfo
->Self
;
2324 /* message must be sent before using item,
2325 because nearly everything may be changed by the application ! */
2327 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2328 if (0 == (Flags
& TPM_NONOTIFY
))
2330 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2331 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2334 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2336 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2337 return MenuInfo
->Self
;
2339 Rect
= ItemInfo
.Rect
;
2341 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2342 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2344 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2346 Dc
= GetDC(MenuInfo
->Wnd
);
2350 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2353 SelectObject(Dc
, hMenuFont
);
2354 ItemInfo
.fMask
|= MIIM_STATE
;
2355 ItemInfo
.fState
|= MF_HILITE
;
2356 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2357 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2358 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2359 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2362 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2363 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2365 ItemInfo
.Rect
= Rect
;
2368 ItemInfo
.fMask
|= MIIM_STATE
;
2369 ItemInfo
.fState
|= MF_MOUSESELECT
;
2370 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2372 if (IS_SYSTEM_MENU(MenuInfo
))
2374 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2375 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2377 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2378 Rect
.top
= Rect
.bottom
;
2379 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2380 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2384 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2385 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2387 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2388 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2389 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2390 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2391 - GetSystemMetrics(SM_CYBORDER
);
2395 Rect
.left
+= ItemInfo
.Rect
.left
;
2396 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2397 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2398 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2402 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
, Flags
,
2403 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2404 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2406 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2409 Ret
= ItemInfo
.hSubMenu
;
2410 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2415 /**********************************************************************
2418 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2420 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2422 void MENU_EndMenu( HWND hwnd
)
2424 ROSMENUINFO MenuInfo
;
2426 if (top_popup_hmenu
)
2427 Ret
= MenuGetRosMenuInfo(&MenuInfo
, top_popup_hmenu
);
2428 if (Ret
&& hwnd
== MenuInfo
.WndOwner
) EndMenu();
2431 /***********************************************************************
2434 * Hide the sub-popup menus of this menu.
2436 static void FASTCALL
2437 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2438 BOOL SendMenuSelect
, UINT wFlags
)
2440 ROSMENUINFO SubMenuInfo
;
2441 ROSMENUITEMINFO ItemInfo
;
2443 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2445 if (NULL
!= MenuInfo
&& NULL
!= top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2447 MenuInitRosMenuItemInfo(&ItemInfo
);
2448 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2449 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2450 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2451 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2453 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2456 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2457 ItemInfo
.fMask
|= MIIM_STATE
;
2458 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2459 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2461 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2462 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2463 DestroyWindow(SubMenuInfo
.Wnd
);
2464 SubMenuInfo
.Wnd
= NULL
;
2465 MenuSetRosMenuInfo(&SubMenuInfo
);
2467 if (!(wFlags
& TPM_NONOTIFY
))
2468 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
2469 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
2474 /***********************************************************************
2475 * MenuSwitchTracking
2477 * Helper function for menu navigation routines.
2479 static void FASTCALL
2480 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
2482 ROSMENUINFO TopMenuInfo
;
2484 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2486 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2487 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2488 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2490 /* both are top level menus (system and menu-bar) */
2491 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2492 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2493 Mt
->TopMenu
= PtMenuInfo
->Self
;
2497 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
2500 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2503 /***********************************************************************
2504 * MenuExecFocusedItem
2506 * Execute a menu item (for instance when user pressed Enter).
2507 * Return the wID of the executed item. Otherwise, -1 indicating
2508 * that no menu item was executed, -2 if a popup is shown;
2509 * Have to receive the flags for the TrackPopupMenu options to avoid
2510 * sending unwanted message.
2514 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2516 ROSMENUITEMINFO ItemInfo
;
2519 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2521 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2526 MenuInitRosMenuItemInfo(&ItemInfo
);
2527 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2529 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2533 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2535 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2537 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2538 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2540 /* If TPM_RETURNCMD is set you return the id, but
2541 do not send a message to the owner */
2542 if (0 == (Flags
& TPM_RETURNCMD
))
2544 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2546 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2547 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2551 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2552 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2553 MenuInfo
->FocusedItem
,
2554 (LPARAM
)MenuInfo
->Self
);
2556 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2560 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2566 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2573 /***********************************************************************
2576 * Return TRUE if we can go on with menu tracking.
2578 static BOOL FASTCALL
2579 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2582 ROSMENUINFO MenuInfo
;
2583 ROSMENUITEMINFO Item
;
2585 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2589 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2593 if (IS_SYSTEM_MENU(&MenuInfo
))
2599 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2601 MenuInitRosMenuItemInfo(&Item
);
2602 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2604 MenuCleanupRosMenuItemInfo(&Item
);
2608 if (!(Item
.fType
& MF_SEPARATOR
) &&
2609 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2611 if (MenuInfo
.FocusedItem
!= Index
)
2613 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2616 /* If the popup menu is not already "popped" */
2617 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2619 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2623 MenuCleanupRosMenuItemInfo(&Item
);
2628 /* else the click was on the menu bar, finish the tracking */
2633 /***********************************************************************
2636 * Return the value of MenuExecFocusedItem if
2637 * the selected item was not a popup. Else open the popup.
2638 * A -1 return value indicates that we go on with menu tracking.
2642 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2645 ROSMENUINFO MenuInfo
;
2646 ROSMENUITEMINFO ItemInfo
;
2648 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2653 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2658 if (! IS_SYSTEM_MENU(&MenuInfo
))
2660 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2662 MenuInitRosMenuItemInfo(&ItemInfo
);
2663 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2664 MenuInfo
.FocusedItem
== Id
)
2666 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2668 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2669 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2670 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2672 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2674 /* If we are dealing with the top-level menu */
2675 /* and this is a click on an already "popped" item: */
2676 /* Stop the menu tracking and close the opened submenus */
2677 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2679 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2683 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2684 MenuInfo
.TimeToHide
= TRUE
;
2685 MenuSetRosMenuInfo(&MenuInfo
);
2691 /***********************************************************************
2694 * Walks menu chain trying to find a menu pt maps to.
2696 static HMENU FASTCALL
2697 MenuPtMenu(HMENU Menu
, POINT Pt
)
2699 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2700 ROSMENUINFO MenuInfo
;
2701 ROSMENUITEMINFO ItemInfo
;
2705 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2710 /* try subpopup first (if any) */
2711 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2713 MenuInitRosMenuItemInfo(&ItemInfo
);
2714 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2715 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2716 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2718 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2721 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2725 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2728 /* check the current window (avoiding WM_HITTEST) */
2729 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2730 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2732 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2737 else if (HTSYSMENU
== Ht
)
2739 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2741 else if (HTMENU
== Ht
)
2743 Ret
= GetMenu(MenuInfo
.Wnd
);
2749 /***********************************************************************
2752 * Return TRUE if we can go on with menu tracking.
2754 static BOOL FASTCALL
2755 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2758 ROSMENUINFO MenuInfo
;
2759 ROSMENUITEMINFO ItemInfo
;
2763 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2767 if (IS_SYSTEM_MENU(&MenuInfo
))
2773 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2778 Index
= NO_SELECTED_ITEM
;
2781 if (NO_SELECTED_ITEM
== Index
)
2783 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2784 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2786 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2790 else if (MenuInfo
.FocusedItem
!= Index
)
2792 MenuInitRosMenuItemInfo(&ItemInfo
);
2793 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2794 !(ItemInfo
.fType
& MF_SEPARATOR
))
2796 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2797 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2798 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2800 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2806 /***********************************************************************
2809 * Return the handle of the selected sub-popup menu (if any).
2811 static HMENU FASTCALL
2812 MenuGetSubPopup(HMENU Menu
)
2814 ROSMENUINFO MenuInfo
;
2815 ROSMENUITEMINFO ItemInfo
;
2817 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2818 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2823 MenuInitRosMenuItemInfo(&ItemInfo
);
2824 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2826 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2829 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2831 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2832 return ItemInfo
.hSubMenu
;
2835 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2839 /***********************************************************************
2842 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2844 static LRESULT FASTCALL
2845 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
, UINT wFlags
)
2847 ROSMENUINFO TopMenuInfo
;
2848 ROSMENUINFO MenuInfo
;
2850 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2852 return (LRESULT
) FALSE
;
2855 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2856 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2858 MDINEXTMENU NextMenu
;
2863 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2864 NextMenu
.hmenuNext
= NULL
;
2865 NextMenu
.hwndNext
= NULL
;
2866 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2868 TRACE("%p [%p] -> %p [%p]\n",
2869 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2871 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2873 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2874 NewWnd
= Mt
->OwnerWnd
;
2875 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2877 /* switch to the menu bar */
2879 if (0 != (Style
& WS_CHILD
)
2880 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2887 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2891 Id
= MenuInfo
.MenuItemCount
- 1;
2894 else if (0 != (Style
& WS_SYSMENU
))
2896 /* switch to the system menu */
2897 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2904 else /* application returned a new menu to switch to */
2906 NewMenu
= NextMenu
.hmenuNext
;
2907 NewWnd
= NextMenu
.hwndNext
;
2909 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2911 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2913 if (0 != (Style
& WS_SYSMENU
)
2914 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2916 /* get the real system menu */
2917 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2919 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2921 /* FIXME: Not sure what to do here;
2922 * perhaps try to track NewMenu as a popup? */
2924 WARN(" -- got confused.\n");
2934 if (NewMenu
!= Mt
->TopMenu
)
2936 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2938 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2940 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2944 if (NewWnd
!= Mt
->OwnerWnd
)
2946 Mt
->OwnerWnd
= NewWnd
;
2947 NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
); // 1
2948 SetCapture(Mt
->OwnerWnd
); // 2
2951 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2952 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2954 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2963 /***********************************************************************
2966 * The idea is not to show the popup if the next input message is
2967 * going to hide it anyway.
2969 static BOOL FASTCALL
2970 MenuSuspendPopup(MTRACKER
* Mt
, UINT uMsg
)
2974 msg
.hwnd
= Mt
->OwnerWnd
;
2976 PeekMessageW( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
); // ported incorrectly since 8317 GvG
2977 // Mt->TrackFlags |= TF_SKIPREMOVE; // This sends TrackMenu into a loop with arrow keys!!!!
2982 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2983 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2985 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2986 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2987 if( msg
.message
== WM_KEYDOWN
&&
2988 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2990 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2996 /* failures go through this */
2997 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3001 /***********************************************************************
3004 * Handle a VK_ESCAPE key event in a menu.
3006 static BOOL FASTCALL
3007 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
3009 BOOL EndMenu
= TRUE
;
3010 ROSMENUINFO MenuInfo
;
3011 HMENU MenuTmp
, MenuPrev
;
3013 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3015 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
3016 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
3018 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3020 /* close topmost popup */
3021 while (MenuTmp
!= Mt
->CurrentMenu
)
3024 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3027 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3029 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
3031 Mt
->CurrentMenu
= MenuPrev
;
3039 /***********************************************************************
3042 * Handle a VK_LEFT key event in a menu.
3044 static void FASTCALL
3045 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3047 ROSMENUINFO MenuInfo
;
3048 ROSMENUINFO TopMenuInfo
;
3049 ROSMENUINFO PrevMenuInfo
;
3050 HMENU MenuTmp
, MenuPrev
;
3053 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3055 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3060 /* Try to move 1 column left (if possible) */
3061 if ( (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)) != NO_SELECTED_ITEM
)
3063 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3065 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3070 /* close topmost popup */
3071 while (MenuTmp
!= Mt
->CurrentMenu
)
3074 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3077 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3081 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3082 Mt
->CurrentMenu
= MenuPrev
;
3084 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))