4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
10 * Note: the style MF_MOUSESELECT is used to mark popup items that
11 * have been selected, i.e. their popup menu is currently displayed.
12 * This is probably not the meaning this style has in MS-Windows.
23 #include "wine/winbase16.h"
24 #include "wine/winuser16.h"
25 #include "wine/unicode.h"
26 #include "wine/port.h"
31 #include "nonclient.h"
37 #include "debugtools.h"
39 DEFAULT_DEBUG_CHANNEL(menu
);
40 DECLARE_DEBUG_CHANNEL(accel
);
42 /* internal popup menu window messages */
44 #define MM_SETMENUHANDLE (WM_USER + 0)
45 #define MM_GETMENUHANDLE (WM_USER + 1)
47 /* Menu item structure */
49 /* ----------- MENUITEMINFO Stuff ----------- */
50 UINT fType
; /* Item type. */
51 UINT fState
; /* Item state. */
52 UINT wID
; /* Item id. */
53 HMENU hSubMenu
; /* Pop-up menu. */
54 HBITMAP hCheckBit
; /* Bitmap when checked. */
55 HBITMAP hUnCheckBit
; /* Bitmap when unchecked. */
56 LPWSTR text
; /* Item text or bitmap handle. */
57 DWORD dwItemData
; /* Application defined. */
58 DWORD dwTypeData
; /* depends on fMask */
59 HBITMAP hbmpItem
; /* bitmap in win98 style menus */
60 /* ----------- Wine stuff ----------- */
61 RECT rect
; /* Item area (relative to menu window) */
62 UINT xTab
; /* X position of text after Tab */
65 /* Popup menu structure */
67 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
68 WORD wMagic
; /* Magic number */
69 HQUEUE16 hTaskQ
; /* Task queue for this menu */
70 WORD Width
; /* Width of the whole menu */
71 WORD Height
; /* Height of the whole menu */
72 WORD nItems
; /* Number of items in the menu */
73 HWND hWnd
; /* Window containing the menu */
74 MENUITEM
*items
; /* Array of menu items */
75 UINT FocusedItem
; /* Currently focused item */
76 HWND hwndOwner
; /* window receiving the messages for ownerdraw */
77 BOOL bTimeToHide
; /* Request hiding when receiving a second click in the top-level menu item */
78 /* ------------ MENUINFO members ------ */
79 DWORD dwStyle
; /* Extended mennu style */
80 UINT cyMax
; /* max hight of the whole menu, 0 is screen hight */
81 HBRUSH hbrBack
; /* brush for menu background */
82 DWORD dwContextHelpID
;
83 DWORD dwMenuData
; /* application defined value */
84 HMENU hSysMenuOwner
; /* Handle to the dummy sys menu holder */
85 } POPUPMENU
, *LPPOPUPMENU
;
87 /* internal flags for menu tracking */
89 #define TF_ENDMENU 0x0001
90 #define TF_SUSPENDPOPUP 0x0002
91 #define TF_SKIPREMOVE 0x0004
96 HMENU hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
97 HMENU hTopMenu
; /* initial menu */
98 HWND hOwnerWnd
; /* where notifications are sent */
102 #define MENU_MAGIC 0x554d /* 'MU' */
103 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
108 /* Internal MENU_TrackMenu() flags */
109 #define TPM_INTERNAL 0xF0000000
110 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
111 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
112 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
114 /* popup menu shade thickness */
115 #define POPUP_XSHADE 4
116 #define POPUP_YSHADE 4
118 /* Space between 2 menu bar items */
119 #define MENU_BAR_ITEMS_SPACE 12
121 /* Minimum width of a tab character */
122 #define MENU_TAB_SPACE 8
124 /* Height of a separator item */
125 #define SEPARATOR_HEIGHT 5
127 /* (other menu->FocusedItem values give the position of the focused item) */
128 #define NO_SELECTED_ITEM 0xffff
130 #define MENU_ITEM_TYPE(flags) \
131 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
133 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
134 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
136 #define IS_SYSTEM_MENU(menu) \
137 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
139 #define IS_SYSTEM_POPUP(menu) \
140 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
142 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
143 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
144 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
145 MF_POPUP | MF_SYSMENU | MF_HELP)
146 #define STATE_MASK (~TYPE_MASK)
148 /* Dimension of the menu bitmaps */
149 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
150 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
152 static HBITMAP hStdRadioCheck
= 0;
153 static HBITMAP hStdCheck
= 0;
154 static HBITMAP hStdMnArrow
= 0;
156 /* Minimze/restore/close buttons to be inserted in menubar */
157 static HBITMAP hBmpMinimize
= 0;
158 static HBITMAP hBmpMinimizeD
= 0;
159 static HBITMAP hBmpMaximize
= 0;
160 static HBITMAP hBmpMaximizeD
= 0;
161 static HBITMAP hBmpClose
= 0;
162 static HBITMAP hBmpCloseD
= 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. */
174 static WND
* pTopPopupWnd
= 0;
175 static UINT uSubPWndLevel
= 0;
177 /* Flag set by EndMenu() to force an exit from menu tracking */
178 static BOOL fEndMenu
= FALSE
;
180 static LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
183 /*********************************************************************
184 * menu class descriptor
186 const struct builtin_class_descr MENU_builtin_class
=
188 POPUPMENU_CLASS_ATOM
, /* name */
189 CS_GLOBALCLASS
| CS_SAVEBITS
, /* style */
190 NULL
, /* procA (winproc is Unicode only) */
191 PopupMenuWndProc
, /* procW */
192 sizeof(HMENU
), /* extra */
193 IDC_ARROWA
, /* cursor */
194 COLOR_MENU
+1 /* brush */
198 /***********************************************************************
199 * debug_print_menuitem
201 * Print a menuitem in readable form.
204 #define debug_print_menuitem(pre, mp, post) \
205 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
207 #define MENUOUT(text) \
208 DPRINTF("%s%s", (count++ ? "," : ""), (text))
210 #define MENUFLAG(bit,text) \
212 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
215 static void do_debug_print_menuitem(const char *prefix
, MENUITEM
* mp
,
218 TRACE("%s ", prefix
);
220 UINT flags
= mp
->fType
;
221 int typ
= MENU_ITEM_TYPE(flags
);
222 DPRINTF( "{ ID=0x%x", mp
->wID
);
223 if (flags
& MF_POPUP
)
224 DPRINTF( ", Sub=0x%x", mp
->hSubMenu
);
228 if (typ
== MFT_STRING
)
230 else if (typ
== MFT_SEPARATOR
)
232 else if (typ
== MFT_OWNERDRAW
)
234 else if (typ
== MFT_BITMAP
)
240 MENUFLAG(MF_POPUP
, "pop");
241 MENUFLAG(MFT_MENUBARBREAK
, "barbrk");
242 MENUFLAG(MFT_MENUBREAK
, "brk");
243 MENUFLAG(MFT_RADIOCHECK
, "radio");
244 MENUFLAG(MFT_RIGHTORDER
, "rorder");
245 MENUFLAG(MF_SYSMENU
, "sys");
246 MENUFLAG(MFT_RIGHTJUSTIFY
, "right"); /* same as MF_HELP */
249 DPRINTF( "+0x%x", flags
);
254 DPRINTF( ", State=");
255 MENUFLAG(MFS_GRAYED
, "grey");
256 MENUFLAG(MFS_DEFAULT
, "default");
257 MENUFLAG(MFS_DISABLED
, "dis");
258 MENUFLAG(MFS_CHECKED
, "check");
259 MENUFLAG(MFS_HILITE
, "hi");
260 MENUFLAG(MF_USECHECKBITMAPS
, "usebit");
261 MENUFLAG(MF_MOUSESELECT
, "mouse");
263 DPRINTF( "+0x%x", flags
);
266 DPRINTF( ", Chk=0x%x", mp
->hCheckBit
);
268 DPRINTF( ", Unc=0x%x", mp
->hUnCheckBit
);
270 if (typ
== MFT_STRING
) {
272 DPRINTF( ", Text=\"%s\"", debugstr_w(mp
->text
));
274 DPRINTF( ", Text=Null");
275 } else if (mp
->text
== NULL
)
278 DPRINTF( ", Text=%p", mp
->text
);
280 DPRINTF( ", ItemData=0x%08lx", mp
->dwItemData
);
286 DPRINTF(" %s\n", postfix
);
293 /***********************************************************************
296 * Validate the given menu handle and returns the menu structure pointer.
298 POPUPMENU
*MENU_GetMenu(HMENU hMenu
)
301 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
302 if (!IS_A_MENU(menu
))
304 WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu
, menu
, menu
? menu
->wMagic
:0);
310 /***********************************************************************
313 * Return the default system menu.
315 static HMENU
MENU_CopySysPopup(void)
317 HMENU hMenu
= LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
320 POPUPMENU
* menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
321 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
322 SetMenuDefaultItem(hMenu
, SC_CLOSE
, FALSE
);
326 ERR("Unable to load default system menu\n" );
329 TRACE("returning %x.\n", hMenu
);
334 /***********************************************************************
335 * MENU_GetTopPopupWnd()
337 * Return the locked pointer pTopPopupWnd.
339 static WND
*MENU_GetTopPopupWnd()
341 return WIN_LockWndPtr(pTopPopupWnd
);
343 /***********************************************************************
344 * MENU_ReleaseTopPopupWnd()
346 * Release the locked pointer pTopPopupWnd.
348 static void MENU_ReleaseTopPopupWnd()
350 WIN_ReleaseWndPtr(pTopPopupWnd
);
352 /***********************************************************************
353 * MENU_DestroyTopPopupWnd()
355 * Destroy the locked pointer pTopPopupWnd.
357 static void MENU_DestroyTopPopupWnd()
359 WND
*tmpWnd
= pTopPopupWnd
;
361 WIN_ReleaseWndPtr(tmpWnd
);
366 /**********************************************************************
369 * Create a copy of the system menu. System menu in Windows is
370 * a special menu bar with the single entry - system menu popup.
371 * This popup is presented to the outside world as a "system menu".
372 * However, the real system menu handle is sometimes seen in the
373 * WM_MENUSELECT parameters (and Word 6 likes it this way).
375 HMENU
MENU_GetSysMenu( HWND hWnd
, HMENU hPopupMenu
)
379 if ((hMenu
= CreateMenu()))
381 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
382 menu
->wFlags
= MF_SYSMENU
;
385 if (hPopupMenu
== (HMENU
)(-1))
386 hPopupMenu
= MENU_CopySysPopup();
387 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
391 InsertMenuA( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
, hPopupMenu
, NULL
);
393 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
394 menu
->items
[0].fState
= 0;
395 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hPopupMenu
);
396 menu
->wFlags
|= MF_SYSMENU
;
398 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu
, hPopupMenu
);
401 DestroyMenu( hMenu
);
403 ERR("failed to load system menu!\n");
408 /***********************************************************************
411 * Menus initialisation.
416 NONCLIENTMETRICSA ncm
;
418 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
423 /* Load menu bitmaps */
424 hStdCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK
));
425 hStdRadioCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK
));
426 hStdMnArrow
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW
));
427 /* Load system buttons bitmaps */
428 hBmpMinimize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE
));
429 hBmpMinimizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED
));
430 hBmpMaximize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE
));
431 hBmpMaximizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED
));
432 hBmpClose
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE
));
433 hBmpCloseD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED
));
438 GetObjectA( hStdCheck
, sizeof(bm
), &bm
);
439 check_bitmap_width
= bm
.bmWidth
;
440 check_bitmap_height
= bm
.bmHeight
;
444 /* Assume that radio checks have the same size as regular checks. */
451 GetObjectA( hStdMnArrow
, sizeof(bm
), &bm
);
452 arrow_bitmap_width
= bm
.bmWidth
;
453 arrow_bitmap_height
= bm
.bmHeight
;
457 if (! (hBitmap
= CreateBitmap( 8, 8, 1, 1, shade_bits
)))
460 if(!(hShadeBrush
= CreatePatternBrush( hBitmap
)))
463 DeleteObject( hBitmap
);
464 if (!(MENU_DefSysPopup
= MENU_CopySysPopup()))
467 ncm
.cbSize
= sizeof (NONCLIENTMETRICSA
);
468 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICSA
), &ncm
, 0)))
471 if (!(hMenuFont
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
474 ncm
.lfMenuFont
.lfWeight
+= 300;
475 if ( ncm
.lfMenuFont
.lfWeight
> 1000)
476 ncm
.lfMenuFont
.lfWeight
= 1000;
478 if (!(hMenuFontBold
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
484 /***********************************************************************
485 * MENU_InitSysMenuPopup
487 * Grey the appropriate items in System menu.
489 static void MENU_InitSysMenuPopup( HMENU hmenu
, DWORD style
, DWORD clsStyle
)
493 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
494 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
495 gray
= ((style
& WS_MAXIMIZE
) != 0);
496 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
497 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
498 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
499 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
500 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
501 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
502 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
503 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
505 /* The menu item must keep its state if it's disabled */
507 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
511 /******************************************************************************
513 * UINT MENU_GetStartOfNextColumn(
516 *****************************************************************************/
518 static UINT
MENU_GetStartOfNextColumn(
521 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
522 UINT i
= menu
->FocusedItem
+ 1;
525 return NO_SELECTED_ITEM
;
527 if( i
== NO_SELECTED_ITEM
)
530 for( ; i
< menu
->nItems
; ++i
) {
531 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
535 return NO_SELECTED_ITEM
;
539 /******************************************************************************
541 * UINT MENU_GetStartOfPrevColumn(
544 *****************************************************************************/
546 static UINT
MENU_GetStartOfPrevColumn(
549 POPUPMENU
const *menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
553 return NO_SELECTED_ITEM
;
555 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
556 return NO_SELECTED_ITEM
;
558 /* Find the start of the column */
560 for(i
= menu
->FocusedItem
; i
!= 0 &&
561 !(menu
->items
[i
].fType
& MF_MENUBARBREAK
);
565 return NO_SELECTED_ITEM
;
567 for(--i
; i
!= 0; --i
) {
568 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
572 TRACE("ret %d.\n", i
);
579 /***********************************************************************
582 * Find a menu item. Return a pointer on the item, and modifies *hmenu
583 * in case the item was in a sub-menu.
585 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
590 if (((*hmenu
)==0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
591 if (wFlags
& MF_BYPOSITION
)
593 if (*nPos
>= menu
->nItems
) return NULL
;
594 return &menu
->items
[*nPos
];
598 MENUITEM
*item
= menu
->items
;
599 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
601 if (item
->wID
== *nPos
)
606 else if (item
->fType
& MF_POPUP
)
608 HMENU hsubmenu
= item
->hSubMenu
;
609 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
621 /***********************************************************************
624 * Find a Sub menu. Return the position of the submenu, and modifies
625 * *hmenu in case it is found in another sub-menu.
626 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
628 UINT
MENU_FindSubMenu( HMENU
*hmenu
, HMENU hSubTarget
)
633 if (((*hmenu
)==0xffff) ||
634 (!(menu
= MENU_GetMenu(*hmenu
))))
635 return NO_SELECTED_ITEM
;
637 for (i
= 0; i
< menu
->nItems
; i
++, item
++) {
638 if(!(item
->fType
& MF_POPUP
)) continue;
639 if (item
->hSubMenu
== hSubTarget
) {
643 HMENU hsubmenu
= item
->hSubMenu
;
644 UINT pos
= MENU_FindSubMenu( &hsubmenu
, hSubTarget
);
645 if (pos
!= NO_SELECTED_ITEM
) {
651 return NO_SELECTED_ITEM
;
654 /***********************************************************************
657 static void MENU_FreeItemData( MENUITEM
* item
)
660 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
661 HeapFree( SystemHeap
, 0, item
->text
);
664 /***********************************************************************
665 * MENU_FindItemByCoords
667 * Find the item at the specified coordinates (screen coords). Does
668 * not work for child windows and therefore should not be called for
669 * an arbitrary system menu.
671 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
,
672 POINT pt
, UINT
*pos
)
678 if (!GetWindowRect(menu
->hWnd
,&wrect
)) return NULL
;
679 pt
.x
-= wrect
.left
;pt
.y
-= wrect
.top
;
681 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
683 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
684 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
694 /***********************************************************************
697 * Find the menu item selected by a key press.
698 * Return item id, -1 if none, -2 if we should close the menu.
700 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
,
701 UINT key
, BOOL forceMenuChar
)
703 TRACE("\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
705 if (!IsMenu( hmenu
))
707 WND
* w
= WIN_FindWndPtr(hwndOwner
);
708 hmenu
= GetSubMenu(w
->hSysMenu
, 0);
709 WIN_ReleaseWndPtr(w
);
714 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
715 MENUITEM
*item
= menu
->items
;
723 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
725 if (item
->text
&& (IS_STRING_ITEM(item
->fType
)))
727 WCHAR
*p
= item
->text
- 2;
730 p
= strchrW (p
+ 2, '&');
732 while (p
!= NULL
&& p
[1] == '&');
733 if (p
&& (toupper(p
[1]) == key
)) return i
;
737 menuchar
= SendMessageA( hwndOwner
, WM_MENUCHAR
,
738 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
739 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
740 if (HIWORD(menuchar
) == 1) return (UINT
)(-2);
744 /***********************************************************************
747 * Load the bitmap associated with the magic menu item and its style
750 static HBITMAP
MENU_LoadMagicItem(UINT id
, BOOL hilite
, DWORD dwItemData
)
753 * Magic menu item id's section
754 * These magic id's are used by windows to insert "standard" mdi
755 * buttons (minimize,restore,close) on menu. Under windows,
756 * these magic id's make sure the right things appear when those
757 * bitmap buttons are pressed/selected/released.
761 { case HBMMENU_SYSTEM
:
762 return (dwItemData
) ?
763 (HBITMAP
)dwItemData
:
764 (hilite
? hBmpMinimizeD
: hBmpMinimize
);
765 case HBMMENU_MBAR_RESTORE
:
766 return (hilite
? hBmpMaximizeD
: hBmpMaximize
);
767 case HBMMENU_MBAR_MINIMIZE
:
768 return (hilite
? hBmpMinimizeD
: hBmpMinimize
);
769 case HBMMENU_MBAR_CLOSE
:
770 return (hilite
? hBmpCloseD
: hBmpClose
);
771 case HBMMENU_CALLBACK
:
772 case HBMMENU_MBAR_CLOSE_D
:
773 case HBMMENU_MBAR_MINIMIZE_D
:
774 case HBMMENU_POPUP_CLOSE
:
775 case HBMMENU_POPUP_RESTORE
:
776 case HBMMENU_POPUP_MAXIMIZE
:
777 case HBMMENU_POPUP_MINIMIZE
:
779 FIXME("Magic 0x%08x not implemented\n", id
);
785 /***********************************************************************
788 * Calculate the size of the menu item and store it in lpitem->rect.
790 static void MENU_CalcItemSize( HDC hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
791 INT orgX
, INT orgY
, BOOL menuBar
)
795 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
796 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem
,
797 (menuBar
? " (MenuBar)" : ""));
799 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
801 if (lpitem
->fType
& MF_OWNERDRAW
)
804 ** Experimentation under Windows reveals that an owner-drawn
805 ** menu is expected to return the size of the content part of
806 ** the menu item, not including the checkmark nor the submenu
807 ** arrow. Windows adds those values itself and returns the
808 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
810 MEASUREITEMSTRUCT mis
;
811 mis
.CtlType
= ODT_MENU
;
813 mis
.itemID
= lpitem
->wID
;
814 mis
.itemData
= (DWORD
)lpitem
->dwItemData
;
817 SendMessageA( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
818 lpitem
->rect
.right
+= mis
.itemWidth
;
822 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
825 /* under at least win95 you seem to be given a standard
826 height for the menu and the height value is ignored */
828 if (TWEAK_WineLook
== WIN31_LOOK
)
829 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
);
831 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
)-1;
834 lpitem
->rect
.bottom
+= mis
.itemHeight
;
836 TRACE("id=%04x size=%dx%d\n",
837 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
838 /* Fall through to get check/arrow width calculation. */
841 if (lpitem
->fType
& MF_SEPARATOR
)
843 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
849 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
850 if (lpitem
->fType
& MF_POPUP
)
851 lpitem
->rect
.right
+= arrow_bitmap_width
;
854 if (lpitem
->fType
& MF_OWNERDRAW
)
857 if (IS_BITMAP_ITEM(lpitem
->fType
))
862 /* Check if there is a magic menu item associated with this item */
863 if((LOWORD((int)lpitem
->text
))<12)
865 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fType
& MF_HILITE
),
869 resBmp
= (HBITMAP
)lpitem
->text
;
871 if (GetObjectA(resBmp
, sizeof(bm
), &bm
))
873 lpitem
->rect
.right
+= bm
.bmWidth
;
874 lpitem
->rect
.bottom
+= bm
.bmHeight
;
875 if (TWEAK_WineLook
== WIN98_LOOK
) {
876 /* Leave space for the sunken border */
877 lpitem
->rect
.right
+= 2;
878 lpitem
->rect
.bottom
+= 2;
885 /* If we get here, then it must be a text item */
886 if (IS_STRING_ITEM( lpitem
->fType
))
889 GetTextExtentPoint32W(hdc
, lpitem
->text
, strlenW(lpitem
->text
), &size
);
891 lpitem
->rect
.right
+= size
.cx
;
892 if (TWEAK_WineLook
== WIN31_LOOK
)
893 lpitem
->rect
.bottom
+= max( size
.cy
, GetSystemMetrics(SM_CYMENU
) );
895 lpitem
->rect
.bottom
+= max(size
.cy
, GetSystemMetrics(SM_CYMENU
)-1);
900 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
902 else if ((p
= strchrW( lpitem
->text
, '\t' )) != NULL
)
904 /* Item contains a tab (only meaningful in popup menus) */
905 GetTextExtentPoint32W(hdc
, lpitem
->text
, (int)(p
- lpitem
->text
) , &size
);
906 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+ size
.cx
;
907 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
911 if (strchrW( lpitem
->text
, '\b' ))
912 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
913 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
914 - arrow_bitmap_width
;
917 TRACE("(%d,%d)-(%d,%d)\n", lpitem
->rect
.left
, lpitem
->rect
.top
, lpitem
->rect
.right
, lpitem
->rect
.bottom
);
921 /***********************************************************************
922 * MENU_PopupMenuCalcSize
924 * Calculate the size of a popup menu.
926 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
931 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
933 lppop
->Width
= lppop
->Height
= 0;
934 if (lppop
->nItems
== 0) return;
937 SelectObject( hdc
, hMenuFont
);
940 maxX
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CXBORDER
) : 2+1 ;
942 while (start
< lppop
->nItems
)
944 lpitem
= &lppop
->items
[start
];
946 orgY
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CYBORDER
) : 2;
948 maxTab
= maxTabWidth
= 0;
950 /* Parse items until column break or end of menu */
951 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
954 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
956 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
958 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
959 maxX
= max( maxX
, lpitem
->rect
.right
);
960 orgY
= lpitem
->rect
.bottom
;
961 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
963 maxTab
= max( maxTab
, lpitem
->xTab
);
964 maxTabWidth
= max(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
968 /* Finish the column (set all items to the largest width found) */
969 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
970 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
972 lpitem
->rect
.right
= maxX
;
973 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
974 lpitem
->xTab
= maxTab
;
977 lppop
->Height
= max( lppop
->Height
, orgY
);
982 /* space for 3d border */
983 if(TWEAK_WineLook
> WIN31_LOOK
)
993 /***********************************************************************
994 * MENU_MenuBarCalcSize
996 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
997 * height is off by 1 pixel which causes lengthy window relocations when
998 * active document window is maximized/restored.
1000 * Calculate the size of the menu bar.
1002 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1003 LPPOPUPMENU lppop
, HWND hwndOwner
)
1006 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1008 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
1009 if (lppop
->nItems
== 0) return;
1010 TRACE("left=%d top=%d right=%d bottom=%d\n",
1011 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
1012 lppop
->Width
= lprect
->right
- lprect
->left
;
1014 maxY
= lprect
->top
+1;
1017 while (start
< lppop
->nItems
)
1019 lpitem
= &lppop
->items
[start
];
1020 orgX
= lprect
->left
;
1023 /* Parse items until line break or end of menu */
1024 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
1026 if ((helpPos
== -1) && (lpitem
->fType
& MF_HELP
)) helpPos
= i
;
1028 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1030 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1032 debug_print_menuitem (" item: ", lpitem
, "");
1033 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
1035 if (lpitem
->rect
.right
> lprect
->right
)
1037 if (i
!= start
) break;
1038 else lpitem
->rect
.right
= lprect
->right
;
1040 maxY
= max( maxY
, lpitem
->rect
.bottom
);
1041 orgX
= lpitem
->rect
.right
;
1044 /* Finish the line (set all items to the largest height found) */
1045 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
1048 lprect
->bottom
= maxY
;
1049 lppop
->Height
= lprect
->bottom
- lprect
->top
;
1051 if (TWEAK_WineLook
== WIN31_LOOK
) {
1052 /* Flush right all magic items and items between the MF_HELP and */
1053 /* the last item (if several lines, only move the last line) */
1054 lpitem
= &lppop
->items
[lppop
->nItems
-1];
1055 orgY
= lpitem
->rect
.top
;
1056 orgX
= lprect
->right
;
1057 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
1058 if ( !IS_BITMAP_ITEM(lpitem
->fType
) && ((helpPos
==-1) || (helpPos
>i
) ))
1060 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
1061 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
1062 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
1063 lpitem
->rect
.right
= orgX
;
1064 orgX
= lpitem
->rect
.left
;
1069 /***********************************************************************
1072 * Draw a single menu item.
1074 static void MENU_DrawMenuItem( HWND hwnd
, HMENU hmenu
, HWND hwndOwner
, HDC hdc
, MENUITEM
*lpitem
,
1075 UINT height
, BOOL menuBar
, UINT odaction
)
1079 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
1081 if (lpitem
->fType
& MF_SYSMENU
)
1083 if( !IsIconic(hwnd
) ) {
1084 if (TWEAK_WineLook
> WIN31_LOOK
)
1085 NC_DrawSysButton95( hwnd
, hdc
,
1087 (MF_HILITE
| MF_MOUSESELECT
) );
1089 NC_DrawSysButton( hwnd
, hdc
,
1091 (MF_HILITE
| MF_MOUSESELECT
) );
1097 if (lpitem
->fType
& MF_OWNERDRAW
)
1100 ** Experimentation under Windows reveals that an owner-drawn
1101 ** menu is given the rectangle which includes the space it requested
1102 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1103 ** and a popup-menu arrow. This is the value of lpitem->rect.
1104 ** Windows will leave all drawing to the application except for
1105 ** the popup-menu arrow. Windows always draws that itself, after
1106 ** the menu owner has finished drawing.
1110 dis
.CtlType
= ODT_MENU
;
1112 dis
.itemID
= lpitem
->wID
;
1113 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1115 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1116 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
1117 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1118 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1119 dis
.hwndItem
= hmenu
;
1121 dis
.rcItem
= lpitem
->rect
;
1122 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1123 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner
,
1124 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1125 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1127 SendMessageA( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
1128 /* Fall through to draw popup-menu arrow */
1131 TRACE("rect={%d,%d,%d,%d}\n", lpitem
->rect
.left
, lpitem
->rect
.top
,
1132 lpitem
->rect
.right
,lpitem
->rect
.bottom
);
1134 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1136 rect
= lpitem
->rect
;
1138 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1140 if (lpitem
->fState
& MF_HILITE
)
1142 if(TWEAK_WineLook
== WIN98_LOOK
)
1145 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1147 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1149 else /* Not Win98 Look */
1151 if(!IS_BITMAP_ITEM(lpitem
->fType
))
1152 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1156 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_MENU
) );
1159 SetBkMode( hdc
, TRANSPARENT
);
1161 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1163 /* vertical separator */
1164 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1166 if (TWEAK_WineLook
> WIN31_LOOK
)
1170 rc
.bottom
= height
- 3;
1171 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1175 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1176 MoveToEx( hdc
, rect
.left
, 0, NULL
);
1177 LineTo( hdc
, rect
.left
, height
);
1181 /* horizontal separator */
1182 if (lpitem
->fType
& MF_SEPARATOR
)
1184 if (TWEAK_WineLook
> WIN31_LOOK
)
1189 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1190 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1194 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1195 MoveToEx( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2, NULL
);
1196 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1204 if (lpitem
->fState
& MF_HILITE
)
1206 if(TWEAK_WineLook
== WIN98_LOOK
)
1209 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1212 if(lpitem
->fState
& MF_GRAYED
)
1213 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1215 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1217 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1219 else /* Not Win98 Look */
1221 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1222 if(!IS_BITMAP_ITEM(lpitem
->fType
))
1223 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1225 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1230 if (lpitem
->fState
& MF_GRAYED
)
1231 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1233 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1234 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
1237 /* helper lines for debugging */
1238 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1239 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1240 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1241 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1246 INT y
= rect
.top
+ rect
.bottom
;
1248 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1250 /* Draw the check mark
1253 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1256 if (lpitem
->fState
& MF_CHECKED
)
1258 HBITMAP bm
= lpitem
->hCheckBit
? lpitem
->hCheckBit
:
1259 ((lpitem
->fType
& MFT_RADIOCHECK
) ? hStdRadioCheck
: hStdCheck
);
1260 HDC hdcMem
= CreateCompatibleDC( hdc
);
1262 SelectObject( hdcMem
, bm
);
1263 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1264 check_bitmap_width
, check_bitmap_height
,
1265 hdcMem
, 0, 0, SRCCOPY
);
1268 else if (lpitem
->hUnCheckBit
)
1270 HDC hdcMem
= CreateCompatibleDC( hdc
);
1272 SelectObject( hdcMem
, lpitem
->hUnCheckBit
);
1273 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1274 check_bitmap_width
, check_bitmap_height
,
1275 hdcMem
, 0, 0, SRCCOPY
);
1280 /* Draw the popup-menu arrow */
1281 if (lpitem
->fType
& MF_POPUP
)
1283 HDC hdcMem
= CreateCompatibleDC( hdc
);
1284 HBITMAP hOrigBitmap
;
1286 hOrigBitmap
= SelectObject( hdcMem
, hStdMnArrow
);
1287 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1288 (y
- arrow_bitmap_height
) / 2,
1289 arrow_bitmap_width
, arrow_bitmap_height
,
1290 hdcMem
, 0, 0, SRCCOPY
);
1291 SelectObject( hdcMem
, hOrigBitmap
);
1295 rect
.left
+= check_bitmap_width
;
1296 rect
.right
-= arrow_bitmap_width
;
1299 /* Done for owner-drawn */
1300 if (lpitem
->fType
& MF_OWNERDRAW
)
1303 /* Draw the item text or bitmap */
1304 if (IS_BITMAP_ITEM(lpitem
->fType
))
1309 HDC hdcMem
= CreateCompatibleDC( hdc
);
1312 * Check if there is a magic menu item associated with this item
1313 * and load the appropriate bitmap
1315 if((LOWORD((int)lpitem
->text
)) < 12)
1317 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fState
& MF_HILITE
),
1318 lpitem
->dwItemData
);
1321 resBmp
= (HBITMAP
)lpitem
->text
;
1326 GetObjectA( resBmp
, sizeof(bm
), &bm
);
1328 SelectObject(hdcMem
,resBmp
);
1330 /* handle fontsize > bitmap_height */
1331 top
= ((rect
.bottom
-rect
.top
)>bm
.bmHeight
) ?
1332 rect
.top
+(rect
.bottom
-rect
.top
-bm
.bmHeight
)/2 : rect
.top
;
1334 BitBlt( hdc
, rect
.left
, top
, rect
.right
- rect
.left
,
1335 rect
.bottom
- rect
.top
, hdcMem
, 0, 0,
1336 ((lpitem
->fState
& MF_HILITE
) && !((LOWORD((DWORD
)lpitem
->text
)) < 12)) ? NOTSRCCOPY
: SRCCOPY
);
1343 /* No bitmap - process text if present */
1344 else if (IS_STRING_ITEM(lpitem
->fType
))
1349 UINT uFormat
= (menuBar
) ?
1350 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1351 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1353 if ( lpitem
->fState
& MFS_DEFAULT
)
1355 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1360 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1361 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1362 i
= strlenW( lpitem
->text
);
1366 for (i
= 0; lpitem
->text
[i
]; i
++)
1367 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1371 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1373 if (!(lpitem
->fState
& MF_HILITE
) )
1375 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1376 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1377 DrawTextW( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1378 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1380 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1383 DrawTextW( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1385 /* paint the shortcut text */
1386 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
1388 if (lpitem
->text
[i
] == '\t')
1390 rect
.left
= lpitem
->xTab
;
1391 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1395 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1398 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1400 if (!(lpitem
->fState
& MF_HILITE
) )
1402 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1403 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1404 DrawTextW( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1405 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1407 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1409 DrawTextW( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1413 SelectObject (hdc
, hfontOld
);
1418 /***********************************************************************
1419 * MENU_DrawPopupMenu
1421 * Paint a popup menu.
1423 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
1425 HBRUSH hPrevBrush
= 0;
1428 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd
, hdc
, hmenu
);
1430 GetClientRect( hwnd
, &rect
);
1432 if(TWEAK_WineLook
== WIN31_LOOK
)
1434 rect
.bottom
-= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1435 rect
.right
-= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
);
1438 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1439 && (SelectObject( hdc
, hMenuFont
)))
1443 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1445 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1451 /* draw 3-d shade */
1452 if(TWEAK_WineLook
== WIN31_LOOK
) {
1453 SelectObject( hdc
, hShadeBrush
);
1454 SetBkMode( hdc
, TRANSPARENT
);
1455 ropPrev
= SetROP2( hdc
, R2_MASKPEN
);
1457 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
1458 PatBlt( hdc
, i
& 0xfffffffe,
1459 rect
.top
+ POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
),
1460 i
%2 + POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1461 rect
.bottom
- rect
.top
, 0x00a000c9 );
1463 PatBlt( hdc
, rect
.left
+ POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1464 i
& 0xfffffffe,rect
.right
- rect
.left
,
1465 i
%2 + POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
), 0x00a000c9 );
1466 SelectObject( hdc
, hPrevPen
);
1467 SelectObject( hdc
, hPrevBrush
);
1468 SetROP2( hdc
, ropPrev
);
1471 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1473 /* draw menu items */
1475 menu
= MENU_GetMenu( hmenu
);
1476 if (menu
&& menu
->nItems
)
1481 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1482 MENU_DrawMenuItem( hwnd
, hmenu
, menu
->hwndOwner
, hdc
, item
,
1483 menu
->Height
, FALSE
, ODA_DRAWENTIRE
);
1488 SelectObject( hdc
, hPrevBrush
);
1493 /***********************************************************************
1496 * Paint a menu bar. Returns the height of the menu bar.
1497 * called from [windows/nonclient.c]
1499 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1506 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1508 lppop
= MENU_GetMenu ((HMENU
)wndPtr
->wIDmenu
);
1509 if (lppop
== NULL
|| lprect
== NULL
)
1511 retvalue
= GetSystemMetrics(SM_CYMENU
);
1515 TRACE("(%04x, %p, %p)\n", hDC
, lprect
, lppop
);
1517 hfontOld
= SelectObject( hDC
, hMenuFont
);
1519 if (lppop
->Height
== 0)
1520 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1522 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1526 retvalue
= lppop
->Height
;
1530 FillRect(hDC
, lprect
, GetSysColorBrush(COLOR_MENU
) );
1532 if (TWEAK_WineLook
== WIN31_LOOK
)
1534 SelectObject( hDC
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1535 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
1536 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1540 SelectObject( hDC
, GetSysColorPen(COLOR_3DFACE
));
1541 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
1542 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1545 if (lppop
->nItems
== 0)
1547 retvalue
= GetSystemMetrics(SM_CYMENU
);
1551 for (i
= 0; i
< lppop
->nItems
; i
++)
1553 MENU_DrawMenuItem( hwnd
, (HMENU
)wndPtr
->wIDmenu
, hwnd
,
1554 hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
, ODA_DRAWENTIRE
);
1556 retvalue
= lppop
->Height
;
1560 SelectObject (hDC
, hfontOld
);
1562 WIN_ReleaseWndPtr(wndPtr
);
1566 /***********************************************************************
1567 * MENU_PatchResidentPopup
1569 BOOL
MENU_PatchResidentPopup( HQUEUE16 checkQueue
, WND
* checkWnd
)
1571 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1577 TRACE("patching resident popup: %04x %04x [%04x %04x]\n",
1578 checkQueue
, checkWnd
? checkWnd
->hwndSelf
: 0, pTPWnd
->hmemTaskQ
,
1579 pTPWnd
->owner
? pTPWnd
->owner
->hwndSelf
: 0);
1581 switch( checkQueue
)
1583 case 0: /* checkWnd is the new popup owner */
1586 pTPWnd
->owner
= checkWnd
;
1587 if( pTPWnd
->hmemTaskQ
!= checkWnd
->hmemTaskQ
)
1588 hTask
= QUEUE_GetQueueTask( checkWnd
->hmemTaskQ
);
1592 case 0xFFFF: /* checkWnd is destroyed */
1593 if( pTPWnd
->owner
== checkWnd
)
1594 pTPWnd
->owner
= NULL
;
1595 MENU_ReleaseTopPopupWnd();
1598 default: /* checkQueue is exiting */
1599 if( pTPWnd
->hmemTaskQ
== checkQueue
)
1601 hTask
= QUEUE_GetQueueTask( pTPWnd
->hmemTaskQ
);
1602 hTask
= TASK_GetNextTask( hTask
);
1609 TDB
* task
= (TDB
*)GlobalLock16( hTask
);
1612 pTPWnd
->hInstance
= task
->hInstance
;
1613 pTPWnd
->hmemTaskQ
= task
->hQueue
;
1614 MENU_ReleaseTopPopupWnd();
1617 else WARN("failed to patch resident popup.\n");
1620 MENU_ReleaseTopPopupWnd();
1624 /***********************************************************************
1627 * Display a popup menu.
1629 static BOOL
MENU_ShowPopup( HWND hwndOwner
, HMENU hmenu
, UINT id
,
1630 INT x
, INT y
, INT xanchor
, INT yanchor
)
1633 WND
*wndOwner
= NULL
;
1635 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1636 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1638 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
1639 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1641 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1642 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1645 /* store the owner for DrawItem */
1646 menu
->hwndOwner
= hwndOwner
;
1648 if( (wndOwner
= WIN_FindWndPtr( hwndOwner
)) )
1652 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1654 /* adjust popup menu pos so that it fits within the desktop */
1656 width
= menu
->Width
+ GetSystemMetrics(SM_CXBORDER
);
1657 height
= menu
->Height
+ GetSystemMetrics(SM_CYBORDER
);
1659 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1662 x
-= width
- xanchor
;
1663 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1664 x
= GetSystemMetrics(SM_CXSCREEN
) - width
;
1668 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1671 y
-= height
+ yanchor
;
1672 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1673 y
= GetSystemMetrics(SM_CYSCREEN
) - height
;
1677 if( TWEAK_WineLook
== WIN31_LOOK
)
1679 width
+= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
); /* add space for shading */
1680 height
+= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1683 /* NOTE: In Windows, top menu popup is not owned. */
1684 if (!pTopPopupWnd
) /* create top level popup menu window */
1686 assert( uSubPWndLevel
== 0 );
1688 pTopPopupWnd
= WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1689 WS_POPUP
, x
, y
, width
, height
,
1690 hwndOwner
, 0, wndOwner
->hInstance
,
1694 WIN_ReleaseWndPtr(wndOwner
);
1697 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1698 MENU_ReleaseTopPopupWnd();
1703 /* create a new window for the submenu */
1705 menu
->hWnd
= CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1706 WS_POPUP
, x
, y
, width
, height
,
1707 hwndOwner
, 0, wndOwner
->hInstance
,
1711 WIN_ReleaseWndPtr(wndOwner
);
1715 else /* top level popup menu window already exists */
1717 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1718 menu
->hWnd
= pTPWnd
->hwndSelf
;
1720 MENU_PatchResidentPopup( 0, wndOwner
);
1721 SendMessageA( pTPWnd
->hwndSelf
, MM_SETMENUHANDLE
, (WPARAM16
)hmenu
, 0L);
1723 /* adjust its size */
1725 SetWindowPos( menu
->hWnd
, 0, x
, y
, width
, height
,
1726 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
1727 MENU_ReleaseTopPopupWnd();
1730 uSubPWndLevel
++; /* menu level counter */
1732 /* Display the window */
1734 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1735 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1736 UpdateWindow( menu
->hWnd
);
1737 WIN_ReleaseWndPtr(wndOwner
);
1744 /***********************************************************************
1747 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
1748 BOOL sendMenuSelect
, HMENU topmenu
)
1753 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1755 lppop
= MENU_GetMenu( hmenu
);
1756 if ((!lppop
) || (!lppop
->nItems
)) return;
1758 if (lppop
->FocusedItem
== wIndex
) return;
1759 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
1760 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1762 SelectObject( hdc
, hMenuFont
);
1764 /* Clear previous highlighted item */
1765 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1767 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1768 MENU_DrawMenuItem(lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,&lppop
->items
[lppop
->FocusedItem
],
1769 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1773 /* Highlight new item (if any) */
1774 lppop
->FocusedItem
= wIndex
;
1775 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1777 if(!(lppop
->items
[wIndex
].fType
& MF_SEPARATOR
)) {
1778 lppop
->items
[wIndex
].fState
|= MF_HILITE
;
1779 MENU_DrawMenuItem( lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,
1780 &lppop
->items
[wIndex
], lppop
->Height
,
1781 !(lppop
->wFlags
& MF_POPUP
), ODA_SELECT
);
1785 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1786 SendMessageA( hwndOwner
, WM_MENUSELECT
,
1787 MAKELONG(ip
->fType
& MF_POPUP
? wIndex
: ip
->wID
,
1788 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1789 (lppop
->wFlags
& MF_SYSMENU
)), hmenu
);
1792 else if (sendMenuSelect
) {
1795 if((pos
=MENU_FindSubMenu(&topmenu
, hmenu
))!=NO_SELECTED_ITEM
){
1796 POPUPMENU
*ptm
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( topmenu
);
1797 MENUITEM
*ip
= &ptm
->items
[pos
];
1798 SendMessageA( hwndOwner
, WM_MENUSELECT
, MAKELONG(pos
,
1799 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1800 (ptm
->wFlags
& MF_SYSMENU
)), topmenu
);
1804 ReleaseDC( lppop
->hWnd
, hdc
);
1808 /***********************************************************************
1809 * MENU_MoveSelection
1811 * Moves currently selected item according to the offset parameter.
1812 * If there is no selection then it should select the last item if
1813 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1815 static void MENU_MoveSelection( HWND hwndOwner
, HMENU hmenu
, INT offset
)
1820 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner
, hmenu
, offset
);
1822 menu
= MENU_GetMenu( hmenu
);
1823 if ((!menu
) || (!menu
->items
)) return;
1825 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1827 if( menu
->nItems
== 1 ) return; else
1828 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1830 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1832 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1837 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1838 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1839 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1841 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1847 /**********************************************************************
1850 * Set an item flags, id and text ptr. Called by InsertMenu() and
1853 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
,
1856 LPWSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1858 debug_print_menuitem("MENU_SetItemData from: ", item
, "");
1860 if (IS_STRING_ITEM(flags
))
1864 flags
|= MF_SEPARATOR
;
1870 /* Item beginning with a backspace is a help item */
1876 if (!(text
= HEAP_strdupW( SystemHeap
, 0, str
))) return FALSE
;
1880 else if (IS_BITMAP_ITEM(flags
))
1881 item
->text
= (LPWSTR
)(HBITMAP
)LOWORD(str
);
1882 else item
->text
= NULL
;
1884 if (flags
& MF_OWNERDRAW
)
1885 item
->dwItemData
= (DWORD
)str
;
1887 item
->dwItemData
= 0;
1889 if ((item
->fType
& MF_POPUP
) && (flags
& MF_POPUP
) && (item
->hSubMenu
!= id
) )
1890 DestroyMenu( item
->hSubMenu
); /* ModifyMenu() spec */
1892 if (flags
& MF_POPUP
)
1894 POPUPMENU
*menu
= MENU_GetMenu((UINT16
)id
);
1895 if (menu
) menu
->wFlags
|= MF_POPUP
;
1907 if (flags
& MF_POPUP
)
1908 item
->hSubMenu
= id
;
1910 if ((item
->fType
& MF_POPUP
) && !(flags
& MF_POPUP
) )
1911 flags
|= MF_POPUP
; /* keep popup */
1913 item
->fType
= flags
& TYPE_MASK
;
1914 item
->fState
= (flags
& STATE_MASK
) &
1915 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1918 /* Don't call SetRectEmpty here! */
1921 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1923 debug_print_menuitem("MENU_SetItemData to : ", item
, "");
1928 /**********************************************************************
1931 * Insert a new item into a menu.
1933 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
1938 if (!(menu
= MENU_GetMenu(hMenu
)))
1941 /* Find where to insert new item */
1943 if (flags
& MF_BYPOSITION
) {
1944 if (pos
> menu
->nItems
)
1947 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1950 if (!(menu
= MENU_GetMenu( hMenu
)))
1955 /* Create new items array */
1957 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1960 WARN("allocation failed\n" );
1963 if (menu
->nItems
> 0)
1965 /* Copy the old array into the new one */
1966 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1967 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1968 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1969 HeapFree( SystemHeap
, 0, menu
->items
);
1971 menu
->items
= newItems
;
1973 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1974 menu
->Height
= 0; /* force size recalculate */
1975 return &newItems
[pos
];
1979 /**********************************************************************
1980 * MENU_ParseResource
1982 * Parse a standard menu resource and add items to the menu.
1983 * Return a pointer to the end of the resource.
1985 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1992 flags
= GET_WORD(res
);
1993 res
+= sizeof(WORD
);
1994 if (!(flags
& MF_POPUP
))
1997 res
+= sizeof(WORD
);
1999 if (!IS_STRING_ITEM(flags
))
2000 ERR("not a string item %04x\n", flags
);
2002 if (!unicode
) res
+= strlen(str
) + 1;
2003 else res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
2004 if (flags
& MF_POPUP
)
2006 HMENU hSubMenu
= CreatePopupMenu();
2007 if (!hSubMenu
) return NULL
;
2008 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
2010 if (!unicode
) AppendMenuA( hMenu
, flags
, (UINT
)hSubMenu
, str
);
2011 else AppendMenuW( hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
2013 else /* Not a popup */
2015 if (!unicode
) AppendMenuA( hMenu
, flags
, id
, *str
? str
: NULL
);
2016 else AppendMenuW( hMenu
, flags
, id
,
2017 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2019 } while (!(flags
& MF_END
));
2024 /**********************************************************************
2025 * MENUEX_ParseResource
2027 * Parse an extended menu resource and add items to the menu.
2028 * Return a pointer to the end of the resource.
2030 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
2036 mii
.cbSize
= sizeof(mii
);
2037 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
2038 mii
.fType
= GET_DWORD(res
);
2039 res
+= sizeof(DWORD
);
2040 mii
.fState
= GET_DWORD(res
);
2041 res
+= sizeof(DWORD
);
2042 mii
.wID
= GET_DWORD(res
);
2043 res
+= sizeof(DWORD
);
2044 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
2045 res
+= sizeof(WORD
);
2046 /* Align the text on a word boundary. */
2047 res
+= (~((int)res
- 1)) & 1;
2048 mii
.dwTypeData
= (LPWSTR
) res
;
2049 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2050 /* Align the following fields on a dword boundary. */
2051 res
+= (~((int)res
- 1)) & 3;
2053 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
2055 LPSTR newstr
= HEAP_strdupWtoA(GetProcessHeap(),
2057 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2058 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, newstr
);
2059 HeapFree( GetProcessHeap(), 0, newstr
);
2062 if (resinfo
& 1) { /* Pop-up? */
2063 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2064 res
+= sizeof(DWORD
);
2065 mii
.hSubMenu
= CreatePopupMenu();
2068 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
2069 DestroyMenu(mii
.hSubMenu
);
2072 mii
.fMask
|= MIIM_SUBMENU
;
2073 mii
.fType
|= MF_POPUP
;
2075 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2076 } while (!(resinfo
& MF_END
));
2081 /***********************************************************************
2084 * Return the handle of the selected sub-popup menu (if any).
2086 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
2091 menu
= MENU_GetMenu( hmenu
);
2093 if ((!menu
) || (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return 0;
2095 item
= &menu
->items
[menu
->FocusedItem
];
2096 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
2097 return item
->hSubMenu
;
2102 /***********************************************************************
2103 * MENU_HideSubPopups
2105 * Hide the sub-popup menus of this menu.
2107 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
2108 BOOL sendMenuSelect
)
2110 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
2112 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, sendMenuSelect
);
2114 if (menu
&& uSubPWndLevel
)
2120 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
2122 item
= &menu
->items
[menu
->FocusedItem
];
2123 if (!(item
->fType
& MF_POPUP
) ||
2124 !(item
->fState
& MF_MOUSESELECT
)) return;
2125 item
->fState
&= ~MF_MOUSESELECT
;
2126 hsubmenu
= item
->hSubMenu
;
2129 submenu
= MENU_GetMenu( hsubmenu
);
2130 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
2131 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
, 0 );
2133 if (submenu
->hWnd
== MENU_GetTopPopupWnd()->hwndSelf
)
2135 ShowWindow( submenu
->hWnd
, SW_HIDE
);
2140 DestroyWindow( submenu
->hWnd
);
2143 MENU_ReleaseTopPopupWnd();
2148 /***********************************************************************
2151 * Display the sub-menu of the selected item of this menu.
2152 * Return the handle of the submenu, or hmenu if no submenu to display.
2154 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
,
2155 BOOL selectFirst
, UINT wFlags
)
2163 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, selectFirst
);
2165 if (!(menu
= MENU_GetMenu( hmenu
))) return hmenu
;
2167 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
)) ||
2168 (menu
->FocusedItem
== NO_SELECTED_ITEM
))
2170 WIN_ReleaseWndPtr(wndPtr
);
2174 item
= &menu
->items
[menu
->FocusedItem
];
2175 if (!(item
->fType
& MF_POPUP
) ||
2176 (item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2178 WIN_ReleaseWndPtr(wndPtr
);
2182 /* message must be sent before using item,
2183 because nearly everything may be changed by the application ! */
2185 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2186 if (!(wFlags
& TPM_NONOTIFY
))
2187 SendMessageA( hwndOwner
, WM_INITMENUPOPUP
, item
->hSubMenu
,
2188 MAKELONG( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
2190 item
= &menu
->items
[menu
->FocusedItem
];
2193 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2194 if (!(item
->fState
& MF_HILITE
))
2196 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC( menu
->hWnd
);
2197 else hdc
= GetDCEx( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2199 SelectObject( hdc
, hMenuFont
);
2201 item
->fState
|= MF_HILITE
;
2202 MENU_DrawMenuItem( menu
->hWnd
, hmenu
, hwndOwner
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
2203 ReleaseDC( menu
->hWnd
, hdc
);
2205 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
2208 item
->fState
|= MF_MOUSESELECT
;
2210 if (IS_SYSTEM_MENU(menu
))
2212 MENU_InitSysMenuPopup(item
->hSubMenu
, wndPtr
->dwStyle
, GetClassLongA(wndPtr
->hwndSelf
, GCL_STYLE
));
2214 NC_GetSysPopupPos( wndPtr
, &rect
);
2215 rect
.top
= rect
.bottom
;
2216 rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2217 rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2221 if (menu
->wFlags
& MF_POPUP
)
2223 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2224 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.top
;
2225 rect
.right
= item
->rect
.left
- item
->rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2226 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
2230 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.left
;
2231 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.bottom
;
2232 rect
.right
= item
->rect
.right
- item
->rect
.left
;
2233 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
2237 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
2238 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2240 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
2241 WIN_ReleaseWndPtr(wndPtr
);
2242 return item
->hSubMenu
;
2247 /**********************************************************************
2250 BOOL
MENU_IsMenuActive(void)
2252 return pTopPopupWnd
&& (pTopPopupWnd
->dwStyle
& WS_VISIBLE
);
2255 /***********************************************************************
2258 * Walks menu chain trying to find a menu pt maps to.
2260 static HMENU
MENU_PtMenu( HMENU hMenu
, POINT pt
)
2262 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2263 register UINT ht
= menu
->FocusedItem
;
2265 /* try subpopup first (if any) */
2266 ht
= (ht
!= NO_SELECTED_ITEM
&&
2267 (menu
->items
[ht
].fType
& MF_POPUP
) &&
2268 (menu
->items
[ht
].fState
& MF_MOUSESELECT
))
2269 ? (UINT
) MENU_PtMenu(menu
->items
[ht
].hSubMenu
, pt
) : 0;
2271 if( !ht
) /* check the current window (avoiding WM_HITTEST) */
2273 ht
= (UINT
)NC_HandleNCHitTest( menu
->hWnd
, pt
);
2274 if( menu
->wFlags
& MF_POPUP
)
2275 ht
= (ht
!= (UINT
)HTNOWHERE
&&
2276 ht
!= (UINT
)HTERROR
) ? (UINT
)hMenu
: 0;
2279 WND
* wndPtr
= WIN_FindWndPtr(menu
->hWnd
);
2281 ht
= ( ht
== HTSYSMENU
) ? (UINT
)(wndPtr
->hSysMenu
)
2282 : ( ht
== HTMENU
) ? (UINT
)(wndPtr
->wIDmenu
) : 0;
2283 WIN_ReleaseWndPtr(wndPtr
);
2289 /***********************************************************************
2290 * MENU_ExecFocusedItem
2292 * Execute a menu item (for instance when user pressed Enter).
2293 * Return the wID of the executed item. Otherwise, -1 indicating
2294 * that no menu item was executed;
2295 * Have to receive the flags for the TrackPopupMenu options to avoid
2296 * sending unwanted message.
2299 static INT
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU hMenu
, UINT wFlags
)
2302 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2304 TRACE("%p hmenu=0x%04x\n", pmt
, hMenu
);
2306 if (!menu
|| !menu
->nItems
||
2307 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return -1;
2309 item
= &menu
->items
[menu
->FocusedItem
];
2311 TRACE("%08x %08x %08x\n",
2312 hMenu
, item
->wID
, item
->hSubMenu
);
2314 if (!(item
->fType
& MF_POPUP
))
2316 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(item
->fType
& MF_SEPARATOR
))
2318 /* If TPM_RETURNCMD is set you return the id, but
2319 do not send a message to the owner */
2320 if(!(wFlags
& TPM_RETURNCMD
))
2322 if( menu
->wFlags
& MF_SYSMENU
)
2323 PostMessageA( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
2324 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
2326 PostMessageA( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
2332 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hMenu
, TRUE
, wFlags
);
2337 /***********************************************************************
2338 * MENU_SwitchTracking
2340 * Helper function for menu navigation routines.
2342 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU hPtMenu
, UINT id
)
2344 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2345 POPUPMENU
*topmenu
= MENU_GetMenu( pmt
->hTopMenu
);
2347 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt
, hPtMenu
, id
);
2349 if( pmt
->hTopMenu
!= hPtMenu
&&
2350 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
2352 /* both are top level menus (system and menu-bar) */
2353 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2354 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2355 pmt
->hTopMenu
= hPtMenu
;
2357 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2358 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
, 0 );
2362 /***********************************************************************
2365 * Return TRUE if we can go on with menu tracking.
2367 static BOOL
MENU_ButtonDown( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2369 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2374 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2377 if( IS_SYSTEM_MENU(ptmenu
) )
2378 item
= ptmenu
->items
;
2380 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2384 if( ptmenu
->FocusedItem
!= id
)
2385 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2387 /* If the popup menu is not already "popped" */
2388 if(!(item
->fState
& MF_MOUSESELECT
))
2390 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2392 /* In win31, a newly popped menu always remains opened for the next buttonup */
2393 if(TWEAK_WineLook
== WIN31_LOOK
)
2394 ptmenu
->bTimeToHide
= FALSE
;
2399 /* Else the click was on the menu bar, finish the tracking */
2404 /***********************************************************************
2407 * Return the value of MENU_ExecFocusedItem if
2408 * the selected item was not a popup. Else open the popup.
2409 * A -1 return value indicates that we go on with menu tracking.
2412 static INT
MENU_ButtonUp( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2414 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2419 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2422 if( IS_SYSTEM_MENU(ptmenu
) )
2423 item
= ptmenu
->items
;
2425 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2427 if( item
&& (ptmenu
->FocusedItem
== id
))
2429 if( !(item
->fType
& MF_POPUP
) )
2430 return MENU_ExecFocusedItem( pmt
, hPtMenu
, wFlags
);
2432 /* If we are dealing with the top-level menu */
2433 /* and this is a click on an already "popped" item: */
2434 /* Stop the menu tracking and close the opened submenus */
2435 if((pmt
->hTopMenu
== hPtMenu
) && (ptmenu
->bTimeToHide
== TRUE
))
2438 ptmenu
->bTimeToHide
= TRUE
;
2444 /***********************************************************************
2447 * Return TRUE if we can go on with menu tracking.
2449 static BOOL
MENU_MouseMove( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2451 UINT id
= NO_SELECTED_ITEM
;
2452 POPUPMENU
*ptmenu
= NULL
;
2456 ptmenu
= MENU_GetMenu( hPtMenu
);
2457 if( IS_SYSTEM_MENU(ptmenu
) )
2460 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2463 if( id
== NO_SELECTED_ITEM
)
2465 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2466 NO_SELECTED_ITEM
, TRUE
, pmt
->hTopMenu
);
2469 else if( ptmenu
->FocusedItem
!= id
)
2471 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2472 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2478 /***********************************************************************
2481 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2483 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT vk
)
2485 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2487 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
2488 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
2494 LRESULT l
= SendMessageA( pmt
->hOwnerWnd
, WM_NEXTMENU
, vk
,
2495 (IS_SYSTEM_MENU(menu
)) ? GetSubMenu16(pmt
->hTopMenu
,0) : pmt
->hTopMenu
);
2497 TRACE("%04x [%04x] -> %04x [%04x]\n",
2498 (UINT16
)pmt
->hCurrentMenu
, (UINT16
)pmt
->hOwnerWnd
, LOWORD(l
), HIWORD(l
) );
2502 wndPtr
= WIN_FindWndPtr(pmt
->hOwnerWnd
);
2504 hNewWnd
= pmt
->hOwnerWnd
;
2505 if( IS_SYSTEM_MENU(menu
) )
2507 /* switch to the menu bar */
2509 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
2511 WIN_ReleaseWndPtr(wndPtr
);
2515 hNewMenu
= wndPtr
->wIDmenu
;
2518 menu
= MENU_GetMenu( hNewMenu
);
2519 id
= menu
->nItems
- 1;
2522 else if( wndPtr
->dwStyle
& WS_SYSMENU
)
2524 /* switch to the system menu */
2525 hNewMenu
= wndPtr
->hSysMenu
;
2529 WIN_ReleaseWndPtr(wndPtr
);
2532 WIN_ReleaseWndPtr(wndPtr
);
2534 else /* application returned a new menu to switch to */
2536 hNewMenu
= LOWORD(l
); hNewWnd
= HIWORD(l
);
2538 if( IsMenu(hNewMenu
) && IsWindow(hNewWnd
) )
2540 wndPtr
= WIN_FindWndPtr(hNewWnd
);
2542 if( wndPtr
->dwStyle
& WS_SYSMENU
&&
2543 GetSubMenu16(wndPtr
->hSysMenu
, 0) == hNewMenu
)
2545 /* get the real system menu */
2546 hNewMenu
= wndPtr
->hSysMenu
;
2548 else if( wndPtr
->dwStyle
& WS_CHILD
|| wndPtr
->wIDmenu
!= hNewMenu
)
2550 /* FIXME: Not sure what to do here;
2551 * perhaps try to track hNewMenu as a popup? */
2553 TRACE(" -- got confused.\n");
2554 WIN_ReleaseWndPtr(wndPtr
);
2557 WIN_ReleaseWndPtr(wndPtr
);
2562 if( hNewMenu
!= pmt
->hTopMenu
)
2564 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
,
2566 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2567 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2570 if( hNewWnd
!= pmt
->hOwnerWnd
)
2573 pmt
->hOwnerWnd
= hNewWnd
;
2574 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
2577 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2578 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
, 0 );
2585 /***********************************************************************
2588 * The idea is not to show the popup if the next input message is
2589 * going to hide it anyway.
2591 static BOOL
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2595 msg
.hwnd
= pmt
->hOwnerWnd
;
2597 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2598 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2603 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2604 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2606 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2607 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2608 if( msg
.message
== WM_KEYDOWN
&&
2609 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2611 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2618 /* failures go through this */
2619 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2623 /***********************************************************************
2626 * Handle a VK_LEFT key event in a menu.
2628 static void MENU_KeyLeft( MTRACKER
* pmt
, UINT wFlags
)
2631 HMENU hmenutmp
, hmenuprev
;
2634 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2635 menu
= MENU_GetMenu( hmenutmp
);
2637 /* Try to move 1 column left (if possible) */
2638 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2639 NO_SELECTED_ITEM
) {
2641 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2646 /* close topmost popup */
2647 while (hmenutmp
!= pmt
->hCurrentMenu
)
2649 hmenuprev
= hmenutmp
;
2650 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2653 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2654 pmt
->hCurrentMenu
= hmenuprev
;
2656 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2658 /* move menu bar selection if no more popups are left */
2660 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2661 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2663 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2665 /* A sublevel menu was displayed - display the next one
2666 * unless there is another displacement coming up */
2668 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2669 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2670 pmt
->hTopMenu
, TRUE
, wFlags
);
2676 /***********************************************************************
2679 * Handle a VK_RIGHT key event in a menu.
2681 static void MENU_KeyRight( MTRACKER
* pmt
, UINT wFlags
)
2684 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2687 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2689 debugstr_w((MENU_GetMenu(pmt
->hCurrentMenu
))->
2691 pmt
->hTopMenu
, debugstr_w(menu
->items
[0].text
) );
2693 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2695 /* If already displaying a popup, try to display sub-popup */
2697 hmenutmp
= pmt
->hCurrentMenu
;
2698 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hmenutmp
, TRUE
, wFlags
);
2700 /* if subpopup was displayed then we are done */
2701 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2704 /* Check to see if there's another column */
2705 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2706 NO_SELECTED_ITEM
) {
2707 TRACE("Going to %d.\n", nextcol
);
2708 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2713 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2715 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2717 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2718 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2719 } else hmenutmp
= 0;
2721 /* try to move to the next item */
2722 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2723 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2725 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2726 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2727 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2728 pmt
->hTopMenu
, TRUE
, wFlags
);
2732 /***********************************************************************
2735 * Menu tracking code.
2737 static INT
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
2738 HWND hwnd
, const RECT
*lprect
)
2743 INT executedMenuId
= -1;
2745 BOOL enterIdleSent
= FALSE
;
2748 mt
.hCurrentMenu
= hmenu
;
2749 mt
.hTopMenu
= hmenu
;
2750 mt
.hOwnerWnd
= hwnd
;
2754 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2755 hmenu
, wFlags
, x
, y
, hwnd
, (lprect
) ? lprect
->left
: 0, (lprect
) ? lprect
->top
: 0,
2756 (lprect
) ? lprect
->right
: 0, (lprect
) ? lprect
->bottom
: 0);
2759 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
2761 if (wFlags
& TPM_BUTTONDOWN
)
2763 /* Get the result in order to start the tracking or not */
2764 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2765 fEndMenu
= !fRemove
;
2768 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
2772 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2773 msg
.hwnd
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2775 /* we have to keep the message in the queue until it's
2776 * clear that menu loop is not over yet. */
2778 if (!MSG_InternalGetMessage( QMSG_WIN32A
, &msg
, msg
.hwnd
, mt
.hOwnerWnd
,
2779 MSGF_MENU
, PM_NOREMOVE
, !enterIdleSent
, &enterIdleSent
)) break;
2781 /* check if EndMenu() tried to cancel us, by posting this message */
2782 if(msg
.message
== WM_CANCELMODE
)
2784 /* we are now out of the loop */
2787 /* remove the message from the queue */
2788 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2790 /* break out of internal loop, ala ESCAPE */
2794 TranslateMessage( &msg
);
2797 if ( (msg
.hwnd
==menu
->hWnd
) || (msg
.message
!=WM_TIMER
) )
2798 enterIdleSent
=FALSE
;
2801 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2804 * use the mouse coordinates in lParam instead of those in the MSG
2805 * struct to properly handle synthetic messages. lParam coords are
2806 * relative to client area, so they must be converted; since they can
2807 * be negative, we must use SLOWORD/SHIWORD instead of LOWORD/HIWORD.
2809 mt
.pt
.x
= SLOWORD(msg
.lParam
);
2810 mt
.pt
.y
= SHIWORD(msg
.lParam
);
2811 ClientToScreen(msg
.hwnd
,&mt
.pt
);
2813 /* Find a menu for this mouse event */
2814 hmenu
= MENU_PtMenu( mt
.hTopMenu
, mt
.pt
);
2818 /* no WM_NC... messages in captured state */
2820 case WM_RBUTTONDBLCLK
:
2821 case WM_RBUTTONDOWN
:
2822 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2824 case WM_LBUTTONDBLCLK
:
2825 case WM_LBUTTONDOWN
:
2826 /* If the message belongs to the menu, removes it from the queue */
2827 /* Else, end menu tracking */
2828 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2829 fEndMenu
= !fRemove
;
2833 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2836 /* Check if a menu was selected by the mouse */
2839 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
2841 /* End the loop if executedMenuId is an item ID */
2842 /* or if the job was done (executedMenuId = 0). */
2843 fEndMenu
= fRemove
= (executedMenuId
!= -1);
2845 /* No menu was selected by the mouse */
2846 /* if the function was called by TrackPopupMenu, continue
2847 with the menu tracking. If not, stop it */
2849 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
2854 /* In win95 winelook, the selected menu item must be changed every time the
2855 mouse moves. In Win31 winelook, the mouse button has to be held down */
2857 if ( (TWEAK_WineLook
> WIN31_LOOK
) ||
2858 ( (msg
.wParam
& MK_LBUTTON
) ||
2859 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
))) )
2861 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
, wFlags
);
2863 } /* switch(msg.message) - mouse */
2865 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2867 fRemove
= TRUE
; /* Keyboard messages are always removed */
2875 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2876 NO_SELECTED_ITEM
, FALSE
, 0 );
2879 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2880 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2883 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2885 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2886 if (!(menu
->wFlags
& MF_POPUP
))
2887 mt
.hCurrentMenu
= MENU_ShowSubPopup(mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
, wFlags
);
2888 else /* otherwise try to move selection */
2889 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2893 MENU_KeyLeft( &mt
, wFlags
);
2897 MENU_KeyRight( &mt
, wFlags
);
2907 hi
.cbSize
= sizeof(HELPINFO
);
2908 hi
.iContextType
= HELPINFO_MENUITEM
;
2909 if (menu
->FocusedItem
== NO_SELECTED_ITEM
)
2912 hi
.iCtrlId
= menu
->items
[menu
->FocusedItem
].wID
;
2913 hi
.hItemHandle
= hmenu
;
2914 hi
.dwContextId
= menu
->dwContextHelpID
;
2915 hi
.MousePos
= msg
.pt
;
2916 SendMessageA(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
2923 break; /* WM_KEYDOWN */
2933 break; /* WM_SYSKEYDOWN */
2939 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
2941 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2942 fEndMenu
= (executedMenuId
!= -1);
2947 /* Hack to avoid control chars. */
2948 /* We will find a better way real soon... */
2949 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2951 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2952 LOWORD(msg
.wParam
), FALSE
);
2953 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
2954 else if (pos
== (UINT
)-1) MessageBeep(0);
2957 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
,
2959 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2960 fEndMenu
= (executedMenuId
!= -1);
2964 } /* switch(msg.message) - kbd */
2968 DispatchMessageA( &msg
);
2971 if (!fEndMenu
) fRemove
= TRUE
;
2973 /* finally remove message from the queue */
2975 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2976 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2977 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2982 /* If dropdown is still painted and the close box is clicked on
2983 then the menu will be destroyed as part of the DispatchMessage above.
2984 This will then invalidate the menu handle in mt.hTopMenu. We should
2985 check for this first. */
2986 if( IsMenu( mt
.hTopMenu
) )
2988 menu
= MENU_GetMenu( mt
.hTopMenu
);
2990 if( IsWindow( mt
.hOwnerWnd
) )
2992 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2994 if (menu
&& menu
->wFlags
& MF_POPUP
)
2996 ShowWindow( menu
->hWnd
, SW_HIDE
);
2999 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
3000 SendMessageA( mt
.hOwnerWnd
, WM_MENUSELECT
, MAKELONG(0,0xffff), 0 );
3003 /* Reset the variable for hiding menu */
3004 if( menu
) menu
->bTimeToHide
= FALSE
;
3007 /* The return value is only used by TrackPopupMenu */
3008 return ((executedMenuId
!= -1) ? executedMenuId
: 0);
3011 /***********************************************************************
3014 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
3016 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd
, hMenu
);
3020 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3021 if (!(wFlags
& TPM_NONOTIFY
))
3022 SendMessageA( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
3024 SendMessageA( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
3026 if (!(wFlags
& TPM_NONOTIFY
))
3027 SendMessageA( hWnd
, WM_INITMENU
, hMenu
, 0 );
3031 /***********************************************************************
3034 static BOOL
MENU_ExitTracking(HWND hWnd
)
3036 TRACE("hwnd=0x%04x\n", hWnd
);
3038 SendMessageA( hWnd
, WM_EXITMENULOOP
, 0, 0 );
3043 /***********************************************************************
3044 * MENU_TrackMouseMenuBar
3046 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3048 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT ht
, POINT pt
)
3050 HWND hWnd
= wndPtr
->hwndSelf
;
3051 HMENU hMenu
= (ht
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
3052 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3054 TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr
, ht
, pt
.x
, pt
.y
);
3058 MENU_InitTracking( hWnd
, hMenu
, FALSE
, wFlags
);
3059 MENU_TrackMenu( hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
3060 MENU_ExitTracking(hWnd
);
3065 /***********************************************************************
3066 * MENU_TrackKbdMenuBar
3068 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3070 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT wParam
, INT vkey
)
3072 UINT uItem
= NO_SELECTED_ITEM
;
3074 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3076 /* find window that has a menu */
3078 while( wndPtr
->dwStyle
& WS_CHILD
)
3079 if( !(wndPtr
= wndPtr
->parent
) ) return;
3081 /* check if we have to track a system menu */
3083 if( (wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
3084 !wndPtr
->wIDmenu
|| vkey
== VK_SPACE
)
3086 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
3087 hTrackMenu
= wndPtr
->hSysMenu
;
3089 wParam
|= HTSYSMENU
; /* prevent item lookup */
3092 hTrackMenu
= wndPtr
->wIDmenu
;
3094 if (IsMenu( hTrackMenu
))
3096 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
, FALSE
, wFlags
);
3098 if( vkey
&& vkey
!= VK_SPACE
)
3100 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
3101 vkey
, (wParam
& HTSYSMENU
) );
3102 if( uItem
>= (UINT
)(-2) )
3104 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3111 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
, 0 );
3113 if( uItem
== NO_SELECTED_ITEM
)
3114 MENU_MoveSelection( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
3116 PostMessageA( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
3118 MENU_TrackMenu( hTrackMenu
, wFlags
, 0, 0, wndPtr
->hwndSelf
, NULL
);
3121 MENU_ExitTracking (wndPtr
->hwndSelf
);
3126 /**********************************************************************
3127 * TrackPopupMenu16 (USER.416)
3129 BOOL16 WINAPI
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
3130 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
3134 CONV_RECT16TO32( lpRect
, &r
);
3135 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
3136 lpRect
? &r
: NULL
);
3140 /**********************************************************************
3141 * TrackPopupMenu (USER32.549)
3143 * Like the win32 API, the function return the command ID only if the
3144 * flag TPM_RETURNCMD is on.
3147 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3148 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
3152 MENU_InitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
3154 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3155 if (!(wFlags
& TPM_NONOTIFY
))
3156 SendMessageA( hWnd
, WM_INITMENUPOPUP
, hMenu
, 0);
3158 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
3159 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
, lpRect
);
3160 MENU_ExitTracking(hWnd
);
3162 if( (!(wFlags
& TPM_RETURNCMD
)) && (ret
!= FALSE
) )
3168 /**********************************************************************
3169 * TrackPopupMenuEx (USER32.550)
3171 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3172 HWND hWnd
, LPTPMPARAMS lpTpm
)
3174 FIXME("not fully implemented\n" );
3175 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, 0, hWnd
,
3176 lpTpm
? &lpTpm
->rcExclude
: NULL
);
3179 /***********************************************************************
3182 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3184 static LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
3186 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3187 hwnd
, message
, wParam
, lParam
);
3193 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lParam
;
3194 SetWindowLongW( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
3198 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
3199 return MA_NOACTIVATE
;
3204 BeginPaint( hwnd
, &ps
);
3205 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
3206 (HMENU
)GetWindowLongA( hwnd
, 0 ) );
3207 EndPaint( hwnd
, &ps
);
3215 /* zero out global pointer in case resident popup window
3216 * was somehow destroyed. */
3218 if(MENU_GetTopPopupWnd() )
3220 if( hwnd
== pTopPopupWnd
->hwndSelf
)
3222 ERR("resident popup destroyed!\n");
3224 MENU_DestroyTopPopupWnd();
3229 MENU_ReleaseTopPopupWnd();
3237 if (!GetWindowLongW( hwnd
, 0 )) ERR("no menu to display\n");
3240 SetWindowLongW( hwnd
, 0, 0 );
3243 case MM_SETMENUHANDLE
:
3244 SetWindowLongW( hwnd
, 0, wParam
);
3247 case MM_GETMENUHANDLE
:
3248 return GetWindowLongW( hwnd
, 0 );
3251 return DefWindowProcW( hwnd
, message
, wParam
, lParam
);
3257 /***********************************************************************
3258 * MENU_GetMenuBarHeight
3260 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3262 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
3263 INT orgX
, INT orgY
)
3271 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3272 hwnd
, menubarWidth
, orgX
, orgY
);
3274 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
3277 if (!(lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
)))
3279 WIN_ReleaseWndPtr(wndPtr
);
3283 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3284 SelectObject( hdc
, hMenuFont
);
3285 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+GetSystemMetrics(SM_CYMENU
));
3286 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
3287 ReleaseDC( hwnd
, hdc
);
3288 retvalue
= lppop
->Height
;
3289 WIN_ReleaseWndPtr(wndPtr
);
3294 /*******************************************************************
3295 * ChangeMenu16 (USER.153)
3297 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
3298 UINT16 id
, UINT16 flags
)
3300 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3301 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3302 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
3305 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3306 /* for MF_DELETE. We should check the parameters for all others */
3307 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3309 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
3310 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
3312 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
3313 flags
& MF_BYPOSITION
? pos
: id
,
3314 flags
& ~MF_REMOVE
);
3315 /* Default: MF_INSERT */
3316 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
3320 /*******************************************************************
3321 * ChangeMenuA (USER32.23)
3323 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
3324 UINT id
, UINT flags
)
3326 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3327 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3328 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
3330 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3331 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
3333 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3334 flags
& MF_BYPOSITION
? pos
: id
,
3335 flags
& ~MF_REMOVE
);
3336 /* Default: MF_INSERT */
3337 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
3341 /*******************************************************************
3342 * ChangeMenuW (USER32.24)
3344 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
3345 UINT id
, UINT flags
)
3347 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3348 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3349 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
3351 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3352 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
3354 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3355 flags
& MF_BYPOSITION
? pos
: id
,
3356 flags
& ~MF_REMOVE
);
3357 /* Default: MF_INSERT */
3358 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
3362 /*******************************************************************
3363 * CheckMenuItem16 (USER.154)
3365 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
3367 return (BOOL16
)CheckMenuItem( hMenu
, id
, flags
);
3371 /*******************************************************************
3372 * CheckMenuItem (USER32.46)
3374 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
3379 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu
, id
, flags
);
3380 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
3381 ret
= item
->fState
& MF_CHECKED
;
3382 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
3383 else item
->fState
&= ~MF_CHECKED
;
3388 /**********************************************************************
3389 * EnableMenuItem16 (USER.155)
3391 UINT16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3393 return EnableMenuItem( hMenu
, wItemID
, wFlags
);
3397 /**********************************************************************
3398 * EnableMenuItem (USER32.170)
3400 UINT WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3406 TRACE("(%04x, %04X, %04X) !\n",
3407 hMenu
, wItemID
, wFlags
);
3409 /* Get the Popupmenu to access the owner menu */
3410 if (!(menu
= MENU_GetMenu(hMenu
)))
3413 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3416 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3417 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3419 /* In win95 if the close item in the system menu change update the close button */
3420 if (TWEAK_WineLook
== WIN95_LOOK
)
3421 if((item
->wID
== SC_CLOSE
) && (oldflags
!= wFlags
))
3423 if (menu
->hSysMenuOwner
!= 0)
3425 POPUPMENU
* parentMenu
;
3427 /* Get the parent menu to access*/
3428 if (!(parentMenu
= MENU_GetMenu(menu
->hSysMenuOwner
)))
3431 /* Refresh the frame to reflect the change*/
3432 SetWindowPos(parentMenu
->hWnd
, 0, 0, 0, 0, 0,
3433 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
3441 /*******************************************************************
3442 * GetMenuString16 (USER.161)
3444 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
3445 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
3447 return GetMenuStringA( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3451 /*******************************************************************
3452 * GetMenuStringA (USER32.268)
3454 INT WINAPI
GetMenuStringA(
3455 HMENU hMenu
, /* [in] menuhandle */
3456 UINT wItemID
, /* [in] menu item (dep. on wFlags) */
3457 LPSTR str
, /* [out] outbuffer. If NULL, func returns entry length*/
3458 INT nMaxSiz
, /* [in] length of buffer. if 0, func returns entry len*/
3459 UINT wFlags
/* [in] MF_ flags */
3463 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3464 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3465 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3466 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3467 if (!str
|| !nMaxSiz
) return strlenW(item
->text
);
3469 if (!WideCharToMultiByte( CP_ACP
, 0, item
->text
, -1, str
, nMaxSiz
, NULL
, NULL
))
3471 TRACE("returning '%s'\n", str
);
3476 /*******************************************************************
3477 * GetMenuStringW (USER32.269)
3479 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3480 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3484 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3485 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3486 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3487 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3488 if (!str
|| !nMaxSiz
) return strlenW(item
->text
);
3490 lstrcpynW( str
, item
->text
, nMaxSiz
);
3491 return strlenW(str
);
3495 /**********************************************************************
3496 * HiliteMenuItem16 (USER.162)
3498 BOOL16 WINAPI
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
3501 return HiliteMenuItem( hWnd
, hMenu
, wItemID
, wHilite
);
3505 /**********************************************************************
3506 * HiliteMenuItem (USER32.318)
3508 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3512 TRACE("(%04x, %04x, %04x, %04x);\n",
3513 hWnd
, hMenu
, wItemID
, wHilite
);
3514 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3515 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3516 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3517 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
3518 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
, 0 );
3523 /**********************************************************************
3524 * GetMenuState16 (USER.250)
3526 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3528 return GetMenuState( hMenu
, wItemID
, wFlags
);
3532 /**********************************************************************
3533 * GetMenuState (USER32.267)
3535 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3538 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3539 hMenu
, wItemID
, wFlags
);
3540 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3541 debug_print_menuitem (" item: ", item
, "");
3542 if (item
->fType
& MF_POPUP
)
3544 POPUPMENU
*menu
= MENU_GetMenu( item
->hSubMenu
);
3545 if (!menu
) return -1;
3546 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3550 /* We used to (from way back then) mask the result to 0xff. */
3551 /* I don't know why and it seems wrong as the documented */
3552 /* return flag MF_SEPARATOR is outside that mask. */
3553 return (item
->fType
| item
->fState
);
3558 /**********************************************************************
3559 * GetMenuItemCount16 (USER.263)
3561 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
3563 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3564 if (!menu
) return -1;
3565 TRACE("(%04x) returning %d\n",
3566 hMenu
, menu
->nItems
);
3567 return menu
->nItems
;
3571 /**********************************************************************
3572 * GetMenuItemCount (USER32.262)
3574 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3576 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3577 if (!menu
) return -1;
3578 TRACE("(%04x) returning %d\n",
3579 hMenu
, menu
->nItems
);
3580 return menu
->nItems
;
3583 /**********************************************************************
3584 * GetMenuItemID16 (USER.264)
3586 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
3588 return (UINT16
) GetMenuItemID (hMenu
, nPos
);
3591 /**********************************************************************
3592 * GetMenuItemID (USER32.263)
3594 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3598 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
3599 if (lpmi
->fType
& MF_POPUP
) return -1;
3604 /*******************************************************************
3605 * InsertMenu16 (USER.410)
3607 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3608 UINT16 id
, SEGPTR data
)
3610 UINT pos32
= (UINT
)pos
;
3611 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT
)-1;
3612 if (IS_STRING_ITEM(flags
) && data
)
3613 return InsertMenuA( hMenu
, pos32
, flags
, id
, MapSL(data
) );
3614 return InsertMenuA( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
3618 /*******************************************************************
3619 * InsertMenuW (USER32.325)
3621 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3622 UINT id
, LPCWSTR str
)
3626 if (IS_STRING_ITEM(flags
) && str
)
3627 TRACE("hMenu %04x, pos %d, flags %08x, "
3628 "id %04x, str '%s'\n",
3629 hMenu
, pos
, flags
, id
, debugstr_w(str
) );
3630 else TRACE("hMenu %04x, pos %d, flags %08x, "
3631 "id %04x, str %08lx (not a string)\n",
3632 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3634 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3636 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3638 RemoveMenu( hMenu
, pos
, flags
);
3642 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3643 (MENU_GetMenu((HMENU16
)id
))->wFlags
|= MF_POPUP
;
3645 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3650 /*******************************************************************
3651 * InsertMenuA (USER32.322)
3653 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3654 UINT id
, LPCSTR str
)
3658 if (IS_STRING_ITEM(flags
) && str
)
3660 LPWSTR newstr
= HEAP_strdupAtoW( GetProcessHeap(), 0, str
);
3661 ret
= InsertMenuW( hMenu
, pos
, flags
, id
, newstr
);
3662 HeapFree( GetProcessHeap(), 0, newstr
);
3665 else return InsertMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
3669 /*******************************************************************
3670 * AppendMenu16 (USER.411)
3672 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3674 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3678 /*******************************************************************
3679 * AppendMenuA (USER32.5)
3681 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3682 UINT id
, LPCSTR data
)
3684 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3688 /*******************************************************************
3689 * AppendMenuW (USER32.6)
3691 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3692 UINT id
, LPCWSTR data
)
3694 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3698 /**********************************************************************
3699 * RemoveMenu16 (USER.412)
3701 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3703 return RemoveMenu( hMenu
, nPos
, wFlags
);
3707 /**********************************************************************
3708 * RemoveMenu (USER32.441)
3710 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3715 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu
, nPos
, wFlags
);
3716 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3717 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3721 MENU_FreeItemData( item
);
3723 if (--menu
->nItems
== 0)
3725 HeapFree( SystemHeap
, 0, menu
->items
);
3730 while(nPos
< menu
->nItems
)
3736 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
3737 menu
->nItems
* sizeof(MENUITEM
) );
3743 /**********************************************************************
3744 * DeleteMenu16 (USER.413)
3746 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3748 return DeleteMenu( hMenu
, nPos
, wFlags
);
3752 /**********************************************************************
3753 * DeleteMenu (USER32.129)
3755 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3757 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3758 if (!item
) return FALSE
;
3759 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3760 /* nPos is now the position of the item */
3761 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3766 /*******************************************************************
3767 * ModifyMenu16 (USER.414)
3769 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3770 UINT16 id
, SEGPTR data
)
3772 if (IS_STRING_ITEM(flags
))
3773 return ModifyMenuA( hMenu
, pos
, flags
, id
, MapSL(data
) );
3774 return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3778 /*******************************************************************
3779 * ModifyMenuW (USER32.398)
3781 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3782 UINT id
, LPCWSTR str
)
3786 if (IS_STRING_ITEM(flags
))
3788 TRACE("%04x %d %04x %04x '%s'\n",
3789 hMenu
, pos
, flags
, id
, str
? debugstr_w(str
) : "#NULL#" );
3790 if (!str
) return FALSE
;
3794 TRACE("%04x %d %04x %04x %08lx\n",
3795 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3798 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3799 return MENU_SetItemData( item
, flags
, id
, str
);
3803 /*******************************************************************
3804 * ModifyMenuA (USER32.397)
3806 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3807 UINT id
, LPCSTR str
)
3811 if (IS_STRING_ITEM(flags
) && str
)
3813 LPWSTR newstr
= HEAP_strdupAtoW( GetProcessHeap(), 0, str
);
3814 ret
= ModifyMenuW( hMenu
, pos
, flags
, id
, newstr
);
3815 HeapFree( GetProcessHeap(), 0, newstr
);
3818 else return ModifyMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
3822 /**********************************************************************
3823 * CreatePopupMenu16 (USER.415)
3825 HMENU16 WINAPI
CreatePopupMenu16(void)
3827 return CreatePopupMenu();
3831 /**********************************************************************
3832 * CreatePopupMenu (USER32.82)
3834 HMENU WINAPI
CreatePopupMenu(void)
3839 if (!(hmenu
= CreateMenu())) return 0;
3840 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
3841 menu
->wFlags
|= MF_POPUP
;
3842 menu
->bTimeToHide
= FALSE
;
3847 /**********************************************************************
3848 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3850 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3852 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
3856 /**********************************************************************
3857 * SetMenuItemBitmaps16 (USER.418)
3859 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3860 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3862 return SetMenuItemBitmaps( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3866 /**********************************************************************
3867 * SetMenuItemBitmaps (USER32.490)
3869 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
3870 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
3873 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3874 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3875 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3877 if (!hNewCheck
&& !hNewUnCheck
)
3879 item
->fState
&= ~MF_USECHECKBITMAPS
;
3881 else /* Install new bitmaps */
3883 item
->hCheckBit
= hNewCheck
;
3884 item
->hUnCheckBit
= hNewUnCheck
;
3885 item
->fState
|= MF_USECHECKBITMAPS
;
3891 /**********************************************************************
3892 * CreateMenu16 (USER.151)
3894 HMENU16 WINAPI
CreateMenu16(void)
3896 return CreateMenu();
3900 /**********************************************************************
3901 * CreateMenu (USER32.81)
3903 HMENU WINAPI
CreateMenu(void)
3907 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3908 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3910 ZeroMemory(menu
, sizeof(POPUPMENU
));
3911 menu
->wMagic
= MENU_MAGIC
;
3912 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3913 menu
->bTimeToHide
= FALSE
;
3915 TRACE("return %04x\n", hMenu
);
3921 /**********************************************************************
3922 * DestroyMenu16 (USER.152)
3924 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3926 return DestroyMenu( hMenu
);
3930 /**********************************************************************
3931 * DestroyMenu (USER32.134)
3933 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
3935 TRACE("(%04x)\n", hMenu
);
3937 /* Silently ignore attempts to destroy default system popup */
3939 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3941 LPPOPUPMENU lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3942 WND
*pTPWnd
= MENU_GetTopPopupWnd();
3944 if( pTPWnd
&& (hMenu
== *(HMENU
*)pTPWnd
->wExtra
) )
3945 *(UINT
*)pTPWnd
->wExtra
= 0;
3947 if (!IS_A_MENU(lppop
)) lppop
= NULL
;
3950 lppop
->wMagic
= 0; /* Mark it as destroyed */
3952 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&&
3953 (!pTPWnd
|| (lppop
->hWnd
!= pTPWnd
->hwndSelf
)))
3954 DestroyWindow( lppop
->hWnd
);
3956 if (lppop
->items
) /* recursively destroy submenus */
3959 MENUITEM
*item
= lppop
->items
;
3960 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3962 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
3963 MENU_FreeItemData( item
);
3965 HeapFree( SystemHeap
, 0, lppop
->items
);
3967 USER_HEAP_FREE( hMenu
);
3968 MENU_ReleaseTopPopupWnd();
3972 MENU_ReleaseTopPopupWnd();
3976 return (hMenu
!= MENU_DefSysPopup
);
3980 /**********************************************************************
3981 * GetSystemMenu16 (USER.156)
3983 HMENU16 WINAPI
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
3985 return GetSystemMenu( hWnd
, bRevert
);
3989 /**********************************************************************
3990 * GetSystemMenu (USER32.291)
3992 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
3994 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3999 if( wndPtr
->hSysMenu
)
4003 DestroyMenu(wndPtr
->hSysMenu
);
4004 wndPtr
->hSysMenu
= 0;
4008 POPUPMENU
*menu
= MENU_GetMenu( wndPtr
->hSysMenu
);
4011 if( menu
->nItems
> 0 && menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
4012 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
4016 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
4017 wndPtr
->hSysMenu
, hWnd
);
4018 wndPtr
->hSysMenu
= 0;
4023 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
4024 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU
)(-1) );
4026 if( wndPtr
->hSysMenu
)
4029 retvalue
= GetSubMenu16(wndPtr
->hSysMenu
, 0);
4031 /* Store the dummy sysmenu handle to facilitate the refresh */
4032 /* of the close button if the SC_CLOSE item change */
4033 menu
= MENU_GetMenu(retvalue
);
4035 menu
->hSysMenuOwner
= wndPtr
->hSysMenu
;
4037 WIN_ReleaseWndPtr(wndPtr
);
4039 return bRevert
? 0 : retvalue
;
4043 /*******************************************************************
4044 * SetSystemMenu16 (USER.280)
4046 BOOL16 WINAPI
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
4048 return SetSystemMenu( hwnd
, hMenu
);
4052 /*******************************************************************
4053 * SetSystemMenu (USER32.508)
4055 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
4057 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
4061 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
4062 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
4063 WIN_ReleaseWndPtr(wndPtr
);
4070 /**********************************************************************
4071 * GetMenu16 (USER.157)
4073 HMENU16 WINAPI
GetMenu16( HWND16 hWnd
)
4075 return (HMENU16
)GetMenu(hWnd
);
4079 /**********************************************************************
4080 * GetMenu (USER32.257)
4082 HMENU WINAPI
GetMenu( HWND hWnd
)
4085 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
4087 if (!wndPtr
) return 0;
4089 retvalue
= (HMENU
)wndPtr
->wIDmenu
;
4090 TRACE("for %swindow %04x returning %04x\n",
4091 (wndPtr
->dwStyle
& WS_CHILD
) ? "child " : "", hWnd
, retvalue
);
4092 WIN_ReleaseWndPtr(wndPtr
);
4097 /**********************************************************************
4098 * SetMenu16 (USER.158)
4100 BOOL16 WINAPI
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
4102 return SetMenu( hWnd
, hMenu
);
4106 /**********************************************************************
4107 * SetMenu (USER32.487)
4109 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
4111 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
4114 TRACE("(%04x, %04x);\n", hWnd
, hMenu
);
4116 if (hMenu
&& !IsMenu(hMenu
))
4118 WARN("hMenu is not a menu handle\n");
4122 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
4124 if (GetCapture() == hWnd
) ReleaseCapture();
4126 wndPtr
->wIDmenu
= (UINT
)hMenu
;
4131 if (!(lpmenu
= MENU_GetMenu(hMenu
)))
4134 lpmenu
->hWnd
= hWnd
;
4135 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
4137 if (IsWindowVisible(hWnd
))
4138 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4139 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4143 WIN_ReleaseWndPtr(wndPtr
);
4149 /**********************************************************************
4150 * GetSubMenu16 (USER.159)
4152 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
4154 return GetSubMenu( hMenu
, nPos
);
4158 /**********************************************************************
4159 * GetSubMenu (USER32.288)
4161 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
4165 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
4166 if (!(lpmi
->fType
& MF_POPUP
)) return 0;
4167 return lpmi
->hSubMenu
;
4171 /**********************************************************************
4172 * DrawMenuBar16 (USER.160)
4174 void WINAPI
DrawMenuBar16( HWND16 hWnd
)
4176 DrawMenuBar( hWnd
);
4180 /**********************************************************************
4181 * DrawMenuBar (USER32.161)
4183 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
4186 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
4187 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
4189 lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
);
4192 WIN_ReleaseWndPtr(wndPtr
);
4196 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
4197 lppop
->hwndOwner
= hWnd
;
4198 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4199 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4200 WIN_ReleaseWndPtr(wndPtr
);
4203 WIN_ReleaseWndPtr(wndPtr
);
4208 /***********************************************************************
4209 * EndMenu (USER.187) (USER32.175)
4211 void WINAPI
EndMenu(void)
4213 /* if we are in the menu code, and it is active */
4214 if (fEndMenu
== FALSE
&& MENU_IsMenuActive())
4216 /* terminate the menu handling code */
4219 /* needs to be posted to wakeup the internal menu handler */
4220 /* which will now terminate the menu, in the event that */
4221 /* the main window was minimized, or lost focus, so we */
4222 /* don't end up with an orphaned menu */
4223 PostMessageA( pTopPopupWnd
->hwndSelf
, WM_CANCELMODE
, 0, 0);
4228 /***********************************************************************
4229 * LookupMenuHandle (USER.217)
4231 HMENU16 WINAPI
LookupMenuHandle16( HMENU16 hmenu
, INT16 id
)
4233 HMENU hmenu32
= hmenu
;
4235 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
4236 else return hmenu32
;
4240 /**********************************************************************
4241 * LoadMenu16 (USER.150)
4243 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, LPCSTR name
)
4249 TRACE("(%04x,%s)\n", instance
, debugres_a(name
) );
4253 if (name
[0] == '#') name
= (LPCSTR
)atoi( name
+ 1 );
4256 if (!name
) return 0;
4258 /* check for Win32 module */
4259 if (HIWORD(instance
)) return LoadMenuA( instance
, name
);
4260 instance
= GetExePtr( instance
);
4262 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENUA
))) return 0;
4263 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
4264 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
4265 FreeResource16( handle
);
4270 /*****************************************************************
4271 * LoadMenuA (USER32.370)
4273 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
4275 HRSRC hrsrc
= FindResourceA( instance
, name
, RT_MENUA
);
4276 if (!hrsrc
) return 0;
4277 return LoadMenuIndirectA( (LPCVOID
)LoadResource( instance
, hrsrc
));
4281 /*****************************************************************
4282 * LoadMenuW (USER32.373)
4284 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
4286 HRSRC hrsrc
= FindResourceW( instance
, name
, RT_MENUW
);
4287 if (!hrsrc
) return 0;
4288 return LoadMenuIndirectW( (LPCVOID
)LoadResource( instance
, hrsrc
));
4292 /**********************************************************************
4293 * LoadMenuIndirect16 (USER.220)
4295 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
4298 WORD version
, offset
;
4299 LPCSTR p
= (LPCSTR
)template;
4301 TRACE("(%p)\n", template );
4302 version
= GET_WORD(p
);
4306 WARN("version must be 0 for Win16\n" );
4309 offset
= GET_WORD(p
);
4310 p
+= sizeof(WORD
) + offset
;
4311 if (!(hMenu
= CreateMenu())) return 0;
4312 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
4314 DestroyMenu( hMenu
);
4321 /**********************************************************************
4322 * LoadMenuIndirectA (USER32.371)
4324 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
4327 WORD version
, offset
;
4328 LPCSTR p
= (LPCSTR
)template;
4330 TRACE("%p\n", template );
4331 version
= GET_WORD(p
);
4336 offset
= GET_WORD(p
);
4337 p
+= sizeof(WORD
) + offset
;
4338 if (!(hMenu
= CreateMenu())) return 0;
4339 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
4341 DestroyMenu( hMenu
);
4346 offset
= GET_WORD(p
);
4347 p
+= sizeof(WORD
) + offset
;
4348 if (!(hMenu
= CreateMenu())) return 0;
4349 if (!MENUEX_ParseResource( p
, hMenu
))
4351 DestroyMenu( hMenu
);
4356 ERR("version %d not supported.\n", version
);
4362 /**********************************************************************
4363 * LoadMenuIndirectW (USER32.372)
4365 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
4367 /* FIXME: is there anything different between A and W? */
4368 return LoadMenuIndirectA( template );
4372 /**********************************************************************
4373 * IsMenu16 (USER.358)
4375 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
4377 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4378 return IS_A_MENU(menu
);
4382 /**********************************************************************
4383 * IsMenu (USER32.346)
4385 BOOL WINAPI
IsMenu(HMENU hmenu
)
4387 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4388 return IS_A_MENU(menu
);
4391 /**********************************************************************
4392 * GetMenuItemInfo_common
4395 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
, BOOL bypos
,
4396 LPMENUITEMINFOW lpmii
, BOOL unicode
)
4398 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
4400 debug_print_menuitem("GetMenuItemInfo_common: ", menu
, "");
4405 if (lpmii
->fMask
& MIIM_TYPE
) {
4406 lpmii
->fType
= menu
->fType
;
4407 switch (MENU_ITEM_TYPE(menu
->fType
)) {
4409 break; /* will be done below */
4412 lpmii
->dwTypeData
= menu
->text
;
4419 /* copy the text string */
4420 if ((lpmii
->fMask
& (MIIM_TYPE
|MIIM_STRING
)) &&
4421 (MENU_ITEM_TYPE(menu
->fType
) == MF_STRING
) && menu
->text
)
4426 len
= strlenW(menu
->text
);
4427 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4428 lstrcpynW(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4432 len
= WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1, NULL
, 0, NULL
, NULL
);
4433 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4434 if (!WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1,
4435 (LPSTR
)lpmii
->dwTypeData
, lpmii
->cch
, NULL
, NULL
))
4436 ((LPSTR
)lpmii
->dwTypeData
)[lpmii
->cch
-1] = 0;
4438 /* if we've copied a substring we return its length */
4439 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4441 if (lpmii
->cch
<= len
) lpmii
->cch
--;
4443 else /* return length of string */
4447 if (lpmii
->fMask
& MIIM_FTYPE
)
4448 lpmii
->fType
= menu
->fType
;
4450 if (lpmii
->fMask
& MIIM_BITMAP
)
4451 lpmii
->hbmpItem
= menu
->hbmpItem
;
4453 if (lpmii
->fMask
& MIIM_STATE
)
4454 lpmii
->fState
= menu
->fState
;
4456 if (lpmii
->fMask
& MIIM_ID
)
4457 lpmii
->wID
= menu
->wID
;
4459 if (lpmii
->fMask
& MIIM_SUBMENU
)
4460 lpmii
->hSubMenu
= menu
->hSubMenu
;
4462 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4463 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4464 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4466 if (lpmii
->fMask
& MIIM_DATA
)
4467 lpmii
->dwItemData
= menu
->dwItemData
;
4472 /**********************************************************************
4473 * GetMenuItemInfoA (USER32.264)
4475 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4476 LPMENUITEMINFOA lpmii
)
4478 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4479 (LPMENUITEMINFOW
)lpmii
, FALSE
);
4482 /**********************************************************************
4483 * GetMenuItemInfoW (USER32.265)
4485 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4486 LPMENUITEMINFOW lpmii
)
4488 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4492 /**********************************************************************
4493 * SetMenuItemInfo_common
4496 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4497 const MENUITEMINFOW
*lpmii
,
4500 if (!menu
) return FALSE
;
4502 if (lpmii
->fMask
& MIIM_TYPE
) {
4503 /* Get rid of old string. */
4504 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4505 HeapFree(SystemHeap
, 0, menu
->text
);
4509 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4510 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4511 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4513 menu
->text
= lpmii
->dwTypeData
;
4515 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4517 menu
->text
= HEAP_strdupW(SystemHeap
, 0, lpmii
->dwTypeData
);
4519 menu
->text
= HEAP_strdupAtoW(SystemHeap
, 0, (LPSTR
)lpmii
->dwTypeData
);
4523 if (lpmii
->fMask
& MIIM_FTYPE
) {
4524 /* free the string when the type is changing */
4525 if ( (!IS_STRING_ITEM(lpmii
->fType
)) && IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4526 HeapFree(SystemHeap
, 0, menu
->text
);
4529 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4530 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4533 if (lpmii
->fMask
& MIIM_STRING
) {
4534 /* free the string when used */
4535 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4536 HeapFree(SystemHeap
, 0, menu
->text
);
4538 menu
->text
= HEAP_strdupW(SystemHeap
, 0, lpmii
->dwTypeData
);
4540 menu
->text
= HEAP_strdupAtoW(SystemHeap
, 0, (LPSTR
) lpmii
->dwTypeData
);
4544 if (lpmii
->fMask
& MIIM_STATE
)
4546 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4547 menu
->fState
= lpmii
->fState
;
4550 if (lpmii
->fMask
& MIIM_ID
)
4551 menu
->wID
= lpmii
->wID
;
4553 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4554 menu
->hSubMenu
= lpmii
->hSubMenu
;
4555 if (menu
->hSubMenu
) {
4556 POPUPMENU
*subMenu
= MENU_GetMenu((UINT16
)menu
->hSubMenu
);
4558 subMenu
->wFlags
|= MF_POPUP
;
4559 menu
->fType
|= MF_POPUP
;
4562 /* FIXME: Return an error ? */
4563 menu
->fType
&= ~MF_POPUP
;
4566 menu
->fType
&= ~MF_POPUP
;
4569 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4571 if (lpmii
->fType
& MFT_RADIOCHECK
)
4572 menu
->fType
|= MFT_RADIOCHECK
;
4574 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4575 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4577 if (lpmii
->fMask
& MIIM_DATA
)
4578 menu
->dwItemData
= lpmii
->dwItemData
;
4580 debug_print_menuitem("SetMenuItemInfo_common: ", menu
, "");
4584 /**********************************************************************
4585 * SetMenuItemInfoA (USER32.491)
4587 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4588 const MENUITEMINFOA
*lpmii
)
4590 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4591 (const MENUITEMINFOW
*)lpmii
, FALSE
);
4594 /**********************************************************************
4595 * SetMenuItemInfoW (USER32.492)
4597 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4598 const MENUITEMINFOW
*lpmii
)
4600 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4604 /**********************************************************************
4605 * SetMenuDefaultItem (USER32.489)
4608 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT uItem
, UINT bypos
)
4614 TRACE("(0x%x,%d,%d)\n", hmenu
, uItem
, bypos
);
4616 if (!(menu
= MENU_GetMenu(hmenu
))) return FALSE
;
4618 /* reset all default-item flags */
4620 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4622 item
->fState
&= ~MFS_DEFAULT
;
4625 /* no default item */
4634 if ( uItem
>= menu
->nItems
) return FALSE
;
4635 item
[uItem
].fState
|= MFS_DEFAULT
;
4640 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4642 if (item
->wID
== uItem
)
4644 item
->fState
|= MFS_DEFAULT
;
4653 /**********************************************************************
4654 * GetMenuDefaultItem (USER32.260)
4656 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4662 TRACE("(0x%x,%d,%d)\n", hmenu
, bypos
, flags
);
4664 if (!(menu
= MENU_GetMenu(hmenu
))) return -1;
4666 /* find default item */
4670 if (! item
) return -1;
4672 while ( !( item
->fState
& MFS_DEFAULT
) )
4675 if (i
>= menu
->nItems
) return -1;
4678 /* default: don't return disabled items */
4679 if ( (!(GMDI_USEDISABLED
& flags
)) && (item
->fState
& MFS_DISABLED
)) return -1;
4681 /* search rekursiv when needed */
4682 if ( (item
->fType
& MF_POPUP
) && (flags
& GMDI_GOINTOPOPUPS
) )
4685 ret
= GetMenuDefaultItem( item
->hSubMenu
, bypos
, flags
);
4686 if ( -1 != ret
) return ret
;
4688 /* when item not found in submenu, return the popup item */
4690 return ( bypos
) ? i
: item
->wID
;
4694 /*******************************************************************
4695 * InsertMenuItem16 (USER.441)
4699 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
4700 const MENUITEMINFO16
*mii
)
4704 miia
.cbSize
= sizeof(miia
);
4705 miia
.fMask
= mii
->fMask
;
4706 miia
.dwTypeData
= (LPSTR
)mii
->dwTypeData
;
4707 miia
.fType
= mii
->fType
;
4708 miia
.fState
= mii
->fState
;
4709 miia
.wID
= mii
->wID
;
4710 miia
.hSubMenu
= mii
->hSubMenu
;
4711 miia
.hbmpChecked
= mii
->hbmpChecked
;
4712 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
4713 miia
.dwItemData
= mii
->dwItemData
;
4714 miia
.cch
= mii
->cch
;
4715 if (IS_STRING_ITEM(miia
.fType
))
4716 miia
.dwTypeData
= MapSL(mii
->dwTypeData
);
4717 return InsertMenuItemA( hmenu
, pos
, byposition
, &miia
);
4721 /**********************************************************************
4722 * InsertMenuItemA (USER32.323)
4724 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4725 const MENUITEMINFOA
*lpmii
)
4727 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4728 return SetMenuItemInfo_common(item
, (const MENUITEMINFOW
*)lpmii
, FALSE
);
4732 /**********************************************************************
4733 * InsertMenuItemW (USER32.324)
4735 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4736 const MENUITEMINFOW
*lpmii
)
4738 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4739 return SetMenuItemInfo_common(item
, lpmii
, TRUE
);
4742 /**********************************************************************
4743 * CheckMenuRadioItem (USER32.47)
4746 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
4747 UINT first
, UINT last
, UINT check
,
4750 MENUITEM
*mifirst
, *milast
, *micheck
;
4751 HMENU mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
4753 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4754 hMenu
, first
, last
, check
, bypos
);
4756 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
4757 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
4758 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
4760 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
4761 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
4762 micheck
> milast
|| micheck
< mifirst
)
4765 while (mifirst
<= milast
)
4767 if (mifirst
== micheck
)
4769 mifirst
->fType
|= MFT_RADIOCHECK
;
4770 mifirst
->fState
|= MFS_CHECKED
;
4772 mifirst
->fType
&= ~MFT_RADIOCHECK
;
4773 mifirst
->fState
&= ~MFS_CHECKED
;
4781 /**********************************************************************
4782 * CheckMenuRadioItem16 (not a Windows API)
4785 BOOL16 WINAPI
CheckMenuRadioItem16(HMENU16 hMenu
,
4786 UINT16 first
, UINT16 last
, UINT16 check
,
4789 return CheckMenuRadioItem (hMenu
, first
, last
, check
, bypos
);
4792 /**********************************************************************
4793 * GetMenuItemRect (USER32.266)
4795 * ATTENTION: Here, the returned values in rect are the screen
4796 * coordinates of the item just like if the menu was
4797 * always on the upper left side of the application.
4800 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
4803 POPUPMENU
*itemMenu
;
4807 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
4809 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
4810 referenceHwnd
= hwnd
;
4814 itemMenu
= MENU_GetMenu(hMenu
);
4815 if (itemMenu
== NULL
)
4818 if(itemMenu
->hWnd
== 0)
4820 referenceHwnd
= itemMenu
->hWnd
;
4823 if ((rect
== NULL
) || (item
== NULL
))
4828 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
4833 /**********************************************************************
4834 * GetMenuItemRect16 (USER.665)
4837 BOOL16 WINAPI
GetMenuItemRect16 (HWND16 hwnd
, HMENU16 hMenu
, UINT16 uItem
,
4843 if (!rect
) return FALSE
;
4844 res
= GetMenuItemRect (hwnd
, hMenu
, uItem
, &r32
);
4845 CONV_RECT32TO16 (&r32
, rect
);
4849 /**********************************************************************
4853 * MIM_APPLYTOSUBMENUS
4854 * actually use the items to draw the menu
4856 BOOL WINAPI
SetMenuInfo (HMENU hMenu
, LPCMENUINFO lpmi
)
4860 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4862 if (lpmi
&& (lpmi
->cbSize
==sizeof(MENUINFO
)) && (menu
= MENU_GetMenu(hMenu
)))
4865 if (lpmi
->fMask
& MIM_BACKGROUND
)
4866 menu
->hbrBack
= lpmi
->hbrBack
;
4868 if (lpmi
->fMask
& MIM_HELPID
)
4869 menu
->dwContextHelpID
= lpmi
->dwContextHelpID
;
4871 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4872 menu
->cyMax
= lpmi
->cyMax
;
4874 if (lpmi
->fMask
& MIM_MENUDATA
)
4875 menu
->dwMenuData
= lpmi
->dwMenuData
;
4877 if (lpmi
->fMask
& MIM_STYLE
)
4878 menu
->dwStyle
= lpmi
->dwStyle
;
4885 /**********************************************************************
4892 BOOL WINAPI
GetMenuInfo (HMENU hMenu
, LPMENUINFO lpmi
)
4895 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4897 if (lpmi
&& (menu
= MENU_GetMenu(hMenu
)))
4900 if (lpmi
->fMask
& MIM_BACKGROUND
)
4901 lpmi
->hbrBack
= menu
->hbrBack
;
4903 if (lpmi
->fMask
& MIM_HELPID
)
4904 lpmi
->dwContextHelpID
= menu
->dwContextHelpID
;
4906 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4907 lpmi
->cyMax
= menu
->cyMax
;
4909 if (lpmi
->fMask
& MIM_MENUDATA
)
4910 lpmi
->dwMenuData
= menu
->dwMenuData
;
4912 if (lpmi
->fMask
& MIM_STYLE
)
4913 lpmi
->dwStyle
= menu
->dwStyle
;
4920 /**********************************************************************
4921 * SetMenuContextHelpId16 (USER.384)
4923 BOOL16 WINAPI
SetMenuContextHelpId16( HMENU16 hMenu
, DWORD dwContextHelpID
)
4925 return SetMenuContextHelpId( hMenu
, dwContextHelpID
);
4929 /**********************************************************************
4930 * SetMenuContextHelpId (USER32.488)
4932 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpID
)
4936 TRACE("(0x%04x 0x%08lx)\n", hMenu
, dwContextHelpID
);
4938 if ((menu
= MENU_GetMenu(hMenu
)))
4940 menu
->dwContextHelpID
= dwContextHelpID
;
4946 /**********************************************************************
4947 * GetMenuContextHelpId16 (USER.385)
4949 DWORD WINAPI
GetMenuContextHelpId16( HMENU16 hMenu
)
4951 return GetMenuContextHelpId( hMenu
);
4954 /**********************************************************************
4955 * GetMenuContextHelpId (USER32.488)
4957 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
4961 TRACE("(0x%04x)\n", hMenu
);
4963 if ((menu
= MENU_GetMenu(hMenu
)))
4965 return menu
->dwContextHelpID
;
4970 /**********************************************************************
4971 * MenuItemFromPoint (USER32.387)
4973 UINT WINAPI
MenuItemFromPoint(HWND hWnd
, HMENU hMenu
, POINT ptScreen
)
4975 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4976 hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4981 /**********************************************************************
4982 * translate_accelerator
4984 static BOOL
translate_accelerator( HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
,
4985 BYTE fVirt
, WORD key
, WORD cmd
)
4989 if (wParam
!= key
) return FALSE
;
4991 if (message
== WM_CHAR
)
4993 if ( !(fVirt
& FALT
) && !(fVirt
& FVIRTKEY
) )
4995 TRACE_(accel
)("found accel for WM_CHAR: ('%c')\n", wParam
& 0xff);
5001 if(fVirt
& FVIRTKEY
)
5004 TRACE_(accel
)("found accel for virt_key %04x (scan %04x)\n",
5005 wParam
, 0xff & HIWORD(lParam
));
5006 if(GetKeyState(VK_SHIFT
) & 0x8000) mask
|= FSHIFT
;
5007 if(GetKeyState(VK_CONTROL
) & 0x8000) mask
|= FCONTROL
;
5008 if(GetKeyState(VK_MENU
) & 0x8000) mask
|= FALT
;
5009 if(mask
== (fVirt
& (FSHIFT
| FCONTROL
| FALT
))) goto found
;
5010 TRACE_(accel
)(", but incorrect SHIFT/CTRL/ALT-state\n");
5014 if (!(lParam
& 0x01000000)) /* no special_key */
5016 if ((fVirt
& FALT
) && (lParam
& 0x20000000))
5017 { /* ^^ ALT pressed */
5018 TRACE_(accel
)("found accel for Alt-%c\n", wParam
& 0xff);
5027 if (message
== WM_KEYUP
|| message
== WM_SYSKEYUP
)
5029 else if (GetCapture())
5031 else if (!IsWindowEnabled(hWnd
))
5035 HMENU hMenu
, hSubMenu
, hSysMenu
;
5036 UINT uSysStat
= (UINT
)-1, uStat
= (UINT
)-1, nPos
;
5037 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
5039 hMenu
= (wndPtr
->dwStyle
& WS_CHILD
) ? 0 : (HMENU
)wndPtr
->wIDmenu
;
5040 hSysMenu
= wndPtr
->hSysMenu
;
5041 WIN_ReleaseWndPtr(wndPtr
);
5043 /* find menu item and ask application to initialize it */
5044 /* 1. in the system menu */
5045 hSubMenu
= hSysMenu
;
5047 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
5049 SendMessageA(hWnd
, WM_INITMENU
, (WPARAM
)hSysMenu
, 0L);
5050 if(hSubMenu
!= hSysMenu
)
5052 nPos
= MENU_FindSubMenu(&hSysMenu
, hSubMenu
);
5053 TRACE_(accel
)("hSysMenu = %04x, hSubMenu = %04x, nPos = %d\n", hSysMenu
, hSubMenu
, nPos
);
5054 SendMessageA(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, TRUE
));
5056 uSysStat
= GetMenuState(GetSubMenu(hSysMenu
, 0), cmd
, MF_BYCOMMAND
);
5058 else /* 2. in the window's menu */
5062 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
5064 SendMessageA(hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0L);
5065 if(hSubMenu
!= hMenu
)
5067 nPos
= MENU_FindSubMenu(&hMenu
, hSubMenu
);
5068 TRACE_(accel
)("hMenu = %04x, hSubMenu = %04x, nPos = %d\n", hMenu
, hSubMenu
, nPos
);
5069 SendMessageA(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, FALSE
));
5071 uStat
= GetMenuState(hMenu
, cmd
, MF_BYCOMMAND
);
5075 if (uSysStat
!= (UINT
)-1)
5077 if (uSysStat
& (MF_DISABLED
|MF_GRAYED
))
5084 if (uStat
!= (UINT
)-1)
5090 if (uStat
& (MF_DISABLED
|MF_GRAYED
))
5101 if( mesg
==WM_COMMAND
)
5103 TRACE_(accel
)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd
);
5104 SendMessageA(hWnd
, mesg
, 0x10000 | cmd
, 0L);
5106 else if( mesg
==WM_SYSCOMMAND
)
5108 TRACE_(accel
)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd
);
5109 SendMessageA(hWnd
, mesg
, cmd
, 0x00010000L
);
5113 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
5114 * #0: unknown (please report!)
5115 * #1: for WM_KEYUP,WM_SYSKEYUP
5116 * #2: mouse is captured
5117 * #3: window is disabled
5118 * #4: it's a disabled system menu option
5119 * #5: it's a menu option, but window is iconic
5120 * #6: it's a menu option, but disabled
5122 TRACE_(accel
)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg
);
5124 ERR_(accel
)(" unknown reason - please report!");
5129 /**********************************************************************
5130 * TranslateAccelerator (USER32.551)(USER32.552)(USER32.553)
5132 INT WINAPI
TranslateAccelerator( HWND hWnd
, HACCEL hAccel
, LPMSG msg
)
5135 LPACCEL16 lpAccelTbl
;
5140 WARN_(accel
)("msg null; should hang here to be win compatible\n");
5143 if (!hAccel
|| !(lpAccelTbl
= (LPACCEL16
) LockResource16(hAccel
)))
5145 WARN_(accel
)("invalid accel handle=%x\n", hAccel
);
5148 if ((msg
->message
!= WM_KEYDOWN
&&
5149 msg
->message
!= WM_KEYUP
&&
5150 msg
->message
!= WM_SYSKEYDOWN
&&
5151 msg
->message
!= WM_SYSKEYUP
&&
5152 msg
->message
!= WM_CHAR
)) return 0;
5154 TRACE_(accel
)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5155 "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
5156 hAccel
,hWnd
,msg
->hwnd
,msg
->message
,msg
->wParam
,msg
->lParam
);
5161 if (translate_accelerator( hWnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
5162 lpAccelTbl
[i
].fVirt
, lpAccelTbl
[i
].key
, lpAccelTbl
[i
].cmd
))
5164 } while ((lpAccelTbl
[i
++].fVirt
& 0x80) == 0);
5165 WARN_(accel
)("couldn't translate accelerator key\n");
5170 /**********************************************************************
5171 * TranslateAccelerator16 (USER.178)
5173 INT16 WINAPI
TranslateAccelerator16( HWND16 hWnd
, HACCEL16 hAccel
, LPMSG16 msg
)
5175 LPACCEL16 lpAccelTbl
;
5180 WARN_(accel
)("msg null; should hang here to be win compatible\n");
5183 if (!hAccel
|| !(lpAccelTbl
= (LPACCEL16
) LockResource16(hAccel
)))
5185 WARN_(accel
)("invalid accel handle=%x\n", hAccel
);
5188 if ((msg
->message
!= WM_KEYDOWN
&&
5189 msg
->message
!= WM_KEYUP
&&
5190 msg
->message
!= WM_SYSKEYDOWN
&&
5191 msg
->message
!= WM_SYSKEYUP
&&
5192 msg
->message
!= WM_CHAR
)) return 0;
5194 TRACE_(accel
)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5195 "msg->hwnd=%04x, msg->message=%04x, wParam=%04x, lParam=%lx\n",
5196 hAccel
,hWnd
,msg
->hwnd
,msg
->message
,msg
->wParam
,msg
->lParam
);
5201 if (translate_accelerator( hWnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
5202 lpAccelTbl
[i
].fVirt
, lpAccelTbl
[i
].key
, lpAccelTbl
[i
].cmd
))
5204 } while ((lpAccelTbl
[i
++].fVirt
& 0x80) == 0);
5205 WARN_(accel
)("couldn't translate accelerator key\n");