blob: 7ad400ccc375ae25c58afef9fe56b28013b17717 [file] [log] [blame]
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001/*
Alexandre Julliard7cbe6571995-01-09 18:21:16 +00002 * Menu functions
3 *
4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00006 * Copyright 1997 Morten Welinder
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00007 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliard7cbe6571995-01-09 18:21:16 +000021 */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +000022
23/*
24 * Note: the style MF_MOUSESELECT is used to mark popup items that
25 * have been selected, i.e. their popup menu is currently displayed.
26 * This is probably not the meaning this style has in MS-Windows.
27 */
Alexandre Julliard401710d1993-09-04 10:09:32 +000028
François Gouget14259412001-11-06 20:57:11 +000029#include "config.h"
Francois Gouget386cf6e2001-10-14 16:25:47 +000030#include "wine/port.h"
31
Alexandre Julliard7ff1c411997-05-25 13:58:18 +000032#include <assert.h>
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +000033#include <ctype.h>
Alexandre Julliard8d24ae61994-04-05 21:42:43 +000034#include <stdlib.h>
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +000035#include <string.h>
Francois Boisvert85dd9fc1999-02-17 12:50:11 +000036
Jeremy Whited3e22d92000-02-10 19:03:02 +000037#include "windef.h"
Alexandre Julliard24a62ab2000-11-28 22:40:56 +000038#include "winnls.h"
Jeremy Whited3e22d92000-02-10 19:03:02 +000039#include "wingdi.h"
Francois Boisvert85dd9fc1999-02-17 12:50:11 +000040#include "wine/winbase16.h"
Michael Veksler3fbb8dc1999-02-21 18:23:26 +000041#include "wine/winuser16.h"
Alexandre Julliard24a62ab2000-11-28 22:40:56 +000042#include "wine/unicode.h"
Jeremy Whited3e22d92000-02-10 19:03:02 +000043#include "win.h"
Alexandre Julliard91222da2000-12-10 23:01:33 +000044#include "controls.h"
Alexandre Julliardc6c09441997-01-12 18:32:19 +000045#include "nonclient.h"
Alexandre Julliard1f579291994-05-25 16:25:21 +000046#include "user.h"
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +000047#include "message.h"
Marcus Meissnerd5e7c791998-12-09 11:06:00 +000048
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000049#include "wine/debug.h"
Alexandre Julliardaca05781994-10-17 18:12:41 +000050
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000051WINE_DEFAULT_DEBUG_CHANNEL(menu);
52WINE_DECLARE_DEBUG_CHANNEL(accel);
Alexandre Julliardd37eb361997-07-20 16:23:21 +000053
Alexandre Julliard7ff1c411997-05-25 13:58:18 +000054/* internal popup menu window messages */
55
56#define MM_SETMENUHANDLE (WM_USER + 0)
57#define MM_GETMENUHANDLE (WM_USER + 1)
58
Alexandre Julliard2d93d001996-05-21 15:01:41 +000059/* Menu item structure */
Alexandre Julliard670cdc41997-08-24 16:00:30 +000060typedef struct {
61 /* ----------- MENUITEMINFO Stuff ----------- */
Juergen Schmied78513941999-04-18 14:40:32 +000062 UINT fType; /* Item type. */
Alexandre Julliarda3960291999-02-26 11:11:13 +000063 UINT fState; /* Item state. */
64 UINT wID; /* Item id. */
65 HMENU hSubMenu; /* Pop-up menu. */
Juergen Schmied78513941999-04-18 14:40:32 +000066 HBITMAP hCheckBit; /* Bitmap when checked. */
Alexandre Julliarda3960291999-02-26 11:11:13 +000067 HBITMAP hUnCheckBit; /* Bitmap when unchecked. */
Aric Stewartc946b1c2000-10-24 21:28:19 +000068 LPWSTR text; /* Item text or bitmap handle. */
Alexandre Julliard670cdc41997-08-24 16:00:30 +000069 DWORD dwItemData; /* Application defined. */
Juergen Schmied78513941999-04-18 14:40:32 +000070 DWORD dwTypeData; /* depends on fMask */
71 HBITMAP hbmpItem; /* bitmap in win98 style menus */
Alexandre Julliard670cdc41997-08-24 16:00:30 +000072 /* ----------- Wine stuff ----------- */
Juergen Schmied78513941999-04-18 14:40:32 +000073 RECT rect; /* Item area (relative to menu window) */
74 UINT xTab; /* X position of text after Tab */
Alexandre Julliard2d93d001996-05-21 15:01:41 +000075} MENUITEM;
76
77/* Popup menu structure */
Alexandre Julliard670cdc41997-08-24 16:00:30 +000078typedef struct {
Alexandre Julliard2d93d001996-05-21 15:01:41 +000079 WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
80 WORD wMagic; /* Magic number */
Alexandre Julliard2d93d001996-05-21 15:01:41 +000081 WORD Width; /* Width of the whole menu */
82 WORD Height; /* Height of the whole menu */
Alexandre Julliarde60ccd12001-05-11 20:05:42 +000083 UINT nItems; /* Number of items in the menu */
Juergen Schmied78513941999-04-18 14:40:32 +000084 HWND hWnd; /* Window containing the menu */
85 MENUITEM *items; /* Array of menu items */
86 UINT FocusedItem; /* Currently focused item */
Juergen Schmied466a6521999-05-02 11:21:08 +000087 HWND hwndOwner; /* window receiving the messages for ownerdraw */
Pascal Lessard2eb0a301999-09-03 16:38:52 +000088 BOOL bTimeToHide; /* Request hiding when receiving a second click in the top-level menu item */
Juergen Schmied78513941999-04-18 14:40:32 +000089 /* ------------ MENUINFO members ------ */
90 DWORD dwStyle; /* Extended mennu style */
91 UINT cyMax; /* max hight of the whole menu, 0 is screen hight */
92 HBRUSH hbrBack; /* brush for menu background */
93 DWORD dwContextHelpID;
94 DWORD dwMenuData; /* application defined value */
Pascal Lessardd814bb61999-07-31 13:02:02 +000095 HMENU hSysMenuOwner; /* Handle to the dummy sys menu holder */
Alexandre Julliard2d93d001996-05-21 15:01:41 +000096} POPUPMENU, *LPPOPUPMENU;
97
Alexandre Julliard7ff1c411997-05-25 13:58:18 +000098/* internal flags for menu tracking */
99
100#define TF_ENDMENU 0x0001
101#define TF_SUSPENDPOPUP 0x0002
102#define TF_SKIPREMOVE 0x0004
103
104typedef struct
105{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000106 UINT trackFlags;
107 HMENU hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
108 HMENU hTopMenu; /* initial menu */
109 HWND hOwnerWnd; /* where notifications are sent */
110 POINT pt;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000111} MTRACKER;
112
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000113#define MENU_MAGIC 0x554d /* 'MU' */
114
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000115#define ITEM_PREV -1
116#define ITEM_NEXT 1
117
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000118 /* Internal MENU_TrackMenu() flags */
119#define TPM_INTERNAL 0xF0000000
120#define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
121#define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
Francois Boisvert85dd9fc1999-02-17 12:50:11 +0000122#define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
Alexandre Julliardf7207251994-07-23 07:57:48 +0000123
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000124 /* popup menu shade thickness */
125#define POPUP_XSHADE 4
126#define POPUP_YSHADE 4
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000127
Alexandre Julliardf7207251994-07-23 07:57:48 +0000128 /* Space between 2 menu bar items */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000129#define MENU_BAR_ITEMS_SPACE 12
Alexandre Julliardf7207251994-07-23 07:57:48 +0000130
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000131 /* Minimum width of a tab character */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000132#define MENU_TAB_SPACE 8
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000133
Alexandre Julliardf7207251994-07-23 07:57:48 +0000134 /* Height of a separator item */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000135#define SEPARATOR_HEIGHT 5
Alexandre Julliardf7207251994-07-23 07:57:48 +0000136
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000137 /* (other menu->FocusedItem values give the position of the focused item) */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000138#define NO_SELECTED_ITEM 0xffff
Alexandre Julliardcdd09231994-01-12 11:12:51 +0000139
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000140#define MENU_ITEM_TYPE(flags) \
141 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
142
143#define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
Juergen Schmied78513941999-04-18 14:40:32 +0000144#define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
François Gouget75b278e2001-01-06 01:45:51 +0000145#define IS_MAGIC_ITEM(text) (LOWORD((int)text)<12)
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000146
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000147#define IS_SYSTEM_MENU(menu) \
148 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
Juergen Schmied78513941999-04-18 14:40:32 +0000149
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000150#define IS_SYSTEM_POPUP(menu) \
151 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
152
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000153#define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
154 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
155 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
156 MF_POPUP | MF_SYSMENU | MF_HELP)
157#define STATE_MASK (~TYPE_MASK)
158
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000159 /* Dimension of the menu bitmaps */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000160static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000161
Alexandre Julliarda3960291999-02-26 11:11:13 +0000162static HBITMAP hStdMnArrow = 0;
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000163static HBITMAP hBmpSysMenu = 0;
Francois Boisvert8b391741999-02-09 14:09:55 +0000164
Juergen Schmied78513941999-04-18 14:40:32 +0000165static HBRUSH hShadeBrush = 0;
166static HFONT hMenuFont = 0;
Juergen Schmied466a6521999-05-02 11:21:08 +0000167static HFONT hMenuFontBold = 0;
Juergen Schmied78513941999-04-18 14:40:32 +0000168
Alexandre Julliarda3960291999-02-26 11:11:13 +0000169static HMENU MENU_DefSysPopup = 0; /* Default system menu popup */
Alexandre Julliard1285c2f1996-05-06 16:06:24 +0000170
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000171/* Use global popup window because there's no way 2 menus can
172 * be tracked at the same time. */
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000173static HWND top_popup;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000174
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000175 /* Flag set by EndMenu() to force an exit from menu tracking */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000176static BOOL fEndMenu = FALSE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000177
Alexandre Julliard91222da2000-12-10 23:01:33 +0000178static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
179
180
181/*********************************************************************
182 * menu class descriptor
183 */
184const struct builtin_class_descr MENU_builtin_class =
185{
186 POPUPMENU_CLASS_ATOM, /* name */
187 CS_GLOBALCLASS | CS_SAVEBITS, /* style */
188 NULL, /* procA (winproc is Unicode only) */
189 PopupMenuWndProc, /* procW */
190 sizeof(HMENU), /* extra */
191 IDC_ARROWA, /* cursor */
192 COLOR_MENU+1 /* brush */
193};
194
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000195
196/***********************************************************************
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000197 * debug_print_menuitem
198 *
199 * Print a menuitem in readable form.
200 */
201
Alexandre Julliard03468f71998-02-15 19:40:49 +0000202#define debug_print_menuitem(pre, mp, post) \
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000203 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
Alexandre Julliard03468f71998-02-15 19:40:49 +0000204
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000205#define MENUOUT(text) \
Alexandre Julliard15de6151999-08-04 12:22:42 +0000206 DPRINTF("%s%s", (count++ ? "," : ""), (text))
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000207
208#define MENUFLAG(bit,text) \
209 do { \
210 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
211 } while (0)
212
Alexandre Julliard03468f71998-02-15 19:40:49 +0000213static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
214 const char *postfix)
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000215{
Alexandre Julliard15de6151999-08-04 12:22:42 +0000216 TRACE("%s ", prefix);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000217 if (mp) {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000218 UINT flags = mp->fType;
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000219 int typ = MENU_ITEM_TYPE(flags);
Alexandre Julliard15de6151999-08-04 12:22:42 +0000220 DPRINTF( "{ ID=0x%x", mp->wID);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000221 if (flags & MF_POPUP)
Alexandre Julliard15de6151999-08-04 12:22:42 +0000222 DPRINTF( ", Sub=0x%x", mp->hSubMenu);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000223 if (flags) {
224 int count = 0;
Alexandre Julliard15de6151999-08-04 12:22:42 +0000225 DPRINTF( ", Typ=");
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000226 if (typ == MFT_STRING)
227 /* Nothing */ ;
228 else if (typ == MFT_SEPARATOR)
229 MENUOUT("sep");
230 else if (typ == MFT_OWNERDRAW)
231 MENUOUT("own");
232 else if (typ == MFT_BITMAP)
233 MENUOUT("bit");
234 else
235 MENUOUT("???");
236 flags -= typ;
237
238 MENUFLAG(MF_POPUP, "pop");
239 MENUFLAG(MFT_MENUBARBREAK, "barbrk");
240 MENUFLAG(MFT_MENUBREAK, "brk");
241 MENUFLAG(MFT_RADIOCHECK, "radio");
242 MENUFLAG(MFT_RIGHTORDER, "rorder");
243 MENUFLAG(MF_SYSMENU, "sys");
Juergen Schmiedcd0ed1e1999-04-26 14:54:38 +0000244 MENUFLAG(MFT_RIGHTJUSTIFY, "right"); /* same as MF_HELP */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000245
246 if (flags)
Alexandre Julliard15de6151999-08-04 12:22:42 +0000247 DPRINTF( "+0x%x", flags);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000248 }
249 flags = mp->fState;
250 if (flags) {
251 int count = 0;
Alexandre Julliard15de6151999-08-04 12:22:42 +0000252 DPRINTF( ", State=");
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000253 MENUFLAG(MFS_GRAYED, "grey");
Juergen Schmied466a6521999-05-02 11:21:08 +0000254 MENUFLAG(MFS_DEFAULT, "default");
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000255 MENUFLAG(MFS_DISABLED, "dis");
256 MENUFLAG(MFS_CHECKED, "check");
257 MENUFLAG(MFS_HILITE, "hi");
258 MENUFLAG(MF_USECHECKBITMAPS, "usebit");
259 MENUFLAG(MF_MOUSESELECT, "mouse");
260 if (flags)
Alexandre Julliard15de6151999-08-04 12:22:42 +0000261 DPRINTF( "+0x%x", flags);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000262 }
263 if (mp->hCheckBit)
Alexandre Julliard15de6151999-08-04 12:22:42 +0000264 DPRINTF( ", Chk=0x%x", mp->hCheckBit);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000265 if (mp->hUnCheckBit)
Alexandre Julliard15de6151999-08-04 12:22:42 +0000266 DPRINTF( ", Unc=0x%x", mp->hUnCheckBit);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000267
268 if (typ == MFT_STRING) {
269 if (mp->text)
François Gougetb99367e2001-02-14 21:42:10 +0000270 DPRINTF( ", Text=%s", debugstr_w(mp->text));
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000271 else
Alexandre Julliard15de6151999-08-04 12:22:42 +0000272 DPRINTF( ", Text=Null");
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000273 } else if (mp->text == NULL)
274 /* Nothing */ ;
275 else
Alexandre Julliard15de6151999-08-04 12:22:42 +0000276 DPRINTF( ", Text=%p", mp->text);
Juergen Schmied7abca951999-04-11 17:02:30 +0000277 if (mp->dwItemData)
Alexandre Julliard15de6151999-08-04 12:22:42 +0000278 DPRINTF( ", ItemData=0x%08lx", mp->dwItemData);
279 DPRINTF( " }");
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000280 } else {
Alexandre Julliard15de6151999-08-04 12:22:42 +0000281 DPRINTF( "NULL");
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000282 }
Alexandre Julliard03468f71998-02-15 19:40:49 +0000283
Alexandre Julliard15de6151999-08-04 12:22:42 +0000284 DPRINTF(" %s\n", postfix);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000285}
286
287#undef MENUOUT
288#undef MENUFLAG
289
Gerard Patel3e629742000-01-17 22:22:16 +0000290
291/***********************************************************************
292 * MENU_GetMenu
293 *
294 * Validate the given menu handle and returns the menu structure pointer.
295 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000296static POPUPMENU *MENU_GetMenu(HMENU hMenu)
Gerard Patel3e629742000-01-17 22:22:16 +0000297{
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000298 POPUPMENU *menu = USER_HEAP_LIN_ADDR(hMenu);
299 if (!menu || menu->wMagic != MENU_MAGIC)
Gerard Patel3e629742000-01-17 22:22:16 +0000300 {
Gerard Patelc6369b02000-05-14 22:52:52 +0000301 WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
Gerard Patel3e629742000-01-17 22:22:16 +0000302 menu = NULL;
303 }
304 return menu;
305}
306
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000307/***********************************************************************
Alexandre Julliardde424282001-08-10 22:51:42 +0000308 * get_win_sys_menu
309 *
310 * Get the system menu of a window
311 */
312static HMENU get_win_sys_menu( HWND hwnd )
313{
314 HMENU ret = 0;
315 WND *win = WIN_FindWndPtr( hwnd );
316 if (win)
317 {
318 ret = win->hSysMenu;
319 WIN_ReleaseWndPtr( win );
320 }
321 return ret;
322}
323
324/***********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000325 * MENU_CopySysPopup
326 *
327 * Return the default system menu.
328 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000329static HMENU MENU_CopySysPopup(void)
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000330{
Bertho Stultiensd1895a71999-04-25 18:31:35 +0000331 HMENU hMenu = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000332
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000333 if( hMenu ) {
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000334 POPUPMENU* menu = MENU_GetMenu(hMenu);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000335 menu->wFlags |= MF_SYSMENU | MF_POPUP;
Juergen Schmied49251861999-05-13 18:42:03 +0000336 SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000337 }
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000338 else
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000339 ERR("Unable to load default system menu\n" );
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000340
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000341 TRACE("returning %x.\n", hMenu );
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000342
343 return hMenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000344}
345
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000346
347/**********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000348 * MENU_GetSysMenu
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000349 *
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000350 * Create a copy of the system menu. System menu in Windows is
Andreas Mohra6d83eb2000-12-27 04:02:46 +0000351 * a special menu bar with the single entry - system menu popup.
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000352 * This popup is presented to the outside world as a "system menu".
353 * However, the real system menu handle is sometimes seen in the
Andreas Mohra6d83eb2000-12-27 04:02:46 +0000354 * WM_MENUSELECT parameters (and Word 6 likes it this way).
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000355 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000356HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000357{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000358 HMENU hMenu;
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000359
Alexandre Julliarda3960291999-02-26 11:11:13 +0000360 if ((hMenu = CreateMenu()))
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000361 {
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000362 POPUPMENU *menu = MENU_GetMenu(hMenu);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000363 menu->wFlags = MF_SYSMENU;
Alexandre Julliardf44bbb82001-09-14 00:24:39 +0000364 menu->hWnd = WIN_GetFullHandle( hWnd );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000365
Alexandre Julliarda3960291999-02-26 11:11:13 +0000366 if (hPopupMenu == (HMENU)(-1))
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000367 hPopupMenu = MENU_CopySysPopup();
368 else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup;
369
370 if (hPopupMenu)
371 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000372 InsertMenuA( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION, hPopupMenu, NULL );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000373
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000374 menu->items[0].fType = MF_SYSMENU | MF_POPUP;
375 menu->items[0].fState = 0;
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000376 if ((menu = MENU_GetMenu(hPopupMenu))) menu->wFlags |= MF_SYSMENU;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000377
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000378 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000379 return hMenu;
380 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000381 DestroyMenu( hMenu );
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000382 }
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000383 ERR("failed to load system menu!\n");
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000384 return 0;
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000385}
386
387
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000388/***********************************************************************
389 * MENU_Init
390 *
391 * Menus initialisation.
392 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000393BOOL MENU_Init()
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000394{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000395 HBITMAP hBitmap;
Juergen Schmied78513941999-04-18 14:40:32 +0000396 NONCLIENTMETRICSA ncm;
397
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000398 static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
399 0x55, 0, 0xAA, 0,
400 0x55, 0, 0xAA, 0,
401 0x55, 0, 0xAA, 0 };
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000402
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000403 /* Load menu bitmaps */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000404 hStdMnArrow = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW));
Francois Boisvert8b391741999-02-09 14:09:55 +0000405 /* Load system buttons bitmaps */
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000406 hBmpSysMenu = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CLOSE));
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000407
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000408 if (hStdMnArrow)
Juergen Schmied78513941999-04-18 14:40:32 +0000409 {
410 BITMAP bm;
411 GetObjectA( hStdMnArrow, sizeof(bm), &bm );
412 arrow_bitmap_width = bm.bmWidth;
413 arrow_bitmap_height = bm.bmHeight;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000414 } else
Juergen Schmied78513941999-04-18 14:40:32 +0000415 return FALSE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000416
Juergen Schmied78513941999-04-18 14:40:32 +0000417 if (! (hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits)))
418 return FALSE;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000419
Juergen Schmied78513941999-04-18 14:40:32 +0000420 if(!(hShadeBrush = CreatePatternBrush( hBitmap )))
421 return FALSE;
422
423 DeleteObject( hBitmap );
424 if (!(MENU_DefSysPopup = MENU_CopySysPopup()))
425 return FALSE;
426
427 ncm.cbSize = sizeof (NONCLIENTMETRICSA);
428 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &ncm, 0)))
429 return FALSE;
430
431 if (!(hMenuFont = CreateFontIndirectA( &ncm.lfMenuFont )))
432 return FALSE;
433
Juergen Schmied466a6521999-05-02 11:21:08 +0000434 ncm.lfMenuFont.lfWeight += 300;
435 if ( ncm.lfMenuFont.lfWeight > 1000)
436 ncm.lfMenuFont.lfWeight = 1000;
437
438 if (!(hMenuFontBold = CreateFontIndirectA( &ncm.lfMenuFont )))
439 return FALSE;
440
Juergen Schmied78513941999-04-18 14:40:32 +0000441 return TRUE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000442}
443
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000444/***********************************************************************
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000445 * MENU_InitSysMenuPopup
446 *
447 * Grey the appropriate items in System menu.
448 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000449static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000450{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000451 BOOL gray;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000452
453 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
Alexandre Julliarda3960291999-02-26 11:11:13 +0000454 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000455 gray = ((style & WS_MAXIMIZE) != 0);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000456 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000457 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000458 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000459 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000460 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000461 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
Alexandre Julliarda3960291999-02-26 11:11:13 +0000462 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000463 gray = (clsStyle & CS_NOCLOSE) != 0;
Pascal Lessardd814bb61999-07-31 13:02:02 +0000464
465 /* The menu item must keep its state if it's disabled */
466 if(gray)
467 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000468}
469
470
Alexandre Julliard641ee761997-08-04 16:34:36 +0000471/******************************************************************************
472 *
Patrik Stridvall2d6457c2000-03-28 20:22:59 +0000473 * UINT MENU_GetStartOfNextColumn(
474 * HMENU hMenu )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000475 *
476 *****************************************************************************/
477
Alexandre Julliarda3960291999-02-26 11:11:13 +0000478static UINT MENU_GetStartOfNextColumn(
479 HMENU hMenu )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000480{
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000481 POPUPMENU *menu = MENU_GetMenu(hMenu);
482 UINT i;
Alexandre Julliard641ee761997-08-04 16:34:36 +0000483
484 if(!menu)
485 return NO_SELECTED_ITEM;
486
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000487 i = menu->FocusedItem + 1;
Alexandre Julliard641ee761997-08-04 16:34:36 +0000488 if( i == NO_SELECTED_ITEM )
489 return i;
490
491 for( ; i < menu->nItems; ++i ) {
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000492 if (menu->items[i].fType & MF_MENUBARBREAK)
Alexandre Julliard641ee761997-08-04 16:34:36 +0000493 return i;
494 }
495
496 return NO_SELECTED_ITEM;
497}
498
499
500/******************************************************************************
501 *
Patrik Stridvall2d6457c2000-03-28 20:22:59 +0000502 * UINT MENU_GetStartOfPrevColumn(
503 * HMENU hMenu )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000504 *
505 *****************************************************************************/
506
Alexandre Julliarda3960291999-02-26 11:11:13 +0000507static UINT MENU_GetStartOfPrevColumn(
508 HMENU hMenu )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000509{
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000510 POPUPMENU *menu = MENU_GetMenu(hMenu);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000511 UINT i;
Alexandre Julliard641ee761997-08-04 16:34:36 +0000512
513 if( !menu )
514 return NO_SELECTED_ITEM;
515
516 if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
517 return NO_SELECTED_ITEM;
518
519 /* Find the start of the column */
520
521 for(i = menu->FocusedItem; i != 0 &&
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000522 !(menu->items[i].fType & MF_MENUBARBREAK);
Alexandre Julliard641ee761997-08-04 16:34:36 +0000523 --i); /* empty */
524
525 if(i == 0)
526 return NO_SELECTED_ITEM;
527
528 for(--i; i != 0; --i) {
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000529 if (menu->items[i].fType & MF_MENUBARBREAK)
Alexandre Julliard641ee761997-08-04 16:34:36 +0000530 break;
531 }
532
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000533 TRACE("ret %d.\n", i );
Alexandre Julliard641ee761997-08-04 16:34:36 +0000534
535 return i;
536}
537
538
539
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000540/***********************************************************************
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000541 * MENU_FindItem
542 *
543 * Find a menu item. Return a pointer on the item, and modifies *hmenu
544 * in case the item was in a sub-menu.
545 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000546static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000547{
548 POPUPMENU *menu;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000549 UINT i;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000550
Gerard Patel3e629742000-01-17 22:22:16 +0000551 if (((*hmenu)==0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000552 if (wFlags & MF_BYPOSITION)
553 {
554 if (*nPos >= menu->nItems) return NULL;
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000555 return &menu->items[*nPos];
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000556 }
557 else
558 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000559 MENUITEM *item = menu->items;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000560 for (i = 0; i < menu->nItems; i++, item++)
561 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000562 if (item->wID == *nPos)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000563 {
564 *nPos = i;
565 return item;
566 }
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000567 else if (item->fType & MF_POPUP)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000568 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000569 HMENU hsubmenu = item->hSubMenu;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000570 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
571 if (subitem)
572 {
573 *hmenu = hsubmenu;
574 return subitem;
575 }
576 }
577 }
578 }
579 return NULL;
580}
581
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000582/***********************************************************************
Rein Klazes80c924f1999-12-12 19:40:46 +0000583 * MENU_FindSubMenu
584 *
585 * Find a Sub menu. Return the position of the submenu, and modifies
586 * *hmenu in case it is found in another sub-menu.
587 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
588 */
589UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget )
590{
591 POPUPMENU *menu;
592 UINT i;
593 MENUITEM *item;
594 if (((*hmenu)==0xffff) ||
Gerard Patel3e629742000-01-17 22:22:16 +0000595 (!(menu = MENU_GetMenu(*hmenu))))
Rein Klazes80c924f1999-12-12 19:40:46 +0000596 return NO_SELECTED_ITEM;
597 item = menu->items;
598 for (i = 0; i < menu->nItems; i++, item++) {
599 if(!(item->fType & MF_POPUP)) continue;
600 if (item->hSubMenu == hSubTarget) {
601 return i;
602 }
603 else {
604 HMENU hsubmenu = item->hSubMenu;
605 UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
606 if (pos != NO_SELECTED_ITEM) {
607 *hmenu = hsubmenu;
608 return pos;
609 }
610 }
611 }
612 return NO_SELECTED_ITEM;
613}
614
615/***********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000616 * MENU_FreeItemData
617 */
618static void MENU_FreeItemData( MENUITEM* item )
619{
620 /* delete text */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000621 if (IS_STRING_ITEM(item->fType) && item->text)
Alexandre Julliardda2892c2001-02-23 01:13:42 +0000622 HeapFree( GetProcessHeap(), 0, item->text );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000623}
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000624
625/***********************************************************************
626 * MENU_FindItemByCoords
627 *
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000628 * Find the item at the specified coordinates (screen coords). Does
629 * not work for child windows and therefore should not be called for
630 * an arbitrary system menu.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000631 */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000632static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000633 POINT pt, UINT *pos )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000634{
635 MENUITEM *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000636 UINT i;
Marcus Meissnerac593bb1999-03-17 15:18:28 +0000637 RECT wrect;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000638
Marcus Meissnerac593bb1999-03-17 15:18:28 +0000639 if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
640 pt.x -= wrect.left;pt.y -= wrect.top;
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000641 item = menu->items;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000642 for (i = 0; i < menu->nItems; i++, item++)
643 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000644 if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
645 (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000646 {
647 if (pos) *pos = i;
648 return item;
649 }
650 }
651 return NULL;
652}
653
654
655/***********************************************************************
656 * MENU_FindItemByKey
657 *
658 * Find the menu item selected by a key press.
659 * Return item id, -1 if none, -2 if we should close the menu.
660 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000661static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu,
662 UINT key, BOOL forceMenuChar )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000663{
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000664 TRACE("\tlooking for '%c' in [%04x]\n", (char)key, (UINT16)hmenu );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000665
Alexandre Julliardde424282001-08-10 22:51:42 +0000666 if (!IsMenu( hmenu )) hmenu = GetSubMenu( get_win_sys_menu(hwndOwner), 0);
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000667
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000668 if (hmenu)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000669 {
Gerard Patel3e629742000-01-17 22:22:16 +0000670 POPUPMENU *menu = MENU_GetMenu( hmenu );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000671 MENUITEM *item = menu->items;
672 LONG menuchar;
673
674 if( !forceMenuChar )
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000675 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000676 UINT i;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000677
678 key = toupper(key);
679 for (i = 0; i < menu->nItems; i++, item++)
680 {
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000681 if (item->text && (IS_STRING_ITEM(item->fType)))
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000682 {
Aric Stewartc946b1c2000-10-24 21:28:19 +0000683 WCHAR *p = item->text - 2;
Norman Stevensa83d0651998-10-12 07:25:35 +0000684 do
685 {
Aric Stewartc946b1c2000-10-24 21:28:19 +0000686 p = strchrW (p + 2, '&');
Norman Stevensa83d0651998-10-12 07:25:35 +0000687 }
688 while (p != NULL && p [1] == '&');
689 if (p && (toupper(p[1]) == key)) return i;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000690 }
691 }
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000692 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000693 menuchar = SendMessageA( hwndOwner, WM_MENUCHAR,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000694 MAKEWPARAM( key, menu->wFlags ), hmenu );
695 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000696 if (HIWORD(menuchar) == 1) return (UINT)(-2);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000697 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000698 return (UINT)(-1);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000699}
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000700
701
Francois Boisvert8b391741999-02-09 14:09:55 +0000702/***********************************************************************
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000703 * MENU_GetBitmapItemSize
Francois Boisvert8b391741999-02-09 14:09:55 +0000704 *
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000705 * Get the size of a bitmap item.
Francois Boisvert8b391741999-02-09 14:09:55 +0000706 */
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000707static void MENU_GetBitmapItemSize( UINT id, DWORD data, SIZE *size )
Francois Boisvert8b391741999-02-09 14:09:55 +0000708{
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000709 BITMAP bm;
710 HBITMAP bmp = (HBITMAP)id;
Francois Boisvert8b391741999-02-09 14:09:55 +0000711
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000712 size->cx = size->cy = 0;
713
714 /* check if there is a magic menu item associated with this item */
715 if (id && IS_MAGIC_ITEM( id ))
716 {
717 switch(LOWORD(id))
718 {
719 case HBMMENU_SYSTEM:
720 if (data)
721 {
722 bmp = (HBITMAP)data;
723 break;
724 }
725 /* fall through */
726 case HBMMENU_MBAR_RESTORE:
727 case HBMMENU_MBAR_MINIMIZE:
728 case HBMMENU_MBAR_MINIMIZE_D:
729 case HBMMENU_MBAR_CLOSE:
730 case HBMMENU_MBAR_CLOSE_D:
731 size->cx = GetSystemMetrics( SM_CXSIZE );
732 size->cy = GetSystemMetrics( SM_CYSIZE );
733 return;
734 case HBMMENU_CALLBACK:
735 case HBMMENU_POPUP_CLOSE:
736 case HBMMENU_POPUP_RESTORE:
737 case HBMMENU_POPUP_MAXIMIZE:
738 case HBMMENU_POPUP_MINIMIZE:
739 default:
740 FIXME("Magic 0x%08x not implemented\n", id);
741 return;
742 }
743 }
744 if (GetObjectA(bmp, sizeof(bm), &bm ))
745 {
746 size->cx = bm.bmWidth;
747 size->cy = bm.bmHeight;
748 }
749}
750
751/***********************************************************************
752 * MENU_DrawBitmapItem
753 *
754 * Draw a bitmap item.
755 */
756static void MENU_DrawBitmapItem( HDC hdc, MENUITEM *lpitem, const RECT *rect, BOOL menuBar )
757{
758 BITMAP bm;
759 DWORD rop;
760 HDC hdcMem;
761 HBITMAP bmp = (HBITMAP)lpitem->text;
762 int w = rect->right - rect->left;
763 int h = rect->bottom - rect->top;
764 int bmp_xoffset = 0;
765 int left, top;
766
767 /* Check if there is a magic menu item associated with this item */
768 if (lpitem->text && IS_MAGIC_ITEM(lpitem->text))
769 {
770 UINT flags = 0;
771 RECT r;
772
773 switch(LOWORD(lpitem->text))
774 {
775 case HBMMENU_SYSTEM:
776 if (lpitem->dwItemData)
777 {
778 bmp = (HBITMAP)lpitem->dwItemData;
779 if (!GetObjectA( bmp, sizeof(bm), &bm )) return;
780 }
781 else
782 {
783 bmp = hBmpSysMenu;
784 if (!GetObjectA( bmp, sizeof(bm), &bm )) return;
785 /* only use right half of the bitmap */
786 bmp_xoffset = bm.bmWidth / 2;
787 bm.bmWidth -= bmp_xoffset;
788 }
789 goto got_bitmap;
790 case HBMMENU_MBAR_RESTORE:
791 flags = DFCS_CAPTIONRESTORE;
792 break;
793 case HBMMENU_MBAR_MINIMIZE:
794 flags = DFCS_CAPTIONMIN;
795 break;
796 case HBMMENU_MBAR_MINIMIZE_D:
797 flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
798 break;
799 case HBMMENU_MBAR_CLOSE:
800 flags = DFCS_CAPTIONCLOSE;
801 break;
802 case HBMMENU_MBAR_CLOSE_D:
803 flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
804 break;
805 case HBMMENU_CALLBACK:
806 case HBMMENU_POPUP_CLOSE:
807 case HBMMENU_POPUP_RESTORE:
808 case HBMMENU_POPUP_MAXIMIZE:
809 case HBMMENU_POPUP_MINIMIZE:
810 default:
811 FIXME("Magic 0x%08x not implemented\n", LOWORD(lpitem->text));
812 return;
813 }
814 r = *rect;
815 InflateRect( &r, -1, -1 );
816 if (lpitem->fState & MF_HILITE) flags |= DFCS_PUSHED;
817 DrawFrameControl( hdc, &r, DFC_CAPTION, flags );
818 return;
Francois Boisvert8b391741999-02-09 14:09:55 +0000819 }
820
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000821 if (!bmp || !GetObjectA( bmp, sizeof(bm), &bm )) return;
822
823 got_bitmap:
824 hdcMem = CreateCompatibleDC( hdc );
825 SelectObject( hdcMem, bmp );
826
827 /* handle fontsize > bitmap_height */
828 top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
829 left=rect->left;
830 if (TWEAK_WineLook == WIN95_LOOK) {
831 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_ITEM(lpitem->text)) ? NOTSRCCOPY : SRCCOPY;
832 if ((lpitem->fState & MF_HILITE) && IS_BITMAP_ITEM(lpitem->fType))
833 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
834 } else {
835 left++;
836 w-=2;
837 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_ITEM(lpitem->text) && (!menuBar)) ? MERGEPAINT : SRCCOPY;
838 }
839 BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop );
840 DeleteDC( hdcMem );
Francois Boisvert8b391741999-02-09 14:09:55 +0000841}
Alexandre Julliardf7207251994-07-23 07:57:48 +0000842
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000843
Alexandre Julliardf7207251994-07-23 07:57:48 +0000844/***********************************************************************
845 * MENU_CalcItemSize
846 *
847 * Calculate the size of the menu item and store it in lpitem->rect.
848 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000849static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
850 INT orgX, INT orgY, BOOL menuBar )
Alexandre Julliardf7207251994-07-23 07:57:48 +0000851{
Aric Stewartc946b1c2000-10-24 21:28:19 +0000852 WCHAR *p;
Alexandre Julliardc1d35cc2001-01-24 19:47:57 +0000853 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000854
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000855 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
Alexandre Julliard03468f71998-02-15 19:40:49 +0000856 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem,
857 (menuBar ? " (MenuBar)" : ""));
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000858
Alexandre Julliarda3960291999-02-26 11:11:13 +0000859 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000860
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000861 if (lpitem->fType & MF_OWNERDRAW)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000862 {
Ken Thomases130f0d82000-05-10 21:38:37 +0000863 /*
864 ** Experimentation under Windows reveals that an owner-drawn
865 ** menu is expected to return the size of the content part of
866 ** the menu item, not including the checkmark nor the submenu
867 ** arrow. Windows adds those values itself and returns the
868 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
869 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000870 MEASUREITEMSTRUCT mis;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000871 mis.CtlType = ODT_MENU;
Juergen Schmied7abca951999-04-11 17:02:30 +0000872 mis.CtlID = 0;
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000873 mis.itemID = lpitem->wID;
Juergen Schmied7abca951999-04-11 17:02:30 +0000874 mis.itemData = (DWORD)lpitem->dwItemData;
875 mis.itemHeight = 0;
876 mis.itemWidth = 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000877 SendMessageA( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000878 lpitem->rect.right += mis.itemWidth;
Aric Stewart70cc1692000-05-10 21:54:07 +0000879
880 if (menuBar)
881 {
882 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
883
884
885 /* under at least win95 you seem to be given a standard
886 height for the menu and the height value is ignored */
887
888 if (TWEAK_WineLook == WIN31_LOOK)
889 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU);
890 else
891 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU)-1;
892 }
893 else
894 lpitem->rect.bottom += mis.itemHeight;
895
896 TRACE("id=%04x size=%dx%d\n",
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000897 lpitem->wID, mis.itemWidth, mis.itemHeight);
Ken Thomases130f0d82000-05-10 21:38:37 +0000898 /* Fall through to get check/arrow width calculation. */
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000899 }
Alexandre Julliardf7207251994-07-23 07:57:48 +0000900
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000901 if (lpitem->fType & MF_SEPARATOR)
Alexandre Julliardf7207251994-07-23 07:57:48 +0000902 {
903 lpitem->rect.bottom += SEPARATOR_HEIGHT;
904 return;
905 }
906
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000907 if (!menuBar)
908 {
909 lpitem->rect.right += 2 * check_bitmap_width;
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000910 if (lpitem->fType & MF_POPUP)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000911 lpitem->rect.right += arrow_bitmap_width;
912 }
Alexandre Julliardf7207251994-07-23 07:57:48 +0000913
Ken Thomases130f0d82000-05-10 21:38:37 +0000914 if (lpitem->fType & MF_OWNERDRAW)
915 return;
916
Juergen Schmied78513941999-04-18 14:40:32 +0000917 if (IS_BITMAP_ITEM(lpitem->fType))
Alexandre Julliardf7207251994-07-23 07:57:48 +0000918 {
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000919 SIZE size;
Francois Boisvert8b391741999-02-09 14:09:55 +0000920
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000921 MENU_GetBitmapItemSize( (int)lpitem->text, lpitem->dwItemData, &size );
922 lpitem->rect.right += size.cx;
923 lpitem->rect.bottom += size.cy;
924 if (TWEAK_WineLook == WIN98_LOOK)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000925 {
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000926 /* Leave space for the sunken border */
927 lpitem->rect.right += 2;
928 lpitem->rect.bottom += 2;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000929 }
Alexandre Julliardf7207251994-07-23 07:57:48 +0000930 }
931
Juergen Schmied78513941999-04-18 14:40:32 +0000932
Gerard Patel2482ef32001-03-19 19:16:21 +0000933 /* it must be a text item - unless it's the system menu */
934 if (!(lpitem->fType & MF_SYSMENU) && IS_STRING_ITEM( lpitem->fType ))
Juergen Schmied78513941999-04-18 14:40:32 +0000935 { SIZE size;
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000936
Aric Stewartc946b1c2000-10-24 21:28:19 +0000937 GetTextExtentPoint32W(hdc, lpitem->text, strlenW(lpitem->text), &size);
Juergen Schmied78513941999-04-18 14:40:32 +0000938
939 lpitem->rect.right += size.cx;
940 if (TWEAK_WineLook == WIN31_LOOK)
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000941 lpitem->rect.bottom += max( size.cy, GetSystemMetrics(SM_CYMENU) );
Juergen Schmied78513941999-04-18 14:40:32 +0000942 else
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000943 lpitem->rect.bottom += max(size.cy, GetSystemMetrics(SM_CYMENU)-1);
Juergen Schmied78513941999-04-18 14:40:32 +0000944 lpitem->xTab = 0;
945
946 if (menuBar)
947 {
948 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
949 }
Aric Stewartc946b1c2000-10-24 21:28:19 +0000950 else if ((p = strchrW( lpitem->text, '\t' )) != NULL)
Juergen Schmied78513941999-04-18 14:40:32 +0000951 {
952 /* Item contains a tab (only meaningful in popup menus) */
Aric Stewartc946b1c2000-10-24 21:28:19 +0000953 GetTextExtentPoint32W(hdc, lpitem->text, (int)(p - lpitem->text) , &size);
Juergen Schmied78513941999-04-18 14:40:32 +0000954 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE + size.cx;
955 lpitem->rect.right += MENU_TAB_SPACE;
956 }
957 else
958 {
Aric Stewartc946b1c2000-10-24 21:28:19 +0000959 if (strchrW( lpitem->text, '\b' ))
Juergen Schmied78513941999-04-18 14:40:32 +0000960 lpitem->rect.right += MENU_TAB_SPACE;
961 lpitem->xTab = lpitem->rect.right - check_bitmap_width
962 - arrow_bitmap_width;
963 }
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000964 }
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000965 TRACE("(%d,%d)-(%d,%d)\n", lpitem->rect.left, lpitem->rect.top, lpitem->rect.right, lpitem->rect.bottom);
Alexandre Julliardf7207251994-07-23 07:57:48 +0000966}
967
968
969/***********************************************************************
970 * MENU_PopupMenuCalcSize
971 *
972 * Calculate the size of a popup menu.
973 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000974static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
Alexandre Julliardf7207251994-07-23 07:57:48 +0000975{
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000976 MENUITEM *lpitem;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000977 HDC hdc;
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000978 int start, i;
979 int orgX, orgY, maxX, maxTab, maxTabWidth;
Alexandre Julliardf7207251994-07-23 07:57:48 +0000980
Alexandre Julliardf7207251994-07-23 07:57:48 +0000981 lppop->Width = lppop->Height = 0;
982 if (lppop->nItems == 0) return;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000983 hdc = GetDC( 0 );
Juergen Schmied78513941999-04-18 14:40:32 +0000984
985 SelectObject( hdc, hMenuFont);
986
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000987 start = 0;
Francois Gouget75f9e642000-11-06 05:25:29 +0000988 maxX = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CXBORDER) : 2+1 ;
Juergen Schmied466a6521999-05-02 11:21:08 +0000989
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000990 while (start < lppop->nItems)
Alexandre Julliardf7207251994-07-23 07:57:48 +0000991 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000992 lpitem = &lppop->items[start];
Alexandre Julliardf7207251994-07-23 07:57:48 +0000993 orgX = maxX;
Marcus Meissnerddca3151999-05-22 11:33:23 +0000994 orgY = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CYBORDER) : 2;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000995
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000996 maxTab = maxTabWidth = 0;
Alexandre Julliardf7207251994-07-23 07:57:48 +0000997
998 /* Parse items until column break or end of menu */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000999 for (i = start; i < lppop->nItems; i++, lpitem++)
Alexandre Julliardf7207251994-07-23 07:57:48 +00001000 {
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001001 if ((i != start) &&
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001002 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001003
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001004 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
Pascal Lessard47274231999-02-13 12:21:46 +00001005
Juergen Schmied466a6521999-05-02 11:21:08 +00001006 if (lpitem->fType & MF_MENUBARBREAK) orgX++;
Francois Gouget6d77d3a2000-03-25 21:44:35 +00001007 maxX = max( maxX, lpitem->rect.right );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001008 orgY = lpitem->rect.bottom;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001009 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001010 {
Francois Gouget6d77d3a2000-03-25 21:44:35 +00001011 maxTab = max( maxTab, lpitem->xTab );
1012 maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001013 }
Alexandre Julliardf7207251994-07-23 07:57:48 +00001014 }
1015
1016 /* Finish the column (set all items to the largest width found) */
Francois Gouget6d77d3a2000-03-25 21:44:35 +00001017 maxX = max( maxX, maxTab + maxTabWidth );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001018 for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001019 {
1020 lpitem->rect.right = maxX;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001021 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
Juergen Schmied466a6521999-05-02 11:21:08 +00001022 lpitem->xTab = maxTab;
1023
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001024 }
Francois Gouget6d77d3a2000-03-25 21:44:35 +00001025 lppop->Height = max( lppop->Height, orgY );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001026 }
1027
1028 lppop->Width = maxX;
Juergen Schmied466a6521999-05-02 11:21:08 +00001029
1030 /* space for 3d border */
1031 if(TWEAK_WineLook > WIN31_LOOK)
1032 {
1033 lppop->Height += 2;
1034 lppop->Width += 2;
1035 }
1036
Alexandre Julliarda3960291999-02-26 11:11:13 +00001037 ReleaseDC( 0, hdc );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001038}
1039
1040
1041/***********************************************************************
1042 * MENU_MenuBarCalcSize
1043 *
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001044 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001045 * height is off by 1 pixel which causes lengthy window relocations when
1046 * active document window is maximized/restored.
1047 *
Alexandre Julliardf7207251994-07-23 07:57:48 +00001048 * Calculate the size of the menu bar.
1049 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001050static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
1051 LPPOPUPMENU lppop, HWND hwndOwner )
Alexandre Julliardf7207251994-07-23 07:57:48 +00001052{
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001053 MENUITEM *lpitem;
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001054 int start, i, orgX, orgY, maxY, helpPos;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001055
1056 if ((lprect == NULL) || (lppop == NULL)) return;
1057 if (lppop->nItems == 0) return;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001058 TRACE("left=%d top=%d right=%d bottom=%d\n",
Alexandre Julliard59730ae1996-03-24 16:20:51 +00001059 lprect->left, lprect->top, lprect->right, lprect->bottom);
Alexandre Julliardf7207251994-07-23 07:57:48 +00001060 lppop->Width = lprect->right - lprect->left;
1061 lppop->Height = 0;
Francois Gouget75f9e642000-11-06 05:25:29 +00001062 maxY = lprect->top+1;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001063 start = 0;
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001064 helpPos = -1;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001065 while (start < lppop->nItems)
Alexandre Julliardf7207251994-07-23 07:57:48 +00001066 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001067 lpitem = &lppop->items[start];
Alexandre Julliardf7207251994-07-23 07:57:48 +00001068 orgX = lprect->left;
1069 orgY = maxY;
1070
1071 /* Parse items until line break or end of menu */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001072 for (i = start; i < lppop->nItems; i++, lpitem++)
Alexandre Julliardf7207251994-07-23 07:57:48 +00001073 {
Francois Gouget58182402001-01-04 20:56:43 +00001074 if ((helpPos == -1) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001075 if ((i != start) &&
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001076 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001077
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001078 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001079 orgX, orgY );
Alexandre Julliard03468f71998-02-15 19:40:49 +00001080 debug_print_menuitem (" item: ", lpitem, "");
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001081 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
Pascal Lessard47274231999-02-13 12:21:46 +00001082
Alexandre Julliardf7207251994-07-23 07:57:48 +00001083 if (lpitem->rect.right > lprect->right)
1084 {
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001085 if (i != start) break;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001086 else lpitem->rect.right = lprect->right;
1087 }
Francois Gouget6d77d3a2000-03-25 21:44:35 +00001088 maxY = max( maxY, lpitem->rect.bottom );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001089 orgX = lpitem->rect.right;
1090 }
1091
1092 /* Finish the line (set all items to the largest height found) */
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001093 while (start < i) lppop->items[start++].rect.bottom = maxY;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001094 }
1095
1096 lprect->bottom = maxY;
1097 lppop->Height = lprect->bottom - lprect->top;
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001098
Francois Gouget58182402001-01-04 20:56:43 +00001099 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1100 /* the last item (if several lines, only move the last line) */
1101 lpitem = &lppop->items[lppop->nItems-1];
1102 orgY = lpitem->rect.top;
1103 orgX = lprect->right;
1104 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--) {
1105 if ( (helpPos==-1) || (helpPos>i) )
1106 break; /* done */
1107 if (lpitem->rect.top != orgY) break; /* Other line */
1108 if (lpitem->rect.right >= orgX) break; /* Too far right already */
1109 lpitem->rect.left += orgX - lpitem->rect.right;
1110 lpitem->rect.right = orgX;
1111 orgX = lpitem->rect.left;
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001112 }
Alexandre Julliardf7207251994-07-23 07:57:48 +00001113}
1114
Alexandre Julliardf7207251994-07-23 07:57:48 +00001115/***********************************************************************
1116 * MENU_DrawMenuItem
1117 *
1118 * Draw a single menu item.
1119 */
Juergen Schmied78513941999-04-18 14:40:32 +00001120static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001121 UINT height, BOOL menuBar, UINT odaction )
Alexandre Julliardf7207251994-07-23 07:57:48 +00001122{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001123 RECT rect;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001124
Alexandre Julliard03468f71998-02-15 19:40:49 +00001125 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001126
1127 if (lpitem->fType & MF_SYSMENU)
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001128 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001129 if( !IsIconic(hwnd) ) {
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001130 if (TWEAK_WineLook > WIN31_LOOK)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001131 NC_DrawSysButton95( hwnd, hdc,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001132 lpitem->fState &
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001133 (MF_HILITE | MF_MOUSESELECT) );
1134 else
1135 NC_DrawSysButton( hwnd, hdc,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001136 lpitem->fState &
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001137 (MF_HILITE | MF_MOUSESELECT) );
1138 }
1139
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001140 return;
1141 }
1142
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001143 if (lpitem->fType & MF_OWNERDRAW)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001144 {
Ken Thomases130f0d82000-05-10 21:38:37 +00001145 /*
1146 ** Experimentation under Windows reveals that an owner-drawn
1147 ** menu is given the rectangle which includes the space it requested
1148 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1149 ** and a popup-menu arrow. This is the value of lpitem->rect.
1150 ** Windows will leave all drawing to the application except for
1151 ** the popup-menu arrow. Windows always draws that itself, after
1152 ** the menu owner has finished drawing.
1153 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001154 DRAWITEMSTRUCT dis;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001155
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001156 dis.CtlType = ODT_MENU;
Juergen Schmied7abca951999-04-11 17:02:30 +00001157 dis.CtlID = 0;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001158 dis.itemID = lpitem->wID;
Juergen Schmied7abca951999-04-11 17:02:30 +00001159 dis.itemData = (DWORD)lpitem->dwItemData;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001160 dis.itemState = 0;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001161 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1162 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED;
1163 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001164 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
Alexandre Julliardd23a82b2001-09-19 20:37:04 +00001165 dis.hwndItem = (HWND)hmenu;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001166 dis.hDC = hdc;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001167 dis.rcItem = lpitem->rect;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001168 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
Juergen Schmied78513941999-04-18 14:40:32 +00001169 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner,
1170 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
1171 dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
1172 dis.rcItem.bottom);
1173 SendMessageA( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
Ken Thomases130f0d82000-05-10 21:38:37 +00001174 /* Fall through to draw popup-menu arrow */
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001175 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001176
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001177 TRACE("rect={%d,%d,%d,%d}\n", lpitem->rect.left, lpitem->rect.top,
Juergen Schmied78513941999-04-18 14:40:32 +00001178 lpitem->rect.right,lpitem->rect.bottom);
1179
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001180 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
Juergen Schmied78513941999-04-18 14:40:32 +00001181
Alexandre Julliardf7207251994-07-23 07:57:48 +00001182 rect = lpitem->rect;
1183
Ken Thomases130f0d82000-05-10 21:38:37 +00001184 if (!(lpitem->fType & MF_OWNERDRAW))
1185 {
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001186 if (lpitem->fState & MF_HILITE)
1187 {
1188 if(TWEAK_WineLook == WIN98_LOOK)
1189 {
1190 if(menuBar)
1191 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1192 else
1193 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1194 }
1195 else /* Not Win98 Look */
1196 {
1197 if(!IS_BITMAP_ITEM(lpitem->fType))
1198 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1199 }
1200 }
Ken Thomases130f0d82000-05-10 21:38:37 +00001201 else
1202 FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) );
1203 }
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001204
Alexandre Julliarda3960291999-02-26 11:11:13 +00001205 SetBkMode( hdc, TRANSPARENT );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001206
Ken Thomases130f0d82000-05-10 21:38:37 +00001207 if (!(lpitem->fType & MF_OWNERDRAW))
Alexandre Julliardf7207251994-07-23 07:57:48 +00001208 {
Ken Thomases130f0d82000-05-10 21:38:37 +00001209 /* vertical separator */
1210 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1211 {
1212 if (TWEAK_WineLook > WIN31_LOOK)
1213 {
1214 RECT rc = rect;
1215 rc.top = 3;
1216 rc.bottom = height - 3;
1217 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1218 }
1219 else
1220 {
1221 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
Alexandre Julliardb0efe282000-08-04 04:18:04 +00001222 MoveToEx( hdc, rect.left, 0, NULL );
Ken Thomases130f0d82000-05-10 21:38:37 +00001223 LineTo( hdc, rect.left, height );
1224 }
1225 }
Juergen Schmied78513941999-04-18 14:40:32 +00001226
Ken Thomases130f0d82000-05-10 21:38:37 +00001227 /* horizontal separator */
1228 if (lpitem->fType & MF_SEPARATOR)
1229 {
1230 if (TWEAK_WineLook > WIN31_LOOK)
1231 {
1232 RECT rc = rect;
1233 rc.left++;
1234 rc.right--;
1235 rc.top += SEPARATOR_HEIGHT / 2;
1236 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1237 }
1238 else
1239 {
1240 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
Alexandre Julliardb0efe282000-08-04 04:18:04 +00001241 MoveToEx( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2, NULL );
Ken Thomases130f0d82000-05-10 21:38:37 +00001242 LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
1243 }
1244 return;
1245 }
Alexandre Julliardf7207251994-07-23 07:57:48 +00001246 }
1247
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001248 /* Setup colors */
1249
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001250 if (lpitem->fState & MF_HILITE)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001251 {
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001252 if(TWEAK_WineLook == WIN98_LOOK)
1253 {
François Gouget75b278e2001-01-06 01:45:51 +00001254 if(menuBar) {
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001255 SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
François Gouget75b278e2001-01-06 01:45:51 +00001256 SetBkColor(hdc, GetSysColor(COLOR_MENU));
1257 } else {
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001258 if(lpitem->fState & MF_GRAYED)
1259 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
1260 else
1261 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
François Gouget75b278e2001-01-06 01:45:51 +00001262 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001263 }
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001264 }
1265 else /* Not Win98 Look */
1266 {
1267 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1268 if(!IS_BITMAP_ITEM(lpitem->fType))
1269 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001270 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001271 }
1272 else
1273 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001274 if (lpitem->fState & MF_GRAYED)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001275 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001276 else
Alexandre Julliarda3960291999-02-26 11:11:13 +00001277 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1278 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001279 }
1280
Juergen Schmied78513941999-04-18 14:40:32 +00001281 /* helper lines for debugging */
1282/* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1283 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
Alexandre Julliardb0efe282000-08-04 04:18:04 +00001284 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
Juergen Schmied78513941999-04-18 14:40:32 +00001285 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1286*/
1287
Alexandre Julliardf7207251994-07-23 07:57:48 +00001288 if (!menuBar)
1289 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001290 INT y = rect.top + rect.bottom;
Alexandre Julliardc1d35cc2001-01-24 19:47:57 +00001291 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
1292 UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001293
Ken Thomases130f0d82000-05-10 21:38:37 +00001294 if (!(lpitem->fType & MF_OWNERDRAW))
1295 {
1296 /* Draw the check mark
1297 *
1298 * FIXME:
1299 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1300 */
Alexandre Julliardc1d35cc2001-01-24 19:47:57 +00001301 HBITMAP bm = (lpitem->fState & MF_CHECKED) ? lpitem->hCheckBit : lpitem->hUnCheckBit;
1302 if (bm) /* we have a custom bitmap */
1303 {
1304 HDC hdcMem = CreateCompatibleDC( hdc );
1305 SelectObject( hdcMem, bm );
1306 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1307 check_bitmap_width, check_bitmap_height,
1308 hdcMem, 0, 0, SRCCOPY );
1309 DeleteDC( hdcMem );
1310 }
1311 else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
1312 {
1313 RECT r;
1314 HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
1315 HDC hdcMem = CreateCompatibleDC( hdc );
1316 SelectObject( hdcMem, bm );
1317 SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height );
1318 DrawFrameControl( hdcMem, &r, DFC_MENU,
1319 (lpitem->fType & MFT_RADIOCHECK) ?
1320 DFCS_MENUBULLET : DFCS_MENUCHECK );
1321 BitBlt( hdc, rect.left, (y - r.bottom) / 2, r.right, r.bottom,
1322 hdcMem, 0, 0, SRCCOPY );
1323 DeleteDC( hdcMem );
1324 DeleteObject( bm );
1325 }
Ken Thomases130f0d82000-05-10 21:38:37 +00001326 }
Juergen Schmied78513941999-04-18 14:40:32 +00001327
Alexandre Julliardf7207251994-07-23 07:57:48 +00001328 /* Draw the popup-menu arrow */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001329 if (lpitem->fType & MF_POPUP)
Alexandre Julliardf7207251994-07-23 07:57:48 +00001330 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001331 HDC hdcMem = CreateCompatibleDC( hdc );
Ken Thomases130f0d82000-05-10 21:38:37 +00001332 HBITMAP hOrigBitmap;
Huw D M Davies2d617be1998-12-08 09:14:09 +00001333
Ken Thomases130f0d82000-05-10 21:38:37 +00001334 hOrigBitmap = SelectObject( hdcMem, hStdMnArrow );
Juergen Schmied78513941999-04-18 14:40:32 +00001335 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
Huw D M Davies2d617be1998-12-08 09:14:09 +00001336 (y - arrow_bitmap_height) / 2,
1337 arrow_bitmap_width, arrow_bitmap_height,
1338 hdcMem, 0, 0, SRCCOPY );
Ken Thomases130f0d82000-05-10 21:38:37 +00001339 SelectObject( hdcMem, hOrigBitmap );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001340 DeleteDC( hdcMem );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001341 }
1342
1343 rect.left += check_bitmap_width;
1344 rect.right -= arrow_bitmap_width;
1345 }
1346
Ken Thomases130f0d82000-05-10 21:38:37 +00001347 /* Done for owner-drawn */
1348 if (lpitem->fType & MF_OWNERDRAW)
1349 return;
1350
Juergen Schmied78513941999-04-18 14:40:32 +00001351 /* Draw the item text or bitmap */
1352 if (IS_BITMAP_ITEM(lpitem->fType))
François Gouget75b278e2001-01-06 01:45:51 +00001353 {
Alexandre Julliardcc2d3822002-01-03 02:35:23 +00001354 MENU_DrawBitmapItem( hdc, lpitem, &rect, menuBar );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001355 return;
Francois Boisvert8b391741999-02-09 14:09:55 +00001356
Alexandre Julliardf7207251994-07-23 07:57:48 +00001357 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001358 /* No bitmap - process text if present */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001359 else if (IS_STRING_ITEM(lpitem->fType))
Alexandre Julliardf7207251994-07-23 07:57:48 +00001360 {
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001361 register int i;
Juergen Schmied466a6521999-05-02 11:21:08 +00001362 HFONT hfontOld = 0;
1363
Juergen Schmied78513941999-04-18 14:40:32 +00001364 UINT uFormat = (menuBar) ?
1365 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1366 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001367
Juergen Schmied466a6521999-05-02 11:21:08 +00001368 if ( lpitem->fState & MFS_DEFAULT )
1369 {
1370 hfontOld = SelectObject( hdc, hMenuFontBold);
1371 }
1372
Alexandre Julliardf7207251994-07-23 07:57:48 +00001373 if (menuBar)
1374 {
1375 rect.left += MENU_BAR_ITEMS_SPACE / 2;
1376 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
Aric Stewartc946b1c2000-10-24 21:28:19 +00001377 i = strlenW( lpitem->text );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001378 }
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001379 else
Alexandre Julliardf7207251994-07-23 07:57:48 +00001380 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001381 for (i = 0; lpitem->text[i]; i++)
Juergen Schmied466a6521999-05-02 11:21:08 +00001382 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1383 break;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001384 }
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001385
Juergen Schmied466a6521999-05-02 11:21:08 +00001386 if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
Juergen Schmied78513941999-04-18 14:40:32 +00001387 {
Juergen Schmied466a6521999-05-02 11:21:08 +00001388 if (!(lpitem->fState & MF_HILITE) )
Juergen Schmied78513941999-04-18 14:40:32 +00001389 {
Juergen Schmied466a6521999-05-02 11:21:08 +00001390 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001391 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
Aric Stewartc946b1c2000-10-24 21:28:19 +00001392 DrawTextW( hdc, lpitem->text, i, &rect, uFormat );
Juergen Schmied466a6521999-05-02 11:21:08 +00001393 --rect.left; --rect.top; --rect.right; --rect.bottom;
Alexandre Julliard641ee761997-08-04 16:34:36 +00001394 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001395 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001396 }
Juergen Schmied466a6521999-05-02 11:21:08 +00001397
Aric Stewartc946b1c2000-10-24 21:28:19 +00001398 DrawTextW( hdc, lpitem->text, i, &rect, uFormat);
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001399
Juergen Schmied466a6521999-05-02 11:21:08 +00001400 /* paint the shortcut text */
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001401 if (lpitem->text[i]) /* There's a tab or flush-right char */
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001402 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001403 if (lpitem->text[i] == '\t')
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001404 {
1405 rect.left = lpitem->xTab;
Juergen Schmiedcd0ed1e1999-04-26 14:54:38 +00001406 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001407 }
Juergen Schmiedcd0ed1e1999-04-26 14:54:38 +00001408 else
1409 {
1410 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1411 }
1412
Juergen Schmied466a6521999-05-02 11:21:08 +00001413 if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1414 {
1415 if (!(lpitem->fState & MF_HILITE) )
1416 {
1417 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1418 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
Aric Stewartc946b1c2000-10-24 21:28:19 +00001419 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
Juergen Schmied466a6521999-05-02 11:21:08 +00001420 --rect.left; --rect.top; --rect.right; --rect.bottom;
1421 }
1422 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1423 }
Aric Stewartc946b1c2000-10-24 21:28:19 +00001424 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001425 }
Juergen Schmied466a6521999-05-02 11:21:08 +00001426
1427 if (hfontOld)
1428 SelectObject (hdc, hfontOld);
Alexandre Julliardf7207251994-07-23 07:57:48 +00001429 }
1430}
1431
1432
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001433/***********************************************************************
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001434 * MENU_DrawPopupMenu
1435 *
1436 * Paint a popup menu.
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001437 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001438static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001439{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001440 HBRUSH hPrevBrush = 0;
1441 RECT rect;
Alexandre Julliard8d24ae61994-04-05 21:42:43 +00001442
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001443 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd, hdc, hmenu);
Juergen Schmied78513941999-04-18 14:40:32 +00001444
Alexandre Julliarda3960291999-02-26 11:11:13 +00001445 GetClientRect( hwnd, &rect );
Alexandre Julliard641ee761997-08-04 16:34:36 +00001446
Alex Korobka44a1b591999-04-01 12:03:52 +00001447 if(TWEAK_WineLook == WIN31_LOOK)
1448 {
Marcus Meissnerddca3151999-05-22 11:33:23 +00001449 rect.bottom -= POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1450 rect.right -= POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER);
Alex Korobka44a1b591999-04-01 12:03:52 +00001451 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001452
Juergen Schmied78513941999-04-18 14:40:32 +00001453 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
1454 && (SelectObject( hdc, hMenuFont)))
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001455 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001456 HPEN hPrevPen;
Alexandre Julliard641ee761997-08-04 16:34:36 +00001457
Alexandre Julliarda3960291999-02-26 11:11:13 +00001458 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001459
Alexandre Julliarda3960291999-02-26 11:11:13 +00001460 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001461 if( hPrevPen )
1462 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001463 INT ropPrev, i;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001464 POPUPMENU *menu;
1465
1466 /* draw 3-d shade */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001467 if(TWEAK_WineLook == WIN31_LOOK) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001468 SelectObject( hdc, hShadeBrush );
1469 SetBkMode( hdc, TRANSPARENT );
1470 ropPrev = SetROP2( hdc, R2_MASKPEN );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001471
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001472 i = rect.right; /* why SetBrushOrg() doesn't? */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001473 PatBlt( hdc, i & 0xfffffffe,
Marcus Meissnerddca3151999-05-22 11:33:23 +00001474 rect.top + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER),
1475 i%2 + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001476 rect.bottom - rect.top, 0x00a000c9 );
1477 i = rect.bottom;
Marcus Meissnerddca3151999-05-22 11:33:23 +00001478 PatBlt( hdc, rect.left + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001479 i & 0xfffffffe,rect.right - rect.left,
Marcus Meissnerddca3151999-05-22 11:33:23 +00001480 i%2 + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER), 0x00a000c9 );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001481 SelectObject( hdc, hPrevPen );
1482 SelectObject( hdc, hPrevBrush );
1483 SetROP2( hdc, ropPrev );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001484 }
1485 else
Alexandre Julliarda3960291999-02-26 11:11:13 +00001486 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001487
1488 /* draw menu items */
1489
Gerard Patel3e629742000-01-17 22:22:16 +00001490 menu = MENU_GetMenu( hmenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001491 if (menu && menu->nItems)
1492 {
1493 MENUITEM *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001494 UINT u;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001495
1496 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
Juergen Schmied78513941999-04-18 14:40:32 +00001497 MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item,
1498 menu->Height, FALSE, ODA_DRAWENTIRE );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001499
1500 }
Juergen Schmied78513941999-04-18 14:40:32 +00001501 } else
1502 {
1503 SelectObject( hdc, hPrevBrush );
1504 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001505 }
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001506}
1507
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001508/***********************************************************************
1509 * MENU_DrawMenuBar
1510 *
1511 * Paint a menu bar. Returns the height of the menu bar.
Juergen Schmied78513941999-04-18 14:40:32 +00001512 * called from [windows/nonclient.c]
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001513 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001514UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1515 BOOL suppress_draw)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001516{
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001517 LPPOPUPMENU lppop;
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00001518 UINT i,retvalue;
Juergen Schmied78513941999-04-18 14:40:32 +00001519 HFONT hfontOld = 0;
Alexandre Julliardde424282001-08-10 22:51:42 +00001520 HMENU hMenu = GetMenu(hwnd);
Juergen Schmied78513941999-04-18 14:40:32 +00001521
Alexandre Julliardde424282001-08-10 22:51:42 +00001522 lppop = MENU_GetMenu( hMenu );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00001523 if (lppop == NULL || lprect == NULL)
1524 {
Marcus Meissnerddca3151999-05-22 11:33:23 +00001525 retvalue = GetSystemMetrics(SM_CYMENU);
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00001526 goto END;
1527 }
Juergen Schmied78513941999-04-18 14:40:32 +00001528
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001529 TRACE("(%04x, %p, %p)\n", hDC, lprect, lppop);
Juergen Schmied78513941999-04-18 14:40:32 +00001530
1531 hfontOld = SelectObject( hDC, hMenuFont);
1532
1533 if (lppop->Height == 0)
1534 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
1535
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001536 lprect->bottom = lprect->top + lppop->Height;
Juergen Schmied78513941999-04-18 14:40:32 +00001537
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00001538 if (suppress_draw)
1539 {
1540 retvalue = lppop->Height;
1541 goto END;
1542 }
Juergen Schmied78513941999-04-18 14:40:32 +00001543
Alexandre Julliarda3960291999-02-26 11:11:13 +00001544 FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001545
Juergen Schmied78513941999-04-18 14:40:32 +00001546 if (TWEAK_WineLook == WIN31_LOOK)
1547 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001548 SelectObject( hDC, GetSysColorPen(COLOR_WINDOWFRAME) );
Alexandre Julliardb0efe282000-08-04 04:18:04 +00001549 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001550 LineTo( hDC, lprect->right, lprect->bottom );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001551 }
Juergen Schmied78513941999-04-18 14:40:32 +00001552 else
1553 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001554 SelectObject( hDC, GetSysColorPen(COLOR_3DFACE));
Alexandre Julliardb0efe282000-08-04 04:18:04 +00001555 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001556 LineTo( hDC, lprect->right, lprect->bottom );
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001557 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001558
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00001559 if (lppop->nItems == 0)
1560 {
Marcus Meissnerddca3151999-05-22 11:33:23 +00001561 retvalue = GetSystemMetrics(SM_CYMENU);
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00001562 goto END;
1563 }
Juergen Schmied78513941999-04-18 14:40:32 +00001564
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001565 for (i = 0; i < lppop->nItems; i++)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001566 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001567 MENU_DrawMenuItem( hwnd, hMenu, hwnd,
1568 hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001569 }
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00001570 retvalue = lppop->Height;
Juergen Schmied78513941999-04-18 14:40:32 +00001571
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00001572END:
Alexandre Julliardde424282001-08-10 22:51:42 +00001573 if (hfontOld) SelectObject (hDC, hfontOld);
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00001574 return retvalue;
Alexandre Julliard2ace16a1996-04-28 15:09:19 +00001575}
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001576
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00001577
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001578/***********************************************************************
1579 * MENU_ShowPopup
1580 *
1581 * Display a popup menu.
1582 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001583static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1584 INT x, INT y, INT xanchor, INT yanchor )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001585{
Alexandre Julliardde424282001-08-10 22:51:42 +00001586 POPUPMENU *menu;
1587 UINT width, height;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001588
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001589 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
Juergen Schmied78513941999-04-18 14:40:32 +00001590 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
1591
Gerard Patel3e629742000-01-17 22:22:16 +00001592 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001593 if (menu->FocusedItem != NO_SELECTED_ITEM)
1594 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001595 menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001596 menu->FocusedItem = NO_SELECTED_ITEM;
1597 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001598
Andreas Mohra6d83eb2000-12-27 04:02:46 +00001599 /* store the owner for DrawItem */
Juergen Schmied78513941999-04-18 14:40:32 +00001600 menu->hwndOwner = hwndOwner;
1601
Alexandre Julliardde424282001-08-10 22:51:42 +00001602
1603 MENU_PopupMenuCalcSize( menu, hwndOwner );
1604
1605 /* adjust popup menu pos so that it fits within the desktop */
1606
1607 width = menu->Width + GetSystemMetrics(SM_CXBORDER);
1608 height = menu->Height + GetSystemMetrics(SM_CYBORDER);
1609
1610 if( x + width > GetSystemMetrics(SM_CXSCREEN ))
Alexandre Julliard0e270f41996-08-24 18:26:35 +00001611 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001612 if( xanchor )
1613 x -= width - xanchor;
1614 if( x + width > GetSystemMetrics(SM_CXSCREEN))
1615 x = GetSystemMetrics(SM_CXSCREEN) - width;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001616 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001617 if( x < 0 ) x = 0;
1618
1619 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1620 {
1621 if( yanchor )
1622 y -= height + yanchor;
1623 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1624 y = GetSystemMetrics(SM_CYSCREEN) - height;
1625 }
1626 if( y < 0 ) y = 0;
1627
1628 if( TWEAK_WineLook == WIN31_LOOK )
1629 {
1630 width += POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER); /* add space for shading */
1631 height += POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1632 }
1633
1634 /* NOTE: In Windows, top menu popup is not owned. */
1635 menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1636 WS_POPUP, x, y, width, height,
1637 hwndOwner, 0, GetWindowLongA(hwndOwner,GWL_HINSTANCE),
1638 (LPVOID)hmenu );
1639 if( !menu->hWnd ) return FALSE;
1640 if (!top_popup) top_popup = menu->hWnd;
1641
1642 /* Display the window */
1643
1644 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1645 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1646 UpdateWindow( menu->hWnd );
1647 return TRUE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001648}
1649
1650
1651/***********************************************************************
1652 * MENU_SelectItem
1653 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001654static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
Rein Klazes80c924f1999-12-12 19:40:46 +00001655 BOOL sendMenuSelect, HMENU topmenu )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001656{
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001657 LPPOPUPMENU lppop;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001658 HDC hdc;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001659
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001660 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
Juergen Schmied78513941999-04-18 14:40:32 +00001661
Gerard Patel3e629742000-01-17 22:22:16 +00001662 lppop = MENU_GetMenu( hmenu );
Gerard Patel8f79fdc2001-05-14 19:20:13 +00001663 if ((!lppop) || (!lppop->nItems) || (!lppop->hWnd)) return;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001664
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001665 if (lppop->FocusedItem == wIndex) return;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001666 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1667 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
Alexandre Julliardf7207251994-07-23 07:57:48 +00001668
Juergen Schmied78513941999-04-18 14:40:32 +00001669 SelectObject( hdc, hMenuFont);
1670
Alexandre Julliardf7207251994-07-23 07:57:48 +00001671 /* Clear previous highlighted item */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001672 if (lppop->FocusedItem != NO_SELECTED_ITEM)
Alexandre Julliardf7207251994-07-23 07:57:48 +00001673 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001674 lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
Juergen Schmied78513941999-04-18 14:40:32 +00001675 MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001676 lppop->Height, !(lppop->wFlags & MF_POPUP),
1677 ODA_SELECT );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001678 }
1679
1680 /* Highlight new item (if any) */
1681 lppop->FocusedItem = wIndex;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001682 if (lppop->FocusedItem != NO_SELECTED_ITEM)
Alexandre Julliardf7207251994-07-23 07:57:48 +00001683 {
Rein Klazes80c924f1999-12-12 19:40:46 +00001684 if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
1685 lppop->items[wIndex].fState |= MF_HILITE;
1686 MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
1687 &lppop->items[wIndex], lppop->Height,
1688 !(lppop->wFlags & MF_POPUP), ODA_SELECT );
1689 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001690 if (sendMenuSelect)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001691 {
1692 MENUITEM *ip = &lppop->items[lppop->FocusedItem];
Juergen Schmied78513941999-04-18 14:40:32 +00001693 SendMessageA( hwndOwner, WM_MENUSELECT,
Rein Klazes80c924f1999-12-12 19:40:46 +00001694 MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
1695 ip->fType | ip->fState | MF_MOUSESELECT |
1696 (lppop->wFlags & MF_SYSMENU)), hmenu);
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001697 }
Alexandre Julliardf7207251994-07-23 07:57:48 +00001698 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001699 else if (sendMenuSelect) {
Rein Klazes80c924f1999-12-12 19:40:46 +00001700 if(topmenu){
1701 int pos;
1702 if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00001703 POPUPMENU *ptm = MENU_GetMenu( topmenu );
Rein Klazes80c924f1999-12-12 19:40:46 +00001704 MENUITEM *ip = &ptm->items[pos];
1705 SendMessageA( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
1706 ip->fType | ip->fState | MF_MOUSESELECT |
1707 (ptm->wFlags & MF_SYSMENU)), topmenu);
1708 }
1709 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001710 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001711 ReleaseDC( lppop->hWnd, hdc );
Alexandre Julliard8d24ae61994-04-05 21:42:43 +00001712}
1713
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001714
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001715/***********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001716 * MENU_MoveSelection
Alexandre Julliard1e37a181996-08-18 16:21:52 +00001717 *
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001718 * Moves currently selected item according to the offset parameter.
1719 * If there is no selection then it should select the last item if
1720 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001721 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001722static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001723{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001724 INT i;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001725 POPUPMENU *menu;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001726
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001727 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner, hmenu, offset);
Juergen Schmied466a6521999-05-02 11:21:08 +00001728
Gerard Patel3e629742000-01-17 22:22:16 +00001729 menu = MENU_GetMenu( hmenu );
1730 if ((!menu) || (!menu->items)) return;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001731
1732 if ( menu->FocusedItem != NO_SELECTED_ITEM )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001733 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001734 if( menu->nItems == 1 ) return; else
Alexandre Julliard1e37a181996-08-18 16:21:52 +00001735 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
1736 ; i += offset)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001737 if (!(menu->items[i].fType & MF_SEPARATOR))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001738 {
Rein Klazes80c924f1999-12-12 19:40:46 +00001739 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001740 return;
1741 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001742 }
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001743
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001744 for ( i = (offset > 0) ? 0 : menu->nItems - 1;
1745 i >= 0 && i < menu->nItems ; i += offset)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001746 if (!(menu->items[i].fType & MF_SEPARATOR))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001747 {
Rein Klazes80c924f1999-12-12 19:40:46 +00001748 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001749 return;
1750 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001751}
1752
1753
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001754/**********************************************************************
1755 * MENU_SetItemData
1756 *
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001757 * Set an item flags, id and text ptr. Called by InsertMenu() and
1758 * ModifyMenu().
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001759 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001760static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id,
Aric Stewartc946b1c2000-10-24 21:28:19 +00001761 LPCWSTR str )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001762{
Aric Stewartc946b1c2000-10-24 21:28:19 +00001763 LPWSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001764
Alexandre Julliard03468f71998-02-15 19:40:49 +00001765 debug_print_menuitem("MENU_SetItemData from: ", item, "");
Gerard Patel2482ef32001-03-19 19:16:21 +00001766 TRACE("flags=%x str=%p\n", flags, str);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001767
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001768 if (IS_STRING_ITEM(flags))
1769 {
Dmitry Timoshkov9316fa32001-02-14 00:23:45 +00001770 if (!str)
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001771 {
1772 flags |= MF_SEPARATOR;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001773 item->text = NULL;
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001774 }
1775 else
1776 {
Aric Stewartc946b1c2000-10-24 21:28:19 +00001777 LPWSTR text;
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001778 /* Item beginning with a backspace is a help item */
1779 if (*str == '\b')
1780 {
1781 flags |= MF_HELP;
1782 str++;
1783 }
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00001784 if (!(text = HeapAlloc( GetProcessHeap(), 0, (strlenW(str)+1) * sizeof(WCHAR) )))
1785 return FALSE;
1786 strcpyW( text, str );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001787 item->text = text;
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001788 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001789 }
Juergen Schmied78513941999-04-18 14:40:32 +00001790 else if (IS_BITMAP_ITEM(flags))
Aric Stewartc946b1c2000-10-24 21:28:19 +00001791 item->text = (LPWSTR)(HBITMAP)LOWORD(str);
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001792 else item->text = NULL;
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001793
Alexandre Julliarda845b881998-06-01 10:44:35 +00001794 if (flags & MF_OWNERDRAW)
1795 item->dwItemData = (DWORD)str;
1796 else
1797 item->dwItemData = 0;
1798
Alexandre Julliard02e90081998-01-04 17:49:09 +00001799 if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001800 DestroyMenu( item->hSubMenu ); /* ModifyMenu() spec */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001801
1802 if (flags & MF_POPUP)
1803 {
Gerard Patel3e629742000-01-17 22:22:16 +00001804 POPUPMENU *menu = MENU_GetMenu((UINT16)id);
1805 if (menu) menu->wFlags |= MF_POPUP;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001806 else
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001807 {
1808 item->wID = 0;
1809 item->hSubMenu = 0;
1810 item->fType = 0;
1811 item->fState = 0;
1812 return FALSE;
1813 }
Alexandre Julliard02e90081998-01-04 17:49:09 +00001814 }
1815
1816 item->wID = id;
1817 if (flags & MF_POPUP)
1818 item->hSubMenu = id;
1819
1820 if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
1821 flags |= MF_POPUP; /* keep popup */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001822
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001823 item->fType = flags & TYPE_MASK;
1824 item->fState = (flags & STATE_MASK) &
1825 ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001826
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001827
1828 /* Don't call SetRectEmpty here! */
1829
1830
Alexandre Julliardda2892c2001-02-23 01:13:42 +00001831 if (prevText) HeapFree( GetProcessHeap(), 0, prevText );
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001832
Alexandre Julliard03468f71998-02-15 19:40:49 +00001833 debug_print_menuitem("MENU_SetItemData to : ", item, "");
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001834 return TRUE;
1835}
1836
1837
1838/**********************************************************************
1839 * MENU_InsertItem
1840 *
1841 * Insert a new item into a menu.
1842 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001843static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001844{
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001845 MENUITEM *newItems;
1846 POPUPMENU *menu;
1847
Gerard Patel3e629742000-01-17 22:22:16 +00001848 if (!(menu = MENU_GetMenu(hMenu)))
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001849 return NULL;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001850
1851 /* Find where to insert new item */
1852
Gerard Patelc6369b02000-05-14 22:52:52 +00001853 if (flags & MF_BYPOSITION) {
1854 if (pos > menu->nItems)
1855 pos = menu->nItems;
Marcus Meissnercb3c7bf2000-01-08 22:25:57 +00001856 } else {
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001857 if (!MENU_FindItem( &hMenu, &pos, flags ))
Gerard Patelc6369b02000-05-14 22:52:52 +00001858 pos = menu->nItems;
1859 else {
1860 if (!(menu = MENU_GetMenu( hMenu )))
1861 return NULL;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001862 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001863 }
1864
1865 /* Create new items array */
1866
Alexandre Julliardda2892c2001-02-23 01:13:42 +00001867 newItems = HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001868 if (!newItems)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001869 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001870 WARN("allocation failed\n" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001871 return NULL;
1872 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001873 if (menu->nItems > 0)
1874 {
Andreas Mohra6d83eb2000-12-27 04:02:46 +00001875 /* Copy the old array into the new one */
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001876 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1877 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001878 (menu->nItems-pos)*sizeof(MENUITEM) );
Alexandre Julliardda2892c2001-02-23 01:13:42 +00001879 HeapFree( GetProcessHeap(), 0, menu->items );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001880 }
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001881 menu->items = newItems;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001882 menu->nItems++;
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001883 memset( &newItems[pos], 0, sizeof(*newItems) );
Gerard Patel6df06941999-09-28 13:05:54 +00001884 menu->Height = 0; /* force size recalculate */
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001885 return &newItems[pos];
1886}
1887
1888
1889/**********************************************************************
1890 * MENU_ParseResource
1891 *
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001892 * Parse a standard menu resource and add items to the menu.
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001893 * Return a pointer to the end of the resource.
1894 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001895static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001896{
1897 WORD flags, id = 0;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001898 LPCSTR str;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001899
1900 do
1901 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001902 flags = GET_WORD(res);
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001903 res += sizeof(WORD);
1904 if (!(flags & MF_POPUP))
1905 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001906 id = GET_WORD(res);
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001907 res += sizeof(WORD);
1908 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001909 if (!IS_STRING_ITEM(flags))
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001910 ERR("not a string item %04x\n", flags );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001911 str = res;
1912 if (!unicode) res += strlen(str) + 1;
Aric Stewartc946b1c2000-10-24 21:28:19 +00001913 else res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001914 if (flags & MF_POPUP)
1915 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001916 HMENU hSubMenu = CreatePopupMenu();
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001917 if (!hSubMenu) return NULL;
1918 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1919 return NULL;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001920 if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
1921 else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001922 }
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001923 else /* Not a popup */
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001924 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001925 if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
1926 else AppendMenuW( hMenu, flags, id,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001927 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001928 }
1929 } while (!(flags & MF_END));
1930 return res;
1931}
1932
1933
Alexandre Julliard641ee761997-08-04 16:34:36 +00001934/**********************************************************************
1935 * MENUEX_ParseResource
1936 *
1937 * Parse an extended menu resource and add items to the menu.
1938 * Return a pointer to the end of the resource.
1939 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001940static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
Alexandre Julliard641ee761997-08-04 16:34:36 +00001941{
Alexandre Julliard641ee761997-08-04 16:34:36 +00001942 WORD resinfo;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001943 do {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001944 MENUITEMINFOW mii;
Alexandre Julliard641ee761997-08-04 16:34:36 +00001945
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001946 mii.cbSize = sizeof(mii);
1947 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
1948 mii.fType = GET_DWORD(res);
Alexandre Julliard641ee761997-08-04 16:34:36 +00001949 res += sizeof(DWORD);
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001950 mii.fState = GET_DWORD(res);
Alexandre Julliard641ee761997-08-04 16:34:36 +00001951 res += sizeof(DWORD);
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001952 mii.wID = GET_DWORD(res);
Alexandre Julliard641ee761997-08-04 16:34:36 +00001953 res += sizeof(DWORD);
1954 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
1955 res += sizeof(WORD);
1956 /* Align the text on a word boundary. */
1957 res += (~((int)res - 1)) & 1;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001958 mii.dwTypeData = (LPWSTR) res;
Aric Stewartc946b1c2000-10-24 21:28:19 +00001959 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
Alexandre Julliard641ee761997-08-04 16:34:36 +00001960 /* Align the following fields on a dword boundary. */
1961 res += (~((int)res - 1)) & 3;
1962
Alexandre Julliardda2892c2001-02-23 01:13:42 +00001963 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1964 mii.fType, mii.fState, mii.wID, resinfo, debugstr_w(mii.dwTypeData));
Alexandre Julliard641ee761997-08-04 16:34:36 +00001965
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001966 if (resinfo & 1) { /* Pop-up? */
Marcus Meissnerde43ef41999-02-28 19:56:59 +00001967 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
Alexandre Julliard641ee761997-08-04 16:34:36 +00001968 res += sizeof(DWORD);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001969 mii.hSubMenu = CreatePopupMenu();
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001970 if (!mii.hSubMenu)
1971 return NULL;
1972 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001973 DestroyMenu(mii.hSubMenu);
Alexandre Julliard641ee761997-08-04 16:34:36 +00001974 return NULL;
Alexandre Julliard641ee761997-08-04 16:34:36 +00001975 }
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001976 mii.fMask |= MIIM_SUBMENU;
1977 mii.fType |= MF_POPUP;
Alexandre Julliard641ee761997-08-04 16:34:36 +00001978 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001979 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
Alexandre Julliard641ee761997-08-04 16:34:36 +00001980 } while (!(resinfo & MF_END));
1981 return res;
1982}
1983
1984
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001985/***********************************************************************
1986 * MENU_GetSubPopup
1987 *
1988 * Return the handle of the selected sub-popup menu (if any).
1989 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001990static HMENU MENU_GetSubPopup( HMENU hmenu )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001991{
1992 POPUPMENU *menu;
1993 MENUITEM *item;
1994
Gerard Patel3e629742000-01-17 22:22:16 +00001995 menu = MENU_GetMenu( hmenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001996
Gerard Patel3e629742000-01-17 22:22:16 +00001997 if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001998
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001999 item = &menu->items[menu->FocusedItem];
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002000 if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
2001 return item->hSubMenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002002 return 0;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002003}
2004
2005
2006/***********************************************************************
2007 * MENU_HideSubPopups
2008 *
2009 * Hide the sub-popup menus of this menu.
2010 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002011static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
2012 BOOL sendMenuSelect )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002013{
Gerard Patel3e629742000-01-17 22:22:16 +00002014 POPUPMENU *menu = MENU_GetMenu( hmenu );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002015
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002016 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
Juergen Schmied466a6521999-05-02 11:21:08 +00002017
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00002018 if (menu && top_popup)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002019 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002020 HMENU hsubmenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002021 POPUPMENU *submenu;
2022 MENUITEM *item;
2023
2024 if (menu->FocusedItem != NO_SELECTED_ITEM)
2025 {
2026 item = &menu->items[menu->FocusedItem];
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002027 if (!(item->fType & MF_POPUP) ||
2028 !(item->fState & MF_MOUSESELECT)) return;
2029 item->fState &= ~MF_MOUSESELECT;
2030 hsubmenu = item->hSubMenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002031 } else return;
2032
Gerard Patel3e629742000-01-17 22:22:16 +00002033 submenu = MENU_GetMenu( hsubmenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002034 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
Rein Klazes80c924f1999-12-12 19:40:46 +00002035 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00002036 DestroyWindow( submenu->hWnd );
2037 submenu->hWnd = 0;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00002038 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002039}
2040
2041
2042/***********************************************************************
2043 * MENU_ShowSubPopup
2044 *
2045 * Display the sub-menu of the selected item of this menu.
2046 * Return the handle of the submenu, or hmenu if no submenu to display.
2047 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002048static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002049 BOOL selectFirst, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002050{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002051 RECT rect;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002052 POPUPMENU *menu;
2053 MENUITEM *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002054 HDC hdc;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002055
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002056 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, selectFirst);
Juergen Schmied466a6521999-05-02 11:21:08 +00002057
Gerard Patel3e629742000-01-17 22:22:16 +00002058 if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002059
Alexandre Julliardde424282001-08-10 22:51:42 +00002060 if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002061
Alexandre Julliard2d93d001996-05-21 15:01:41 +00002062 item = &menu->items[menu->FocusedItem];
Alexandre Julliardde424282001-08-10 22:51:42 +00002063 if (!(item->fType & MF_POPUP) || (item->fState & (MF_GRAYED | MF_DISABLED)))
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002064 return hmenu;
Alexandre Julliard02e90081998-01-04 17:49:09 +00002065
Andreas Mohra6d83eb2000-12-27 04:02:46 +00002066 /* message must be sent before using item,
2067 because nearly everything may be changed by the application ! */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00002068
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002069 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2070 if (!(wFlags & TPM_NONOTIFY))
2071 SendMessageA( hwndOwner, WM_INITMENUPOPUP, item->hSubMenu,
Alexandre Julliard02e90081998-01-04 17:49:09 +00002072 MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
2073
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00002074 item = &menu->items[menu->FocusedItem];
2075 rect = item->rect;
2076
Andreas Mohra6d83eb2000-12-27 04:02:46 +00002077 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
Alexandre Julliard02e90081998-01-04 17:49:09 +00002078 if (!(item->fState & MF_HILITE))
2079 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002080 if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
2081 else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
Juergen Schmied78513941999-04-18 14:40:32 +00002082
2083 SelectObject( hdc, hMenuFont);
2084
Alexandre Julliard02e90081998-01-04 17:49:09 +00002085 item->fState |= MF_HILITE;
Juergen Schmied78513941999-04-18 14:40:32 +00002086 MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002087 ReleaseDC( menu->hWnd, hdc );
Alexandre Julliard02e90081998-01-04 17:49:09 +00002088 }
2089 if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
2090 item->rect = rect;
2091
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002092 item->fState |= MF_MOUSESELECT;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002093
2094 if (IS_SYSTEM_MENU(menu))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002095 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002096 MENU_InitSysMenuPopup(item->hSubMenu,
2097 GetWindowLongA( menu->hWnd, GWL_STYLE ),
2098 GetClassLongA( menu->hWnd, GCL_STYLE));
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002099
Alexandre Julliardde424282001-08-10 22:51:42 +00002100 NC_GetSysPopupPos( menu->hWnd, &rect );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002101 rect.top = rect.bottom;
Marcus Meissnerddca3151999-05-22 11:33:23 +00002102 rect.right = GetSystemMetrics(SM_CXSIZE);
2103 rect.bottom = GetSystemMetrics(SM_CYSIZE);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002104 }
2105 else
2106 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002107 GetWindowRect( menu->hWnd, &rect );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002108 if (menu->wFlags & MF_POPUP)
2109 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002110 rect.left += item->rect.right - GetSystemMetrics(SM_CXBORDER);
2111 rect.top += item->rect.top;
Ken Thomases130f0d82000-05-10 21:38:37 +00002112 rect.right = item->rect.left - item->rect.right + GetSystemMetrics(SM_CXBORDER);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002113 rect.bottom = item->rect.top - item->rect.bottom;
2114 }
2115 else
2116 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002117 rect.left += item->rect.left;
2118 rect.top += item->rect.bottom;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002119 rect.right = item->rect.right - item->rect.left;
2120 rect.bottom = item->rect.bottom - item->rect.top;
2121 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002122 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002123
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002124 MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002125 rect.left, rect.top, rect.right, rect.bottom );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002126 if (selectFirst)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002127 MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2128 return item->hSubMenu;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002129}
2130
Ulrich Czekalla33026a22000-02-26 19:13:44 +00002131
2132
2133/**********************************************************************
2134 * MENU_IsMenuActive
2135 */
2136BOOL MENU_IsMenuActive(void)
2137{
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00002138 return (top_popup != 0);
Ulrich Czekalla33026a22000-02-26 19:13:44 +00002139}
2140
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002141/***********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002142 * MENU_PtMenu
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002143 *
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002144 * Walks menu chain trying to find a menu pt maps to.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002145 */
Alexandre Julliard83f52d12000-09-26 22:20:14 +00002146static HMENU MENU_PtMenu( HMENU hMenu, POINT pt )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002147{
Gerard Patel3e629742000-01-17 22:22:16 +00002148 POPUPMENU *menu = MENU_GetMenu( hMenu );
Alexandre Julliardde424282001-08-10 22:51:42 +00002149 UINT item = menu->FocusedItem;
2150 HMENU ret;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002151
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002152 /* try subpopup first (if any) */
Alexandre Julliardde424282001-08-10 22:51:42 +00002153 ret = (item != NO_SELECTED_ITEM &&
2154 (menu->items[item].fType & MF_POPUP) &&
2155 (menu->items[item].fState & MF_MOUSESELECT))
2156 ? MENU_PtMenu(menu->items[item].hSubMenu, pt) : 0;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002157
Alexandre Julliardde424282001-08-10 22:51:42 +00002158 if (!ret) /* check the current window (avoiding WM_HITTEST) */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002159 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002160 INT ht = NC_HandleNCHitTest( menu->hWnd, pt );
2161 if( menu->wFlags & MF_POPUP )
2162 {
2163 if (ht != HTNOWHERE && ht != HTERROR) ret = hMenu;
2164 }
2165 else if (ht == HTSYSMENU)
2166 ret = get_win_sys_menu( menu->hWnd );
2167 else if (ht == HTMENU)
2168 ret = GetMenu( menu->hWnd );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002169 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002170 return ret;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002171}
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002172
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002173/***********************************************************************
2174 * MENU_ExecFocusedItem
2175 *
2176 * Execute a menu item (for instance when user pressed Enter).
Karl Lessard13409b31999-09-28 16:24:58 +00002177 * Return the wID of the executed item. Otherwise, -1 indicating
Andreas Mohr2e011a52000-06-01 23:28:25 +00002178 * that no menu item was executed;
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002179 * Have to receive the flags for the TrackPopupMenu options to avoid
2180 * sending unwanted message.
2181 *
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002182 */
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002183static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002184{
2185 MENUITEM *item;
Gerard Patel3e629742000-01-17 22:22:16 +00002186 POPUPMENU *menu = MENU_GetMenu( hMenu );
Juergen Schmied466a6521999-05-02 11:21:08 +00002187
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002188 TRACE("%p hmenu=0x%04x\n", pmt, hMenu);
Juergen Schmied466a6521999-05-02 11:21:08 +00002189
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002190 if (!menu || !menu->nItems ||
Karl Lessard13409b31999-09-28 16:24:58 +00002191 (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002192
Alexandre Julliard2d93d001996-05-21 15:01:41 +00002193 item = &menu->items[menu->FocusedItem];
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002194
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002195 TRACE("%08x %08x %08x\n",
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002196 hMenu, item->wID, item->hSubMenu);
2197
2198 if (!(item->fType & MF_POPUP))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002199 {
Francois Gouget93fd46a2000-10-23 00:37:49 +00002200 if (!(item->fState & (MF_GRAYED | MF_DISABLED)) && !(item->fType & MF_SEPARATOR))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002201 {
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002202 /* If TPM_RETURNCMD is set you return the id, but
2203 do not send a message to the owner */
2204 if(!(wFlags & TPM_RETURNCMD))
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002205 {
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002206 if( menu->wFlags & MF_SYSMENU )
2207 PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2208 MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2209 else
2210 PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002211 }
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00002212 return item->wID;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002213 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002214 }
2215 else
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002216 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002217
Karl Lessard13409b31999-09-28 16:24:58 +00002218 return -1;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002219}
2220
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002221/***********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002222 * MENU_SwitchTracking
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002223 *
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002224 * Helper function for menu navigation routines.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002225 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002226static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002227{
Gerard Patel3e629742000-01-17 22:22:16 +00002228 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2229 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002230
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002231 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt, hPtMenu, id);
Juergen Schmied466a6521999-05-02 11:21:08 +00002232
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002233 if( pmt->hTopMenu != hPtMenu &&
2234 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002235 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002236 /* both are top level menus (system and menu-bar) */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002237 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
Rein Klazes80c924f1999-12-12 19:40:46 +00002238 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002239 pmt->hTopMenu = hPtMenu;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002240 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002241 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
Rein Klazes80c924f1999-12-12 19:40:46 +00002242 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002243}
2244
2245
2246/***********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002247 * MENU_ButtonDown
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002248 *
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002249 * Return TRUE if we can go on with menu tracking.
2250 */
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002251static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002252{
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002253 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
Juergen Schmied466a6521999-05-02 11:21:08 +00002254
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002255 if (hPtMenu)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002256 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002257 UINT id = 0;
Gerard Patel3e629742000-01-17 22:22:16 +00002258 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002259 MENUITEM *item;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002260
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002261 if( IS_SYSTEM_MENU(ptmenu) )
2262 item = ptmenu->items;
2263 else
2264 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002265
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002266 if( item )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002267 {
Pascal Lessard2eb0a301999-09-03 16:38:52 +00002268 if( ptmenu->FocusedItem != id )
2269 MENU_SwitchTracking( pmt, hPtMenu, id );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002270
Pascal Lessard2eb0a301999-09-03 16:38:52 +00002271 /* If the popup menu is not already "popped" */
2272 if(!(item->fState & MF_MOUSESELECT ))
Pascal Lessard07c447f1999-09-19 12:03:25 +00002273 {
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002274 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002275
Andreas Mohra6d83eb2000-12-27 04:02:46 +00002276 /* In win31, a newly popped menu always remains opened for the next buttonup */
Pascal Lessard07c447f1999-09-19 12:03:25 +00002277 if(TWEAK_WineLook == WIN31_LOOK)
2278 ptmenu->bTimeToHide = FALSE;
2279 }
2280
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002281 return TRUE;
2282 }
Pascal Lessard445c9101999-09-20 18:27:14 +00002283 /* Else the click was on the menu bar, finish the tracking */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002284 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002285 return FALSE;
2286}
2287
2288/***********************************************************************
2289 * MENU_ButtonUp
2290 *
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002291 * Return the value of MENU_ExecFocusedItem if
2292 * the selected item was not a popup. Else open the popup.
Karl Lessard13409b31999-09-28 16:24:58 +00002293 * A -1 return value indicates that we go on with menu tracking.
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002294 *
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002295 */
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002296static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002297{
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002298 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
Juergen Schmied466a6521999-05-02 11:21:08 +00002299
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002300 if (hPtMenu)
2301 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002302 UINT id = 0;
Gerard Patel3e629742000-01-17 22:22:16 +00002303 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002304 MENUITEM *item;
2305
2306 if( IS_SYSTEM_MENU(ptmenu) )
2307 item = ptmenu->items;
2308 else
2309 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2310
Alexandre Julliard491502b1997-11-01 19:08:16 +00002311 if( item && (ptmenu->FocusedItem == id ))
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002312 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002313 if( !(item->fType & MF_POPUP) )
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002314 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002315
Andreas Mohra6d83eb2000-12-27 04:02:46 +00002316 /* If we are dealing with the top-level menu */
2317 /* and this is a click on an already "popped" item: */
2318 /* Stop the menu tracking and close the opened submenus */
Pascal Lessard2eb0a301999-09-03 16:38:52 +00002319 if((pmt->hTopMenu == hPtMenu) && (ptmenu->bTimeToHide == TRUE))
Karl Lessard13409b31999-09-28 16:24:58 +00002320 return 0;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002321 }
Pascal Lessard2eb0a301999-09-03 16:38:52 +00002322 ptmenu->bTimeToHide = TRUE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002323 }
Karl Lessard13409b31999-09-28 16:24:58 +00002324 return -1;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002325}
2326
2327
2328/***********************************************************************
2329 * MENU_MouseMove
2330 *
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002331 * Return TRUE if we can go on with menu tracking.
2332 */
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002333static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002334{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002335 UINT id = NO_SELECTED_ITEM;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002336 POPUPMENU *ptmenu = NULL;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002337
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002338 if( hPtMenu )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002339 {
Gerard Patel3e629742000-01-17 22:22:16 +00002340 ptmenu = MENU_GetMenu( hPtMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002341 if( IS_SYSTEM_MENU(ptmenu) )
2342 id = 0;
2343 else
2344 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2345 }
2346
2347 if( id == NO_SELECTED_ITEM )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002348 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002349 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
Rein Klazes80c924f1999-12-12 19:40:46 +00002350 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2351
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002352 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002353 else if( ptmenu->FocusedItem != id )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002354 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002355 MENU_SwitchTracking( pmt, hPtMenu, id );
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002356 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002357 }
2358 return TRUE;
2359}
2360
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002361
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002362/***********************************************************************
2363 * MENU_DoNextMenu
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002364 *
2365 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002366 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002367static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002368{
Gerard Patel3e629742000-01-17 22:22:16 +00002369 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002370
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002371 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2372 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2373 {
Alexandre Julliardb3ec0302001-08-18 18:10:04 +00002374 MDINEXTMENU next_menu;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002375 HMENU hNewMenu;
2376 HWND hNewWnd;
2377 UINT id = 0;
Alexandre Julliardb3ec0302001-08-18 18:10:04 +00002378
2379 next_menu.hmenuIn = (IS_SYSTEM_MENU(menu)) ? GetSubMenu(pmt->hTopMenu,0) : pmt->hTopMenu;
2380 next_menu.hmenuNext = 0;
2381 next_menu.hwndNext = 0;
2382 SendMessageW( pmt->hOwnerWnd, WM_NEXTMENU, vk, (LPARAM)&next_menu );
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002383
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002384 TRACE("%04x [%04x] -> %04x [%04x]\n",
Alexandre Julliardb3ec0302001-08-18 18:10:04 +00002385 pmt->hCurrentMenu, pmt->hOwnerWnd, next_menu.hmenuNext, next_menu.hwndNext );
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002386
Alexandre Julliardb3ec0302001-08-18 18:10:04 +00002387 if (!next_menu.hmenuNext || !next_menu.hwndNext)
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002388 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002389 DWORD style = GetWindowLongA( pmt->hOwnerWnd, GWL_STYLE );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002390 hNewWnd = pmt->hOwnerWnd;
2391 if( IS_SYSTEM_MENU(menu) )
2392 {
2393 /* switch to the menu bar */
2394
Alexandre Julliardde424282001-08-10 22:51:42 +00002395 if(style & WS_CHILD || !(hNewMenu = GetMenu(hNewWnd))) return FALSE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002396
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002397 if( vk == VK_LEFT )
2398 {
Gerard Patel3e629742000-01-17 22:22:16 +00002399 menu = MENU_GetMenu( hNewMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002400 id = menu->nItems - 1;
2401 }
2402 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002403 else if (style & WS_SYSMENU )
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002404 {
2405 /* switch to the system menu */
Alexandre Julliardde424282001-08-10 22:51:42 +00002406 hNewMenu = get_win_sys_menu( hNewWnd );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002407 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002408 else return FALSE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002409 }
2410 else /* application returned a new menu to switch to */
2411 {
Alexandre Julliardb3ec0302001-08-18 18:10:04 +00002412 hNewMenu = next_menu.hmenuNext;
Alexandre Julliardf44bbb82001-09-14 00:24:39 +00002413 hNewWnd = WIN_GetFullHandle( next_menu.hwndNext );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002414
Alexandre Julliarda3960291999-02-26 11:11:13 +00002415 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002416 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002417 DWORD style = GetWindowLongA( hNewWnd, GWL_STYLE );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002418
Alexandre Julliardde424282001-08-10 22:51:42 +00002419 if (style & WS_SYSMENU &&
2420 GetSubMenu(get_win_sys_menu(hNewWnd), 0) == hNewMenu )
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002421 {
2422 /* get the real system menu */
Alexandre Julliardde424282001-08-10 22:51:42 +00002423 hNewMenu = get_win_sys_menu(hNewWnd);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002424 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002425 else if (style & WS_CHILD || GetMenu(hNewWnd) != hNewMenu )
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002426 {
Andreas Mohra6d83eb2000-12-27 04:02:46 +00002427 /* FIXME: Not sure what to do here;
2428 * perhaps try to track hNewMenu as a popup? */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002429
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002430 TRACE(" -- got confused.\n");
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002431 return FALSE;
2432 }
2433 }
2434 else return FALSE;
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002435 }
2436
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002437 if( hNewMenu != pmt->hTopMenu )
2438 {
Rein Klazes80c924f1999-12-12 19:40:46 +00002439 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
2440 FALSE, 0 );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002441 if( pmt->hCurrentMenu != pmt->hTopMenu )
2442 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2443 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002444
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002445 if( hNewWnd != pmt->hOwnerWnd )
2446 {
2447 ReleaseCapture();
2448 pmt->hOwnerWnd = hNewWnd;
2449 EVENT_Capture( pmt->hOwnerWnd, HTMENU );
2450 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002451
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002452 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
Rein Klazes80c924f1999-12-12 19:40:46 +00002453 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002454
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002455 return TRUE;
2456 }
2457 return FALSE;
2458}
2459
2460/***********************************************************************
2461 * MENU_SuspendPopup
2462 *
2463 * The idea is not to show the popup if the next input message is
2464 * going to hide it anyway.
2465 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002466static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002467{
Juergen Schmied78513941999-04-18 14:40:32 +00002468 MSG msg;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002469
2470 msg.hwnd = pmt->hOwnerWnd;
2471
Juergen Schmied78513941999-04-18 14:40:32 +00002472 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002473 pmt->trackFlags |= TF_SKIPREMOVE;
2474
2475 switch( uMsg )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002476 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002477 case WM_KEYDOWN:
Juergen Schmied78513941999-04-18 14:40:32 +00002478 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002479 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2480 {
Juergen Schmied78513941999-04-18 14:40:32 +00002481 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2482 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002483 if( msg.message == WM_KEYDOWN &&
2484 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2485 {
2486 pmt->trackFlags |= TF_SUSPENDPOPUP;
2487 return TRUE;
2488 }
2489 }
2490 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002491 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002492
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002493 /* failures go through this */
2494 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2495 return FALSE;
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002496}
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002497
2498/***********************************************************************
Ulrich Czekalla18ce3882001-05-18 23:20:20 +00002499 * MENU_KeyEscape
2500 *
2501 * Handle a VK_ESCAPE key event in a menu.
2502 */
2503static BOOL MENU_KeyEscape(MTRACKER* pmt, UINT wFlags)
2504{
2505 BOOL bEndMenu = TRUE;
2506
2507 if (pmt->hCurrentMenu != pmt->hTopMenu)
2508 {
2509 POPUPMENU *menu = MENU_GetMenu(pmt->hCurrentMenu);
2510
2511 if (menu->wFlags & MF_POPUP)
2512 {
2513 HMENU hmenutmp, hmenuprev;
2514
2515 hmenuprev = hmenutmp = pmt->hTopMenu;
2516
2517 /* close topmost popup */
2518 while (hmenutmp != pmt->hCurrentMenu)
2519 {
2520 hmenuprev = hmenutmp;
2521 hmenutmp = MENU_GetSubPopup( hmenuprev );
2522 }
2523
2524 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2525 pmt->hCurrentMenu = hmenuprev;
2526 bEndMenu = FALSE;
2527 }
2528 }
2529
2530 return bEndMenu;
2531}
2532
2533/***********************************************************************
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002534 * MENU_KeyLeft
2535 *
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002536 * Handle a VK_LEFT key event in a menu.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002537 */
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002538static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002539{
2540 POPUPMENU *menu;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002541 HMENU hmenutmp, hmenuprev;
2542 UINT prevcol;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002543
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002544 hmenuprev = hmenutmp = pmt->hTopMenu;
Gerard Patel3e629742000-01-17 22:22:16 +00002545 menu = MENU_GetMenu( hmenutmp );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002546
Alexandre Julliard641ee761997-08-04 16:34:36 +00002547 /* Try to move 1 column left (if possible) */
2548 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
2549 NO_SELECTED_ITEM ) {
2550
2551 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
Rein Klazes80c924f1999-12-12 19:40:46 +00002552 prevcol, TRUE, 0 );
Alexandre Julliard641ee761997-08-04 16:34:36 +00002553 return;
2554 }
2555
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002556 /* close topmost popup */
2557 while (hmenutmp != pmt->hCurrentMenu)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002558 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002559 hmenuprev = hmenutmp;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002560 hmenutmp = MENU_GetSubPopup( hmenuprev );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002561 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002562
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002563 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2564 pmt->hCurrentMenu = hmenuprev;
2565
2566 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002567 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002568 /* move menu bar selection if no more popups are left */
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002569
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002570 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2571 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002572
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002573 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002574 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002575 /* A sublevel menu was displayed - display the next one
2576 * unless there is another displacement coming up */
2577
2578 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002579 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2580 pmt->hTopMenu, TRUE, wFlags);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002581 }
2582 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002583}
2584
2585
2586/***********************************************************************
2587 * MENU_KeyRight
2588 *
2589 * Handle a VK_RIGHT key event in a menu.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002590 */
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002591static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002592{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002593 HMENU hmenutmp;
Gerard Patel3e629742000-01-17 22:22:16 +00002594 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002595 UINT nextcol;
Alexandre Julliard641ee761997-08-04 16:34:36 +00002596
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002597 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
Alexandre Julliard641ee761997-08-04 16:34:36 +00002598 pmt->hCurrentMenu,
Aric Stewartc946b1c2000-10-24 21:28:19 +00002599 debugstr_w((MENU_GetMenu(pmt->hCurrentMenu))->
2600 items[0].text),
2601 pmt->hTopMenu, debugstr_w(menu->items[0].text) );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002602
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002603 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002604 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002605 /* If already displaying a popup, try to display sub-popup */
2606
2607 hmenutmp = pmt->hCurrentMenu;
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002608 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002609
2610 /* if subpopup was displayed then we are done */
2611 if (hmenutmp != pmt->hCurrentMenu) return;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002612 }
2613
Alexandre Julliard641ee761997-08-04 16:34:36 +00002614 /* Check to see if there's another column */
2615 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
2616 NO_SELECTED_ITEM ) {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002617 TRACE("Going to %d.\n", nextcol );
Alexandre Julliard641ee761997-08-04 16:34:36 +00002618 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
Rein Klazes80c924f1999-12-12 19:40:46 +00002619 nextcol, TRUE, 0 );
Alexandre Julliard641ee761997-08-04 16:34:36 +00002620 return;
2621 }
2622
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002623 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002624 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002625 if( pmt->hCurrentMenu != pmt->hTopMenu )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002626 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002627 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2628 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2629 } else hmenutmp = 0;
2630
2631 /* try to move to the next item */
2632 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2633 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2634
2635 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2636 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002637 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2638 pmt->hTopMenu, TRUE, wFlags);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002639 }
2640}
2641
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002642/***********************************************************************
2643 * MENU_TrackMenu
2644 *
2645 * Menu tracking code.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002646 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002647static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2648 HWND hwnd, const RECT *lprect )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002649{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002650 MSG msg;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002651 POPUPMENU *menu;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002652 BOOL fRemove;
Karl Lessard13409b31999-09-28 16:24:58 +00002653 INT executedMenuId = -1;
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002654 MTRACKER mt;
Francis Beaudet7ed1af31999-08-15 16:58:03 +00002655 BOOL enterIdleSent = FALSE;
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002656
2657 mt.trackFlags = 0;
2658 mt.hCurrentMenu = hmenu;
2659 mt.hTopMenu = hmenu;
Alexandre Julliardf44bbb82001-09-14 00:24:39 +00002660 mt.hOwnerWnd = WIN_GetFullHandle( hwnd );
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002661 mt.pt.x = x;
2662 mt.pt.y = y;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002663
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002664 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
Juergen Schmiedc77fd5b1999-04-21 14:27:37 +00002665 hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
2666 (lprect) ? lprect->right : 0, (lprect) ? lprect->bottom : 0);
Juergen Schmied78513941999-04-18 14:40:32 +00002667
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002668 fEndMenu = FALSE;
Gerard Patel3e629742000-01-17 22:22:16 +00002669 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002670
Pascal Lessardae6de762000-01-09 02:38:02 +00002671 if (wFlags & TPM_BUTTONDOWN)
2672 {
2673 /* Get the result in order to start the tracking or not */
2674 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2675 fEndMenu = !fRemove;
2676 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002677
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002678 EVENT_Capture( mt.hOwnerWnd, HTMENU );
2679
2680 while (!fEndMenu)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002681 {
Gerard Patel3e629742000-01-17 22:22:16 +00002682 menu = MENU_GetMenu( mt.hCurrentMenu );
Marcus Meissner4a699392001-02-13 01:49:06 +00002683 if (!menu) /* sometimes happens if I do a window manager close */
2684 break;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002685
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002686 /* we have to keep the message in the queue until it's
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002687 * clear that menu loop is not over yet. */
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002688
Alexandre Julliardbfb4a232001-08-06 18:05:47 +00002689 for (;;)
2690 {
2691 if (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
2692 {
2693 if (!CallMsgFilterA( &msg, MSGF_MENU )) break;
2694 /* remove the message from the queue */
2695 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2696 }
2697 else
2698 {
2699 if (!enterIdleSent)
2700 {
2701 HWND win = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2702 enterIdleSent = TRUE;
2703 SendMessageW( mt.hOwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM)win );
2704 }
2705 WaitMessage();
2706 }
2707 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002708
Rob Farnumb2007932000-05-23 23:34:17 +00002709 /* check if EndMenu() tried to cancel us, by posting this message */
2710 if(msg.message == WM_CANCELMODE)
2711 {
2712 /* we are now out of the loop */
2713 fEndMenu = TRUE;
2714
2715 /* remove the message from the queue */
2716 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2717
2718 /* break out of internal loop, ala ESCAPE */
2719 break;
2720 }
2721
Alexandre Julliarda3960291999-02-26 11:11:13 +00002722 TranslateMessage( &msg );
Stephane Lussierb3a99de1999-02-09 15:35:12 +00002723 mt.pt = msg.pt;
Alexandre Julliardac9c9b01996-07-28 18:50:11 +00002724
Francis Beaudet7ed1af31999-08-15 16:58:03 +00002725 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2726 enterIdleSent=FALSE;
2727
Alexandre Julliarde2abbb11995-03-19 17:39:39 +00002728 fRemove = FALSE;
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002729 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002730 {
Louis Philippe Gagnon9cdd22c2000-11-27 22:39:35 +00002731 /*
2732 * use the mouse coordinates in lParam instead of those in the MSG
2733 * struct to properly handle synthetic messages. lParam coords are
2734 * relative to client area, so they must be converted; since they can
2735 * be negative, we must use SLOWORD/SHIWORD instead of LOWORD/HIWORD.
2736 */
2737 mt.pt.x = SLOWORD(msg.lParam);
2738 mt.pt.y = SHIWORD(msg.lParam);
2739 ClientToScreen(msg.hwnd,&mt.pt);
2740
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002741 /* Find a menu for this mouse event */
Louis Philippe Gagnon9cdd22c2000-11-27 22:39:35 +00002742 hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002743
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002744 switch(msg.message)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002745 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002746 /* no WM_NC... messages in captured state */
2747
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002748 case WM_RBUTTONDBLCLK:
2749 case WM_RBUTTONDOWN:
2750 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2751 /* fall through */
2752 case WM_LBUTTONDBLCLK:
2753 case WM_LBUTTONDOWN:
Karl Lessard4a0a7df1999-11-07 05:17:10 +00002754 /* If the message belongs to the menu, removes it from the queue */
2755 /* Else, end menu tracking */
2756 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2757 fEndMenu = !fRemove;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002758 break;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002759
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002760 case WM_RBUTTONUP:
2761 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2762 /* fall through */
2763 case WM_LBUTTONUP:
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00002764 /* Check if a menu was selected by the mouse */
2765 if (hmenu)
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002766 {
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002767 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00002768
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002769 /* End the loop if executedMenuId is an item ID */
Karl Lessard13409b31999-09-28 16:24:58 +00002770 /* or if the job was done (executedMenuId = 0). */
2771 fEndMenu = fRemove = (executedMenuId != -1);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002772 }
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00002773 /* No menu was selected by the mouse */
2774 /* if the function was called by TrackPopupMenu, continue
2775 with the menu tracking. If not, stop it */
2776 else
2777 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
2778
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002779 break;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002780
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002781 case WM_MOUSEMOVE:
Alexandre Julliard8da12c41999-01-17 16:55:11 +00002782 /* In win95 winelook, the selected menu item must be changed every time the
2783 mouse moves. In Win31 winelook, the mouse button has to be held down */
2784
2785 if ( (TWEAK_WineLook > WIN31_LOOK) ||
2786 ( (msg.wParam & MK_LBUTTON) ||
2787 ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) )
2788
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002789 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
Alexandre Julliard8da12c41999-01-17 16:55:11 +00002790
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002791 } /* switch(msg.message) - mouse */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002792 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002793 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002794 {
Alexandre Julliarde2abbb11995-03-19 17:39:39 +00002795 fRemove = TRUE; /* Keyboard messages are always removed */
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002796 switch(msg.message)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002797 {
2798 case WM_KEYDOWN:
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002799 switch(msg.wParam)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002800 {
2801 case VK_HOME:
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002802 case VK_END:
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002803 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
Rein Klazes80c924f1999-12-12 19:40:46 +00002804 NO_SELECTED_ITEM, FALSE, 0 );
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002805 /* fall through */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002806 case VK_UP:
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002807 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002808 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002809 break;
2810
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002811 case VK_DOWN: /* If on menu bar, pull-down the menu */
2812
Gerard Patel3e629742000-01-17 22:22:16 +00002813 menu = MENU_GetMenu( mt.hCurrentMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002814 if (!(menu->wFlags & MF_POPUP))
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002815 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002816 else /* otherwise try to move selection */
2817 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002818 break;
2819
2820 case VK_LEFT:
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002821 MENU_KeyLeft( &mt, wFlags );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002822 break;
2823
2824 case VK_RIGHT:
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002825 MENU_KeyRight( &mt, wFlags );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002826 break;
2827
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002828 case VK_ESCAPE:
Ulrich Czekalla18ce3882001-05-18 23:20:20 +00002829 fEndMenu = MENU_KeyEscape(&mt, wFlags);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002830 break;
2831
Ulrich Czekalla33026a22000-02-26 19:13:44 +00002832 case VK_F1:
2833 {
2834 HELPINFO hi;
2835 hi.cbSize = sizeof(HELPINFO);
2836 hi.iContextType = HELPINFO_MENUITEM;
2837 if (menu->FocusedItem == NO_SELECTED_ITEM)
2838 hi.iCtrlId = 0;
2839 else
2840 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
2841 hi.hItemHandle = hmenu;
2842 hi.dwContextId = menu->dwContextHelpID;
2843 hi.MousePos = msg.pt;
2844 SendMessageA(hwnd, WM_HELP, 0, (LPARAM)&hi);
2845 break;
2846 }
2847
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002848 default:
2849 break;
2850 }
2851 break; /* WM_KEYDOWN */
2852
2853 case WM_SYSKEYDOWN:
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002854 switch(msg.wParam)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002855 {
2856 case VK_MENU:
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002857 fEndMenu = TRUE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002858 break;
2859
2860 }
2861 break; /* WM_SYSKEYDOWN */
2862
2863 case WM_CHAR:
2864 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002865 UINT pos;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002866
Norman Stevensa83d0651998-10-12 07:25:35 +00002867 if (msg.wParam == '\r' || msg.wParam == ' ')
2868 {
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002869 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
Karl Lessard13409b31999-09-28 16:24:58 +00002870 fEndMenu = (executedMenuId != -1);
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00002871
Norman Stevensa83d0651998-10-12 07:25:35 +00002872 break;
2873 }
2874
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002875 /* Hack to avoid control chars. */
2876 /* We will find a better way real soon... */
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002877 if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002878
2879 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
Stephane Lussierb3a99de1999-02-09 15:35:12 +00002880 LOWORD(msg.wParam), FALSE );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002881 if (pos == (UINT)-2) fEndMenu = TRUE;
2882 else if (pos == (UINT)-1) MessageBeep(0);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002883 else
2884 {
Rein Klazes80c924f1999-12-12 19:40:46 +00002885 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
2886 TRUE, 0 );
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002887 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
Karl Lessard13409b31999-09-28 16:24:58 +00002888 fEndMenu = (executedMenuId != -1);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002889 }
2890 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002891 break;
2892 } /* switch(msg.message) - kbd */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002893 }
2894 else
2895 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002896 DispatchMessageA( &msg );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002897 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002898
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002899 if (!fEndMenu) fRemove = TRUE;
2900
2901 /* finally remove message from the queue */
2902
2903 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
Alexandre Julliarda3960291999-02-26 11:11:13 +00002904 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002905 else mt.trackFlags &= ~TF_SKIPREMOVE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002906 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002907
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002908 ReleaseCapture();
Juergen Schmiedc77fd5b1999-04-21 14:27:37 +00002909
Guy Albertellif12b70a2000-05-11 00:06:11 +00002910 /* If dropdown is still painted and the close box is clicked on
2911 then the menu will be destroyed as part of the DispatchMessage above.
2912 This will then invalidate the menu handle in mt.hTopMenu. We should
2913 check for this first. */
2914 if( IsMenu( mt.hTopMenu ) )
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00002915 {
Guy Albertellif12b70a2000-05-11 00:06:11 +00002916 menu = MENU_GetMenu( mt.hTopMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002917
Guy Albertellif12b70a2000-05-11 00:06:11 +00002918 if( IsWindow( mt.hOwnerWnd ) )
2919 {
2920 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
2921
2922 if (menu && menu->wFlags & MF_POPUP)
2923 {
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00002924 DestroyWindow( menu->hWnd );
2925 menu->hWnd = 0;
Guy Albertellif12b70a2000-05-11 00:06:11 +00002926 }
2927 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2928 SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
2929 }
2930
2931 /* Reset the variable for hiding menu */
2932 if( menu ) menu->bTimeToHide = FALSE;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00002933 }
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00002934
Juergen Schmied371c4201999-10-13 12:27:44 +00002935 /* The return value is only used by TrackPopupMenu */
2936 return ((executedMenuId != -1) ? executedMenuId : 0);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002937}
2938
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002939/***********************************************************************
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002940 * MENU_InitTracking
2941 */
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002942static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002943{
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002944 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd, hMenu);
Juergen Schmied78513941999-04-18 14:40:32 +00002945
Alexandre Julliarda3960291999-02-26 11:11:13 +00002946 HideCaret(0);
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002947
2948 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2949 if (!(wFlags & TPM_NONOTIFY))
2950 SendMessageA( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
2951
Alexandre Julliardd23a82b2001-09-19 20:37:04 +00002952 SendMessageA( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002953
2954 if (!(wFlags & TPM_NONOTIFY))
Gerard Patelcf2ff272001-03-14 17:24:59 +00002955 {
2956 POPUPMENU *menu;
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002957 SendMessageA( hWnd, WM_INITMENU, hMenu, 0 );
Gerard Patelcf2ff272001-03-14 17:24:59 +00002958 if ((menu = MENU_GetMenu( hMenu )) && (!menu->Height))
2959 { /* app changed/recreated menu bar entries in WM_INITMENU
2960 Recalculate menu sizes else clicks will not work */
Gerard Patel326b2802001-07-17 00:43:22 +00002961 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
2962 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
2963
Gerard Patelcf2ff272001-03-14 17:24:59 +00002964 }
2965 }
Juergen Schmied78513941999-04-18 14:40:32 +00002966 return TRUE;
2967}
2968/***********************************************************************
2969 * MENU_ExitTracking
2970 */
2971static BOOL MENU_ExitTracking(HWND hWnd)
2972{
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002973 TRACE("hwnd=0x%04x\n", hWnd);
Juergen Schmied78513941999-04-18 14:40:32 +00002974
2975 SendMessageA( hWnd, WM_EXITMENULOOP, 0, 0 );
2976 ShowCaret(0);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002977 return TRUE;
2978}
2979
2980/***********************************************************************
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002981 * MENU_TrackMouseMenuBar
2982 *
2983 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2984 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002985void MENU_TrackMouseMenuBar( HWND hWnd, INT ht, POINT pt )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002986{
Alexandre Julliardde424282001-08-10 22:51:42 +00002987 HMENU hMenu = (ht == HTSYSMENU) ? get_win_sys_menu( hWnd ) : GetMenu( hWnd );
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002988 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002989
Alexandre Julliardde424282001-08-10 22:51:42 +00002990 TRACE("wnd=%x ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y);
Juergen Schmied78513941999-04-18 14:40:32 +00002991
Alexandre Julliarda3960291999-02-26 11:11:13 +00002992 if (IsMenu(hMenu))
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002993 {
Alexandre Julliardb662e112001-10-16 21:52:26 +00002994 /* map point to parent client coordinates */
2995 HWND parent = GetAncestor( hWnd, GA_PARENT );
2996 if (parent != GetDesktopWindow()) ScreenToClient( parent, &pt );
2997
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002998 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
2999 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
Juergen Schmied78513941999-04-18 14:40:32 +00003000 MENU_ExitTracking(hWnd);
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003001 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003002}
3003
3004
3005/***********************************************************************
3006 * MENU_TrackKbdMenuBar
3007 *
3008 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3009 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003010void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, INT vkey)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003011{
Alexandre Julliardde424282001-08-10 22:51:42 +00003012 UINT uItem = NO_SELECTED_ITEM;
3013 HMENU hTrackMenu;
3014 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00003015
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003016 /* find window that has a menu */
Alexandre Julliardde424282001-08-10 22:51:42 +00003017
3018 while (GetWindowLongA( hwnd, GWL_STYLE ) & WS_CHILD)
3019 if (!(hwnd = GetParent( hwnd ))) return;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00003020
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003021 /* check if we have to track a system menu */
Alexandre Julliardde424282001-08-10 22:51:42 +00003022
3023 hTrackMenu = GetMenu( hwnd );
3024 if (!hTrackMenu || IsIconic(hwnd) || vkey == VK_SPACE )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003025 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003026 if (!(GetWindowLongA( hwnd, GWL_STYLE ) & WS_SYSMENU)) return;
3027 hTrackMenu = get_win_sys_menu( hwnd );
3028 uItem = 0;
3029 wParam |= HTSYSMENU; /* prevent item lookup */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003030 }
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00003031
Alexandre Julliardde424282001-08-10 22:51:42 +00003032 if (!IsMenu( hTrackMenu )) return;
3033
3034 MENU_InitTracking( hwnd, hTrackMenu, FALSE, wFlags );
3035
3036 if( vkey && vkey != VK_SPACE )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003037 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003038 uItem = MENU_FindItemByKey( hwnd, hTrackMenu, vkey, (wParam & HTSYSMENU) );
3039 if( uItem >= (UINT)(-2) )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003040 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003041 if( uItem == (UINT)(-1) ) MessageBeep(0);
3042 hTrackMenu = 0;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003043 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003044 }
Alexandre Julliardde424282001-08-10 22:51:42 +00003045
3046 if( hTrackMenu )
3047 {
3048 MENU_SelectItem( hwnd, hTrackMenu, uItem, TRUE, 0 );
3049
3050 if( uItem == NO_SELECTED_ITEM )
3051 MENU_MoveSelection( hwnd, hTrackMenu, ITEM_NEXT );
3052 else if( vkey )
3053 PostMessageA( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
3054
3055 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
3056 }
3057 MENU_ExitTracking( hwnd );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003058}
3059
3060
3061/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003062 * TrackPopupMenu (USER32.@)
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00003063 *
3064 * Like the win32 API, the function return the command ID only if the
3065 * flag TPM_RETURNCMD is on.
3066 *
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00003067 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003068BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3069 INT nReserved, HWND hWnd, const RECT *lpRect )
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00003070{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003071 BOOL ret = FALSE;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003072
Abey Georgeb59d4bc1999-09-22 15:10:42 +00003073 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3074
3075 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3076 if (!(wFlags & TPM_NONOTIFY))
3077 SendMessageA( hWnd, WM_INITMENUPOPUP, hMenu, 0);
3078
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00003079 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00003080 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
Juergen Schmied78513941999-04-18 14:40:32 +00003081 MENU_ExitTracking(hWnd);
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00003082
3083 if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
3084 ret = 1;
3085
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003086 return ret;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00003087}
3088
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003089/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003090 * TrackPopupMenuEx (USER32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003091 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003092BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3093 HWND hWnd, LPTPMPARAMS lpTpm )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003094{
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003095 FIXME("not fully implemented\n" );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003096 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003097 lpTpm ? &lpTpm->rcExclude : NULL );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003098}
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00003099
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003100/***********************************************************************
3101 * PopupMenuWndProc
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003102 *
3103 * NOTE: Windows has totally different (and undocumented) popup wndproc.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003104 */
Alexandre Julliard91222da2000-12-10 23:01:33 +00003105static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
3106{
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003107 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
Juergen Schmied78513941999-04-18 14:40:32 +00003108 hwnd, message, wParam, lParam);
3109
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003110 switch(message)
3111 {
3112 case WM_CREATE:
3113 {
Alexandre Julliard91222da2000-12-10 23:01:33 +00003114 CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
3115 SetWindowLongW( hwnd, 0, (LONG)cs->lpCreateParams );
3116 return 0;
Alexandre Julliardf7207251994-07-23 07:57:48 +00003117 }
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003118
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003119 case WM_MOUSEACTIVATE: /* We don't want to be activated */
Alexandre Julliard91222da2000-12-10 23:01:33 +00003120 return MA_NOACTIVATE;
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003121
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003122 case WM_PAINT:
3123 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003124 PAINTSTRUCT ps;
3125 BeginPaint( hwnd, &ps );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003126 MENU_DrawPopupMenu( hwnd, ps.hdc,
Alexandre Julliarda3960291999-02-26 11:11:13 +00003127 (HMENU)GetWindowLongA( hwnd, 0 ) );
3128 EndPaint( hwnd, &ps );
Alexandre Julliard91222da2000-12-10 23:01:33 +00003129 return 0;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003130 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003131 case WM_ERASEBKGND:
Alexandre Julliard91222da2000-12-10 23:01:33 +00003132 return 1;
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003133
Alexandre Julliard2ace16a1996-04-28 15:09:19 +00003134 case WM_DESTROY:
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003135 /* zero out global pointer in case resident popup window was destroyed. */
3136 if (hwnd == top_popup) top_popup = 0;
3137 break;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003138
3139 case WM_SHOWWINDOW:
3140
3141 if( wParam )
3142 {
Alexandre Julliard91222da2000-12-10 23:01:33 +00003143 if (!GetWindowLongW( hwnd, 0 )) ERR("no menu to display\n");
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003144 }
3145 else
Alexandre Julliard91222da2000-12-10 23:01:33 +00003146 SetWindowLongW( hwnd, 0, 0 );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003147 break;
3148
3149 case MM_SETMENUHANDLE:
Alexandre Julliard91222da2000-12-10 23:01:33 +00003150 SetWindowLongW( hwnd, 0, wParam );
Alexandre Julliard2ace16a1996-04-28 15:09:19 +00003151 break;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003152
3153 case MM_GETMENUHANDLE:
Alexandre Julliard91222da2000-12-10 23:01:33 +00003154 return GetWindowLongW( hwnd, 0 );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003155
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003156 default:
Alexandre Julliard91222da2000-12-10 23:01:33 +00003157 return DefWindowProcW( hwnd, message, wParam, lParam );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003158 }
Alexandre Julliard91222da2000-12-10 23:01:33 +00003159 return 0;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003160}
3161
3162
Alexandre Julliard8d24ae61994-04-05 21:42:43 +00003163/***********************************************************************
Alexandre Julliard2d159fb1994-07-15 16:04:31 +00003164 * MENU_GetMenuBarHeight
3165 *
3166 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3167 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003168UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3169 INT orgX, INT orgY )
Alexandre Julliard2d159fb1994-07-15 16:04:31 +00003170{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003171 HDC hdc;
3172 RECT rectBar;
Alexandre Julliard2d159fb1994-07-15 16:04:31 +00003173 LPPOPUPMENU lppop;
3174
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003175 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
Alexandre Julliardde424282001-08-10 22:51:42 +00003176 hwnd, menubarWidth, orgX, orgY );
Juergen Schmied78513941999-04-18 14:40:32 +00003177
Alexandre Julliardde424282001-08-10 22:51:42 +00003178 if (!(lppop = MENU_GetMenu( GetMenu(hwnd) ))) return 0;
Juergen Schmied78513941999-04-18 14:40:32 +00003179
Alexandre Julliarda3960291999-02-26 11:11:13 +00003180 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
Juergen Schmied78513941999-04-18 14:40:32 +00003181 SelectObject( hdc, hMenuFont);
Marcus Meissnerddca3151999-05-22 11:33:23 +00003182 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
Juergen Schmied78513941999-04-18 14:40:32 +00003183 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003184 ReleaseDC( hwnd, hdc );
Alexandre Julliardde424282001-08-10 22:51:42 +00003185 return lppop->Height;
Alexandre Julliard2d159fb1994-07-15 16:04:31 +00003186}
3187
3188
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003189/*******************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003190 * ChangeMenu (USER.153)
Alexandre Julliard401710d1993-09-04 10:09:32 +00003191 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003192BOOL16 WINAPI ChangeMenu16( HMENU16 hMenu, UINT16 pos, SEGPTR data,
3193 UINT16 id, UINT16 flags )
Alexandre Julliard401710d1993-09-04 10:09:32 +00003194{
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003195 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
Alexandre Julliard59730ae1996-03-24 16:20:51 +00003196 hMenu, pos, (DWORD)data, id, flags );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003197 if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
3198 id, data );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003199
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003200 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3201 /* for MF_DELETE. We should check the parameters for all others */
3202 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003203
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003204 if (flags & MF_DELETE) return DeleteMenu16(hMenu, pos, flags & ~MF_DELETE);
3205 if (flags & MF_CHANGE) return ModifyMenu16(hMenu, pos, flags & ~MF_CHANGE,
3206 id, data );
3207 if (flags & MF_REMOVE) return RemoveMenu16(hMenu,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003208 flags & MF_BYPOSITION ? pos : id,
3209 flags & ~MF_REMOVE );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003210 /* Default: MF_INSERT */
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003211 return InsertMenu16( hMenu, pos, flags, id, data );
3212}
3213
3214
3215/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003216 * ChangeMenuA (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003217 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003218BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3219 UINT id, UINT flags )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003220{
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003221 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003222 hMenu, pos, (DWORD)data, id, flags );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003223 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003224 id, data );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003225 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3226 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003227 id, data );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003228 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003229 flags & MF_BYPOSITION ? pos : id,
3230 flags & ~MF_REMOVE );
3231 /* Default: MF_INSERT */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003232 return InsertMenuA( hMenu, pos, flags, id, data );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003233}
3234
3235
3236/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003237 * ChangeMenuW (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003238 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003239BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3240 UINT id, UINT flags )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003241{
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003242 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003243 hMenu, pos, (DWORD)data, id, flags );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003244 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003245 id, data );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003246 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3247 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003248 id, data );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003249 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003250 flags & MF_BYPOSITION ? pos : id,
3251 flags & ~MF_REMOVE );
3252 /* Default: MF_INSERT */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003253 return InsertMenuW( hMenu, pos, flags, id, data );
Alexandre Julliard401710d1993-09-04 10:09:32 +00003254}
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003255
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003256
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003257/*******************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003258 * CheckMenuItem (USER.154)
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003259 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003260BOOL16 WINAPI CheckMenuItem16( HMENU16 hMenu, UINT16 id, UINT16 flags )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003261{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003262 return (BOOL16)CheckMenuItem( hMenu, id, flags );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003263}
3264
3265
3266/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003267 * CheckMenuItem (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003268 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003269DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003270{
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003271 MENUITEM *item;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003272 DWORD ret;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003273
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003274 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu, id, flags );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003275 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003276 ret = item->fState & MF_CHECKED;
3277 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3278 else item->fState &= ~MF_CHECKED;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003279 return ret;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003280}
3281
3282
3283/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003284 * EnableMenuItem (USER.155)
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003285 */
Alexandre Julliardf90efa91998-06-14 15:24:15 +00003286UINT16 WINAPI EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003287{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003288 return EnableMenuItem( hMenu, wItemID, wFlags );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003289}
3290
3291
3292/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003293 * EnableMenuItem (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003294 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003295UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003296{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003297 UINT oldflags;
Alexandre Julliardf90efa91998-06-14 15:24:15 +00003298 MENUITEM *item;
Pascal Lessardd814bb61999-07-31 13:02:02 +00003299 POPUPMENU *menu;
Alexandre Julliardf7207251994-07-23 07:57:48 +00003300
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003301 TRACE("(%04x, %04X, %04X) !\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00003302 hMenu, wItemID, wFlags);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003303
Pascal Lessardd814bb61999-07-31 13:02:02 +00003304 /* Get the Popupmenu to access the owner menu */
Gerard Patel3e629742000-01-17 22:22:16 +00003305 if (!(menu = MENU_GetMenu(hMenu)))
Pascal Lessardd814bb61999-07-31 13:02:02 +00003306 return (UINT)-1;
3307
Alexandre Julliardf90efa91998-06-14 15:24:15 +00003308 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
Alexandre Julliarda3960291999-02-26 11:11:13 +00003309 return (UINT)-1;
Alexandre Julliardf90efa91998-06-14 15:24:15 +00003310
3311 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3312 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
Pascal Lessardd814bb61999-07-31 13:02:02 +00003313
3314 /* In win95 if the close item in the system menu change update the close button */
3315 if (TWEAK_WineLook == WIN95_LOOK)
3316 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3317 {
3318 if (menu->hSysMenuOwner != 0)
3319 {
3320 POPUPMENU* parentMenu;
3321
3322 /* Get the parent menu to access*/
Gerard Patel3e629742000-01-17 22:22:16 +00003323 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
Pascal Lessardd814bb61999-07-31 13:02:02 +00003324 return (UINT)-1;
3325
3326 /* Refresh the frame to reflect the change*/
3327 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
Stephane Lussiera833f631999-08-21 14:46:06 +00003328 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
Pascal Lessardd814bb61999-07-31 13:02:02 +00003329 }
3330 }
3331
Alexandre Julliardf90efa91998-06-14 15:24:15 +00003332 return oldflags;
Alexandre Julliard1f579291994-05-25 16:25:21 +00003333}
3334
3335
Alexandre Julliardaf0bae51995-10-03 17:06:08 +00003336/*******************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003337 * GetMenuString (USER.161)
Alexandre Julliard1f579291994-05-25 16:25:21 +00003338 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003339INT16 WINAPI GetMenuString16( HMENU16 hMenu, UINT16 wItemID,
3340 LPSTR str, INT16 nMaxSiz, UINT16 wFlags )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003341{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003342 return GetMenuStringA( hMenu, wItemID, str, nMaxSiz, wFlags );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003343}
3344
3345
3346/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003347 * GetMenuStringA (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003348 */
Marcus Meissnercb3c7bf2000-01-08 22:25:57 +00003349INT WINAPI GetMenuStringA(
3350 HMENU hMenu, /* [in] menuhandle */
3351 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3352 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3353 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
3354 UINT wFlags /* [in] MF_ flags */
3355) {
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003356 MENUITEM *item;
Alexandre Julliardaf0bae51995-10-03 17:06:08 +00003357
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003358 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
Alexandre Julliardaf0bae51995-10-03 17:06:08 +00003359 hMenu, wItemID, str, nMaxSiz, wFlags );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003360 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003361 if (!IS_STRING_ITEM(item->fType)) return 0;
Aric Stewartc946b1c2000-10-24 21:28:19 +00003362 if (!str || !nMaxSiz) return strlenW(item->text);
Marcus Meissnercb3c7bf2000-01-08 22:25:57 +00003363 str[0] = '\0';
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00003364 if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
3365 str[nMaxSiz-1] = 0;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003366 TRACE("returning '%s'\n", str );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003367 return strlen(str);
Alexandre Julliard1f579291994-05-25 16:25:21 +00003368}
3369
3370
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003371/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003372 * GetMenuStringW (USER32.@)
Alexandre Julliard1f579291994-05-25 16:25:21 +00003373 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003374INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3375 LPWSTR str, INT nMaxSiz, UINT wFlags )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003376{
3377 MENUITEM *item;
3378
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003379 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003380 hMenu, wItemID, str, nMaxSiz, wFlags );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003381 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003382 if (!IS_STRING_ITEM(item->fType)) return 0;
Aric Stewartc946b1c2000-10-24 21:28:19 +00003383 if (!str || !nMaxSiz) return strlenW(item->text);
Marcus Meissnercb3c7bf2000-01-08 22:25:57 +00003384 str[0] = '\0';
Aric Stewartc946b1c2000-10-24 21:28:19 +00003385 lstrcpynW( str, item->text, nMaxSiz );
3386 return strlenW(str);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003387}
3388
3389
3390/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003391 * HiliteMenuItem (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003392 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003393BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3394 UINT wHilite )
Alexandre Julliard1f579291994-05-25 16:25:21 +00003395{
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003396 LPPOPUPMENU menu;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003397 TRACE("(%04x, %04x, %04x, %04x);\n",
Alexandre Julliard59730ae1996-03-24 16:20:51 +00003398 hWnd, hMenu, wItemID, wHilite);
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003399 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
Gerard Patel3e629742000-01-17 22:22:16 +00003400 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003401 if (menu->FocusedItem == wItemID) return TRUE;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00003402 MENU_HideSubPopups( hWnd, hMenu, FALSE );
Rein Klazes80c924f1999-12-12 19:40:46 +00003403 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003404 return TRUE;
Alexandre Julliard1f579291994-05-25 16:25:21 +00003405}
3406
3407
3408/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003409 * GetMenuState (USER.250)
Alexandre Julliard7cc9c0c1994-06-15 15:45:11 +00003410 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003411UINT16 WINAPI GetMenuState16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003412{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003413 return GetMenuState( hMenu, wItemID, wFlags );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003414}
3415
3416
3417/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003418 * GetMenuState (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003419 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003420UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
Alexandre Julliard7cc9c0c1994-06-15 15:45:11 +00003421{
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003422 MENUITEM *item;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003423 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
Alexandre Julliardaca05781994-10-17 18:12:41 +00003424 hMenu, wItemID, wFlags);
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003425 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
Alexandre Julliard03468f71998-02-15 19:40:49 +00003426 debug_print_menuitem (" item: ", item, "");
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003427 if (item->fType & MF_POPUP)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003428 {
Gerard Patel3e629742000-01-17 22:22:16 +00003429 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003430 if (!menu) return -1;
Alexandre Julliard829fe321998-07-26 14:27:39 +00003431 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003432 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00003433 else
Alexandre Julliard491502b1997-11-01 19:08:16 +00003434 {
Alexandre Julliard829fe321998-07-26 14:27:39 +00003435 /* We used to (from way back then) mask the result to 0xff. */
3436 /* I don't know why and it seems wrong as the documented */
3437 /* return flag MF_SEPARATOR is outside that mask. */
3438 return (item->fType | item->fState);
Alexandre Julliard491502b1997-11-01 19:08:16 +00003439 }
Alexandre Julliard7cc9c0c1994-06-15 15:45:11 +00003440}
3441
3442
3443/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003444 * GetMenuItemCount (USER.263)
Alexandre Julliard1f579291994-05-25 16:25:21 +00003445 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003446INT16 WINAPI GetMenuItemCount16( HMENU16 hMenu )
Alexandre Julliard1f579291994-05-25 16:25:21 +00003447{
Gerard Patel3e629742000-01-17 22:22:16 +00003448 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3449 if (!menu) return -1;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003450 TRACE("(%04x) returning %d\n",
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003451 hMenu, menu->nItems );
3452 return menu->nItems;
Alexandre Julliard1f579291994-05-25 16:25:21 +00003453}
3454
3455
3456/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003457 * GetMenuItemCount (USER32.@)
Alexandre Julliard1f579291994-05-25 16:25:21 +00003458 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003459INT WINAPI GetMenuItemCount( HMENU hMenu )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003460{
Gerard Patel3e629742000-01-17 22:22:16 +00003461 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3462 if (!menu) return -1;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003463 TRACE("(%04x) returning %d\n",
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003464 hMenu, menu->nItems );
3465 return menu->nItems;
3466}
3467
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003468/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003469 * GetMenuItemID (USER.264)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003470 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003471UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
Alexandre Julliard1f579291994-05-25 16:25:21 +00003472{
Juergen Schmiedc77fd5b1999-04-21 14:27:37 +00003473 return (UINT16) GetMenuItemID (hMenu, nPos);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003474}
3475
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003476/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003477 * GetMenuItemID (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003478 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003479UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003480{
Juergen Schmiedc77fd5b1999-04-21 14:27:37 +00003481 MENUITEM * lpmi;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003482
Mike McCormack34329cf2001-07-10 19:06:12 +00003483 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return -1;
Juergen Schmiedc77fd5b1999-04-21 14:27:37 +00003484 if (lpmi->fType & MF_POPUP) return -1;
3485 return lpmi->wID;
3486
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003487}
3488
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003489/*******************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003490 * InsertMenu (USER.410)
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003491 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003492BOOL16 WINAPI InsertMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3493 UINT16 id, SEGPTR data )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003494{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003495 UINT pos32 = (UINT)pos;
3496 if ((pos == (UINT16)-1) && (flags & MF_BYPOSITION)) pos32 = (UINT)-1;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003497 if (IS_STRING_ITEM(flags) && data)
Alexandre Julliard982a2232000-12-13 20:20:09 +00003498 return InsertMenuA( hMenu, pos32, flags, id, MapSL(data) );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003499 return InsertMenuA( hMenu, pos32, flags, id, (LPSTR)data );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003500}
3501
3502
3503/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003504 * InsertMenuW (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003505 */
Aric Stewartc946b1c2000-10-24 21:28:19 +00003506BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3507 UINT id, LPCWSTR str )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003508{
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003509 MENUITEM *item;
Alexandre Julliarde2991ea1995-07-29 13:09:43 +00003510
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003511 if (IS_STRING_ITEM(flags) && str)
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003512 TRACE("hMenu %04x, pos %d, flags %08x, "
Francois Gougete76218d2001-05-09 17:31:31 +00003513 "id %04x, str %s\n",
Aric Stewartc946b1c2000-10-24 21:28:19 +00003514 hMenu, pos, flags, id, debugstr_w(str) );
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003515 else TRACE("hMenu %04x, pos %d, flags %08x, "
Alexandre Julliardd37eb361997-07-20 16:23:21 +00003516 "id %04x, str %08lx (not a string)\n",
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003517 hMenu, pos, flags, id, (DWORD)str );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003518
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003519 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003520
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003521 if (!(MENU_SetItemData( item, flags, id, str )))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003522 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003523 RemoveMenu( hMenu, pos, flags );
Alexandre Julliarde2abbb11995-03-19 17:39:39 +00003524 return FALSE;
3525 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003526
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003527 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
Gerard Patel3e629742000-01-17 22:22:16 +00003528 (MENU_GetMenu((HMENU16)id))->wFlags |= MF_POPUP;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003529
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003530 item->hCheckBit = item->hUnCheckBit = 0;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003531 return TRUE;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003532}
3533
3534
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003535/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003536 * InsertMenuA (USER32.@)
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003537 */
Aric Stewartc946b1c2000-10-24 21:28:19 +00003538BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3539 UINT id, LPCSTR str )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003540{
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00003541 BOOL ret = FALSE;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003542
3543 if (IS_STRING_ITEM(flags) && str)
3544 {
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00003545 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3546 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3547 if (newstr)
3548 {
3549 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3550 ret = InsertMenuW( hMenu, pos, flags, id, newstr );
3551 HeapFree( GetProcessHeap(), 0, newstr );
3552 }
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003553 return ret;
3554 }
Aric Stewartc946b1c2000-10-24 21:28:19 +00003555 else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003556}
3557
3558
3559/*******************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003560 * AppendMenu (USER.411)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003561 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003562BOOL16 WINAPI AppendMenu16(HMENU16 hMenu, UINT16 flags, UINT16 id, SEGPTR data)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003563{
3564 return InsertMenu16( hMenu, -1, flags | MF_BYPOSITION, id, data );
3565}
3566
3567
3568/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003569 * AppendMenuA (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003570 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003571BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3572 UINT id, LPCSTR data )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003573{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003574 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003575}
3576
3577
3578/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003579 * AppendMenuW (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003580 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003581BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3582 UINT id, LPCWSTR data )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003583{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003584 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003585}
3586
3587
3588/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003589 * RemoveMenu (USER.412)
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003590 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003591BOOL16 WINAPI RemoveMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003592{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003593 return RemoveMenu( hMenu, nPos, wFlags );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003594}
3595
3596
3597/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003598 * RemoveMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003599 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003600BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003601{
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003602 LPPOPUPMENU menu;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003603 MENUITEM *item;
3604
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003605 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003606 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
Gerard Patel3e629742000-01-17 22:22:16 +00003607 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003608
3609 /* Remove item */
3610
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003611 MENU_FreeItemData( item );
3612
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003613 if (--menu->nItems == 0)
3614 {
Alexandre Julliardda2892c2001-02-23 01:13:42 +00003615 HeapFree( GetProcessHeap(), 0, menu->items );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003616 menu->items = NULL;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003617 }
3618 else
3619 {
3620 while(nPos < menu->nItems)
3621 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003622 *item = *(item+1);
3623 item++;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003624 nPos++;
3625 }
Alexandre Julliardda2892c2001-02-23 01:13:42 +00003626 menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003627 menu->nItems * sizeof(MENUITEM) );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003628 }
3629 return TRUE;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003630}
3631
3632
3633/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003634 * DeleteMenu (USER.413)
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003635 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003636BOOL16 WINAPI DeleteMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003637{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003638 return DeleteMenu( hMenu, nPos, wFlags );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003639}
3640
3641
3642/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003643 * DeleteMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003644 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003645BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003646{
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003647 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3648 if (!item) return FALSE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00003649 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003650 /* nPos is now the position of the item */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003651 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003652 return TRUE;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003653}
3654
3655
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003656/*******************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003657 * ModifyMenu (USER.414)
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003658 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003659BOOL16 WINAPI ModifyMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
3660 UINT16 id, SEGPTR data )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003661{
3662 if (IS_STRING_ITEM(flags))
Alexandre Julliard982a2232000-12-13 20:20:09 +00003663 return ModifyMenuA( hMenu, pos, flags, id, MapSL(data) );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003664 return ModifyMenuA( hMenu, pos, flags, id, (LPSTR)data );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003665}
3666
3667
3668/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003669 * ModifyMenuW (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003670 */
Aric Stewartc946b1c2000-10-24 21:28:19 +00003671BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3672 UINT id, LPCWSTR str )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003673{
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003674 MENUITEM *item;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003675
3676 if (IS_STRING_ITEM(flags))
Alexandre Julliarde2991ea1995-07-29 13:09:43 +00003677 {
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003678 TRACE("%04x %d %04x %04x %s\n",
3679 hMenu, pos, flags, id, debugstr_w(str) );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003680 if (!str) return FALSE;
Alexandre Julliarde2991ea1995-07-29 13:09:43 +00003681 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003682 else
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003683 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003684 TRACE("%04x %d %04x %04x %08lx\n",
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003685 hMenu, pos, flags, id, (DWORD)str );
3686 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003687
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003688 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003689 return MENU_SetItemData( item, flags, id, str );
3690}
3691
3692
3693/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003694 * ModifyMenuA (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003695 */
Aric Stewartc946b1c2000-10-24 21:28:19 +00003696BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3697 UINT id, LPCSTR str )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003698{
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00003699 BOOL ret = FALSE;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003700
3701 if (IS_STRING_ITEM(flags) && str)
3702 {
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00003703 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3704 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3705 if (newstr)
3706 {
3707 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3708 ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
3709 HeapFree( GetProcessHeap(), 0, newstr );
3710 }
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003711 return ret;
3712 }
Aric Stewartc946b1c2000-10-24 21:28:19 +00003713 else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003714}
3715
3716
3717/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003718 * CreatePopupMenu (USER.415)
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003719 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003720HMENU16 WINAPI CreatePopupMenu16(void)
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003721{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003722 return CreatePopupMenu();
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003723}
3724
3725
3726/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003727 * CreatePopupMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003728 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003729HMENU WINAPI CreatePopupMenu(void)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003730{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003731 HMENU hmenu;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003732 POPUPMENU *menu;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003733
Alexandre Julliarda3960291999-02-26 11:11:13 +00003734 if (!(hmenu = CreateMenu())) return 0;
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003735 menu = MENU_GetMenu( hmenu );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003736 menu->wFlags |= MF_POPUP;
Pascal Lessard2eb0a301999-09-03 16:38:52 +00003737 menu->bTimeToHide = FALSE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003738 return hmenu;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00003739}
3740
3741
3742/**********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00003743 * GetMenuCheckMarkDimensions (USER.417)
3744 * GetMenuCheckMarkDimensions (USER32.@)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00003745 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003746DWORD WINAPI GetMenuCheckMarkDimensions(void)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00003747{
Alexandre Julliardc1d35cc2001-01-24 19:47:57 +00003748 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003749}
3750
3751
3752/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003753 * SetMenuItemBitmaps (USER.418)
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003754 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003755BOOL16 WINAPI SetMenuItemBitmaps16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags,
3756 HBITMAP16 hNewUnCheck, HBITMAP16 hNewCheck)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003757{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003758 return SetMenuItemBitmaps( hMenu, nPos, wFlags, hNewUnCheck, hNewCheck );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003759}
3760
3761
3762/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003763 * SetMenuItemBitmaps (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003764 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003765BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3766 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003767{
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003768 MENUITEM *item;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003769 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003770 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3771 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003772
3773 if (!hNewCheck && !hNewUnCheck)
3774 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003775 item->fState &= ~MF_USECHECKBITMAPS;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003776 }
3777 else /* Install new bitmaps */
3778 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003779 item->hCheckBit = hNewCheck;
3780 item->hUnCheckBit = hNewUnCheck;
3781 item->fState |= MF_USECHECKBITMAPS;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003782 }
3783 return TRUE;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003784}
3785
3786
3787/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003788 * CreateMenu (USER.151)
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003789 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003790HMENU16 WINAPI CreateMenu16(void)
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003791{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003792 return CreateMenu();
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003793}
3794
3795
3796/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003797 * CreateMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003798 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003799HMENU WINAPI CreateMenu(void)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003800{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003801 HMENU hMenu;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003802 LPPOPUPMENU menu;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003803 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
Alexandre Julliarde2abbb11995-03-19 17:39:39 +00003804 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
Juergen Schmied78513941999-04-18 14:40:32 +00003805
3806 ZeroMemory(menu, sizeof(POPUPMENU));
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003807 menu->wMagic = MENU_MAGIC;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003808 menu->FocusedItem = NO_SELECTED_ITEM;
Pascal Lessard2eb0a301999-09-03 16:38:52 +00003809 menu->bTimeToHide = FALSE;
Juergen Schmied78513941999-04-18 14:40:32 +00003810
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003811 TRACE("return %04x\n", hMenu );
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00003812
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003813 return hMenu;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003814}
3815
3816
3817/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003818 * DestroyMenu (USER.152)
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003819 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003820BOOL16 WINAPI DestroyMenu16( HMENU16 hMenu )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003821{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003822 return DestroyMenu( hMenu );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003823}
3824
3825
3826/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003827 * DestroyMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003828 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003829BOOL WINAPI DestroyMenu( HMENU hMenu )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003830{
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003831 TRACE("(%04x)\n", hMenu);
Alexandre Julliard1285c2f1996-05-06 16:06:24 +00003832
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003833 /* Silently ignore attempts to destroy default system popup */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003834
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003835 if (hMenu && hMenu != MENU_DefSysPopup)
Alexandre Julliardff8331e1995-09-18 11:19:54 +00003836 {
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003837 LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003838
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003839 if (!lppop) return FALSE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003840
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003841 lppop->wMagic = 0; /* Mark it as destroyed */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003842
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003843 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd)
Gerard Patel8f79fdc2001-05-14 19:20:13 +00003844 {
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003845 DestroyWindow( lppop->hWnd );
Gerard Patel8f79fdc2001-05-14 19:20:13 +00003846 lppop->hWnd = 0;
3847 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003848
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003849 if (lppop->items) /* recursively destroy submenus */
Francois Boisvert3a3cd9f1999-03-28 12:42:52 +00003850 {
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003851 int i;
3852 MENUITEM *item = lppop->items;
3853 for (i = lppop->nItems; i > 0; i--, item++)
3854 {
3855 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3856 MENU_FreeItemData( item );
3857 }
3858 HeapFree( GetProcessHeap(), 0, lppop->items );
Francois Boisvert3a3cd9f1999-03-28 12:42:52 +00003859 }
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003860 USER_HEAP_FREE( hMenu );
Alexandre Julliardff8331e1995-09-18 11:19:54 +00003861 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003862 return (hMenu != MENU_DefSysPopup);
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003863}
3864
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003865
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003866/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003867 * GetSystemMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003868 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003869HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003870{
Alexandre Julliardb7258be1995-09-01 15:57:28 +00003871 WND *wndPtr = WIN_FindWndPtr( hWnd );
Eric Pouech562309a1999-08-21 12:59:44 +00003872 HMENU retvalue = 0;
Alexandre Julliardb7258be1995-09-01 15:57:28 +00003873
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003874 if (wndPtr)
Alexandre Julliard1285c2f1996-05-06 16:06:24 +00003875 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003876 if( wndPtr->hSysMenu )
3877 {
3878 if( bRevert )
3879 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003880 DestroyMenu(wndPtr->hSysMenu);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003881 wndPtr->hSysMenu = 0;
3882 }
3883 else
3884 {
Gerard Patel3e629742000-01-17 22:22:16 +00003885 POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
3886 if( menu )
Eric Pouech562309a1999-08-21 12:59:44 +00003887 {
3888 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3889 menu->items[0].hSubMenu = MENU_CopySysPopup();
3890 }
3891 else
3892 {
3893 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3894 wndPtr->hSysMenu, hWnd);
3895 wndPtr->hSysMenu = 0;
3896 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003897 }
3898 }
3899
3900 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
Alexandre Julliarda3960291999-02-26 11:11:13 +00003901 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003902
3903 if( wndPtr->hSysMenu )
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00003904 {
Eric Pouech562309a1999-08-21 12:59:44 +00003905 POPUPMENU *menu;
Dmitry Timoshkov56a19922001-07-02 01:21:26 +00003906 retvalue = GetSubMenu(wndPtr->hSysMenu, 0);
Pascal Lessardd814bb61999-07-31 13:02:02 +00003907
3908 /* Store the dummy sysmenu handle to facilitate the refresh */
3909 /* of the close button if the SC_CLOSE item change */
Gerard Patel3e629742000-01-17 22:22:16 +00003910 menu = MENU_GetMenu(retvalue);
3911 if ( menu )
Eric Pouech562309a1999-08-21 12:59:44 +00003912 menu->hSysMenuOwner = wndPtr->hSysMenu;
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00003913 }
3914 WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard1285c2f1996-05-06 16:06:24 +00003915 }
Francois Jacques20af4c32000-06-18 17:17:54 +00003916 return bRevert ? 0 : retvalue;
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003917}
3918
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003919
3920/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003921 * SetSystemMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003922 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003923BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
Alexandre Julliard1d62f6b1994-05-04 19:15:00 +00003924{
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003925 WND *wndPtr = WIN_FindWndPtr(hwnd);
Alexandre Julliard1d62f6b1994-05-04 19:15:00 +00003926
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003927 if (wndPtr)
3928 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003929 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003930 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00003931 WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003932 return TRUE;
3933 }
3934 return FALSE;
Alexandre Julliard1d62f6b1994-05-04 19:15:00 +00003935}
3936
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003937
3938/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003939 * GetMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003940 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003941HMENU WINAPI GetMenu( HWND hWnd )
Dmitry Timoshkovfbb2c9b2000-09-09 19:38:34 +00003942{
Alexandre Julliardde424282001-08-10 22:51:42 +00003943 HMENU retvalue = (HMENU)GetWindowLongA( hWnd, GWL_ID );
3944 TRACE("for %04x returning %04x\n", hWnd, retvalue);
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00003945 return retvalue;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003946}
3947
3948
3949/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003950 * SetMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003951 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003952BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003953{
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003954 TRACE("(%04x, %04x);\n", hWnd, hMenu);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003955
Richard Cohen56753621999-09-19 14:08:13 +00003956 if (hMenu && !IsMenu(hMenu))
3957 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003958 WARN("hMenu %x is not a menu handle\n", hMenu);
3959 return FALSE;
Richard Cohen56753621999-09-19 14:08:13 +00003960 }
Alexandre Julliardde424282001-08-10 22:51:42 +00003961 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
Richard Cohen56753621999-09-19 14:08:13 +00003962
Alexandre Julliardf44bbb82001-09-14 00:24:39 +00003963 hWnd = WIN_GetFullHandle( hWnd );
Alexandre Julliardde424282001-08-10 22:51:42 +00003964 if (GetCapture() == hWnd) ReleaseCapture();
3965
3966 if (hMenu != 0)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003967 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003968 LPPOPUPMENU lpmenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003969
Alexandre Julliardde424282001-08-10 22:51:42 +00003970 if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003971
Alexandre Julliardde424282001-08-10 22:51:42 +00003972 lpmenu->hWnd = hWnd;
3973 lpmenu->Height = 0; /* Make sure we recalculate the size */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003974 }
Alexandre Julliardde424282001-08-10 22:51:42 +00003975 SetWindowLongA( hWnd, GWL_ID, hMenu );
3976
3977 if (IsWindowVisible(hWnd))
3978 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3979 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3980 return TRUE;
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003981}
3982
3983
Alexandre Julliardd18872d1994-05-11 12:18:19 +00003984
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003985/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003986 * GetSubMenu (USER.159)
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003987 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003988HMENU16 WINAPI GetSubMenu16( HMENU16 hMenu, INT16 nPos )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003989{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003990 return GetSubMenu( hMenu, nPos );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003991}
3992
3993
3994/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003995 * GetSubMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003996 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003997HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003998{
Juergen Schmiedc77fd5b1999-04-21 14:27:37 +00003999 MENUITEM * lpmi;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004000
Juergen Schmiedc77fd5b1999-04-21 14:27:37 +00004001 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
4002 if (!(lpmi->fType & MF_POPUP)) return 0;
4003 return lpmi->hSubMenu;
Alexandre Julliarddba420a1994-02-02 06:48:31 +00004004}
4005
4006
4007/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004008 * DrawMenuBar (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004009 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004010BOOL WINAPI DrawMenuBar( HWND hWnd )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004011{
4012 LPPOPUPMENU lppop;
Alexandre Julliardde424282001-08-10 22:51:42 +00004013 HMENU hMenu = GetMenu(hWnd);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004014
Alexandre Julliardde424282001-08-10 22:51:42 +00004015 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
4016 if (!hMenu || !(lppop = MENU_GetMenu( hMenu ))) return FALSE;
4017
4018 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
4019 lppop->hwndOwner = hWnd;
4020 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4021 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4022 return TRUE;
Alexandre Julliardcdd09231994-01-12 11:12:51 +00004023}
4024
Eric Pouecha862f682001-02-26 22:33:29 +00004025/***********************************************************************
4026 * DrawMenuBarTemp (USER32.@)
Andreas Mohr69249672001-12-26 20:34:12 +00004027 *
4028 * UNDOCUMENTED !!
4029 *
4030 * called by W98SE desk.cpl Control Panel Applet
4031 *
4032 * Not 100% sure about the param names, but close.
Eric Pouecha862f682001-02-26 22:33:29 +00004033 */
Andreas Mohr69249672001-12-26 20:34:12 +00004034DWORD WINAPI DrawMenuBarTemp(HWND someHWND, HDC someHDC, LPRECT someRECT, HMENU someHMENU, HFONT someFONT)
Eric Pouecha862f682001-02-26 22:33:29 +00004035{
Andreas Mohr69249672001-12-26 20:34:12 +00004036 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, 0x%08x): stub\n", someHWND, someHDC, someRECT, someHMENU, someFONT);
Eric Pouecha862f682001-02-26 22:33:29 +00004037 return 0;
4038}
Alexandre Julliardcdd09231994-01-12 11:12:51 +00004039
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00004040/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00004041 * EndMenu (USER.187)
4042 * EndMenu (USER32.@)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00004043 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004044void WINAPI EndMenu(void)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00004045{
Rob Farnumb2007932000-05-23 23:34:17 +00004046 /* if we are in the menu code, and it is active */
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00004047 if (!fEndMenu && top_popup)
Rob Farnumb2007932000-05-23 23:34:17 +00004048 {
4049 /* terminate the menu handling code */
4050 fEndMenu = TRUE;
Alex Korobka4f1ac051999-03-28 09:37:57 +00004051
Rob Farnumb2007932000-05-23 23:34:17 +00004052 /* needs to be posted to wakeup the internal menu handler */
4053 /* which will now terminate the menu, in the event that */
4054 /* the main window was minimized, or lost focus, so we */
4055 /* don't end up with an orphaned menu */
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00004056 PostMessageA( top_popup, WM_CANCELMODE, 0, 0);
Rob Farnumb2007932000-05-23 23:34:17 +00004057 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00004058}
4059
4060
4061/***********************************************************************
4062 * LookupMenuHandle (USER.217)
4063 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004064HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00004065{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004066 HMENU hmenu32 = hmenu;
4067 UINT id32 = id;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004068 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4069 else return hmenu32;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00004070}
4071
4072
Alexandre Julliardcdd09231994-01-12 11:12:51 +00004073/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00004074 * LoadMenu (USER.150)
Alexandre Julliard594997c1995-04-30 10:05:20 +00004075 */
Alexandre Julliardac7efef2000-11-27 21:54:01 +00004076HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
Alexandre Julliard594997c1995-04-30 10:05:20 +00004077{
Alexandre Julliard18f92e71996-07-17 20:02:21 +00004078 HRSRC16 hRsrc;
4079 HGLOBAL16 handle;
4080 HMENU16 hMenu;
Alexandre Julliard594997c1995-04-30 10:05:20 +00004081
Alexandre Julliardac7efef2000-11-27 21:54:01 +00004082 TRACE("(%04x,%s)\n", instance, debugres_a(name) );
4083
Alexandre Julliard594997c1995-04-30 10:05:20 +00004084 if (HIWORD(name))
4085 {
Alexandre Julliardac7efef2000-11-27 21:54:01 +00004086 if (name[0] == '#') name = (LPCSTR)atoi( name + 1 );
Alexandre Julliard594997c1995-04-30 10:05:20 +00004087 }
Alexandre Julliard594997c1995-04-30 10:05:20 +00004088
4089 if (!name) return 0;
Alexandre Julliardac7efef2000-11-27 21:54:01 +00004090
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00004091 /* check for Win32 module */
Alexandre Julliardac7efef2000-11-27 21:54:01 +00004092 if (HIWORD(instance)) return LoadMenuA( instance, name );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +00004093 instance = GetExePtr( instance );
Alexandre Julliard594997c1995-04-30 10:05:20 +00004094
Alexandre Julliardac7efef2000-11-27 21:54:01 +00004095 if (!(hRsrc = FindResource16( instance, name, RT_MENUA ))) return 0;
Alexandre Julliard18f92e71996-07-17 20:02:21 +00004096 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4097 hMenu = LoadMenuIndirect16(LockResource16(handle));
4098 FreeResource16( handle );
Alexandre Julliard594997c1995-04-30 10:05:20 +00004099 return hMenu;
4100}
4101
4102
Alexandre Julliard18f92e71996-07-17 20:02:21 +00004103/*****************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004104 * LoadMenuA (USER32.@)
Alexandre Julliard18f92e71996-07-17 20:02:21 +00004105 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004106HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
Alexandre Julliard18f92e71996-07-17 20:02:21 +00004107{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004108 HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
Alexandre Julliard18f92e71996-07-17 20:02:21 +00004109 if (!hrsrc) return 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +00004110 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
Alexandre Julliard18f92e71996-07-17 20:02:21 +00004111}
4112
4113
4114/*****************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004115 * LoadMenuW (USER32.@)
Alexandre Julliard18f92e71996-07-17 20:02:21 +00004116 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004117HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
Alexandre Julliard18f92e71996-07-17 20:02:21 +00004118{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004119 HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
Alexandre Julliard18f92e71996-07-17 20:02:21 +00004120 if (!hrsrc) return 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +00004121 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
Alexandre Julliard18f92e71996-07-17 20:02:21 +00004122}
4123
4124
Alexandre Julliard594997c1995-04-30 10:05:20 +00004125/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00004126 * LoadMenuIndirect (USER.220)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00004127 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004128HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00004129{
Alexandre Julliardbf9130a1996-10-13 17:45:47 +00004130 HMENU16 hMenu;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004131 WORD version, offset;
4132 LPCSTR p = (LPCSTR)template;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00004133
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00004134 TRACE("(%p)\n", template );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004135 version = GET_WORD(p);
4136 p += sizeof(WORD);
4137 if (version)
4138 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00004139 WARN("version must be 0 for Win16\n" );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004140 return 0;
4141 }
4142 offset = GET_WORD(p);
4143 p += sizeof(WORD) + offset;
Alexandre Julliarda3960291999-02-26 11:11:13 +00004144 if (!(hMenu = CreateMenu())) return 0;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004145 if (!MENU_ParseResource( p, hMenu, FALSE ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +00004146 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00004147 DestroyMenu( hMenu );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004148 return 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00004149 }
4150 return hMenu;
Alexandre Julliardcdd09231994-01-12 11:12:51 +00004151}
4152
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00004153
Alexandre Julliard7cc9c0c1994-06-15 15:45:11 +00004154/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004155 * LoadMenuIndirectA (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004156 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004157HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004158{
Alexandre Julliardbf9130a1996-10-13 17:45:47 +00004159 HMENU16 hMenu;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004160 WORD version, offset;
4161 LPCSTR p = (LPCSTR)template;
4162
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00004163 TRACE("%p\n", template );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004164 version = GET_WORD(p);
4165 p += sizeof(WORD);
Alexandre Julliard641ee761997-08-04 16:34:36 +00004166 switch (version)
4167 {
4168 case 0:
4169 offset = GET_WORD(p);
4170 p += sizeof(WORD) + offset;
Alexandre Julliarda3960291999-02-26 11:11:13 +00004171 if (!(hMenu = CreateMenu())) return 0;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004172 if (!MENU_ParseResource( p, hMenu, TRUE ))
4173 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00004174 DestroyMenu( hMenu );
Alexandre Julliard641ee761997-08-04 16:34:36 +00004175 return 0;
4176 }
4177 return hMenu;
4178 case 1:
4179 offset = GET_WORD(p);
4180 p += sizeof(WORD) + offset;
Alexandre Julliarda3960291999-02-26 11:11:13 +00004181 if (!(hMenu = CreateMenu())) return 0;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004182 if (!MENUEX_ParseResource( p, hMenu))
4183 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00004184 DestroyMenu( hMenu );
Alexandre Julliard641ee761997-08-04 16:34:36 +00004185 return 0;
4186 }
4187 return hMenu;
4188 default:
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00004189 ERR("version %d not supported.\n", version);
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004190 return 0;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004191 }
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004192}
4193
4194
4195/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004196 * LoadMenuIndirectW (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004197 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004198HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004199{
4200 /* FIXME: is there anything different between A and W? */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004201 return LoadMenuIndirectA( template );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004202}
4203
4204
4205/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00004206 * IsMenu (USER.358)
Alexandre Julliard7cc9c0c1994-06-15 15:45:11 +00004207 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004208BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004209{
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00004210 return IsMenu( hmenu );
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004211}
4212
4213
4214/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004215 * IsMenu (USER32.@)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004216 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004217BOOL WINAPI IsMenu(HMENU hmenu)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004218{
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00004219 LPPOPUPMENU menu = MENU_GetMenu(hmenu);
4220 return menu != NULL;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004221}
4222
Alexandre Julliard641ee761997-08-04 16:34:36 +00004223/**********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00004224 * GetMenuItemInfo_common
Alexandre Julliard641ee761997-08-04 16:34:36 +00004225 */
4226
Juergen Schmied78513941999-04-18 14:40:32 +00004227static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
Aric Stewartc946b1c2000-10-24 21:28:19 +00004228 LPMENUITEMINFOW lpmii, BOOL unicode)
Alexandre Julliard641ee761997-08-04 16:34:36 +00004229{
Juergen Schmied78513941999-04-18 14:40:32 +00004230 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4231
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00004232 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
Juergen Schmied78513941999-04-18 14:40:32 +00004233
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004234 if (!menu)
4235 return FALSE;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004236
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004237 if (lpmii->fMask & MIIM_TYPE) {
4238 lpmii->fType = menu->fType;
4239 switch (MENU_ITEM_TYPE(menu->fType)) {
Huw D M Davies2d6eaba2000-03-24 19:48:53 +00004240 case MF_STRING:
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00004241 break; /* will be done below */
Huw D M Davies2d6eaba2000-03-24 19:48:53 +00004242 case MF_OWNERDRAW:
4243 case MF_BITMAP:
4244 lpmii->dwTypeData = menu->text;
4245 /* fall through */
4246 default:
4247 lpmii->cch = 0;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004248 }
Alexandre Julliard641ee761997-08-04 16:34:36 +00004249 }
Juergen Schmied78513941999-04-18 14:40:32 +00004250
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00004251 /* copy the text string */
4252 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)) &&
4253 (MENU_ITEM_TYPE(menu->fType) == MF_STRING) && menu->text)
4254 {
4255 int len;
4256 if (unicode)
4257 {
4258 len = strlenW(menu->text);
4259 if(lpmii->dwTypeData && lpmii->cch)
4260 lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4261 }
4262 else
4263 {
4264 len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL, 0, NULL, NULL );
4265 if(lpmii->dwTypeData && lpmii->cch)
4266 if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4267 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4268 ((LPSTR)lpmii->dwTypeData)[lpmii->cch-1] = 0;
4269 }
4270 /* if we've copied a substring we return its length */
4271 if(lpmii->dwTypeData && lpmii->cch)
4272 {
4273 if (lpmii->cch <= len) lpmii->cch--;
4274 }
4275 else /* return length of string */
4276 lpmii->cch = len;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004277 }
Juergen Schmied78513941999-04-18 14:40:32 +00004278
4279 if (lpmii->fMask & MIIM_FTYPE)
4280 lpmii->fType = menu->fType;
4281
4282 if (lpmii->fMask & MIIM_BITMAP)
4283 lpmii->hbmpItem = menu->hbmpItem;
4284
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004285 if (lpmii->fMask & MIIM_STATE)
4286 lpmii->fState = menu->fState;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004287
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004288 if (lpmii->fMask & MIIM_ID)
4289 lpmii->wID = menu->wID;
4290
4291 if (lpmii->fMask & MIIM_SUBMENU)
4292 lpmii->hSubMenu = menu->hSubMenu;
4293
4294 if (lpmii->fMask & MIIM_CHECKMARKS) {
4295 lpmii->hbmpChecked = menu->hCheckBit;
4296 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4297 }
4298 if (lpmii->fMask & MIIM_DATA)
4299 lpmii->dwItemData = menu->dwItemData;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004300
4301 return TRUE;
4302}
4303
4304/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004305 * GetMenuItemInfoA (USER32.@)
Alexandre Julliard641ee761997-08-04 16:34:36 +00004306 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004307BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4308 LPMENUITEMINFOA lpmii)
Alexandre Julliard641ee761997-08-04 16:34:36 +00004309{
Aric Stewartc946b1c2000-10-24 21:28:19 +00004310 return GetMenuItemInfo_common (hmenu, item, bypos,
4311 (LPMENUITEMINFOW)lpmii, FALSE);
Alexandre Julliard641ee761997-08-04 16:34:36 +00004312}
4313
4314/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004315 * GetMenuItemInfoW (USER32.@)
Alexandre Julliard641ee761997-08-04 16:34:36 +00004316 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004317BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4318 LPMENUITEMINFOW lpmii)
Alexandre Julliard641ee761997-08-04 16:34:36 +00004319{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004320 return GetMenuItemInfo_common (hmenu, item, bypos,
Aric Stewartc946b1c2000-10-24 21:28:19 +00004321 lpmii, TRUE);
Alexandre Julliard641ee761997-08-04 16:34:36 +00004322}
4323
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00004324
4325/* set a menu item text from a ASCII or Unicode string */
4326inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
4327{
4328 if (!text)
4329 {
4330 menu->text = NULL;
4331 menu->fType |= MF_SEPARATOR;
4332 }
4333 else if (unicode)
4334 {
4335 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
4336 strcpyW( menu->text, text );
4337 }
4338 else
4339 {
4340 LPCSTR str = (LPCSTR)text;
4341 int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
4342 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
4343 MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
4344 }
4345}
4346
4347
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004348/**********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00004349 * SetMenuItemInfo_common
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004350 */
4351
Alexandre Julliarda3960291999-02-26 11:11:13 +00004352static BOOL SetMenuItemInfo_common(MENUITEM * menu,
Aric Stewartc946b1c2000-10-24 21:28:19 +00004353 const MENUITEMINFOW *lpmii,
Alexandre Julliarda3960291999-02-26 11:11:13 +00004354 BOOL unicode)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004355{
4356 if (!menu) return FALSE;
4357
Gerard Patel2482ef32001-03-19 19:16:21 +00004358 debug_print_menuitem("MENU_SetItemInfo_common from: ", menu, "");
4359
Juergen Schmied78513941999-04-18 14:40:32 +00004360 if (lpmii->fMask & MIIM_TYPE ) {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004361 /* Get rid of old string. */
Juergen Schmied78513941999-04-18 14:40:32 +00004362 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
Alexandre Julliardda2892c2001-02-23 01:13:42 +00004363 HeapFree(GetProcessHeap(), 0, menu->text);
Juergen Schmied78513941999-04-18 14:40:32 +00004364 menu->text = NULL;
4365 }
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004366
Juergen Schmied78513941999-04-18 14:40:32 +00004367 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4368 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4369 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
Paul Millar39da2221999-04-11 12:08:42 +00004370
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004371 menu->text = lpmii->dwTypeData;
Juergen Schmied78513941999-04-18 14:40:32 +00004372
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00004373 if (IS_STRING_ITEM(menu->fType))
4374 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004375 }
Juergen Schmied78513941999-04-18 14:40:32 +00004376
4377 if (lpmii->fMask & MIIM_FTYPE ) {
4378 /* free the string when the type is changing */
4379 if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
Alexandre Julliardda2892c2001-02-23 01:13:42 +00004380 HeapFree(GetProcessHeap(), 0, menu->text);
Juergen Schmied78513941999-04-18 14:40:32 +00004381 menu->text = NULL;
4382 }
4383 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4384 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
Gerard Patel2482ef32001-03-19 19:16:21 +00004385 if ( IS_STRING_ITEM(menu->fType) && !menu->text )
4386 menu->fType |= MF_SEPARATOR;
Juergen Schmied78513941999-04-18 14:40:32 +00004387 }
4388
4389 if (lpmii->fMask & MIIM_STRING ) {
4390 /* free the string when used */
4391 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
Alexandre Julliardda2892c2001-02-23 01:13:42 +00004392 HeapFree(GetProcessHeap(), 0, menu->text);
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00004393 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
Juergen Schmied78513941999-04-18 14:40:32 +00004394 }
4395 }
4396
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004397 if (lpmii->fMask & MIIM_STATE)
Juergen Schmied466a6521999-05-02 11:21:08 +00004398 {
Dimitrie O. Paun693cca52002-01-29 03:12:19 +00004399 /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004400 menu->fState = lpmii->fState;
Juergen Schmied466a6521999-05-02 11:21:08 +00004401 }
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004402
4403 if (lpmii->fMask & MIIM_ID)
4404 menu->wID = lpmii->wID;
4405
Alexandre Julliarda0d77311998-09-13 16:32:00 +00004406 if (lpmii->fMask & MIIM_SUBMENU) {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004407 menu->hSubMenu = lpmii->hSubMenu;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00004408 if (menu->hSubMenu) {
Gerard Patel3e629742000-01-17 22:22:16 +00004409 POPUPMENU *subMenu = MENU_GetMenu((UINT16)menu->hSubMenu);
4410 if (subMenu) {
Alexandre Julliarda0d77311998-09-13 16:32:00 +00004411 subMenu->wFlags |= MF_POPUP;
4412 menu->fType |= MF_POPUP;
4413 }
4414 else
4415 /* FIXME: Return an error ? */
4416 menu->fType &= ~MF_POPUP;
4417 }
4418 else
4419 menu->fType &= ~MF_POPUP;
4420 }
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004421
4422 if (lpmii->fMask & MIIM_CHECKMARKS)
4423 {
Susan Farleyf1d467a2000-05-12 21:59:31 +00004424 if (lpmii->fType & MFT_RADIOCHECK)
4425 menu->fType |= MFT_RADIOCHECK;
4426
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004427 menu->hCheckBit = lpmii->hbmpChecked;
4428 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4429 }
4430 if (lpmii->fMask & MIIM_DATA)
4431 menu->dwItemData = lpmii->dwItemData;
4432
Gerard Patel2482ef32001-03-19 19:16:21 +00004433 debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004434 return TRUE;
4435}
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004436
4437/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004438 * SetMenuItemInfoA (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004439 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004440BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4441 const MENUITEMINFOA *lpmii)
Alexandre Julliard7cc9c0c1994-06-15 15:45:11 +00004442{
Marcus Meissner05aeaf12001-07-08 20:31:41 +00004443 if ((lpmii->fType & (MF_HILITE|MF_POPUP)) || (lpmii->fState)) {
4444 /* QuickTime does pass invalid data into SetMenuItemInfo.
4445 * do some of the checks Windows does.
4446 */
4447 WARN("Bad masks for type (0x%08x) or state (0x%08x)\n",
4448 lpmii->fType,lpmii->fState );
4449 return FALSE;
4450 }
4451
Alexandre Julliarda3960291999-02-26 11:11:13 +00004452 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
Aric Stewartc946b1c2000-10-24 21:28:19 +00004453 (const MENUITEMINFOW *)lpmii, FALSE);
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004454}
4455
4456/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004457 * SetMenuItemInfoW (USER32.@)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004458 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004459BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4460 const MENUITEMINFOW *lpmii)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004461{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004462 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
Aric Stewartc946b1c2000-10-24 21:28:19 +00004463 lpmii, TRUE);
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004464}
4465
4466/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004467 * SetMenuDefaultItem (USER32.@)
Juergen Schmied466a6521999-05-02 11:21:08 +00004468 *
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004469 */
Juergen Schmied466a6521999-05-02 11:21:08 +00004470BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004471{
Juergen Schmied466a6521999-05-02 11:21:08 +00004472 UINT i;
4473 POPUPMENU *menu;
4474 MENUITEM *item;
4475
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00004476 TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
Alexandre Julliarda845b881998-06-01 10:44:35 +00004477
Gerard Patel3e629742000-01-17 22:22:16 +00004478 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
Alexandre Julliarda845b881998-06-01 10:44:35 +00004479
Juergen Schmied466a6521999-05-02 11:21:08 +00004480 /* reset all default-item flags */
4481 item = menu->items;
4482 for (i = 0; i < menu->nItems; i++, item++)
4483 {
4484 item->fState &= ~MFS_DEFAULT;
4485 }
4486
4487 /* no default item */
4488 if ( -1 == uItem)
4489 {
4490 return TRUE;
4491 }
Alexandre Julliarda845b881998-06-01 10:44:35 +00004492
Juergen Schmied466a6521999-05-02 11:21:08 +00004493 item = menu->items;
4494 if ( bypos )
4495 {
4496 if ( uItem >= menu->nItems ) return FALSE;
4497 item[uItem].fState |= MFS_DEFAULT;
4498 return TRUE;
4499 }
4500 else
4501 {
4502 for (i = 0; i < menu->nItems; i++, item++)
4503 {
4504 if (item->wID == uItem)
4505 {
4506 item->fState |= MFS_DEFAULT;
4507 return TRUE;
4508 }
4509 }
4510
4511 }
4512 return FALSE;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004513}
4514
Alexandre Julliarda845b881998-06-01 10:44:35 +00004515/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004516 * GetMenuDefaultItem (USER32.@)
Alexandre Julliarda845b881998-06-01 10:44:35 +00004517 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004518UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
Alexandre Julliarda845b881998-06-01 10:44:35 +00004519{
Juergen Schmied466a6521999-05-02 11:21:08 +00004520 POPUPMENU *menu;
4521 MENUITEM * item;
4522 UINT i = 0;
Alexandre Julliarda845b881998-06-01 10:44:35 +00004523
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00004524 TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
Alexandre Julliarda845b881998-06-01 10:44:35 +00004525
Gerard Patel3e629742000-01-17 22:22:16 +00004526 if (!(menu = MENU_GetMenu(hmenu))) return -1;
Juergen Schmied466a6521999-05-02 11:21:08 +00004527
4528 /* find default item */
4529 item = menu->items;
Juergen Schmied49251861999-05-13 18:42:03 +00004530
4531 /* empty menu */
4532 if (! item) return -1;
4533
Juergen Schmied466a6521999-05-02 11:21:08 +00004534 while ( !( item->fState & MFS_DEFAULT ) )
4535 {
4536 i++; item++;
4537 if (i >= menu->nItems ) return -1;
4538 }
4539
4540 /* default: don't return disabled items */
4541 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4542
4543 /* search rekursiv when needed */
4544 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4545 {
4546 UINT ret;
4547 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4548 if ( -1 != ret ) return ret;
4549
4550 /* when item not found in submenu, return the popup item */
4551 }
4552 return ( bypos ) ? i : item->wID;
4553
Alexandre Julliarda845b881998-06-01 10:44:35 +00004554}
4555
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004556/*******************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00004557 * InsertMenuItem (USER.441)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004558 *
4559 * FIXME: untested
4560 */
4561BOOL16 WINAPI InsertMenuItem16( HMENU16 hmenu, UINT16 pos, BOOL16 byposition,
4562 const MENUITEMINFO16 *mii )
4563{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004564 MENUITEMINFOA miia;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004565
4566 miia.cbSize = sizeof(miia);
4567 miia.fMask = mii->fMask;
Alexandre Julliard982a2232000-12-13 20:20:09 +00004568 miia.dwTypeData = (LPSTR)mii->dwTypeData;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004569 miia.fType = mii->fType;
4570 miia.fState = mii->fState;
4571 miia.wID = mii->wID;
4572 miia.hSubMenu = mii->hSubMenu;
4573 miia.hbmpChecked = mii->hbmpChecked;
4574 miia.hbmpUnchecked = mii->hbmpUnchecked;
4575 miia.dwItemData = mii->dwItemData;
4576 miia.cch = mii->cch;
4577 if (IS_STRING_ITEM(miia.fType))
Alexandre Julliard982a2232000-12-13 20:20:09 +00004578 miia.dwTypeData = MapSL(mii->dwTypeData);
Alexandre Julliarda3960291999-02-26 11:11:13 +00004579 return InsertMenuItemA( hmenu, pos, byposition, &miia );
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004580}
4581
4582
4583/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004584 * InsertMenuItemA (USER32.@)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004585 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004586BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4587 const MENUITEMINFOA *lpmii)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004588{
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00004589 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
Aric Stewartc946b1c2000-10-24 21:28:19 +00004590 return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)lpmii, FALSE);
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004591}
4592
4593
4594/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004595 * InsertMenuItemW (USER32.@)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004596 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004597BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4598 const MENUITEMINFOW *lpmii)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004599{
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00004600 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
Aric Stewartc946b1c2000-10-24 21:28:19 +00004601 return SetMenuItemInfo_common(item, lpmii, TRUE);
Alexandre Julliard7cc9c0c1994-06-15 15:45:11 +00004602}
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004603
4604/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004605 * CheckMenuRadioItem (USER32.@)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004606 */
4607
Alexandre Julliarda3960291999-02-26 11:11:13 +00004608BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4609 UINT first, UINT last, UINT check,
4610 UINT bypos)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004611{
4612 MENUITEM *mifirst, *milast, *micheck;
Alexandre Julliarda3960291999-02-26 11:11:13 +00004613 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004614
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00004615 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00004616 hMenu, first, last, check, bypos);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004617
4618 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4619 milast = MENU_FindItem (&mlast, &last, bypos);
4620 micheck = MENU_FindItem (&mcheck, &check, bypos);
4621
4622 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4623 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4624 micheck > milast || micheck < mifirst)
4625 return FALSE;
4626
4627 while (mifirst <= milast)
4628 {
4629 if (mifirst == micheck)
4630 {
4631 mifirst->fType |= MFT_RADIOCHECK;
4632 mifirst->fState |= MFS_CHECKED;
4633 } else {
4634 mifirst->fType &= ~MFT_RADIOCHECK;
4635 mifirst->fState &= ~MFS_CHECKED;
4636 }
4637 mifirst++;
4638 }
4639
4640 return TRUE;
4641}
4642
4643/**********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00004644 * CheckMenuRadioItem (USER.666)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004645 */
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004646BOOL16 WINAPI CheckMenuRadioItem16(HMENU16 hMenu,
4647 UINT16 first, UINT16 last, UINT16 check,
4648 BOOL16 bypos)
4649{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004650 return CheckMenuRadioItem (hMenu, first, last, check, bypos);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004651}
4652
4653/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004654 * GetMenuItemRect (USER32.@)
Pascal Lessard47274231999-02-13 12:21:46 +00004655 *
4656 * ATTENTION: Here, the returned values in rect are the screen
4657 * coordinates of the item just like if the menu was
4658 * always on the upper left side of the application.
4659 *
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004660 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004661BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4662 LPRECT rect)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004663{
Pascal Lessard47274231999-02-13 12:21:46 +00004664 POPUPMENU *itemMenu;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004665 MENUITEM *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00004666 HWND referenceHwnd;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004667
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00004668 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004669
4670 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
Pascal Lessard47274231999-02-13 12:21:46 +00004671 referenceHwnd = hwnd;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004672
Pascal Lessard47274231999-02-13 12:21:46 +00004673 if(!hwnd)
4674 {
Gerard Patel3e629742000-01-17 22:22:16 +00004675 itemMenu = MENU_GetMenu(hMenu);
Pascal Lessard47274231999-02-13 12:21:46 +00004676 if (itemMenu == NULL)
4677 return FALSE;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004678
Marcus Meissnerac593bb1999-03-17 15:18:28 +00004679 if(itemMenu->hWnd == 0)
Pascal Lessard47274231999-02-13 12:21:46 +00004680 return FALSE;
4681 referenceHwnd = itemMenu->hWnd;
4682 }
4683
4684 if ((rect == NULL) || (item == NULL))
4685 return FALSE;
4686
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004687 *rect = item->rect;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004688
Alexandre Julliarda3960291999-02-26 11:11:13 +00004689 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
Pascal Lessard47274231999-02-13 12:21:46 +00004690
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004691 return TRUE;
4692}
4693
Paul Quinn1beaae51998-12-15 15:38:36 +00004694
4695/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004696 * SetMenuInfo (USER32.@)
Juergen Schmied78513941999-04-18 14:40:32 +00004697 *
4698 * FIXME
4699 * MIM_APPLYTOSUBMENUS
4700 * actually use the items to draw the menu
4701 */
4702BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4703{
4704 POPUPMENU *menu;
4705
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00004706 TRACE("(0x%04x %p)\n", hMenu, lpmi);
Juergen Schmied78513941999-04-18 14:40:32 +00004707
Gerard Patel3e629742000-01-17 22:22:16 +00004708 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
Juergen Schmied78513941999-04-18 14:40:32 +00004709 {
4710
4711 if (lpmi->fMask & MIM_BACKGROUND)
4712 menu->hbrBack = lpmi->hbrBack;
4713
4714 if (lpmi->fMask & MIM_HELPID)
4715 menu->dwContextHelpID = lpmi->dwContextHelpID;
4716
4717 if (lpmi->fMask & MIM_MAXHEIGHT)
4718 menu->cyMax = lpmi->cyMax;
4719
4720 if (lpmi->fMask & MIM_MENUDATA)
4721 menu->dwMenuData = lpmi->dwMenuData;
4722
4723 if (lpmi->fMask & MIM_STYLE)
4724 menu->dwStyle = lpmi->dwStyle;
4725
4726 return TRUE;
4727 }
4728 return FALSE;
4729}
4730
4731/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004732 * GetMenuInfo (USER32.@)
Juergen Schmied78513941999-04-18 14:40:32 +00004733 *
4734 * NOTES
4735 * win98/NT5.0
4736 *
4737 */
4738BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4739{ POPUPMENU *menu;
4740
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00004741 TRACE("(0x%04x %p)\n", hMenu, lpmi);
Juergen Schmied78513941999-04-18 14:40:32 +00004742
Gerard Patel3e629742000-01-17 22:22:16 +00004743 if (lpmi && (menu = MENU_GetMenu(hMenu)))
Juergen Schmied78513941999-04-18 14:40:32 +00004744 {
4745
4746 if (lpmi->fMask & MIM_BACKGROUND)
4747 lpmi->hbrBack = menu->hbrBack;
4748
4749 if (lpmi->fMask & MIM_HELPID)
4750 lpmi->dwContextHelpID = menu->dwContextHelpID;
4751
4752 if (lpmi->fMask & MIM_MAXHEIGHT)
4753 lpmi->cyMax = menu->cyMax;
4754
4755 if (lpmi->fMask & MIM_MENUDATA)
4756 lpmi->dwMenuData = menu->dwMenuData;
4757
4758 if (lpmi->fMask & MIM_STYLE)
4759 lpmi->dwStyle = menu->dwStyle;
4760
4761 return TRUE;
4762 }
4763 return FALSE;
4764}
4765
4766/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00004767 * SetMenuContextHelpId (USER.384)
Paul Quinn1beaae51998-12-15 15:38:36 +00004768 */
Juergen Schmied78513941999-04-18 14:40:32 +00004769BOOL16 WINAPI SetMenuContextHelpId16( HMENU16 hMenu, DWORD dwContextHelpID)
Paul Quinn1beaae51998-12-15 15:38:36 +00004770{
Juergen Schmied78513941999-04-18 14:40:32 +00004771 return SetMenuContextHelpId( hMenu, dwContextHelpID );
Paul Quinn1beaae51998-12-15 15:38:36 +00004772}
4773
4774
4775/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004776 * SetMenuContextHelpId (USER32.@)
Paul Quinn1beaae51998-12-15 15:38:36 +00004777 */
Juergen Schmied78513941999-04-18 14:40:32 +00004778BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
Paul Quinn1beaae51998-12-15 15:38:36 +00004779{
Juergen Schmied78513941999-04-18 14:40:32 +00004780 LPPOPUPMENU menu;
4781
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00004782 TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
Juergen Schmied78513941999-04-18 14:40:32 +00004783
Gerard Patel3e629742000-01-17 22:22:16 +00004784 if ((menu = MENU_GetMenu(hMenu)))
Juergen Schmied78513941999-04-18 14:40:32 +00004785 {
4786 menu->dwContextHelpID = dwContextHelpID;
4787 return TRUE;
4788 }
4789 return FALSE;
Paul Quinn1beaae51998-12-15 15:38:36 +00004790}
4791
4792/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00004793 * GetMenuContextHelpId (USER.385)
Paul Quinn1beaae51998-12-15 15:38:36 +00004794 */
4795DWORD WINAPI GetMenuContextHelpId16( HMENU16 hMenu )
4796{
Juergen Schmied78513941999-04-18 14:40:32 +00004797 return GetMenuContextHelpId( hMenu );
Paul Quinn1beaae51998-12-15 15:38:36 +00004798}
4799
4800/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004801 * GetMenuContextHelpId (USER32.@)
Paul Quinn1beaae51998-12-15 15:38:36 +00004802 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004803DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
Paul Quinn1beaae51998-12-15 15:38:36 +00004804{
Juergen Schmied78513941999-04-18 14:40:32 +00004805 LPPOPUPMENU menu;
4806
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00004807 TRACE("(0x%04x)\n", hMenu);
Juergen Schmied78513941999-04-18 14:40:32 +00004808
Gerard Patel3e629742000-01-17 22:22:16 +00004809 if ((menu = MENU_GetMenu(hMenu)))
Juergen Schmied78513941999-04-18 14:40:32 +00004810 {
4811 return menu->dwContextHelpID;
4812 }
4813 return 0;
Paul Quinn1beaae51998-12-15 15:38:36 +00004814}
Eric Pouech0c62bf01999-09-13 15:11:35 +00004815
4816/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004817 * MenuItemFromPoint (USER32.@)
Eric Pouech0c62bf01999-09-13 15:11:35 +00004818 */
4819UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4820{
4821 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4822 hWnd, hMenu, ptScreen.x, ptScreen.y);
4823 return 0;
4824}
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004825
4826
4827/**********************************************************************
4828 * translate_accelerator
4829 */
4830static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4831 BYTE fVirt, WORD key, WORD cmd )
4832{
4833 UINT mesg = 0;
4834
4835 if (wParam != key) return FALSE;
4836
4837 if (message == WM_CHAR)
4838 {
4839 if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
4840 {
4841 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
4842 goto found;
4843 }
4844 }
4845 else
4846 {
4847 if(fVirt & FVIRTKEY)
4848 {
4849 INT mask = 0;
4850 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
4851 wParam, 0xff & HIWORD(lParam));
4852 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
4853 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
4854 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
4855 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
4856 TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
4857 }
4858 else
4859 {
4860 if (!(lParam & 0x01000000)) /* no special_key */
4861 {
4862 if ((fVirt & FALT) && (lParam & 0x20000000))
4863 { /* ^^ ALT pressed */
4864 TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
4865 goto found;
4866 }
4867 }
4868 }
4869 }
4870 return FALSE;
4871
4872 found:
4873 if (message == WM_KEYUP || message == WM_SYSKEYUP)
4874 mesg = 1;
4875 else if (GetCapture())
4876 mesg = 2;
4877 else if (!IsWindowEnabled(hWnd))
4878 mesg = 3;
4879 else
4880 {
4881 HMENU hMenu, hSubMenu, hSysMenu;
4882 UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004883
Alexandre Julliardde424282001-08-10 22:51:42 +00004884 hMenu = (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
4885 hSysMenu = get_win_sys_menu( hWnd );
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004886
4887 /* find menu item and ask application to initialize it */
4888 /* 1. in the system menu */
4889 hSubMenu = hSysMenu;
4890 nPos = cmd;
4891 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4892 {
4893 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
4894 if(hSubMenu != hSysMenu)
4895 {
4896 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
4897 TRACE_(accel)("hSysMenu = %04x, hSubMenu = %04x, nPos = %d\n", hSysMenu, hSubMenu, nPos);
4898 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
4899 }
4900 uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
4901 }
4902 else /* 2. in the window's menu */
4903 {
4904 hSubMenu = hMenu;
4905 nPos = cmd;
4906 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4907 {
4908 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
4909 if(hSubMenu != hMenu)
4910 {
4911 nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
4912 TRACE_(accel)("hMenu = %04x, hSubMenu = %04x, nPos = %d\n", hMenu, hSubMenu, nPos);
4913 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
4914 }
4915 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
4916 }
4917 }
4918
4919 if (uSysStat != (UINT)-1)
4920 {
4921 if (uSysStat & (MF_DISABLED|MF_GRAYED))
4922 mesg=4;
4923 else
4924 mesg=WM_SYSCOMMAND;
4925 }
4926 else
4927 {
4928 if (uStat != (UINT)-1)
4929 {
4930 if (IsIconic(hWnd))
4931 mesg=5;
4932 else
4933 {
4934 if (uStat & (MF_DISABLED|MF_GRAYED))
4935 mesg=6;
4936 else
4937 mesg=WM_COMMAND;
4938 }
4939 }
4940 else
4941 mesg=WM_COMMAND;
4942 }
4943 }
4944
4945 if( mesg==WM_COMMAND )
4946 {
4947 TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
4948 SendMessageA(hWnd, mesg, 0x10000 | cmd, 0L);
4949 }
4950 else if( mesg==WM_SYSCOMMAND )
4951 {
4952 TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
4953 SendMessageA(hWnd, mesg, cmd, 0x00010000L);
4954 }
4955 else
4956 {
4957 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
4958 * #0: unknown (please report!)
4959 * #1: for WM_KEYUP,WM_SYSKEYUP
4960 * #2: mouse is captured
4961 * #3: window is disabled
4962 * #4: it's a disabled system menu option
4963 * #5: it's a menu option, but window is iconic
4964 * #6: it's a menu option, but disabled
4965 */
4966 TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
4967 if(mesg==0)
4968 ERR_(accel)(" unknown reason - please report!");
4969 }
4970 return TRUE;
4971}
4972
4973/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004974 * TranslateAccelerator (USER32.@)
Patrik Stridvall17fd4e32001-06-28 18:04:41 +00004975 * TranslateAcceleratorA (USER32.@)
Patrik Stridvall15a3b742001-04-27 18:03:51 +00004976 * TranslateAcceleratorW (USER32.@)
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004977 */
4978INT WINAPI TranslateAccelerator( HWND hWnd, HACCEL hAccel, LPMSG msg )
4979{
4980 /* YES, Accel16! */
4981 LPACCEL16 lpAccelTbl;
4982 int i;
4983
4984 if (msg == NULL)
4985 {
4986 WARN_(accel)("msg null; should hang here to be win compatible\n");
4987 return 0;
4988 }
4989 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(hAccel)))
4990 {
4991 WARN_(accel)("invalid accel handle=%x\n", hAccel);
4992 return 0;
4993 }
4994 if ((msg->message != WM_KEYDOWN &&
4995 msg->message != WM_KEYUP &&
4996 msg->message != WM_SYSKEYDOWN &&
4997 msg->message != WM_SYSKEYUP &&
4998 msg->message != WM_CHAR)) return 0;
4999
5000 TRACE_(accel)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5001 "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
5002 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
5003
5004 i = 0;
5005 do
5006 {
5007 if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
5008 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
5009 return 1;
5010 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
5011 WARN_(accel)("couldn't translate accelerator key\n");
5012 return 0;
5013}