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)
69 #define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
70 #define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
71 #define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */
72 #define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */
77 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
78 HMENU TopMenu
; /* initial menu */
79 HWND OwnerWnd
; /* where notifications are sent */
84 /*********************************************************************
85 * PopupMenu class descriptor
87 const struct builtin_class_descr POPUPMENU_builtin_class
=
89 POPUPMENU_CLASS_ATOMW
, /* name */
90 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
91 (WNDPROC
) NULL
, /* FIXME - procA */
92 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
93 sizeof(MENUINFO
*), /* extra */
94 (LPCWSTR
) IDC_ARROW
, /* cursor */
95 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
99 #define GET_WORD(ptr) (*(WORD *)(ptr))
102 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
105 HFONT hMenuFont
= NULL
;
106 HFONT hMenuFontBold
= NULL
;
108 /* Dimension of the menu bitmaps */
109 static HBITMAP BmpSysMenu
= NULL
;
111 static SIZE MenuCharSize
;
113 /***********************************************************************
116 * Get full information about menu
119 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
121 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
122 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
124 return NtUserMenuInfo(Menu
, MenuInfo
, FALSE
);
127 /***********************************************************************
130 * Set full information about menu
133 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
135 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
136 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
138 return NtUserMenuInfo(MenuInfo
->Self
, MenuInfo
, TRUE
);
141 /***********************************************************************
142 * MenuInitRosMenuItemInfo
144 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
147 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
149 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
150 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
153 /***********************************************************************
154 * MenuGetRosMenuItemInfo
156 * Get full information about a menu item
159 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
161 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
163 if (ItemInfo
->dwTypeData
!= NULL
)
165 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
169 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
170 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
171 ItemInfo
->dwTypeData
= NULL
;
173 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
179 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
182 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0,
183 ItemInfo
->cch
* sizeof(WCHAR
));
184 if (NULL
== ItemInfo
->dwTypeData
)
189 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
194 ItemInfo
->dwTypeData
[ItemInfo
->cch
- 1] = UNICODE_NULL
;
196 ItemInfo
->fMask
= Save_Mask
;
200 /***********************************************************************
201 * MenuSetRosMenuItemInfo
203 * Set selected information about a menu item, need to set the mask bits.
206 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
210 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
211 ItemInfo
->dwTypeData
!= NULL
)
213 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
215 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
220 /***********************************************************************
221 * MenuCleanupRosMenuItemInfo
223 * Cleanup after use of MenuGet/SetRosMenuItemInfo
226 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
228 if (ItemInfo
->dwTypeData
!= NULL
)
230 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
231 ItemInfo
->dwTypeData
= NULL
;
235 /***********************************************************************
236 * MenuGetAllRosMenuItemInfo
238 * Get full information about all menu items
241 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
245 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
246 if (BufSize
== (DWORD
) -1 || BufSize
== 0)
250 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
251 if (NULL
== *ItemInfo
)
256 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
259 /***********************************************************************
260 * MenuCleanupAllRosMenuItemInfo
262 * Cleanup after use of MenuGetAllRosMenuItemInfo
265 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
267 HeapFree(GetProcessHeap(), 0, ItemInfo
);
270 /***********************************************************************
271 * MenuInitSysMenuPopup
273 * Grey the appropriate items in System menu.
275 void FASTCALL
MenuInitSysMenuPopup(HMENU hmenu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
283 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
284 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
285 gray
= ((style
& WS_MAXIMIZE
) != 0);
286 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
287 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
288 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
289 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
290 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
291 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
292 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
293 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
295 /* The menu item must keep its state if it's disabled */
297 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
299 /* Set default menu item */
300 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
301 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
302 else DefItem
= SC_CLOSE
;
304 mii
.cbSize
= sizeof(MENUITEMINFOW
);
305 mii
.fMask
|= MIIM_STATE
;
306 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(hmenu
, DefItem
, FALSE
, &mii
) &&
307 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
))) DefItem
= SC_CLOSE
;
309 SetMenuDefaultItem(hmenu
, DefItem
, MF_BYCOMMAND
);
312 /******************************************************************************
314 * UINT MenuGetStartOfNextColumn(
315 * PROSMENUINFO MenuInfo)
317 *****************************************************************************/
318 static UINT
MenuGetStartOfNextColumn(
319 PROSMENUINFO MenuInfo
)
321 PROSMENUITEMINFO MenuItems
;
324 i
= MenuInfo
->FocusedItem
;
325 if ( i
== NO_SELECTED_ITEM
)
328 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
329 return NO_SELECTED_ITEM
;
331 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
332 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
335 return NO_SELECTED_ITEM
;
338 /******************************************************************************
340 * UINT MenuGetStartOfPrevColumn(
341 * PROSMENUINFO MenuInfo)
343 *****************************************************************************/
345 static UINT FASTCALL
MenuGetStartOfPrevColumn(
346 PROSMENUINFO MenuInfo
)
348 PROSMENUITEMINFO MenuItems
;
351 if (!MenuInfo
->FocusedItem
|| MenuInfo
->FocusedItem
== NO_SELECTED_ITEM
)
352 return NO_SELECTED_ITEM
;
354 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
355 return NO_SELECTED_ITEM
;
357 /* Find the start of the column */
358 for (i
= MenuInfo
->FocusedItem
;
359 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
367 MenuCleanupAllRosMenuItemInfo(MenuItems
);
368 return NO_SELECTED_ITEM
;
371 for (--i
; 0 != i
; --i
)
372 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
375 MenuCleanupAllRosMenuItemInfo(MenuItems
);
376 TRACE("ret %d.\n", i
);
381 /***********************************************************************
384 * Find a Sub menu. Return the position of the submenu, and modifies
385 * *hmenu in case it is found in another sub-menu.
386 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
388 static UINT FASTCALL
MenuFindSubMenu(HMENU
*hmenu
, HMENU hSubTarget
)
392 ROSMENUITEMINFO item
;
393 if (((*hmenu
)==(HMENU
)0xffff) ||
394 (!MenuGetRosMenuInfo(&menu
, *hmenu
)))
395 return NO_SELECTED_ITEM
;
397 MenuInitRosMenuItemInfo(&item
);
398 for (i
= 0; i
< menu
.MenuItemCount
; i
++) {
399 if (! MenuGetRosMenuItemInfo(menu
.Self
, i
, &item
))
401 MenuCleanupRosMenuItemInfo(&item
);
402 return NO_SELECTED_ITEM
;
404 if (!(item
.fType
& MF_POPUP
)) continue;
405 if (item
.hSubMenu
== hSubTarget
) {
406 MenuCleanupRosMenuItemInfo(&item
);
410 HMENU hsubmenu
= item
.hSubMenu
;
411 UINT pos
= MenuFindSubMenu(&hsubmenu
, hSubTarget
);
412 if (pos
!= NO_SELECTED_ITEM
) {
418 MenuCleanupRosMenuItemInfo(&item
);
419 return NO_SELECTED_ITEM
;
422 /***********************************************************************
425 * Load the arrow bitmap. We can't do this from MenuInit since user32
426 * can also be used (and thus initialized) from text-mode.
429 MenuLoadBitmaps(VOID
)
431 /* Load system buttons bitmaps */
432 if (NULL
== BmpSysMenu
)
434 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
438 /***********************************************************************
441 * Draws popup magic glyphs (can be found in system menu).
444 MenuDrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
447 HFONT hFont
, hOldFont
;
453 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
456 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
459 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
462 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
466 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
469 ZeroMemory(&lf
, sizeof(LOGFONTW
));
470 InflateRect(r
, -2, -2);
471 lf
.lfHeight
= r
->bottom
- r
->top
;
473 lf
.lfWeight
= FW_NORMAL
;
474 lf
.lfCharSet
= DEFAULT_CHARSET
;
475 lstrcpy(lf
.lfFaceName
, TEXT("Marlett"));
476 hFont
= CreateFontIndirect(&lf
);
477 /* save font and text color */
478 hOldFont
= SelectObject(dc
, hFont
);
479 clrsave
= GetTextColor(dc
);
480 bkmode
= GetBkMode(dc
);
481 /* set color and drawing mode */
482 SetBkMode(dc
, TRANSPARENT
);
488 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
489 TextOut(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
492 SetTextColor(dc
, GetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
493 /* draw selected symbol */
494 TextOut(dc
, r
->left
, r
->top
, &symbol
, 1);
495 /* restore previous settings */
496 SetTextColor(dc
, clrsave
);
497 SelectObject(dc
, hOldFont
);
498 SetBkMode(dc
, bkmode
);
502 /***********************************************************************
505 * Find the menu item selected by a key press.
506 * Return item id, -1 if none, -2 if we should close the menu.
508 static UINT FASTCALL
MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
509 WCHAR Key
, BOOL ForceMenuChar
)
511 ROSMENUINFO SysMenuInfo
;
512 PROSMENUITEMINFO Items
, ItemInfo
;
516 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
518 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
520 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
522 MenuInfo
= &SysMenuInfo
;
530 if (NULL
!= MenuInfo
)
532 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
540 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
542 if ((ItemInfo
->lpstr
) && NULL
!= ItemInfo
->dwTypeData
)
544 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
547 p
= strchrW(p
+ 2, '&');
549 while (NULL
!= p
&& L
'&' == p
[1]);
550 if (NULL
!= p
&& (toupperW(p
[1]) == Key
))
558 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
559 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
560 if (2 == HIWORD(MenuChar
))
562 return LOWORD(MenuChar
);
564 if (1 == HIWORD(MenuChar
))
573 /***********************************************************************
574 * MenuGetBitmapItemSize
576 * Get the size of a bitmap item.
578 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
, HWND WndOwner
)
581 HBITMAP bmp
= lpitem
->hbmpItem
;
583 size
->cx
= size
->cy
= 0;
585 /* check if there is a magic menu item associated with this item */
586 if (IS_MAGIC_BITMAP(bmp
))
588 switch((INT_PTR
) bmp
)
590 case (INT_PTR
)HBMMENU_CALLBACK
:
592 MEASUREITEMSTRUCT measItem
;
593 measItem
.CtlType
= ODT_MENU
;
595 measItem
.itemID
= lpitem
->wID
;
596 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
597 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
598 measItem
.itemData
= lpitem
->dwItemData
;
599 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
600 size
->cx
= measItem
.itemWidth
;
601 size
->cy
= measItem
.itemHeight
;
606 case (INT_PTR
) HBMMENU_SYSTEM
:
607 if (0 != lpitem
->dwItemData
)
609 bmp
= (HBITMAP
) lpitem
->dwItemData
;
613 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
614 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
615 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
616 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
617 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
618 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
619 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
620 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
621 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
622 /* FIXME: Why we need to subtract these magic values? */
623 /* to make them smaller than the menu bar? */
624 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
625 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
630 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
632 size
->cx
= bm
.bmWidth
;
633 size
->cy
= bm
.bmHeight
;
637 /***********************************************************************
640 * Draw a bitmap item.
642 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
643 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
649 int w
= rect
->right
- rect
->left
;
650 int h
= rect
->bottom
- rect
->top
;
653 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
656 /* Check if there is a magic menu item associated with this item */
657 if (IS_MAGIC_BITMAP(hbmToDraw
))
663 switch ((INT_PTR
)hbmToDraw
)
665 case (INT_PTR
)HBMMENU_SYSTEM
:
666 if (lpitem
->dwTypeData
)
668 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
669 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
673 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
675 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
676 /* only use right half of the bitmap */
677 bmp_xoffset
= bm
.bmWidth
/ 2;
678 bm
.bmWidth
-= bmp_xoffset
;
681 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
682 flags
= DFCS_CAPTIONRESTORE
;
684 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
686 flags
= DFCS_CAPTIONMIN
;
688 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
690 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
692 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
693 flags
= DFCS_CAPTIONCLOSE
;
695 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
696 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
698 case (INT_PTR
)HBMMENU_CALLBACK
:
700 DRAWITEMSTRUCT drawItem
;
702 drawItem
.CtlType
= ODT_MENU
;
704 drawItem
.itemID
= lpitem
->wID
;
705 drawItem
.itemAction
= odaction
;
706 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
707 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
708 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
709 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
710 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
711 drawItem
.hwndItem
= (HWND
)hmenu
;
713 drawItem
.rcItem
= *rect
;
714 drawItem
.itemData
= lpitem
->dwItemData
;
715 /* some applications make this assumption on the DC's origin */
716 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
717 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
718 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
719 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
724 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
725 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
726 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
727 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
728 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
731 InflateRect(&r
, -1, -1);
732 if (0 != (lpitem
->fState
& MF_HILITE
))
734 flags
|= DFCS_PUSHED
;
736 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
740 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
743 hdcMem
= CreateCompatibleDC( hdc
);
744 SelectObject( hdcMem
, bmp
);
746 /* handle fontsize > bitmap_height */
747 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
749 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
750 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
751 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
752 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
756 /***********************************************************************
759 * Calculate the size of the menu item and store it in lpitem->rect.
761 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
762 INT orgX
, INT orgY
, BOOL menuBar
)
765 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
768 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
770 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
772 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
774 if (lpitem
->fType
& MF_OWNERDRAW
)
776 MEASUREITEMSTRUCT mis
;
777 mis
.CtlType
= ODT_MENU
;
779 mis
.itemID
= lpitem
->wID
;
780 mis
.itemData
= lpitem
->dwItemData
;
781 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
783 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
784 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
785 * width of a menufont character to the width of an owner-drawn menu.
787 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
790 /* under at least win95 you seem to be given a standard
791 height for the menu and the height value is ignored */
792 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
794 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
796 TRACE("id=%04lx size=%dx%d\n",
797 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
801 if (lpitem
->fType
& MF_SEPARATOR
)
803 lpitem
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
805 lpitem
->Rect
.right
+= check_bitmap_width
+ MenuCharSize
.cx
;
811 if (lpitem
->hbmpItem
)
816 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
817 /* Keep the size of the bitmap in callback mode to be able
818 * to draw it correctly */
819 lpitem
->Rect
.right
= lpitem
->Rect
.left
+ size
.cx
;
820 if (MenuInfo
->maxBmpSize
.cx
< abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
||
821 MenuInfo
->maxBmpSize
.cy
< abs(size
.cy
))
823 MenuInfo
->maxBmpSize
.cx
= abs(size
.cx
) + MENU_ITEM_HBMP_SPACE
;
824 MenuInfo
->maxBmpSize
.cy
= abs(size
.cy
);
826 MenuSetRosMenuInfo(MenuInfo
);
827 itemheight
= size
.cy
+ 2;
829 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
830 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
831 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
832 lpitem
->dxTab
= lpitem
->Rect
.right
;
833 lpitem
->Rect
.right
+= check_bitmap_width
;
834 } else /* hbmpItem & MenuBar */ {
835 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
836 lpitem
->Rect
.right
+= size
.cx
;
837 if( lpitem
->lpstr
) lpitem
->Rect
.right
+= 2;
838 itemheight
= size
.cy
;
840 /* Special case: Minimize button doesn't have a space behind it. */
841 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
842 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
843 lpitem
->Rect
.right
-= 1;
847 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
848 lpitem
->Rect
.right
+= check_bitmap_width
;
849 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
850 lpitem
->dxTab
= lpitem
->Rect
.right
;
851 lpitem
->Rect
.right
+= check_bitmap_width
;
854 /* it must be a text item - unless it's the system menu */
855 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->lpstr
) {
856 HFONT hfontOld
= NULL
;
857 RECT rc
= lpitem
->Rect
;
858 LONG txtheight
, txtwidth
;
860 if ( lpitem
->fState
& MFS_DEFAULT
) {
861 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
864 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
865 DT_SINGLELINE
|DT_CALCRECT
);
866 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
867 itemheight
= max( max( itemheight
, txtheight
),
868 GetSystemMetrics( SM_CYMENU
) - 1);
869 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
871 if ((p
= strchrW( lpitem
->dwTypeData
, '\t' )) != NULL
) {
874 int n
= (int)( p
- lpitem
->dwTypeData
);
875 /* Item contains a tab (only meaningful in popup menus) */
876 /* get text size before the tab */
877 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, n
, &rc
,
878 DT_SINGLELINE
|DT_CALCRECT
);
879 txtwidth
= rc
.right
- rc
.left
;
880 p
+= 1; /* advance past the Tab */
881 /* get text size after the tab */
882 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
883 DT_SINGLELINE
|DT_CALCRECT
);
884 lpitem
->dxTab
+= txtwidth
;
885 txtheight
= max( txtheight
, tmpheight
);
886 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
887 tmprc
.right
- tmprc
.left
; /* space for the short cut */
889 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
890 DT_SINGLELINE
|DT_CALCRECT
);
891 txtwidth
= rc
.right
- rc
.left
;
892 lpitem
->dxTab
+= txtwidth
;
894 lpitem
->Rect
.right
+= 2 + txtwidth
;
895 itemheight
= max( itemheight
,
896 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
898 if (hfontOld
) SelectObject (hdc
, hfontOld
);
899 } else if( menuBar
) {
900 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
902 lpitem
->Rect
.bottom
+= itemheight
;
903 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
906 /***********************************************************************
907 * MenuPopupMenuCalcSize
909 * Calculate the size of a popup menu.
911 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
913 ROSMENUITEMINFO lpitem
;
916 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
918 MenuInfo
->Width
= MenuInfo
->Height
= 0;
919 if (MenuInfo
->MenuItemCount
== 0)
921 MenuSetRosMenuInfo(MenuInfo
);
926 SelectObject( hdc
, hMenuFont
);
931 MenuInfo
->maxBmpSize
.cx
= 0;
932 MenuInfo
->maxBmpSize
.cy
= 0;
934 MenuInitRosMenuItemInfo(&lpitem
);
935 while (start
< MenuInfo
->MenuItemCount
)
940 maxTab
= maxTabWidth
= 0;
942 /* Parse items until column break or end of menu */
943 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
945 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
947 MenuCleanupRosMenuItemInfo(&lpitem
);
948 MenuSetRosMenuInfo(MenuInfo
);
952 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
954 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
);
955 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
957 MenuCleanupRosMenuItemInfo(&lpitem
);
958 MenuSetRosMenuInfo(MenuInfo
);
961 // Not sure here,, The patch from wine removes this.
962 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
966 maxX
= max(maxX
, lpitem
.Rect
.right
);
967 orgY
= lpitem
.Rect
.bottom
;
968 if ((lpitem
.lpstr
) && lpitem
.dxTab
)
970 maxTab
= max( maxTab
, lpitem
.dxTab
);
971 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.dxTab
);
975 /* Finish the column (set all items to the largest width found) */
976 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
979 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
981 lpitem
.Rect
.right
= maxX
;
982 if ((lpitem
.lpstr
) && 0 != lpitem
.dxTab
)
984 lpitem
.dxTab
= maxTab
;
986 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
990 MenuInfo
->Height
= max(MenuInfo
->Height
, orgY
);
993 MenuInfo
->Width
= maxX
;
995 /* space for 3d border */
996 MenuInfo
->Height
+= 2;
997 MenuInfo
->Width
+= 2;
999 MenuCleanupRosMenuItemInfo(&lpitem
);
1000 MenuSetRosMenuInfo(MenuInfo
);
1001 ReleaseDC( 0, hdc
);
1004 /***********************************************************************
1005 * MenuMenuBarCalcSize
1007 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1008 * height is off by 1 pixel which causes lengthy window relocations when
1009 * active document window is maximized/restored.
1011 * Calculate the size of the menu bar.
1013 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1014 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
1016 ROSMENUITEMINFO ItemInfo
;
1017 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1019 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
1020 if (MenuInfo
->MenuItemCount
== 0) return;
1021 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
1022 MenuInfo
->Width
= lprect
->right
- lprect
->left
;
1023 MenuInfo
->Height
= 0;
1024 maxY
= lprect
->top
+ 1;
1028 MenuInfo
->maxBmpSize
.cx
= 0;
1029 MenuInfo
->maxBmpSize
.cy
= 0;
1031 MenuInitRosMenuItemInfo(&ItemInfo
);
1032 while (start
< MenuInfo
->MenuItemCount
)
1034 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1036 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1039 orgX
= lprect
->left
;
1042 /* Parse items until line break or end of menu */
1043 for (i
= start
; i
< MenuInfo
->MenuItemCount
; i
++)
1045 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1047 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1049 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1050 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
);
1051 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1053 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1057 if (ItemInfo
.Rect
.right
> lprect
->right
)
1059 if (i
!= start
) break;
1060 else ItemInfo
.Rect
.right
= lprect
->right
;
1062 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
1063 orgX
= ItemInfo
.Rect
.right
;
1064 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1066 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1068 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1074 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1075 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1077 /* Finish the line (set all items to the largest height found) */
1080 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1082 ItemInfo
.Rect
.bottom
= maxY
;
1083 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
1088 start
= i
; /* This works! */
1092 lprect
->bottom
= maxY
;
1093 MenuInfo
->Height
= lprect
->bottom
- lprect
->top
;
1094 MenuSetRosMenuInfo(MenuInfo
);
1098 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1099 /* the last item (if several lines, only move the last line) */
1100 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1102 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1105 orgY
= ItemInfo
.Rect
.top
;
1106 orgX
= lprect
->right
;
1107 for (i
= MenuInfo
->MenuItemCount
- 1; helpPos
<= i
; i
--)
1113 if (ItemInfo
.Rect
.top
!= orgY
)
1115 break; /* Other line */
1117 if (orgX
<= ItemInfo
.Rect
.right
)
1119 break; /* Too far right already */
1121 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1122 ItemInfo
.Rect
.right
= orgX
;
1123 orgX
= ItemInfo
.Rect
.left
;
1124 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1125 if (helpPos
+ 1 <= i
&&
1126 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1128 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1134 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1137 /***********************************************************************
1140 * Draw a single menu item.
1142 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1143 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1147 BOOL flat_menu
= FALSE
;
1149 PWND Wnd
= ValidateHwnd(hWnd
);
1154 if (lpitem
->fType
& MF_SYSMENU
)
1156 if ( (Wnd
->style
& WS_MINIMIZE
))
1158 UserGetInsideRectNC(Wnd
, &rect
);
1159 UserDrawSysMenuButton(hWnd
, hdc
, &rect
,
1160 lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1165 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1166 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1170 if (lpitem
->fState
& MF_HILITE
)
1172 if(menuBar
&& !flat_menu
) {
1173 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1174 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1176 if (lpitem
->fState
& MF_GRAYED
)
1177 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1179 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1180 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1185 if (lpitem
->fState
& MF_GRAYED
)
1186 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1188 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1189 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1192 rect
= lpitem
->Rect
;
1194 if (lpitem
->fType
& MF_OWNERDRAW
)
1197 ** Experimentation under Windows reveals that an owner-drawn
1198 ** menu is given the rectangle which includes the space it requested
1199 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1200 ** and a popup-menu arrow. This is the value of lpitem->rect.
1201 ** Windows will leave all drawing to the application except for
1202 ** the popup-menu arrow. Windows always draws that itself, after
1203 ** the menu owner has finished drawing.
1207 dis
.CtlType
= ODT_MENU
;
1209 dis
.itemID
= lpitem
->wID
;
1210 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1212 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1213 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1214 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1215 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1216 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1219 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1220 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1221 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1222 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1224 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1225 /* Draw the popup-menu arrow */
1226 if (lpitem
->fType
& MF_POPUP
)
1229 CopyRect(&rectTemp
, &rect
);
1230 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1231 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1236 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1238 if (lpitem
->fState
& MF_HILITE
)
1242 InflateRect (&rect
, -1, -1);
1243 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1244 InflateRect (&rect
, 1, 1);
1245 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1250 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1252 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1256 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1258 SetBkMode( hdc
, TRANSPARENT
);
1260 /* vertical separator */
1261 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1268 rc
.bottom
= Height
- 3;
1271 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1272 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1273 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1274 LineTo( hdc
, rc
.left
, rc
.bottom
);
1275 SelectObject( hdc
, oldPen
);
1278 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1281 /* horizontal separator */
1282 if (lpitem
->fType
& MF_SEPARATOR
)
1289 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1292 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1293 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1294 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1295 LineTo( hdc
, rc
.right
, rc
.top
);
1296 SelectObject( hdc
, oldPen
);
1299 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1304 /* helper lines for debugging */
1305 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1306 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1307 SelectObject(hdc
, GetStockObject(DC_PEN
));
1308 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1309 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1310 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1316 INT y
= rect
.top
+ rect
.bottom
;
1318 int checked
= FALSE
;
1319 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1320 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1321 /* Draw the check mark
1324 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1326 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1327 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1328 lpitem
->hbmpUnchecked
;
1329 if (bm
) /* we have a custom bitmap */
1331 HDC hdcMem
= CreateCompatibleDC( hdc
);
1333 SelectObject( hdcMem
, bm
);
1334 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1335 check_bitmap_width
, check_bitmap_height
,
1336 hdcMem
, 0, 0, SRCCOPY
);
1340 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1343 CopyRect(&r
, &rect
);
1344 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1345 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1346 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1347 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1351 if ( lpitem
->hbmpItem
)
1354 CopyRect(&bmpRect
, &rect
);
1355 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1356 bmpRect
.left
+= check_bitmap_width
+ 2;
1357 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1359 bmpRect
.right
= bmpRect
.left
+ MenuInfo
->maxBmpSize
.cx
;
1360 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1363 /* Draw the popup-menu arrow */
1364 if (lpitem
->fType
& MF_POPUP
)
1367 CopyRect(&rectTemp
, &rect
);
1368 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1369 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1372 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1373 rect
.left
+= check_bitmap_width
;
1374 rect
.right
-= check_bitmap_width
;
1376 else if( lpitem
->hbmpItem
)
1377 { /* Draw the bitmap */
1378 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
->Self
, WndOwner
, odaction
, menuBar
);
1381 /* process text if present */
1387 UINT uFormat
= menuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
1388 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1390 if(MenuInfo
->dwStyle
& MNS_CHECKORBMP
)
1391 rect
.left
+= max(0, MenuInfo
->maxBmpSize
.cx
- GetSystemMetrics(SM_CXMENUCHECK
));
1393 rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
1395 if ( lpitem
->fState
& MFS_DEFAULT
)
1397 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1401 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1402 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1405 Text
= (PWCHAR
) lpitem
->dwTypeData
;
1408 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1409 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1413 if(lpitem
->fState
& MF_GRAYED
)
1415 if (!(lpitem
->fState
& MF_HILITE
) )
1417 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1418 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1419 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1420 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1422 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1425 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1427 /* paint the shortcut text */
1428 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1430 if (L
'\t' == Text
[i
])
1432 rect
.left
= lpitem
->dxTab
;
1433 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1437 rect
.right
= lpitem
->dxTab
;
1438 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1441 if (lpitem
->fState
& MF_GRAYED
)
1443 if (!(lpitem
->fState
& MF_HILITE
) )
1445 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1446 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1447 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1448 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1450 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1452 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1456 SelectObject (hdc
, hfontOld
);
1460 /***********************************************************************
1463 * Paint a popup menu.
1465 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1467 HBRUSH hPrevBrush
= 0;
1470 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1472 GetClientRect( hwnd
, &rect
);
1474 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1475 && (SelectObject( hdc
, hMenuFont
)))
1479 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1481 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1484 BOOL flat_menu
= FALSE
;
1485 ROSMENUINFO MenuInfo
;
1486 ROSMENUITEMINFO ItemInfo
;
1488 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1490 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1492 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1494 /* draw menu items */
1495 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.MenuItemCount
)
1499 MenuInitRosMenuItemInfo(&ItemInfo
);
1501 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
1503 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1505 MenuDrawMenuItem(hwnd
, &MenuInfo
, MenuInfo
.WndOwner
, hdc
, &ItemInfo
,
1506 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
1510 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1514 SelectObject( hdc
, hPrevBrush
);
1519 /***********************************************************************
1522 * Paint a menu bar. Returns the height of the menu bar.
1523 * called from [windows/nonclient.c]
1525 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1530 HMENU hMenu
= GetMenu(hwnd
);
1532 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
1534 return GetSystemMetrics(SM_CYMENU
);
1539 hfontOld
= SelectObject(hDC
, hMenuFont
);
1541 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
1543 lprect
->bottom
= lprect
->top
+ lppop
.Height
;
1545 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1546 return lppop
.Height
;
1549 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1552 /***********************************************************************
1555 * Display a popup menu.
1557 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
1558 INT x
, INT y
, INT xanchor
, INT yanchor
)
1560 ROSMENUINFO MenuInfo
;
1561 ROSMENUITEMINFO ItemInfo
;
1567 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1568 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1570 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
1571 if (MenuInfo
.FocusedItem
!= NO_SELECTED_ITEM
)
1573 MenuInitRosMenuItemInfo(&ItemInfo
);
1574 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1576 ItemInfo
.fMask
|= MIIM_STATE
;
1577 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1578 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1580 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1581 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1584 /* store the owner for DrawItem */
1585 MenuInfo
.WndOwner
= hwndOwner
;
1586 MenuSetRosMenuInfo(&MenuInfo
);
1588 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
1590 /* adjust popup menu pos so that it fits within the desktop */
1592 width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1593 height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1595 /* FIXME: should use item rect */
1598 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
1599 info
.cbSize
= sizeof(info
);
1600 GetMonitorInfoW( monitor
, &info
);
1602 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
1603 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
1605 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
1606 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
1608 if( x
+ width
> info
.rcWork
.right
)
1610 if( xanchor
&& x
>= width
- xanchor
)
1611 x
-= width
- xanchor
;
1613 if( x
+ width
> info
.rcWork
.right
)
1614 x
= info
.rcWork
.right
- width
;
1616 if( x
< info
.rcWork
.left
) x
= info
.rcWork
.left
;
1618 if( y
+ height
> info
.rcWork
.bottom
)
1620 if( yanchor
&& y
>= height
+ yanchor
)
1621 y
-= height
+ yanchor
;
1623 if( y
+ height
> info
.rcWork
.bottom
)
1624 y
= info
.rcWork
.bottom
- height
;
1626 if( y
< info
.rcWork
.top
) y
= info
.rcWork
.top
;
1628 /* NOTE: In Windows, top menu popup is not owned. */
1629 MenuInfo
.Wnd
= CreateWindowExW( 0, POPUPMENU_CLASS_ATOMW
, NULL
,
1630 WS_POPUP
, x
, y
, width
, height
,
1631 hwndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
1632 (LPVOID
) MenuInfo
.Self
);
1633 if ( !MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
)) return FALSE
;
1635 top_popup
= MenuInfo
.Wnd
;
1636 top_popup_hmenu
= hmenu
;
1639 /* Display the window */
1641 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1642 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1643 UpdateWindow( MenuInfo
.Wnd
);
1648 /***********************************************************************
1651 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
1652 BOOL sendMenuSelect
, HMENU topmenu
)
1654 ROSMENUITEMINFO ItemInfo
;
1655 ROSMENUINFO TopMenuInfo
;
1658 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1660 if (!hmenu
|| !hmenu
->MenuItemCount
|| !hmenu
->Wnd
) return;
1661 if (hmenu
->FocusedItem
== wIndex
) return;
1662 if (hmenu
->Flags
& MF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
1663 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1665 top_popup
= hmenu
->Wnd
;
1666 top_popup_hmenu
= hmenu
->Self
;
1669 SelectObject( hdc
, hMenuFont
);
1671 MenuInitRosMenuItemInfo(&ItemInfo
);
1673 /* Clear previous highlighted item */
1674 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1676 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1678 ItemInfo
.fMask
|= MIIM_STATE
;
1679 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1680 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1682 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
1683 hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1687 /* Highlight new item (if any) */
1688 hmenu
->FocusedItem
= wIndex
;
1689 MenuSetRosMenuInfo(hmenu
);
1690 if (hmenu
->FocusedItem
!= NO_SELECTED_ITEM
)
1692 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
))
1694 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
1696 ItemInfo
.fMask
|= MIIM_STATE
;
1697 ItemInfo
.fState
|= MF_HILITE
;
1698 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->FocusedItem
, &ItemInfo
);
1699 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
1700 &ItemInfo
, hmenu
->Height
, ! (hmenu
->Flags
& MF_POPUP
),
1705 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1706 MAKELONG(ItemInfo
.fType
& MF_POPUP
? wIndex
: ItemInfo
.wID
,
1707 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
1708 (hmenu
->Flags
& MF_SYSMENU
)), (LPARAM
) hmenu
->Self
);
1712 else if (sendMenuSelect
) {
1715 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
1716 if (pos
!= NO_SELECTED_ITEM
)
1718 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
1719 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
1721 SendMessageW(hwndOwner
, WM_MENUSELECT
,
1722 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
1724 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
1730 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1731 ReleaseDC(hmenu
->Wnd
, hdc
);
1734 /***********************************************************************
1737 * Moves currently selected item according to the Offset parameter.
1738 * If there is no selection then it should select the last item if
1739 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
1741 static void FASTCALL
1742 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
1745 ROSMENUITEMINFO ItemInfo
;
1748 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
1750 /* Prevent looping */
1751 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
1753 else if (Offset
< -1)
1755 else if (Offset
> 1)
1758 MenuInitRosMenuItemInfo(&ItemInfo
);
1760 OrigPos
= MenuInfo
->FocusedItem
;
1761 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
1768 i
= MenuInfo
->FocusedItem
;
1775 /* Clip and wrap around */
1778 i
= MenuInfo
->MenuItemCount
- 1;
1780 else if (i
>= MenuInfo
->MenuItemCount
)
1784 /* If this is a good candidate; */
1785 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1786 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1788 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1789 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1792 } while (i
!= OrigPos
);
1795 MenuCleanupRosMenuItemInfo(&ItemInfo
);
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
);
1806 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*) lParam
;
1807 SetWindowLongPtrA(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
1811 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1812 return MA_NOACTIVATE
;
1817 BeginPaint(Wnd
, &ps
);
1818 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrA(Wnd
, 0));
1823 case WM_PRINTCLIENT
:
1825 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1826 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1834 /* zero out global pointer in case resident popup window was destroyed. */
1835 if (Wnd
== top_popup
)
1838 top_popup_hmenu
= NULL
;
1845 if (0 == GetWindowLongPtrA(Wnd
, 0))
1847 OutputDebugStringA("no menu to display\n");
1852 SetWindowLongPtrA(Wnd
, 0, 0);
1856 case MM_SETMENUHANDLE
:
1857 SetWindowLongPtrA(Wnd
, 0, wParam
);
1860 case MM_GETMENUHANDLE
:
1862 return GetWindowLongPtrA(Wnd
, 0);
1865 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1871 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1873 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1879 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1880 SetWindowLongPtrW(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
1884 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1885 return MA_NOACTIVATE
;
1890 BeginPaint(Wnd
, &ps
);
1891 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1896 case WM_PRINTCLIENT
:
1898 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1899 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1907 /* zero out global pointer in case resident popup window was destroyed. */
1908 if (Wnd
== top_popup
)
1911 top_popup_hmenu
= NULL
;
1918 if (0 == GetWindowLongPtrW(Wnd
, 0))
1920 OutputDebugStringA("no menu to display\n");
1925 SetWindowLongPtrW(Wnd
, 0, 0);
1929 case MM_SETMENUHANDLE
:
1930 SetWindowLongPtrW(Wnd
, 0, wParam
);
1933 case MM_GETMENUHANDLE
:
1935 return GetWindowLongPtrW(Wnd
, 0);
1938 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1944 /**********************************************************************
1945 * MENU_ParseResource
1947 * Parse a standard menu resource and add items to the menu.
1948 * Return a pointer to the end of the resource.
1950 * NOTE: flags is equivalent to the mtOption field
1952 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1961 flags
= GET_WORD(res
);
1963 /* remove MF_END flag before passing it to AppendMenu()! */
1964 end
= (flags
& MF_END
);
1965 if(end
) flags
^= MF_END
;
1967 res
+= sizeof(WORD
);
1968 if(!(flags
& MF_POPUP
))
1971 res
+= sizeof(WORD
);
1975 res
+= strlen(str
) + 1;
1977 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1978 if (flags
& MF_POPUP
)
1980 hSubMenu
= CreatePopupMenu();
1981 if(!hSubMenu
) return NULL
;
1982 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
1985 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
1987 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1989 else /* Not a popup */
1994 flags
= MF_SEPARATOR
;
1998 if (*(LPCWSTR
)str
== 0)
1999 flags
= MF_SEPARATOR
;
2002 if (flags
& MF_SEPARATOR
)
2004 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
2005 flags
|= MF_GRAYED
| MF_DISABLED
;
2009 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
2011 AppendMenuW(hMenu
, flags
, id
,
2012 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2019 /**********************************************************************
2020 * MENUEX_ParseResource
2022 * Parse an extended menu resource and add items to the menu.
2023 * Return a pointer to the end of the resource.
2025 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
2031 mii
.cbSize
= sizeof(mii
);
2032 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
2033 mii
.fType
= GET_DWORD(res
);
2034 res
+= sizeof(DWORD
);
2035 mii
.fState
= GET_DWORD(res
);
2036 res
+= sizeof(DWORD
);
2037 mii
.wID
= GET_DWORD(res
);
2038 res
+= sizeof(DWORD
);
2039 resinfo
= GET_WORD(res
);
2040 res
+= sizeof(WORD
);
2041 /* Align the text on a word boundary. */
2042 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2043 mii
.dwTypeData
= (LPWSTR
) res
;
2044 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2045 /* Align the following fields on a dword boundary. */
2046 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2048 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2049 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2051 if (resinfo
& 1) { /* Pop-up? */
2052 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2053 res
+= sizeof(DWORD
);
2054 mii
.hSubMenu
= CreatePopupMenu();
2057 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
2058 DestroyMenu(mii
.hSubMenu
);
2061 mii
.fMask
|= MIIM_SUBMENU
;
2062 mii
.fType
|= MF_POPUP
;
2063 mii
.wID
= (UINT
) mii
.hSubMenu
;
2065 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
2067 mii
.fType
|= MF_SEPARATOR
;
2069 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2070 } while (!(resinfo
& MF_END
));
2075 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
2077 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
2078 LRESULT Result
= (LRESULT
)hmenu
;
2079 MENUINFO menuinfo
= {0};
2080 MENUITEMINFOW info
= {0};
2082 // removing space for checkboxes from menu
2083 menuinfo
.cbSize
= sizeof(menuinfo
);
2084 menuinfo
.fMask
= MIM_STYLE
;
2085 GetMenuInfo(hmenu
, &menuinfo
);
2086 menuinfo
.dwStyle
|= MNS_NOCHECK
;
2087 SetMenuInfo(hmenu
, &menuinfo
);
2089 // adding bitmaps to menu items
2090 info
.cbSize
= sizeof(info
);
2091 info
.fMask
|= MIIM_BITMAP
;
2092 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
2093 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
2094 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
2095 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
2096 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
2097 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
2098 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
2099 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
2101 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
2108 NONCLIENTMETRICSW ncm
;
2110 /* get the menu font */
2111 if(!hMenuFont
|| !hMenuFontBold
)
2113 ncm
.cbSize
= sizeof(ncm
);
2114 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
2116 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
2120 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2121 if(hMenuFont
== NULL
)
2123 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
2127 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
2128 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
2129 if(hMenuFontBold
== NULL
)
2131 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
2132 DeleteObject(hMenuFont
);
2146 DeleteObject(hMenuFont
);
2152 DeleteObject(hMenuFontBold
);
2153 hMenuFontBold
= NULL
;
2157 /***********************************************************************
2158 * DrawMenuBarTemp (USER32.@)
2162 * called by W98SE desk.cpl Control Panel Applet
2164 * Not 100% sure about the param names, but close.
2169 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2171 ROSMENUINFO MenuInfo
;
2172 ROSMENUITEMINFO ItemInfo
;
2174 HFONT FontOld
= NULL
;
2175 BOOL flat_menu
= FALSE
;
2177 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2181 Menu
= GetMenu(Wnd
);
2189 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2191 return GetSystemMetrics(SM_CYMENU
);
2194 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2196 FontOld
= SelectObject(DC
, Font
);
2198 if (0 == MenuInfo
.Height
)
2200 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2203 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
2205 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2207 SelectObject(DC
, GetStockObject(DC_PEN
));
2208 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2209 MoveToEx(DC
, Rect
->left
, Rect
->bottom
, NULL
);
2210 LineTo(DC
, Rect
->right
, Rect
->bottom
);
2212 if (0 == MenuInfo
.MenuItemCount
)
2214 SelectObject(DC
, FontOld
);
2215 return GetSystemMetrics(SM_CYMENU
);
2218 MenuInitRosMenuItemInfo(&ItemInfo
);
2219 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2221 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2223 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2224 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
2227 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2229 SelectObject(DC
, FontOld
);
2231 return MenuInfo
.Height
;
2234 /***********************************************************************
2237 * Display the sub-menu of the selected item of this menu.
2238 * Return the handle of the submenu, or menu if no submenu to display.
2240 static HMENU FASTCALL
2241 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2243 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2245 ROSMENUITEMINFO ItemInfo
;
2246 ROSMENUINFO SubMenuInfo
;
2250 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2252 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2254 return MenuInfo
->Self
;
2257 MenuInitRosMenuItemInfo(&ItemInfo
);
2258 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2260 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2261 return MenuInfo
->Self
;
2263 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2265 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2266 return MenuInfo
->Self
;
2269 /* message must be sent before using item,
2270 because nearly everything may be changed by the application ! */
2272 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2273 if (0 == (Flags
& TPM_NONOTIFY
))
2275 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2276 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2279 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2281 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2282 return MenuInfo
->Self
;
2284 Rect
= ItemInfo
.Rect
;
2286 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2287 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2289 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2291 Dc
= GetDC(MenuInfo
->Wnd
);
2295 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2298 SelectObject(Dc
, hMenuFont
);
2299 ItemInfo
.fMask
|= MIIM_STATE
;
2300 ItemInfo
.fState
|= MF_HILITE
;
2301 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2302 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2303 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2304 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2307 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2308 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2310 ItemInfo
.Rect
= Rect
;
2313 ItemInfo
.fMask
|= MIIM_STATE
;
2314 ItemInfo
.fState
|= MF_MOUSESELECT
;
2315 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2317 if (IS_SYSTEM_MENU(MenuInfo
))
2319 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2320 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2322 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2323 Rect
.top
= Rect
.bottom
;
2324 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2325 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2329 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2330 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2332 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2333 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2334 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2335 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2336 - GetSystemMetrics(SM_CYBORDER
);
2340 Rect
.left
+= ItemInfo
.Rect
.left
;
2341 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2342 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2343 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2347 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
, Flags
,
2348 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2349 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2351 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2354 Ret
= ItemInfo
.hSubMenu
;
2355 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2360 /**********************************************************************
2363 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2365 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2367 void MENU_EndMenu( HWND hwnd
)
2369 ROSMENUINFO MenuInfo
;
2371 if (top_popup_hmenu
)
2372 Ret
= MenuGetRosMenuInfo(&MenuInfo
, top_popup_hmenu
);
2373 if (Ret
&& hwnd
== MenuInfo
.WndOwner
) EndMenu();
2376 /***********************************************************************
2379 * Hide the sub-popup menus of this menu.
2381 static void FASTCALL
2382 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2383 BOOL SendMenuSelect
, UINT wFlags
)
2385 ROSMENUINFO SubMenuInfo
;
2386 ROSMENUITEMINFO ItemInfo
;
2388 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2390 if (NULL
!= MenuInfo
&& NULL
!= top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2392 MenuInitRosMenuItemInfo(&ItemInfo
);
2393 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2394 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2395 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2396 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2398 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2401 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2402 ItemInfo
.fMask
|= MIIM_STATE
;
2403 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2404 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2406 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2407 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2408 DestroyWindow(SubMenuInfo
.Wnd
);
2409 SubMenuInfo
.Wnd
= NULL
;
2410 MenuSetRosMenuInfo(&SubMenuInfo
);
2412 if (!(wFlags
& TPM_NONOTIFY
))
2413 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
2414 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
2419 /***********************************************************************
2420 * MenuSwitchTracking
2422 * Helper function for menu navigation routines.
2424 static void FASTCALL
2425 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
2427 ROSMENUINFO TopMenuInfo
;
2429 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2431 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2432 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2433 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2435 /* both are top level menus (system and menu-bar) */
2436 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2437 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2438 Mt
->TopMenu
= PtMenuInfo
->Self
;
2442 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
2445 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2448 /***********************************************************************
2449 * MenuExecFocusedItem
2451 * Execute a menu item (for instance when user pressed Enter).
2452 * Return the wID of the executed item. Otherwise, -1 indicating
2453 * that no menu item was executed, -2 if a popup is shown;
2454 * Have to receive the flags for the TrackPopupMenu options to avoid
2455 * sending unwanted message.
2459 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2461 ROSMENUITEMINFO ItemInfo
;
2464 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2466 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2471 MenuInitRosMenuItemInfo(&ItemInfo
);
2472 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2474 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2478 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2480 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2482 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2483 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2485 /* If TPM_RETURNCMD is set you return the id, but
2486 do not send a message to the owner */
2487 if (0 == (Flags
& TPM_RETURNCMD
))
2489 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2491 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2492 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2496 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2497 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2498 MenuInfo
->FocusedItem
,
2499 (LPARAM
)MenuInfo
->Self
);
2501 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2505 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2511 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2518 /***********************************************************************
2521 * Return TRUE if we can go on with menu tracking.
2523 static BOOL FASTCALL
2524 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2527 ROSMENUINFO MenuInfo
;
2528 ROSMENUITEMINFO Item
;
2530 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2534 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2538 if (IS_SYSTEM_MENU(&MenuInfo
))
2544 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2546 MenuInitRosMenuItemInfo(&Item
);
2547 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2549 MenuCleanupRosMenuItemInfo(&Item
);
2553 if (!(Item
.fType
& MF_SEPARATOR
) &&
2554 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2556 if (MenuInfo
.FocusedItem
!= Index
)
2558 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2561 /* If the popup menu is not already "popped" */
2562 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2564 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2568 MenuCleanupRosMenuItemInfo(&Item
);
2573 /* else the click was on the menu bar, finish the tracking */
2578 /***********************************************************************
2581 * Return the value of MenuExecFocusedItem if
2582 * the selected item was not a popup. Else open the popup.
2583 * A -1 return value indicates that we go on with menu tracking.
2587 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2590 ROSMENUINFO MenuInfo
;
2591 ROSMENUITEMINFO ItemInfo
;
2593 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2598 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2603 if (! IS_SYSTEM_MENU(&MenuInfo
))
2605 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2607 MenuInitRosMenuItemInfo(&ItemInfo
);
2608 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2609 MenuInfo
.FocusedItem
== Id
)
2611 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2613 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2614 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2615 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2617 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2619 /* If we are dealing with the top-level menu */
2620 /* and this is a click on an already "popped" item: */
2621 /* Stop the menu tracking and close the opened submenus */
2622 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2624 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2628 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2629 MenuInfo
.TimeToHide
= TRUE
;
2630 MenuSetRosMenuInfo(&MenuInfo
);
2636 /***********************************************************************
2639 * Walks menu chain trying to find a menu pt maps to.
2641 static HMENU FASTCALL
2642 MenuPtMenu(HMENU Menu
, POINT Pt
)
2644 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2645 ROSMENUINFO MenuInfo
;
2646 ROSMENUITEMINFO ItemInfo
;
2650 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2655 /* try subpopup first (if any) */
2656 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2658 MenuInitRosMenuItemInfo(&ItemInfo
);
2659 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2660 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2661 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2663 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2666 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2670 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2673 /* check the current window (avoiding WM_HITTEST) */
2674 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2675 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2677 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2682 else if (HTSYSMENU
== Ht
)
2684 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2686 else if (HTMENU
== Ht
)
2688 Ret
= GetMenu(MenuInfo
.Wnd
);
2694 /***********************************************************************
2697 * Return TRUE if we can go on with menu tracking.
2699 static BOOL FASTCALL
2700 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2703 ROSMENUINFO MenuInfo
;
2704 ROSMENUITEMINFO ItemInfo
;
2708 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2712 if (IS_SYSTEM_MENU(&MenuInfo
))
2718 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2723 Index
= NO_SELECTED_ITEM
;
2726 if (NO_SELECTED_ITEM
== Index
)
2728 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2729 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2731 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2735 else if (MenuInfo
.FocusedItem
!= Index
)
2737 MenuInitRosMenuItemInfo(&ItemInfo
);
2738 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2739 !(ItemInfo
.fType
& MF_SEPARATOR
))
2741 MenuSwitchTracking(Mt
, &MenuInfo
, Index
, Flags
);
2742 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2743 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2745 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2751 /***********************************************************************
2754 * Return the handle of the selected sub-popup menu (if any).
2756 static HMENU FASTCALL
2757 MenuGetSubPopup(HMENU Menu
)
2759 ROSMENUINFO MenuInfo
;
2760 ROSMENUITEMINFO ItemInfo
;
2762 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2763 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2768 MenuInitRosMenuItemInfo(&ItemInfo
);
2769 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2771 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2774 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2776 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2777 return ItemInfo
.hSubMenu
;
2780 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2784 /***********************************************************************
2787 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2789 static LRESULT FASTCALL
2790 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
, UINT wFlags
)
2792 ROSMENUINFO TopMenuInfo
;
2793 ROSMENUINFO MenuInfo
;
2795 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2797 return (LRESULT
) FALSE
;
2800 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2801 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2803 MDINEXTMENU NextMenu
;
2808 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2809 NextMenu
.hmenuNext
= NULL
;
2810 NextMenu
.hwndNext
= NULL
;
2811 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2813 TRACE("%p [%p] -> %p [%p]\n",
2814 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2816 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2818 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2819 NewWnd
= Mt
->OwnerWnd
;
2820 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2822 /* switch to the menu bar */
2824 if (0 != (Style
& WS_CHILD
)
2825 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2832 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2836 Id
= MenuInfo
.MenuItemCount
- 1;
2839 else if (0 != (Style
& WS_SYSMENU
))
2841 /* switch to the system menu */
2842 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2849 else /* application returned a new menu to switch to */
2851 NewMenu
= NextMenu
.hmenuNext
;
2852 NewWnd
= NextMenu
.hwndNext
;
2854 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2856 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2858 if (0 != (Style
& WS_SYSMENU
)
2859 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2861 /* get the real system menu */
2862 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2864 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2866 /* FIXME: Not sure what to do here;
2867 * perhaps try to track NewMenu as a popup? */
2869 WARN(" -- got confused.\n");
2879 if (NewMenu
!= Mt
->TopMenu
)
2881 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2883 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2885 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2889 if (NewWnd
!= Mt
->OwnerWnd
)
2891 Mt
->OwnerWnd
= NewWnd
;
2892 SetCapture(Mt
->OwnerWnd
);
2893 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
);
2896 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2897 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2899 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2908 /***********************************************************************
2911 * The idea is not to show the popup if the next input message is
2912 * going to hide it anyway.
2914 static BOOL FASTCALL
2915 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
2919 Msg
.hwnd
= Mt
->OwnerWnd
;
2921 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2922 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
2927 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2928 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
2930 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2931 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2932 if (WM_KEYDOWN
== Msg
.message
2933 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
2935 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2942 /* failures go through this */
2943 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
2948 /***********************************************************************
2951 * Handle a VK_ESCAPE key event in a menu.
2953 static BOOL FASTCALL
2954 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
2956 BOOL EndMenu
= TRUE
;
2957 ROSMENUINFO MenuInfo
;
2958 HMENU MenuTmp
, MenuPrev
;
2960 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2962 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
2963 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
2965 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2967 /* close topmost popup */
2968 while (MenuTmp
!= Mt
->CurrentMenu
)
2971 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2974 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
2976 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
, Flags
);
2978 Mt
->CurrentMenu
= MenuPrev
;
2986 /***********************************************************************
2989 * Handle a VK_LEFT key event in a menu.
2991 static void FASTCALL
2992 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
2994 ROSMENUINFO MenuInfo
;
2995 ROSMENUINFO TopMenuInfo
;
2996 ROSMENUINFO PrevMenuInfo
;
2997 HMENU MenuTmp
, MenuPrev
;
3000 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3002 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3007 /* Try to move 1 column left (if possible) */
3008 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
3010 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3012 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3017 /* close topmost popup */
3018 while (MenuTmp
!= Mt
->CurrentMenu
)
3021 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3024 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3028 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
, Flags
);
3029 Mt
->CurrentMenu
= MenuPrev
;
3031 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3035 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
3037 /* move menu bar selection if no more popups are left */
3039 if (! MenuDoNextMenu(Mt
, VK_LEFT
, Flags
))
3041 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3044 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3046 /* A sublevel menu was displayed - display the next one
3047 * unless there is another displacement coming up */
3049 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3050 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3052 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3059 /***********************************************************************
3062 * Handle a VK_RIGHT key event in a menu.
3064 static void FASTCALL
MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3067 ROSMENUINFO MenuInfo
;
3068 ROSMENUINFO CurrentMenuInfo
;
3071 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3072 Mt
->CurrentMenu
, Mt
->TopMenu
);
3074 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
)) return;
3075 if ((MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3077 /* If already displaying a popup, try to display sub-popup */
3079 hmenutmp
= Mt
->CurrentMenu
;
3080 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3082 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3085 /* if subpopup was displayed then we are done */
3086 if (hmenutmp
!= Mt
->CurrentMenu
) return;
3089 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3094 /* Check to see if there's another column */
3095 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
3097 TRACE("Going to %d.\n", NextCol
);
3098 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3100 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3105 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3107 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3109 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);