menu.c 142 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
Alexandre Julliard's avatar
Alexandre Julliard committed
2 3 4 5
 * Menu functions
 *
 * Copyright 1993 Martin Ayotte
 * Copyright 1994 Alexandre Julliard
Alexandre Julliard's avatar
Alexandre Julliard committed
6
 * Copyright 1997 Morten Welinder
Alexandre Julliard's avatar
Alexandre Julliard committed
7
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
8 9 10 11 12 13

/*
 * Note: the style MF_MOUSESELECT is used to mark popup items that
 * have been selected, i.e. their popup menu is currently displayed.
 * This is probably not the meaning this style has in MS-Windows.
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
14

15
#include "config.h"
16 17
#include "wine/port.h"

Alexandre Julliard's avatar
Alexandre Julliard committed
18
#include <assert.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
19
#include <ctype.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
20
#include <stdlib.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
21
#include <string.h>
22

23
#include "windef.h"
24
#include "winnls.h"
25
#include "wingdi.h"
26
#include "wine/winbase16.h"
27
#include "wine/winuser16.h"
28
#include "wine/unicode.h"
29
#include "win.h"
30
#include "controls.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
31
#include "nonclient.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
32
#include "user.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
33
#include "message.h"
34

35
#include "debugtools.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
36

37 38
DEFAULT_DEBUG_CHANNEL(menu);
DECLARE_DEBUG_CHANNEL(accel);
Alexandre Julliard's avatar
Alexandre Julliard committed
39

Alexandre Julliard's avatar
Alexandre Julliard committed
40 41 42 43 44
/* internal popup menu window messages */

#define MM_SETMENUHANDLE	(WM_USER + 0)
#define MM_GETMENUHANDLE	(WM_USER + 1)

Alexandre Julliard's avatar
Alexandre Julliard committed
45
/* Menu item structure */
Alexandre Julliard's avatar
Alexandre Julliard committed
46 47
typedef struct {
    /* ----------- MENUITEMINFO Stuff ----------- */
48
    UINT fType;			/* Item type. */
49 50 51
    UINT fState;		/* Item state.  */
    UINT wID;			/* Item id.  */
    HMENU hSubMenu;		/* Pop-up menu.  */
52
    HBITMAP hCheckBit;		/* Bitmap when checked.  */
53
    HBITMAP hUnCheckBit;	/* Bitmap when unchecked.  */
54
    LPWSTR text;			/* Item text or bitmap handle.  */
Alexandre Julliard's avatar
Alexandre Julliard committed
55
    DWORD dwItemData;		/* Application defined.  */
56 57
    DWORD dwTypeData;		/* depends on fMask */
    HBITMAP hbmpItem;		/* bitmap in win98 style menus */
Alexandre Julliard's avatar
Alexandre Julliard committed
58
    /* ----------- Wine stuff ----------- */
59 60
    RECT      rect;		/* Item area (relative to menu window) */
    UINT      xTab;		/* X position of text after Tab */
Alexandre Julliard's avatar
Alexandre Julliard committed
61 62 63
} MENUITEM;

/* Popup menu structure */
Alexandre Julliard's avatar
Alexandre Julliard committed
64
typedef struct {
Alexandre Julliard's avatar
Alexandre Julliard committed
65 66 67 68
    WORD        wFlags;       /* Menu flags (MF_POPUP, MF_SYSMENU) */
    WORD        wMagic;       /* Magic number */
    WORD	Width;        /* Width of the whole menu */
    WORD	Height;       /* Height of the whole menu */
69
    UINT        nItems;       /* Number of items in the menu */
70 71 72
    HWND        hWnd;         /* Window containing the menu */
    MENUITEM    *items;       /* Array of menu items */
    UINT        FocusedItem;  /* Currently focused item */
73
    HWND	hwndOwner;    /* window receiving the messages for ownerdraw */
74
    BOOL        bTimeToHide;  /* Request hiding when receiving a second click in the top-level menu item */
75 76 77 78 79 80
    /* ------------ MENUINFO members ------ */
    DWORD	dwStyle;	/* Extended mennu style */
    UINT	cyMax;		/* max hight of the whole menu, 0 is screen hight */
    HBRUSH	hbrBack;	/* brush for menu background */
    DWORD	dwContextHelpID;
    DWORD	dwMenuData;	/* application defined value */
81
    HMENU       hSysMenuOwner;  /* Handle to the dummy sys menu holder */
Alexandre Julliard's avatar
Alexandre Julliard committed
82 83
} POPUPMENU, *LPPOPUPMENU;

Alexandre Julliard's avatar
Alexandre Julliard committed
84 85 86 87 88 89 90 91
/* internal flags for menu tracking */

#define TF_ENDMENU              0x0001
#define TF_SUSPENDPOPUP         0x0002
#define TF_SKIPREMOVE		0x0004

typedef struct
{
92 93 94 95 96
    UINT	trackFlags;
    HMENU	hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
    HMENU	hTopMenu;     /* initial menu */
    HWND	hOwnerWnd;    /* where notifications are sent */
    POINT	pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
97 98
} MTRACKER;

Alexandre Julliard's avatar
Alexandre Julliard committed
99 100
#define MENU_MAGIC   0x554d  /* 'MU' */

Alexandre Julliard's avatar
Alexandre Julliard committed
101 102 103
#define ITEM_PREV		-1
#define ITEM_NEXT		 1

Alexandre Julliard's avatar
Alexandre Julliard committed
104 105 106 107
  /* Internal MENU_TrackMenu() flags */
#define TPM_INTERNAL		0xF0000000
#define TPM_ENTERIDLEEX	 	0x80000000		/* set owner window for WM_ENTERIDLE */
#define TPM_BUTTONDOWN		0x40000000		/* menu was clicked before tracking */
108
#define TPM_POPUPMENU           0x20000000              /* menu is a popup menu */
Alexandre Julliard's avatar
Alexandre Julliard committed
109

Alexandre Julliard's avatar
Alexandre Julliard committed
110 111 112
  /* popup menu shade thickness */
#define POPUP_XSHADE		4
#define POPUP_YSHADE		4
Alexandre Julliard's avatar
Alexandre Julliard committed
113

Alexandre Julliard's avatar
Alexandre Julliard committed
114
  /* Space between 2 menu bar items */
Alexandre Julliard's avatar
Alexandre Julliard committed
115
#define MENU_BAR_ITEMS_SPACE 12
Alexandre Julliard's avatar
Alexandre Julliard committed
116

Alexandre Julliard's avatar
Alexandre Julliard committed
117
  /* Minimum width of a tab character */
Alexandre Julliard's avatar
Alexandre Julliard committed
118
#define MENU_TAB_SPACE 8
Alexandre Julliard's avatar
Alexandre Julliard committed
119

Alexandre Julliard's avatar
Alexandre Julliard committed
120
  /* Height of a separator item */
Alexandre Julliard's avatar
Alexandre Julliard committed
121
#define SEPARATOR_HEIGHT 5
Alexandre Julliard's avatar
Alexandre Julliard committed
122

Alexandre Julliard's avatar
Alexandre Julliard committed
123
  /* (other menu->FocusedItem values give the position of the focused item) */
Alexandre Julliard's avatar
Alexandre Julliard committed
124 125
#define NO_SELECTED_ITEM  0xffff

Alexandre Julliard's avatar
Alexandre Julliard committed
126 127 128 129
#define MENU_ITEM_TYPE(flags) \
  ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))

#define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
130
#define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
131
#define IS_MAGIC_ITEM(text)   (LOWORD((int)text)<12)
Alexandre Julliard's avatar
Alexandre Julliard committed
132

Alexandre Julliard's avatar
Alexandre Julliard committed
133 134
#define IS_SYSTEM_MENU(menu)  \
	(!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
135

Alexandre Julliard's avatar
Alexandre Julliard committed
136 137 138
#define IS_SYSTEM_POPUP(menu) \
	((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)

Alexandre Julliard's avatar
Alexandre Julliard committed
139 140 141 142 143 144
#define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
		   MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
		   MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
		   MF_POPUP | MF_SYSMENU | MF_HELP)
#define STATE_MASK (~TYPE_MASK)

Alexandre Julliard's avatar
Alexandre Julliard committed
145 146
  /* Dimension of the menu bitmaps */
static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
147

148
static HBITMAP hStdMnArrow = 0;
149
static HBITMAP hBmpSysMenu = 0;
150

151 152
static HBRUSH	hShadeBrush = 0;
static HFONT	hMenuFont = 0;
153
static HFONT	hMenuFontBold = 0;
154

155
static HMENU MENU_DefSysPopup = 0;  /* Default system menu popup */
Alexandre Julliard's avatar
Alexandre Julliard committed
156

Alexandre Julliard's avatar
Alexandre Julliard committed
157 158
/* Use global popup window because there's no way 2 menus can
 * be tracked at the same time.  */ 
159
static HWND top_popup;
Alexandre Julliard's avatar
Alexandre Julliard committed
160

Alexandre Julliard's avatar
Alexandre Julliard committed
161
  /* Flag set by EndMenu() to force an exit from menu tracking */
162
static BOOL fEndMenu = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
163

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );


/*********************************************************************
 * menu class descriptor
 */
const struct builtin_class_descr MENU_builtin_class =
{
    POPUPMENU_CLASS_ATOM,          /* name */
    CS_GLOBALCLASS | CS_SAVEBITS,  /* style */
    NULL,                          /* procA (winproc is Unicode only) */
    PopupMenuWndProc,              /* procW */
    sizeof(HMENU),                 /* extra */
    IDC_ARROWA,                    /* cursor */
    COLOR_MENU+1                   /* brush */
};

Alexandre Julliard's avatar
Alexandre Julliard committed
181

Alexandre Julliard's avatar
Alexandre Julliard committed
182 183 184 185 186 187
/***********************************************************************
 *           debug_print_menuitem
 *
 * Print a menuitem in readable form.
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
188
#define debug_print_menuitem(pre, mp, post) \
Alexandre Julliard's avatar
Alexandre Julliard committed
189
  if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
Alexandre Julliard's avatar
Alexandre Julliard committed
190

Alexandre Julliard's avatar
Alexandre Julliard committed
191
#define MENUOUT(text) \
192
  DPRINTF("%s%s", (count++ ? "," : ""), (text))
Alexandre Julliard's avatar
Alexandre Julliard committed
193 194 195 196 197 198

#define MENUFLAG(bit,text) \
  do { \
    if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
  } while (0)

Alexandre Julliard's avatar
Alexandre Julliard committed
199 200
static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp, 
				    const char *postfix)
Alexandre Julliard's avatar
Alexandre Julliard committed
201
{
202
    TRACE("%s ", prefix);
Alexandre Julliard's avatar
Alexandre Julliard committed
203
    if (mp) {
204
	UINT flags = mp->fType;
Alexandre Julliard's avatar
Alexandre Julliard committed
205
	int typ = MENU_ITEM_TYPE(flags);
206
	DPRINTF( "{ ID=0x%x", mp->wID);
Alexandre Julliard's avatar
Alexandre Julliard committed
207
	if (flags & MF_POPUP)
208
	    DPRINTF( ", Sub=0x%x", mp->hSubMenu);
Alexandre Julliard's avatar
Alexandre Julliard committed
209 210
	if (flags) {
	    int count = 0;
211
	    DPRINTF( ", Typ=");
Alexandre Julliard's avatar
Alexandre Julliard committed
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
	    if (typ == MFT_STRING)
		/* Nothing */ ;
	    else if (typ == MFT_SEPARATOR)
		MENUOUT("sep");
	    else if (typ == MFT_OWNERDRAW)
		MENUOUT("own");
	    else if (typ == MFT_BITMAP)
		MENUOUT("bit");
	    else
		MENUOUT("???");
	    flags -= typ;

	    MENUFLAG(MF_POPUP, "pop");
	    MENUFLAG(MFT_MENUBARBREAK, "barbrk");
	    MENUFLAG(MFT_MENUBREAK, "brk");
	    MENUFLAG(MFT_RADIOCHECK, "radio");
	    MENUFLAG(MFT_RIGHTORDER, "rorder");
	    MENUFLAG(MF_SYSMENU, "sys");
230
	    MENUFLAG(MFT_RIGHTJUSTIFY, "right");	/* same as MF_HELP */
Alexandre Julliard's avatar
Alexandre Julliard committed
231 232

	    if (flags)
233
		DPRINTF( "+0x%x", flags);
Alexandre Julliard's avatar
Alexandre Julliard committed
234 235 236 237
	}
	flags = mp->fState;
	if (flags) {
	    int count = 0;
238
	    DPRINTF( ", State=");
Alexandre Julliard's avatar
Alexandre Julliard committed
239
	    MENUFLAG(MFS_GRAYED, "grey");
240
	    MENUFLAG(MFS_DEFAULT, "default");
Alexandre Julliard's avatar
Alexandre Julliard committed
241 242 243 244 245 246
	    MENUFLAG(MFS_DISABLED, "dis");
	    MENUFLAG(MFS_CHECKED, "check");
	    MENUFLAG(MFS_HILITE, "hi");
	    MENUFLAG(MF_USECHECKBITMAPS, "usebit");
	    MENUFLAG(MF_MOUSESELECT, "mouse");
	    if (flags)
247
		DPRINTF( "+0x%x", flags);
Alexandre Julliard's avatar
Alexandre Julliard committed
248 249
	}
	if (mp->hCheckBit)
250
	    DPRINTF( ", Chk=0x%x", mp->hCheckBit);
Alexandre Julliard's avatar
Alexandre Julliard committed
251
	if (mp->hUnCheckBit)
252
	    DPRINTF( ", Unc=0x%x", mp->hUnCheckBit);
Alexandre Julliard's avatar
Alexandre Julliard committed
253 254 255

	if (typ == MFT_STRING) {
	    if (mp->text)
256
		DPRINTF( ", Text=%s", debugstr_w(mp->text));
Alexandre Julliard's avatar
Alexandre Julliard committed
257
	    else
258
		DPRINTF( ", Text=Null");
Alexandre Julliard's avatar
Alexandre Julliard committed
259 260 261
	} else if (mp->text == NULL)
	    /* Nothing */ ;
	else
262
	    DPRINTF( ", Text=%p", mp->text);
263
	if (mp->dwItemData)
264 265
	    DPRINTF( ", ItemData=0x%08lx", mp->dwItemData);
	DPRINTF( " }");
Alexandre Julliard's avatar
Alexandre Julliard committed
266
    } else {
267
	DPRINTF( "NULL");
Alexandre Julliard's avatar
Alexandre Julliard committed
268
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
269

270
    DPRINTF(" %s\n", postfix);
Alexandre Julliard's avatar
Alexandre Julliard committed
271 272 273 274 275
}

#undef MENUOUT
#undef MENUFLAG

276 277 278 279 280 281

/***********************************************************************
 *           MENU_GetMenu
 *
 * Validate the given menu handle and returns the menu structure pointer.
 */
282
static POPUPMENU *MENU_GetMenu(HMENU hMenu)
283
{
284 285
    POPUPMENU *menu = USER_HEAP_LIN_ADDR(hMenu);
    if (!menu || menu->wMagic != MENU_MAGIC)
286
    {
287
        WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0); 
288 289 290 291 292
        menu = NULL;
    }
    return menu;
}

293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
/***********************************************************************
 *           get_win_sys_menu
 *
 * Get the system menu of a window
 */
static HMENU get_win_sys_menu( HWND hwnd )
{
    HMENU ret = 0;
    WND *win = WIN_FindWndPtr( hwnd );
    if (win)
    {
        ret = win->hSysMenu;
        WIN_ReleaseWndPtr( win );
    }
    return ret;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
310 311
/***********************************************************************
 *           MENU_CopySysPopup
Alexandre Julliard's avatar
Alexandre Julliard committed
312
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
313
 * Return the default system menu.
Alexandre Julliard's avatar
Alexandre Julliard committed
314
 */
315
static HMENU MENU_CopySysPopup(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
316
{
317
    HMENU hMenu = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
Alexandre Julliard's avatar
Alexandre Julliard committed
318

Alexandre Julliard's avatar
Alexandre Julliard committed
319
    if( hMenu ) {
320
        POPUPMENU* menu = MENU_GetMenu(hMenu);
Alexandre Julliard's avatar
Alexandre Julliard committed
321
        menu->wFlags |= MF_SYSMENU | MF_POPUP;
322
	SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
323
    }
324
    else
325
	ERR("Unable to load default system menu\n" );
Alexandre Julliard's avatar
Alexandre Julliard committed
326

327
    TRACE("returning %x.\n", hMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
328 329

    return hMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
330 331 332
}


Alexandre Julliard's avatar
Alexandre Julliard committed
333 334
/**********************************************************************
 *           MENU_GetSysMenu
Alexandre Julliard's avatar
Alexandre Julliard committed
335
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
336
 * Create a copy of the system menu. System menu in Windows is
337
 * a special menu bar with the single entry - system menu popup.
Alexandre Julliard's avatar
Alexandre Julliard committed
338 339
 * This popup is presented to the outside world as a "system menu". 
 * However, the real system menu handle is sometimes seen in the 
340
 * WM_MENUSELECT parameters (and Word 6 likes it this way).
Alexandre Julliard's avatar
Alexandre Julliard committed
341
 */
342
HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
343
{
344
    HMENU hMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
345

346
    if ((hMenu = CreateMenu()))
Alexandre Julliard's avatar
Alexandre Julliard committed
347
    {
348
	POPUPMENU *menu = MENU_GetMenu(hMenu);
Alexandre Julliard's avatar
Alexandre Julliard committed
349
	menu->wFlags = MF_SYSMENU;
350
	menu->hWnd = WIN_GetFullHandle( hWnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
351

352
	if (hPopupMenu == (HMENU)(-1))
Alexandre Julliard's avatar
Alexandre Julliard committed
353 354
	    hPopupMenu = MENU_CopySysPopup();
	else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup; 
Alexandre Julliard's avatar
Alexandre Julliard committed
355

Alexandre Julliard's avatar
Alexandre Julliard committed
356 357
	if (hPopupMenu)
	{
358
	    InsertMenuA( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION, hPopupMenu, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
359

Alexandre Julliard's avatar
Alexandre Julliard committed
360 361
            menu->items[0].fType = MF_SYSMENU | MF_POPUP;
            menu->items[0].fState = 0;
362
            if ((menu = MENU_GetMenu(hPopupMenu))) menu->wFlags |= MF_SYSMENU;
Alexandre Julliard's avatar
Alexandre Julliard committed
363

364
	    TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
365 366
	    return hMenu;
	}
367
	DestroyMenu( hMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
368
    }
369
    ERR("failed to load system menu!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
370
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
371 372 373
}


Alexandre Julliard's avatar
Alexandre Julliard committed
374
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
375
 *           MENU_Init
Alexandre Julliard's avatar
Alexandre Julliard committed
376
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
377
 * Menus initialisation.
Alexandre Julliard's avatar
Alexandre Julliard committed
378
 */
379
BOOL MENU_Init()
Alexandre Julliard's avatar
Alexandre Julliard committed
380
{
381
    HBITMAP hBitmap;
382 383
    NONCLIENTMETRICSA ncm;

Alexandre Julliard's avatar
Alexandre Julliard committed
384 385 386 387 388
    static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
					    0x55, 0, 0xAA, 0,
					    0x55, 0, 0xAA, 0,
					    0x55, 0, 0xAA, 0 };

Alexandre Julliard's avatar
Alexandre Julliard committed
389
    /* Load menu bitmaps */
390
    hStdMnArrow = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW));
391
    /* Load system buttons bitmaps */
392
    hBmpSysMenu = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CLOSE));
Alexandre Julliard's avatar
Alexandre Julliard committed
393

Alexandre Julliard's avatar
Alexandre Julliard committed
394
    if (hStdMnArrow)
395 396 397 398 399
    {
	BITMAP bm;
	GetObjectA( hStdMnArrow, sizeof(bm), &bm );
	arrow_bitmap_width = bm.bmWidth;
	arrow_bitmap_height = bm.bmHeight;
Alexandre Julliard's avatar
Alexandre Julliard committed
400
    } else
401
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
402

403 404
    if (! (hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits))) 
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
405

406 407 408 409 410 411 412 413 414 415 416 417 418 419
    if(!(hShadeBrush = CreatePatternBrush( hBitmap ))) 
	return FALSE;
	
    DeleteObject( hBitmap );
    if (!(MENU_DefSysPopup = MENU_CopySysPopup()))
	return FALSE;

    ncm.cbSize = sizeof (NONCLIENTMETRICSA);
    if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &ncm, 0)))
	return FALSE;
	
    if (!(hMenuFont = CreateFontIndirectA( &ncm.lfMenuFont )))
	return FALSE;

420 421 422 423 424 425 426
    ncm.lfMenuFont.lfWeight += 300;
    if ( ncm.lfMenuFont.lfWeight > 1000)
	ncm.lfMenuFont.lfWeight = 1000;

    if (!(hMenuFontBold = CreateFontIndirectA( &ncm.lfMenuFont )))
	return FALSE;

427
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
428 429
}

Alexandre Julliard's avatar
Alexandre Julliard committed
430 431 432 433 434
/***********************************************************************
 *           MENU_InitSysMenuPopup
 *
 * Grey the appropriate items in System menu.
 */
435
static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
Alexandre Julliard's avatar
Alexandre Julliard committed
436
{
437
    BOOL gray;
Alexandre Julliard's avatar
Alexandre Julliard committed
438 439

    gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
440
    EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard's avatar
Alexandre Julliard committed
441
    gray = ((style & WS_MAXIMIZE) != 0);
442
    EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard's avatar
Alexandre Julliard committed
443
    gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
444
    EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard's avatar
Alexandre Julliard committed
445
    gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
446
    EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard's avatar
Alexandre Julliard committed
447
    gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
448
    EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
Alexandre Julliard's avatar
Alexandre Julliard committed
449
    gray = (clsStyle & CS_NOCLOSE) != 0;
450 451 452 453

    /* The menu item must keep its state if it's disabled */
    if(gray)
	EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
Alexandre Julliard's avatar
Alexandre Julliard committed
454 455 456
}


Alexandre Julliard's avatar
Alexandre Julliard committed
457 458
/******************************************************************************
 *
459 460
 *   UINT  MENU_GetStartOfNextColumn(
 *     HMENU  hMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
461 462 463
 *
 *****************************************************************************/

