3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * Partly based on Wine code
6 * Copyright 1993 Martin Ayotte
7 * Copyright 1994 Alexandre Julliard
8 * Copyright 1997 Morten Welinder
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /* $Id: menu.c,v 1.56 2004/03/15 23:49:29 gvg Exp $
26 * PROJECT: ReactOS user32.dll
27 * FILE: lib/user32/windows/menu.c
29 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
31 * 09-05-2001 CSH Created
34 /* INCLUDES ******************************************************************/
46 #include <user32/callback.h>
47 #include "user32/regcontrol.h"
48 #include "../controls/controls.h"
53 /* internal popup menu window messages */
54 #define MM_SETMENUHANDLE (WM_USER + 0)
55 #define MM_GETMENUHANDLE (WM_USER + 1)
57 /* Internal MenuTrackMenu() flags */
58 #define TPM_INTERNAL 0xF0000000
59 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
60 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
61 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
63 /* TYPES *********************************************************************/
65 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
67 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
68 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
69 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
71 #define IS_SYSTEM_MENU(MenuInfo) \
72 (0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
74 #define IS_SYSTEM_POPUP(MenuInfo) \
75 (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
77 #define IS_MAGIC_ITEM(Bmp) ((int) Bmp <12)
79 #define MENU_BAR_ITEMS_SPACE (12)
80 #define SEPARATOR_HEIGHT (5)
81 #define MENU_TAB_SPACE (8)
87 #define MF_END (0x0080)
91 #define MIIM_STRING (0x00000040)
94 #define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
95 #define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
96 #define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */
97 #define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */
99 /* internal flags for menu tracking */
101 #define TF_ENDMENU 0x0001
102 #define TF_SUSPENDPOPUP 0x0002
103 #define TF_SKIPREMOVE 0x0004
108 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
109 HMENU TopMenu
; /* initial menu */
110 HWND OwnerWnd
; /* where notifications are sent */
114 static LRESULT WINAPI
PopupMenuWndProcW(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
116 /*********************************************************************
117 * PopupMenu class descriptor
119 const struct builtin_class_descr POPUPMENU_builtin_class
=
121 POPUPMENU_CLASS_ATOMW
, /* name */
122 CS_GLOBALCLASS
| CS_SAVEBITS
| CS_DBLCLKS
, /* style */
123 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
124 (WNDPROC
) NULL
, /* FIXME - procA */
125 sizeof(MENUINFO
*), /* extra */
126 (LPCWSTR
) IDC_ARROW
, /* cursor */
127 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
131 /* INTERNAL FUNCTIONS ********************************************************/
133 /* Rip the fun and easy to use and fun WINE unicode string manipulation routines.
134 * Of course I didnt copy the ASM code because we want this to be portable
135 * and it needs to go away.
139 #define GET_WORD(ptr) (*(WORD *)(ptr))
142 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
145 HFONT hMenuFont
= NULL
;
146 HFONT hMenuFontBold
= NULL
;
148 /* Flag set by EndMenu() to force an exit from menu tracking */
149 static BOOL fEndMenu
= FALSE
;
151 /* Use global popup window because there's no way 2 menus can
152 * be tracked at the same time. */
153 static HWND TopPopup
;
155 /* Dimension of the menu bitmaps */
156 static WORD ArrowBitmapWidth
= 0, ArrowBitmapHeight
= 0;
158 static HBITMAP StdMnArrow
= NULL
;
159 static HBITMAP BmpSysMenu
= NULL
;
161 /***********************************************************************
164 * Get full information about menu
167 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
169 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
170 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
172 return NtUserMenuInfo(Menu
, MenuInfo
, FALSE
);
175 /***********************************************************************
178 * Set full information about menu
181 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
183 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
184 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
186 return NtUserMenuInfo(MenuInfo
->Self
, MenuInfo
, TRUE
);
189 /***********************************************************************
190 * MenuInitRosMenuItemInfo
192 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
195 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
197 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
198 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
201 /***********************************************************************
202 * MenuGetRosMenuItemInfo
204 * Get full information about a menu item
206 #define INITIAL_STRING_SIZE 32 /* in WCHARs */
208 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
212 if (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
) && NULL
!= ItemInfo
->dwTypeData
)
214 /* There's already a buffer allocated */
215 Text
.Buffer
= ItemInfo
->dwTypeData
;
216 Text
.Length
= ItemInfo
->cch
* sizeof(WCHAR
);
217 Text
.MaximumLength
= (ItemInfo
->cch
< INITIAL_STRING_SIZE
? INITIAL_STRING_SIZE
218 : ItemInfo
->cch
+ 1) * sizeof(WCHAR
);
222 Text
.Buffer
= HeapAlloc(GetProcessHeap(), 0, INITIAL_STRING_SIZE
* sizeof(WCHAR
));
223 if (NULL
== Text
.Buffer
)
228 Text
.MaximumLength
= INITIAL_STRING_SIZE
* sizeof(WCHAR
);
229 ItemInfo
->cch
= INITIAL_STRING_SIZE
- 1;
231 ItemInfo
->dwTypeData
= (LPWSTR
) &Text
;
233 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
234 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
236 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
238 if (NULL
!= Text
.Buffer
)
240 HeapFree(GetProcessHeap(), 0, Text
.Buffer
);
241 ItemInfo
->dwTypeData
= NULL
;
248 if (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
))
250 /* We have a string... */
251 if (Text
.MaximumLength
< (ItemInfo
->cch
+ 1) * sizeof(WCHAR
))
253 /* ...but we didn't allocate enough memory. Let's try again */
254 HeapFree(GetProcessHeap(), 0, Text
.Buffer
);
255 Text
.Buffer
= HeapAlloc(GetProcessHeap(), 0, (ItemInfo
->cch
+ 1) * sizeof(WCHAR
));
256 if (NULL
== Text
.Buffer
)
258 ItemInfo
->dwTypeData
= NULL
;
262 Text
.Length
= (ItemInfo
->cch
+ 1) * sizeof(WCHAR
);
263 Text
.MaximumLength
= (ItemInfo
->cch
+ 1) * sizeof(WCHAR
);
265 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
267 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
268 ItemInfo
->dwTypeData
= NULL
;
275 if (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
))
277 ItemInfo
->dwTypeData
= Text
.Buffer
;
278 ItemInfo
->cch
= Text
.Length
/ sizeof(WCHAR
);
279 Text
.Buffer
[ItemInfo
->cch
] = L
'\0';
283 /* Not a string, clean up the buffer */
284 if (NULL
!= Text
.Buffer
)
286 HeapFree(GetProcessHeap(), 0, Text
.Buffer
);
293 /***********************************************************************
294 * MenuSetRosMenuItemInfo
296 * Set full information about a menu item
299 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
305 StringVal
= (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
) && NULL
!= ItemInfo
->dwTypeData
);
308 Text
.Buffer
= ItemInfo
->dwTypeData
;
309 Text
.Length
= wcslen(Text
.Buffer
) * sizeof(WCHAR
);
310 Text
.MaximumLength
= Text
.Length
+ sizeof(WCHAR
);
311 ItemInfo
->dwTypeData
= (LPWSTR
) &Text
;
313 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
314 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
316 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
320 ItemInfo
->dwTypeData
= Text
.Buffer
;
326 /***********************************************************************
327 * MenuCleanupRosMenuItemInfo
329 * Cleanup after use of MenuGet/SetRosMenuItemInfo
332 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
334 if (MF_STRING
== MENU_ITEM_TYPE(ItemInfo
->fType
) && NULL
!= ItemInfo
->dwTypeData
)
336 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
337 ItemInfo
->dwTypeData
= NULL
;
342 /***********************************************************************
343 * MenuGetAllRosMenuItemInfo
345 * Get full information about all menu items
348 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
352 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
357 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
358 if (NULL
== *ItemInfo
)
363 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
366 /***********************************************************************
367 * MenuCleanupAllRosMenuItemInfo
369 * Cleanup after use of MenuGetAllRosMenuItemInfo
372 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
374 HeapFree(GetProcessHeap(), 0, ItemInfo
);
378 /***********************************************************************
381 * Load the arrow bitmap. We can't do this from MenuInit since user32
382 * can also be used (and thus initialized) from text-mode.
385 MenuLoadBitmaps(VOID
)
387 /* Load menu bitmaps */
388 if (NULL
== StdMnArrow
)
390 StdMnArrow
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW
));
392 if (NULL
!= StdMnArrow
)
395 GetObjectW(StdMnArrow
, sizeof(BITMAP
), &bm
);
396 ArrowBitmapWidth
= bm
.bmWidth
;
397 ArrowBitmapHeight
= bm
.bmHeight
;
401 /* Load system buttons bitmaps */
402 if (NULL
== BmpSysMenu
)
404 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
408 /***********************************************************************
409 * MenuGetBitmapItemSize
411 * Get the size of a bitmap item.
414 MenuGetBitmapItemSize(UINT Id
, DWORD Data
, SIZE
*Size
)
417 HBITMAP Bmp
= (HBITMAP
) Id
;
419 Size
->cx
= Size
->cy
= 0;
421 /* check if there is a magic menu item associated with this item */
422 if (0 != Id
&& IS_MAGIC_ITEM(Id
))
426 case (INT_PTR
) HBMMENU_SYSTEM
:
429 Bmp
= (HBITMAP
) Data
;
433 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
434 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
435 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
436 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
437 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
438 Size
->cx
= GetSystemMetrics(SM_CXSIZE
);
439 Size
->cy
= GetSystemMetrics(SM_CYSIZE
);
441 case (INT_PTR
) HBMMENU_CALLBACK
:
442 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
443 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
444 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
445 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
447 FIXME("Magic menu bitmap not implemented\n");
452 if (GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
454 Size
->cx
= Bm
.bmWidth
;
455 Size
->cy
= Bm
.bmHeight
;
459 /***********************************************************************
462 * Draw a bitmap item.
465 MenuDrawBitmapItem(HDC Dc
, PROSMENUITEMINFO Item
, const RECT
*Rect
, BOOL MenuBar
)
470 HBITMAP Bmp
= (HBITMAP
) Item
->hbmpItem
;
471 int w
= Rect
->right
- Rect
->left
;
472 int h
= Rect
->bottom
- Rect
->top
;
476 /* Check if there is a magic menu item associated with this item */
477 if (IS_MAGIC_ITEM(Item
->hbmpItem
))
482 switch ((int) Item
->hbmpItem
)
484 case (INT_PTR
) HBMMENU_SYSTEM
:
485 if (NULL
!= Item
->hbmpItem
)
487 Bmp
= Item
->hbmpItem
;
488 if (! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
496 if (! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
500 /* only use right half of the bitmap */
501 BmpXoffset
= Bm
.bmWidth
/ 2;
502 Bm
.bmWidth
-= BmpXoffset
;
505 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
506 Flags
= DFCS_CAPTIONRESTORE
;
508 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
509 Flags
= DFCS_CAPTIONMIN
;
511 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
512 Flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
514 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
515 Flags
= DFCS_CAPTIONCLOSE
;
517 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
518 Flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
520 case (INT_PTR
) HBMMENU_CALLBACK
:
521 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
522 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
523 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
524 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
526 FIXME("Magic menu bitmap not implemented\n");
530 InflateRect(&r
, -1, -1);
531 if (0 != (Item
->fState
& MF_HILITE
))
533 Flags
|= DFCS_PUSHED
;
535 DrawFrameControl(Dc
, &r
, DFC_CAPTION
, Flags
);
539 if (NULL
== Bmp
|| ! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
545 DcMem
= CreateCompatibleDC(Dc
);
546 SelectObject(DcMem
, Bmp
);
548 /* handle fontsize > bitmap_height */
549 Top
= (Bm
.bmHeight
< h
) ? Rect
->top
+ (h
- Bm
.bmHeight
) / 2 : Rect
->top
;
551 Rop
= (0 != (Item
->fState
& MF_HILITE
) && ! IS_MAGIC_ITEM(Item
->hbmpItem
)) ? NOTSRCCOPY
: SRCCOPY
;
552 if (0 != (Item
->fState
& MF_HILITE
) && IS_BITMAP_ITEM(Item
->fType
))
554 SetBkColor(Dc
, GetSysColor(COLOR_HIGHLIGHT
));
556 BitBlt(Dc
, Left
, Top
, w
, h
, DcMem
, BmpXoffset
, 0, Rop
);
560 /***********************************************************************
563 * Draw a single menu item.
566 MenuDrawMenuItem(HWND Wnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC Dc
,
567 PROSMENUITEMINFO Item
, UINT Height
, BOOL MenuBar
, UINT Action
)
572 if (0 != (Item
->fType
& MF_SYSMENU
))
576 UserGetInsideRectNC(Wnd
, &Rect
);
577 UserDrawSysMenuButton(Wnd
, Dc
, &Rect
,
578 Item
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
584 if (0 != (Item
->fType
& MF_OWNERDRAW
))
587 ** Experimentation under Windows reveals that an owner-drawn
588 ** menu is given the rectangle which includes the space it requested
589 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
590 ** and a popup-menu arrow. This is the value of lpitem->rect.
591 ** Windows will leave all drawing to the application except for
592 ** the popup-menu arrow. Windows always draws that itself, after
593 ** the menu owner has finished drawing.
597 dis
.CtlType
= ODT_MENU
;
599 dis
.itemID
= Item
->wID
;
600 dis
.itemData
= (DWORD
)Item
->dwItemData
;
602 if (0 != (Item
->fState
& MF_CHECKED
))
604 dis
.itemState
|= ODS_CHECKED
;
606 if (0 != (Item
->fState
& MF_GRAYED
))
608 dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
610 if (0 != (Item
->fState
& MF_HILITE
))
612 dis
.itemState
|= ODS_SELECTED
;
614 dis
.itemAction
= Action
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
615 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
617 dis
.rcItem
= Item
->Rect
;
618 DPRINT("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
619 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hwndOwner
,
620 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
621 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
623 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
624 /* Fall through to draw popup-menu arrow */
627 DPRINT("rect={%ld,%ld,%ld,%ld}\n", Item
->rect
.left
, Item
->rect
.top
,
628 Item
->rect
.right
, Item
->rect
.bottom
);
630 if (MenuBar
&& 0 != (Item
->fType
& MF_SEPARATOR
))
637 if (0 == (Item
->fType
& MF_OWNERDRAW
))
639 if (Item
->fState
& MF_HILITE
)
643 DrawEdge(Dc
, &Rect
, BDR_SUNKENOUTER
, BF_RECT
);
647 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
652 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_MENU
));
656 SetBkMode(Dc
, TRANSPARENT
);
658 if (0 == (Item
->fType
& MF_OWNERDRAW
))
660 /* vertical separator */
661 if (! MenuBar
&& 0 != (Item
->fType
& MF_MENUBARBREAK
))
665 rc
.bottom
= Height
- 3;
666 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
669 /* horizontal separator */
670 if (0 != (Item
->fType
& MF_SEPARATOR
))
675 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
676 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_TOP
);
684 if (0 != (Item
->fState
& MF_HILITE
))
688 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
689 SetBkColor(Dc
, GetSysColor(COLOR_MENU
));
693 if (0 != (Item
->fState
& MF_GRAYED
))
695 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
699 SetTextColor(Dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
701 SetBkColor(Dc
, GetSysColor(COLOR_HIGHLIGHT
));
706 if (0 != (Item
->fState
& MF_GRAYED
))
708 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
712 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
714 SetBkColor(Dc
, GetSysColor(COLOR_MENU
));
718 /* helper lines for debugging */
719 FrameRect(Dc
, &Rect
, GetStockObject(BLACK_BRUSH
));
720 SelectObject(Dc
, SYSCOLOR_GetPen(COLOR_WINDOWFRAME
));
721 MoveToEx(Dc
, Rect
.left
, (Rect
.top
+ Rect
.bottom
) / 2, NULL
);
722 LineTo(Dc
, Rect
.right
, (Rect
.top
+ Rect
.bottom
) / 2);
727 INT y
= Rect
.top
+ Rect
.bottom
;
728 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
729 UINT CheckBitmapHeight
= GetSystemMetrics(SM_CYMENUCHECK
);
731 if (0 == (Item
->fType
& MF_OWNERDRAW
))
733 /* Draw the check mark
736 * Custom checkmark bitmaps are monochrome but not always 1bpp.
738 HBITMAP bm
= 0 != (Item
->fState
& MF_CHECKED
) ? Item
->hbmpChecked
: Item
->hbmpUnchecked
;
739 if (NULL
!= bm
) /* we have a custom bitmap */
741 HDC DcMem
= CreateCompatibleDC(Dc
);
742 SelectObject(DcMem
, bm
);
743 BitBlt(Dc
, Rect
.left
, (y
- CheckBitmapHeight
) / 2,
744 CheckBitmapWidth
, CheckBitmapHeight
,
745 DcMem
, 0, 0, SRCCOPY
);
748 else if (0 != (Item
->fState
& MF_CHECKED
)) /* standard bitmaps */
751 HBITMAP bm
= CreateBitmap(CheckBitmapWidth
, CheckBitmapHeight
, 1, 1, NULL
);
752 HDC DcMem
= CreateCompatibleDC(Dc
);
753 SelectObject(DcMem
, bm
);
754 SetRect( &r
, 0, 0, CheckBitmapWidth
, CheckBitmapHeight
);
755 DrawFrameControl(DcMem
, &r
, DFC_MENU
,
756 0 != (Item
->fType
& MFT_RADIOCHECK
) ?
757 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
758 BitBlt(Dc
, Rect
.left
, (y
- r
.bottom
) / 2, r
.right
, r
.bottom
,
759 DcMem
, 0, 0, SRCCOPY
);
765 /* Draw the popup-menu arrow */
766 if (0 != (Item
->fType
& MF_POPUP
))
768 HDC DcMem
= CreateCompatibleDC(Dc
);
771 OrigBitmap
= SelectObject(DcMem
, StdMnArrow
);
772 BitBlt(Dc
, Rect
.right
- ArrowBitmapWidth
- 1,
773 (y
- ArrowBitmapHeight
) / 2,
774 ArrowBitmapWidth
, ArrowBitmapHeight
,
775 DcMem
, 0, 0, SRCCOPY
);
776 SelectObject(DcMem
, OrigBitmap
);
780 Rect
.left
+= CheckBitmapWidth
;
781 Rect
.right
-= ArrowBitmapWidth
;
784 /* Done for owner-drawn */
785 if (0 != (Item
->fType
& MF_OWNERDRAW
))
790 /* Draw the item text or bitmap */
791 if (IS_BITMAP_ITEM(Item
->fType
))
793 MenuDrawBitmapItem(Dc
, Item
, &Rect
, MenuBar
);
796 /* No bitmap - process text if present */
797 else if (IS_STRING_ITEM(Item
->fType
))
800 HFONT FontOld
= NULL
;
802 UINT uFormat
= MenuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
803 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
805 if (0 != (Item
->fState
& MFS_DEFAULT
))
807 FontOld
= SelectObject(Dc
, hMenuFontBold
);
812 Rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
813 Rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
816 Text
= (PWCHAR
) Item
->dwTypeData
;
817 for (i
= 0; L
'\0' != Text
[i
]; i
++)
819 if (L
'\t' == Text
[i
] || L
'\b' == Text
[i
])
825 if (0 != (Item
->fState
& MF_GRAYED
))
827 if (0 == (Item
->fState
& MF_HILITE
))
829 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
830 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
831 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
832 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
834 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
837 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
839 /* paint the shortcut text */
840 if (! MenuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
842 if (L
'\t' == Text
[i
])
844 Rect
.left
= Item
->XTab
;
845 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
849 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
852 if (0 != (Item
->fState
& MF_GRAYED
))
854 if (0 == (Item
->fState
& MF_HILITE
))
856 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
857 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
858 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
859 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
861 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
863 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
868 SelectObject(Dc
, FontOld
);
873 /***********************************************************************
876 * Paint a popup menu.
879 MenuDrawPopupMenu(HWND Wnd
, HDC Dc
, HMENU Menu
)
881 HBRUSH PrevBrush
= NULL
;
884 ROSMENUINFO MenuInfo
;
885 ROSMENUITEMINFO ItemInfo
;
888 DPRINT("wnd=%x dc=%x menu=%x\n", Wnd
, Dc
, Menu
);
890 GetClientRect(Wnd
, &Rect
);
892 if (NULL
!= (PrevBrush
= SelectObject(Dc
, GetSysColorBrush(COLOR_MENU
)))
893 && NULL
!= SelectObject(Dc
, hMenuFont
))
895 Rectangle(Dc
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
897 PrevPen
= SelectObject(Dc
, GetStockObject(NULL_PEN
));
900 DrawEdge(Dc
, &Rect
, EDGE_RAISED
, BF_RECT
);
902 /* draw menu items */
904 if (MenuGetRosMenuInfo(&MenuInfo
, Menu
) && 0 != MenuInfo
.MenuItemCount
)
906 MenuInitRosMenuItemInfo(&ItemInfo
);
908 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
910 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
912 MenuDrawMenuItem(Wnd
, &MenuInfo
, MenuInfo
.WndOwner
, Dc
, &ItemInfo
,
913 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
920 SelectObject(Dc
, PrevBrush
);
925 static LRESULT WINAPI
926 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
928 DPRINT("hwnd=%x msg=0x%04x wp=0x%04x lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
934 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
935 SetWindowLongW(Wnd
, 0, (LONG
) cs
->lpCreateParams
);
939 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
940 return MA_NOACTIVATE
;
945 BeginPaint(Wnd
, &ps
);
946 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongW(Wnd
, 0));
955 /* zero out global pointer in case resident popup window was destroyed. */
965 if (0 == GetWindowLongW(Wnd
, 0))
967 OutputDebugStringA("no menu to display\n");
972 SetWindowLongW(Wnd
, 0, 0);
976 case MM_SETMENUHANDLE
:
977 SetWindowLongW(Wnd
, 0, wParam
);
980 case MM_GETMENUHANDLE
:
981 return GetWindowLongW(Wnd
, 0);
984 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
990 /**********************************************************************
991 * MENUEX_ParseResource
993 * Parse an extended menu resource and add items to the menu.
994 * Return a pointer to the end of the resource.
996 * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
998 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1006 mii
.cbSize
= sizeof(mii
);
1007 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
1008 mii
.fType
= GET_DWORD(res
);
1009 res
+= sizeof(DWORD
);
1010 mii
.fState
= GET_DWORD(res
);
1011 res
+= sizeof(DWORD
);
1012 mii
.wID
= GET_DWORD(res
);
1013 res
+= sizeof(DWORD
);
1014 resinfo
= GET_WORD(res
);
1015 res
+= sizeof(WORD
);
1016 /* Align the text on a word boundary. */
1017 res
+= (~((int)res
- 1)) & 1;
1018 mii
.dwTypeData
= (LPWSTR
) res
;
1019 res
+= (1 + wcslen(mii
.dwTypeData
)) * sizeof(WCHAR
);
1020 /* Align the following fields on a dword boundary. */
1021 res
+= (~((int)res
- 1)) & 3;
1023 if (resinfo
& 1) /* Pop-up? */
1025 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1026 res
+= sizeof(DWORD
);
1027 mii
.hSubMenu
= CreatePopupMenu();
1030 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
1032 DestroyMenu(mii
.hSubMenu
);
1035 mii
.fMask
|= MIIM_SUBMENU
;
1036 mii
.fType
|= MF_POPUP
;
1038 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
1040 DbgPrint("WARN: Converting NULL menu item %04x, type %04x to SEPARATOR\n",
1041 mii
.wID
, mii
.fType
);
1042 mii
.fType
|= MF_SEPARATOR
;
1044 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1046 while (!(resinfo
& MF_END
));
1051 /**********************************************************************
1052 * MENU_ParseResource
1054 * Parse a standard menu resource and add items to the menu.
1055 * Return a pointer to the end of the resource.
1057 * NOTE: flags is equivalent to the mtOption field
1059 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1068 flags
= GET_WORD(res
);
1070 /* remove MF_END flag before passing it to AppendMenu()! */
1071 end
= (flags
& MF_END
);
1072 if(end
) flags
^= MF_END
;
1074 res
+= sizeof(WORD
);
1075 if(!(flags
& MF_POPUP
))
1078 res
+= sizeof(WORD
);
1082 res
+= strlen(str
) + 1;
1084 res
+= (wcslen((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1085 if (flags
& MF_POPUP
)
1087 hSubMenu
= CreatePopupMenu();
1088 if(!hSubMenu
) return NULL
;
1089 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
1092 AppendMenuA(hMenu
, flags
, (UINT
)hSubMenu
, str
);
1094 AppendMenuW(hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1096 else /* Not a popup */
1099 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
1101 AppendMenuW(hMenu
, flags
, id
,
1102 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1111 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
1115 hUser32
= GetModuleHandleW(L
"USER32");
1116 Result
= (LRESULT
)LoadMenuW(hUser32
, L
"SYSMENU");
1117 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
1124 NONCLIENTMETRICSW ncm
;
1126 /* get the menu font */
1127 if(!hMenuFont
|| !hMenuFontBold
)
1129 ncm
.cbSize
= sizeof(ncm
);
1130 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
1132 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
1136 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1137 if(hMenuFont
== NULL
)
1139 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
1143 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
1144 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1145 if(hMenuFontBold
== NULL
)
1147 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
1156 /***********************************************************************
1159 * Calculate the size of the menu item and store it in ItemInfo->rect.
1161 static void FASTCALL
1162 MenuCalcItemSize(HDC Dc
, PROSMENUITEMINFO ItemInfo
, HWND WndOwner
,
1163 INT OrgX
, INT OrgY
, BOOL MenuBar
)
1166 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
1168 DPRINT("dc=%x owner=%x (%d,%d)\n", Dc
, WndOwner
, OrgX
, OrgY
);
1170 SetRect(&ItemInfo
->Rect
, OrgX
, OrgY
, OrgX
, OrgY
);
1172 if (0 != (ItemInfo
->fType
& MF_OWNERDRAW
))
1175 ** Experimentation under Windows reveals that an owner-drawn
1176 ** menu is expected to return the size of the content part of
1177 ** the menu item, not including the checkmark nor the submenu
1178 ** arrow. Windows adds those values itself and returns the
1179 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
1181 MEASUREITEMSTRUCT mis
;
1182 mis
.CtlType
= ODT_MENU
;
1184 mis
.itemID
= ItemInfo
->wID
;
1185 mis
.itemData
= (DWORD
)ItemInfo
->dwItemData
;
1188 SendMessageW(WndOwner
, WM_MEASUREITEM
, 0, (LPARAM
) &mis
);
1189 ItemInfo
->Rect
.right
+= mis
.itemWidth
;
1193 ItemInfo
->Rect
.right
+= MENU_BAR_ITEMS_SPACE
;
1195 /* under at least win95 you seem to be given a standard
1196 height for the menu and the height value is ignored */
1198 ItemInfo
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENU
) - 1;
1202 ItemInfo
->Rect
.bottom
+= mis
.itemHeight
;
1205 DPRINT("id=%04x size=%dx%d\n", ItemInfo
->wID
, mis
.itemWidth
, mis
.itemHeight
);
1206 /* Fall through to get check/arrow width calculation. */
1209 if (0 != (ItemInfo
->fType
& MF_SEPARATOR
))
1211 ItemInfo
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
1217 ItemInfo
->Rect
.right
+= 2 * CheckBitmapWidth
;
1218 if (0 != (ItemInfo
->fType
& MF_POPUP
))
1220 ItemInfo
->Rect
.right
+= ArrowBitmapWidth
;
1224 if (0 != (ItemInfo
->fType
& MF_OWNERDRAW
))
1229 if (IS_BITMAP_ITEM(ItemInfo
->fType
))
1233 MenuGetBitmapItemSize((int) ItemInfo
->hbmpItem
, (DWORD
) ItemInfo
->hbmpItem
, &Size
);
1234 ItemInfo
->Rect
.right
+= Size
.cx
;
1235 ItemInfo
->Rect
.bottom
+= Size
.cy
;
1237 /* Leave space for the sunken border */
1238 ItemInfo
->Rect
.right
+= 2;
1239 ItemInfo
->Rect
.bottom
+= 2;
1242 /* it must be a text item - unless it's the system menu */
1243 if (0 == (ItemInfo
->fType
& MF_SYSMENU
) && IS_STRING_ITEM(ItemInfo
->fType
))
1247 GetTextExtentPoint32W(Dc
, (LPWSTR
) ItemInfo
->dwTypeData
,
1248 wcslen((LPWSTR
) ItemInfo
->dwTypeData
), &Size
);
1250 ItemInfo
->Rect
.right
+= Size
.cx
;
1251 ItemInfo
->Rect
.bottom
+= max(Size
.cy
, GetSystemMetrics(SM_CYMENU
) - 1);
1256 ItemInfo
->Rect
.right
+= MENU_BAR_ITEMS_SPACE
;
1258 else if ((p
= wcschr((LPWSTR
) ItemInfo
->dwTypeData
, L
'\t' )) != NULL
)
1260 /* Item contains a tab (only meaningful in popup menus) */
1261 GetTextExtentPoint32W(Dc
, (LPWSTR
) ItemInfo
->dwTypeData
,
1262 (int)(p
- (LPWSTR
) ItemInfo
->dwTypeData
), &Size
);
1263 ItemInfo
->XTab
= CheckBitmapWidth
+ MENU_TAB_SPACE
+ Size
.cx
;
1264 ItemInfo
->Rect
.right
+= MENU_TAB_SPACE
;
1268 if (NULL
!= wcschr((LPWSTR
) ItemInfo
->dwTypeData
, L
'\b'))
1270 ItemInfo
->Rect
.right
+= MENU_TAB_SPACE
;
1272 ItemInfo
->XTab
= ItemInfo
->Rect
.right
- CheckBitmapWidth
1277 DPRINT("(%ld,%ld)-(%ld,%ld)\n", ItemInfo
->Rect
.left
, ItemInfo
->Rect
.top
, ItemInfo
->Rect
.right
, ItemInfo
->Rect
.bottom
);
1280 /***********************************************************************
1281 * MenuPopupMenuCalcSize
1283 * Calculate the size of a popup menu.
1285 static void FASTCALL
1286 MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1288 ROSMENUITEMINFO ItemInfo
;
1291 int OrgX
, OrgY
, MaxX
, MaxTab
, MaxTabWidth
;
1293 MenuInfo
->Width
= MenuInfo
->Height
= 0;
1294 if (0 == MenuInfo
->MenuItemCount
)
1296 MenuSetRosMenuInfo(MenuInfo
);
1301 SelectObject(Dc
, hMenuFont
);
1306 MenuInitRosMenuItemInfo(&ItemInfo
);
1307 while (Start
< MenuInfo
->MenuItemCount
)
1312 MaxTab
= MaxTabWidth
= 0;
1314 /* Parse items until column break or end of menu */
1315 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1317 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1319 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1320 MenuSetRosMenuInfo(MenuInfo
);
1324 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1329 MenuCalcItemSize(Dc
, &ItemInfo
, WndOwner
, OrgX
, OrgY
, FALSE
);
1330 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1332 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1333 MenuSetRosMenuInfo(MenuInfo
);
1337 if (0 != (ItemInfo
.fType
& MF_MENUBARBREAK
))
1341 MaxX
= max(MaxX
, ItemInfo
.Rect
.right
);
1342 OrgY
= ItemInfo
.Rect
.bottom
;
1343 if (IS_STRING_ITEM(ItemInfo
.fType
) && 0 != ItemInfo
.XTab
)
1345 MaxTab
= max(MaxTab
, ItemInfo
.XTab
);
1346 MaxTabWidth
= max(MaxTabWidth
, ItemInfo
.Rect
.right
- ItemInfo
.XTab
);
1350 /* Finish the column (set all items to the largest width found) */
1351 MaxX
= max(MaxX
, MaxTab
+ MaxTabWidth
);
1354 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1356 ItemInfo
.Rect
.right
= MaxX
;
1357 if (IS_STRING_ITEM(ItemInfo
.fType
) && 0 != ItemInfo
.XTab
)
1359 ItemInfo
.XTab
= MaxTab
;
1361 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1365 MenuInfo
->Height
= max(MenuInfo
->Height
, OrgY
);
1368 MenuInfo
->Width
= MaxX
;
1370 /* space for 3d border */
1371 MenuInfo
->Height
+= 2;
1372 MenuInfo
->Width
+= 2;
1374 ReleaseDC(NULL
, Dc
);
1375 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1376 MenuSetRosMenuInfo(MenuInfo
);
1379 /***********************************************************************
1380 * MenuMenuBarCalcSize
1382 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1383 * height is off by 1 pixel which causes lengthy window relocations when
1384 * active document window is maximized/restored.
1386 * Calculate the size of the menu bar.
1388 static void FASTCALL
1389 MenuMenuBarCalcSize(HDC Dc
, LPRECT Rect
, PROSMENUINFO MenuInfo
, HWND WndOwner
)
1391 ROSMENUITEMINFO ItemInfo
;
1392 int Start
, i
, OrgX
, OrgY
, MaxY
, HelpPos
;
1394 if (NULL
== Rect
|| NULL
== MenuInfo
)
1398 if (0 == MenuInfo
->MenuItemCount
)
1403 DPRINT("left=%ld top=%ld right=%ld bottom=%ld\n",
1404 Rrect
->left
, Rect
->top
, Rect
->right
, Rect
->bottom
);
1405 MenuInfo
->Width
= Rect
->right
- Rect
->left
;
1406 MenuInfo
->Height
= 0;
1407 MaxY
= Rect
->top
+ 1;
1410 MenuInitRosMenuItemInfo(&ItemInfo
);
1411 while (Start
< MenuInfo
->MenuItemCount
)
1413 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1415 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1421 /* Parse items until line break or end of menu */
1422 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1424 if (-1 == HelpPos
&& 0 != (ItemInfo
.fType
& MF_RIGHTJUSTIFY
))
1429 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1434 DPRINT("calling MENU_CalcItemSize org=(%d, %d)\n", OrgX
, OrgY
);
1435 MenuCalcItemSize(Dc
, &ItemInfo
, WndOwner
, OrgX
, OrgY
, TRUE
);
1436 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1438 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1442 if (ItemInfo
.Rect
.right
> Rect
->right
)
1450 ItemInfo
.Rect
.right
= Rect
->right
;
1453 MaxY
= max(MaxY
, ItemInfo
.Rect
.bottom
);
1454 OrgX
= ItemInfo
.Rect
.right
;
1455 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1457 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1459 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1465 /* Finish the line (set all items to the largest height found) */
1468 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1470 ItemInfo
.Rect
.bottom
= MaxY
;
1471 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1477 Rect
->bottom
= MaxY
;
1478 MenuInfo
->Height
= Rect
->bottom
- Rect
->top
;
1479 MenuSetRosMenuInfo(MenuInfo
);
1483 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1484 /* the last item (if several lines, only move the last line) */
1485 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1487 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1490 OrgY
= ItemInfo
.Rect
.top
;
1492 for (i
= MenuInfo
->MenuItemCount
- 1; HelpPos
<= i
; i
--)
1498 if (ItemInfo
.Rect
.top
!= OrgY
)
1500 break; /* Other line */
1502 if (OrgX
<= ItemInfo
.Rect
.right
)
1504 break; /* Too far right already */
1506 ItemInfo
.Rect
.left
+= OrgX
- ItemInfo
.Rect
.right
;
1507 ItemInfo
.Rect
.right
= OrgX
;
1508 OrgX
= ItemInfo
.Rect
.left
;
1509 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1510 if (HelpPos
+ 1 <= i
&&
1511 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1513 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1519 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1522 /***********************************************************************
1523 * DrawMenuBarTemp (USER32.@)
1527 * called by W98SE desk.cpl Control Panel Applet
1529 * Not 100% sure about the param names, but close.
1534 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
1536 ROSMENUINFO MenuInfo
;
1537 ROSMENUITEMINFO ItemInfo
;
1539 HFONT FontOld
= NULL
;
1543 Menu
= GetMenu(Wnd
);
1551 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1553 return GetSystemMetrics(SM_CYMENU
);
1556 DPRINT("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
1558 FontOld
= SelectObject(DC
, Font
);
1560 if (0 == MenuInfo
.Height
)
1562 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1565 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1567 FillRect(DC
, Rect
, GetSysColorBrush(COLOR_MENU
));
1569 SelectObject(DC
, GetSysColorPen(COLOR_3DFACE
));
1570 MoveToEx(DC
, Rect
->left
, Rect
->bottom
, NULL
);
1571 LineTo(DC
, Rect
->right
, Rect
->bottom
);
1573 if (0 == MenuInfo
.MenuItemCount
)
1575 SelectObject(DC
, FontOld
);
1576 return GetSystemMetrics(SM_CYMENU
);
1579 MenuInitRosMenuItemInfo(&ItemInfo
);
1580 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
1582 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
1584 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
1585 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
1588 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1590 SelectObject(DC
, FontOld
);
1592 return MenuInfo
.Height
;
1596 /***********************************************************************
1599 * Paint a menu bar. Returns the height of the menu bar.
1600 * called from [windows/nonclient.c]
1602 UINT
MenuDrawMenuBar(HDC DC
, LPRECT Rect
, HWND Wnd
, BOOL SuppressDraw
)
1604 ROSMENUINFO MenuInfo
;
1605 HFONT FontOld
= NULL
;
1606 HMENU Menu
= GetMenu(Wnd
);
1608 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1610 return GetSystemMetrics(SM_CYMENU
);
1615 FontOld
= SelectObject(DC
, hMenuFont
);
1617 if (0 == MenuInfo
.Height
)
1619 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1622 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1624 if (NULL
!= FontOld
)
1626 SelectObject(DC
, FontOld
);
1628 return MenuInfo
.Height
;
1632 return DrawMenuBarTemp(Wnd
, DC
, Rect
, Menu
, NULL
);
1636 /***********************************************************************
1639 static BOOL FASTCALL
1640 MenuInitTracking(HWND Wnd
, HMENU Menu
, BOOL Popup
, UINT Flags
)
1642 DPRINT("Wnd=%p Menu=%p\n", Wnd
, Menu
);
1646 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
1647 if (0 == (Flags
& TPM_NONOTIFY
))
1649 SendMessageW(Wnd
, WM_ENTERMENULOOP
, Popup
, 0);
1652 SendMessageW(Wnd
, WM_SETCURSOR
, (WPARAM
) Wnd
, HTCAPTION
);
1654 if (0 == (Flags
& TPM_NONOTIFY
))
1656 ROSMENUINFO MenuInfo
;
1658 SendMessageW(Wnd
, WM_INITMENU
, (WPARAM
)Menu
, 0);
1660 if (MenuGetRosMenuInfo(&MenuInfo
, Menu
) && 0 == MenuInfo
.Height
)
1662 /* app changed/recreated menu bar entries in WM_INITMENU
1663 Recalculate menu sizes else clicks will not work */
1664 SetWindowPos(Wnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
1665 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
1674 /***********************************************************************
1677 * Display a popup menu.
1679 static BOOL FASTCALL
1680 MenuShowPopup(HWND WndOwner
, HMENU Menu
, UINT Id
,
1681 INT X
, INT Y
, INT XAnchor
, INT YAnchor
)
1683 ROSMENUINFO MenuInfo
;
1684 ROSMENUITEMINFO ItemInfo
;
1687 DPRINT("owner=%x hmenu=%x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1688 WndOwner
, Menu
, Id
, X
, Y
, XAnchor
, YAnchor
);
1690 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1695 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
1697 MenuInitRosMenuItemInfo(&ItemInfo
);
1698 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1700 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1701 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1703 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1704 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1707 /* store the owner for DrawItem */
1708 MenuInfo
.WndOwner
= WndOwner
;
1709 MenuSetRosMenuInfo(&MenuInfo
);
1711 MenuPopupMenuCalcSize(&MenuInfo
, WndOwner
);
1713 /* adjust popup menu pos so that it fits within the desktop */
1715 Width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1716 Height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1718 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1722 X
-= Width
- XAnchor
;
1724 if (GetSystemMetrics(SM_CXSCREEN
) < X
+ Width
)
1726 X
= GetSystemMetrics(SM_CXSCREEN
) - Width
;
1734 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1738 Y
-= Height
+ YAnchor
;
1740 if (GetSystemMetrics(SM_CYSCREEN
) < Y
+ Height
)
1742 Y
= GetSystemMetrics(SM_CYSCREEN
) - Height
;
1751 /* NOTE: In Windows, top menu popup is not owned. */
1752 MenuInfo
.Wnd
= CreateWindowExW(0, POPUPMENU_CLASS_ATOMW
, NULL
,
1753 WS_POPUP
, X
, Y
, Width
, Height
,
1754 WndOwner
, 0, (HINSTANCE
) GetWindowLongW(WndOwner
, GWL_HINSTANCE
),
1755 (LPVOID
) MenuInfo
.Self
);
1756 if (NULL
== MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
))
1760 if (NULL
== TopPopup
)
1762 TopPopup
= MenuInfo
.Wnd
;
1765 /* Display the window */
1766 SetWindowPos(MenuInfo
.Wnd
, HWND_TOP
, 0, 0, 0, 0,
1767 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1768 UpdateWindow(MenuInfo
.Wnd
);
1773 /***********************************************************************
1776 * Find a Sub menu. Return the position of the submenu, and modifies
1777 * *hmenu in case it is found in another sub-menu.
1778 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
1780 static UINT FASTCALL
1781 MenuFindSubMenu(HMENU
*Menu
, HMENU SubTarget
)
1783 ROSMENUINFO MenuInfo
;
1784 ROSMENUITEMINFO ItemInfo
;
1789 if ((HMENU
) 0xffff == *Menu
1790 || ! MenuGetRosMenuInfo(&MenuInfo
, *Menu
))
1792 return NO_SELECTED_ITEM
;
1795 MenuInitRosMenuItemInfo(&ItemInfo
);
1796 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
1798 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
1800 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1801 return NO_SELECTED_ITEM
;
1803 if (0 == (ItemInfo
.fType
& MF_POPUP
))
1807 if (ItemInfo
.hSubMenu
== SubTarget
)
1809 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1812 SubMenu
= ItemInfo
.hSubMenu
;
1813 Pos
= MenuFindSubMenu(&SubMenu
, SubTarget
);
1814 if (NO_SELECTED_ITEM
!= Pos
)
1820 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1822 return NO_SELECTED_ITEM
;
1825 /***********************************************************************
1828 static void FASTCALL
1829 MenuSelectItem(HWND WndOwner
, PROSMENUINFO MenuInfo
, UINT Index
,
1830 BOOL SendMenuSelect
, HMENU TopMenu
)
1833 ROSMENUITEMINFO ItemInfo
;
1834 ROSMENUINFO TopMenuInfo
;
1837 DPRINT("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner
, MenuInfo
, Index
, SendMenuSelect
);
1839 if (NULL
== MenuInfo
|| 0 == MenuInfo
->MenuItemCount
|| NULL
== MenuInfo
->Wnd
)
1844 if (MenuInfo
->FocusedItem
== Index
)
1849 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
1851 Dc
= GetDC(MenuInfo
->Wnd
);
1855 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1858 if (NULL
== TopPopup
)
1860 TopPopup
= MenuInfo
->Wnd
;
1863 SelectObject(Dc
, hMenuFont
);
1864 MenuInitRosMenuItemInfo(&ItemInfo
);
1866 /* Clear previous highlighted item */
1867 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
1869 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
1871 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1872 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
1874 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
,
1875 MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
1879 /* Highlight new item (if any) */
1880 MenuInfo
->FocusedItem
= Index
;
1881 MenuSetRosMenuInfo(MenuInfo
);
1882 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
1884 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
1886 if (0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1888 ItemInfo
.fState
|= MF_HILITE
;
1889 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
1890 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
,
1891 &ItemInfo
, MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
1896 SendMessageW(WndOwner
, WM_MENUSELECT
,
1897 MAKELONG(ItemInfo
.fType
& MF_POPUP
? Index
: ItemInfo
.wID
,
1898 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
1899 (MenuInfo
->Flags
& MF_SYSMENU
)), (LPARAM
) MenuInfo
->Self
);
1903 else if (SendMenuSelect
)
1905 if (NULL
!= TopMenu
)
1907 Pos
= MenuFindSubMenu(&TopMenu
, MenuInfo
->Self
);
1908 if (NO_SELECTED_ITEM
!= Pos
)
1910 if (MenuGetRosMenuInfo(&TopMenuInfo
, TopMenu
)
1911 && MenuGetRosMenuItemInfo(TopMenu
, Pos
, &ItemInfo
))
1913 SendMessageW(WndOwner
, WM_MENUSELECT
,
1914 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
1916 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
1923 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1924 ReleaseDC(MenuInfo
->Wnd
, Dc
);
1927 /***********************************************************************
1930 * Moves currently selected item according to the Offset parameter.
1931 * If there is no selection then it should select the last item if
1932 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
1934 static void FASTCALL
1935 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
1938 ROSMENUITEMINFO ItemInfo
;
1940 DPRINT("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, offset
);
1942 MenuInitRosMenuItemInfo(&ItemInfo
);
1943 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
1945 if (1 == MenuInfo
->MenuItemCount
)
1947 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1952 for (i
= MenuInfo
->FocusedItem
+ Offset
;
1953 0 <= i
&& i
< MenuInfo
->MenuItemCount
;
1956 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1957 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1959 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1960 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1967 for (i
= (0 < Offset
) ? 0 : MenuInfo
->MenuItemCount
- 1;
1968 0 <= i
&& i
< MenuInfo
->MenuItemCount
; i
+= Offset
)
1970 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
1971 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
1973 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
1974 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1979 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1982 /***********************************************************************
1983 * MenuInitSysMenuPopup
1985 * Grey the appropriate items in System menu.
1987 static void FASTCALL
1988 MenuInitSysMenuPopup(HMENU Menu
, DWORD Style
, DWORD ClsStyle
)
1992 Gray
= 0 == (Style
& WS_THICKFRAME
) || 0 != (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
1993 EnableMenuItem(Menu
, SC_SIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
1994 Gray
= 0 != (Style
& WS_MAXIMIZE
);
1995 EnableMenuItem(Menu
, SC_MOVE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
1996 Gray
= 0 == (Style
& WS_MINIMIZEBOX
) || 0 != (Style
& WS_MINIMIZE
);
1997 EnableMenuItem(Menu
, SC_MINIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
1998 Gray
= 0 == (Style
& WS_MAXIMIZEBOX
) || 0 != (Style
& WS_MAXIMIZE
);
1999 EnableMenuItem(Menu
, SC_MAXIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2000 Gray
= 0 == (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2001 EnableMenuItem(Menu
, SC_RESTORE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2002 Gray
= 0 != (ClsStyle
& CS_NOCLOSE
);
2004 /* The menu item must keep its state if it's disabled */
2007 EnableMenuItem(Menu
, SC_CLOSE
, MF_GRAYED
);
2011 /***********************************************************************
2014 * Display the sub-menu of the selected item of this menu.
2015 * Return the handle of the submenu, or menu if no submenu to display.
2017 static HMENU FASTCALL
2018 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2020 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2022 ROSMENUITEMINFO ItemInfo
;
2023 ROSMENUINFO SubMenuInfo
;
2027 DPRINT("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2029 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2031 return MenuInfo
->Self
;
2034 MenuInitRosMenuItemInfo(&ItemInfo
);
2035 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2037 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2038 return MenuInfo
->Self
;
2040 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2042 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2043 return MenuInfo
->Self
;
2046 /* message must be sent before using item,
2047 because nearly everything may be changed by the application ! */
2049 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2050 if (0 == (Flags
& TPM_NONOTIFY
))
2052 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2053 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2056 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2058 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2059 return MenuInfo
->Self
;
2061 Rect
= ItemInfo
.Rect
;
2063 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2064 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2066 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2068 Dc
= GetDC(MenuInfo
->Wnd
);
2072 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2075 SelectObject(Dc
, hMenuFont
);
2077 ItemInfo
.fState
|= MF_HILITE
;
2078 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2079 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2080 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2081 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2084 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2085 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2087 ItemInfo
.Rect
= Rect
;
2090 ItemInfo
.fState
|= MF_MOUSESELECT
;
2092 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2094 if (IS_SYSTEM_MENU(MenuInfo
))
2096 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
,
2097 GetWindowLongW(MenuInfo
->Wnd
, GWL_STYLE
),
2098 GetClassLongW(MenuInfo
->Wnd
, GCL_STYLE
));
2100 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2101 Rect
.top
= Rect
.bottom
;
2102 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2103 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2107 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2108 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2110 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2111 Rect
.top
+= ItemInfo
.Rect
.top
;
2112 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2113 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
;
2117 Rect
.left
+= ItemInfo
.Rect
.left
;
2118 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2119 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2120 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2124 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
,
2125 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2126 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2128 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2131 Ret
= ItemInfo
.hSubMenu
;
2132 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2137 /***********************************************************************
2140 * Hide the sub-popup menus of this menu.
2142 static void FASTCALL
2143 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SendMenuSelect
)
2145 ROSMENUINFO SubMenuInfo
;
2146 ROSMENUITEMINFO ItemInfo
;
2148 DPRINT("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2150 if (NULL
!= MenuInfo
&& NULL
!= TopPopup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2152 MenuInitRosMenuItemInfo(&ItemInfo
);
2153 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2154 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2155 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2157 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2160 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2161 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2162 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2164 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
);
2165 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2166 DestroyWindow(SubMenuInfo
.Wnd
);
2167 SubMenuInfo
.Wnd
= NULL
;
2168 MenuSetRosMenuInfo(&SubMenuInfo
);
2173 /***********************************************************************
2174 * MenuSwitchTracking
2176 * Helper function for menu navigation routines.
2178 static void FASTCALL
2179 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
)
2181 ROSMENUINFO TopMenuInfo
;
2183 DPRINT("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2185 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2186 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2187 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2189 /* both are top level menus (system and menu-bar) */
2190 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2191 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2192 Mt
->TopMenu
= PtMenuInfo
->Self
;
2196 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
);
2199 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2202 /***********************************************************************
2203 * MenuExecFocusedItem
2205 * Execute a menu item (for instance when user pressed Enter).
2206 * Return the wID of the executed item. Otherwise, -1 indicating
2207 * that no menu item was executed;
2208 * Have to receive the flags for the TrackPopupMenu options to avoid
2209 * sending unwanted message.
2213 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2215 ROSMENUITEMINFO ItemInfo
;
2218 DPRINT("%p menu=%p\n", Mt
, MenuInfo
);
2220 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2225 MenuInitRosMenuItemInfo(&ItemInfo
);
2226 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2228 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2232 DPRINT("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2234 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2236 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2237 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2239 /* If TPM_RETURNCMD is set you return the id, but
2240 do not send a message to the owner */
2241 if (0 == (Flags
& TPM_RETURNCMD
))
2243 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2245 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2246 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2250 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2254 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2260 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2266 /***********************************************************************
2269 * Return TRUE if we can go on with menu tracking.
2271 static BOOL FASTCALL
2272 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2275 ROSMENUINFO MenuInfo
;
2276 ROSMENUITEMINFO Item
;
2278 DPRINT("%x PtMenu=%p\n", Mt
, PtMenu
);
2282 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2286 if (IS_SYSTEM_MENU(&MenuInfo
))
2292 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2294 MenuInitRosMenuItemInfo(&Item
);
2295 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2297 MenuCleanupRosMenuItemInfo(&Item
);
2301 if (MenuInfo
.FocusedItem
!= Index
)
2303 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2306 /* If the popup menu is not already "popped" */
2307 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2309 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2312 MenuCleanupRosMenuItemInfo(&Item
);
2317 /* else the click was on the menu bar, finish the tracking */
2322 /***********************************************************************
2325 * Return the value of MenuExecFocusedItem if
2326 * the selected item was not a popup. Else open the popup.
2327 * A -1 return value indicates that we go on with menu tracking.
2331 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2334 ROSMENUINFO MenuInfo
;
2335 ROSMENUITEMINFO ItemInfo
;
2337 DPRINT("%p hmenu=%x\n", Mt
, PtMenu
);
2342 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2347 if (! IS_SYSTEM_MENU(&MenuInfo
))
2349 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2351 MenuInitRosMenuItemInfo(&ItemInfo
);
2352 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2353 MenuInfo
.FocusedItem
== Id
)
2355 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2357 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2358 return MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2360 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2362 /* If we are dealing with the top-level menu */
2363 /* and this is a click on an already "popped" item: */
2364 /* Stop the menu tracking and close the opened submenus */
2365 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2367 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2371 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2372 MenuInfo
.TimeToHide
= TRUE
;
2373 MenuSetRosMenuInfo(&MenuInfo
);
2379 /***********************************************************************
2382 * Walks menu chain trying to find a menu pt maps to.
2384 static HMENU FASTCALL
2385 MenuPtMenu(HMENU Menu
, POINT Pt
)
2387 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2388 ROSMENUINFO MenuInfo
;
2389 ROSMENUITEMINFO ItemInfo
;
2393 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2398 /* try subpopup first (if any) */
2399 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2401 MenuInitRosMenuItemInfo(&ItemInfo
);
2402 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2403 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2404 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2406 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2409 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2413 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2416 /* check the current window (avoiding WM_HITTEST) */
2417 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2418 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2420 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2425 else if (HTSYSMENU
== Ht
)
2427 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2429 else if (HTMENU
== Ht
)
2431 Ret
= GetMenu(MenuInfo
.Wnd
);
2437 /***********************************************************************
2440 * Return TRUE if we can go on with menu tracking.
2442 static BOOL FASTCALL
2443 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2446 ROSMENUINFO MenuInfo
;
2450 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2454 if (IS_SYSTEM_MENU(&MenuInfo
))
2460 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2465 Index
= NO_SELECTED_ITEM
;
2468 if (NO_SELECTED_ITEM
== Index
)
2470 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2471 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2473 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2477 else if (MenuInfo
.FocusedItem
!= Index
)
2479 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2480 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2486 /******************************************************************************
2488 * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo)
2490 static UINT
MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo
)
2493 PROSMENUITEMINFO MenuItems
;
2495 i
= MenuInfo
->FocusedItem
;
2496 if (NO_SELECTED_ITEM
== i
)
2501 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2503 return NO_SELECTED_ITEM
;
2506 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
2508 if (0 != (MenuItems
[i
].fType
& MF_MENUBARBREAK
))
2514 return NO_SELECTED_ITEM
;
2517 /******************************************************************************
2519 * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo)
2521 static UINT FASTCALL
2522 MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo
)
2525 PROSMENUITEMINFO MenuItems
;
2527 if (0 == MenuInfo
->FocusedItem
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2529 return NO_SELECTED_ITEM
;
2532 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2534 return NO_SELECTED_ITEM
;
2537 /* Find the start of the column */
2539 for (i
= MenuInfo
->FocusedItem
;
2540 0 != i
&& 0 == (MenuItems
[i
].fType
& MF_MENUBARBREAK
);
2548 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2549 return NO_SELECTED_ITEM
;
2552 for (--i
; 0 != i
; --i
)
2554 if (MenuItems
[i
].fType
& MF_MENUBARBREAK
)
2560 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2561 DPRINT("ret %d.\n", i
);
2566 /***********************************************************************
2569 * Return the handle of the selected sub-popup menu (if any).
2571 static HMENU FASTCALL
2572 MenuGetSubPopup(HMENU Menu
)
2574 ROSMENUINFO MenuInfo
;
2575 ROSMENUITEMINFO ItemInfo
;
2577 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2578 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2583 MenuInitRosMenuItemInfo(&ItemInfo
);
2584 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2586 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2589 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2591 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2592 return ItemInfo
.hSubMenu
;
2595 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2599 /***********************************************************************
2602 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2604 static LRESULT FASTCALL
2605 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
)
2607 ROSMENUINFO TopMenuInfo
;
2608 ROSMENUINFO MenuInfo
;
2610 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2612 return (LRESULT
) FALSE
;
2615 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2616 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2618 MDINEXTMENU NextMenu
;
2623 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2624 NextMenu
.hmenuNext
= NULL
;
2625 NextMenu
.hwndNext
= NULL
;
2626 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2628 DPRINT("%p [%p] -> %p [%p]\n",
2629 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2631 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2633 DWORD Style
= GetWindowLongW(Mt
->OwnerWnd
, GWL_STYLE
);
2634 NewWnd
= Mt
->OwnerWnd
;
2635 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2637 /* switch to the menu bar */
2639 if (0 != (Style
& WS_CHILD
)
2640 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2647 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2651 Id
= MenuInfo
.MenuItemCount
- 1;
2654 else if (0 != (Style
& WS_SYSMENU
))
2656 /* switch to the system menu */
2657 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2664 else /* application returned a new menu to switch to */
2666 NewMenu
= NextMenu
.hmenuNext
;
2667 NewWnd
= NextMenu
.hwndNext
;
2669 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2671 DWORD Style
= GetWindowLongW(NewWnd
, GWL_STYLE
);
2673 if (0 != (Style
& WS_SYSMENU
)
2674 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
2676 /* get the real system menu */
2677 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2679 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
2681 /* FIXME: Not sure what to do here;
2682 * perhaps try to track NewMenu as a popup? */
2684 DPRINT(" -- got confused.\n");
2694 if (NewMenu
!= Mt
->TopMenu
)
2696 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
2698 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2700 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2704 if (NewWnd
!= Mt
->OwnerWnd
)
2706 Mt
->OwnerWnd
= NewWnd
;
2707 SetCapture(Mt
->OwnerWnd
);
2710 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
2711 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2713 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
2722 /***********************************************************************
2725 * The idea is not to show the popup if the next input message is
2726 * going to hide it anyway.
2728 static BOOL FASTCALL
2729 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
2733 Msg
.hwnd
= Mt
->OwnerWnd
;
2735 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2736 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
2741 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2742 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
2744 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2745 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2746 if (WM_KEYDOWN
== Msg
.message
2747 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
2749 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
2756 /* failures go through this */
2757 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
2762 /***********************************************************************
2765 * Handle a VK_ESCAPE key event in a menu.
2767 static BOOL FASTCALL
2768 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
2770 BOOL EndMenu
= TRUE
;
2771 ROSMENUINFO MenuInfo
;
2772 HMENU MenuTmp
, MenuPrev
;
2774 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2776 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
2777 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
2779 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2781 /* close topmost popup */
2782 while (MenuTmp
!= Mt
->CurrentMenu
)
2785 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2788 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
2790 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
);
2792 Mt
->CurrentMenu
= MenuPrev
;
2800 /***********************************************************************
2803 * Handle a VK_LEFT key event in a menu.
2805 static void FASTCALL
2806 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
2808 ROSMENUINFO MenuInfo
;
2809 ROSMENUINFO TopMenuInfo
;
2810 ROSMENUINFO PrevMenuInfo
;
2811 HMENU MenuTmp
, MenuPrev
;
2814 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
2816 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2821 /* Try to move 1 column left (if possible) */
2822 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
2824 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2826 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
2831 /* close topmost popup */
2832 while (MenuTmp
!= Mt
->CurrentMenu
)
2835 MenuTmp
= MenuGetSubPopup(MenuPrev
);
2838 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
2842 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
);
2843 Mt
->CurrentMenu
= MenuPrev
;
2845 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2849 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
2851 /* move menu bar selection if no more popups are left */
2853 if (! MenuDoNextMenu(Mt
, VK_LEFT
))
2855 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
2858 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
2860 /* A sublevel menu was displayed - display the next one
2861 * unless there is another displacement coming up */
2863 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
2864 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2866 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
2873 /***********************************************************************
2876 * Handle a VK_RIGHT key event in a menu.
2878 static void FASTCALL
2879 MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
2882 ROSMENUINFO MenuInfo
;
2883 ROSMENUINFO CurrentMenuInfo
;
2886 DPRINT("MenuKeyRight called, cur %p, top %p.\n",
2887 Mt
->CurrentMenu
, Mt
->TopMenu
);
2889 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
2893 if (0 != (MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
2895 /* If already displaying a popup, try to display sub-popup */
2897 MenuTmp
= Mt
->CurrentMenu
;
2898 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
2900 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
2903 /* if subpopup was displayed then we are done */
2904 if (MenuTmp
!= Mt
->CurrentMenu
)
2910 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
2915 /* Check to see if there's another column */
2916 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
2918 DPRINT("Going to %d.\n", NextCol
);
2919 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2921 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
2926 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
2928 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
2930 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
);
2931 MenuTmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
2938 /* try to move to the next item */
2939 if (! MenuDoNextMenu(Mt
, VK_RIGHT
))
2941 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
2944 if (NULL
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
2946 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
2947 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
2949 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
2956 /***********************************************************************
2959 * Find the menu item selected by a key press.
2960 * Return item id, -1 if none, -2 if we should close the menu.
2962 static UINT FASTCALL
2963 MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2964 WCHAR Key
, BOOL ForceMenuChar
)
2966 ROSMENUINFO SysMenuInfo
;
2967 PROSMENUITEMINFO Items
, ItemInfo
;
2971 DPRINT("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
2973 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
2975 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
2977 MenuInfo
= &SysMenuInfo
;
2985 if (NULL
!= MenuInfo
)
2987 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
2991 if (! ForceMenuChar
)
2993 Key
= towupper(Key
);
2995 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
2997 if (IS_STRING_ITEM(ItemInfo
->fType
) && NULL
!= ItemInfo
->dwTypeData
)
2999 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
3002 p
= wcschr(p
+ 2, '&');
3004 while (NULL
!= p
&& L
'&' == p
[1]);
3005 if (NULL
!= p
&& (towupper(p
[1]) == Key
))
3013 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
3014 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
3015 if (2 == HIWORD(MenuChar
))
3017 return LOWORD(MenuChar
);
3019 if (1 == HIWORD(MenuChar
))
3028 /***********************************************************************
3031 * Menu tracking code.
3034 MenuTrackMenu(HMENU Menu
, UINT Flags
, INT x
, INT y
,
3035 HWND Wnd
, const RECT
*Rect
)
3038 ROSMENUINFO MenuInfo
;
3039 ROSMENUITEMINFO ItemInfo
;
3041 INT ExecutedMenuId
= -1;
3043 BOOL EnterIdleSent
= FALSE
;
3046 Mt
.CurrentMenu
= Menu
;
3052 DPRINT("Menu=%x Flags=0x%08x (%d,%d) Wnd=%x (%ld,%ld)-(%ld,%ld)\n",
3053 Menu
, Flags
, x
, y
, Wnd
, Rect
? Rect
->left
: 0, Rect
? Rect
->top
: 0,
3054 Rect
? Rect
->right
: 0, Rect
? Rect
->bottom
: 0);
3057 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
3062 if (0 != (Flags
& TPM_BUTTONDOWN
))
3064 /* Get the result in order to start the tracking or not */
3065 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3066 fEndMenu
= ! fRemove
;
3069 SetCapture(Mt
.OwnerWnd
);
3073 /* we have to keep the message in the queue until it's
3074 * clear that menu loop is not over yet. */
3078 if (PeekMessageW(&Msg
, 0, 0, 0, PM_NOREMOVE
))
3080 if (! CallMsgFilterW(&Msg
, MSGF_MENU
))
3084 /* remove the message from the queue */
3085 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3089 if (! EnterIdleSent
)
3091 HWND Win
= (0 != (Flags
& TPM_ENTERIDLEEX
)
3092 && 0 != (MenuInfo
.Flags
& MF_POPUP
)) ? MenuInfo
.Wnd
: NULL
;
3093 EnterIdleSent
= TRUE
;
3094 SendMessageW(Mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) Win
);
3100 /* check if EndMenu() tried to cancel us, by posting this message */
3101 if (WM_CANCELMODE
== Msg
.message
)
3103 /* we are now out of the loop */
3106 /* remove the message from the queue */
3107 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3109 /* break out of internal loop, ala ESCAPE */
3113 TranslateMessage(&Msg
);
3116 if (Msg
.hwnd
== MenuInfo
.Wnd
|| WM_TIMER
!= Msg
.message
)
3118 EnterIdleSent
= FALSE
;
3122 if (WM_MOUSEFIRST
<= Msg
.message
&& Msg
.message
<= WM_MOUSELAST
)
3125 * Use the mouse coordinates in lParam instead of those in the MSG
3126 * struct to properly handle synthetic messages. They are already
3127 * in screen coordinates.
3129 Mt
.Pt
.x
= (short) LOWORD(Msg
.lParam
);
3130 Mt
.Pt
.y
= (short) HIWORD(Msg
.lParam
);
3132 /* Find a menu for this mouse event */
3133 Menu
= MenuPtMenu(Mt
.TopMenu
, Mt
.Pt
);
3137 /* no WM_NC... messages in captured state */
3139 case WM_RBUTTONDBLCLK
:
3140 case WM_RBUTTONDOWN
:
3141 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3146 case WM_LBUTTONDBLCLK
:
3147 case WM_LBUTTONDOWN
:
3148 /* If the message belongs to the menu, removes it from the queue */
3149 /* Else, end menu tracking */
3150 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3151 fEndMenu
= ! fRemove
;
3155 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3161 /* Check if a menu was selected by the mouse */
3164 ExecutedMenuId
= MenuButtonUp(&Mt
, Menu
, Flags
);
3166 /* End the loop if ExecutedMenuId is an item ID */
3167 /* or if the job was done (ExecutedMenuId = 0). */
3168 fEndMenu
= fRemove
= (-1 != ExecutedMenuId
);
3172 /* No menu was selected by the mouse */
3173 /* if the function was called by TrackPopupMenu, continue
3174 with the menu tracking. If not, stop it */
3175 fEndMenu
= (0 != (Flags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3182 fEndMenu
|= ! MenuMouseMove(&Mt
, Menu
, Flags
);
3186 } /* switch(Msg.message) - mouse */
3188 else if (WM_KEYFIRST
<= Msg
.message
&& Msg
.message
<= WM_KEYLAST
)
3190 fRemove
= TRUE
; /* Keyboard messages are always removed */
3198 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3200 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3206 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3208 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
,
3209 VK_HOME
== Msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3213 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3214 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3216 if (0 == (MenuInfo
.Flags
& MF_POPUP
))
3218 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3220 Mt
.CurrentMenu
= MenuShowSubPopup(Mt
.OwnerWnd
, &MenuInfo
,
3224 else /* otherwise try to move selection */
3226 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3232 MenuKeyLeft(&Mt
, Flags
);
3236 MenuKeyRight(&Mt
, Flags
);
3240 fEndMenu
= MenuKeyEscape(&Mt
, Flags
);
3246 hi
.cbSize
= sizeof(HELPINFO
);
3247 hi
.iContextType
= HELPINFO_MENUITEM
;
3248 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3250 if (NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
3256 MenuInitRosMenuItemInfo(&ItemInfo
);
3257 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3258 MenuInfo
.FocusedItem
,
3261 hi
.iCtrlId
= ItemInfo
.wID
;
3267 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3270 hi
.hItemHandle
= Menu
;
3271 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3272 hi
.MousePos
= Msg
.pt
;
3273 SendMessageW(Wnd
, WM_HELP
, 0, (LPARAM
) &hi
);
3280 break; /* WM_KEYDOWN */
3289 break; /* WM_SYSKEYDOWN */
3295 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3299 if (L
'\r' == Msg
.wParam
|| L
' ' == Msg
.wParam
)
3301 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3302 fEndMenu
= (ExecutedMenuId
!= -1);
3306 /* Hack to avoid control chars. */
3307 /* We will find a better way real soon... */
3308 if (Msg
.wParam
< 32)
3313 Pos
= MenuFindItemByKey(Mt
.OwnerWnd
, &MenuInfo
,
3314 LOWORD(Msg
.wParam
), FALSE
);
3315 if ((UINT
) -2 == Pos
)
3319 else if ((UINT
) -1 == Pos
)
3325 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, Pos
, TRUE
, 0);
3326 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3327 fEndMenu
= (-1 != ExecutedMenuId
);
3331 } /* switch(msg.message) - kbd */
3335 DispatchMessageW(&Msg
);
3343 /* finally remove message from the queue */
3345 if (fRemove
&& 0 == (Mt
.TrackFlags
& TF_SKIPREMOVE
))
3347 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3351 Mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3355 SetCapture(NULL
); /* release the capture */
3357 /* If dropdown is still painted and the close box is clicked on
3358 then the menu will be destroyed as part of the DispatchMessage above.
3359 This will then invalidate the menu handle in Mt.hTopMenu. We should
3360 check for this first. */
3361 if (IsMenu(Mt
.TopMenu
))
3363 if (IsWindow(Mt
.OwnerWnd
))
3365 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3367 MenuHideSubPopups(Mt
.OwnerWnd
, &MenuInfo
, FALSE
);
3369 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
3371 DestroyWindow(MenuInfo
.Wnd
);
3372 MenuInfo
.Wnd
= NULL
;
3374 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3377 SendMessageW(Mt
.OwnerWnd
, WM_MENUSELECT
, MAKELONG(0, 0xffff), 0);
3380 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3382 /* Reset the variable for hiding menu */
3383 MenuInfo
.TimeToHide
= FALSE
;
3384 MenuSetRosMenuInfo(&MenuInfo
);
3388 /* The return value is only used by TrackPopupMenu */
3389 return (-1 != ExecutedMenuId
) ? ExecutedMenuId
: 0;
3392 /***********************************************************************
3395 static BOOL FASTCALL
3396 MenuExitTracking(HWND Wnd
)
3398 DPRINT("hwnd=%p\n", hWnd
);
3400 SendMessageW(Wnd
, WM_EXITMENULOOP
, 0, 0);
3407 MenuTrackMouseMenuBar(HWND Wnd
, ULONG Ht
, POINT Pt
)
3409 HMENU Menu
= (HTSYSMENU
== Ht
) ? NtUserGetSystemMenu(Wnd
, FALSE
) : GetMenu(Wnd
);
3410 UINT Flags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3412 DPRINT("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd
, Ht
, pt
.x
, pt
.y
);
3416 /* map point to parent client coordinates */
3417 HWND Parent
= GetAncestor(Wnd
, GA_PARENT
);
3418 if (Parent
!= GetDesktopWindow())
3420 ScreenToClient(Parent
, &Pt
);
3423 MenuInitTracking(Wnd
, Menu
, FALSE
, Flags
);
3424 MenuTrackMenu(Menu
, Flags
, Pt
.x
, Pt
.y
, Wnd
, NULL
);
3425 MenuExitTracking(Wnd
);
3431 MenuTrackKbdMenuBar(HWND hWnd
, ULONG wParam
, ULONG Key
)
3435 /* FUNCTIONS *****************************************************************/
3438 MenuIsStringItem(ULONG TypeData)
3440 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
3448 AppendMenuA(HMENU hMenu
,
3450 UINT_PTR uIDNewItem
,
3453 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3462 AppendMenuW(HMENU hMenu
,
3464 UINT_PTR uIDNewItem
,
3467 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
3476 CheckMenuItem(HMENU hmenu
,
3480 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
3488 CheckMenuRadioItem(HMENU hmenu
,
3506 return NtUserCreateMenu(FALSE
);
3514 CreatePopupMenu(VOID
)
3517 return NtUserCreateMenu(TRUE
);
3525 DeleteMenu(HMENU hMenu
,
3529 return NtUserDeleteMenu(hMenu
, uPosition
, uFlags
);
3537 DestroyMenu(HMENU hMenu
)
3539 return NtUserDestroyMenu(hMenu
);
3547 DrawMenuBar(HWND hWnd
)
3550 /* FIXME - return NtUserCallHwndLock(hWnd, 0x55); */
3559 EnableMenuItem(HMENU hMenu
,
3563 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
3573 guii
.cbSize
= sizeof(GUITHREADINFO
);
3574 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
3576 PostMessageW(guii
.hwndMenuOwner
, WM_CANCELMODE
, 0, 0);
3588 return NtUserGetMenu(hWnd
);
3596 GetMenuBarInfo(HWND hwnd
,
3601 return (BOOL
)NtUserGetMenuBarInfo(hwnd
, idObject
, idItem
, pmbi
);
3609 GetMenuCheckMarkDimensions(VOID
)
3611 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
3612 GetSystemMetrics(SM_CYMENUCHECK
)));
3620 GetMenuDefaultItem(HMENU hMenu
,
3624 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
3632 GetMenuInfo(HMENU hmenu
,
3638 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
3641 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
3642 mi
.cbSize
= sizeof(MENUINFO
);
3643 mi
.fMask
= lpcmi
->fMask
;
3645 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
3647 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
3656 GetMenuItemCount(HMENU Menu
)
3658 ROSMENUINFO MenuInfo
;
3660 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
3668 GetMenuItemID(HMENU hMenu
,
3671 ROSMENUITEMINFO mii
;
3673 mii
.cbSize
= sizeof(MENUITEMINFOW
);
3674 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
3676 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
3681 if (NULL
!= mii
.hSubMenu
)
3702 LPMENUITEMINFOA lpmii
)
3718 LPMENUITEMINFOW lpmii
)
3729 GetMenuItemRect(HWND hWnd
,
3749 ROSMENUINFO MenuInfo
;
3750 ROSMENUITEMINFO mii
;
3752 mii
.cbSize
= sizeof(MENUITEMINFOW
);
3753 mii
.fMask
= MIIM_STATE
| MIIM_TYPE
| MIIM_SUBMENU
;
3756 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
3761 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
3765 nSubItems
= MenuInfo
.MenuItemCount
;
3767 /* FIXME - ported from wine, does that work (0xff)? */
3768 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
3769 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
3771 return (UINT
)-1; /* Invalid submenu */
3774 /* FIXME - ported from wine, does that work? */
3775 return (mii
.fType
| mii
.fState
);
3827 mi
.cbSize
= sizeof(MENUITEMINFOW
);
3828 mi
.fMask
= MIIM_SUBMENU
;
3830 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
3832 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
3849 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
3851 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
3866 return NtUserHiliteMenuItem(hwnd
, hmenu
, uItemHilite
, uHilite
);
3879 UINT_PTR uIDNewItem
,
3883 mii
.cbSize
= sizeof(MENUITEMINFOA
);
3884 mii
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
;
3886 mii
.fState
= MFS_ENABLED
;
3888 if(uFlags
& MF_BITMAP
)
3890 mii
.fType
|= MFT_BITMAP
;
3892 else if(uFlags
& MF_OWNERDRAW
)
3894 mii
.fType
|= MFT_OWNERDRAW
;
3897 if(uFlags
& MF_RIGHTJUSTIFY
)
3899 mii
.fType
|= MFT_RIGHTJUSTIFY
;
3901 if(uFlags
& MF_MENUBREAK
)
3903 mii
.fType
|= MFT_MENUBREAK
;
3905 if(uFlags
& MF_MENUBARBREAK
)
3907 mii
.fType
|= MFT_MENUBARBREAK
;
3909 if(uFlags
& MF_DISABLED
)
3911 mii
.fState
|= MFS_DISABLED
;
3913 if(uFlags
& MF_GRAYED
)
3915 mii
.fState
|= MFS_GRAYED
;
3918 mii
.dwTypeData
= (LPSTR
)lpNewItem
;
3919 if(uFlags
& MF_POPUP
)
3921 mii
.fMask
|= MIIM_SUBMENU
;
3922 mii
.hSubMenu
= (HMENU
)uIDNewItem
;
3926 mii
.fMask
|= MIIM_ID
;
3927 mii
.wID
= (UINT
)uIDNewItem
;
3929 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)!(MF_BYPOSITION
& uFlags
), &mii
);
3942 LPCMENUITEMINFOA lpmii
)
3945 UNICODE_STRING MenuText
;
3947 BOOL CleanHeap
= FALSE
;
3950 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
3951 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
3953 RtlMoveMemory ( &mi
, lpmii
, lpmii
->cbSize
);
3955 /* copy the text string */
3956 if((mi
.fMask
& (MIIM_TYPE
| MIIM_STRING
)) &&
3957 (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
) && mi
.dwTypeData
)
3959 Status
= HEAP_strdupAtoW ( &mi
.dwTypeData
, (LPCSTR
)mi
.dwTypeData
, &mi
.cch
);
3960 if (!NT_SUCCESS (Status
))
3962 SetLastError (RtlNtStatusToDosError(Status
));
3965 RtlInitUnicodeString(&MenuText
, (PWSTR
)mi
.dwTypeData
);
3966 mi
.dwTypeData
= (LPWSTR
)&MenuText
;
3970 res
= NtUserInsertMenuItem(hMenu
, uItem
, fByPosition
, &mi
);
3972 if ( CleanHeap
) HEAP_free ( mi
.dwTypeData
);
3987 LPCMENUITEMINFOW lpmii
)
3990 UNICODE_STRING MenuText
;
3992 BOOL CleanHeap
= FALSE
;
3993 HANDLE hHeap
= RtlGetProcessHeap();
3994 mi
.hbmpItem
= (HBITMAP
)0;
3996 // while we could just pass 'lpmii' to win32k, we make a copy so that
3997 // if a bad user passes bad data, we crash his process instead of the
4000 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4001 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4003 memcpy(&mi
, lpmii
, lpmii
->cbSize
);
4005 /* copy the text string */
4006 if((mi
.fMask
& (MIIM_TYPE
| MIIM_STRING
)) &&
4007 (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
) && mi
.dwTypeData
)
4011 if(!RtlCreateUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
))
4013 SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY
));
4016 mi
.dwTypeData
= (LPWSTR
)&MenuText
;
4017 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4022 res
= NtUserInsertMenuItem(hMenu
, uItem
, fByPosition
, &mi
);
4024 if(CleanHeap
) RtlFreeHeap (hHeap
, 0, mi
.dwTypeData
);
4039 UINT_PTR uIDNewItem
,
4043 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4044 mii
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
;
4046 mii
.fState
= MFS_ENABLED
;
4048 if(uFlags
& MF_BITMAP
)
4050 mii
.fType
|= MFT_BITMAP
;
4052 else if(uFlags
& MF_OWNERDRAW
)
4054 mii
.fType
|= MFT_OWNERDRAW
;
4057 if(uFlags
& MF_RIGHTJUSTIFY
)
4059 mii
.fType
|= MFT_RIGHTJUSTIFY
;
4061 if(uFlags
& MF_MENUBREAK
)
4063 mii
.fType
|= MFT_MENUBREAK
;
4065 if(uFlags
& MF_MENUBARBREAK
)
4067 mii
.fType
|= MFT_MENUBARBREAK
;
4069 if(uFlags
& MF_DISABLED
)
4071 mii
.fState
|= MFS_DISABLED
;
4073 if(uFlags
& MF_GRAYED
)
4075 mii
.fState
|= MFS_GRAYED
;
4078 mii
.dwTypeData
= (LPWSTR
)lpNewItem
;
4079 mii
.cch
= (NULL
== lpNewItem
? 0 : wcslen(lpNewItem
));
4080 if(uFlags
& MF_POPUP
)
4082 mii
.fType
|= MF_POPUP
;
4083 mii
.fMask
|= MIIM_SUBMENU
;
4084 mii
.hSubMenu
= (HMENU
)uIDNewItem
;
4088 mii
.fMask
|= MIIM_ID
;
4089 mii
.wID
= (UINT
)uIDNewItem
;
4091 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)!(MF_BYPOSITION
& uFlags
), &mii
);
4103 ROSMENUINFO MenuInfo
;
4105 return MenuGetRosMenuInfo(&MenuInfo
, Menu
);
4113 LoadMenuA(HINSTANCE hInstance
,
4116 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4117 if (Resource
== NULL
)
4121 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4129 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4131 return(LoadMenuIndirectW(lpMenuTemplate
));
4139 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4142 WORD version
, offset
;
4143 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4145 version
= GET_WORD(p
);
4150 case 0: /* standard format is version of 0 */
4151 offset
= GET_WORD(p
);
4152 p
+= sizeof(WORD
) + offset
;
4153 if (!(hMenu
= CreateMenu())) return 0;
4154 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4160 case 1: /* extended format is version of 1 */
4161 offset
= GET_WORD(p
);
4162 p
+= sizeof(WORD
) + offset
;
4163 if (!(hMenu
= CreateMenu())) return 0;
4164 if (!MENUEX_ParseResource(p
, hMenu
))
4166 DestroyMenu( hMenu
);
4171 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4181 LoadMenuW(HINSTANCE hInstance
,
4184 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4185 if (Resource
== NULL
)
4189 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4203 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4216 UINT_PTR uIDNewItem
,
4233 UINT_PTR uIDNewItem
,
4251 return NtUserRemoveMenu(hMenu
, uPosition
, uFlags
);
4262 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
4276 return NtUserSetMenuDefaultItem(hMenu
, uItem
, fByPos
);
4291 if(lpcmi
->cbSize
!= sizeof(MENUINFO
))
4294 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
4295 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
4308 HBITMAP hBitmapUnchecked
,
4309 HBITMAP hBitmapChecked
)
4325 LPMENUITEMINFOA lpmii
)
4341 LPMENUITEMINFOW lpmii
)
4358 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
4363 SetLastError(ERROR_INVALID_MENU_HANDLE
);
4366 return NtUserSetSystemMenu(hwnd
, hMenu
);
4386 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
4388 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4389 if (0 == (Flags
& TPM_NONOTIFY
))
4391 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
4394 if (MenuShowPopup(Wnd
, Menu
, 0, x
, y
, 0, 0 ))
4396 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
, Rect
);
4398 MenuExitTracking(Wnd
);
4417 /* Not fully implemented */
4418 return TrackPopupMenu(Menu
, Flags
, x
, y
, 0, Wnd
,
4419 NULL
!= Tpm
? &Tpm
->rcExclude
: NULL
);
4428 SetMenuContextHelpId(HMENU hmenu
,
4429 DWORD dwContextHelpId
)
4431 return NtUserSetMenuContextHelpId(hmenu
, dwContextHelpId
);
4440 GetMenuContextHelpId(HMENU hmenu
)
4443 mi
.cbSize
= sizeof(ROSMENUINFO
);
4444 mi
.fMask
= MIM_HELPID
;
4446 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
4448 return mi
.dwContextHelpID
;
4493 LPCWSTR lpszNewItem
,
4498 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
4499 for MF_DELETE. We should check the parameters for all others
4500 MF_* actions also (anybody got a doc on ChangeMenu?).
4503 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
4506 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
4509 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
4512 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
4515 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
4516 flags
&~ MF_REMOVE
);
4518 default : /* MF_INSERT */
4519 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
4536 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
4537 for MF_DELETE. We should check the parameters for all others
4538 MF_* actions also (anybody got a doc on ChangeMenu?).
4541 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
4544 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
4547 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
4550 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
4553 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
4554 flags
&~ MF_REMOVE
);
4556 default : /* MF_INSERT */
4557 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);