4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Note: the style MF_MOUSESELECT is used to mark popup items that
25 * have been selected, i.e. their popup menu is currently displayed.
26 * This is probably not the meaning this style has in MS-Windows.
30 #include "wine/port.h"
40 #include "wine/winbase16.h"
41 #include "wine/winuser16.h"
42 #include "wine/unicode.h"
45 #include "nonclient.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(menu
);
52 WINE_DECLARE_DEBUG_CHANNEL(accel
);
54 /* internal popup menu window messages */
56 #define MM_SETMENUHANDLE (WM_USER + 0)
57 #define MM_GETMENUHANDLE (WM_USER + 1)
59 /* Menu item structure */
61 /* ----------- MENUITEMINFO Stuff ----------- */
62 UINT fType
; /* Item type. */
63 UINT fState
; /* Item state. */
64 UINT wID
; /* Item id. */
65 HMENU hSubMenu
; /* Pop-up menu. */
66 HBITMAP hCheckBit
; /* Bitmap when checked. */
67 HBITMAP hUnCheckBit
; /* Bitmap when unchecked. */
68 LPWSTR text
; /* Item text or bitmap handle. */
69 DWORD dwItemData
; /* Application defined. */
70 DWORD dwTypeData
; /* depends on fMask */
71 HBITMAP hbmpItem
; /* bitmap in win98 style menus */
72 /* ----------- Wine stuff ----------- */
73 RECT rect
; /* Item area (relative to menu window) */
74 UINT xTab
; /* X position of text after Tab */
77 /* Popup menu structure */
79 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
80 WORD wMagic
; /* Magic number */
81 WORD Width
; /* Width of the whole menu */
82 WORD Height
; /* Height of the whole menu */
83 UINT nItems
; /* Number of items in the menu */
84 HWND hWnd
; /* Window containing the menu */
85 MENUITEM
*items
; /* Array of menu items */
86 UINT FocusedItem
; /* Currently focused item */
87 HWND hwndOwner
; /* window receiving the messages for ownerdraw */
88 BOOL bTimeToHide
; /* Request hiding when receiving a second click in the top-level menu item */
89 /* ------------ MENUINFO members ------ */
90 DWORD dwStyle
; /* Extended mennu style */
91 UINT cyMax
; /* max hight of the whole menu, 0 is screen hight */
92 HBRUSH hbrBack
; /* brush for menu background */
93 DWORD dwContextHelpID
;
94 DWORD dwMenuData
; /* application defined value */
95 HMENU hSysMenuOwner
; /* Handle to the dummy sys menu holder */
96 } POPUPMENU
, *LPPOPUPMENU
;
98 /* internal flags for menu tracking */
100 #define TF_ENDMENU 0x0001
101 #define TF_SUSPENDPOPUP 0x0002
102 #define TF_SKIPREMOVE 0x0004
107 HMENU hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
108 HMENU hTopMenu
; /* initial menu */
109 HWND hOwnerWnd
; /* where notifications are sent */
113 #define MENU_MAGIC 0x554d /* 'MU' */
118 /* Internal MENU_TrackMenu() flags */
119 #define TPM_INTERNAL 0xF0000000
120 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
121 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
122 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
124 /* popup menu shade thickness */
125 #define POPUP_XSHADE 4
126 #define POPUP_YSHADE 4
128 /* Space between 2 menu bar items */
129 #define MENU_BAR_ITEMS_SPACE 12
131 /* Minimum width of a tab character */
132 #define MENU_TAB_SPACE 8
134 /* Height of a separator item */
135 #define SEPARATOR_HEIGHT 5
137 /* (other menu->FocusedItem values give the position of the focused item) */
138 #define NO_SELECTED_ITEM 0xffff
140 #define MENU_ITEM_TYPE(flags) \
141 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
143 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
144 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
145 #define IS_MAGIC_ITEM(text) (LOWORD((int)text)<12)
147 #define IS_SYSTEM_MENU(menu) \
148 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
150 #define IS_SYSTEM_POPUP(menu) \
151 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
153 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
154 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
155 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
156 MF_POPUP | MF_SYSMENU | MF_HELP)
157 #define STATE_MASK (~TYPE_MASK)
159 /* Dimension of the menu bitmaps */
160 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
162 static HBITMAP hStdMnArrow
= 0;
163 static HBITMAP hBmpSysMenu
= 0;
165 static HBRUSH hShadeBrush
= 0;
166 static HFONT hMenuFont
= 0;
167 static HFONT hMenuFontBold
= 0;
169 static HMENU MENU_DefSysPopup
= 0; /* Default system menu popup */
171 /* Use global popup window because there's no way 2 menus can
172 * be tracked at the same time. */
173 static HWND top_popup
;
175 /* Flag set by EndMenu() to force an exit from menu tracking */
176 static BOOL fEndMenu
= FALSE
;
178 static LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
181 /*********************************************************************
182 * menu class descriptor
184 const struct builtin_class_descr MENU_builtin_class
=
186 POPUPMENU_CLASS_ATOM
, /* name */
187 CS_GLOBALCLASS
| CS_SAVEBITS
, /* style */
188 NULL
, /* procA (winproc is Unicode only) */
189 PopupMenuWndProc
, /* procW */
190 sizeof(HMENU
), /* extra */
191 IDC_ARROWA
, /* cursor */
192 COLOR_MENU
+1 /* brush */
196 /***********************************************************************
197 * debug_print_menuitem
199 * Print a menuitem in readable form.
202 #define debug_print_menuitem(pre, mp, post) \
203 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
205 #define MENUOUT(text) \
206 DPRINTF("%s%s", (count++ ? "," : ""), (text))
208 #define MENUFLAG(bit,text) \
210 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
213 static void do_debug_print_menuitem(const char *prefix
, MENUITEM
* mp
,
216 TRACE("%s ", prefix
);
218 UINT flags
= mp
->fType
;
219 int typ
= MENU_ITEM_TYPE(flags
);
220 DPRINTF( "{ ID=0x%x", mp
->wID
);
221 if (flags
& MF_POPUP
)
222 DPRINTF( ", Sub=0x%x", mp
->hSubMenu
);
226 if (typ
== MFT_STRING
)
228 else if (typ
== MFT_SEPARATOR
)
230 else if (typ
== MFT_OWNERDRAW
)
232 else if (typ
== MFT_BITMAP
)
238 MENUFLAG(MF_POPUP
, "pop");
239 MENUFLAG(MFT_MENUBARBREAK
, "barbrk");
240 MENUFLAG(MFT_MENUBREAK
, "brk");
241 MENUFLAG(MFT_RADIOCHECK
, "radio");
242 MENUFLAG(MFT_RIGHTORDER
, "rorder");
243 MENUFLAG(MF_SYSMENU
, "sys");
244 MENUFLAG(MFT_RIGHTJUSTIFY
, "right"); /* same as MF_HELP */
247 DPRINTF( "+0x%x", flags
);
252 DPRINTF( ", State=");
253 MENUFLAG(MFS_GRAYED
, "grey");
254 MENUFLAG(MFS_DEFAULT
, "default");
255 MENUFLAG(MFS_DISABLED
, "dis");
256 MENUFLAG(MFS_CHECKED
, "check");
257 MENUFLAG(MFS_HILITE
, "hi");
258 MENUFLAG(MF_USECHECKBITMAPS
, "usebit");
259 MENUFLAG(MF_MOUSESELECT
, "mouse");
261 DPRINTF( "+0x%x", flags
);
264 DPRINTF( ", Chk=0x%x", mp
->hCheckBit
);
266 DPRINTF( ", Unc=0x%x", mp
->hUnCheckBit
);
268 if (typ
== MFT_STRING
) {
270 DPRINTF( ", Text=%s", debugstr_w(mp
->text
));
272 DPRINTF( ", Text=Null");
273 } else if (mp
->text
== NULL
)
276 DPRINTF( ", Text=%p", mp
->text
);
278 DPRINTF( ", ItemData=0x%08lx", mp
->dwItemData
);
284 DPRINTF(" %s\n", postfix
);
291 /***********************************************************************
294 * Validate the given menu handle and returns the menu structure pointer.
296 static POPUPMENU
*MENU_GetMenu(HMENU hMenu
)
298 POPUPMENU
*menu
= USER_HEAP_LIN_ADDR(hMenu
);
299 if (!menu
|| menu
->wMagic
!= MENU_MAGIC
)
301 WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu
, menu
, menu
? menu
->wMagic
:0);
307 /***********************************************************************
310 * Get the system menu of a window
312 static HMENU
get_win_sys_menu( HWND hwnd
)
315 WND
*win
= WIN_FindWndPtr( hwnd
);
319 WIN_ReleaseWndPtr( win
);
324 /***********************************************************************
327 * Return the default system menu.
329 static HMENU
MENU_CopySysPopup(void)
331 HMENU hMenu
= LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
334 POPUPMENU
* menu
= MENU_GetMenu(hMenu
);
335 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
336 SetMenuDefaultItem(hMenu
, SC_CLOSE
, FALSE
);
339 ERR("Unable to load default system menu\n" );
341 TRACE("returning %x.\n", hMenu
);
347 /**********************************************************************
350 * Create a copy of the system menu. System menu in Windows is
351 * a special menu bar with the single entry - system menu popup.
352 * This popup is presented to the outside world as a "system menu".
353 * However, the real system menu handle is sometimes seen in the
354 * WM_MENUSELECT parameters (and Word 6 likes it this way).
356 HMENU
MENU_GetSysMenu( HWND hWnd
, HMENU hPopupMenu
)
360 if ((hMenu
= CreateMenu()))
362 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
363 menu
->wFlags
= MF_SYSMENU
;
364 menu
->hWnd
= WIN_GetFullHandle( hWnd
);
366 if (hPopupMenu
== (HMENU
)(-1))
367 hPopupMenu
= MENU_CopySysPopup();
368 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
372 InsertMenuA( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
, hPopupMenu
, NULL
);
374 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
375 menu
->items
[0].fState
= 0;
376 if ((menu
= MENU_GetMenu(hPopupMenu
))) menu
->wFlags
|= MF_SYSMENU
;
378 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu
, hPopupMenu
);
381 DestroyMenu( hMenu
);
383 ERR("failed to load system menu!\n");
388 /***********************************************************************
391 * Menus initialisation.
396 NONCLIENTMETRICSA ncm
;
398 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
403 /* Load menu bitmaps */
404 hStdMnArrow
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW
));
405 /* Load system buttons bitmaps */
406 hBmpSysMenu
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CLOSE
));
411 GetObjectA( hStdMnArrow
, sizeof(bm
), &bm
);
412 arrow_bitmap_width
= bm
.bmWidth
;
413 arrow_bitmap_height
= bm
.bmHeight
;
417 if (! (hBitmap
= CreateBitmap( 8, 8, 1, 1, shade_bits
)))
420 if(!(hShadeBrush
= CreatePatternBrush( hBitmap
)))
423 DeleteObject( hBitmap
);
424 if (!(MENU_DefSysPopup
= MENU_CopySysPopup()))
427 ncm
.cbSize
= sizeof (NONCLIENTMETRICSA
);
428 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICSA
), &ncm
, 0)))
431 if (!(hMenuFont
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
434 ncm
.lfMenuFont
.lfWeight
+= 300;
435 if ( ncm
.lfMenuFont
.lfWeight
> 1000)
436 ncm
.lfMenuFont
.lfWeight
= 1000;
438 if (!(hMenuFontBold
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
444 /***********************************************************************
445 * MENU_InitSysMenuPopup
447 * Grey the appropriate items in System menu.
449 static void MENU_InitSysMenuPopup( HMENU hmenu
, DWORD style
, DWORD clsStyle
)
453 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
454 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
455 gray
= ((style
& WS_MAXIMIZE
) != 0);
456 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
457 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
458 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
459 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
460 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
461 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
462 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
463 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
465 /* The menu item must keep its state if it's disabled */
467 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
471 /******************************************************************************
473 * UINT MENU_GetStartOfNextColumn(
476 *****************************************************************************/
478 static UINT
MENU_GetStartOfNextColumn(
481 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
485 return NO_SELECTED_ITEM
;
487 i
= menu
->FocusedItem
+ 1;
488 if( i
== NO_SELECTED_ITEM
)
491 for( ; i
< menu
->nItems
; ++i
) {
492 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
496 return NO_SELECTED_ITEM
;
500 /******************************************************************************
502 * UINT MENU_GetStartOfPrevColumn(
505 *****************************************************************************/
507 static UINT
MENU_GetStartOfPrevColumn(
510 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
514 return NO_SELECTED_ITEM
;
516 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
517 return NO_SELECTED_ITEM
;
519 /* Find the start of the column */
521 for(i
= menu
->FocusedItem
; i
!= 0 &&
522 !(menu
->items
[i
].fType
& MF_MENUBARBREAK
);
526 return NO_SELECTED_ITEM
;
528 for(--i
; i
!= 0; --i
) {
529 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
533 TRACE("ret %d.\n", i
);
540 /***********************************************************************
543 * Find a menu item. Return a pointer on the item, and modifies *hmenu
544 * in case the item was in a sub-menu.
546 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
551 if (((*hmenu
)==0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
552 if (wFlags
& MF_BYPOSITION
)
554 if (*nPos
>= menu
->nItems
) return NULL
;
555 return &menu
->items
[*nPos
];
559 MENUITEM
*item
= menu
->items
;
560 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
562 if (item
->wID
== *nPos
)
567 else if (item
->fType
& MF_POPUP
)
569 HMENU hsubmenu
= item
->hSubMenu
;
570 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
582 /***********************************************************************
585 * Find a Sub menu. Return the position of the submenu, and modifies
586 * *hmenu in case it is found in another sub-menu.
587 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
589 UINT
MENU_FindSubMenu( HMENU
*hmenu
, HMENU hSubTarget
)
594 if (((*hmenu
)==0xffff) ||
595 (!(menu
= MENU_GetMenu(*hmenu
))))
596 return NO_SELECTED_ITEM
;
598 for (i
= 0; i
< menu
->nItems
; i
++, item
++) {
599 if(!(item
->fType
& MF_POPUP
)) continue;
600 if (item
->hSubMenu
== hSubTarget
) {
604 HMENU hsubmenu
= item
->hSubMenu
;
605 UINT pos
= MENU_FindSubMenu( &hsubmenu
, hSubTarget
);
606 if (pos
!= NO_SELECTED_ITEM
) {
612 return NO_SELECTED_ITEM
;
615 /***********************************************************************
618 static void MENU_FreeItemData( MENUITEM
* item
)
621 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
622 HeapFree( GetProcessHeap(), 0, item
->text
);
625 /***********************************************************************
626 * MENU_FindItemByCoords
628 * Find the item at the specified coordinates (screen coords). Does
629 * not work for child windows and therefore should not be called for
630 * an arbitrary system menu.
632 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
,
633 POINT pt
, UINT
*pos
)
639 if (!GetWindowRect(menu
->hWnd
,&wrect
)) return NULL
;
640 pt
.x
-= wrect
.left
;pt
.y
-= wrect
.top
;
642 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
644 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
645 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
655 /***********************************************************************
658 * Find the menu item selected by a key press.
659 * Return item id, -1 if none, -2 if we should close the menu.
661 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
,
662 UINT key
, BOOL forceMenuChar
)
664 TRACE("\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
666 if (!IsMenu( hmenu
)) hmenu
= GetSubMenu( get_win_sys_menu(hwndOwner
), 0);
670 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
671 MENUITEM
*item
= menu
->items
;
679 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
681 if (item
->text
&& (IS_STRING_ITEM(item
->fType
)))
683 WCHAR
*p
= item
->text
- 2;
686 p
= strchrW (p
+ 2, '&');
688 while (p
!= NULL
&& p
[1] == '&');
689 if (p
&& (toupper(p
[1]) == key
)) return i
;
693 menuchar
= SendMessageA( hwndOwner
, WM_MENUCHAR
,
694 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
695 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
696 if (HIWORD(menuchar
) == 1) return (UINT
)(-2);
702 /***********************************************************************
703 * MENU_GetBitmapItemSize
705 * Get the size of a bitmap item.
707 static void MENU_GetBitmapItemSize( UINT id
, DWORD data
, SIZE
*size
)
710 HBITMAP bmp
= (HBITMAP
)id
;
712 size
->cx
= size
->cy
= 0;
714 /* check if there is a magic menu item associated with this item */
715 if (id
&& IS_MAGIC_ITEM( id
))
726 case HBMMENU_MBAR_RESTORE
:
727 case HBMMENU_MBAR_MINIMIZE
:
728 case HBMMENU_MBAR_MINIMIZE_D
:
729 case HBMMENU_MBAR_CLOSE
:
730 case HBMMENU_MBAR_CLOSE_D
:
731 size
->cx
= GetSystemMetrics( SM_CXSIZE
);
732 size
->cy
= GetSystemMetrics( SM_CYSIZE
);
734 case HBMMENU_CALLBACK
:
735 case HBMMENU_POPUP_CLOSE
:
736 case HBMMENU_POPUP_RESTORE
:
737 case HBMMENU_POPUP_MAXIMIZE
:
738 case HBMMENU_POPUP_MINIMIZE
:
740 FIXME("Magic 0x%08x not implemented\n", id
);
744 if (GetObjectA(bmp
, sizeof(bm
), &bm
))
746 size
->cx
= bm
.bmWidth
;
747 size
->cy
= bm
.bmHeight
;
751 /***********************************************************************
752 * MENU_DrawBitmapItem
754 * Draw a bitmap item.
756 static void MENU_DrawBitmapItem( HDC hdc
, MENUITEM
*lpitem
, const RECT
*rect
, BOOL menuBar
)
761 HBITMAP bmp
= (HBITMAP
)lpitem
->text
;
762 int w
= rect
->right
- rect
->left
;
763 int h
= rect
->bottom
- rect
->top
;
767 /* Check if there is a magic menu item associated with this item */
768 if (lpitem
->text
&& IS_MAGIC_ITEM(lpitem
->text
))
773 switch(LOWORD(lpitem
->text
))
776 if (lpitem
->dwItemData
)
778 bmp
= (HBITMAP
)lpitem
->dwItemData
;
779 if (!GetObjectA( bmp
, sizeof(bm
), &bm
)) return;
784 if (!GetObjectA( bmp
, sizeof(bm
), &bm
)) return;
785 /* only use right half of the bitmap */
786 bmp_xoffset
= bm
.bmWidth
/ 2;
787 bm
.bmWidth
-= bmp_xoffset
;
790 case HBMMENU_MBAR_RESTORE
:
791 flags
= DFCS_CAPTIONRESTORE
;
793 case HBMMENU_MBAR_MINIMIZE
:
794 flags
= DFCS_CAPTIONMIN
;
796 case HBMMENU_MBAR_MINIMIZE_D
:
797 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
799 case HBMMENU_MBAR_CLOSE
:
800 flags
= DFCS_CAPTIONCLOSE
;
802 case HBMMENU_MBAR_CLOSE_D
:
803 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
805 case HBMMENU_CALLBACK
:
806 case HBMMENU_POPUP_CLOSE
:
807 case HBMMENU_POPUP_RESTORE
:
808 case HBMMENU_POPUP_MAXIMIZE
:
809 case HBMMENU_POPUP_MINIMIZE
:
811 FIXME("Magic 0x%08x not implemented\n", LOWORD(lpitem
->text
));
815 InflateRect( &r
, -1, -1 );
816 if (lpitem
->fState
& MF_HILITE
) flags
|= DFCS_PUSHED
;
817 DrawFrameControl( hdc
, &r
, DFC_CAPTION
, flags
);
821 if (!bmp
|| !GetObjectA( bmp
, sizeof(bm
), &bm
)) return;
824 hdcMem
= CreateCompatibleDC( hdc
);
825 SelectObject( hdcMem
, bmp
);
827 /* handle fontsize > bitmap_height */
828 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
830 if (TWEAK_WineLook
== WIN95_LOOK
) {
831 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_ITEM(lpitem
->text
)) ? NOTSRCCOPY
: SRCCOPY
;
832 if ((lpitem
->fState
& MF_HILITE
) && IS_BITMAP_ITEM(lpitem
->fType
))
833 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
837 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_ITEM(lpitem
->text
) && (!menuBar
)) ? MERGEPAINT
: SRCCOPY
;
839 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
844 /***********************************************************************
847 * Calculate the size of the menu item and store it in lpitem->rect.
849 static void MENU_CalcItemSize( HDC hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
850 INT orgX
, INT orgY
, BOOL menuBar
)
853 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
855 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
856 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem
,
857 (menuBar
? " (MenuBar)" : ""));
859 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
861 if (lpitem
->fType
& MF_OWNERDRAW
)
864 ** Experimentation under Windows reveals that an owner-drawn
865 ** menu is expected to return the size of the content part of
866 ** the menu item, not including the checkmark nor the submenu
867 ** arrow. Windows adds those values itself and returns the
868 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
870 MEASUREITEMSTRUCT mis
;
871 mis
.CtlType
= ODT_MENU
;
873 mis
.itemID
= lpitem
->wID
;
874 mis
.itemData
= (DWORD
)lpitem
->dwItemData
;
877 SendMessageA( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
878 lpitem
->rect
.right
+= mis
.itemWidth
;
882 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
885 /* under at least win95 you seem to be given a standard
886 height for the menu and the height value is ignored */
888 if (TWEAK_WineLook
== WIN31_LOOK
)
889 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
);
891 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
)-1;
894 lpitem
->rect
.bottom
+= mis
.itemHeight
;
896 TRACE("id=%04x size=%dx%d\n",
897 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
898 /* Fall through to get check/arrow width calculation. */
901 if (lpitem
->fType
& MF_SEPARATOR
)
903 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
909 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
910 if (lpitem
->fType
& MF_POPUP
)
911 lpitem
->rect
.right
+= arrow_bitmap_width
;
914 if (lpitem
->fType
& MF_OWNERDRAW
)
917 if (IS_BITMAP_ITEM(lpitem
->fType
))
921 MENU_GetBitmapItemSize( (int)lpitem
->text
, lpitem
->dwItemData
, &size
);
922 lpitem
->rect
.right
+= size
.cx
;
923 lpitem
->rect
.bottom
+= size
.cy
;
924 if (TWEAK_WineLook
== WIN98_LOOK
)
926 /* Leave space for the sunken border */
927 lpitem
->rect
.right
+= 2;
928 lpitem
->rect
.bottom
+= 2;
933 /* it must be a text item - unless it's the system menu */
934 if (!(lpitem
->fType
& MF_SYSMENU
) && IS_STRING_ITEM( lpitem
->fType
))
937 GetTextExtentPoint32W(hdc
, lpitem
->text
, strlenW(lpitem
->text
), &size
);
939 lpitem
->rect
.right
+= size
.cx
;
940 if (TWEAK_WineLook
== WIN31_LOOK
)
941 lpitem
->rect
.bottom
+= max( size
.cy
, GetSystemMetrics(SM_CYMENU
) );
943 lpitem
->rect
.bottom
+= max(size
.cy
, GetSystemMetrics(SM_CYMENU
)-1);
948 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
950 else if ((p
= strchrW( lpitem
->text
, '\t' )) != NULL
)
952 /* Item contains a tab (only meaningful in popup menus) */
953 GetTextExtentPoint32W(hdc
, lpitem
->text
, (int)(p
- lpitem
->text
) , &size
);
954 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+ size
.cx
;
955 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
959 if (strchrW( lpitem
->text
, '\b' ))
960 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
961 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
962 - arrow_bitmap_width
;
965 TRACE("(%d,%d)-(%d,%d)\n", lpitem
->rect
.left
, lpitem
->rect
.top
, lpitem
->rect
.right
, lpitem
->rect
.bottom
);
969 /***********************************************************************
970 * MENU_PopupMenuCalcSize
972 * Calculate the size of a popup menu.
974 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
979 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
981 lppop
->Width
= lppop
->Height
= 0;
982 if (lppop
->nItems
== 0) return;
985 SelectObject( hdc
, hMenuFont
);
988 maxX
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CXBORDER
) : 2+1 ;
990 while (start
< lppop
->nItems
)
992 lpitem
= &lppop
->items
[start
];
994 orgY
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CYBORDER
) : 2;
996 maxTab
= maxTabWidth
= 0;
998 /* Parse items until column break or end of menu */
999 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
1002 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1004 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
1006 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
1007 maxX
= max( maxX
, lpitem
->rect
.right
);
1008 orgY
= lpitem
->rect
.bottom
;
1009 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
1011 maxTab
= max( maxTab
, lpitem
->xTab
);
1012 maxTabWidth
= max(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
1016 /* Finish the column (set all items to the largest width found) */
1017 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
1018 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
1020 lpitem
->rect
.right
= maxX
;
1021 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
1022 lpitem
->xTab
= maxTab
;
1025 lppop
->Height
= max( lppop
->Height
, orgY
);
1028 lppop
->Width
= maxX
;
1030 /* space for 3d border */
1031 if(TWEAK_WineLook
> WIN31_LOOK
)
1037 ReleaseDC( 0, hdc
);
1041 /***********************************************************************
1042 * MENU_MenuBarCalcSize
1044 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1045 * height is off by 1 pixel which causes lengthy window relocations when
1046 * active document window is maximized/restored.
1048 * Calculate the size of the menu bar.
1050 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1051 LPPOPUPMENU lppop
, HWND hwndOwner
)
1054 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1056 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
1057 if (lppop
->nItems
== 0) return;
1058 TRACE("left=%d top=%d right=%d bottom=%d\n",
1059 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
1060 lppop
->Width
= lprect
->right
- lprect
->left
;
1062 maxY
= lprect
->top
+1;
1065 while (start
< lppop
->nItems
)
1067 lpitem
= &lppop
->items
[start
];
1068 orgX
= lprect
->left
;
1071 /* Parse items until line break or end of menu */
1072 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
1074 if ((helpPos
== -1) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1076 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1078 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1080 debug_print_menuitem (" item: ", lpitem
, "");
1081 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
1083 if (lpitem
->rect
.right
> lprect
->right
)
1085 if (i
!= start
) break;
1086 else lpitem
->rect
.right
= lprect
->right
;
1088 maxY
= max( maxY
, lpitem
->rect
.bottom
);
1089 orgX
= lpitem
->rect
.right
;
1092 /* Finish the line (set all items to the largest height found) */
1093 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
1096 lprect
->bottom
= maxY
;
1097 lppop
->Height
= lprect
->bottom
- lprect
->top
;
1099 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1100 /* the last item (if several lines, only move the last line) */
1101 lpitem
= &lppop
->items
[lppop
->nItems
-1];
1102 orgY
= lpitem
->rect
.top
;
1103 orgX
= lprect
->right
;
1104 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
1105 if ( (helpPos
==-1) || (helpPos
>i
) )
1107 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
1108 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
1109 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
1110 lpitem
->rect
.right
= orgX
;
1111 orgX
= lpitem
->rect
.left
;
1115 /***********************************************************************
1118 * Draw a single menu item.
1120 static void MENU_DrawMenuItem( HWND hwnd
, HMENU hmenu
, HWND hwndOwner
, HDC hdc
, MENUITEM
*lpitem
,
1121 UINT height
, BOOL menuBar
, UINT odaction
)
1125 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
1127 if (lpitem
->fType
& MF_SYSMENU
)
1129 if( !IsIconic(hwnd
) ) {
1130 if (TWEAK_WineLook
> WIN31_LOOK
)
1131 NC_DrawSysButton95( hwnd
, hdc
,
1133 (MF_HILITE
| MF_MOUSESELECT
) );
1135 NC_DrawSysButton( hwnd
, hdc
,
1137 (MF_HILITE
| MF_MOUSESELECT
) );
1143 if (lpitem
->fType
& MF_OWNERDRAW
)
1146 ** Experimentation under Windows reveals that an owner-drawn
1147 ** menu is given the rectangle which includes the space it requested
1148 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1149 ** and a popup-menu arrow. This is the value of lpitem->rect.
1150 ** Windows will leave all drawing to the application except for
1151 ** the popup-menu arrow. Windows always draws that itself, after
1152 ** the menu owner has finished drawing.
1156 dis
.CtlType
= ODT_MENU
;
1158 dis
.itemID
= lpitem
->wID
;
1159 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1161 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1162 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
1163 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1164 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1165 dis
.hwndItem
= (HWND
)hmenu
;
1167 dis
.rcItem
= lpitem
->rect
;
1168 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1169 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner
,
1170 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1171 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1173 SendMessageA( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
1174 /* Fall through to draw popup-menu arrow */
1177 TRACE("rect={%d,%d,%d,%d}\n", lpitem
->rect
.left
, lpitem
->rect
.top
,
1178 lpitem
->rect
.right
,lpitem
->rect
.bottom
);
1180 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1182 rect
= lpitem
->rect
;
1184 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1186 if (lpitem
->fState
& MF_HILITE
)
1188 if(TWEAK_WineLook
== WIN98_LOOK
)
1191 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1193 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1195 else /* Not Win98 Look */
1197 if(!IS_BITMAP_ITEM(lpitem
->fType
))
1198 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1202 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_MENU
) );
1205 SetBkMode( hdc
, TRANSPARENT
);
1207 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1209 /* vertical separator */
1210 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1212 if (TWEAK_WineLook
> WIN31_LOOK
)
1216 rc
.bottom
= height
- 3;
1217 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1221 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1222 MoveToEx( hdc
, rect
.left
, 0, NULL
);
1223 LineTo( hdc
, rect
.left
, height
);
1227 /* horizontal separator */
1228 if (lpitem
->fType
& MF_SEPARATOR
)
1230 if (TWEAK_WineLook
> WIN31_LOOK
)
1235 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1236 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1240 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1241 MoveToEx( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2, NULL
);
1242 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1250 if (lpitem
->fState
& MF_HILITE
)
1252 if(TWEAK_WineLook
== WIN98_LOOK
)
1255 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1256 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1258 if(lpitem
->fState
& MF_GRAYED
)
1259 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1261 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1262 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1265 else /* Not Win98 Look */
1267 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1268 if(!IS_BITMAP_ITEM(lpitem
->fType
))
1269 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1274 if (lpitem
->fState
& MF_GRAYED
)
1275 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1277 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1278 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
1281 /* helper lines for debugging */
1282 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1283 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1284 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1285 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1290 INT y
= rect
.top
+ rect
.bottom
;
1291 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1292 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1294 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1296 /* Draw the check mark
1299 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1301 HBITMAP bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hCheckBit
: lpitem
->hUnCheckBit
;
1302 if (bm
) /* we have a custom bitmap */
1304 HDC hdcMem
= CreateCompatibleDC( hdc
);
1305 SelectObject( hdcMem
, bm
);
1306 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1307 check_bitmap_width
, check_bitmap_height
,
1308 hdcMem
, 0, 0, SRCCOPY
);
1311 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1314 HBITMAP bm
= CreateBitmap( check_bitmap_width
, check_bitmap_height
, 1, 1, NULL
);
1315 HDC hdcMem
= CreateCompatibleDC( hdc
);
1316 SelectObject( hdcMem
, bm
);
1317 SetRect( &r
, 0, 0, check_bitmap_width
, check_bitmap_height
);
1318 DrawFrameControl( hdcMem
, &r
, DFC_MENU
,
1319 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1320 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1321 BitBlt( hdc
, rect
.left
, (y
- r
.bottom
) / 2, r
.right
, r
.bottom
,
1322 hdcMem
, 0, 0, SRCCOPY
);
1328 /* Draw the popup-menu arrow */
1329 if (lpitem
->fType
& MF_POPUP
)
1331 HDC hdcMem
= CreateCompatibleDC( hdc
);
1332 HBITMAP hOrigBitmap
;
1334 hOrigBitmap
= SelectObject( hdcMem
, hStdMnArrow
);
1335 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1336 (y
- arrow_bitmap_height
) / 2,
1337 arrow_bitmap_width
, arrow_bitmap_height
,
1338 hdcMem
, 0, 0, SRCCOPY
);
1339 SelectObject( hdcMem
, hOrigBitmap
);
1343 rect
.left
+= check_bitmap_width
;
1344 rect
.right
-= arrow_bitmap_width
;
1347 /* Done for owner-drawn */
1348 if (lpitem
->fType
& MF_OWNERDRAW
)
1351 /* Draw the item text or bitmap */
1352 if (IS_BITMAP_ITEM(lpitem
->fType
))
1354 MENU_DrawBitmapItem( hdc
, lpitem
, &rect
, menuBar
);
1358 /* No bitmap - process text if present */
1359 else if (IS_STRING_ITEM(lpitem
->fType
))
1364 UINT uFormat
= (menuBar
) ?
1365 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1366 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1368 if ( lpitem
->fState
& MFS_DEFAULT
)
1370 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1375 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1376 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1377 i
= strlenW( lpitem
->text
);
1381 for (i
= 0; lpitem
->text
[i
]; i
++)
1382 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1386 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1388 if (!(lpitem
->fState
& MF_HILITE
) )
1390 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1391 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1392 DrawTextW( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1393 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1395 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1398 DrawTextW( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1400 /* paint the shortcut text */
1401 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
1403 if (lpitem
->text
[i
] == '\t')
1405 rect
.left
= lpitem
->xTab
;
1406 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1410 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1413 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1415 if (!(lpitem
->fState
& MF_HILITE
) )
1417 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1418 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1419 DrawTextW( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1420 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1422 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1424 DrawTextW( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1428 SelectObject (hdc
, hfontOld
);
1433 /***********************************************************************
1434 * MENU_DrawPopupMenu
1436 * Paint a popup menu.
1438 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
1440 HBRUSH hPrevBrush
= 0;
1443 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd
, hdc
, hmenu
);
1445 GetClientRect( hwnd
, &rect
);
1447 if(TWEAK_WineLook
== WIN31_LOOK
)
1449 rect
.bottom
-= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1450 rect
.right
-= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
);
1453 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1454 && (SelectObject( hdc
, hMenuFont
)))
1458 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1460 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1466 /* draw 3-d shade */
1467 if(TWEAK_WineLook
== WIN31_LOOK
) {
1468 SelectObject( hdc
, hShadeBrush
);
1469 SetBkMode( hdc
, TRANSPARENT
);
1470 ropPrev
= SetROP2( hdc
, R2_MASKPEN
);
1472 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
1473 PatBlt( hdc
, i
& 0xfffffffe,
1474 rect
.top
+ POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
),
1475 i
%2 + POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1476 rect
.bottom
- rect
.top
, 0x00a000c9 );
1478 PatBlt( hdc
, rect
.left
+ POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1479 i
& 0xfffffffe,rect
.right
- rect
.left
,
1480 i
%2 + POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
), 0x00a000c9 );
1481 SelectObject( hdc
, hPrevPen
);
1482 SelectObject( hdc
, hPrevBrush
);
1483 SetROP2( hdc
, ropPrev
);
1486 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1488 /* draw menu items */
1490 menu
= MENU_GetMenu( hmenu
);
1491 if (menu
&& menu
->nItems
)
1496 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1497 MENU_DrawMenuItem( hwnd
, hmenu
, menu
->hwndOwner
, hdc
, item
,
1498 menu
->Height
, FALSE
, ODA_DRAWENTIRE
);
1503 SelectObject( hdc
, hPrevBrush
);
1508 /***********************************************************************
1511 * Paint a menu bar. Returns the height of the menu bar.
1512 * called from [windows/nonclient.c]
1514 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1520 HMENU hMenu
= GetMenu(hwnd
);
1522 lppop
= MENU_GetMenu( hMenu
);
1523 if (lppop
== NULL
|| lprect
== NULL
)
1525 retvalue
= GetSystemMetrics(SM_CYMENU
);
1529 TRACE("(%04x, %p, %p)\n", hDC
, lprect
, lppop
);
1531 hfontOld
= SelectObject( hDC
, hMenuFont
);
1533 if (lppop
->Height
== 0)
1534 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1536 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1540 retvalue
= lppop
->Height
;
1544 FillRect(hDC
, lprect
, GetSysColorBrush(COLOR_MENU
) );
1546 if (TWEAK_WineLook
== WIN31_LOOK
)
1548 SelectObject( hDC
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1549 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
1550 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1554 SelectObject( hDC
, GetSysColorPen(COLOR_3DFACE
));
1555 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
1556 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1559 if (lppop
->nItems
== 0)
1561 retvalue
= GetSystemMetrics(SM_CYMENU
);
1565 for (i
= 0; i
< lppop
->nItems
; i
++)
1567 MENU_DrawMenuItem( hwnd
, hMenu
, hwnd
,
1568 hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
, ODA_DRAWENTIRE
);
1570 retvalue
= lppop
->Height
;
1573 if (hfontOld
) SelectObject (hDC
, hfontOld
);
1578 /***********************************************************************
1581 * Display a popup menu.
1583 static BOOL
MENU_ShowPopup( HWND hwndOwner
, HMENU hmenu
, UINT id
,
1584 INT x
, INT y
, INT xanchor
, INT yanchor
)
1589 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1590 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1592 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
1593 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1595 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1596 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1599 /* store the owner for DrawItem */
1600 menu
->hwndOwner
= hwndOwner
;
1603 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1605 /* adjust popup menu pos so that it fits within the desktop */
1607 width
= menu
->Width
+ GetSystemMetrics(SM_CXBORDER
);
1608 height
= menu
->Height
+ GetSystemMetrics(SM_CYBORDER
);
1610 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1613 x
-= width
- xanchor
;
1614 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1615 x
= GetSystemMetrics(SM_CXSCREEN
) - width
;
1619 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1622 y
-= height
+ yanchor
;
1623 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1624 y
= GetSystemMetrics(SM_CYSCREEN
) - height
;
1628 if( TWEAK_WineLook
== WIN31_LOOK
)
1630 width
+= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
); /* add space for shading */
1631 height
+= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1634 /* NOTE: In Windows, top menu popup is not owned. */
1635 menu
->hWnd
= CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1636 WS_POPUP
, x
, y
, width
, height
,
1637 hwndOwner
, 0, GetWindowLongA(hwndOwner
,GWL_HINSTANCE
),
1639 if( !menu
->hWnd
) return FALSE
;
1640 if (!top_popup
) top_popup
= menu
->hWnd
;
1642 /* Display the window */
1644 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1645 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1646 UpdateWindow( menu
->hWnd
);
1651 /***********************************************************************
1654 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
1655 BOOL sendMenuSelect
, HMENU topmenu
)
1660 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1662 lppop
= MENU_GetMenu( hmenu
);
1663 if ((!lppop
) || (!lppop
->nItems
) || (!lppop
->hWnd
)) return;
1665 if (lppop
->FocusedItem
== wIndex
) return;
1666 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
1667 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1669 SelectObject( hdc
, hMenuFont
);
1671 /* Clear previous highlighted item */
1672 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1674 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1675 MENU_DrawMenuItem(lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,&lppop
->items
[lppop
->FocusedItem
],
1676 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1680 /* Highlight new item (if any) */
1681 lppop
->FocusedItem
= wIndex
;
1682 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1684 if(!(lppop
->items
[wIndex
].fType
& MF_SEPARATOR
)) {
1685 lppop
->items
[wIndex
].fState
|= MF_HILITE
;
1686 MENU_DrawMenuItem( lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,
1687 &lppop
->items
[wIndex
], lppop
->Height
,
1688 !(lppop
->wFlags
& MF_POPUP
), ODA_SELECT
);
1692 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1693 SendMessageA( hwndOwner
, WM_MENUSELECT
,
1694 MAKELONG(ip
->fType
& MF_POPUP
? wIndex
: ip
->wID
,
1695 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1696 (lppop
->wFlags
& MF_SYSMENU
)), hmenu
);
1699 else if (sendMenuSelect
) {
1702 if((pos
=MENU_FindSubMenu(&topmenu
, hmenu
))!=NO_SELECTED_ITEM
){
1703 POPUPMENU
*ptm
= MENU_GetMenu( topmenu
);
1704 MENUITEM
*ip
= &ptm
->items
[pos
];
1705 SendMessageA( hwndOwner
, WM_MENUSELECT
, MAKELONG(pos
,
1706 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1707 (ptm
->wFlags
& MF_SYSMENU
)), topmenu
);
1711 ReleaseDC( lppop
->hWnd
, hdc
);
1715 /***********************************************************************
1716 * MENU_MoveSelection
1718 * Moves currently selected item according to the offset parameter.
1719 * If there is no selection then it should select the last item if
1720 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1722 static void MENU_MoveSelection( HWND hwndOwner
, HMENU hmenu
, INT offset
)
1727 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner
, hmenu
, offset
);
1729 menu
= MENU_GetMenu( hmenu
);
1730 if ((!menu
) || (!menu
->items
)) return;
1732 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1734 if( menu
->nItems
== 1 ) return; else
1735 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1737 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1739 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1744 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1745 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1746 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1748 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1754 /**********************************************************************
1757 * Set an item flags, id and text ptr. Called by InsertMenu() and
1760 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
,
1763 LPWSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1765 debug_print_menuitem("MENU_SetItemData from: ", item
, "");
1766 TRACE("flags=%x str=%p\n", flags
, str
);
1768 if (IS_STRING_ITEM(flags
))
1772 flags
|= MF_SEPARATOR
;
1778 /* Item beginning with a backspace is a help item */
1784 if (!(text
= HeapAlloc( GetProcessHeap(), 0, (strlenW(str
)+1) * sizeof(WCHAR
) )))
1786 strcpyW( text
, str
);
1790 else if (IS_BITMAP_ITEM(flags
))
1791 item
->text
= (LPWSTR
)(HBITMAP
)LOWORD(str
);
1792 else item
->text
= NULL
;
1794 if (flags
& MF_OWNERDRAW
)
1795 item
->dwItemData
= (DWORD
)str
;
1797 item
->dwItemData
= 0;
1799 if ((item
->fType
& MF_POPUP
) && (flags
& MF_POPUP
) && (item
->hSubMenu
!= id
) )
1800 DestroyMenu( item
->hSubMenu
); /* ModifyMenu() spec */
1802 if (flags
& MF_POPUP
)
1804 POPUPMENU
*menu
= MENU_GetMenu((UINT16
)id
);
1805 if (menu
) menu
->wFlags
|= MF_POPUP
;
1817 if (flags
& MF_POPUP
)
1818 item
->hSubMenu
= id
;
1820 if ((item
->fType
& MF_POPUP
) && !(flags
& MF_POPUP
) )
1821 flags
|= MF_POPUP
; /* keep popup */
1823 item
->fType
= flags
& TYPE_MASK
;
1824 item
->fState
= (flags
& STATE_MASK
) &
1825 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1828 /* Don't call SetRectEmpty here! */
1831 if (prevText
) HeapFree( GetProcessHeap(), 0, prevText
);
1833 debug_print_menuitem("MENU_SetItemData to : ", item
, "");
1838 /**********************************************************************
1841 * Insert a new item into a menu.
1843 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
1848 if (!(menu
= MENU_GetMenu(hMenu
)))
1851 /* Find where to insert new item */
1853 if (flags
& MF_BYPOSITION
) {
1854 if (pos
> menu
->nItems
)
1857 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1860 if (!(menu
= MENU_GetMenu( hMenu
)))
1865 /* Create new items array */
1867 newItems
= HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1870 WARN("allocation failed\n" );
1873 if (menu
->nItems
> 0)
1875 /* Copy the old array into the new one */
1876 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1877 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1878 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1879 HeapFree( GetProcessHeap(), 0, menu
->items
);
1881 menu
->items
= newItems
;
1883 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1884 menu
->Height
= 0; /* force size recalculate */
1885 return &newItems
[pos
];
1889 /**********************************************************************
1890 * MENU_ParseResource
1892 * Parse a standard menu resource and add items to the menu.
1893 * Return a pointer to the end of the resource.
1895 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1902 flags
= GET_WORD(res
);
1903 res
+= sizeof(WORD
);
1904 if (!(flags
& MF_POPUP
))
1907 res
+= sizeof(WORD
);
1909 if (!IS_STRING_ITEM(flags
))
1910 ERR("not a string item %04x\n", flags
);
1912 if (!unicode
) res
+= strlen(str
) + 1;
1913 else res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1914 if (flags
& MF_POPUP
)
1916 HMENU hSubMenu
= CreatePopupMenu();
1917 if (!hSubMenu
) return NULL
;
1918 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1920 if (!unicode
) AppendMenuA( hMenu
, flags
, (UINT
)hSubMenu
, str
);
1921 else AppendMenuW( hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1923 else /* Not a popup */
1925 if (!unicode
) AppendMenuA( hMenu
, flags
, id
, *str
? str
: NULL
);
1926 else AppendMenuW( hMenu
, flags
, id
,
1927 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1929 } while (!(flags
& MF_END
));
1934 /**********************************************************************
1935 * MENUEX_ParseResource
1937 * Parse an extended menu resource and add items to the menu.
1938 * Return a pointer to the end of the resource.
1940 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1946 mii
.cbSize
= sizeof(mii
);
1947 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
1948 mii
.fType
= GET_DWORD(res
);
1949 res
+= sizeof(DWORD
);
1950 mii
.fState
= GET_DWORD(res
);
1951 res
+= sizeof(DWORD
);
1952 mii
.wID
= GET_DWORD(res
);
1953 res
+= sizeof(DWORD
);
1954 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
1955 res
+= sizeof(WORD
);
1956 /* Align the text on a word boundary. */
1957 res
+= (~((int)res
- 1)) & 1;
1958 mii
.dwTypeData
= (LPWSTR
) res
;
1959 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1960 /* Align the following fields on a dword boundary. */
1961 res
+= (~((int)res
- 1)) & 3;
1963 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1964 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, debugstr_w(mii
.dwTypeData
));
1966 if (resinfo
& 1) { /* Pop-up? */
1967 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1968 res
+= sizeof(DWORD
);
1969 mii
.hSubMenu
= CreatePopupMenu();
1972 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
1973 DestroyMenu(mii
.hSubMenu
);
1976 mii
.fMask
|= MIIM_SUBMENU
;
1977 mii
.fType
|= MF_POPUP
;
1979 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1980 } while (!(resinfo
& MF_END
));
1985 /***********************************************************************
1988 * Return the handle of the selected sub-popup menu (if any).
1990 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
1995 menu
= MENU_GetMenu( hmenu
);
1997 if ((!menu
) || (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return 0;
1999 item
= &menu
->items
[menu
->FocusedItem
];
2000 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
2001 return item
->hSubMenu
;
2006 /***********************************************************************
2007 * MENU_HideSubPopups
2009 * Hide the sub-popup menus of this menu.
2011 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
2012 BOOL sendMenuSelect
)
2014 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
2016 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, sendMenuSelect
);
2018 if (menu
&& top_popup
)
2024 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
2026 item
= &menu
->items
[menu
->FocusedItem
];
2027 if (!(item
->fType
& MF_POPUP
) ||
2028 !(item
->fState
& MF_MOUSESELECT
)) return;
2029 item
->fState
&= ~MF_MOUSESELECT
;
2030 hsubmenu
= item
->hSubMenu
;
2033 submenu
= MENU_GetMenu( hsubmenu
);
2034 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
2035 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
, 0 );
2036 DestroyWindow( submenu
->hWnd
);
2042 /***********************************************************************
2045 * Display the sub-menu of the selected item of this menu.
2046 * Return the handle of the submenu, or hmenu if no submenu to display.
2048 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
,
2049 BOOL selectFirst
, UINT wFlags
)
2056 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, selectFirst
);
2058 if (!(menu
= MENU_GetMenu( hmenu
))) return hmenu
;
2060 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return hmenu
;
2062 item
= &menu
->items
[menu
->FocusedItem
];
2063 if (!(item
->fType
& MF_POPUP
) || (item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2066 /* message must be sent before using item,
2067 because nearly everything may be changed by the application ! */
2069 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2070 if (!(wFlags
& TPM_NONOTIFY
))
2071 SendMessageA( hwndOwner
, WM_INITMENUPOPUP
, item
->hSubMenu
,
2072 MAKELONG( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
2074 item
= &menu
->items
[menu
->FocusedItem
];
2077 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2078 if (!(item
->fState
& MF_HILITE
))
2080 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC( menu
->hWnd
);
2081 else hdc
= GetDCEx( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2083 SelectObject( hdc
, hMenuFont
);
2085 item
->fState
|= MF_HILITE
;
2086 MENU_DrawMenuItem( menu
->hWnd
, hmenu
, hwndOwner
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
2087 ReleaseDC( menu
->hWnd
, hdc
);
2089 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
2092 item
->fState
|= MF_MOUSESELECT
;
2094 if (IS_SYSTEM_MENU(menu
))
2096 MENU_InitSysMenuPopup(item
->hSubMenu
,
2097 GetWindowLongA( menu
->hWnd
, GWL_STYLE
),
2098 GetClassLongA( menu
->hWnd
, GCL_STYLE
));
2100 NC_GetSysPopupPos( menu
->hWnd
, &rect
);
2101 rect
.top
= rect
.bottom
;
2102 rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2103 rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2107 GetWindowRect( menu
->hWnd
, &rect
);
2108 if (menu
->wFlags
& MF_POPUP
)
2110 rect
.left
+= item
->rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2111 rect
.top
+= item
->rect
.top
;
2112 rect
.right
= item
->rect
.left
- item
->rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2113 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
2117 rect
.left
+= item
->rect
.left
;
2118 rect
.top
+= item
->rect
.bottom
;
2119 rect
.right
= item
->rect
.right
- item
->rect
.left
;
2120 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
2124 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
2125 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2127 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
2128 return item
->hSubMenu
;
2133 /**********************************************************************
2136 BOOL
MENU_IsMenuActive(void)
2138 return (top_popup
!= 0);
2141 /***********************************************************************
2144 * Walks menu chain trying to find a menu pt maps to.
2146 static HMENU
MENU_PtMenu( HMENU hMenu
, POINT pt
)
2148 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2149 UINT item
= menu
->FocusedItem
;
2152 /* try subpopup first (if any) */
2153 ret
= (item
!= NO_SELECTED_ITEM
&&
2154 (menu
->items
[item
].fType
& MF_POPUP
) &&
2155 (menu
->items
[item
].fState
& MF_MOUSESELECT
))
2156 ? MENU_PtMenu(menu
->items
[item
].hSubMenu
, pt
) : 0;
2158 if (!ret
) /* check the current window (avoiding WM_HITTEST) */
2160 INT ht
= NC_HandleNCHitTest( menu
->hWnd
, pt
);
2161 if( menu
->wFlags
& MF_POPUP
)
2163 if (ht
!= HTNOWHERE
&& ht
!= HTERROR
) ret
= hMenu
;
2165 else if (ht
== HTSYSMENU
)
2166 ret
= get_win_sys_menu( menu
->hWnd
);
2167 else if (ht
== HTMENU
)
2168 ret
= GetMenu( menu
->hWnd
);
2173 /***********************************************************************
2174 * MENU_ExecFocusedItem
2176 * Execute a menu item (for instance when user pressed Enter).
2177 * Return the wID of the executed item. Otherwise, -1 indicating
2178 * that no menu item was executed;
2179 * Have to receive the flags for the TrackPopupMenu options to avoid
2180 * sending unwanted message.
2183 static INT
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU hMenu
, UINT wFlags
)
2186 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2188 TRACE("%p hmenu=0x%04x\n", pmt
, hMenu
);
2190 if (!menu
|| !menu
->nItems
||
2191 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return -1;
2193 item
= &menu
->items
[menu
->FocusedItem
];
2195 TRACE("%08x %08x %08x\n",
2196 hMenu
, item
->wID
, item
->hSubMenu
);
2198 if (!(item
->fType
& MF_POPUP
))
2200 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(item
->fType
& MF_SEPARATOR
))
2202 /* If TPM_RETURNCMD is set you return the id, but
2203 do not send a message to the owner */
2204 if(!(wFlags
& TPM_RETURNCMD
))
2206 if( menu
->wFlags
& MF_SYSMENU
)
2207 PostMessageA( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
2208 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
2210 PostMessageA( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
2216 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hMenu
, TRUE
, wFlags
);
2221 /***********************************************************************
2222 * MENU_SwitchTracking
2224 * Helper function for menu navigation routines.
2226 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU hPtMenu
, UINT id
)
2228 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2229 POPUPMENU
*topmenu
= MENU_GetMenu( pmt
->hTopMenu
);
2231 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt
, hPtMenu
, id
);
2233 if( pmt
->hTopMenu
!= hPtMenu
&&
2234 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
2236 /* both are top level menus (system and menu-bar) */
2237 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2238 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2239 pmt
->hTopMenu
= hPtMenu
;
2241 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2242 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
, 0 );
2246 /***********************************************************************
2249 * Return TRUE if we can go on with menu tracking.
2251 static BOOL
MENU_ButtonDown( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2253 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2258 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2261 if( IS_SYSTEM_MENU(ptmenu
) )
2262 item
= ptmenu
->items
;
2264 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2268 if( ptmenu
->FocusedItem
!= id
)
2269 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2271 /* If the popup menu is not already "popped" */
2272 if(!(item
->fState
& MF_MOUSESELECT
))
2274 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2276 /* In win31, a newly popped menu always remains opened for the next buttonup */
2277 if(TWEAK_WineLook
== WIN31_LOOK
)
2278 ptmenu
->bTimeToHide
= FALSE
;
2283 /* Else the click was on the menu bar, finish the tracking */
2288 /***********************************************************************
2291 * Return the value of MENU_ExecFocusedItem if
2292 * the selected item was not a popup. Else open the popup.
2293 * A -1 return value indicates that we go on with menu tracking.
2296 static INT
MENU_ButtonUp( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2298 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2303 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2306 if( IS_SYSTEM_MENU(ptmenu
) )
2307 item
= ptmenu
->items
;
2309 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2311 if( item
&& (ptmenu
->FocusedItem
== id
))
2313 if( !(item
->fType
& MF_POPUP
) )
2314 return MENU_ExecFocusedItem( pmt
, hPtMenu
, wFlags
);
2316 /* If we are dealing with the top-level menu */
2317 /* and this is a click on an already "popped" item: */
2318 /* Stop the menu tracking and close the opened submenus */
2319 if((pmt
->hTopMenu
== hPtMenu
) && (ptmenu
->bTimeToHide
== TRUE
))
2322 ptmenu
->bTimeToHide
= TRUE
;
2328 /***********************************************************************
2331 * Return TRUE if we can go on with menu tracking.
2333 static BOOL
MENU_MouseMove( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2335 UINT id
= NO_SELECTED_ITEM
;
2336 POPUPMENU
*ptmenu
= NULL
;
2340 ptmenu
= MENU_GetMenu( hPtMenu
);
2341 if( IS_SYSTEM_MENU(ptmenu
) )
2344 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2347 if( id
== NO_SELECTED_ITEM
)
2349 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2350 NO_SELECTED_ITEM
, TRUE
, pmt
->hTopMenu
);
2353 else if( ptmenu
->FocusedItem
!= id
)
2355 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2356 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2362 /***********************************************************************
2365 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2367 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT vk
)
2369 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2371 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
2372 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
2374 MDINEXTMENU next_menu
;
2379 next_menu
.hmenuIn
= (IS_SYSTEM_MENU(menu
)) ? GetSubMenu(pmt
->hTopMenu
,0) : pmt
->hTopMenu
;
2380 next_menu
.hmenuNext
= 0;
2381 next_menu
.hwndNext
= 0;
2382 SendMessageW( pmt
->hOwnerWnd
, WM_NEXTMENU
, vk
, (LPARAM
)&next_menu
);
2384 TRACE("%04x [%04x] -> %04x [%04x]\n",
2385 pmt
->hCurrentMenu
, pmt
->hOwnerWnd
, next_menu
.hmenuNext
, next_menu
.hwndNext
);
2387 if (!next_menu
.hmenuNext
|| !next_menu
.hwndNext
)
2389 DWORD style
= GetWindowLongA( pmt
->hOwnerWnd
, GWL_STYLE
);
2390 hNewWnd
= pmt
->hOwnerWnd
;
2391 if( IS_SYSTEM_MENU(menu
) )
2393 /* switch to the menu bar */
2395 if(style
& WS_CHILD
|| !(hNewMenu
= GetMenu(hNewWnd
))) return FALSE
;
2399 menu
= MENU_GetMenu( hNewMenu
);
2400 id
= menu
->nItems
- 1;
2403 else if (style
& WS_SYSMENU
)
2405 /* switch to the system menu */
2406 hNewMenu
= get_win_sys_menu( hNewWnd
);
2410 else /* application returned a new menu to switch to */
2412 hNewMenu
= next_menu
.hmenuNext
;
2413 hNewWnd
= WIN_GetFullHandle( next_menu
.hwndNext
);
2415 if( IsMenu(hNewMenu
) && IsWindow(hNewWnd
) )
2417 DWORD style
= GetWindowLongA( hNewWnd
, GWL_STYLE
);
2419 if (style
& WS_SYSMENU
&&
2420 GetSubMenu(get_win_sys_menu(hNewWnd
), 0) == hNewMenu
)
2422 /* get the real system menu */
2423 hNewMenu
= get_win_sys_menu(hNewWnd
);
2425 else if (style
& WS_CHILD
|| GetMenu(hNewWnd
) != hNewMenu
)
2427 /* FIXME: Not sure what to do here;
2428 * perhaps try to track hNewMenu as a popup? */
2430 TRACE(" -- got confused.\n");
2437 if( hNewMenu
!= pmt
->hTopMenu
)
2439 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
,
2441 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2442 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2445 if( hNewWnd
!= pmt
->hOwnerWnd
)
2448 pmt
->hOwnerWnd
= hNewWnd
;
2449 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
2452 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2453 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
, 0 );
2460 /***********************************************************************
2463 * The idea is not to show the popup if the next input message is
2464 * going to hide it anyway.
2466 static BOOL
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2470 msg
.hwnd
= pmt
->hOwnerWnd
;
2472 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2473 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2478 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2479 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2481 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2482 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2483 if( msg
.message
== WM_KEYDOWN
&&
2484 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2486 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2493 /* failures go through this */
2494 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2498 /***********************************************************************
2501 * Handle a VK_ESCAPE key event in a menu.
2503 static BOOL
MENU_KeyEscape(MTRACKER
* pmt
, UINT wFlags
)
2505 BOOL bEndMenu
= TRUE
;
2507 if (pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2509 POPUPMENU
*menu
= MENU_GetMenu(pmt
->hCurrentMenu
);
2511 if (menu
->wFlags
& MF_POPUP
)
2513 HMENU hmenutmp
, hmenuprev
;
2515 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2517 /* close topmost popup */
2518 while (hmenutmp
!= pmt
->hCurrentMenu
)
2520 hmenuprev
= hmenutmp
;
2521 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2524 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2525 pmt
->hCurrentMenu
= hmenuprev
;
2533 /***********************************************************************
2536 * Handle a VK_LEFT key event in a menu.
2538 static void MENU_KeyLeft( MTRACKER
* pmt
, UINT wFlags
)
2541 HMENU hmenutmp
, hmenuprev
;
2544 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2545 menu
= MENU_GetMenu( hmenutmp
);
2547 /* Try to move 1 column left (if possible) */
2548 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2549 NO_SELECTED_ITEM
) {
2551 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2556 /* close topmost popup */
2557 while (hmenutmp
!= pmt
->hCurrentMenu
)
2559 hmenuprev
= hmenutmp
;
2560 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2563 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2564 pmt
->hCurrentMenu
= hmenuprev
;
2566 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2568 /* move menu bar selection if no more popups are left */
2570 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2571 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2573 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2575 /* A sublevel menu was displayed - display the next one
2576 * unless there is another displacement coming up */
2578 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2579 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2580 pmt
->hTopMenu
, TRUE
, wFlags
);
2586 /***********************************************************************
2589 * Handle a VK_RIGHT key event in a menu.
2591 static void MENU_KeyRight( MTRACKER
* pmt
, UINT wFlags
)
2594 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2597 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2599 debugstr_w((MENU_GetMenu(pmt
->hCurrentMenu
))->
2601 pmt
->hTopMenu
, debugstr_w(menu
->items
[0].text
) );
2603 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2605 /* If already displaying a popup, try to display sub-popup */
2607 hmenutmp
= pmt
->hCurrentMenu
;
2608 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hmenutmp
, TRUE
, wFlags
);
2610 /* if subpopup was displayed then we are done */
2611 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2614 /* Check to see if there's another column */
2615 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2616 NO_SELECTED_ITEM
) {
2617 TRACE("Going to %d.\n", nextcol
);
2618 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2623 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2625 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2627 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2628 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2629 } else hmenutmp
= 0;
2631 /* try to move to the next item */
2632 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2633 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2635 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2636 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2637 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2638 pmt
->hTopMenu
, TRUE
, wFlags
);
2642 /***********************************************************************
2645 * Menu tracking code.
2647 static INT
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
2648 HWND hwnd
, const RECT
*lprect
)
2653 INT executedMenuId
= -1;
2655 BOOL enterIdleSent
= FALSE
;
2658 mt
.hCurrentMenu
= hmenu
;
2659 mt
.hTopMenu
= hmenu
;
2660 mt
.hOwnerWnd
= WIN_GetFullHandle( hwnd
);
2664 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2665 hmenu
, wFlags
, x
, y
, hwnd
, (lprect
) ? lprect
->left
: 0, (lprect
) ? lprect
->top
: 0,
2666 (lprect
) ? lprect
->right
: 0, (lprect
) ? lprect
->bottom
: 0);
2669 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
2671 if (wFlags
& TPM_BUTTONDOWN
)
2673 /* Get the result in order to start the tracking or not */
2674 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2675 fEndMenu
= !fRemove
;
2678 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
2682 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2683 if (!menu
) /* sometimes happens if I do a window manager close */
2686 /* we have to keep the message in the queue until it's
2687 * clear that menu loop is not over yet. */
2691 if (PeekMessageA( &msg
, 0, 0, 0, PM_NOREMOVE
))
2693 if (!CallMsgFilterA( &msg
, MSGF_MENU
)) break;
2694 /* remove the message from the queue */
2695 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2701 HWND win
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2702 enterIdleSent
= TRUE
;
2703 SendMessageW( mt
.hOwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
)win
);
2709 /* check if EndMenu() tried to cancel us, by posting this message */
2710 if(msg
.message
== WM_CANCELMODE
)
2712 /* we are now out of the loop */
2715 /* remove the message from the queue */
2716 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2718 /* break out of internal loop, ala ESCAPE */
2722 TranslateMessage( &msg
);
2725 if ( (msg
.hwnd
==menu
->hWnd
) || (msg
.message
!=WM_TIMER
) )
2726 enterIdleSent
=FALSE
;
2729 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2732 * use the mouse coordinates in lParam instead of those in the MSG
2733 * struct to properly handle synthetic messages. lParam coords are
2734 * relative to client area, so they must be converted; since they can
2735 * be negative, we must use SLOWORD/SHIWORD instead of LOWORD/HIWORD.
2737 mt
.pt
.x
= SLOWORD(msg
.lParam
);
2738 mt
.pt
.y
= SHIWORD(msg
.lParam
);
2739 ClientToScreen(msg
.hwnd
,&mt
.pt
);
2741 /* Find a menu for this mouse event */
2742 hmenu
= MENU_PtMenu( mt
.hTopMenu
, mt
.pt
);
2746 /* no WM_NC... messages in captured state */
2748 case WM_RBUTTONDBLCLK
:
2749 case WM_RBUTTONDOWN
:
2750 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2752 case WM_LBUTTONDBLCLK
:
2753 case WM_LBUTTONDOWN
:
2754 /* If the message belongs to the menu, removes it from the queue */
2755 /* Else, end menu tracking */
2756 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2757 fEndMenu
= !fRemove
;
2761 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2764 /* Check if a menu was selected by the mouse */
2767 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
2769 /* End the loop if executedMenuId is an item ID */
2770 /* or if the job was done (executedMenuId = 0). */
2771 fEndMenu
= fRemove
= (executedMenuId
!= -1);
2773 /* No menu was selected by the mouse */
2774 /* if the function was called by TrackPopupMenu, continue
2775 with the menu tracking. If not, stop it */
2777 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
2782 /* In win95 winelook, the selected menu item must be changed every time the
2783 mouse moves. In Win31 winelook, the mouse button has to be held down */
2785 if ( (TWEAK_WineLook
> WIN31_LOOK
) ||
2786 ( (msg
.wParam
& MK_LBUTTON
) ||
2787 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
))) )
2789 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
, wFlags
);
2791 } /* switch(msg.message) - mouse */
2793 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2795 fRemove
= TRUE
; /* Keyboard messages are always removed */
2803 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2804 NO_SELECTED_ITEM
, FALSE
, 0 );
2807 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2808 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2811 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2813 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2814 if (!(menu
->wFlags
& MF_POPUP
))
2815 mt
.hCurrentMenu
= MENU_ShowSubPopup(mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
, wFlags
);
2816 else /* otherwise try to move selection */
2817 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2821 MENU_KeyLeft( &mt
, wFlags
);
2825 MENU_KeyRight( &mt
, wFlags
);
2829 fEndMenu
= MENU_KeyEscape(&mt
, wFlags
);
2835 hi
.cbSize
= sizeof(HELPINFO
);
2836 hi
.iContextType
= HELPINFO_MENUITEM
;
2837 if (menu
->FocusedItem
== NO_SELECTED_ITEM
)
2840 hi
.iCtrlId
= menu
->items
[menu
->FocusedItem
].wID
;
2841 hi
.hItemHandle
= hmenu
;
2842 hi
.dwContextId
= menu
->dwContextHelpID
;
2843 hi
.MousePos
= msg
.pt
;
2844 SendMessageA(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
2851 break; /* WM_KEYDOWN */
2861 break; /* WM_SYSKEYDOWN */
2867 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
2869 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2870 fEndMenu
= (executedMenuId
!= -1);
2875 /* Hack to avoid control chars. */
2876 /* We will find a better way real soon... */
2877 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2879 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2880 LOWORD(msg
.wParam
), FALSE
);
2881 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
2882 else if (pos
== (UINT
)-1) MessageBeep(0);
2885 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
,
2887 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2888 fEndMenu
= (executedMenuId
!= -1);
2892 } /* switch(msg.message) - kbd */
2896 DispatchMessageA( &msg
);
2899 if (!fEndMenu
) fRemove
= TRUE
;
2901 /* finally remove message from the queue */
2903 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2904 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2905 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2910 /* If dropdown is still painted and the close box is clicked on
2911 then the menu will be destroyed as part of the DispatchMessage above.
2912 This will then invalidate the menu handle in mt.hTopMenu. We should
2913 check for this first. */
2914 if( IsMenu( mt
.hTopMenu
) )
2916 menu
= MENU_GetMenu( mt
.hTopMenu
);
2918 if( IsWindow( mt
.hOwnerWnd
) )
2920 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2922 if (menu
&& menu
->wFlags
& MF_POPUP
)
2924 DestroyWindow( menu
->hWnd
);
2927 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2928 SendMessageA( mt
.hOwnerWnd
, WM_MENUSELECT
, MAKELONG(0,0xffff), 0 );
2931 /* Reset the variable for hiding menu */
2932 if( menu
) menu
->bTimeToHide
= FALSE
;
2935 /* The return value is only used by TrackPopupMenu */
2936 return ((executedMenuId
!= -1) ? executedMenuId
: 0);
2939 /***********************************************************************
2942 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
2944 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd
, hMenu
);
2948 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2949 if (!(wFlags
& TPM_NONOTIFY
))
2950 SendMessageA( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
2952 SendMessageA( hWnd
, WM_SETCURSOR
, (WPARAM
)hWnd
, HTCAPTION
);
2954 if (!(wFlags
& TPM_NONOTIFY
))
2957 SendMessageA( hWnd
, WM_INITMENU
, hMenu
, 0 );
2958 if ((menu
= MENU_GetMenu( hMenu
)) && (!menu
->Height
))
2959 { /* app changed/recreated menu bar entries in WM_INITMENU
2960 Recalculate menu sizes else clicks will not work */
2961 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2962 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2968 /***********************************************************************
2971 static BOOL
MENU_ExitTracking(HWND hWnd
)
2973 TRACE("hwnd=0x%04x\n", hWnd
);
2975 SendMessageA( hWnd
, WM_EXITMENULOOP
, 0, 0 );
2980 /***********************************************************************
2981 * MENU_TrackMouseMenuBar
2983 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2985 void MENU_TrackMouseMenuBar( HWND hWnd
, INT ht
, POINT pt
)
2987 HMENU hMenu
= (ht
== HTSYSMENU
) ? get_win_sys_menu( hWnd
) : GetMenu( hWnd
);
2988 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
2990 TRACE("wnd=%x ht=0x%04x (%ld,%ld)\n", hWnd
, ht
, pt
.x
, pt
.y
);
2994 /* map point to parent client coordinates */
2995 HWND parent
= GetAncestor( hWnd
, GA_PARENT
);
2996 if (parent
!= GetDesktopWindow()) ScreenToClient( parent
, &pt
);
2998 MENU_InitTracking( hWnd
, hMenu
, FALSE
, wFlags
);
2999 MENU_TrackMenu( hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
3000 MENU_ExitTracking(hWnd
);
3005 /***********************************************************************
3006 * MENU_TrackKbdMenuBar
3008 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3010 void MENU_TrackKbdMenuBar( HWND hwnd
, UINT wParam
, INT vkey
)
3012 UINT uItem
= NO_SELECTED_ITEM
;
3014 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3016 /* find window that has a menu */
3018 while (GetWindowLongA( hwnd
, GWL_STYLE
) & WS_CHILD
)
3019 if (!(hwnd
= GetParent( hwnd
))) return;
3021 /* check if we have to track a system menu */
3023 hTrackMenu
= GetMenu( hwnd
);
3024 if (!hTrackMenu
|| IsIconic(hwnd
) || vkey
== VK_SPACE
)
3026 if (!(GetWindowLongA( hwnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3027 hTrackMenu
= get_win_sys_menu( hwnd
);
3029 wParam
|= HTSYSMENU
; /* prevent item lookup */
3032 if (!IsMenu( hTrackMenu
)) return;
3034 MENU_InitTracking( hwnd
, hTrackMenu
, FALSE
, wFlags
);
3036 if( vkey
&& vkey
!= VK_SPACE
)
3038 uItem
= MENU_FindItemByKey( hwnd
, hTrackMenu
, vkey
, (wParam
& HTSYSMENU
) );
3039 if( uItem
>= (UINT
)(-2) )
3041 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3048 MENU_SelectItem( hwnd
, hTrackMenu
, uItem
, TRUE
, 0 );
3050 if( uItem
== NO_SELECTED_ITEM
)
3051 MENU_MoveSelection( hwnd
, hTrackMenu
, ITEM_NEXT
);
3053 PostMessageA( hwnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3055 MENU_TrackMenu( hTrackMenu
, wFlags
, 0, 0, hwnd
, NULL
);
3057 MENU_ExitTracking( hwnd
);
3061 /**********************************************************************
3062 * TrackPopupMenu (USER32.@)
3064 * Like the win32 API, the function return the command ID only if the
3065 * flag TPM_RETURNCMD is on.
3068 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3069 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
3073 MENU_InitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
3075 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3076 if (!(wFlags
& TPM_NONOTIFY
))
3077 SendMessageA( hWnd
, WM_INITMENUPOPUP
, hMenu
, 0);
3079 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
3080 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
, lpRect
);
3081 MENU_ExitTracking(hWnd
);
3083 if( (!(wFlags
& TPM_RETURNCMD
)) && (ret
!= FALSE
) )
3089 /**********************************************************************
3090 * TrackPopupMenuEx (USER32.@)
3092 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3093 HWND hWnd
, LPTPMPARAMS lpTpm
)
3095 FIXME("not fully implemented\n" );
3096 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, 0, hWnd
,
3097 lpTpm
? &lpTpm
->rcExclude
: NULL
);
3100 /***********************************************************************
3103 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3105 static LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
3107 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3108 hwnd
, message
, wParam
, lParam
);
3114 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lParam
;
3115 SetWindowLongW( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
3119 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
3120 return MA_NOACTIVATE
;
3125 BeginPaint( hwnd
, &ps
);
3126 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
3127 (HMENU
)GetWindowLongA( hwnd
, 0 ) );
3128 EndPaint( hwnd
, &ps
);
3135 /* zero out global pointer in case resident popup window was destroyed. */
3136 if (hwnd
== top_popup
) top_popup
= 0;
3143 if (!GetWindowLongW( hwnd
, 0 )) ERR("no menu to display\n");
3146 SetWindowLongW( hwnd
, 0, 0 );
3149 case MM_SETMENUHANDLE
:
3150 SetWindowLongW( hwnd
, 0, wParam
);
3153 case MM_GETMENUHANDLE
:
3154 return GetWindowLongW( hwnd
, 0 );
3157 return DefWindowProcW( hwnd
, message
, wParam
, lParam
);
3163 /***********************************************************************
3164 * MENU_GetMenuBarHeight
3166 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3168 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
3169 INT orgX
, INT orgY
)
3175 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3176 hwnd
, menubarWidth
, orgX
, orgY
);
3178 if (!(lppop
= MENU_GetMenu( GetMenu(hwnd
) ))) return 0;
3180 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3181 SelectObject( hdc
, hMenuFont
);
3182 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+GetSystemMetrics(SM_CYMENU
));
3183 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
3184 ReleaseDC( hwnd
, hdc
);
3185 return lppop
->Height
;
3189 /*******************************************************************
3190 * ChangeMenu (USER.153)
3192 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
3193 UINT16 id
, UINT16 flags
)
3195 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3196 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3197 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
3200 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3201 /* for MF_DELETE. We should check the parameters for all others */
3202 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3204 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
3205 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
3207 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
3208 flags
& MF_BYPOSITION
? pos
: id
,
3209 flags
& ~MF_REMOVE
);
3210 /* Default: MF_INSERT */
3211 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
3215 /*******************************************************************
3216 * ChangeMenuA (USER32.@)
3218 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
3219 UINT id
, UINT flags
)
3221 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3222 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3223 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
3225 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3226 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
3228 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3229 flags
& MF_BYPOSITION
? pos
: id
,
3230 flags
& ~MF_REMOVE
);
3231 /* Default: MF_INSERT */
3232 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
3236 /*******************************************************************
3237 * ChangeMenuW (USER32.@)
3239 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
3240 UINT id
, UINT flags
)
3242 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3243 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3244 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
3246 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3247 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
3249 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3250 flags
& MF_BYPOSITION
? pos
: id
,
3251 flags
& ~MF_REMOVE
);
3252 /* Default: MF_INSERT */
3253 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
3257 /*******************************************************************
3258 * CheckMenuItem (USER.154)
3260 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
3262 return (BOOL16
)CheckMenuItem( hMenu
, id
, flags
);
3266 /*******************************************************************
3267 * CheckMenuItem (USER32.@)
3269 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
3274 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu
, id
, flags
);
3275 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
3276 ret
= item
->fState
& MF_CHECKED
;
3277 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
3278 else item
->fState
&= ~MF_CHECKED
;
3283 /**********************************************************************
3284 * EnableMenuItem (USER.155)
3286 UINT16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3288 return EnableMenuItem( hMenu
, wItemID
, wFlags
);
3292 /**********************************************************************
3293 * EnableMenuItem (USER32.@)
3295 UINT WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3301 TRACE("(%04x, %04X, %04X) !\n",
3302 hMenu
, wItemID
, wFlags
);
3304 /* Get the Popupmenu to access the owner menu */
3305 if (!(menu
= MENU_GetMenu(hMenu
)))
3308 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3311 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3312 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3314 /* In win95 if the close item in the system menu change update the close button */
3315 if (TWEAK_WineLook
== WIN95_LOOK
)
3316 if((item
->wID
== SC_CLOSE
) && (oldflags
!= wFlags
))
3318 if (menu
->hSysMenuOwner
!= 0)
3320 POPUPMENU
* parentMenu
;
3322 /* Get the parent menu to access*/
3323 if (!(parentMenu
= MENU_GetMenu(menu
->hSysMenuOwner
)))
3326 /* Refresh the frame to reflect the change*/
3327 SetWindowPos(parentMenu
->hWnd
, 0, 0, 0, 0, 0,
3328 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
3336 /*******************************************************************
3337 * GetMenuString (USER.161)
3339 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
3340 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
3342 return GetMenuStringA( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3346 /*******************************************************************
3347 * GetMenuStringA (USER32.@)
3349 INT WINAPI
GetMenuStringA(
3350 HMENU hMenu
, /* [in] menuhandle */
3351 UINT wItemID
, /* [in] menu item (dep. on wFlags) */
3352 LPSTR str
, /* [out] outbuffer. If NULL, func returns entry length*/
3353 INT nMaxSiz
, /* [in] length of buffer. if 0, func returns entry len*/
3354 UINT wFlags
/* [in] MF_ flags */
3358 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3359 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3360 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3361 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3362 if (!str
|| !nMaxSiz
) return strlenW(item
->text
);
3364 if (!WideCharToMultiByte( CP_ACP
, 0, item
->text
, -1, str
, nMaxSiz
, NULL
, NULL
))
3366 TRACE("returning '%s'\n", str
);
3371 /*******************************************************************
3372 * GetMenuStringW (USER32.@)
3374 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3375 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3379 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3380 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3381 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3382 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3383 if (!str
|| !nMaxSiz
) return strlenW(item
->text
);
3385 lstrcpynW( str
, item
->text
, nMaxSiz
);
3386 return strlenW(str
);
3390 /**********************************************************************
3391 * HiliteMenuItem (USER32.@)
3393 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3397 TRACE("(%04x, %04x, %04x, %04x);\n",
3398 hWnd
, hMenu
, wItemID
, wHilite
);
3399 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3400 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3401 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3402 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
3403 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
, 0 );
3408 /**********************************************************************
3409 * GetMenuState (USER.250)
3411 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3413 return GetMenuState( hMenu
, wItemID
, wFlags
);
3417 /**********************************************************************
3418 * GetMenuState (USER32.@)
3420 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3423 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3424 hMenu
, wItemID
, wFlags
);
3425 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3426 debug_print_menuitem (" item: ", item
, "");
3427 if (item
->fType
& MF_POPUP
)
3429 POPUPMENU
*menu
= MENU_GetMenu( item
->hSubMenu
);
3430 if (!menu
) return -1;
3431 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3435 /* We used to (from way back then) mask the result to 0xff. */
3436 /* I don't know why and it seems wrong as the documented */
3437 /* return flag MF_SEPARATOR is outside that mask. */
3438 return (item
->fType
| item
->fState
);
3443 /**********************************************************************
3444 * GetMenuItemCount (USER.263)
3446 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
3448 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3449 if (!menu
) return -1;
3450 TRACE("(%04x) returning %d\n",
3451 hMenu
, menu
->nItems
);
3452 return menu
->nItems
;
3456 /**********************************************************************
3457 * GetMenuItemCount (USER32.@)
3459 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3461 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3462 if (!menu
) return -1;
3463 TRACE("(%04x) returning %d\n",
3464 hMenu
, menu
->nItems
);
3465 return menu
->nItems
;
3468 /**********************************************************************
3469 * GetMenuItemID (USER.264)
3471 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
3473 return (UINT16
) GetMenuItemID (hMenu
, nPos
);
3476 /**********************************************************************
3477 * GetMenuItemID (USER32.@)
3479 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3483 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return -1;
3484 if (lpmi
->fType
& MF_POPUP
) return -1;
3489 /*******************************************************************
3490 * InsertMenu (USER.410)
3492 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3493 UINT16 id
, SEGPTR data
)
3495 UINT pos32
= (UINT
)pos
;
3496 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT
)-1;
3497 if (IS_STRING_ITEM(flags
) && data
)
3498 return InsertMenuA( hMenu
, pos32
, flags
, id
, MapSL(data
) );
3499 return InsertMenuA( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
3503 /*******************************************************************
3504 * InsertMenuW (USER32.@)
3506 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3507 UINT id
, LPCWSTR str
)
3511 if (IS_STRING_ITEM(flags
) && str
)
3512 TRACE("hMenu %04x, pos %d, flags %08x, "
3513 "id %04x, str %s\n",
3514 hMenu
, pos
, flags
, id
, debugstr_w(str
) );
3515 else TRACE("hMenu %04x, pos %d, flags %08x, "
3516 "id %04x, str %08lx (not a string)\n",
3517 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3519 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3521 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3523 RemoveMenu( hMenu
, pos
, flags
);
3527 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3528 (MENU_GetMenu((HMENU16
)id
))->wFlags
|= MF_POPUP
;
3530 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3535 /*******************************************************************
3536 * InsertMenuA (USER32.@)
3538 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3539 UINT id
, LPCSTR str
)
3543 if (IS_STRING_ITEM(flags
) && str
)
3545 INT len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
3546 LPWSTR newstr
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3549 MultiByteToWideChar( CP_ACP
, 0, str
, -1, newstr
, len
);
3550 ret
= InsertMenuW( hMenu
, pos
, flags
, id
, newstr
);
3551 HeapFree( GetProcessHeap(), 0, newstr
);
3555 else return InsertMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
3559 /*******************************************************************
3560 * AppendMenu (USER.411)
3562 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3564 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3568 /*******************************************************************
3569 * AppendMenuA (USER32.@)
3571 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3572 UINT id
, LPCSTR data
)
3574 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3578 /*******************************************************************
3579 * AppendMenuW (USER32.@)
3581 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3582 UINT id
, LPCWSTR data
)
3584 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3588 /**********************************************************************
3589 * RemoveMenu (USER.412)
3591 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3593 return RemoveMenu( hMenu
, nPos
, wFlags
);
3597 /**********************************************************************
3598 * RemoveMenu (USER32.@)
3600 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3605 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu
, nPos
, wFlags
);
3606 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3607 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3611 MENU_FreeItemData( item
);
3613 if (--menu
->nItems
== 0)
3615 HeapFree( GetProcessHeap(), 0, menu
->items
);
3620 while(nPos
< menu
->nItems
)
3626 menu
->items
= HeapReAlloc( GetProcessHeap(), 0, menu
->items
,
3627 menu
->nItems
* sizeof(MENUITEM
) );
3633 /**********************************************************************
3634 * DeleteMenu (USER.413)
3636 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3638 return DeleteMenu( hMenu
, nPos
, wFlags
);
3642 /**********************************************************************
3643 * DeleteMenu (USER32.@)
3645 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3647 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3648 if (!item
) return FALSE
;
3649 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3650 /* nPos is now the position of the item */
3651 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3656 /*******************************************************************
3657 * ModifyMenu (USER.414)
3659 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3660 UINT16 id
, SEGPTR data
)
3662 if (IS_STRING_ITEM(flags
))
3663 return ModifyMenuA( hMenu
, pos
, flags
, id
, MapSL(data
) );
3664 return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3668 /*******************************************************************
3669 * ModifyMenuW (USER32.@)
3671 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3672 UINT id
, LPCWSTR str
)
3676 if (IS_STRING_ITEM(flags
))
3678 TRACE("%04x %d %04x %04x %s\n",
3679 hMenu
, pos
, flags
, id
, debugstr_w(str
) );
3680 if (!str
) return FALSE
;
3684 TRACE("%04x %d %04x %04x %08lx\n",
3685 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3688 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3689 return MENU_SetItemData( item
, flags
, id
, str
);
3693 /*******************************************************************
3694 * ModifyMenuA (USER32.@)
3696 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3697 UINT id
, LPCSTR str
)
3701 if (IS_STRING_ITEM(flags
) && str
)
3703 INT len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
3704 LPWSTR newstr
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3707 MultiByteToWideChar( CP_ACP
, 0, str
, -1, newstr
, len
);
3708 ret
= ModifyMenuW( hMenu
, pos
, flags
, id
, newstr
);
3709 HeapFree( GetProcessHeap(), 0, newstr
);
3713 else return ModifyMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
3717 /**********************************************************************
3718 * CreatePopupMenu (USER.415)
3720 HMENU16 WINAPI
CreatePopupMenu16(void)
3722 return CreatePopupMenu();
3726 /**********************************************************************
3727 * CreatePopupMenu (USER32.@)
3729 HMENU WINAPI
CreatePopupMenu(void)
3734 if (!(hmenu
= CreateMenu())) return 0;
3735 menu
= MENU_GetMenu( hmenu
);
3736 menu
->wFlags
|= MF_POPUP
;
3737 menu
->bTimeToHide
= FALSE
;
3742 /**********************************************************************
3743 * GetMenuCheckMarkDimensions (USER.417)
3744 * GetMenuCheckMarkDimensions (USER32.@)
3746 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3748 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK
), GetSystemMetrics(SM_CYMENUCHECK
) );
3752 /**********************************************************************
3753 * SetMenuItemBitmaps (USER.418)
3755 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3756 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3758 return SetMenuItemBitmaps( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3762 /**********************************************************************
3763 * SetMenuItemBitmaps (USER32.@)
3765 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
3766 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
3769 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3770 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3771 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3773 if (!hNewCheck
&& !hNewUnCheck
)
3775 item
->fState
&= ~MF_USECHECKBITMAPS
;
3777 else /* Install new bitmaps */
3779 item
->hCheckBit
= hNewCheck
;
3780 item
->hUnCheckBit
= hNewUnCheck
;
3781 item
->fState
|= MF_USECHECKBITMAPS
;
3787 /**********************************************************************
3788 * CreateMenu (USER.151)
3790 HMENU16 WINAPI
CreateMenu16(void)
3792 return CreateMenu();
3796 /**********************************************************************
3797 * CreateMenu (USER32.@)
3799 HMENU WINAPI
CreateMenu(void)
3803 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3804 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3806 ZeroMemory(menu
, sizeof(POPUPMENU
));
3807 menu
->wMagic
= MENU_MAGIC
;
3808 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3809 menu
->bTimeToHide
= FALSE
;
3811 TRACE("return %04x\n", hMenu
);
3817 /**********************************************************************
3818 * DestroyMenu (USER.152)
3820 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3822 return DestroyMenu( hMenu
);
3826 /**********************************************************************
3827 * DestroyMenu (USER32.@)
3829 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
3831 TRACE("(%04x)\n", hMenu
);
3833 /* Silently ignore attempts to destroy default system popup */
3835 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3837 LPPOPUPMENU lppop
= MENU_GetMenu(hMenu
);
3839 if (!lppop
) return FALSE
;
3841 lppop
->wMagic
= 0; /* Mark it as destroyed */
3843 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
)
3845 DestroyWindow( lppop
->hWnd
);
3849 if (lppop
->items
) /* recursively destroy submenus */
3852 MENUITEM
*item
= lppop
->items
;
3853 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3855 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
3856 MENU_FreeItemData( item
);
3858 HeapFree( GetProcessHeap(), 0, lppop
->items
);
3860 USER_HEAP_FREE( hMenu
);
3862 return (hMenu
!= MENU_DefSysPopup
);
3866 /**********************************************************************
3867 * GetSystemMenu (USER32.@)
3869 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
3871 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3876 if( wndPtr
->hSysMenu
)
3880 DestroyMenu(wndPtr
->hSysMenu
);
3881 wndPtr
->hSysMenu
= 0;
3885 POPUPMENU
*menu
= MENU_GetMenu( wndPtr
->hSysMenu
);
3888 if( menu
->nItems
> 0 && menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
3889 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
3893 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3894 wndPtr
->hSysMenu
, hWnd
);
3895 wndPtr
->hSysMenu
= 0;
3900 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
3901 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU
)(-1) );
3903 if( wndPtr
->hSysMenu
)
3906 retvalue
= GetSubMenu(wndPtr
->hSysMenu
, 0);
3908 /* Store the dummy sysmenu handle to facilitate the refresh */
3909 /* of the close button if the SC_CLOSE item change */
3910 menu
= MENU_GetMenu(retvalue
);
3912 menu
->hSysMenuOwner
= wndPtr
->hSysMenu
;
3914 WIN_ReleaseWndPtr(wndPtr
);
3916 return bRevert
? 0 : retvalue
;
3920 /*******************************************************************
3921 * SetSystemMenu (USER32.@)
3923 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
3925 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
3929 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
3930 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
3931 WIN_ReleaseWndPtr(wndPtr
);
3938 /**********************************************************************
3939 * GetMenu (USER32.@)
3941 HMENU WINAPI
GetMenu( HWND hWnd
)
3943 HMENU retvalue
= (HMENU
)GetWindowLongA( hWnd
, GWL_ID
);
3944 TRACE("for %04x returning %04x\n", hWnd
, retvalue
);
3949 /**********************************************************************
3950 * SetMenu (USER32.@)
3952 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
3954 TRACE("(%04x, %04x);\n", hWnd
, hMenu
);
3956 if (hMenu
&& !IsMenu(hMenu
))
3958 WARN("hMenu %x is not a menu handle\n", hMenu
);
3961 if (GetWindowLongA( hWnd
, GWL_STYLE
) & WS_CHILD
) return FALSE
;
3963 hWnd
= WIN_GetFullHandle( hWnd
);
3964 if (GetCapture() == hWnd
) ReleaseCapture();
3970 if (!(lpmenu
= MENU_GetMenu(hMenu
))) return FALSE
;
3972 lpmenu
->hWnd
= hWnd
;
3973 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
3975 SetWindowLongA( hWnd
, GWL_ID
, hMenu
);
3977 if (IsWindowVisible(hWnd
))
3978 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3979 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3985 /**********************************************************************
3986 * GetSubMenu (USER.159)
3988 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
3990 return GetSubMenu( hMenu
, nPos
);
3994 /**********************************************************************
3995 * GetSubMenu (USER32.@)
3997 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
4001 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
4002 if (!(lpmi
->fType
& MF_POPUP
)) return 0;
4003 return lpmi
->hSubMenu
;
4007 /**********************************************************************
4008 * DrawMenuBar (USER32.@)
4010 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
4013 HMENU hMenu
= GetMenu(hWnd
);
4015 if (GetWindowLongA( hWnd
, GWL_STYLE
) & WS_CHILD
) return FALSE
;
4016 if (!hMenu
|| !(lppop
= MENU_GetMenu( hMenu
))) return FALSE
;
4018 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
4019 lppop
->hwndOwner
= hWnd
;
4020 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4021 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4025 /***********************************************************************
4026 * DrawMenuBarTemp (USER32.@)
4030 * called by W98SE desk.cpl Control Panel Applet
4032 * Not 100% sure about the param names, but close.
4034 DWORD WINAPI
DrawMenuBarTemp(HWND someHWND
, HDC someHDC
, LPRECT someRECT
, HMENU someHMENU
, HFONT someFONT
)
4036 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, 0x%08x): stub\n", someHWND
, someHDC
, someRECT
, someHMENU
, someFONT
);
4040 /***********************************************************************
4041 * EndMenu (USER.187)
4042 * EndMenu (USER32.@)
4044 void WINAPI
EndMenu(void)
4046 /* if we are in the menu code, and it is active */
4047 if (!fEndMenu
&& top_popup
)
4049 /* terminate the menu handling code */
4052 /* needs to be posted to wakeup the internal menu handler */
4053 /* which will now terminate the menu, in the event that */
4054 /* the main window was minimized, or lost focus, so we */
4055 /* don't end up with an orphaned menu */
4056 PostMessageA( top_popup
, WM_CANCELMODE
, 0, 0);
4061 /***********************************************************************
4062 * LookupMenuHandle (USER.217)
4064 HMENU16 WINAPI
LookupMenuHandle16( HMENU16 hmenu
, INT16 id
)
4066 HMENU hmenu32
= hmenu
;
4068 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
4069 else return hmenu32
;
4073 /**********************************************************************
4074 * LoadMenu (USER.150)
4076 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, LPCSTR name
)
4082 TRACE("(%04x,%s)\n", instance
, debugres_a(name
) );
4086 if (name
[0] == '#') name
= (LPCSTR
)atoi( name
+ 1 );
4089 if (!name
) return 0;
4091 /* check for Win32 module */
4092 if (HIWORD(instance
)) return LoadMenuA( instance
, name
);
4093 instance
= GetExePtr( instance
);
4095 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENUA
))) return 0;
4096 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
4097 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
4098 FreeResource16( handle
);
4103 /*****************************************************************
4104 * LoadMenuA (USER32.@)
4106 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
4108 HRSRC hrsrc
= FindResourceA( instance
, name
, RT_MENUA
);
4109 if (!hrsrc
) return 0;
4110 return LoadMenuIndirectA( (LPCVOID
)LoadResource( instance
, hrsrc
));
4114 /*****************************************************************
4115 * LoadMenuW (USER32.@)
4117 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
4119 HRSRC hrsrc
= FindResourceW( instance
, name
, RT_MENUW
);
4120 if (!hrsrc
) return 0;
4121 return LoadMenuIndirectW( (LPCVOID
)LoadResource( instance
, hrsrc
));
4125 /**********************************************************************
4126 * LoadMenuIndirect (USER.220)
4128 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
4131 WORD version
, offset
;
4132 LPCSTR p
= (LPCSTR
)template;
4134 TRACE("(%p)\n", template );
4135 version
= GET_WORD(p
);
4139 WARN("version must be 0 for Win16\n" );
4142 offset
= GET_WORD(p
);
4143 p
+= sizeof(WORD
) + offset
;
4144 if (!(hMenu
= CreateMenu())) return 0;
4145 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
4147 DestroyMenu( hMenu
);
4154 /**********************************************************************
4155 * LoadMenuIndirectA (USER32.@)
4157 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
4160 WORD version
, offset
;
4161 LPCSTR p
= (LPCSTR
)template;
4163 TRACE("%p\n", template );
4164 version
= GET_WORD(p
);
4169 offset
= GET_WORD(p
);
4170 p
+= sizeof(WORD
) + offset
;
4171 if (!(hMenu
= CreateMenu())) return 0;
4172 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
4174 DestroyMenu( hMenu
);
4179 offset
= GET_WORD(p
);
4180 p
+= sizeof(WORD
) + offset
;
4181 if (!(hMenu
= CreateMenu())) return 0;
4182 if (!MENUEX_ParseResource( p
, hMenu
))
4184 DestroyMenu( hMenu
);
4189 ERR("version %d not supported.\n", version
);
4195 /**********************************************************************
4196 * LoadMenuIndirectW (USER32.@)
4198 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
4200 /* FIXME: is there anything different between A and W? */
4201 return LoadMenuIndirectA( template );
4205 /**********************************************************************
4208 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
4210 return IsMenu( hmenu
);
4214 /**********************************************************************
4217 BOOL WINAPI
IsMenu(HMENU hmenu
)
4219 LPPOPUPMENU menu
= MENU_GetMenu(hmenu
);
4220 return menu
!= NULL
;
4223 /**********************************************************************
4224 * GetMenuItemInfo_common
4227 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
, BOOL bypos
,
4228 LPMENUITEMINFOW lpmii
, BOOL unicode
)
4230 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
4232 debug_print_menuitem("GetMenuItemInfo_common: ", menu
, "");
4237 if (lpmii
->fMask
& MIIM_TYPE
) {
4238 lpmii
->fType
= menu
->fType
;
4239 switch (MENU_ITEM_TYPE(menu
->fType
)) {
4241 break; /* will be done below */
4244 lpmii
->dwTypeData
= menu
->text
;
4251 /* copy the text string */
4252 if ((lpmii
->fMask
& (MIIM_TYPE
|MIIM_STRING
)) &&
4253 (MENU_ITEM_TYPE(menu
->fType
) == MF_STRING
) && menu
->text
)
4258 len
= strlenW(menu
->text
);
4259 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4260 lstrcpynW(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4264 len
= WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1, NULL
, 0, NULL
, NULL
);
4265 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4266 if (!WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1,
4267 (LPSTR
)lpmii
->dwTypeData
, lpmii
->cch
, NULL
, NULL
))
4268 ((LPSTR
)lpmii
->dwTypeData
)[lpmii
->cch
-1] = 0;
4270 /* if we've copied a substring we return its length */
4271 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4273 if (lpmii
->cch
<= len
) lpmii
->cch
--;
4275 else /* return length of string */
4279 if (lpmii
->fMask
& MIIM_FTYPE
)
4280 lpmii
->fType
= menu
->fType
;
4282 if (lpmii
->fMask
& MIIM_BITMAP
)
4283 lpmii
->hbmpItem
= menu
->hbmpItem
;
4285 if (lpmii
->fMask
& MIIM_STATE
)
4286 lpmii
->fState
= menu
->fState
;
4288 if (lpmii
->fMask
& MIIM_ID
)
4289 lpmii
->wID
= menu
->wID
;
4291 if (lpmii
->fMask
& MIIM_SUBMENU
)
4292 lpmii
->hSubMenu
= menu
->hSubMenu
;
4294 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4295 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4296 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4298 if (lpmii
->fMask
& MIIM_DATA
)
4299 lpmii
->dwItemData
= menu
->dwItemData
;
4304 /**********************************************************************
4305 * GetMenuItemInfoA (USER32.@)
4307 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4308 LPMENUITEMINFOA lpmii
)
4310 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4311 (LPMENUITEMINFOW
)lpmii
, FALSE
);
4314 /**********************************************************************
4315 * GetMenuItemInfoW (USER32.@)
4317 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4318 LPMENUITEMINFOW lpmii
)
4320 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4325 /* set a menu item text from a ASCII or Unicode string */
4326 inline static void set_menu_item_text( MENUITEM
*menu
, LPCWSTR text
, BOOL unicode
)
4331 menu
->fType
|= MF_SEPARATOR
;
4335 if ((menu
->text
= HeapAlloc( GetProcessHeap(), 0, (strlenW(text
)+1) * sizeof(WCHAR
) )))
4336 strcpyW( menu
->text
, text
);
4340 LPCSTR str
= (LPCSTR
)text
;
4341 int len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
4342 if ((menu
->text
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
4343 MultiByteToWideChar( CP_ACP
, 0, str
, -1, menu
->text
, len
);
4348 /**********************************************************************
4349 * SetMenuItemInfo_common
4352 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4353 const MENUITEMINFOW
*lpmii
,
4356 if (!menu
) return FALSE
;
4358 debug_print_menuitem("MENU_SetItemInfo_common from: ", menu
, "");
4360 if (lpmii
->fMask
& MIIM_TYPE
) {
4361 /* Get rid of old string. */
4362 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4363 HeapFree(GetProcessHeap(), 0, menu
->text
);
4367 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4368 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4369 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4371 menu
->text
= lpmii
->dwTypeData
;
4373 if (IS_STRING_ITEM(menu
->fType
))
4374 set_menu_item_text( menu
, lpmii
->dwTypeData
, unicode
);
4377 if (lpmii
->fMask
& MIIM_FTYPE
) {
4378 /* free the string when the type is changing */
4379 if ( (!IS_STRING_ITEM(lpmii
->fType
)) && IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4380 HeapFree(GetProcessHeap(), 0, menu
->text
);
4383 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4384 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4385 if ( IS_STRING_ITEM(menu
->fType
) && !menu
->text
)
4386 menu
->fType
|= MF_SEPARATOR
;
4389 if (lpmii
->fMask
& MIIM_STRING
) {
4390 /* free the string when used */
4391 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4392 HeapFree(GetProcessHeap(), 0, menu
->text
);
4393 set_menu_item_text( menu
, lpmii
->dwTypeData
, unicode
);
4397 if (lpmii
->fMask
& MIIM_STATE
)
4399 /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
4400 menu
->fState
= lpmii
->fState
;
4403 if (lpmii
->fMask
& MIIM_ID
)
4404 menu
->wID
= lpmii
->wID
;
4406 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4407 menu
->hSubMenu
= lpmii
->hSubMenu
;
4408 if (menu
->hSubMenu
) {
4409 POPUPMENU
*subMenu
= MENU_GetMenu((UINT16
)menu
->hSubMenu
);
4411 subMenu
->wFlags
|= MF_POPUP
;
4412 menu
->fType
|= MF_POPUP
;
4415 /* FIXME: Return an error ? */
4416 menu
->fType
&= ~MF_POPUP
;
4419 menu
->fType
&= ~MF_POPUP
;
4422 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4424 if (lpmii
->fType
& MFT_RADIOCHECK
)
4425 menu
->fType
|= MFT_RADIOCHECK
;
4427 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4428 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4430 if (lpmii
->fMask
& MIIM_DATA
)
4431 menu
->dwItemData
= lpmii
->dwItemData
;
4433 debug_print_menuitem("SetMenuItemInfo_common to : ", menu
, "");
4437 /**********************************************************************
4438 * SetMenuItemInfoA (USER32.@)
4440 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4441 const MENUITEMINFOA
*lpmii
)
4443 if ((lpmii
->fType
& (MF_HILITE
|MF_POPUP
)) || (lpmii
->fState
)) {
4444 /* QuickTime does pass invalid data into SetMenuItemInfo.
4445 * do some of the checks Windows does.
4447 WARN("Bad masks for type (0x%08x) or state (0x%08x)\n",
4448 lpmii
->fType
,lpmii
->fState
);
4452 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4453 (const MENUITEMINFOW
*)lpmii
, FALSE
);
4456 /**********************************************************************
4457 * SetMenuItemInfoW (USER32.@)
4459 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4460 const MENUITEMINFOW
*lpmii
)
4462 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4466 /**********************************************************************
4467 * SetMenuDefaultItem (USER32.@)
4470 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT uItem
, UINT bypos
)
4476 TRACE("(0x%x,%d,%d)\n", hmenu
, uItem
, bypos
);
4478 if (!(menu
= MENU_GetMenu(hmenu
))) return FALSE
;
4480 /* reset all default-item flags */
4482 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4484 item
->fState
&= ~MFS_DEFAULT
;
4487 /* no default item */
4496 if ( uItem
>= menu
->nItems
) return FALSE
;
4497 item
[uItem
].fState
|= MFS_DEFAULT
;
4502 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4504 if (item
->wID
== uItem
)
4506 item
->fState
|= MFS_DEFAULT
;
4515 /**********************************************************************
4516 * GetMenuDefaultItem (USER32.@)
4518 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4524 TRACE("(0x%x,%d,%d)\n", hmenu
, bypos
, flags
);
4526 if (!(menu
= MENU_GetMenu(hmenu
))) return -1;
4528 /* find default item */
4532 if (! item
) return -1;
4534 while ( !( item
->fState
& MFS_DEFAULT
) )
4537 if (i
>= menu
->nItems
) return -1;
4540 /* default: don't return disabled items */
4541 if ( (!(GMDI_USEDISABLED
& flags
)) && (item
->fState
& MFS_DISABLED
)) return -1;
4543 /* search rekursiv when needed */
4544 if ( (item
->fType
& MF_POPUP
) && (flags
& GMDI_GOINTOPOPUPS
) )
4547 ret
= GetMenuDefaultItem( item
->hSubMenu
, bypos
, flags
);
4548 if ( -1 != ret
) return ret
;
4550 /* when item not found in submenu, return the popup item */
4552 return ( bypos
) ? i
: item
->wID
;
4556 /*******************************************************************
4557 * InsertMenuItem (USER.441)
4561 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
4562 const MENUITEMINFO16
*mii
)
4566 miia
.cbSize
= sizeof(miia
);
4567 miia
.fMask
= mii
->fMask
;
4568 miia
.dwTypeData
= (LPSTR
)mii
->dwTypeData
;
4569 miia
.fType
= mii
->fType
;
4570 miia
.fState
= mii
->fState
;
4571 miia
.wID
= mii
->wID
;
4572 miia
.hSubMenu
= mii
->hSubMenu
;
4573 miia
.hbmpChecked
= mii
->hbmpChecked
;
4574 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
4575 miia
.dwItemData
= mii
->dwItemData
;
4576 miia
.cch
= mii
->cch
;
4577 if (IS_STRING_ITEM(miia
.fType
))
4578 miia
.dwTypeData
= MapSL(mii
->dwTypeData
);
4579 return InsertMenuItemA( hmenu
, pos
, byposition
, &miia
);
4583 /**********************************************************************
4584 * InsertMenuItemA (USER32.@)
4586 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4587 const MENUITEMINFOA
*lpmii
)
4589 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4590 return SetMenuItemInfo_common(item
, (const MENUITEMINFOW
*)lpmii
, FALSE
);
4594 /**********************************************************************
4595 * InsertMenuItemW (USER32.@)
4597 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4598 const MENUITEMINFOW
*lpmii
)
4600 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4601 return SetMenuItemInfo_common(item
, lpmii
, TRUE
);
4604 /**********************************************************************
4605 * CheckMenuRadioItem (USER32.@)
4608 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
4609 UINT first
, UINT last
, UINT check
,
4612 MENUITEM
*mifirst
, *milast
, *micheck
;
4613 HMENU mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
4615 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4616 hMenu
, first
, last
, check
, bypos
);
4618 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
4619 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
4620 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
4622 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
4623 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
4624 micheck
> milast
|| micheck
< mifirst
)
4627 while (mifirst
<= milast
)
4629 if (mifirst
== micheck
)
4631 mifirst
->fType
|= MFT_RADIOCHECK
;
4632 mifirst
->fState
|= MFS_CHECKED
;
4634 mifirst
->fType
&= ~MFT_RADIOCHECK
;
4635 mifirst
->fState
&= ~MFS_CHECKED
;
4643 /**********************************************************************
4644 * CheckMenuRadioItem (USER.666)
4646 BOOL16 WINAPI
CheckMenuRadioItem16(HMENU16 hMenu
,
4647 UINT16 first
, UINT16 last
, UINT16 check
,
4650 return CheckMenuRadioItem (hMenu
, first
, last
, check
, bypos
);
4653 /**********************************************************************
4654 * GetMenuItemRect (USER32.@)
4656 * ATTENTION: Here, the returned values in rect are the screen
4657 * coordinates of the item just like if the menu was
4658 * always on the upper left side of the application.
4661 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
4664 POPUPMENU
*itemMenu
;
4668 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
4670 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
4671 referenceHwnd
= hwnd
;
4675 itemMenu
= MENU_GetMenu(hMenu
);
4676 if (itemMenu
== NULL
)
4679 if(itemMenu
->hWnd
== 0)
4681 referenceHwnd
= itemMenu
->hWnd
;
4684 if ((rect
== NULL
) || (item
== NULL
))
4689 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
4695 /**********************************************************************
4696 * SetMenuInfo (USER32.@)
4699 * MIM_APPLYTOSUBMENUS
4700 * actually use the items to draw the menu
4702 BOOL WINAPI
SetMenuInfo (HMENU hMenu
, LPCMENUINFO lpmi
)
4706 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4708 if (lpmi
&& (lpmi
->cbSize
==sizeof(MENUINFO
)) && (menu
= MENU_GetMenu(hMenu
)))
4711 if (lpmi
->fMask
& MIM_BACKGROUND
)
4712 menu
->hbrBack
= lpmi
->hbrBack
;
4714 if (lpmi
->fMask
& MIM_HELPID
)
4715 menu
->dwContextHelpID
= lpmi
->dwContextHelpID
;
4717 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4718 menu
->cyMax
= lpmi
->cyMax
;
4720 if (lpmi
->fMask
& MIM_MENUDATA
)
4721 menu
->dwMenuData
= lpmi
->dwMenuData
;
4723 if (lpmi
->fMask
& MIM_STYLE
)
4724 menu
->dwStyle
= lpmi
->dwStyle
;
4731 /**********************************************************************
4732 * GetMenuInfo (USER32.@)
4738 BOOL WINAPI
GetMenuInfo (HMENU hMenu
, LPMENUINFO lpmi
)
4741 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4743 if (lpmi
&& (menu
= MENU_GetMenu(hMenu
)))
4746 if (lpmi
->fMask
& MIM_BACKGROUND
)
4747 lpmi
->hbrBack
= menu
->hbrBack
;
4749 if (lpmi
->fMask
& MIM_HELPID
)
4750 lpmi
->dwContextHelpID
= menu
->dwContextHelpID
;
4752 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4753 lpmi
->cyMax
= menu
->cyMax
;
4755 if (lpmi
->fMask
& MIM_MENUDATA
)
4756 lpmi
->dwMenuData
= menu
->dwMenuData
;
4758 if (lpmi
->fMask
& MIM_STYLE
)
4759 lpmi
->dwStyle
= menu
->dwStyle
;
4766 /**********************************************************************
4767 * SetMenuContextHelpId (USER.384)
4769 BOOL16 WINAPI
SetMenuContextHelpId16( HMENU16 hMenu
, DWORD dwContextHelpID
)
4771 return SetMenuContextHelpId( hMenu
, dwContextHelpID
);
4775 /**********************************************************************
4776 * SetMenuContextHelpId (USER32.@)
4778 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpID
)
4782 TRACE("(0x%04x 0x%08lx)\n", hMenu
, dwContextHelpID
);
4784 if ((menu
= MENU_GetMenu(hMenu
)))
4786 menu
->dwContextHelpID
= dwContextHelpID
;
4792 /**********************************************************************
4793 * GetMenuContextHelpId (USER.385)
4795 DWORD WINAPI
GetMenuContextHelpId16( HMENU16 hMenu
)
4797 return GetMenuContextHelpId( hMenu
);
4800 /**********************************************************************
4801 * GetMenuContextHelpId (USER32.@)
4803 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
4807 TRACE("(0x%04x)\n", hMenu
);
4809 if ((menu
= MENU_GetMenu(hMenu
)))
4811 return menu
->dwContextHelpID
;
4816 /**********************************************************************
4817 * MenuItemFromPoint (USER32.@)
4819 UINT WINAPI
MenuItemFromPoint(HWND hWnd
, HMENU hMenu
, POINT ptScreen
)
4821 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
4825 /*FIXME: Do we have to handle hWnd here? */
4826 item
= MENU_FindItemByCoords(menu
, ptScreen
, &pos
);
4832 /**********************************************************************
4833 * translate_accelerator
4835 static BOOL
translate_accelerator( HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
,
4836 BYTE fVirt
, WORD key
, WORD cmd
)
4840 if (wParam
!= key
) return FALSE
;
4842 if (message
== WM_CHAR
)
4844 if ( !(fVirt
& FALT
) && !(fVirt
& FVIRTKEY
) )
4846 TRACE_(accel
)("found accel for WM_CHAR: ('%c')\n", wParam
& 0xff);
4852 if(fVirt
& FVIRTKEY
)
4855 TRACE_(accel
)("found accel for virt_key %04x (scan %04x)\n",
4856 wParam
, 0xff & HIWORD(lParam
));
4857 if(GetKeyState(VK_SHIFT
) & 0x8000) mask
|= FSHIFT
;
4858 if(GetKeyState(VK_CONTROL
) & 0x8000) mask
|= FCONTROL
;
4859 if(GetKeyState(VK_MENU
) & 0x8000) mask
|= FALT
;
4860 if(mask
== (fVirt
& (FSHIFT
| FCONTROL
| FALT
))) goto found
;
4861 TRACE_(accel
)(", but incorrect SHIFT/CTRL/ALT-state\n");
4865 if (!(lParam
& 0x01000000)) /* no special_key */
4867 if ((fVirt
& FALT
) && (lParam
& 0x20000000))
4868 { /* ^^ ALT pressed */
4869 TRACE_(accel
)("found accel for Alt-%c\n", wParam
& 0xff);
4878 if (message
== WM_KEYUP
|| message
== WM_SYSKEYUP
)
4880 else if (GetCapture())
4882 else if (!IsWindowEnabled(hWnd
))
4886 HMENU hMenu
, hSubMenu
, hSysMenu
;
4887 UINT uSysStat
= (UINT
)-1, uStat
= (UINT
)-1, nPos
;
4889 hMenu
= (GetWindowLongA( hWnd
, GWL_STYLE
) & WS_CHILD
) ? 0 : GetMenu(hWnd
);
4890 hSysMenu
= get_win_sys_menu( hWnd
);
4892 /* find menu item and ask application to initialize it */
4893 /* 1. in the system menu */
4894 hSubMenu
= hSysMenu
;
4896 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
4898 SendMessageA(hWnd
, WM_INITMENU
, (WPARAM
)hSysMenu
, 0L);
4899 if(hSubMenu
!= hSysMenu
)
4901 nPos
= MENU_FindSubMenu(&hSysMenu
, hSubMenu
);
4902 TRACE_(accel
)("hSysMenu = %04x, hSubMenu = %04x, nPos = %d\n", hSysMenu
, hSubMenu
, nPos
);
4903 SendMessageA(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, TRUE
));
4905 uSysStat
= GetMenuState(GetSubMenu(hSysMenu
, 0), cmd
, MF_BYCOMMAND
);
4907 else /* 2. in the window's menu */
4911 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
4913 SendMessageA(hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0L);
4914 if(hSubMenu
!= hMenu
)
4916 nPos
= MENU_FindSubMenu(&hMenu
, hSubMenu
);
4917 TRACE_(accel
)("hMenu = %04x, hSubMenu = %04x, nPos = %d\n", hMenu
, hSubMenu
, nPos
);
4918 SendMessageA(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, FALSE
));
4920 uStat
= GetMenuState(hMenu
, cmd
, MF_BYCOMMAND
);
4924 if (uSysStat
!= (UINT
)-1)
4926 if (uSysStat
& (MF_DISABLED
|MF_GRAYED
))
4933 if (uStat
!= (UINT
)-1)
4939 if (uStat
& (MF_DISABLED
|MF_GRAYED
))
4950 if( mesg
==WM_COMMAND
)
4952 TRACE_(accel
)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd
);
4953 SendMessageA(hWnd
, mesg
, 0x10000 | cmd
, 0L);
4955 else if( mesg
==WM_SYSCOMMAND
)
4957 TRACE_(accel
)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd
);
4958 SendMessageA(hWnd
, mesg
, cmd
, 0x00010000L
);
4962 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
4963 * #0: unknown (please report!)
4964 * #1: for WM_KEYUP,WM_SYSKEYUP
4965 * #2: mouse is captured
4966 * #3: window is disabled
4967 * #4: it's a disabled system menu option
4968 * #5: it's a menu option, but window is iconic
4969 * #6: it's a menu option, but disabled
4971 TRACE_(accel
)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg
);
4973 ERR_(accel
)(" unknown reason - please report!");
4978 /**********************************************************************
4979 * TranslateAccelerator (USER32.@)
4980 * TranslateAcceleratorA (USER32.@)
4981 * TranslateAcceleratorW (USER32.@)
4983 INT WINAPI
TranslateAccelerator( HWND hWnd
, HACCEL hAccel
, LPMSG msg
)
4986 LPACCEL16 lpAccelTbl
;
4991 WARN_(accel
)("msg null; should hang here to be win compatible\n");
4994 if (!hAccel
|| !(lpAccelTbl
= (LPACCEL16
) LockResource16(hAccel
)))
4996 WARN_(accel
)("invalid accel handle=%x\n", hAccel
);
4999 if ((msg
->message
!= WM_KEYDOWN
&&
5000 msg
->message
!= WM_KEYUP
&&
5001 msg
->message
!= WM_SYSKEYDOWN
&&
5002 msg
->message
!= WM_SYSKEYUP
&&
5003 msg
->message
!= WM_CHAR
)) return 0;
5005 TRACE_(accel
)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5006 "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
5007 hAccel
,hWnd
,msg
->hwnd
,msg
->message
,msg
->wParam
,msg
->lParam
);
5012 if (translate_accelerator( hWnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
5013 lpAccelTbl
[i
].fVirt
, lpAccelTbl
[i
].key
, lpAccelTbl
[i
].cmd
))
5015 } while ((lpAccelTbl
[i
++].fVirt
& 0x80) == 0);
5016 WARN_(accel
)("couldn't translate accelerator key\n");