4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
10 * Note: the style MF_MOUSESELECT is used to mark popup items that
11 * have been selected, i.e. their popup menu is currently displayed.
12 * This is probably not the meaning this style has in MS-Windows.
15 #include "wine/port.h"
25 #include "wine/winbase16.h"
26 #include "wine/winuser16.h"
27 #include "wine/unicode.h"
30 #include "nonclient.h"
34 #include "debugtools.h"
36 DEFAULT_DEBUG_CHANNEL(menu
);
37 DECLARE_DEBUG_CHANNEL(accel
);
39 /* internal popup menu window messages */
41 #define MM_SETMENUHANDLE (WM_USER + 0)
42 #define MM_GETMENUHANDLE (WM_USER + 1)
44 /* Menu item structure */
46 /* ----------- MENUITEMINFO Stuff ----------- */
47 UINT fType
; /* Item type. */
48 UINT fState
; /* Item state. */
49 UINT wID
; /* Item id. */
50 HMENU hSubMenu
; /* Pop-up menu. */
51 HBITMAP hCheckBit
; /* Bitmap when checked. */
52 HBITMAP hUnCheckBit
; /* Bitmap when unchecked. */
53 LPWSTR text
; /* Item text or bitmap handle. */
54 DWORD dwItemData
; /* Application defined. */
55 DWORD dwTypeData
; /* depends on fMask */
56 HBITMAP hbmpItem
; /* bitmap in win98 style menus */
57 /* ----------- Wine stuff ----------- */
58 RECT rect
; /* Item area (relative to menu window) */
59 UINT xTab
; /* X position of text after Tab */
62 /* Popup menu structure */
64 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
65 WORD wMagic
; /* Magic number */
66 WORD Width
; /* Width of the whole menu */
67 WORD Height
; /* Height of the whole menu */
68 UINT nItems
; /* Number of items in the menu */
69 HWND hWnd
; /* Window containing the menu */
70 MENUITEM
*items
; /* Array of menu items */
71 UINT FocusedItem
; /* Currently focused item */
72 HWND hwndOwner
; /* window receiving the messages for ownerdraw */
73 BOOL bTimeToHide
; /* Request hiding when receiving a second click in the top-level menu item */
74 /* ------------ MENUINFO members ------ */
75 DWORD dwStyle
; /* Extended mennu style */
76 UINT cyMax
; /* max hight of the whole menu, 0 is screen hight */
77 HBRUSH hbrBack
; /* brush for menu background */
78 DWORD dwContextHelpID
;
79 DWORD dwMenuData
; /* application defined value */
80 HMENU hSysMenuOwner
; /* Handle to the dummy sys menu holder */
81 } POPUPMENU
, *LPPOPUPMENU
;
83 /* internal flags for menu tracking */
85 #define TF_ENDMENU 0x0001
86 #define TF_SUSPENDPOPUP 0x0002
87 #define TF_SKIPREMOVE 0x0004
92 HMENU hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
93 HMENU hTopMenu
; /* initial menu */
94 HWND hOwnerWnd
; /* where notifications are sent */
98 #define MENU_MAGIC 0x554d /* 'MU' */
103 /* Internal MENU_TrackMenu() flags */
104 #define TPM_INTERNAL 0xF0000000
105 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
106 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
107 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
109 /* popup menu shade thickness */
110 #define POPUP_XSHADE 4
111 #define POPUP_YSHADE 4
113 /* Space between 2 menu bar items */
114 #define MENU_BAR_ITEMS_SPACE 12
116 /* Minimum width of a tab character */
117 #define MENU_TAB_SPACE 8
119 /* Height of a separator item */
120 #define SEPARATOR_HEIGHT 5
122 /* (other menu->FocusedItem values give the position of the focused item) */
123 #define NO_SELECTED_ITEM 0xffff
125 #define MENU_ITEM_TYPE(flags) \
126 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
128 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
129 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
130 #define IS_MAGIC_ITEM(text) (LOWORD((int)text)<12)
132 #define IS_SYSTEM_MENU(menu) \
133 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
135 #define IS_SYSTEM_POPUP(menu) \
136 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
138 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
139 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
140 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
141 MF_POPUP | MF_SYSMENU | MF_HELP)
142 #define STATE_MASK (~TYPE_MASK)
144 /* Dimension of the menu bitmaps */
145 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
147 static HBITMAP hStdMnArrow
= 0;
149 /* Minimze/restore/close buttons to be inserted in menubar */
150 static HBITMAP hBmpMinimize
= 0;
151 static HBITMAP hBmpMinimizeD
= 0;
152 static HBITMAP hBmpMaximize
= 0;
153 static HBITMAP hBmpMaximizeD
= 0;
154 static HBITMAP hBmpClose
= 0;
155 static HBITMAP hBmpCloseD
= 0;
158 static HBRUSH hShadeBrush
= 0;
159 static HFONT hMenuFont
= 0;
160 static HFONT hMenuFontBold
= 0;
162 static HMENU MENU_DefSysPopup
= 0; /* Default system menu popup */
164 /* Use global popup window because there's no way 2 menus can
165 * be tracked at the same time. */
166 static HWND top_popup
;
168 /* Flag set by EndMenu() to force an exit from menu tracking */
169 static BOOL fEndMenu
= FALSE
;
171 static LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
174 /*********************************************************************
175 * menu class descriptor
177 const struct builtin_class_descr MENU_builtin_class
=
179 POPUPMENU_CLASS_ATOM
, /* name */
180 CS_GLOBALCLASS
| CS_SAVEBITS
, /* style */
181 NULL
, /* procA (winproc is Unicode only) */
182 PopupMenuWndProc
, /* procW */
183 sizeof(HMENU
), /* extra */
184 IDC_ARROWA
, /* cursor */
185 COLOR_MENU
+1 /* brush */
189 /***********************************************************************
190 * debug_print_menuitem
192 * Print a menuitem in readable form.
195 #define debug_print_menuitem(pre, mp, post) \
196 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
198 #define MENUOUT(text) \
199 DPRINTF("%s%s", (count++ ? "," : ""), (text))
201 #define MENUFLAG(bit,text) \
203 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
206 static void do_debug_print_menuitem(const char *prefix
, MENUITEM
* mp
,
209 TRACE("%s ", prefix
);
211 UINT flags
= mp
->fType
;
212 int typ
= MENU_ITEM_TYPE(flags
);
213 DPRINTF( "{ ID=0x%x", mp
->wID
);
214 if (flags
& MF_POPUP
)
215 DPRINTF( ", Sub=0x%x", mp
->hSubMenu
);
219 if (typ
== MFT_STRING
)
221 else if (typ
== MFT_SEPARATOR
)
223 else if (typ
== MFT_OWNERDRAW
)
225 else if (typ
== MFT_BITMAP
)
231 MENUFLAG(MF_POPUP
, "pop");
232 MENUFLAG(MFT_MENUBARBREAK
, "barbrk");
233 MENUFLAG(MFT_MENUBREAK
, "brk");
234 MENUFLAG(MFT_RADIOCHECK
, "radio");
235 MENUFLAG(MFT_RIGHTORDER
, "rorder");
236 MENUFLAG(MF_SYSMENU
, "sys");
237 MENUFLAG(MFT_RIGHTJUSTIFY
, "right"); /* same as MF_HELP */
240 DPRINTF( "+0x%x", flags
);
245 DPRINTF( ", State=");
246 MENUFLAG(MFS_GRAYED
, "grey");
247 MENUFLAG(MFS_DEFAULT
, "default");
248 MENUFLAG(MFS_DISABLED
, "dis");
249 MENUFLAG(MFS_CHECKED
, "check");
250 MENUFLAG(MFS_HILITE
, "hi");
251 MENUFLAG(MF_USECHECKBITMAPS
, "usebit");
252 MENUFLAG(MF_MOUSESELECT
, "mouse");
254 DPRINTF( "+0x%x", flags
);
257 DPRINTF( ", Chk=0x%x", mp
->hCheckBit
);
259 DPRINTF( ", Unc=0x%x", mp
->hUnCheckBit
);
261 if (typ
== MFT_STRING
) {
263 DPRINTF( ", Text=%s", debugstr_w(mp
->text
));
265 DPRINTF( ", Text=Null");
266 } else if (mp
->text
== NULL
)
269 DPRINTF( ", Text=%p", mp
->text
);
271 DPRINTF( ", ItemData=0x%08lx", mp
->dwItemData
);
277 DPRINTF(" %s\n", postfix
);
284 /***********************************************************************
287 * Validate the given menu handle and returns the menu structure pointer.
289 static POPUPMENU
*MENU_GetMenu(HMENU hMenu
)
291 POPUPMENU
*menu
= USER_HEAP_LIN_ADDR(hMenu
);
292 if (!menu
|| menu
->wMagic
!= MENU_MAGIC
)
294 WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu
, menu
, menu
? menu
->wMagic
:0);
300 /***********************************************************************
303 * Get the system menu of a window
305 static HMENU
get_win_sys_menu( HWND hwnd
)
308 WND
*win
= WIN_FindWndPtr( hwnd
);
312 WIN_ReleaseWndPtr( win
);
317 /***********************************************************************
320 * Return the default system menu.
322 static HMENU
MENU_CopySysPopup(void)
324 HMENU hMenu
= LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
327 POPUPMENU
* menu
= MENU_GetMenu(hMenu
);
328 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
329 SetMenuDefaultItem(hMenu
, SC_CLOSE
, FALSE
);
332 ERR("Unable to load default system menu\n" );
334 TRACE("returning %x.\n", hMenu
);
340 /**********************************************************************
343 * Create a copy of the system menu. System menu in Windows is
344 * a special menu bar with the single entry - system menu popup.
345 * This popup is presented to the outside world as a "system menu".
346 * However, the real system menu handle is sometimes seen in the
347 * WM_MENUSELECT parameters (and Word 6 likes it this way).
349 HMENU
MENU_GetSysMenu( HWND hWnd
, HMENU hPopupMenu
)
353 if ((hMenu
= CreateMenu()))
355 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
356 menu
->wFlags
= MF_SYSMENU
;
357 menu
->hWnd
= WIN_GetFullHandle( hWnd
);
359 if (hPopupMenu
== (HMENU
)(-1))
360 hPopupMenu
= MENU_CopySysPopup();
361 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
365 InsertMenuA( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
, hPopupMenu
, NULL
);
367 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
368 menu
->items
[0].fState
= 0;
369 if ((menu
= MENU_GetMenu(hPopupMenu
))) menu
->wFlags
|= MF_SYSMENU
;
371 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu
, hPopupMenu
);
374 DestroyMenu( hMenu
);
376 ERR("failed to load system menu!\n");
381 /***********************************************************************
384 * Menus initialisation.
389 NONCLIENTMETRICSA ncm
;
391 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
396 /* Load menu bitmaps */
397 hStdMnArrow
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW
));
398 /* Load system buttons bitmaps */
399 hBmpMinimize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE
));
400 hBmpMinimizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED
));
401 hBmpMaximize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE
));
402 hBmpMaximizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED
));
403 hBmpClose
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE
));
404 hBmpCloseD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED
));
409 GetObjectA( hStdMnArrow
, sizeof(bm
), &bm
);
410 arrow_bitmap_width
= bm
.bmWidth
;
411 arrow_bitmap_height
= bm
.bmHeight
;
415 if (! (hBitmap
= CreateBitmap( 8, 8, 1, 1, shade_bits
)))
418 if(!(hShadeBrush
= CreatePatternBrush( hBitmap
)))
421 DeleteObject( hBitmap
);
422 if (!(MENU_DefSysPopup
= MENU_CopySysPopup()))
425 ncm
.cbSize
= sizeof (NONCLIENTMETRICSA
);
426 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICSA
), &ncm
, 0)))
429 if (!(hMenuFont
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
432 ncm
.lfMenuFont
.lfWeight
+= 300;
433 if ( ncm
.lfMenuFont
.lfWeight
> 1000)
434 ncm
.lfMenuFont
.lfWeight
= 1000;
436 if (!(hMenuFontBold
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
442 /***********************************************************************
443 * MENU_InitSysMenuPopup
445 * Grey the appropriate items in System menu.
447 static void MENU_InitSysMenuPopup( HMENU hmenu
, DWORD style
, DWORD clsStyle
)
451 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
452 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
453 gray
= ((style
& WS_MAXIMIZE
) != 0);
454 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
455 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
456 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
457 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
458 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
459 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
460 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
461 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
463 /* The menu item must keep its state if it's disabled */
465 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
469 /******************************************************************************
471 * UINT MENU_GetStartOfNextColumn(
474 *****************************************************************************/
476 static UINT
MENU_GetStartOfNextColumn(
479 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
483 return NO_SELECTED_ITEM
;
485 i
= menu
->FocusedItem
+ 1;
486 if( i
== NO_SELECTED_ITEM
)
489 for( ; i
< menu
->nItems
; ++i
) {
490 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
494 return NO_SELECTED_ITEM
;
498 /******************************************************************************
500 * UINT MENU_GetStartOfPrevColumn(
503 *****************************************************************************/
505 static UINT
MENU_GetStartOfPrevColumn(
508 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
512 return NO_SELECTED_ITEM
;
514 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
515 return NO_SELECTED_ITEM
;
517 /* Find the start of the column */
519 for(i
= menu
->FocusedItem
; i
!= 0 &&
520 !(menu
->items
[i
].fType
& MF_MENUBARBREAK
);
524 return NO_SELECTED_ITEM
;
526 for(--i
; i
!= 0; --i
) {
527 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
531 TRACE("ret %d.\n", i
);
538 /***********************************************************************
541 * Find a menu item. Return a pointer on the item, and modifies *hmenu
542 * in case the item was in a sub-menu.
544 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
549 if (((*hmenu
)==0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
550 if (wFlags
& MF_BYPOSITION
)
552 if (*nPos
>= menu
->nItems
) return NULL
;
553 return &menu
->items
[*nPos
];
557 MENUITEM
*item
= menu
->items
;
558 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
560 if (item
->wID
== *nPos
)
565 else if (item
->fType
& MF_POPUP
)
567 HMENU hsubmenu
= item
->hSubMenu
;
568 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
580 /***********************************************************************
583 * Find a Sub menu. Return the position of the submenu, and modifies
584 * *hmenu in case it is found in another sub-menu.
585 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
587 UINT
MENU_FindSubMenu( HMENU
*hmenu
, HMENU hSubTarget
)
592 if (((*hmenu
)==0xffff) ||
593 (!(menu
= MENU_GetMenu(*hmenu
))))
594 return NO_SELECTED_ITEM
;
596 for (i
= 0; i
< menu
->nItems
; i
++, item
++) {
597 if(!(item
->fType
& MF_POPUP
)) continue;
598 if (item
->hSubMenu
== hSubTarget
) {
602 HMENU hsubmenu
= item
->hSubMenu
;
603 UINT pos
= MENU_FindSubMenu( &hsubmenu
, hSubTarget
);
604 if (pos
!= NO_SELECTED_ITEM
) {
610 return NO_SELECTED_ITEM
;
613 /***********************************************************************
616 static void MENU_FreeItemData( MENUITEM
* item
)
619 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
620 HeapFree( GetProcessHeap(), 0, item
->text
);
623 /***********************************************************************
624 * MENU_FindItemByCoords
626 * Find the item at the specified coordinates (screen coords). Does
627 * not work for child windows and therefore should not be called for
628 * an arbitrary system menu.
630 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
,
631 POINT pt
, UINT
*pos
)
637 if (!GetWindowRect(menu
->hWnd
,&wrect
)) return NULL
;
638 pt
.x
-= wrect
.left
;pt
.y
-= wrect
.top
;
640 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
642 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
643 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
653 /***********************************************************************
656 * Find the menu item selected by a key press.
657 * Return item id, -1 if none, -2 if we should close the menu.
659 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
,
660 UINT key
, BOOL forceMenuChar
)
662 TRACE("\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
664 if (!IsMenu( hmenu
)) hmenu
= GetSubMenu( get_win_sys_menu(hwndOwner
), 0);
668 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
669 MENUITEM
*item
= menu
->items
;
677 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
679 if (item
->text
&& (IS_STRING_ITEM(item
->fType
)))
681 WCHAR
*p
= item
->text
- 2;
684 p
= strchrW (p
+ 2, '&');
686 while (p
!= NULL
&& p
[1] == '&');
687 if (p
&& (toupper(p
[1]) == key
)) return i
;
691 menuchar
= SendMessageA( hwndOwner
, WM_MENUCHAR
,
692 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
693 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
694 if (HIWORD(menuchar
) == 1) return (UINT
)(-2);
698 /***********************************************************************
701 * Load the bitmap associated with the magic menu item and its style
704 static HBITMAP
MENU_LoadMagicItem(UINT id
, BOOL hilite
, DWORD dwItemData
)
707 * Magic menu item id's section
708 * These magic id's are used by windows to insert "standard" mdi
709 * buttons (minimize,restore,close) on menu. Under windows,
710 * these magic id's make sure the right things appear when those
711 * bitmap buttons are pressed/selected/released.
715 { case HBMMENU_SYSTEM
:
716 return (dwItemData
) ?
717 (HBITMAP
)dwItemData
:
718 (hilite
? hBmpMinimizeD
: hBmpMinimize
);
719 case HBMMENU_MBAR_RESTORE
:
720 return (hilite
? hBmpMaximizeD
: hBmpMaximize
);
721 case HBMMENU_MBAR_MINIMIZE
:
722 return (hilite
? hBmpMinimizeD
: hBmpMinimize
);
723 case HBMMENU_MBAR_CLOSE
:
724 return (hilite
? hBmpCloseD
: hBmpClose
);
725 case HBMMENU_CALLBACK
:
726 case HBMMENU_MBAR_CLOSE_D
:
727 case HBMMENU_MBAR_MINIMIZE_D
:
728 case HBMMENU_POPUP_CLOSE
:
729 case HBMMENU_POPUP_RESTORE
:
730 case HBMMENU_POPUP_MAXIMIZE
:
731 case HBMMENU_POPUP_MINIMIZE
:
733 FIXME("Magic 0x%08x not implemented\n", id
);
739 /***********************************************************************
742 * Calculate the size of the menu item and store it in lpitem->rect.
744 static void MENU_CalcItemSize( HDC hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
745 INT orgX
, INT orgY
, BOOL menuBar
)
748 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
750 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
751 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem
,
752 (menuBar
? " (MenuBar)" : ""));
754 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
756 if (lpitem
->fType
& MF_OWNERDRAW
)
759 ** Experimentation under Windows reveals that an owner-drawn
760 ** menu is expected to return the size of the content part of
761 ** the menu item, not including the checkmark nor the submenu
762 ** arrow. Windows adds those values itself and returns the
763 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
765 MEASUREITEMSTRUCT mis
;
766 mis
.CtlType
= ODT_MENU
;
768 mis
.itemID
= lpitem
->wID
;
769 mis
.itemData
= (DWORD
)lpitem
->dwItemData
;
772 SendMessageA( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
773 lpitem
->rect
.right
+= mis
.itemWidth
;
777 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
780 /* under at least win95 you seem to be given a standard
781 height for the menu and the height value is ignored */
783 if (TWEAK_WineLook
== WIN31_LOOK
)
784 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
);
786 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
)-1;
789 lpitem
->rect
.bottom
+= mis
.itemHeight
;
791 TRACE("id=%04x size=%dx%d\n",
792 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
793 /* Fall through to get check/arrow width calculation. */
796 if (lpitem
->fType
& MF_SEPARATOR
)
798 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
804 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
805 if (lpitem
->fType
& MF_POPUP
)
806 lpitem
->rect
.right
+= arrow_bitmap_width
;
809 if (lpitem
->fType
& MF_OWNERDRAW
)
812 if (IS_BITMAP_ITEM(lpitem
->fType
))
817 /* Check if there is a magic menu item associated with this item */
818 if (IS_MAGIC_ITEM(lpitem
->text
))
820 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fType
& MF_HILITE
),
824 resBmp
= (HBITMAP
)lpitem
->text
;
826 if (GetObjectA(resBmp
, sizeof(bm
), &bm
))
828 lpitem
->rect
.right
+= bm
.bmWidth
;
829 lpitem
->rect
.bottom
+= bm
.bmHeight
;
830 if (TWEAK_WineLook
== WIN98_LOOK
) {
831 /* Leave space for the sunken border */
832 lpitem
->rect
.right
+= 2;
833 lpitem
->rect
.bottom
+= 2;
840 /* it must be a text item - unless it's the system menu */
841 if (!(lpitem
->fType
& MF_SYSMENU
) && IS_STRING_ITEM( lpitem
->fType
))
844 GetTextExtentPoint32W(hdc
, lpitem
->text
, strlenW(lpitem
->text
), &size
);
846 lpitem
->rect
.right
+= size
.cx
;
847 if (TWEAK_WineLook
== WIN31_LOOK
)
848 lpitem
->rect
.bottom
+= max( size
.cy
, GetSystemMetrics(SM_CYMENU
) );
850 lpitem
->rect
.bottom
+= max(size
.cy
, GetSystemMetrics(SM_CYMENU
)-1);
855 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
857 else if ((p
= strchrW( lpitem
->text
, '\t' )) != NULL
)
859 /* Item contains a tab (only meaningful in popup menus) */
860 GetTextExtentPoint32W(hdc
, lpitem
->text
, (int)(p
- lpitem
->text
) , &size
);
861 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+ size
.cx
;
862 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
866 if (strchrW( lpitem
->text
, '\b' ))
867 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
868 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
869 - arrow_bitmap_width
;
872 TRACE("(%d,%d)-(%d,%d)\n", lpitem
->rect
.left
, lpitem
->rect
.top
, lpitem
->rect
.right
, lpitem
->rect
.bottom
);
876 /***********************************************************************
877 * MENU_PopupMenuCalcSize
879 * Calculate the size of a popup menu.
881 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
886 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
888 lppop
->Width
= lppop
->Height
= 0;
889 if (lppop
->nItems
== 0) return;
892 SelectObject( hdc
, hMenuFont
);
895 maxX
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CXBORDER
) : 2+1 ;
897 while (start
< lppop
->nItems
)
899 lpitem
= &lppop
->items
[start
];
901 orgY
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CYBORDER
) : 2;
903 maxTab
= maxTabWidth
= 0;
905 /* Parse items until column break or end of menu */
906 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
909 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
911 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
913 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
914 maxX
= max( maxX
, lpitem
->rect
.right
);
915 orgY
= lpitem
->rect
.bottom
;
916 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
918 maxTab
= max( maxTab
, lpitem
->xTab
);
919 maxTabWidth
= max(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
923 /* Finish the column (set all items to the largest width found) */
924 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
925 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
927 lpitem
->rect
.right
= maxX
;
928 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
929 lpitem
->xTab
= maxTab
;
932 lppop
->Height
= max( lppop
->Height
, orgY
);
937 /* space for 3d border */
938 if(TWEAK_WineLook
> WIN31_LOOK
)
948 /***********************************************************************
949 * MENU_MenuBarCalcSize
951 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
952 * height is off by 1 pixel which causes lengthy window relocations when
953 * active document window is maximized/restored.
955 * Calculate the size of the menu bar.
957 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
,
958 LPPOPUPMENU lppop
, HWND hwndOwner
)
961 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
963 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
964 if (lppop
->nItems
== 0) return;
965 TRACE("left=%d top=%d right=%d bottom=%d\n",
966 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
967 lppop
->Width
= lprect
->right
- lprect
->left
;
969 maxY
= lprect
->top
+1;
972 while (start
< lppop
->nItems
)
974 lpitem
= &lppop
->items
[start
];
978 /* Parse items until line break or end of menu */
979 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
981 if ((helpPos
== -1) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
983 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
985 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
987 debug_print_menuitem (" item: ", lpitem
, "");
988 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
990 if (lpitem
->rect
.right
> lprect
->right
)
992 if (i
!= start
) break;
993 else lpitem
->rect
.right
= lprect
->right
;
995 maxY
= max( maxY
, lpitem
->rect
.bottom
);
996 orgX
= lpitem
->rect
.right
;
999 /* Finish the line (set all items to the largest height found) */
1000 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
1003 lprect
->bottom
= maxY
;
1004 lppop
->Height
= lprect
->bottom
- lprect
->top
;
1006 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1007 /* the last item (if several lines, only move the last line) */
1008 lpitem
= &lppop
->items
[lppop
->nItems
-1];
1009 orgY
= lpitem
->rect
.top
;
1010 orgX
= lprect
->right
;
1011 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
1012 if ( (helpPos
==-1) || (helpPos
>i
) )
1014 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
1015 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
1016 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
1017 lpitem
->rect
.right
= orgX
;
1018 orgX
= lpitem
->rect
.left
;
1022 /***********************************************************************
1025 * Draw a single menu item.
1027 static void MENU_DrawMenuItem( HWND hwnd
, HMENU hmenu
, HWND hwndOwner
, HDC hdc
, MENUITEM
*lpitem
,
1028 UINT height
, BOOL menuBar
, UINT odaction
)
1032 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
1034 if (lpitem
->fType
& MF_SYSMENU
)
1036 if( !IsIconic(hwnd
) ) {
1037 if (TWEAK_WineLook
> WIN31_LOOK
)
1038 NC_DrawSysButton95( hwnd
, hdc
,
1040 (MF_HILITE
| MF_MOUSESELECT
) );
1042 NC_DrawSysButton( hwnd
, hdc
,
1044 (MF_HILITE
| MF_MOUSESELECT
) );
1050 if (lpitem
->fType
& MF_OWNERDRAW
)
1053 ** Experimentation under Windows reveals that an owner-drawn
1054 ** menu is given the rectangle which includes the space it requested
1055 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1056 ** and a popup-menu arrow. This is the value of lpitem->rect.
1057 ** Windows will leave all drawing to the application except for
1058 ** the popup-menu arrow. Windows always draws that itself, after
1059 ** the menu owner has finished drawing.
1063 dis
.CtlType
= ODT_MENU
;
1065 dis
.itemID
= lpitem
->wID
;
1066 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1068 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1069 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
1070 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1071 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1072 dis
.hwndItem
= (HWND
)hmenu
;
1074 dis
.rcItem
= lpitem
->rect
;
1075 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1076 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner
,
1077 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1078 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1080 SendMessageA( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
1081 /* Fall through to draw popup-menu arrow */
1084 TRACE("rect={%d,%d,%d,%d}\n", lpitem
->rect
.left
, lpitem
->rect
.top
,
1085 lpitem
->rect
.right
,lpitem
->rect
.bottom
);
1087 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1089 rect
= lpitem
->rect
;
1091 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1093 if (lpitem
->fState
& MF_HILITE
)
1095 if(TWEAK_WineLook
== WIN98_LOOK
)
1098 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1100 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1102 else /* Not Win98 Look */
1104 if(!IS_BITMAP_ITEM(lpitem
->fType
))
1105 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1109 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_MENU
) );
1112 SetBkMode( hdc
, TRANSPARENT
);
1114 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1116 /* vertical separator */
1117 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1119 if (TWEAK_WineLook
> WIN31_LOOK
)
1123 rc
.bottom
= height
- 3;
1124 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1128 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1129 MoveToEx( hdc
, rect
.left
, 0, NULL
);
1130 LineTo( hdc
, rect
.left
, height
);
1134 /* horizontal separator */
1135 if (lpitem
->fType
& MF_SEPARATOR
)
1137 if (TWEAK_WineLook
> WIN31_LOOK
)
1142 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1143 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1147 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1148 MoveToEx( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2, NULL
);
1149 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1157 if (lpitem
->fState
& MF_HILITE
)
1159 if(TWEAK_WineLook
== WIN98_LOOK
)
1162 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1163 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1165 if(lpitem
->fState
& MF_GRAYED
)
1166 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1168 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1169 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1172 else /* Not Win98 Look */
1174 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1175 if(!IS_BITMAP_ITEM(lpitem
->fType
))
1176 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1181 if (lpitem
->fState
& MF_GRAYED
)
1182 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1184 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1185 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
1188 /* helper lines for debugging */
1189 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1190 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1191 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1192 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1197 INT y
= rect
.top
+ rect
.bottom
;
1198 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1199 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1201 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1203 /* Draw the check mark
1206 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1208 HBITMAP bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hCheckBit
: lpitem
->hUnCheckBit
;
1209 if (bm
) /* we have a custom bitmap */
1211 HDC hdcMem
= CreateCompatibleDC( hdc
);
1212 SelectObject( hdcMem
, bm
);
1213 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1214 check_bitmap_width
, check_bitmap_height
,
1215 hdcMem
, 0, 0, SRCCOPY
);
1218 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1221 HBITMAP bm
= CreateBitmap( check_bitmap_width
, check_bitmap_height
, 1, 1, NULL
);
1222 HDC hdcMem
= CreateCompatibleDC( hdc
);
1223 SelectObject( hdcMem
, bm
);
1224 SetRect( &r
, 0, 0, check_bitmap_width
, check_bitmap_height
);
1225 DrawFrameControl( hdcMem
, &r
, DFC_MENU
,
1226 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1227 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1228 BitBlt( hdc
, rect
.left
, (y
- r
.bottom
) / 2, r
.right
, r
.bottom
,
1229 hdcMem
, 0, 0, SRCCOPY
);
1235 /* Draw the popup-menu arrow */
1236 if (lpitem
->fType
& MF_POPUP
)
1238 HDC hdcMem
= CreateCompatibleDC( hdc
);
1239 HBITMAP hOrigBitmap
;
1241 hOrigBitmap
= SelectObject( hdcMem
, hStdMnArrow
);
1242 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1243 (y
- arrow_bitmap_height
) / 2,
1244 arrow_bitmap_width
, arrow_bitmap_height
,
1245 hdcMem
, 0, 0, SRCCOPY
);
1246 SelectObject( hdcMem
, hOrigBitmap
);
1250 rect
.left
+= check_bitmap_width
;
1251 rect
.right
-= arrow_bitmap_width
;
1254 /* Done for owner-drawn */
1255 if (lpitem
->fType
& MF_OWNERDRAW
)
1258 /* Draw the item text or bitmap */
1259 if (IS_BITMAP_ITEM(lpitem
->fType
))
1266 HDC hdcMem
= CreateCompatibleDC( hdc
);
1269 * Check if there is a magic menu item associated with this item
1270 * and load the appropriate bitmap
1272 if (IS_MAGIC_ITEM(lpitem
->text
))
1274 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fState
& MF_HILITE
),
1275 lpitem
->dwItemData
);
1278 resBmp
= (HBITMAP
)lpitem
->text
;
1283 GetObjectA( resBmp
, sizeof(bm
), &bm
);
1285 SelectObject(hdcMem
,resBmp
);
1287 /* handle fontsize > bitmap_height */
1288 h
=rect
.bottom
- rect
.top
;
1289 top
= (h
>bm
.bmHeight
) ?
1290 rect
.top
+(h
-bm
.bmHeight
)/2 : rect
.top
;
1291 w
=rect
.right
- rect
.left
;
1293 if (TWEAK_WineLook
== WIN95_LOOK
) {
1294 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_ITEM(lpitem
->text
)) ? NOTSRCCOPY
: SRCCOPY
;
1295 if ((lpitem
->fState
& MF_HILITE
) && IS_BITMAP_ITEM(lpitem
->fType
))
1296 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1300 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_ITEM(lpitem
->text
) && (!menuBar
)) ? MERGEPAINT
: SRCCOPY
;
1302 BitBlt( hdc
, left
, top
, w
,
1311 /* No bitmap - process text if present */
1312 else if (IS_STRING_ITEM(lpitem
->fType
))
1317 UINT uFormat
= (menuBar
) ?
1318 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1319 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1321 if ( lpitem
->fState
& MFS_DEFAULT
)
1323 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1328 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1329 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1330 i
= strlenW( lpitem
->text
);
1334 for (i
= 0; lpitem
->text
[i
]; i
++)
1335 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1339 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1341 if (!(lpitem
->fState
& MF_HILITE
) )
1343 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1344 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1345 DrawTextW( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1346 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1348 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1351 DrawTextW( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1353 /* paint the shortcut text */
1354 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
1356 if (lpitem
->text
[i
] == '\t')
1358 rect
.left
= lpitem
->xTab
;
1359 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1363 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1366 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1368 if (!(lpitem
->fState
& MF_HILITE
) )
1370 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1371 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1372 DrawTextW( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1373 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1375 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1377 DrawTextW( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1381 SelectObject (hdc
, hfontOld
);
1386 /***********************************************************************
1387 * MENU_DrawPopupMenu
1389 * Paint a popup menu.
1391 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
1393 HBRUSH hPrevBrush
= 0;
1396 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd
, hdc
, hmenu
);
1398 GetClientRect( hwnd
, &rect
);
1400 if(TWEAK_WineLook
== WIN31_LOOK
)
1402 rect
.bottom
-= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1403 rect
.right
-= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
);
1406 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1407 && (SelectObject( hdc
, hMenuFont
)))
1411 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1413 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1419 /* draw 3-d shade */
1420 if(TWEAK_WineLook
== WIN31_LOOK
) {
1421 SelectObject( hdc
, hShadeBrush
);
1422 SetBkMode( hdc
, TRANSPARENT
);
1423 ropPrev
= SetROP2( hdc
, R2_MASKPEN
);
1425 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
1426 PatBlt( hdc
, i
& 0xfffffffe,
1427 rect
.top
+ POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
),
1428 i
%2 + POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1429 rect
.bottom
- rect
.top
, 0x00a000c9 );
1431 PatBlt( hdc
, rect
.left
+ POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1432 i
& 0xfffffffe,rect
.right
- rect
.left
,
1433 i
%2 + POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
), 0x00a000c9 );
1434 SelectObject( hdc
, hPrevPen
);
1435 SelectObject( hdc
, hPrevBrush
);
1436 SetROP2( hdc
, ropPrev
);
1439 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1441 /* draw menu items */
1443 menu
= MENU_GetMenu( hmenu
);
1444 if (menu
&& menu
->nItems
)
1449 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1450 MENU_DrawMenuItem( hwnd
, hmenu
, menu
->hwndOwner
, hdc
, item
,
1451 menu
->Height
, FALSE
, ODA_DRAWENTIRE
);
1456 SelectObject( hdc
, hPrevBrush
);
1461 /***********************************************************************
1464 * Paint a menu bar. Returns the height of the menu bar.
1465 * called from [windows/nonclient.c]
1467 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1473 HMENU hMenu
= GetMenu(hwnd
);
1475 lppop
= MENU_GetMenu( hMenu
);
1476 if (lppop
== NULL
|| lprect
== NULL
)
1478 retvalue
= GetSystemMetrics(SM_CYMENU
);
1482 TRACE("(%04x, %p, %p)\n", hDC
, lprect
, lppop
);
1484 hfontOld
= SelectObject( hDC
, hMenuFont
);
1486 if (lppop
->Height
== 0)
1487 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1489 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1493 retvalue
= lppop
->Height
;
1497 FillRect(hDC
, lprect
, GetSysColorBrush(COLOR_MENU
) );
1499 if (TWEAK_WineLook
== WIN31_LOOK
)
1501 SelectObject( hDC
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1502 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
1503 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1507 SelectObject( hDC
, GetSysColorPen(COLOR_3DFACE
));
1508 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
1509 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1512 if (lppop
->nItems
== 0)
1514 retvalue
= GetSystemMetrics(SM_CYMENU
);
1518 for (i
= 0; i
< lppop
->nItems
; i
++)
1520 MENU_DrawMenuItem( hwnd
, hMenu
, hwnd
,
1521 hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
, ODA_DRAWENTIRE
);
1523 retvalue
= lppop
->Height
;
1526 if (hfontOld
) SelectObject (hDC
, hfontOld
);
1531 /***********************************************************************
1534 * Display a popup menu.
1536 static BOOL
MENU_ShowPopup( HWND hwndOwner
, HMENU hmenu
, UINT id
,
1537 INT x
, INT y
, INT xanchor
, INT yanchor
)
1542 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1543 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1545 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
1546 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1548 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1549 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1552 /* store the owner for DrawItem */
1553 menu
->hwndOwner
= hwndOwner
;
1556 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1558 /* adjust popup menu pos so that it fits within the desktop */
1560 width
= menu
->Width
+ GetSystemMetrics(SM_CXBORDER
);
1561 height
= menu
->Height
+ GetSystemMetrics(SM_CYBORDER
);
1563 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1566 x
-= width
- xanchor
;
1567 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1568 x
= GetSystemMetrics(SM_CXSCREEN
) - width
;
1572 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1575 y
-= height
+ yanchor
;
1576 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1577 y
= GetSystemMetrics(SM_CYSCREEN
) - height
;
1581 if( TWEAK_WineLook
== WIN31_LOOK
)
1583 width
+= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
); /* add space for shading */
1584 height
+= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1587 /* NOTE: In Windows, top menu popup is not owned. */
1588 menu
->hWnd
= CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1589 WS_POPUP
, x
, y
, width
, height
,
1590 hwndOwner
, 0, GetWindowLongA(hwndOwner
,GWL_HINSTANCE
),
1592 if( !menu
->hWnd
) return FALSE
;
1593 if (!top_popup
) top_popup
= menu
->hWnd
;
1595 /* Display the window */
1597 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1598 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1599 UpdateWindow( menu
->hWnd
);
1604 /***********************************************************************
1607 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
1608 BOOL sendMenuSelect
, HMENU topmenu
)
1613 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1615 lppop
= MENU_GetMenu( hmenu
);
1616 if ((!lppop
) || (!lppop
->nItems
) || (!lppop
->hWnd
)) return;
1618 if (lppop
->FocusedItem
== wIndex
) return;
1619 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
1620 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1622 SelectObject( hdc
, hMenuFont
);
1624 /* Clear previous highlighted item */
1625 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1627 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1628 MENU_DrawMenuItem(lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,&lppop
->items
[lppop
->FocusedItem
],
1629 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1633 /* Highlight new item (if any) */
1634 lppop
->FocusedItem
= wIndex
;
1635 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1637 if(!(lppop
->items
[wIndex
].fType
& MF_SEPARATOR
)) {
1638 lppop
->items
[wIndex
].fState
|= MF_HILITE
;
1639 MENU_DrawMenuItem( lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,
1640 &lppop
->items
[wIndex
], lppop
->Height
,
1641 !(lppop
->wFlags
& MF_POPUP
), ODA_SELECT
);
1645 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1646 SendMessageA( hwndOwner
, WM_MENUSELECT
,
1647 MAKELONG(ip
->fType
& MF_POPUP
? wIndex
: ip
->wID
,
1648 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1649 (lppop
->wFlags
& MF_SYSMENU
)), hmenu
);
1652 else if (sendMenuSelect
) {
1655 if((pos
=MENU_FindSubMenu(&topmenu
, hmenu
))!=NO_SELECTED_ITEM
){
1656 POPUPMENU
*ptm
= MENU_GetMenu( topmenu
);
1657 MENUITEM
*ip
= &ptm
->items
[pos
];
1658 SendMessageA( hwndOwner
, WM_MENUSELECT
, MAKELONG(pos
,
1659 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1660 (ptm
->wFlags
& MF_SYSMENU
)), topmenu
);
1664 ReleaseDC( lppop
->hWnd
, hdc
);
1668 /***********************************************************************
1669 * MENU_MoveSelection
1671 * Moves currently selected item according to the offset parameter.
1672 * If there is no selection then it should select the last item if
1673 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1675 static void MENU_MoveSelection( HWND hwndOwner
, HMENU hmenu
, INT offset
)
1680 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner
, hmenu
, offset
);
1682 menu
= MENU_GetMenu( hmenu
);
1683 if ((!menu
) || (!menu
->items
)) return;
1685 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1687 if( menu
->nItems
== 1 ) return; else
1688 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1690 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1692 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1697 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1698 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1699 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1701 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1707 /**********************************************************************
1710 * Set an item flags, id and text ptr. Called by InsertMenu() and
1713 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
,
1716 LPWSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1718 debug_print_menuitem("MENU_SetItemData from: ", item
, "");
1719 TRACE("flags=%x str=%p\n", flags
, str
);
1721 if (IS_STRING_ITEM(flags
))
1725 flags
|= MF_SEPARATOR
;
1731 /* Item beginning with a backspace is a help item */
1737 if (!(text
= HeapAlloc( GetProcessHeap(), 0, (strlenW(str
)+1) * sizeof(WCHAR
) )))
1739 strcpyW( text
, str
);
1743 else if (IS_BITMAP_ITEM(flags
))
1744 item
->text
= (LPWSTR
)(HBITMAP
)LOWORD(str
);
1745 else item
->text
= NULL
;
1747 if (flags
& MF_OWNERDRAW
)
1748 item
->dwItemData
= (DWORD
)str
;
1750 item
->dwItemData
= 0;
1752 if ((item
->fType
& MF_POPUP
) && (flags
& MF_POPUP
) && (item
->hSubMenu
!= id
) )
1753 DestroyMenu( item
->hSubMenu
); /* ModifyMenu() spec */
1755 if (flags
& MF_POPUP
)
1757 POPUPMENU
*menu
= MENU_GetMenu((UINT16
)id
);
1758 if (menu
) menu
->wFlags
|= MF_POPUP
;
1770 if (flags
& MF_POPUP
)
1771 item
->hSubMenu
= id
;
1773 if ((item
->fType
& MF_POPUP
) && !(flags
& MF_POPUP
) )
1774 flags
|= MF_POPUP
; /* keep popup */
1776 item
->fType
= flags
& TYPE_MASK
;
1777 item
->fState
= (flags
& STATE_MASK
) &
1778 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1781 /* Don't call SetRectEmpty here! */
1784 if (prevText
) HeapFree( GetProcessHeap(), 0, prevText
);
1786 debug_print_menuitem("MENU_SetItemData to : ", item
, "");
1791 /**********************************************************************
1794 * Insert a new item into a menu.
1796 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
1801 if (!(menu
= MENU_GetMenu(hMenu
)))
1804 /* Find where to insert new item */
1806 if (flags
& MF_BYPOSITION
) {
1807 if (pos
> menu
->nItems
)
1810 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1813 if (!(menu
= MENU_GetMenu( hMenu
)))
1818 /* Create new items array */
1820 newItems
= HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1823 WARN("allocation failed\n" );
1826 if (menu
->nItems
> 0)
1828 /* Copy the old array into the new one */
1829 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1830 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1831 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1832 HeapFree( GetProcessHeap(), 0, menu
->items
);
1834 menu
->items
= newItems
;
1836 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1837 menu
->Height
= 0; /* force size recalculate */
1838 return &newItems
[pos
];
1842 /**********************************************************************
1843 * MENU_ParseResource
1845 * Parse a standard menu resource and add items to the menu.
1846 * Return a pointer to the end of the resource.
1848 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1855 flags
= GET_WORD(res
);
1856 res
+= sizeof(WORD
);
1857 if (!(flags
& MF_POPUP
))
1860 res
+= sizeof(WORD
);
1862 if (!IS_STRING_ITEM(flags
))
1863 ERR("not a string item %04x\n", flags
);
1865 if (!unicode
) res
+= strlen(str
) + 1;
1866 else res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1867 if (flags
& MF_POPUP
)
1869 HMENU hSubMenu
= CreatePopupMenu();
1870 if (!hSubMenu
) return NULL
;
1871 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1873 if (!unicode
) AppendMenuA( hMenu
, flags
, (UINT
)hSubMenu
, str
);
1874 else AppendMenuW( hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1876 else /* Not a popup */
1878 if (!unicode
) AppendMenuA( hMenu
, flags
, id
, *str
? str
: NULL
);
1879 else AppendMenuW( hMenu
, flags
, id
,
1880 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1882 } while (!(flags
& MF_END
));
1887 /**********************************************************************
1888 * MENUEX_ParseResource
1890 * Parse an extended menu resource and add items to the menu.
1891 * Return a pointer to the end of the resource.
1893 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1899 mii
.cbSize
= sizeof(mii
);
1900 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
1901 mii
.fType
= GET_DWORD(res
);
1902 res
+= sizeof(DWORD
);
1903 mii
.fState
= GET_DWORD(res
);
1904 res
+= sizeof(DWORD
);
1905 mii
.wID
= GET_DWORD(res
);
1906 res
+= sizeof(DWORD
);
1907 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
1908 res
+= sizeof(WORD
);
1909 /* Align the text on a word boundary. */
1910 res
+= (~((int)res
- 1)) & 1;
1911 mii
.dwTypeData
= (LPWSTR
) res
;
1912 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1913 /* Align the following fields on a dword boundary. */
1914 res
+= (~((int)res
- 1)) & 3;
1916 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1917 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, debugstr_w(mii
.dwTypeData
));
1919 if (resinfo
& 1) { /* Pop-up? */
1920 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1921 res
+= sizeof(DWORD
);
1922 mii
.hSubMenu
= CreatePopupMenu();
1925 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
1926 DestroyMenu(mii
.hSubMenu
);
1929 mii
.fMask
|= MIIM_SUBMENU
;
1930 mii
.fType
|= MF_POPUP
;
1932 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1933 } while (!(resinfo
& MF_END
));
1938 /***********************************************************************
1941 * Return the handle of the selected sub-popup menu (if any).
1943 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
1948 menu
= MENU_GetMenu( hmenu
);
1950 if ((!menu
) || (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return 0;
1952 item
= &menu
->items
[menu
->FocusedItem
];
1953 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
1954 return item
->hSubMenu
;
1959 /***********************************************************************
1960 * MENU_HideSubPopups
1962 * Hide the sub-popup menus of this menu.
1964 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
1965 BOOL sendMenuSelect
)
1967 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
1969 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, sendMenuSelect
);
1971 if (menu
&& top_popup
)
1977 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1979 item
= &menu
->items
[menu
->FocusedItem
];
1980 if (!(item
->fType
& MF_POPUP
) ||
1981 !(item
->fState
& MF_MOUSESELECT
)) return;
1982 item
->fState
&= ~MF_MOUSESELECT
;
1983 hsubmenu
= item
->hSubMenu
;
1986 submenu
= MENU_GetMenu( hsubmenu
);
1987 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
1988 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
, 0 );
1989 DestroyWindow( submenu
->hWnd
);
1995 /***********************************************************************
1998 * Display the sub-menu of the selected item of this menu.
1999 * Return the handle of the submenu, or hmenu if no submenu to display.
2001 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
,
2002 BOOL selectFirst
, UINT wFlags
)
2009 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, selectFirst
);
2011 if (!(menu
= MENU_GetMenu( hmenu
))) return hmenu
;
2013 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return hmenu
;
2015 item
= &menu
->items
[menu
->FocusedItem
];
2016 if (!(item
->fType
& MF_POPUP
) || (item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2019 /* message must be sent before using item,
2020 because nearly everything may be changed by the application ! */
2022 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2023 if (!(wFlags
& TPM_NONOTIFY
))
2024 SendMessageA( hwndOwner
, WM_INITMENUPOPUP
, item
->hSubMenu
,
2025 MAKELONG( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
2027 item
= &menu
->items
[menu
->FocusedItem
];
2030 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2031 if (!(item
->fState
& MF_HILITE
))
2033 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC( menu
->hWnd
);
2034 else hdc
= GetDCEx( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2036 SelectObject( hdc
, hMenuFont
);
2038 item
->fState
|= MF_HILITE
;
2039 MENU_DrawMenuItem( menu
->hWnd
, hmenu
, hwndOwner
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
2040 ReleaseDC( menu
->hWnd
, hdc
);
2042 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
2045 item
->fState
|= MF_MOUSESELECT
;
2047 if (IS_SYSTEM_MENU(menu
))
2049 MENU_InitSysMenuPopup(item
->hSubMenu
,
2050 GetWindowLongA( menu
->hWnd
, GWL_STYLE
),
2051 GetClassLongA( menu
->hWnd
, GCL_STYLE
));
2053 NC_GetSysPopupPos( menu
->hWnd
, &rect
);
2054 rect
.top
= rect
.bottom
;
2055 rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2056 rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2060 GetWindowRect( menu
->hWnd
, &rect
);
2061 if (menu
->wFlags
& MF_POPUP
)
2063 rect
.left
+= item
->rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2064 rect
.top
+= item
->rect
.top
;
2065 rect
.right
= item
->rect
.left
- item
->rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2066 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
2070 rect
.left
+= item
->rect
.left
;
2071 rect
.top
+= item
->rect
.bottom
;
2072 rect
.right
= item
->rect
.right
- item
->rect
.left
;
2073 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
2077 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
2078 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2080 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
2081 return item
->hSubMenu
;
2086 /**********************************************************************
2089 BOOL
MENU_IsMenuActive(void)
2091 return (top_popup
!= 0);
2094 /***********************************************************************
2097 * Walks menu chain trying to find a menu pt maps to.
2099 static HMENU
MENU_PtMenu( HMENU hMenu
, POINT pt
)
2101 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2102 UINT item
= menu
->FocusedItem
;
2105 /* try subpopup first (if any) */
2106 ret
= (item
!= NO_SELECTED_ITEM
&&
2107 (menu
->items
[item
].fType
& MF_POPUP
) &&
2108 (menu
->items
[item
].fState
& MF_MOUSESELECT
))
2109 ? MENU_PtMenu(menu
->items
[item
].hSubMenu
, pt
) : 0;
2111 if (!ret
) /* check the current window (avoiding WM_HITTEST) */
2113 INT ht
= NC_HandleNCHitTest( menu
->hWnd
, pt
);
2114 if( menu
->wFlags
& MF_POPUP
)
2116 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= hMenu
;
2118 else if (ht
== HTSYSMENU
)
2119 ret
= get_win_sys_menu( menu
->hWnd
);
2120 else if (ht
== HTMENU
)
2121 ret
= GetMenu( menu
->hWnd
);
2126 /***********************************************************************
2127 * MENU_ExecFocusedItem
2129 * Execute a menu item (for instance when user pressed Enter).
2130 * Return the wID of the executed item. Otherwise, -1 indicating
2131 * that no menu item was executed;
2132 * Have to receive the flags for the TrackPopupMenu options to avoid
2133 * sending unwanted message.
2136 static INT
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU hMenu
, UINT wFlags
)
2139 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2141 TRACE("%p hmenu=0x%04x\n", pmt
, hMenu
);
2143 if (!menu
|| !menu
->nItems
||
2144 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return -1;
2146 item
= &menu
->items
[menu
->FocusedItem
];
2148 TRACE("%08x %08x %08x\n",
2149 hMenu
, item
->wID
, item
->hSubMenu
);
2151 if (!(item
->fType
& MF_POPUP
))
2153 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(item
->fType
& MF_SEPARATOR
))
2155 /* If TPM_RETURNCMD is set you return the id, but
2156 do not send a message to the owner */
2157 if(!(wFlags
& TPM_RETURNCMD
))
2159 if( menu
->wFlags
& MF_SYSMENU
)
2160 PostMessageA( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
2161 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
2163 PostMessageA( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
2169 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hMenu
, TRUE
, wFlags
);
2174 /***********************************************************************
2175 * MENU_SwitchTracking
2177 * Helper function for menu navigation routines.
2179 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU hPtMenu
, UINT id
)
2181 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2182 POPUPMENU
*topmenu
= MENU_GetMenu( pmt
->hTopMenu
);
2184 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt
, hPtMenu
, id
);
2186 if( pmt
->hTopMenu
!= hPtMenu
&&
2187 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
2189 /* both are top level menus (system and menu-bar) */
2190 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2191 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2192 pmt
->hTopMenu
= hPtMenu
;
2194 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2195 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
, 0 );
2199 /***********************************************************************
2202 * Return TRUE if we can go on with menu tracking.
2204 static BOOL
MENU_ButtonDown( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2206 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2211 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2214 if( IS_SYSTEM_MENU(ptmenu
) )
2215 item
= ptmenu
->items
;
2217 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2221 if( ptmenu
->FocusedItem
!= id
)
2222 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2224 /* If the popup menu is not already "popped" */
2225 if(!(item
->fState
& MF_MOUSESELECT
))
2227 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2229 /* In win31, a newly popped menu always remains opened for the next buttonup */
2230 if(TWEAK_WineLook
== WIN31_LOOK
)
2231 ptmenu
->bTimeToHide
= FALSE
;
2236 /* Else the click was on the menu bar, finish the tracking */
2241 /***********************************************************************
2244 * Return the value of MENU_ExecFocusedItem if
2245 * the selected item was not a popup. Else open the popup.
2246 * A -1 return value indicates that we go on with menu tracking.
2249 static INT
MENU_ButtonUp( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2251 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2256 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2259 if( IS_SYSTEM_MENU(ptmenu
) )
2260 item
= ptmenu
->items
;
2262 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2264 if( item
&& (ptmenu
->FocusedItem
== id
))
2266 if( !(item
->fType
& MF_POPUP
) )
2267 return MENU_ExecFocusedItem( pmt
, hPtMenu
, wFlags
);
2269 /* If we are dealing with the top-level menu */
2270 /* and this is a click on an already "popped" item: */
2271 /* Stop the menu tracking and close the opened submenus */
2272 if((pmt
->hTopMenu
== hPtMenu
) && (ptmenu
->bTimeToHide
== TRUE
))
2275 ptmenu
->bTimeToHide
= TRUE
;
2281 /***********************************************************************
2284 * Return TRUE if we can go on with menu tracking.
2286 static BOOL
MENU_MouseMove( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2288 UINT id
= NO_SELECTED_ITEM
;
2289 POPUPMENU
*ptmenu
= NULL
;
2293 ptmenu
= MENU_GetMenu( hPtMenu
);
2294 if( IS_SYSTEM_MENU(ptmenu
) )
2297 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2300 if( id
== NO_SELECTED_ITEM
)
2302 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2303 NO_SELECTED_ITEM
, TRUE
, pmt
->hTopMenu
);
2306 else if( ptmenu
->FocusedItem
!= id
)
2308 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2309 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2315 /***********************************************************************
2318 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2320 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT vk
)
2322 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2324 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
2325 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
2327 MDINEXTMENU next_menu
;
2332 next_menu
.hmenuIn
= (IS_SYSTEM_MENU(menu
)) ? GetSubMenu(pmt
->hTopMenu
,0) : pmt
->hTopMenu
;
2333 next_menu
.hmenuNext
= 0;
2334 next_menu
.hwndNext
= 0;
2335 SendMessageW( pmt
->hOwnerWnd
, WM_NEXTMENU
, vk
, (LPARAM
)&next_menu
);
2337 TRACE("%04x [%04x] -> %04x [%04x]\n",
2338 pmt
->hCurrentMenu
, pmt
->hOwnerWnd
, next_menu
.hmenuNext
, next_menu
.hwndNext
);
2340 if (!next_menu
.hmenuNext
|| !next_menu
.hwndNext
)
2342 DWORD style
= GetWindowLongA( pmt
->hOwnerWnd
, GWL_STYLE
);
2343 hNewWnd
= pmt
->hOwnerWnd
;
2344 if( IS_SYSTEM_MENU(menu
) )
2346 /* switch to the menu bar */
2348 if(style
& WS_CHILD
|| !(hNewMenu
= GetMenu(hNewWnd
))) return FALSE
;
2352 menu
= MENU_GetMenu( hNewMenu
);
2353 id
= menu
->nItems
- 1;
2356 else if (style
& WS_SYSMENU
)
2358 /* switch to the system menu */
2359 hNewMenu
= get_win_sys_menu( hNewWnd
);
2363 else /* application returned a new menu to switch to */
2365 hNewMenu
= next_menu
.hmenuNext
;
2366 hNewWnd
= WIN_GetFullHandle( next_menu
.hwndNext
);
2368 if( IsMenu(hNewMenu
) && IsWindow(hNewWnd
) )
2370 DWORD style
= GetWindowLongA( hNewWnd
, GWL_STYLE
);
2372 if (style
& WS_SYSMENU
&&
2373 GetSubMenu(get_win_sys_menu(hNewWnd
), 0) == hNewMenu
)
2375 /* get the real system menu */
2376 hNewMenu
= get_win_sys_menu(hNewWnd
);
2378 else if (style
& WS_CHILD
|| GetMenu(hNewWnd
) != hNewMenu
)
2380 /* FIXME: Not sure what to do here;
2381 * perhaps try to track hNewMenu as a popup? */
2383 TRACE(" -- got confused.\n");
2390 if( hNewMenu
!= pmt
->hTopMenu
)
2392 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
,
2394 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2395 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2398 if( hNewWnd
!= pmt
->hOwnerWnd
)
2401 pmt
->hOwnerWnd
= hNewWnd
;
2402 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
2405 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2406 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
, 0 );
2413 /***********************************************************************
2416 * The idea is not to show the popup if the next input message is
2417 * going to hide it anyway.
2419 static BOOL
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2423 msg
.hwnd
= pmt
->hOwnerWnd
;
2425 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2426 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2431 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2432 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2434 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2435 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2436 if( msg
.message
== WM_KEYDOWN
&&
2437 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2439 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2446 /* failures go through this */
2447 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2451 /***********************************************************************
2454 * Handle a VK_ESCAPE key event in a menu.
2456 static BOOL
MENU_KeyEscape(MTRACKER
* pmt
, UINT wFlags
)
2458 BOOL bEndMenu
= TRUE
;
2460 if (pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2462 POPUPMENU
*menu
= MENU_GetMenu(pmt
->hCurrentMenu
);
2464 if (menu
->wFlags
& MF_POPUP
)
2466 HMENU hmenutmp
, hmenuprev
;
2468 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2470 /* close topmost popup */
2471 while (hmenutmp
!= pmt
->hCurrentMenu
)
2473 hmenuprev
= hmenutmp
;
2474 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2477 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2478 pmt
->hCurrentMenu
= hmenuprev
;
2486 /***********************************************************************
2489 * Handle a VK_LEFT key event in a menu.
2491 static void MENU_KeyLeft( MTRACKER
* pmt
, UINT wFlags
)
2494 HMENU hmenutmp
, hmenuprev
;
2497 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2498 menu
= MENU_GetMenu( hmenutmp
);
2500 /* Try to move 1 column left (if possible) */
2501 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2502 NO_SELECTED_ITEM
) {
2504 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2509 /* close topmost popup */
2510 while (hmenutmp
!= pmt
->hCurrentMenu
)
2512 hmenuprev
= hmenutmp
;
2513 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2516 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2517 pmt
->hCurrentMenu
= hmenuprev
;
2519 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2521 /* move menu bar selection if no more popups are left */
2523 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2524 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2526 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2528 /* A sublevel menu was displayed - display the next one
2529 * unless there is another displacement coming up */
2531 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2532 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2533 pmt
->hTopMenu
, TRUE
, wFlags
);
2539 /***********************************************************************
2542 * Handle a VK_RIGHT key event in a menu.
2544 static void MENU_KeyRight( MTRACKER
* pmt
, UINT wFlags
)
2547 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2550 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2552 debugstr_w((MENU_GetMenu(pmt
->hCurrentMenu
))->
2554 pmt
->hTopMenu
, debugstr_w(menu
->items
[0].text
) );
2556 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2558 /* If already displaying a popup, try to display sub-popup */
2560 hmenutmp
= pmt
->hCurrentMenu
;
2561 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hmenutmp
, TRUE
, wFlags
);
2563 /* if subpopup was displayed then we are done */
2564 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2567 /* Check to see if there's another column */
2568 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2569 NO_SELECTED_ITEM
) {
2570 TRACE("Going to %d.\n", nextcol
);
2571 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2576 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2578 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2580 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2581 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2582 } else hmenutmp
= 0;
2584 /* try to move to the next item */
2585 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2586 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2588 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2589 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2590 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2591 pmt
->hTopMenu
, TRUE
, wFlags
);
2595 /***********************************************************************
2598 * Menu tracking code.
2600 static INT
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
2601 HWND hwnd
, const RECT
*lprect
)
2606 INT executedMenuId
= -1;
2608 BOOL enterIdleSent
= FALSE
;
2611 mt
.hCurrentMenu
= hmenu
;
2612 mt
.hTopMenu
= hmenu
;
2613 mt
.hOwnerWnd
= WIN_GetFullHandle( hwnd
);
2617 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2618 hmenu
, wFlags
, x
, y
, hwnd
, (lprect
) ? lprect
->left
: 0, (lprect
) ? lprect
->top
: 0,
2619 (lprect
) ? lprect
->right
: 0, (lprect
) ? lprect
->bottom
: 0);
2622 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
2624 if (wFlags
& TPM_BUTTONDOWN
)
2626 /* Get the result in order to start the tracking or not */
2627 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2628 fEndMenu
= !fRemove
;
2631 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
2635 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2636 if (!menu
) /* sometimes happens if I do a window manager close */
2639 /* we have to keep the message in the queue until it's
2640 * clear that menu loop is not over yet. */
2644 if (PeekMessageA( &msg
, 0, 0, 0, PM_NOREMOVE
))
2646 if (!CallMsgFilterA( &msg
, MSGF_MENU
)) break;
2647 /* remove the message from the queue */
2648 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2654 HWND win
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2655 enterIdleSent
= TRUE
;
2656 SendMessageW( mt
.hOwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
)win
);
2662 /* check if EndMenu() tried to cancel us, by posting this message */
2663 if(msg
.message
== WM_CANCELMODE
)
2665 /* we are now out of the loop */
2668 /* remove the message from the queue */
2669 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2671 /* break out of internal loop, ala ESCAPE */
2675 TranslateMessage( &msg
);
2678 if ( (msg
.hwnd
==menu
->hWnd
) || (msg
.message
!=WM_TIMER
) )
2679 enterIdleSent
=FALSE
;
2682 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2685 * use the mouse coordinates in lParam instead of those in the MSG
2686 * struct to properly handle synthetic messages. lParam coords are
2687 * relative to client area, so they must be converted; since they can
2688 * be negative, we must use SLOWORD/SHIWORD instead of LOWORD/HIWORD.
2690 mt
.pt
.x
= SLOWORD(msg
.lParam
);
2691 mt
.pt
.y
= SHIWORD(msg
.lParam
);
2692 ClientToScreen(msg
.hwnd
,&mt
.pt
);
2694 /* Find a menu for this mouse event */
2695 hmenu
= MENU_PtMenu( mt
.hTopMenu
, mt
.pt
);
2699 /* no WM_NC... messages in captured state */
2701 case WM_RBUTTONDBLCLK
:
2702 case WM_RBUTTONDOWN
:
2703 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2705 case WM_LBUTTONDBLCLK
:
2706 case WM_LBUTTONDOWN
:
2707 /* If the message belongs to the menu, removes it from the queue */
2708 /* Else, end menu tracking */
2709 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2710 fEndMenu
= !fRemove
;
2714 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2717 /* Check if a menu was selected by the mouse */
2720 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
2722 /* End the loop if executedMenuId is an item ID */
2723 /* or if the job was done (executedMenuId = 0). */
2724 fEndMenu
= fRemove
= (executedMenuId
!= -1);
2726 /* No menu was selected by the mouse */
2727 /* if the function was called by TrackPopupMenu, continue
2728 with the menu tracking. If not, stop it */
2730 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
2735 /* In win95 winelook, the selected menu item must be changed every time the
2736 mouse moves. In Win31 winelook, the mouse button has to be held down */
2738 if ( (TWEAK_WineLook
> WIN31_LOOK
) ||
2739 ( (msg
.wParam
& MK_LBUTTON
) ||
2740 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
))) )
2742 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
, wFlags
);
2744 } /* switch(msg.message) - mouse */
2746 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2748 fRemove
= TRUE
; /* Keyboard messages are always removed */
2756 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2757 NO_SELECTED_ITEM
, FALSE
, 0 );
2760 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2761 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2764 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2766 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2767 if (!(menu
->wFlags
& MF_POPUP
))
2768 mt
.hCurrentMenu
= MENU_ShowSubPopup(mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
, wFlags
);
2769 else /* otherwise try to move selection */
2770 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2774 MENU_KeyLeft( &mt
, wFlags
);
2778 MENU_KeyRight( &mt
, wFlags
);
2782 fEndMenu
= MENU_KeyEscape(&mt
, wFlags
);
2788 hi
.cbSize
= sizeof(HELPINFO
);
2789 hi
.iContextType
= HELPINFO_MENUITEM
;
2790 if (menu
->FocusedItem
== NO_SELECTED_ITEM
)
2793 hi
.iCtrlId
= menu
->items
[menu
->FocusedItem
].wID
;
2794 hi
.hItemHandle
= hmenu
;
2795 hi
.dwContextId
= menu
->dwContextHelpID
;
2796 hi
.MousePos
= msg
.pt
;
2797 SendMessageA(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
2804 break; /* WM_KEYDOWN */
2814 break; /* WM_SYSKEYDOWN */
2820 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
2822 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2823 fEndMenu
= (executedMenuId
!= -1);
2828 /* Hack to avoid control chars. */
2829 /* We will find a better way real soon... */
2830 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2832 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2833 LOWORD(msg
.wParam
), FALSE
);
2834 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
2835 else if (pos
== (UINT
)-1) MessageBeep(0);
2838 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
,
2840 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2841 fEndMenu
= (executedMenuId
!= -1);
2845 } /* switch(msg.message) - kbd */
2849 DispatchMessageA( &msg
);
2852 if (!fEndMenu
) fRemove
= TRUE
;
2854 /* finally remove message from the queue */
2856 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2857 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2858 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2863 /* If dropdown is still painted and the close box is clicked on
2864 then the menu will be destroyed as part of the DispatchMessage above.
2865 This will then invalidate the menu handle in mt.hTopMenu. We should
2866 check for this first. */
2867 if( IsMenu( mt
.hTopMenu
) )
2869 menu
= MENU_GetMenu( mt
.hTopMenu
);
2871 if( IsWindow( mt
.hOwnerWnd
) )
2873 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2875 if (menu
&& menu
->wFlags
& MF_POPUP
)
2877 DestroyWindow( menu
->hWnd
);
2880 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2881 SendMessageA( mt
.hOwnerWnd
, WM_MENUSELECT
, MAKELONG(0,0xffff), 0 );
2884 /* Reset the variable for hiding menu */
2885 if( menu
) menu
->bTimeToHide
= FALSE
;
2888 /* The return value is only used by TrackPopupMenu */
2889 return ((executedMenuId
!= -1) ? executedMenuId
: 0);
2892 /***********************************************************************
2895 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
2897 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd
, hMenu
);
2901 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2902 if (!(wFlags
& TPM_NONOTIFY
))
2903 SendMessageA( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
2905 SendMessageA( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
2907 if (!(wFlags
& TPM_NONOTIFY
))
2910 SendMessageA( hWnd
, WM_INITMENU
, hMenu
, 0 );
2911 if ((menu
= MENU_GetMenu( hMenu
)) && (!menu
->Height
))
2912 { /* app changed/recreated menu bar entries in WM_INITMENU
2913 Recalculate menu sizes else clicks will not work */
2914 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2915 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2921 /***********************************************************************
2924 static BOOL
MENU_ExitTracking(HWND hWnd
)
2926 TRACE("hwnd=0x%04x\n", hWnd
);
2928 SendMessageA( hWnd
, WM_EXITMENULOOP
, 0, 0 );
2933 /***********************************************************************
2934 * MENU_TrackMouseMenuBar
2936 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2938 void MENU_TrackMouseMenuBar( HWND hWnd
, INT ht
, POINT pt
)
2940 HMENU hMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( hWnd
) : GetMenu( hWnd
);
2941 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
2943 TRACE("wnd=%x ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
2947 /* map point to parent client coordinates */
2948 HWND parent
= GetAncestor( hWnd
, GA_PARENT
);
2949 if (parent
!= GetDesktopWindow()) ScreenToClient( parent
, &pt
);
2951 MENU_InitTracking( hWnd
, hMenu
, FALSE
, wFlags
);
2952 MENU_TrackMenu( hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
2953 MENU_ExitTracking(hWnd
);
2958 /***********************************************************************
2959 * MENU_TrackKbdMenuBar
2961 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2963 void MENU_TrackKbdMenuBar( HWND hwnd
, UINT wParam
, INT vkey
)
2965 UINT uItem
= NO_SELECTED_ITEM
;
2967 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
2969 /* find window that has a menu */
2971 while (GetWindowLongA( hwnd
, GWL_STYLE
) & WS_CHILD
)
2972 if (!(hwnd
= GetParent( hwnd
))) return;
2974 /* check if we have to track a system menu */
2976 hTrackMenu
= GetMenu( hwnd
);
2977 if (!hTrackMenu
|| IsIconic(hwnd
) || vkey
== VK_SPACE
)
2979 if (!(GetWindowLongA( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
2980 hTrackMenu
= get_win_sys_menu( hwnd
);
2982 wParam
|= HTSYSMENU
; /* prevent item lookup */
2985 if (!IsMenu( hTrackMenu
)) return;
2987 MENU_InitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
2989 if( vkey
&& vkey
!= VK_SPACE
)
2991 uItem
= MENU_FindItemByKey( hwnd
, hTrackMenu
, vkey
, (wParam
& HTSYSMENU
) );
2992 if( uItem
>= (UINT
)(-2) )
2994 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3001 MENU_SelectItem( hwnd
, hTrackMenu
, uItem
, TRUE
, 0 );
3003 if( uItem
== NO_SELECTED_ITEM
)
3004 MENU_MoveSelection( hwnd
, hTrackMenu
, ITEM_NEXT
);
3006 PostMessageA( hwnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3008 MENU_TrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
3010 MENU_ExitTracking( hwnd
);
3014 /**********************************************************************
3015 * TrackPopupMenu (USER32.@)
3017 * Like the win32 API, the function return the command ID only if the
3018 * flag TPM_RETURNCMD is on.
3021 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3022 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
3026 MENU_InitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
3028 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3029 if (!(wFlags
& TPM_NONOTIFY
))
3030 SendMessageA( hWnd
, WM_INITMENUPOPUP
, hMenu
, 0);
3032 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
3033 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
, lpRect
);
3034 MENU_ExitTracking(hWnd
);
3036 if( (!(wFlags
& TPM_RETURNCMD
)) && (ret
!= FALSE
) )
3042 /**********************************************************************
3043 * TrackPopupMenuEx (USER32.@)
3045 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3046 HWND hWnd
, LPTPMPARAMS lpTpm
)
3048 FIXME("not fully implemented\n" );
3049 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, 0, hWnd
,
3050 lpTpm
? &lpTpm
->rcExclude
: NULL
);
3053 /***********************************************************************
3056 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3058 static LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
3060 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3061 hwnd
, message
, wParam
, lParam
);
3067 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lParam
;
3068 SetWindowLongW( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
3072 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
3073 return MA_NOACTIVATE
;
3078 BeginPaint( hwnd
, &ps
);
3079 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
3080 (HMENU
)GetWindowLongA( hwnd
, 0 ) );
3081 EndPaint( hwnd
, &ps
);
3088 /* zero out global pointer in case resident popup window was destroyed. */
3089 if (hwnd
== top_popup
) top_popup
= 0;
3096 if (!GetWindowLongW( hwnd
, 0 )) ERR("no menu to display\n");
3099 SetWindowLongW( hwnd
, 0, 0 );
3102 case MM_SETMENUHANDLE
:
3103 SetWindowLongW( hwnd
, 0, wParam
);
3106 case MM_GETMENUHANDLE
:
3107 return GetWindowLongW( hwnd
, 0 );
3110 return DefWindowProcW( hwnd
, message
, wParam
, lParam
);
3116 /***********************************************************************
3117 * MENU_GetMenuBarHeight
3119 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3121 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
3122 INT orgX
, INT orgY
)
3128 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3129 hwnd
, menubarWidth
, orgX
, orgY
);
3131 if (!(lppop
= MENU_GetMenu( GetMenu(hwnd
) ))) return 0;
3133 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3134 SelectObject( hdc
, hMenuFont
);
3135 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+GetSystemMetrics(SM_CYMENU
));
3136 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
3137 ReleaseDC( hwnd
, hdc
);
3138 return lppop
->Height
;
3142 /*******************************************************************
3143 * ChangeMenu (USER.153)
3145 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
3146 UINT16 id
, UINT16 flags
)
3148 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3149 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3150 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
3153 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3154 /* for MF_DELETE. We should check the parameters for all others */
3155 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3157 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
3158 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
3160 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
3161 flags
& MF_BYPOSITION
? pos
: id
,
3162 flags
& ~MF_REMOVE
);
3163 /* Default: MF_INSERT */
3164 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
3168 /*******************************************************************
3169 * ChangeMenuA (USER32.@)
3171 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
3172 UINT id
, UINT flags
)
3174 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3175 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3176 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
3178 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3179 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
3181 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3182 flags
& MF_BYPOSITION
? pos
: id
,
3183 flags
& ~MF_REMOVE
);
3184 /* Default: MF_INSERT */
3185 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
3189 /*******************************************************************
3190 * ChangeMenuW (USER32.@)
3192 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
3193 UINT id
, UINT flags
)
3195 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3196 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3197 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
3199 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3200 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
3202 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3203 flags
& MF_BYPOSITION
? pos
: id
,
3204 flags
& ~MF_REMOVE
);
3205 /* Default: MF_INSERT */
3206 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
3210 /*******************************************************************
3211 * CheckMenuItem (USER.154)
3213 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
3215 return (BOOL16
)CheckMenuItem( hMenu
, id
, flags
);
3219 /*******************************************************************
3220 * CheckMenuItem (USER32.@)
3222 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
3227 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu
, id
, flags
);
3228 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
3229 ret
= item
->fState
& MF_CHECKED
;
3230 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
3231 else item
->fState
&= ~MF_CHECKED
;
3236 /**********************************************************************
3237 * EnableMenuItem (USER.155)
3239 UINT16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3241 return EnableMenuItem( hMenu
, wItemID
, wFlags
);
3245 /**********************************************************************
3246 * EnableMenuItem (USER32.@)
3248 UINT WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3254 TRACE("(%04x, %04X, %04X) !\n",
3255 hMenu
, wItemID
, wFlags
);
3257 /* Get the Popupmenu to access the owner menu */
3258 if (!(menu
= MENU_GetMenu(hMenu
)))
3261 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3264 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3265 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3267 /* In win95 if the close item in the system menu change update the close button */
3268 if (TWEAK_WineLook
== WIN95_LOOK
)
3269 if((item
->wID
== SC_CLOSE
) && (oldflags
!= wFlags
))
3271 if (menu
->hSysMenuOwner
!= 0)
3273 POPUPMENU
* parentMenu
;
3275 /* Get the parent menu to access*/
3276 if (!(parentMenu
= MENU_GetMenu(menu
->hSysMenuOwner
)))
3279 /* Refresh the frame to reflect the change*/
3280 SetWindowPos(parentMenu
->hWnd
, 0, 0, 0, 0, 0,
3281 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
3289 /*******************************************************************
3290 * GetMenuString (USER.161)
3292 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
3293 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
3295 return GetMenuStringA( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3299 /*******************************************************************
3300 * GetMenuStringA (USER32.@)
3302 INT WINAPI
GetMenuStringA(
3303 HMENU hMenu
, /* [in] menuhandle */
3304 UINT wItemID
, /* [in] menu item (dep. on wFlags) */
3305 LPSTR str
, /* [out] outbuffer. If NULL, func returns entry length*/
3306 INT nMaxSiz
, /* [in] length of buffer. if 0, func returns entry len*/
3307 UINT wFlags
/* [in] MF_ flags */
3311 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3312 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3313 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3314 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3315 if (!str
|| !nMaxSiz
) return strlenW(item
->text
);
3317 if (!WideCharToMultiByte( CP_ACP
, 0, item
->text
, -1, str
, nMaxSiz
, NULL
, NULL
))
3319 TRACE("returning '%s'\n", str
);
3324 /*******************************************************************
3325 * GetMenuStringW (USER32.@)
3327 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3328 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3332 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3333 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3334 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3335 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3336 if (!str
|| !nMaxSiz
) return strlenW(item
->text
);
3338 lstrcpynW( str
, item
->text
, nMaxSiz
);
3339 return strlenW(str
);
3343 /**********************************************************************
3344 * HiliteMenuItem (USER32.@)
3346 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3350 TRACE("(%04x, %04x, %04x, %04x);\n",
3351 hWnd
, hMenu
, wItemID
, wHilite
);
3352 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3353 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3354 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3355 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
3356 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
, 0 );
3361 /**********************************************************************
3362 * GetMenuState (USER.250)
3364 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3366 return GetMenuState( hMenu
, wItemID
, wFlags
);
3370 /**********************************************************************
3371 * GetMenuState (USER32.@)
3373 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3376 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3377 hMenu
, wItemID
, wFlags
);
3378 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3379 debug_print_menuitem (" item: ", item
, "");
3380 if (item
->fType
& MF_POPUP
)
3382 POPUPMENU
*menu
= MENU_GetMenu( item
->hSubMenu
);
3383 if (!menu
) return -1;
3384 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3388 /* We used to (from way back then) mask the result to 0xff. */
3389 /* I don't know why and it seems wrong as the documented */
3390 /* return flag MF_SEPARATOR is outside that mask. */
3391 return (item
->fType
| item
->fState
);
3396 /**********************************************************************
3397 * GetMenuItemCount (USER.263)
3399 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
3401 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3402 if (!menu
) return -1;
3403 TRACE("(%04x) returning %d\n",
3404 hMenu
, menu
->nItems
);
3405 return menu
->nItems
;
3409 /**********************************************************************
3410 * GetMenuItemCount (USER32.@)
3412 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3414 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3415 if (!menu
) return -1;
3416 TRACE("(%04x) returning %d\n",
3417 hMenu
, menu
->nItems
);
3418 return menu
->nItems
;
3421 /**********************************************************************
3422 * GetMenuItemID (USER.264)
3424 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
3426 return (UINT16
) GetMenuItemID (hMenu
, nPos
);
3429 /**********************************************************************
3430 * GetMenuItemID (USER32.@)
3432 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3436 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return -1;
3437 if (lpmi
->fType
& MF_POPUP
) return -1;
3442 /*******************************************************************
3443 * InsertMenu (USER.410)
3445 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3446 UINT16 id
, SEGPTR data
)
3448 UINT pos32
= (UINT
)pos
;
3449 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT
)-1;
3450 if (IS_STRING_ITEM(flags
) && data
)
3451 return InsertMenuA( hMenu
, pos32
, flags
, id
, MapSL(data
) );
3452 return InsertMenuA( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
3456 /*******************************************************************
3457 * InsertMenuW (USER32.@)
3459 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3460 UINT id
, LPCWSTR str
)
3464 if (IS_STRING_ITEM(flags
) && str
)
3465 TRACE("hMenu %04x, pos %d, flags %08x, "
3466 "id %04x, str %s\n",
3467 hMenu
, pos
, flags
, id
, debugstr_w(str
) );
3468 else TRACE("hMenu %04x, pos %d, flags %08x, "
3469 "id %04x, str %08lx (not a string)\n",
3470 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3472 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3474 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3476 RemoveMenu( hMenu
, pos
, flags
);
3480 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3481 (MENU_GetMenu((HMENU16
)id
))->wFlags
|= MF_POPUP
;
3483 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3488 /*******************************************************************
3489 * InsertMenuA (USER32.@)
3491 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3492 UINT id
, LPCSTR str
)
3496 if (IS_STRING_ITEM(flags
) && str
)
3498 INT len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
3499 LPWSTR newstr
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3502 MultiByteToWideChar( CP_ACP
, 0, str
, -1, newstr
, len
);
3503 ret
= InsertMenuW( hMenu
, pos
, flags
, id
, newstr
);
3504 HeapFree( GetProcessHeap(), 0, newstr
);
3508 else return InsertMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
3512 /*******************************************************************
3513 * AppendMenu (USER.411)
3515 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3517 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3521 /*******************************************************************
3522 * AppendMenuA (USER32.@)
3524 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3525 UINT id
, LPCSTR data
)
3527 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3531 /*******************************************************************
3532 * AppendMenuW (USER32.@)
3534 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3535 UINT id
, LPCWSTR data
)
3537 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3541 /**********************************************************************
3542 * RemoveMenu (USER.412)
3544 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3546 return RemoveMenu( hMenu
, nPos
, wFlags
);
3550 /**********************************************************************
3551 * RemoveMenu (USER32.@)
3553 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3558 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu
, nPos
, wFlags
);
3559 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3560 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3564 MENU_FreeItemData( item
);
3566 if (--menu
->nItems
== 0)
3568 HeapFree( GetProcessHeap(), 0, menu
->items
);
3573 while(nPos
< menu
->nItems
)
3579 menu
->items
= HeapReAlloc( GetProcessHeap(), 0, menu
->items
,
3580 menu
->nItems
* sizeof(MENUITEM
) );
3586 /**********************************************************************
3587 * DeleteMenu (USER.413)
3589 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3591 return DeleteMenu( hMenu
, nPos
, wFlags
);
3595 /**********************************************************************
3596 * DeleteMenu (USER32.@)
3598 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3600 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3601 if (!item
) return FALSE
;
3602 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3603 /* nPos is now the position of the item */
3604 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3609 /*******************************************************************
3610 * ModifyMenu (USER.414)
3612 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3613 UINT16 id
, SEGPTR data
)
3615 if (IS_STRING_ITEM(flags
))
3616 return ModifyMenuA( hMenu
, pos
, flags
, id
, MapSL(data
) );
3617 return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3621 /*******************************************************************
3622 * ModifyMenuW (USER32.@)
3624 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3625 UINT id
, LPCWSTR str
)
3629 if (IS_STRING_ITEM(flags
))
3631 TRACE("%04x %d %04x %04x %s\n",
3632 hMenu
, pos
, flags
, id
, debugstr_w(str
) );
3633 if (!str
) return FALSE
;
3637 TRACE("%04x %d %04x %04x %08lx\n",
3638 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3641 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3642 return MENU_SetItemData( item
, flags
, id
, str
);
3646 /*******************************************************************
3647 * ModifyMenuA (USER32.@)
3649 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3650 UINT id
, LPCSTR str
)
3654 if (IS_STRING_ITEM(flags
) && str
)
3656 INT len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
3657 LPWSTR newstr
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3660 MultiByteToWideChar( CP_ACP
, 0, str
, -1, newstr
, len
);
3661 ret
= ModifyMenuW( hMenu
, pos
, flags
, id
, newstr
);
3662 HeapFree( GetProcessHeap(), 0, newstr
);
3666 else return ModifyMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
3670 /**********************************************************************
3671 * CreatePopupMenu (USER.415)
3673 HMENU16 WINAPI
CreatePopupMenu16(void)
3675 return CreatePopupMenu();
3679 /**********************************************************************
3680 * CreatePopupMenu (USER32.@)
3682 HMENU WINAPI
CreatePopupMenu(void)
3687 if (!(hmenu
= CreateMenu())) return 0;
3688 menu
= MENU_GetMenu( hmenu
);
3689 menu
->wFlags
|= MF_POPUP
;
3690 menu
->bTimeToHide
= FALSE
;
3695 /**********************************************************************
3696 * GetMenuCheckMarkDimensions (USER.417)
3697 * GetMenuCheckMarkDimensions (USER32.@)
3699 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3701 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK
), GetSystemMetrics(SM_CYMENUCHECK
) );
3705 /**********************************************************************
3706 * SetMenuItemBitmaps (USER.418)
3708 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3709 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3711 return SetMenuItemBitmaps( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3715 /**********************************************************************
3716 * SetMenuItemBitmaps (USER32.@)
3718 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
3719 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
3722 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3723 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3724 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3726 if (!hNewCheck
&& !hNewUnCheck
)
3728 item
->fState
&= ~MF_USECHECKBITMAPS
;
3730 else /* Install new bitmaps */
3732 item
->hCheckBit
= hNewCheck
;
3733 item
->hUnCheckBit
= hNewUnCheck
;
3734 item
->fState
|= MF_USECHECKBITMAPS
;
3740 /**********************************************************************
3741 * CreateMenu (USER.151)
3743 HMENU16 WINAPI
CreateMenu16(void)
3745 return CreateMenu();
3749 /**********************************************************************
3750 * CreateMenu (USER32.@)
3752 HMENU WINAPI
CreateMenu(void)
3756 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3757 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3759 ZeroMemory(menu
, sizeof(POPUPMENU
));
3760 menu
->wMagic
= MENU_MAGIC
;
3761 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3762 menu
->bTimeToHide
= FALSE
;
3764 TRACE("return %04x\n", hMenu
);
3770 /**********************************************************************
3771 * DestroyMenu (USER.152)
3773 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3775 return DestroyMenu( hMenu
);
3779 /**********************************************************************
3780 * DestroyMenu (USER32.@)
3782 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
3784 TRACE("(%04x)\n", hMenu
);
3786 /* Silently ignore attempts to destroy default system popup */
3788 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3790 LPPOPUPMENU lppop
= MENU_GetMenu(hMenu
);
3792 if (!lppop
) return FALSE
;
3794 lppop
->wMagic
= 0; /* Mark it as destroyed */
3796 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
)
3798 DestroyWindow( lppop
->hWnd
);
3802 if (lppop
->items
) /* recursively destroy submenus */
3805 MENUITEM
*item
= lppop
->items
;
3806 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3808 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
3809 MENU_FreeItemData( item
);
3811 HeapFree( GetProcessHeap(), 0, lppop
->items
);
3813 USER_HEAP_FREE( hMenu
);
3815 return (hMenu
!= MENU_DefSysPopup
);
3819 /**********************************************************************
3820 * GetSystemMenu (USER32.@)
3822 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
3824 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3829 if( wndPtr
->hSysMenu
)
3833 DestroyMenu(wndPtr
->hSysMenu
);
3834 wndPtr
->hSysMenu
= 0;
3838 POPUPMENU
*menu
= MENU_GetMenu( wndPtr
->hSysMenu
);
3841 if( menu
->nItems
> 0 && menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
3842 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
3846 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3847 wndPtr
->hSysMenu
, hWnd
);
3848 wndPtr
->hSysMenu
= 0;
3853 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
3854 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU
)(-1) );
3856 if( wndPtr
->hSysMenu
)
3859 retvalue
= GetSubMenu(wndPtr
->hSysMenu
, 0);
3861 /* Store the dummy sysmenu handle to facilitate the refresh */
3862 /* of the close button if the SC_CLOSE item change */
3863 menu
= MENU_GetMenu(retvalue
);
3865 menu
->hSysMenuOwner
= wndPtr
->hSysMenu
;
3867 WIN_ReleaseWndPtr(wndPtr
);
3869 return bRevert
? 0 : retvalue
;
3873 /*******************************************************************
3874 * SetSystemMenu (USER32.@)
3876 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
3878 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
3882 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
3883 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
3884 WIN_ReleaseWndPtr(wndPtr
);
3891 /**********************************************************************
3892 * GetMenu (USER32.@)
3894 HMENU WINAPI
GetMenu( HWND hWnd
)
3896 HMENU retvalue
= (HMENU
)GetWindowLongA( hWnd
, GWL_ID
);
3897 TRACE("for %04x returning %04x\n", hWnd
, retvalue
);
3902 /**********************************************************************
3903 * SetMenu (USER32.@)
3905 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
3907 TRACE("(%04x, %04x);\n", hWnd
, hMenu
);
3909 if (hMenu
&& !IsMenu(hMenu
))
3911 WARN("hMenu %x is not a menu handle\n", hMenu
);
3914 if (GetWindowLongA( hWnd
, GWL_STYLE
) & WS_CHILD
) return FALSE
;
3916 hWnd
= WIN_GetFullHandle( hWnd
);
3917 if (GetCapture() == hWnd
) ReleaseCapture();
3923 if (!(lpmenu
= MENU_GetMenu(hMenu
))) return FALSE
;
3925 lpmenu
->hWnd
= hWnd
;
3926 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
3928 SetWindowLongA( hWnd
, GWL_ID
, hMenu
);
3930 if (IsWindowVisible(hWnd
))
3931 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3932 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3938 /**********************************************************************
3939 * GetSubMenu (USER.159)
3941 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
3943 return GetSubMenu( hMenu
, nPos
);
3947 /**********************************************************************
3948 * GetSubMenu (USER32.@)
3950 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
3954 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
3955 if (!(lpmi
->fType
& MF_POPUP
)) return 0;
3956 return lpmi
->hSubMenu
;
3960 /**********************************************************************
3961 * DrawMenuBar (USER32.@)
3963 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
3966 HMENU hMenu
= GetMenu(hWnd
);
3968 if (GetWindowLongA( hWnd
, GWL_STYLE
) & WS_CHILD
) return FALSE
;
3969 if (!hMenu
|| !(lppop
= MENU_GetMenu( hMenu
))) return FALSE
;
3971 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
3972 lppop
->hwndOwner
= hWnd
;
3973 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3974 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3978 /***********************************************************************
3979 * DrawMenuBarTemp (USER32.@)
3981 DWORD WINAPI
DrawMenuBarTemp(DWORD p1
, DWORD p2
)
3983 FIXME("(%08lx %08lx): stub\n", p1
, p2
);
3987 /***********************************************************************
3988 * EndMenu (USER.187)
3989 * EndMenu (USER32.@)
3991 void WINAPI
EndMenu(void)
3993 /* if we are in the menu code, and it is active */
3994 if (!fEndMenu
&& top_popup
)
3996 /* terminate the menu handling code */
3999 /* needs to be posted to wakeup the internal menu handler */
4000 /* which will now terminate the menu, in the event that */
4001 /* the main window was minimized, or lost focus, so we */
4002 /* don't end up with an orphaned menu */
4003 PostMessageA( top_popup
, WM_CANCELMODE
, 0, 0);
4008 /***********************************************************************
4009 * LookupMenuHandle (USER.217)
4011 HMENU16 WINAPI
LookupMenuHandle16( HMENU16 hmenu
, INT16 id
)
4013 HMENU hmenu32
= hmenu
;
4015 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
4016 else return hmenu32
;
4020 /**********************************************************************
4021 * LoadMenu (USER.150)
4023 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, LPCSTR name
)
4029 TRACE("(%04x,%s)\n", instance
, debugres_a(name
) );
4033 if (name
[0] == '#') name
= (LPCSTR
)atoi( name
+ 1 );
4036 if (!name
) return 0;
4038 /* check for Win32 module */
4039 if (HIWORD(instance
)) return LoadMenuA( instance
, name
);
4040 instance
= GetExePtr( instance
);
4042 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENUA
))) return 0;
4043 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
4044 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
4045 FreeResource16( handle
);
4050 /*****************************************************************
4051 * LoadMenuA (USER32.@)
4053 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
4055 HRSRC hrsrc
= FindResourceA( instance
, name
, RT_MENUA
);
4056 if (!hrsrc
) return 0;
4057 return LoadMenuIndirectA( (LPCVOID
)LoadResource( instance
, hrsrc
));
4061 /*****************************************************************
4062 * LoadMenuW (USER32.@)
4064 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
4066 HRSRC hrsrc
= FindResourceW( instance
, name
, RT_MENUW
);
4067 if (!hrsrc
) return 0;
4068 return LoadMenuIndirectW( (LPCVOID
)LoadResource( instance
, hrsrc
));
4072 /**********************************************************************
4073 * LoadMenuIndirect (USER.220)
4075 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
4078 WORD version
, offset
;
4079 LPCSTR p
= (LPCSTR
)template;
4081 TRACE("(%p)\n", template );
4082 version
= GET_WORD(p
);
4086 WARN("version must be 0 for Win16\n" );
4089 offset
= GET_WORD(p
);
4090 p
+= sizeof(WORD
) + offset
;
4091 if (!(hMenu
= CreateMenu())) return 0;
4092 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
4094 DestroyMenu( hMenu
);
4101 /**********************************************************************
4102 * LoadMenuIndirectA (USER32.@)
4104 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
4107 WORD version
, offset
;
4108 LPCSTR p
= (LPCSTR
)template;
4110 TRACE("%p\n", template );
4111 version
= GET_WORD(p
);
4116 offset
= GET_WORD(p
);
4117 p
+= sizeof(WORD
) + offset
;
4118 if (!(hMenu
= CreateMenu())) return 0;
4119 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
4121 DestroyMenu( hMenu
);
4126 offset
= GET_WORD(p
);
4127 p
+= sizeof(WORD
) + offset
;
4128 if (!(hMenu
= CreateMenu())) return 0;
4129 if (!MENUEX_ParseResource( p
, hMenu
))
4131 DestroyMenu( hMenu
);
4136 ERR("version %d not supported.\n", version
);
4142 /**********************************************************************
4143 * LoadMenuIndirectW (USER32.@)
4145 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
4147 /* FIXME: is there anything different between A and W? */
4148 return LoadMenuIndirectA( template );
4152 /**********************************************************************
4155 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
4157 return IsMenu( hmenu
);
4161 /**********************************************************************
4164 BOOL WINAPI
IsMenu(HMENU hmenu
)
4166 LPPOPUPMENU menu
= MENU_GetMenu(hmenu
);
4167 return menu
!= NULL
;
4170 /**********************************************************************
4171 * GetMenuItemInfo_common
4174 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
, BOOL bypos
,
4175 LPMENUITEMINFOW lpmii
, BOOL unicode
)
4177 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
4179 debug_print_menuitem("GetMenuItemInfo_common: ", menu
, "");
4184 if (lpmii
->fMask
& MIIM_TYPE
) {
4185 lpmii
->fType
= menu
->fType
;
4186 switch (MENU_ITEM_TYPE(menu
->fType
)) {
4188 break; /* will be done below */
4191 lpmii
->dwTypeData
= menu
->text
;
4198 /* copy the text string */
4199 if ((lpmii
->fMask
& (MIIM_TYPE
|MIIM_STRING
)) &&
4200 (MENU_ITEM_TYPE(menu
->fType
) == MF_STRING
) && menu
->text
)
4205 len
= strlenW(menu
->text
);
4206 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4207 lstrcpynW(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4211 len
= WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1, NULL
, 0, NULL
, NULL
);
4212 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4213 if (!WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1,
4214 (LPSTR
)lpmii
->dwTypeData
, lpmii
->cch
, NULL
, NULL
))
4215 ((LPSTR
)lpmii
->dwTypeData
)[lpmii
->cch
-1] = 0;
4217 /* if we've copied a substring we return its length */
4218 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4220 if (lpmii
->cch
<= len
) lpmii
->cch
--;
4222 else /* return length of string */
4226 if (lpmii
->fMask
& MIIM_FTYPE
)
4227 lpmii
->fType
= menu
->fType
;
4229 if (lpmii
->fMask
& MIIM_BITMAP
)
4230 lpmii
->hbmpItem
= menu
->hbmpItem
;
4232 if (lpmii
->fMask
& MIIM_STATE
)
4233 lpmii
->fState
= menu
->fState
;
4235 if (lpmii
->fMask
& MIIM_ID
)
4236 lpmii
->wID
= menu
->wID
;
4238 if (lpmii
->fMask
& MIIM_SUBMENU
)
4239 lpmii
->hSubMenu
= menu
->hSubMenu
;
4241 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4242 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4243 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4245 if (lpmii
->fMask
& MIIM_DATA
)
4246 lpmii
->dwItemData
= menu
->dwItemData
;
4251 /**********************************************************************
4252 * GetMenuItemInfoA (USER32.@)
4254 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4255 LPMENUITEMINFOA lpmii
)
4257 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4258 (LPMENUITEMINFOW
)lpmii
, FALSE
);
4261 /**********************************************************************
4262 * GetMenuItemInfoW (USER32.@)
4264 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4265 LPMENUITEMINFOW lpmii
)
4267 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4272 /* set a menu item text from a ASCII or Unicode string */
4273 inline static void set_menu_item_text( MENUITEM
*menu
, LPCWSTR text
, BOOL unicode
)
4278 menu
->fType
|= MF_SEPARATOR
;
4282 if ((menu
->text
= HeapAlloc( GetProcessHeap(), 0, (strlenW(text
)+1) * sizeof(WCHAR
) )))
4283 strcpyW( menu
->text
, text
);
4287 LPCSTR str
= (LPCSTR
)text
;
4288 int len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
4289 if ((menu
->text
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
4290 MultiByteToWideChar( CP_ACP
, 0, str
, -1, menu
->text
, len
);
4295 /**********************************************************************
4296 * SetMenuItemInfo_common
4299 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4300 const MENUITEMINFOW
*lpmii
,
4303 if (!menu
) return FALSE
;
4305 debug_print_menuitem("MENU_SetItemInfo_common from: ", menu
, "");
4307 if (lpmii
->fMask
& MIIM_TYPE
) {
4308 /* Get rid of old string. */
4309 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4310 HeapFree(GetProcessHeap(), 0, menu
->text
);
4314 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4315 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4316 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4318 menu
->text
= lpmii
->dwTypeData
;
4320 if (IS_STRING_ITEM(menu
->fType
))
4321 set_menu_item_text( menu
, lpmii
->dwTypeData
, unicode
);
4324 if (lpmii
->fMask
& MIIM_FTYPE
) {
4325 /* free the string when the type is changing */
4326 if ( (!IS_STRING_ITEM(lpmii
->fType
)) && IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4327 HeapFree(GetProcessHeap(), 0, menu
->text
);
4330 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4331 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4332 if ( IS_STRING_ITEM(menu
->fType
) && !menu
->text
)
4333 menu
->fType
|= MF_SEPARATOR
;
4336 if (lpmii
->fMask
& MIIM_STRING
) {
4337 /* free the string when used */
4338 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4339 HeapFree(GetProcessHeap(), 0, menu
->text
);
4340 set_menu_item_text( menu
, lpmii
->dwTypeData
, unicode
);
4344 if (lpmii
->fMask
& MIIM_STATE
)
4346 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4347 menu
->fState
= lpmii
->fState
;
4350 if (lpmii
->fMask
& MIIM_ID
)
4351 menu
->wID
= lpmii
->wID
;
4353 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4354 menu
->hSubMenu
= lpmii
->hSubMenu
;
4355 if (menu
->hSubMenu
) {
4356 POPUPMENU
*subMenu
= MENU_GetMenu((UINT16
)menu
->hSubMenu
);
4358 subMenu
->wFlags
|= MF_POPUP
;
4359 menu
->fType
|= MF_POPUP
;
4362 /* FIXME: Return an error ? */
4363 menu
->fType
&= ~MF_POPUP
;
4366 menu
->fType
&= ~MF_POPUP
;
4369 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4371 if (lpmii
->fType
& MFT_RADIOCHECK
)
4372 menu
->fType
|= MFT_RADIOCHECK
;
4374 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4375 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4377 if (lpmii
->fMask
& MIIM_DATA
)
4378 menu
->dwItemData
= lpmii
->dwItemData
;
4380 debug_print_menuitem("SetMenuItemInfo_common to : ", menu
, "");
4384 /**********************************************************************
4385 * SetMenuItemInfoA (USER32.@)
4387 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4388 const MENUITEMINFOA
*lpmii
)
4390 if ((lpmii
->fType
& (MF_HILITE
|MF_POPUP
)) || (lpmii
->fState
)) {
4391 /* QuickTime does pass invalid data into SetMenuItemInfo.
4392 * do some of the checks Windows does.
4394 WARN("Bad masks for type (0x%08x) or state (0x%08x)\n",
4395 lpmii
->fType
,lpmii
->fState
);
4399 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4400 (const MENUITEMINFOW
*)lpmii
, FALSE
);
4403 /**********************************************************************
4404 * SetMenuItemInfoW (USER32.@)
4406 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4407 const MENUITEMINFOW
*lpmii
)
4409 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4413 /**********************************************************************
4414 * SetMenuDefaultItem (USER32.@)
4417 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT uItem
, UINT bypos
)
4423 TRACE("(0x%x,%d,%d)\n", hmenu
, uItem
, bypos
);
4425 if (!(menu
= MENU_GetMenu(hmenu
))) return FALSE
;
4427 /* reset all default-item flags */
4429 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4431 item
->fState
&= ~MFS_DEFAULT
;
4434 /* no default item */
4443 if ( uItem
>= menu
->nItems
) return FALSE
;
4444 item
[uItem
].fState
|= MFS_DEFAULT
;
4449 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4451 if (item
->wID
== uItem
)
4453 item
->fState
|= MFS_DEFAULT
;
4462 /**********************************************************************
4463 * GetMenuDefaultItem (USER32.@)
4465 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4471 TRACE("(0x%x,%d,%d)\n", hmenu
, bypos
, flags
);
4473 if (!(menu
= MENU_GetMenu(hmenu
))) return -1;
4475 /* find default item */
4479 if (! item
) return -1;
4481 while ( !( item
->fState
& MFS_DEFAULT
) )
4484 if (i
>= menu
->nItems
) return -1;
4487 /* default: don't return disabled items */
4488 if ( (!(GMDI_USEDISABLED
& flags
)) && (item
->fState
& MFS_DISABLED
)) return -1;
4490 /* search rekursiv when needed */
4491 if ( (item
->fType
& MF_POPUP
) && (flags
& GMDI_GOINTOPOPUPS
) )
4494 ret
= GetMenuDefaultItem( item
->hSubMenu
, bypos
, flags
);
4495 if ( -1 != ret
) return ret
;
4497 /* when item not found in submenu, return the popup item */
4499 return ( bypos
) ? i
: item
->wID
;
4503 /*******************************************************************
4504 * InsertMenuItem (USER.441)
4508 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
4509 const MENUITEMINFO16
*mii
)
4513 miia
.cbSize
= sizeof(miia
);
4514 miia
.fMask
= mii
->fMask
;
4515 miia
.dwTypeData
= (LPSTR
)mii
->dwTypeData
;
4516 miia
.fType
= mii
->fType
;
4517 miia
.fState
= mii
->fState
;
4518 miia
.wID
= mii
->wID
;
4519 miia
.hSubMenu
= mii
->hSubMenu
;
4520 miia
.hbmpChecked
= mii
->hbmpChecked
;
4521 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
4522 miia
.dwItemData
= mii
->dwItemData
;
4523 miia
.cch
= mii
->cch
;
4524 if (IS_STRING_ITEM(miia
.fType
))
4525 miia
.dwTypeData
= MapSL(mii
->dwTypeData
);
4526 return InsertMenuItemA( hmenu
, pos
, byposition
, &miia
);
4530 /**********************************************************************
4531 * InsertMenuItemA (USER32.@)
4533 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4534 const MENUITEMINFOA
*lpmii
)
4536 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4537 return SetMenuItemInfo_common(item
, (const MENUITEMINFOW
*)lpmii
, FALSE
);
4541 /**********************************************************************
4542 * InsertMenuItemW (USER32.@)
4544 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4545 const MENUITEMINFOW
*lpmii
)
4547 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4548 return SetMenuItemInfo_common(item
, lpmii
, TRUE
);
4551 /**********************************************************************
4552 * CheckMenuRadioItem (USER32.@)
4555 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
4556 UINT first
, UINT last
, UINT check
,
4559 MENUITEM
*mifirst
, *milast
, *micheck
;
4560 HMENU mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
4562 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4563 hMenu
, first
, last
, check
, bypos
);
4565 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
4566 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
4567 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
4569 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
4570 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
4571 micheck
> milast
|| micheck
< mifirst
)
4574 while (mifirst
<= milast
)
4576 if (mifirst
== micheck
)
4578 mifirst
->fType
|= MFT_RADIOCHECK
;
4579 mifirst
->fState
|= MFS_CHECKED
;
4581 mifirst
->fType
&= ~MFT_RADIOCHECK
;
4582 mifirst
->fState
&= ~MFS_CHECKED
;
4590 /**********************************************************************
4591 * CheckMenuRadioItem (USER.666)
4593 BOOL16 WINAPI
CheckMenuRadioItem16(HMENU16 hMenu
,
4594 UINT16 first
, UINT16 last
, UINT16 check
,
4597 return CheckMenuRadioItem (hMenu
, first
, last
, check
, bypos
);
4600 /**********************************************************************
4601 * GetMenuItemRect (USER32.@)
4603 * ATTENTION: Here, the returned values in rect are the screen
4604 * coordinates of the item just like if the menu was
4605 * always on the upper left side of the application.
4608 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
4611 POPUPMENU
*itemMenu
;
4615 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
4617 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
4618 referenceHwnd
= hwnd
;
4622 itemMenu
= MENU_GetMenu(hMenu
);
4623 if (itemMenu
== NULL
)
4626 if(itemMenu
->hWnd
== 0)
4628 referenceHwnd
= itemMenu
->hWnd
;
4631 if ((rect
== NULL
) || (item
== NULL
))
4636 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
4642 /**********************************************************************
4643 * SetMenuInfo (USER32.@)
4646 * MIM_APPLYTOSUBMENUS
4647 * actually use the items to draw the menu
4649 BOOL WINAPI
SetMenuInfo (HMENU hMenu
, LPCMENUINFO lpmi
)
4653 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4655 if (lpmi
&& (lpmi
->cbSize
==sizeof(MENUINFO
)) && (menu
= MENU_GetMenu(hMenu
)))
4658 if (lpmi
->fMask
& MIM_BACKGROUND
)
4659 menu
->hbrBack
= lpmi
->hbrBack
;
4661 if (lpmi
->fMask
& MIM_HELPID
)
4662 menu
->dwContextHelpID
= lpmi
->dwContextHelpID
;
4664 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4665 menu
->cyMax
= lpmi
->cyMax
;
4667 if (lpmi
->fMask
& MIM_MENUDATA
)
4668 menu
->dwMenuData
= lpmi
->dwMenuData
;
4670 if (lpmi
->fMask
& MIM_STYLE
)
4671 menu
->dwStyle
= lpmi
->dwStyle
;
4678 /**********************************************************************
4679 * GetMenuInfo (USER32.@)
4685 BOOL WINAPI
GetMenuInfo (HMENU hMenu
, LPMENUINFO lpmi
)
4688 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4690 if (lpmi
&& (menu
= MENU_GetMenu(hMenu
)))
4693 if (lpmi
->fMask
& MIM_BACKGROUND
)
4694 lpmi
->hbrBack
= menu
->hbrBack
;
4696 if (lpmi
->fMask
& MIM_HELPID
)
4697 lpmi
->dwContextHelpID
= menu
->dwContextHelpID
;
4699 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4700 lpmi
->cyMax
= menu
->cyMax
;
4702 if (lpmi
->fMask
& MIM_MENUDATA
)
4703 lpmi
->dwMenuData
= menu
->dwMenuData
;
4705 if (lpmi
->fMask
& MIM_STYLE
)
4706 lpmi
->dwStyle
= menu
->dwStyle
;
4713 /**********************************************************************
4714 * SetMenuContextHelpId (USER.384)
4716 BOOL16 WINAPI
SetMenuContextHelpId16( HMENU16 hMenu
, DWORD dwContextHelpID
)
4718 return SetMenuContextHelpId( hMenu
, dwContextHelpID
);
4722 /**********************************************************************
4723 * SetMenuContextHelpId (USER32.@)
4725 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpID
)
4729 TRACE("(0x%04x 0x%08lx)\n", hMenu
, dwContextHelpID
);
4731 if ((menu
= MENU_GetMenu(hMenu
)))
4733 menu
->dwContextHelpID
= dwContextHelpID
;
4739 /**********************************************************************
4740 * GetMenuContextHelpId (USER.385)
4742 DWORD WINAPI
GetMenuContextHelpId16( HMENU16 hMenu
)
4744 return GetMenuContextHelpId( hMenu
);
4747 /**********************************************************************
4748 * GetMenuContextHelpId (USER32.@)
4750 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
4754 TRACE("(0x%04x)\n", hMenu
);
4756 if ((menu
= MENU_GetMenu(hMenu
)))
4758 return menu
->dwContextHelpID
;
4763 /**********************************************************************
4764 * MenuItemFromPoint (USER32.@)
4766 UINT WINAPI
MenuItemFromPoint(HWND hWnd
, HMENU hMenu
, POINT ptScreen
)
4768 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4769 hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4774 /**********************************************************************
4775 * translate_accelerator
4777 static BOOL
translate_accelerator( HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
,
4778 BYTE fVirt
, WORD key
, WORD cmd
)
4782 if (wParam
!= key
) return FALSE
;
4784 if (message
== WM_CHAR
)
4786 if ( !(fVirt
& FALT
) && !(fVirt
& FVIRTKEY
) )
4788 TRACE_(accel
)("found accel for WM_CHAR: ('%c')\n", wParam
& 0xff);
4794 if(fVirt
& FVIRTKEY
)
4797 TRACE_(accel
)("found accel for virt_key %04x (scan %04x)\n",
4798 wParam
, 0xff & HIWORD(lParam
));
4799 if(GetKeyState(VK_SHIFT
) & 0x8000) mask
|= FSHIFT
;
4800 if(GetKeyState(VK_CONTROL
) & 0x8000) mask
|= FCONTROL
;
4801 if(GetKeyState(VK_MENU
) & 0x8000) mask
|= FALT
;
4802 if(mask
== (fVirt
& (FSHIFT
| FCONTROL
| FALT
))) goto found
;
4803 TRACE_(accel
)(", but incorrect SHIFT/CTRL/ALT-state\n");
4807 if (!(lParam
& 0x01000000)) /* no special_key */
4809 if ((fVirt
& FALT
) && (lParam
& 0x20000000))
4810 { /* ^^ ALT pressed */
4811 TRACE_(accel
)("found accel for Alt-%c\n", wParam
& 0xff);
4820 if (message
== WM_KEYUP
|| message
== WM_SYSKEYUP
)
4822 else if (GetCapture())
4824 else if (!IsWindowEnabled(hWnd
))
4828 HMENU hMenu
, hSubMenu
, hSysMenu
;
4829 UINT uSysStat
= (UINT
)-1, uStat
= (UINT
)-1, nPos
;
4831 hMenu
= (GetWindowLongA( hWnd
, GWL_STYLE
) & WS_CHILD
) ? 0 : GetMenu(hWnd
);
4832 hSysMenu
= get_win_sys_menu( hWnd
);
4834 /* find menu item and ask application to initialize it */
4835 /* 1. in the system menu */
4836 hSubMenu
= hSysMenu
;
4838 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
4840 SendMessageA(hWnd
, WM_INITMENU
, (WPARAM
)hSysMenu
, 0L);
4841 if(hSubMenu
!= hSysMenu
)
4843 nPos
= MENU_FindSubMenu(&hSysMenu
, hSubMenu
);
4844 TRACE_(accel
)("hSysMenu = %04x, hSubMenu = %04x, nPos = %d\n", hSysMenu
, hSubMenu
, nPos
);
4845 SendMessageA(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, TRUE
));
4847 uSysStat
= GetMenuState(GetSubMenu(hSysMenu
, 0), cmd
, MF_BYCOMMAND
);
4849 else /* 2. in the window's menu */
4853 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
4855 SendMessageA(hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0L);
4856 if(hSubMenu
!= hMenu
)
4858 nPos
= MENU_FindSubMenu(&hMenu
, hSubMenu
);
4859 TRACE_(accel
)("hMenu = %04x, hSubMenu = %04x, nPos = %d\n", hMenu
, hSubMenu
, nPos
);
4860 SendMessageA(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, FALSE
));
4862 uStat
= GetMenuState(hMenu
, cmd
, MF_BYCOMMAND
);
4866 if (uSysStat
!= (UINT
)-1)
4868 if (uSysStat
& (MF_DISABLED
|MF_GRAYED
))
4875 if (uStat
!= (UINT
)-1)
4881 if (uStat
& (MF_DISABLED
|MF_GRAYED
))
4892 if( mesg
==WM_COMMAND
)
4894 TRACE_(accel
)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd
);
4895 SendMessageA(hWnd
, mesg
, 0x10000 | cmd
, 0L);
4897 else if( mesg
==WM_SYSCOMMAND
)
4899 TRACE_(accel
)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd
);
4900 SendMessageA(hWnd
, mesg
, cmd
, 0x00010000L
);
4904 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
4905 * #0: unknown (please report!)
4906 * #1: for WM_KEYUP,WM_SYSKEYUP
4907 * #2: mouse is captured
4908 * #3: window is disabled
4909 * #4: it's a disabled system menu option
4910 * #5: it's a menu option, but window is iconic
4911 * #6: it's a menu option, but disabled
4913 TRACE_(accel
)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg
);
4915 ERR_(accel
)(" unknown reason - please report!");
4920 /**********************************************************************
4921 * TranslateAccelerator (USER32.@)
4922 * TranslateAcceleratorA (USER32.@)
4923 * TranslateAcceleratorW (USER32.@)
4925 INT WINAPI
TranslateAccelerator( HWND hWnd
, HACCEL hAccel
, LPMSG msg
)
4928 LPACCEL16 lpAccelTbl
;
4933 WARN_(accel
)("msg null; should hang here to be win compatible\n");
4936 if (!hAccel
|| !(lpAccelTbl
= (LPACCEL16
) LockResource16(hAccel
)))
4938 WARN_(accel
)("invalid accel handle=%x\n", hAccel
);
4941 if ((msg
->message
!= WM_KEYDOWN
&&
4942 msg
->message
!= WM_KEYUP
&&
4943 msg
->message
!= WM_SYSKEYDOWN
&&
4944 msg
->message
!= WM_SYSKEYUP
&&
4945 msg
->message
!= WM_CHAR
)) return 0;
4947 TRACE_(accel
)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
4948 "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
4949 hAccel
,hWnd
,msg
->hwnd
,msg
->message
,msg
->wParam
,msg
->lParam
);
4954 if (translate_accelerator( hWnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
4955 lpAccelTbl
[i
].fVirt
, lpAccelTbl
[i
].key
, lpAccelTbl
[i
].cmd
))
4957 } while ((lpAccelTbl
[i
++].fVirt
& 0x80) == 0);
4958 WARN_(accel
)("couldn't translate accelerator key\n");