464 465
static UINT  MENU_GetStartOfNextColumn(
    HMENU  hMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
466
{
467 468
    POPUPMENU *menu = MENU_GetMenu(hMenu);
    UINT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
469 470 471 472

    if(!menu)
	return NO_SELECTED_ITEM;

473
    i = menu->FocusedItem + 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
474 475 476 477
    if( i == NO_SELECTED_ITEM )
	return i;

    for( ; i < menu->nItems; ++i ) {
Alexandre Julliard's avatar
Alexandre Julliard committed
478
	if (menu->items[i].fType & MF_MENUBARBREAK)
Alexandre Julliard's avatar
Alexandre Julliard committed
479 480 481 482 483 484 485 486 487
	    return i;
    }

    return NO_SELECTED_ITEM;
}


/******************************************************************************
 *
488 489
 *   UINT  MENU_GetStartOfPrevColumn(
 *     HMENU  hMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
490 491 492
 *
 *****************************************************************************/

493 494
static UINT  MENU_GetStartOfPrevColumn(
    HMENU  hMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
495
{
496
    POPUPMENU *menu = MENU_GetMenu(hMenu);
497
    UINT  i;
Alexandre Julliard's avatar
Alexandre Julliard committed
498 499 500 501 502 503 504 505 506 507

    if( !menu )
	return NO_SELECTED_ITEM;

    if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
	return NO_SELECTED_ITEM;

    /* Find the start of the column */

    for(i = menu->FocusedItem; i != 0 &&
Alexandre Julliard's avatar
Alexandre Julliard committed
508
	 !(menu->items[i].fType & MF_MENUBARBREAK);
Alexandre Julliard's avatar
Alexandre Julliard committed
509 510 511 512 513 514
	--i); /* empty */

    if(i == 0)
	return NO_SELECTED_ITEM;

    for(--i; i != 0; --i) {
Alexandre Julliard's avatar
Alexandre Julliard committed
515
	if (menu->items[i].fType & MF_MENUBARBREAK)
Alexandre Julliard's avatar
Alexandre Julliard committed
516 517 518
	    break;
    }

519
    TRACE("ret %d.\n", i );
Alexandre Julliard's avatar
Alexandre Julliard committed
520 521 522 523 524 525

    return i;
}



Alexandre Julliard's avatar
Alexandre Julliard committed
526 527 528 529 530 531
/***********************************************************************
 *           MENU_FindItem
 *
 * Find a menu item. Return a pointer on the item, and modifies *hmenu
 * in case the item was in a sub-menu.
 */
532
static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
533 534
{
    POPUPMENU *menu;
535
    UINT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
536

537
    if (((*hmenu)==0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
538 539 540
    if (wFlags & MF_BYPOSITION)
    {
	if (*nPos >= menu->nItems) return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
541
	return &menu->items[*nPos];
Alexandre Julliard's avatar
Alexandre Julliard committed
542 543 544
    }
    else
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
545
        MENUITEM *item = menu->items;
Alexandre Julliard's avatar
Alexandre Julliard committed
546 547
	for (i = 0; i < menu->nItems; i++, item++)
	{
Alexandre Julliard's avatar
Alexandre Julliard committed
548
	    if (item->wID == *nPos)
Alexandre Julliard's avatar
Alexandre Julliard committed
549 550 551 552
	    {
		*nPos = i;
		return item;
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
553
	    else if (item->fType & MF_POPUP)
Alexandre Julliard's avatar
Alexandre Julliard committed
554
	    {
555
		HMENU hsubmenu = item->hSubMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
556 557 558 559 560 561 562 563 564 565 566 567
		MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
		if (subitem)
		{
		    *hmenu = hsubmenu;
		    return subitem;
		}
	    }
	}
    }
    return NULL;
}

568 569 570 571 572 573 574 575 576 577 578 579 580
/***********************************************************************
 *           MENU_FindSubMenu
 *
 * Find a Sub menu. Return the position of the submenu, and modifies 
 * *hmenu in case it is found in another sub-menu.
 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
 */
UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget )
{
    POPUPMENU *menu;
    UINT i;
    MENUITEM *item;
    if (((*hmenu)==0xffff) || 
581
            (!(menu = MENU_GetMenu(*hmenu)))) 
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
        return NO_SELECTED_ITEM;
    item = menu->items;
    for (i = 0; i < menu->nItems; i++, item++) {
        if(!(item->fType & MF_POPUP)) continue;
        if (item->hSubMenu == hSubTarget) {
            return i;
        }
        else  {
            HMENU hsubmenu = item->hSubMenu;
            UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
            if (pos != NO_SELECTED_ITEM) {
                *hmenu = hsubmenu;
                return pos;
            }
        }
    }
    return NO_SELECTED_ITEM;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
601 602 603 604 605 606
/***********************************************************************
 *           MENU_FreeItemData
 */
static void MENU_FreeItemData( MENUITEM* item )
{
    /* delete text */
Alexandre Julliard's avatar
Alexandre Julliard committed
607
    if (IS_STRING_ITEM(item->fType) && item->text)
608
        HeapFree( GetProcessHeap(), 0, item->text );
Alexandre Julliard's avatar
Alexandre Julliard committed
609
}
Alexandre Julliard's avatar
Alexandre Julliard committed
610 611 612 613

/***********************************************************************
 *           MENU_FindItemByCoords
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
614 615 616
 * Find the item at the specified coordinates (screen coords). Does 
 * not work for child windows and therefore should not be called for 
 * an arbitrary system menu.
Alexandre Julliard's avatar
Alexandre Julliard committed
617
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
618
static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu, 
619
					POINT pt, UINT *pos )
Alexandre Julliard's avatar
Alexandre Julliard committed
620 621
{
    MENUITEM *item;
622
    UINT i;
623
    RECT wrect;
Alexandre Julliard's avatar
Alexandre Julliard committed
624

625 626
    if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
    pt.x -= wrect.left;pt.y -= wrect.top;
Alexandre Julliard's avatar
Alexandre Julliard committed
627
    item = menu->items;
Alexandre Julliard's avatar
Alexandre Julliard committed
628 629
    for (i = 0; i < menu->nItems; i++, item++)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
630 631
	if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
	    (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
Alexandre Julliard's avatar
Alexandre Julliard committed
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
	{
	    if (pos) *pos = i;
	    return item;
	}
    }
    return NULL;
}


/***********************************************************************
 *           MENU_FindItemByKey
 *
 * Find the menu item selected by a key press.
 * Return item id, -1 if none, -2 if we should close the menu.
 */
647 648
static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu, 
				  UINT key, BOOL forceMenuChar )
Alexandre Julliard's avatar
Alexandre Julliard committed
649
{
650
    TRACE("\tlooking for '%c' in [%04x]\n", (char)key, (UINT16)hmenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
651

652
    if (!IsMenu( hmenu )) hmenu = GetSubMenu( get_win_sys_menu(hwndOwner), 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
653

Alexandre Julliard's avatar
Alexandre Julliard committed
654
    if (hmenu)
Alexandre Julliard's avatar
Alexandre Julliard committed
655
    {
656
	POPUPMENU *menu = MENU_GetMenu( hmenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
657 658 659 660
	MENUITEM *item = menu->items;
	LONG menuchar;

	if( !forceMenuChar )
Alexandre Julliard's avatar
Alexandre Julliard committed
661
	{
662
	     UINT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
663 664 665 666

	     key = toupper(key);
	     for (i = 0; i < menu->nItems; i++, item++)
	     {
Alexandre Julliard's avatar
Alexandre Julliard committed
667
		if (item->text && (IS_STRING_ITEM(item->fType)))
Alexandre Julliard's avatar
Alexandre Julliard committed
668
		{
669
		    WCHAR *p = item->text - 2;
670 671
		    do
		    {
672
		    	p = strchrW (p + 2, '&');
673 674 675
		    }
		    while (p != NULL && p [1] == '&');
		    if (p && (toupper(p[1]) == key)) return i;
Alexandre Julliard's avatar
Alexandre Julliard committed
676 677
		}
	     }
Alexandre Julliard's avatar
Alexandre Julliard committed
678
	}
679
	menuchar = SendMessageA( hwndOwner, WM_MENUCHAR, 
Alexandre Julliard's avatar
Alexandre Julliard committed
680 681
                                   MAKEWPARAM( key, menu->wFlags ), hmenu );
	if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
682
	if (HIWORD(menuchar) == 1) return (UINT)(-2);
Alexandre Julliard's avatar
Alexandre Julliard committed
683
    }
684
    return (UINT)(-1);
Alexandre Julliard's avatar
Alexandre Julliard committed
685
}
686 687


688
/***********************************************************************
689
 *           MENU_GetBitmapItemSize
690
 *
691
 * Get the size of a bitmap item.
692
 */
693 694 695 696 697 698
static void MENU_GetBitmapItemSize( UINT id, DWORD data, SIZE *size )
{
    BITMAP bm;
    HBITMAP bmp = (HBITMAP)id;

    size->cx = size->cy = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
699

700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
    /* check if there is a magic menu item associated with this item */
    if (id && IS_MAGIC_ITEM( id ))
    {
        switch(LOWORD(id))
        {
        case HBMMENU_SYSTEM:
            if (data)
            {
                bmp = (HBITMAP)data;
                break;
            }
            /* fall through */
        case HBMMENU_MBAR_RESTORE:
        case HBMMENU_MBAR_MINIMIZE:
        case HBMMENU_MBAR_MINIMIZE_D:
        case HBMMENU_MBAR_CLOSE:
        case HBMMENU_MBAR_CLOSE_D:
            size->cx = GetSystemMetrics( SM_CXSIZE );
            size->cy = GetSystemMetrics( SM_CYSIZE );
            return;
        case HBMMENU_CALLBACK:
        case HBMMENU_POPUP_CLOSE:
        case HBMMENU_POPUP_RESTORE:
        case HBMMENU_POPUP_MAXIMIZE:
        case HBMMENU_POPUP_MINIMIZE:
        default:
            FIXME("Magic 0x%08x not implemented\n", id);
            return;
        }
    }
    if (GetObjectA(bmp, sizeof(bm), &bm ))
    {
        size->cx = bm.bmWidth;
        size->cy = bm.bmHeight;
    }
}

/***********************************************************************
 *           MENU_DrawBitmapItem
 *
 * Draw a bitmap item.
 */
static void MENU_DrawBitmapItem( HDC hdc, MENUITEM *lpitem, const RECT *rect, BOOL menuBar )
743
{
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
    BITMAP bm;
    DWORD rop;
    HDC hdcMem;
    HBITMAP bmp = (HBITMAP)lpitem->text;
    int w = rect->right - rect->left;
    int h = rect->bottom - rect->top;
    int bmp_xoffset = 0;
    int left, top;

    /* Check if there is a magic menu item associated with this item */
    if (lpitem->text && IS_MAGIC_ITEM(lpitem->text))
    {
        UINT flags = 0;
        RECT r;

        switch(LOWORD(lpitem->text))
        {
        case HBMMENU_SYSTEM:
            if (lpitem->dwItemData)
            {
                bmp = (HBITMAP)lpitem->dwItemData;
                if (!GetObjectA( bmp, sizeof(bm), &bm )) return;
            }
            else
            {
                bmp = hBmpSysMenu;
                if (!GetObjectA( bmp, sizeof(bm), &bm )) return;
                /* only use right half of the bitmap */
                bmp_xoffset = bm.bmWidth / 2;
                bm.bmWidth -= bmp_xoffset;
            }
            goto got_bitmap;
        case HBMMENU_MBAR_RESTORE:
            flags = DFCS_CAPTIONRESTORE;
            break;
        case HBMMENU_MBAR_MINIMIZE:
            flags = DFCS_CAPTIONMIN;
            break;
        case HBMMENU_MBAR_MINIMIZE_D:
            flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
            break;
        case HBMMENU_MBAR_CLOSE:
            flags = DFCS_CAPTIONCLOSE;
            break;
        case HBMMENU_MBAR_CLOSE_D:
            flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
            break;
        case HBMMENU_CALLBACK:
        case HBMMENU_POPUP_CLOSE:
        case HBMMENU_POPUP_RESTORE:
        case HBMMENU_POPUP_MAXIMIZE:
        case HBMMENU_POPUP_MINIMIZE:
        default:
            FIXME("Magic 0x%08x not implemented\n", LOWORD(lpitem->text));
            return;
        }
        r = *rect;
        InflateRect( &r, -1, -1 );
        if (lpitem->fState & MF_HILITE) flags |= DFCS_PUSHED;
        DrawFrameControl( hdc, &r, DFC_CAPTION, flags );
        return;
805 806
    }

807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
    if (!bmp || !GetObjectA( bmp, sizeof(bm), &bm )) return;

 got_bitmap:
    hdcMem = CreateCompatibleDC( hdc );
    SelectObject( hdcMem, bmp );

    /* handle fontsize > bitmap_height */
    top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
    left=rect->left;
    if (TWEAK_WineLook == WIN95_LOOK) {
        rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_ITEM(lpitem->text)) ? NOTSRCCOPY : SRCCOPY;
        if ((lpitem->fState & MF_HILITE) && IS_BITMAP_ITEM(lpitem->fType))
            SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
    } else {
        left++;
        w-=2;
        rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_ITEM(lpitem->text) && (!menuBar)) ? MERGEPAINT : SRCCOPY;
    }
    BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop );
    DeleteDC( hdcMem );
827
}
Alexandre Julliard's avatar
Alexandre Julliard committed
828

829

Alexandre Julliard's avatar
Alexandre Julliard committed
830 831 832 833 834
/***********************************************************************
 *           MENU_CalcItemSize
 *
 * Calculate the size of the menu item and store it in lpitem->rect.
 */
835 836
static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
			       INT orgX, INT orgY, BOOL menuBar )
Alexandre Julliard's avatar
Alexandre Julliard committed
837
{
838
    WCHAR *p;
839
    UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
Alexandre Julliard's avatar
Alexandre Julliard committed
840

841
    TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
Alexandre Julliard's avatar
Alexandre Julliard committed
842 843
    debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem, 
			 (menuBar ? " (MenuBar)" : ""));
Alexandre Julliard's avatar
Alexandre Julliard committed
844

845
    SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
Alexandre Julliard's avatar
Alexandre Julliard committed
846

Alexandre Julliard's avatar
Alexandre Julliard committed
847
    if (lpitem->fType & MF_OWNERDRAW)
Alexandre Julliard's avatar
Alexandre Julliard committed
848
    {
849 850 851 852 853 854 855
        /*
        ** Experimentation under Windows reveals that an owner-drawn
        ** menu is expected to return the size of the content part of
        ** the menu item, not including the checkmark nor the submenu
        ** arrow.  Windows adds those values itself and returns the
        ** enlarged rectangle on subsequent WM_DRAWITEM messages.
        */
856
        MEASUREITEMSTRUCT mis;
Alexandre Julliard's avatar
Alexandre Julliard committed
857
        mis.CtlType    = ODT_MENU;
858
        mis.CtlID      = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
859
        mis.itemID     = lpitem->wID;
860 861 862
        mis.itemData   = (DWORD)lpitem->dwItemData;
        mis.itemHeight = 0;
        mis.itemWidth  = 0;
863
        SendMessageA( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
Alexandre Julliard's avatar
Alexandre Julliard committed
864
        lpitem->rect.right  += mis.itemWidth;
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882

 	if (menuBar)
	{
	     lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
	

             /* under at least win95 you seem to be given a standard
                height for the menu and the height value is ignored */

	     if (TWEAK_WineLook == WIN31_LOOK)
	    	lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU);
	     else
	    	lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU)-1;
        }
        else
            lpitem->rect.bottom += mis.itemHeight;
	
	TRACE("id=%04x size=%dx%d\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
883
                     lpitem->wID, mis.itemWidth, mis.itemHeight);
884
        /* Fall through to get check/arrow width calculation. */
Alexandre Julliard's avatar
Alexandre Julliard committed
885
    } 
Alexandre Julliard's avatar
Alexandre Julliard committed
886

Alexandre Julliard's avatar
Alexandre Julliard committed
887
    if (lpitem->fType & MF_SEPARATOR)
Alexandre Julliard's avatar
Alexandre Julliard committed
888 889 890 891 892
    {
	lpitem->rect.bottom += SEPARATOR_HEIGHT;
	return;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
893 894 895
    if (!menuBar)
    {
	lpitem->rect.right += 2 * check_bitmap_width;
Alexandre Julliard's avatar
Alexandre Julliard committed
896
	if (lpitem->fType & MF_POPUP)
Alexandre Julliard's avatar
Alexandre Julliard committed
897 898
	    lpitem->rect.right += arrow_bitmap_width;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
899

900 901 902
    if (lpitem->fType & MF_OWNERDRAW)
        return;

903
    if (IS_BITMAP_ITEM(lpitem->fType))
Alexandre Julliard's avatar
Alexandre Julliard committed
904
    {
905
        SIZE size;
906

907 908 909 910
        MENU_GetBitmapItemSize( (int)lpitem->text, lpitem->dwItemData, &size );
        lpitem->rect.right  += size.cx;
        lpitem->rect.bottom += size.cy;
        if (TWEAK_WineLook == WIN98_LOOK)
Alexandre Julliard's avatar
Alexandre Julliard committed
911
        {
912 913 914
            /* Leave space for the sunken border */
            lpitem->rect.right  += 2;
            lpitem->rect.bottom += 2;
Alexandre Julliard's avatar
Alexandre Julliard committed
915
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
916 917
    }
    
Alexandre Julliard's avatar
Alexandre Julliard committed
918

919 920
    /* it must be a text item - unless it's the system menu */
    if (!(lpitem->fType & MF_SYSMENU) && IS_STRING_ITEM( lpitem->fType ))
921 922
    {   SIZE size;

923
	GetTextExtentPoint32W(hdc, lpitem->text,  strlenW(lpitem->text), &size);
924 925
	
	lpitem->rect.right  += size.cx;
Alexandre Julliard's avatar
Alexandre Julliard committed
926
	if (TWEAK_WineLook == WIN31_LOOK)
927
	    lpitem->rect.bottom += max( size.cy, GetSystemMetrics(SM_CYMENU) );
928
	else
929
	    lpitem->rect.bottom += max(size.cy, GetSystemMetrics(SM_CYMENU)-1);
930
	lpitem->xTab = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
931

932 933 934 935
	if (menuBar)
	{
	     lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
	}
936
	else if ((p = strchrW( lpitem->text, '\t' )) != NULL)
937 938
	{
	    /* Item contains a tab (only meaningful in popup menus) */
939
	    GetTextExtentPoint32W(hdc, lpitem->text, (int)(p - lpitem->text) , &size);
940 941 942 943 944
	    lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE + size.cx;
	    lpitem->rect.right += MENU_TAB_SPACE;
	}
	else
	{
945
	    if (strchrW( lpitem->text, '\b' ))
946 947 948 949
	        lpitem->rect.right += MENU_TAB_SPACE;
	    lpitem->xTab = lpitem->rect.right - check_bitmap_width 
	                   - arrow_bitmap_width;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
950
    }
951
    TRACE("(%d,%d)-(%d,%d)\n", lpitem->rect.left, lpitem->rect.top, lpitem->rect.right, lpitem->rect.bottom);
Alexandre Julliard's avatar
Alexandre Julliard committed
952 953 954 955 956 957 958 959
}


/***********************************************************************
 *           MENU_PopupMenuCalcSize
 *
 * Calculate the size of a popup menu.
 */
960
static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
Alexandre Julliard's avatar
Alexandre Julliard committed
961
{
Alexandre Julliard's avatar
Alexandre Julliard committed
962
    MENUITEM *lpitem;
963
    HDC hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
964 965
    int start, i;
    int orgX, orgY, maxX, maxTab, maxTabWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
966 967 968

    lppop->Width = lppop->Height = 0;
    if (lppop->nItems == 0) return;
969
    hdc = GetDC( 0 );
970 971 972

    SelectObject( hdc, hMenuFont);
    
Alexandre Julliard's avatar
Alexandre Julliard committed
973
    start = 0;
974
    maxX = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CXBORDER) : 2+1 ;
975

Alexandre Julliard's avatar
Alexandre Julliard committed
976
    while (start < lppop->nItems)
Alexandre Julliard's avatar
Alexandre Julliard committed
977
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
978
	lpitem = &lppop->items[start];
Alexandre Julliard's avatar
Alexandre Julliard committed
979
	orgX = maxX;
980
	orgY = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CYBORDER) : 2;
Alexandre Julliard's avatar
Alexandre Julliard committed
981

Alexandre Julliard's avatar
Alexandre Julliard committed
982
	maxTab = maxTabWidth = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
983 984

	  /* Parse items until column break or end of menu */
Alexandre Julliard's avatar
Alexandre Julliard committed
985
	for (i = start; i < lppop->nItems; i++, lpitem++)
Alexandre Julliard's avatar
Alexandre Julliard committed
986
	{
Alexandre Julliard's avatar
Alexandre Julliard committed
987
	    if ((i != start) &&
Alexandre Julliard's avatar
Alexandre Julliard committed
988
		(lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
Alexandre Julliard's avatar
Alexandre Julliard committed
989

Alexandre Julliard's avatar
Alexandre Julliard committed
990
	    MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
991

992
	    if (lpitem->fType & MF_MENUBARBREAK) orgX++;
993
	    maxX = max( maxX, lpitem->rect.right );
Alexandre Julliard's avatar
Alexandre Julliard committed
994
	    orgY = lpitem->rect.bottom;
Alexandre Julliard's avatar
Alexandre Julliard committed
995
	    if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
Alexandre Julliard's avatar
Alexandre Julliard committed
996
	    {
997 998
		maxTab = max( maxTab, lpitem->xTab );
		maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
Alexandre Julliard's avatar
Alexandre Julliard committed
999
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1000 1001 1002
	}

	  /* Finish the column (set all items to the largest width found) */
1003
	maxX = max( maxX, maxTab + maxTabWidth );
Alexandre Julliard's avatar
Alexandre Julliard committed
1004
	for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
Alexandre Julliard's avatar
Alexandre Julliard committed
1005 1006
	{
	    lpitem->rect.right = maxX;
Alexandre Julliard's avatar
Alexandre Julliard committed
1007
	    if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
1008 1009
		lpitem->xTab = maxTab;
	
Alexandre Julliard's avatar
Alexandre Julliard committed
1010
	}
1011
	lppop->Height = max( lppop->Height, orgY );
Alexandre Julliard's avatar
Alexandre Julliard committed
1012 1013
    }

1014 1015 1016
    lppop->Width  = maxX;

    /* space for 3d border */
Alexandre Julliard's avatar
Alexandre Julliard committed
1017
    if(TWEAK_WineLook > WIN31_LOOK)
1018 1019 1020 1021
    {
	lppop->Height += 2;
	lppop->Width += 2;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1022

1023
    ReleaseDC( 0, hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1024 1025 1026 1027 1028 1029
}


/***********************************************************************
 *           MENU_MenuBarCalcSize
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1030
 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
Alexandre Julliard's avatar
Alexandre Julliard committed
1031 1032 1033
 * height is off by 1 pixel which causes lengthy window relocations when
 * active document window is maximized/restored.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1034 1035
 * Calculate the size of the menu bar.
 */
1036 1037
static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
                                  LPPOPUPMENU lppop, HWND hwndOwner )
Alexandre Julliard's avatar
Alexandre Julliard committed
1038
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1039
    MENUITEM *lpitem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1040
    int start, i, orgX, orgY, maxY, helpPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1041 1042 1043

    if ((lprect == NULL) || (lppop == NULL)) return;
    if (lppop->nItems == 0) return;
1044
    TRACE("left=%d top=%d right=%d bottom=%d\n", 
Alexandre Julliard's avatar
Alexandre Julliard committed
1045
                 lprect->left, lprect->top, lprect->right, lprect->bottom);
Alexandre Julliard's avatar
Alexandre Julliard committed
1046 1047
    lppop->Width  = lprect->right - lprect->left;
    lppop->Height = 0;
1048
    maxY = lprect->top+1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1049
    start = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1050
    helpPos = -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1051
    while (start < lppop->nItems)
Alexandre Julliard's avatar
Alexandre Julliard committed
1052
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1053
	lpitem = &lppop->items[start];
Alexandre Julliard's avatar
Alexandre Julliard committed
1054 1055 1056 1057
	orgX = lprect->left;
	orgY = maxY;

	  /* Parse items until line break or end of menu */
Alexandre Julliard's avatar
Alexandre Julliard committed
1058
	for (i = start; i < lppop->nItems; i++, lpitem++)
Alexandre Julliard's avatar
Alexandre Julliard committed
1059
	{
1060
	    if ((helpPos == -1) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i;
Alexandre Julliard's avatar
Alexandre Julliard committed
1061
	    if ((i != start) &&
Alexandre Julliard's avatar
Alexandre Julliard committed
1062
		(lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1063

1064
	    TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", 
Alexandre Julliard's avatar
Alexandre Julliard committed
1065
			 orgX, orgY );
Alexandre Julliard's avatar
Alexandre Julliard committed
1066
	    debug_print_menuitem ("  item: ", lpitem, "");
Alexandre Julliard's avatar
Alexandre Julliard committed
1067
	    MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
1068

Alexandre Julliard's avatar
Alexandre Julliard committed
1069 1070
	    if (lpitem->rect.right > lprect->right)
	    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1071
		if (i != start) break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1072 1073
		else lpitem->rect.right = lprect->right;
	    }
1074
	    maxY = max( maxY, lpitem->rect.bottom );
Alexandre Julliard's avatar
Alexandre Julliard committed
1075 1076 1077 1078
	    orgX = lpitem->rect.right;
	}

	  /* Finish the line (set all items to the largest height found) */
Alexandre Julliard's avatar
Alexandre Julliard committed
1079
	while (start < i) lppop->items[start++].rect.bottom = maxY;
Alexandre Julliard's avatar
Alexandre Julliard committed
1080 1081 1082 1083
    }

    lprect->bottom = maxY;
    lppop->Height = lprect->bottom - lprect->top;
Alexandre Julliard's avatar
Alexandre Julliard committed
1084

1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
    /* Flush right all items between the MF_RIGHTJUSTIFY and */
    /* the last item (if several lines, only move the last line) */
    lpitem = &lppop->items[lppop->nItems-1];
    orgY = lpitem->rect.top;
    orgX = lprect->right;
    for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--) {
        if ( (helpPos==-1) || (helpPos>i) )
            break;				/* done */
        if (lpitem->rect.top != orgY) break;	/* Other line */
        if (lpitem->rect.right >= orgX) break;	/* Too far right already */
        lpitem->rect.left += orgX - lpitem->rect.right;
        lpitem->rect.right = orgX;
        orgX = lpitem->rect.left;
Alexandre Julliard's avatar
Alexandre Julliard committed
1098
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1099 1100 1101 1102 1103 1104 1105
}

/***********************************************************************
 *           MENU_DrawMenuItem
 *
 * Draw a single menu item.
 */
1106
static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
1107
			       UINT height, BOOL menuBar, UINT odaction )
Alexandre Julliard's avatar
Alexandre Julliard committed
1108
{
1109
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
1110

Alexandre Julliard's avatar
Alexandre Julliard committed
1111
    debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
Alexandre Julliard's avatar
Alexandre Julliard committed
1112 1113

    if (lpitem->fType & MF_SYSMENU)
Alexandre Julliard's avatar
Alexandre Julliard committed
1114
    {
1115
	if( !IsIconic(hwnd) ) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1116
	    if (TWEAK_WineLook > WIN31_LOOK)
Alexandre Julliard's avatar
Alexandre Julliard committed
1117
		NC_DrawSysButton95( hwnd, hdc,
Alexandre Julliard's avatar
Alexandre Julliard committed
1118
				    lpitem->fState &
Alexandre Julliard's avatar
Alexandre Julliard committed
1119 1120 1121
				    (MF_HILITE | MF_MOUSESELECT) );
	    else
		NC_DrawSysButton( hwnd, hdc, 
Alexandre Julliard's avatar
Alexandre Julliard committed
1122
				  lpitem->fState &
Alexandre Julliard's avatar
Alexandre Julliard committed
1123 1124 1125
				  (MF_HILITE | MF_MOUSESELECT) );
	}

Alexandre Julliard's avatar
Alexandre Julliard committed
1126 1127 1128
	return;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1129
    if (lpitem->fType & MF_OWNERDRAW)
Alexandre Julliard's avatar
Alexandre Julliard committed
1130
    {
1131 1132 1133 1134 1135 1136 1137 1138 1139
        /*
        ** Experimentation under Windows reveals that an owner-drawn
        ** menu is given the rectangle which includes the space it requested
        ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
        ** and a popup-menu arrow.  This is the value of lpitem->rect.
        ** Windows will leave all drawing to the application except for
        ** the popup-menu arrow.  Windows always draws that itself, after
        ** the menu owner has finished drawing.
        */
1140
        DRAWITEMSTRUCT dis;
Alexandre Julliard's avatar
Alexandre Julliard committed
1141

Alexandre Julliard's avatar
Alexandre Julliard committed
1142
        dis.CtlType   = ODT_MENU;
1143
	dis.CtlID     = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1144
        dis.itemID    = lpitem->wID;
1145
        dis.itemData  = (DWORD)lpitem->dwItemData;
Alexandre Julliard's avatar
Alexandre Julliard committed
1146
        dis.itemState = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1147 1148 1149
        if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
        if (lpitem->fState & MF_GRAYED)  dis.itemState |= ODS_GRAYED;
        if (lpitem->fState & MF_HILITE)  dis.itemState |= ODS_SELECTED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1150
        dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1151
        dis.hwndItem   = (HWND)hmenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
1152
        dis.hDC        = hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1153
        dis.rcItem     = lpitem->rect;
1154
        TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1155 1156 1157 1158 1159
	      "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner,
	      dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem, 
	      dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
	      dis.rcItem.bottom);
        SendMessageA( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
1160
        /* Fall through to draw popup-menu arrow */
Alexandre Julliard's avatar
Alexandre Julliard committed
1161
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1162

1163
    TRACE("rect={%d,%d,%d,%d}\n", lpitem->rect.left, lpitem->rect.top,
1164
					lpitem->rect.right,lpitem->rect.bottom);
Alexandre Julliard's avatar
Alexandre Julliard committed
1165

1166
    if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1167

1168
    rect = lpitem->rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
1169

1170 1171
    if (!(lpitem->fType & MF_OWNERDRAW))
    {
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
	if (lpitem->fState & MF_HILITE)
	{
	    if(TWEAK_WineLook == WIN98_LOOK)
	    {
		if(menuBar)
		    DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
		else
		    FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
	    }
	    else /* Not Win98 Look */
	    {
		if(!IS_BITMAP_ITEM(lpitem->fType))
		    FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
	    }
	}
1187 1188 1189
        else
	    FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) );
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1190

1191
    SetBkMode( hdc, TRANSPARENT );
Alexandre Julliard's avatar
Alexandre Julliard committed
1192

1193
    if (!(lpitem->fType & MF_OWNERDRAW))
Alexandre Julliard's avatar
Alexandre Julliard committed
1194
    {
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
        /* vertical separator */
        if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
        {
	    if (TWEAK_WineLook > WIN31_LOOK) 
	    {
	        RECT rc = rect;
	        rc.top = 3;
	        rc.bottom = height - 3;
	        DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
	    }
	    else 
	    {
	        SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1208
	        MoveToEx( hdc, rect.left, 0, NULL );
1209 1210 1211
	        LineTo( hdc, rect.left, height );
	    }
        }
1212

1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
        /* horizontal separator */
        if (lpitem->fType & MF_SEPARATOR)
        {
	    if (TWEAK_WineLook > WIN31_LOOK) 
	    {
	        RECT rc = rect;
	        rc.left++;
	        rc.right--;
	        rc.top += SEPARATOR_HEIGHT / 2;
	        DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
	    }
	    else 
	    {
	        SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1227
	        MoveToEx( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2, NULL );
1228 1229 1230 1231
	        LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
	    }
	    return;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1232 1233
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1234 1235
      /* Setup colors */

1236
    if (lpitem->fState & MF_HILITE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1237
    {
1238 1239
	if(TWEAK_WineLook == WIN98_LOOK)
	{
1240
            if(menuBar) {
1241
		SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
1242 1243
                SetBkColor(hdc, GetSysColor(COLOR_MENU));
	    } else {
1244 1245 1246 1247
		if(lpitem->fState & MF_GRAYED)
		    SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
		else
		    SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1248
                SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1249 1250 1251 1252 1253 1254 1255 1256
	    }
	}
	else /* Not Win98 Look */
	{
	    SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
	    if(!IS_BITMAP_ITEM(lpitem->fType))
		SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1257 1258 1259
    }
    else
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1260
	if (lpitem->fState & MF_GRAYED)
1261
	    SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1262
	else
1263 1264
	    SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
	SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1265 1266
    }

1267 1268 1269
	/* helper lines for debugging */
/*	FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
	SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1270
	MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1271 1272 1273
	LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
*/

Alexandre Julliard's avatar
Alexandre Julliard committed
1274 1275
    if (!menuBar)
    {
1276
	INT	y = rect.top + rect.bottom;
1277 1278
        UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
        UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
Alexandre Julliard's avatar
Alexandre Julliard committed
1279

1280 1281 1282 1283 1284 1285 1286
        if (!(lpitem->fType & MF_OWNERDRAW))
        {
	      /* Draw the check mark
	       *
	       * FIXME:
	       * Custom checkmark bitmaps are monochrome but not always 1bpp. 
	       */
1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311
            HBITMAP bm = (lpitem->fState & MF_CHECKED) ? lpitem->hCheckBit : lpitem->hUnCheckBit;
            if (bm)  /* we have a custom bitmap */
            {
                HDC hdcMem = CreateCompatibleDC( hdc );
                SelectObject( hdcMem, bm );
                BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
                        check_bitmap_width, check_bitmap_height,
                        hdcMem, 0, 0, SRCCOPY );
                DeleteDC( hdcMem );
            }
            else if (lpitem->fState & MF_CHECKED)  /* standard bitmaps */
            {
                RECT r;
                HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
                HDC hdcMem = CreateCompatibleDC( hdc );
                SelectObject( hdcMem, bm );
                SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height );
                DrawFrameControl( hdcMem, &r, DFC_MENU,
                                  (lpitem->fType & MFT_RADIOCHECK) ?
                                  DFCS_MENUBULLET : DFCS_MENUCHECK );
                BitBlt( hdc, rect.left, (y - r.bottom) / 2, r.right, r.bottom,
                        hdcMem, 0, 0, SRCCOPY );
                DeleteDC( hdcMem );
                DeleteObject( bm );
            }
1312
        }
1313
	
Alexandre Julliard's avatar
Alexandre Julliard committed
1314
	  /* Draw the popup-menu arrow */
Alexandre Julliard's avatar
Alexandre Julliard committed
1315
	if (lpitem->fType & MF_POPUP)
Alexandre Julliard's avatar
Alexandre Julliard committed
1316
	{
1317
	    HDC hdcMem = CreateCompatibleDC( hdc );
1318
	    HBITMAP hOrigBitmap;
1319

1320
	    hOrigBitmap = SelectObject( hdcMem, hStdMnArrow );
1321
	    BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1322 1323 1324
		      (y - arrow_bitmap_height) / 2,
		      arrow_bitmap_width, arrow_bitmap_height,
		      hdcMem, 0, 0, SRCCOPY );
1325
            SelectObject( hdcMem, hOrigBitmap );
1326
	    DeleteDC( hdcMem );
Alexandre Julliard's avatar
Alexandre Julliard committed
1327 1328 1329 1330 1331 1332
	}

	rect.left += check_bitmap_width;
	rect.right -= arrow_bitmap_width;
    }

1333 1334 1335 1336
    /* Done for owner-drawn */
    if (lpitem->fType & MF_OWNERDRAW)
        return;

1337 1338
    /* Draw the item text or bitmap */
    if (IS_BITMAP_ITEM(lpitem->fType))
1339
    {
1340
        MENU_DrawBitmapItem( hdc, lpitem, &rect, menuBar );
Alexandre Julliard's avatar
Alexandre Julliard committed
1341
	return;
1342

Alexandre Julliard's avatar
Alexandre Julliard committed
1343
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1344
    /* No bitmap - process text if present */
Alexandre Julliard's avatar
Alexandre Julliard committed
1345
    else if (IS_STRING_ITEM(lpitem->fType))
Alexandre Julliard's avatar
Alexandre Julliard committed
1346
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1347
	register int i;
1348 1349
	HFONT hfontOld = 0;
	
1350 1351 1352
	UINT uFormat = (menuBar) ?
			DT_CENTER | DT_VCENTER | DT_SINGLELINE :
			DT_LEFT | DT_VCENTER | DT_SINGLELINE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1353

1354 1355 1356 1357 1358
	if ( lpitem->fState & MFS_DEFAULT )
	{
	     hfontOld = SelectObject( hdc, hMenuFontBold);
	}

Alexandre Julliard's avatar
Alexandre Julliard committed
1359 1360 1361 1362
	if (menuBar)
	{
	    rect.left += MENU_BAR_ITEMS_SPACE / 2;
	    rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1363
	    i = strlenW( lpitem->text );
Alexandre Julliard's avatar
Alexandre Julliard committed
1364 1365 1366
	}
	else
	{
Alexandre Julliard's avatar
Alexandre Julliard committed
1367
	    for (i = 0; lpitem->text[i]; i++)
1368 1369
		if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
		    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1370 1371
	}

1372
	if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1373
	{
1374
	    if (!(lpitem->fState & MF_HILITE) )
1375
	    {
1376
		++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1377
		SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1378
		DrawTextW( hdc, lpitem->text, i, &rect, uFormat );
1379
		--rect.left; --rect.top; --rect.right; --rect.bottom;
Alexandre Julliard's avatar
Alexandre Julliard committed
1380
	    }
1381
	    SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
Alexandre Julliard's avatar
Alexandre Julliard committed
1382
	}
1383
	
1384
	DrawTextW( hdc, lpitem->text, i, &rect, uFormat);
Alexandre Julliard's avatar
Alexandre Julliard committed
1385

1386
	/* paint the shortcut text */
Alexandre Julliard's avatar
Alexandre Julliard committed
1387
	if (lpitem->text[i])  /* There's a tab or flush-right char */
Alexandre Julliard's avatar
Alexandre Julliard committed
1388
	{
Alexandre Julliard's avatar
Alexandre Julliard committed
1389
	    if (lpitem->text[i] == '\t')
Alexandre Julliard's avatar
Alexandre Julliard committed
1390 1391
	    {
		rect.left = lpitem->xTab;
1392
		uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1393
	    }
1394 1395 1396 1397 1398
	    else 
	    {
		uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
	    }

1399 1400 1401 1402 1403 1404
	    if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
	    {
		if (!(lpitem->fState & MF_HILITE) )
		{
		    ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
		    SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1405
		    DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1406 1407 1408 1409
		    --rect.left; --rect.top; --rect.right; --rect.bottom;
		}
		SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
	    }
1410
	    DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
Alexandre Julliard's avatar
Alexandre Julliard committed
1411
	}
1412 1413 1414

	if (hfontOld) 
	    SelectObject (hdc, hfontOld);
Alexandre Julliard's avatar
Alexandre Julliard committed
1415 1416 1417 1418
    }
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1419
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1420 1421 1422
 *           MENU_DrawPopupMenu
 *
 * Paint a popup menu.
Alexandre Julliard's avatar
Alexandre Julliard committed
1423
 */
1424
static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
1425
{
1426 1427
    HBRUSH hPrevBrush = 0;
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
1428

1429
    TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd, hdc, hmenu);
1430

1431
    GetClientRect( hwnd, &rect );
Alexandre Julliard's avatar
Alexandre Julliard committed
1432

1433 1434
    if(TWEAK_WineLook == WIN31_LOOK) 
    {
1435 1436
	rect.bottom -= POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
	rect.right -= POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER);
1437
    } 
Alexandre Julliard's avatar
Alexandre Julliard committed
1438

1439 1440
    if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) )) 
        && (SelectObject( hdc, hMenuFont)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1441
    {
1442
	HPEN hPrevPen;
Alexandre Julliard's avatar
Alexandre Julliard committed
1443
	
1444
	Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
Alexandre Julliard's avatar
Alexandre Julliard committed
1445

1446
	hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1447 1448
	if( hPrevPen )
	{
1449
	    INT ropPrev, i;
Alexandre Julliard's avatar
Alexandre Julliard committed
1450 1451 1452
	    POPUPMENU *menu;

	    /* draw 3-d shade */
Alexandre Julliard's avatar
Alexandre Julliard committed
1453
	    if(TWEAK_WineLook == WIN31_LOOK) {
1454 1455 1456
		SelectObject( hdc, hShadeBrush );
		SetBkMode( hdc, TRANSPARENT );
		ropPrev = SetROP2( hdc, R2_MASKPEN );
Alexandre Julliard's avatar
Alexandre Julliard committed
1457 1458

		i = rect.right;		/* why SetBrushOrg() doesn't? */
1459
		PatBlt( hdc, i & 0xfffffffe,
1460 1461
			  rect.top + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER),
			  i%2 + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
Alexandre Julliard's avatar
Alexandre Julliard committed
1462 1463
			  rect.bottom - rect.top, 0x00a000c9 );
		i = rect.bottom;
1464
		PatBlt( hdc, rect.left + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
Alexandre Julliard's avatar
Alexandre Julliard committed
1465
			  i & 0xfffffffe,rect.right - rect.left,
1466
			  i%2 + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER), 0x00a000c9 );
1467 1468 1469
		SelectObject( hdc, hPrevPen );
		SelectObject( hdc, hPrevBrush );
		SetROP2( hdc, ropPrev );
Alexandre Julliard's avatar
Alexandre Julliard committed
1470 1471
	    }
	    else
1472
		DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
Alexandre Julliard's avatar
Alexandre Julliard committed
1473 1474 1475

	    /* draw menu items */

1476
	    menu = MENU_GetMenu( hmenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
1477 1478 1479
	    if (menu && menu->nItems)
	    {
		MENUITEM *item;
1480
		UINT u;
Alexandre Julliard's avatar
Alexandre Julliard committed
1481 1482

		for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
1483 1484
		    MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item, 
				       menu->Height, FALSE, ODA_DRAWENTIRE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1485 1486

	    }
1487 1488 1489 1490
	} else 
	{
	    SelectObject( hdc, hPrevBrush );
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1491
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1492
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1493

Alexandre Julliard's avatar
Alexandre Julliard committed
1494 1495 1496 1497
/***********************************************************************
 *           MENU_DrawMenuBar
 *
 * Paint a menu bar. Returns the height of the menu bar.
1498
 * called from [windows/nonclient.c]
Alexandre Julliard's avatar
Alexandre Julliard committed
1499
 */
1500 1501
UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
                         BOOL suppress_draw)
Alexandre Julliard's avatar
Alexandre Julliard committed
1502 1503
{
    LPPOPUPMENU lppop;
1504
    UINT i,retvalue;
1505
    HFONT hfontOld = 0;
1506
    HMENU hMenu = GetMenu(hwnd);
1507

1508
    lppop = MENU_GetMenu( hMenu );
1509 1510
    if (lppop == NULL || lprect == NULL)
    {
1511
        retvalue = GetSystemMetrics(SM_CYMENU);
1512 1513
        goto END;
    }
1514

1515
    TRACE("(%04x, %p, %p)\n", hDC, lprect, lppop);
1516 1517 1518 1519 1520 1521

    hfontOld = SelectObject( hDC, hMenuFont);

    if (lppop->Height == 0)
        MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);

Alexandre Julliard's avatar
Alexandre Julliard committed
1522
    lprect->bottom = lprect->top + lppop->Height;
1523

1524 1525 1526 1527 1528
    if (suppress_draw)
    {
        retvalue = lppop->Height;
        goto END;
    }
1529

1530
    FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1531

1532 1533
    if (TWEAK_WineLook == WIN31_LOOK) 
    {
1534
	SelectObject( hDC, GetSysColorPen(COLOR_WINDOWFRAME) );
1535
	MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
1536
	LineTo( hDC, lprect->right, lprect->bottom );
Alexandre Julliard's avatar
Alexandre Julliard committed
1537
    }
1538 1539
    else 
    {
1540
	SelectObject( hDC, GetSysColorPen(COLOR_3DFACE));
1541
	MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
1542
	LineTo( hDC, lprect->right, lprect->bottom );
Alexandre Julliard's avatar
Alexandre Julliard committed
1543
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1544

1545 1546
    if (lppop->nItems == 0)
    {
1547
        retvalue = GetSystemMetrics(SM_CYMENU);
1548 1549
        goto END;
    }
1550

Alexandre Julliard's avatar
Alexandre Julliard committed
1551
    for (i = 0; i < lppop->nItems; i++)
Alexandre Julliard's avatar
Alexandre Julliard committed
1552
    {
1553 1554
        MENU_DrawMenuItem( hwnd, hMenu, hwnd,
                           hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1555
    }
1556
    retvalue = lppop->Height;
1557

1558
END:
1559
    if (hfontOld) SelectObject (hDC, hfontOld);
1560
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1561
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1562

1563

Alexandre Julliard's avatar
Alexandre Julliard committed
1564 1565 1566 1567 1568
/***********************************************************************
 *           MENU_ShowPopup
 *
 * Display a popup menu.
 */
1569 1570
static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
                              INT x, INT y, INT xanchor, INT yanchor )
Alexandre Julliard's avatar
Alexandre Julliard committed
1571
{
1572 1573
    POPUPMENU *menu;
    UINT width, height;
Alexandre Julliard's avatar
Alexandre Julliard committed
1574

1575
    TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1576 1577
    hwndOwner, hmenu, id, x, y, xanchor, yanchor);

1578
    if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1579 1580
    if (menu->FocusedItem != NO_SELECTED_ITEM)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1581
	menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
Alexandre Julliard's avatar
Alexandre Julliard committed
1582 1583
	menu->FocusedItem = NO_SELECTED_ITEM;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1584

1585
    /* store the owner for DrawItem */
1586 1587
    menu->hwndOwner = hwndOwner;

Alexandre Julliard's avatar
Alexandre Julliard committed
1588

1589
    MENU_PopupMenuCalcSize( menu, hwndOwner );
Alexandre Julliard's avatar
Alexandre Julliard committed
1590

1591
    /* adjust popup menu pos so that it fits within the desktop */
Alexandre Julliard's avatar
Alexandre Julliard committed
1592

1593 1594
    width = menu->Width + GetSystemMetrics(SM_CXBORDER);
    height = menu->Height + GetSystemMetrics(SM_CYBORDER); 
Alexandre Julliard's avatar
Alexandre Julliard committed
1595

1596 1597 1598 1599 1600 1601 1602 1603
    if( x + width > GetSystemMetrics(SM_CXSCREEN ))
    {
        if( xanchor )
            x -= width - xanchor;
        if( x + width > GetSystemMetrics(SM_CXSCREEN))
            x = GetSystemMetrics(SM_CXSCREEN) - width;
    }
    if( x < 0 ) x = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1604

1605 1606 1607 1608 1609 1610 1611 1612
    if( y + height > GetSystemMetrics(SM_CYSCREEN ))
    {
        if( yanchor )
            y -= height + yanchor;
        if( y + height > GetSystemMetrics(SM_CYSCREEN ))
            y = GetSystemMetrics(SM_CYSCREEN) - height;
    }
    if( y < 0 ) y = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1613

1614 1615 1616 1617 1618
    if( TWEAK_WineLook == WIN31_LOOK )
    {
        width += POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER);  /* add space for shading */
        height += POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1619

1620 1621 1622 1623 1624 1625 1626
    /* NOTE: In Windows, top menu popup is not owned. */
    menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
                                WS_POPUP, x, y, width, height,
                                hwndOwner, 0, GetWindowLongA(hwndOwner,GWL_HINSTANCE),
                                (LPVOID)hmenu );
    if( !menu->hWnd ) return FALSE;
    if (!top_popup) top_popup = menu->hWnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
1627

1628 1629 1630 1631 1632 1633
    /* Display the window */

    SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
                  SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
    UpdateWindow( menu->hWnd );
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1634 1635 1636
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1637 1638 1639
/***********************************************************************
 *           MENU_SelectItem
 */
1640
static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1641
                             BOOL sendMenuSelect, HMENU topmenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
1642
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1643
    LPPOPUPMENU lppop;
1644
    HDC hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1645

1646
    TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
1647

1648
    lppop = MENU_GetMenu( hmenu );
1649
    if ((!lppop) || (!lppop->nItems) || (!lppop->hWnd)) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1650

Alexandre Julliard's avatar
Alexandre Julliard committed
1651
    if (lppop->FocusedItem == wIndex) return;
1652 1653
    if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
    else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
Alexandre Julliard's avatar
Alexandre Julliard committed
1654

1655 1656
    SelectObject( hdc, hMenuFont);

Alexandre Julliard's avatar
Alexandre Julliard committed
1657 1658
      /* Clear previous highlighted item */
    if (lppop->FocusedItem != NO_SELECTED_ITEM) 
Alexandre Julliard's avatar
Alexandre Julliard committed
1659
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1660
	lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1661
	MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
Alexandre Julliard's avatar
Alexandre Julliard committed
1662 1663
                          lppop->Height, !(lppop->wFlags & MF_POPUP),
			  ODA_SELECT );
