4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
7 * Copyright 2005 Maxime Bellengé
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * Note: the style MF_MOUSESELECT is used to mark popup items that
26 * have been selected, i.e. their popup menu is currently displayed.
27 * This is probably not the meaning this style has in MS-Windows.
39 #include "wine/port.h"
48 #include "wine/winbase16.h"
49 #include "wine/winuser16.h"
51 #include "wine/server.h"
52 #include "wine/unicode.h"
55 #include "user_private.h"
56 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(menu
);
59 WINE_DECLARE_DEBUG_CHANNEL(accel
);
61 /* internal popup menu window messages */
63 #define MM_SETMENUHANDLE (WM_USER + 0)
64 #define MM_GETMENUHANDLE (WM_USER + 1)
66 /* Menu item structure */
68 /* ----------- MENUITEMINFO Stuff ----------- */
69 UINT fType
; /* Item type. */
70 UINT fState
; /* Item state. */
71 UINT_PTR wID
; /* Item id. */
72 HMENU hSubMenu
; /* Pop-up menu. */
73 HBITMAP hCheckBit
; /* Bitmap when checked. */
74 HBITMAP hUnCheckBit
; /* Bitmap when unchecked. */
75 LPWSTR text
; /* Item text or bitmap handle. */
76 DWORD dwItemData
; /* Application defined. */
77 DWORD dwTypeData
; /* depends on fMask */
78 HBITMAP hbmpItem
; /* bitmap in win98 style menus */
79 /* ----------- Wine stuff ----------- */
80 RECT rect
; /* Item area (relative to menu window) */
81 UINT xTab
; /* X position of text after Tab */
84 /* Popup menu structure */
86 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
87 WORD wMagic
; /* Magic number */
88 WORD Width
; /* Width of the whole menu */
89 WORD Height
; /* Height of the whole menu */
90 UINT nItems
; /* Number of items in the menu */
91 HWND hWnd
; /* Window containing the menu */
92 MENUITEM
*items
; /* Array of menu items */
93 UINT FocusedItem
; /* Currently focused item */
94 HWND hwndOwner
; /* window receiving the messages for ownerdraw */
95 BOOL bTimeToHide
; /* Request hiding when receiving a second click in the top-level menu item */
96 /* ------------ MENUINFO members ------ */
97 DWORD dwStyle
; /* Extended mennu style */
98 UINT cyMax
; /* max hight of the whole menu, 0 is screen hight */
99 HBRUSH hbrBack
; /* brush for menu background */
100 DWORD dwContextHelpID
;
101 DWORD dwMenuData
; /* application defined value */
102 HMENU hSysMenuOwner
; /* Handle to the dummy sys menu holder */
103 SIZE maxBmpSize
; /* Maximum size of the bitmap items in MIIM_BITMAP state */
104 } POPUPMENU
, *LPPOPUPMENU
;
106 /* internal flags for menu tracking */
108 #define TF_ENDMENU 0x0001
109 #define TF_SUSPENDPOPUP 0x0002
110 #define TF_SKIPREMOVE 0x0004
115 HMENU hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
116 HMENU hTopMenu
; /* initial menu */
117 HWND hOwnerWnd
; /* where notifications are sent */
121 #define MENU_MAGIC 0x554d /* 'MU' */
126 /* Internal MENU_TrackMenu() flags */
127 #define TPM_INTERNAL 0xF0000000
128 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
129 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
130 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
132 /* popup menu shade thickness */
133 #define POPUP_XSHADE 4
134 #define POPUP_YSHADE 4
136 /* Space between 2 menu bar items */
137 #define MENU_BAR_ITEMS_SPACE 12
139 /* Minimum width of a tab character */
140 #define MENU_TAB_SPACE 8
142 /* Height of a separator item */
143 #define SEPARATOR_HEIGHT 5
145 /* Space between 2 columns */
146 #define MENU_COL_SPACE 4
148 /* (other menu->FocusedItem values give the position of the focused item) */
149 #define NO_SELECTED_ITEM 0xffff
151 #define MENU_ITEM_TYPE(flags) \
152 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
154 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
155 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
156 #define IS_MAGIC_ITEM(text) (LOWORD((int)text)<12)
158 #define IS_SYSTEM_MENU(menu) \
159 (!((menu)->wFlags & MF_POPUP) && ((menu)->wFlags & MF_SYSMENU))
161 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
162 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
163 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
164 MF_POPUP | MF_SYSMENU | MF_HELP)
165 #define STATE_MASK (~TYPE_MASK)
167 #define WIN_ALLOWED_MENU(style) ((style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
169 /* Dimension of the menu bitmaps */
170 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
172 static HBITMAP hStdMnArrow
= 0;
173 static HBITMAP hBmpSysMenu
= 0;
175 static HBRUSH hShadeBrush
= 0;
176 static HFONT hMenuFont
= 0;
177 static HFONT hMenuFontBold
= 0;
178 static SIZE menucharsize
;
179 static UINT ODitemheight
; /* default owner drawn item height */
181 static HMENU MENU_DefSysPopup
= 0; /* Default system menu popup */
183 /* Use global popup window because there's no way 2 menus can
184 * be tracked at the same time. */
185 static HWND top_popup
;
187 /* Flag set by EndMenu() to force an exit from menu tracking */
188 static BOOL fEndMenu
= FALSE
;
190 static LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
192 DWORD WINAPI
DrawMenuBarTemp(HWND hwnd
, HDC hDC
, LPRECT lprect
, HMENU hMenu
, HFONT hFont
);
194 /*********************************************************************
195 * menu class descriptor
197 const struct builtin_class_descr MENU_builtin_class
=
199 POPUPMENU_CLASS_ATOMA
, /* name */
200 CS_DROPSHADOW
| CS_SAVEBITS
| CS_DBLCLKS
, /* style */
201 NULL
, /* procA (winproc is Unicode only) */
202 PopupMenuWndProc
, /* procW */
203 sizeof(HMENU
), /* extra */
204 IDC_ARROW
, /* cursor */
205 (HBRUSH
)(COLOR_MENU
+1) /* brush */
209 /***********************************************************************
210 * debug_print_menuitem
212 * Print a menuitem in readable form.
215 #define debug_print_menuitem(pre, mp, post) \
216 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
218 #define MENUOUT(text) \
219 DPRINTF("%s%s", (count++ ? "," : ""), (text))
221 #define MENUFLAG(bit,text) \
223 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
226 static void do_debug_print_menuitem(const char *prefix
, MENUITEM
* mp
,
229 TRACE("%s ", prefix
);
231 UINT flags
= mp
->fType
;
232 int type
= MENU_ITEM_TYPE(flags
);
233 DPRINTF( "{ ID=0x%x", mp
->wID
);
234 if (flags
& MF_POPUP
)
235 DPRINTF( ", Sub=%p", mp
->hSubMenu
);
239 if (type
== MFT_STRING
)
241 else if (type
== MFT_SEPARATOR
)
243 else if (type
== MFT_OWNERDRAW
)
245 else if (type
== MFT_BITMAP
)
251 MENUFLAG(MF_POPUP
, "pop");
252 MENUFLAG(MFT_MENUBARBREAK
, "barbrk");
253 MENUFLAG(MFT_MENUBREAK
, "brk");
254 MENUFLAG(MFT_RADIOCHECK
, "radio");
255 MENUFLAG(MFT_RIGHTORDER
, "rorder");
256 MENUFLAG(MF_SYSMENU
, "sys");
257 MENUFLAG(MFT_RIGHTJUSTIFY
, "right"); /* same as MF_HELP */
260 DPRINTF( "+0x%x", flags
);
265 DPRINTF( ", State=");
266 MENUFLAG(MFS_GRAYED
, "grey");
267 MENUFLAG(MFS_DEFAULT
, "default");
268 MENUFLAG(MFS_DISABLED
, "dis");
269 MENUFLAG(MFS_CHECKED
, "check");
270 MENUFLAG(MFS_HILITE
, "hi");
271 MENUFLAG(MF_USECHECKBITMAPS
, "usebit");
272 MENUFLAG(MF_MOUSESELECT
, "mouse");
274 DPRINTF( "+0x%x", flags
);
277 DPRINTF( ", Chk=%p", mp
->hCheckBit
);
279 DPRINTF( ", Unc=%p", mp
->hUnCheckBit
);
281 if (type
== MFT_STRING
) {
283 DPRINTF( ", Text=%s", debugstr_w(mp
->text
));
285 DPRINTF( ", Text=Null");
286 } else if (mp
->text
== NULL
)
289 DPRINTF( ", Text=%p", mp
->text
);
291 DPRINTF( ", ItemData=0x%08lx", mp
->dwItemData
);
297 DPRINTF(" %s\n", postfix
);
304 /***********************************************************************
307 * Validate the given menu handle and returns the menu structure pointer.
309 static POPUPMENU
*MENU_GetMenu(HMENU hMenu
)
311 POPUPMENU
*menu
= USER_HEAP_LIN_ADDR(hMenu
);
312 if (!menu
|| menu
->wMagic
!= MENU_MAGIC
)
314 WARN("invalid menu handle=%p, ptr=%p, magic=%x\n", hMenu
, menu
, menu
? menu
->wMagic
:0);
320 /***********************************************************************
323 * Get the system menu of a window
325 static HMENU
get_win_sys_menu( HWND hwnd
)
328 WND
*win
= WIN_GetPtr( hwnd
);
329 if (win
&& win
!= WND_OTHER_PROCESS
&& win
!= WND_DESKTOP
)
332 WIN_ReleasePtr( win
);
337 /***********************************************************************
340 * Return the default system menu.
342 static HMENU
MENU_CopySysPopup(void)
344 static const WCHAR sysmenuW
[] = {'S','Y','S','M','E','N','U',0};
345 HMENU hMenu
= LoadMenuW(user32_module
, sysmenuW
);
348 POPUPMENU
* menu
= MENU_GetMenu(hMenu
);
349 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
350 SetMenuDefaultItem(hMenu
, SC_CLOSE
, FALSE
);
353 ERR("Unable to load default system menu\n" );
355 TRACE("returning %p.\n", hMenu
);
361 /**********************************************************************
364 * Create a copy of the system menu. System menu in Windows is
365 * a special menu bar with the single entry - system menu popup.
366 * This popup is presented to the outside world as a "system menu".
367 * However, the real system menu handle is sometimes seen in the
368 * WM_MENUSELECT parameters (and Word 6 likes it this way).
370 HMENU
MENU_GetSysMenu( HWND hWnd
, HMENU hPopupMenu
)
374 TRACE("loading system menu, hWnd %p, hPopupMenu %p\n", hWnd
, hPopupMenu
);
375 if ((hMenu
= CreateMenu()))
377 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
378 menu
->wFlags
= MF_SYSMENU
;
379 menu
->hWnd
= WIN_GetFullHandle( hWnd
);
380 TRACE("hWnd %p (hMenu %p)\n", menu
->hWnd
, hMenu
);
382 if (hPopupMenu
== (HMENU
)(-1))
383 hPopupMenu
= MENU_CopySysPopup();
384 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
388 if (GetClassLongW(hWnd
, GCL_STYLE
) & CS_NOCLOSE
)
389 DeleteMenu(hPopupMenu
, SC_CLOSE
, MF_BYCOMMAND
);
391 InsertMenuW( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
,
392 (UINT_PTR
)hPopupMenu
, NULL
);
394 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
395 menu
->items
[0].fState
= 0;
396 if ((menu
= MENU_GetMenu(hPopupMenu
))) menu
->wFlags
|= MF_SYSMENU
;
398 TRACE("hMenu=%p (hPopup %p)\n", hMenu
, hPopupMenu
);
401 DestroyMenu( hMenu
);
403 ERR("failed to load system menu!\n");
408 /***********************************************************************
411 * Menus initialisation.
416 NONCLIENTMETRICSW ncm
;
418 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
423 /* Load menu bitmaps */
424 hStdMnArrow
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW
));
425 /* Load system buttons bitmaps */
426 hBmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
431 GetObjectW( hStdMnArrow
, sizeof(bm
), &bm
);
432 arrow_bitmap_width
= bm
.bmWidth
;
433 arrow_bitmap_height
= bm
.bmHeight
;
437 if (! (hBitmap
= CreateBitmap( 8, 8, 1, 1, shade_bits
)))
440 if(!(hShadeBrush
= CreatePatternBrush( hBitmap
)))
443 DeleteObject( hBitmap
);
444 if (!(MENU_DefSysPopup
= MENU_CopySysPopup()))
447 ncm
.cbSize
= sizeof(NONCLIENTMETRICSW
);
448 if (!(SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICSW
), &ncm
, 0)))
451 if (!(hMenuFont
= CreateFontIndirectW( &ncm
.lfMenuFont
)))
454 ncm
.lfMenuFont
.lfWeight
+= 300;
455 if ( ncm
.lfMenuFont
.lfWeight
> 1000)
456 ncm
.lfMenuFont
.lfWeight
= 1000;
458 if (!(hMenuFontBold
= CreateFontIndirectW( &ncm
.lfMenuFont
)))
464 /***********************************************************************
465 * MENU_InitSysMenuPopup
467 * Grey the appropriate items in System menu.
469 static void MENU_InitSysMenuPopup( HMENU hmenu
, DWORD style
, DWORD clsStyle
)
473 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
474 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
475 gray
= ((style
& WS_MAXIMIZE
) != 0);
476 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
477 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
478 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
479 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
480 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
481 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
482 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
483 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
485 /* The menu item must keep its state if it's disabled */
487 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
491 /******************************************************************************
493 * UINT MENU_GetStartOfNextColumn(
496 *****************************************************************************/
498 static UINT
MENU_GetStartOfNextColumn(
501 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
505 return NO_SELECTED_ITEM
;
507 i
= menu
->FocusedItem
+ 1;
508 if( i
== NO_SELECTED_ITEM
)
511 for( ; i
< menu
->nItems
; ++i
) {
512 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
516 return NO_SELECTED_ITEM
;
520 /******************************************************************************
522 * UINT MENU_GetStartOfPrevColumn(
525 *****************************************************************************/
527 static UINT
MENU_GetStartOfPrevColumn(
530 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
534 return NO_SELECTED_ITEM
;
536 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
537 return NO_SELECTED_ITEM
;
539 /* Find the start of the column */
541 for(i
= menu
->FocusedItem
; i
!= 0 &&
542 !(menu
->items
[i
].fType
& MF_MENUBARBREAK
);
546 return NO_SELECTED_ITEM
;
548 for(--i
; i
!= 0; --i
) {
549 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
553 TRACE("ret %d.\n", i
);
560 /***********************************************************************
563 * Find a menu item. Return a pointer on the item, and modifies *hmenu
564 * in case the item was in a sub-menu.
566 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
571 if ((*hmenu
== (HMENU
)0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
572 if (wFlags
& MF_BYPOSITION
)
574 if (*nPos
>= menu
->nItems
) return NULL
;
575 return &menu
->items
[*nPos
];
579 MENUITEM
*item
= menu
->items
;
580 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
582 if (item
->wID
== *nPos
)
587 else if (item
->fType
& MF_POPUP
)
589 HMENU hsubmenu
= item
->hSubMenu
;
590 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
602 /***********************************************************************
605 * Find a Sub menu. Return the position of the submenu, and modifies
606 * *hmenu in case it is found in another sub-menu.
607 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
609 UINT
MENU_FindSubMenu( HMENU
*hmenu
, HMENU hSubTarget
)
614 if (((*hmenu
)==(HMENU
)0xffff) ||
615 (!(menu
= MENU_GetMenu(*hmenu
))))
616 return NO_SELECTED_ITEM
;
618 for (i
= 0; i
< menu
->nItems
; i
++, item
++) {
619 if(!(item
->fType
& MF_POPUP
)) continue;
620 if (item
->hSubMenu
== hSubTarget
) {
624 HMENU hsubmenu
= item
->hSubMenu
;
625 UINT pos
= MENU_FindSubMenu( &hsubmenu
, hSubTarget
);
626 if (pos
!= NO_SELECTED_ITEM
) {
632 return NO_SELECTED_ITEM
;
635 /***********************************************************************
638 static void MENU_FreeItemData( MENUITEM
* item
)
641 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
642 HeapFree( GetProcessHeap(), 0, item
->text
);
645 /***********************************************************************
646 * MENU_FindItemByCoords
648 * Find the item at the specified coordinates (screen coords). Does
649 * not work for child windows and therefore should not be called for
650 * an arbitrary system menu.
652 static MENUITEM
*MENU_FindItemByCoords( const POPUPMENU
*menu
,
653 POINT pt
, UINT
*pos
)
659 if (!GetWindowRect(menu
->hWnd
,&wrect
)) return NULL
;
660 pt
.x
-= wrect
.left
;pt
.y
-= wrect
.top
;
662 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
664 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
665 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
675 /***********************************************************************
678 * Find the menu item selected by a key press.
679 * Return item id, -1 if none, -2 if we should close the menu.
681 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
,
682 WCHAR key
, BOOL forceMenuChar
)
684 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)key
, key
, hmenu
);
686 if (!IsMenu( hmenu
)) hmenu
= GetSubMenu( get_win_sys_menu(hwndOwner
), 0);
690 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
691 MENUITEM
*item
= menu
->items
;
698 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
700 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
702 WCHAR
*p
= item
->text
- 2;
705 p
= strchrW (p
+ 2, '&');
707 while (p
!= NULL
&& p
[1] == '&');
708 if (p
&& (toupperW(p
[1]) == toupperW(key
))) return i
;
712 menuchar
= SendMessageW( hwndOwner
, WM_MENUCHAR
,
713 MAKEWPARAM( key
, menu
->wFlags
), (LPARAM
)hmenu
);
714 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
715 if (HIWORD(menuchar
) == 1) return (UINT
)(-2);
721 /***********************************************************************
722 * MENU_GetBitmapItemSize
724 * Get the size of a bitmap item.
726 static void MENU_GetBitmapItemSize( UINT id
, DWORD data
, SIZE
*size
)
729 HBITMAP bmp
= (HBITMAP
)id
;
731 size
->cx
= size
->cy
= 0;
733 /* check if there is a magic menu item associated with this item */
734 if (id
&& IS_MAGIC_ITEM( id
))
738 case (INT_PTR
)HBMMENU_SYSTEM
:
745 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
746 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
747 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
748 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
749 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
750 size
->cx
= GetSystemMetrics( SM_CYMENU
) - 4;
753 case (INT_PTR
)HBMMENU_CALLBACK
:
754 case (INT_PTR
)HBMMENU_POPUP_CLOSE
:
755 case (INT_PTR
)HBMMENU_POPUP_RESTORE
:
756 case (INT_PTR
)HBMMENU_POPUP_MAXIMIZE
:
757 case (INT_PTR
)HBMMENU_POPUP_MINIMIZE
:
759 FIXME("Magic 0x%08x not implemented\n", id
);
763 if (GetObjectW(bmp
, sizeof(bm
), &bm
))
765 size
->cx
= bm
.bmWidth
;
766 size
->cy
= bm
.bmHeight
;
770 /***********************************************************************
771 * MENU_DrawBitmapItem
773 * Draw a bitmap item.
774 * drawhbmbitmap : True to draw the hbmbitmap(MIIM_BITMAP)/False to draw the MF_BITMAP
776 static void MENU_DrawBitmapItem( HDC hdc
, MENUITEM
*lpitem
, const RECT
*rect
, BOOL menuBar
, BOOL drawhbmbitmap
)
781 HBITMAP bmp
= (HBITMAP
)lpitem
->text
;
782 int w
= rect
->right
- rect
->left
;
783 int h
= rect
->bottom
- rect
->top
;
786 HBITMAP hbmToDraw
= (drawhbmbitmap
)?lpitem
->hbmpItem
:(HBITMAP
)lpitem
->text
;
788 /* Check if there is a magic menu item associated with this item */
789 if (hbmToDraw
&& IS_MAGIC_ITEM(hbmToDraw
))
794 switch(LOWORD(hbmToDraw
))
796 case (INT_PTR
)HBMMENU_SYSTEM
:
797 if (lpitem
->dwItemData
)
799 bmp
= (HBITMAP
)lpitem
->dwItemData
;
800 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
805 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
806 /* only use right half of the bitmap */
807 bmp_xoffset
= bm
.bmWidth
/ 2;
808 bm
.bmWidth
-= bmp_xoffset
;
811 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
812 flags
= DFCS_CAPTIONRESTORE
;
814 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
815 flags
= DFCS_CAPTIONMIN
;
817 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
818 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
820 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
821 flags
= DFCS_CAPTIONCLOSE
;
823 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
824 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
826 case (INT_PTR
)HBMMENU_CALLBACK
:
827 case (INT_PTR
)HBMMENU_POPUP_CLOSE
:
828 case (INT_PTR
)HBMMENU_POPUP_RESTORE
:
829 case (INT_PTR
)HBMMENU_POPUP_MAXIMIZE
:
830 case (INT_PTR
)HBMMENU_POPUP_MINIMIZE
:
832 FIXME("Magic 0x%08x not implemented\n", LOWORD(hbmToDraw
));
836 InflateRect( &r
, -1, -1 );
837 if (lpitem
->fState
& MF_HILITE
) flags
|= DFCS_PUSHED
;
838 DrawFrameControl( hdc
, &r
, DFC_CAPTION
, flags
);
842 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
845 hdcMem
= CreateCompatibleDC( hdc
);
846 SelectObject( hdcMem
, bmp
);
848 /* handle fontsize > bitmap_height */
849 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
851 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_ITEM(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
852 if ((lpitem
->fState
& MF_HILITE
) && IS_BITMAP_ITEM(lpitem
->fType
))
853 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
854 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
859 /***********************************************************************
862 * Calculate the size of the menu item and store it in lpitem->rect.
864 static void MENU_CalcItemSize( HDC hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
865 INT orgX
, INT orgY
, BOOL menuBar
, POPUPMENU
* lppop
)
868 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
870 TRACE("dc=%p owner=%p (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
871 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem
,
872 (menuBar
? " (MenuBar)" : ""));
874 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
876 if (lpitem
->fType
& MF_OWNERDRAW
)
878 MEASUREITEMSTRUCT mis
;
879 /* not done in Menu_Init: GetDialogBaseUnits() breaks there */
880 if( !menucharsize
.cx
) {
881 DIALOG_GetCharSize( hdc
, hMenuFont
, &menucharsize
);
882 /* Win95/98/ME will use menucharsize.cy here. Testing is possible
883 * but it is unlikely an application will depend on that */
884 ODitemheight
= HIWORD( GetDialogBaseUnits());
886 mis
.CtlType
= ODT_MENU
;
888 mis
.itemID
= lpitem
->wID
;
889 mis
.itemData
= (DWORD
)lpitem
->dwItemData
;
890 mis
.itemHeight
= ODitemheight
;
892 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
893 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
894 * width of a menufont character to the width of an owner-drawn menu.
896 lpitem
->rect
.right
+= mis
.itemWidth
+ 2 * menucharsize
.cx
;
898 /* under at least win95 you seem to be given a standard
899 height for the menu and the height value is ignored */
900 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
902 lpitem
->rect
.bottom
+= mis
.itemHeight
;
904 TRACE("id=%04x size=%ldx%ld\n",
905 lpitem
->wID
, lpitem
->rect
.right
-lpitem
->rect
.left
,
906 lpitem
->rect
.bottom
-lpitem
->rect
.top
);
910 if (lpitem
->fType
& MF_SEPARATOR
)
912 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
918 /* New style MIIM_BITMAP */
919 if (lpitem
->hbmpItem
)
921 if (lpitem
->hbmpItem
== HBMMENU_CALLBACK
)
923 MEASUREITEMSTRUCT measItem
;
924 measItem
.CtlType
= ODT_MENU
;
926 measItem
.itemID
= lpitem
->wID
;
927 measItem
.itemWidth
= lpitem
->rect
.right
- lpitem
->rect
.left
;
928 measItem
.itemHeight
= lpitem
->rect
.bottom
- lpitem
->rect
.top
;
929 measItem
.itemData
= lpitem
->dwItemData
;
931 SendMessageW( hwndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
933 /* Keep the size of the bitmap in callback mode to be able to draw it correctly */
934 lppop
->maxBmpSize
.cx
= max(lppop
->maxBmpSize
.cx
, measItem
.itemWidth
- (lpitem
->rect
.right
- lpitem
->rect
.left
));
935 lppop
->maxBmpSize
.cy
= max(lppop
->maxBmpSize
.cy
, measItem
.itemHeight
- (lpitem
->rect
.bottom
- lpitem
->rect
.top
));
936 lpitem
->rect
.right
= lpitem
->rect
.left
+ measItem
.itemWidth
;
939 MENU_GetBitmapItemSize((UINT
)lpitem
->hbmpItem
, lpitem
->dwItemData
, &size
);
940 lppop
->maxBmpSize
.cx
= max(lppop
->maxBmpSize
.cx
, size
.cx
);
941 lppop
->maxBmpSize
.cy
= max(lppop
->maxBmpSize
.cy
, size
.cy
);
942 lpitem
->rect
.right
+= size
.cx
;
943 lpitem
->rect
.bottom
+= size
.cy
;
945 if (lppop
->dwStyle
& MNS_CHECKORBMP
)
946 lpitem
->rect
.right
+= check_bitmap_width
;
948 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
950 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
951 if (lpitem
->fType
& MF_POPUP
)
952 lpitem
->rect
.right
+= arrow_bitmap_width
;
955 if (IS_BITMAP_ITEM(lpitem
->fType
))
959 MENU_GetBitmapItemSize( (int)lpitem
->text
, lpitem
->dwItemData
, &size
);
960 lpitem
->rect
.right
+= size
.cx
;
961 lpitem
->rect
.bottom
+= size
.cy
;
962 /* Leave space for the sunken border */
963 lpitem
->rect
.right
+= 2;
964 lpitem
->rect
.bottom
+= 2;
968 /* it must be a text item - unless it's the system menu */
969 if (!(lpitem
->fType
& MF_SYSMENU
) && IS_STRING_ITEM( lpitem
->fType
))
972 GetTextExtentPoint32W(hdc
, lpitem
->text
, strlenW(lpitem
->text
), &size
);
974 lpitem
->rect
.right
+= size
.cx
;
975 lpitem
->rect
.bottom
+= max(max(size
.cy
, GetSystemMetrics(SM_CYMENU
)-1), lppop
->maxBmpSize
.cy
);
980 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
982 else if ((p
= strchrW( lpitem
->text
, '\t' )) != NULL
)
984 /* Item contains a tab (only meaningful in popup menus) */
985 GetTextExtentPoint32W(hdc
, lpitem
->text
, (int)(p
- lpitem
->text
) , &size
);
986 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+ size
.cx
;
987 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
991 if (strchrW( lpitem
->text
, '\b' ))
992 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
993 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
994 - arrow_bitmap_width
;
997 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->rect
.left
, lpitem
->rect
.top
, lpitem
->rect
.right
, lpitem
->rect
.bottom
);
1001 /***********************************************************************
1002 * MENU_PopupMenuCalcSize
1004 * Calculate the size of a popup menu.
1006 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
1011 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
1013 lppop
->Width
= lppop
->Height
= 0;
1014 if (lppop
->nItems
== 0) return;
1017 SelectObject( hdc
, hMenuFont
);
1022 lppop
->maxBmpSize
.cx
= 0;
1023 lppop
->maxBmpSize
.cy
= 0;
1025 while (start
< lppop
->nItems
)
1027 lpitem
= &lppop
->items
[start
];
1029 if( lpitem
->fType
& MF_MENUBREAK
)
1030 orgX
+= MENU_COL_SPACE
;
1033 maxTab
= maxTabWidth
= 0;
1034 /* Parse items until column break or end of menu */
1035 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
1038 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1040 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
, lppop
);
1042 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
1043 maxX
= max( maxX
, lpitem
->rect
.right
);
1044 orgY
= lpitem
->rect
.bottom
;
1045 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
1047 maxTab
= max( maxTab
, lpitem
->xTab
);
1048 maxTabWidth
= max(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
1052 /* Finish the column (set all items to the largest width found) */
1053 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
1054 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
1056 lpitem
->rect
.right
= maxX
;
1057 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
1058 lpitem
->xTab
= maxTab
;
1061 lppop
->Height
= max( lppop
->Height
, orgY
);
1064 lppop
->Width
= maxX
;
1066 /* space for 3d border */
1070 ReleaseDC( 0, hdc
);
1074 /***********************************************************************
1075 * MENU_MenuBarCalcSize
1077 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1078 * height is off by 1 pixel which causes lengthy window relocations when
1079 * active document window is maximized/restored.
1081 * Calculate the size of the menu bar.
1083 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1084 LPPOPUPMENU lppop
, HWND hwndOwner
)
1087 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1089 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
1090 if (lppop
->nItems
== 0) return;
1091 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n",
1092 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
1093 lppop
->Width
= lprect
->right
- lprect
->left
;
1095 maxY
= lprect
->top
+1;
1098 lppop
->maxBmpSize
.cx
= 0;
1099 lppop
->maxBmpSize
.cy
= 0;
1100 while (start
< lppop
->nItems
)
1102 lpitem
= &lppop
->items
[start
];
1103 orgX
= lprect
->left
;
1106 /* Parse items until line break or end of menu */
1107 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
1109 if ((helpPos
== -1) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1111 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1113 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1115 debug_print_menuitem (" item: ", lpitem
, "");
1116 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
, lppop
);
1118 if (lpitem
->rect
.right
> lprect
->right
)
1120 if (i
!= start
) break;
1121 else lpitem
->rect
.right
= lprect
->right
;
1123 maxY
= max( maxY
, lpitem
->rect
.bottom
);
1124 orgX
= lpitem
->rect
.right
;
1127 /* Finish the line (set all items to the largest height found) */
1128 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
1131 lprect
->bottom
= maxY
;
1132 lppop
->Height
= lprect
->bottom
- lprect
->top
;
1134 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1135 /* the last item (if several lines, only move the last line) */
1136 lpitem
= &lppop
->items
[lppop
->nItems
-1];
1137 orgY
= lpitem
->rect
.top
;
1138 orgX
= lprect
->right
;
1139 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
1140 if ( (helpPos
==-1) || (helpPos
>i
) )
1142 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
1143 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
1144 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
1145 lpitem
->rect
.right
= orgX
;
1146 orgX
= lpitem
->rect
.left
;
1150 /***********************************************************************
1153 * Draw a single menu item.
1155 static void MENU_DrawMenuItem( HWND hwnd
, HMENU hmenu
, HWND hwndOwner
, HDC hdc
, MENUITEM
*lpitem
,
1156 UINT height
, BOOL menuBar
, UINT odaction
)
1160 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
1162 if (lpitem
->fType
& MF_SYSMENU
)
1164 if( !IsIconic(hwnd
) )
1165 NC_DrawSysButton( hwnd
, hdc
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
) );
1171 if (lpitem
->fState
& MF_HILITE
)
1174 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1175 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1177 if(lpitem
->fState
& MF_GRAYED
)
1178 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1180 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1181 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1186 if (lpitem
->fState
& MF_GRAYED
)
1187 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1189 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1190 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
1193 if (lpitem
->fType
& MF_OWNERDRAW
)
1196 ** Experimentation under Windows reveals that an owner-drawn
1197 ** menu is given the rectangle which includes the space it requested
1198 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1199 ** and a popup-menu arrow. This is the value of lpitem->rect.
1200 ** Windows will leave all drawing to the application except for
1201 ** the popup-menu arrow. Windows always draws that itself, after
1202 ** the menu owner has finished drawing.
1206 dis
.CtlType
= ODT_MENU
;
1208 dis
.itemID
= lpitem
->wID
;
1209 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1211 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1212 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
|ODS_DISABLED
;
1213 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1214 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1215 dis
.hwndItem
= (HWND
)hmenu
;
1217 dis
.rcItem
= lpitem
->rect
;
1218 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1219 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hwndOwner
,
1220 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1221 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1223 SendMessageW( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
1224 /* Fall through to draw popup-menu arrow */
1227 TRACE("rect={%ld,%ld,%ld,%ld}\n", lpitem
->rect
.left
, lpitem
->rect
.top
,
1228 lpitem
->rect
.right
,lpitem
->rect
.bottom
);
1230 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1232 rect
= lpitem
->rect
;
1234 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1236 if (lpitem
->fState
& MF_HILITE
)
1239 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1241 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1244 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_MENU
) );
1247 SetBkMode( hdc
, TRANSPARENT
);
1249 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1251 /* vertical separator */
1252 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1256 rc
.bottom
= height
- 3;
1257 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1260 /* horizontal separator */
1261 if (lpitem
->fType
& MF_SEPARATOR
)
1266 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1267 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1272 /* helper lines for debugging */
1273 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1274 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1275 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1276 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1282 INT y
= rect
.top
+ rect
.bottom
;
1283 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1284 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1286 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1288 /* New style MIIM_BITMAP */
1289 if (lpitem
->hbmpItem
)
1291 POPUPMENU
*menu
= MENU_GetMenu(hmenu
);
1292 HBITMAP hbm
= lpitem
->hbmpItem
;
1294 if (hbm
== HBMMENU_CALLBACK
)
1296 DRAWITEMSTRUCT drawItem
;
1297 drawItem
.CtlType
= ODT_MENU
;
1299 drawItem
.itemID
= lpitem
->wID
;
1300 drawItem
.itemAction
= odaction
;
1301 drawItem
.itemState
|= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1302 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1303 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1304 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1305 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1306 drawItem
.hwndItem
= (HWND
)hmenu
;
1308 drawItem
.rcItem
= lpitem
->rect
;
1309 drawItem
.itemData
= lpitem
->dwItemData
;
1311 if (!(lpitem
->fState
& MF_CHECKED
))
1312 SendMessageW( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1315 MENU_DrawBitmapItem(hdc
, lpitem
, &rect
, FALSE
, TRUE
);
1317 if (menu
->dwStyle
& MNS_CHECKORBMP
)
1318 rect
.left
+= menu
->maxBmpSize
.cx
- check_bitmap_width
;
1320 rect
.left
+= menu
->maxBmpSize
.cx
;
1322 /* Draw the check mark
1325 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1327 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hCheckBit
: lpitem
->hUnCheckBit
;
1328 if (bm
) /* we have a custom bitmap */
1330 HDC hdcMem
= CreateCompatibleDC( hdc
);
1331 SelectObject( hdcMem
, bm
);
1332 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1333 check_bitmap_width
, check_bitmap_height
,
1334 hdcMem
, 0, 0, SRCCOPY
);
1337 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1340 HBITMAP bm
= CreateBitmap( check_bitmap_width
, check_bitmap_height
, 1, 1, NULL
);
1341 HDC hdcMem
= CreateCompatibleDC( hdc
);
1342 SelectObject( hdcMem
, bm
);
1343 SetRect( &r
, 0, 0, check_bitmap_width
, check_bitmap_height
);
1344 DrawFrameControl( hdcMem
, &r
, DFC_MENU
,
1345 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1346 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1347 BitBlt( hdc
, rect
.left
, (y
- r
.bottom
) / 2, r
.right
, r
.bottom
,
1348 hdcMem
, 0, 0, SRCCOPY
);
1354 /* Draw the popup-menu arrow */
1355 if (lpitem
->fType
& MF_POPUP
)
1357 HDC hdcMem
= CreateCompatibleDC( hdc
);
1358 HBITMAP hOrigBitmap
;
1360 hOrigBitmap
= SelectObject( hdcMem
, hStdMnArrow
);
1361 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1362 (y
- arrow_bitmap_height
) / 2,
1363 arrow_bitmap_width
, arrow_bitmap_height
,
1364 hdcMem
, 0, 0, SRCCOPY
);
1365 SelectObject( hdcMem
, hOrigBitmap
);
1369 rect
.left
+= check_bitmap_width
;
1370 rect
.right
-= arrow_bitmap_width
;
1373 /* Done for owner-drawn */
1374 if (lpitem
->fType
& MF_OWNERDRAW
)
1377 /* Draw the item text or bitmap */
1378 if (IS_BITMAP_ITEM(lpitem
->fType
))
1380 MENU_DrawBitmapItem( hdc
, lpitem
, &rect
, menuBar
, FALSE
);
1383 /* No bitmap - process text if present */
1384 else if (IS_STRING_ITEM(lpitem
->fType
))
1389 UINT uFormat
= (menuBar
) ?
1390 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1391 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1393 if ( lpitem
->fState
& MFS_DEFAULT
)
1395 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1400 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1401 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1404 for (i
= 0; lpitem
->text
[i
]; i
++)
1405 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1408 if(lpitem
->fState
& MF_GRAYED
)
1410 if (!(lpitem
->fState
& MF_HILITE
) )
1412 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1413 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1414 DrawTextW( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1415 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1417 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1420 DrawTextW( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1422 /* paint the shortcut text */
1423 if (!menuBar
&& lpitem
->text
[i
]) /* There's a tab or flush-right char */
1425 if (lpitem
->text
[i
] == '\t')
1427 rect
.left
= lpitem
->xTab
;
1428 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1432 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1435 if(lpitem
->fState
& MF_GRAYED
)
1437 if (!(lpitem
->fState
& MF_HILITE
) )
1439 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1440 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1441 DrawTextW( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1442 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1444 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1446 DrawTextW( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1450 SelectObject (hdc
, hfontOld
);
1455 /***********************************************************************
1456 * MENU_DrawPopupMenu
1458 * Paint a popup menu.
1460 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
1462 HBRUSH hPrevBrush
= 0;
1465 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1467 GetClientRect( hwnd
, &rect
);
1469 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1470 && (SelectObject( hdc
, hMenuFont
)))
1474 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1476 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1481 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1483 /* draw menu items */
1485 menu
= MENU_GetMenu( hmenu
);
1486 if (menu
&& menu
->nItems
)
1491 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1492 MENU_DrawMenuItem( hwnd
, hmenu
, menu
->hwndOwner
, hdc
, item
,
1493 menu
->Height
, FALSE
, ODA_DRAWENTIRE
);
1498 SelectObject( hdc
, hPrevBrush
);
1503 /***********************************************************************
1506 * Paint a menu bar. Returns the height of the menu bar.
1507 * called from [windows/nonclient.c]
1509 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1514 HMENU hMenu
= GetMenu(hwnd
);
1516 lppop
= MENU_GetMenu( hMenu
);
1517 if (lppop
== NULL
|| lprect
== NULL
)
1519 return GetSystemMetrics(SM_CYMENU
);
1524 hfontOld
= SelectObject( hDC
, hMenuFont
);
1526 if (lppop
->Height
== 0)
1527 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1529 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1531 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1532 return lppop
->Height
;
1535 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1539 /***********************************************************************
1542 * Display a popup menu.
1544 static BOOL
MENU_ShowPopup( HWND hwndOwner
, HMENU hmenu
, UINT id
,
1545 INT x
, INT y
, INT xanchor
, INT yanchor
)
1550 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1551 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1553 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
1554 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1556 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1557 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1560 /* store the owner for DrawItem */
1561 menu
->hwndOwner
= hwndOwner
;
1563 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1565 /* adjust popup menu pos so that it fits within the desktop */
1567 width
= menu
->Width
+ GetSystemMetrics(SM_CXBORDER
);
1568 height
= menu
->Height
+ GetSystemMetrics(SM_CYBORDER
);
1570 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1573 x
-= width
- xanchor
;
1574 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1575 x
= GetSystemMetrics(SM_CXSCREEN
) - width
;
1579 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1582 y
-= height
+ yanchor
;
1583 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1584 y
= GetSystemMetrics(SM_CYSCREEN
) - height
;
1588 /* NOTE: In Windows, top menu popup is not owned. */
1589 menu
->hWnd
= CreateWindowExW( 0, POPUPMENU_CLASS_ATOMW
, NULL
,
1590 WS_POPUP
, x
, y
, width
, height
,
1591 hwndOwner
, 0, (HINSTANCE
)GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
1593 if( !menu
->hWnd
) return FALSE
;
1594 if (!top_popup
) top_popup
= menu
->hWnd
;
1596 /* Display the window */
1598 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1599 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1600 UpdateWindow( menu
->hWnd
);
1605 /***********************************************************************
1608 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
1609 BOOL sendMenuSelect
, HMENU topmenu
)
1614 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1616 lppop
= MENU_GetMenu( hmenu
);
1617 if ((!lppop
) || (!lppop
->nItems
) || (!lppop
->hWnd
)) return;
1619 if (lppop
->FocusedItem
== wIndex
) return;
1620 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
1621 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1622 if (!top_popup
) top_popup
= lppop
->hWnd
;
1624 SelectObject( hdc
, hMenuFont
);
1626 /* Clear previous highlighted item */
1627 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1629 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1630 MENU_DrawMenuItem(lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,&lppop
->items
[lppop
->FocusedItem
],
1631 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1635 /* Highlight new item (if any) */
1636 lppop
->FocusedItem
= wIndex
;
1637 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1639 if(!(lppop
->items
[wIndex
].fType
& MF_SEPARATOR
)) {
1640 lppop
->items
[wIndex
].fState
|= MF_HILITE
;
1641 MENU_DrawMenuItem( lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,
1642 &lppop
->items
[wIndex
], lppop
->Height
,
1643 !(lppop
->wFlags
& MF_POPUP
), ODA_SELECT
);
1647 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1648 SendMessageW( hwndOwner
, WM_MENUSELECT
,
1649 MAKELONG(ip
->fType
& MF_POPUP
? wIndex
: ip
->wID
,
1650 ip
->fType
| ip
->fState
|
1651 (lppop
->wFlags
& MF_SYSMENU
)), (LPARAM
)hmenu
);
1654 else if (sendMenuSelect
) {
1657 if((pos
=MENU_FindSubMenu(&topmenu
, hmenu
))!=NO_SELECTED_ITEM
){
1658 POPUPMENU
*ptm
= MENU_GetMenu( topmenu
);
1659 MENUITEM
*ip
= &ptm
->items
[pos
];
1660 SendMessageW( hwndOwner
, WM_MENUSELECT
, MAKELONG(pos
,
1661 ip
->fType
| ip
->fState
|
1662 (ptm
->wFlags
& MF_SYSMENU
)), (LPARAM
)topmenu
);
1666 ReleaseDC( lppop
->hWnd
, hdc
);
1670 /***********************************************************************
1671 * MENU_MoveSelection
1673 * Moves currently selected item according to the offset parameter.
1674 * If there is no selection then it should select the last item if
1675 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1677 static void MENU_MoveSelection( HWND hwndOwner
, HMENU hmenu
, INT offset
)
1682 TRACE("hwnd=%p hmenu=%p off=0x%04x\n", hwndOwner
, hmenu
, offset
);
1684 menu
= MENU_GetMenu( hmenu
);
1685 if ((!menu
) || (!menu
->items
)) return;
1687 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1689 if( menu
->nItems
== 1 ) return; else
1690 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1692 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1694 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1699 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1700 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1701 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1703 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1709 /**********************************************************************
1712 * Set an item's flags, id and text ptr. Called by InsertMenu() and
1715 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT_PTR id
,
1718 LPWSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1720 debug_print_menuitem("MENU_SetItemData from: ", item
, "");
1721 TRACE("flags=%x str=%p\n", flags
, str
);
1723 if (IS_STRING_ITEM(flags
))
1727 flags
|= MF_SEPARATOR
;
1733 /* Item beginning with a backspace is a help item */
1739 if (!(text
= HeapAlloc( GetProcessHeap(), 0, (strlenW(str
)+1) * sizeof(WCHAR
) )))
1741 strcpyW( text
, str
);
1745 else if (IS_BITMAP_ITEM(flags
))
1746 item
->text
= (LPWSTR
)HBITMAP_32(LOWORD(str
));
1747 else item
->text
= NULL
;
1749 if (flags
& MF_OWNERDRAW
)
1750 item
->dwItemData
= (DWORD
)str
;
1752 item
->dwItemData
= 0;
1754 if ((item
->fType
& MF_POPUP
) && (flags
& MF_POPUP
) && (item
->hSubMenu
!= (HMENU
)id
) )
1755 DestroyMenu( item
->hSubMenu
); /* ModifyMenu() spec */
1757 if (flags
& MF_POPUP
)
1759 POPUPMENU
*menu
= MENU_GetMenu((HMENU
)id
);
1760 if (menu
) menu
->wFlags
|= MF_POPUP
;
1772 if (flags
& MF_POPUP
) item
->hSubMenu
= (HMENU
)id
;
1774 if ((item
->fType
& MF_POPUP
) && !(flags
& MF_POPUP
) )
1775 flags
|= MF_POPUP
; /* keep popup */
1777 item
->fType
= flags
& TYPE_MASK
;
1778 item
->fState
= (flags
& STATE_MASK
) &
1779 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1782 /* Don't call SetRectEmpty here! */
1785 HeapFree( GetProcessHeap(), 0, prevText
);
1787 debug_print_menuitem("MENU_SetItemData to : ", item
, "");
1792 /**********************************************************************
1795 * Insert (allocate) a new item into a menu.
1797 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
1802 if (!(menu
= MENU_GetMenu(hMenu
)))
1805 /* Find where to insert new item */
1807 if (flags
& MF_BYPOSITION
) {
1808 if (pos
> menu
->nItems
)
1811 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1814 if (!(menu
= MENU_GetMenu( hMenu
)))
1819 /* Create new items array */
1821 newItems
= HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1824 WARN("allocation failed\n" );
1827 if (menu
->nItems
> 0)
1829 /* Copy the old array into the new one */
1830 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1831 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1832 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1833 HeapFree( GetProcessHeap(), 0, menu
->items
);
1835 menu
->items
= newItems
;
1837 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1838 menu
->Height
= 0; /* force size recalculate */
1839 return &newItems
[pos
];
1843 /**********************************************************************
1844 * MENU_ParseResource
1846 * Parse a standard menu resource and add items to the menu.
1847 * Return a pointer to the end of the resource.
1849 * NOTE: flags is equivalent to the mtOption field
1851 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1858 flags
= GET_WORD(res
);
1859 res
+= sizeof(WORD
);
1860 if (!(flags
& MF_POPUP
))
1863 res
+= sizeof(WORD
);
1866 if (!unicode
) res
+= strlen(str
) + 1;
1867 else res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1868 if (flags
& MF_POPUP
)
1870 HMENU hSubMenu
= CreatePopupMenu();
1871 if (!hSubMenu
) return NULL
;
1872 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1874 if (!unicode
) AppendMenuA( hMenu
, flags
, (UINT
)hSubMenu
, str
);
1875 else AppendMenuW( hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1877 else /* Not a popup */
1879 if (!unicode
) AppendMenuA( hMenu
, flags
, id
, *str
? str
: NULL
);
1880 else AppendMenuW( hMenu
, flags
, id
,
1881 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1883 } while (!(flags
& MF_END
));
1888 /**********************************************************************
1889 * MENUEX_ParseResource
1891 * Parse an extended menu resource and add items to the menu.
1892 * Return a pointer to the end of the resource.
1894 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1900 mii
.cbSize
= sizeof(mii
);
1901 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
1902 mii
.fType
= GET_DWORD(res
);
1903 res
+= sizeof(DWORD
);
1904 mii
.fState
= GET_DWORD(res
);
1905 res
+= sizeof(DWORD
);
1906 mii
.wID
= GET_DWORD(res
);
1907 res
+= sizeof(DWORD
);
1908 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
1909 res
+= sizeof(WORD
);
1910 /* Align the text on a word boundary. */
1911 res
+= (~((int)res
- 1)) & 1;
1912 mii
.dwTypeData
= (LPWSTR
) res
;
1913 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1914 /* Align the following fields on a dword boundary. */
1915 res
+= (~((int)res
- 1)) & 3;
1917 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1918 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, debugstr_w(mii
.dwTypeData
));
1920 if (resinfo
& 1) { /* Pop-up? */
1921 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1922 res
+= sizeof(DWORD
);
1923 mii
.hSubMenu
= CreatePopupMenu();
1926 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
1927 DestroyMenu(mii
.hSubMenu
);
1930 mii
.fMask
|= MIIM_SUBMENU
;
1931 mii
.fType
|= MF_POPUP
;
1933 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
1935 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
1936 mii
.wID
, mii
.fType
);
1937 mii
.fType
|= MF_SEPARATOR
;
1939 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1940 } while (!(resinfo
& MF_END
));
1945 /***********************************************************************
1948 * Return the handle of the selected sub-popup menu (if any).
1950 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
1955 menu
= MENU_GetMenu( hmenu
);
1957 if ((!menu
) || (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return 0;
1959 item
= &menu
->items
[menu
->FocusedItem
];
1960 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
1961 return item
->hSubMenu
;
1966 /***********************************************************************
1967 * MENU_HideSubPopups
1969 * Hide the sub-popup menus of this menu.
1971 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
1972 BOOL sendMenuSelect
)
1974 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
1976 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner
, hmenu
, sendMenuSelect
);
1978 if (menu
&& top_popup
)
1984 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1986 item
= &menu
->items
[menu
->FocusedItem
];
1987 if (!(item
->fType
& MF_POPUP
) ||
1988 !(item
->fState
& MF_MOUSESELECT
)) return;
1989 item
->fState
&= ~MF_MOUSESELECT
;
1990 hsubmenu
= item
->hSubMenu
;
1993 submenu
= MENU_GetMenu( hsubmenu
);
1994 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
1995 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
, 0 );
1996 DestroyWindow( submenu
->hWnd
);
2002 /***********************************************************************
2005 * Display the sub-menu of the selected item of this menu.
2006 * Return the handle of the submenu, or hmenu if no submenu to display.
2008 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
,
2009 BOOL selectFirst
, UINT wFlags
)
2016 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner
, hmenu
, selectFirst
);
2018 if (!(menu
= MENU_GetMenu( hmenu
))) return hmenu
;
2020 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return hmenu
;
2022 item
= &menu
->items
[menu
->FocusedItem
];
2023 if (!(item
->fType
& MF_POPUP
) || (item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2026 /* message must be sent before using item,
2027 because nearly everything may be changed by the application ! */
2029 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2030 if (!(wFlags
& TPM_NONOTIFY
))
2031 SendMessageW( hwndOwner
, WM_INITMENUPOPUP
, (WPARAM
)item
->hSubMenu
,
2032 MAKELONG( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
2034 item
= &menu
->items
[menu
->FocusedItem
];
2037 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2038 if (!(item
->fState
& MF_HILITE
))
2040 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC( menu
->hWnd
);
2041 else hdc
= GetDCEx( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2043 SelectObject( hdc
, hMenuFont
);
2045 item
->fState
|= MF_HILITE
;
2046 MENU_DrawMenuItem( menu
->hWnd
, hmenu
, hwndOwner
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
2047 ReleaseDC( menu
->hWnd
, hdc
);
2049 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
2052 item
->fState
|= MF_MOUSESELECT
;
2054 if (IS_SYSTEM_MENU(menu
))
2056 MENU_InitSysMenuPopup(item
->hSubMenu
,
2057 GetWindowLongW( menu
->hWnd
, GWL_STYLE
),
2058 GetClassLongW( menu
->hWnd
, GCL_STYLE
));
2060 NC_GetSysPopupPos( menu
->hWnd
, &rect
);
2061 rect
.top
= rect
.bottom
;
2062 rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2063 rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2067 GetWindowRect( menu
->hWnd
, &rect
);
2068 if (menu
->wFlags
& MF_POPUP
)
2070 rect
.left
+= item
->rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2071 rect
.top
+= item
->rect
.top
;
2072 rect
.right
= item
->rect
.left
- item
->rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2073 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
2077 rect
.left
+= item
->rect
.left
;
2078 rect
.top
+= item
->rect
.bottom
;
2079 rect
.right
= item
->rect
.right
- item
->rect
.left
;
2080 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
2084 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
2085 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2087 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
2088 return item
->hSubMenu
;
2093 /**********************************************************************
2096 HWND
MENU_IsMenuActive(void)
2101 /***********************************************************************
2104 * Walks menu chain trying to find a menu pt maps to.
2106 static HMENU
MENU_PtMenu( HMENU hMenu
, POINT pt
)
2108 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2109 UINT item
= menu
->FocusedItem
;
2112 /* try subpopup first (if any) */
2113 ret
= (item
!= NO_SELECTED_ITEM
&&
2114 (menu
->items
[item
].fType
& MF_POPUP
) &&
2115 (menu
->items
[item
].fState
& MF_MOUSESELECT
))
2116 ? MENU_PtMenu(menu
->items
[item
].hSubMenu
, pt
) : 0;
2118 if (!ret
) /* check the current window (avoiding WM_HITTEST) */
2120 INT ht
= NC_HandleNCHitTest( menu
->hWnd
, pt
);
2121 if( menu
->wFlags
& MF_POPUP
)
2123 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= hMenu
;
2125 else if (ht
== HTSYSMENU
)
2126 ret
= get_win_sys_menu( menu
->hWnd
);
2127 else if (ht
== HTMENU
)
2128 ret
= GetMenu( menu
->hWnd
);
2133 /***********************************************************************
2134 * MENU_ExecFocusedItem
2136 * Execute a menu item (for instance when user pressed Enter).
2137 * Return the wID of the executed item. Otherwise, -1 indicating
2138 * that no menu item was executed;
2139 * Have to receive the flags for the TrackPopupMenu options to avoid
2140 * sending unwanted message.
2143 static INT
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU hMenu
, UINT wFlags
)
2146 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2148 TRACE("%p hmenu=%p\n", pmt
, hMenu
);
2150 if (!menu
|| !menu
->nItems
||
2151 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return -1;
2153 item
= &menu
->items
[menu
->FocusedItem
];
2155 TRACE("%p %08x %p\n", hMenu
, item
->wID
, item
->hSubMenu
);
2157 if (!(item
->fType
& MF_POPUP
))
2159 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(item
->fType
& MF_SEPARATOR
))
2161 /* If TPM_RETURNCMD is set you return the id, but
2162 do not send a message to the owner */
2163 if(!(wFlags
& TPM_RETURNCMD
))
2165 if( menu
->wFlags
& MF_SYSMENU
)
2166 PostMessageW( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
2167 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
2169 PostMessageW( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
2175 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hMenu
, TRUE
, wFlags
);
2180 /***********************************************************************
2181 * MENU_SwitchTracking
2183 * Helper function for menu navigation routines.
2185 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU hPtMenu
, UINT id
)
2187 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2188 POPUPMENU
*topmenu
= MENU_GetMenu( pmt
->hTopMenu
);
2190 TRACE("%p hmenu=%p 0x%04x\n", pmt
, hPtMenu
, id
);
2192 if( pmt
->hTopMenu
!= hPtMenu
&&
2193 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
2195 /* both are top level menus (system and menu-bar) */
2196 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2197 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2198 pmt
->hTopMenu
= hPtMenu
;
2200 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2201 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
, 0 );
2205 /***********************************************************************
2208 * Return TRUE if we can go on with menu tracking.
2210 static BOOL
MENU_ButtonDown( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2212 TRACE("%p hPtMenu=%p\n", pmt
, hPtMenu
);
2217 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2220 if( IS_SYSTEM_MENU(ptmenu
) )
2221 item
= ptmenu
->items
;
2223 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2227 if( ptmenu
->FocusedItem
!= id
)
2228 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2230 /* If the popup menu is not already "popped" */
2231 if(!(item
->fState
& MF_MOUSESELECT
))
2233 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2238 /* Else the click was on the menu bar, finish the tracking */
2243 /***********************************************************************
2246 * Return the value of MENU_ExecFocusedItem if
2247 * the selected item was not a popup. Else open the popup.
2248 * A -1 return value indicates that we go on with menu tracking.
2251 static INT
MENU_ButtonUp( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2253 TRACE("%p hmenu=%p\n", pmt
, hPtMenu
);
2258 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2261 if( IS_SYSTEM_MENU(ptmenu
) )
2262 item
= ptmenu
->items
;
2264 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2266 if( item
&& (ptmenu
->FocusedItem
== id
))
2268 if( !(item
->fType
& MF_POPUP
) )
2269 return MENU_ExecFocusedItem( pmt
, hPtMenu
, wFlags
);
2271 /* If we are dealing with the top-level menu */
2272 /* and this is a click on an already "popped" item: */
2273 /* Stop the menu tracking and close the opened submenus */
2274 if((pmt
->hTopMenu
== hPtMenu
) && ptmenu
->bTimeToHide
)
2277 ptmenu
->bTimeToHide
= TRUE
;
2283 /***********************************************************************
2286 * Return TRUE if we can go on with menu tracking.
2288 static BOOL
MENU_MouseMove( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2290 UINT id
= NO_SELECTED_ITEM
;
2291 POPUPMENU
*ptmenu
= NULL
;
2295 ptmenu
= MENU_GetMenu( hPtMenu
);
2296 if( IS_SYSTEM_MENU(ptmenu
) )
2299 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2302 if( id
== NO_SELECTED_ITEM
)
2304 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2305 NO_SELECTED_ITEM
, TRUE
, pmt
->hTopMenu
);
2308 else if( ptmenu
->FocusedItem
!= id
)
2310 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2311 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2317 /***********************************************************************
2320 static void MENU_SetCapture( HWND hwnd
)
2324 SERVER_START_REQ( set_capture_window
)
2327 req
->flags
= CAPTURE_MENU
;
2328 if (!wine_server_call_err( req
))
2330 previous
= reply
->previous
;
2331 hwnd
= reply
->full_handle
;
2336 if (previous
&& previous
!= hwnd
)
2337 SendMessageW( previous
, WM_CAPTURECHANGED
, 0, (LPARAM
)hwnd
);
2341 /***********************************************************************
2344 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2346 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT vk
)
2348 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2350 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
2351 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
2353 MDINEXTMENU next_menu
;
2358 next_menu
.hmenuIn
= (IS_SYSTEM_MENU(menu
)) ? GetSubMenu(pmt
->hTopMenu
,0) : pmt
->hTopMenu
;
2359 next_menu
.hmenuNext
= 0;
2360 next_menu
.hwndNext
= 0;
2361 SendMessageW( pmt
->hOwnerWnd
, WM_NEXTMENU
, vk
, (LPARAM
)&next_menu
);
2363 TRACE("%p [%p] -> %p [%p]\n",
2364 pmt
->hCurrentMenu
, pmt
->hOwnerWnd
, next_menu
.hmenuNext
, next_menu
.hwndNext
);
2366 if (!next_menu
.hmenuNext
|| !next_menu
.hwndNext
)
2368 DWORD style
= GetWindowLongW( pmt
->hOwnerWnd
, GWL_STYLE
);
2369 hNewWnd
= pmt
->hOwnerWnd
;
2370 if( IS_SYSTEM_MENU(menu
) )
2372 /* switch to the menu bar */
2374 if(style
& WS_CHILD
|| !(hNewMenu
= GetMenu(hNewWnd
))) return FALSE
;
2378 menu
= MENU_GetMenu( hNewMenu
);
2379 id
= menu
->nItems
- 1;
2382 else if (style
& WS_SYSMENU
)
2384 /* switch to the system menu */
2385 hNewMenu
= get_win_sys_menu( hNewWnd
);
2389 else /* application returned a new menu to switch to */
2391 hNewMenu
= next_menu
.hmenuNext
;
2392 hNewWnd
= WIN_GetFullHandle( next_menu
.hwndNext
);
2394 if( IsMenu(hNewMenu
) && IsWindow(hNewWnd
) )
2396 DWORD style
= GetWindowLongW( hNewWnd
, GWL_STYLE
);
2398 if (style
& WS_SYSMENU
&&
2399 GetSubMenu(get_win_sys_menu(hNewWnd
), 0) == hNewMenu
)
2401 /* get the real system menu */
2402 hNewMenu
= get_win_sys_menu(hNewWnd
);
2404 else if (style
& WS_CHILD
|| GetMenu(hNewWnd
) != hNewMenu
)
2406 /* FIXME: Not sure what to do here;
2407 * perhaps try to track hNewMenu as a popup? */
2409 TRACE(" -- got confused.\n");
2416 if( hNewMenu
!= pmt
->hTopMenu
)
2418 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
,
2420 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2421 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2424 if( hNewWnd
!= pmt
->hOwnerWnd
)
2426 pmt
->hOwnerWnd
= hNewWnd
;
2427 MENU_SetCapture( pmt
->hOwnerWnd
);
2430 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2431 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
, 0 );
2438 /***********************************************************************
2441 * The idea is not to show the popup if the next input message is
2442 * going to hide it anyway.
2444 static BOOL
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2448 msg
.hwnd
= pmt
->hOwnerWnd
;
2450 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2451 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2456 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2457 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2459 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2460 PeekMessageW( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2461 if( msg
.message
== WM_KEYDOWN
&&
2462 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2464 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2471 /* failures go through this */
2472 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2476 /***********************************************************************
2479 * Handle a VK_ESCAPE key event in a menu.
2481 static BOOL
MENU_KeyEscape(MTRACKER
* pmt
, UINT wFlags
)
2483 BOOL bEndMenu
= TRUE
;
2485 if (pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2487 POPUPMENU
*menu
= MENU_GetMenu(pmt
->hCurrentMenu
);
2489 if (menu
->wFlags
& MF_POPUP
)
2491 HMENU hmenutmp
, hmenuprev
;
2493 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2495 /* close topmost popup */
2496 while (hmenutmp
!= pmt
->hCurrentMenu
)
2498 hmenuprev
= hmenutmp
;
2499 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2502 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2503 pmt
->hCurrentMenu
= hmenuprev
;
2511 /***********************************************************************
2514 * Handle a VK_LEFT key event in a menu.
2516 static void MENU_KeyLeft( MTRACKER
* pmt
, UINT wFlags
)
2519 HMENU hmenutmp
, hmenuprev
;
2522 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2523 menu
= MENU_GetMenu( hmenutmp
);
2525 /* Try to move 1 column left (if possible) */
2526 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2527 NO_SELECTED_ITEM
) {
2529 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2534 /* close topmost popup */
2535 while (hmenutmp
!= pmt
->hCurrentMenu
)
2537 hmenuprev
= hmenutmp
;
2538 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2541 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2542 pmt
->hCurrentMenu
= hmenuprev
;
2544 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2546 /* move menu bar selection if no more popups are left */
2548 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2549 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2551 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2553 /* A sublevel menu was displayed - display the next one
2554 * unless there is another displacement coming up */
2556 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2557 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2558 pmt
->hTopMenu
, TRUE
, wFlags
);
2564 /***********************************************************************
2567 * Handle a VK_RIGHT key event in a menu.
2569 static void MENU_KeyRight( MTRACKER
* pmt
, UINT wFlags
)
2572 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2575 TRACE("MENU_KeyRight called, cur %p (%s), top %p (%s).\n",
2577 debugstr_w((MENU_GetMenu(pmt
->hCurrentMenu
))->items
[0].text
),
2578 pmt
->hTopMenu
, debugstr_w(menu
->items
[0].text
) );
2580 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2582 /* If already displaying a popup, try to display sub-popup */
2584 hmenutmp
= pmt
->hCurrentMenu
;
2585 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hmenutmp
, TRUE
, wFlags
);
2587 /* if subpopup was displayed then we are done */
2588 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2591 /* Check to see if there's another column */
2592 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2593 NO_SELECTED_ITEM
) {
2594 TRACE("Going to %d.\n", nextcol
);
2595 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2600 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2602 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2604 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2605 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2606 } else hmenutmp
= 0;
2608 /* try to move to the next item */
2609 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2610 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2612 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2613 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2614 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2615 pmt
->hTopMenu
, TRUE
, wFlags
);
2619 /***********************************************************************
2622 * Menu tracking code.
2624 static BOOL
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
2625 HWND hwnd
, const RECT
*lprect
)
2630 INT executedMenuId
= -1;
2632 BOOL enterIdleSent
= FALSE
;
2635 mt
.hCurrentMenu
= hmenu
;
2636 mt
.hTopMenu
= hmenu
;
2637 mt
.hOwnerWnd
= WIN_GetFullHandle( hwnd
);
2641 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%p (%ld,%ld)-(%ld,%ld)\n",
2642 hmenu
, wFlags
, x
, y
, hwnd
, (lprect
) ? lprect
->left
: 0, (lprect
) ? lprect
->top
: 0,
2643 (lprect
) ? lprect
->right
: 0, (lprect
) ? lprect
->bottom
: 0);
2646 if (!(menu
= MENU_GetMenu( hmenu
)))
2648 WARN("Invalid menu handle %p\n", hmenu
);
2649 SetLastError(ERROR_INVALID_MENU_HANDLE
);
2653 if (wFlags
& TPM_BUTTONDOWN
)
2655 /* Get the result in order to start the tracking or not */
2656 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2657 fEndMenu
= !fRemove
;
2660 if (wFlags
& TF_ENDMENU
) fEndMenu
= TRUE
;
2662 MENU_SetCapture( mt
.hOwnerWnd
);
2666 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2667 if (!menu
) /* sometimes happens if I do a window manager close */
2670 /* we have to keep the message in the queue until it's
2671 * clear that menu loop is not over yet. */
2675 if (PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
))
2677 if (!CallMsgFilterW( &msg
, MSGF_MENU
)) break;
2678 /* remove the message from the queue */
2679 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2685 HWND win
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2686 enterIdleSent
= TRUE
;
2687 SendMessageW( mt
.hOwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
)win
);
2693 /* check if EndMenu() tried to cancel us, by posting this message */
2694 if(msg
.message
== WM_CANCELMODE
)
2696 /* we are now out of the loop */
2699 /* remove the message from the queue */
2700 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2702 /* break out of internal loop, ala ESCAPE */
2706 TranslateMessage( &msg
);
2709 if ( (msg
.hwnd
==menu
->hWnd
) || (msg
.message
!=WM_TIMER
) )
2710 enterIdleSent
=FALSE
;
2713 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2716 * Use the mouse coordinates in lParam instead of those in the MSG
2717 * struct to properly handle synthetic messages. They are already
2718 * in screen coordinates.
2720 mt
.pt
.x
= (short)LOWORD(msg
.lParam
);
2721 mt
.pt
.y
= (short)HIWORD(msg
.lParam
);
2723 /* Find a menu for this mouse event */
2724 hmenu
= MENU_PtMenu( mt
.hTopMenu
, mt
.pt
);
2728 /* no WM_NC... messages in captured state */
2730 case WM_RBUTTONDBLCLK
:
2731 case WM_RBUTTONDOWN
:
2732 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2734 case WM_LBUTTONDBLCLK
:
2735 case WM_LBUTTONDOWN
:
2736 /* If the message belongs to the menu, removes it from the queue */
2737 /* Else, end menu tracking */
2738 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2739 fEndMenu
= !fRemove
;
2743 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2746 /* Check if a menu was selected by the mouse */
2749 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
2751 /* End the loop if executedMenuId is an item ID */
2752 /* or if the job was done (executedMenuId = 0). */
2753 fEndMenu
= fRemove
= (executedMenuId
!= -1);
2755 /* No menu was selected by the mouse */
2756 /* if the function was called by TrackPopupMenu, continue
2757 with the menu tracking. If not, stop it */
2759 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
2764 /* the selected menu item must be changed every time */
2765 /* the mouse moves. */
2768 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
, wFlags
);
2770 } /* switch(msg.message) - mouse */
2772 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2774 fRemove
= TRUE
; /* Keyboard messages are always removed */
2787 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2788 NO_SELECTED_ITEM
, FALSE
, 0 );
2791 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2792 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2795 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2797 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2798 if (!(menu
->wFlags
& MF_POPUP
))
2799 mt
.hCurrentMenu
= MENU_ShowSubPopup(mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
, wFlags
);
2800 else /* otherwise try to move selection */
2801 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2805 MENU_KeyLeft( &mt
, wFlags
);
2809 MENU_KeyRight( &mt
, wFlags
);
2813 fEndMenu
= MENU_KeyEscape(&mt
, wFlags
);
2819 hi
.cbSize
= sizeof(HELPINFO
);
2820 hi
.iContextType
= HELPINFO_MENUITEM
;
2821 if (menu
->FocusedItem
== NO_SELECTED_ITEM
)
2824 hi
.iCtrlId
= menu
->items
[menu
->FocusedItem
].wID
;
2825 hi
.hItemHandle
= hmenu
;
2826 hi
.dwContextId
= menu
->dwContextHelpID
;
2827 hi
.MousePos
= msg
.pt
;
2828 SendMessageW(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
2835 break; /* WM_KEYDOWN */
2842 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
2844 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2845 fEndMenu
= (executedMenuId
!= -1);
2850 /* Hack to avoid control chars. */
2851 /* We will find a better way real soon... */
2852 if (msg
.wParam
< 32) break;
2854 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2855 LOWORD(msg
.wParam
), FALSE
);
2856 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
2857 else if (pos
== (UINT
)-1) MessageBeep(0);
2860 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
,
2862 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2863 fEndMenu
= (executedMenuId
!= -1);
2867 } /* switch(msg.message) - kbd */
2871 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2872 DispatchMessageW( &msg
);
2876 if (!fEndMenu
) fRemove
= TRUE
;
2878 /* finally remove message from the queue */
2880 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2881 PeekMessageW( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2882 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2885 MENU_SetCapture(0); /* release the capture */
2887 /* If dropdown is still painted and the close box is clicked on
2888 then the menu will be destroyed as part of the DispatchMessage above.
2889 This will then invalidate the menu handle in mt.hTopMenu. We should
2890 check for this first. */
2891 if( IsMenu( mt
.hTopMenu
) )
2893 menu
= MENU_GetMenu( mt
.hTopMenu
);
2895 if( IsWindow( mt
.hOwnerWnd
) )
2897 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2899 if (menu
&& (menu
->wFlags
& MF_POPUP
))
2901 DestroyWindow( menu
->hWnd
);
2904 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2905 SendMessageW( mt
.hOwnerWnd
, WM_MENUSELECT
, MAKELONG(0,0xffff), 0 );
2908 /* Reset the variable for hiding menu */
2909 if( menu
) menu
->bTimeToHide
= FALSE
;
2912 /* The return value is only used by TrackPopupMenu */
2913 if (!(wFlags
& TPM_RETURNCMD
)) return TRUE
;
2914 if (executedMenuId
== -1) executedMenuId
= 0;
2915 return executedMenuId
;
2918 /***********************************************************************
2921 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
2925 TRACE("hwnd=%p hmenu=%p\n", hWnd
, hMenu
);
2929 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2930 if (!(wFlags
& TPM_NONOTIFY
))
2931 SendMessageW( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
2933 SendMessageW( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
2935 if (!(wFlags
& TPM_NONOTIFY
))
2937 SendMessageW( hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0 );
2938 /* If an app changed/recreated menu bar entries in WM_INITMENU
2939 * menu sizes will be recalculated once the menu created/shown.
2943 /* This makes the menus of applications built with Delphi work.
2944 * It also enables menus to be displayed in more than one window,
2945 * but there are some bugs left that need to be fixed in this case.
2947 if ((menu
= MENU_GetMenu( hMenu
))) menu
->hWnd
= hWnd
;
2951 /***********************************************************************
2954 static BOOL
MENU_ExitTracking(HWND hWnd
)
2956 TRACE("hwnd=%p\n", hWnd
);
2958 SendMessageW( hWnd
, WM_EXITMENULOOP
, 0, 0 );
2964 /***********************************************************************
2965 * MENU_TrackMouseMenuBar
2967 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2969 void MENU_TrackMouseMenuBar( HWND hWnd
, INT ht
, POINT pt
)
2971 HMENU hMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( hWnd
) : GetMenu( hWnd
);
2972 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
2974 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
2978 MENU_InitTracking( hWnd
, hMenu
, FALSE
, wFlags
);
2979 MENU_TrackMenu( hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
2980 MENU_ExitTracking(hWnd
);
2985 /***********************************************************************
2986 * MENU_TrackKbdMenuBar
2988 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2990 void MENU_TrackKbdMenuBar( HWND hwnd
, UINT wParam
, WCHAR wChar
)
2992 UINT uItem
= NO_SELECTED_ITEM
;
2994 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
2996 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd
, wParam
, wChar
);
2998 /* find window that has a menu */
3000 while (!WIN_ALLOWED_MENU(GetWindowLongW( hwnd
, GWL_STYLE
)))
3001 if (!(hwnd
= GetAncestor( hwnd
, GA_PARENT
))) return;
3003 /* check if we have to track a system menu */
3005 hTrackMenu
= GetMenu( hwnd
);
3006 if (!hTrackMenu
|| IsIconic(hwnd
) || wChar
== ' ' )
3008 if (!(GetWindowLongW( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3009 hTrackMenu
= get_win_sys_menu( hwnd
);
3011 wParam
|= HTSYSMENU
; /* prevent item lookup */
3014 if (!IsMenu( hTrackMenu
)) return;
3016 MENU_InitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
3018 if( wChar
&& wChar
!= ' ' )
3020 uItem
= MENU_FindItemByKey( hwnd
, hTrackMenu
, wChar
, (wParam
& HTSYSMENU
) );
3021 if ( uItem
>= (UINT
)(-2) )
3023 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3024 /* schedule end of menu tracking */
3025 wFlags
|= TF_ENDMENU
;
3030 MENU_SelectItem( hwnd
, hTrackMenu
, uItem
, TRUE
, 0 );
3032 if (wParam
& HTSYSMENU
)
3034 /* prevent sysmenu activation for managed windows on Alt down/up */
3035 if (GetPropA( hwnd
, "__wine_x11_managed" ))
3036 wFlags
|= TF_ENDMENU
; /* schedule end of menu tracking */
3040 if( uItem
== NO_SELECTED_ITEM
)
3041 MENU_MoveSelection( hwnd
, hTrackMenu
, ITEM_NEXT
);
3043 PostMessageW( hwnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3047 MENU_TrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
3048 MENU_ExitTracking( hwnd
);
3052 /**********************************************************************
3053 * TrackPopupMenu (USER32.@)
3055 * Like the win32 API, the function return the command ID only if the
3056 * flag TPM_RETURNCMD is on.
3059 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3060 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
3064 MENU_InitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
3066 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3067 if (!(wFlags
& TPM_NONOTIFY
))
3068 SendMessageW( hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hMenu
, 0);
3070 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
3071 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
, lpRect
);
3072 MENU_ExitTracking(hWnd
);
3077 /**********************************************************************
3078 * TrackPopupMenuEx (USER32.@)
3080 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3081 HWND hWnd
, LPTPMPARAMS lpTpm
)
3083 FIXME("not fully implemented\n" );
3084 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, 0, hWnd
,
3085 lpTpm
? &lpTpm
->rcExclude
: NULL
);
3088 /***********************************************************************
3091 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3093 static LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
3095 TRACE("hwnd=%p msg=0x%04x wp=0x%04x lp=0x%08lx\n", hwnd
, message
, wParam
, lParam
);
3101 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lParam
;
3102 SetWindowLongW( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
3106 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
3107 return MA_NOACTIVATE
;
3112 BeginPaint( hwnd
, &ps
);
3113 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
3114 (HMENU
)GetWindowLongW( hwnd
, 0 ) );
3115 EndPaint( hwnd
, &ps
);
3122 /* zero out global pointer in case resident popup window was destroyed. */
3123 if (hwnd
== top_popup
) top_popup
= 0;
3130 if (!GetWindowLongW( hwnd
, 0 )) ERR("no menu to display\n");
3133 SetWindowLongW( hwnd
, 0, 0 );
3136 case MM_SETMENUHANDLE
:
3137 SetWindowLongW( hwnd
, 0, wParam
);
3140 case MM_GETMENUHANDLE
:
3141 return GetWindowLongW( hwnd
, 0 );
3144 return DefWindowProcW( hwnd
, message
, wParam
, lParam
);
3150 /***********************************************************************
3151 * MENU_GetMenuBarHeight
3153 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3155 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
3156 INT orgX
, INT orgY
)
3162 TRACE("HWND %p, width %d, at (%d, %d).\n", hwnd
, menubarWidth
, orgX
, orgY
);
3164 if (!(lppop
= MENU_GetMenu( GetMenu(hwnd
) ))) return 0;
3166 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3167 SelectObject( hdc
, hMenuFont
);
3168 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+GetSystemMetrics(SM_CYMENU
));
3169 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
3170 ReleaseDC( hwnd
, hdc
);
3171 return lppop
->Height
;
3175 /*******************************************************************
3176 * ChangeMenuA (USER32.@)
3178 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
3179 UINT id
, UINT flags
)
3181 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu
, pos
, data
, id
, flags
);
3182 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
3184 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3185 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
3187 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3188 flags
& MF_BYPOSITION
? pos
: id
,
3189 flags
& ~MF_REMOVE
);
3190 /* Default: MF_INSERT */
3191 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
3195 /*******************************************************************
3196 * ChangeMenuW (USER32.@)
3198 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
3199 UINT id
, UINT flags
)
3201 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu
, pos
, data
, id
, flags
);
3202 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
3204 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3205 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
3207 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3208 flags
& MF_BYPOSITION
? pos
: id
,
3209 flags
& ~MF_REMOVE
);
3210 /* Default: MF_INSERT */
3211 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
3215 /*******************************************************************
3216 * CheckMenuItem (USER32.@)
3218 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
3223 TRACE("menu=%p id=%04x flags=%04x\n", hMenu
, id
, flags
);
3224 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
3225 ret
= item
->fState
& MF_CHECKED
;
3226 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
3227 else item
->fState
&= ~MF_CHECKED
;
3232 /**********************************************************************
3233 * EnableMenuItem (USER32.@)
3235 UINT WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3241 TRACE("(%p, %04x, %04x) !\n", hMenu
, wItemID
, wFlags
);
3243 /* Get the Popupmenu to access the owner menu */
3244 if (!(menu
= MENU_GetMenu(hMenu
)))
3247 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3250 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3251 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3253 /* If the close item in the system menu change update the close button */
3254 if((item
->wID
== SC_CLOSE
) && (oldflags
!= wFlags
))
3256 if (menu
->hSysMenuOwner
!= 0)
3259 POPUPMENU
* parentMenu
;
3261 /* Get the parent menu to access*/
3262 if (!(parentMenu
= MENU_GetMenu(menu
->hSysMenuOwner
)))
3265 /* Refresh the frame to reflect the change */
3266 GetWindowRect(parentMenu
->hWnd
, &rc
);
3267 MapWindowPoints(0, parentMenu
->hWnd
, (POINT
*)&rc
, 2);
3269 RedrawWindow(parentMenu
->hWnd
, &rc
, 0, RDW_FRAME
| RDW_INVALIDATE
| RDW_NOCHILDREN
);
3277 /*******************************************************************
3278 * GetMenuStringA (USER32.@)
3280 INT WINAPI
GetMenuStringA(
3281 HMENU hMenu
, /* [in] menuhandle */
3282 UINT wItemID
, /* [in] menu item (dep. on wFlags) */
3283 LPSTR str
, /* [out] outbuffer. If NULL, func returns entry length*/
3284 INT nMaxSiz
, /* [in] length of buffer. if 0, func returns entry len*/
3285 UINT wFlags
/* [in] MF_ flags */
3289 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3290 if (str
&& nMaxSiz
) str
[0] = '\0';
3291 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3292 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3293 if (!str
|| !nMaxSiz
) return strlenW(item
->text
);
3294 if (!WideCharToMultiByte( CP_ACP
, 0, item
->text
, -1, str
, nMaxSiz
, NULL
, NULL
))
3296 TRACE("returning '%s'\n", str
);
3301 /*******************************************************************
3302 * GetMenuStringW (USER32.@)
3304 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3305 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3309 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3310 if (str
&& nMaxSiz
) str
[0] = '\0';
3311 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3312 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3313 if (!str
|| !nMaxSiz
) return strlenW(item
->text
);
3314 lstrcpynW( str
, item
->text
, nMaxSiz
);
3315 return strlenW(str
);
3319 /**********************************************************************
3320 * HiliteMenuItem (USER32.@)
3322 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3326 TRACE("(%p, %p, %04x, %04x);\n", hWnd
, hMenu
, wItemID
, wHilite
);
3327 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3328 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3329 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3330 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
3331 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
, 0 );
3336 /**********************************************************************
3337 * GetMenuState (USER32.@)
3339 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3342 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu
, wItemID
, wFlags
);
3343 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3344 debug_print_menuitem (" item: ", item
, "");
3345 if (item
->fType
& MF_POPUP
)
3347 POPUPMENU
*menu
= MENU_GetMenu( item
->hSubMenu
);
3348 if (!menu
) return -1;
3349 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3353 /* We used to (from way back then) mask the result to 0xff. */
3354 /* I don't know why and it seems wrong as the documented */
3355 /* return flag MF_SEPARATOR is outside that mask. */
3356 return (item
->fType
| item
->fState
);
3361 /**********************************************************************
3362 * GetMenuItemCount (USER32.@)
3364 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3366 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3367 if (!menu
) return -1;
3368 TRACE("(%p) returning %d\n", hMenu
, menu
->nItems
);
3369 return menu
->nItems
;
3373 /**********************************************************************
3374 * GetMenuItemID (USER32.@)
3376 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3380 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return -1;
3381 if (lpmi
->fType
& MF_POPUP
) return -1;
3387 /*******************************************************************
3388 * InsertMenuW (USER32.@)
3390 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3391 UINT_PTR id
, LPCWSTR str
)
3395 if (IS_STRING_ITEM(flags
) && str
)
3396 TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %s\n",
3397 hMenu
, pos
, flags
, id
, debugstr_w(str
) );
3398 else TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %08lx (not a string)\n",
3399 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3401 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3403 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3405 RemoveMenu( hMenu
, pos
, flags
);
3409 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3410 (MENU_GetMenu((HMENU
)id
))->wFlags
|= MF_POPUP
;
3412 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3417 /*******************************************************************
3418 * InsertMenuA (USER32.@)
3420 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3421 UINT_PTR id
, LPCSTR str
)
3425 if (IS_STRING_ITEM(flags
) && str
)
3427 INT len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
3428 LPWSTR newstr
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3431 MultiByteToWideChar( CP_ACP
, 0, str
, -1, newstr
, len
);
3432 ret
= InsertMenuW( hMenu
, pos
, flags
, id
, newstr
);
3433 HeapFree( GetProcessHeap(), 0, newstr
);
3437 else return InsertMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
3441 /*******************************************************************
3442 * AppendMenuA (USER32.@)
3444 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3445 UINT_PTR id
, LPCSTR data
)
3447 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3451 /*******************************************************************
3452 * AppendMenuW (USER32.@)
3454 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3455 UINT_PTR id
, LPCWSTR data
)
3457 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3461 /**********************************************************************
3462 * RemoveMenu (USER32.@)
3464 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3469 TRACE("(menu=%p pos=%04x flags=%04x)\n",hMenu
, nPos
, wFlags
);
3470 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3471 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3475 MENU_FreeItemData( item
);
3477 if (--menu
->nItems
== 0)
3479 HeapFree( GetProcessHeap(), 0, menu
->items
);
3484 while(nPos
< menu
->nItems
)
3490 menu
->items
= HeapReAlloc( GetProcessHeap(), 0, menu
->items
,
3491 menu
->nItems
* sizeof(MENUITEM
) );
3497 /**********************************************************************
3498 * DeleteMenu (USER32.@)
3500 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3502 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3503 if (!item
) return FALSE
;
3504 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3505 /* nPos is now the position of the item */
3506 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3511 /*******************************************************************
3512 * ModifyMenuW (USER32.@)
3514 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3515 UINT_PTR id
, LPCWSTR str
)
3519 if (IS_STRING_ITEM(flags
))
3521 TRACE("%p %d %04x %04x %s\n", hMenu
, pos
, flags
, id
, debugstr_w(str
) );
3525 TRACE("%p %d %04x %04x %08lx\n", hMenu
, pos
, flags
, id
, (DWORD
)str
);
3528 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3529 MENU_GetMenu(hMenu
)->Height
= 0; /* force size recalculate */
3530 return MENU_SetItemData( item
, flags
, id
, str
);
3534 /*******************************************************************
3535 * ModifyMenuA (USER32.@)
3537 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3538 UINT_PTR id
, LPCSTR str
)
3542 if (IS_STRING_ITEM(flags
) && str
)
3544 INT len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
3545 LPWSTR newstr
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3548 MultiByteToWideChar( CP_ACP
, 0, str
, -1, newstr
, len
);
3549 ret
= ModifyMenuW( hMenu
, pos
, flags
, id
, newstr
);
3550 HeapFree( GetProcessHeap(), 0, newstr
);
3554 else return ModifyMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
3558 /**********************************************************************
3559 * CreatePopupMenu (USER32.@)
3561 HMENU WINAPI
CreatePopupMenu(void)
3566 if (!(hmenu
= CreateMenu())) return 0;
3567 menu
= MENU_GetMenu( hmenu
);
3568 menu
->wFlags
|= MF_POPUP
;
3569 menu
->bTimeToHide
= FALSE
;
3574 /**********************************************************************
3575 * GetMenuCheckMarkDimensions (USER.417)
3576 * GetMenuCheckMarkDimensions (USER32.@)
3578 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3580 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK
), GetSystemMetrics(SM_CYMENUCHECK
) );
3584 /**********************************************************************
3585 * SetMenuItemBitmaps (USER32.@)
3587 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
3588 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
3591 TRACE("(%p, %04x, %04x, %p, %p)\n",
3592 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3593 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3595 if (!hNewCheck
&& !hNewUnCheck
)
3597 item
->fState
&= ~MF_USECHECKBITMAPS
;
3599 else /* Install new bitmaps */
3601 item
->hCheckBit
= hNewCheck
;
3602 item
->hUnCheckBit
= hNewUnCheck
;
3603 item
->fState
|= MF_USECHECKBITMAPS
;
3609 /**********************************************************************
3610 * CreateMenu (USER32.@)
3612 HMENU WINAPI
CreateMenu(void)
3616 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3617 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3619 ZeroMemory(menu
, sizeof(POPUPMENU
));
3620 menu
->wMagic
= MENU_MAGIC
;
3621 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3622 menu
->bTimeToHide
= FALSE
;
3624 TRACE("return %p\n", hMenu
);
3630 /**********************************************************************
3631 * DestroyMenu (USER32.@)
3633 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
3635 TRACE("(%p)\n", hMenu
);
3637 /* Silently ignore attempts to destroy default system popup */
3639 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3641 LPPOPUPMENU lppop
= MENU_GetMenu(hMenu
);
3643 if (!lppop
) return FALSE
;
3645 lppop
->wMagic
= 0; /* Mark it as destroyed */
3647 /* DestroyMenu should not destroy system menu popup owner */
3648 if ((lppop
->wFlags
& (MF_POPUP
| MF_SYSMENU
)) == MF_POPUP
&& lppop
->hWnd
)
3650 DestroyWindow( lppop
->hWnd
);
3654 if (lppop
->items
) /* recursively destroy submenus */
3657 MENUITEM
*item
= lppop
->items
;
3658 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3660 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
3661 MENU_FreeItemData( item
);
3663 HeapFree( GetProcessHeap(), 0, lppop
->items
);
3665 USER_HEAP_FREE( hMenu
);
3667 return (hMenu
!= MENU_DefSysPopup
);
3671 /**********************************************************************
3672 * GetSystemMenu (USER32.@)
3674 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
3676 WND
*wndPtr
= WIN_GetPtr( hWnd
);
3679 if (wndPtr
== WND_DESKTOP
) return 0;
3680 if (wndPtr
== WND_OTHER_PROCESS
)
3682 if (IsWindow( hWnd
)) FIXME( "not supported on other process window %p\n", hWnd
);
3686 if( wndPtr
->hSysMenu
)
3690 DestroyMenu(wndPtr
->hSysMenu
);
3691 wndPtr
->hSysMenu
= 0;
3695 POPUPMENU
*menu
= MENU_GetMenu( wndPtr
->hSysMenu
);
3698 if( menu
->nItems
> 0 && menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
3699 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
3703 WARN("Current sys-menu (%p) of wnd %p is broken\n",
3704 wndPtr
->hSysMenu
, hWnd
);
3705 wndPtr
->hSysMenu
= 0;
3710 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
3711 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU
)(-1) );
3713 if( wndPtr
->hSysMenu
)
3716 retvalue
= GetSubMenu(wndPtr
->hSysMenu
, 0);
3718 /* Store the dummy sysmenu handle to facilitate the refresh */
3719 /* of the close button if the SC_CLOSE item change */
3720 menu
= MENU_GetMenu(retvalue
);
3722 menu
->hSysMenuOwner
= wndPtr
->hSysMenu
;
3724 WIN_ReleasePtr( wndPtr
);
3726 return bRevert
? 0 : retvalue
;
3730 /*******************************************************************
3731 * SetSystemMenu (USER32.@)
3733 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
3735 WND
*wndPtr
= WIN_GetPtr( hwnd
);
3737 if (wndPtr
&& wndPtr
!= WND_OTHER_PROCESS
&& wndPtr
!= WND_DESKTOP
)
3739 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
3740 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
3741 WIN_ReleasePtr( wndPtr
);
3748 /**********************************************************************
3749 * GetMenu (USER32.@)
3751 HMENU WINAPI
GetMenu( HWND hWnd
)
3753 HMENU retvalue
= (HMENU
)GetWindowLongPtrW( hWnd
, GWLP_ID
);
3754 TRACE("for %p returning %p\n", hWnd
, retvalue
);
3758 /**********************************************************************
3759 * GetMenuBarInfo (USER32.@)
3761 BOOL WINAPI
GetMenuBarInfo( HWND hwnd
, LONG idObject
, LONG idItem
, PMENUBARINFO pmbi
)
3763 FIXME( "(%p,0x%08lx,0x%08lx,%p)\n", hwnd
, idObject
, idItem
, pmbi
);
3767 /**********************************************************************
3770 * Helper for SetMenu. Also called by WIN_CreateWindowEx to avoid the
3771 * SetWindowPos call that would result if SetMenu were called directly.
3773 BOOL
MENU_SetMenu( HWND hWnd
, HMENU hMenu
)
3775 TRACE("(%p, %p);\n", hWnd
, hMenu
);
3777 if (hMenu
&& !IsMenu(hMenu
))
3779 WARN("hMenu %p is not a menu handle\n", hMenu
);
3782 if (!WIN_ALLOWED_MENU(GetWindowLongW( hWnd
, GWL_STYLE
)))
3785 hWnd
= WIN_GetFullHandle( hWnd
);
3786 if (GetCapture() == hWnd
) MENU_SetCapture(0); /* release the capture */
3792 if (!(lpmenu
= MENU_GetMenu(hMenu
))) return FALSE
;
3794 lpmenu
->hWnd
= hWnd
;
3795 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
3797 SetWindowLongPtrW( hWnd
, GWLP_ID
, (LONG_PTR
)hMenu
);
3802 /**********************************************************************
3803 * SetMenu (USER32.@)
3805 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
3807 if(!MENU_SetMenu(hWnd
, hMenu
))
3810 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3811 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3816 /**********************************************************************
3817 * GetSubMenu (USER32.@)
3819 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
3823 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
3824 if (!(lpmi
->fType
& MF_POPUP
)) return 0;
3825 return lpmi
->hSubMenu
;
3829 /**********************************************************************
3830 * DrawMenuBar (USER32.@)
3832 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
3835 HMENU hMenu
= GetMenu(hWnd
);
3837 if (!WIN_ALLOWED_MENU(GetWindowLongW( hWnd
, GWL_STYLE
)))
3839 if (!hMenu
|| !(lppop
= MENU_GetMenu( hMenu
))) return FALSE
;
3841 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
3842 lppop
->hwndOwner
= hWnd
;
3843 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3844 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3848 /***********************************************************************
3849 * DrawMenuBarTemp (USER32.@)
3853 * called by W98SE desk.cpl Control Panel Applet
3855 * Not 100% sure about the param names, but close.
3857 DWORD WINAPI
DrawMenuBarTemp(HWND hwnd
, HDC hDC
, LPRECT lprect
, HMENU hMenu
, HFONT hFont
)
3864 hMenu
= GetMenu(hwnd
);
3869 lppop
= MENU_GetMenu( hMenu
);
3870 if (lppop
== NULL
|| lprect
== NULL
)
3872 retvalue
= GetSystemMetrics(SM_CYMENU
);
3876 TRACE("(%p, %p, %p, %p, %p)\n", hwnd
, hDC
, lprect
, hMenu
, hFont
);
3878 hfontOld
= SelectObject( hDC
, hFont
);
3880 if (lppop
->Height
== 0)
3881 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
3883 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
3885 FillRect(hDC
, lprect
, GetSysColorBrush(COLOR_MENU
) );
3887 SelectObject( hDC
, SYSCOLOR_GetPen(COLOR_3DFACE
));
3888 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
3889 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
3891 if (lppop
->nItems
== 0)
3893 retvalue
= GetSystemMetrics(SM_CYMENU
);
3897 for (i
= 0; i
< lppop
->nItems
; i
++)
3899 MENU_DrawMenuItem( hwnd
, hMenu
, hwnd
,
3900 hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
, ODA_DRAWENTIRE
);
3902 retvalue
= lppop
->Height
;
3905 if (hfontOld
) SelectObject (hDC
, hfontOld
);
3909 /***********************************************************************
3910 * EndMenu (USER.187)
3911 * EndMenu (USER32.@)
3913 void WINAPI
EndMenu(void)
3915 /* if we are in the menu code, and it is active */
3916 if (!fEndMenu
&& top_popup
)
3918 /* terminate the menu handling code */
3921 /* needs to be posted to wakeup the internal menu handler */
3922 /* which will now terminate the menu, in the event that */
3923 /* the main window was minimized, or lost focus, so we */
3924 /* don't end up with an orphaned menu */
3925 PostMessageW( top_popup
, WM_CANCELMODE
, 0, 0);
3930 /***********************************************************************
3931 * LookupMenuHandle (USER.217)
3933 HMENU16 WINAPI
LookupMenuHandle16( HMENU16 hmenu
, INT16 id
)
3935 HMENU hmenu32
= HMENU_32(hmenu
);
3937 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
3938 else return HMENU_16(hmenu32
);
3942 /**********************************************************************
3943 * LoadMenu (USER.150)
3945 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, LPCSTR name
)
3951 if (HIWORD(name
) && name
[0] == '#') name
= (LPCSTR
)atoi( name
+ 1 );
3952 if (!name
) return 0;
3954 instance
= GetExePtr( instance
);
3955 if (!(hRsrc
= FindResource16( instance
, name
, (LPSTR
)RT_MENU
))) return 0;
3956 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
3957 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
3958 FreeResource16( handle
);
3963 /*****************************************************************
3964 * LoadMenuA (USER32.@)
3966 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
3968 HRSRC hrsrc
= FindResourceA( instance
, name
, (LPSTR
)RT_MENU
);
3969 if (!hrsrc
) return 0;
3970 return LoadMenuIndirectA( (LPCVOID
)LoadResource( instance
, hrsrc
));
3974 /*****************************************************************
3975 * LoadMenuW (USER32.@)
3977 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
3979 HRSRC hrsrc
= FindResourceW( instance
, name
, (LPWSTR
)RT_MENU
);
3980 if (!hrsrc
) return 0;
3981 return LoadMenuIndirectW( (LPCVOID
)LoadResource( instance
, hrsrc
));
3985 /**********************************************************************
3986 * LoadMenuIndirect (USER.220)
3988 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
3991 WORD version
, offset
;
3992 LPCSTR p
= (LPCSTR
)template;
3994 TRACE("(%p)\n", template );
3995 version
= GET_WORD(p
);
3999 WARN("version must be 0 for Win16\n" );
4002 offset
= GET_WORD(p
);
4003 p
+= sizeof(WORD
) + offset
;
4004 if (!(hMenu
= CreateMenu())) return 0;
4005 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
4007 DestroyMenu( hMenu
);
4010 return HMENU_16(hMenu
);
4014 /**********************************************************************
4015 * LoadMenuIndirectW (USER32.@)
4017 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
4020 WORD version
, offset
;
4021 LPCSTR p
= (LPCSTR
)template;
4023 version
= GET_WORD(p
);
4025 TRACE("%p, ver %d\n", template, version
);
4028 case 0: /* standard format is version of 0 */
4029 offset
= GET_WORD(p
);
4030 p
+= sizeof(WORD
) + offset
;
4031 if (!(hMenu
= CreateMenu())) return 0;
4032 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
4034 DestroyMenu( hMenu
);
4038 case 1: /* extended format is version of 1 */
4039 offset
= GET_WORD(p
);
4040 p
+= sizeof(WORD
) + offset
;
4041 if (!(hMenu
= CreateMenu())) return 0;
4042 if (!MENUEX_ParseResource( p
, hMenu
))
4044 DestroyMenu( hMenu
);
4049 ERR("version %d not supported.\n", version
);
4055 /**********************************************************************
4056 * LoadMenuIndirectA (USER32.@)
4058 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
4060 return LoadMenuIndirectW( template );
4064 /**********************************************************************
4067 BOOL WINAPI
IsMenu(HMENU hmenu
)
4069 LPPOPUPMENU menu
= MENU_GetMenu(hmenu
);
4070 return menu
!= NULL
;
4073 /**********************************************************************
4074 * GetMenuItemInfo_common
4077 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
, BOOL bypos
,
4078 LPMENUITEMINFOW lpmii
, BOOL unicode
)
4080 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
4082 debug_print_menuitem("GetMenuItemInfo_common: ", menu
, "");
4087 if (lpmii
->fMask
& MIIM_TYPE
) {
4088 lpmii
->fType
= menu
->fType
;
4089 switch (MENU_ITEM_TYPE(menu
->fType
)) {
4091 break; /* will be done below */
4094 lpmii
->dwTypeData
= menu
->text
;
4101 /* copy the text string */
4102 if ((lpmii
->fMask
& (MIIM_TYPE
|MIIM_STRING
)) &&
4103 (MENU_ITEM_TYPE(menu
->fType
) == MF_STRING
) && menu
->text
)
4108 len
= strlenW(menu
->text
);
4109 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4110 lstrcpynW(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4114 len
= WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1, NULL
, 0, NULL
, NULL
);
4115 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4116 if (!WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1,
4117 (LPSTR
)lpmii
->dwTypeData
, lpmii
->cch
, NULL
, NULL
))
4118 ((LPSTR
)lpmii
->dwTypeData
)[lpmii
->cch
-1] = 0;
4120 /* if we've copied a substring we return its length */
4121 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4123 if (lpmii
->cch
<= len
) lpmii
->cch
--;
4125 else /* return length of string */
4129 if (lpmii
->fMask
& MIIM_FTYPE
)
4130 lpmii
->fType
= menu
->fType
;
4132 if (lpmii
->fMask
& MIIM_BITMAP
)
4133 lpmii
->hbmpItem
= menu
->hbmpItem
;
4135 if (lpmii
->fMask
& MIIM_STATE
)
4136 lpmii
->fState
= menu
->fState
;
4138 if (lpmii
->fMask
& MIIM_ID
)
4139 lpmii
->wID
= menu
->wID
;
4141 if (lpmii
->fMask
& MIIM_SUBMENU
)
4142 lpmii
->hSubMenu
= menu
->hSubMenu
;
4144 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4145 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4146 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4148 if (lpmii
->fMask
& MIIM_DATA
)
4149 lpmii
->dwItemData
= menu
->dwItemData
;
4154 /**********************************************************************
4155 * GetMenuItemInfoA (USER32.@)
4157 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4158 LPMENUITEMINFOA lpmii
)
4160 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4161 (LPMENUITEMINFOW
)lpmii
, FALSE
);
4164 /**********************************************************************
4165 * GetMenuItemInfoW (USER32.@)
4167 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4168 LPMENUITEMINFOW lpmii
)
4170 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4175 /* set a menu item text from a ASCII or Unicode string */
4176 inline static void set_menu_item_text( MENUITEM
*menu
, LPCWSTR text
, BOOL unicode
)
4181 menu
->fType
|= MF_SEPARATOR
;
4185 if ((menu
->text
= HeapAlloc( GetProcessHeap(), 0, (strlenW(text
)+1) * sizeof(WCHAR
) )))
4186 strcpyW( menu
->text
, text
);
4190 LPCSTR str
= (LPCSTR
)text
;
4191 int len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
4192 if ((menu
->text
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
4193 MultiByteToWideChar( CP_ACP
, 0, str
, -1, menu
->text
, len
);
4198 /**********************************************************************
4199 * SetMenuItemInfo_common
4202 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4203 const MENUITEMINFOW
*lpmii
,
4206 if (!menu
) return FALSE
;
4208 debug_print_menuitem("MENU_SetItemInfo_common from: ", menu
, "");
4210 if (lpmii
->fMask
& MIIM_TYPE
) {
4211 /* Get rid of old string. */
4212 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4213 HeapFree(GetProcessHeap(), 0, menu
->text
);
4217 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4218 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4219 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4221 menu
->text
= lpmii
->dwTypeData
;
4223 if (IS_STRING_ITEM(menu
->fType
))
4224 set_menu_item_text( menu
, lpmii
->dwTypeData
, unicode
);
4227 if (lpmii
->fMask
& MIIM_FTYPE
) {
4228 /* free the string when the type is changing */
4229 if ( (!IS_STRING_ITEM(lpmii
->fType
)) && IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4230 HeapFree(GetProcessHeap(), 0, menu
->text
);
4233 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4234 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4235 if ( IS_STRING_ITEM(menu
->fType
) && !menu
->text
)
4236 menu
->fType
|= MF_SEPARATOR
;
4239 if (lpmii
->fMask
& MIIM_STRING
) {
4240 if (IS_STRING_ITEM(menu
->fType
)) {
4241 /* free the string when used */
4242 HeapFree(GetProcessHeap(), 0, menu
->text
);
4243 set_menu_item_text( menu
, lpmii
->dwTypeData
, unicode
);
4247 if (lpmii
->fMask
& MIIM_STATE
)
4249 /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
4250 menu
->fState
= lpmii
->fState
;
4253 if (lpmii
->fMask
& MIIM_ID
)
4254 menu
->wID
= lpmii
->wID
;
4256 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4257 menu
->hSubMenu
= lpmii
->hSubMenu
;
4258 if (menu
->hSubMenu
) {
4259 POPUPMENU
*subMenu
= MENU_GetMenu(menu
->hSubMenu
);
4261 subMenu
->wFlags
|= MF_POPUP
;
4262 menu
->fType
|= MF_POPUP
;
4265 /* FIXME: Return an error ? */
4266 menu
->fType
&= ~MF_POPUP
;
4269 menu
->fType
&= ~MF_POPUP
;
4272 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4274 if (lpmii
->fType
& MFT_RADIOCHECK
)
4275 menu
->fType
|= MFT_RADIOCHECK
;
4277 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4278 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4280 if (lpmii
->fMask
& MIIM_DATA
)
4281 menu
->dwItemData
= lpmii
->dwItemData
;
4283 if (lpmii
->fMask
& MIIM_BITMAP
)
4284 menu
->hbmpItem
= lpmii
->hbmpItem
;
4286 debug_print_menuitem("SetMenuItemInfo_common to : ", menu
, "");
4290 /**********************************************************************
4291 * SetMenuItemInfoA (USER32.@)
4293 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4294 const MENUITEMINFOA
*lpmii
)
4296 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4297 (const MENUITEMINFOW
*)lpmii
, FALSE
);
4300 /**********************************************************************
4301 * SetMenuItemInfoW (USER32.@)
4303 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4304 const MENUITEMINFOW
*lpmii
)
4306 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4310 /**********************************************************************
4311 * SetMenuDefaultItem (USER32.@)
4314 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT uItem
, UINT bypos
)
4320 TRACE("(%p,%d,%d)\n", hmenu
, uItem
, bypos
);
4322 if (!(menu
= MENU_GetMenu(hmenu
))) return FALSE
;
4324 /* reset all default-item flags */
4326 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4328 item
->fState
&= ~MFS_DEFAULT
;
4331 /* no default item */
4340 if ( uItem
>= menu
->nItems
) return FALSE
;
4341 item
[uItem
].fState
|= MFS_DEFAULT
;
4346 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4348 if (item
->wID
== uItem
)
4350 item
->fState
|= MFS_DEFAULT
;
4359 /**********************************************************************
4360 * GetMenuDefaultItem (USER32.@)
4362 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4368 TRACE("(%p,%d,%d)\n", hmenu
, bypos
, flags
);
4370 if (!(menu
= MENU_GetMenu(hmenu
))) return -1;
4372 /* find default item */
4376 if (! item
) return -1;
4378 while ( !( item
->fState
& MFS_DEFAULT
) )
4381 if (i
>= menu
->nItems
) return -1;
4384 /* default: don't return disabled items */
4385 if ( (!(GMDI_USEDISABLED
& flags
)) && (item
->fState
& MFS_DISABLED
)) return -1;
4387 /* search rekursiv when needed */
4388 if ( (item
->fType
& MF_POPUP
) && (flags
& GMDI_GOINTOPOPUPS
) )
4391 ret
= GetMenuDefaultItem( item
->hSubMenu
, bypos
, flags
);
4392 if ( -1 != ret
) return ret
;
4394 /* when item not found in submenu, return the popup item */
4396 return ( bypos
) ? i
: item
->wID
;
4401 /**********************************************************************
4402 * InsertMenuItemA (USER32.@)
4404 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4405 const MENUITEMINFOA
*lpmii
)
4407 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4408 return SetMenuItemInfo_common(item
, (const MENUITEMINFOW
*)lpmii
, FALSE
);
4412 /**********************************************************************
4413 * InsertMenuItemW (USER32.@)
4415 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4416 const MENUITEMINFOW
*lpmii
)
4418 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4419 return SetMenuItemInfo_common(item
, lpmii
, TRUE
);
4422 /**********************************************************************
4423 * CheckMenuRadioItem (USER32.@)
4426 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
4427 UINT first
, UINT last
, UINT check
,
4430 MENUITEM
*mifirst
, *milast
, *micheck
;
4431 HMENU mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
4433 TRACE("%p: %d-%d, check %d, bypos=%d\n", hMenu
, first
, last
, check
, bypos
);
4435 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
4436 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
4437 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
4439 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
4440 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
4441 micheck
> milast
|| micheck
< mifirst
)
4444 while (mifirst
<= milast
)
4446 if (mifirst
== micheck
)
4448 mifirst
->fType
|= MFT_RADIOCHECK
;
4449 mifirst
->fState
|= MFS_CHECKED
;
4451 mifirst
->fType
&= ~MFT_RADIOCHECK
;
4452 mifirst
->fState
&= ~MFS_CHECKED
;
4461 /**********************************************************************
4462 * GetMenuItemRect (USER32.@)
4464 * ATTENTION: Here, the returned values in rect are the screen
4465 * coordinates of the item just like if the menu was
4466 * always on the upper left side of the application.
4469 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
4472 POPUPMENU
*itemMenu
;
4476 TRACE("(%p,%p,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
4478 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
4479 referenceHwnd
= hwnd
;
4483 itemMenu
= MENU_GetMenu(hMenu
);
4484 if (itemMenu
== NULL
)
4487 if(itemMenu
->hWnd
== 0)
4489 referenceHwnd
= itemMenu
->hWnd
;
4492 if ((rect
== NULL
) || (item
== NULL
))
4497 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
4503 /**********************************************************************
4504 * SetMenuInfo (USER32.@)
4507 * MIM_APPLYTOSUBMENUS
4508 * actually use the items to draw the menu
4510 BOOL WINAPI
SetMenuInfo (HMENU hMenu
, LPCMENUINFO lpmi
)
4514 TRACE("(%p %p)\n", hMenu
, lpmi
);
4516 if (lpmi
&& (lpmi
->cbSize
==sizeof(MENUINFO
)) && (menu
= MENU_GetMenu(hMenu
)))
4519 if (lpmi
->fMask
& MIM_BACKGROUND
)
4520 menu
->hbrBack
= lpmi
->hbrBack
;
4522 if (lpmi
->fMask
& MIM_HELPID
)
4523 menu
->dwContextHelpID
= lpmi
->dwContextHelpID
;
4525 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4526 menu
->cyMax
= lpmi
->cyMax
;
4528 if (lpmi
->fMask
& MIM_MENUDATA
)
4529 menu
->dwMenuData
= lpmi
->dwMenuData
;
4531 if (lpmi
->fMask
& MIM_STYLE
)
4533 menu
->dwStyle
= lpmi
->dwStyle
;
4534 if (menu
->dwStyle
& MNS_AUTODISMISS
) FIXME("MNS_AUTODISMISS unimplemented\n");
4535 if (menu
->dwStyle
& MNS_DRAGDROP
) FIXME("MNS_DRAGDROP unimplemented\n");
4536 if (menu
->dwStyle
& MNS_MODELESS
) FIXME("MNS_MODELESS unimplemented\n");
4537 if (menu
->dwStyle
& MNS_NOCHECK
) FIXME("MNS_NOCHECK unimplemented\n");
4538 if (menu
->dwStyle
& MNS_NOTIFYBYPOS
) FIXME("MNS_NOTIFYBYPOS unimplemented\n");
4546 /**********************************************************************
4547 * GetMenuInfo (USER32.@)
4553 BOOL WINAPI
GetMenuInfo (HMENU hMenu
, LPMENUINFO lpmi
)
4556 TRACE("(%p %p)\n", hMenu
, lpmi
);
4558 if (lpmi
&& (menu
= MENU_GetMenu(hMenu
)))
4561 if (lpmi
->fMask
& MIM_BACKGROUND
)
4562 lpmi
->hbrBack
= menu
->hbrBack
;
4564 if (lpmi
->fMask
& MIM_HELPID
)
4565 lpmi
->dwContextHelpID
= menu
->dwContextHelpID
;
4567 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4568 lpmi
->cyMax
= menu
->cyMax
;
4570 if (lpmi
->fMask
& MIM_MENUDATA
)
4571 lpmi
->dwMenuData
= menu
->dwMenuData
;
4573 if (lpmi
->fMask
& MIM_STYLE
)
4574 lpmi
->dwStyle
= menu
->dwStyle
;
4582 /**********************************************************************
4583 * SetMenuContextHelpId (USER32.@)
4585 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpID
)
4589 TRACE("(%p 0x%08lx)\n", hMenu
, dwContextHelpID
);
4591 if ((menu
= MENU_GetMenu(hMenu
)))
4593 menu
->dwContextHelpID
= dwContextHelpID
;
4600 /**********************************************************************
4601 * GetMenuContextHelpId (USER32.@)
4603 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
4607 TRACE("(%p)\n", hMenu
);
4609 if ((menu
= MENU_GetMenu(hMenu
)))
4611 return menu
->dwContextHelpID
;
4616 /**********************************************************************
4617 * MenuItemFromPoint (USER32.@)
4619 INT WINAPI
MenuItemFromPoint(HWND hWnd
, HMENU hMenu
, POINT ptScreen
)
4621 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
4624 /*FIXME: Do we have to handle hWnd here? */
4625 if (!menu
) return -1;
4626 if (!MENU_FindItemByCoords(menu
, ptScreen
, &pos
)) return -1;
4631 /**********************************************************************
4632 * translate_accelerator
4634 static BOOL
translate_accelerator( HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
,
4635 BYTE fVirt
, WORD key
, WORD cmd
)
4640 if (wParam
!= key
) return FALSE
;
4642 if (GetKeyState(VK_CONTROL
) & 0x8000) mask
|= FCONTROL
;
4643 if (GetKeyState(VK_MENU
) & 0x8000) mask
|= FALT
;
4644 if (GetKeyState(VK_SHIFT
) & 0x8000) mask
|= FSHIFT
;
4646 if (message
== WM_CHAR
|| message
== WM_SYSCHAR
)
4648 if ( !(fVirt
& FVIRTKEY
) && (mask
& FALT
) == (fVirt
& FALT
) )
4650 TRACE_(accel
)("found accel for WM_CHAR: ('%c')\n", wParam
& 0xff);
4656 if(fVirt
& FVIRTKEY
)
4658 TRACE_(accel
)("found accel for virt_key %04x (scan %04x)\n",
4659 wParam
, 0xff & HIWORD(lParam
));
4661 if(mask
== (fVirt
& (FSHIFT
| FCONTROL
| FALT
))) goto found
;
4662 TRACE_(accel
)(", but incorrect SHIFT/CTRL/ALT-state\n");
4666 if (!(lParam
& 0x01000000)) /* no special_key */
4668 if ((fVirt
& FALT
) && (lParam
& 0x20000000))
4669 { /* ^^ ALT pressed */
4670 TRACE_(accel
)("found accel for Alt-%c\n", wParam
& 0xff);
4679 if (message
== WM_KEYUP
|| message
== WM_SYSKEYUP
)
4683 HMENU hMenu
, hSubMenu
, hSysMenu
;
4684 UINT uSysStat
= (UINT
)-1, uStat
= (UINT
)-1, nPos
;
4686 hMenu
= (GetWindowLongW( hWnd
, GWL_STYLE
) & WS_CHILD
) ? 0 : GetMenu(hWnd
);
4687 hSysMenu
= get_win_sys_menu( hWnd
);
4689 /* find menu item and ask application to initialize it */
4690 /* 1. in the system menu */
4691 hSubMenu
= hSysMenu
;
4693 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
4697 if (!IsWindowEnabled(hWnd
))
4701 SendMessageW(hWnd
, WM_INITMENU
, (WPARAM
)hSysMenu
, 0L);
4702 if(hSubMenu
!= hSysMenu
)
4704 nPos
= MENU_FindSubMenu(&hSysMenu
, hSubMenu
);
4705 TRACE_(accel
)("hSysMenu = %p, hSubMenu = %p, nPos = %d\n", hSysMenu
, hSubMenu
, nPos
);
4706 SendMessageW(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, TRUE
));
4708 uSysStat
= GetMenuState(GetSubMenu(hSysMenu
, 0), cmd
, MF_BYCOMMAND
);
4711 else /* 2. in the window's menu */
4715 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
4719 if (!IsWindowEnabled(hWnd
))
4723 SendMessageW(hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0L);
4724 if(hSubMenu
!= hMenu
)
4726 nPos
= MENU_FindSubMenu(&hMenu
, hSubMenu
);
4727 TRACE_(accel
)("hMenu = %p, hSubMenu = %p, nPos = %d\n", hMenu
, hSubMenu
, nPos
);
4728 SendMessageW(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, FALSE
));
4730 uStat
= GetMenuState(hMenu
, cmd
, MF_BYCOMMAND
);
4737 if (uSysStat
!= (UINT
)-1)
4739 if (uSysStat
& (MF_DISABLED
|MF_GRAYED
))
4746 if (uStat
!= (UINT
)-1)
4752 if (uStat
& (MF_DISABLED
|MF_GRAYED
))
4764 if( mesg
==WM_COMMAND
)
4766 TRACE_(accel
)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd
);
4767 SendMessageW(hWnd
, mesg
, 0x10000 | cmd
, 0L);
4769 else if( mesg
==WM_SYSCOMMAND
)
4771 TRACE_(accel
)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd
);
4772 SendMessageW(hWnd
, mesg
, cmd
, 0x00010000L
);
4776 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
4777 * #0: unknown (please report!)
4778 * #1: for WM_KEYUP,WM_SYSKEYUP
4779 * #2: mouse is captured
4780 * #3: window is disabled
4781 * #4: it's a disabled system menu option
4782 * #5: it's a menu option, but window is iconic
4783 * #6: it's a menu option, but disabled
4785 TRACE_(accel
)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg
);
4787 ERR_(accel
)(" unknown reason - please report!\n");
4792 /**********************************************************************
4793 * TranslateAccelerator (USER32.@)
4794 * TranslateAcceleratorA (USER32.@)
4796 INT WINAPI
TranslateAcceleratorA( HWND hWnd
, HACCEL hAccel
, LPMSG msg
)
4799 LPACCEL16 lpAccelTbl
;
4803 if (!hWnd
|| !msg
) return 0;
4805 if (!hAccel
|| !(lpAccelTbl
= (LPACCEL16
) LockResource16(HACCEL_16(hAccel
))))
4807 WARN_(accel
)("invalid accel handle=%p\n", hAccel
);
4811 wParam
= msg
->wParam
;
4813 switch (msg
->message
)
4822 char ch
= LOWORD(wParam
);
4824 MultiByteToWideChar(CP_ACP
, 0, &ch
, 1, &wch
, 1);
4825 wParam
= MAKEWPARAM(wch
, HIWORD(wParam
));
4833 TRACE_(accel
)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
4834 hAccel
,hWnd
,msg
->hwnd
,msg
->message
,msg
->wParam
,msg
->lParam
);
4838 if (translate_accelerator( hWnd
, msg
->message
, wParam
, msg
->lParam
,
4839 lpAccelTbl
[i
].fVirt
, lpAccelTbl
[i
].key
, lpAccelTbl
[i
].cmd
))
4841 } while ((lpAccelTbl
[i
++].fVirt
& 0x80) == 0);
4846 /**********************************************************************
4847 * TranslateAcceleratorW (USER32.@)
4849 INT WINAPI
TranslateAcceleratorW( HWND hWnd
, HACCEL hAccel
, LPMSG msg
)
4852 LPACCEL16 lpAccelTbl
;
4855 if (!hWnd
|| !msg
) return 0;
4857 if (!hAccel
|| !(lpAccelTbl
= (LPACCEL16
) LockResource16(HACCEL_16(hAccel
))))
4859 WARN_(accel
)("invalid accel handle=%p\n", hAccel
);
4863 switch (msg
->message
)
4875 TRACE_(accel
)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08x, lParam %08lx\n",
4876 hAccel
,hWnd
,msg
->hwnd
,msg
->message
,msg
->wParam
,msg
->lParam
);
4880 if (translate_accelerator( hWnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
4881 lpAccelTbl
[i
].fVirt
, lpAccelTbl
[i
].key
, lpAccelTbl
[i
].cmd
))
4883 } while ((lpAccelTbl
[i
++].fVirt
& 0x80) == 0);