4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
7 * Copyright 2005 Maxime Bellengé
8 * Copyright 2006 Phil Krylov
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library 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 GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * Note: the style MF_MOUSESELECT is used to mark popup items that
27 * have been selected, i.e. their popup menu is currently displayed.
28 * This is probably not the meaning this style has in MS-Windows.
30 * Note 2: where there is a difference, these menu API's are according
31 * the behavior of Windows 2k and Windows XP. Known differences with
32 * Windows 9x/ME are documented in the comments, in case an application
33 * is found to depend on the old behavior.
43 #include "wine/port.h"
54 #include "wine/server.h"
55 #include "wine/unicode.h"
56 #include "wine/exception.h"
59 #include "user_private.h"
60 #include "wine/debug.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(menu
);
63 WINE_DECLARE_DEBUG_CHANNEL(accel
);
65 /* internal popup menu window messages */
67 #define MM_SETMENUHANDLE (WM_USER + 0)
68 #define MM_GETMENUHANDLE (WM_USER + 1)
70 /* Menu item structure */
72 /* ----------- MENUITEMINFO Stuff ----------- */
73 UINT fType
; /* Item type. */
74 UINT fState
; /* Item state. */
75 UINT_PTR wID
; /* Item id. */
76 HMENU hSubMenu
; /* Pop-up menu. */
77 HBITMAP hCheckBit
; /* Bitmap when checked. */
78 HBITMAP hUnCheckBit
; /* Bitmap when unchecked. */
79 LPWSTR text
; /* Item text. */
80 ULONG_PTR dwItemData
; /* Application defined. */
81 LPWSTR dwTypeData
; /* depends on fMask */
82 HBITMAP hbmpItem
; /* bitmap */
83 /* ----------- Wine stuff ----------- */
84 RECT rect
; /* Item area (relative to menu window) */
85 UINT xTab
; /* X position of text after Tab */
86 SIZE bmpsize
; /* size needed for the HBMMENU_CALLBACK
90 /* Popup menu structure */
92 struct user_object obj
;
93 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
94 WORD Width
; /* Width of the whole menu */
95 WORD Height
; /* Height of the whole menu */
96 UINT nItems
; /* Number of items in the menu */
97 HWND hWnd
; /* Window containing the menu */
98 MENUITEM
*items
; /* Array of menu items */
99 UINT FocusedItem
; /* Currently focused item */
100 HWND hwndOwner
; /* window receiving the messages for ownerdraw */
101 BOOL bTimeToHide
; /* Request hiding when receiving a second click in the top-level menu item */
102 BOOL bScrolling
; /* Scroll arrows are active */
103 UINT nScrollPos
; /* Current scroll position */
104 UINT nTotalHeight
; /* Total height of menu items inside menu */
105 /* ------------ MENUINFO members ------ */
106 DWORD dwStyle
; /* Extended menu style */
107 UINT cyMax
; /* max height of the whole menu, 0 is screen height */
108 HBRUSH hbrBack
; /* brush for menu background */
109 DWORD dwContextHelpID
;
110 DWORD dwMenuData
; /* application defined value */
111 HMENU hSysMenuOwner
; /* Handle to the dummy sys menu holder */
112 WORD textOffset
; /* Offset of text when items have both bitmaps and text */
113 } POPUPMENU
, *LPPOPUPMENU
;
115 /* internal flags for menu tracking */
117 #define TF_ENDMENU 0x10000
118 #define TF_SUSPENDPOPUP 0x20000
119 #define TF_SKIPREMOVE 0x40000
124 HMENU hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
125 HMENU hTopMenu
; /* initial menu */
126 HWND hOwnerWnd
; /* where notifications are sent */
130 #define MENU_MAGIC 0x554d /* 'MU' */
135 /* Internal MENU_TrackMenu() flags */
136 #define TPM_INTERNAL 0xF0000000
137 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
138 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
140 /* Space between 2 columns */
141 #define MENU_COL_SPACE 4
143 /* top and bottom margins for popup menus */
144 #define MENU_TOP_MARGIN 3
145 #define MENU_BOTTOM_MARGIN 2
147 /* maximum allowed depth of any branch in the menu tree.
148 * This value is slightly larger than in windows (25) to
149 * stay on the safe side. */
150 #define MAXMENUDEPTH 30
152 /* (other menu->FocusedItem values give the position of the focused item) */
153 #define NO_SELECTED_ITEM 0xffff
155 #define MENU_ITEM_TYPE(flags) \
156 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
158 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
159 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
160 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
162 #define IS_SYSTEM_MENU(menu) \
163 (!((menu)->wFlags & MF_POPUP) && ((menu)->wFlags & MF_SYSMENU))
165 #define MENUITEMINFO_TYPE_MASK \
166 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
167 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
168 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
169 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
170 #define STATE_MASK (~TYPE_MASK)
171 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
173 #define WIN_ALLOWED_MENU(style) ((style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
175 static SIZE menucharsize
;
176 static UINT ODitemheight
; /* default owner drawn item height */
178 /* Use global popup window because there's no way 2 menus can
179 * be tracked at the same time. */
180 static HWND top_popup
;
181 static HMENU top_popup_hmenu
;
183 /* Flag set by EndMenu() to force an exit from menu tracking */
184 static BOOL fEndMenu
= FALSE
;
186 DWORD WINAPI
DrawMenuBarTemp(HWND hwnd
, HDC hDC
, LPRECT lprect
, HMENU hMenu
, HFONT hFont
);
188 static BOOL
SetMenuItemInfo_common( MENUITEM
*, const MENUITEMINFOW
*, BOOL
);
190 /*********************************************************************
191 * menu class descriptor
193 const struct builtin_class_descr MENU_builtin_class
=
195 (LPCWSTR
)POPUPMENU_CLASS_ATOM
, /* name */
196 CS_DROPSHADOW
| CS_SAVEBITS
| CS_DBLCLKS
, /* style */
197 WINPROC_MENU
, /* proc */
198 sizeof(HMENU
), /* extra */
199 IDC_ARROW
, /* cursor */
200 (HBRUSH
)(COLOR_MENU
+1) /* brush */
204 /***********************************************************************
205 * debug_print_menuitem
207 * Print a menuitem in readable form.
210 #define debug_print_menuitem(pre, mp, post) \
211 do { if (TRACE_ON(menu)) do_debug_print_menuitem(pre, mp, post); } while (0)
213 #define MENUOUT(text) \
214 TRACE("%s%s", (count++ ? "," : ""), (text))
216 #define MENUFLAG(bit,text) \
218 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
221 static void do_debug_print_menuitem(const char *prefix
, const MENUITEM
*mp
,
224 static const char * const hbmmenus
[] = { "HBMMENU_CALLBACK", "", "HBMMENU_SYSTEM",
225 "HBMMENU_MBAR_RESTORE", "HBMMENU_MBAR_MINIMIZE", "UNKNOWN BITMAP", "HBMMENU_MBAR_CLOSE",
226 "HBMMENU_MBAR_CLOSE_D", "HBMMENU_MBAR_MINIMIZE_D", "HBMMENU_POPUP_CLOSE",
227 "HBMMENU_POPUP_RESTORE", "HBMMENU_POPUP_MAXIMIZE", "HBMMENU_POPUP_MINIMIZE"};
228 TRACE("%s ", prefix
);
230 UINT flags
= mp
->fType
;
231 TRACE( "{ ID=0x%lx", mp
->wID
);
233 TRACE( ", Sub=%p", mp
->hSubMenu
);
237 MENUFLAG( MFT_SEPARATOR
, "sep");
238 MENUFLAG( MFT_OWNERDRAW
, "own");
239 MENUFLAG( MFT_BITMAP
, "bit");
240 MENUFLAG(MF_POPUP
, "pop");
241 MENUFLAG(MFT_MENUBARBREAK
, "barbrk");
242 MENUFLAG(MFT_MENUBREAK
, "brk");
243 MENUFLAG(MFT_RADIOCHECK
, "radio");
244 MENUFLAG(MFT_RIGHTORDER
, "rorder");
245 MENUFLAG(MF_SYSMENU
, "sys");
246 MENUFLAG(MFT_RIGHTJUSTIFY
, "right"); /* same as MF_HELP */
248 TRACE( "+0x%x", flags
);
254 MENUFLAG(MFS_GRAYED
, "grey");
255 MENUFLAG(MFS_DEFAULT
, "default");
256 MENUFLAG(MFS_DISABLED
, "dis");
257 MENUFLAG(MFS_CHECKED
, "check");
258 MENUFLAG(MFS_HILITE
, "hi");
259 MENUFLAG(MF_USECHECKBITMAPS
, "usebit");
260 MENUFLAG(MF_MOUSESELECT
, "mouse");
262 TRACE( "+0x%x", flags
);
265 TRACE( ", Chk=%p", mp
->hCheckBit
);
267 TRACE( ", Unc=%p", mp
->hUnCheckBit
);
269 TRACE( ", Text=%s", debugstr_w(mp
->text
));
271 TRACE( ", ItemData=0x%08lx", mp
->dwItemData
);
274 if( IS_MAGIC_BITMAP(mp
->hbmpItem
))
275 TRACE( ", hbitmap=%s", hbmmenus
[ (INT_PTR
)mp
->hbmpItem
+ 1]);
277 TRACE( ", hbitmap=%p", mp
->hbmpItem
);
282 TRACE(" %s\n", postfix
);
289 /***********************************************************************
292 * Validate the given menu handle and returns the menu structure pointer.
294 static POPUPMENU
*MENU_GetMenu(HMENU hMenu
)
296 POPUPMENU
*menu
= get_user_handle_ptr( hMenu
, USER_MENU
);
298 if (menu
== OBJ_OTHER_PROCESS
)
300 WARN( "other process menu %p?\n", hMenu
);
303 if (menu
) release_user_handle_ptr( menu
); /* FIXME! */
304 else WARN("invalid menu handle=%p\n", hMenu
);
308 /***********************************************************************
311 * Get the system menu of a window
313 static HMENU
get_win_sys_menu( HWND hwnd
)
316 WND
*win
= WIN_GetPtr( hwnd
);
317 if (win
&& win
!= WND_OTHER_PROCESS
&& win
!= WND_DESKTOP
)
320 WIN_ReleasePtr( win
);
325 /***********************************************************************
328 static HFONT
get_menu_font( BOOL bold
)
330 static HFONT hMenuFont
, hMenuFontBold
;
332 HFONT ret
= bold
? hMenuFontBold
: hMenuFont
;
336 NONCLIENTMETRICSW ncm
;
339 ncm
.cbSize
= sizeof(NONCLIENTMETRICSW
);
340 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICSW
), &ncm
, 0);
344 ncm
.lfMenuFont
.lfWeight
+= 300;
345 if (ncm
.lfMenuFont
.lfWeight
> 1000) ncm
.lfMenuFont
.lfWeight
= 1000;
347 if (!(ret
= CreateFontIndirectW( &ncm
.lfMenuFont
))) return 0;
348 prev
= InterlockedCompareExchangePointer( (void **)(bold
? &hMenuFontBold
: &hMenuFont
),
352 /* another thread beat us to it */
360 /***********************************************************************
363 static HBITMAP
get_arrow_bitmap(void)
365 static HBITMAP arrow_bitmap
;
367 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW
));
371 /***********************************************************************
372 * get_down_arrow_bitmap
374 static HBITMAP
get_down_arrow_bitmap(void)
376 static HBITMAP arrow_bitmap
;
378 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW
));
382 /***********************************************************************
383 * get_down_arrow_inactive_bitmap
385 static HBITMAP
get_down_arrow_inactive_bitmap(void)
387 static HBITMAP arrow_bitmap
;
389 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI
));
393 /***********************************************************************
394 * get_up_arrow_bitmap
396 static HBITMAP
get_up_arrow_bitmap(void)
398 static HBITMAP arrow_bitmap
;
400 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW
));
404 /***********************************************************************
405 * get_up_arrow_inactive_bitmap
407 static HBITMAP
get_up_arrow_inactive_bitmap(void)
409 static HBITMAP arrow_bitmap
;
411 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI
));
415 /***********************************************************************
418 * Return the default system menu.
420 static HMENU
MENU_CopySysPopup(BOOL mdi
)
422 static const WCHAR sysmenuW
[] = {'S','Y','S','M','E','N','U',0};
423 static const WCHAR sysmenumdiW
[] = {'S','Y','S','M','E','N','U','M','D','I',0};
424 HMENU hMenu
= LoadMenuW(user32_module
, (mdi
? sysmenumdiW
: sysmenuW
));
428 MENUITEMINFOW miteminfo
;
429 POPUPMENU
* menu
= MENU_GetMenu(hMenu
);
430 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
431 /* decorate the menu with bitmaps */
432 minfo
.cbSize
= sizeof( MENUINFO
);
433 minfo
.dwStyle
= MNS_CHECKORBMP
;
434 minfo
.fMask
= MIM_STYLE
;
435 SetMenuInfo( hMenu
, &minfo
);
436 miteminfo
.cbSize
= sizeof( MENUITEMINFOW
);
437 miteminfo
.fMask
= MIIM_BITMAP
;
438 miteminfo
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
439 SetMenuItemInfoW( hMenu
, SC_CLOSE
, FALSE
, &miteminfo
);
440 miteminfo
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
441 SetMenuItemInfoW( hMenu
, SC_RESTORE
, FALSE
, &miteminfo
);
442 miteminfo
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
443 SetMenuItemInfoW( hMenu
, SC_MAXIMIZE
, FALSE
, &miteminfo
);
444 miteminfo
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
445 SetMenuItemInfoW( hMenu
, SC_MINIMIZE
, FALSE
, &miteminfo
);
446 SetMenuDefaultItem(hMenu
, SC_CLOSE
, FALSE
);
449 ERR("Unable to load default system menu\n" );
451 TRACE("returning %p (mdi=%d).\n", hMenu
, mdi
);
457 /**********************************************************************
460 * Create a copy of the system menu. System menu in Windows is
461 * a special menu bar with the single entry - system menu popup.
462 * This popup is presented to the outside world as a "system menu".
463 * However, the real system menu handle is sometimes seen in the
464 * WM_MENUSELECT parameters (and Word 6 likes it this way).
466 static HMENU
MENU_GetSysMenu( HWND hWnd
, HMENU hPopupMenu
)
470 TRACE("loading system menu, hWnd %p, hPopupMenu %p\n", hWnd
, hPopupMenu
);
471 if ((hMenu
= CreateMenu()))
473 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
474 menu
->wFlags
= MF_SYSMENU
;
475 menu
->hWnd
= WIN_GetFullHandle( hWnd
);
476 TRACE("hWnd %p (hMenu %p)\n", menu
->hWnd
, hMenu
);
480 if (GetWindowLongW(hWnd
, GWL_EXSTYLE
) & WS_EX_MDICHILD
)
481 hPopupMenu
= MENU_CopySysPopup(TRUE
);
483 hPopupMenu
= MENU_CopySysPopup(FALSE
);
488 if (GetClassLongW(hWnd
, GCL_STYLE
) & CS_NOCLOSE
)
489 DeleteMenu(hPopupMenu
, SC_CLOSE
, MF_BYCOMMAND
);
491 InsertMenuW( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
,
492 (UINT_PTR
)hPopupMenu
, NULL
);
494 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
495 menu
->items
[0].fState
= 0;
496 if ((menu
= MENU_GetMenu(hPopupMenu
))) menu
->wFlags
|= MF_SYSMENU
;
498 TRACE("hMenu=%p (hPopup %p)\n", hMenu
, hPopupMenu
);
501 DestroyMenu( hMenu
);
503 ERR("failed to load system menu!\n");
508 /***********************************************************************
509 * MENU_InitSysMenuPopup
511 * Grey the appropriate items in System menu.
513 static void MENU_InitSysMenuPopup( HMENU hmenu
, DWORD style
, DWORD clsStyle
)
517 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
518 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
519 gray
= ((style
& WS_MAXIMIZE
) != 0);
520 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
521 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
522 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
523 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
524 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
525 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
526 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
527 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
529 /* The menu item must keep its state if it's disabled */
531 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
535 /******************************************************************************
537 * UINT MENU_GetStartOfNextColumn(
540 *****************************************************************************/
542 static UINT
MENU_GetStartOfNextColumn(
545 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
549 return NO_SELECTED_ITEM
;
551 i
= menu
->FocusedItem
+ 1;
552 if( i
== NO_SELECTED_ITEM
)
555 for( ; i
< menu
->nItems
; ++i
) {
556 if (menu
->items
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
560 return NO_SELECTED_ITEM
;
564 /******************************************************************************
566 * UINT MENU_GetStartOfPrevColumn(
569 *****************************************************************************/
571 static UINT
MENU_GetStartOfPrevColumn(
574 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
578 return NO_SELECTED_ITEM
;
580 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
581 return NO_SELECTED_ITEM
;
583 /* Find the start of the column */
585 for(i
= menu
->FocusedItem
; i
!= 0 &&
586 !(menu
->items
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
590 return NO_SELECTED_ITEM
;
592 for(--i
; i
!= 0; --i
) {
593 if (menu
->items
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
597 TRACE("ret %d.\n", i
);
604 /***********************************************************************
607 * Find a menu item. Return a pointer on the item, and modifies *hmenu
608 * in case the item was in a sub-menu.
610 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
613 MENUITEM
*fallback
= NULL
;
614 UINT fallback_pos
= 0;
617 if ((*hmenu
== (HMENU
)0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
618 if (wFlags
& MF_BYPOSITION
)
620 if (*nPos
>= menu
->nItems
) return NULL
;
621 return &menu
->items
[*nPos
];
625 MENUITEM
*item
= menu
->items
;
626 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
628 if (item
->fType
& MF_POPUP
)
630 HMENU hsubmenu
= item
->hSubMenu
;
631 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
637 else if (item
->wID
== *nPos
)
639 /* fallback to this item if nothing else found */
644 else if (item
->wID
== *nPos
)
653 *nPos
= fallback_pos
;
658 /***********************************************************************
661 * Find a Sub menu. Return the position of the submenu, and modifies
662 * *hmenu in case it is found in another sub-menu.
663 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
665 static UINT
MENU_FindSubMenu( HMENU
*hmenu
, HMENU hSubTarget
)
670 if (((*hmenu
)==(HMENU
)0xffff) ||
671 (!(menu
= MENU_GetMenu(*hmenu
))))
672 return NO_SELECTED_ITEM
;
674 for (i
= 0; i
< menu
->nItems
; i
++, item
++) {
675 if(!(item
->fType
& MF_POPUP
)) continue;
676 if (item
->hSubMenu
== hSubTarget
) {
680 HMENU hsubmenu
= item
->hSubMenu
;
681 UINT pos
= MENU_FindSubMenu( &hsubmenu
, hSubTarget
);
682 if (pos
!= NO_SELECTED_ITEM
) {
688 return NO_SELECTED_ITEM
;
691 /***********************************************************************
694 static void MENU_FreeItemData( MENUITEM
* item
)
697 HeapFree( GetProcessHeap(), 0, item
->text
);
700 /***********************************************************************
701 * MENU_AdjustMenuItemRect
703 * Adjust menu item rectangle according to scrolling state.
706 MENU_AdjustMenuItemRect(const POPUPMENU
*menu
, LPRECT rect
)
708 if (menu
->bScrolling
)
710 UINT arrow_bitmap_height
;
713 GetObjectW(get_up_arrow_bitmap(), sizeof(bmp
), &bmp
);
714 arrow_bitmap_height
= bmp
.bmHeight
;
715 rect
->top
+= arrow_bitmap_height
- menu
->nScrollPos
;
716 rect
->bottom
+= arrow_bitmap_height
- menu
->nScrollPos
;
721 /***********************************************************************
722 * MENU_FindItemByCoords
724 * Find the item at the specified coordinates (screen coords). Does
725 * not work for child windows and therefore should not be called for
726 * an arbitrary system menu.
728 static MENUITEM
*MENU_FindItemByCoords( const POPUPMENU
*menu
,
729 POINT pt
, UINT
*pos
)
735 if (!GetWindowRect(menu
->hWnd
, &rect
)) return NULL
;
736 if (GetWindowLongW( menu
->hWnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
) pt
.x
= rect
.right
- 1 - pt
.x
;
737 else pt
.x
-= rect
.left
;
740 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
743 MENU_AdjustMenuItemRect(menu
, &rect
);
744 if (PtInRect(&rect
, pt
))
754 /***********************************************************************
757 * Find the menu item selected by a key press.
758 * Return item id, -1 if none, -2 if we should close the menu.
760 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
,
761 WCHAR key
, BOOL forceMenuChar
)
763 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)key
, key
, hmenu
);
765 if (!IsMenu( hmenu
)) hmenu
= GetSubMenu( get_win_sys_menu(hwndOwner
), 0);
769 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
770 MENUITEM
*item
= menu
->items
;
777 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
781 WCHAR
*p
= item
->text
- 2;
784 p
= strchrW (p
+ 2, '&');
786 while (p
!= NULL
&& p
[1] == '&');
787 if (p
&& (toupperW(p
[1]) == toupperW(key
))) return i
;
791 menuchar
= SendMessageW( hwndOwner
, WM_MENUCHAR
,
792 MAKEWPARAM( key
, menu
->wFlags
), (LPARAM
)hmenu
);
793 if (HIWORD(menuchar
) == MNC_EXECUTE
) return LOWORD(menuchar
);
794 if (HIWORD(menuchar
) == MNC_CLOSE
) return (UINT
)(-2);
800 /***********************************************************************
801 * MENU_GetBitmapItemSize
803 * Get the size of a bitmap item.
805 static void MENU_GetBitmapItemSize( MENUITEM
*lpitem
, SIZE
*size
,
809 HBITMAP bmp
= lpitem
->hbmpItem
;
811 size
->cx
= size
->cy
= 0;
813 /* check if there is a magic menu item associated with this item */
814 switch( (INT_PTR
) bmp
)
816 case (INT_PTR
)HBMMENU_CALLBACK
:
818 MEASUREITEMSTRUCT measItem
;
819 measItem
.CtlType
= ODT_MENU
;
821 measItem
.itemID
= lpitem
->wID
;
822 measItem
.itemWidth
= lpitem
->rect
.right
- lpitem
->rect
.left
;
823 measItem
.itemHeight
= lpitem
->rect
.bottom
- lpitem
->rect
.top
;
824 measItem
.itemData
= lpitem
->dwItemData
;
825 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&measItem
);
826 size
->cx
= measItem
.itemWidth
;
827 size
->cy
= measItem
.itemHeight
;
831 case (INT_PTR
)HBMMENU_SYSTEM
:
832 if (lpitem
->dwItemData
)
834 bmp
= (HBITMAP
)lpitem
->dwItemData
;
838 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
839 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
840 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
841 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
842 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
843 size
->cx
= GetSystemMetrics( SM_CYMENU
) - 4;
846 case (INT_PTR
)HBMMENU_POPUP_CLOSE
:
847 case (INT_PTR
)HBMMENU_POPUP_RESTORE
:
848 case (INT_PTR
)HBMMENU_POPUP_MAXIMIZE
:
849 case (INT_PTR
)HBMMENU_POPUP_MINIMIZE
:
850 size
->cx
= GetSystemMetrics( SM_CXMENUSIZE
);
851 size
->cy
= GetSystemMetrics( SM_CYMENUSIZE
);
854 if (GetObjectW(bmp
, sizeof(bm
), &bm
))
856 size
->cx
= bm
.bmWidth
;
857 size
->cy
= bm
.bmHeight
;
861 /***********************************************************************
862 * MENU_DrawBitmapItem
864 * Draw a bitmap item.
866 static void MENU_DrawBitmapItem( HDC hdc
, MENUITEM
*lpitem
, const RECT
*rect
,
867 HMENU hmenu
, HWND hwndOwner
, UINT odaction
, BOOL menuBar
)
873 int w
= rect
->right
- rect
->left
;
874 int h
= rect
->bottom
- rect
->top
;
877 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
880 /* Check if there is a magic menu item associated with this item */
881 if (IS_MAGIC_BITMAP(hbmToDraw
))
887 switch((INT_PTR
)hbmToDraw
)
889 case (INT_PTR
)HBMMENU_SYSTEM
:
890 if (lpitem
->dwItemData
)
892 bmp
= (HBITMAP
)lpitem
->dwItemData
;
893 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
897 static HBITMAP hBmpSysMenu
;
899 if (!hBmpSysMenu
) hBmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
901 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
902 /* only use right half of the bitmap */
903 bmp_xoffset
= bm
.bmWidth
/ 2;
904 bm
.bmWidth
-= bmp_xoffset
;
907 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
908 flags
= DFCS_CAPTIONRESTORE
;
910 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
911 flags
= DFCS_CAPTIONMIN
;
913 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
914 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
916 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
917 flags
= DFCS_CAPTIONCLOSE
;
919 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
920 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
922 case (INT_PTR
)HBMMENU_CALLBACK
:
924 DRAWITEMSTRUCT drawItem
;
925 drawItem
.CtlType
= ODT_MENU
;
927 drawItem
.itemID
= lpitem
->wID
;
928 drawItem
.itemAction
= odaction
;
929 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
930 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
931 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
932 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
933 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
934 drawItem
.hwndItem
= (HWND
)hmenu
;
936 drawItem
.itemData
= lpitem
->dwItemData
;
937 drawItem
.rcItem
= *rect
;
938 SendMessageW( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
942 case (INT_PTR
)HBMMENU_POPUP_CLOSE
:
945 case (INT_PTR
)HBMMENU_POPUP_RESTORE
:
948 case (INT_PTR
)HBMMENU_POPUP_MAXIMIZE
:
951 case (INT_PTR
)HBMMENU_POPUP_MINIMIZE
:
955 FIXME("Magic %p not implemented\n", hbmToDraw
);
960 /* draw the magic bitmaps using marlett font characters */
961 /* FIXME: fontsize and the position (x,y) could probably be better */
962 HFONT hfont
, hfontsav
;
963 LOGFONTW logfont
= { 0, 0, 0, 0, FW_NORMAL
,
964 0, 0, 0, SYMBOL_CHARSET
, 0, 0, 0, 0,
965 { 'M','a','r','l','e','t','t',0 } };
966 logfont
.lfHeight
= min( h
, w
) - 5 ;
967 TRACE(" height %d rect %s\n", logfont
.lfHeight
, wine_dbgstr_rect( rect
));
968 hfont
= CreateFontIndirectW( &logfont
);
969 hfontsav
= SelectObject(hdc
, hfont
);
970 TextOutW( hdc
, rect
->left
, rect
->top
+ 2, &bmchr
, 1);
971 SelectObject(hdc
, hfontsav
);
972 DeleteObject( hfont
);
977 InflateRect( &r
, -1, -1 );
978 if (lpitem
->fState
& MF_HILITE
) flags
|= DFCS_PUSHED
;
979 DrawFrameControl( hdc
, &r
, DFC_CAPTION
, flags
);
984 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
987 hdcMem
= CreateCompatibleDC( hdc
);
988 SelectObject( hdcMem
, bmp
);
990 /* handle fontsize > bitmap_height */
991 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
993 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
994 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
995 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
996 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
1001 /***********************************************************************
1004 * Calculate the size of the menu item and store it in lpitem->rect.
1006 static void MENU_CalcItemSize( HDC hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
1007 INT orgX
, INT orgY
, BOOL menuBar
, POPUPMENU
* lppop
)
1010 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1011 UINT arrow_bitmap_width
;
1015 TRACE("dc=%p owner=%p (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
1016 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem
,
1017 (menuBar
? " (MenuBar)" : ""));
1019 GetObjectW( get_arrow_bitmap(), sizeof(bm
), &bm
);
1020 arrow_bitmap_width
= bm
.bmWidth
;
1022 /* not done in Menu_Init: GetDialogBaseUnits() breaks there */
1023 if( !menucharsize
.cx
) {
1024 menucharsize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &menucharsize
.cy
);
1025 /* Win95/98/ME will use menucharsize.cy here. Testing is possible
1026 * but it is unlikely an application will depend on that */
1027 ODitemheight
= HIWORD( GetDialogBaseUnits());
1030 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
1032 if (lpitem
->fType
& MF_OWNERDRAW
)
1034 MEASUREITEMSTRUCT mis
;
1035 mis
.CtlType
= ODT_MENU
;
1037 mis
.itemID
= lpitem
->wID
;
1038 mis
.itemData
= lpitem
->dwItemData
;
1039 mis
.itemHeight
= ODitemheight
;
1041 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1042 /* Tests reveal that Windows ( Win95 through WinXP) adds twice the average
1043 * width of a menufont character to the width of an owner-drawn menu.
1045 lpitem
->rect
.right
+= mis
.itemWidth
+ 2 * menucharsize
.cx
;
1047 /* under at least win95 you seem to be given a standard
1048 height for the menu and the height value is ignored */
1049 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
1051 lpitem
->rect
.bottom
+= mis
.itemHeight
;
1053 TRACE("id=%04lx size=%dx%d\n",
1054 lpitem
->wID
, lpitem
->rect
.right
-lpitem
->rect
.left
,
1055 lpitem
->rect
.bottom
-lpitem
->rect
.top
);
1059 if (lpitem
->fType
& MF_SEPARATOR
)
1061 lpitem
->rect
.bottom
+= GetSystemMetrics( SM_CYMENUSIZE
)/2;
1063 lpitem
->rect
.right
+= arrow_bitmap_width
+ menucharsize
.cx
;
1071 if (lpitem
->hbmpItem
) {
1074 MENU_GetBitmapItemSize(lpitem
, &size
, hwndOwner
);
1075 /* Keep the size of the bitmap in callback mode to be able
1076 * to draw it correctly */
1077 lpitem
->bmpsize
= size
;
1078 lppop
->textOffset
= max( lppop
->textOffset
, size
.cx
);
1079 lpitem
->rect
.right
+= size
.cx
+ 2;
1080 itemheight
= size
.cy
+ 2;
1082 if( !(lppop
->dwStyle
& MNS_NOCHECK
))
1083 lpitem
->rect
.right
+= check_bitmap_width
;
1084 lpitem
->rect
.right
+= 4 + menucharsize
.cx
;
1085 lpitem
->xTab
= lpitem
->rect
.right
;
1086 lpitem
->rect
.right
+= arrow_bitmap_width
;
1087 } else if (lpitem
->hbmpItem
) { /* menuBar */
1090 MENU_GetBitmapItemSize( lpitem
, &size
, hwndOwner
);
1091 lpitem
->bmpsize
= size
;
1092 lpitem
->rect
.right
+= size
.cx
;
1093 if( lpitem
->text
) lpitem
->rect
.right
+= 2;
1094 itemheight
= size
.cy
;
1097 /* it must be a text item - unless it's the system menu */
1098 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->text
) {
1099 HFONT hfontOld
= NULL
;
1100 RECT rc
= lpitem
->rect
;
1101 LONG txtheight
, txtwidth
;
1103 if ( lpitem
->fState
& MFS_DEFAULT
) {
1104 hfontOld
= SelectObject( hdc
, get_menu_font(TRUE
) );
1107 txtheight
= DrawTextW( hdc
, lpitem
->text
, -1, &rc
,
1108 DT_SINGLELINE
|DT_CALCRECT
);
1109 lpitem
->rect
.right
+= rc
.right
- rc
.left
;
1110 itemheight
= max( max( itemheight
, txtheight
),
1111 GetSystemMetrics( SM_CYMENU
) - 1);
1112 lpitem
->rect
.right
+= 2 * menucharsize
.cx
;
1114 if ((p
= strchrW( lpitem
->text
, '\t' )) != NULL
) {
1117 int n
= (int)( p
- lpitem
->text
);
1118 /* Item contains a tab (only meaningful in popup menus) */
1119 /* get text size before the tab */
1120 txtheight
= DrawTextW( hdc
, lpitem
->text
, n
, &rc
,
1121 DT_SINGLELINE
|DT_CALCRECT
);
1122 txtwidth
= rc
.right
- rc
.left
;
1123 p
+= 1; /* advance past the Tab */
1124 /* get text size after the tab */
1125 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1126 DT_SINGLELINE
|DT_CALCRECT
);
1127 lpitem
->xTab
+= txtwidth
;
1128 txtheight
= max( txtheight
, tmpheight
);
1129 txtwidth
+= menucharsize
.cx
+ /* space for the tab */
1130 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1132 txtheight
= DrawTextW( hdc
, lpitem
->text
, -1, &rc
,
1133 DT_SINGLELINE
|DT_CALCRECT
);
1134 txtwidth
= rc
.right
- rc
.left
;
1135 lpitem
->xTab
+= txtwidth
;
1137 lpitem
->rect
.right
+= 2 + txtwidth
;
1138 itemheight
= max( itemheight
,
1139 max( txtheight
+ 2, menucharsize
.cy
+ 4));
1141 if (hfontOld
) SelectObject (hdc
, hfontOld
);
1142 } else if( menuBar
) {
1143 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
1145 lpitem
->rect
.bottom
+= itemheight
;
1146 TRACE("%s\n", wine_dbgstr_rect( &lpitem
->rect
));
1150 /***********************************************************************
1151 * MENU_GetMaxPopupHeight
1154 MENU_GetMaxPopupHeight(const POPUPMENU
*lppop
)
1157 return lppop
->cyMax
;
1158 return GetSystemMetrics(SM_CYSCREEN
) - GetSystemMetrics(SM_CYBORDER
);
1162 /***********************************************************************
1163 * MENU_PopupMenuCalcSize
1165 * Calculate the size of a popup menu.
1167 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
)
1172 int textandbmp
= FALSE
;
1173 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
1175 lppop
->Width
= lppop
->Height
= 0;
1176 if (lppop
->nItems
== 0) return;
1179 SelectObject( hdc
, get_menu_font(FALSE
));
1184 lppop
->textOffset
= 0;
1186 while (start
< lppop
->nItems
)
1188 lpitem
= &lppop
->items
[start
];
1190 if( lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
1191 orgX
+= MENU_COL_SPACE
;
1192 orgY
= MENU_TOP_MARGIN
;
1194 maxTab
= maxTabWidth
= 0;
1195 /* Parse items until column break or end of menu */
1196 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
1199 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1201 MENU_CalcItemSize( hdc
, lpitem
, lppop
->hwndOwner
, orgX
, orgY
, FALSE
, lppop
);
1202 maxX
= max( maxX
, lpitem
->rect
.right
);
1203 orgY
= lpitem
->rect
.bottom
;
1204 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
1206 maxTab
= max( maxTab
, lpitem
->xTab
);
1207 maxTabWidth
= max(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
1209 if( lpitem
->text
&& lpitem
->hbmpItem
) textandbmp
= TRUE
;
1212 /* Finish the column (set all items to the largest width found) */
1213 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
1214 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
1216 lpitem
->rect
.right
= maxX
;
1217 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
1218 lpitem
->xTab
= maxTab
;
1221 lppop
->Height
= max( lppop
->Height
, orgY
);
1224 lppop
->Width
= maxX
;
1225 /* if none of the items have both text and bitmap then
1226 * the text and bitmaps are all aligned on the left. If there is at
1227 * least one item with both text and bitmap then bitmaps are
1228 * on the left and texts left aligned with the right hand side
1230 if( !textandbmp
) lppop
->textOffset
= 0;
1232 /* space for 3d border */
1233 lppop
->Height
+= MENU_BOTTOM_MARGIN
;
1236 /* Adjust popup height if it exceeds maximum */
1237 maxHeight
= MENU_GetMaxPopupHeight(lppop
);
1238 lppop
->nTotalHeight
= lppop
->Height
- MENU_TOP_MARGIN
;
1239 if (lppop
->Height
>= maxHeight
)
1241 lppop
->Height
= maxHeight
;
1242 lppop
->bScrolling
= TRUE
;
1246 lppop
->bScrolling
= FALSE
;
1249 ReleaseDC( 0, hdc
);
1253 /***********************************************************************
1254 * MENU_MenuBarCalcSize
1256 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1257 * height is off by 1 pixel which causes lengthy window relocations when
1258 * active document window is maximized/restored.
1260 * Calculate the size of the menu bar.
1262 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1263 LPPOPUPMENU lppop
, HWND hwndOwner
)
1266 UINT start
, i
, helpPos
;
1267 int orgX
, orgY
, maxY
;
1269 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
1270 if (lppop
->nItems
== 0) return;
1271 TRACE("lprect %p %s\n", lprect
, wine_dbgstr_rect( lprect
));
1272 lppop
->Width
= lprect
->right
- lprect
->left
;
1274 maxY
= lprect
->top
+1;
1277 lppop
->textOffset
= 0;
1278 while (start
< lppop
->nItems
)
1280 lpitem
= &lppop
->items
[start
];
1281 orgX
= lprect
->left
;
1284 /* Parse items until line break or end of menu */
1285 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
1287 if ((helpPos
== ~0U) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1289 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1291 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1292 debug_print_menuitem (" item: ", lpitem
, "");
1293 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
, lppop
);
1295 if (lpitem
->rect
.right
> lprect
->right
)
1297 if (i
!= start
) break;
1298 else lpitem
->rect
.right
= lprect
->right
;
1300 maxY
= max( maxY
, lpitem
->rect
.bottom
);
1301 orgX
= lpitem
->rect
.right
;
1304 /* Finish the line (set all items to the largest height found) */
1305 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
1308 lprect
->bottom
= maxY
;
1309 lppop
->Height
= lprect
->bottom
- lprect
->top
;
1311 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1312 /* the last item (if several lines, only move the last line) */
1313 if (helpPos
== ~0U) return;
1314 lpitem
= &lppop
->items
[lppop
->nItems
-1];
1315 orgY
= lpitem
->rect
.top
;
1316 orgX
= lprect
->right
;
1317 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
1318 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
1319 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
1320 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
1321 lpitem
->rect
.right
= orgX
;
1322 orgX
= lpitem
->rect
.left
;
1327 /***********************************************************************
1328 * MENU_DrawScrollArrows
1330 * Draw scroll arrows.
1333 MENU_DrawScrollArrows(const POPUPMENU
*lppop
, HDC hdc
)
1335 HDC hdcMem
= CreateCompatibleDC(hdc
);
1336 HBITMAP hOrigBitmap
;
1337 UINT arrow_bitmap_width
, arrow_bitmap_height
;
1341 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp
), &bmp
);
1342 arrow_bitmap_width
= bmp
.bmWidth
;
1343 arrow_bitmap_height
= bmp
.bmHeight
;
1346 if (lppop
->nScrollPos
)
1347 hOrigBitmap
= SelectObject(hdcMem
, get_up_arrow_bitmap());
1349 hOrigBitmap
= SelectObject(hdcMem
, get_up_arrow_inactive_bitmap());
1352 rect
.right
= lppop
->Width
;
1353 rect
.bottom
= arrow_bitmap_height
;
1354 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENU
));
1355 BitBlt(hdc
, (lppop
->Width
- arrow_bitmap_width
) / 2, 0,
1356 arrow_bitmap_width
, arrow_bitmap_height
, hdcMem
, 0, 0, SRCCOPY
);
1357 rect
.top
= lppop
->Height
- arrow_bitmap_height
;
1358 rect
.bottom
= lppop
->Height
;
1359 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENU
));
1360 if (lppop
->nScrollPos
< lppop
->nTotalHeight
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
))
1361 SelectObject(hdcMem
, get_down_arrow_bitmap());
1363 SelectObject(hdcMem
, get_down_arrow_inactive_bitmap());
1364 BitBlt(hdc
, (lppop
->Width
- arrow_bitmap_width
) / 2,
1365 lppop
->Height
- arrow_bitmap_height
,
1366 arrow_bitmap_width
, arrow_bitmap_height
, hdcMem
, 0, 0, SRCCOPY
);
1367 SelectObject(hdcMem
, hOrigBitmap
);
1372 /***********************************************************************
1375 * Draws the popup-menu arrow.
1377 static void draw_popup_arrow( HDC hdc
, RECT rect
, UINT arrow_bitmap_width
,
1378 UINT arrow_bitmap_height
)
1380 HDC hdcMem
= CreateCompatibleDC( hdc
);
1381 HBITMAP hOrigBitmap
;
1383 hOrigBitmap
= SelectObject( hdcMem
, get_arrow_bitmap() );
1384 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1385 (rect
.top
+ rect
.bottom
- arrow_bitmap_height
) / 2,
1386 arrow_bitmap_width
, arrow_bitmap_height
,
1387 hdcMem
, 0, 0, SRCCOPY
);
1388 SelectObject( hdcMem
, hOrigBitmap
);
1391 /***********************************************************************
1394 * Draw a single menu item.
1396 static void MENU_DrawMenuItem( HWND hwnd
, HMENU hmenu
, HWND hwndOwner
, HDC hdc
, MENUITEM
*lpitem
,
1397 UINT height
, BOOL menuBar
, UINT odaction
)
1400 BOOL flat_menu
= FALSE
;
1402 UINT arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
1403 POPUPMENU
*menu
= MENU_GetMenu(hmenu
);
1406 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
1410 GetObjectW( get_arrow_bitmap(), sizeof(bmp
), &bmp
);
1411 arrow_bitmap_width
= bmp
.bmWidth
;
1412 arrow_bitmap_height
= bmp
.bmHeight
;
1415 if (lpitem
->fType
& MF_SYSMENU
)
1417 if( !IsIconic(hwnd
) )
1418 NC_DrawSysButton( hwnd
, hdc
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
) );
1422 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1423 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1427 if (lpitem
->fState
& MF_HILITE
)
1429 if(menuBar
&& !flat_menu
) {
1430 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1431 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1433 if(lpitem
->fState
& MF_GRAYED
)
1434 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1436 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1437 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1442 if (lpitem
->fState
& MF_GRAYED
)
1443 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1445 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1446 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1449 TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem
->rect
));
1450 rect
= lpitem
->rect
;
1451 MENU_AdjustMenuItemRect(MENU_GetMenu(hmenu
), &rect
);
1453 if (lpitem
->fType
& MF_OWNERDRAW
)
1456 ** Experimentation under Windows reveals that an owner-drawn
1457 ** menu is given the rectangle which includes the space it requested
1458 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1459 ** and a popup-menu arrow. This is the value of lpitem->rect.
1460 ** Windows will leave all drawing to the application except for
1461 ** the popup-menu arrow. Windows always draws that itself, after
1462 ** the menu owner has finished drawing.
1466 dis
.CtlType
= ODT_MENU
;
1468 dis
.itemID
= lpitem
->wID
;
1469 dis
.itemData
= lpitem
->dwItemData
;
1471 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1472 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
|ODS_DISABLED
;
1473 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1474 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1475 dis
.hwndItem
= (HWND
)hmenu
;
1478 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1479 "hwndItem=%p, hdc=%p, rcItem=%s\n", hwndOwner
,
1480 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1481 dis
.hDC
, wine_dbgstr_rect( &dis
.rcItem
));
1482 SendMessageW( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
1483 /* Draw the popup-menu arrow */
1484 if (lpitem
->fType
& MF_POPUP
)
1485 draw_popup_arrow( hdc
, rect
, arrow_bitmap_width
,
1486 arrow_bitmap_height
);
1490 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1492 if (lpitem
->fState
& MF_HILITE
)
1496 InflateRect (&rect
, -1, -1);
1497 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1498 InflateRect (&rect
, 1, 1);
1499 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1504 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1506 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1510 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1512 SetBkMode( hdc
, TRANSPARENT
);
1514 /* vertical separator */
1515 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1520 rc
.left
-= MENU_COL_SPACE
/ 2 + 1;
1522 rc
.bottom
= height
- 3;
1525 oldPen
= SelectObject( hdc
, SYSCOLOR_GetPen(COLOR_BTNSHADOW
) );
1526 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1527 LineTo( hdc
, rc
.left
, rc
.bottom
);
1528 SelectObject( hdc
, oldPen
);
1531 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1534 /* horizontal separator */
1535 if (lpitem
->fType
& MF_SEPARATOR
)
1542 rc
.top
= ( rc
.top
+ rc
.bottom
) / 2;
1545 oldPen
= SelectObject( hdc
, SYSCOLOR_GetPen(COLOR_BTNSHADOW
) );
1546 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1547 LineTo( hdc
, rc
.right
, rc
.top
);
1548 SelectObject( hdc
, oldPen
);
1551 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1555 /* helper lines for debugging */
1556 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1557 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1558 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1559 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1562 if (lpitem
->hbmpItem
) {
1563 /* calculate the bitmap rectangle in coordinates relative
1564 * to the item rectangle */
1566 if( lpitem
->hbmpItem
== HBMMENU_CALLBACK
)
1569 bmprc
.left
= lpitem
->text
? menucharsize
.cx
: 0;
1571 else if (menu
->dwStyle
& MNS_NOCHECK
)
1573 else if (menu
->dwStyle
& MNS_CHECKORBMP
)
1576 bmprc
.left
= 4 + GetSystemMetrics(SM_CXMENUCHECK
);
1577 bmprc
.right
= bmprc
.left
+ lpitem
->bmpsize
.cx
;
1578 if( menuBar
&& !(lpitem
->hbmpItem
== HBMMENU_CALLBACK
))
1581 bmprc
.top
= (rect
.bottom
- rect
.top
-
1582 lpitem
->bmpsize
.cy
) / 2;
1583 bmprc
.bottom
= bmprc
.top
+ lpitem
->bmpsize
.cy
;
1589 INT y
= rect
.top
+ rect
.bottom
;
1591 int checked
= FALSE
;
1592 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1593 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1594 /* Draw the check mark
1597 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1599 if( !(menu
->dwStyle
& MNS_NOCHECK
)) {
1600 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hCheckBit
:
1601 lpitem
->hUnCheckBit
;
1602 if (bm
) /* we have a custom bitmap */
1604 HDC hdcMem
= CreateCompatibleDC( hdc
);
1606 SelectObject( hdcMem
, bm
);
1607 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1608 check_bitmap_width
, check_bitmap_height
,
1609 hdcMem
, 0, 0, SRCCOPY
);
1613 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1616 HBITMAP bm
= CreateBitmap( check_bitmap_width
,
1617 check_bitmap_height
, 1, 1, NULL
);
1618 HDC hdcMem
= CreateCompatibleDC( hdc
);
1620 SelectObject( hdcMem
, bm
);
1621 SetRect( &r
, 0, 0, check_bitmap_width
, check_bitmap_height
);
1622 DrawFrameControl( hdcMem
, &r
, DFC_MENU
,
1623 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1624 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1625 BitBlt( hdc
, rc
.left
, (y
- r
.bottom
) / 2, r
.right
, r
.bottom
,
1626 hdcMem
, 0, 0, SRCCOPY
);
1632 if( lpitem
->hbmpItem
&&
1633 !( checked
&& (menu
->dwStyle
& MNS_CHECKORBMP
))) {
1635 /* some applications make this assumption on the DC's origin */
1636 SetViewportOrgEx( hdc
, rect
.left
, rect
.top
, &origorg
);
1637 MENU_DrawBitmapItem(hdc
, lpitem
, &bmprc
, hmenu
, hwndOwner
,
1639 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1641 /* Draw the popup-menu arrow */
1642 if (lpitem
->fType
& MF_POPUP
)
1643 draw_popup_arrow( hdc
, rect
, arrow_bitmap_width
,
1644 arrow_bitmap_height
);
1646 if( !(menu
->dwStyle
& MNS_NOCHECK
))
1647 rect
.left
+= check_bitmap_width
;
1648 rect
.right
-= arrow_bitmap_width
;
1650 else if( lpitem
->hbmpItem
)
1651 { /* Draw the bitmap */
1654 SetViewportOrgEx( hdc
, rect
.left
, rect
.top
, &origorg
);
1655 MENU_DrawBitmapItem( hdc
, lpitem
, &bmprc
, hmenu
, hwndOwner
,
1657 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1659 /* process text if present */
1665 UINT uFormat
= (menuBar
) ?
1666 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1667 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1669 if( !(menu
->dwStyle
& MNS_CHECKORBMP
))
1670 rect
.left
+= menu
->textOffset
;
1672 if ( lpitem
->fState
& MFS_DEFAULT
)
1674 hfontOld
= SelectObject( hdc
, get_menu_font(TRUE
) );
1678 if( lpitem
->hbmpItem
)
1679 rect
.left
+= lpitem
->bmpsize
.cx
;
1680 if( !(lpitem
->hbmpItem
== HBMMENU_CALLBACK
))
1681 rect
.left
+= menucharsize
.cx
;
1682 rect
.right
-= menucharsize
.cx
;
1685 for (i
= 0; lpitem
->text
[i
]; i
++)
1686 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1689 if(lpitem
->fState
& MF_GRAYED
)
1691 if (!(lpitem
->fState
& MF_HILITE
) )
1693 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1694 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1695 DrawTextW( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1696 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1698 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1701 DrawTextW( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1703 /* paint the shortcut text */
1704 if (!menuBar
&& lpitem
->text
[i
]) /* There's a tab or flush-right char */
1706 if (lpitem
->text
[i
] == '\t')
1708 rect
.left
= lpitem
->xTab
;
1709 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1713 rect
.right
= lpitem
->xTab
;
1714 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1717 if(lpitem
->fState
& MF_GRAYED
)
1719 if (!(lpitem
->fState
& MF_HILITE
) )
1721 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1722 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1723 DrawTextW( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1724 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1726 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1728 DrawTextW( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1732 SelectObject (hdc
, hfontOld
);
1737 /***********************************************************************
1738 * MENU_DrawPopupMenu
1740 * Paint a popup menu.
1742 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
1744 HBRUSH hPrevBrush
= 0;
1747 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1749 GetClientRect( hwnd
, &rect
);
1751 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1752 && (SelectObject( hdc
, get_menu_font(FALSE
))))
1756 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1758 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1762 BOOL flat_menu
= FALSE
;
1764 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1766 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1768 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1770 if( (menu
= MENU_GetMenu( hmenu
)))
1772 TRACE("hmenu %p Style %08x\n", hmenu
, menu
->dwStyle
);
1773 /* draw menu items */
1780 for( u
= menu
->nItems
; u
> 0; u
--, item
++)
1781 MENU_DrawMenuItem( hwnd
, hmenu
, menu
->hwndOwner
, hdc
,
1782 item
, menu
->Height
, FALSE
, ODA_DRAWENTIRE
);
1784 /* draw scroll arrows */
1785 if (menu
->bScrolling
)
1786 MENU_DrawScrollArrows(menu
, hdc
);
1790 SelectObject( hdc
, hPrevBrush
);
1795 /***********************************************************************
1798 * Paint a menu bar. Returns the height of the menu bar.
1799 * called from [windows/nonclient.c]
1801 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1806 HMENU hMenu
= GetMenu(hwnd
);
1808 lppop
= MENU_GetMenu( hMenu
);
1809 if (lppop
== NULL
|| lprect
== NULL
)
1811 return GetSystemMetrics(SM_CYMENU
);
1816 hfontOld
= SelectObject( hDC
, get_menu_font(FALSE
));
1818 if (lppop
->Height
== 0)
1819 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1821 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1823 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1824 return lppop
->Height
;
1827 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1831 /***********************************************************************
1834 * Display a popup menu.
1836 static BOOL
MENU_ShowPopup( HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
1837 INT x
, INT y
, INT xanchor
, INT yanchor
)
1846 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1847 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1849 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
1850 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1852 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1853 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1856 /* store the owner for DrawItem */
1857 if (!IsWindow( hwndOwner
))
1859 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
1862 menu
->hwndOwner
= hwndOwner
;
1864 menu
->nScrollPos
= 0;
1865 MENU_PopupMenuCalcSize( menu
);
1867 /* adjust popup menu pos so that it fits within the desktop */
1869 width
= menu
->Width
+ GetSystemMetrics(SM_CXBORDER
);
1870 height
= menu
->Height
+ GetSystemMetrics(SM_CYBORDER
);
1872 /* FIXME: should use item rect */
1875 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
1876 info
.cbSize
= sizeof(info
);
1877 GetMonitorInfoW( monitor
, &info
);
1879 if (flags
& TPM_LAYOUTRTL
)
1881 ex_style
= WS_EX_LAYOUTRTL
;
1882 flags
^= TPM_RIGHTALIGN
;
1885 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
1886 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
1888 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
1889 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
1891 if( x
+ width
> info
.rcWork
.right
)
1893 if( xanchor
&& x
>= width
- xanchor
)
1894 x
-= width
- xanchor
;
1896 if( x
+ width
> info
.rcWork
.right
)
1897 x
= info
.rcWork
.right
- width
;
1899 if( x
< info
.rcWork
.left
) x
= info
.rcWork
.left
;
1901 if( y
+ height
> info
.rcWork
.bottom
)
1903 if( yanchor
&& y
>= height
+ yanchor
)
1904 y
-= height
+ yanchor
;
1906 if( y
+ height
> info
.rcWork
.bottom
)
1907 y
= info
.rcWork
.bottom
- height
;
1909 if( y
< info
.rcWork
.top
) y
= info
.rcWork
.top
;
1911 /* NOTE: In Windows, top menu popup is not owned. */
1912 menu
->hWnd
= CreateWindowExW( ex_style
, (LPCWSTR
)POPUPMENU_CLASS_ATOM
, NULL
,
1913 WS_POPUP
, x
, y
, width
, height
,
1914 hwndOwner
, 0, (HINSTANCE
)GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
1916 if( !menu
->hWnd
) return FALSE
;
1918 top_popup
= menu
->hWnd
;
1919 top_popup_hmenu
= hmenu
;
1921 /* Display the window */
1923 SetWindowPos( menu
->hWnd
, HWND_TOPMOST
, 0, 0, 0, 0,
1924 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1925 UpdateWindow( menu
->hWnd
);
1930 /***********************************************************************
1931 * MENU_EnsureMenuItemVisible
1934 MENU_EnsureMenuItemVisible(LPPOPUPMENU lppop
, UINT wIndex
, HDC hdc
)
1936 if (lppop
->bScrolling
)
1938 MENUITEM
*item
= &lppop
->items
[wIndex
];
1939 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
1940 UINT nOldPos
= lppop
->nScrollPos
;
1942 UINT arrow_bitmap_height
;
1945 GetClientRect(lppop
->hWnd
, &rc
);
1947 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp
), &bmp
);
1948 arrow_bitmap_height
= bmp
.bmHeight
;
1950 rc
.top
+= arrow_bitmap_height
;
1951 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
1953 nMaxHeight
-= GetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
1954 if (item
->rect
.bottom
> lppop
->nScrollPos
+ nMaxHeight
)
1957 lppop
->nScrollPos
= item
->rect
.bottom
- nMaxHeight
;
1958 ScrollWindow(lppop
->hWnd
, 0, nOldPos
- lppop
->nScrollPos
, &rc
, &rc
);
1959 MENU_DrawScrollArrows(lppop
, hdc
);
1961 else if (item
->rect
.top
- MENU_TOP_MARGIN
< lppop
->nScrollPos
)
1963 lppop
->nScrollPos
= item
->rect
.top
- MENU_TOP_MARGIN
;
1964 ScrollWindow(lppop
->hWnd
, 0, nOldPos
- lppop
->nScrollPos
, &rc
, &rc
);
1965 MENU_DrawScrollArrows(lppop
, hdc
);
1971 /***********************************************************************
1974 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
1975 BOOL sendMenuSelect
, HMENU topmenu
)
1980 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1982 lppop
= MENU_GetMenu( hmenu
);
1983 if ((!lppop
) || (!lppop
->nItems
) || (!lppop
->hWnd
)) return;
1985 if (lppop
->FocusedItem
== wIndex
) return;
1986 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
1987 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1989 top_popup
= lppop
->hWnd
;
1990 top_popup_hmenu
= hmenu
;
1993 SelectObject( hdc
, get_menu_font(FALSE
));
1995 /* Clear previous highlighted item */
1996 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1998 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1999 MENU_DrawMenuItem(lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,&lppop
->items
[lppop
->FocusedItem
],
2000 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
2004 /* Highlight new item (if any) */
2005 lppop
->FocusedItem
= wIndex
;
2006 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
2008 if(!(lppop
->items
[wIndex
].fType
& MF_SEPARATOR
)) {
2009 lppop
->items
[wIndex
].fState
|= MF_HILITE
;
2010 MENU_EnsureMenuItemVisible(lppop
, wIndex
, hdc
);
2011 MENU_DrawMenuItem( lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,
2012 &lppop
->items
[wIndex
], lppop
->Height
,
2013 !(lppop
->wFlags
& MF_POPUP
), ODA_SELECT
);
2017 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
2018 SendMessageW( hwndOwner
, WM_MENUSELECT
,
2019 MAKEWPARAM(ip
->fType
& MF_POPUP
? wIndex
: ip
->wID
,
2020 ip
->fType
| ip
->fState
|
2021 (lppop
->wFlags
& MF_SYSMENU
)), (LPARAM
)hmenu
);
2024 else if (sendMenuSelect
) {
2027 if((pos
=MENU_FindSubMenu(&topmenu
, hmenu
))!=NO_SELECTED_ITEM
){
2028 POPUPMENU
*ptm
= MENU_GetMenu( topmenu
);
2029 MENUITEM
*ip
= &ptm
->items
[pos
];
2030 SendMessageW( hwndOwner
, WM_MENUSELECT
, MAKEWPARAM(pos
,
2031 ip
->fType
| ip
->fState
|
2032 (ptm
->wFlags
& MF_SYSMENU
)), (LPARAM
)topmenu
);
2036 ReleaseDC( lppop
->hWnd
, hdc
);
2040 /***********************************************************************
2041 * MENU_MoveSelection
2043 * Moves currently selected item according to the offset parameter.
2044 * If there is no selection then it should select the last item if
2045 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
2047 static void MENU_MoveSelection( HWND hwndOwner
, HMENU hmenu
, INT offset
)
2052 TRACE("hwnd=%p hmenu=%p off=0x%04x\n", hwndOwner
, hmenu
, offset
);
2054 menu
= MENU_GetMenu( hmenu
);
2055 if ((!menu
) || (!menu
->items
)) return;
2057 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
2059 if( menu
->nItems
== 1 ) return; else
2060 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
2062 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
2064 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
2069 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
2070 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
2071 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
2073 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
2079 /**********************************************************************
2082 * Insert (allocate) a new item into a menu.
2084 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
2089 if (!(menu
= MENU_GetMenu(hMenu
)))
2092 /* Find where to insert new item */
2094 if (flags
& MF_BYPOSITION
) {
2095 if (pos
> menu
->nItems
)
2098 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
2101 if (!(menu
= MENU_GetMenu( hMenu
)))
2106 /* Make sure that MDI system buttons stay on the right side.
2107 * Note: XP treats only bitmap handles 1 - 6 as "magic" ones
2108 * regardless of their id.
2110 while (pos
> 0 && (INT_PTR
)menu
->items
[pos
- 1].hbmpItem
>= (INT_PTR
)HBMMENU_SYSTEM
&&
2111 (INT_PTR
)menu
->items
[pos
- 1].hbmpItem
<= (INT_PTR
)HBMMENU_MBAR_CLOSE_D
)
2114 TRACE("inserting at %u flags %x\n", pos
, flags
);
2116 /* Create new items array */
2118 newItems
= HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
2121 WARN("allocation failed\n" );
2124 if (menu
->nItems
> 0)
2126 /* Copy the old array into the new one */
2127 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
2128 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
2129 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
2130 HeapFree( GetProcessHeap(), 0, menu
->items
);
2132 menu
->items
= newItems
;
2134 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
2135 menu
->Height
= 0; /* force size recalculate */
2136 return &newItems
[pos
];
2140 /**********************************************************************
2141 * MENU_ParseResource
2143 * Parse a standard menu resource and add items to the menu.
2144 * Return a pointer to the end of the resource.
2146 * NOTE: flags is equivalent to the mtOption field
2148 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
)
2156 flags
= GET_WORD(res
);
2157 end_flag
= flags
& MF_END
;
2158 /* Remove MF_END because it has the same value as MF_HILITE */
2160 res
+= sizeof(WORD
);
2161 if (!(flags
& MF_POPUP
))
2164 res
+= sizeof(WORD
);
2167 res
+= (strlenW(str
) + 1) * sizeof(WCHAR
);
2168 if (flags
& MF_POPUP
)
2170 HMENU hSubMenu
= CreatePopupMenu();
2171 if (!hSubMenu
) return NULL
;
2172 if (!(res
= MENU_ParseResource( res
, hSubMenu
))) return NULL
;
2173 AppendMenuW( hMenu
, flags
, (UINT_PTR
)hSubMenu
, str
);
2175 else /* Not a popup */
2177 AppendMenuW( hMenu
, flags
, id
, *str
? str
: NULL
);
2179 } while (!end_flag
);
2184 /**********************************************************************
2185 * MENUEX_ParseResource
2187 * Parse an extended menu resource and add items to the menu.
2188 * Return a pointer to the end of the resource.
2190 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
2196 mii
.cbSize
= sizeof(mii
);
2197 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
2198 mii
.fType
= GET_DWORD(res
);
2199 res
+= sizeof(DWORD
);
2200 mii
.fState
= GET_DWORD(res
);
2201 res
+= sizeof(DWORD
);
2202 mii
.wID
= GET_DWORD(res
);
2203 res
+= sizeof(DWORD
);
2204 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
2205 res
+= sizeof(WORD
);
2206 /* Align the text on a word boundary. */
2207 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2208 mii
.dwTypeData
= (LPWSTR
) res
;
2209 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2210 /* Align the following fields on a dword boundary. */
2211 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2213 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2214 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, debugstr_w(mii
.dwTypeData
));
2216 if (resinfo
& 1) { /* Pop-up? */
2217 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2218 res
+= sizeof(DWORD
);
2219 mii
.hSubMenu
= CreatePopupMenu();
2222 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
2223 DestroyMenu(mii
.hSubMenu
);
2226 mii
.fMask
|= MIIM_SUBMENU
;
2227 mii
.fType
|= MF_POPUP
;
2229 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
2231 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
2232 mii
.wID
, mii
.fType
);
2233 mii
.fType
|= MF_SEPARATOR
;
2235 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2236 } while (!(resinfo
& MF_END
));
2241 /***********************************************************************
2244 * Return the handle of the selected sub-popup menu (if any).
2246 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
2251 menu
= MENU_GetMenu( hmenu
);
2253 if ((!menu
) || (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return 0;
2255 item
= &menu
->items
[menu
->FocusedItem
];
2256 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
2257 return item
->hSubMenu
;
2262 /***********************************************************************
2263 * MENU_HideSubPopups
2265 * Hide the sub-popup menus of this menu.
2267 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
2268 BOOL sendMenuSelect
, UINT wFlags
)
2270 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
2272 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner
, hmenu
, sendMenuSelect
);
2274 if (menu
&& top_popup
)
2280 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
2282 item
= &menu
->items
[menu
->FocusedItem
];
2283 if (!(item
->fType
& MF_POPUP
) ||
2284 !(item
->fState
& MF_MOUSESELECT
)) return;
2285 item
->fState
&= ~MF_MOUSESELECT
;
2286 hsubmenu
= item
->hSubMenu
;
2289 if (!(submenu
= MENU_GetMenu( hsubmenu
))) return;
2290 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
, wFlags
);
2291 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
, 0 );
2292 DestroyWindow( submenu
->hWnd
);
2295 if (!(wFlags
& TPM_NONOTIFY
))
2296 SendMessageW( hwndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)hsubmenu
,
2297 MAKELPARAM(0, IS_SYSTEM_MENU(submenu
)) );
2302 /***********************************************************************
2305 * Display the sub-menu of the selected item of this menu.
2306 * Return the handle of the submenu, or hmenu if no submenu to display.
2308 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
,
2309 BOOL selectFirst
, UINT wFlags
)
2316 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner
, hmenu
, selectFirst
);
2318 if (!(menu
= MENU_GetMenu( hmenu
))) return hmenu
;
2320 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return hmenu
;
2322 item
= &menu
->items
[menu
->FocusedItem
];
2323 if (!(item
->fType
& MF_POPUP
) || (item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2326 /* message must be sent before using item,
2327 because nearly everything may be changed by the application ! */
2329 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2330 if (!(wFlags
& TPM_NONOTIFY
))
2331 SendMessageW( hwndOwner
, WM_INITMENUPOPUP
, (WPARAM
)item
->hSubMenu
,
2332 MAKELPARAM( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
2334 item
= &menu
->items
[menu
->FocusedItem
];
2337 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2338 if (!(item
->fState
& MF_HILITE
))
2340 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC( menu
->hWnd
);
2341 else hdc
= GetDCEx( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2343 SelectObject( hdc
, get_menu_font(FALSE
));
2345 item
->fState
|= MF_HILITE
;
2346 MENU_DrawMenuItem( menu
->hWnd
, hmenu
, hwndOwner
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
2347 ReleaseDC( menu
->hWnd
, hdc
);
2349 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
2352 item
->fState
|= MF_MOUSESELECT
;
2354 if (IS_SYSTEM_MENU(menu
))
2356 MENU_InitSysMenuPopup(item
->hSubMenu
,
2357 GetWindowLongW( menu
->hWnd
, GWL_STYLE
),
2358 GetClassLongW( menu
->hWnd
, GCL_STYLE
));
2360 NC_GetSysPopupPos( menu
->hWnd
, &rect
);
2361 if (wFlags
& TPM_LAYOUTRTL
) rect
.left
= rect
.right
;
2362 rect
.top
= rect
.bottom
;
2363 rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2364 rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2368 GetWindowRect( menu
->hWnd
, &rect
);
2369 if (menu
->wFlags
& MF_POPUP
)
2371 RECT rc
= item
->rect
;
2373 MENU_AdjustMenuItemRect(menu
, &rc
);
2375 /* The first item in the popup menu has to be at the
2376 same y position as the focused menu item */
2377 if (wFlags
& TPM_LAYOUTRTL
)
2378 rect
.left
+= GetSystemMetrics(SM_CXBORDER
);
2380 rect
.left
+= rc
.right
- GetSystemMetrics(SM_CXBORDER
);
2381 rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;
2382 rect
.right
= rc
.left
- rc
.right
+ GetSystemMetrics(SM_CXBORDER
);
2383 rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
2384 - MENU_BOTTOM_MARGIN
- GetSystemMetrics(SM_CYBORDER
);
2388 if (wFlags
& TPM_LAYOUTRTL
)
2389 rect
.left
= rect
.right
- item
->rect
.left
;
2391 rect
.left
+= item
->rect
.left
;
2392 rect
.top
+= item
->rect
.bottom
;
2393 rect
.right
= item
->rect
.right
- item
->rect
.left
;
2394 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
2398 /* use default alignment for submenus */
2399 wFlags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
2401 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
, wFlags
,
2402 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2404 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
2405 return item
->hSubMenu
;
2410 /**********************************************************************
2413 HWND
MENU_IsMenuActive(void)
2418 /**********************************************************************
2421 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2423 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2425 void MENU_EndMenu( HWND hwnd
)
2428 menu
= top_popup_hmenu
? MENU_GetMenu( top_popup_hmenu
) : NULL
;
2429 if (menu
&& hwnd
== menu
->hwndOwner
) EndMenu();
2432 /***********************************************************************
2435 * Walks menu chain trying to find a menu pt maps to.
2437 static HMENU
MENU_PtMenu( HMENU hMenu
, POINT pt
)
2439 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2440 UINT item
= menu
->FocusedItem
;
2443 /* try subpopup first (if any) */
2444 ret
= (item
!= NO_SELECTED_ITEM
&&
2445 (menu
->items
[item
].fType
& MF_POPUP
) &&
2446 (menu
->items
[item
].fState
& MF_MOUSESELECT
))
2447 ? MENU_PtMenu(menu
->items
[item
].hSubMenu
, pt
) : 0;
2449 if (!ret
) /* check the current window (avoiding WM_HITTEST) */
2451 INT ht
= NC_HandleNCHitTest( menu
->hWnd
, pt
);
2452 if( menu
->wFlags
& MF_POPUP
)
2454 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= hMenu
;
2456 else if (ht
== HTSYSMENU
)
2457 ret
= get_win_sys_menu( menu
->hWnd
);
2458 else if (ht
== HTMENU
)
2459 ret
= GetMenu( menu
->hWnd
);
2464 /***********************************************************************
2465 * MENU_ExecFocusedItem
2467 * Execute a menu item (for instance when user pressed Enter).
2468 * Return the wID of the executed item. Otherwise, -1 indicating
2469 * that no menu item was executed, -2 if a popup is shown;
2470 * Have to receive the flags for the TrackPopupMenu options to avoid
2471 * sending unwanted message.
2474 static INT
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU hMenu
, UINT wFlags
)
2477 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2479 TRACE("%p hmenu=%p\n", pmt
, hMenu
);
2481 if (!menu
|| !menu
->nItems
||
2482 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return -1;
2484 item
= &menu
->items
[menu
->FocusedItem
];
2486 TRACE("hMenu %p wID %08lx hSubMenu %p fType %04x\n", hMenu
, item
->wID
, item
->hSubMenu
, item
->fType
);
2488 if (!(item
->fType
& MF_POPUP
))
2490 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(item
->fType
& MF_SEPARATOR
))
2492 /* If TPM_RETURNCMD is set you return the id, but
2493 do not send a message to the owner */
2494 if(!(wFlags
& TPM_RETURNCMD
))
2496 if( menu
->wFlags
& MF_SYSMENU
)
2497 PostMessageW( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
2498 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
2501 POPUPMENU
*topmenu
= MENU_GetMenu( pmt
->hTopMenu
);
2502 DWORD dwStyle
= menu
->dwStyle
| (topmenu
? topmenu
->dwStyle
: 0);
2504 if (dwStyle
& MNS_NOTIFYBYPOS
)
2505 PostMessageW( pmt
->hOwnerWnd
, WM_MENUCOMMAND
, menu
->FocusedItem
,
2508 PostMessageW( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
2516 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hMenu
, TRUE
, wFlags
);
2523 /***********************************************************************
2524 * MENU_SwitchTracking
2526 * Helper function for menu navigation routines.
2528 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU hPtMenu
, UINT id
, UINT wFlags
)
2530 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2531 POPUPMENU
*topmenu
= MENU_GetMenu( pmt
->hTopMenu
);
2533 TRACE("%p hmenu=%p 0x%04x\n", pmt
, hPtMenu
, id
);
2535 if( pmt
->hTopMenu
!= hPtMenu
&&
2536 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
2538 /* both are top level menus (system and menu-bar) */
2539 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
, wFlags
);
2540 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2541 pmt
->hTopMenu
= hPtMenu
;
2543 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2544 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
, 0 );
2548 /***********************************************************************
2551 * Return TRUE if we can go on with menu tracking.
2553 static BOOL
MENU_ButtonDown( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2555 TRACE("%p hPtMenu=%p\n", pmt
, hPtMenu
);
2560 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2563 if( IS_SYSTEM_MENU(ptmenu
) )
2564 item
= ptmenu
->items
;
2566 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2570 if( ptmenu
->FocusedItem
!= id
)
2571 MENU_SwitchTracking( pmt
, hPtMenu
, id
, wFlags
);
2573 /* If the popup menu is not already "popped" */
2574 if(!(item
->fState
& MF_MOUSESELECT
))
2576 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2581 /* Else the click was on the menu bar, finish the tracking */
2586 /***********************************************************************
2589 * Return the value of MENU_ExecFocusedItem if
2590 * the selected item was not a popup. Else open the popup.
2591 * A -1 return value indicates that we go on with menu tracking.
2594 static INT
MENU_ButtonUp( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2596 TRACE("%p hmenu=%p\n", pmt
, hPtMenu
);
2601 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2604 if( IS_SYSTEM_MENU(ptmenu
) )
2605 item
= ptmenu
->items
;
2607 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2609 if( item
&& (ptmenu
->FocusedItem
== id
))
2611 debug_print_menuitem ("FocusedItem: ", item
, "");
2613 if( !(item
->fType
& MF_POPUP
) )
2615 INT executedMenuId
= MENU_ExecFocusedItem( pmt
, hPtMenu
, wFlags
);
2616 if (executedMenuId
== -1 || executedMenuId
== -2) return -1;
2617 return executedMenuId
;
2620 /* If we are dealing with the top-level menu */
2621 /* and this is a click on an already "popped" item: */
2622 /* Stop the menu tracking and close the opened submenus */
2623 if((pmt
->hTopMenu
== hPtMenu
) && ptmenu
->bTimeToHide
)
2626 ptmenu
->bTimeToHide
= TRUE
;
2632 /***********************************************************************
2635 * Return TRUE if we can go on with menu tracking.
2637 static BOOL
MENU_MouseMove( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2639 UINT id
= NO_SELECTED_ITEM
;
2640 POPUPMENU
*ptmenu
= NULL
;
2644 ptmenu
= MENU_GetMenu( hPtMenu
);
2645 if( IS_SYSTEM_MENU(ptmenu
) )
2648 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2651 if( id
== NO_SELECTED_ITEM
)
2653 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2654 NO_SELECTED_ITEM
, TRUE
, pmt
->hTopMenu
);
2657 else if( ptmenu
->FocusedItem
!= id
)
2659 MENU_SwitchTracking( pmt
, hPtMenu
, id
, wFlags
);
2660 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2666 /***********************************************************************
2669 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2671 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT vk
, UINT wFlags
)
2673 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2676 /* When skipping left, we need to do something special after the
2678 if (vk
== VK_LEFT
&& menu
->FocusedItem
== 0)
2682 /* When skipping right, for the non-system menu, we need to
2683 handle the last non-special menu item (ie skip any window
2684 icons such as MDI maximize, restore or close) */
2685 else if ((vk
== VK_RIGHT
) && !IS_SYSTEM_MENU(menu
))
2687 UINT i
= menu
->FocusedItem
+ 1;
2688 while (i
< menu
->nItems
) {
2689 if ((menu
->items
[i
].wID
>= SC_SIZE
&&
2690 menu
->items
[i
].wID
<= SC_RESTORE
)) {
2694 if (i
== menu
->nItems
) {
2698 /* When skipping right, we need to cater for the system menu */
2699 else if ((vk
== VK_RIGHT
) && IS_SYSTEM_MENU(menu
))
2701 if (menu
->FocusedItem
== (menu
->nItems
- 1)) {
2708 MDINEXTMENU next_menu
;
2713 next_menu
.hmenuIn
= (IS_SYSTEM_MENU(menu
)) ? GetSubMenu(pmt
->hTopMenu
,0) : pmt
->hTopMenu
;
2714 next_menu
.hmenuNext
= 0;
2715 next_menu
.hwndNext
= 0;
2716 SendMessageW( pmt
->hOwnerWnd
, WM_NEXTMENU
, vk
, (LPARAM
)&next_menu
);
2718 TRACE("%p [%p] -> %p [%p]\n",
2719 pmt
->hCurrentMenu
, pmt
->hOwnerWnd
, next_menu
.hmenuNext
, next_menu
.hwndNext
);
2721 if (!next_menu
.hmenuNext
|| !next_menu
.hwndNext
)
2723 DWORD style
= GetWindowLongW( pmt
->hOwnerWnd
, GWL_STYLE
);
2724 hNewWnd
= pmt
->hOwnerWnd
;
2725 if( IS_SYSTEM_MENU(menu
) )
2727 /* switch to the menu bar */
2729 if(style
& WS_CHILD
|| !(hNewMenu
= GetMenu(hNewWnd
))) return FALSE
;
2733 menu
= MENU_GetMenu( hNewMenu
);
2734 id
= menu
->nItems
- 1;
2736 /* Skip backwards over any system predefined icons,
2737 eg. MDI close, restore etc icons */
2739 (menu
->items
[id
].wID
>= SC_SIZE
&&
2740 menu
->items
[id
].wID
<= SC_RESTORE
)) id
--;
2743 else if (style
& WS_SYSMENU
)
2745 /* switch to the system menu */
2746 hNewMenu
= get_win_sys_menu( hNewWnd
);
2750 else /* application returned a new menu to switch to */
2752 hNewMenu
= next_menu
.hmenuNext
;
2753 hNewWnd
= WIN_GetFullHandle( next_menu
.hwndNext
);
2755 if( IsMenu(hNewMenu
) && IsWindow(hNewWnd
) )
2757 DWORD style
= GetWindowLongW( hNewWnd
, GWL_STYLE
);
2759 if (style
& WS_SYSMENU
&&
2760 GetSubMenu(get_win_sys_menu(hNewWnd
), 0) == hNewMenu
)
2762 /* get the real system menu */
2763 hNewMenu
= get_win_sys_menu(hNewWnd
);
2765 else if (style
& WS_CHILD
|| GetMenu(hNewWnd
) != hNewMenu
)
2767 /* FIXME: Not sure what to do here;
2768 * perhaps try to track hNewMenu as a popup? */
2770 TRACE(" -- got confused.\n");
2777 if( hNewMenu
!= pmt
->hTopMenu
)
2779 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
,
2781 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2782 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
, wFlags
);
2785 if( hNewWnd
!= pmt
->hOwnerWnd
)
2787 pmt
->hOwnerWnd
= hNewWnd
;
2788 set_capture_window( pmt
->hOwnerWnd
, GUI_INMENUMODE
, NULL
);
2791 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2792 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
, 0 );
2799 /***********************************************************************
2802 * The idea is not to show the popup if the next input message is
2803 * going to hide it anyway.
2805 static BOOL
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2809 msg
.hwnd
= pmt
->hOwnerWnd
;
2811 PeekMessageW( &msg
, 0, uMsg
, uMsg
, PM_NOYIELD
| PM_REMOVE
);
2812 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2817 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2818 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2820 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2821 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2822 if( msg
.message
== WM_KEYDOWN
&&
2823 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2825 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2832 /* failures go through this */
2833 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2837 /***********************************************************************
2840 * Handle a VK_ESCAPE key event in a menu.
2842 static BOOL
MENU_KeyEscape(MTRACKER
* pmt
, UINT wFlags
)
2844 BOOL bEndMenu
= TRUE
;
2846 if (pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2848 POPUPMENU
*menu
= MENU_GetMenu(pmt
->hCurrentMenu
);
2850 if (menu
->wFlags
& MF_POPUP
)
2852 HMENU hmenutmp
, hmenuprev
;
2854 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2856 /* close topmost popup */
2857 while (hmenutmp
!= pmt
->hCurrentMenu
)
2859 hmenuprev
= hmenutmp
;
2860 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2863 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
, wFlags
);
2864 pmt
->hCurrentMenu
= hmenuprev
;
2872 /***********************************************************************
2875 * Handle a VK_LEFT key event in a menu.
2877 static void MENU_KeyLeft( MTRACKER
* pmt
, UINT wFlags
)
2880 HMENU hmenutmp
, hmenuprev
;
2883 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2884 menu
= MENU_GetMenu( hmenutmp
);
2886 /* Try to move 1 column left (if possible) */
2887 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2888 NO_SELECTED_ITEM
) {
2890 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2895 /* close topmost popup */
2896 while (hmenutmp
!= pmt
->hCurrentMenu
)
2898 hmenuprev
= hmenutmp
;
2899 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2902 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
, wFlags
);
2903 pmt
->hCurrentMenu
= hmenuprev
;
2905 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2907 /* move menu bar selection if no more popups are left */
2909 if( !MENU_DoNextMenu( pmt
, VK_LEFT
, wFlags
) )
2910 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2912 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2914 /* A sublevel menu was displayed - display the next one
2915 * unless there is another displacement coming up */
2917 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2918 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2919 pmt
->hTopMenu
, TRUE
, wFlags
);
2925 /***********************************************************************
2928 * Handle a VK_RIGHT key event in a menu.
2930 static void MENU_KeyRight( MTRACKER
* pmt
, UINT wFlags
)
2933 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2936 TRACE("MENU_KeyRight called, cur %p (%s), top %p (%s).\n",
2938 debugstr_w((MENU_GetMenu(pmt
->hCurrentMenu
))->items
[0].text
),
2939 pmt
->hTopMenu
, debugstr_w(menu
->items
[0].text
) );
2941 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2943 /* If already displaying a popup, try to display sub-popup */
2945 hmenutmp
= pmt
->hCurrentMenu
;
2946 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hmenutmp
, TRUE
, wFlags
);
2948 /* if subpopup was displayed then we are done */
2949 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2952 /* Check to see if there's another column */
2953 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2954 NO_SELECTED_ITEM
) {
2955 TRACE("Going to %d.\n", nextcol
);
2956 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2961 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2963 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2965 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
, wFlags
);
2966 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2967 } else hmenutmp
= 0;
2969 /* try to move to the next item */
2970 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
, wFlags
) )
2971 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2973 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2974 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2975 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2976 pmt
->hTopMenu
, TRUE
, wFlags
);
2980 static void CALLBACK
release_capture( BOOL __normal
)
2982 set_capture_window( 0, GUI_INMENUMODE
, NULL
);
2985 /***********************************************************************
2988 * Menu tracking code.
2990 static BOOL
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
2991 HWND hwnd
, const RECT
*lprect
)
2996 INT executedMenuId
= -1;
2998 BOOL enterIdleSent
= FALSE
;
3002 mt
.hCurrentMenu
= hmenu
;
3003 mt
.hTopMenu
= hmenu
;
3004 mt
.hOwnerWnd
= WIN_GetFullHandle( hwnd
);
3008 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%p %s\n",
3009 hmenu
, wFlags
, x
, y
, hwnd
, wine_dbgstr_rect( lprect
));
3012 if (!(menu
= MENU_GetMenu( hmenu
)))
3014 WARN("Invalid menu handle %p\n", hmenu
);
3015 SetLastError(ERROR_INVALID_MENU_HANDLE
);
3019 if (wFlags
& TPM_BUTTONDOWN
)
3021 /* Get the result in order to start the tracking or not */
3022 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
3023 fEndMenu
= !fRemove
;
3026 if (wFlags
& TF_ENDMENU
) fEndMenu
= TRUE
;
3028 /* owner may not be visible when tracking a popup, so use the menu itself */
3029 capture_win
= (wFlags
& TPM_POPUPMENU
) ? menu
->hWnd
: mt
.hOwnerWnd
;
3030 set_capture_window( capture_win
, GUI_INMENUMODE
, NULL
);
3032 __TRY
while (!fEndMenu
)
3034 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
3035 if (!menu
) /* sometimes happens if I do a window manager close */
3038 /* we have to keep the message in the queue until it's
3039 * clear that menu loop is not over yet. */
3043 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
3045 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
3046 /* remove the message from the queue */
3047 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3053 HWND win
= menu
->wFlags
& MF_POPUP
? menu
->hWnd
: 0;
3054 enterIdleSent
= TRUE
;
3055 SendMessageW( mt
.hOwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
)win
);
3061 /* check if EndMenu() tried to cancel us, by posting this message */
3062 if(msg
.message
== WM_CANCELMODE
)
3064 /* we are now out of the loop */
3067 /* remove the message from the queue */
3068 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3070 /* break out of internal loop, ala ESCAPE */
3074 TranslateMessage( &msg
);
3077 if ( (msg
.hwnd
==menu
->hWnd
) || (msg
.message
!=WM_TIMER
) )
3078 enterIdleSent
=FALSE
;
3081 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
3084 * Use the mouse coordinates in lParam instead of those in the MSG
3085 * struct to properly handle synthetic messages. They are already
3086 * in screen coordinates.
3088 mt
.pt
.x
= (short)LOWORD(msg
.lParam
);
3089 mt
.pt
.y
= (short)HIWORD(msg
.lParam
);
3091 /* Find a menu for this mouse event */
3092 hmenu
= MENU_PtMenu( mt
.hTopMenu
, mt
.pt
);
3096 /* no WM_NC... messages in captured state */
3098 case WM_RBUTTONDBLCLK
:
3099 case WM_RBUTTONDOWN
:
3100 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3102 case WM_LBUTTONDBLCLK
:
3103 case WM_LBUTTONDOWN
:
3104 /* If the message belongs to the menu, removes it from the queue */
3105 /* Else, end menu tracking */
3106 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
3107 fEndMenu
= !fRemove
;
3111 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
3114 /* Check if a menu was selected by the mouse */
3117 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
3118 TRACE("executedMenuId %d\n", executedMenuId
);
3120 /* End the loop if executedMenuId is an item ID */
3121 /* or if the job was done (executedMenuId = 0). */
3122 fEndMenu
= fRemove
= (executedMenuId
!= -1);
3124 /* No menu was selected by the mouse */
3125 /* if the function was called by TrackPopupMenu, continue
3126 with the menu tracking. If not, stop it */
3128 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3133 /* the selected menu item must be changed every time */
3134 /* the mouse moves. */
3137 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
, wFlags
);
3139 } /* switch(msg.message) - mouse */
3141 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
3143 fRemove
= TRUE
; /* Keyboard messages are always removed */
3157 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
3158 NO_SELECTED_ITEM
, FALSE
, 0 );
3159 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
3160 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
3164 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3166 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
3167 if (!(menu
->wFlags
& MF_POPUP
))
3168 mt
.hCurrentMenu
= MENU_ShowSubPopup(mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
, wFlags
);
3169 else /* otherwise try to move selection */
3170 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
3171 (msg
.wParam
== VK_UP
)? ITEM_PREV
: ITEM_NEXT
);
3175 MENU_KeyLeft( &mt
, wFlags
);
3179 MENU_KeyRight( &mt
, wFlags
);
3183 fEndMenu
= MENU_KeyEscape(&mt
, wFlags
);
3189 hi
.cbSize
= sizeof(HELPINFO
);
3190 hi
.iContextType
= HELPINFO_MENUITEM
;
3191 if (menu
->FocusedItem
== NO_SELECTED_ITEM
)
3194 hi
.iCtrlId
= menu
->items
[menu
->FocusedItem
].wID
;
3195 hi
.hItemHandle
= hmenu
;
3196 hi
.dwContextId
= menu
->dwContextHelpID
;
3197 hi
.MousePos
= msg
.pt
;
3198 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
3205 break; /* WM_KEYDOWN */
3212 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
3214 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
3215 fEndMenu
= (executedMenuId
!= -2);
3220 /* Hack to avoid control chars. */
3221 /* We will find a better way real soon... */
3222 if (msg
.wParam
< 32) break;
3224 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
3225 LOWORD(msg
.wParam
), FALSE
);
3226 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
3227 else if (pos
== (UINT
)-1) MessageBeep(0);
3230 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
,
3232 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
3233 fEndMenu
= (executedMenuId
!= -2);
3237 } /* switch(msg.message) - kbd */
3241 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3242 DispatchMessageW( &msg
);
3246 if (!fEndMenu
) fRemove
= TRUE
;
3248 /* finally remove message from the queue */
3250 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
3251 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
3252 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
3254 __FINALLY( release_capture
)
3256 /* If dropdown is still painted and the close box is clicked on
3257 then the menu will be destroyed as part of the DispatchMessage above.
3258 This will then invalidate the menu handle in mt.hTopMenu. We should
3259 check for this first. */
3260 if( IsMenu( mt
.hTopMenu
) )
3262 menu
= MENU_GetMenu( mt
.hTopMenu
);
3264 if( IsWindow( mt
.hOwnerWnd
) )
3266 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
, wFlags
);
3268 if (menu
&& (menu
->wFlags
& MF_POPUP
))
3270 DestroyWindow( menu
->hWnd
);
3273 if (!(wFlags
& TPM_NONOTIFY
))
3274 SendMessageW( mt
.hOwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)mt
.hTopMenu
,
3275 MAKELPARAM(0, IS_SYSTEM_MENU(menu
)) );
3277 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
3278 SendMessageW( mt
.hOwnerWnd
, WM_MENUSELECT
, MAKEWPARAM(0,0xffff), 0 );
3281 /* Reset the variable for hiding menu */
3282 if( menu
) menu
->bTimeToHide
= FALSE
;
3285 /* The return value is only used by TrackPopupMenu */
3286 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
3287 if (executedMenuId
== -1) executedMenuId
= 0;
3288 return executedMenuId
;
3291 /***********************************************************************
3294 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
3298 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
3302 /* This makes the menus of applications built with Delphi work.
3303 * It also enables menus to be displayed in more than one window,
3304 * but there are some bugs left that need to be fixed in this case.
3306 if ((menu
= MENU_GetMenu( hMenu
))) menu
->hWnd
= hWnd
;
3307 if (!top_popup
) top_popup_hmenu
= hMenu
;
3309 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3310 if (!(wFlags
& TPM_NONOTIFY
))
3311 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
3313 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
3315 if (!(wFlags
& TPM_NONOTIFY
))
3317 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
3318 /* If an app changed/recreated menu bar entries in WM_INITMENU
3319 * menu sizes will be recalculated once the menu created/shown.
3326 /***********************************************************************
3329 static BOOL
MENU_ExitTracking(HWND hWnd
, BOOL bPopup
)
3331 TRACE("hwnd=%p\n", hWnd
);
3333 SendMessageW( hWnd
, WM_EXITMENULOOP
, bPopup
, 0 );
3336 top_popup_hmenu
= NULL
;
3340 /***********************************************************************
3341 * MENU_TrackMouseMenuBar
3343 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3345 void MENU_TrackMouseMenuBar( HWND hWnd
, INT ht
, POINT pt
)
3347 HMENU hMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( hWnd
) : GetMenu( hWnd
);
3348 UINT wFlags
= TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3350 TRACE("wnd=%p ht=0x%04x %s\n", hWnd
, ht
, wine_dbgstr_point( &pt
));
3352 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
3355 MENU_InitTracking( hWnd
, hMenu
, FALSE
, wFlags
);
3356 MENU_TrackMenu( hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
3357 MENU_ExitTracking(hWnd
, FALSE
);
3362 /***********************************************************************
3363 * MENU_TrackKbdMenuBar
3365 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3367 void MENU_TrackKbdMenuBar( HWND hwnd
, UINT wParam
, WCHAR wChar
)
3369 UINT uItem
= NO_SELECTED_ITEM
;
3371 UINT wFlags
= TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3373 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
3375 /* find window that has a menu */
3377 while (!WIN_ALLOWED_MENU(GetWindowLongW( hwnd
, GWL_STYLE
)))
3378 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
3380 /* check if we have to track a system menu */
3382 hTrackMenu
= GetMenu( hwnd
);
3383 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
3385 if (!(GetWindowLongW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3386 hTrackMenu
= get_win_sys_menu( hwnd
);
3388 wParam
|= HTSYSMENU
; /* prevent item lookup */
3390 if (GetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
) wFlags
|= TPM_LAYOUTRTL
;
3392 if (!IsMenu( hTrackMenu
)) return;
3394 MENU_InitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
3396 if( wChar
&& wChar
!= ' ' )
3398 uItem
= MENU_FindItemByKey( hwnd
, hTrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
3399 if ( uItem
>= (UINT
)(-2) )
3401 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3402 /* schedule end of menu tracking */
3403 wFlags
|= TF_ENDMENU
;
3408 MENU_SelectItem( hwnd
, hTrackMenu
, uItem
, TRUE
, 0 );
3410 if (!(wParam
& HTSYSMENU
) || wChar
== ' ')
3412 if( uItem
== NO_SELECTED_ITEM
)
3413 MENU_MoveSelection( hwnd
, hTrackMenu
, ITEM_NEXT
);
3415 PostMessageW( hwnd
, WM_KEYDOWN
, VK_RETURN
, 0 );
3419 MENU_TrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
3420 MENU_ExitTracking( hwnd
, FALSE
);
3423 /**********************************************************************
3424 * TrackPopupMenuEx (USER32.@)
3426 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3427 HWND hWnd
, LPTPMPARAMS lpTpm
)
3432 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p rect %s\n",
3433 hMenu
, wFlags
, x
, y
, hWnd
, lpTpm
,
3434 lpTpm
? wine_dbgstr_rect( &lpTpm
->rcExclude
) : "-" );
3436 /* Parameter check */
3437 /* FIXME: this check is performed several times, here and in the called
3438 functions. That could be optimized */
3439 if (!(menu
= MENU_GetMenu( hMenu
)))
3441 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3445 if (IsWindow(menu
->hWnd
))
3447 SetLastError( ERROR_POPUP_ALREADY_ACTIVE
);
3451 MENU_InitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
3453 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3454 if (!(wFlags
& TPM_NONOTIFY
))
3455 SendMessageW( hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hMenu
, 0);
3457 if (MENU_ShowPopup( hWnd
, hMenu
, 0, wFlags
, x
, y
, 0, 0 ))
3458 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
,
3459 lpTpm
? &lpTpm
->rcExclude
: NULL
);
3460 MENU_ExitTracking(hWnd
, TRUE
);
3465 /**********************************************************************
3466 * TrackPopupMenu (USER32.@)
3468 * Like the win32 API, the function return the command ID only if the
3469 * flag TPM_RETURNCMD is on.
3472 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3473 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
3475 return TrackPopupMenuEx( hMenu
, wFlags
, x
, y
, hWnd
, NULL
);
3478 /***********************************************************************
3481 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3483 LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
3485 TRACE("hwnd=%p msg=0x%04x wp=0x%04lx lp=0x%08lx\n", hwnd
, message
, wParam
, lParam
);
3491 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lParam
;
3492 SetWindowLongPtrW( hwnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
3496 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
3497 return MA_NOACTIVATE
;
3502 BeginPaint( hwnd
, &ps
);
3503 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
3504 (HMENU
)GetWindowLongPtrW( hwnd
, 0 ) );
3505 EndPaint( hwnd
, &ps
);
3509 case WM_PRINTCLIENT
:
3511 MENU_DrawPopupMenu( hwnd
, (HDC
)wParam
,
3512 (HMENU
)GetWindowLongPtrW( hwnd
, 0 ) );
3520 /* zero out global pointer in case resident popup window was destroyed. */
3521 if (hwnd
== top_popup
) {
3523 top_popup_hmenu
= NULL
;
3531 if (!GetWindowLongPtrW( hwnd
, 0 )) ERR("no menu to display\n");
3534 SetWindowLongPtrW( hwnd
, 0, 0 );
3537 case MM_SETMENUHANDLE
:
3538 SetWindowLongPtrW( hwnd
, 0, wParam
);
3541 case MM_GETMENUHANDLE
:
3543 return GetWindowLongPtrW( hwnd
, 0 );
3546 return DefWindowProcW( hwnd
, message
, wParam
, lParam
);
3552 /***********************************************************************
3553 * MENU_GetMenuBarHeight
3555 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3557 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
3558 INT orgX
, INT orgY
)
3564 TRACE("HWND %p, width %d, at (%d, %d).\n", hwnd
, menubarWidth
, orgX
, orgY
);
3566 if (!(lppop
= MENU_GetMenu( GetMenu(hwnd
) ))) return 0;
3568 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3569 SelectObject( hdc
, get_menu_font(FALSE
));
3570 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+GetSystemMetrics(SM_CYMENU
));
3571 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
3572 ReleaseDC( hwnd
, hdc
);
3573 return lppop
->Height
;
3577 /*******************************************************************
3578 * ChangeMenuA (USER32.@)
3580 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
3581 UINT id
, UINT flags
)
3583 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu
, pos
, data
, id
, flags
);
3584 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
3586 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3587 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
3589 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3590 flags
& MF_BYPOSITION
? pos
: id
,
3591 flags
& ~MF_REMOVE
);
3592 /* Default: MF_INSERT */
3593 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
3597 /*******************************************************************
3598 * ChangeMenuW (USER32.@)
3600 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
3601 UINT id
, UINT flags
)
3603 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu
, pos
, data
, id
, flags
);
3604 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
3606 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3607 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
3609 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3610 flags
& MF_BYPOSITION
? pos
: id
,
3611 flags
& ~MF_REMOVE
);
3612 /* Default: MF_INSERT */
3613 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
3617 /*******************************************************************
3618 * CheckMenuItem (USER32.@)
3620 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
3625 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
3626 ret
= item
->fState
& MF_CHECKED
;
3627 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
3628 else item
->fState
&= ~MF_CHECKED
;
3633 /**********************************************************************
3634 * EnableMenuItem (USER32.@)
3636 BOOL WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3642 TRACE("(%p, %04x, %04x) !\n", hMenu
, wItemID
, wFlags
);
3644 /* Get the Popupmenu to access the owner menu */
3645 if (!(menu
= MENU_GetMenu(hMenu
)))
3648 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3651 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3652 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3654 /* If the close item in the system menu change update the close button */
3655 if((item
->wID
== SC_CLOSE
) && (oldflags
!= wFlags
))
3657 if (menu
->hSysMenuOwner
!= 0)
3660 POPUPMENU
* parentMenu
;
3662 /* Get the parent menu to access*/
3663 if (!(parentMenu
= MENU_GetMenu(menu
->hSysMenuOwner
)))
3666 /* Refresh the frame to reflect the change */
3667 WIN_GetRectangles( parentMenu
->hWnd
, COORDS_CLIENT
, &rc
, NULL
);
3669 RedrawWindow(parentMenu
->hWnd
, &rc
, 0, RDW_FRAME
| RDW_INVALIDATE
| RDW_NOCHILDREN
);
3677 /*******************************************************************
3678 * GetMenuStringA (USER32.@)
3680 INT WINAPI
GetMenuStringA(
3681 HMENU hMenu
, /* [in] menuhandle */
3682 UINT wItemID
, /* [in] menu item (dep. on wFlags) */
3683 LPSTR str
, /* [out] outbuffer. If NULL, func returns entry length*/
3684 INT nMaxSiz
, /* [in] length of buffer. if 0, func returns entry len*/
3685 UINT wFlags
/* [in] MF_ flags */
3689 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3690 if (str
&& nMaxSiz
) str
[0] = '\0';
3691 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) {
3692 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
3695 if (!item
->text
) return 0;
3696 if (!str
|| !nMaxSiz
) return strlenW(item
->text
);
3697 if (!WideCharToMultiByte( CP_ACP
, 0, item
->text
, -1, str
, nMaxSiz
, NULL
, NULL
))
3699 TRACE("returning %s\n", debugstr_a(str
));
3704 /*******************************************************************
3705 * GetMenuStringW (USER32.@)
3707 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3708 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3712 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3713 if (str
&& nMaxSiz
) str
[0] = '\0';
3714 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) {
3715 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
3718 if (!str
|| !nMaxSiz
) return item
->text
? strlenW(item
->text
) : 0;
3719 if( !(item
->text
)) {
3723 lstrcpynW( str
, item
->text
, nMaxSiz
);
3724 TRACE("returning %s\n", debugstr_w(str
));
3725 return strlenW(str
);
3729 /**********************************************************************
3730 * HiliteMenuItem (USER32.@)
3732 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3736 TRACE("(%p, %p, %04x, %04x);\n", hWnd
, hMenu
, wItemID
, wHilite
);
3737 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3738 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3739 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3740 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
, 0 );
3741 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
, 0 );
3746 /**********************************************************************
3747 * GetMenuState (USER32.@)
3749 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3752 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu
, wItemID
, wFlags
);
3753 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3754 debug_print_menuitem (" item: ", item
, "");
3755 if (item
->fType
& MF_POPUP
)
3757 POPUPMENU
*menu
= MENU_GetMenu( item
->hSubMenu
);
3758 if (!menu
) return -1;
3759 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3763 /* We used to (from way back then) mask the result to 0xff. */
3764 /* I don't know why and it seems wrong as the documented */
3765 /* return flag MF_SEPARATOR is outside that mask. */
3766 return (item
->fType
| item
->fState
);
3771 /**********************************************************************
3772 * GetMenuItemCount (USER32.@)
3774 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3776 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3777 if (!menu
) return -1;
3778 TRACE("(%p) returning %d\n", hMenu
, menu
->nItems
);
3779 return menu
->nItems
;
3783 /**********************************************************************
3784 * GetMenuItemID (USER32.@)
3786 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3790 if (!(lpmi
= MENU_FindItem(&hMenu
,(UINT
*)&nPos
,MF_BYPOSITION
))) return -1;
3791 if (lpmi
->fType
& MF_POPUP
) return -1;
3797 /**********************************************************************
3800 * Uses flags, id and text ptr, passed by InsertMenu() and
3801 * ModifyMenu() to setup a MenuItemInfo structure.
3803 static void MENU_mnu2mnuii( UINT flags
, UINT_PTR id
, LPCWSTR str
,
3804 LPMENUITEMINFOW pmii
)
3806 ZeroMemory( pmii
, sizeof( MENUITEMINFOW
));
3807 pmii
->cbSize
= sizeof( MENUITEMINFOW
);
3808 pmii
->fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
3809 /* setting bitmap clears text and vice versa */
3810 if( IS_STRING_ITEM(flags
)) {
3811 pmii
->fMask
|= MIIM_STRING
| MIIM_BITMAP
;
3813 flags
|= MF_SEPARATOR
;
3814 /* Item beginning with a backspace is a help item */
3815 /* FIXME: wrong place, this is only true in win16 */
3816 else if( *str
== '\b') {
3820 pmii
->dwTypeData
= (LPWSTR
)str
;
3821 } else if( flags
& MFT_BITMAP
){
3822 pmii
->fMask
|= MIIM_BITMAP
| MIIM_STRING
;
3823 pmii
->hbmpItem
= (HBITMAP
)str
;
3825 if( flags
& MF_OWNERDRAW
){
3826 pmii
->fMask
|= MIIM_DATA
;
3827 pmii
->dwItemData
= (ULONG_PTR
) str
;
3829 if( flags
& MF_POPUP
) {
3830 pmii
->fMask
|= MIIM_SUBMENU
;
3831 pmii
->hSubMenu
= (HMENU
)id
;
3833 if( flags
& MF_SEPARATOR
) flags
|= MF_GRAYED
| MF_DISABLED
;
3834 pmii
->fState
= flags
& MENUITEMINFO_STATE_MASK
& ~MFS_DEFAULT
;
3835 pmii
->fType
= flags
& MENUITEMINFO_TYPE_MASK
;
3836 pmii
->wID
= (UINT
)id
;
3840 /*******************************************************************
3841 * InsertMenuW (USER32.@)
3843 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3844 UINT_PTR id
, LPCWSTR str
)
3849 if (IS_STRING_ITEM(flags
) && str
)
3850 TRACE("hMenu %p, pos %d, flags %08x, id %04lx, str %s\n",
3851 hMenu
, pos
, flags
, id
, debugstr_w(str
) );
3852 else TRACE("hMenu %p, pos %d, flags %08x, id %04lx, str %p (not a string)\n",
3853 hMenu
, pos
, flags
, id
, str
);
3855 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3856 MENU_mnu2mnuii( flags
, id
, str
, &mii
);
3857 if (!(SetMenuItemInfo_common( item
, &mii
, TRUE
)))
3859 RemoveMenu( hMenu
, pos
, flags
);
3863 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3868 /*******************************************************************
3869 * InsertMenuA (USER32.@)
3871 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3872 UINT_PTR id
, LPCSTR str
)
3876 if (IS_STRING_ITEM(flags
) && str
)
3878 INT len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
3879 LPWSTR newstr
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3882 MultiByteToWideChar( CP_ACP
, 0, str
, -1, newstr
, len
);
3883 ret
= InsertMenuW( hMenu
, pos
, flags
, id
, newstr
);
3884 HeapFree( GetProcessHeap(), 0, newstr
);
3888 else return InsertMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
3892 /*******************************************************************
3893 * AppendMenuA (USER32.@)
3895 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3896 UINT_PTR id
, LPCSTR data
)
3898 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3902 /*******************************************************************
3903 * AppendMenuW (USER32.@)
3905 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3906 UINT_PTR id
, LPCWSTR data
)
3908 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3912 /**********************************************************************
3913 * RemoveMenu (USER32.@)
3915 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3920 TRACE("(menu=%p pos=%04x flags=%04x)\n",hMenu
, nPos
, wFlags
);
3921 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3922 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3926 MENU_FreeItemData( item
);
3928 if (--menu
->nItems
== 0)
3930 HeapFree( GetProcessHeap(), 0, menu
->items
);
3935 while(nPos
< menu
->nItems
)
3941 menu
->items
= HeapReAlloc( GetProcessHeap(), 0, menu
->items
,
3942 menu
->nItems
* sizeof(MENUITEM
) );
3948 /**********************************************************************
3949 * DeleteMenu (USER32.@)
3951 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3953 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3954 if (!item
) return FALSE
;
3955 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3956 /* nPos is now the position of the item */
3957 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3962 /*******************************************************************
3963 * ModifyMenuW (USER32.@)
3965 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3966 UINT_PTR id
, LPCWSTR str
)
3971 if (IS_STRING_ITEM(flags
))
3972 TRACE("%p %d %04x %04lx %s\n", hMenu
, pos
, flags
, id
, debugstr_w(str
) );
3974 TRACE("%p %d %04x %04lx %p\n", hMenu
, pos
, flags
, id
, str
);
3976 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3977 MENU_GetMenu(hMenu
)->Height
= 0; /* force size recalculate */
3978 MENU_mnu2mnuii( flags
, id
, str
, &mii
);
3979 return SetMenuItemInfo_common( item
, &mii
, TRUE
);
3983 /*******************************************************************
3984 * ModifyMenuA (USER32.@)
3986 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3987 UINT_PTR id
, LPCSTR str
)
3991 if (IS_STRING_ITEM(flags
) && str
)
3993 INT len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
3994 LPWSTR newstr
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3997 MultiByteToWideChar( CP_ACP
, 0, str
, -1, newstr
, len
);
3998 ret
= ModifyMenuW( hMenu
, pos
, flags
, id
, newstr
);
3999 HeapFree( GetProcessHeap(), 0, newstr
);
4003 else return ModifyMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
4007 /**********************************************************************
4008 * CreatePopupMenu (USER32.@)
4010 HMENU WINAPI
CreatePopupMenu(void)
4015 if (!(hmenu
= CreateMenu())) return 0;
4016 menu
= MENU_GetMenu( hmenu
);
4017 menu
->wFlags
|= MF_POPUP
;
4018 menu
->bTimeToHide
= FALSE
;
4023 /**********************************************************************
4024 * GetMenuCheckMarkDimensions (USER.417)
4025 * GetMenuCheckMarkDimensions (USER32.@)
4027 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
4029 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK
), GetSystemMetrics(SM_CYMENUCHECK
) );
4033 /**********************************************************************
4034 * SetMenuItemBitmaps (USER32.@)
4036 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
4037 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
4041 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
4043 if (!hNewCheck
&& !hNewUnCheck
)
4045 item
->fState
&= ~MF_USECHECKBITMAPS
;
4047 else /* Install new bitmaps */
4049 item
->hCheckBit
= hNewCheck
;
4050 item
->hUnCheckBit
= hNewUnCheck
;
4051 item
->fState
|= MF_USECHECKBITMAPS
;
4057 /**********************************************************************
4058 * CreateMenu (USER32.@)
4060 HMENU WINAPI
CreateMenu(void)
4065 if (!(menu
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*menu
) ))) return 0;
4066 menu
->FocusedItem
= NO_SELECTED_ITEM
;
4067 menu
->bTimeToHide
= FALSE
;
4069 if (!(hMenu
= alloc_user_handle( &menu
->obj
, USER_MENU
))) HeapFree( GetProcessHeap(), 0, menu
);
4071 TRACE("return %p\n", hMenu
);
4077 /**********************************************************************
4078 * DestroyMenu (USER32.@)
4080 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
4084 TRACE("(%p)\n", hMenu
);
4086 if (!(lppop
= free_user_handle( hMenu
, USER_MENU
))) return FALSE
;
4087 if (lppop
== OBJ_OTHER_PROCESS
) return FALSE
;
4089 /* DestroyMenu should not destroy system menu popup owner */
4090 if ((lppop
->wFlags
& (MF_POPUP
| MF_SYSMENU
)) == MF_POPUP
&& lppop
->hWnd
)
4092 DestroyWindow( lppop
->hWnd
);
4096 if (lppop
->items
) /* recursively destroy submenus */
4099 MENUITEM
*item
= lppop
->items
;
4100 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
4102 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
4103 MENU_FreeItemData( item
);
4105 HeapFree( GetProcessHeap(), 0, lppop
->items
);
4107 HeapFree( GetProcessHeap(), 0, lppop
);
4112 /**********************************************************************
4113 * GetSystemMenu (USER32.@)
4115 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
4117 WND
*wndPtr
= WIN_GetPtr( hWnd
);
4120 if (wndPtr
== WND_DESKTOP
) return 0;
4121 if (wndPtr
== WND_OTHER_PROCESS
)
4123 if (IsWindow( hWnd
)) FIXME( "not supported on other process window %p\n", hWnd
);
4127 if (wndPtr
->hSysMenu
&& bRevert
)
4129 DestroyMenu(wndPtr
->hSysMenu
);
4130 wndPtr
->hSysMenu
= 0;
4133 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
4134 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, 0 );
4136 if( wndPtr
->hSysMenu
)
4139 retvalue
= GetSubMenu(wndPtr
->hSysMenu
, 0);
4141 /* Store the dummy sysmenu handle to facilitate the refresh */
4142 /* of the close button if the SC_CLOSE item change */
4143 menu
= MENU_GetMenu(retvalue
);
4145 menu
->hSysMenuOwner
= wndPtr
->hSysMenu
;
4147 WIN_ReleasePtr( wndPtr
);
4149 return bRevert
? 0 : retvalue
;
4153 /*******************************************************************
4154 * SetSystemMenu (USER32.@)
4156 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
4158 WND
*wndPtr
= WIN_GetPtr( hwnd
);
4160 if (wndPtr
&& wndPtr
!= WND_OTHER_PROCESS
&& wndPtr
!= WND_DESKTOP
)
4162 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
4163 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
4164 WIN_ReleasePtr( wndPtr
);
4171 /**********************************************************************
4172 * GetMenu (USER32.@)
4174 HMENU WINAPI
GetMenu( HWND hWnd
)
4176 HMENU retvalue
= (HMENU
)GetWindowLongPtrW( hWnd
, GWLP_ID
);
4177 TRACE("for %p returning %p\n", hWnd
, retvalue
);
4181 /**********************************************************************
4182 * GetMenuBarInfo (USER32.@)
4184 BOOL WINAPI
GetMenuBarInfo( HWND hwnd
, LONG idObject
, LONG idItem
, PMENUBARINFO pmbi
)
4190 TRACE( "(%p,0x%08x,0x%08x,%p)\n", hwnd
, idObject
, idItem
, pmbi
);
4195 class_atom
= GetClassLongW(hwnd
, GCW_ATOM
);
4198 if (class_atom
!= POPUPMENU_CLASS_ATOM
)
4200 WARN("called on invalid window: %d\n", class_atom
);
4201 SetLastError(ERROR_INVALID_MENU_HANDLE
);
4205 hmenu
= (HMENU
)GetWindowLongPtrW(hwnd
, 0);
4208 hmenu
= GetMenu(hwnd
);
4211 hmenu
= GetSystemMenu(hwnd
, FALSE
);
4220 if (pmbi
->cbSize
!= sizeof(MENUBARINFO
))
4222 SetLastError(ERROR_INVALID_PARAMETER
);
4226 menu
= MENU_GetMenu(hmenu
);
4229 if (idItem
< 0 || idItem
> menu
->nItems
)
4234 SetRectEmpty(&pmbi
->rcBar
);
4236 else if (idItem
== 0)
4238 GetMenuItemRect(hwnd
, hmenu
, 0, &pmbi
->rcBar
);
4239 pmbi
->rcBar
.right
= pmbi
->rcBar
.left
+ menu
->Width
;
4240 pmbi
->rcBar
.bottom
= pmbi
->rcBar
.top
+ menu
->Height
;
4244 GetMenuItemRect(hwnd
, hmenu
, idItem
- 1, &pmbi
->rcBar
);
4247 pmbi
->hMenu
= hmenu
;
4248 pmbi
->hwndMenu
= NULL
;
4249 pmbi
->fBarFocused
= top_popup_hmenu
== hmenu
;
4252 pmbi
->fFocused
= menu
->FocusedItem
== idItem
- 1;
4253 if (pmbi
->fFocused
&& (menu
->items
[idItem
- 1].fType
& MF_POPUP
))
4255 menu
= MENU_GetMenu(menu
->items
[idItem
- 1].hSubMenu
);
4257 pmbi
->hwndMenu
= menu
->hWnd
;
4262 pmbi
->fFocused
= pmbi
->fBarFocused
;
4268 /**********************************************************************
4271 * Helper for SetMenu. Also called by WIN_CreateWindowEx to avoid the
4272 * SetWindowPos call that would result if SetMenu were called directly.
4274 BOOL
MENU_SetMenu( HWND hWnd
, HMENU hMenu
)
4276 TRACE("(%p, %p);\n", hWnd
, hMenu
);
4278 if (hMenu
&& !IsMenu(hMenu
))
4280 WARN("hMenu %p is not a menu handle\n", hMenu
);
4283 if (!WIN_ALLOWED_MENU(GetWindowLongW( hWnd
, GWL_STYLE
)))
4286 hWnd
= WIN_GetFullHandle( hWnd
);
4287 if (GetCapture() == hWnd
)
4288 set_capture_window( 0, GUI_INMENUMODE
, NULL
); /* release the capture */
4294 if (!(lpmenu
= MENU_GetMenu(hMenu
))) return FALSE
;
4296 lpmenu
->hWnd
= hWnd
;
4297 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
4299 SetWindowLongPtrW( hWnd
, GWLP_ID
, (LONG_PTR
)hMenu
);
4304 /**********************************************************************
4305 * SetMenu (USER32.@)
4307 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
4309 if(!MENU_SetMenu(hWnd
, hMenu
))
4312 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4313 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4318 /**********************************************************************
4319 * GetSubMenu (USER32.@)
4321 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
4325 if (!(lpmi
= MENU_FindItem(&hMenu
,(UINT
*)&nPos
,MF_BYPOSITION
))) return 0;
4326 if (!(lpmi
->fType
& MF_POPUP
)) return 0;
4327 return lpmi
->hSubMenu
;
4331 /**********************************************************************
4332 * DrawMenuBar (USER32.@)
4334 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
4337 HMENU hMenu
= GetMenu(hWnd
);
4339 if (!WIN_ALLOWED_MENU(GetWindowLongW( hWnd
, GWL_STYLE
)))
4341 if (!hMenu
|| !(lppop
= MENU_GetMenu( hMenu
))) return FALSE
;
4343 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
4344 lppop
->hwndOwner
= hWnd
;
4345 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4346 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4350 /***********************************************************************
4351 * DrawMenuBarTemp (USER32.@)
4355 * called by W98SE desk.cpl Control Panel Applet
4357 * Not 100% sure about the param names, but close.
4359 DWORD WINAPI
DrawMenuBarTemp(HWND hwnd
, HDC hDC
, LPRECT lprect
, HMENU hMenu
, HFONT hFont
)
4364 BOOL flat_menu
= FALSE
;
4366 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
4369 hMenu
= GetMenu(hwnd
);
4372 hFont
= get_menu_font(FALSE
);
4374 lppop
= MENU_GetMenu( hMenu
);
4375 if (lppop
== NULL
|| lprect
== NULL
)
4377 retvalue
= GetSystemMetrics(SM_CYMENU
);
4381 TRACE("(%p, %p, %p, %p, %p)\n", hwnd
, hDC
, lprect
, hMenu
, hFont
);
4383 hfontOld
= SelectObject( hDC
, hFont
);
4385 if (lppop
->Height
== 0)
4386 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
4388 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
4390 FillRect(hDC
, lprect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
) );
4392 SelectObject( hDC
, SYSCOLOR_GetPen(COLOR_3DFACE
));
4393 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
4394 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
4396 if (lppop
->nItems
== 0)
4398 retvalue
= GetSystemMetrics(SM_CYMENU
);
4402 for (i
= 0; i
< lppop
->nItems
; i
++)
4404 MENU_DrawMenuItem( hwnd
, hMenu
, hwnd
,
4405 hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
, ODA_DRAWENTIRE
);
4407 retvalue
= lppop
->Height
;
4410 if (hfontOld
) SelectObject (hDC
, hfontOld
);
4414 /***********************************************************************
4415 * EndMenu (USER.187)
4416 * EndMenu (USER32.@)
4418 BOOL WINAPI
EndMenu(void)
4420 /* if we are in the menu code, and it is active */
4421 if (!fEndMenu
&& top_popup
)
4423 /* terminate the menu handling code */
4426 /* needs to be posted to wakeup the internal menu handler */
4427 /* which will now terminate the menu, in the event that */
4428 /* the main window was minimized, or lost focus, so we */
4429 /* don't end up with an orphaned menu */
4430 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
4436 /*****************************************************************
4437 * LoadMenuA (USER32.@)
4439 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
4441 HRSRC hrsrc
= FindResourceA( instance
, name
, (LPSTR
)RT_MENU
);
4442 if (!hrsrc
) return 0;
4443 return LoadMenuIndirectA( LoadResource( instance
, hrsrc
));
4447 /*****************************************************************
4448 * LoadMenuW (USER32.@)
4450 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
4452 HRSRC hrsrc
= FindResourceW( instance
, name
, (LPWSTR
)RT_MENU
);
4453 if (!hrsrc
) return 0;
4454 return LoadMenuIndirectW( LoadResource( instance
, hrsrc
));
4458 /**********************************************************************
4459 * LoadMenuIndirectW (USER32.@)
4461 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
4464 WORD version
, offset
;
4465 LPCSTR p
= template;
4467 version
= GET_WORD(p
);
4469 TRACE("%p, ver %d\n", template, version
);
4472 case 0: /* standard format is version of 0 */
4473 offset
= GET_WORD(p
);
4474 p
+= sizeof(WORD
) + offset
;
4475 if (!(hMenu
= CreateMenu())) return 0;
4476 if (!MENU_ParseResource( p
, hMenu
))
4478 DestroyMenu( hMenu
);
4482 case 1: /* extended format is version of 1 */
4483 offset
= GET_WORD(p
);
4484 p
+= sizeof(WORD
) + offset
;
4485 if (!(hMenu
= CreateMenu())) return 0;
4486 if (!MENUEX_ParseResource( p
, hMenu
))
4488 DestroyMenu( hMenu
);
4493 ERR("version %d not supported.\n", version
);
4499 /**********************************************************************
4500 * LoadMenuIndirectA (USER32.@)
4502 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
4504 return LoadMenuIndirectW( template );
4508 /**********************************************************************
4511 BOOL WINAPI
IsMenu(HMENU hmenu
)
4513 LPPOPUPMENU menu
= MENU_GetMenu(hmenu
);
4517 SetLastError(ERROR_INVALID_MENU_HANDLE
);
4523 /**********************************************************************
4524 * GetMenuItemInfo_common
4527 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
, BOOL bypos
,
4528 LPMENUITEMINFOW lpmii
, BOOL unicode
)
4530 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
4532 debug_print_menuitem("GetMenuItemInfo_common: ", menu
, "");
4535 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
4539 if( lpmii
->fMask
& MIIM_TYPE
) {
4540 if( lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
)) {
4541 WARN("invalid combination of fMask bits used\n");
4542 /* this does not happen on Win9x/ME */
4543 SetLastError( ERROR_INVALID_PARAMETER
);
4546 lpmii
->fType
= menu
->fType
& MENUITEMINFO_TYPE_MASK
;
4547 if( menu
->hbmpItem
) lpmii
->fType
|= MFT_BITMAP
;
4548 lpmii
->hbmpItem
= menu
->hbmpItem
; /* not on Win9x/ME */
4549 if( lpmii
->fType
& MFT_BITMAP
) {
4550 lpmii
->dwTypeData
= (LPWSTR
) menu
->hbmpItem
;
4552 } else if( lpmii
->fType
& (MFT_OWNERDRAW
| MFT_SEPARATOR
)) {
4553 /* this does not happen on Win9x/ME */
4554 lpmii
->dwTypeData
= 0;
4559 /* copy the text string */
4560 if ((lpmii
->fMask
& (MIIM_TYPE
|MIIM_STRING
))) {
4562 if(lpmii
->dwTypeData
&& lpmii
->cch
) {
4565 *((WCHAR
*)lpmii
->dwTypeData
) = 0;
4567 *((CHAR
*)lpmii
->dwTypeData
) = 0;
4573 len
= strlenW(menu
->text
);
4574 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4575 lstrcpynW(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4579 len
= WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1, NULL
,
4580 0, NULL
, NULL
) - 1;
4581 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4582 if (!WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1,
4583 (LPSTR
)lpmii
->dwTypeData
, lpmii
->cch
, NULL
, NULL
))
4584 ((LPSTR
)lpmii
->dwTypeData
)[lpmii
->cch
- 1] = 0;
4586 /* if we've copied a substring we return its length */
4587 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4588 if (lpmii
->cch
<= len
+ 1)
4593 /* return length of string */
4594 /* not on Win9x/ME if fType & MFT_BITMAP */
4600 if (lpmii
->fMask
& MIIM_FTYPE
)
4601 lpmii
->fType
= menu
->fType
& MENUITEMINFO_TYPE_MASK
;
4603 if (lpmii
->fMask
& MIIM_BITMAP
)
4604 lpmii
->hbmpItem
= menu
->hbmpItem
;
4606 if (lpmii
->fMask
& MIIM_STATE
)
4607 lpmii
->fState
= menu
->fState
& MENUITEMINFO_STATE_MASK
;
4609 if (lpmii
->fMask
& MIIM_ID
)
4610 lpmii
->wID
= menu
->wID
;
4612 if (lpmii
->fMask
& MIIM_SUBMENU
)
4613 lpmii
->hSubMenu
= menu
->hSubMenu
;
4615 /* hSubMenu is always cleared
4616 * (not on Win9x/ME ) */
4617 lpmii
->hSubMenu
= 0;
4620 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4621 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4622 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4624 if (lpmii
->fMask
& MIIM_DATA
)
4625 lpmii
->dwItemData
= menu
->dwItemData
;
4630 /**********************************************************************
4631 * GetMenuItemInfoA (USER32.@)
4633 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4634 LPMENUITEMINFOA lpmii
)
4638 if( lpmii
->cbSize
!= sizeof( mii
) &&
4639 lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
)) {
4640 SetLastError( ERROR_INVALID_PARAMETER
);
4643 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
4644 mii
.cbSize
= sizeof( mii
);
4645 ret
= GetMenuItemInfo_common (hmenu
, item
, bypos
,
4646 (LPMENUITEMINFOW
)&mii
, FALSE
);
4647 mii
.cbSize
= lpmii
->cbSize
;
4648 memcpy( lpmii
, &mii
, mii
.cbSize
);
4652 /**********************************************************************
4653 * GetMenuItemInfoW (USER32.@)
4655 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4656 LPMENUITEMINFOW lpmii
)
4660 if( lpmii
->cbSize
!= sizeof( mii
) &&
4661 lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
)) {
4662 SetLastError( ERROR_INVALID_PARAMETER
);
4665 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
4666 mii
.cbSize
= sizeof( mii
);
4667 ret
= GetMenuItemInfo_common (hmenu
, item
, bypos
, &mii
, TRUE
);
4668 mii
.cbSize
= lpmii
->cbSize
;
4669 memcpy( lpmii
, &mii
, mii
.cbSize
);
4674 /* set a menu item text from a ASCII or Unicode string */
4675 static inline void set_menu_item_text( MENUITEM
*menu
, LPCWSTR text
, BOOL unicode
)
4681 if ((menu
->text
= HeapAlloc( GetProcessHeap(), 0, (strlenW(text
)+1) * sizeof(WCHAR
) )))
4682 strcpyW( menu
->text
, text
);
4686 LPCSTR str
= (LPCSTR
)text
;
4687 int len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
4688 if ((menu
->text
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
4689 MultiByteToWideChar( CP_ACP
, 0, str
, -1, menu
->text
, len
);
4694 /**********************************************************************
4697 * detect if there are loops in the menu tree (or the depth is too large)
4699 static int MENU_depth( POPUPMENU
*pmenu
, int depth
)
4706 if( depth
> MAXMENUDEPTH
) return depth
;
4707 item
= pmenu
->items
;
4709 for( i
= 0; i
< pmenu
->nItems
&& subdepth
<= MAXMENUDEPTH
; i
++, item
++){
4710 POPUPMENU
*psubmenu
= item
->hSubMenu
? MENU_GetMenu( item
->hSubMenu
) : NULL
;
4712 int bdepth
= MENU_depth( psubmenu
, depth
);
4713 if( bdepth
> subdepth
) subdepth
= bdepth
;
4715 if( subdepth
> MAXMENUDEPTH
)
4716 TRACE("<- hmenu %p\n", item
->hSubMenu
);
4722 /**********************************************************************
4723 * SetMenuItemInfo_common
4725 * Note: does not support the MIIM_TYPE flag. Use the MIIM_FTYPE,
4726 * MIIM_BITMAP and MIIM_STRING flags instead.
4729 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4730 const MENUITEMINFOW
*lpmii
,
4733 if (!menu
) return FALSE
;
4735 debug_print_menuitem("SetMenuItemInfo_common from: ", menu
, "");
4737 if (lpmii
->fMask
& MIIM_FTYPE
) {
4738 menu
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
4739 menu
->fType
|= lpmii
->fType
& MENUITEMINFO_TYPE_MASK
;
4741 if (lpmii
->fMask
& MIIM_STRING
) {
4742 /* free the string when used */
4743 HeapFree(GetProcessHeap(), 0, menu
->text
);
4744 set_menu_item_text( menu
, lpmii
->dwTypeData
, unicode
);
4747 if (lpmii
->fMask
& MIIM_STATE
)
4748 /* Other menu items having MFS_DEFAULT are not converted
4750 menu
->fState
= lpmii
->fState
& MENUITEMINFO_STATE_MASK
;
4752 if (lpmii
->fMask
& MIIM_ID
)
4753 menu
->wID
= lpmii
->wID
;
4755 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4756 menu
->hSubMenu
= lpmii
->hSubMenu
;
4757 if (menu
->hSubMenu
) {
4758 POPUPMENU
*subMenu
= MENU_GetMenu(menu
->hSubMenu
);
4760 if( MENU_depth( subMenu
, 0) > MAXMENUDEPTH
) {
4761 ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
4765 subMenu
->wFlags
|= MF_POPUP
;
4766 menu
->fType
|= MF_POPUP
;
4768 SetLastError( ERROR_INVALID_PARAMETER
);
4773 menu
->fType
&= ~MF_POPUP
;
4776 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4778 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4779 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4781 if (lpmii
->fMask
& MIIM_DATA
)
4782 menu
->dwItemData
= lpmii
->dwItemData
;
4784 if (lpmii
->fMask
& MIIM_BITMAP
)
4785 menu
->hbmpItem
= lpmii
->hbmpItem
;
4787 if( !menu
->text
&& !(menu
->fType
& MFT_OWNERDRAW
) && !menu
->hbmpItem
)
4788 menu
->fType
|= MFT_SEPARATOR
;
4790 debug_print_menuitem("SetMenuItemInfo_common to : ", menu
, "");
4794 /**********************************************************************
4795 * MENU_NormalizeMenuItemInfoStruct
4797 * Helper for SetMenuItemInfo and InsertMenuItemInfo:
4798 * check, copy and extend the MENUITEMINFO struct from the version that the application
4799 * supplied to the version used by wine source. */
4800 static BOOL
MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW
*pmii_in
,
4801 MENUITEMINFOW
*pmii_out
)
4803 /* do we recognize the size? */
4804 if( pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) &&
4805 pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) - sizeof( pmii_in
->hbmpItem
)) {
4806 SetLastError( ERROR_INVALID_PARAMETER
);
4809 /* copy the fields that we have */
4810 memcpy( pmii_out
, pmii_in
, pmii_in
->cbSize
);
4811 /* if the hbmpItem member is missing then extend */
4812 if( pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
)) {
4813 pmii_out
->cbSize
= sizeof( MENUITEMINFOW
);
4814 pmii_out
->hbmpItem
= NULL
;
4816 /* test for invalid bit combinations */
4817 if( (pmii_out
->fMask
& MIIM_TYPE
&&
4818 pmii_out
->fMask
& (MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
)) ||
4819 (pmii_out
->fMask
& MIIM_FTYPE
&& pmii_out
->fType
& MFT_BITMAP
)) {
4820 WARN("invalid combination of fMask bits used\n");
4821 /* this does not happen on Win9x/ME */
4822 SetLastError( ERROR_INVALID_PARAMETER
);
4825 /* convert old style (MIIM_TYPE) to the new */
4826 if( pmii_out
->fMask
& MIIM_TYPE
){
4827 pmii_out
->fMask
|= MIIM_FTYPE
;
4828 if( IS_STRING_ITEM(pmii_out
->fType
)){
4829 pmii_out
->fMask
|= MIIM_STRING
;
4830 } else if( (pmii_out
->fType
) & MFT_BITMAP
){
4831 pmii_out
->fMask
|= MIIM_BITMAP
;
4832 pmii_out
->hbmpItem
= UlongToHandle(LOWORD(pmii_out
->dwTypeData
));
4838 /**********************************************************************
4839 * SetMenuItemInfoA (USER32.@)
4841 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4842 const MENUITEMINFOA
*lpmii
)
4846 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu
, item
, bypos
, lpmii
);
4848 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
4850 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4854 /**********************************************************************
4855 * SetMenuItemInfoW (USER32.@)
4857 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4858 const MENUITEMINFOW
*lpmii
)
4862 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu
, item
, bypos
, lpmii
);
4864 if (!MENU_NormalizeMenuItemInfoStruct( lpmii
, &mii
)) return FALSE
;
4865 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
,
4866 &item
, bypos
? MF_BYPOSITION
: 0), &mii
, TRUE
);
4869 /**********************************************************************
4870 * SetMenuDefaultItem (USER32.@)
4873 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT uItem
, UINT bypos
)
4879 TRACE("(%p,%d,%d)\n", hmenu
, uItem
, bypos
);
4881 if (!(menu
= MENU_GetMenu(hmenu
))) return FALSE
;
4883 /* reset all default-item flags */
4885 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4887 item
->fState
&= ~MFS_DEFAULT
;
4890 /* no default item */
4899 if ( uItem
>= menu
->nItems
) return FALSE
;
4900 item
[uItem
].fState
|= MFS_DEFAULT
;
4905 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4907 if (item
->wID
== uItem
)
4909 item
->fState
|= MFS_DEFAULT
;
4918 /**********************************************************************
4919 * GetMenuDefaultItem (USER32.@)
4921 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4927 TRACE("(%p,%d,%d)\n", hmenu
, bypos
, flags
);
4929 if (!(menu
= MENU_GetMenu(hmenu
))) return -1;
4931 /* find default item */
4935 if (! item
) return -1;
4937 while ( !( item
->fState
& MFS_DEFAULT
) )
4940 if (i
>= menu
->nItems
) return -1;
4943 /* default: don't return disabled items */
4944 if ( (!(GMDI_USEDISABLED
& flags
)) && (item
->fState
& MFS_DISABLED
)) return -1;
4946 /* search rekursiv when needed */
4947 if ( (item
->fType
& MF_POPUP
) && (flags
& GMDI_GOINTOPOPUPS
) )
4950 ret
= GetMenuDefaultItem( item
->hSubMenu
, bypos
, flags
);
4951 if ( -1 != ret
) return ret
;
4953 /* when item not found in submenu, return the popup item */
4955 return ( bypos
) ? i
: item
->wID
;
4960 /**********************************************************************
4961 * InsertMenuItemA (USER32.@)
4963 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4964 const MENUITEMINFOA
*lpmii
)
4969 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, bypos
, lpmii
);
4971 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
4973 item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4974 return SetMenuItemInfo_common(item
, &mii
, FALSE
);
4978 /**********************************************************************
4979 * InsertMenuItemW (USER32.@)
4981 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4982 const MENUITEMINFOW
*lpmii
)
4987 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, bypos
, lpmii
);
4989 if (!MENU_NormalizeMenuItemInfoStruct( lpmii
, &mii
)) return FALSE
;
4991 item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4992 return SetMenuItemInfo_common(item
, &mii
, TRUE
);
4995 /**********************************************************************
4996 * CheckMenuRadioItem (USER32.@)
4999 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
5000 UINT first
, UINT last
, UINT check
,
5005 MENUITEM
*mi_first
= NULL
, *mi_check
;
5006 HMENU m_first
, m_check
;
5008 for (i
= first
; i
<= last
; i
++)
5015 mi_first
= MENU_FindItem(&m_first
, &pos
, bypos
);
5016 if (!mi_first
) continue;
5017 mi_check
= mi_first
;
5023 mi_check
= MENU_FindItem(&m_check
, &pos
, bypos
);
5024 if (!mi_check
) continue;
5027 if (m_first
!= m_check
) continue;
5028 if (mi_check
->fType
== MFT_SEPARATOR
) continue;
5032 mi_check
->fType
|= MFT_RADIOCHECK
;
5033 mi_check
->fState
|= MFS_CHECKED
;
5038 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
5039 mi_check
->fState
&= ~MFS_CHECKED
;
5047 /**********************************************************************
5048 * GetMenuItemRect (USER32.@)
5050 * ATTENTION: Here, the returned values in rect are the screen
5051 * coordinates of the item just like if the menu was
5052 * always on the upper left side of the application.
5055 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
5058 POPUPMENU
*itemMenu
;
5062 TRACE("(%p,%p,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
5064 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
5065 referenceHwnd
= hwnd
;
5069 itemMenu
= MENU_GetMenu(hMenu
);
5070 if (itemMenu
== NULL
)
5073 if(itemMenu
->hWnd
== 0)
5075 referenceHwnd
= itemMenu
->hWnd
;
5078 if ((rect
== NULL
) || (item
== NULL
))
5083 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
5088 /**********************************************************************
5089 * SetMenuInfo (USER32.@)
5092 * actually use the items to draw the menu
5093 * (recalculate and/or redraw)
5095 static BOOL
menu_SetMenuInfo( HMENU hMenu
, LPCMENUINFO lpmi
)
5098 if( !(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
5100 if (lpmi
->fMask
& MIM_BACKGROUND
)
5101 menu
->hbrBack
= lpmi
->hbrBack
;
5103 if (lpmi
->fMask
& MIM_HELPID
)
5104 menu
->dwContextHelpID
= lpmi
->dwContextHelpID
;
5106 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
5107 menu
->cyMax
= lpmi
->cyMax
;
5109 if (lpmi
->fMask
& MIM_MENUDATA
)
5110 menu
->dwMenuData
= lpmi
->dwMenuData
;
5112 if (lpmi
->fMask
& MIM_STYLE
)
5113 menu
->dwStyle
= lpmi
->dwStyle
;
5115 if( lpmi
->fMask
& MIM_APPLYTOSUBMENUS
) {
5117 MENUITEM
*item
= menu
->items
;
5118 for( i
= menu
->nItems
; i
; i
--, item
++)
5119 if( item
->fType
& MF_POPUP
)
5120 menu_SetMenuInfo( item
->hSubMenu
, lpmi
);
5125 BOOL WINAPI
SetMenuInfo (HMENU hMenu
, LPCMENUINFO lpmi
)
5127 TRACE("(%p %p)\n", hMenu
, lpmi
);
5128 if( lpmi
&& (lpmi
->cbSize
== sizeof( MENUINFO
)) && (menu_SetMenuInfo( hMenu
, lpmi
))) {
5129 if( lpmi
->fMask
& MIM_STYLE
) {
5130 if (lpmi
->dwStyle
& MNS_AUTODISMISS
) FIXME("MNS_AUTODISMISS unimplemented\n");
5131 if (lpmi
->dwStyle
& MNS_DRAGDROP
) FIXME("MNS_DRAGDROP unimplemented\n");
5132 if (lpmi
->dwStyle
& MNS_MODELESS
) FIXME("MNS_MODELESS unimplemented\n");
5136 SetLastError( ERROR_INVALID_PARAMETER
);
5140 /**********************************************************************
5141 * GetMenuInfo (USER32.@)
5147 BOOL WINAPI
GetMenuInfo (HMENU hMenu
, LPMENUINFO lpmi
)
5150 TRACE("(%p %p)\n", hMenu
, lpmi
);
5152 if (lpmi
&& (lpmi
->cbSize
== sizeof( MENUINFO
)) && (menu
= MENU_GetMenu(hMenu
)))
5155 if (lpmi
->fMask
& MIM_BACKGROUND
)
5156 lpmi
->hbrBack
= menu
->hbrBack
;
5158 if (lpmi
->fMask
& MIM_HELPID
)
5159 lpmi
->dwContextHelpID
= menu
->dwContextHelpID
;
5161 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
5162 lpmi
->cyMax
= menu
->cyMax
;
5164 if (lpmi
->fMask
& MIM_MENUDATA
)
5165 lpmi
->dwMenuData
= menu
->dwMenuData
;
5167 if (lpmi
->fMask
& MIM_STYLE
)
5168 lpmi
->dwStyle
= menu
->dwStyle
;
5172 SetLastError( ERROR_INVALID_PARAMETER
);
5177 /**********************************************************************
5178 * SetMenuContextHelpId (USER32.@)
5180 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpID
)
5184 TRACE("(%p 0x%08x)\n", hMenu
, dwContextHelpID
);
5186 if ((menu
= MENU_GetMenu(hMenu
)))
5188 menu
->dwContextHelpID
= dwContextHelpID
;
5195 /**********************************************************************
5196 * GetMenuContextHelpId (USER32.@)
5198 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
5202 TRACE("(%p)\n", hMenu
);
5204 if ((menu
= MENU_GetMenu(hMenu
)))
5206 return menu
->dwContextHelpID
;
5211 /**********************************************************************
5212 * MenuItemFromPoint (USER32.@)
5214 INT WINAPI
MenuItemFromPoint(HWND hWnd
, HMENU hMenu
, POINT ptScreen
)
5216 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
5219 /*FIXME: Do we have to handle hWnd here? */
5220 if (!menu
) return -1;
5221 if (!MENU_FindItemByCoords(menu
, ptScreen
, &pos
)) return -1;
5226 /**********************************************************************
5227 * translate_accelerator
5229 static BOOL
translate_accelerator( HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
,
5230 BYTE fVirt
, WORD key
, WORD cmd
)
5235 if (wParam
!= key
) return FALSE
;
5237 if (GetKeyState(VK_CONTROL
) & 0x8000) mask
|= FCONTROL
;
5238 if (GetKeyState(VK_MENU
) & 0x8000) mask
|= FALT
;
5239 if (GetKeyState(VK_SHIFT
) & 0x8000) mask
|= FSHIFT
;
5241 if (message
== WM_CHAR
|| message
== WM_SYSCHAR
)
5243 if ( !(fVirt
& FVIRTKEY
) && (mask
& FALT
) == (fVirt
& FALT
) )
5245 TRACE_(accel
)("found accel for WM_CHAR: ('%c')\n", LOWORD(wParam
) & 0xff);
5251 if(fVirt
& FVIRTKEY
)
5253 TRACE_(accel
)("found accel for virt_key %04lx (scan %04x)\n",
5254 wParam
, 0xff & HIWORD(lParam
));
5256 if(mask
== (fVirt
& (FSHIFT
| FCONTROL
| FALT
))) goto found
;
5257 TRACE_(accel
)(", but incorrect SHIFT/CTRL/ALT-state\n");
5261 if (!(lParam
& 0x01000000)) /* no special_key */
5263 if ((fVirt
& FALT
) && (lParam
& 0x20000000))
5264 { /* ^^ ALT pressed */
5265 TRACE_(accel
)("found accel for Alt-%c\n", LOWORD(wParam
) & 0xff);
5274 if (message
== WM_KEYUP
|| message
== WM_SYSKEYUP
)
5278 HMENU hMenu
, hSubMenu
, hSysMenu
;
5279 UINT uSysStat
= (UINT
)-1, uStat
= (UINT
)-1, nPos
;
5281 hMenu
= (GetWindowLongW( hWnd
, GWL_STYLE
) & WS_CHILD
) ? 0 : GetMenu(hWnd
);
5282 hSysMenu
= get_win_sys_menu( hWnd
);
5284 /* find menu item and ask application to initialize it */
5285 /* 1. in the system menu */
5286 hSubMenu
= hSysMenu
;
5288 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
5292 if (!IsWindowEnabled(hWnd
))
5296 SendMessageW(hWnd
, WM_INITMENU
, (WPARAM
)hSysMenu
, 0L);
5297 if(hSubMenu
!= hSysMenu
)
5299 nPos
= MENU_FindSubMenu(&hSysMenu
, hSubMenu
);
5300 TRACE_(accel
)("hSysMenu = %p, hSubMenu = %p, nPos = %d\n", hSysMenu
, hSubMenu
, nPos
);
5301 SendMessageW(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, TRUE
));
5303 uSysStat
= GetMenuState(GetSubMenu(hSysMenu
, 0), cmd
, MF_BYCOMMAND
);
5306 else /* 2. in the window's menu */
5310 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
5314 if (!IsWindowEnabled(hWnd
))
5318 SendMessageW(hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0L);
5319 if(hSubMenu
!= hMenu
)
5321 nPos
= MENU_FindSubMenu(&hMenu
, hSubMenu
);
5322 TRACE_(accel
)("hMenu = %p, hSubMenu = %p, nPos = %d\n", hMenu
, hSubMenu
, nPos
);
5323 SendMessageW(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, FALSE
));
5325 uStat
= GetMenuState(hMenu
, cmd
, MF_BYCOMMAND
);
5332 if (uSysStat
!= (UINT
)-1)
5334 if (uSysStat
& (MF_DISABLED
|MF_GRAYED
))
5341 if (uStat
!= (UINT
)-1)
5347 if (uStat
& (MF_DISABLED
|MF_GRAYED
))
5359 if( mesg
==WM_COMMAND
)
5361 TRACE_(accel
)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd
);
5362 SendMessageW(hWnd
, mesg
, 0x10000 | cmd
, 0L);
5364 else if( mesg
==WM_SYSCOMMAND
)
5366 TRACE_(accel
)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd
);
5367 SendMessageW(hWnd
, mesg
, cmd
, 0x00010000L
);
5371 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
5372 * #0: unknown (please report!)
5373 * #1: for WM_KEYUP,WM_SYSKEYUP
5374 * #2: mouse is captured
5375 * #3: window is disabled
5376 * #4: it's a disabled system menu option
5377 * #5: it's a menu option, but window is iconic
5378 * #6: it's a menu option, but disabled
5380 TRACE_(accel
)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg
);
5382 ERR_(accel
)(" unknown reason - please report!\n");
5387 /**********************************************************************
5388 * TranslateAcceleratorA (USER32.@)
5389 * TranslateAccelerator (USER32.@)
5391 INT WINAPI
TranslateAcceleratorA( HWND hWnd
, HACCEL hAccel
, LPMSG msg
)
5393 switch (msg
->message
)
5397 return TranslateAcceleratorW( hWnd
, hAccel
, msg
);
5403 char ch
= LOWORD(msg
->wParam
);
5405 MultiByteToWideChar(CP_ACP
, 0, &ch
, 1, &wch
, 1);
5406 msgW
.wParam
= MAKEWPARAM(wch
, HIWORD(msg
->wParam
));
5407 return TranslateAcceleratorW( hWnd
, hAccel
, &msgW
);
5415 /**********************************************************************
5416 * TranslateAcceleratorW (USER32.@)
5418 INT WINAPI
TranslateAcceleratorW( HWND hWnd
, HACCEL hAccel
, LPMSG msg
)
5420 ACCEL data
[32], *ptr
= data
;
5423 if (!hWnd
) return 0;
5425 if (msg
->message
!= WM_KEYDOWN
&&
5426 msg
->message
!= WM_SYSKEYDOWN
&&
5427 msg
->message
!= WM_CHAR
&&
5428 msg
->message
!= WM_SYSCHAR
)
5431 TRACE_(accel
)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08lx, lParam %08lx\n",
5432 hAccel
,hWnd
,msg
->hwnd
,msg
->message
,msg
->wParam
,msg
->lParam
);
5434 if (!(count
= CopyAcceleratorTableW( hAccel
, NULL
, 0 ))) return 0;
5435 if (count
> sizeof(data
)/sizeof(data
[0]))
5437 if (!(ptr
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*ptr
) ))) return 0;
5439 count
= CopyAcceleratorTableW( hAccel
, ptr
, count
);
5440 for (i
= 0; i
< count
; i
++)
5442 if (translate_accelerator( hWnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
5443 ptr
[i
].fVirt
, ptr
[i
].key
, ptr
[i
].cmd
))
5446 if (ptr
!= data
) HeapFree( GetProcessHeap(), 0, ptr
);