Alexandre Julliard's avatar
Alexandre Julliard committed
1664 1665 1666 1667 1668 1669
    }

      /* Highlight new item (if any) */
    lppop->FocusedItem = wIndex;
    if (lppop->FocusedItem != NO_SELECTED_ITEM) 
    {
1670 1671 1672 1673 1674 1675
        if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
            lppop->items[wIndex].fState |= MF_HILITE;
            MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc, 
                    &lppop->items[wIndex], lppop->Height,
                    !(lppop->wFlags & MF_POPUP), ODA_SELECT );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1676
        if (sendMenuSelect)
Alexandre Julliard's avatar
Alexandre Julliard committed
1677 1678
        {
            MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1679
	    SendMessageA( hwndOwner, WM_MENUSELECT, 
1680 1681 1682
                     MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
                     ip->fType | ip->fState | MF_MOUSESELECT |
                     (lppop->wFlags & MF_SYSMENU)), hmenu);
Alexandre Julliard's avatar
Alexandre Julliard committed
1683
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1684
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1685
    else if (sendMenuSelect) {
1686 1687 1688
        if(topmenu){
            int pos;
            if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
1689
                POPUPMENU *ptm = MENU_GetMenu( topmenu );
1690 1691 1692 1693 1694 1695
                MENUITEM *ip = &ptm->items[pos];
                SendMessageA( hwndOwner, WM_MENUSELECT, MAKELONG(pos, 
                         ip->fType | ip->fState | MF_MOUSESELECT |
                         (ptm->wFlags & MF_SYSMENU)), topmenu);
            }
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1696
    }
1697
    ReleaseDC( lppop->hWnd, hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1698 1699 1700 1701
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1702
 *           MENU_MoveSelection
Alexandre Julliard's avatar
Alexandre Julliard committed
1703
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1704 1705 1706
 * Moves currently selected item according to the offset parameter.
 * If there is no selection then it should select the last item if
 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
Alexandre Julliard's avatar
Alexandre Julliard committed
1707
 */
1708
static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
Alexandre Julliard's avatar
Alexandre Julliard committed
1709
{
1710
    INT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
1711 1712
    POPUPMENU *menu;

1713
    TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner, hmenu, offset);
1714

1715 1716
    menu = MENU_GetMenu( hmenu );
    if ((!menu) || (!menu->items)) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1717 1718

    if ( menu->FocusedItem != NO_SELECTED_ITEM )
Alexandre Julliard's avatar
Alexandre Julliard committed
1719
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1720
	if( menu->nItems == 1 ) return; else
Alexandre Julliard's avatar
Alexandre Julliard committed
1721 1722
	for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems 
					    ; i += offset)
Alexandre Julliard's avatar
Alexandre Julliard committed
1723
	    if (!(menu->items[i].fType & MF_SEPARATOR))
