blob: bdae2a24f0fed6f7f3fede131764ebadfd5e7ede [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 Julliard864ca062003-08-20 18:22:31 +000038#include "winbase.h"
Jeremy Whited3e22d92000-02-10 19:03:02 +000039#include "wingdi.h"
Alexandre Julliard864ca062003-08-20 18:22:31 +000040#include "winnls.h"
Francois Boisvert85dd9fc1999-02-17 12:50:11 +000041#include "wine/winbase16.h"
Michael Veksler3fbb8dc1999-02-21 18:23:26 +000042#include "wine/winuser16.h"
Alexandre Julliard0ca051e2002-10-17 16:43:42 +000043#include "wownt32.h"
Alexandre Julliarda9e8f592002-10-12 01:24:37 +000044#include "wine/server.h"
Alexandre Julliard24a62ab2000-11-28 22:40:56 +000045#include "wine/unicode.h"
Jeremy Whited3e22d92000-02-10 19:03:02 +000046#include "win.h"
Alexandre Julliard91222da2000-12-10 23:01:33 +000047#include "controls.h"
Alexandre Julliardc6c09441997-01-12 18:32:19 +000048#include "nonclient.h"
Alexandre Julliard1f579291994-05-25 16:25:21 +000049#include "user.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000050#include "wine/debug.h"
Alexandre Julliardaca05781994-10-17 18:12:41 +000051
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000052WINE_DEFAULT_DEBUG_CHANNEL(menu);
53WINE_DECLARE_DEBUG_CHANNEL(accel);
Alexandre Julliardd37eb361997-07-20 16:23:21 +000054
Alexandre Julliard7ff1c411997-05-25 13:58:18 +000055/* internal popup menu window messages */
56
57#define MM_SETMENUHANDLE (WM_USER + 0)
58#define MM_GETMENUHANDLE (WM_USER + 1)
59
Alexandre Julliard2d93d001996-05-21 15:01:41 +000060/* Menu item structure */
Alexandre Julliard670cdc41997-08-24 16:00:30 +000061typedef struct {
62 /* ----------- MENUITEMINFO Stuff ----------- */
Juergen Schmied78513941999-04-18 14:40:32 +000063 UINT fType; /* Item type. */
Alexandre Julliarda3960291999-02-26 11:11:13 +000064 UINT fState; /* Item state. */
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +000065 UINT_PTR wID; /* Item id. */
Alexandre Julliarda3960291999-02-26 11:11:13 +000066 HMENU hSubMenu; /* Pop-up menu. */
Juergen Schmied78513941999-04-18 14:40:32 +000067 HBITMAP hCheckBit; /* Bitmap when checked. */
Alexandre Julliarda3960291999-02-26 11:11:13 +000068 HBITMAP hUnCheckBit; /* Bitmap when unchecked. */
Aric Stewartc946b1c2000-10-24 21:28:19 +000069 LPWSTR text; /* Item text or bitmap handle. */
Alexandre Julliard670cdc41997-08-24 16:00:30 +000070 DWORD dwItemData; /* Application defined. */
Juergen Schmied78513941999-04-18 14:40:32 +000071 DWORD dwTypeData; /* depends on fMask */
72 HBITMAP hbmpItem; /* bitmap in win98 style menus */
Alexandre Julliard670cdc41997-08-24 16:00:30 +000073 /* ----------- Wine stuff ----------- */
Juergen Schmied78513941999-04-18 14:40:32 +000074 RECT rect; /* Item area (relative to menu window) */
75 UINT xTab; /* X position of text after Tab */
Alexandre Julliard2d93d001996-05-21 15:01:41 +000076} MENUITEM;
77
78/* Popup menu structure */
Alexandre Julliard670cdc41997-08-24 16:00:30 +000079typedef struct {
Alexandre Julliard2d93d001996-05-21 15:01:41 +000080 WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
81 WORD wMagic; /* Magic number */
Alexandre Julliard2d93d001996-05-21 15:01:41 +000082 WORD Width; /* Width of the whole menu */
83 WORD Height; /* Height of the whole menu */
Alexandre Julliarde60ccd12001-05-11 20:05:42 +000084 UINT nItems; /* Number of items in the menu */
Juergen Schmied78513941999-04-18 14:40:32 +000085 HWND hWnd; /* Window containing the menu */
86 MENUITEM *items; /* Array of menu items */
87 UINT FocusedItem; /* Currently focused item */
Juergen Schmied466a6521999-05-02 11:21:08 +000088 HWND hwndOwner; /* window receiving the messages for ownerdraw */
Pascal Lessard2eb0a301999-09-03 16:38:52 +000089 BOOL bTimeToHide; /* Request hiding when receiving a second click in the top-level menu item */
Juergen Schmied78513941999-04-18 14:40:32 +000090 /* ------------ MENUINFO members ------ */
91 DWORD dwStyle; /* Extended mennu style */
92 UINT cyMax; /* max hight of the whole menu, 0 is screen hight */
93 HBRUSH hbrBack; /* brush for menu background */
94 DWORD dwContextHelpID;
95 DWORD dwMenuData; /* application defined value */
Pascal Lessardd814bb61999-07-31 13:02:02 +000096 HMENU hSysMenuOwner; /* Handle to the dummy sys menu holder */
Alexandre Julliard2d93d001996-05-21 15:01:41 +000097} POPUPMENU, *LPPOPUPMENU;
98
Alexandre Julliard7ff1c411997-05-25 13:58:18 +000099/* internal flags for menu tracking */
100
101#define TF_ENDMENU 0x0001
102#define TF_SUSPENDPOPUP 0x0002
103#define TF_SKIPREMOVE 0x0004
104
105typedef struct
106{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000107 UINT trackFlags;
108 HMENU hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
109 HMENU hTopMenu; /* initial menu */
110 HWND hOwnerWnd; /* where notifications are sent */
111 POINT pt;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000112} MTRACKER;
113
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000114#define MENU_MAGIC 0x554d /* 'MU' */
115
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000116#define ITEM_PREV -1
117#define ITEM_NEXT 1
118
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000119 /* Internal MENU_TrackMenu() flags */
120#define TPM_INTERNAL 0xF0000000
121#define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
122#define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
Francois Boisvert85dd9fc1999-02-17 12:50:11 +0000123#define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
Alexandre Julliardf7207251994-07-23 07:57:48 +0000124
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000125 /* popup menu shade thickness */
126#define POPUP_XSHADE 4
127#define POPUP_YSHADE 4
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000128
Alexandre Julliardf7207251994-07-23 07:57:48 +0000129 /* Space between 2 menu bar items */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000130#define MENU_BAR_ITEMS_SPACE 12
Alexandre Julliardf7207251994-07-23 07:57:48 +0000131
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000132 /* Minimum width of a tab character */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000133#define MENU_TAB_SPACE 8
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000134
Alexandre Julliardf7207251994-07-23 07:57:48 +0000135 /* Height of a separator item */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000136#define SEPARATOR_HEIGHT 5
Alexandre Julliardf7207251994-07-23 07:57:48 +0000137
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000138 /* (other menu->FocusedItem values give the position of the focused item) */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000139#define NO_SELECTED_ITEM 0xffff
Alexandre Julliardcdd09231994-01-12 11:12:51 +0000140
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000141#define MENU_ITEM_TYPE(flags) \
142 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
143
144#define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
Juergen Schmied78513941999-04-18 14:40:32 +0000145#define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
François Gouget75b278e2001-01-06 01:45:51 +0000146#define IS_MAGIC_ITEM(text) (LOWORD((int)text)<12)
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000147
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000148#define IS_SYSTEM_MENU(menu) \
149 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
Juergen Schmied78513941999-04-18 14:40:32 +0000150
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000151#define IS_SYSTEM_POPUP(menu) \
152 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
153
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000154#define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
155 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
156 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
157 MF_POPUP | MF_SYSMENU | MF_HELP)
158#define STATE_MASK (~TYPE_MASK)
159
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000160 /* Dimension of the menu bitmaps */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000161static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000162
Alexandre Julliarda3960291999-02-26 11:11:13 +0000163static HBITMAP hStdMnArrow = 0;
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000164static HBITMAP hBmpSysMenu = 0;
Francois Boisvert8b391741999-02-09 14:09:55 +0000165
Juergen Schmied78513941999-04-18 14:40:32 +0000166static HBRUSH hShadeBrush = 0;
167static HFONT hMenuFont = 0;
Juergen Schmied466a6521999-05-02 11:21:08 +0000168static HFONT hMenuFontBold = 0;
Juergen Schmied78513941999-04-18 14:40:32 +0000169
Alexandre Julliarda3960291999-02-26 11:11:13 +0000170static HMENU MENU_DefSysPopup = 0; /* Default system menu popup */
Alexandre Julliard1285c2f1996-05-06 16:06:24 +0000171
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000172/* Use global popup window because there's no way 2 menus can
Vincent Béron9a624912002-05-31 23:06:46 +0000173 * be tracked at the same time. */
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000174static HWND top_popup;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000175
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000176 /* Flag set by EndMenu() to force an exit from menu tracking */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000177static BOOL fEndMenu = FALSE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000178
Alexandre Julliard91222da2000-12-10 23:01:33 +0000179static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
180
Robert Shearman9caa6ba2003-01-14 19:28:49 +0000181DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont);
Alexandre Julliard91222da2000-12-10 23:01:33 +0000182
183/*********************************************************************
184 * menu class descriptor
185 */
186const struct builtin_class_descr MENU_builtin_class =
187{
188 POPUPMENU_CLASS_ATOM, /* name */
189 CS_GLOBALCLASS | CS_SAVEBITS, /* style */
190 NULL, /* procA (winproc is Unicode only) */
191 PopupMenuWndProc, /* procW */
192 sizeof(HMENU), /* extra */
193 IDC_ARROWA, /* cursor */
Alexandre Julliard7ef66af2002-11-22 04:47:10 +0000194 (HBRUSH)(COLOR_MENU+1) /* brush */
Alexandre Julliard91222da2000-12-10 23:01:33 +0000195};
196
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000197
198/***********************************************************************
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000199 * debug_print_menuitem
200 *
201 * Print a menuitem in readable form.
202 */
203
Alexandre Julliard03468f71998-02-15 19:40:49 +0000204#define debug_print_menuitem(pre, mp, post) \
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000205 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
Alexandre Julliard03468f71998-02-15 19:40:49 +0000206
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000207#define MENUOUT(text) \
Alexandre Julliard15de6151999-08-04 12:22:42 +0000208 DPRINTF("%s%s", (count++ ? "," : ""), (text))
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000209
210#define MENUFLAG(bit,text) \
211 do { \
212 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
213 } while (0)
214
Vincent Béron9a624912002-05-31 23:06:46 +0000215static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
Alexandre Julliard03468f71998-02-15 19:40:49 +0000216 const char *postfix)
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000217{
Alexandre Julliard15de6151999-08-04 12:22:42 +0000218 TRACE("%s ", prefix);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000219 if (mp) {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000220 UINT flags = mp->fType;
Andreas Mohr8578f012002-08-28 23:31:56 +0000221 int type = MENU_ITEM_TYPE(flags);
Alexandre Julliard15de6151999-08-04 12:22:42 +0000222 DPRINTF( "{ ID=0x%x", mp->wID);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000223 if (flags & MF_POPUP)
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000224 DPRINTF( ", Sub=%p", mp->hSubMenu);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000225 if (flags) {
226 int count = 0;
Andreas Mohr8578f012002-08-28 23:31:56 +0000227 DPRINTF( ", Type=");
228 if (type == MFT_STRING)
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000229 /* Nothing */ ;
Andreas Mohr8578f012002-08-28 23:31:56 +0000230 else if (type == MFT_SEPARATOR)
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000231 MENUOUT("sep");
Andreas Mohr8578f012002-08-28 23:31:56 +0000232 else if (type == MFT_OWNERDRAW)
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000233 MENUOUT("own");
Andreas Mohr8578f012002-08-28 23:31:56 +0000234 else if (type == MFT_BITMAP)
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000235 MENUOUT("bit");
236 else
237 MENUOUT("???");
Andreas Mohr8578f012002-08-28 23:31:56 +0000238 flags -= type;
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000239
240 MENUFLAG(MF_POPUP, "pop");
241 MENUFLAG(MFT_MENUBARBREAK, "barbrk");
242 MENUFLAG(MFT_MENUBREAK, "brk");
243 MENUFLAG(MFT_RADIOCHECK, "radio");
244 MENUFLAG(MFT_RIGHTORDER, "rorder");
245 MENUFLAG(MF_SYSMENU, "sys");
Juergen Schmiedcd0ed1e1999-04-26 14:54:38 +0000246 MENUFLAG(MFT_RIGHTJUSTIFY, "right"); /* same as MF_HELP */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000247
248 if (flags)
Alexandre Julliard15de6151999-08-04 12:22:42 +0000249 DPRINTF( "+0x%x", flags);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000250 }
251 flags = mp->fState;
252 if (flags) {
253 int count = 0;
Alexandre Julliard15de6151999-08-04 12:22:42 +0000254 DPRINTF( ", State=");
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000255 MENUFLAG(MFS_GRAYED, "grey");
Juergen Schmied466a6521999-05-02 11:21:08 +0000256 MENUFLAG(MFS_DEFAULT, "default");
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000257 MENUFLAG(MFS_DISABLED, "dis");
258 MENUFLAG(MFS_CHECKED, "check");
259 MENUFLAG(MFS_HILITE, "hi");
260 MENUFLAG(MF_USECHECKBITMAPS, "usebit");
261 MENUFLAG(MF_MOUSESELECT, "mouse");
262 if (flags)
Alexandre Julliard15de6151999-08-04 12:22:42 +0000263 DPRINTF( "+0x%x", flags);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000264 }
265 if (mp->hCheckBit)
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000266 DPRINTF( ", Chk=%p", mp->hCheckBit);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000267 if (mp->hUnCheckBit)
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000268 DPRINTF( ", Unc=%p", mp->hUnCheckBit);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000269
Andreas Mohr8578f012002-08-28 23:31:56 +0000270 if (type == MFT_STRING) {
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000271 if (mp->text)
François Gougetb99367e2001-02-14 21:42:10 +0000272 DPRINTF( ", Text=%s", debugstr_w(mp->text));
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000273 else
Alexandre Julliard15de6151999-08-04 12:22:42 +0000274 DPRINTF( ", Text=Null");
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000275 } else if (mp->text == NULL)
276 /* Nothing */ ;
277 else
Alexandre Julliard15de6151999-08-04 12:22:42 +0000278 DPRINTF( ", Text=%p", mp->text);
Juergen Schmied7abca951999-04-11 17:02:30 +0000279 if (mp->dwItemData)
Alexandre Julliard15de6151999-08-04 12:22:42 +0000280 DPRINTF( ", ItemData=0x%08lx", mp->dwItemData);
281 DPRINTF( " }");
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000282 } else {
Alexandre Julliard15de6151999-08-04 12:22:42 +0000283 DPRINTF( "NULL");
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000284 }
Alexandre Julliard03468f71998-02-15 19:40:49 +0000285
Alexandre Julliard15de6151999-08-04 12:22:42 +0000286 DPRINTF(" %s\n", postfix);
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000287}
288
289#undef MENUOUT
290#undef MENUFLAG
291
Gerard Patel3e629742000-01-17 22:22:16 +0000292
293/***********************************************************************
294 * MENU_GetMenu
295 *
296 * Validate the given menu handle and returns the menu structure pointer.
297 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000298static POPUPMENU *MENU_GetMenu(HMENU hMenu)
Gerard Patel3e629742000-01-17 22:22:16 +0000299{
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000300 POPUPMENU *menu = USER_HEAP_LIN_ADDR(hMenu);
301 if (!menu || menu->wMagic != MENU_MAGIC)
Gerard Patel3e629742000-01-17 22:22:16 +0000302 {
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000303 WARN("invalid menu handle=%p, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
Gerard Patel3e629742000-01-17 22:22:16 +0000304 menu = NULL;
305 }
306 return menu;
307}
308
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000309/***********************************************************************
Alexandre Julliardde424282001-08-10 22:51:42 +0000310 * get_win_sys_menu
311 *
312 * Get the system menu of a window
313 */
314static HMENU get_win_sys_menu( HWND hwnd )
315{
316 HMENU ret = 0;
317 WND *win = WIN_FindWndPtr( hwnd );
318 if (win)
319 {
320 ret = win->hSysMenu;
321 WIN_ReleaseWndPtr( win );
322 }
323 return ret;
324}
325
326/***********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000327 * MENU_CopySysPopup
328 *
329 * Return the default system menu.
330 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000331static HMENU MENU_CopySysPopup(void)
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000332{
Bertho Stultiensd1895a71999-04-25 18:31:35 +0000333 HMENU hMenu = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000334
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000335 if( hMenu ) {
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000336 POPUPMENU* menu = MENU_GetMenu(hMenu);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000337 menu->wFlags |= MF_SYSMENU | MF_POPUP;
Juergen Schmied49251861999-05-13 18:42:03 +0000338 SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000339 }
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000340 else
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000341 ERR("Unable to load default system menu\n" );
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000342
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000343 TRACE("returning %p.\n", hMenu );
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000344
345 return hMenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000346}
347
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000348
349/**********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000350 * MENU_GetSysMenu
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000351 *
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000352 * Create a copy of the system menu. System menu in Windows is
Andreas Mohra6d83eb2000-12-27 04:02:46 +0000353 * a special menu bar with the single entry - system menu popup.
Vincent Béron9a624912002-05-31 23:06:46 +0000354 * This popup is presented to the outside world as a "system menu".
355 * However, the real system menu handle is sometimes seen in the
Andreas Mohra6d83eb2000-12-27 04:02:46 +0000356 * WM_MENUSELECT parameters (and Word 6 likes it this way).
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000357 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000358HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000359{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000360 HMENU hMenu;
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000361
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000362 TRACE("loading system menu, hWnd %p, hPopupMenu %p\n", hWnd, hPopupMenu);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000363 if ((hMenu = CreateMenu()))
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000364 {
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000365 POPUPMENU *menu = MENU_GetMenu(hMenu);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000366 menu->wFlags = MF_SYSMENU;
Alexandre Julliardf44bbb82001-09-14 00:24:39 +0000367 menu->hWnd = WIN_GetFullHandle( hWnd );
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000368 TRACE("hWnd %p (hMenu %p)\n", menu->hWnd, hMenu);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000369
Alexandre Julliarda3960291999-02-26 11:11:13 +0000370 if (hPopupMenu == (HMENU)(-1))
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000371 hPopupMenu = MENU_CopySysPopup();
Vincent Béron9a624912002-05-31 23:06:46 +0000372 else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000373
374 if (hPopupMenu)
375 {
Alexandre Julliard7ef66af2002-11-22 04:47:10 +0000376 InsertMenuA( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION,
377 (UINT_PTR)hPopupMenu, NULL );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000378
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000379 menu->items[0].fType = MF_SYSMENU | MF_POPUP;
380 menu->items[0].fState = 0;
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000381 if ((menu = MENU_GetMenu(hPopupMenu))) menu->wFlags |= MF_SYSMENU;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000382
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000383 TRACE("hMenu=%p (hPopup %p)\n", hMenu, hPopupMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000384 return hMenu;
385 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000386 DestroyMenu( hMenu );
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000387 }
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000388 ERR("failed to load system menu!\n");
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000389 return 0;
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000390}
391
392
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000393/***********************************************************************
394 * MENU_Init
395 *
396 * Menus initialisation.
397 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000398BOOL MENU_Init()
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000399{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000400 HBITMAP hBitmap;
Juergen Schmied78513941999-04-18 14:40:32 +0000401 NONCLIENTMETRICSA ncm;
402
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000403 static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
404 0x55, 0, 0xAA, 0,
405 0x55, 0, 0xAA, 0,
406 0x55, 0, 0xAA, 0 };
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000407
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000408 /* Load menu bitmaps */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000409 hStdMnArrow = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW));
Francois Boisvert8b391741999-02-09 14:09:55 +0000410 /* Load system buttons bitmaps */
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000411 hBmpSysMenu = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CLOSE));
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000412
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000413 if (hStdMnArrow)
Juergen Schmied78513941999-04-18 14:40:32 +0000414 {
415 BITMAP bm;
416 GetObjectA( hStdMnArrow, sizeof(bm), &bm );
417 arrow_bitmap_width = bm.bmWidth;
418 arrow_bitmap_height = bm.bmHeight;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000419 } else
Juergen Schmied78513941999-04-18 14:40:32 +0000420 return FALSE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000421
Vincent Béron9a624912002-05-31 23:06:46 +0000422 if (! (hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits)))
Juergen Schmied78513941999-04-18 14:40:32 +0000423 return FALSE;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000424
Vincent Béron9a624912002-05-31 23:06:46 +0000425 if(!(hShadeBrush = CreatePatternBrush( hBitmap )))
Juergen Schmied78513941999-04-18 14:40:32 +0000426 return FALSE;
Vincent Béron9a624912002-05-31 23:06:46 +0000427
Juergen Schmied78513941999-04-18 14:40:32 +0000428 DeleteObject( hBitmap );
429 if (!(MENU_DefSysPopup = MENU_CopySysPopup()))
430 return FALSE;
431
432 ncm.cbSize = sizeof (NONCLIENTMETRICSA);
433 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &ncm, 0)))
434 return FALSE;
Vincent Béron9a624912002-05-31 23:06:46 +0000435
Juergen Schmied78513941999-04-18 14:40:32 +0000436 if (!(hMenuFont = CreateFontIndirectA( &ncm.lfMenuFont )))
437 return FALSE;
438
Juergen Schmied466a6521999-05-02 11:21:08 +0000439 ncm.lfMenuFont.lfWeight += 300;
440 if ( ncm.lfMenuFont.lfWeight > 1000)
441 ncm.lfMenuFont.lfWeight = 1000;
442
443 if (!(hMenuFontBold = CreateFontIndirectA( &ncm.lfMenuFont )))
444 return FALSE;
445
Juergen Schmied78513941999-04-18 14:40:32 +0000446 return TRUE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000447}
448
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000449/***********************************************************************
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000450 * MENU_InitSysMenuPopup
451 *
452 * Grey the appropriate items in System menu.
453 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000454static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000455{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000456 BOOL gray;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000457
458 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
Alexandre Julliarda3960291999-02-26 11:11:13 +0000459 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000460 gray = ((style & WS_MAXIMIZE) != 0);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000461 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000462 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000463 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000464 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000465 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000466 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
Alexandre Julliarda3960291999-02-26 11:11:13 +0000467 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000468 gray = (clsStyle & CS_NOCLOSE) != 0;
Pascal Lessardd814bb61999-07-31 13:02:02 +0000469
470 /* The menu item must keep its state if it's disabled */
471 if(gray)
472 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000473}
474
475
Alexandre Julliard641ee761997-08-04 16:34:36 +0000476/******************************************************************************
477 *
Patrik Stridvall2d6457c2000-03-28 20:22:59 +0000478 * UINT MENU_GetStartOfNextColumn(
479 * HMENU hMenu )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000480 *
481 *****************************************************************************/
482
Alexandre Julliarda3960291999-02-26 11:11:13 +0000483static UINT MENU_GetStartOfNextColumn(
484 HMENU hMenu )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000485{
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000486 POPUPMENU *menu = MENU_GetMenu(hMenu);
487 UINT i;
Alexandre Julliard641ee761997-08-04 16:34:36 +0000488
489 if(!menu)
490 return NO_SELECTED_ITEM;
491
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000492 i = menu->FocusedItem + 1;
Alexandre Julliard641ee761997-08-04 16:34:36 +0000493 if( i == NO_SELECTED_ITEM )
494 return i;
495
496 for( ; i < menu->nItems; ++i ) {
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000497 if (menu->items[i].fType & MF_MENUBARBREAK)
Alexandre Julliard641ee761997-08-04 16:34:36 +0000498 return i;
499 }
500
501 return NO_SELECTED_ITEM;
502}
503
504
505/******************************************************************************
506 *
Patrik Stridvall2d6457c2000-03-28 20:22:59 +0000507 * UINT MENU_GetStartOfPrevColumn(
508 * HMENU hMenu )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000509 *
510 *****************************************************************************/
511
Alexandre Julliarda3960291999-02-26 11:11:13 +0000512static UINT MENU_GetStartOfPrevColumn(
513 HMENU hMenu )
Alexandre Julliard641ee761997-08-04 16:34:36 +0000514{
Alexandre Julliarde60ccd12001-05-11 20:05:42 +0000515 POPUPMENU *menu = MENU_GetMenu(hMenu);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000516 UINT i;
Alexandre Julliard641ee761997-08-04 16:34:36 +0000517
518 if( !menu )
519 return NO_SELECTED_ITEM;
520
521 if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
522 return NO_SELECTED_ITEM;
523
524 /* Find the start of the column */
525
526 for(i = menu->FocusedItem; i != 0 &&
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000527 !(menu->items[i].fType & MF_MENUBARBREAK);
Alexandre Julliard641ee761997-08-04 16:34:36 +0000528 --i); /* empty */
529
530 if(i == 0)
531 return NO_SELECTED_ITEM;
532
533 for(--i; i != 0; --i) {
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000534 if (menu->items[i].fType & MF_MENUBARBREAK)
Alexandre Julliard641ee761997-08-04 16:34:36 +0000535 break;
536 }
537
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000538 TRACE("ret %d.\n", i );
Alexandre Julliard641ee761997-08-04 16:34:36 +0000539
540 return i;
541}
542
543
544
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000545/***********************************************************************
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000546 * MENU_FindItem
547 *
548 * Find a menu item. Return a pointer on the item, and modifies *hmenu
549 * in case the item was in a sub-menu.
550 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000551static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000552{
553 POPUPMENU *menu;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000554 UINT i;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000555
Alexandre Julliarda8a422f2002-11-22 20:43:01 +0000556 if ((*hmenu == (HMENU)0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000557 if (wFlags & MF_BYPOSITION)
558 {
559 if (*nPos >= menu->nItems) return NULL;
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000560 return &menu->items[*nPos];
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000561 }
562 else
563 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000564 MENUITEM *item = menu->items;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000565 for (i = 0; i < menu->nItems; i++, item++)
566 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000567 if (item->wID == *nPos)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000568 {
569 *nPos = i;
570 return item;
571 }
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000572 else if (item->fType & MF_POPUP)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000573 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000574 HMENU hsubmenu = item->hSubMenu;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000575 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
576 if (subitem)
577 {
578 *hmenu = hsubmenu;
579 return subitem;
580 }
581 }
582 }
583 }
584 return NULL;
585}
586
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000587/***********************************************************************
Rein Klazes80c924f1999-12-12 19:40:46 +0000588 * MENU_FindSubMenu
589 *
Vincent Béron9a624912002-05-31 23:06:46 +0000590 * Find a Sub menu. Return the position of the submenu, and modifies
Rein Klazes80c924f1999-12-12 19:40:46 +0000591 * *hmenu in case it is found in another sub-menu.
592 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
593 */
594UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget )
595{
596 POPUPMENU *menu;
597 UINT i;
598 MENUITEM *item;
Alexandre Julliard7ef66af2002-11-22 04:47:10 +0000599 if (((*hmenu)==(HMENU)0xffff) ||
Vincent Béron9a624912002-05-31 23:06:46 +0000600 (!(menu = MENU_GetMenu(*hmenu))))
Rein Klazes80c924f1999-12-12 19:40:46 +0000601 return NO_SELECTED_ITEM;
602 item = menu->items;
603 for (i = 0; i < menu->nItems; i++, item++) {
604 if(!(item->fType & MF_POPUP)) continue;
605 if (item->hSubMenu == hSubTarget) {
606 return i;
607 }
608 else {
609 HMENU hsubmenu = item->hSubMenu;
610 UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
611 if (pos != NO_SELECTED_ITEM) {
612 *hmenu = hsubmenu;
613 return pos;
614 }
615 }
616 }
617 return NO_SELECTED_ITEM;
618}
619
620/***********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000621 * MENU_FreeItemData
622 */
623static void MENU_FreeItemData( MENUITEM* item )
624{
625 /* delete text */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000626 if (IS_STRING_ITEM(item->fType) && item->text)
Alexandre Julliardda2892c2001-02-23 01:13:42 +0000627 HeapFree( GetProcessHeap(), 0, item->text );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000628}
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000629
630/***********************************************************************
631 * MENU_FindItemByCoords
632 *
Vincent Béron9a624912002-05-31 23:06:46 +0000633 * Find the item at the specified coordinates (screen coords). Does
634 * not work for child windows and therefore should not be called for
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000635 * an arbitrary system menu.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000636 */
Vincent Béron9a624912002-05-31 23:06:46 +0000637static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000638 POINT pt, UINT *pos )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000639{
640 MENUITEM *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000641 UINT i;
Marcus Meissnerac593bb1999-03-17 15:18:28 +0000642 RECT wrect;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000643
Marcus Meissnerac593bb1999-03-17 15:18:28 +0000644 if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
645 pt.x -= wrect.left;pt.y -= wrect.top;
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000646 item = menu->items;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000647 for (i = 0; i < menu->nItems; i++, item++)
648 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000649 if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
650 (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000651 {
652 if (pos) *pos = i;
653 return item;
654 }
655 }
656 return NULL;
657}
658
659
660/***********************************************************************
661 * MENU_FindItemByKey
662 *
663 * Find the menu item selected by a key press.
664 * Return item id, -1 if none, -2 if we should close the menu.
665 */
Vincent Béron9a624912002-05-31 23:06:46 +0000666static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000667 UINT key, BOOL forceMenuChar )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000668{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000669 TRACE("\tlooking for '%c' in [%p]\n", (char)key, hmenu );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000670
Alexandre Julliardde424282001-08-10 22:51:42 +0000671 if (!IsMenu( hmenu )) hmenu = GetSubMenu( get_win_sys_menu(hwndOwner), 0);
Alexandre Julliardc981d0b1996-03-31 16:40:13 +0000672
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000673 if (hmenu)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000674 {
Gerard Patel3e629742000-01-17 22:22:16 +0000675 POPUPMENU *menu = MENU_GetMenu( hmenu );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000676 MENUITEM *item = menu->items;
677 LONG menuchar;
678
679 if( !forceMenuChar )
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000680 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000681 UINT i;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000682
683 key = toupper(key);
684 for (i = 0; i < menu->nItems; i++, item++)
685 {
Andreas Mohr8578f012002-08-28 23:31:56 +0000686 if (IS_STRING_ITEM(item->fType) && item->text)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000687 {
Aric Stewartc946b1c2000-10-24 21:28:19 +0000688 WCHAR *p = item->text - 2;
Norman Stevensa83d0651998-10-12 07:25:35 +0000689 do
690 {
Aric Stewartc946b1c2000-10-24 21:28:19 +0000691 p = strchrW (p + 2, '&');
Norman Stevensa83d0651998-10-12 07:25:35 +0000692 }
693 while (p != NULL && p [1] == '&');
694 if (p && (toupper(p[1]) == key)) return i;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000695 }
696 }
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000697 }
Vincent Béron9a624912002-05-31 23:06:46 +0000698 menuchar = SendMessageA( hwndOwner, WM_MENUCHAR,
Alexandre Julliard7ef66af2002-11-22 04:47:10 +0000699 MAKEWPARAM( key, menu->wFlags ), (LPARAM)hmenu );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000700 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000701 if (HIWORD(menuchar) == 1) return (UINT)(-2);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000702 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000703 return (UINT)(-1);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000704}
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000705
706
Francois Boisvert8b391741999-02-09 14:09:55 +0000707/***********************************************************************
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000708 * MENU_GetBitmapItemSize
Francois Boisvert8b391741999-02-09 14:09:55 +0000709 *
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000710 * Get the size of a bitmap item.
Francois Boisvert8b391741999-02-09 14:09:55 +0000711 */
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000712static void MENU_GetBitmapItemSize( UINT id, DWORD data, SIZE *size )
Francois Boisvert8b391741999-02-09 14:09:55 +0000713{
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000714 BITMAP bm;
715 HBITMAP bmp = (HBITMAP)id;
Francois Boisvert8b391741999-02-09 14:09:55 +0000716
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000717 size->cx = size->cy = 0;
718
719 /* check if there is a magic menu item associated with this item */
720 if (id && IS_MAGIC_ITEM( id ))
721 {
722 switch(LOWORD(id))
723 {
Alexandre Julliard101c4302002-11-22 22:25:59 +0000724 case (INT_PTR)HBMMENU_SYSTEM:
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000725 if (data)
726 {
727 bmp = (HBITMAP)data;
728 break;
729 }
730 /* fall through */
Alexandre Julliard101c4302002-11-22 22:25:59 +0000731 case (INT_PTR)HBMMENU_MBAR_RESTORE:
732 case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
733 case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
734 case (INT_PTR)HBMMENU_MBAR_CLOSE:
735 case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000736 size->cx = GetSystemMetrics( SM_CXSIZE );
737 size->cy = GetSystemMetrics( SM_CYSIZE );
738 return;
Alexandre Julliard101c4302002-11-22 22:25:59 +0000739 case (INT_PTR)HBMMENU_CALLBACK:
740 case (INT_PTR)HBMMENU_POPUP_CLOSE:
741 case (INT_PTR)HBMMENU_POPUP_RESTORE:
742 case (INT_PTR)HBMMENU_POPUP_MAXIMIZE:
743 case (INT_PTR)HBMMENU_POPUP_MINIMIZE:
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000744 default:
745 FIXME("Magic 0x%08x not implemented\n", id);
746 return;
747 }
748 }
749 if (GetObjectA(bmp, sizeof(bm), &bm ))
750 {
751 size->cx = bm.bmWidth;
752 size->cy = bm.bmHeight;
753 }
754}
755
756/***********************************************************************
757 * MENU_DrawBitmapItem
758 *
759 * Draw a bitmap item.
760 */
761static void MENU_DrawBitmapItem( HDC hdc, MENUITEM *lpitem, const RECT *rect, BOOL menuBar )
762{
763 BITMAP bm;
764 DWORD rop;
765 HDC hdcMem;
766 HBITMAP bmp = (HBITMAP)lpitem->text;
767 int w = rect->right - rect->left;
768 int h = rect->bottom - rect->top;
769 int bmp_xoffset = 0;
770 int left, top;
771
772 /* Check if there is a magic menu item associated with this item */
773 if (lpitem->text && IS_MAGIC_ITEM(lpitem->text))
774 {
775 UINT flags = 0;
776 RECT r;
777
778 switch(LOWORD(lpitem->text))
779 {
Alexandre Julliard101c4302002-11-22 22:25:59 +0000780 case (INT_PTR)HBMMENU_SYSTEM:
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000781 if (lpitem->dwItemData)
782 {
783 bmp = (HBITMAP)lpitem->dwItemData;
784 if (!GetObjectA( bmp, sizeof(bm), &bm )) return;
785 }
786 else
787 {
788 bmp = hBmpSysMenu;
789 if (!GetObjectA( bmp, sizeof(bm), &bm )) return;
790 /* only use right half of the bitmap */
791 bmp_xoffset = bm.bmWidth / 2;
792 bm.bmWidth -= bmp_xoffset;
793 }
794 goto got_bitmap;
Alexandre Julliard101c4302002-11-22 22:25:59 +0000795 case (INT_PTR)HBMMENU_MBAR_RESTORE:
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000796 flags = DFCS_CAPTIONRESTORE;
797 break;
Alexandre Julliard101c4302002-11-22 22:25:59 +0000798 case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000799 flags = DFCS_CAPTIONMIN;
800 break;
Alexandre Julliard101c4302002-11-22 22:25:59 +0000801 case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000802 flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
803 break;
Alexandre Julliard101c4302002-11-22 22:25:59 +0000804 case (INT_PTR)HBMMENU_MBAR_CLOSE:
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000805 flags = DFCS_CAPTIONCLOSE;
806 break;
Alexandre Julliard101c4302002-11-22 22:25:59 +0000807 case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000808 flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
809 break;
Alexandre Julliard101c4302002-11-22 22:25:59 +0000810 case (INT_PTR)HBMMENU_CALLBACK:
811 case (INT_PTR)HBMMENU_POPUP_CLOSE:
812 case (INT_PTR)HBMMENU_POPUP_RESTORE:
813 case (INT_PTR)HBMMENU_POPUP_MAXIMIZE:
814 case (INT_PTR)HBMMENU_POPUP_MINIMIZE:
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000815 default:
816 FIXME("Magic 0x%08x not implemented\n", LOWORD(lpitem->text));
817 return;
818 }
819 r = *rect;
820 InflateRect( &r, -1, -1 );
821 if (lpitem->fState & MF_HILITE) flags |= DFCS_PUSHED;
822 DrawFrameControl( hdc, &r, DFC_CAPTION, flags );
823 return;
Francois Boisvert8b391741999-02-09 14:09:55 +0000824 }
825
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000826 if (!bmp || !GetObjectA( bmp, sizeof(bm), &bm )) return;
827
828 got_bitmap:
829 hdcMem = CreateCompatibleDC( hdc );
830 SelectObject( hdcMem, bmp );
831
832 /* handle fontsize > bitmap_height */
833 top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
834 left=rect->left;
835 if (TWEAK_WineLook == WIN95_LOOK) {
836 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_ITEM(lpitem->text)) ? NOTSRCCOPY : SRCCOPY;
837 if ((lpitem->fState & MF_HILITE) && IS_BITMAP_ITEM(lpitem->fType))
838 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
839 } else {
840 left++;
841 w-=2;
842 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_ITEM(lpitem->text) && (!menuBar)) ? MERGEPAINT : SRCCOPY;
843 }
844 BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop );
845 DeleteDC( hdcMem );
Francois Boisvert8b391741999-02-09 14:09:55 +0000846}
Alexandre Julliardf7207251994-07-23 07:57:48 +0000847
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000848
Alexandre Julliardf7207251994-07-23 07:57:48 +0000849/***********************************************************************
850 * MENU_CalcItemSize
851 *
852 * Calculate the size of the menu item and store it in lpitem->rect.
853 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000854static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
855 INT orgX, INT orgY, BOOL menuBar )
Alexandre Julliardf7207251994-07-23 07:57:48 +0000856{
Aric Stewartc946b1c2000-10-24 21:28:19 +0000857 WCHAR *p;
Alexandre Julliardc1d35cc2001-01-24 19:47:57 +0000858 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000859
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000860 TRACE("dc=%p owner=%p (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
Vincent Béron9a624912002-05-31 23:06:46 +0000861 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem,
Alexandre Julliard03468f71998-02-15 19:40:49 +0000862 (menuBar ? " (MenuBar)" : ""));
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000863
Alexandre Julliarda3960291999-02-26 11:11:13 +0000864 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000865
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000866 if (lpitem->fType & MF_OWNERDRAW)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000867 {
Ken Thomases130f0d82000-05-10 21:38:37 +0000868 /*
869 ** Experimentation under Windows reveals that an owner-drawn
870 ** menu is expected to return the size of the content part of
871 ** the menu item, not including the checkmark nor the submenu
872 ** arrow. Windows adds those values itself and returns the
873 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
874 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000875 MEASUREITEMSTRUCT mis;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000876 mis.CtlType = ODT_MENU;
Juergen Schmied7abca951999-04-11 17:02:30 +0000877 mis.CtlID = 0;
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000878 mis.itemID = lpitem->wID;
Juergen Schmied7abca951999-04-11 17:02:30 +0000879 mis.itemData = (DWORD)lpitem->dwItemData;
880 mis.itemHeight = 0;
881 mis.itemWidth = 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000882 SendMessageA( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000883 lpitem->rect.right += mis.itemWidth;
Aric Stewart70cc1692000-05-10 21:54:07 +0000884
885 if (menuBar)
886 {
887 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
Vincent Béron9a624912002-05-31 23:06:46 +0000888
Aric Stewart70cc1692000-05-10 21:54:07 +0000889
890 /* under at least win95 you seem to be given a standard
891 height for the menu and the height value is ignored */
892
893 if (TWEAK_WineLook == WIN31_LOOK)
894 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU);
895 else
896 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU)-1;
897 }
898 else
899 lpitem->rect.bottom += mis.itemHeight;
Vincent Béron9a624912002-05-31 23:06:46 +0000900
Aric Stewart70cc1692000-05-10 21:54:07 +0000901 TRACE("id=%04x size=%dx%d\n",
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000902 lpitem->wID, mis.itemWidth, mis.itemHeight);
Ken Thomases130f0d82000-05-10 21:38:37 +0000903 /* Fall through to get check/arrow width calculation. */
Vincent Béron9a624912002-05-31 23:06:46 +0000904 }
Alexandre Julliardf7207251994-07-23 07:57:48 +0000905
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000906 if (lpitem->fType & MF_SEPARATOR)
Alexandre Julliardf7207251994-07-23 07:57:48 +0000907 {
908 lpitem->rect.bottom += SEPARATOR_HEIGHT;
909 return;
910 }
911
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000912 if (!menuBar)
913 {
914 lpitem->rect.right += 2 * check_bitmap_width;
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000915 if (lpitem->fType & MF_POPUP)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000916 lpitem->rect.right += arrow_bitmap_width;
917 }
Alexandre Julliardf7207251994-07-23 07:57:48 +0000918
Ken Thomases130f0d82000-05-10 21:38:37 +0000919 if (lpitem->fType & MF_OWNERDRAW)
920 return;
921
Juergen Schmied78513941999-04-18 14:40:32 +0000922 if (IS_BITMAP_ITEM(lpitem->fType))
Alexandre Julliardf7207251994-07-23 07:57:48 +0000923 {
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000924 SIZE size;
Francois Boisvert8b391741999-02-09 14:09:55 +0000925
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000926 MENU_GetBitmapItemSize( (int)lpitem->text, lpitem->dwItemData, &size );
927 lpitem->rect.right += size.cx;
928 lpitem->rect.bottom += size.cy;
929 if (TWEAK_WineLook == WIN98_LOOK)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000930 {
Alexandre Julliardcc2d3822002-01-03 02:35:23 +0000931 /* Leave space for the sunken border */
932 lpitem->rect.right += 2;
933 lpitem->rect.bottom += 2;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000934 }
Alexandre Julliardf7207251994-07-23 07:57:48 +0000935 }
Vincent Béron9a624912002-05-31 23:06:46 +0000936
Juergen Schmied78513941999-04-18 14:40:32 +0000937
Gerard Patel2482ef32001-03-19 19:16:21 +0000938 /* it must be a text item - unless it's the system menu */
939 if (!(lpitem->fType & MF_SYSMENU) && IS_STRING_ITEM( lpitem->fType ))
Juergen Schmied78513941999-04-18 14:40:32 +0000940 { SIZE size;
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000941
Aric Stewartc946b1c2000-10-24 21:28:19 +0000942 GetTextExtentPoint32W(hdc, lpitem->text, strlenW(lpitem->text), &size);
Vincent Béron9a624912002-05-31 23:06:46 +0000943
Juergen Schmied78513941999-04-18 14:40:32 +0000944 lpitem->rect.right += size.cx;
945 if (TWEAK_WineLook == WIN31_LOOK)
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000946 lpitem->rect.bottom += max( size.cy, GetSystemMetrics(SM_CYMENU) );
Juergen Schmied78513941999-04-18 14:40:32 +0000947 else
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000948 lpitem->rect.bottom += max(size.cy, GetSystemMetrics(SM_CYMENU)-1);
Juergen Schmied78513941999-04-18 14:40:32 +0000949 lpitem->xTab = 0;
950
951 if (menuBar)
952 {
953 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
954 }
Aric Stewartc946b1c2000-10-24 21:28:19 +0000955 else if ((p = strchrW( lpitem->text, '\t' )) != NULL)
Juergen Schmied78513941999-04-18 14:40:32 +0000956 {
957 /* Item contains a tab (only meaningful in popup menus) */
Aric Stewartc946b1c2000-10-24 21:28:19 +0000958 GetTextExtentPoint32W(hdc, lpitem->text, (int)(p - lpitem->text) , &size);
Juergen Schmied78513941999-04-18 14:40:32 +0000959 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE + size.cx;
960 lpitem->rect.right += MENU_TAB_SPACE;
961 }
962 else
963 {
Aric Stewartc946b1c2000-10-24 21:28:19 +0000964 if (strchrW( lpitem->text, '\b' ))
Juergen Schmied78513941999-04-18 14:40:32 +0000965 lpitem->rect.right += MENU_TAB_SPACE;
Vincent Béron9a624912002-05-31 23:06:46 +0000966 lpitem->xTab = lpitem->rect.right - check_bitmap_width
Juergen Schmied78513941999-04-18 14:40:32 +0000967 - arrow_bitmap_width;
968 }
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000969 }
Dan Kegel0fd521f2003-01-08 21:09:25 +0000970 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->rect.left, lpitem->rect.top, lpitem->rect.right, lpitem->rect.bottom);
Alexandre Julliardf7207251994-07-23 07:57:48 +0000971}
972
973
974/***********************************************************************
975 * MENU_PopupMenuCalcSize
976 *
977 * Calculate the size of a popup menu.
978 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000979static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
Alexandre Julliardf7207251994-07-23 07:57:48 +0000980{
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000981 MENUITEM *lpitem;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000982 HDC hdc;
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000983 int start, i;
984 int orgX, orgY, maxX, maxTab, maxTabWidth;
Alexandre Julliardf7207251994-07-23 07:57:48 +0000985
Alexandre Julliardf7207251994-07-23 07:57:48 +0000986 lppop->Width = lppop->Height = 0;
987 if (lppop->nItems == 0) return;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000988 hdc = GetDC( 0 );
Juergen Schmied78513941999-04-18 14:40:32 +0000989
990 SelectObject( hdc, hMenuFont);
Vincent Béron9a624912002-05-31 23:06:46 +0000991
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000992 start = 0;
Francois Gouget75f9e642000-11-06 05:25:29 +0000993 maxX = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CXBORDER) : 2+1 ;
Juergen Schmied466a6521999-05-02 11:21:08 +0000994
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +0000995 while (start < lppop->nItems)
Alexandre Julliardf7207251994-07-23 07:57:48 +0000996 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000997 lpitem = &lppop->items[start];
Alexandre Julliardf7207251994-07-23 07:57:48 +0000998 orgX = maxX;
Marcus Meissnerddca3151999-05-22 11:33:23 +0000999 orgY = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CYBORDER) : 2;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001000
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001001 maxTab = maxTabWidth = 0;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001002
1003 /* Parse items until column break or end of menu */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001004 for (i = start; i < lppop->nItems; i++, lpitem++)
Alexandre Julliardf7207251994-07-23 07:57:48 +00001005 {
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001006 if ((i != start) &&
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001007 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001008
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001009 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
Pascal Lessard47274231999-02-13 12:21:46 +00001010
Juergen Schmied466a6521999-05-02 11:21:08 +00001011 if (lpitem->fType & MF_MENUBARBREAK) orgX++;
Francois Gouget6d77d3a2000-03-25 21:44:35 +00001012 maxX = max( maxX, lpitem->rect.right );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001013 orgY = lpitem->rect.bottom;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001014 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001015 {
Francois Gouget6d77d3a2000-03-25 21:44:35 +00001016 maxTab = max( maxTab, lpitem->xTab );
1017 maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001018 }
Alexandre Julliardf7207251994-07-23 07:57:48 +00001019 }
1020
1021 /* Finish the column (set all items to the largest width found) */
Francois Gouget6d77d3a2000-03-25 21:44:35 +00001022 maxX = max( maxX, maxTab + maxTabWidth );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001023 for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001024 {
1025 lpitem->rect.right = maxX;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001026 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
Juergen Schmied466a6521999-05-02 11:21:08 +00001027 lpitem->xTab = maxTab;
Vincent Béron9a624912002-05-31 23:06:46 +00001028
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001029 }
Francois Gouget6d77d3a2000-03-25 21:44:35 +00001030 lppop->Height = max( lppop->Height, orgY );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001031 }
1032
1033 lppop->Width = maxX;
Juergen Schmied466a6521999-05-02 11:21:08 +00001034
1035 /* space for 3d border */
1036 if(TWEAK_WineLook > WIN31_LOOK)
1037 {
1038 lppop->Height += 2;
1039 lppop->Width += 2;
1040 }
1041
Alexandre Julliarda3960291999-02-26 11:11:13 +00001042 ReleaseDC( 0, hdc );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001043}
1044
1045
1046/***********************************************************************
1047 * MENU_MenuBarCalcSize
1048 *
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001049 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001050 * height is off by 1 pixel which causes lengthy window relocations when
1051 * active document window is maximized/restored.
1052 *
Alexandre Julliardf7207251994-07-23 07:57:48 +00001053 * Calculate the size of the menu bar.
1054 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001055static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
1056 LPPOPUPMENU lppop, HWND hwndOwner )
Alexandre Julliardf7207251994-07-23 07:57:48 +00001057{
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001058 MENUITEM *lpitem;
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001059 int start, i, orgX, orgY, maxY, helpPos;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001060
1061 if ((lprect == NULL) || (lppop == NULL)) return;
1062 if (lppop->nItems == 0) return;
Dan Kegel0fd521f2003-01-08 21:09:25 +00001063 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n",
1064 lprect->left, lprect->top, lprect->right, lprect->bottom);
Alexandre Julliardf7207251994-07-23 07:57:48 +00001065 lppop->Width = lprect->right - lprect->left;
1066 lppop->Height = 0;
Francois Gouget75f9e642000-11-06 05:25:29 +00001067 maxY = lprect->top+1;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001068 start = 0;
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001069 helpPos = -1;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001070 while (start < lppop->nItems)
Alexandre Julliardf7207251994-07-23 07:57:48 +00001071 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001072 lpitem = &lppop->items[start];
Alexandre Julliardf7207251994-07-23 07:57:48 +00001073 orgX = lprect->left;
1074 orgY = maxY;
1075
1076 /* Parse items until line break or end of menu */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001077 for (i = start; i < lppop->nItems; i++, lpitem++)
Alexandre Julliardf7207251994-07-23 07:57:48 +00001078 {
Francois Gouget58182402001-01-04 20:56:43 +00001079 if ((helpPos == -1) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001080 if ((i != start) &&
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001081 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001082
Vincent Béron9a624912002-05-31 23:06:46 +00001083 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001084 orgX, orgY );
Alexandre Julliard03468f71998-02-15 19:40:49 +00001085 debug_print_menuitem (" item: ", lpitem, "");
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001086 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
Pascal Lessard47274231999-02-13 12:21:46 +00001087
Alexandre Julliardf7207251994-07-23 07:57:48 +00001088 if (lpitem->rect.right > lprect->right)
1089 {
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001090 if (i != start) break;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001091 else lpitem->rect.right = lprect->right;
1092 }
Francois Gouget6d77d3a2000-03-25 21:44:35 +00001093 maxY = max( maxY, lpitem->rect.bottom );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001094 orgX = lpitem->rect.right;
1095 }
1096
1097 /* Finish the line (set all items to the largest height found) */
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001098 while (start < i) lppop->items[start++].rect.bottom = maxY;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001099 }
1100
1101 lprect->bottom = maxY;
1102 lppop->Height = lprect->bottom - lprect->top;
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001103
Francois Gouget58182402001-01-04 20:56:43 +00001104 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1105 /* the last item (if several lines, only move the last line) */
1106 lpitem = &lppop->items[lppop->nItems-1];
1107 orgY = lpitem->rect.top;
1108 orgX = lprect->right;
1109 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--) {
1110 if ( (helpPos==-1) || (helpPos>i) )
1111 break; /* done */
1112 if (lpitem->rect.top != orgY) break; /* Other line */
1113 if (lpitem->rect.right >= orgX) break; /* Too far right already */
1114 lpitem->rect.left += orgX - lpitem->rect.right;
1115 lpitem->rect.right = orgX;
1116 orgX = lpitem->rect.left;
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001117 }
Alexandre Julliardf7207251994-07-23 07:57:48 +00001118}
1119
Alexandre Julliardf7207251994-07-23 07:57:48 +00001120/***********************************************************************
1121 * MENU_DrawMenuItem
1122 *
1123 * Draw a single menu item.
1124 */
Juergen Schmied78513941999-04-18 14:40:32 +00001125static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001126 UINT height, BOOL menuBar, UINT odaction )
Alexandre Julliardf7207251994-07-23 07:57:48 +00001127{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001128 RECT rect;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001129
Alexandre Julliard03468f71998-02-15 19:40:49 +00001130 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001131
1132 if (lpitem->fType & MF_SYSMENU)
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001133 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001134 if( !IsIconic(hwnd) ) {
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001135 if (TWEAK_WineLook > WIN31_LOOK)
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001136 NC_DrawSysButton95( hwnd, hdc,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001137 lpitem->fState &
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001138 (MF_HILITE | MF_MOUSESELECT) );
1139 else
Vincent Béron9a624912002-05-31 23:06:46 +00001140 NC_DrawSysButton( hwnd, hdc,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001141 lpitem->fState &
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001142 (MF_HILITE | MF_MOUSESELECT) );
1143 }
1144
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001145 return;
1146 }
1147
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001148 if (lpitem->fType & MF_OWNERDRAW)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001149 {
Ken Thomases130f0d82000-05-10 21:38:37 +00001150 /*
1151 ** Experimentation under Windows reveals that an owner-drawn
1152 ** menu is given the rectangle which includes the space it requested
1153 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1154 ** and a popup-menu arrow. This is the value of lpitem->rect.
1155 ** Windows will leave all drawing to the application except for
1156 ** the popup-menu arrow. Windows always draws that itself, after
1157 ** the menu owner has finished drawing.
1158 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001159 DRAWITEMSTRUCT dis;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001160
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001161 dis.CtlType = ODT_MENU;
Juergen Schmied7abca951999-04-11 17:02:30 +00001162 dis.CtlID = 0;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001163 dis.itemID = lpitem->wID;
Juergen Schmied7abca951999-04-11 17:02:30 +00001164 dis.itemData = (DWORD)lpitem->dwItemData;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001165 dis.itemState = 0;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001166 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
Alberto Massari3d60c632002-12-17 04:16:31 +00001167 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED|ODS_DISABLED;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001168 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001169 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
Alexandre Julliardd23a82b2001-09-19 20:37:04 +00001170 dis.hwndItem = (HWND)hmenu;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001171 dis.hDC = hdc;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001172 dis.rcItem = lpitem->rect;
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00001173 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
Dan Kegel0fd521f2003-01-08 21:09:25 +00001174 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hwndOwner,
Vincent Béron9a624912002-05-31 23:06:46 +00001175 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
Juergen Schmied78513941999-04-18 14:40:32 +00001176 dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
1177 dis.rcItem.bottom);
1178 SendMessageA( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
Ken Thomases130f0d82000-05-10 21:38:37 +00001179 /* Fall through to draw popup-menu arrow */
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001180 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001181
Dan Kegel0fd521f2003-01-08 21:09:25 +00001182 TRACE("rect={%ld,%ld,%ld,%ld}\n", lpitem->rect.left, lpitem->rect.top,
Juergen Schmied78513941999-04-18 14:40:32 +00001183 lpitem->rect.right,lpitem->rect.bottom);
1184
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001185 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
Juergen Schmied78513941999-04-18 14:40:32 +00001186
Alexandre Julliardf7207251994-07-23 07:57:48 +00001187 rect = lpitem->rect;
1188
Ken Thomases130f0d82000-05-10 21:38:37 +00001189 if (!(lpitem->fType & MF_OWNERDRAW))
1190 {
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001191 if (lpitem->fState & MF_HILITE)
1192 {
1193 if(TWEAK_WineLook == WIN98_LOOK)
1194 {
1195 if(menuBar)
1196 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1197 else
1198 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1199 }
1200 else /* Not Win98 Look */
1201 {
1202 if(!IS_BITMAP_ITEM(lpitem->fType))
1203 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1204 }
1205 }
Ken Thomases130f0d82000-05-10 21:38:37 +00001206 else
1207 FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) );
1208 }
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001209
Alexandre Julliarda3960291999-02-26 11:11:13 +00001210 SetBkMode( hdc, TRANSPARENT );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001211
Ken Thomases130f0d82000-05-10 21:38:37 +00001212 if (!(lpitem->fType & MF_OWNERDRAW))
Alexandre Julliardf7207251994-07-23 07:57:48 +00001213 {
Ken Thomases130f0d82000-05-10 21:38:37 +00001214 /* vertical separator */
1215 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1216 {
Vincent Béron9a624912002-05-31 23:06:46 +00001217 if (TWEAK_WineLook > WIN31_LOOK)
Ken Thomases130f0d82000-05-10 21:38:37 +00001218 {
1219 RECT rc = rect;
1220 rc.top = 3;
1221 rc.bottom = height - 3;
1222 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1223 }
Vincent Béron9a624912002-05-31 23:06:46 +00001224 else
Ken Thomases130f0d82000-05-10 21:38:37 +00001225 {
Alexandre Julliard4344c362002-05-20 18:15:28 +00001226 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
Alexandre Julliardb0efe282000-08-04 04:18:04 +00001227 MoveToEx( hdc, rect.left, 0, NULL );
Ken Thomases130f0d82000-05-10 21:38:37 +00001228 LineTo( hdc, rect.left, height );
1229 }
1230 }
Juergen Schmied78513941999-04-18 14:40:32 +00001231
Ken Thomases130f0d82000-05-10 21:38:37 +00001232 /* horizontal separator */
1233 if (lpitem->fType & MF_SEPARATOR)
1234 {
Vincent Béron9a624912002-05-31 23:06:46 +00001235 if (TWEAK_WineLook > WIN31_LOOK)
Ken Thomases130f0d82000-05-10 21:38:37 +00001236 {
1237 RECT rc = rect;
1238 rc.left++;
1239 rc.right--;
1240 rc.top += SEPARATOR_HEIGHT / 2;
1241 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1242 }
Vincent Béron9a624912002-05-31 23:06:46 +00001243 else
Ken Thomases130f0d82000-05-10 21:38:37 +00001244 {
Alexandre Julliard4344c362002-05-20 18:15:28 +00001245 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
Alexandre Julliardb0efe282000-08-04 04:18:04 +00001246 MoveToEx( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2, NULL );
Ken Thomases130f0d82000-05-10 21:38:37 +00001247 LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
1248 }
1249 return;
1250 }
Alexandre Julliardf7207251994-07-23 07:57:48 +00001251 }
1252
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001253 /* Setup colors */
1254
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001255 if (lpitem->fState & MF_HILITE)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001256 {
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001257 if(TWEAK_WineLook == WIN98_LOOK)
1258 {
François Gouget75b278e2001-01-06 01:45:51 +00001259 if(menuBar) {
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001260 SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
François Gouget75b278e2001-01-06 01:45:51 +00001261 SetBkColor(hdc, GetSysColor(COLOR_MENU));
1262 } else {
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001263 if(lpitem->fState & MF_GRAYED)
1264 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
1265 else
1266 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
François Gouget75b278e2001-01-06 01:45:51 +00001267 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001268 }
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001269 }
1270 else /* Not Win98 Look */
1271 {
1272 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1273 if(!IS_BITMAP_ITEM(lpitem->fType))
1274 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
Dmitry Timoshkovd0ff2ec2000-11-01 02:11:41 +00001275 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001276 }
1277 else
1278 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001279 if (lpitem->fState & MF_GRAYED)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001280 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001281 else
Alexandre Julliarda3960291999-02-26 11:11:13 +00001282 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1283 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001284 }
1285
Juergen Schmied78513941999-04-18 14:40:32 +00001286 /* helper lines for debugging */
1287/* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
Alexandre Julliard4344c362002-05-20 18:15:28 +00001288 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
Alexandre Julliardb0efe282000-08-04 04:18:04 +00001289 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
Juergen Schmied78513941999-04-18 14:40:32 +00001290 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1291*/
1292
Alexandre Julliardf7207251994-07-23 07:57:48 +00001293 if (!menuBar)
1294 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001295 INT y = rect.top + rect.bottom;
Alexandre Julliardc1d35cc2001-01-24 19:47:57 +00001296 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
1297 UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001298
Ken Thomases130f0d82000-05-10 21:38:37 +00001299 if (!(lpitem->fType & MF_OWNERDRAW))
1300 {
1301 /* Draw the check mark
1302 *
1303 * FIXME:
Vincent Béron9a624912002-05-31 23:06:46 +00001304 * Custom checkmark bitmaps are monochrome but not always 1bpp.
Ken Thomases130f0d82000-05-10 21:38:37 +00001305 */
Alexandre Julliardc1d35cc2001-01-24 19:47:57 +00001306 HBITMAP bm = (lpitem->fState & MF_CHECKED) ? lpitem->hCheckBit : lpitem->hUnCheckBit;
1307 if (bm) /* we have a custom bitmap */
1308 {
1309 HDC hdcMem = CreateCompatibleDC( hdc );
1310 SelectObject( hdcMem, bm );
1311 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1312 check_bitmap_width, check_bitmap_height,
1313 hdcMem, 0, 0, SRCCOPY );
1314 DeleteDC( hdcMem );
1315 }
1316 else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
1317 {
1318 RECT r;
1319 HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
1320 HDC hdcMem = CreateCompatibleDC( hdc );
1321 SelectObject( hdcMem, bm );
1322 SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height );
1323 DrawFrameControl( hdcMem, &r, DFC_MENU,
1324 (lpitem->fType & MFT_RADIOCHECK) ?
1325 DFCS_MENUBULLET : DFCS_MENUCHECK );
1326 BitBlt( hdc, rect.left, (y - r.bottom) / 2, r.right, r.bottom,
1327 hdcMem, 0, 0, SRCCOPY );
1328 DeleteDC( hdcMem );
1329 DeleteObject( bm );
1330 }
Ken Thomases130f0d82000-05-10 21:38:37 +00001331 }
Vincent Béron9a624912002-05-31 23:06:46 +00001332
Alexandre Julliardf7207251994-07-23 07:57:48 +00001333 /* Draw the popup-menu arrow */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001334 if (lpitem->fType & MF_POPUP)
Alexandre Julliardf7207251994-07-23 07:57:48 +00001335 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001336 HDC hdcMem = CreateCompatibleDC( hdc );
Ken Thomases130f0d82000-05-10 21:38:37 +00001337 HBITMAP hOrigBitmap;
Huw D M Davies2d617be1998-12-08 09:14:09 +00001338
Ken Thomases130f0d82000-05-10 21:38:37 +00001339 hOrigBitmap = SelectObject( hdcMem, hStdMnArrow );
Juergen Schmied78513941999-04-18 14:40:32 +00001340 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
Huw D M Davies2d617be1998-12-08 09:14:09 +00001341 (y - arrow_bitmap_height) / 2,
1342 arrow_bitmap_width, arrow_bitmap_height,
1343 hdcMem, 0, 0, SRCCOPY );
Ken Thomases130f0d82000-05-10 21:38:37 +00001344 SelectObject( hdcMem, hOrigBitmap );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001345 DeleteDC( hdcMem );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001346 }
1347
1348 rect.left += check_bitmap_width;
1349 rect.right -= arrow_bitmap_width;
1350 }
1351
Ken Thomases130f0d82000-05-10 21:38:37 +00001352 /* Done for owner-drawn */
1353 if (lpitem->fType & MF_OWNERDRAW)
1354 return;
1355
Juergen Schmied78513941999-04-18 14:40:32 +00001356 /* Draw the item text or bitmap */
1357 if (IS_BITMAP_ITEM(lpitem->fType))
François Gouget75b278e2001-01-06 01:45:51 +00001358 {
Alexandre Julliardcc2d3822002-01-03 02:35:23 +00001359 MENU_DrawBitmapItem( hdc, lpitem, &rect, menuBar );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001360 return;
Francois Boisvert8b391741999-02-09 14:09:55 +00001361
Alexandre Julliardf7207251994-07-23 07:57:48 +00001362 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001363 /* No bitmap - process text if present */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001364 else if (IS_STRING_ITEM(lpitem->fType))
Alexandre Julliardf7207251994-07-23 07:57:48 +00001365 {
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001366 register int i;
Juergen Schmied466a6521999-05-02 11:21:08 +00001367 HFONT hfontOld = 0;
Vincent Béron9a624912002-05-31 23:06:46 +00001368
Juergen Schmied78513941999-04-18 14:40:32 +00001369 UINT uFormat = (menuBar) ?
1370 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1371 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001372
Juergen Schmied466a6521999-05-02 11:21:08 +00001373 if ( lpitem->fState & MFS_DEFAULT )
1374 {
1375 hfontOld = SelectObject( hdc, hMenuFontBold);
1376 }
1377
Alexandre Julliardf7207251994-07-23 07:57:48 +00001378 if (menuBar)
1379 {
1380 rect.left += MENU_BAR_ITEMS_SPACE / 2;
1381 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001382 }
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001383
Andreas Mohr957f1f92002-06-04 23:08:16 +00001384 for (i = 0; lpitem->text[i]; i++)
1385 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1386 break;
1387
1388 if( (TWEAK_WineLook != WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
Juergen Schmied78513941999-04-18 14:40:32 +00001389 {
Juergen Schmied466a6521999-05-02 11:21:08 +00001390 if (!(lpitem->fState & MF_HILITE) )
Juergen Schmied78513941999-04-18 14:40:32 +00001391 {
Juergen Schmied466a6521999-05-02 11:21:08 +00001392 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001393 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
Aric Stewartc946b1c2000-10-24 21:28:19 +00001394 DrawTextW( hdc, lpitem->text, i, &rect, uFormat );
Juergen Schmied466a6521999-05-02 11:21:08 +00001395 --rect.left; --rect.top; --rect.right; --rect.bottom;
Alexandre Julliard641ee761997-08-04 16:34:36 +00001396 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001397 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001398 }
Vincent Béron9a624912002-05-31 23:06:46 +00001399
Aric Stewartc946b1c2000-10-24 21:28:19 +00001400 DrawTextW( hdc, lpitem->text, i, &rect, uFormat);
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001401
Juergen Schmied466a6521999-05-02 11:21:08 +00001402 /* paint the shortcut text */
Andreas Mohr957f1f92002-06-04 23:08:16 +00001403 if (!menuBar && lpitem->text[i]) /* There's a tab or flush-right char */
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001404 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001405 if (lpitem->text[i] == '\t')
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001406 {
1407 rect.left = lpitem->xTab;
Juergen Schmiedcd0ed1e1999-04-26 14:54:38 +00001408 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001409 }
Vincent Béron9a624912002-05-31 23:06:46 +00001410 else
Juergen Schmiedcd0ed1e1999-04-26 14:54:38 +00001411 {
1412 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1413 }
1414
Andreas Mohr8578f012002-08-28 23:31:56 +00001415 if( (TWEAK_WineLook != WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
Juergen Schmied466a6521999-05-02 11:21:08 +00001416 {
1417 if (!(lpitem->fState & MF_HILITE) )
1418 {
1419 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1420 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
Aric Stewartc946b1c2000-10-24 21:28:19 +00001421 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
Juergen Schmied466a6521999-05-02 11:21:08 +00001422 --rect.left; --rect.top; --rect.right; --rect.bottom;
1423 }
1424 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1425 }
Aric Stewartc946b1c2000-10-24 21:28:19 +00001426 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
Alexandre Julliard940d58c1994-09-16 09:24:37 +00001427 }
Juergen Schmied466a6521999-05-02 11:21:08 +00001428
Vincent Béron9a624912002-05-31 23:06:46 +00001429 if (hfontOld)
Juergen Schmied466a6521999-05-02 11:21:08 +00001430 SelectObject (hdc, hfontOld);
Alexandre Julliardf7207251994-07-23 07:57:48 +00001431 }
1432}
1433
1434
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001435/***********************************************************************
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001436 * MENU_DrawPopupMenu
1437 *
1438 * Paint a popup menu.
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001439 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001440static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001441{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001442 HBRUSH hPrevBrush = 0;
1443 RECT rect;
Alexandre Julliard8d24ae61994-04-05 21:42:43 +00001444
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00001445 TRACE("wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu);
Juergen Schmied78513941999-04-18 14:40:32 +00001446
Alexandre Julliarda3960291999-02-26 11:11:13 +00001447 GetClientRect( hwnd, &rect );
Alexandre Julliard641ee761997-08-04 16:34:36 +00001448
Vincent Béron9a624912002-05-31 23:06:46 +00001449 if(TWEAK_WineLook == WIN31_LOOK)
Alex Korobka44a1b591999-04-01 12:03:52 +00001450 {
Marcus Meissnerddca3151999-05-22 11:33:23 +00001451 rect.bottom -= POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1452 rect.right -= POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER);
Vincent Béron9a624912002-05-31 23:06:46 +00001453 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001454
Vincent Béron9a624912002-05-31 23:06:46 +00001455 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
Juergen Schmied78513941999-04-18 14:40:32 +00001456 && (SelectObject( hdc, hMenuFont)))
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001457 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001458 HPEN hPrevPen;
Vincent Béron9a624912002-05-31 23:06:46 +00001459
Alexandre Julliarda3960291999-02-26 11:11:13 +00001460 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001461
Alexandre Julliarda3960291999-02-26 11:11:13 +00001462 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001463 if( hPrevPen )
1464 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001465 INT ropPrev, i;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001466 POPUPMENU *menu;
1467
1468 /* draw 3-d shade */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001469 if(TWEAK_WineLook == WIN31_LOOK) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001470 SelectObject( hdc, hShadeBrush );
1471 SetBkMode( hdc, TRANSPARENT );
1472 ropPrev = SetROP2( hdc, R2_MASKPEN );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001473
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001474 i = rect.right; /* why SetBrushOrg() doesn't? */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001475 PatBlt( hdc, i & 0xfffffffe,
Marcus Meissnerddca3151999-05-22 11:33:23 +00001476 rect.top + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER),
1477 i%2 + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001478 rect.bottom - rect.top, 0x00a000c9 );
1479 i = rect.bottom;
Marcus Meissnerddca3151999-05-22 11:33:23 +00001480 PatBlt( hdc, rect.left + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001481 i & 0xfffffffe,rect.right - rect.left,
Marcus Meissnerddca3151999-05-22 11:33:23 +00001482 i%2 + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER), 0x00a000c9 );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001483 SelectObject( hdc, hPrevPen );
1484 SelectObject( hdc, hPrevBrush );
1485 SetROP2( hdc, ropPrev );
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001486 }
1487 else
Alexandre Julliarda3960291999-02-26 11:11:13 +00001488 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001489
1490 /* draw menu items */
1491
Gerard Patel3e629742000-01-17 22:22:16 +00001492 menu = MENU_GetMenu( hmenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001493 if (menu && menu->nItems)
1494 {
1495 MENUITEM *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001496 UINT u;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001497
1498 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
Vincent Béron9a624912002-05-31 23:06:46 +00001499 MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item,
Juergen Schmied78513941999-04-18 14:40:32 +00001500 menu->Height, FALSE, ODA_DRAWENTIRE );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001501
1502 }
Vincent Béron9a624912002-05-31 23:06:46 +00001503 } else
Juergen Schmied78513941999-04-18 14:40:32 +00001504 {
1505 SelectObject( hdc, hPrevBrush );
1506 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001507 }
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001508}
1509
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001510/***********************************************************************
1511 * MENU_DrawMenuBar
1512 *
1513 * Paint a menu bar. Returns the height of the menu bar.
Juergen Schmied78513941999-04-18 14:40:32 +00001514 * called from [windows/nonclient.c]
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001515 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001516UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1517 BOOL suppress_draw)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001518{
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001519 LPPOPUPMENU lppop;
Juergen Schmied78513941999-04-18 14:40:32 +00001520 HFONT hfontOld = 0;
Alexandre Julliardde424282001-08-10 22:51:42 +00001521 HMENU hMenu = GetMenu(hwnd);
Juergen Schmied78513941999-04-18 14:40:32 +00001522
Alexandre Julliardde424282001-08-10 22:51:42 +00001523 lppop = MENU_GetMenu( hMenu );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00001524 if (lppop == NULL || lprect == NULL)
1525 {
Robert Shearman9caa6ba2003-01-14 19:28:49 +00001526 return GetSystemMetrics(SM_CYMENU);
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00001527 }
Juergen Schmied78513941999-04-18 14:40:32 +00001528
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00001529 if (suppress_draw)
1530 {
Robert Shearman9caa6ba2003-01-14 19:28:49 +00001531 hfontOld = SelectObject( hDC, hMenuFont);
Juergen Schmied78513941999-04-18 14:40:32 +00001532
Robert Shearman9caa6ba2003-01-14 19:28:49 +00001533 if (lppop->Height == 0)
1534 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001535
Robert Shearman9caa6ba2003-01-14 19:28:49 +00001536 lprect->bottom = lprect->top + lppop->Height;
1537
1538 if (hfontOld) SelectObject( hDC, hfontOld);
1539 return lppop->Height;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001540 }
Vincent Béron9a624912002-05-31 23:06:46 +00001541 else
Robert Shearman9caa6ba2003-01-14 19:28:49 +00001542 return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL);
Alexandre Julliard2ace16a1996-04-28 15:09:19 +00001543}
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001544
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00001545
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001546/***********************************************************************
1547 * MENU_ShowPopup
1548 *
1549 * Display a popup menu.
1550 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001551static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1552 INT x, INT y, INT xanchor, INT yanchor )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001553{
Alexandre Julliardde424282001-08-10 22:51:42 +00001554 POPUPMENU *menu;
1555 UINT width, height;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001556
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00001557 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1558 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
Juergen Schmied78513941999-04-18 14:40:32 +00001559
Gerard Patel3e629742000-01-17 22:22:16 +00001560 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001561 if (menu->FocusedItem != NO_SELECTED_ITEM)
1562 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001563 menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001564 menu->FocusedItem = NO_SELECTED_ITEM;
1565 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001566
Andreas Mohra6d83eb2000-12-27 04:02:46 +00001567 /* store the owner for DrawItem */
Juergen Schmied78513941999-04-18 14:40:32 +00001568 menu->hwndOwner = hwndOwner;
1569
Alexandre Julliardde424282001-08-10 22:51:42 +00001570
1571 MENU_PopupMenuCalcSize( menu, hwndOwner );
1572
1573 /* adjust popup menu pos so that it fits within the desktop */
1574
1575 width = menu->Width + GetSystemMetrics(SM_CXBORDER);
Vincent Béron9a624912002-05-31 23:06:46 +00001576 height = menu->Height + GetSystemMetrics(SM_CYBORDER);
Alexandre Julliardde424282001-08-10 22:51:42 +00001577
1578 if( x + width > GetSystemMetrics(SM_CXSCREEN ))
Alexandre Julliard0e270f41996-08-24 18:26:35 +00001579 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001580 if( xanchor )
1581 x -= width - xanchor;
1582 if( x + width > GetSystemMetrics(SM_CXSCREEN))
1583 x = GetSystemMetrics(SM_CXSCREEN) - width;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001584 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001585 if( x < 0 ) x = 0;
1586
1587 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1588 {
1589 if( yanchor )
1590 y -= height + yanchor;
1591 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1592 y = GetSystemMetrics(SM_CYSCREEN) - height;
1593 }
1594 if( y < 0 ) y = 0;
1595
1596 if( TWEAK_WineLook == WIN31_LOOK )
1597 {
1598 width += POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER); /* add space for shading */
1599 height += POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1600 }
1601
1602 /* NOTE: In Windows, top menu popup is not owned. */
1603 menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1604 WS_POPUP, x, y, width, height,
Alexandre Julliard7ef66af2002-11-22 04:47:10 +00001605 hwndOwner, 0, (HINSTANCE)GetWindowLongA(hwndOwner,GWL_HINSTANCE),
Alexandre Julliardde424282001-08-10 22:51:42 +00001606 (LPVOID)hmenu );
1607 if( !menu->hWnd ) return FALSE;
1608 if (!top_popup) top_popup = menu->hWnd;
1609
1610 /* Display the window */
1611
1612 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1613 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1614 UpdateWindow( menu->hWnd );
1615 return TRUE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001616}
1617
1618
1619/***********************************************************************
1620 * MENU_SelectItem
1621 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001622static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
Rein Klazes80c924f1999-12-12 19:40:46 +00001623 BOOL sendMenuSelect, HMENU topmenu )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001624{
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001625 LPPOPUPMENU lppop;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001626 HDC hdc;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001627
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00001628 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
Juergen Schmied78513941999-04-18 14:40:32 +00001629
Gerard Patel3e629742000-01-17 22:22:16 +00001630 lppop = MENU_GetMenu( hmenu );
Gerard Patel8f79fdc2001-05-14 19:20:13 +00001631 if ((!lppop) || (!lppop->nItems) || (!lppop->hWnd)) return;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001632
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001633 if (lppop->FocusedItem == wIndex) return;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001634 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1635 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
Rizsanyi Zsolt0026d782002-05-09 01:14:35 +00001636 if (!top_popup) top_popup = lppop->hWnd;
Alexandre Julliardf7207251994-07-23 07:57:48 +00001637
Juergen Schmied78513941999-04-18 14:40:32 +00001638 SelectObject( hdc, hMenuFont);
1639
Alexandre Julliardf7207251994-07-23 07:57:48 +00001640 /* Clear previous highlighted item */
Vincent Béron9a624912002-05-31 23:06:46 +00001641 if (lppop->FocusedItem != NO_SELECTED_ITEM)
Alexandre Julliardf7207251994-07-23 07:57:48 +00001642 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001643 lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
Juergen Schmied78513941999-04-18 14:40:32 +00001644 MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
Alexandre Julliard46ea8b31998-05-03 19:01:20 +00001645 lppop->Height, !(lppop->wFlags & MF_POPUP),
1646 ODA_SELECT );
Alexandre Julliardf7207251994-07-23 07:57:48 +00001647 }
1648
1649 /* Highlight new item (if any) */
1650 lppop->FocusedItem = wIndex;
Vincent Béron9a624912002-05-31 23:06:46 +00001651 if (lppop->FocusedItem != NO_SELECTED_ITEM)
Alexandre Julliardf7207251994-07-23 07:57:48 +00001652 {
Rein Klazes80c924f1999-12-12 19:40:46 +00001653 if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
1654 lppop->items[wIndex].fState |= MF_HILITE;
Vincent Béron9a624912002-05-31 23:06:46 +00001655 MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
Rein Klazes80c924f1999-12-12 19:40:46 +00001656 &lppop->items[wIndex], lppop->Height,
1657 !(lppop->wFlags & MF_POPUP), ODA_SELECT );
1658 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001659 if (sendMenuSelect)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001660 {
1661 MENUITEM *ip = &lppop->items[lppop->FocusedItem];
Vincent Béron9a624912002-05-31 23:06:46 +00001662 SendMessageA( hwndOwner, WM_MENUSELECT,
Rein Klazes80c924f1999-12-12 19:40:46 +00001663 MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
1664 ip->fType | ip->fState | MF_MOUSESELECT |
Alexandre Julliard7ef66af2002-11-22 04:47:10 +00001665 (lppop->wFlags & MF_SYSMENU)), (LPARAM)hmenu);
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001666 }
Alexandre Julliardf7207251994-07-23 07:57:48 +00001667 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001668 else if (sendMenuSelect) {
Rein Klazes80c924f1999-12-12 19:40:46 +00001669 if(topmenu){
1670 int pos;
1671 if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00001672 POPUPMENU *ptm = MENU_GetMenu( topmenu );
Rein Klazes80c924f1999-12-12 19:40:46 +00001673 MENUITEM *ip = &ptm->items[pos];
Vincent Béron9a624912002-05-31 23:06:46 +00001674 SendMessageA( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
Rein Klazes80c924f1999-12-12 19:40:46 +00001675 ip->fType | ip->fState | MF_MOUSESELECT |
Alexandre Julliard7ef66af2002-11-22 04:47:10 +00001676 (ptm->wFlags & MF_SYSMENU)), (LPARAM)topmenu);
Rein Klazes80c924f1999-12-12 19:40:46 +00001677 }
1678 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001679 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001680 ReleaseDC( lppop->hWnd, hdc );
Alexandre Julliard8d24ae61994-04-05 21:42:43 +00001681}
1682
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001683
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001684/***********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001685 * MENU_MoveSelection
Alexandre Julliard1e37a181996-08-18 16:21:52 +00001686 *
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001687 * Moves currently selected item according to the offset parameter.
1688 * If there is no selection then it should select the last item if
1689 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001690 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001691static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001692{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001693 INT i;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001694 POPUPMENU *menu;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001695
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00001696 TRACE("hwnd=%p hmenu=%p off=0x%04x\n", hwndOwner, hmenu, offset);
Juergen Schmied466a6521999-05-02 11:21:08 +00001697
Gerard Patel3e629742000-01-17 22:22:16 +00001698 menu = MENU_GetMenu( hmenu );
1699 if ((!menu) || (!menu->items)) return;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001700
1701 if ( menu->FocusedItem != NO_SELECTED_ITEM )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001702 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001703 if( menu->nItems == 1 ) return; else
Vincent Béron9a624912002-05-31 23:06:46 +00001704 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
Alexandre Julliard1e37a181996-08-18 16:21:52 +00001705 ; i += offset)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001706 if (!(menu->items[i].fType & MF_SEPARATOR))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001707 {
Rein Klazes80c924f1999-12-12 19:40:46 +00001708 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001709 return;
1710 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001711 }
Alexandre Julliard5f721f81994-01-04 20:14:34 +00001712
Vincent Béron9a624912002-05-31 23:06:46 +00001713 for ( i = (offset > 0) ? 0 : menu->nItems - 1;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001714 i >= 0 && i < menu->nItems ; i += offset)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001715 if (!(menu->items[i].fType & MF_SEPARATOR))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001716 {
Rein Klazes80c924f1999-12-12 19:40:46 +00001717 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001718 return;
1719 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001720}
1721
1722
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001723/**********************************************************************
1724 * MENU_SetItemData
1725 *
Andreas Mohr8578f012002-08-28 23:31:56 +00001726 * Set an item's flags, id and text ptr. Called by InsertMenu() and
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001727 * ModifyMenu().
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001728 */
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +00001729static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT_PTR id,
Aric Stewartc946b1c2000-10-24 21:28:19 +00001730 LPCWSTR str )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001731{
Aric Stewartc946b1c2000-10-24 21:28:19 +00001732 LPWSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001733
Alexandre Julliard03468f71998-02-15 19:40:49 +00001734 debug_print_menuitem("MENU_SetItemData from: ", item, "");
Gerard Patel2482ef32001-03-19 19:16:21 +00001735 TRACE("flags=%x str=%p\n", flags, str);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001736
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001737 if (IS_STRING_ITEM(flags))
1738 {
Dmitry Timoshkov9316fa32001-02-14 00:23:45 +00001739 if (!str)
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001740 {
1741 flags |= MF_SEPARATOR;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001742 item->text = NULL;
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001743 }
1744 else
1745 {
Aric Stewartc946b1c2000-10-24 21:28:19 +00001746 LPWSTR text;
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001747 /* Item beginning with a backspace is a help item */
1748 if (*str == '\b')
1749 {
1750 flags |= MF_HELP;
1751 str++;
1752 }
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00001753 if (!(text = HeapAlloc( GetProcessHeap(), 0, (strlenW(str)+1) * sizeof(WCHAR) )))
1754 return FALSE;
1755 strcpyW( text, str );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001756 item->text = text;
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001757 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001758 }
Juergen Schmied78513941999-04-18 14:40:32 +00001759 else if (IS_BITMAP_ITEM(flags))
Alexandre Julliarda8a422f2002-11-22 20:43:01 +00001760 item->text = (LPWSTR)HBITMAP_32(LOWORD(str));
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001761 else item->text = NULL;
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001762
Vincent Béron9a624912002-05-31 23:06:46 +00001763 if (flags & MF_OWNERDRAW)
Alexandre Julliarda845b881998-06-01 10:44:35 +00001764 item->dwItemData = (DWORD)str;
1765 else
1766 item->dwItemData = 0;
1767
Alexandre Julliard7ef66af2002-11-22 04:47:10 +00001768 if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != (HMENU)id) )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001769 DestroyMenu( item->hSubMenu ); /* ModifyMenu() spec */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001770
1771 if (flags & MF_POPUP)
1772 {
Alexandre Julliard7ef66af2002-11-22 04:47:10 +00001773 POPUPMENU *menu = MENU_GetMenu((HMENU)id);
Gerard Patel3e629742000-01-17 22:22:16 +00001774 if (menu) menu->wFlags |= MF_POPUP;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001775 else
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001776 {
1777 item->wID = 0;
1778 item->hSubMenu = 0;
1779 item->fType = 0;
1780 item->fState = 0;
1781 return FALSE;
1782 }
Vincent Béron9a624912002-05-31 23:06:46 +00001783 }
Alexandre Julliard02e90081998-01-04 17:49:09 +00001784
1785 item->wID = id;
Alexandre Julliard7ef66af2002-11-22 04:47:10 +00001786 if (flags & MF_POPUP) item->hSubMenu = (HMENU)id;
Alexandre Julliard02e90081998-01-04 17:49:09 +00001787
1788 if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
1789 flags |= MF_POPUP; /* keep popup */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001790
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001791 item->fType = flags & TYPE_MASK;
1792 item->fState = (flags & STATE_MASK) &
1793 ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001794
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001795
1796 /* Don't call SetRectEmpty here! */
1797
1798
Alexandre Julliardda2892c2001-02-23 01:13:42 +00001799 if (prevText) HeapFree( GetProcessHeap(), 0, prevText );
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001800
Alexandre Julliard03468f71998-02-15 19:40:49 +00001801 debug_print_menuitem("MENU_SetItemData to : ", item, "");
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001802 return TRUE;
1803}
1804
1805
1806/**********************************************************************
1807 * MENU_InsertItem
1808 *
Andreas Mohr8578f012002-08-28 23:31:56 +00001809 * Insert (allocate) a new item into a menu.
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001810 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001811static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001812{
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001813 MENUITEM *newItems;
1814 POPUPMENU *menu;
1815
Vincent Béron9a624912002-05-31 23:06:46 +00001816 if (!(menu = MENU_GetMenu(hMenu)))
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001817 return NULL;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001818
1819 /* Find where to insert new item */
1820
Gerard Patelc6369b02000-05-14 22:52:52 +00001821 if (flags & MF_BYPOSITION) {
Vincent Béron9a624912002-05-31 23:06:46 +00001822 if (pos > menu->nItems)
Gerard Patelc6369b02000-05-14 22:52:52 +00001823 pos = menu->nItems;
Marcus Meissnercb3c7bf2000-01-08 22:25:57 +00001824 } else {
Vincent Béron9a624912002-05-31 23:06:46 +00001825 if (!MENU_FindItem( &hMenu, &pos, flags ))
Gerard Patelc6369b02000-05-14 22:52:52 +00001826 pos = menu->nItems;
1827 else {
1828 if (!(menu = MENU_GetMenu( hMenu )))
1829 return NULL;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001830 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001831 }
1832
1833 /* Create new items array */
1834
Alexandre Julliardda2892c2001-02-23 01:13:42 +00001835 newItems = HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001836 if (!newItems)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001837 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001838 WARN("allocation failed\n" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001839 return NULL;
1840 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001841 if (menu->nItems > 0)
1842 {
Andreas Mohra6d83eb2000-12-27 04:02:46 +00001843 /* Copy the old array into the new one */
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001844 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1845 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001846 (menu->nItems-pos)*sizeof(MENUITEM) );
Alexandre Julliardda2892c2001-02-23 01:13:42 +00001847 HeapFree( GetProcessHeap(), 0, menu->items );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001848 }
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001849 menu->items = newItems;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001850 menu->nItems++;
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001851 memset( &newItems[pos], 0, sizeof(*newItems) );
Gerard Patel6df06941999-09-28 13:05:54 +00001852 menu->Height = 0; /* force size recalculate */
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001853 return &newItems[pos];
1854}
1855
1856
1857/**********************************************************************
1858 * MENU_ParseResource
1859 *
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001860 * Parse a standard menu resource and add items to the menu.
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001861 * Return a pointer to the end of the resource.
Chris Morgan36595822002-11-06 21:57:50 +00001862 *
1863 * NOTE: flags is equivalent to the mtOption field
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001864 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001865static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001866{
1867 WORD flags, id = 0;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001868 LPCSTR str;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001869
1870 do
1871 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001872 flags = GET_WORD(res);
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001873 res += sizeof(WORD);
1874 if (!(flags & MF_POPUP))
1875 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001876 id = GET_WORD(res);
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001877 res += sizeof(WORD);
1878 }
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001879 str = res;
1880 if (!unicode) res += strlen(str) + 1;
Aric Stewartc946b1c2000-10-24 21:28:19 +00001881 else res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001882 if (flags & MF_POPUP)
1883 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001884 HMENU hSubMenu = CreatePopupMenu();
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001885 if (!hSubMenu) return NULL;
1886 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1887 return NULL;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001888 if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
1889 else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001890 }
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001891 else /* Not a popup */
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001892 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001893 if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
1894 else AppendMenuW( hMenu, flags, id,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001895 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001896 }
1897 } while (!(flags & MF_END));
1898 return res;
1899}
1900
1901
Alexandre Julliard641ee761997-08-04 16:34:36 +00001902/**********************************************************************
1903 * MENUEX_ParseResource
1904 *
1905 * Parse an extended menu resource and add items to the menu.
1906 * Return a pointer to the end of the resource.
1907 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001908static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
Alexandre Julliard641ee761997-08-04 16:34:36 +00001909{
Alexandre Julliard641ee761997-08-04 16:34:36 +00001910 WORD resinfo;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001911 do {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001912 MENUITEMINFOW mii;
Alexandre Julliard641ee761997-08-04 16:34:36 +00001913
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001914 mii.cbSize = sizeof(mii);
1915 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
1916 mii.fType = GET_DWORD(res);
Alexandre Julliard641ee761997-08-04 16:34:36 +00001917 res += sizeof(DWORD);
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001918 mii.fState = GET_DWORD(res);
Alexandre Julliard641ee761997-08-04 16:34:36 +00001919 res += sizeof(DWORD);
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001920 mii.wID = GET_DWORD(res);
Alexandre Julliard641ee761997-08-04 16:34:36 +00001921 res += sizeof(DWORD);
1922 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
1923 res += sizeof(WORD);
1924 /* Align the text on a word boundary. */
1925 res += (~((int)res - 1)) & 1;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001926 mii.dwTypeData = (LPWSTR) res;
Aric Stewartc946b1c2000-10-24 21:28:19 +00001927 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
Alexandre Julliard641ee761997-08-04 16:34:36 +00001928 /* Align the following fields on a dword boundary. */
1929 res += (~((int)res - 1)) & 3;
1930
Alexandre Julliardda2892c2001-02-23 01:13:42 +00001931 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1932 mii.fType, mii.fState, mii.wID, resinfo, debugstr_w(mii.dwTypeData));
Alexandre Julliard641ee761997-08-04 16:34:36 +00001933
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001934 if (resinfo & 1) { /* Pop-up? */
Marcus Meissnerde43ef41999-02-28 19:56:59 +00001935 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
Alexandre Julliard641ee761997-08-04 16:34:36 +00001936 res += sizeof(DWORD);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001937 mii.hSubMenu = CreatePopupMenu();
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001938 if (!mii.hSubMenu)
1939 return NULL;
1940 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001941 DestroyMenu(mii.hSubMenu);
Alexandre Julliard641ee761997-08-04 16:34:36 +00001942 return NULL;
Dmitry Timoshkov5076dba2002-04-02 02:36:44 +00001943 }
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001944 mii.fMask |= MIIM_SUBMENU;
1945 mii.fType |= MF_POPUP;
Alexandre Julliard641ee761997-08-04 16:34:36 +00001946 }
Dmitry Timoshkov5076dba2002-04-02 02:36:44 +00001947 else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
1948 {
1949 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
1950 mii.wID, mii.fType);
1951 mii.fType |= MF_SEPARATOR;
1952 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001953 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
Alexandre Julliard641ee761997-08-04 16:34:36 +00001954 } while (!(resinfo & MF_END));
1955 return res;
1956}
1957
1958
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001959/***********************************************************************
1960 * MENU_GetSubPopup
1961 *
1962 * Return the handle of the selected sub-popup menu (if any).
1963 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001964static HMENU MENU_GetSubPopup( HMENU hmenu )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001965{
1966 POPUPMENU *menu;
1967 MENUITEM *item;
1968
Gerard Patel3e629742000-01-17 22:22:16 +00001969 menu = MENU_GetMenu( hmenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001970
Gerard Patel3e629742000-01-17 22:22:16 +00001971 if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001972
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001973 item = &menu->items[menu->FocusedItem];
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001974 if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
1975 return item->hSubMenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001976 return 0;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001977}
1978
1979
1980/***********************************************************************
1981 * MENU_HideSubPopups
1982 *
1983 * Hide the sub-popup menus of this menu.
1984 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001985static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
1986 BOOL sendMenuSelect )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001987{
Gerard Patel3e629742000-01-17 22:22:16 +00001988 POPUPMENU *menu = MENU_GetMenu( hmenu );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001989
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00001990 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
Juergen Schmied466a6521999-05-02 11:21:08 +00001991
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00001992 if (menu && top_popup)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00001993 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001994 HMENU hsubmenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001995 POPUPMENU *submenu;
1996 MENUITEM *item;
1997
1998 if (menu->FocusedItem != NO_SELECTED_ITEM)
1999 {
2000 item = &menu->items[menu->FocusedItem];
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002001 if (!(item->fType & MF_POPUP) ||
2002 !(item->fState & MF_MOUSESELECT)) return;
2003 item->fState &= ~MF_MOUSESELECT;
2004 hsubmenu = item->hSubMenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002005 } else return;
2006
Gerard Patel3e629742000-01-17 22:22:16 +00002007 submenu = MENU_GetMenu( hsubmenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002008 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
Rein Klazes80c924f1999-12-12 19:40:46 +00002009 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00002010 DestroyWindow( submenu->hWnd );
2011 submenu->hWnd = 0;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00002012 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002013}
2014
2015
2016/***********************************************************************
2017 * MENU_ShowSubPopup
2018 *
2019 * Display the sub-menu of the selected item of this menu.
2020 * Return the handle of the submenu, or hmenu if no submenu to display.
2021 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002022static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002023 BOOL selectFirst, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002024{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002025 RECT rect;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002026 POPUPMENU *menu;
2027 MENUITEM *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002028 HDC hdc;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002029
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002030 TRACE("owner=%p hmenu=%p 0x%04x\n", hwndOwner, hmenu, selectFirst);
Juergen Schmied466a6521999-05-02 11:21:08 +00002031
Gerard Patel3e629742000-01-17 22:22:16 +00002032 if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002033
Alexandre Julliardde424282001-08-10 22:51:42 +00002034 if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002035
Alexandre Julliard2d93d001996-05-21 15:01:41 +00002036 item = &menu->items[menu->FocusedItem];
Alexandre Julliardde424282001-08-10 22:51:42 +00002037 if (!(item->fType & MF_POPUP) || (item->fState & (MF_GRAYED | MF_DISABLED)))
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002038 return hmenu;
Alexandre Julliard02e90081998-01-04 17:49:09 +00002039
Andreas Mohra6d83eb2000-12-27 04:02:46 +00002040 /* message must be sent before using item,
2041 because nearly everything may be changed by the application ! */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00002042
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002043 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2044 if (!(wFlags & TPM_NONOTIFY))
Alexandre Julliard7ef66af2002-11-22 04:47:10 +00002045 SendMessageA( hwndOwner, WM_INITMENUPOPUP, (WPARAM)item->hSubMenu,
2046 MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
Alexandre Julliard02e90081998-01-04 17:49:09 +00002047
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00002048 item = &menu->items[menu->FocusedItem];
2049 rect = item->rect;
2050
Andreas Mohra6d83eb2000-12-27 04:02:46 +00002051 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
Vincent Béron9a624912002-05-31 23:06:46 +00002052 if (!(item->fState & MF_HILITE))
Alexandre Julliard02e90081998-01-04 17:49:09 +00002053 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002054 if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
2055 else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
Juergen Schmied78513941999-04-18 14:40:32 +00002056
2057 SelectObject( hdc, hMenuFont);
2058
Alexandre Julliard02e90081998-01-04 17:49:09 +00002059 item->fState |= MF_HILITE;
Vincent Béron9a624912002-05-31 23:06:46 +00002060 MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002061 ReleaseDC( menu->hWnd, hdc );
Alexandre Julliard02e90081998-01-04 17:49:09 +00002062 }
2063 if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
2064 item->rect = rect;
2065
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002066 item->fState |= MF_MOUSESELECT;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002067
2068 if (IS_SYSTEM_MENU(menu))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002069 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002070 MENU_InitSysMenuPopup(item->hSubMenu,
2071 GetWindowLongA( menu->hWnd, GWL_STYLE ),
2072 GetClassLongA( menu->hWnd, GCL_STYLE));
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002073
Alexandre Julliardde424282001-08-10 22:51:42 +00002074 NC_GetSysPopupPos( menu->hWnd, &rect );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002075 rect.top = rect.bottom;
Marcus Meissnerddca3151999-05-22 11:33:23 +00002076 rect.right = GetSystemMetrics(SM_CXSIZE);
2077 rect.bottom = GetSystemMetrics(SM_CYSIZE);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002078 }
2079 else
2080 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002081 GetWindowRect( menu->hWnd, &rect );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002082 if (menu->wFlags & MF_POPUP)
2083 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002084 rect.left += item->rect.right - GetSystemMetrics(SM_CXBORDER);
2085 rect.top += item->rect.top;
Ken Thomases130f0d82000-05-10 21:38:37 +00002086 rect.right = item->rect.left - item->rect.right + GetSystemMetrics(SM_CXBORDER);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002087 rect.bottom = item->rect.top - item->rect.bottom;
2088 }
2089 else
2090 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002091 rect.left += item->rect.left;
2092 rect.top += item->rect.bottom;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002093 rect.right = item->rect.right - item->rect.left;
2094 rect.bottom = item->rect.bottom - item->rect.top;
2095 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002096 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002097
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002098 MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002099 rect.left, rect.top, rect.right, rect.bottom );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002100 if (selectFirst)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002101 MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2102 return item->hSubMenu;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002103}
2104
Ulrich Czekalla33026a22000-02-26 19:13:44 +00002105
2106
2107/**********************************************************************
2108 * MENU_IsMenuActive
2109 */
2110BOOL MENU_IsMenuActive(void)
2111{
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00002112 return (top_popup != 0);
Ulrich Czekalla33026a22000-02-26 19:13:44 +00002113}
2114
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002115/***********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002116 * MENU_PtMenu
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002117 *
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002118 * Walks menu chain trying to find a menu pt maps to.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002119 */
Alexandre Julliard83f52d12000-09-26 22:20:14 +00002120static HMENU MENU_PtMenu( HMENU hMenu, POINT pt )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002121{
Gerard Patel3e629742000-01-17 22:22:16 +00002122 POPUPMENU *menu = MENU_GetMenu( hMenu );
Alexandre Julliardde424282001-08-10 22:51:42 +00002123 UINT item = menu->FocusedItem;
2124 HMENU ret;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002125
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002126 /* try subpopup first (if any) */
Alexandre Julliardde424282001-08-10 22:51:42 +00002127 ret = (item != NO_SELECTED_ITEM &&
2128 (menu->items[item].fType & MF_POPUP) &&
2129 (menu->items[item].fState & MF_MOUSESELECT))
2130 ? MENU_PtMenu(menu->items[item].hSubMenu, pt) : 0;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002131
Alexandre Julliardde424282001-08-10 22:51:42 +00002132 if (!ret) /* check the current window (avoiding WM_HITTEST) */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002133 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002134 INT ht = NC_HandleNCHitTest( menu->hWnd, pt );
2135 if( menu->wFlags & MF_POPUP )
2136 {
2137 if (ht != HTNOWHERE && ht != HTERROR) ret = hMenu;
2138 }
2139 else if (ht == HTSYSMENU)
2140 ret = get_win_sys_menu( menu->hWnd );
2141 else if (ht == HTMENU)
2142 ret = GetMenu( menu->hWnd );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002143 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002144 return ret;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002145}
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002146
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002147/***********************************************************************
2148 * MENU_ExecFocusedItem
2149 *
2150 * Execute a menu item (for instance when user pressed Enter).
Karl Lessard13409b31999-09-28 16:24:58 +00002151 * Return the wID of the executed item. Otherwise, -1 indicating
Andreas Mohr2e011a52000-06-01 23:28:25 +00002152 * that no menu item was executed;
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002153 * Have to receive the flags for the TrackPopupMenu options to avoid
2154 * sending unwanted message.
2155 *
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002156 */
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002157static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002158{
2159 MENUITEM *item;
Gerard Patel3e629742000-01-17 22:22:16 +00002160 POPUPMENU *menu = MENU_GetMenu( hMenu );
Juergen Schmied466a6521999-05-02 11:21:08 +00002161
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002162 TRACE("%p hmenu=%p\n", pmt, hMenu);
Juergen Schmied466a6521999-05-02 11:21:08 +00002163
Vincent Béron9a624912002-05-31 23:06:46 +00002164 if (!menu || !menu->nItems ||
Karl Lessard13409b31999-09-28 16:24:58 +00002165 (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002166
Alexandre Julliard2d93d001996-05-21 15:01:41 +00002167 item = &menu->items[menu->FocusedItem];
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002168
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002169 TRACE("%p %08x %p\n", hMenu, item->wID, item->hSubMenu);
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002170
2171 if (!(item->fType & MF_POPUP))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002172 {
Francois Gouget93fd46a2000-10-23 00:37:49 +00002173 if (!(item->fState & (MF_GRAYED | MF_DISABLED)) && !(item->fType & MF_SEPARATOR))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002174 {
Vincent Béron9a624912002-05-31 23:06:46 +00002175 /* If TPM_RETURNCMD is set you return the id, but
2176 do not send a message to the owner */
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002177 if(!(wFlags & TPM_RETURNCMD))
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002178 {
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002179 if( menu->wFlags & MF_SYSMENU )
2180 PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2181 MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2182 else
2183 PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002184 }
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00002185 return item->wID;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002186 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002187 }
2188 else
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002189 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002190
Karl Lessard13409b31999-09-28 16:24:58 +00002191 return -1;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002192}
2193
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002194/***********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002195 * MENU_SwitchTracking
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002196 *
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002197 * Helper function for menu navigation routines.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002198 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002199static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002200{
Gerard Patel3e629742000-01-17 22:22:16 +00002201 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2202 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002203
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002204 TRACE("%p hmenu=%p 0x%04x\n", pmt, hPtMenu, id);
Juergen Schmied466a6521999-05-02 11:21:08 +00002205
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002206 if( pmt->hTopMenu != hPtMenu &&
2207 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002208 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002209 /* both are top level menus (system and menu-bar) */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002210 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
Rein Klazes80c924f1999-12-12 19:40:46 +00002211 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002212 pmt->hTopMenu = hPtMenu;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002213 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002214 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
Rein Klazes80c924f1999-12-12 19:40:46 +00002215 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002216}
2217
2218
2219/***********************************************************************
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002220 * MENU_ButtonDown
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002221 *
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002222 * Return TRUE if we can go on with menu tracking.
2223 */
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002224static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002225{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002226 TRACE("%p hPtMenu=%p\n", pmt, hPtMenu);
Juergen Schmied466a6521999-05-02 11:21:08 +00002227
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002228 if (hPtMenu)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002229 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002230 UINT id = 0;
Gerard Patel3e629742000-01-17 22:22:16 +00002231 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002232 MENUITEM *item;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002233
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002234 if( IS_SYSTEM_MENU(ptmenu) )
2235 item = ptmenu->items;
2236 else
2237 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002238
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002239 if( item )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002240 {
Pascal Lessard2eb0a301999-09-03 16:38:52 +00002241 if( ptmenu->FocusedItem != id )
2242 MENU_SwitchTracking( pmt, hPtMenu, id );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002243
Pascal Lessard2eb0a301999-09-03 16:38:52 +00002244 /* If the popup menu is not already "popped" */
2245 if(!(item->fState & MF_MOUSESELECT ))
Pascal Lessard07c447f1999-09-19 12:03:25 +00002246 {
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002247 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002248
Andreas Mohra6d83eb2000-12-27 04:02:46 +00002249 /* In win31, a newly popped menu always remains opened for the next buttonup */
Pascal Lessard07c447f1999-09-19 12:03:25 +00002250 if(TWEAK_WineLook == WIN31_LOOK)
Vincent Béron9a624912002-05-31 23:06:46 +00002251 ptmenu->bTimeToHide = FALSE;
Pascal Lessard07c447f1999-09-19 12:03:25 +00002252 }
2253
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002254 return TRUE;
Vincent Béron9a624912002-05-31 23:06:46 +00002255 }
Pascal Lessard445c9101999-09-20 18:27:14 +00002256 /* Else the click was on the menu bar, finish the tracking */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002257 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002258 return FALSE;
2259}
2260
2261/***********************************************************************
2262 * MENU_ButtonUp
2263 *
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002264 * Return the value of MENU_ExecFocusedItem if
2265 * the selected item was not a popup. Else open the popup.
Karl Lessard13409b31999-09-28 16:24:58 +00002266 * A -1 return value indicates that we go on with menu tracking.
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002267 *
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002268 */
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002269static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002270{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002271 TRACE("%p hmenu=%p\n", pmt, hPtMenu);
Juergen Schmied466a6521999-05-02 11:21:08 +00002272
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002273 if (hPtMenu)
2274 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002275 UINT id = 0;
Gerard Patel3e629742000-01-17 22:22:16 +00002276 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002277 MENUITEM *item;
2278
2279 if( IS_SYSTEM_MENU(ptmenu) )
2280 item = ptmenu->items;
2281 else
2282 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2283
Alexandre Julliard491502b1997-11-01 19:08:16 +00002284 if( item && (ptmenu->FocusedItem == id ))
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002285 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002286 if( !(item->fType & MF_POPUP) )
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002287 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002288
Andreas Mohra6d83eb2000-12-27 04:02:46 +00002289 /* If we are dealing with the top-level menu */
2290 /* and this is a click on an already "popped" item: */
2291 /* Stop the menu tracking and close the opened submenus */
Pascal Lessard2eb0a301999-09-03 16:38:52 +00002292 if((pmt->hTopMenu == hPtMenu) && (ptmenu->bTimeToHide == TRUE))
Karl Lessard13409b31999-09-28 16:24:58 +00002293 return 0;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002294 }
Pascal Lessard2eb0a301999-09-03 16:38:52 +00002295 ptmenu->bTimeToHide = TRUE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002296 }
Karl Lessard13409b31999-09-28 16:24:58 +00002297 return -1;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002298}
2299
2300
2301/***********************************************************************
2302 * MENU_MouseMove
2303 *
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002304 * Return TRUE if we can go on with menu tracking.
2305 */
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002306static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002307{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002308 UINT id = NO_SELECTED_ITEM;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002309 POPUPMENU *ptmenu = NULL;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002310
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002311 if( hPtMenu )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002312 {
Gerard Patel3e629742000-01-17 22:22:16 +00002313 ptmenu = MENU_GetMenu( hPtMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002314 if( IS_SYSTEM_MENU(ptmenu) )
2315 id = 0;
2316 else
2317 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
Vincent Béron9a624912002-05-31 23:06:46 +00002318 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002319
2320 if( id == NO_SELECTED_ITEM )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002321 {
Vincent Béron9a624912002-05-31 23:06:46 +00002322 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
Rein Klazes80c924f1999-12-12 19:40:46 +00002323 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
Vincent Béron9a624912002-05-31 23:06:46 +00002324
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002325 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002326 else if( ptmenu->FocusedItem != id )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002327 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002328 MENU_SwitchTracking( pmt, hPtMenu, id );
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002329 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002330 }
2331 return TRUE;
2332}
2333
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002334
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002335/***********************************************************************
Alexandre Julliarda9e8f592002-10-12 01:24:37 +00002336 * MENU_SetCapture
2337 */
2338static void MENU_SetCapture( HWND hwnd )
2339{
2340 HWND previous = 0;
2341
2342 SERVER_START_REQ( set_capture_window )
2343 {
2344 req->handle = hwnd;
2345 req->flags = CAPTURE_MENU;
2346 if (!wine_server_call_err( req ))
2347 {
2348 previous = reply->previous;
2349 hwnd = reply->full_handle;
2350 }
2351 }
2352 SERVER_END_REQ;
2353
2354 if (previous && previous != hwnd)
2355 SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
2356}
2357
2358
2359/***********************************************************************
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002360 * MENU_DoNextMenu
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002361 *
2362 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002363 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002364static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002365{
Gerard Patel3e629742000-01-17 22:22:16 +00002366 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002367
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002368 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2369 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2370 {
Alexandre Julliardb3ec0302001-08-18 18:10:04 +00002371 MDINEXTMENU next_menu;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002372 HMENU hNewMenu;
2373 HWND hNewWnd;
2374 UINT id = 0;
Alexandre Julliardb3ec0302001-08-18 18:10:04 +00002375
2376 next_menu.hmenuIn = (IS_SYSTEM_MENU(menu)) ? GetSubMenu(pmt->hTopMenu,0) : pmt->hTopMenu;
2377 next_menu.hmenuNext = 0;
2378 next_menu.hwndNext = 0;
2379 SendMessageW( pmt->hOwnerWnd, WM_NEXTMENU, vk, (LPARAM)&next_menu );
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002380
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002381 TRACE("%p [%p] -> %p [%p]\n",
Alexandre Julliardb3ec0302001-08-18 18:10:04 +00002382 pmt->hCurrentMenu, pmt->hOwnerWnd, next_menu.hmenuNext, next_menu.hwndNext );
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002383
Alexandre Julliardb3ec0302001-08-18 18:10:04 +00002384 if (!next_menu.hmenuNext || !next_menu.hwndNext)
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002385 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002386 DWORD style = GetWindowLongA( pmt->hOwnerWnd, GWL_STYLE );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002387 hNewWnd = pmt->hOwnerWnd;
2388 if( IS_SYSTEM_MENU(menu) )
2389 {
2390 /* switch to the menu bar */
2391
Alexandre Julliardde424282001-08-10 22:51:42 +00002392 if(style & WS_CHILD || !(hNewMenu = GetMenu(hNewWnd))) return FALSE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002393
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002394 if( vk == VK_LEFT )
2395 {
Gerard Patel3e629742000-01-17 22:22:16 +00002396 menu = MENU_GetMenu( hNewMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002397 id = menu->nItems - 1;
2398 }
2399 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002400 else if (style & WS_SYSMENU )
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002401 {
2402 /* switch to the system menu */
Alexandre Julliardde424282001-08-10 22:51:42 +00002403 hNewMenu = get_win_sys_menu( hNewWnd );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002404 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002405 else return FALSE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002406 }
2407 else /* application returned a new menu to switch to */
2408 {
Alexandre Julliardb3ec0302001-08-18 18:10:04 +00002409 hNewMenu = next_menu.hmenuNext;
Alexandre Julliardf44bbb82001-09-14 00:24:39 +00002410 hNewWnd = WIN_GetFullHandle( next_menu.hwndNext );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002411
Alexandre Julliarda3960291999-02-26 11:11:13 +00002412 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002413 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002414 DWORD style = GetWindowLongA( hNewWnd, GWL_STYLE );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002415
Alexandre Julliardde424282001-08-10 22:51:42 +00002416 if (style & WS_SYSMENU &&
2417 GetSubMenu(get_win_sys_menu(hNewWnd), 0) == hNewMenu )
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002418 {
2419 /* get the real system menu */
Alexandre Julliardde424282001-08-10 22:51:42 +00002420 hNewMenu = get_win_sys_menu(hNewWnd);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002421 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002422 else if (style & WS_CHILD || GetMenu(hNewWnd) != hNewMenu )
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002423 {
Andreas Mohra6d83eb2000-12-27 04:02:46 +00002424 /* FIXME: Not sure what to do here;
2425 * perhaps try to track hNewMenu as a popup? */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002426
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002427 TRACE(" -- got confused.\n");
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002428 return FALSE;
2429 }
2430 }
2431 else return FALSE;
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002432 }
2433
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002434 if( hNewMenu != pmt->hTopMenu )
2435 {
Vincent Béron9a624912002-05-31 23:06:46 +00002436 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
Rein Klazes80c924f1999-12-12 19:40:46 +00002437 FALSE, 0 );
Vincent Béron9a624912002-05-31 23:06:46 +00002438 if( pmt->hCurrentMenu != pmt->hTopMenu )
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002439 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2440 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002441
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002442 if( hNewWnd != pmt->hOwnerWnd )
2443 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002444 pmt->hOwnerWnd = hNewWnd;
Alexandre Julliarda9e8f592002-10-12 01:24:37 +00002445 MENU_SetCapture( pmt->hOwnerWnd );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002446 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002447
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002448 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
Vincent Béron9a624912002-05-31 23:06:46 +00002449 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002450
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002451 return TRUE;
2452 }
2453 return FALSE;
2454}
2455
2456/***********************************************************************
2457 * MENU_SuspendPopup
2458 *
2459 * The idea is not to show the popup if the next input message is
2460 * going to hide it anyway.
2461 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002462static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002463{
Juergen Schmied78513941999-04-18 14:40:32 +00002464 MSG msg;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002465
2466 msg.hwnd = pmt->hOwnerWnd;
2467
Juergen Schmied78513941999-04-18 14:40:32 +00002468 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002469 pmt->trackFlags |= TF_SKIPREMOVE;
2470
2471 switch( uMsg )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002472 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002473 case WM_KEYDOWN:
Juergen Schmied78513941999-04-18 14:40:32 +00002474 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002475 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2476 {
Juergen Schmied78513941999-04-18 14:40:32 +00002477 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2478 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002479 if( msg.message == WM_KEYDOWN &&
2480 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2481 {
2482 pmt->trackFlags |= TF_SUSPENDPOPUP;
2483 return TRUE;
2484 }
2485 }
2486 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002487 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002488
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002489 /* failures go through this */
2490 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2491 return FALSE;
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002492}
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002493
2494/***********************************************************************
Ulrich Czekalla18ce3882001-05-18 23:20:20 +00002495 * MENU_KeyEscape
2496 *
Vincent Béron9a624912002-05-31 23:06:46 +00002497 * Handle a VK_ESCAPE key event in a menu.
Ulrich Czekalla18ce3882001-05-18 23:20:20 +00002498 */
2499static BOOL MENU_KeyEscape(MTRACKER* pmt, UINT wFlags)
2500{
2501 BOOL bEndMenu = TRUE;
2502
2503 if (pmt->hCurrentMenu != pmt->hTopMenu)
2504 {
2505 POPUPMENU *menu = MENU_GetMenu(pmt->hCurrentMenu);
2506
2507 if (menu->wFlags & MF_POPUP)
2508 {
2509 HMENU hmenutmp, hmenuprev;
2510
2511 hmenuprev = hmenutmp = pmt->hTopMenu;
2512
2513 /* close topmost popup */
2514 while (hmenutmp != pmt->hCurrentMenu)
2515 {
2516 hmenuprev = hmenutmp;
2517 hmenutmp = MENU_GetSubPopup( hmenuprev );
2518 }
2519
2520 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2521 pmt->hCurrentMenu = hmenuprev;
2522 bEndMenu = FALSE;
2523 }
2524 }
2525
2526 return bEndMenu;
2527}
2528
2529/***********************************************************************
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002530 * MENU_KeyLeft
2531 *
Vincent Béron9a624912002-05-31 23:06:46 +00002532 * Handle a VK_LEFT key event in a menu.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002533 */
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002534static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002535{
2536 POPUPMENU *menu;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002537 HMENU hmenutmp, hmenuprev;
2538 UINT prevcol;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002539
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002540 hmenuprev = hmenutmp = pmt->hTopMenu;
Gerard Patel3e629742000-01-17 22:22:16 +00002541 menu = MENU_GetMenu( hmenutmp );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002542
Alexandre Julliard641ee761997-08-04 16:34:36 +00002543 /* Try to move 1 column left (if possible) */
Vincent Béron9a624912002-05-31 23:06:46 +00002544 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
Alexandre Julliard641ee761997-08-04 16:34:36 +00002545 NO_SELECTED_ITEM ) {
Vincent Béron9a624912002-05-31 23:06:46 +00002546
Alexandre Julliard641ee761997-08-04 16:34:36 +00002547 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
Rein Klazes80c924f1999-12-12 19:40:46 +00002548 prevcol, TRUE, 0 );
Alexandre Julliard641ee761997-08-04 16:34:36 +00002549 return;
2550 }
2551
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002552 /* close topmost popup */
2553 while (hmenutmp != pmt->hCurrentMenu)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002554 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002555 hmenuprev = hmenutmp;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002556 hmenutmp = MENU_GetSubPopup( hmenuprev );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002557 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002558
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002559 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
Vincent Béron9a624912002-05-31 23:06:46 +00002560 pmt->hCurrentMenu = hmenuprev;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002561
2562 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002563 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002564 /* move menu bar selection if no more popups are left */
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002565
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002566 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2567 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002568
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002569 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002570 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002571 /* A sublevel menu was displayed - display the next one
2572 * unless there is another displacement coming up */
2573
2574 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002575 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2576 pmt->hTopMenu, TRUE, wFlags);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002577 }
2578 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002579}
2580
2581
2582/***********************************************************************
2583 * MENU_KeyRight
2584 *
2585 * Handle a VK_RIGHT key event in a menu.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002586 */
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002587static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002588{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002589 HMENU hmenutmp;
Gerard Patel3e629742000-01-17 22:22:16 +00002590 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002591 UINT nextcol;
Alexandre Julliard641ee761997-08-04 16:34:36 +00002592
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002593 TRACE("MENU_KeyRight called, cur %p (%s), top %p (%s).\n",
2594 pmt->hCurrentMenu,
2595 debugstr_w((MENU_GetMenu(pmt->hCurrentMenu))->items[0].text),
2596 pmt->hTopMenu, debugstr_w(menu->items[0].text) );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002597
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002598 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002599 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002600 /* If already displaying a popup, try to display sub-popup */
2601
2602 hmenutmp = pmt->hCurrentMenu;
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002603 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002604
2605 /* if subpopup was displayed then we are done */
2606 if (hmenutmp != pmt->hCurrentMenu) return;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002607 }
2608
Alexandre Julliard641ee761997-08-04 16:34:36 +00002609 /* Check to see if there's another column */
Vincent Béron9a624912002-05-31 23:06:46 +00002610 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
Alexandre Julliard641ee761997-08-04 16:34:36 +00002611 NO_SELECTED_ITEM ) {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002612 TRACE("Going to %d.\n", nextcol );
Alexandre Julliard641ee761997-08-04 16:34:36 +00002613 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
Rein Klazes80c924f1999-12-12 19:40:46 +00002614 nextcol, TRUE, 0 );
Alexandre Julliard641ee761997-08-04 16:34:36 +00002615 return;
2616 }
2617
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002618 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002619 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002620 if( pmt->hCurrentMenu != pmt->hTopMenu )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002621 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002622 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2623 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2624 } else hmenutmp = 0;
2625
2626 /* try to move to the next item */
2627 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2628 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2629
2630 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2631 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
Vincent Béron9a624912002-05-31 23:06:46 +00002632 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002633 pmt->hTopMenu, TRUE, wFlags);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002634 }
2635}
2636
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002637/***********************************************************************
2638 * MENU_TrackMenu
2639 *
2640 * Menu tracking code.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002641 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002642static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2643 HWND hwnd, const RECT *lprect )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002644{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002645 MSG msg;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002646 POPUPMENU *menu;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002647 BOOL fRemove;
Karl Lessard13409b31999-09-28 16:24:58 +00002648 INT executedMenuId = -1;
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002649 MTRACKER mt;
Francis Beaudet7ed1af31999-08-15 16:58:03 +00002650 BOOL enterIdleSent = FALSE;
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002651
2652 mt.trackFlags = 0;
2653 mt.hCurrentMenu = hmenu;
2654 mt.hTopMenu = hmenu;
Alexandre Julliardf44bbb82001-09-14 00:24:39 +00002655 mt.hOwnerWnd = WIN_GetFullHandle( hwnd );
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002656 mt.pt.x = x;
2657 mt.pt.y = y;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002658
Dan Kegel0fd521f2003-01-08 21:09:25 +00002659 TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%p (%ld,%ld)-(%ld,%ld)\n",
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002660 hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
2661 (lprect) ? lprect->right : 0, (lprect) ? lprect->bottom : 0);
Juergen Schmied78513941999-04-18 14:40:32 +00002662
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002663 fEndMenu = FALSE;
Gerard Patel3e629742000-01-17 22:22:16 +00002664 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002665
Vincent Béron9a624912002-05-31 23:06:46 +00002666 if (wFlags & TPM_BUTTONDOWN)
Pascal Lessardae6de762000-01-09 02:38:02 +00002667 {
2668 /* Get the result in order to start the tracking or not */
2669 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
Vincent Béron9a624912002-05-31 23:06:46 +00002670 fEndMenu = !fRemove;
Pascal Lessardae6de762000-01-09 02:38:02 +00002671 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002672
Alexandre Julliarda9e8f592002-10-12 01:24:37 +00002673 MENU_SetCapture( mt.hOwnerWnd );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002674
2675 while (!fEndMenu)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002676 {
Gerard Patel3e629742000-01-17 22:22:16 +00002677 menu = MENU_GetMenu( mt.hCurrentMenu );
Marcus Meissner4a699392001-02-13 01:49:06 +00002678 if (!menu) /* sometimes happens if I do a window manager close */
2679 break;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002680
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002681 /* we have to keep the message in the queue until it's
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002682 * clear that menu loop is not over yet. */
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002683
Alexandre Julliardbfb4a232001-08-06 18:05:47 +00002684 for (;;)
2685 {
2686 if (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
2687 {
2688 if (!CallMsgFilterA( &msg, MSGF_MENU )) break;
2689 /* remove the message from the queue */
2690 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2691 }
2692 else
2693 {
2694 if (!enterIdleSent)
2695 {
2696 HWND win = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2697 enterIdleSent = TRUE;
2698 SendMessageW( mt.hOwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM)win );
2699 }
2700 WaitMessage();
2701 }
2702 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002703
Rob Farnumb2007932000-05-23 23:34:17 +00002704 /* check if EndMenu() tried to cancel us, by posting this message */
Vincent Béron9a624912002-05-31 23:06:46 +00002705 if(msg.message == WM_CANCELMODE)
Rob Farnumb2007932000-05-23 23:34:17 +00002706 {
2707 /* we are now out of the loop */
2708 fEndMenu = TRUE;
2709
2710 /* remove the message from the queue */
2711 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
Vincent Béron9a624912002-05-31 23:06:46 +00002712
Rob Farnumb2007932000-05-23 23:34:17 +00002713 /* break out of internal loop, ala ESCAPE */
2714 break;
2715 }
2716
Alexandre Julliarda3960291999-02-26 11:11:13 +00002717 TranslateMessage( &msg );
Stephane Lussierb3a99de1999-02-09 15:35:12 +00002718 mt.pt = msg.pt;
Alexandre Julliardac9c9b01996-07-28 18:50:11 +00002719
Francis Beaudet7ed1af31999-08-15 16:58:03 +00002720 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2721 enterIdleSent=FALSE;
2722
Alexandre Julliarde2abbb11995-03-19 17:39:39 +00002723 fRemove = FALSE;
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002724 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002725 {
Vincent Béron9a624912002-05-31 23:06:46 +00002726 /*
Alexandre Julliarda9e8f592002-10-12 01:24:37 +00002727 * Use the mouse coordinates in lParam instead of those in the MSG
2728 * struct to properly handle synthetic messages. They are already
2729 * in screen coordinates.
Louis Philippe Gagnon9cdd22c2000-11-27 22:39:35 +00002730 */
2731 mt.pt.x = SLOWORD(msg.lParam);
2732 mt.pt.y = SHIWORD(msg.lParam);
Louis Philippe Gagnon9cdd22c2000-11-27 22:39:35 +00002733
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002734 /* Find a menu for this mouse event */
Louis Philippe Gagnon9cdd22c2000-11-27 22:39:35 +00002735 hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002736
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002737 switch(msg.message)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002738 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002739 /* no WM_NC... messages in captured state */
2740
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002741 case WM_RBUTTONDBLCLK:
2742 case WM_RBUTTONDOWN:
2743 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2744 /* fall through */
2745 case WM_LBUTTONDBLCLK:
2746 case WM_LBUTTONDOWN:
Karl Lessard4a0a7df1999-11-07 05:17:10 +00002747 /* If the message belongs to the menu, removes it from the queue */
2748 /* Else, end menu tracking */
2749 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2750 fEndMenu = !fRemove;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002751 break;
Vincent Béron9a624912002-05-31 23:06:46 +00002752
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002753 case WM_RBUTTONUP:
2754 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2755 /* fall through */
2756 case WM_LBUTTONUP:
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00002757 /* Check if a menu was selected by the mouse */
2758 if (hmenu)
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002759 {
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002760 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00002761
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002762 /* End the loop if executedMenuId is an item ID */
Karl Lessard13409b31999-09-28 16:24:58 +00002763 /* or if the job was done (executedMenuId = 0). */
2764 fEndMenu = fRemove = (executedMenuId != -1);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002765 }
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00002766 /* No menu was selected by the mouse */
2767 /* if the function was called by TrackPopupMenu, continue
2768 with the menu tracking. If not, stop it */
2769 else
2770 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
Vincent Béron9a624912002-05-31 23:06:46 +00002771
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002772 break;
Vincent Béron9a624912002-05-31 23:06:46 +00002773
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002774 case WM_MOUSEMOVE:
Alexandre Julliard8da12c41999-01-17 16:55:11 +00002775 /* In win95 winelook, the selected menu item must be changed every time the
2776 mouse moves. In Win31 winelook, the mouse button has to be held down */
Vincent Béron9a624912002-05-31 23:06:46 +00002777
Rizsanyi Zsolt0026d782002-05-09 01:14:35 +00002778 if ( hmenu && ((TWEAK_WineLook > WIN31_LOOK) ||
Alexandre Julliard8da12c41999-01-17 16:55:11 +00002779 ( (msg.wParam & MK_LBUTTON) ||
Rizsanyi Zsolt0026d782002-05-09 01:14:35 +00002780 ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON)))) )
Alexandre Julliard8da12c41999-01-17 16:55:11 +00002781
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002782 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
Alexandre Julliard8da12c41999-01-17 16:55:11 +00002783
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002784 } /* switch(msg.message) - mouse */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002785 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002786 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002787 {
Alexandre Julliarde2abbb11995-03-19 17:39:39 +00002788 fRemove = TRUE; /* Keyboard messages are always removed */
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002789 switch(msg.message)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002790 {
2791 case WM_KEYDOWN:
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002792 switch(msg.wParam)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002793 {
2794 case VK_HOME:
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002795 case VK_END:
Vincent Béron9a624912002-05-31 23:06:46 +00002796 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
Rein Klazes80c924f1999-12-12 19:40:46 +00002797 NO_SELECTED_ITEM, FALSE, 0 );
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002798 /* fall through */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002799 case VK_UP:
Vincent Béron9a624912002-05-31 23:06:46 +00002800 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002801 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002802 break;
2803
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002804 case VK_DOWN: /* If on menu bar, pull-down the menu */
2805
Gerard Patel3e629742000-01-17 22:22:16 +00002806 menu = MENU_GetMenu( mt.hCurrentMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002807 if (!(menu->wFlags & MF_POPUP))
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002808 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002809 else /* otherwise try to move selection */
2810 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002811 break;
2812
2813 case VK_LEFT:
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002814 MENU_KeyLeft( &mt, wFlags );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002815 break;
Vincent Béron9a624912002-05-31 23:06:46 +00002816
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002817 case VK_RIGHT:
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002818 MENU_KeyRight( &mt, wFlags );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002819 break;
Vincent Béron9a624912002-05-31 23:06:46 +00002820
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002821 case VK_ESCAPE:
Ulrich Czekalla18ce3882001-05-18 23:20:20 +00002822 fEndMenu = MENU_KeyEscape(&mt, wFlags);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002823 break;
2824
Ulrich Czekalla33026a22000-02-26 19:13:44 +00002825 case VK_F1:
2826 {
2827 HELPINFO hi;
2828 hi.cbSize = sizeof(HELPINFO);
2829 hi.iContextType = HELPINFO_MENUITEM;
Vincent Béron9a624912002-05-31 23:06:46 +00002830 if (menu->FocusedItem == NO_SELECTED_ITEM)
Ulrich Czekalla33026a22000-02-26 19:13:44 +00002831 hi.iCtrlId = 0;
Vincent Béron9a624912002-05-31 23:06:46 +00002832 else
2833 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
Ulrich Czekalla33026a22000-02-26 19:13:44 +00002834 hi.hItemHandle = hmenu;
2835 hi.dwContextId = menu->dwContextHelpID;
2836 hi.MousePos = msg.pt;
2837 SendMessageA(hwnd, WM_HELP, 0, (LPARAM)&hi);
2838 break;
2839 }
2840
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002841 default:
2842 break;
2843 }
2844 break; /* WM_KEYDOWN */
2845
2846 case WM_SYSKEYDOWN:
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002847 switch(msg.wParam)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002848 {
2849 case VK_MENU:
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002850 fEndMenu = TRUE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002851 break;
Vincent Béron9a624912002-05-31 23:06:46 +00002852
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002853 }
2854 break; /* WM_SYSKEYDOWN */
2855
2856 case WM_CHAR:
2857 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002858 UINT pos;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002859
Norman Stevensa83d0651998-10-12 07:25:35 +00002860 if (msg.wParam == '\r' || msg.wParam == ' ')
2861 {
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002862 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
Karl Lessard13409b31999-09-28 16:24:58 +00002863 fEndMenu = (executedMenuId != -1);
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00002864
Norman Stevensa83d0651998-10-12 07:25:35 +00002865 break;
2866 }
2867
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002868 /* Hack to avoid control chars. */
2869 /* We will find a better way real soon... */
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002870 if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002871
Vincent Béron9a624912002-05-31 23:06:46 +00002872 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
Stephane Lussierb3a99de1999-02-09 15:35:12 +00002873 LOWORD(msg.wParam), FALSE );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002874 if (pos == (UINT)-2) fEndMenu = TRUE;
2875 else if (pos == (UINT)-1) MessageBeep(0);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002876 else
2877 {
Rein Klazes80c924f1999-12-12 19:40:46 +00002878 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
2879 TRUE, 0 );
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00002880 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
Karl Lessard13409b31999-09-28 16:24:58 +00002881 fEndMenu = (executedMenuId != -1);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002882 }
Vincent Béron9a624912002-05-31 23:06:46 +00002883 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002884 break;
2885 } /* switch(msg.message) - kbd */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002886 }
2887 else
2888 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002889 DispatchMessageA( &msg );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002890 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002891
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002892 if (!fEndMenu) fRemove = TRUE;
2893
2894 /* finally remove message from the queue */
2895
2896 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
Alexandre Julliarda3960291999-02-26 11:11:13 +00002897 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002898 else mt.trackFlags &= ~TF_SKIPREMOVE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002899 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +00002900
Alexandre Julliarda9e8f592002-10-12 01:24:37 +00002901 MENU_SetCapture(0); /* release the capture */
Juergen Schmiedc77fd5b1999-04-21 14:27:37 +00002902
Guy Albertellif12b70a2000-05-11 00:06:11 +00002903 /* If dropdown is still painted and the close box is clicked on
2904 then the menu will be destroyed as part of the DispatchMessage above.
2905 This will then invalidate the menu handle in mt.hTopMenu. We should
2906 check for this first. */
2907 if( IsMenu( mt.hTopMenu ) )
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00002908 {
Guy Albertellif12b70a2000-05-11 00:06:11 +00002909 menu = MENU_GetMenu( mt.hTopMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00002910
Guy Albertellif12b70a2000-05-11 00:06:11 +00002911 if( IsWindow( mt.hOwnerWnd ) )
2912 {
2913 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
2914
Vincent Béron9a624912002-05-31 23:06:46 +00002915 if (menu && menu->wFlags & MF_POPUP)
Guy Albertellif12b70a2000-05-11 00:06:11 +00002916 {
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00002917 DestroyWindow( menu->hWnd );
2918 menu->hWnd = 0;
Guy Albertellif12b70a2000-05-11 00:06:11 +00002919 }
2920 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2921 SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
2922 }
2923
2924 /* Reset the variable for hiding menu */
2925 if( menu ) menu->bTimeToHide = FALSE;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00002926 }
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00002927
Juergen Schmied371c4201999-10-13 12:27:44 +00002928 /* The return value is only used by TrackPopupMenu */
2929 return ((executedMenuId != -1) ? executedMenuId : 0);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002930}
2931
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002932/***********************************************************************
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002933 * MENU_InitTracking
2934 */
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002935static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002936{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002937 TRACE("hwnd=%p hmenu=%p\n", hWnd, hMenu);
Juergen Schmied78513941999-04-18 14:40:32 +00002938
Alexandre Julliarda3960291999-02-26 11:11:13 +00002939 HideCaret(0);
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002940
2941 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2942 if (!(wFlags & TPM_NONOTIFY))
2943 SendMessageA( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
2944
Alexandre Julliardd23a82b2001-09-19 20:37:04 +00002945 SendMessageA( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002946
2947 if (!(wFlags & TPM_NONOTIFY))
Gerard Patelcf2ff272001-03-14 17:24:59 +00002948 {
2949 POPUPMENU *menu;
Alexandre Julliard7ef66af2002-11-22 04:47:10 +00002950 SendMessageA( hWnd, WM_INITMENU, (WPARAM)hMenu, 0 );
Gerard Patelcf2ff272001-03-14 17:24:59 +00002951 if ((menu = MENU_GetMenu( hMenu )) && (!menu->Height))
2952 { /* app changed/recreated menu bar entries in WM_INITMENU
2953 Recalculate menu sizes else clicks will not work */
Gerard Patel326b2802001-07-17 00:43:22 +00002954 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
2955 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
Vincent Béron9a624912002-05-31 23:06:46 +00002956
Gerard Patelcf2ff272001-03-14 17:24:59 +00002957 }
2958 }
Juergen Schmied78513941999-04-18 14:40:32 +00002959 return TRUE;
2960}
2961/***********************************************************************
2962 * MENU_ExitTracking
2963 */
2964static BOOL MENU_ExitTracking(HWND hWnd)
2965{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002966 TRACE("hwnd=%p\n", hWnd);
Juergen Schmied78513941999-04-18 14:40:32 +00002967
2968 SendMessageA( hWnd, WM_EXITMENULOOP, 0, 0 );
2969 ShowCaret(0);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002970 return TRUE;
2971}
2972
2973/***********************************************************************
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002974 * MENU_TrackMouseMenuBar
2975 *
2976 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2977 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002978void MENU_TrackMouseMenuBar( HWND hWnd, INT ht, POINT pt )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002979{
Alexandre Julliardde424282001-08-10 22:51:42 +00002980 HMENU hMenu = (ht == HTSYSMENU) ? get_win_sys_menu( hWnd ) : GetMenu( hWnd );
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002981 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002982
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002983 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y);
Juergen Schmied78513941999-04-18 14:40:32 +00002984
Alexandre Julliarda3960291999-02-26 11:11:13 +00002985 if (IsMenu(hMenu))
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002986 {
Alexandre Julliardb662e112001-10-16 21:52:26 +00002987 /* map point to parent client coordinates */
2988 HWND parent = GetAncestor( hWnd, GA_PARENT );
2989 if (parent != GetDesktopWindow()) ScreenToClient( parent, &pt );
2990
Abey Georgeb59d4bc1999-09-22 15:10:42 +00002991 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
2992 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
Juergen Schmied78513941999-04-18 14:40:32 +00002993 MENU_ExitTracking(hWnd);
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002994 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00002995}
2996
2997
2998/***********************************************************************
2999 * MENU_TrackKbdMenuBar
3000 *
3001 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3002 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003003void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, INT vkey)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003004{
Alexandre Julliardde424282001-08-10 22:51:42 +00003005 UINT uItem = NO_SELECTED_ITEM;
3006 HMENU hTrackMenu;
3007 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00003008
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003009 /* find window that has a menu */
Alexandre Julliardde424282001-08-10 22:51:42 +00003010
3011 while (GetWindowLongA( hwnd, GWL_STYLE ) & WS_CHILD)
3012 if (!(hwnd = GetParent( hwnd ))) return;
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00003013
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003014 /* check if we have to track a system menu */
Alexandre Julliardde424282001-08-10 22:51:42 +00003015
3016 hTrackMenu = GetMenu( hwnd );
3017 if (!hTrackMenu || IsIconic(hwnd) || vkey == VK_SPACE )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003018 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003019 if (!(GetWindowLongA( hwnd, GWL_STYLE ) & WS_SYSMENU)) return;
Alexandre Julliardcfd60b22003-05-12 03:19:03 +00003020 if (GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_MANAGED) return;
Alexandre Julliardde424282001-08-10 22:51:42 +00003021 hTrackMenu = get_win_sys_menu( hwnd );
3022 uItem = 0;
3023 wParam |= HTSYSMENU; /* prevent item lookup */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003024 }
Alexandre Julliardc981d0b1996-03-31 16:40:13 +00003025
Alexandre Julliardde424282001-08-10 22:51:42 +00003026 if (!IsMenu( hTrackMenu )) return;
3027
3028 MENU_InitTracking( hwnd, hTrackMenu, FALSE, wFlags );
3029
3030 if( vkey && vkey != VK_SPACE )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003031 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003032 uItem = MENU_FindItemByKey( hwnd, hTrackMenu, vkey, (wParam & HTSYSMENU) );
3033 if( uItem >= (UINT)(-2) )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003034 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003035 if( uItem == (UINT)(-1) ) MessageBeep(0);
3036 hTrackMenu = 0;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003037 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003038 }
Alexandre Julliardde424282001-08-10 22:51:42 +00003039
3040 if( hTrackMenu )
3041 {
3042 MENU_SelectItem( hwnd, hTrackMenu, uItem, TRUE, 0 );
3043
3044 if( uItem == NO_SELECTED_ITEM )
3045 MENU_MoveSelection( hwnd, hTrackMenu, ITEM_NEXT );
3046 else if( vkey )
3047 PostMessageA( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
3048
3049 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
3050 }
3051 MENU_ExitTracking( hwnd );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003052}
3053
3054
3055/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003056 * TrackPopupMenu (USER32.@)
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00003057 *
3058 * Like the win32 API, the function return the command ID only if the
3059 * flag TPM_RETURNCMD is on.
3060 *
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00003061 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003062BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3063 INT nReserved, HWND hWnd, const RECT *lpRect )
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00003064{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003065 BOOL ret = FALSE;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003066
Abey Georgeb59d4bc1999-09-22 15:10:42 +00003067 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3068
3069 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3070 if (!(wFlags & TPM_NONOTIFY))
Alexandre Julliard7ef66af2002-11-22 04:47:10 +00003071 SendMessageA( hWnd, WM_INITMENUPOPUP, (WPARAM)hMenu, 0);
Abey Georgeb59d4bc1999-09-22 15:10:42 +00003072
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00003073 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
Francois Boisvert85dd9fc1999-02-17 12:50:11 +00003074 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
Juergen Schmied78513941999-04-18 14:40:32 +00003075 MENU_ExitTracking(hWnd);
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00003076
3077 if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
3078 ret = 1;
3079
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003080 return ret;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00003081}
3082
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003083/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003084 * TrackPopupMenuEx (USER32.@)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003085 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003086BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3087 HWND hWnd, LPTPMPARAMS lpTpm )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003088{
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003089 FIXME("not fully implemented\n" );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003090 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003091 lpTpm ? &lpTpm->rcExclude : NULL );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00003092}
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00003093
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003094/***********************************************************************
3095 * PopupMenuWndProc
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003096 *
3097 * NOTE: Windows has totally different (and undocumented) popup wndproc.
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003098 */
Alexandre Julliard91222da2000-12-10 23:01:33 +00003099static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
3100{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003101 TRACE("hwnd=%p msg=0x%04x wp=0x%04x lp=0x%08lx\n", hwnd, message, wParam, lParam);
Juergen Schmied78513941999-04-18 14:40:32 +00003102
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003103 switch(message)
3104 {
3105 case WM_CREATE:
3106 {
Alexandre Julliard91222da2000-12-10 23:01:33 +00003107 CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
3108 SetWindowLongW( hwnd, 0, (LONG)cs->lpCreateParams );
3109 return 0;
Alexandre Julliardf7207251994-07-23 07:57:48 +00003110 }
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003111
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003112 case WM_MOUSEACTIVATE: /* We don't want to be activated */
Alexandre Julliard91222da2000-12-10 23:01:33 +00003113 return MA_NOACTIVATE;
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003114
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003115 case WM_PAINT:
3116 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003117 PAINTSTRUCT ps;
3118 BeginPaint( hwnd, &ps );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003119 MENU_DrawPopupMenu( hwnd, ps.hdc,
Alexandre Julliarda3960291999-02-26 11:11:13 +00003120 (HMENU)GetWindowLongA( hwnd, 0 ) );
3121 EndPaint( hwnd, &ps );
Alexandre Julliard91222da2000-12-10 23:01:33 +00003122 return 0;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003123 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003124 case WM_ERASEBKGND:
Alexandre Julliard91222da2000-12-10 23:01:33 +00003125 return 1;
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003126
Alexandre Julliard2ace16a1996-04-28 15:09:19 +00003127 case WM_DESTROY:
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003128 /* zero out global pointer in case resident popup window was destroyed. */
3129 if (hwnd == top_popup) top_popup = 0;
3130 break;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003131
3132 case WM_SHOWWINDOW:
3133
3134 if( wParam )
3135 {
Alexandre Julliard91222da2000-12-10 23:01:33 +00003136 if (!GetWindowLongW( hwnd, 0 )) ERR("no menu to display\n");
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003137 }
3138 else
Alexandre Julliard91222da2000-12-10 23:01:33 +00003139 SetWindowLongW( hwnd, 0, 0 );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003140 break;
3141
3142 case MM_SETMENUHANDLE:
Alexandre Julliard91222da2000-12-10 23:01:33 +00003143 SetWindowLongW( hwnd, 0, wParam );
Alexandre Julliard2ace16a1996-04-28 15:09:19 +00003144 break;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003145
3146 case MM_GETMENUHANDLE:
Alexandre Julliard91222da2000-12-10 23:01:33 +00003147 return GetWindowLongW( hwnd, 0 );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003148
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003149 default:
Alexandre Julliard91222da2000-12-10 23:01:33 +00003150 return DefWindowProcW( hwnd, message, wParam, lParam );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003151 }
Alexandre Julliard91222da2000-12-10 23:01:33 +00003152 return 0;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003153}
3154
3155
Alexandre Julliard8d24ae61994-04-05 21:42:43 +00003156/***********************************************************************
Alexandre Julliard2d159fb1994-07-15 16:04:31 +00003157 * MENU_GetMenuBarHeight
3158 *
3159 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3160 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003161UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3162 INT orgX, INT orgY )
Alexandre Julliard2d159fb1994-07-15 16:04:31 +00003163{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003164 HDC hdc;
3165 RECT rectBar;
Alexandre Julliard2d159fb1994-07-15 16:04:31 +00003166 LPPOPUPMENU lppop;
3167
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003168 TRACE("HWND %p, width %d, at (%d, %d).\n", hwnd, menubarWidth, orgX, orgY );
Juergen Schmied78513941999-04-18 14:40:32 +00003169
Alexandre Julliardde424282001-08-10 22:51:42 +00003170 if (!(lppop = MENU_GetMenu( GetMenu(hwnd) ))) return 0;
Juergen Schmied78513941999-04-18 14:40:32 +00003171
Alexandre Julliarda3960291999-02-26 11:11:13 +00003172 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
Vincent Béron9a624912002-05-31 23:06:46 +00003173 SelectObject( hdc, hMenuFont);
Marcus Meissnerddca3151999-05-22 11:33:23 +00003174 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
Vincent Béron9a624912002-05-31 23:06:46 +00003175 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003176 ReleaseDC( hwnd, hdc );
Alexandre Julliardde424282001-08-10 22:51:42 +00003177 return lppop->Height;
Alexandre Julliard2d159fb1994-07-15 16:04:31 +00003178}
3179
3180
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003181/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003182 * ChangeMenuA (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003183 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003184BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3185 UINT id, UINT flags )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003186{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003187 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003188 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003189 id, data );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003190 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3191 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003192 id, data );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003193 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003194 flags & MF_BYPOSITION ? pos : id,
3195 flags & ~MF_REMOVE );
3196 /* Default: MF_INSERT */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003197 return InsertMenuA( hMenu, pos, flags, id, data );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003198}
3199
3200
3201/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003202 * ChangeMenuW (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003203 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003204BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3205 UINT id, UINT flags )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003206{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003207 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003208 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003209 id, data );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003210 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3211 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003212 id, data );
Alexandre Julliarda3960291999-02-26 11:11:13 +00003213 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003214 flags & MF_BYPOSITION ? pos : id,
3215 flags & ~MF_REMOVE );
3216 /* Default: MF_INSERT */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003217 return InsertMenuW( hMenu, pos, flags, id, data );
Alexandre Julliard401710d1993-09-04 10:09:32 +00003218}
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003219
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003220
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003221/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003222 * CheckMenuItem (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003223 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003224DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003225{
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003226 MENUITEM *item;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003227 DWORD ret;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003228
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003229 TRACE("menu=%p id=%04x flags=%04x\n", hMenu, id, flags );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003230 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003231 ret = item->fState & MF_CHECKED;
3232 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3233 else item->fState &= ~MF_CHECKED;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003234 return ret;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003235}
3236
3237
3238/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003239 * EnableMenuItem (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003240 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003241UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003242{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003243 UINT oldflags;
Alexandre Julliardf90efa91998-06-14 15:24:15 +00003244 MENUITEM *item;
Pascal Lessardd814bb61999-07-31 13:02:02 +00003245 POPUPMENU *menu;
Alexandre Julliardf7207251994-07-23 07:57:48 +00003246
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003247 TRACE("(%p, %04x, %04x) !\n", hMenu, wItemID, wFlags);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003248
Pascal Lessardd814bb61999-07-31 13:02:02 +00003249 /* Get the Popupmenu to access the owner menu */
Vincent Béron9a624912002-05-31 23:06:46 +00003250 if (!(menu = MENU_GetMenu(hMenu)))
Pascal Lessardd814bb61999-07-31 13:02:02 +00003251 return (UINT)-1;
3252
Alexandre Julliardf90efa91998-06-14 15:24:15 +00003253 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
Alexandre Julliarda3960291999-02-26 11:11:13 +00003254 return (UINT)-1;
Alexandre Julliardf90efa91998-06-14 15:24:15 +00003255
3256 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3257 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
Pascal Lessardd814bb61999-07-31 13:02:02 +00003258
3259 /* In win95 if the close item in the system menu change update the close button */
Vincent Béron9a624912002-05-31 23:06:46 +00003260 if (TWEAK_WineLook == WIN95_LOOK)
Pascal Lessardd814bb61999-07-31 13:02:02 +00003261 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3262 {
3263 if (menu->hSysMenuOwner != 0)
3264 {
3265 POPUPMENU* parentMenu;
3266
3267 /* Get the parent menu to access*/
Vincent Béron9a624912002-05-31 23:06:46 +00003268 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
Pascal Lessardd814bb61999-07-31 13:02:02 +00003269 return (UINT)-1;
3270
3271 /* Refresh the frame to reflect the change*/
3272 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
Stephane Lussiera833f631999-08-21 14:46:06 +00003273 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
Pascal Lessardd814bb61999-07-31 13:02:02 +00003274 }
3275 }
Vincent Béron9a624912002-05-31 23:06:46 +00003276
Alexandre Julliardf90efa91998-06-14 15:24:15 +00003277 return oldflags;
Alexandre Julliard1f579291994-05-25 16:25:21 +00003278}
3279
3280
Alexandre Julliardaf0bae51995-10-03 17:06:08 +00003281/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003282 * GetMenuStringA (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003283 */
Vincent Béron9a624912002-05-31 23:06:46 +00003284INT WINAPI GetMenuStringA(
Marcus Meissnercb3c7bf2000-01-08 22:25:57 +00003285 HMENU hMenu, /* [in] menuhandle */
3286 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3287 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3288 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
Vincent Béron9a624912002-05-31 23:06:46 +00003289 UINT wFlags /* [in] MF_ flags */
Marcus Meissnercb3c7bf2000-01-08 22:25:57 +00003290) {
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003291 MENUITEM *item;
Alexandre Julliardaf0bae51995-10-03 17:06:08 +00003292
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003293 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003294 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003295 if (!IS_STRING_ITEM(item->fType)) return 0;
Aric Stewartc946b1c2000-10-24 21:28:19 +00003296 if (!str || !nMaxSiz) return strlenW(item->text);
Marcus Meissnercb3c7bf2000-01-08 22:25:57 +00003297 str[0] = '\0';
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00003298 if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
3299 str[nMaxSiz-1] = 0;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003300 TRACE("returning '%s'\n", str );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003301 return strlen(str);
Alexandre Julliard1f579291994-05-25 16:25:21 +00003302}
3303
3304
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003305/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003306 * GetMenuStringW (USER32.@)
Alexandre Julliard1f579291994-05-25 16:25:21 +00003307 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003308INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3309 LPWSTR str, INT nMaxSiz, UINT wFlags )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003310{
3311 MENUITEM *item;
3312
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003313 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003314 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003315 if (!IS_STRING_ITEM(item->fType)) return 0;
Aric Stewartc946b1c2000-10-24 21:28:19 +00003316 if (!str || !nMaxSiz) return strlenW(item->text);
Marcus Meissnercb3c7bf2000-01-08 22:25:57 +00003317 str[0] = '\0';
Aric Stewartc946b1c2000-10-24 21:28:19 +00003318 lstrcpynW( str, item->text, nMaxSiz );
3319 return strlenW(str);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003320}
3321
3322
3323/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003324 * HiliteMenuItem (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003325 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003326BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3327 UINT wHilite )
Alexandre Julliard1f579291994-05-25 16:25:21 +00003328{
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003329 LPPOPUPMENU menu;
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003330 TRACE("(%p, %p, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite);
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003331 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
Gerard Patel3e629742000-01-17 22:22:16 +00003332 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003333 if (menu->FocusedItem == wItemID) return TRUE;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00003334 MENU_HideSubPopups( hWnd, hMenu, FALSE );
Rein Klazes80c924f1999-12-12 19:40:46 +00003335 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003336 return TRUE;
Alexandre Julliard1f579291994-05-25 16:25:21 +00003337}
3338
3339
3340/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003341 * GetMenuState (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003342 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003343UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
Alexandre Julliard7cc9c0c1994-06-15 15:45:11 +00003344{
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003345 MENUITEM *item;
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003346 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu, wItemID, wFlags);
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003347 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
Alexandre Julliard03468f71998-02-15 19:40:49 +00003348 debug_print_menuitem (" item: ", item, "");
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003349 if (item->fType & MF_POPUP)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003350 {
Gerard Patel3e629742000-01-17 22:22:16 +00003351 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003352 if (!menu) return -1;
Alexandre Julliard829fe321998-07-26 14:27:39 +00003353 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003354 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00003355 else
Alexandre Julliard491502b1997-11-01 19:08:16 +00003356 {
Alexandre Julliard829fe321998-07-26 14:27:39 +00003357 /* We used to (from way back then) mask the result to 0xff. */
3358 /* I don't know why and it seems wrong as the documented */
3359 /* return flag MF_SEPARATOR is outside that mask. */
3360 return (item->fType | item->fState);
Alexandre Julliard491502b1997-11-01 19:08:16 +00003361 }
Alexandre Julliard7cc9c0c1994-06-15 15:45:11 +00003362}
3363
3364
3365/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003366 * GetMenuItemCount (USER32.@)
Alexandre Julliard1f579291994-05-25 16:25:21 +00003367 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003368INT WINAPI GetMenuItemCount( HMENU hMenu )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003369{
Gerard Patel3e629742000-01-17 22:22:16 +00003370 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3371 if (!menu) return -1;
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003372 TRACE("(%p) returning %d\n", hMenu, menu->nItems );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003373 return menu->nItems;
3374}
3375
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003376
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003377/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003378 * GetMenuItemID (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003379 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003380UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003381{
Juergen Schmiedc77fd5b1999-04-21 14:27:37 +00003382 MENUITEM * lpmi;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003383
Mike McCormack34329cf2001-07-10 19:06:12 +00003384 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return -1;
Juergen Schmiedc77fd5b1999-04-21 14:27:37 +00003385 if (lpmi->fType & MF_POPUP) return -1;
3386 return lpmi->wID;
3387
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003388}
3389
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003390
3391/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003392 * InsertMenuW (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003393 */
Aric Stewartc946b1c2000-10-24 21:28:19 +00003394BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +00003395 UINT_PTR id, LPCWSTR str )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003396{
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003397 MENUITEM *item;
Alexandre Julliarde2991ea1995-07-29 13:09:43 +00003398
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003399 if (IS_STRING_ITEM(flags) && str)
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003400 TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %s\n",
3401 hMenu, pos, flags, id, debugstr_w(str) );
3402 else TRACE("hMenu %p, pos %d, flags %08x, id %04x, str %08lx (not a string)\n",
3403 hMenu, pos, flags, id, (DWORD)str );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003404
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003405 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003406
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003407 if (!(MENU_SetItemData( item, flags, id, str )))
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003408 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003409 RemoveMenu( hMenu, pos, flags );
Alexandre Julliarde2abbb11995-03-19 17:39:39 +00003410 return FALSE;
3411 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003412
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003413 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
Alexandre Julliard7ef66af2002-11-22 04:47:10 +00003414 (MENU_GetMenu((HMENU)id))->wFlags |= MF_POPUP;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003415
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003416 item->hCheckBit = item->hUnCheckBit = 0;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003417 return TRUE;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003418}
3419
3420
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003421/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003422 * InsertMenuA (USER32.@)
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003423 */
Aric Stewartc946b1c2000-10-24 21:28:19 +00003424BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +00003425 UINT_PTR id, LPCSTR str )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003426{
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00003427 BOOL ret = FALSE;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003428
3429 if (IS_STRING_ITEM(flags) && str)
3430 {
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00003431 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3432 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3433 if (newstr)
3434 {
3435 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3436 ret = InsertMenuW( hMenu, pos, flags, id, newstr );
3437 HeapFree( GetProcessHeap(), 0, newstr );
3438 }
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003439 return ret;
3440 }
Aric Stewartc946b1c2000-10-24 21:28:19 +00003441 else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003442}
3443
3444
3445/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003446 * AppendMenuA (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003447 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003448BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +00003449 UINT_PTR id, LPCSTR data )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003450{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003451 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003452}
3453
3454
3455/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003456 * AppendMenuW (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003457 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003458BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +00003459 UINT_PTR id, LPCWSTR data )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003460{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003461 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003462}
3463
3464
3465/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003466 * RemoveMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003467 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003468BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003469{
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003470 LPPOPUPMENU menu;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003471 MENUITEM *item;
3472
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003473 TRACE("(menu=%p pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003474 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
Gerard Patel3e629742000-01-17 22:22:16 +00003475 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
Vincent Béron9a624912002-05-31 23:06:46 +00003476
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003477 /* Remove item */
3478
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003479 MENU_FreeItemData( item );
3480
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003481 if (--menu->nItems == 0)
3482 {
Alexandre Julliardda2892c2001-02-23 01:13:42 +00003483 HeapFree( GetProcessHeap(), 0, menu->items );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003484 menu->items = NULL;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003485 }
3486 else
3487 {
3488 while(nPos < menu->nItems)
3489 {
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003490 *item = *(item+1);
3491 item++;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003492 nPos++;
3493 }
Alexandre Julliardda2892c2001-02-23 01:13:42 +00003494 menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003495 menu->nItems * sizeof(MENUITEM) );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003496 }
3497 return TRUE;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003498}
3499
3500
3501/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003502 * DeleteMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003503 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003504BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003505{
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003506 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3507 if (!item) return FALSE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00003508 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003509 /* nPos is now the position of the item */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003510 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003511 return TRUE;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003512}
3513
3514
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003515/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003516 * ModifyMenuW (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003517 */
Aric Stewartc946b1c2000-10-24 21:28:19 +00003518BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +00003519 UINT_PTR id, LPCWSTR str )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003520{
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003521 MENUITEM *item;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003522
3523 if (IS_STRING_ITEM(flags))
Alexandre Julliarde2991ea1995-07-29 13:09:43 +00003524 {
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003525 TRACE("%p %d %04x %04x %s\n", hMenu, pos, flags, id, debugstr_w(str) );
Alexandre Julliarde2991ea1995-07-29 13:09:43 +00003526 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003527 else
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003528 {
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003529 TRACE("%p %d %04x %04x %08lx\n", hMenu, pos, flags, id, (DWORD)str );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003530 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003531
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003532 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003533 return MENU_SetItemData( item, flags, id, str );
3534}
3535
3536
3537/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003538 * ModifyMenuA (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003539 */
Aric Stewartc946b1c2000-10-24 21:28:19 +00003540BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +00003541 UINT_PTR id, LPCSTR str )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003542{
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00003543 BOOL ret = FALSE;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003544
3545 if (IS_STRING_ITEM(flags) && str)
3546 {
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00003547 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3548 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3549 if (newstr)
3550 {
3551 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3552 ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
3553 HeapFree( GetProcessHeap(), 0, newstr );
3554 }
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003555 return ret;
3556 }
Aric Stewartc946b1c2000-10-24 21:28:19 +00003557 else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003558}
3559
3560
3561/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003562 * CreatePopupMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003563 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003564HMENU WINAPI CreatePopupMenu(void)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003565{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003566 HMENU hmenu;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003567 POPUPMENU *menu;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003568
Alexandre Julliarda3960291999-02-26 11:11:13 +00003569 if (!(hmenu = CreateMenu())) return 0;
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003570 menu = MENU_GetMenu( hmenu );
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003571 menu->wFlags |= MF_POPUP;
Pascal Lessard2eb0a301999-09-03 16:38:52 +00003572 menu->bTimeToHide = FALSE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003573 return hmenu;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00003574}
3575
3576
3577/**********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00003578 * GetMenuCheckMarkDimensions (USER.417)
3579 * GetMenuCheckMarkDimensions (USER32.@)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00003580 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003581DWORD WINAPI GetMenuCheckMarkDimensions(void)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00003582{
Alexandre Julliardc1d35cc2001-01-24 19:47:57 +00003583 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003584}
3585
3586
3587/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003588 * SetMenuItemBitmaps (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003589 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003590BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3591 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003592{
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003593 MENUITEM *item;
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003594 TRACE("(%p, %04x, %04x, %p, %p)\n",
3595 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003596 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003597
3598 if (!hNewCheck && !hNewUnCheck)
3599 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003600 item->fState &= ~MF_USECHECKBITMAPS;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003601 }
3602 else /* Install new bitmaps */
3603 {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003604 item->hCheckBit = hNewCheck;
3605 item->hUnCheckBit = hNewUnCheck;
3606 item->fState |= MF_USECHECKBITMAPS;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003607 }
3608 return TRUE;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003609}
3610
3611
3612/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003613 * CreateMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003614 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003615HMENU WINAPI CreateMenu(void)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003616{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003617 HMENU hMenu;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003618 LPPOPUPMENU menu;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003619 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
Alexandre Julliarde2abbb11995-03-19 17:39:39 +00003620 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
Juergen Schmied78513941999-04-18 14:40:32 +00003621
3622 ZeroMemory(menu, sizeof(POPUPMENU));
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003623 menu->wMagic = MENU_MAGIC;
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003624 menu->FocusedItem = NO_SELECTED_ITEM;
Pascal Lessard2eb0a301999-09-03 16:38:52 +00003625 menu->bTimeToHide = FALSE;
Juergen Schmied78513941999-04-18 14:40:32 +00003626
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003627 TRACE("return %p\n", hMenu );
Pascal Lessardd9ab1f31999-05-29 10:56:43 +00003628
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003629 return hMenu;
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003630}
3631
3632
3633/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003634 * DestroyMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003635 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003636BOOL WINAPI DestroyMenu( HMENU hMenu )
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003637{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003638 TRACE("(%p)\n", hMenu);
Alexandre Julliard1285c2f1996-05-06 16:06:24 +00003639
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003640 /* Silently ignore attempts to destroy default system popup */
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003641
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003642 if (hMenu && hMenu != MENU_DefSysPopup)
Alexandre Julliardff8331e1995-09-18 11:19:54 +00003643 {
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003644 LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003645
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003646 if (!lppop) return FALSE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003647
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003648 lppop->wMagic = 0; /* Mark it as destroyed */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003649
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003650 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd)
Gerard Patel8f79fdc2001-05-14 19:20:13 +00003651 {
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003652 DestroyWindow( lppop->hWnd );
Gerard Patel8f79fdc2001-05-14 19:20:13 +00003653 lppop->hWnd = 0;
3654 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003655
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003656 if (lppop->items) /* recursively destroy submenus */
Francois Boisvert3a3cd9f1999-03-28 12:42:52 +00003657 {
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003658 int i;
3659 MENUITEM *item = lppop->items;
3660 for (i = lppop->nItems; i > 0; i--, item++)
3661 {
3662 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3663 MENU_FreeItemData( item );
3664 }
3665 HeapFree( GetProcessHeap(), 0, lppop->items );
Francois Boisvert3a3cd9f1999-03-28 12:42:52 +00003666 }
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003667 USER_HEAP_FREE( hMenu );
Alexandre Julliardff8331e1995-09-18 11:19:54 +00003668 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003669 return (hMenu != MENU_DefSysPopup);
Alexandre Julliard5f721f81994-01-04 20:14:34 +00003670}
3671
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003672
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003673/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003674 * GetSystemMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003675 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003676HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003677{
Alexandre Julliardb7258be1995-09-01 15:57:28 +00003678 WND *wndPtr = WIN_FindWndPtr( hWnd );
Eric Pouech562309a1999-08-21 12:59:44 +00003679 HMENU retvalue = 0;
Alexandre Julliardb7258be1995-09-01 15:57:28 +00003680
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003681 if (wndPtr)
Alexandre Julliard1285c2f1996-05-06 16:06:24 +00003682 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003683 if( wndPtr->hSysMenu )
3684 {
3685 if( bRevert )
3686 {
Vincent Béron9a624912002-05-31 23:06:46 +00003687 DestroyMenu(wndPtr->hSysMenu);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003688 wndPtr->hSysMenu = 0;
3689 }
3690 else
3691 {
Gerard Patel3e629742000-01-17 22:22:16 +00003692 POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
Vincent Béron9a624912002-05-31 23:06:46 +00003693 if( menu )
Eric Pouech562309a1999-08-21 12:59:44 +00003694 {
3695 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3696 menu->items[0].hSubMenu = MENU_CopySysPopup();
3697 }
Vincent Béron9a624912002-05-31 23:06:46 +00003698 else
Eric Pouech562309a1999-08-21 12:59:44 +00003699 {
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003700 WARN("Current sys-menu (%p) of wnd %p is broken\n",
Eric Pouech562309a1999-08-21 12:59:44 +00003701 wndPtr->hSysMenu, hWnd);
3702 wndPtr->hSysMenu = 0;
3703 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003704 }
3705 }
3706
3707 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
Alexandre Julliarda3960291999-02-26 11:11:13 +00003708 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003709
3710 if( wndPtr->hSysMenu )
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00003711 {
Eric Pouech562309a1999-08-21 12:59:44 +00003712 POPUPMENU *menu;
Dmitry Timoshkov56a19922001-07-02 01:21:26 +00003713 retvalue = GetSubMenu(wndPtr->hSysMenu, 0);
Pascal Lessardd814bb61999-07-31 13:02:02 +00003714
3715 /* Store the dummy sysmenu handle to facilitate the refresh */
3716 /* of the close button if the SC_CLOSE item change */
Gerard Patel3e629742000-01-17 22:22:16 +00003717 menu = MENU_GetMenu(retvalue);
3718 if ( menu )
Eric Pouech562309a1999-08-21 12:59:44 +00003719 menu->hSysMenuOwner = wndPtr->hSysMenu;
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00003720 }
3721 WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard1285c2f1996-05-06 16:06:24 +00003722 }
Francois Jacques20af4c32000-06-18 17:17:54 +00003723 return bRevert ? 0 : retvalue;
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003724}
3725
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003726
3727/*******************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003728 * SetSystemMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003729 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003730BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
Alexandre Julliard1d62f6b1994-05-04 19:15:00 +00003731{
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003732 WND *wndPtr = WIN_FindWndPtr(hwnd);
Alexandre Julliard1d62f6b1994-05-04 19:15:00 +00003733
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003734 if (wndPtr)
3735 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003736 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003737 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00003738 WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003739 return TRUE;
3740 }
3741 return FALSE;
Alexandre Julliard1d62f6b1994-05-04 19:15:00 +00003742}
3743
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003744
3745/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003746 * GetMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003747 */
Vincent Béron9a624912002-05-31 23:06:46 +00003748HMENU WINAPI GetMenu( HWND hWnd )
Dmitry Timoshkovfbb2c9b2000-09-09 19:38:34 +00003749{
Alexandre Julliardde424282001-08-10 22:51:42 +00003750 HMENU retvalue = (HMENU)GetWindowLongA( hWnd, GWL_ID );
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003751 TRACE("for %p returning %p\n", hWnd, retvalue);
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00003752 return retvalue;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003753}
3754
3755
3756/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003757 * SetMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003758 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003759BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003760{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003761 TRACE("(%p, %p);\n", hWnd, hMenu);
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003762
Richard Cohen56753621999-09-19 14:08:13 +00003763 if (hMenu && !IsMenu(hMenu))
3764 {
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003765 WARN("hMenu %p is not a menu handle\n", hMenu);
Alexandre Julliardde424282001-08-10 22:51:42 +00003766 return FALSE;
Richard Cohen56753621999-09-19 14:08:13 +00003767 }
Alexandre Julliardde424282001-08-10 22:51:42 +00003768 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
Richard Cohen56753621999-09-19 14:08:13 +00003769
Alexandre Julliardf44bbb82001-09-14 00:24:39 +00003770 hWnd = WIN_GetFullHandle( hWnd );
Alexandre Julliarda9e8f592002-10-12 01:24:37 +00003771 if (GetCapture() == hWnd) MENU_SetCapture(0); /* release the capture */
Alexandre Julliardde424282001-08-10 22:51:42 +00003772
3773 if (hMenu != 0)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003774 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003775 LPPOPUPMENU lpmenu;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003776
Alexandre Julliardde424282001-08-10 22:51:42 +00003777 if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003778
Alexandre Julliardde424282001-08-10 22:51:42 +00003779 lpmenu->hWnd = hWnd;
3780 lpmenu->Height = 0; /* Make sure we recalculate the size */
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00003781 }
Alexandre Julliarda8a422f2002-11-22 20:43:01 +00003782 SetWindowLongA( hWnd, GWL_ID, (LONG_PTR)hMenu );
Alexandre Julliardde424282001-08-10 22:51:42 +00003783
3784 if (IsWindowVisible(hWnd))
3785 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3786 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3787 return TRUE;
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003788}
3789
3790
Alexandre Julliardd18872d1994-05-11 12:18:19 +00003791
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003792/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003793 * GetSubMenu (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003794 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003795HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003796{
Juergen Schmiedc77fd5b1999-04-21 14:27:37 +00003797 MENUITEM * lpmi;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003798
Juergen Schmiedc77fd5b1999-04-21 14:27:37 +00003799 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
3800 if (!(lpmi->fType & MF_POPUP)) return 0;
3801 return lpmi->hSubMenu;
Alexandre Julliarddba420a1994-02-02 06:48:31 +00003802}
3803
3804
3805/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003806 * DrawMenuBar (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003807 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003808BOOL WINAPI DrawMenuBar( HWND hWnd )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003809{
3810 LPPOPUPMENU lppop;
Alexandre Julliardde424282001-08-10 22:51:42 +00003811 HMENU hMenu = GetMenu(hWnd);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003812
Alexandre Julliardde424282001-08-10 22:51:42 +00003813 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
3814 if (!hMenu || !(lppop = MENU_GetMenu( hMenu ))) return FALSE;
3815
3816 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
3817 lppop->hwndOwner = hWnd;
3818 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3819 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3820 return TRUE;
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003821}
3822
Eric Pouecha862f682001-02-26 22:33:29 +00003823/***********************************************************************
3824 * DrawMenuBarTemp (USER32.@)
Andreas Mohr69249672001-12-26 20:34:12 +00003825 *
3826 * UNDOCUMENTED !!
Vincent Béron9a624912002-05-31 23:06:46 +00003827 *
Andreas Mohr69249672001-12-26 20:34:12 +00003828 * called by W98SE desk.cpl Control Panel Applet
3829 *
3830 * Not 100% sure about the param names, but close.
Eric Pouecha862f682001-02-26 22:33:29 +00003831 */
Robert Shearman9caa6ba2003-01-14 19:28:49 +00003832DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont)
Eric Pouecha862f682001-02-26 22:33:29 +00003833{
Robert Shearman9caa6ba2003-01-14 19:28:49 +00003834 LPPOPUPMENU lppop;
3835 UINT i,retvalue;
3836 HFONT hfontOld = 0;
3837
3838 if (!hMenu)
3839 hMenu = GetMenu(hwnd);
3840
3841 if (!hFont)
3842 hFont = hMenuFont;
3843
3844 lppop = MENU_GetMenu( hMenu );
3845 if (lppop == NULL || lprect == NULL)
3846 {
3847 retvalue = GetSystemMetrics(SM_CYMENU);
3848 goto END;
3849 }
3850
3851 TRACE("(%p, %p, %p, %p, %p)\n", hwnd, hDC, lprect, hMenu, hFont);
3852
3853 hfontOld = SelectObject( hDC, hFont);
3854
3855 if (lppop->Height == 0)
3856 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
3857
3858 lprect->bottom = lprect->top + lppop->Height;
3859
3860 FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
3861
3862 if (TWEAK_WineLook == WIN31_LOOK)
3863 {
3864 SelectObject( hDC, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
3865 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
3866 LineTo( hDC, lprect->right, lprect->bottom );
3867 }
3868 else
3869 {
3870 SelectObject( hDC, SYSCOLOR_GetPen(COLOR_3DFACE));
3871 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
3872 LineTo( hDC, lprect->right, lprect->bottom );
3873 }
3874
3875 if (lppop->nItems == 0)
3876 {
3877 retvalue = GetSystemMetrics(SM_CYMENU);
3878 goto END;
3879 }
3880
3881 for (i = 0; i < lppop->nItems; i++)
3882 {
3883 MENU_DrawMenuItem( hwnd, hMenu, hwnd,
3884 hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
3885 }
3886 retvalue = lppop->Height;
3887
3888END:
3889 if (hfontOld) SelectObject (hDC, hfontOld);
3890 return retvalue;
Eric Pouecha862f682001-02-26 22:33:29 +00003891}
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003892
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003893/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00003894 * EndMenu (USER.187)
3895 * EndMenu (USER32.@)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003896 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003897void WINAPI EndMenu(void)
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003898{
Rob Farnumb2007932000-05-23 23:34:17 +00003899 /* if we are in the menu code, and it is active */
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003900 if (!fEndMenu && top_popup)
Rob Farnumb2007932000-05-23 23:34:17 +00003901 {
3902 /* terminate the menu handling code */
3903 fEndMenu = TRUE;
Alex Korobka4f1ac051999-03-28 09:37:57 +00003904
Rob Farnumb2007932000-05-23 23:34:17 +00003905 /* needs to be posted to wakeup the internal menu handler */
3906 /* which will now terminate the menu, in the event that */
3907 /* the main window was minimized, or lost focus, so we */
3908 /* don't end up with an orphaned menu */
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00003909 PostMessageA( top_popup, WM_CANCELMODE, 0, 0);
Rob Farnumb2007932000-05-23 23:34:17 +00003910 }
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003911}
3912
3913
3914/***********************************************************************
3915 * LookupMenuHandle (USER.217)
3916 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003917HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003918{
Alexandre Julliarda8a422f2002-11-22 20:43:01 +00003919 HMENU hmenu32 = HMENU_32(hmenu);
Alexandre Julliarda3960291999-02-26 11:11:13 +00003920 UINT id32 = id;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003921 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
Alexandre Julliarda8a422f2002-11-22 20:43:01 +00003922 else return HMENU_16(hmenu32);
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003923}
3924
3925
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003926/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003927 * LoadMenu (USER.150)
Alexandre Julliard594997c1995-04-30 10:05:20 +00003928 */
Alexandre Julliardac7efef2000-11-27 21:54:01 +00003929HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
Alexandre Julliard594997c1995-04-30 10:05:20 +00003930{
Alexandre Julliard18f92e71996-07-17 20:02:21 +00003931 HRSRC16 hRsrc;
3932 HGLOBAL16 handle;
3933 HMENU16 hMenu;
Alexandre Julliard594997c1995-04-30 10:05:20 +00003934
Alexandre Julliard7ef66af2002-11-22 04:47:10 +00003935 if (HIWORD(name) && name[0] == '#') name = (LPCSTR)atoi( name + 1 );
Alexandre Julliard594997c1995-04-30 10:05:20 +00003936 if (!name) return 0;
Alexandre Julliardac7efef2000-11-27 21:54:01 +00003937
Alexandre Julliard3db94ef1997-09-28 17:43:24 +00003938 instance = GetExePtr( instance );
Alexandre Julliardac7efef2000-11-27 21:54:01 +00003939 if (!(hRsrc = FindResource16( instance, name, RT_MENUA ))) return 0;
Alexandre Julliard18f92e71996-07-17 20:02:21 +00003940 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
3941 hMenu = LoadMenuIndirect16(LockResource16(handle));
3942 FreeResource16( handle );
Alexandre Julliard594997c1995-04-30 10:05:20 +00003943 return hMenu;
3944}
3945
3946
Alexandre Julliard18f92e71996-07-17 20:02:21 +00003947/*****************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003948 * LoadMenuA (USER32.@)
Alexandre Julliard18f92e71996-07-17 20:02:21 +00003949 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003950HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
Alexandre Julliard18f92e71996-07-17 20:02:21 +00003951{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003952 HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
Alexandre Julliard18f92e71996-07-17 20:02:21 +00003953 if (!hrsrc) return 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +00003954 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
Alexandre Julliard18f92e71996-07-17 20:02:21 +00003955}
3956
3957
3958/*****************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00003959 * LoadMenuW (USER32.@)
Alexandre Julliard18f92e71996-07-17 20:02:21 +00003960 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003961HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
Alexandre Julliard18f92e71996-07-17 20:02:21 +00003962{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003963 HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
Alexandre Julliard18f92e71996-07-17 20:02:21 +00003964 if (!hrsrc) return 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +00003965 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
Alexandre Julliard18f92e71996-07-17 20:02:21 +00003966}
3967
3968
Alexandre Julliard594997c1995-04-30 10:05:20 +00003969/**********************************************************************
Patrik Stridvall15a3b742001-04-27 18:03:51 +00003970 * LoadMenuIndirect (USER.220)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00003971 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00003972HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00003973{
Alexandre Julliarda8a422f2002-11-22 20:43:01 +00003974 HMENU hMenu;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003975 WORD version, offset;
3976 LPCSTR p = (LPCSTR)template;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00003977
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003978 TRACE("(%p)\n", template );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003979 version = GET_WORD(p);
3980 p += sizeof(WORD);
3981 if (version)
3982 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003983 WARN("version must be 0 for Win16\n" );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003984 return 0;
3985 }
3986 offset = GET_WORD(p);
3987 p += sizeof(WORD) + offset;
Alexandre Julliarda3960291999-02-26 11:11:13 +00003988 if (!(hMenu = CreateMenu())) return 0;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003989 if (!MENU_ParseResource( p, hMenu, FALSE ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003990 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003991 DestroyMenu( hMenu );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00003992 return 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00003993 }
Alexandre Julliarda8a422f2002-11-22 20:43:01 +00003994 return HMENU_16(hMenu);
Alexandre Julliardcdd09231994-01-12 11:12:51 +00003995}
3996
Alexandre Julliard3f2abfa1994-08-16 15:43:11 +00003997
Alexandre Julliard7cc9c0c1994-06-15 15:45:11 +00003998/**********************************************************************
Tony Lambregts6dc4cb42003-03-04 02:14:58 +00003999 * LoadMenuIndirectW (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004000 */
Tony Lambregts6dc4cb42003-03-04 02:14:58 +00004001HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004002{
Alexandre Julliarda8a422f2002-11-22 20:43:01 +00004003 HMENU hMenu;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004004 WORD version, offset;
4005 LPCSTR p = (LPCSTR)template;
4006
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004007 version = GET_WORD(p);
4008 p += sizeof(WORD);
Andreas Mohr8578f012002-08-28 23:31:56 +00004009 TRACE("%p, ver %d\n", template, version );
Alexandre Julliard641ee761997-08-04 16:34:36 +00004010 switch (version)
Andreas Mohr8578f012002-08-28 23:31:56 +00004011 {
Chris Morgan36595822002-11-06 21:57:50 +00004012 case 0: /* standard format is version of 0 */
Alexandre Julliard641ee761997-08-04 16:34:36 +00004013 offset = GET_WORD(p);
4014 p += sizeof(WORD) + offset;
Alexandre Julliarda3960291999-02-26 11:11:13 +00004015 if (!(hMenu = CreateMenu())) return 0;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004016 if (!MENU_ParseResource( p, hMenu, TRUE ))
4017 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00004018 DestroyMenu( hMenu );
Alexandre Julliard641ee761997-08-04 16:34:36 +00004019 return 0;
4020 }
4021 return hMenu;
Chris Morgan36595822002-11-06 21:57:50 +00004022 case 1: /* extended format is version of 1 */
Alexandre Julliard641ee761997-08-04 16:34:36 +00004023 offset = GET_WORD(p);
4024 p += sizeof(WORD) + offset;
Alexandre Julliarda3960291999-02-26 11:11:13 +00004025 if (!(hMenu = CreateMenu())) return 0;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004026 if (!MENUEX_ParseResource( p, hMenu))
4027 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00004028 DestroyMenu( hMenu );
Alexandre Julliard641ee761997-08-04 16:34:36 +00004029 return 0;
4030 }
4031 return hMenu;
4032 default:
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00004033 ERR("version %d not supported.\n", version);
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004034 return 0;
Andreas Mohr8578f012002-08-28 23:31:56 +00004035 }
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004036}
4037
4038
4039/**********************************************************************
Tony Lambregts6dc4cb42003-03-04 02:14:58 +00004040 * LoadMenuIndirectA (USER32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004041 */
Tony Lambregts6dc4cb42003-03-04 02:14:58 +00004042HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004043{
Tony Lambregts6dc4cb42003-03-04 02:14:58 +00004044 return LoadMenuIndirectW( template );
Alexandre Julliard2d93d001996-05-21 15:01:41 +00004045}
4046
4047
4048/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004049 * IsMenu (USER32.@)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004050 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004051BOOL WINAPI IsMenu(HMENU hmenu)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004052{
Alexandre Julliarde60ccd12001-05-11 20:05:42 +00004053 LPPOPUPMENU menu = MENU_GetMenu(hmenu);
4054 return menu != NULL;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004055}
4056
Alexandre Julliard641ee761997-08-04 16:34:36 +00004057/**********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00004058 * GetMenuItemInfo_common
Alexandre Julliard641ee761997-08-04 16:34:36 +00004059 */
4060
Juergen Schmied78513941999-04-18 14:40:32 +00004061static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
Aric Stewartc946b1c2000-10-24 21:28:19 +00004062 LPMENUITEMINFOW lpmii, BOOL unicode)
Alexandre Julliard641ee761997-08-04 16:34:36 +00004063{
Juergen Schmied78513941999-04-18 14:40:32 +00004064 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4065
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00004066 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
Juergen Schmied78513941999-04-18 14:40:32 +00004067
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004068 if (!menu)
4069 return FALSE;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004070
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004071 if (lpmii->fMask & MIIM_TYPE) {
4072 lpmii->fType = menu->fType;
4073 switch (MENU_ITEM_TYPE(menu->fType)) {
Huw D M Davies2d6eaba2000-03-24 19:48:53 +00004074 case MF_STRING:
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00004075 break; /* will be done below */
Huw D M Davies2d6eaba2000-03-24 19:48:53 +00004076 case MF_OWNERDRAW:
4077 case MF_BITMAP:
4078 lpmii->dwTypeData = menu->text;
4079 /* fall through */
4080 default:
4081 lpmii->cch = 0;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004082 }
Alexandre Julliard641ee761997-08-04 16:34:36 +00004083 }
Juergen Schmied78513941999-04-18 14:40:32 +00004084
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00004085 /* copy the text string */
4086 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)) &&
4087 (MENU_ITEM_TYPE(menu->fType) == MF_STRING) && menu->text)
4088 {
4089 int len;
4090 if (unicode)
4091 {
4092 len = strlenW(menu->text);
4093 if(lpmii->dwTypeData && lpmii->cch)
4094 lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4095 }
4096 else
4097 {
4098 len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL, 0, NULL, NULL );
4099 if(lpmii->dwTypeData && lpmii->cch)
4100 if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4101 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4102 ((LPSTR)lpmii->dwTypeData)[lpmii->cch-1] = 0;
4103 }
4104 /* if we've copied a substring we return its length */
4105 if(lpmii->dwTypeData && lpmii->cch)
4106 {
4107 if (lpmii->cch <= len) lpmii->cch--;
4108 }
4109 else /* return length of string */
4110 lpmii->cch = len;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004111 }
Juergen Schmied78513941999-04-18 14:40:32 +00004112
4113 if (lpmii->fMask & MIIM_FTYPE)
4114 lpmii->fType = menu->fType;
4115
4116 if (lpmii->fMask & MIIM_BITMAP)
4117 lpmii->hbmpItem = menu->hbmpItem;
4118
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004119 if (lpmii->fMask & MIIM_STATE)
4120 lpmii->fState = menu->fState;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004121
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004122 if (lpmii->fMask & MIIM_ID)
4123 lpmii->wID = menu->wID;
4124
4125 if (lpmii->fMask & MIIM_SUBMENU)
4126 lpmii->hSubMenu = menu->hSubMenu;
4127
4128 if (lpmii->fMask & MIIM_CHECKMARKS) {
4129 lpmii->hbmpChecked = menu->hCheckBit;
4130 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4131 }
4132 if (lpmii->fMask & MIIM_DATA)
4133 lpmii->dwItemData = menu->dwItemData;
Alexandre Julliard641ee761997-08-04 16:34:36 +00004134
4135 return TRUE;
4136}
4137
4138/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004139 * GetMenuItemInfoA (USER32.@)
Alexandre Julliard641ee761997-08-04 16:34:36 +00004140 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004141BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4142 LPMENUITEMINFOA lpmii)
Alexandre Julliard641ee761997-08-04 16:34:36 +00004143{
Vincent Béron9a624912002-05-31 23:06:46 +00004144 return GetMenuItemInfo_common (hmenu, item, bypos,
Aric Stewartc946b1c2000-10-24 21:28:19 +00004145 (LPMENUITEMINFOW)lpmii, FALSE);
Alexandre Julliard641ee761997-08-04 16:34:36 +00004146}
4147
4148/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004149 * GetMenuItemInfoW (USER32.@)
Alexandre Julliard641ee761997-08-04 16:34:36 +00004150 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004151BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4152 LPMENUITEMINFOW lpmii)
Alexandre Julliard641ee761997-08-04 16:34:36 +00004153{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004154 return GetMenuItemInfo_common (hmenu, item, bypos,
Aric Stewartc946b1c2000-10-24 21:28:19 +00004155 lpmii, TRUE);
Alexandre Julliard641ee761997-08-04 16:34:36 +00004156}
4157
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00004158
4159/* set a menu item text from a ASCII or Unicode string */
4160inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
4161{
4162 if (!text)
4163 {
4164 menu->text = NULL;
4165 menu->fType |= MF_SEPARATOR;
4166 }
4167 else if (unicode)
4168 {
4169 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
4170 strcpyW( menu->text, text );
4171 }
4172 else
4173 {
4174 LPCSTR str = (LPCSTR)text;
4175 int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
4176 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
4177 MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
4178 }
4179}
4180
4181
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004182/**********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00004183 * SetMenuItemInfo_common
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004184 */
4185
Alexandre Julliarda3960291999-02-26 11:11:13 +00004186static BOOL SetMenuItemInfo_common(MENUITEM * menu,
Aric Stewartc946b1c2000-10-24 21:28:19 +00004187 const MENUITEMINFOW *lpmii,
Alexandre Julliarda3960291999-02-26 11:11:13 +00004188 BOOL unicode)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004189{
4190 if (!menu) return FALSE;
4191
Gerard Patel2482ef32001-03-19 19:16:21 +00004192 debug_print_menuitem("MENU_SetItemInfo_common from: ", menu, "");
4193
Juergen Schmied78513941999-04-18 14:40:32 +00004194 if (lpmii->fMask & MIIM_TYPE ) {
Andreas Mohr8578f012002-08-28 23:31:56 +00004195 /* Get rid of old string. */
4196 if (IS_STRING_ITEM(menu->fType) && menu->text) {
Alexandre Julliardda2892c2001-02-23 01:13:42 +00004197 HeapFree(GetProcessHeap(), 0, menu->text);
Juergen Schmied78513941999-04-18 14:40:32 +00004198 menu->text = NULL;
4199 }
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004200
Vincent Béron9a624912002-05-31 23:06:46 +00004201 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
Juergen Schmied78513941999-04-18 14:40:32 +00004202 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4203 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
Paul Millar39da2221999-04-11 12:08:42 +00004204
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004205 menu->text = lpmii->dwTypeData;
Juergen Schmied78513941999-04-18 14:40:32 +00004206
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00004207 if (IS_STRING_ITEM(menu->fType))
4208 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004209 }
Juergen Schmied78513941999-04-18 14:40:32 +00004210
4211 if (lpmii->fMask & MIIM_FTYPE ) {
4212 /* free the string when the type is changing */
4213 if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
Alexandre Julliardda2892c2001-02-23 01:13:42 +00004214 HeapFree(GetProcessHeap(), 0, menu->text);
Juergen Schmied78513941999-04-18 14:40:32 +00004215 menu->text = NULL;
4216 }
4217 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4218 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
Gerard Patel2482ef32001-03-19 19:16:21 +00004219 if ( IS_STRING_ITEM(menu->fType) && !menu->text )
4220 menu->fType |= MF_SEPARATOR;
Juergen Schmied78513941999-04-18 14:40:32 +00004221 }
4222
4223 if (lpmii->fMask & MIIM_STRING ) {
4224 /* free the string when used */
Andreas Mohr8578f012002-08-28 23:31:56 +00004225 if (IS_STRING_ITEM(menu->fType) && menu->text) {
Alexandre Julliardda2892c2001-02-23 01:13:42 +00004226 HeapFree(GetProcessHeap(), 0, menu->text);
Alexandre Julliardef06b4a2001-07-22 23:08:10 +00004227 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
Juergen Schmied78513941999-04-18 14:40:32 +00004228 }
4229 }
4230
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004231 if (lpmii->fMask & MIIM_STATE)
Juergen Schmied466a6521999-05-02 11:21:08 +00004232 {
Dimitrie O. Paun693cca52002-01-29 03:12:19 +00004233 /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004234 menu->fState = lpmii->fState;
Juergen Schmied466a6521999-05-02 11:21:08 +00004235 }
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004236
4237 if (lpmii->fMask & MIIM_ID)
4238 menu->wID = lpmii->wID;
4239
Alexandre Julliarda0d77311998-09-13 16:32:00 +00004240 if (lpmii->fMask & MIIM_SUBMENU) {
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004241 menu->hSubMenu = lpmii->hSubMenu;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00004242 if (menu->hSubMenu) {
Michael Stefaniuc61d92562002-10-19 00:52:55 +00004243 POPUPMENU *subMenu = MENU_GetMenu(menu->hSubMenu);
Gerard Patel3e629742000-01-17 22:22:16 +00004244 if (subMenu) {
Alexandre Julliarda0d77311998-09-13 16:32:00 +00004245 subMenu->wFlags |= MF_POPUP;
4246 menu->fType |= MF_POPUP;
4247 }
4248 else
4249 /* FIXME: Return an error ? */
4250 menu->fType &= ~MF_POPUP;
4251 }
4252 else
4253 menu->fType &= ~MF_POPUP;
4254 }
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004255
4256 if (lpmii->fMask & MIIM_CHECKMARKS)
4257 {
Susan Farleyf1d467a2000-05-12 21:59:31 +00004258 if (lpmii->fType & MFT_RADIOCHECK)
4259 menu->fType |= MFT_RADIOCHECK;
4260
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004261 menu->hCheckBit = lpmii->hbmpChecked;
4262 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4263 }
4264 if (lpmii->fMask & MIIM_DATA)
4265 menu->dwItemData = lpmii->dwItemData;
4266
Gerard Patel2482ef32001-03-19 19:16:21 +00004267 debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004268 return TRUE;
4269}
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004270
4271/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004272 * SetMenuItemInfoA (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004273 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004274BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
Vincent Béron9a624912002-05-31 23:06:46 +00004275 const MENUITEMINFOA *lpmii)
Alexandre Julliard7cc9c0c1994-06-15 15:45:11 +00004276{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004277 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
Aric Stewartc946b1c2000-10-24 21:28:19 +00004278 (const MENUITEMINFOW *)lpmii, FALSE);
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004279}
4280
4281/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004282 * SetMenuItemInfoW (USER32.@)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004283 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004284BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4285 const MENUITEMINFOW *lpmii)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004286{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004287 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
Aric Stewartc946b1c2000-10-24 21:28:19 +00004288 lpmii, TRUE);
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004289}
4290
4291/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004292 * SetMenuDefaultItem (USER32.@)
Juergen Schmied466a6521999-05-02 11:21:08 +00004293 *
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004294 */
Juergen Schmied466a6521999-05-02 11:21:08 +00004295BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004296{
Juergen Schmied466a6521999-05-02 11:21:08 +00004297 UINT i;
4298 POPUPMENU *menu;
4299 MENUITEM *item;
Vincent Béron9a624912002-05-31 23:06:46 +00004300
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00004301 TRACE("(%p,%d,%d)\n", hmenu, uItem, bypos);
Alexandre Julliarda845b881998-06-01 10:44:35 +00004302
Gerard Patel3e629742000-01-17 22:22:16 +00004303 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
Alexandre Julliarda845b881998-06-01 10:44:35 +00004304
Juergen Schmied466a6521999-05-02 11:21:08 +00004305 /* reset all default-item flags */
4306 item = menu->items;
4307 for (i = 0; i < menu->nItems; i++, item++)
4308 {
4309 item->fState &= ~MFS_DEFAULT;
4310 }
Vincent Béron9a624912002-05-31 23:06:46 +00004311
Juergen Schmied466a6521999-05-02 11:21:08 +00004312 /* no default item */
4313 if ( -1 == uItem)
4314 {
4315 return TRUE;
4316 }
Alexandre Julliarda845b881998-06-01 10:44:35 +00004317
Juergen Schmied466a6521999-05-02 11:21:08 +00004318 item = menu->items;
4319 if ( bypos )
4320 {
4321 if ( uItem >= menu->nItems ) return FALSE;
4322 item[uItem].fState |= MFS_DEFAULT;
4323 return TRUE;
4324 }
4325 else
4326 {
4327 for (i = 0; i < menu->nItems; i++, item++)
4328 {
4329 if (item->wID == uItem)
4330 {
4331 item->fState |= MFS_DEFAULT;
4332 return TRUE;
4333 }
4334 }
Vincent Béron9a624912002-05-31 23:06:46 +00004335
Juergen Schmied466a6521999-05-02 11:21:08 +00004336 }
4337 return FALSE;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004338}
4339
Alexandre Julliarda845b881998-06-01 10:44:35 +00004340/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004341 * GetMenuDefaultItem (USER32.@)
Alexandre Julliarda845b881998-06-01 10:44:35 +00004342 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004343UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
Alexandre Julliarda845b881998-06-01 10:44:35 +00004344{
Juergen Schmied466a6521999-05-02 11:21:08 +00004345 POPUPMENU *menu;
4346 MENUITEM * item;
4347 UINT i = 0;
Alexandre Julliarda845b881998-06-01 10:44:35 +00004348
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00004349 TRACE("(%p,%d,%d)\n", hmenu, bypos, flags);
Alexandre Julliarda845b881998-06-01 10:44:35 +00004350
Gerard Patel3e629742000-01-17 22:22:16 +00004351 if (!(menu = MENU_GetMenu(hmenu))) return -1;
Juergen Schmied466a6521999-05-02 11:21:08 +00004352
4353 /* find default item */
4354 item = menu->items;
Vincent Béron9a624912002-05-31 23:06:46 +00004355
Juergen Schmied49251861999-05-13 18:42:03 +00004356 /* empty menu */
4357 if (! item) return -1;
Vincent Béron9a624912002-05-31 23:06:46 +00004358
Juergen Schmied466a6521999-05-02 11:21:08 +00004359 while ( !( item->fState & MFS_DEFAULT ) )
4360 {
4361 i++; item++;
4362 if (i >= menu->nItems ) return -1;
4363 }
Vincent Béron9a624912002-05-31 23:06:46 +00004364
Juergen Schmied466a6521999-05-02 11:21:08 +00004365 /* default: don't return disabled items */
4366 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4367
4368 /* search rekursiv when needed */
4369 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4370 {
4371 UINT ret;
4372 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4373 if ( -1 != ret ) return ret;
4374
4375 /* when item not found in submenu, return the popup item */
4376 }
4377 return ( bypos ) ? i : item->wID;
4378
Alexandre Julliarda845b881998-06-01 10:44:35 +00004379}
4380
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004381
4382/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004383 * InsertMenuItemA (USER32.@)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004384 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004385BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4386 const MENUITEMINFOA *lpmii)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004387{
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00004388 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
Aric Stewartc946b1c2000-10-24 21:28:19 +00004389 return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)lpmii, FALSE);
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004390}
4391
4392
4393/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004394 * InsertMenuItemW (USER32.@)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004395 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004396BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4397 const MENUITEMINFOW *lpmii)
Alexandre Julliard670cdc41997-08-24 16:00:30 +00004398{
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00004399 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
Aric Stewartc946b1c2000-10-24 21:28:19 +00004400 return SetMenuItemInfo_common(item, lpmii, TRUE);
Alexandre Julliard7cc9c0c1994-06-15 15:45:11 +00004401}
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004402
4403/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004404 * CheckMenuRadioItem (USER32.@)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004405 */
4406
Alexandre Julliarda3960291999-02-26 11:11:13 +00004407BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4408 UINT first, UINT last, UINT check,
4409 UINT bypos)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004410{
4411 MENUITEM *mifirst, *milast, *micheck;
Alexandre Julliarda3960291999-02-26 11:11:13 +00004412 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004413
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00004414 TRACE("%p: %d-%d, check %d, bypos=%d\n", hMenu, first, last, check, bypos);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004415
4416 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4417 milast = MENU_FindItem (&mlast, &last, bypos);
4418 micheck = MENU_FindItem (&mcheck, &check, bypos);
4419
4420 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4421 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4422 micheck > milast || micheck < mifirst)
4423 return FALSE;
4424
4425 while (mifirst <= milast)
4426 {
4427 if (mifirst == micheck)
4428 {
4429 mifirst->fType |= MFT_RADIOCHECK;
4430 mifirst->fState |= MFS_CHECKED;
4431 } else {
4432 mifirst->fType &= ~MFT_RADIOCHECK;
4433 mifirst->fState &= ~MFS_CHECKED;
4434 }
4435 mifirst++;
4436 }
4437
4438 return TRUE;
4439}
4440
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004441
4442/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004443 * GetMenuItemRect (USER32.@)
Pascal Lessard47274231999-02-13 12:21:46 +00004444 *
Vincent Béron9a624912002-05-31 23:06:46 +00004445 * ATTENTION: Here, the returned values in rect are the screen
4446 * coordinates of the item just like if the menu was
Pascal Lessard47274231999-02-13 12:21:46 +00004447 * always on the upper left side of the application.
Vincent Béron9a624912002-05-31 23:06:46 +00004448 *
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004449 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004450BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4451 LPRECT rect)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004452{
Pascal Lessard47274231999-02-13 12:21:46 +00004453 POPUPMENU *itemMenu;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004454 MENUITEM *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00004455 HWND referenceHwnd;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004456
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00004457 TRACE("(%p,%p,%d,%p)\n", hwnd, hMenu, uItem, rect);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004458
4459 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
Pascal Lessard47274231999-02-13 12:21:46 +00004460 referenceHwnd = hwnd;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004461
Pascal Lessard47274231999-02-13 12:21:46 +00004462 if(!hwnd)
4463 {
Gerard Patel3e629742000-01-17 22:22:16 +00004464 itemMenu = MENU_GetMenu(hMenu);
Vincent Béron9a624912002-05-31 23:06:46 +00004465 if (itemMenu == NULL)
Pascal Lessard47274231999-02-13 12:21:46 +00004466 return FALSE;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004467
Marcus Meissnerac593bb1999-03-17 15:18:28 +00004468 if(itemMenu->hWnd == 0)
Pascal Lessard47274231999-02-13 12:21:46 +00004469 return FALSE;
4470 referenceHwnd = itemMenu->hWnd;
4471 }
4472
Vincent Béron9a624912002-05-31 23:06:46 +00004473 if ((rect == NULL) || (item == NULL))
Pascal Lessard47274231999-02-13 12:21:46 +00004474 return FALSE;
4475
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004476 *rect = item->rect;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004477
Alexandre Julliarda3960291999-02-26 11:11:13 +00004478 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
Pascal Lessard47274231999-02-13 12:21:46 +00004479
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00004480 return TRUE;
4481}
4482
Paul Quinn1beaae51998-12-15 15:38:36 +00004483
4484/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004485 * SetMenuInfo (USER32.@)
Juergen Schmied78513941999-04-18 14:40:32 +00004486 *
4487 * FIXME
4488 * MIM_APPLYTOSUBMENUS
4489 * actually use the items to draw the menu
4490 */
4491BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4492{
4493 POPUPMENU *menu;
4494
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00004495 TRACE("(%p %p)\n", hMenu, lpmi);
Juergen Schmied78513941999-04-18 14:40:32 +00004496
Gerard Patel3e629742000-01-17 22:22:16 +00004497 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
Juergen Schmied78513941999-04-18 14:40:32 +00004498 {
4499
4500 if (lpmi->fMask & MIM_BACKGROUND)
4501 menu->hbrBack = lpmi->hbrBack;
4502
4503 if (lpmi->fMask & MIM_HELPID)
4504 menu->dwContextHelpID = lpmi->dwContextHelpID;
4505
4506 if (lpmi->fMask & MIM_MAXHEIGHT)
4507 menu->cyMax = lpmi->cyMax;
4508
4509 if (lpmi->fMask & MIM_MENUDATA)
4510 menu->dwMenuData = lpmi->dwMenuData;
4511
4512 if (lpmi->fMask & MIM_STYLE)
4513 menu->dwStyle = lpmi->dwStyle;
4514
4515 return TRUE;
4516 }
4517 return FALSE;
4518}
4519
4520/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004521 * GetMenuInfo (USER32.@)
Juergen Schmied78513941999-04-18 14:40:32 +00004522 *
4523 * NOTES
4524 * win98/NT5.0
4525 *
4526 */
4527BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4528{ POPUPMENU *menu;
4529
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00004530 TRACE("(%p %p)\n", hMenu, lpmi);
Juergen Schmied78513941999-04-18 14:40:32 +00004531
Gerard Patel3e629742000-01-17 22:22:16 +00004532 if (lpmi && (menu = MENU_GetMenu(hMenu)))
Juergen Schmied78513941999-04-18 14:40:32 +00004533 {
4534
4535 if (lpmi->fMask & MIM_BACKGROUND)
4536 lpmi->hbrBack = menu->hbrBack;
4537
4538 if (lpmi->fMask & MIM_HELPID)
4539 lpmi->dwContextHelpID = menu->dwContextHelpID;
4540
4541 if (lpmi->fMask & MIM_MAXHEIGHT)
4542 lpmi->cyMax = menu->cyMax;
4543
4544 if (lpmi->fMask & MIM_MENUDATA)
4545 lpmi->dwMenuData = menu->dwMenuData;
4546
4547 if (lpmi->fMask & MIM_STYLE)
4548 lpmi->dwStyle = menu->dwStyle;
4549
4550 return TRUE;
4551 }
4552 return FALSE;
4553}
4554
Paul Quinn1beaae51998-12-15 15:38:36 +00004555
4556/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004557 * SetMenuContextHelpId (USER32.@)
Paul Quinn1beaae51998-12-15 15:38:36 +00004558 */
Juergen Schmied78513941999-04-18 14:40:32 +00004559BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
Paul Quinn1beaae51998-12-15 15:38:36 +00004560{
Juergen Schmied78513941999-04-18 14:40:32 +00004561 LPPOPUPMENU menu;
4562
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00004563 TRACE("(%p 0x%08lx)\n", hMenu, dwContextHelpID);
Juergen Schmied78513941999-04-18 14:40:32 +00004564
Gerard Patel3e629742000-01-17 22:22:16 +00004565 if ((menu = MENU_GetMenu(hMenu)))
Juergen Schmied78513941999-04-18 14:40:32 +00004566 {
4567 menu->dwContextHelpID = dwContextHelpID;
4568 return TRUE;
4569 }
4570 return FALSE;
Paul Quinn1beaae51998-12-15 15:38:36 +00004571}
4572
Vincent Béron9a624912002-05-31 23:06:46 +00004573
Paul Quinn1beaae51998-12-15 15:38:36 +00004574/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004575 * GetMenuContextHelpId (USER32.@)
Paul Quinn1beaae51998-12-15 15:38:36 +00004576 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00004577DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
Paul Quinn1beaae51998-12-15 15:38:36 +00004578{
Juergen Schmied78513941999-04-18 14:40:32 +00004579 LPPOPUPMENU menu;
4580
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00004581 TRACE("(%p)\n", hMenu);
Juergen Schmied78513941999-04-18 14:40:32 +00004582
Gerard Patel3e629742000-01-17 22:22:16 +00004583 if ((menu = MENU_GetMenu(hMenu)))
Juergen Schmied78513941999-04-18 14:40:32 +00004584 {
4585 return menu->dwContextHelpID;
4586 }
4587 return 0;
Paul Quinn1beaae51998-12-15 15:38:36 +00004588}
Eric Pouech0c62bf01999-09-13 15:11:35 +00004589
4590/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004591 * MenuItemFromPoint (USER32.@)
Eric Pouech0c62bf01999-09-13 15:11:35 +00004592 */
4593UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4594{
Uwe Bonnes6815f3a2002-03-28 22:04:45 +00004595 POPUPMENU *menu = MENU_GetMenu(hMenu);
4596 UINT pos;
4597 MENUITEM *item;
4598
4599 /*FIXME: Do we have to handle hWnd here? */
4600 item = MENU_FindItemByCoords(menu, ptScreen, &pos);
4601
4602 return pos;
Eric Pouech0c62bf01999-09-13 15:11:35 +00004603}
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004604
4605
4606/**********************************************************************
4607 * translate_accelerator
4608 */
4609static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4610 BYTE fVirt, WORD key, WORD cmd )
4611{
4612 UINT mesg = 0;
4613
4614 if (wParam != key) return FALSE;
4615
4616 if (message == WM_CHAR)
4617 {
4618 if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
4619 {
4620 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
4621 goto found;
4622 }
4623 }
4624 else
4625 {
4626 if(fVirt & FVIRTKEY)
4627 {
4628 INT mask = 0;
4629 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
4630 wParam, 0xff & HIWORD(lParam));
4631 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
4632 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
4633 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
4634 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
4635 TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
4636 }
4637 else
4638 {
4639 if (!(lParam & 0x01000000)) /* no special_key */
4640 {
4641 if ((fVirt & FALT) && (lParam & 0x20000000))
4642 { /* ^^ ALT pressed */
4643 TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
4644 goto found;
4645 }
4646 }
4647 }
4648 }
4649 return FALSE;
4650
4651 found:
4652 if (message == WM_KEYUP || message == WM_SYSKEYUP)
4653 mesg = 1;
4654 else if (GetCapture())
4655 mesg = 2;
4656 else if (!IsWindowEnabled(hWnd))
4657 mesg = 3;
4658 else
4659 {
4660 HMENU hMenu, hSubMenu, hSysMenu;
4661 UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004662
Alexandre Julliardde424282001-08-10 22:51:42 +00004663 hMenu = (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
4664 hSysMenu = get_win_sys_menu( hWnd );
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004665
4666 /* find menu item and ask application to initialize it */
4667 /* 1. in the system menu */
4668 hSubMenu = hSysMenu;
4669 nPos = cmd;
4670 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4671 {
4672 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
4673 if(hSubMenu != hSysMenu)
4674 {
4675 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00004676 TRACE_(accel)("hSysMenu = %p, hSubMenu = %p, nPos = %d\n", hSysMenu, hSubMenu, nPos);
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004677 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
4678 }
4679 uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
4680 }
4681 else /* 2. in the window's menu */
4682 {
4683 hSubMenu = hMenu;
4684 nPos = cmd;
4685 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4686 {
4687 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
4688 if(hSubMenu != hMenu)
4689 {
4690 nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00004691 TRACE_(accel)("hMenu = %p, hSubMenu = %p, nPos = %d\n", hMenu, hSubMenu, nPos);
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004692 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
4693 }
4694 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
4695 }
4696 }
4697
4698 if (uSysStat != (UINT)-1)
4699 {
4700 if (uSysStat & (MF_DISABLED|MF_GRAYED))
4701 mesg=4;
4702 else
4703 mesg=WM_SYSCOMMAND;
4704 }
4705 else
4706 {
4707 if (uStat != (UINT)-1)
4708 {
4709 if (IsIconic(hWnd))
4710 mesg=5;
4711 else
4712 {
4713 if (uStat & (MF_DISABLED|MF_GRAYED))
4714 mesg=6;
4715 else
4716 mesg=WM_COMMAND;
4717 }
4718 }
4719 else
4720 mesg=WM_COMMAND;
4721 }
4722 }
4723
4724 if( mesg==WM_COMMAND )
4725 {
4726 TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
4727 SendMessageA(hWnd, mesg, 0x10000 | cmd, 0L);
4728 }
4729 else if( mesg==WM_SYSCOMMAND )
4730 {
4731 TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
4732 SendMessageA(hWnd, mesg, cmd, 0x00010000L);
4733 }
4734 else
4735 {
Vincent Béron9a624912002-05-31 23:06:46 +00004736 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004737 * #0: unknown (please report!)
4738 * #1: for WM_KEYUP,WM_SYSKEYUP
4739 * #2: mouse is captured
Vincent Béron9a624912002-05-31 23:06:46 +00004740 * #3: window is disabled
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004741 * #4: it's a disabled system menu option
4742 * #5: it's a menu option, but window is iconic
4743 * #6: it's a menu option, but disabled
4744 */
4745 TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
4746 if(mesg==0)
4747 ERR_(accel)(" unknown reason - please report!");
4748 }
4749 return TRUE;
4750}
4751
4752/**********************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00004753 * TranslateAccelerator (USER32.@)
Patrik Stridvall17fd4e32001-06-28 18:04:41 +00004754 * TranslateAcceleratorA (USER32.@)
Patrik Stridvall15a3b742001-04-27 18:03:51 +00004755 * TranslateAcceleratorW (USER32.@)
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004756 */
4757INT WINAPI TranslateAccelerator( HWND hWnd, HACCEL hAccel, LPMSG msg )
4758{
4759 /* YES, Accel16! */
4760 LPACCEL16 lpAccelTbl;
4761 int i;
4762
4763 if (msg == NULL)
4764 {
4765 WARN_(accel)("msg null; should hang here to be win compatible\n");
4766 return 0;
4767 }
Michael Stefaniuc4a75c5c2002-08-28 00:39:39 +00004768 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004769 {
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00004770 WARN_(accel)("invalid accel handle=%p\n", hAccel);
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004771 return 0;
4772 }
4773 if ((msg->message != WM_KEYDOWN &&
4774 msg->message != WM_KEYUP &&
4775 msg->message != WM_SYSKEYDOWN &&
4776 msg->message != WM_SYSKEYUP &&
4777 msg->message != WM_CHAR)) return 0;
4778
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00004779 TRACE_(accel)("TranslateAccelerators hAccel=%p, hWnd=%p,"
4780 "msg->hwnd=%p, msg->message=%04x, wParam=%08x, lParam=%lx\n",
Dmitry Timoshkovef559322000-10-26 21:47:20 +00004781 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
4782
4783 i = 0;
4784 do
4785 {
4786 if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
4787 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
4788 return 1;
4789 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
4790 WARN_(accel)("couldn't translate accelerator key\n");
4791 return 0;
4792}