Alexandre Julliard's avatar
Alexandre Julliard committed
1724
	    {
1725
		MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1726
		return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1727
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1728
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1729

Alexandre Julliard's avatar
Alexandre Julliard committed
1730 1731
    for ( i = (offset > 0) ? 0 : menu->nItems - 1; 
		  i >= 0 && i < menu->nItems ; i += offset)
Alexandre Julliard's avatar
Alexandre Julliard committed
1732
	if (!(menu->items[i].fType & MF_SEPARATOR))
Alexandre Julliard's avatar
Alexandre Julliard committed
1733
	{
1734
	    MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1735 1736
	    return;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1737 1738 1739
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1740 1741 1742
/**********************************************************************
 *         MENU_SetItemData
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1743 1744
 * Set an item flags, id and text ptr. Called by InsertMenu() and
 * ModifyMenu().
Alexandre Julliard's avatar
Alexandre Julliard committed
1745
 */
1746
static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id,
1747
                                LPCWSTR str )
Alexandre Julliard's avatar
Alexandre Julliard committed
1748
{
1749
    LPWSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1750

Alexandre Julliard's avatar
Alexandre Julliard committed
1751
    debug_print_menuitem("MENU_SetItemData from: ", item, "");
1752
    TRACE("flags=%x str=%p\n", flags, str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1753

Alexandre Julliard's avatar
Alexandre Julliard committed
1754 1755
    if (IS_STRING_ITEM(flags))
    {
1756
        if (!str)
Alexandre Julliard's avatar
Alexandre Julliard committed
1757 1758
        {
            flags |= MF_SEPARATOR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1759
            item->text = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1760 1761 1762
        }
        else
        {
1763
            LPWSTR text;
Alexandre Julliard's avatar
Alexandre Julliard committed
1764 1765 1766 1767 1768 1769
            /* Item beginning with a backspace is a help item */
            if (*str == '\b')
            {
                flags |= MF_HELP;
                str++;
            }
1770 1771 1772
            if (!(text = HeapAlloc( GetProcessHeap(), 0, (strlenW(str)+1) * sizeof(WCHAR) )))
                return FALSE;
            strcpyW( text, str );
Alexandre Julliard's avatar
Alexandre Julliard committed
1773
            item->text = text;
Alexandre Julliard's avatar
Alexandre Julliard committed
1774
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1775
    }
1776
    else if (IS_BITMAP_ITEM(flags))
1777
        item->text = (LPWSTR)(HBITMAP)LOWORD(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1778
    else item->text = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1779

Alexandre Julliard's avatar
Alexandre Julliard committed
1780 1781 1782 1783 1784
    if (flags & MF_OWNERDRAW) 
        item->dwItemData = (DWORD)str;
    else
        item->dwItemData = 0;

Alexandre Julliard's avatar
Alexandre Julliard committed
1785
    if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) )
1786
	DestroyMenu( item->hSubMenu );   /* ModifyMenu() spec */
Alexandre Julliard's avatar
Alexandre Julliard committed
1787 1788 1789

    if (flags & MF_POPUP)
    {
1790 1791
	POPUPMENU *menu = MENU_GetMenu((UINT16)id);
        if (menu) menu->wFlags |= MF_POPUP;
Alexandre Julliard's avatar
Alexandre Julliard committed
1792
	else
Alexandre Julliard's avatar
Alexandre Julliard committed
1793 1794 1795 1796 1797 1798 1799
        {
            item->wID = 0;
            item->hSubMenu = 0;
            item->fType = 0;
            item->fState = 0;
	    return FALSE;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1800 1801 1802 1803 1804 1805 1806 1807
    } 

    item->wID = id;
    if (flags & MF_POPUP)
      item->hSubMenu = id;

    if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
      flags |= MF_POPUP; /* keep popup */
Alexandre Julliard's avatar
Alexandre Julliard committed
1808

Alexandre Julliard's avatar
Alexandre Julliard committed
1809 1810 1811
    item->fType = flags & TYPE_MASK;
    item->fState = (flags & STATE_MASK) &
        ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
Alexandre Julliard's avatar
Alexandre Julliard committed
1812

Alexandre Julliard's avatar
Alexandre Julliard committed
1813 1814 1815 1816

    /* Don't call SetRectEmpty here! */


1817
    if (prevText) HeapFree( GetProcessHeap(), 0, prevText );
Alexandre Julliard's avatar
Alexandre Julliard committed
1818

Alexandre Julliard's avatar
Alexandre Julliard committed
1819
    debug_print_menuitem("MENU_SetItemData to  : ", item, "");
Alexandre Julliard's avatar
Alexandre Julliard committed
1820 1821 1822 1823 1824 1825 1826 1827 1828
    return TRUE;
}


/**********************************************************************
 *         MENU_InsertItem
 *
 * Insert a new item into a menu.
 */
1829
static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
1830 1831 1832 1833
{
    MENUITEM *newItems;
    POPUPMENU *menu;

1834
    if (!(menu = MENU_GetMenu(hMenu))) 
Alexandre Julliard's avatar
Alexandre Julliard committed
1835 1836 1837 1838
        return NULL;

    /* Find where to insert new item */

1839 1840 1841
    if (flags & MF_BYPOSITION) {
        if (pos > menu->nItems) 
            pos = menu->nItems;
1842
    } else {
Alexandre Julliard's avatar
Alexandre Julliard committed
1843
        if (!MENU_FindItem( &hMenu, &pos, flags )) 
1844 1845 1846 1847
            pos = menu->nItems;
        else {
            if (!(menu = MENU_GetMenu( hMenu )))
                return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1848 1849 1850 1851 1852
        }
    }

    /* Create new items array */

1853
    newItems = HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1854
    if (!newItems)
Alexandre Julliard's avatar
Alexandre Julliard committed
1855
    {
1856
        WARN("allocation failed\n" );
Alexandre Julliard's avatar
Alexandre Julliard committed
1857 1858 1859 1860
        return NULL;
    }
    if (menu->nItems > 0)
    {
1861
	  /* Copy the old array into the new one */
Alexandre Julliard's avatar
Alexandre Julliard committed
1862 1863
	if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
	if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
Alexandre Julliard's avatar
Alexandre Julliard committed
1864
					(menu->nItems-pos)*sizeof(MENUITEM) );
1865
        HeapFree( GetProcessHeap(), 0, menu->items );
Alexandre Julliard's avatar
Alexandre Julliard committed
1866
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1867
    menu->items = newItems;
Alexandre Julliard's avatar
Alexandre Julliard committed
1868
    menu->nItems++;
Alexandre Julliard's avatar
Alexandre Julliard committed
1869
    memset( &newItems[pos], 0, sizeof(*newItems) );
1870
    menu->Height = 0; /* force size recalculate */
Alexandre Julliard's avatar
Alexandre Julliard committed
1871 1872 1873 1874 1875 1876 1877
    return &newItems[pos];
}


/**********************************************************************
 *         MENU_ParseResource
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1878
 * Parse a standard menu resource and add items to the menu.
Alexandre Julliard's avatar
Alexandre Julliard committed
1879 1880
 * Return a pointer to the end of the resource.
 */
1881
static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
1882 1883
{
    WORD flags, id = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1884
    LPCSTR str;
Alexandre Julliard's avatar
Alexandre Julliard committed
1885 1886 1887

    do
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1888
        flags = GET_WORD(res);
Alexandre Julliard's avatar
Alexandre Julliard committed
1889 1890 1891
        res += sizeof(WORD);
        if (!(flags & MF_POPUP))
        {
Alexandre Julliard's avatar
Alexandre Julliard committed
1892
            id = GET_WORD(res);
Alexandre Julliard's avatar
Alexandre Julliard committed
1893 1894 1895
            res += sizeof(WORD);
        }
        if (!IS_STRING_ITEM(flags))
1896
            ERR("not a string item %04x\n", flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
1897 1898
        str = res;
        if (!unicode) res += strlen(str) + 1;
1899
        else res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
Alexandre Julliard's avatar
Alexandre Julliard committed
1900 1901
        if (flags & MF_POPUP)
        {
1902
            HMENU hSubMenu = CreatePopupMenu();
Alexandre Julliard's avatar
Alexandre Julliard committed
1903 1904 1905
            if (!hSubMenu) return NULL;
            if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
                return NULL;
1906 1907
            if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
            else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
Alexandre Julliard's avatar
Alexandre Julliard committed
1908
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1909
        else  /* Not a popup */
Alexandre Julliard's avatar
Alexandre Julliard committed
1910
        {
1911 1912
            if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
            else AppendMenuW( hMenu, flags, id,
Alexandre Julliard's avatar
Alexandre Julliard committed
1913
                                *(LPCWSTR)str ? (LPCWSTR)str : NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
1914 1915 1916 1917 1918 1919
        }
    } while (!(flags & MF_END));
    return res;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1920 1921 1922 1923 1924 1925
/**********************************************************************
 *         MENUEX_ParseResource
 *
 * Parse an extended menu resource and add items to the menu.
 * Return a pointer to the end of the resource.
 */
1926
static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
Alexandre Julliard's avatar
Alexandre Julliard committed
1927 1928
{
    WORD resinfo;
Alexandre Julliard's avatar
Alexandre Julliard committed
1929
    do {
1930
	MENUITEMINFOW mii;
Alexandre Julliard's avatar
Alexandre Julliard committed
1931

Alexandre Julliard's avatar
Alexandre Julliard committed
1932 1933 1934
	mii.cbSize = sizeof(mii);
	mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
	mii.fType = GET_DWORD(res);
Alexandre Julliard's avatar
Alexandre Julliard committed
1935
        res += sizeof(DWORD);
Alexandre Julliard's avatar
Alexandre Julliard committed
1936
	mii.fState = GET_DWORD(res);
Alexandre Julliard's avatar
Alexandre Julliard committed
1937
        res += sizeof(DWORD);
Alexandre Julliard's avatar
Alexandre Julliard committed
1938
	mii.wID = GET_DWORD(res);
Alexandre Julliard's avatar
Alexandre Julliard committed
1939 1940 1941 1942 1943
        res += sizeof(DWORD);
	resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte.  */
        res += sizeof(WORD);
	/* Align the text on a word boundary.  */
	res += (~((int)res - 1)) & 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1944
	mii.dwTypeData = (LPWSTR) res;
1945
	res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
Alexandre Julliard's avatar
Alexandre Julliard committed
1946 1947 1948
	/* Align the following fields on a dword boundary.  */
	res += (~((int)res - 1)) & 3;

1949 1950
        TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
              mii.fType, mii.fState, mii.wID, resinfo, debugstr_w(mii.dwTypeData));
Alexandre Julliard's avatar
Alexandre Julliard committed
1951

Alexandre Julliard's avatar
Alexandre Julliard committed
1952
	if (resinfo & 1) {	/* Pop-up? */
1953
	    /* DWORD helpid = GET_DWORD(res); FIXME: use this.  */
Alexandre Julliard's avatar
Alexandre Julliard committed
1954
	    res += sizeof(DWORD);
1955
	    mii.hSubMenu = CreatePopupMenu();
Alexandre Julliard's avatar
Alexandre Julliard committed
1956 1957 1958
	    if (!mii.hSubMenu)
		return NULL;
	    if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
1959
		DestroyMenu(mii.hSubMenu);
Alexandre Julliard's avatar
Alexandre Julliard committed
1960 1961
                return NULL;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1962 1963
	    mii.fMask |= MIIM_SUBMENU;
	    mii.fType |= MF_POPUP;
Alexandre Julliard's avatar
Alexandre Julliard committed
1964
        }
1965
	InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
Alexandre Julliard's avatar
Alexandre Julliard committed
1966 1967 1968 1969 1970
    } while (!(resinfo & MF_END));
    return res;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1971 1972 1973 1974 1975
/***********************************************************************
 *           MENU_GetSubPopup
 *
 * Return the handle of the selected sub-popup menu (if any).
 */
1976
static HMENU MENU_GetSubPopup( HMENU hmenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
1977
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1978 1979 1980
    POPUPMENU *menu;
    MENUITEM *item;

1981
    menu = MENU_GetMenu( hmenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
1982

1983
    if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1984

Alexandre Julliard's avatar
Alexandre Julliard committed
1985
    item = &menu->items[menu->FocusedItem];
Alexandre Julliard's avatar
Alexandre Julliard committed
1986 1987
    if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
        return item->hSubMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
1988
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1989 1990 1991
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1992 1993 1994 1995 1996
/***********************************************************************
 *           MENU_HideSubPopups
 *
 * Hide the sub-popup menus of this menu.
 */
1997 1998
static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
                                BOOL sendMenuSelect )
Alexandre Julliard's avatar
Alexandre Julliard committed
1999
{
2000
    POPUPMENU *menu = MENU_GetMenu( hmenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
2001

2002
    TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
2003

2004
    if (menu && top_popup)
Alexandre Julliard's avatar
Alexandre Julliard committed
2005
    {
2006
	HMENU hsubmenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
2007 2008 2009 2010 2011 2012
	POPUPMENU *submenu;
	MENUITEM *item;

	if (menu->FocusedItem != NO_SELECTED_ITEM)
	{
	    item = &menu->items[menu->FocusedItem];
Alexandre Julliard's avatar
Alexandre Julliard committed
2013 2014 2015 2016
	    if (!(item->fType & MF_POPUP) ||
		!(item->fState & MF_MOUSESELECT)) return;
	    item->fState &= ~MF_MOUSESELECT;
	    hsubmenu = item->hSubMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
2017 2018
	} else return;

2019
	submenu = MENU_GetMenu( hsubmenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
2020
	MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
2021
	MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
2022 2023
        DestroyWindow( submenu->hWnd );
        submenu->hWnd = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2024
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2025 2026 2027
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2028 2029 2030 2031 2032 2033
/***********************************************************************
 *           MENU_ShowSubPopup
 *
 * Display the sub-menu of the selected item of this menu.
 * Return the handle of the submenu, or hmenu if no submenu to display.
 */
2034
static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
2035
                                  BOOL selectFirst, UINT wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
2036
{
2037
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
2038 2039
    POPUPMENU *menu;
    MENUITEM *item;
2040
    HDC hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
2041

2042
    TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, selectFirst);
2043

2044
    if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
2045

2046
    if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
2047

Alexandre Julliard's avatar
Alexandre Julliard committed
2048
    item = &menu->items[menu->FocusedItem];
2049
    if (!(item->fType & MF_POPUP) || (item->fState & (MF_GRAYED | MF_DISABLED)))
2050
        return hmenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
2051

2052 2053
    /* message must be sent before using item,
       because nearly everything may be changed by the application ! */
Alexandre Julliard's avatar
Alexandre Julliard committed
2054

2055 2056 2057
    /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
    if (!(wFlags & TPM_NONOTIFY))
       SendMessageA( hwndOwner, WM_INITMENUPOPUP, item->hSubMenu,
Alexandre Julliard's avatar
Alexandre Julliard committed
2058 2059
		   MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));

Alexandre Julliard's avatar
Alexandre Julliard committed
2060 2061 2062
    item = &menu->items[menu->FocusedItem];
    rect = item->rect;

2063
    /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
Alexandre Julliard's avatar
Alexandre Julliard committed
2064 2065
    if (!(item->fState & MF_HILITE)) 
    {
2066 2067
        if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
        else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
2068 2069 2070

        SelectObject( hdc, hMenuFont);

Alexandre Julliard's avatar
Alexandre Julliard committed
2071
        item->fState |= MF_HILITE;
2072
        MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE ); 
2073
	ReleaseDC( menu->hWnd, hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
2074 2075 2076 2077
    }
    if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
      item->rect = rect;

Alexandre Julliard's avatar
Alexandre Julliard committed
2078
    item->fState |= MF_MOUSESELECT;
Alexandre Julliard's avatar
Alexandre Julliard committed
2079 2080

    if (IS_SYSTEM_MENU(menu))
Alexandre Julliard's avatar
Alexandre Julliard committed
2081
    {
2082 2083 2084
	MENU_InitSysMenuPopup(item->hSubMenu,
                              GetWindowLongA( menu->hWnd, GWL_STYLE ),
                              GetClassLongA( menu->hWnd, GCL_STYLE));
Alexandre Julliard's avatar
Alexandre Julliard committed
2085

2086
	NC_GetSysPopupPos( menu->hWnd, &rect );
Alexandre Julliard's avatar
Alexandre Julliard committed
2087
	rect.top = rect.bottom;
2088 2089
	rect.right = GetSystemMetrics(SM_CXSIZE);
        rect.bottom = GetSystemMetrics(SM_CYSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
2090 2091 2092
    }
    else
    {
2093
        GetWindowRect( menu->hWnd, &rect );
Alexandre Julliard's avatar
Alexandre Julliard committed
2094 2095
	if (menu->wFlags & MF_POPUP)
	{
2096 2097
	    rect.left += item->rect.right - GetSystemMetrics(SM_CXBORDER);
	    rect.top += item->rect.top;
2098
	    rect.right = item->rect.left - item->rect.right + GetSystemMetrics(SM_CXBORDER);
Alexandre Julliard's avatar
Alexandre Julliard committed
2099 2100 2101 2102
	    rect.bottom = item->rect.top - item->rect.bottom;
	}
	else
	{
2103 2104
	    rect.left += item->rect.left;
	    rect.top += item->rect.bottom;
Alexandre Julliard's avatar
Alexandre Julliard committed
2105 2106 2107
	    rect.right = item->rect.right - item->rect.left;
	    rect.bottom = item->rect.bottom - item->rect.top;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
2108
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2109

Alexandre Julliard's avatar
Alexandre Julliard committed
2110
    MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
Alexandre Julliard's avatar
Alexandre Julliard committed
2111
		    rect.left, rect.top, rect.right, rect.bottom );
Alexandre Julliard's avatar
Alexandre Julliard committed
2112
    if (selectFirst)
Alexandre Julliard's avatar
Alexandre Julliard committed
2113 2114
        MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
    return item->hSubMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
2115
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2116

2117 2118 2119 2120 2121 2122 2123


/**********************************************************************
 *         MENU_IsMenuActive
 */
BOOL MENU_IsMenuActive(void)
{
2124
    return (top_popup != 0);
2125 2126
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2127
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
2128
 *           MENU_PtMenu
Alexandre Julliard's avatar
Alexandre Julliard committed
2129
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
2130 2131
 * Walks menu chain trying to find a menu pt maps to.
 */
2132
static HMENU MENU_PtMenu( HMENU hMenu, POINT pt )
Alexandre Julliard's avatar
Alexandre Julliard committed
2133
{
2134
   POPUPMENU *menu = MENU_GetMenu( hMenu );
2135 2136
   UINT item = menu->FocusedItem;
   HMENU ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2137 2138

   /* try subpopup first (if any) */
2139 2140 2141 2142
   ret = (item != NO_SELECTED_ITEM &&
          (menu->items[item].fType & MF_POPUP) &&
          (menu->items[item].fState & MF_MOUSESELECT))
        ? MENU_PtMenu(menu->items[item].hSubMenu, pt) : 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2143

2144
   if (!ret)  /* check the current window (avoiding WM_HITTEST) */
Alexandre Julliard's avatar
Alexandre Julliard committed
2145
   {
2146 2147 2148 2149 2150 2151 2152 2153 2154
       INT ht = NC_HandleNCHitTest( menu->hWnd, pt );
       if( menu->wFlags & MF_POPUP )
       {
           if (ht != HTNOWHERE && ht != HTERROR) ret = hMenu;
       }
       else if (ht == HTSYSMENU)
           ret = get_win_sys_menu( menu->hWnd );
       else if (ht == HTMENU)
           ret = GetMenu( menu->hWnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
2155
   }
2156
   return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2157
}
2158

Alexandre Julliard's avatar
Alexandre Julliard committed
2159 2160 2161 2162
/***********************************************************************
 *           MENU_ExecFocusedItem
 *
 * Execute a menu item (for instance when user pressed Enter).
2163
 * Return the wID of the executed item. Otherwise, -1 indicating
2164
 * that no menu item was executed;
2165 2166 2167
 * Have to receive the flags for the TrackPopupMenu options to avoid
 * sending unwanted message.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
2168
 */
2169
static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
2170 2171
{
    MENUITEM *item;
2172
    POPUPMENU *menu = MENU_GetMenu( hMenu );
2173

2174
    TRACE("%p hmenu=0x%04x\n", pmt, hMenu);
2175

Alexandre Julliard's avatar
Alexandre Julliard committed
2176
    if (!menu || !menu->nItems || 
2177
	(menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
2178

Alexandre Julliard's avatar
Alexandre Julliard committed
2179
    item = &menu->items[menu->FocusedItem];
Alexandre Julliard's avatar
Alexandre Julliard committed
2180

2181
    TRACE("%08x %08x %08x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2182 2183 2184
                 hMenu, item->wID, item->hSubMenu);

    if (!(item->fType & MF_POPUP))
Alexandre Julliard's avatar
Alexandre Julliard committed
2185
    {
2186
	if (!(item->fState & (MF_GRAYED | MF_DISABLED)) && !(item->fType & MF_SEPARATOR))
Alexandre Julliard's avatar
Alexandre Julliard committed
2187
	{
2188 2189 2190
	    /* If TPM_RETURNCMD is set you return the id, but 
	       do not send a message to the owner */	   
	    if(!(wFlags & TPM_RETURNCMD))
Alexandre Julliard's avatar
Alexandre Julliard committed
2191
	    {
2192 2193 2194 2195 2196
		if( menu->wFlags & MF_SYSMENU )
		    PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
				  MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
		else
		    PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2197
	    }
2198
	    return item->wID;
Alexandre Julliard's avatar
Alexandre Julliard committed
2199
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
2200 2201
    }
    else
2202
	pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2203

2204
    return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
2205 2206
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2207
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
2208
 *           MENU_SwitchTracking
Alexandre Julliard's avatar
Alexandre Julliard committed
2209
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
2210
 * Helper function for menu navigation routines.
Alexandre Julliard's avatar
Alexandre Julliard committed
2211
 */
2212
static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
Alexandre Julliard's avatar
Alexandre Julliard committed
2213
{
2214 2215
    POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
    POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
2216

2217
    TRACE("%p hmenu=0x%04x 0x%04x\n", pmt, hPtMenu, id);
2218

Alexandre Julliard's avatar
Alexandre Julliard committed
2219 2220
    if( pmt->hTopMenu != hPtMenu &&
	!((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
Alexandre Julliard's avatar
Alexandre Julliard committed
2221
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
2222 2223
	/* both are top level menus (system and menu-bar) */
	MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2224
	MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2225 2226 2227
        pmt->hTopMenu = hPtMenu;
    }
    else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2228
    MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2229 2230 2231 2232 2233 2234 2235 2236
}


/***********************************************************************
 *           MENU_ButtonDown
 *
 * Return TRUE if we can go on with menu tracking.
 */
2237
static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
2238
{
2239
    TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2240

Alexandre Julliard's avatar
Alexandre Julliard committed
2241
    if (hPtMenu)
Alexandre Julliard's avatar
Alexandre Julliard committed
2242
    {
2243
	UINT id = 0;
2244
	POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
2245 2246 2247 2248 2249 2250 2251 2252
	MENUITEM *item;

	if( IS_SYSTEM_MENU(ptmenu) )
	    item = ptmenu->items;
	else
	    item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );

	if( item )
Alexandre Julliard's avatar
Alexandre Julliard committed
2253
	{
2254 2255
	    if( ptmenu->FocusedItem != id )
		MENU_SwitchTracking( pmt, hPtMenu, id );
Alexandre Julliard's avatar
Alexandre Julliard committed
2256

2257 2258
	    /* If the popup menu is not already "popped" */
	    if(!(item->fState & MF_MOUSESELECT ))
2259
	    {
2260
		pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
Alexandre Julliard's avatar
Alexandre Julliard committed
2261

2262
		/* In win31, a newly popped menu always remains opened for the next buttonup */
2263 2264 2265 2266
		if(TWEAK_WineLook == WIN31_LOOK)
		    ptmenu->bTimeToHide = FALSE;		    
	    }

Alexandre Julliard's avatar
Alexandre Julliard committed
2267 2268
	    return TRUE;
	} 
2269
	/* Else the click was on the menu bar, finish the tracking */
Alexandre Julliard's avatar
Alexandre Julliard committed
2270
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2271
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2272 2273
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2274 2275 2276
/***********************************************************************
 *           MENU_ButtonUp
 *
2277 2278
 * Return the value of MENU_ExecFocusedItem if
 * the selected item was not a popup. Else open the popup.
2279
 * A -1 return value indicates that we go on with menu tracking.
2280
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
2281
 */
2282
static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
2283
{
2284
    TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2285

Alexandre Julliard's avatar
Alexandre Julliard committed
2286
    if (hPtMenu)
Alexandre Julliard's avatar
Alexandre Julliard committed
2287
    {
2288
	UINT id = 0;
2289
	POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
2290
	MENUITEM *item;
Alexandre Julliard's avatar
Alexandre Julliard committed
2291

Alexandre Julliard's avatar
Alexandre Julliard committed
2292 2293 2294 2295
        if( IS_SYSTEM_MENU(ptmenu) )
            item = ptmenu->items;
        else
            item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
Alexandre Julliard's avatar
Alexandre Julliard committed
2296

Alexandre Julliard's avatar
Alexandre Julliard committed
2297
	if( item && (ptmenu->FocusedItem == id ))
Alexandre Julliard's avatar
Alexandre Julliard committed
2298
	{
Alexandre Julliard's avatar
Alexandre Julliard committed
2299
	    if( !(item->fType & MF_POPUP) )
2300
		return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
2301

2302 2303 2304
	    /* If we are dealing with the top-level menu            */
	    /* and this is a click on an already "popped" item:     */
	    /* Stop the menu tracking and close the opened submenus */
2305
	    if((pmt->hTopMenu == hPtMenu) && (ptmenu->bTimeToHide == TRUE))
2306
		return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2307
	}
2308
	ptmenu->bTimeToHide = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2309
    }
2310
    return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
2311 2312 2313
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2314 2315 2316 2317 2318
/***********************************************************************
 *           MENU_MouseMove
 *
 * Return TRUE if we can go on with menu tracking.
 */
2319
static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
2320
{
2321
    UINT id = NO_SELECTED_ITEM;
Alexandre Julliard's avatar
Alexandre Julliard committed
2322
    POPUPMENU *ptmenu = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
2323

Alexandre Julliard's avatar
Alexandre Julliard committed
2324
    if( hPtMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
2325
    {
2326
	ptmenu = MENU_GetMenu( hPtMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
2327 2328 2329 2330 2331 2332 2333
        if( IS_SYSTEM_MENU(ptmenu) )
	    id = 0;
        else
            MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
    } 

    if( id == NO_SELECTED_ITEM )
Alexandre Julliard's avatar
Alexandre Julliard committed
2334
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
2335
	MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu, 
2336 2337
			 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
        
Alexandre Julliard's avatar
Alexandre Julliard committed
2338
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2339
    else if( ptmenu->FocusedItem != id )
Alexandre Julliard's avatar
Alexandre Julliard committed
2340
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
2341
	    MENU_SwitchTracking( pmt, hPtMenu, id );
2342
	    pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
2343 2344
    }
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2345 2346
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2347

Alexandre Julliard's avatar
Alexandre Julliard committed
2348 2349
/***********************************************************************
 *           MENU_DoNextMenu
Alexandre Julliard's avatar
Alexandre Julliard committed
2350 2351
 *
 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
Alexandre Julliard's avatar
Alexandre Julliard committed
2352
 */
2353
static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
Alexandre Julliard's avatar
Alexandre Julliard committed
2354
{
2355
    POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
2356 2357 2358 2359

    if( (vk == VK_LEFT &&  menu->FocusedItem == 0 ) ||
        (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
    {
2360
        MDINEXTMENU next_menu;
2361 2362 2363
	HMENU hNewMenu;
	HWND  hNewWnd;
	UINT  id = 0;
2364 2365 2366 2367 2368

        next_menu.hmenuIn = (IS_SYSTEM_MENU(menu)) ? GetSubMenu(pmt->hTopMenu,0) : pmt->hTopMenu;
        next_menu.hmenuNext = 0;
        next_menu.hwndNext = 0;
        SendMessageW( pmt->hOwnerWnd, WM_NEXTMENU, vk, (LPARAM)&next_menu );
Alexandre Julliard's avatar
Alexandre Julliard committed
2369

2370
	TRACE("%04x [%04x] -> %04x [%04x]\n",
2371
              pmt->hCurrentMenu, pmt->hOwnerWnd, next_menu.hmenuNext, next_menu.hwndNext );
Alexandre Julliard's avatar
Alexandre Julliard committed
2372

2373
	if (!next_menu.hmenuNext || !next_menu.hwndNext)
Alexandre Julliard's avatar
Alexandre Julliard committed
2374
	{
2375
            DWORD style = GetWindowLongA( pmt->hOwnerWnd, GWL_STYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
2376 2377 2378 2379
	    hNewWnd = pmt->hOwnerWnd;
	    if( IS_SYSTEM_MENU(menu) )
	    {
		/* switch to the menu bar */
Alexandre Julliard's avatar
Alexandre Julliard committed
2380

2381
                if(style & WS_CHILD || !(hNewMenu = GetMenu(hNewWnd))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2382

Alexandre Julliard's avatar
Alexandre Julliard committed
2383 2384
	        if( vk == VK_LEFT )
	        {
2385
		    menu = MENU_GetMenu( hNewMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
2386 2387 2388
		    id = menu->nItems - 1;
	        }
	    }
2389
	    else if (style & WS_SYSMENU )
Alexandre Julliard's avatar
Alexandre Julliard committed
2390 2391
	    {
		/* switch to the system menu */
2392
	        hNewMenu = get_win_sys_menu( hNewWnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
2393
	    }
2394
            else return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2395 2396 2397
	}
	else    /* application returned a new menu to switch to */
	{
2398
            hNewMenu = next_menu.hmenuNext;
2399
            hNewWnd = WIN_GetFullHandle( next_menu.hwndNext );
Alexandre Julliard's avatar
Alexandre Julliard committed
2400

2401
	    if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
Alexandre Julliard's avatar
Alexandre Julliard committed
2402
	    {
2403
                DWORD style = GetWindowLongA( hNewWnd, GWL_STYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
2404

2405 2406
		if (style & WS_SYSMENU &&
		    GetSubMenu(get_win_sys_menu(hNewWnd), 0) == hNewMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
2407 2408
		{
	            /* get the real system menu */
2409
		    hNewMenu =  get_win_sys_menu(hNewWnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2410
		}
2411
	        else if (style & WS_CHILD || GetMenu(hNewWnd) != hNewMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
2412
		{
2413 2414
		    /* FIXME: Not sure what to do here;
		     * perhaps try to track hNewMenu as a popup? */
Alexandre Julliard's avatar
Alexandre Julliard committed
2415

2416
		    TRACE(" -- got confused.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2417 2418 2419 2420 2421 2422 2423
		    return FALSE;
		}
	    }
	    else return FALSE;
	}

	if( hNewMenu != pmt->hTopMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
2424
	{
2425 2426
	    MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, 
                    FALSE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2427 2428
	    if( pmt->hCurrentMenu != pmt->hTopMenu ) 
		MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
2429 2430
	}

Alexandre Julliard's avatar
Alexandre Julliard committed
2431 2432 2433 2434 2435 2436
	if( hNewWnd != pmt->hOwnerWnd )
	{
	    ReleaseCapture(); 
	    pmt->hOwnerWnd = hNewWnd;
	    EVENT_Capture( pmt->hOwnerWnd, HTMENU );
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
2437

Alexandre Julliard's avatar
Alexandre Julliard committed
2438
	pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2439
	MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 ); 
Alexandre Julliard's avatar
Alexandre Julliard committed
2440

Alexandre Julliard's avatar
Alexandre Julliard committed
2441 2442 2443 2444
	return TRUE;
    }
    return FALSE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2445

Alexandre Julliard's avatar
Alexandre Julliard committed
2446 2447 2448 2449 2450 2451
/***********************************************************************
 *           MENU_SuspendPopup
 *
 * The idea is not to show the popup if the next input message is
 * going to hide it anyway.
 */
2452
static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
Alexandre Julliard's avatar
Alexandre Julliard committed
2453
{
2454
    MSG msg;
Alexandre Julliard's avatar
Alexandre Julliard committed
2455

Alexandre Julliard's avatar
Alexandre Julliard committed
2456
    msg.hwnd = pmt->hOwnerWnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
2457

2458
    PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
Alexandre Julliard's avatar
Alexandre Julliard committed
2459 2460 2461 2462 2463
    pmt->trackFlags |= TF_SKIPREMOVE;

    switch( uMsg )
    {
	case WM_KEYDOWN:
2464
	     PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
Alexandre Julliard's avatar
Alexandre Julliard committed
2465 2466
	     if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
	     {
2467 2468
		 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
	         PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
Alexandre Julliard's avatar
Alexandre Julliard committed
2469 2470 2471 2472 2473 2474 2475 2476
	         if( msg.message == WM_KEYDOWN &&
		    (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
	         {
		     pmt->trackFlags |= TF_SUSPENDPOPUP;
		     return TRUE;
	         }
	     }
	     break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2477
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2478

Alexandre Julliard's avatar
Alexandre Julliard committed
2479 2480 2481
    /* failures go through this */
    pmt->trackFlags &= ~TF_SUSPENDPOPUP;
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2482
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2483

2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518
/***********************************************************************
 *           MENU_KeyEscape
 *
 * Handle a VK_ESCAPE key event in a menu. 
 */
static BOOL MENU_KeyEscape(MTRACKER* pmt, UINT wFlags)
{
    BOOL bEndMenu = TRUE;

    if (pmt->hCurrentMenu != pmt->hTopMenu)
    {
        POPUPMENU *menu = MENU_GetMenu(pmt->hCurrentMenu);

        if (menu->wFlags & MF_POPUP)
        {
            HMENU hmenutmp, hmenuprev;

            hmenuprev = hmenutmp = pmt->hTopMenu;

            /* close topmost popup */
            while (hmenutmp != pmt->hCurrentMenu)
            {
                hmenuprev = hmenutmp;
                hmenutmp = MENU_GetSubPopup( hmenuprev );
            }

            MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
            pmt->hCurrentMenu = hmenuprev;
            bEndMenu = FALSE;
        }
    }

    return bEndMenu;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2519 2520 2521
/***********************************************************************
 *           MENU_KeyLeft
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
2522
 * Handle a VK_LEFT key event in a menu. 
Alexandre Julliard's avatar
Alexandre Julliard committed
2523
 */
2524
static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
2525
{
Alexandre Julliard's avatar
Alexandre Julliard committed
2526
    POPUPMENU *menu;
2527 2528
    HMENU hmenutmp, hmenuprev;
    UINT  prevcol;
Alexandre Julliard's avatar
Alexandre Julliard committed
2529

Alexandre Julliard's avatar
Alexandre Julliard committed
2530
    hmenuprev = hmenutmp = pmt->hTopMenu;
2531
    menu = MENU_GetMenu( hmenutmp );
Alexandre Julliard's avatar
Alexandre Julliard committed
2532

Alexandre Julliard's avatar
Alexandre Julliard committed
2533 2534 2535 2536 2537
    /* Try to move 1 column left (if possible) */
    if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) != 
	NO_SELECTED_ITEM ) {
	
	MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2538
			 prevcol, TRUE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2539 2540 2541
	return;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
2542 2543
    /* close topmost popup */
    while (hmenutmp != pmt->hCurrentMenu)
Alexandre Julliard's avatar
Alexandre Julliard committed
2544
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
2545
	hmenuprev = hmenutmp;
Alexandre Julliard's avatar
Alexandre Julliard committed
2546 2547
	hmenutmp = MENU_GetSubPopup( hmenuprev );
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2548

Alexandre Julliard's avatar
Alexandre Julliard committed
2549 2550 2551 2552
    MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
    pmt->hCurrentMenu = hmenuprev; 

    if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
Alexandre Julliard's avatar
Alexandre Julliard committed
2553
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
2554
	/* move menu bar selection if no more popups are left */
Alexandre Julliard's avatar
Alexandre Julliard committed
2555

Alexandre Julliard's avatar
Alexandre Julliard committed
2556 2557
	if( !MENU_DoNextMenu( pmt, VK_LEFT) )
	     MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
Alexandre Julliard's avatar
Alexandre Julliard committed
2558

Alexandre Julliard's avatar
Alexandre Julliard committed
2559
	if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
Alexandre Julliard's avatar
Alexandre Julliard committed
2560
	{
Alexandre Julliard's avatar
Alexandre Julliard committed
2561 2562 2563 2564
	   /* A sublevel menu was displayed - display the next one
	    * unless there is another displacement coming up */

	    if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2565 2566
		pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
						pmt->hTopMenu, TRUE, wFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
2567
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
2568
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2569 2570 2571
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2572 2573 2574 2575 2576
/***********************************************************************
 *           MENU_KeyRight
 *
 * Handle a VK_RIGHT key event in a menu.
 */
2577
static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
2578
{
2579
    HMENU hmenutmp;
2580
    POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2581
    UINT  nextcol;
Alexandre Julliard's avatar
Alexandre Julliard committed
2582

2583
    TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2584
		  pmt->hCurrentMenu,
2585 2586 2587
		  debugstr_w((MENU_GetMenu(pmt->hCurrentMenu))->
		     items[0].text),
		  pmt->hTopMenu, debugstr_w(menu->items[0].text) );
Alexandre Julliard's avatar
Alexandre Julliard committed
2588

Alexandre Julliard's avatar
Alexandre Julliard committed
2589
    if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
Alexandre Julliard's avatar
Alexandre Julliard committed
2590
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
2591
	/* If already displaying a popup, try to display sub-popup */
Alexandre Julliard's avatar
Alexandre Julliard committed
2592

Alexandre Julliard's avatar
Alexandre Julliard committed
2593
	hmenutmp = pmt->hCurrentMenu;
2594
	pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
2595

Alexandre Julliard's avatar
Alexandre Julliard committed
2596 2597
	/* if subpopup was displayed then we are done */
	if (hmenutmp != pmt->hCurrentMenu) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
2598
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2599

Alexandre Julliard's avatar
Alexandre Julliard committed
2600 2601 2602
    /* Check to see if there's another column */
    if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) != 
	NO_SELECTED_ITEM ) {
2603
	TRACE("Going to %d.\n", nextcol );
Alexandre Julliard's avatar
Alexandre Julliard committed
2604
	MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2605
			 nextcol, TRUE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2606 2607 2608
	return;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
2609
    if (!(menu->wFlags & MF_POPUP))	/* menu bar tracking */
Alexandre Julliard's avatar
Alexandre Julliard committed
2610
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
2611
	if( pmt->hCurrentMenu != pmt->hTopMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
2612
	{
Alexandre Julliard's avatar
Alexandre Julliard committed
2613 2614 2615 2616 2617 2618 2619 2620 2621 2622
	    MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
	    hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
	} else hmenutmp = 0;

	/* try to move to the next item */
	if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
	     MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );

	if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
	    if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2623 2624
		pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, 
						       pmt->hTopMenu, TRUE, wFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
2625 2626
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2627

Alexandre Julliard's avatar
Alexandre Julliard committed
2628 2629 2630 2631 2632
/***********************************************************************
 *           MENU_TrackMenu
 *
 * Menu tracking code.
 */
2633 2634
static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
                              HWND hwnd, const RECT *lprect )
Alexandre Julliard's avatar
Alexandre Julliard committed
2635
{
2636
    MSG msg;
Alexandre Julliard's avatar
Alexandre Julliard committed
2637
    POPUPMENU *menu;
2638
    BOOL fRemove;
2639
    INT executedMenuId = -1;
2640
    MTRACKER mt;
2641
    BOOL enterIdleSent = FALSE;
2642 2643 2644 2645

    mt.trackFlags = 0;
    mt.hCurrentMenu = hmenu;
    mt.hTopMenu = hmenu;
2646
    mt.hOwnerWnd = WIN_GetFullHandle( hwnd );
2647 2648
    mt.pt.x = x;
    mt.pt.y = y;
Alexandre Julliard's avatar
Alexandre Julliard committed
2649

2650
    TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2651 2652
	    hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
	    (lprect) ? lprect->right : 0,  (lprect) ? lprect->bottom : 0);
2653

Alexandre Julliard's avatar
Alexandre Julliard committed
2654
    fEndMenu = FALSE;
2655
    if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2656

2657 2658 2659 2660 2661 2662
    if (wFlags & TPM_BUTTONDOWN) 
    {
	/* Get the result in order to start the tracking or not */
	fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
	fEndMenu = !fRemove;   
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2663 2664

    EVENT_Capture( mt.hOwnerWnd, HTMENU );
Alexandre Julliard's avatar
Alexandre Julliard committed
2665

Alexandre Julliard's avatar
Alexandre Julliard committed
2666
    while (!fEndMenu)
Alexandre Julliard's avatar
Alexandre Julliard committed
2667
    {
2668
	menu = MENU_GetMenu( mt.hCurrentMenu );
2669 2670
	if (!menu) /* sometimes happens if I do a window manager close */
	    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2671

Alexandre Julliard's avatar
Alexandre Julliard committed
2672
	/* we have to keep the message in the queue until it's
Alexandre Julliard's avatar
Alexandre Julliard committed
2673
	 * clear that menu loop is not over yet. */
Alexandre Julliard's avatar
Alexandre Julliard committed
2674

2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693
        for (;;)
        {
            if (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
            {
                if (!CallMsgFilterA( &msg, MSGF_MENU )) break;
                /* remove the message from the queue */
                PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
            }
            else
            {
                if (!enterIdleSent)
                {
                    HWND win = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
                    enterIdleSent = TRUE;
                    SendMessageW( mt.hOwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM)win );
                }
                WaitMessage();
            }
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
2694

2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707
	/* check if EndMenu() tried to cancel us, by posting this message */
        if(msg.message == WM_CANCELMODE) 
	{
	    /* we are now out of the loop */
    	    fEndMenu = TRUE;

	    /* remove the message from the queue */
	    PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
	   
	    /* break out of internal loop, ala ESCAPE */
	    break;
	}

2708
        TranslateMessage( &msg );
2709
        mt.pt = msg.pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
2710

2711 2712 2713
	if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
	  enterIdleSent=FALSE;

Alexandre Julliard's avatar
Alexandre Julliard committed
2714
        fRemove = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2715
	if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
Alexandre Julliard's avatar
Alexandre Julliard committed
2716
	{
2717 2718 2719 2720 2721 2722 2723 2724 2725 2726
            /* 
             * use the mouse coordinates in lParam instead of those in the MSG
             * struct to properly handle synthetic messages. lParam coords are 
             * relative to client area, so they must be converted; since they can
             * be negative, we must use SLOWORD/SHIWORD instead of LOWORD/HIWORD.
             */
            mt.pt.x = SLOWORD(msg.lParam);
            mt.pt.y = SHIWORD(msg.lParam);
            ClientToScreen(msg.hwnd,&mt.pt);

Alexandre Julliard's avatar
Alexandre Julliard committed
2727
	    /* Find a menu for this mouse event */
2728
	    hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt );
Alexandre Julliard's avatar
Alexandre Julliard committed
2729

Alexandre Julliard's avatar
Alexandre Julliard committed
2730
	    switch(msg.message)
Alexandre Julliard's avatar
Alexandre Julliard committed
2731
	    {
Alexandre Julliard's avatar
Alexandre Julliard committed
2732 2733
		/* no WM_NC... messages in captured state */

Alexandre Julliard's avatar
Alexandre Julliard committed
2734 2735 2736 2737 2738 2739
		case WM_RBUTTONDBLCLK:
		case WM_RBUTTONDOWN:
		    if (!(wFlags & TPM_RIGHTBUTTON)) break;
		    /* fall through */
		case WM_LBUTTONDBLCLK:
		case WM_LBUTTONDOWN:
2740 2741 2742 2743
		    /* If the message belongs to the menu, removes it from the queue */
		    /* Else, end menu tracking */
		    fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
		    fEndMenu = !fRemove;
Alexandre Julliard's avatar
Alexandre Julliard committed
2744
		    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2745
		
Alexandre Julliard's avatar
Alexandre Julliard committed
2746 2747 2748 2749
		case WM_RBUTTONUP:
		    if (!(wFlags & TPM_RIGHTBUTTON)) break;
		    /* fall through */
		case WM_LBUTTONUP:
2750 2751
		    /* Check if a menu was selected by the mouse */
		    if (hmenu)
Alexandre Julliard's avatar
Alexandre Julliard committed
2752
		    {
2753 2754 2755
                        executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);

			/* End the loop if executedMenuId is an item ID */
2756 2757
			/* or if the job was done (executedMenuId = 0). */
                        fEndMenu = fRemove = (executedMenuId != -1);
Alexandre Julliard's avatar
Alexandre Julliard committed
2758
		    }
2759 2760 2761 2762 2763 2764
                    /* No menu was selected by the mouse */
                    /* if the function was called by TrackPopupMenu, continue
                       with the menu tracking. If not, stop it */
                    else
                        fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
                    
Alexandre Julliard's avatar
Alexandre Julliard committed
2765
		    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2766
		
Alexandre Julliard's avatar
Alexandre Julliard committed
2767
		case WM_MOUSEMOVE:
2768 2769 2770 2771 2772 2773 2774
                    /* In win95 winelook, the selected menu item must be changed every time the
                       mouse moves. In Win31 winelook, the mouse button has to be held down */
                     
                    if ( (TWEAK_WineLook > WIN31_LOOK) ||
                         ( (msg.wParam & MK_LBUTTON) ||
                           ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) )

2775
			fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
2776

Alexandre Julliard's avatar
Alexandre Julliard committed
2777
	    } /* switch(msg.message) - mouse */
Alexandre Julliard's avatar
Alexandre Julliard committed
2778
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
2779
	else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
Alexandre Julliard's avatar
Alexandre Julliard committed
2780
	{
Alexandre Julliard's avatar
Alexandre Julliard committed
2781
            fRemove = TRUE;  /* Keyboard messages are always removed */
Alexandre Julliard's avatar
Alexandre Julliard committed
2782
	    switch(msg.message)
Alexandre Julliard's avatar
Alexandre Julliard committed
2783 2784
	    {
	    case WM_KEYDOWN:
Alexandre Julliard's avatar
Alexandre Julliard committed
2785
		switch(msg.wParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2786 2787 2788
		{
		case VK_HOME:
		case VK_END:
Alexandre Julliard's avatar
Alexandre Julliard committed
2789
		    MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, 
2790
				     NO_SELECTED_ITEM, FALSE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2791
		/* fall through */
Alexandre Julliard's avatar
Alexandre Julliard committed
2792
		case VK_UP:
Alexandre Julliard's avatar
Alexandre Julliard committed
2793
		    MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, 
Alexandre Julliard's avatar
Alexandre Julliard committed
2794
				       (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
Alexandre Julliard's avatar
Alexandre Julliard committed
2795 2796
		    break;

Alexandre Julliard's avatar
Alexandre Julliard committed
2797 2798
		case VK_DOWN: /* If on menu bar, pull-down the menu */

2799
		    menu = MENU_GetMenu( mt.hCurrentMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
2800
		    if (!(menu->wFlags & MF_POPUP))
2801
			mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
2802 2803
		    else      /* otherwise try to move selection */
			MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
Alexandre Julliard's avatar
Alexandre Julliard committed
2804 2805 2806
		    break;

		case VK_LEFT:
2807
		    MENU_KeyLeft( &mt, wFlags );
Alexandre Julliard's avatar
Alexandre Julliard committed
2808 2809 2810
		    break;
		    
		case VK_RIGHT:
2811
		    MENU_KeyRight( &mt, wFlags );
Alexandre Julliard's avatar
Alexandre Julliard committed
2812 2813 2814
		    break;
		    
		case VK_ESCAPE:
2815
                    fEndMenu = MENU_KeyEscape(&mt, wFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
2816 2817
		    break;

2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833
		case VK_F1:
		    {
			HELPINFO hi;
			hi.cbSize = sizeof(HELPINFO);
			hi.iContextType = HELPINFO_MENUITEM;
			if (menu->FocusedItem == NO_SELECTED_ITEM) 
			    hi.iCtrlId = 0;
		        else	
			    hi.iCtrlId = menu->items[menu->FocusedItem].wID; 
			hi.hItemHandle = hmenu;
			hi.dwContextId = menu->dwContextHelpID;
			hi.MousePos = msg.pt;
			SendMessageA(hwnd, WM_HELP, 0, (LPARAM)&hi);
			break;
		    }

Alexandre Julliard's avatar
Alexandre Julliard committed
2834 2835 2836 2837 2838 2839
		default:
		    break;
		}
		break;  /* WM_KEYDOWN */

	    case WM_SYSKEYDOWN:
Alexandre Julliard's avatar
Alexandre Julliard committed
2840
		switch(msg.wParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2841 2842
		{
		case VK_MENU:
Alexandre Julliard's avatar
Alexandre Julliard committed
2843
		    fEndMenu = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2844 2845 2846 2847 2848 2849 2850
		    break;
		    
		}
		break;  /* WM_SYSKEYDOWN */

	    case WM_CHAR:
		{
2851
		    UINT	pos;
Alexandre Julliard's avatar
Alexandre Julliard committed
2852

2853 2854
		    if (msg.wParam == '\r' || msg.wParam == ' ')
		    {
2855
                        executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2856
                        fEndMenu = (executedMenuId != -1);
2857

2858 2859 2860
			break;
		    }

Alexandre Julliard's avatar
Alexandre Julliard committed
2861 2862
		      /* Hack to avoid control chars. */
		      /* We will find a better way real soon... */
Alexandre Julliard's avatar
Alexandre Julliard committed
2863
		    if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2864 2865

		    pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu, 
2866
                                              LOWORD(msg.wParam), FALSE );
2867 2868
		    if (pos == (UINT)-2) fEndMenu = TRUE;
		    else if (pos == (UINT)-1) MessageBeep(0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2869 2870
		    else
		    {
2871 2872
			MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
                                TRUE, 0 );
2873
                        executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
2874
                        fEndMenu = (executedMenuId != -1);
Alexandre Julliard's avatar
Alexandre Julliard committed
2875 2876
		    }
		}		    
Alexandre Julliard's avatar
Alexandre Julliard committed
2877 2878
		break;
	    }  /* switch(msg.message) - kbd */
Alexandre Julliard's avatar
Alexandre Julliard committed
2879 2880 2881
	}
	else
	{
2882
	    DispatchMessageA( &msg );
Alexandre Julliard's avatar
Alexandre Julliard committed
2883 2884
	}

Alexandre Julliard's avatar
Alexandre Julliard committed
2885 2886 2887 2888 2889
	if (!fEndMenu) fRemove = TRUE;

	/* finally remove message from the queue */

        if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
2890
	    PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
Alexandre Julliard's avatar
Alexandre Julliard committed
2891
	else mt.trackFlags &= ~TF_SKIPREMOVE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2892
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2893

Alexandre Julliard's avatar
Alexandre Julliard committed
2894
    ReleaseCapture();
2895

2896 2897 2898 2899 2900
    /* If dropdown is still painted and the close box is clicked on
       then the menu will be destroyed as part of the DispatchMessage above.
       This will then invalidate the menu handle in mt.hTopMenu. We should
       check for this first.  */
    if( IsMenu( mt.hTopMenu ) )
Alexandre Julliard's avatar
Alexandre Julliard committed
2901
    {
2902
	menu = MENU_GetMenu( mt.hTopMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
2903

2904 2905 2906 2907 2908 2909
        if( IsWindow( mt.hOwnerWnd ) )
        {
	    MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );

	    if (menu && menu->wFlags & MF_POPUP) 
	    {
2910 2911
                DestroyWindow( menu->hWnd );
                menu->hWnd = 0;
2912 2913 2914 2915 2916 2917 2918
	    }
	    MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
	    SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
        }

        /* Reset the variable for hiding menu */
        if( menu ) menu->bTimeToHide = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2919
    }
2920

2921 2922
    /* The return value is only used by TrackPopupMenu */
    return ((executedMenuId != -1) ? executedMenuId : 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2923
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2924

Alexandre Julliard's avatar
Alexandre Julliard committed
2925 2926 2927
/***********************************************************************
 *           MENU_InitTracking
 */
2928
static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
2929
{
2930
    TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd, hMenu);
2931

2932
    HideCaret(0);
2933 2934 2935 2936 2937

    /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
    if (!(wFlags & TPM_NONOTIFY))
       SendMessageA( hWnd, WM_ENTERMENULOOP, bPopup, 0 );

2938
    SendMessageA( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
2939 2940

    if (!(wFlags & TPM_NONOTIFY))
2941 2942
    {
       POPUPMENU *menu;
2943
       SendMessageA( hWnd, WM_INITMENU, hMenu, 0 );
2944 2945 2946
       if ((menu = MENU_GetMenu( hMenu )) && (!menu->Height))
       { /* app changed/recreated menu bar entries in WM_INITMENU
            Recalculate menu sizes else clicks will not work */
2947 2948 2949
          SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
                        SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
                                                        
2950 2951
       }
    }
2952 2953 2954 2955 2956 2957 2958
    return TRUE;
}
/***********************************************************************
 *           MENU_ExitTracking
 */
static BOOL MENU_ExitTracking(HWND hWnd)
{
2959
    TRACE("hwnd=0x%04x\n", hWnd);
2960 2961 2962

    SendMessageA( hWnd, WM_EXITMENULOOP, 0, 0 );
    ShowCaret(0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2963 2964 2965
    return TRUE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2966 2967 2968 2969 2970
/***********************************************************************
 *           MENU_TrackMouseMenuBar
 *
 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
 */
2971
void MENU_TrackMouseMenuBar( HWND hWnd, INT ht, POINT pt )
Alexandre Julliard's avatar
Alexandre Julliard committed
2972
{
2973
    HMENU hMenu = (ht == HTSYSMENU) ? get_win_sys_menu( hWnd ) : GetMenu( hWnd );
2974
    UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
Alexandre Julliard's avatar
Alexandre Julliard committed
2975

2976
    TRACE("wnd=%x ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y);
2977

2978
    if (IsMenu(hMenu))
Alexandre Julliard's avatar
Alexandre Julliard committed
2979
    {
2980 2981 2982 2983
        /* map point to parent client coordinates */
        HWND parent = GetAncestor( hWnd, GA_PARENT );
        if (parent != GetDesktopWindow()) ScreenToClient( parent, &pt );

2984 2985
	MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
	MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
2986
	MENU_ExitTracking(hWnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2987
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2988 2989 2990 2991 2992 2993 2994 2995
}


/***********************************************************************
 *           MENU_TrackKbdMenuBar
 *
 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
 */
2996
void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, INT vkey)
Alexandre Julliard's avatar
Alexandre Julliard committed
2997
{
2998 2999 3000
    UINT uItem = NO_SELECTED_ITEM;
    HMENU hTrackMenu;
    UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
Alexandre Julliard's avatar
Alexandre Julliard committed
3001

Alexandre Julliard's avatar
Alexandre Julliard committed
3002
    /* find window that has a menu */
3003 3004 3005

    while (GetWindowLongA( hwnd, GWL_STYLE ) & WS_CHILD)
        if (!(hwnd = GetParent( hwnd ))) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
3006

Alexandre Julliard's avatar
Alexandre Julliard committed
3007
    /* check if we have to track a system menu */
3008 3009 3010

    hTrackMenu = GetMenu( hwnd );
    if (!hTrackMenu || IsIconic(hwnd) || vkey == VK_SPACE )
Alexandre Julliard's avatar
Alexandre Julliard committed
3011
    {
3012 3013 3014 3015
        if (!(GetWindowLongA( hwnd, GWL_STYLE ) & WS_SYSMENU)) return;
        hTrackMenu = get_win_sys_menu( hwnd );
        uItem = 0;
        wParam |= HTSYSMENU; /* prevent item lookup */
Alexandre Julliard's avatar
Alexandre Julliard committed
3016
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3017

3018 3019 3020
    if (!IsMenu( hTrackMenu )) return;

    MENU_InitTracking( hwnd, hTrackMenu, FALSE, wFlags );
Alexandre Julliard's avatar
Alexandre Julliard committed
3021

3022 3023 3024 3025
    if( vkey && vkey != VK_SPACE )
    {
        uItem = MENU_FindItemByKey( hwnd, hTrackMenu, vkey, (wParam & HTSYSMENU) );
        if( uItem >= (UINT)(-2) )
Alexandre Julliard's avatar
Alexandre Julliard committed
3026
        {
3027 3028
            if( uItem == (UINT)(-1) ) MessageBeep(0);
            hTrackMenu = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
3029
        }
3030
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3031

3032 3033 3034
    if( hTrackMenu )
    {
        MENU_SelectItem( hwnd, hTrackMenu, uItem, TRUE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
3035

3036 3037 3038 3039
        if( uItem == NO_SELECTED_ITEM )
            MENU_MoveSelection( hwnd, hTrackMenu, ITEM_NEXT );
        else if( vkey )
            PostMessageA( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
3040

3041
        MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
3042
    }
3043
    MENU_ExitTracking( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
3044 3045 3046
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3047
/**********************************************************************
3048
 *           TrackPopupMenu   (USER32.@)
3049 3050 3051 3052
 *
 * Like the win32 API, the function return the command ID only if the
 * flag TPM_RETURNCMD is on.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
3053
 */
3054 3055
BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
                           INT nReserved, HWND hWnd, const RECT *lpRect )
Alexandre Julliard's avatar
Alexandre Julliard committed
3056
{
3057
    BOOL ret = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3058

3059 3060 3061 3062 3063 3064
    MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);

    /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
    if (!(wFlags & TPM_NONOTIFY))
        SendMessageA( hWnd, WM_INITMENUPOPUP, hMenu, 0);

3065
    if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
3066
	ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
3067
    MENU_ExitTracking(hWnd);
3068 3069 3070 3071

    if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
	ret = 1;

Alexandre Julliard's avatar
Alexandre Julliard committed
3072
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
3073 3074
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3075
/**********************************************************************
3076
 *           TrackPopupMenuEx   (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3077
 */
3078 3079
BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
                                HWND hWnd, LPTPMPARAMS lpTpm )
Alexandre Julliard's avatar
Alexandre Julliard committed
3080
{
3081
    FIXME("not fully implemented\n" );
3082
    return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
Alexandre Julliard's avatar
Alexandre Julliard committed
3083
                             lpTpm ? &lpTpm->rcExclude : NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
3084
}
Alexandre Julliard's avatar
Alexandre Julliard committed
3085

Alexandre Julliard's avatar
Alexandre Julliard committed
3086 3087
/***********************************************************************
 *           PopupMenuWndProc
Alexandre Julliard's avatar
Alexandre Julliard committed
3088 3089
 *
 * NOTE: Windows has totally different (and undocumented) popup wndproc.
Alexandre Julliard's avatar
Alexandre Julliard committed
3090
 */
3091 3092
static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
3093
    TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3094 3095
    hwnd, message, wParam, lParam);

Alexandre Julliard's avatar
Alexandre Julliard committed
3096 3097 3098 3099
    switch(message)
    {
    case WM_CREATE:
	{
3100 3101 3102
	    CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
	    SetWindowLongW( hwnd, 0, (LONG)cs->lpCreateParams );
            return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
3103 3104 3105
	}

    case WM_MOUSEACTIVATE:  /* We don't want to be activated */
3106
        return MA_NOACTIVATE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3107 3108 3109

    case WM_PAINT:
	{
3110 3111
	    PAINTSTRUCT ps;
	    BeginPaint( hwnd, &ps );
Alexandre Julliard's avatar
Alexandre Julliard committed
3112
	    MENU_DrawPopupMenu( hwnd, ps.hdc,
3113 3114
                                (HMENU)GetWindowLongA( hwnd, 0 ) );
	    EndPaint( hwnd, &ps );
3115
            return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
3116
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
3117
    case WM_ERASEBKGND:
3118
        return 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
3119

Alexandre Julliard's avatar
Alexandre Julliard committed
3120
    case WM_DESTROY:
3121 3122 3123
        /* zero out global pointer in case resident popup window was destroyed. */
        if (hwnd == top_popup) top_popup = 0;
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
3124

Alexandre Julliard's avatar
Alexandre Julliard committed
3125 3126 3127 3128
    case WM_SHOWWINDOW:

	if( wParam )
	{
3129
            if (!GetWindowLongW( hwnd, 0 )) ERR("no menu to display\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
3130 3131
	}
	else
3132
            SetWindowLongW( hwnd, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
3133 3134 3135
	break;

    case MM_SETMENUHANDLE:
3136
        SetWindowLongW( hwnd, 0, wParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
3137
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
3138 3139

    case MM_GETMENUHANDLE:
3140
        return GetWindowLongW( hwnd, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
3141

Alexandre Julliard's avatar
Alexandre Julliard committed
3142
    default:
3143
        return DefWindowProcW( hwnd, message, wParam, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
3144
    }
3145
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
3146
}
Alexandre Julliard's avatar
Alexandre Julliard committed
3147

Alexandre Julliard's avatar
Alexandre Julliard committed
3148

Alexandre Julliard's avatar
Alexandre Julliard committed
3149 3150 3151 3152 3153
/***********************************************************************
 *           MENU_GetMenuBarHeight
 *
 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
 */
3154 3155
UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
                              INT orgX, INT orgY )
Alexandre Julliard's avatar
Alexandre Julliard committed
3156
{
3157 3158
    HDC hdc;
    RECT rectBar;
Alexandre Julliard's avatar
Alexandre Julliard committed
3159 3160
    LPPOPUPMENU lppop;

3161
    TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3162
          hwnd, menubarWidth, orgX, orgY );
3163

3164
    if (!(lppop = MENU_GetMenu( GetMenu(hwnd) ))) return 0;
3165

3166
    hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3167
    SelectObject( hdc, hMenuFont);       
3168
    SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3169
    MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );    
3170
    ReleaseDC( hwnd, hdc );
3171
    return lppop->Height;
Alexandre Julliard's avatar
Alexandre Julliard committed
3172 3173 3174
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3175
/*******************************************************************
3176
 *         ChangeMenu    (USER.153)
Alexandre Julliard's avatar
Alexandre Julliard committed
3177
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3178 3179
BOOL16 WINAPI ChangeMenu16( HMENU16 hMenu, UINT16 pos, SEGPTR data,
                            UINT16 id, UINT16 flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3180
{
3181
    TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
3182
                  hMenu, pos, (DWORD)data, id, flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
3183 3184
    if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
                                                id, data );
Alexandre Julliard's avatar
Alexandre Julliard committed
3185

Alexandre Julliard's avatar
Alexandre Julliard committed
3186 3187 3188
    /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
    /* for MF_DELETE. We should check the parameters for all others */
    /* MF_* actions also (anybody got a doc on ChangeMenu?). */
Alexandre Julliard's avatar
Alexandre Julliard committed
3189

Alexandre Julliard's avatar
Alexandre Julliard committed
3190 3191 3192 3193
    if (flags & MF_DELETE) return DeleteMenu16(hMenu, pos, flags & ~MF_DELETE);
    if (flags & MF_CHANGE) return ModifyMenu16(hMenu, pos, flags & ~MF_CHANGE,
                                               id, data );
    if (flags & MF_REMOVE) return RemoveMenu16(hMenu,
Alexandre Julliard's avatar
Alexandre Julliard committed
3194 3195
                                              flags & MF_BYPOSITION ? pos : id,
                                              flags & ~MF_REMOVE );
Alexandre Julliard's avatar
Alexandre Julliard committed
3196
    /* Default: MF_INSERT */
Alexandre Julliard's avatar
Alexandre Julliard committed
3197 3198 3199 3200 3201
    return InsertMenu16( hMenu, pos, flags, id, data );
}


/*******************************************************************
3202
 *         ChangeMenuA    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3203
 */
3204 3205
BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
                             UINT id, UINT flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3206
{
3207
    TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
3208
                  hMenu, pos, (DWORD)data, id, flags );
3209
    if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
Alexandre Julliard's avatar
Alexandre Julliard committed
3210
                                                 id, data );
3211 3212
    if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
    if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
Alexandre Julliard's avatar
Alexandre Julliard committed
3213
                                                id, data );
3214
    if (flags & MF_REMOVE) return RemoveMenu( hMenu,
Alexandre Julliard's avatar
Alexandre Julliard committed
3215 3216 3217
                                              flags & MF_BYPOSITION ? pos : id,
                                              flags & ~MF_REMOVE );
    /* Default: MF_INSERT */
3218
    return InsertMenuA( hMenu, pos, flags, id, data );
Alexandre Julliard's avatar
Alexandre Julliard committed
3219 3220 3221 3222
}


/*******************************************************************
3223
 *         ChangeMenuW    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3224
 */
3225 3226
BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
                             UINT id, UINT flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3227
{
3228
    TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
3229
                  hMenu, pos, (DWORD)data, id, flags );
3230
    if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
Alexandre Julliard's avatar
Alexandre Julliard committed
3231
                                                 id, data );
3232 3233
    if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
    if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
Alexandre Julliard's avatar
Alexandre Julliard committed
3234
                                                id, data );
3235
    if (flags & MF_REMOVE) return RemoveMenu( hMenu,
Alexandre Julliard's avatar
Alexandre Julliard committed
3236 3237 3238
                                              flags & MF_BYPOSITION ? pos : id,
                                              flags & ~MF_REMOVE );
    /* Default: MF_INSERT */
3239
    return InsertMenuW( hMenu, pos, flags, id, data );
Alexandre Julliard's avatar
Alexandre Julliard committed
3240
}
Alexandre Julliard's avatar
Alexandre Julliard committed
3241 3242


Alexandre Julliard's avatar
Alexandre Julliard committed
3243
/*******************************************************************
3244
 *         CheckMenuItem    (USER.154)
Alexandre Julliard's avatar
Alexandre Julliard committed
3245
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3246
BOOL16 WINAPI CheckMenuItem16( HMENU16 hMenu, UINT16 id, UINT16 flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3247
{
3248
    return (BOOL16)CheckMenuItem( hMenu, id, flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
3249 3250 3251 3252
}


/*******************************************************************
3253
 *         CheckMenuItem    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3254
 */
3255
DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3256
{
Alexandre Julliard's avatar
Alexandre Julliard committed
3257
    MENUITEM *item;
Alexandre Julliard's avatar
Alexandre Julliard committed
3258
    DWORD ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
3259

3260
    TRACE("menu=%04x id=%04x flags=%04x\n", hMenu, id, flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
3261
    if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
3262 3263 3264
    ret = item->fState & MF_CHECKED;
    if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
    else item->fState &= ~MF_CHECKED;
Alexandre Julliard's avatar
Alexandre Julliard committed
3265
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
3266 3267 3268 3269
}


/**********************************************************************
3270
 *         EnableMenuItem    (USER.155)
Alexandre Julliard's avatar
Alexandre Julliard committed
3271
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3272
UINT16 WINAPI EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3273
{
3274
    return EnableMenuItem( hMenu, wItemID, wFlags );
Alexandre Julliard's avatar
Alexandre Julliard committed
3275 3276 3277 3278
}


/**********************************************************************
3279
 *         EnableMenuItem    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3280
 */
3281
UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3282
{
3283
    UINT    oldflags;
Alexandre Julliard's avatar
Alexandre Julliard committed
3284
    MENUITEM *item;
3285
    POPUPMENU *menu;
Alexandre Julliard's avatar
Alexandre Julliard committed
3286

3287
    TRACE("(%04x, %04X, %04X) !\n", 
Alexandre Julliard's avatar
Alexandre Julliard committed
3288
		 hMenu, wItemID, wFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
3289

3290
    /* Get the Popupmenu to access the owner menu */
3291
    if (!(menu = MENU_GetMenu(hMenu))) 
3292 3293
	return (UINT)-1;

Alexandre Julliard's avatar
Alexandre Julliard committed
3294
    if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3295
	return (UINT)-1;
Alexandre Julliard's avatar
Alexandre Julliard committed
3296 3297 3298

    oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
    item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3299 3300 3301 3302 3303 3304 3305 3306 3307 3308

    /* In win95 if the close item in the system menu change update the close button */
    if (TWEAK_WineLook == WIN95_LOOK)    
	if((item->wID == SC_CLOSE) && (oldflags != wFlags))
	{
	    if (menu->hSysMenuOwner != 0)
	    {
		POPUPMENU* parentMenu;

		/* Get the parent menu to access*/
3309
		if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner))) 
3310 3311 3312 3313
		    return (UINT)-1;

		/* Refresh the frame to reflect the change*/
		SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
3314
			     SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
3315 3316 3317
	    }
	}
	   
Alexandre Julliard's avatar
Alexandre Julliard committed
3318
    return oldflags;
Alexandre Julliard's avatar
Alexandre Julliard committed
3319 3320 3321
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3322
/*******************************************************************
3323
 *         GetMenuString    (USER.161)
Alexandre Julliard's avatar
Alexandre Julliard committed
3324
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3325 3326
INT16 WINAPI GetMenuString16( HMENU16 hMenu, UINT16 wItemID,
                              LPSTR str, INT16 nMaxSiz, UINT16 wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3327
{
3328
    return GetMenuStringA( hMenu, wItemID, str, nMaxSiz, wFlags );
Alexandre Julliard's avatar
Alexandre Julliard committed
3329 3330 3331 3332
}


/*******************************************************************
3333
 *         GetMenuStringA    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3334
 */
3335 3336 3337 3338 3339 3340 3341
INT WINAPI GetMenuStringA( 
	HMENU hMenu,	/* [in] menuhandle */
	UINT wItemID,	/* [in] menu item (dep. on wFlags) */
	LPSTR str,	/* [out] outbuffer. If NULL, func returns entry length*/
	INT nMaxSiz,	/* [in] length of buffer. if 0, func returns entry len*/
	UINT wFlags	/* [in] MF_ flags */ 
) {
Alexandre Julliard's avatar
Alexandre Julliard committed
3342
    MENUITEM *item;
Alexandre Julliard's avatar
Alexandre Julliard committed
3343

3344
    TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
3345
                 hMenu, wItemID, str, nMaxSiz, wFlags );
Alexandre Julliard's avatar
Alexandre Julliard committed
3346
    if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
3347
    if (!IS_STRING_ITEM(item->fType)) return 0;
3348
    if (!str || !nMaxSiz) return strlenW(item->text);
3349
    str[0] = '\0';
3350 3351
    if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
        str[nMaxSiz-1] = 0;
3352
    TRACE("returning '%s'\n", str );
Alexandre Julliard's avatar
Alexandre Julliard committed
3353
    return strlen(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
3354 3355 3356
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3357
/*******************************************************************
3358
 *         GetMenuStringW    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3359
 */
3360 3361
INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
                               LPWSTR str, INT nMaxSiz, UINT wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3362 3363 3364
{
    MENUITEM *item;

3365
    TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
3366 3367
                 hMenu, wItemID, str, nMaxSiz, wFlags );
    if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
3368
    if (!IS_STRING_ITEM(item->fType)) return 0;
3369
    if (!str || !nMaxSiz) return strlenW(item->text);
3370
    str[0] = '\0';
3371 3372
    lstrcpynW( str, item->text, nMaxSiz );
    return strlenW(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
3373 3374 3375
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3376
/**********************************************************************
3377
 *         HiliteMenuItem    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3378
 */
3379 3380
BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
                                UINT wHilite )
Alexandre Julliard's avatar
Alexandre Julliard committed
3381
{
Alexandre Julliard's avatar
Alexandre Julliard committed
3382
    LPPOPUPMENU menu;
3383
    TRACE("(%04x, %04x, %04x, %04x);\n", 
Alexandre Julliard's avatar
Alexandre Julliard committed
3384
                 hWnd, hMenu, wItemID, wHilite);
Alexandre Julliard's avatar
Alexandre Julliard committed
3385
    if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3386
    if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3387
    if (menu->FocusedItem == wItemID) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3388
    MENU_HideSubPopups( hWnd, hMenu, FALSE );
3389
    MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
3390
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3391 3392 3393 3394
}


/**********************************************************************
3395
 *         GetMenuState    (USER.250)
Alexandre Julliard's avatar
Alexandre Julliard committed
3396
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3397
UINT16 WINAPI GetMenuState16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3398
{
3399
    return GetMenuState( hMenu, wItemID, wFlags );
Alexandre Julliard's avatar
Alexandre Julliard committed
3400 3401 3402 3403
}


/**********************************************************************
3404
 *         GetMenuState    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3405
 */
3406
UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3407
{
Alexandre Julliard's avatar
Alexandre Julliard committed
3408
    MENUITEM *item;
3409
    TRACE("(menu=%04x, id=%04x, flags=%04x);\n", 
Alexandre Julliard's avatar
Alexandre Julliard committed
3410
		 hMenu, wItemID, wFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
3411
    if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
3412
    debug_print_menuitem ("  item: ", item, "");
Alexandre Julliard's avatar
Alexandre Julliard committed
3413
    if (item->fType & MF_POPUP)
Alexandre Julliard's avatar
Alexandre Julliard committed
3414
    {
3415
	POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
3416
	if (!menu) return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
3417
	else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
Alexandre Julliard's avatar
Alexandre Julliard committed
3418
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3419
    else
Alexandre Julliard's avatar
Alexandre Julliard committed
3420
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
3421 3422 3423 3424
	/* We used to (from way back then) mask the result to 0xff.  */
	/* I don't know why and it seems wrong as the documented */
	/* return flag MF_SEPARATOR is outside that mask.  */
	return (item->fType | item->fState);
Alexandre Julliard's avatar
Alexandre Julliard committed
3425
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3426 3427 3428 3429
}


/**********************************************************************
3430
 *         GetMenuItemCount    (USER.263)
Alexandre Julliard's avatar
Alexandre Julliard committed
3431
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3432
INT16 WINAPI GetMenuItemCount16( HMENU16 hMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
3433
{
3434 3435
    LPPOPUPMENU	menu = MENU_GetMenu(hMenu);
    if (!menu) return -1;
3436
    TRACE("(%04x) returning %d\n", 
Alexandre Julliard's avatar
Alexandre Julliard committed
3437 3438 3439 3440 3441 3442
                  hMenu, menu->nItems );
    return menu->nItems;
}


/**********************************************************************
3443
 *         GetMenuItemCount    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3444
 */
3445
INT WINAPI GetMenuItemCount( HMENU hMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
3446
{
3447 3448
    LPPOPUPMENU	menu = MENU_GetMenu(hMenu);
    if (!menu) return -1;
3449
    TRACE("(%04x) returning %d\n", 
Alexandre Julliard's avatar
Alexandre Julliard committed
3450 3451 3452 3453 3454
                  hMenu, menu->nItems );
    return menu->nItems;
}

/**********************************************************************
3455
 *         GetMenuItemID    (USER.264)
Alexandre Julliard's avatar
Alexandre Julliard committed
3456
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3457
UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
Alexandre Julliard's avatar
Alexandre Julliard committed
3458
{
3459
    return (UINT16) GetMenuItemID (hMenu, nPos);
Alexandre Julliard's avatar
Alexandre Julliard committed
3460 3461 3462
}

/**********************************************************************
3463
 *         GetMenuItemID    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3464
 */
3465
UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
Alexandre Julliard's avatar
Alexandre Julliard committed
3466
{
3467
    MENUITEM * lpmi;
Alexandre Julliard's avatar
Alexandre Julliard committed
3468

3469
    if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return -1;
3470 3471
    if (lpmi->fType & MF_POPUP) return -1;
    return lpmi->wID;
Alexandre Julliard's avatar
Alexandre Julliard committed
3472

3473
}
Alexandre Julliard's avatar
Alexandre Julliard committed
3474 3475

/*******************************************************************
3476
 *         InsertMenu    (USER.410)
Alexandre Julliard's avatar
Alexandre Julliard committed
3477
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3478 3479
BOOL16 WINAPI InsertMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
                            UINT16 id, SEGPTR data )
Alexandre Julliard's avatar
Alexandre Julliard committed
3480
{
3481 3482
    UINT pos32 = (UINT)pos;
    if ((pos == (UINT16)-1) && (flags & MF_BYPOSITION)) pos32 = (UINT)-1;
Alexandre Julliard's avatar
Alexandre Julliard committed
3483
    if (IS_STRING_ITEM(flags) && data)
3484
        return InsertMenuA( hMenu, pos32, flags, id, MapSL(data) );
3485
    return InsertMenuA( hMenu, pos32, flags, id, (LPSTR)data );
Alexandre Julliard's avatar
Alexandre Julliard committed
3486 3487 3488
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3489
/*******************************************************************
3490
 *         InsertMenuW    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3491
 */
3492 3493
BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
                             UINT id, LPCWSTR str )
Alexandre Julliard's avatar
Alexandre Julliard committed
3494
{
Alexandre Julliard's avatar
Alexandre Julliard committed
3495
    MENUITEM *item;
Alexandre Julliard's avatar
Alexandre Julliard committed
3496

Alexandre Julliard's avatar
Alexandre Julliard committed
3497
    if (IS_STRING_ITEM(flags) && str)
3498
        TRACE("hMenu %04x, pos %d, flags %08x, "
3499
		      "id %04x, str %s\n",
3500
                      hMenu, pos, flags, id, debugstr_w(str) );
3501
    else TRACE("hMenu %04x, pos %d, flags %08x, "
Alexandre Julliard's avatar
Alexandre Julliard committed
3502
		       "id %04x, str %08lx (not a string)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
3503
                       hMenu, pos, flags, id, (DWORD)str );
Alexandre Julliard's avatar
Alexandre Julliard committed
3504

Alexandre Julliard's avatar
Alexandre Julliard committed
3505
    if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3506

Alexandre Julliard's avatar
Alexandre Julliard committed
3507
    if (!(MENU_SetItemData( item, flags, id, str )))
Alexandre Julliard's avatar
Alexandre Julliard committed
3508
    {
3509
        RemoveMenu( hMenu, pos, flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
3510 3511
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3512

Alexandre Julliard's avatar
Alexandre Julliard committed
3513
    if (flags & MF_POPUP)  /* Set the MF_POPUP flag on the popup-menu */
3514
	(MENU_GetMenu((HMENU16)id))->wFlags |= MF_POPUP;
Alexandre Julliard's avatar
Alexandre Julliard committed
3515

Alexandre Julliard's avatar
Alexandre Julliard committed
3516
    item->hCheckBit = item->hUnCheckBit = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
3517
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3518 3519 3520
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3521
/*******************************************************************
3522
 *         InsertMenuA    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3523
 */
3524 3525
BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
                             UINT id, LPCSTR str )
Alexandre Julliard's avatar
Alexandre Julliard committed
3526
{
3527
    BOOL ret = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3528 3529 3530

    if (IS_STRING_ITEM(flags) && str)
    {
3531 3532 3533 3534 3535 3536 3537 3538
        INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
        LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
        if (newstr)
        {
            MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
            ret = InsertMenuW( hMenu, pos, flags, id, newstr );
            HeapFree( GetProcessHeap(), 0, newstr );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
3539 3540
        return ret;
    }
3541
    else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
Alexandre Julliard's avatar
Alexandre Julliard committed
3542 3543 3544 3545
}


/*******************************************************************
3546
 *         AppendMenu    (USER.411)
Alexandre Julliard's avatar
Alexandre Julliard committed
3547
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3548
BOOL16 WINAPI AppendMenu16(HMENU16 hMenu, UINT16 flags, UINT16 id, SEGPTR data)
Alexandre Julliard's avatar
Alexandre Julliard committed
3549 3550 3551 3552 3553 3554
{
    return InsertMenu16( hMenu, -1, flags | MF_BYPOSITION, id, data );
}


/*******************************************************************
3555
 *         AppendMenuA    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3556
 */
3557 3558
BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
                             UINT id, LPCSTR data )
Alexandre Julliard's avatar
Alexandre Julliard committed
3559
{
3560
    return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
Alexandre Julliard's avatar
Alexandre Julliard committed
3561 3562 3563 3564
}


/*******************************************************************
3565
 *         AppendMenuW    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3566
 */
3567 3568
BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
                             UINT id, LPCWSTR data )
Alexandre Julliard's avatar
Alexandre Julliard committed
3569
{
3570
    return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
Alexandre Julliard's avatar
Alexandre Julliard committed
3571 3572 3573
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3574
/**********************************************************************
3575
 *         RemoveMenu   (USER.412)
Alexandre Julliard's avatar
Alexandre Julliard committed
3576
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3577
BOOL16 WINAPI RemoveMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3578
{
3579
    return RemoveMenu( hMenu, nPos, wFlags );
Alexandre Julliard's avatar
Alexandre Julliard committed
3580 3581 3582 3583
}


/**********************************************************************
3584
 *         RemoveMenu    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3585
 */
3586
BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3587
{
Alexandre Julliard's avatar
Alexandre Julliard committed
3588
    LPPOPUPMENU	menu;
Alexandre Julliard's avatar
Alexandre Julliard committed
3589 3590
    MENUITEM *item;

3591
    TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
3592
    if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3593
    if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3594 3595 3596
    
      /* Remove item */

Alexandre Julliard's avatar
Alexandre Julliard committed
3597 3598
    MENU_FreeItemData( item );

Alexandre Julliard's avatar
Alexandre Julliard committed
3599 3600
    if (--menu->nItems == 0)
    {
3601
        HeapFree( GetProcessHeap(), 0, menu->items );
Alexandre Julliard's avatar
Alexandre Julliard committed
3602
        menu->items = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
3603 3604 3605 3606 3607
    }
    else
    {
	while(nPos < menu->nItems)
	{
Alexandre Julliard's avatar
Alexandre Julliard committed
3608 3609
	    *item = *(item+1);
	    item++;
Alexandre Julliard's avatar
Alexandre Julliard committed
3610 3611
	    nPos++;
	}
3612
        menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
Alexandre Julliard's avatar
Alexandre Julliard committed
3613
                                   menu->nItems * sizeof(MENUITEM) );
Alexandre Julliard's avatar
Alexandre Julliard committed
3614 3615
    }
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3616 3617 3618
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3619
/**********************************************************************
3620
 *         DeleteMenu    (USER.413)
Alexandre Julliard's avatar
Alexandre Julliard committed
3621
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3622
BOOL16 WINAPI DeleteMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3623
{
3624
    return DeleteMenu( hMenu, nPos, wFlags );
Alexandre Julliard's avatar
Alexandre Julliard committed
3625 3626 3627 3628
}


/**********************************************************************
3629
 *         DeleteMenu    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3630
 */
3631
BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
3632
{
Alexandre Julliard's avatar
Alexandre Julliard committed
3633 3634
    MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
    if (!item) return FALSE;
3635
    if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
3636
      /* nPos is now the position of the item */
3637
    RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
Alexandre Julliard's avatar
Alexandre Julliard committed
3638 3639 3640 3641
    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3642
/*******************************************************************
3643
 *         ModifyMenu    (USER.414)
Alexandre Julliard's avatar
Alexandre Julliard committed
3644
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3645 3646
BOOL16 WINAPI ModifyMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
                            UINT16 id, SEGPTR data )
Alexandre Julliard's avatar
Alexandre Julliard committed
3647 3648
{
    if (IS_STRING_ITEM(flags))
3649
        return ModifyMenuA( hMenu, pos, flags, id, MapSL(data) );
3650
    return ModifyMenuA( hMenu, pos, flags, id, (LPSTR)data );
Alexandre Julliard's avatar
Alexandre Julliard committed
3651 3652 3653 3654
}


/*******************************************************************
3655
 *         ModifyMenuW    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3656
 */
3657 3658
BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
                             UINT id, LPCWSTR str )
Alexandre Julliard's avatar
Alexandre Julliard committed
3659
{
Alexandre Julliard's avatar
Alexandre Julliard committed
3660 3661 3662
    MENUITEM *item;

    if (IS_STRING_ITEM(flags))
Alexandre Julliard's avatar
Alexandre Julliard committed
3663
    {
3664 3665
	TRACE("%04x %d %04x %04x %s\n",
                      hMenu, pos, flags, id, debugstr_w(str) );
Alexandre Julliard's avatar
Alexandre Julliard committed
3666
        if (!str) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3667
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3668
    else
Alexandre Julliard's avatar
Alexandre Julliard committed
3669
    {
3670
	TRACE("%04x %d %04x %04x %08lx\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
3671 3672 3673
                      hMenu, pos, flags, id, (DWORD)str );
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
3674
    if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3675 3676 3677 3678 3679
    return MENU_SetItemData( item, flags, id, str );
}


/*******************************************************************
3680
 *         ModifyMenuA    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3681
 */
3682 3683
BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
                             UINT id, LPCSTR str )
Alexandre Julliard's avatar
Alexandre Julliard committed
3684
{
3685
    BOOL ret = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3686

Alexandre Julliard's avatar
Alexandre Julliard committed
3687 3688
    if (IS_STRING_ITEM(flags) && str)
    {
3689 3690 3691 3692 3693 3694 3695 3696
        INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
        LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
        if (newstr)
        {
            MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
            ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
            HeapFree( GetProcessHeap(), 0, newstr );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
3697 3698
        return ret;
    }
3699
    else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
Alexandre Julliard's avatar
Alexandre Julliard committed
3700 3701 3702 3703
}


/**********************************************************************
3704
 *         CreatePopupMenu    (USER.415)
Alexandre Julliard's avatar
Alexandre Julliard committed
3705
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3706
HMENU16 WINAPI CreatePopupMenu16(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
3707
{
3708
    return CreatePopupMenu();
Alexandre Julliard's avatar
Alexandre Julliard committed
3709 3710 3711 3712
}


/**********************************************************************
3713
 *         CreatePopupMenu    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3714
 */
3715
HMENU WINAPI CreatePopupMenu(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
3716
{
3717
    HMENU hmenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
3718 3719
    POPUPMENU *menu;

3720
    if (!(hmenu = CreateMenu())) return 0;
3721
    menu = MENU_GetMenu( hmenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
3722
    menu->wFlags |= MF_POPUP;
3723
    menu->bTimeToHide = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3724
    return hmenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
3725 3726 3727 3728
}


/**********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
3729 3730
 *         GetMenuCheckMarkDimensions    (USER.417)
 *         GetMenuCheckMarkDimensions    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3731
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3732
DWORD WINAPI GetMenuCheckMarkDimensions(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
3733
{
3734
    return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
Alexandre Julliard's avatar
Alexandre Julliard committed
3735 3736 3737
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3738
/**********************************************************************
3739
 *         SetMenuItemBitmaps    (USER.418)
Alexandre Julliard's avatar
Alexandre Julliard committed
3740
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3741 3742
BOOL16 WINAPI SetMenuItemBitmaps16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags,
                                    HBITMAP16 hNewUnCheck, HBITMAP16 hNewCheck)
Alexandre Julliard's avatar
Alexandre Julliard committed
3743
{
3744
    return SetMenuItemBitmaps( hMenu, nPos, wFlags, hNewUnCheck, hNewCheck );
Alexandre Julliard's avatar
Alexandre Julliard committed
3745 3746 3747 3748
}


/**********************************************************************
3749
 *         SetMenuItemBitmaps    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3750
 */
3751 3752
BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
                                    HBITMAP hNewUnCheck, HBITMAP hNewCheck)
Alexandre Julliard's avatar
Alexandre Julliard committed
3753
{
Alexandre Julliard's avatar
Alexandre Julliard committed
3754
    MENUITEM *item;
3755
    TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
3756 3757
                 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
    if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3758 3759 3760

    if (!hNewCheck && !hNewUnCheck)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
3761
	item->fState &= ~MF_USECHECKBITMAPS;
Alexandre Julliard's avatar
Alexandre Julliard committed
3762 3763 3764
    }
    else  /* Install new bitmaps */
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
3765 3766 3767
	item->hCheckBit = hNewCheck;
	item->hUnCheckBit = hNewUnCheck;
	item->fState |= MF_USECHECKBITMAPS;
Alexandre Julliard's avatar
Alexandre Julliard committed
3768 3769
    }
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3770 3771 3772
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3773
/**********************************************************************
3774
 *         CreateMenu    (USER.151)
Alexandre Julliard's avatar
Alexandre Julliard committed
3775
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3776
HMENU16 WINAPI CreateMenu16(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
3777
{
3778
    return CreateMenu();
Alexandre Julliard's avatar
Alexandre Julliard committed
3779 3780 3781 3782
}


/**********************************************************************
3783
 *         CreateMenu    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3784
 */
3785
HMENU WINAPI CreateMenu(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
3786
{
3787
    HMENU hMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
3788
    LPPOPUPMENU menu;
Alexandre Julliard's avatar
Alexandre Julliard committed
3789
    if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
3790
    menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3791 3792

    ZeroMemory(menu, sizeof(POPUPMENU));
Alexandre Julliard's avatar
Alexandre Julliard committed
3793 3794
    menu->wMagic = MENU_MAGIC;
    menu->FocusedItem = NO_SELECTED_ITEM;
3795
    menu->bTimeToHide = FALSE;
3796

3797
    TRACE("return %04x\n", hMenu );
3798

Alexandre Julliard's avatar
Alexandre Julliard committed
3799
    return hMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
3800 3801 3802 3803
}


/**********************************************************************
3804
 *         DestroyMenu    (USER.152)
Alexandre Julliard's avatar
Alexandre Julliard committed
3805
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3806
BOOL16 WINAPI DestroyMenu16( HMENU16 hMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
3807
{
3808
    return DestroyMenu( hMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
3809 3810 3811 3812
}


/**********************************************************************
3813
 *         DestroyMenu    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3814
 */
3815
BOOL WINAPI DestroyMenu( HMENU hMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
3816
{
3817
    TRACE("(%04x)\n", hMenu);
Alexandre Julliard's avatar
Alexandre Julliard committed
3818

Alexandre Julliard's avatar
Alexandre Julliard committed
3819 3820 3821 3822
    /* Silently ignore attempts to destroy default system popup */

    if (hMenu && hMenu != MENU_DefSysPopup)
    {
3823
        LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
Alexandre Julliard's avatar
Alexandre Julliard committed
3824

3825
        if (!lppop) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3826

3827
        lppop->wMagic = 0;  /* Mark it as destroyed */
Alexandre Julliard's avatar
Alexandre Julliard committed
3828

3829
        if ((lppop->wFlags & MF_POPUP) && lppop->hWnd)
3830
        {
3831
            DestroyWindow( lppop->hWnd );
3832 3833
            lppop->hWnd = 0;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
3834

3835
        if (lppop->items) /* recursively destroy submenus */
3836
        {
3837 3838 3839 3840 3841 3842 3843 3844
            int i;
            MENUITEM *item = lppop->items;
            for (i = lppop->nItems; i > 0; i--, item++)
            {
                if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
                MENU_FreeItemData( item );
            }
            HeapFree( GetProcessHeap(), 0, lppop->items );
3845
        }
3846
        USER_HEAP_FREE( hMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
3847
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3848
    return (hMenu != MENU_DefSysPopup);
Alexandre Julliard's avatar
Alexandre Julliard committed
3849 3850
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3851

Alexandre Julliard's avatar
Alexandre Julliard committed
3852
/**********************************************************************
3853
 *         GetSystemMenu    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3854
 */
3855
HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
Alexandre Julliard's avatar
Alexandre Julliard committed
3856
{
Alexandre Julliard's avatar
Alexandre Julliard committed
3857
    WND *wndPtr = WIN_FindWndPtr( hWnd );
3858
    HMENU retvalue = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
3859

Alexandre Julliard's avatar
Alexandre Julliard committed
3860
    if (wndPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
3861
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
3862 3863 3864 3865
	if( wndPtr->hSysMenu )
	{
	    if( bRevert )
	    {
3866
		DestroyMenu(wndPtr->hSysMenu); 
Alexandre Julliard's avatar
Alexandre Julliard committed
3867 3868 3869 3870
		wndPtr->hSysMenu = 0;
	    }
	    else
	    {
3871 3872
		POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
		if( menu ) 
3873 3874 3875 3876 3877 3878 3879 3880 3881 3882
                {
		   if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
		      menu->items[0].hSubMenu = MENU_CopySysPopup();
		}
		else 
		{
		   WARN("Current sys-menu (%04x) of wnd %04x is broken\n", 
			wndPtr->hSysMenu, hWnd);
		   wndPtr->hSysMenu = 0;
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
3883 3884 3885 3886
	    }
	}

	if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3887
	    wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
Alexandre Julliard's avatar
Alexandre Julliard committed
3888 3889

	if( wndPtr->hSysMenu )
3890
        {
3891
	    POPUPMENU *menu;
3892
	    retvalue = GetSubMenu(wndPtr->hSysMenu, 0);
3893 3894 3895

	    /* Store the dummy sysmenu handle to facilitate the refresh */
	    /* of the close button if the SC_CLOSE item change */
3896 3897
	    menu = MENU_GetMenu(retvalue);
	    if ( menu )
3898
	       menu->hSysMenuOwner = wndPtr->hSysMenu;
3899 3900
        }
        WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
3901
    }
3902
    return bRevert ? 0 : retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
3903 3904
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3905

Alexandre Julliard's avatar
Alexandre Julliard committed
3906
/*******************************************************************
3907
 *         SetSystemMenu    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3908
 */
3909
BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
3910
{
Alexandre Julliard's avatar
Alexandre Julliard committed
3911
    WND *wndPtr = WIN_FindWndPtr(hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
3912

Alexandre Julliard's avatar
Alexandre Julliard committed
3913 3914
    if (wndPtr)
    {
3915
	if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
3916
	wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
3917
        WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
3918 3919 3920
	return TRUE;
    }
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3921 3922
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3923

Alexandre Julliard's avatar
Alexandre Julliard committed
3924
/**********************************************************************
3925
 *         GetMenu    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3926
 */
3927
HMENU WINAPI GetMenu( HWND hWnd ) 
3928
{
3929 3930
    HMENU retvalue = (HMENU)GetWindowLongA( hWnd, GWL_ID );
    TRACE("for %04x returning %04x\n", hWnd, retvalue);
3931
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
3932 3933
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3934

Alexandre Julliard's avatar
Alexandre Julliard committed
3935
/**********************************************************************
3936
 *         SetMenu    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3937
 */
3938
BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
3939
{
3940
    TRACE("(%04x, %04x);\n", hWnd, hMenu);
Alexandre Julliard's avatar
Alexandre Julliard committed
3941

3942 3943
    if (hMenu && !IsMenu(hMenu))
    {
3944 3945
        WARN("hMenu %x is not a menu handle\n", hMenu);
        return FALSE;
3946
    }
3947
    if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
3948

3949
    hWnd = WIN_GetFullHandle( hWnd );
3950
    if (GetCapture() == hWnd) ReleaseCapture();
Alexandre Julliard's avatar
Alexandre Julliard committed
3951

3952 3953 3954
    if (hMenu != 0)
    {
        LPPOPUPMENU lpmenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
3955

3956
        if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
3957

3958 3959
        lpmenu->hWnd = hWnd;
        lpmenu->Height = 0;  /* Make sure we recalculate the size */
Alexandre Julliard's avatar
Alexandre Julliard committed
3960
    }
3961 3962 3963 3964 3965 3966
    SetWindowLongA( hWnd, GWL_ID, hMenu );

    if (IsWindowVisible(hWnd))
        SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
                      SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3967 3968 3969 3970 3971
}



/**********************************************************************
3972
 *         GetSubMenu    (USER.159)
Alexandre Julliard's avatar
Alexandre Julliard committed
3973
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
3974
HMENU16 WINAPI GetSubMenu16( HMENU16 hMenu, INT16 nPos )
Alexandre Julliard's avatar
Alexandre Julliard committed
3975
{
3976
    return GetSubMenu( hMenu, nPos );
Alexandre Julliard's avatar
Alexandre Julliard committed
3977 3978
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3979

Alexandre Julliard's avatar
Alexandre Julliard committed
3980
/**********************************************************************
3981
 *         GetSubMenu    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3982
 */
3983
HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
Alexandre Julliard's avatar
Alexandre Julliard committed
3984
{
3985
    MENUITEM * lpmi;
Alexandre Julliard's avatar
Alexandre Julliard committed
3986

3987 3988 3989
    if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
    if (!(lpmi->fType & MF_POPUP)) return 0;
    return lpmi->hSubMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
3990 3991 3992
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3993
/**********************************************************************
3994
 *         DrawMenuBar    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3995
 */
3996
BOOL WINAPI DrawMenuBar( HWND hWnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
3997 3998
{
    LPPOPUPMENU lppop;
3999
    HMENU hMenu = GetMenu(hWnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
4000

4001 4002 4003 4004 4005 4006 4007 4008
    if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
    if (!hMenu || !(lppop = MENU_GetMenu( hMenu ))) return FALSE;

    lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
    lppop->hwndOwner = hWnd;
    SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
                  SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
4009 4010
}

4011 4012
/***********************************************************************
 *           DrawMenuBarTemp   (USER32.@)
4013 4014 4015 4016 4017 4018
 *
 * UNDOCUMENTED !!
 * 
 * called by W98SE desk.cpl Control Panel Applet
 *
 * Not 100% sure about the param names, but close.
4019
 */
4020
DWORD WINAPI DrawMenuBarTemp(HWND someHWND, HDC someHDC, LPRECT someRECT, HMENU someHMENU, HFONT someFONT)
4021
{
4022
    FIXME("(0x%08x, 0x%08x, %p, 0x%08x, 0x%08x): stub\n", someHWND, someHDC, someRECT, someHMENU, someFONT);
4023 4024
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
4025

Alexandre Julliard's avatar
Alexandre Julliard committed
4026
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
4027 4028
 *           EndMenu   (USER.187)
 *           EndMenu   (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4029
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
4030
void WINAPI EndMenu(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
4031
{
4032
    /* if we are in the menu code, and it is active */
4033
    if (!fEndMenu && top_popup)
4034 4035 4036 4037 4038 4039 4040 4041
    {
	/* terminate the menu handling code */
        fEndMenu = TRUE;

	/* needs to be posted to wakeup the internal menu handler */
	/* which will now terminate the menu, in the event that */
	/* the main window was minimized, or lost focus, so we */
	/* don't end up with an orphaned menu */
4042
        PostMessageA( top_popup, WM_CANCELMODE, 0, 0);
4043
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
4044 4045 4046 4047 4048 4049
}


/***********************************************************************
 *           LookupMenuHandle   (USER.217)
 */
4050
HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
Alexandre Julliard's avatar
Alexandre Julliard committed
4051
{
4052 4053
    HMENU hmenu32 = hmenu;
    UINT id32 = id;
Alexandre Julliard's avatar
Alexandre Julliard committed
4054 4055
    if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
    else return hmenu32;
Alexandre Julliard's avatar
Alexandre Julliard committed
4056 4057 4058
}


Alexandre Julliard's avatar
Alexandre Julliard committed
4059
/**********************************************************************
4060
 *	    LoadMenu    (USER.150)
Alexandre Julliard's avatar
Alexandre Julliard committed
4061
 */
4062
HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
Alexandre Julliard's avatar
Alexandre Julliard committed
4063
{
Alexandre Julliard's avatar
Alexandre Julliard committed
4064 4065 4066
    HRSRC16 hRsrc;
    HGLOBAL16 handle;
    HMENU16 hMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
4067

4068 4069
    TRACE("(%04x,%s)\n", instance, debugres_a(name) );

Alexandre Julliard's avatar
Alexandre Julliard committed
4070 4071
    if (HIWORD(name))
    {
4072
        if (name[0] == '#') name = (LPCSTR)atoi( name + 1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
4073 4074 4075
    }

    if (!name) return 0;
4076

Alexandre Julliard's avatar
Alexandre Julliard committed
4077
    /* check for Win32 module */
4078
    if (HIWORD(instance)) return LoadMenuA( instance, name );
Alexandre Julliard's avatar
Alexandre Julliard committed
4079
    instance = GetExePtr( instance );
Alexandre Julliard's avatar
Alexandre Julliard committed
4080

4081
    if (!(hRsrc = FindResource16( instance, name, RT_MENUA ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
4082 4083 4084
    if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
    hMenu = LoadMenuIndirect16(LockResource16(handle));
    FreeResource16( handle );
Alexandre Julliard's avatar
Alexandre Julliard committed
4085 4086 4087 4088
    return hMenu;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
4089
/*****************************************************************
4090
 *        LoadMenuA   (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4091
 */
4092
HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
Alexandre Julliard's avatar
Alexandre Julliard committed
4093
{
4094
    HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
Alexandre Julliard's avatar
Alexandre Julliard committed
4095
    if (!hrsrc) return 0;
4096
    return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
Alexandre Julliard's avatar
Alexandre Julliard committed
4097 4098 4099 4100
}


/*****************************************************************
4101
 *        LoadMenuW   (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4102
 */
4103
HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
Alexandre Julliard's avatar
Alexandre Julliard committed
4104
{
4105
    HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
Alexandre Julliard's avatar
Alexandre Julliard committed
4106
    if (!hrsrc) return 0;
4107
    return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
Alexandre Julliard's avatar
Alexandre Julliard committed
4108 4109 4110
}


Alexandre Julliard's avatar
Alexandre Julliard committed
4111
/**********************************************************************
4112
 *	    LoadMenuIndirect    (USER.220)
Alexandre Julliard's avatar
Alexandre Julliard committed
4113
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
4114
HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
Alexandre Julliard's avatar
Alexandre Julliard committed
4115
{
Alexandre Julliard's avatar
Alexandre Julliard committed
4116
    HMENU16 hMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
4117 4118
    WORD version, offset;
    LPCSTR p = (LPCSTR)template;
Alexandre Julliard's avatar
Alexandre Julliard committed
4119

4120
    TRACE("(%p)\n", template );
Alexandre Julliard's avatar
Alexandre Julliard committed
4121 4122 4123 4124
    version = GET_WORD(p);
    p += sizeof(WORD);
    if (version)
    {
4125
        WARN("version must be 0 for Win16\n" );
Alexandre Julliard's avatar
Alexandre Julliard committed
4126 4127 4128 4129
        return 0;
    }
    offset = GET_WORD(p);
    p += sizeof(WORD) + offset;
4130
    if (!(hMenu = CreateMenu())) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
4131
    if (!MENU_ParseResource( p, hMenu, FALSE ))
Alexandre Julliard's avatar
Alexandre Julliard committed
4132
    {
4133
        DestroyMenu( hMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
4134
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
4135 4136
    }
    return hMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
4137 4138
}

Alexandre Julliard's avatar
Alexandre Julliard committed
4139

Alexandre Julliard's avatar
Alexandre Julliard committed
4140
/**********************************************************************
4141
 *	    LoadMenuIndirectA    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4142
 */
4143
HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
Alexandre Julliard's avatar
Alexandre Julliard committed
4144
{
Alexandre Julliard's avatar
Alexandre Julliard committed
4145
    HMENU16 hMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
4146 4147 4148
    WORD version, offset;
    LPCSTR p = (LPCSTR)template;

4149
    TRACE("%p\n", template );
Alexandre Julliard's avatar
Alexandre Julliard committed
4150 4151
    version = GET_WORD(p);
    p += sizeof(WORD);
Alexandre Julliard's avatar
Alexandre Julliard committed
4152 4153 4154 4155 4156
    switch (version)
      {
      case 0:
	offset = GET_WORD(p);
	p += sizeof(WORD) + offset;
4157
	if (!(hMenu = CreateMenu())) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
4158 4159
	if (!MENU_ParseResource( p, hMenu, TRUE ))
	  {
4160
	    DestroyMenu( hMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
4161 4162 4163 4164 4165 4166
	    return 0;
	  }
	return hMenu;
      case 1:
	offset = GET_WORD(p);
	p += sizeof(WORD) + offset;
4167
	if (!(hMenu = CreateMenu())) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
4168 4169
	if (!MENUEX_ParseResource( p, hMenu))
	  {
4170
	    DestroyMenu( hMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
4171 4172 4173 4174
	    return 0;
	  }
	return hMenu;
      default:
4175
        ERR("version %d not supported.\n", version);
Alexandre Julliard's avatar
Alexandre Julliard committed
4176
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
4177
      }
Alexandre Julliard's avatar
Alexandre Julliard committed
4178 4179 4180 4181
}


/**********************************************************************
4182
 *	    LoadMenuIndirectW    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4183
 */
4184
HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
Alexandre Julliard's avatar
Alexandre Julliard committed
4185 4186
{
    /* FIXME: is there anything different between A and W? */
4187
    return LoadMenuIndirectA( template );
Alexandre Julliard's avatar
Alexandre Julliard committed
4188 4189 4190
}


Alexandre Julliard's avatar
Alexandre Julliard committed
4191
/**********************************************************************
4192
 *		IsMenu    (USER.358)
Alexandre Julliard's avatar
Alexandre Julliard committed
4193
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
4194
BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
4195
{
4196
    return IsMenu( hmenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
4197 4198 4199 4200
}


/**********************************************************************
4201
 *		IsMenu    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4202
 */
4203
BOOL WINAPI IsMenu(HMENU hmenu)
Alexandre Julliard's avatar
Alexandre Julliard committed
4204
{
4205 4206
    LPPOPUPMENU menu = MENU_GetMenu(hmenu);
    return menu != NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
4207 4208
}

Alexandre Julliard's avatar
Alexandre Julliard committed
4209
/**********************************************************************
4210
 *		GetMenuItemInfo_common
Alexandre Julliard's avatar
Alexandre Julliard committed
4211 4212
 */

4213
static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4214
					LPMENUITEMINFOW lpmii, BOOL unicode)
Alexandre Julliard's avatar
Alexandre Julliard committed
4215
{
4216 4217
    MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);

4218
    debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4219

Alexandre Julliard's avatar
Alexandre Julliard committed
4220 4221 4222 4223 4224 4225
    if (!menu)
	return FALSE;

    if (lpmii->fMask & MIIM_TYPE) {
	lpmii->fType = menu->fType;
	switch (MENU_ITEM_TYPE(menu->fType)) {
4226
	case MF_STRING:
4227
            break;  /* will be done below */
4228 4229 4230 4231 4232 4233
	case MF_OWNERDRAW:
	case MF_BITMAP:
	    lpmii->dwTypeData = menu->text;
	    /* fall through */
	default:
	    lpmii->cch = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
4234 4235
	}
    }
4236

4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262
    /* copy the text string */
    if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)) &&
         (MENU_ITEM_TYPE(menu->fType) == MF_STRING) && menu->text)
    {
        int len;
        if (unicode)
        {
            len = strlenW(menu->text);
            if(lpmii->dwTypeData && lpmii->cch)
                lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
        }
        else
        {
            len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL, 0, NULL, NULL );
            if(lpmii->dwTypeData && lpmii->cch)
                if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
                                          (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
                    ((LPSTR)lpmii->dwTypeData)[lpmii->cch-1] = 0;
        }
        /* if we've copied a substring we return its length */
        if(lpmii->dwTypeData && lpmii->cch)
        {
            if (lpmii->cch <= len) lpmii->cch--;
        }
        else /* return length of string */
            lpmii->cch = len;
Alexandre Julliard's avatar
Alexandre Julliard committed
4263
    }
4264 4265 4266 4267 4268 4269 4270

    if (lpmii->fMask & MIIM_FTYPE)
	lpmii->fType = menu->fType;

    if (lpmii->fMask & MIIM_BITMAP)
	lpmii->hbmpItem = menu->hbmpItem;

Alexandre Julliard's avatar
Alexandre Julliard committed
4271 4272
    if (lpmii->fMask & MIIM_STATE)
	lpmii->fState = menu->fState;
Alexandre Julliard's avatar
Alexandre Julliard committed
4273

Alexandre Julliard's avatar
Alexandre Julliard committed
4274 4275
    if (lpmii->fMask & MIIM_ID)
	lpmii->wID = menu->wID;
Alexandre Julliard's avatar
Alexandre Julliard committed
4276

Alexandre Julliard's avatar
Alexandre Julliard committed
4277 4278
    if (lpmii->fMask & MIIM_SUBMENU)
	lpmii->hSubMenu = menu->hSubMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
4279

Alexandre Julliard's avatar
Alexandre Julliard committed
4280 4281 4282
    if (lpmii->fMask & MIIM_CHECKMARKS) {
	lpmii->hbmpChecked = menu->hCheckBit;
	lpmii->hbmpUnchecked = menu->hUnCheckBit;
Alexandre Julliard's avatar
Alexandre Julliard committed
4283
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
4284 4285
    if (lpmii->fMask & MIIM_DATA)
	lpmii->dwItemData = menu->dwItemData;
Alexandre Julliard's avatar
Alexandre Julliard committed
4286 4287 4288 4289 4290

  return TRUE;
}

/**********************************************************************
4291
 *		GetMenuItemInfoA    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4292
 */
4293 4294
BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
                                  LPMENUITEMINFOA lpmii)
Alexandre Julliard's avatar
Alexandre Julliard committed
4295
{
4296 4297
    return GetMenuItemInfo_common (hmenu, item, bypos, 
                                    (LPMENUITEMINFOW)lpmii, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
4298 4299 4300
}

/**********************************************************************
4301
 *		GetMenuItemInfoW    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4302
 */
4303 4304
BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
                                  LPMENUITEMINFOW lpmii)
Alexandre Julliard's avatar
Alexandre Julliard committed
4305
{
4306
    return GetMenuItemInfo_common (hmenu, item, bypos,
4307
                                     lpmii, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
4308 4309
}

4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333

/* set a menu item text from a ASCII or Unicode string */
inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
{
    if (!text)
    {
        menu->text = NULL;
        menu->fType |= MF_SEPARATOR;
    }
    else if (unicode)
    {
        if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
            strcpyW( menu->text, text );
    }
    else
    {
        LPCSTR str = (LPCSTR)text;
        int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
        if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
            MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
    }
}


Alexandre Julliard's avatar
Alexandre Julliard committed
4334
/**********************************************************************
4335
 *		SetMenuItemInfo_common
Alexandre Julliard's avatar
Alexandre Julliard committed
4336 4337
 */

4338
static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4339
				       const MENUITEMINFOW *lpmii,
4340
				       BOOL unicode)
Alexandre Julliard's avatar
Alexandre Julliard committed
4341 4342 4343
{
    if (!menu) return FALSE;

4344 4345
    debug_print_menuitem("MENU_SetItemInfo_common from: ", menu, "");

4346
    if (lpmii->fMask & MIIM_TYPE ) {
Alexandre Julliard's avatar
Alexandre Julliard committed
4347
	/* Get rid of old string.  */
4348
	if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4349
	    HeapFree(GetProcessHeap(), 0, menu->text);
4350 4351
	    menu->text = NULL;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
4352

4353 4354 4355
	/* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */ 
	menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
	menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4356

Alexandre Julliard's avatar
Alexandre Julliard committed
4357
	menu->text = lpmii->dwTypeData;
4358

4359 4360
       if (IS_STRING_ITEM(menu->fType))
           set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4361 4362 4363 4364 4365
    }

    if (lpmii->fMask & MIIM_FTYPE ) {
	/* free the string when the type is changing */
	if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4366
	    HeapFree(GetProcessHeap(), 0, menu->text);
4367 4368 4369 4370
	    menu->text = NULL;
	}
	menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
	menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4371 4372
        if ( IS_STRING_ITEM(menu->fType) && !menu->text )
            menu->fType |= MF_SEPARATOR;
4373 4374 4375 4376 4377
    }

    if (lpmii->fMask & MIIM_STRING ) {
	/* free the string when used */
	if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4378
	    HeapFree(GetProcessHeap(), 0, menu->text);
4379
            set_menu_item_text( menu, lpmii->dwTypeData, unicode );
Alexandre Julliard's avatar
Alexandre Julliard committed
4380 4381
	}
    }
4382

Alexandre Julliard's avatar
Alexandre Julliard committed
4383
    if (lpmii->fMask & MIIM_STATE)
4384
    {
4385
	/* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
Alexandre Julliard's avatar
Alexandre Julliard committed
4386
	menu->fState = lpmii->fState;
4387
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
4388 4389 4390 4391

    if (lpmii->fMask & MIIM_ID)
	menu->wID = lpmii->wID;

Alexandre Julliard's avatar
Alexandre Julliard committed
4392
    if (lpmii->fMask & MIIM_SUBMENU) {
Alexandre Julliard's avatar
Alexandre Julliard committed
4393
	menu->hSubMenu = lpmii->hSubMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
4394
	if (menu->hSubMenu) {
4395 4396
	    POPUPMENU *subMenu = MENU_GetMenu((UINT16)menu->hSubMenu);
	    if (subMenu) {
Alexandre Julliard's avatar
Alexandre Julliard committed
4397 4398 4399 4400 4401 4402 4403 4404 4405 4406
		subMenu->wFlags |= MF_POPUP;
		menu->fType |= MF_POPUP;
	    }
	    else
		/* FIXME: Return an error ? */
		menu->fType &= ~MF_POPUP;
	}
	else
	    menu->fType &= ~MF_POPUP;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
4407 4408 4409

    if (lpmii->fMask & MIIM_CHECKMARKS)
    {
4410 4411 4412
        if (lpmii->fType & MFT_RADIOCHECK)
            menu->fType |= MFT_RADIOCHECK;

Alexandre Julliard's avatar
Alexandre Julliard committed
4413 4414 4415 4416 4417 4418
	menu->hCheckBit = lpmii->hbmpChecked;
	menu->hUnCheckBit = lpmii->hbmpUnchecked;
    }
    if (lpmii->fMask & MIIM_DATA)
	menu->dwItemData = lpmii->dwItemData;

4419
    debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
Alexandre Julliard's avatar
Alexandre Julliard committed
4420 4421
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
4422 4423

/**********************************************************************
4424
 *		SetMenuItemInfoA    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4425
 */
4426 4427
BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
                                 const MENUITEMINFOA *lpmii) 
Alexandre Julliard's avatar
Alexandre Julliard committed
4428
{
4429 4430 4431 4432 4433 4434 4435 4436 4437
    if ((lpmii->fType & (MF_HILITE|MF_POPUP)) || (lpmii->fState)) {
	/* QuickTime does pass invalid data into SetMenuItemInfo. 
	 * do some of the checks Windows does.
	 */
        WARN("Bad masks for type (0x%08x) or state (0x%08x)\n",
             lpmii->fType,lpmii->fState );
	return FALSE;
    }

4438
    return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4439
				    (const MENUITEMINFOW *)lpmii, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
4440 4441 4442
}

/**********************************************************************
4443
 *		SetMenuItemInfoW    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4444
 */
4445 4446
BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
                                 const MENUITEMINFOW *lpmii)
Alexandre Julliard's avatar
Alexandre Julliard committed
4447
{
4448
    return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4449
				    lpmii, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
4450 4451 4452
}

/**********************************************************************
4453
 *		SetMenuDefaultItem    (USER32.@)
4454
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
4455
 */
4456
BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
Alexandre Julliard's avatar
Alexandre Julliard committed
4457
{
4458 4459 4460 4461
	UINT i;
	POPUPMENU *menu;
	MENUITEM *item;
	
4462
	TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
Alexandre Julliard's avatar
Alexandre Julliard committed
4463

4464
	if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
4465

4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477
	/* reset all default-item flags */
	item = menu->items;
	for (i = 0; i < menu->nItems; i++, item++)
	{
	    item->fState &= ~MFS_DEFAULT;
	}
	
	/* no default item */
	if ( -1 == uItem)
	{
	    return TRUE;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
4478

4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498
	item = menu->items;
	if ( bypos )
	{
	    if ( uItem >= menu->nItems ) return FALSE;
	    item[uItem].fState |= MFS_DEFAULT;
	    return TRUE;
	}
	else
	{
	    for (i = 0; i < menu->nItems; i++, item++)
	    {
		if (item->wID == uItem)
		{
		     item->fState |= MFS_DEFAULT;
		     return TRUE;
		}
	    }
		
	}
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
4499 4500
}

Alexandre Julliard's avatar
Alexandre Julliard committed
4501
/**********************************************************************
4502
 *		GetMenuDefaultItem    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4503
 */
4504
UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
Alexandre Julliard's avatar
Alexandre Julliard committed
4505
{
4506 4507 4508
	POPUPMENU *menu;
	MENUITEM * item;
	UINT i = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
4509

4510
	TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
4511

4512
	if (!(menu = MENU_GetMenu(hmenu))) return -1;
4513 4514 4515

	/* find default item */
	item = menu->items;
4516 4517 4518 4519
	
	/* empty menu */
	if (! item) return -1;
	
4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538
	while ( !( item->fState & MFS_DEFAULT ) )
	{
	    i++; item++;
	    if  (i >= menu->nItems ) return -1;
	}
	
	/* default: don't return disabled items */
	if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;

	/* search rekursiv when needed */
	if ( (item->fType & MF_POPUP) &&  (flags & GMDI_GOINTOPOPUPS) )
	{
	    UINT ret;
	    ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
	    if ( -1 != ret ) return ret;

	    /* when item not found in submenu, return the popup item */
	}
	return ( bypos ) ? i : item->wID;
Alexandre Julliard's avatar
Alexandre Julliard committed
4539 4540 4541

}

Alexandre Julliard's avatar
Alexandre Julliard committed
4542
/*******************************************************************
4543
 *              InsertMenuItem   (USER.441)
Alexandre Julliard's avatar
Alexandre Julliard committed
4544 4545 4546 4547 4548 4549
 *
 * FIXME: untested
 */
BOOL16 WINAPI InsertMenuItem16( HMENU16 hmenu, UINT16 pos, BOOL16 byposition,
                                const MENUITEMINFO16 *mii )
{
4550
    MENUITEMINFOA miia;
Alexandre Julliard's avatar
Alexandre Julliard committed
4551 4552 4553

    miia.cbSize        = sizeof(miia);
    miia.fMask         = mii->fMask;
4554
    miia.dwTypeData    = (LPSTR)mii->dwTypeData;
Alexandre Julliard's avatar
Alexandre Julliard committed
4555 4556 4557 4558 4559 4560 4561 4562 4563
    miia.fType         = mii->fType;
    miia.fState        = mii->fState;
    miia.wID           = mii->wID;
    miia.hSubMenu      = mii->hSubMenu;
    miia.hbmpChecked   = mii->hbmpChecked;
    miia.hbmpUnchecked = mii->hbmpUnchecked;
    miia.dwItemData    = mii->dwItemData;
    miia.cch           = mii->cch;
    if (IS_STRING_ITEM(miia.fType))
4564
        miia.dwTypeData = MapSL(mii->dwTypeData);
4565
    return InsertMenuItemA( hmenu, pos, byposition, &miia );
Alexandre Julliard's avatar
Alexandre Julliard committed
4566 4567 4568 4569
}


/**********************************************************************
4570
 *		InsertMenuItemA    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4571
 */
4572 4573
BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
                                const MENUITEMINFOA *lpmii)
Alexandre Julliard's avatar
Alexandre Julliard committed
4574
{
Alexandre Julliard's avatar
Alexandre Julliard committed
4575
    MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4576
    return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)lpmii, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
4577 4578 4579 4580
}


/**********************************************************************
4581
 *		InsertMenuItemW    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4582
 */
4583 4584
BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
                                const MENUITEMINFOW *lpmii)
Alexandre Julliard's avatar
Alexandre Julliard committed
4585
{
Alexandre Julliard's avatar
Alexandre Julliard committed
4586
    MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4587
    return SetMenuItemInfo_common(item, lpmii, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
4588
}
Alexandre Julliard's avatar
Alexandre Julliard committed
4589 4590

/**********************************************************************
4591
 *		CheckMenuRadioItem    (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
4592 4593
 */

4594 4595 4596
BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
				   UINT first, UINT last, UINT check,
				   UINT bypos)
Alexandre Julliard's avatar
Alexandre Julliard committed
4597 4598
{
     MENUITEM *mifirst, *milast, *micheck;
4599
     HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
4600

4601
     TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
4602
		  hMenu, first, last, check, bypos);
Alexandre Julliard's avatar
Alexandre Julliard committed
4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629

     mifirst = MENU_FindItem (&mfirst, &first, bypos);
     milast = MENU_FindItem (&mlast, &last, bypos);
     micheck = MENU_FindItem (&mcheck, &check, bypos);

     if (mifirst == NULL || milast == NULL || micheck == NULL ||
	 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
	 micheck > milast || micheck < mifirst)
	  return FALSE;

     while (mifirst <= milast)
     {
	  if (mifirst == micheck)
	  {
	       mifirst->fType |= MFT_RADIOCHECK;
	       mifirst->fState |= MFS_CHECKED;
	  } else {
	       mifirst->fType &= ~MFT_RADIOCHECK;
	       mifirst->fState &= ~MFS_CHECKED;
	  }
	  mifirst++;
     }

     return TRUE;
}

/**********************************************************************
4630
 *		CheckMenuRadioItem (USER.666)
Alexandre Julliard's avatar
Alexandre Julliard committed
4631 4632 4633 4634 4635
 */
BOOL16 WINAPI CheckMenuRadioItem16(HMENU16 hMenu,
				   UINT16 first, UINT16 last, UINT16 check,
				   BOOL16 bypos)
{
4636
     return CheckMenuRadioItem (hMenu, first, last, check, bypos);
Alexandre Julliard's avatar
Alexandre Julliard committed
4637 4638 4639
}

/**********************************************************************
4640
 *		GetMenuItemRect    (USER32.@)
4641 4642 4643 4644 4645
 *
 *      ATTENTION: Here, the returned values in rect are the screen 
 *                 coordinates of the item just like if the menu was 
 *                 always on the upper left side of the application.
 *                 
Alexandre Julliard's avatar
Alexandre Julliard committed
4646
 */
4647 4648
BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
				 LPRECT rect)
Alexandre Julliard's avatar
Alexandre Julliard committed
4649
{
4650
     POPUPMENU *itemMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
4651
     MENUITEM *item;
4652
     HWND referenceHwnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
4653

4654
     TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
Alexandre Julliard's avatar
Alexandre Julliard committed
4655 4656

     item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4657 4658 4659 4660
     referenceHwnd = hwnd;

     if(!hwnd)
     {
4661
	 itemMenu = MENU_GetMenu(hMenu);
4662 4663
	 if (itemMenu == NULL) 
	     return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
4664

4665
	 if(itemMenu->hWnd == 0)
4666 4667 4668 4669 4670 4671
	     return FALSE;
	 referenceHwnd = itemMenu->hWnd;
     }

     if ((rect == NULL) || (item == NULL)) 
	 return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
4672 4673 4674

     *rect = item->rect;

4675
     MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4676

Alexandre Julliard's avatar
Alexandre Julliard committed
4677 4678 4679
     return TRUE;
}

4680

4681
/**********************************************************************
4682
 *		SetMenuInfo    (USER32.@)
4683 4684 4685 4686 4687 4688 4689 4690 4691
 *
 * FIXME
 *	MIM_APPLYTOSUBMENUS
 *	actually use the items to draw the menu
 */
BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
{
    POPUPMENU *menu;

4692
    TRACE("(0x%04x %p)\n", hMenu, lpmi);
4693

4694
    if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717
    {

	if (lpmi->fMask & MIM_BACKGROUND)
	    menu->hbrBack = lpmi->hbrBack;

	if (lpmi->fMask & MIM_HELPID)
	    menu->dwContextHelpID = lpmi->dwContextHelpID;

	if (lpmi->fMask & MIM_MAXHEIGHT)
	    menu->cyMax = lpmi->cyMax;

	if (lpmi->fMask & MIM_MENUDATA)
	    menu->dwMenuData = lpmi->dwMenuData;

	if (lpmi->fMask & MIM_STYLE)
	    menu->dwStyle = lpmi->dwStyle;

	return TRUE;
    }
    return FALSE;
}

/**********************************************************************
4718
 *		GetMenuInfo    (USER32.@)
4719 4720 4721 4722 4723 4724 4725 4726
 *
 *  NOTES
 *	win98/NT5.0
 *
 */
BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
{   POPUPMENU *menu;

4727
    TRACE("(0x%04x %p)\n", hMenu, lpmi);
4728

4729
    if (lpmi && (menu = MENU_GetMenu(hMenu)))
4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751
    {

	if (lpmi->fMask & MIM_BACKGROUND)
	    lpmi->hbrBack = menu->hbrBack;

	if (lpmi->fMask & MIM_HELPID)
	    lpmi->dwContextHelpID = menu->dwContextHelpID;

	if (lpmi->fMask & MIM_MAXHEIGHT)
	    lpmi->cyMax = menu->cyMax;

	if (lpmi->fMask & MIM_MENUDATA)
	    lpmi->dwMenuData = menu->dwMenuData;

	if (lpmi->fMask & MIM_STYLE)
	    lpmi->dwStyle = menu->dwStyle;

	return TRUE;
    }
    return FALSE;
}

4752
/**********************************************************************
4753
 *         SetMenuContextHelpId    (USER.384)
4754
 */
4755
BOOL16 WINAPI SetMenuContextHelpId16( HMENU16 hMenu, DWORD dwContextHelpID)
4756
{
4757
	return SetMenuContextHelpId( hMenu, dwContextHelpID );
4758 4759 4760 4761
}


/**********************************************************************
4762
 *         SetMenuContextHelpId    (USER32.@)
4763
 */
4764
BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4765
{
4766 4767
    LPPOPUPMENU menu;

4768
    TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
4769

4770
    if ((menu = MENU_GetMenu(hMenu)))
4771 4772 4773 4774 4775
    {
	menu->dwContextHelpID = dwContextHelpID;
	return TRUE;
    }
    return FALSE;
4776 4777 4778
}

/**********************************************************************
4779
 *         GetMenuContextHelpId    (USER.385)
4780 4781 4782
 */
DWORD WINAPI GetMenuContextHelpId16( HMENU16 hMenu )
{
4783
	return GetMenuContextHelpId( hMenu );
4784 4785 4786
}
 
/**********************************************************************
4787
 *         GetMenuContextHelpId    (USER32.@)
4788
 */
4789
DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4790
{
4791 4792
    LPPOPUPMENU menu;

4793
    TRACE("(0x%04x)\n", hMenu);
4794

4795
    if ((menu = MENU_GetMenu(hMenu)))
4796 4797 4798 4799
    {
	return menu->dwContextHelpID;
    }
    return 0;
4800
}
4801 4802

/**********************************************************************
4803
 *         MenuItemFromPoint    (USER32.@)
4804 4805 4806 4807 4808 4809 4810
 */
UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
{
    FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n", 
	  hWnd, hMenu, ptScreen.x, ptScreen.y);
    return 0;
}
4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869


/**********************************************************************
 *           translate_accelerator
 */
static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
                                   BYTE fVirt, WORD key, WORD cmd )
{
    UINT mesg = 0;

    if (wParam != key) return FALSE;

    if (message == WM_CHAR)
    {
        if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
        {
            TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
            goto found;
        }
    }
    else
    {
        if(fVirt & FVIRTKEY)
        {
            INT mask = 0;
            TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
                          wParam, 0xff & HIWORD(lParam));
            if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
            if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
            if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
            if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
            TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
        }
        else
        {
            if (!(lParam & 0x01000000))  /* no special_key */
            {
                if ((fVirt & FALT) && (lParam & 0x20000000))
                {                              /* ^^ ALT pressed */
                    TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
                    goto found;
                }
            }
        }
    }
    return FALSE;

 found:
    if (message == WM_KEYUP || message == WM_SYSKEYUP)
        mesg = 1;
    else if (GetCapture())
        mesg = 2;
    else if (!IsWindowEnabled(hWnd))
        mesg = 3;
    else
    {
        HMENU hMenu, hSubMenu, hSysMenu;
        UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;

4870 4871
        hMenu = (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
        hSysMenu = get_win_sys_menu( hWnd );
4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959

        /* find menu item and ask application to initialize it */
        /* 1. in the system menu */
        hSubMenu = hSysMenu;
        nPos = cmd;
        if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
        {
            SendMessageA(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
            if(hSubMenu != hSysMenu)
            {
                nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
                TRACE_(accel)("hSysMenu = %04x, hSubMenu = %04x, nPos = %d\n", hSysMenu, hSubMenu, nPos);
                SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
            }
            uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
        }
        else /* 2. in the window's menu */
        {
            hSubMenu = hMenu;
            nPos = cmd;
            if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
            {
                SendMessageA(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
                if(hSubMenu != hMenu)
                {
                    nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
                    TRACE_(accel)("hMenu = %04x, hSubMenu = %04x, nPos = %d\n", hMenu, hSubMenu, nPos);
                    SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
                }
                uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
            }
        }

        if (uSysStat != (UINT)-1)
        {
            if (uSysStat & (MF_DISABLED|MF_GRAYED))
                mesg=4;
            else
                mesg=WM_SYSCOMMAND;
        }
        else
        {
            if (uStat != (UINT)-1)
            {
                if (IsIconic(hWnd))
                    mesg=5;
                else
                {
                    if (uStat & (MF_DISABLED|MF_GRAYED))
                        mesg=6;
                    else
                        mesg=WM_COMMAND;
                }
            }
            else
                mesg=WM_COMMAND;
        }
    }

    if( mesg==WM_COMMAND )
    {
        TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
        SendMessageA(hWnd, mesg, 0x10000 | cmd, 0L);
    }
    else if( mesg==WM_SYSCOMMAND )
    {
        TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
        SendMessageA(hWnd, mesg, cmd, 0x00010000L);
    }
    else
    {
        /*  some reasons for NOT sending the WM_{SYS}COMMAND message: 
         *   #0: unknown (please report!)
         *   #1: for WM_KEYUP,WM_SYSKEYUP
         *   #2: mouse is captured
         *   #3: window is disabled 
         *   #4: it's a disabled system menu option
         *   #5: it's a menu option, but window is iconic
         *   #6: it's a menu option, but disabled
         */
        TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
        if(mesg==0)
            ERR_(accel)(" unknown reason - please report!");
    }
    return TRUE;
}

/**********************************************************************
4960
 *      TranslateAccelerator      (USER32.@)
4961
 *      TranslateAcceleratorA     (USER32.@)
4962
 *      TranslateAcceleratorW     (USER32.@)
4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999
 */
INT WINAPI TranslateAccelerator( HWND hWnd, HACCEL hAccel, LPMSG msg )
{
    /* YES, Accel16! */
    LPACCEL16 lpAccelTbl;
    int i;

    if (msg == NULL)
    {
        WARN_(accel)("msg null; should hang here to be win compatible\n");
        return 0;
    }
    if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(hAccel)))
    {
        WARN_(accel)("invalid accel handle=%x\n", hAccel);
        return 0;
    }
    if ((msg->message != WM_KEYDOWN &&
         msg->message != WM_KEYUP &&
         msg->message != WM_SYSKEYDOWN &&
         msg->message != WM_SYSKEYUP &&
         msg->message != WM_CHAR)) return 0;

    TRACE_(accel)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
                  "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
                  hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);

    i = 0;
    do
    {
        if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
                                   lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
            return 1;
    } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
    WARN_(accel)("couldn't translate accelerator key\n");
    return 0;
}