1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00
wine/controls/menu.c
Alexandre Julliard a69b88b2f2 Release 980315
Sun Mar 15 03:46:50 1998  Dimitrie O. Paun  <dimi@mail.cs.toronto.edu>

	* [*/*]
	Fixed some dprintf_ such that there is one and only one
	new line for each dprintf and that new line occurs at the end.
	Transformed some fprintfs into proper debug statements.
	Removed much redundancy from most of the debug statements. The
	redundancy appeared because now the component and function
	name is output automatically. Most debug statements also used to
	output the name of the function.
	All these changes prepared the source to switch completely to
	the new debugging interface.
	For more info, refer to ./documentation/debug-msg

Sat Mar 14 19:45:23 1997  Andreas Mohr <100.30936@germany.net>

	* [misc/shell.c] [if1632/kernel.spec]
	Changed parameters of FUNC004() to fix a crash.
	Not sure if this fix is correct (doc wanted).

	* [windows/user.c] [if1632/user.spec] [include/user.h]
	Implemented UserSeeUserDo.

	* [msdos/int21.c] [include/msdos.h]
	Added "GET LIST OF LISTS" (INT 21/52h).

Sat Mar 14 15:48:02 1998  Douglas Ridgway <ridgway@gmcl.com>

	* [include/windows.h] [relay32/gdi32.spec] [objects/enhmetafile.c]
	Beginnings of enhanced metafile support.

Fri Mar 13 20:53:09 1998  John Richardson <jrichard@zko.dec.com>

	* [win32/console.c]
	Restart interrupted console writes.

Fri Mar 13 18:59:24 1998  Matthew Becker <mbecker@glasscity.net>

	* [*/*.c]
	Updated documentation for API manpages.

	* [windows/dce.c]
	ReleaseDC16: Fixed cast.

	* [include/windows.h] [memory/virtual.c]
	VirtualQuery{Ex} should return DWORD instead of BOOL32.

Fri Mar 13 13:03:06 1998  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [README][documentation/status/]
	README updated, added lzexpand,version and multimedia
	status notes to new documentation/status directory.

	* [ole/*.c][if1632/typelib.spec]
	Added typelib stubs, several small additions and fixes.

	* [loader/pe_image.c]
	Fixed a small bug (fixup_imports got passed the wrong hModule in a
	remapcase).

	* [loader/signal.c][if1632/signal.c][misc/winsock_dns.c]
	  [loader/module.c]
	Fixed some recursive debugger crashes (caused by invalid FS).

	* [misc/registry.c]
	Two bugs fixed.

Fri Mar 13 04:55:01 1998  David Lee Lambert <lamber45@egr.msu.edu>

	* [include/winnt.h] [include/winnls.h]
	Moved LANG_xxx flags to winnls.h

	* [include/winnls.h]
	Added flags for GetDateFormat(); fixed validity of
	LOCALE_SYSTEM_DEFAULT.

	* [include/windows.h] 
	Added GetTimeFormat() prototypes.

	* [ole/ole2nls.c]
	Implemented ASCII date- and time-functions,  using an
	optimized common core;  added stubs for Unicode versions;  
	started work on a Unicode core.

	* [AUTHORS]
	Added my name.

Mon Mar  9 20:10:15 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [relay32/comctl32.spec] [include/imagelist.h]
	  [include/commctrl.h] [misc/imagelist.c] [misc/Makefile.in]
	First attempt at implementing ImageLists.

Sun Mar  8 20:19:49 1998  Uwe Bonnes  <bon@elektron.ikp.physik.tu-darmstadt.de>

	* [files/dos_fs.c] [configure.in]
	Try to get FileTimeToLocalFileTime,FileTimeToSystemTime and
	SystemTimeToFileTime right.
	Use timegm() where available.

	* [misc/lstr.c]
	Fix an off by one error in FormatMessage and handle the case 
	when args = NULL (used by programs to get the length of the 
	string).

	* [win32/console.c]
	Actual display a per-process Title string, better working
	attempt for WriteConsole32W and ReadConsole32W.

Fri Mar  6 20:33:45 1998  Slaven Rezic  <eserte@cs.tu-berlin.de>

	* [include/config.h.in][configure.in][multimedia/audio.c]
	  [multimedia/dsound.c]
	Added check for FreeBSD sound system.

Sun Mar  1 17:40:10 1998  Jason Schonberg <schon@mti.sgi.com>

	* [controls/edit.c] [include/ole.h] [include/shlobj.h]
	Removed final commas in enum types.

Mon Feb 23 07:52:18 1998  Luiz Otavio L. Zorzella  <zorzella@nr.conexware.com>

	* [multimedia/time.c]
	Workaround to avoid infinite recursion inside timeGetTime.

	* [multimedia/audio.c]
	WODM_GETNUMDEVS and WIDM_GETNUMDEVS only return 1 now if the
	SOUND_DEV can be opened, or if it's busy.
1998-03-15 20:29:56 +00:00

4019 lines
112 KiB
C

/*
* Menu functions
*
* Copyright 1993 Martin Ayotte
* Copyright 1994 Alexandre Julliard
* Copyright 1997 Morten Welinder
*/
/*
* 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.
*/
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "windows.h"
#include "bitmap.h"
#include "gdi.h"
#include "sysmetrics.h"
#include "task.h"
#include "win.h"
#include "heap.h"
#include "menu.h"
#include "module.h"
#include "neexe.h"
#include "nonclient.h"
#include "user.h"
#include "message.h"
#include "graphics.h"
#include "resource.h"
#include "tweak.h"
#include "debug.h"
UINT32 MENU_BarItemTopNudge;
UINT32 MENU_BarItemLeftNudge;
UINT32 MENU_ItemTopNudge;
UINT32 MENU_ItemLeftNudge;
UINT32 MENU_HighlightTopNudge;
UINT32 MENU_HighlightLeftNudge;
UINT32 MENU_HighlightBottomNudge;
UINT32 MENU_HighlightRightNudge;
/* internal popup menu window messages */
#define MM_SETMENUHANDLE (WM_USER + 0)
#define MM_GETMENUHANDLE (WM_USER + 1)
/* Menu item structure */
typedef struct {
/* ----------- MENUITEMINFO Stuff ----------- */
UINT32 fType; /* Item type. */
UINT32 fState; /* Item state. */
UINT32 wID; /* Item id. */
HMENU32 hSubMenu; /* Pop-up menu. */
HBITMAP32 hCheckBit; /* Bitmap when checked. */
HBITMAP32 hUnCheckBit; /* Bitmap when unchecked. */
LPSTR text; /* Item text or bitmap handle. */
DWORD dwItemData; /* Application defined. */
/* ----------- Wine stuff ----------- */
RECT32 rect; /* Item area (relative to menu window) */
UINT32 xTab; /* X position of text after Tab */
} MENUITEM;
/* Popup menu structure */
typedef struct {
WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
WORD wMagic; /* Magic number */
HQUEUE16 hTaskQ; /* Task queue for this menu */
WORD Width; /* Width of the whole menu */
WORD Height; /* Height of the whole menu */
WORD nItems; /* Number of items in the menu */
HWND32 hWnd; /* Window containing the menu */
MENUITEM *items; /* Array of menu items */
UINT32 FocusedItem; /* Currently focused item */
} POPUPMENU, *LPPOPUPMENU;
/* internal flags for menu tracking */
#define TF_ENDMENU 0x0001
#define TF_SUSPENDPOPUP 0x0002
#define TF_SKIPREMOVE 0x0004
typedef struct
{
UINT32 trackFlags;
HMENU32 hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
HMENU32 hTopMenu; /* initial menu */
HWND32 hOwnerWnd; /* where notifications are sent */
POINT32 pt;
} MTRACKER;
#define MENU_MAGIC 0x554d /* 'MU' */
#define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
#define ITEM_PREV -1
#define ITEM_NEXT 1
/* 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 */
/* popup menu shade thickness */
#define POPUP_XSHADE 4
#define POPUP_YSHADE 4
/* Space between 2 menu bar items */
#define MENU_BAR_ITEMS_SPACE 12
/* Minimum width of a tab character */
#define MENU_TAB_SPACE 8
/* Height of a separator item */
#define SEPARATOR_HEIGHT 5
/* (other menu->FocusedItem values give the position of the focused item) */
#define NO_SELECTED_ITEM 0xffff
#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)
#define IS_SYSTEM_MENU(menu) \
(!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
#define IS_SYSTEM_POPUP(menu) \
((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
#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)
/* Dimension of the menu bitmaps */
static WORD check_bitmap_width = 0, check_bitmap_height = 0;
static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
static HBITMAP32 hStdRadioCheck = 0;
static HBITMAP32 hStdCheck = 0;
static HBITMAP32 hStdMnArrow = 0;
static HBRUSH32 hShadeBrush = 0;
static HMENU32 MENU_DefSysPopup = 0; /* Default system menu popup */
/* Use global popup window because there's no way 2 menus can
* be tracked at the same time. */
static WND* pTopPopupWnd = 0;
static UINT32 uSubPWndLevel = 0;
/* Flag set by EndMenu() to force an exit from menu tracking */
static BOOL32 fEndMenu = FALSE;
/***********************************************************************
* debug_print_menuitem
*
* Print a menuitem in readable form.
*/
#define debug_print_menuitem(pre, mp, post) \
if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
#define MENUOUT(text) \
dsprintf(menu, "%s%s", (count++ ? "," : ""), (text))
#define MENUFLAG(bit,text) \
do { \
if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
} while (0)
static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
const char *postfix)
{
dbg_decl_str(menu, 256);
if (mp) {
UINT32 flags = mp->fType;
int typ = MENU_ITEM_TYPE(flags);
dsprintf(menu, "{ ID=0x%x", mp->wID);
if (flags & MF_POPUP)
dsprintf(menu, ", Sub=0x%x", mp->hSubMenu);
if (flags) {
int count = 0;
dsprintf(menu, ", Typ=");
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");
MENUFLAG(MFT_RIGHTJUSTIFY, "right");
if (flags)
dsprintf(menu, "+0x%x", flags);
}
flags = mp->fState;
if (flags) {
int count = 0;
dsprintf(menu, ", State=");
MENUFLAG(MFS_GRAYED, "grey");
MENUFLAG(MFS_DISABLED, "dis");
MENUFLAG(MFS_CHECKED, "check");
MENUFLAG(MFS_HILITE, "hi");
MENUFLAG(MF_USECHECKBITMAPS, "usebit");
MENUFLAG(MF_MOUSESELECT, "mouse");
if (flags)
dsprintf(menu, "+0x%x", flags);
}
if (mp->hCheckBit)
dsprintf(menu, ", Chk=0x%x", mp->hCheckBit);
if (mp->hUnCheckBit)
dsprintf(menu, ", Unc=0x%x", mp->hUnCheckBit);
if (typ == MFT_STRING) {
if (mp->text)
dsprintf(menu, ", Text=\"%s\"", mp->text);
else
dsprintf(menu, ", Text=Null");
} else if (mp->text == NULL)
/* Nothing */ ;
else
dsprintf(menu, ", Text=%p", mp->text);
dsprintf(menu, " }");
} else {
dsprintf(menu, "NULL");
}
TRACE(menu, "%s %s %s\n", prefix, dbg_str(menu), postfix);
}
#undef MENUOUT
#undef MENUFLAG
/***********************************************************************
* MENU_CopySysPopup
*
* Return the default system menu.
*/
static HMENU32 MENU_CopySysPopup(void)
{
HMENU32 hMenu = LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU));
if( hMenu ) {
POPUPMENU* menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu);
menu->wFlags |= MF_SYSMENU | MF_POPUP;
}
else {
hMenu = 0;
ERR(menu, "Unable to load default system menu\n" );
}
TRACE(menu, "returning %x.\n", hMenu );
return hMenu;
}
/**********************************************************************
* MENU_GetSysMenu
*
* Create a copy of the system menu. System menu in Windows is
* a special menu-bar with the single entry - system menu popup.
* This popup is presented to the outside world as a "system menu".
* However, the real system menu handle is sometimes seen in the
* WM_MENUSELECT paramemters (and Word 6 likes it this way).
*/
HMENU32 MENU_GetSysMenu( HWND32 hWnd, HMENU32 hPopupMenu )
{
HMENU32 hMenu;
if ((hMenu = CreateMenu32()))
{
POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
menu->wFlags = MF_SYSMENU;
menu->hWnd = hWnd;
if (hPopupMenu == (HMENU32)(-1))
hPopupMenu = MENU_CopySysPopup();
else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup;
if (hPopupMenu)
{
InsertMenu32A( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION, hPopupMenu, NULL );
menu->items[0].fType = MF_SYSMENU | MF_POPUP;
menu->items[0].fState = 0;
menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hPopupMenu);
menu->wFlags |= MF_SYSMENU;
TRACE(menu,"GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu );
return hMenu;
}
DestroyMenu32( hMenu );
}
ERR(menu, "failed to load system menu!\n");
return 0;
}
/***********************************************************************
* MENU_Init
*
* Menus initialisation.
*/
BOOL32 MENU_Init()
{
HBITMAP32 hBitmap;
static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
0x55, 0, 0xAA, 0,
0x55, 0, 0xAA, 0,
0x55, 0, 0xAA, 0 };
/* Load menu bitmaps */
hStdCheck = LoadBitmap32A(0, (LPSTR)MAKEINTRESOURCE(OBM_CHECK));
hStdRadioCheck = LoadBitmap32A(0, (LPSTR)MAKEINTRESOURCE(OBM_RADIOCHECK));
hStdMnArrow = LoadBitmap32A(0, (LPSTR)MAKEINTRESOURCE(OBM_MNARROW));
if (hStdCheck)
{
BITMAP32 bm;
GetObject32A( hStdCheck, sizeof(bm), &bm );
check_bitmap_width = bm.bmWidth;
check_bitmap_height = bm.bmHeight;
} else
return FALSE;
/* Assume that radio checks have the same size as regular check. */
if (!hStdRadioCheck)
return FALSE;
if (hStdMnArrow)
{
BITMAP32 bm;
GetObject32A( hStdMnArrow, sizeof(bm), &bm );
arrow_bitmap_width = bm.bmWidth;
arrow_bitmap_height = bm.bmHeight;
} else
return FALSE;
if ((hBitmap = CreateBitmap32( 8, 8, 1, 1, shade_bits)))
{
if((hShadeBrush = CreatePatternBrush32( hBitmap )))
{
DeleteObject32( hBitmap );
if ((MENU_DefSysPopup = MENU_CopySysPopup()))
return TRUE;
}
}
return FALSE;
}
/***********************************************************************
* MENU_InitSysMenuPopup
*
* Grey the appropriate items in System menu.
*/
static void MENU_InitSysMenuPopup( HMENU32 hmenu, DWORD style, DWORD clsStyle )
{
BOOL32 gray;
gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
EnableMenuItem32( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
gray = ((style & WS_MAXIMIZE) != 0);
EnableMenuItem32( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
EnableMenuItem32( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
EnableMenuItem32( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
EnableMenuItem32( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
gray = (clsStyle & CS_NOCLOSE) != 0;
EnableMenuItem32( hmenu, SC_CLOSE, (gray ? MF_GRAYED : MF_ENABLED) );
}
/******************************************************************************
*
* UINT32 MENU_GetStartOfNextColumn(
* HMENU32 hMenu )
*
*****************************************************************************/
static UINT32 MENU_GetStartOfNextColumn(
HMENU32 hMenu )
{
POPUPMENU *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
UINT32 i = menu->FocusedItem + 1;
if(!menu)
return NO_SELECTED_ITEM;
if( i == NO_SELECTED_ITEM )
return i;
for( ; i < menu->nItems; ++i ) {
if (menu->items[i].fType & MF_MENUBARBREAK)
return i;
}
return NO_SELECTED_ITEM;
}
/******************************************************************************
*
* UINT32 MENU_GetStartOfPrevColumn(
* HMENU32 hMenu )
*
*****************************************************************************/
static UINT32 MENU_GetStartOfPrevColumn(
HMENU32 hMenu )
{
POPUPMENU const *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu);
UINT32 i;
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 &&
!(menu->items[i].fType & MF_MENUBARBREAK);
--i); /* empty */
if(i == 0)
return NO_SELECTED_ITEM;
for(--i; i != 0; --i) {
if (menu->items[i].fType & MF_MENUBARBREAK)
break;
}
TRACE(menu, "ret %d.\n", i );
return i;
}
/***********************************************************************
* MENU_FindItem
*
* Find a menu item. Return a pointer on the item, and modifies *hmenu
* in case the item was in a sub-menu.
*/
static MENUITEM *MENU_FindItem( HMENU32 *hmenu, UINT32 *nPos, UINT32 wFlags )
{
POPUPMENU *menu;
UINT32 i;
if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(*hmenu))) return NULL;
if (wFlags & MF_BYPOSITION)
{
if (*nPos >= menu->nItems) return NULL;
return &menu->items[*nPos];
}
else
{
MENUITEM *item = menu->items;
for (i = 0; i < menu->nItems; i++, item++)
{
if (item->wID == *nPos)
{
*nPos = i;
return item;
}
else if (item->fType & MF_POPUP)
{
HMENU32 hsubmenu = item->hSubMenu;
MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
if (subitem)
{
*hmenu = hsubmenu;
return subitem;
}
}
}
}
return NULL;
}
/***********************************************************************
* MENU_FreeItemData
*/
static void MENU_FreeItemData( MENUITEM* item )
{
/* delete text */
if (IS_STRING_ITEM(item->fType) && item->text)
HeapFree( SystemHeap, 0, item->text );
}
/***********************************************************************
* MENU_FindItemByCoords
*
* 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.
*/
static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu,
POINT32 pt, UINT32 *pos )
{
MENUITEM *item;
WND *wndPtr;
UINT32 i;
if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return NULL;
pt.x -= wndPtr->rectWindow.left;
pt.y -= wndPtr->rectWindow.top;
item = menu->items;
for (i = 0; i < menu->nItems; i++, item++)
{
if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
(pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
{
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.
*/
static UINT32 MENU_FindItemByKey( HWND32 hwndOwner, HMENU32 hmenu,
UINT32 key, BOOL32 forceMenuChar )
{
TRACE(menu,"\tlooking for '%c' in [%04x]\n", (char)key, (UINT16)hmenu );
if (!IsMenu32( hmenu ))
{
WND* w = WIN_FindWndPtr(hwndOwner);
hmenu = GetSubMenu32(w->hSysMenu, 0);
}
if (hmenu)
{
POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
MENUITEM *item = menu->items;
LONG menuchar;
if( !forceMenuChar )
{
UINT32 i;
key = toupper(key);
for (i = 0; i < menu->nItems; i++, item++)
{
if (item->text && (IS_STRING_ITEM(item->fType)))
{
char *p = strchr( item->text, '&' );
if (p && (p[1] != '&') && (toupper(p[1]) == key)) return i;
}
}
}
menuchar = SendMessage32A( hwndOwner, WM_MENUCHAR,
MAKEWPARAM( key, menu->wFlags ), hmenu );
if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
if (HIWORD(menuchar) == 1) return (UINT32)(-2);
}
return (UINT32)(-1);
}
/***********************************************************************
* MENU_CalcItemSize
*
* Calculate the size of the menu item and store it in lpitem->rect.
*/
static void MENU_CalcItemSize( HDC32 hdc, MENUITEM *lpitem, HWND32 hwndOwner,
INT32 orgX, INT32 orgY, BOOL32 menuBar )
{
DWORD dwSize;
char *p;
TRACE(menu, "HDC 0x%x at (%d,%d)\n",
hdc, orgX, orgY);
debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem,
(menuBar ? " (MenuBar)" : ""));
SetRect32( &lpitem->rect, orgX, orgY, orgX, orgY );
if (lpitem->fType & MF_OWNERDRAW)
{
MEASUREITEMSTRUCT32 mis;
mis.CtlType = ODT_MENU;
mis.itemID = lpitem->wID;
mis.itemData = (DWORD)lpitem->text;
mis.itemHeight = 16;
mis.itemWidth = 30;
SendMessage32A( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
lpitem->rect.bottom += mis.itemHeight;
lpitem->rect.right += mis.itemWidth;
TRACE(menu, "%08x %dx%d\n",
lpitem->wID, mis.itemWidth, mis.itemHeight);
return;
}
if (lpitem->fType & MF_SEPARATOR)
{
lpitem->rect.bottom += SEPARATOR_HEIGHT;
return;
}
if (!menuBar)
{
lpitem->rect.right += 2 * check_bitmap_width;
if (lpitem->fType & MF_POPUP)
lpitem->rect.right += arrow_bitmap_width;
}
if (lpitem->fType & MF_BITMAP)
{
BITMAP32 bm;
if (GetObject32A( (HBITMAP32)lpitem->text, sizeof(bm), &bm ))
{
lpitem->rect.right += bm.bmWidth;
lpitem->rect.bottom += bm.bmHeight;
}
return;
}
/* If we get here, then it must be a text item */
if (IS_STRING_ITEM( lpitem->fType ))
{
dwSize = GetTextExtent( hdc, lpitem->text, strlen(lpitem->text) );
lpitem->rect.right += LOWORD(dwSize);
lpitem->rect.bottom += MAX( HIWORD(dwSize), SYSMETRICS_CYMENU );
lpitem->xTab = 0;
if (menuBar) lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
else if ((p = strchr( lpitem->text, '\t' )) != NULL)
{
/* Item contains a tab (only meaningful in popup menus) */
lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE +
LOWORD( GetTextExtent( hdc, lpitem->text,
(int)(p - lpitem->text) ));
lpitem->rect.right += MENU_TAB_SPACE;
}
else
{
if (strchr( lpitem->text, '\b' ))
lpitem->rect.right += MENU_TAB_SPACE;
lpitem->xTab = lpitem->rect.right - check_bitmap_width
- arrow_bitmap_width;
}
}
}
/***********************************************************************
* MENU_PopupMenuCalcSize
*
* Calculate the size of a popup menu.
*/
static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND32 hwndOwner )
{
MENUITEM *lpitem;
HDC32 hdc;
int start, i;
int orgX, orgY, maxX, maxTab, maxTabWidth;
lppop->Width = lppop->Height = 0;
if (lppop->nItems == 0) return;
hdc = GetDC32( 0 );
start = 0;
maxX = SYSMETRICS_CXBORDER;
while (start < lppop->nItems)
{
lpitem = &lppop->items[start];
orgX = maxX;
orgY = SYSMETRICS_CYBORDER;
maxTab = maxTabWidth = 0;
/* Parse items until column break or end of menu */
for (i = start; i < lppop->nItems; i++, lpitem++)
{
if ((i != start) &&
(lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
if(TWEAK_Win95Look)
++orgY;
MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
if (lpitem->fType & MF_MENUBARBREAK) orgX++;
maxX = MAX( maxX, lpitem->rect.right );
orgY = lpitem->rect.bottom;
if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
{
maxTab = MAX( maxTab, lpitem->xTab );
maxTabWidth = MAX(maxTabWidth,lpitem->rect.right-lpitem->xTab);
}
}
/* Finish the column (set all items to the largest width found) */
maxX = MAX( maxX, maxTab + maxTabWidth );
for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
{
lpitem->rect.right = maxX;
if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
lpitem->xTab = maxTab;
}
lppop->Height = MAX( lppop->Height, orgY );
}
lppop->Width = maxX;
ReleaseDC32( 0, hdc );
}
/***********************************************************************
* MENU_MenuBarCalcSize
*
* FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
* height is off by 1 pixel which causes lengthy window relocations when
* active document window is maximized/restored.
*
* Calculate the size of the menu bar.
*/
static void MENU_MenuBarCalcSize( HDC32 hdc, LPRECT32 lprect,
LPPOPUPMENU lppop, HWND32 hwndOwner )
{
MENUITEM *lpitem;
int start, i, orgX, orgY, maxY, helpPos;
if ((lprect == NULL) || (lppop == NULL)) return;
if (lppop->nItems == 0) return;
TRACE(menu,"MENU_MenuBarCalcSize left=%d top=%d right=%d bottom=%d\n",
lprect->left, lprect->top, lprect->right, lprect->bottom);
lppop->Width = lprect->right - lprect->left;
lppop->Height = 0;
maxY = lprect->top;
start = 0;
helpPos = -1;
while (start < lppop->nItems)
{
lpitem = &lppop->items[start];
orgX = lprect->left;
orgY = maxY;
/* Parse items until line break or end of menu */
for (i = start; i < lppop->nItems; i++, lpitem++)
{
if ((helpPos == -1) && (lpitem->fType & MF_HELP)) helpPos = i;
if ((i != start) &&
(lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
TRACE(menu, "calling MENU_CalcItemSize org=(%d, %d)\n",
orgX, orgY );
debug_print_menuitem (" item: ", lpitem, "");
MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
if (lpitem->rect.right > lprect->right)
{
if (i != start) break;
else lpitem->rect.right = lprect->right;
}
maxY = MAX( maxY, lpitem->rect.bottom );
orgX = lpitem->rect.right;
}
/* Finish the line (set all items to the largest height found) */
while (start < i) lppop->items[start++].rect.bottom = maxY;
}
lprect->bottom = maxY;
lppop->Height = lprect->bottom - lprect->top;
/* Flush right all items between the MF_HELP and the last item */
/* (if several lines, only move the last line) */
if (helpPos != -1)
{
lpitem = &lppop->items[lppop->nItems-1];
orgY = lpitem->rect.top;
orgX = lprect->right;
for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--)
{
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;
}
}
}
/***********************************************************************
* MENU_DrawMenuItem
*
* Draw a single menu item.
*/
static void MENU_DrawMenuItem( HWND32 hwnd, HDC32 hdc, MENUITEM *lpitem,
UINT32 height, BOOL32 menuBar )
{
RECT32 rect;
debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
if (lpitem->fType & MF_SYSMENU)
{
if( !IsIconic32(hwnd) ) {
if(TWEAK_Win95Look)
NC_DrawSysButton95( hwnd, hdc,
lpitem->fState &
(MF_HILITE | MF_MOUSESELECT) );
else
NC_DrawSysButton( hwnd, hdc,
lpitem->fState &
(MF_HILITE | MF_MOUSESELECT) );
}
return;
}
if (lpitem->fType & MF_OWNERDRAW)
{
DRAWITEMSTRUCT32 dis;
TRACE(menu, "Ownerdraw!\n" );
dis.CtlType = ODT_MENU;
dis.itemID = lpitem->wID;
dis.itemData = (DWORD)lpitem->text;
dis.itemState = 0;
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;
dis.itemAction = ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS;
dis.hwndItem = hwnd;
dis.hDC = hdc;
dis.rcItem = lpitem->rect;
SendMessage32A( hwnd, WM_DRAWITEM, 0, (LPARAM)&dis );
return;
}
if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
rect = lpitem->rect;
/* Draw the background */
if(TWEAK_Win95Look) {
rect.left += 2;
rect.right -= 2;
/*
if(menuBar) {
--rect.left;
++rect.bottom;
--rect.top;
}
InflateRect32( &rect, -1, -1 );
*/
}
if (lpitem->fState & MF_HILITE) {
RECT32 r = rect;
r.top += MENU_HighlightTopNudge;
r.bottom += MENU_HighlightBottomNudge;
r.left += MENU_HighlightLeftNudge;
r.right += MENU_HighlightRightNudge;
FillRect32( hdc, &r, GetSysColorBrush32(COLOR_HIGHLIGHT) );
}
else {
RECT32 r = rect;
r.top += MENU_HighlightTopNudge;
r.bottom += MENU_HighlightBottomNudge;
r.left += MENU_HighlightLeftNudge;
r.right += MENU_HighlightRightNudge;
FillRect32( hdc, &r, GetSysColorBrush32(COLOR_MENU) );
}
SetBkMode32( hdc, TRANSPARENT );
/* Draw the separator bar (if any) */
if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
{
if(TWEAK_Win95Look)
TWEAK_DrawMenuSeparatorVert95(hdc, rect.left - 1, 3, height - 3);
else {
SelectObject32( hdc, GetSysColorPen32(COLOR_WINDOWFRAME) );
MoveTo( hdc, rect.left, 0 );
LineTo32( hdc, rect.left, height );
}
}
if (lpitem->fType & MF_SEPARATOR)
{
if(TWEAK_Win95Look)
TWEAK_DrawMenuSeparatorHoriz95(hdc, rect.left + 1,
rect.top + SEPARATOR_HEIGHT / 2 + 1,
rect.right - 1);
else {
SelectObject32( hdc, GetSysColorPen32(COLOR_WINDOWFRAME) );
MoveTo( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2 );
LineTo32( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
}
return;
}
/* Setup colors */
if (lpitem->fState & MF_HILITE)
{
if (lpitem->fState & MF_GRAYED)
SetTextColor32( hdc, GetSysColor32( COLOR_GRAYTEXT ) );
else
SetTextColor32( hdc, GetSysColor32( COLOR_HIGHLIGHTTEXT ) );
SetBkColor32( hdc, GetSysColor32( COLOR_HIGHLIGHT ) );
}
else
{
if (lpitem->fState & MF_GRAYED)
SetTextColor32( hdc, GetSysColor32( COLOR_GRAYTEXT ) );
else
SetTextColor32( hdc, GetSysColor32( COLOR_MENUTEXT ) );
SetBkColor32( hdc, GetSysColor32( COLOR_MENU ) );
}
if (!menuBar)
{
INT32 y = rect.top + rect.bottom;
/* Draw the check mark
*
* Custom checkmark bitmaps are monochrome but not always 1bpp.
* In this case we want GRAPH_DrawBitmap() to copy a plane which
* is 1 for a white pixel and 0 for a black one.
*/
if (lpitem->fState & MF_CHECKED)
{
HBITMAP32 bm =
lpitem->hCheckBit ? lpitem->hCheckBit :
((lpitem->fType & MFT_RADIOCHECK)
? hStdRadioCheck : hStdCheck);
GRAPH_DrawBitmap( hdc, bm, rect.left,
(y - check_bitmap_height) / 2,
0, 0, check_bitmap_width,
check_bitmap_height, TRUE );
} else if (lpitem->hUnCheckBit)
GRAPH_DrawBitmap( hdc, lpitem->hUnCheckBit, rect.left,
(y - check_bitmap_height) / 2, 0, 0,
check_bitmap_width, check_bitmap_height, TRUE );
/* Draw the popup-menu arrow */
if (lpitem->fType & MF_POPUP)
{
GRAPH_DrawBitmap( hdc, hStdMnArrow,
rect.right-arrow_bitmap_width-1,
(y - arrow_bitmap_height) / 2, 0, 0,
arrow_bitmap_width, arrow_bitmap_height, FALSE );
}
rect.left += check_bitmap_width;
rect.right -= arrow_bitmap_width;
}
/* Draw the item text or bitmap */
if (lpitem->fType & MF_BITMAP)
{
GRAPH_DrawBitmap( hdc, (HBITMAP32)lpitem->text,
rect.left, rect.top, 0, 0,
rect.right-rect.left, rect.bottom-rect.top, FALSE );
return;
}
/* No bitmap - process text if present */
else if (IS_STRING_ITEM(lpitem->fType))
{
register int i;
if (menuBar)
{
rect.left += MENU_BAR_ITEMS_SPACE / 2;
rect.right -= MENU_BAR_ITEMS_SPACE / 2;
i = strlen( lpitem->text );
rect.top += MENU_BarItemTopNudge;
rect.left += MENU_BarItemLeftNudge;
}
else
{
for (i = 0; lpitem->text[i]; i++)
if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
break;
rect.top += MENU_ItemTopNudge;
rect.left += MENU_ItemLeftNudge;
}
if(!TWEAK_Win95Look || !(lpitem->fState & MF_GRAYED)) {
DrawText32A( hdc, lpitem->text, i, &rect,
DT_LEFT | DT_VCENTER | DT_SINGLELINE );
}
else {
if (!(lpitem->fState & MF_HILITE))
{
++rect.left;
++rect.top;
++rect.right;
++rect.bottom;
SetTextColor32(hdc, RGB(0xff, 0xff, 0xff));
DrawText32A( hdc, lpitem->text, i, &rect,
DT_LEFT | DT_VCENTER | DT_SINGLELINE );
--rect.left;
--rect.top;
--rect.right;
--rect.bottom;
}
SetTextColor32(hdc, RGB(0x80, 0x80, 0x80));
DrawText32A( hdc, lpitem->text, i, &rect,
DT_LEFT | DT_VCENTER | DT_SINGLELINE );
}
if (lpitem->text[i]) /* There's a tab or flush-right char */
{
if (lpitem->text[i] == '\t')
{
rect.left = lpitem->xTab;
DrawText32A( hdc, lpitem->text + i + 1, -1, &rect,
DT_LEFT | DT_VCENTER | DT_SINGLELINE );
}
else DrawText32A( hdc, lpitem->text + i + 1, -1, &rect,
DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
}
}
}
/***********************************************************************
* MENU_DrawPopupMenu
*
* Paint a popup menu.
*/
static void MENU_DrawPopupMenu( HWND32 hwnd, HDC32 hdc, HMENU32 hmenu )
{
HBRUSH32 hPrevBrush = 0;
RECT32 rect;
GetClientRect32( hwnd, &rect );
/* if(!TWEAK_Win95Look) { */
rect.bottom -= POPUP_YSHADE * SYSMETRICS_CYBORDER;
rect.right -= POPUP_XSHADE * SYSMETRICS_CXBORDER;
/* } */
if((hPrevBrush = SelectObject32( hdc, GetSysColorBrush32(COLOR_MENU) )))
{
HPEN32 hPrevPen;
Rectangle32( hdc, rect.left, rect.top, rect.right, rect.bottom );
hPrevPen = SelectObject32( hdc, GetStockObject32( NULL_PEN ) );
if( hPrevPen )
{
INT32 ropPrev, i;
POPUPMENU *menu;
/* draw 3-d shade */
if(!TWEAK_Win95Look) {
SelectObject32( hdc, hShadeBrush );
SetBkMode32( hdc, TRANSPARENT );
ropPrev = SetROP232( hdc, R2_MASKPEN );
i = rect.right; /* why SetBrushOrg() doesn't? */
PatBlt32( hdc, i & 0xfffffffe,
rect.top + POPUP_YSHADE*SYSMETRICS_CYBORDER,
i%2 + POPUP_XSHADE*SYSMETRICS_CXBORDER,
rect.bottom - rect.top, 0x00a000c9 );
i = rect.bottom;
PatBlt32( hdc, rect.left + POPUP_XSHADE*SYSMETRICS_CXBORDER,
i & 0xfffffffe,rect.right - rect.left,
i%2 + POPUP_YSHADE*SYSMETRICS_CYBORDER, 0x00a000c9 );
SelectObject32( hdc, hPrevPen );
SelectObject32( hdc, hPrevBrush );
SetROP232( hdc, ropPrev );
}
else
TWEAK_DrawReliefRect95(hdc, &rect);
/* draw menu items */
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
if (menu && menu->nItems)
{
MENUITEM *item;
UINT32 u;
for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
MENU_DrawMenuItem( hwnd, hdc, item, menu->Height, FALSE );
}
} else SelectObject32( hdc, hPrevBrush );
}
}
/***********************************************************************
* MENU_DrawMenuBar
*
* Paint a menu bar. Returns the height of the menu bar.
*/
UINT32 MENU_DrawMenuBar( HDC32 hDC, LPRECT32 lprect, HWND32 hwnd,
BOOL32 suppress_draw)
{
LPPOPUPMENU lppop;
UINT32 i;
WND *wndPtr = WIN_FindWndPtr( hwnd );
lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( (HMENU16)wndPtr->wIDmenu );
if (lppop == NULL || lprect == NULL) return SYSMETRICS_CYMENU;
TRACE(menu,"(%04x, %p, %p); !\n",
hDC, lprect, lppop);
if (lppop->Height == 0) MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
lprect->bottom = lprect->top + lppop->Height;
if (suppress_draw) return lppop->Height;
if(TWEAK_Win95Look)
++lprect->bottom;
FillRect32(hDC, lprect, GetSysColorBrush32(COLOR_MENU) );
if(!TWEAK_Win95Look) {
SelectObject32( hDC, GetSysColorPen32(COLOR_WINDOWFRAME) );
MoveTo( hDC, lprect->left, lprect->bottom );
LineTo32( hDC, lprect->right, lprect->bottom );
}
if (lppop->nItems == 0) return SYSMETRICS_CYMENU;
for (i = 0; i < lppop->nItems; i++)
{
MENU_DrawMenuItem( hwnd, hDC, &lppop->items[i], lppop->Height, TRUE );
}
return lppop->Height;
}
/***********************************************************************
* MENU_PatchResidentPopup
*/
BOOL32 MENU_PatchResidentPopup( HQUEUE16 checkQueue, WND* checkWnd )
{
if( pTopPopupWnd )
{
HTASK16 hTask = 0;
TRACE(menu,"patching resident popup: %04x %04x [%04x %04x]\n",
checkQueue, checkWnd ? checkWnd->hwndSelf : 0, pTopPopupWnd->hmemTaskQ,
pTopPopupWnd->owner ? pTopPopupWnd->owner->hwndSelf : 0);
switch( checkQueue )
{
case 0: /* checkWnd is the new popup owner */
if( checkWnd )
{
pTopPopupWnd->owner = checkWnd;
if( pTopPopupWnd->hmemTaskQ != checkWnd->hmemTaskQ )
hTask = QUEUE_GetQueueTask( checkWnd->hmemTaskQ );
}
break;
case 0xFFFF: /* checkWnd is destroyed */
if( pTopPopupWnd->owner == checkWnd )
pTopPopupWnd->owner = NULL;
return TRUE;
default: /* checkQueue is exiting */
if( pTopPopupWnd->hmemTaskQ == checkQueue )
{
hTask = QUEUE_GetQueueTask( pTopPopupWnd->hmemTaskQ );
hTask = TASK_GetNextTask( hTask );
}
break;
}
if( hTask )
{
TDB* task = (TDB*)GlobalLock16( hTask );
if( task )
{
pTopPopupWnd->hInstance = task->hInstance;
pTopPopupWnd->hmemTaskQ = task->hQueue;
return TRUE;
}
else WARN(menu,"failed to patch resident popup.\n");
}
}
return FALSE;
}
/***********************************************************************
* MENU_ShowPopup
*
* Display a popup menu.
*/
static BOOL32 MENU_ShowPopup( HWND32 hwndOwner, HMENU32 hmenu, UINT32 id,
INT32 x, INT32 y, INT32 xanchor, INT32 yanchor )
{
POPUPMENU *menu;
WND *wndOwner = NULL;
if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
if (menu->FocusedItem != NO_SELECTED_ITEM)
{
menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
menu->FocusedItem = NO_SELECTED_ITEM;
}
if( (wndOwner = WIN_FindWndPtr( hwndOwner )) )
{
UINT32 width, height;
MENU_PopupMenuCalcSize( menu, hwndOwner );
/* adjust popup menu pos so that it fits within the desktop */
width = menu->Width + SYSMETRICS_CXBORDER;
height = menu->Height + SYSMETRICS_CYBORDER;
if( x + width > SYSMETRICS_CXSCREEN )
{
if( xanchor )
x -= width - xanchor;
if( x + width > SYSMETRICS_CXSCREEN)
x = SYSMETRICS_CXSCREEN - width;
}
if( x < 0 ) x = 0;
if( y + height > SYSMETRICS_CYSCREEN )
{
if( yanchor )
y -= height + yanchor;
if( y + height > SYSMETRICS_CYSCREEN )
y = SYSMETRICS_CYSCREEN - height;
}
if( y < 0 ) y = 0;
width += POPUP_XSHADE * SYSMETRICS_CXBORDER; /* add space for shading */
height += POPUP_YSHADE * SYSMETRICS_CYBORDER;
/* NOTE: In Windows, top menu popup is not owned. */
if (!pTopPopupWnd) /* create top level popup menu window */
{
assert( uSubPWndLevel == 0 );
pTopPopupWnd = WIN_FindWndPtr(CreateWindow32A( POPUPMENU_CLASS_ATOM, NULL,
WS_POPUP, x, y, width, height,
hwndOwner, 0, wndOwner->hInstance,
(LPVOID)hmenu ));
if (!pTopPopupWnd) return FALSE;
menu->hWnd = pTopPopupWnd->hwndSelf;
}
else
if( uSubPWndLevel )
{
/* create a new window for the submenu */
menu->hWnd = CreateWindow32A( POPUPMENU_CLASS_ATOM, NULL,
WS_POPUP, x, y, width, height,
menu->hWnd, 0, wndOwner->hInstance,
(LPVOID)hmenu );
if( !menu->hWnd ) return FALSE;
}
else /* top level popup menu window already exists */
{
menu->hWnd = pTopPopupWnd->hwndSelf;
MENU_PatchResidentPopup( 0, wndOwner );
SendMessage16( pTopPopupWnd->hwndSelf, MM_SETMENUHANDLE, (WPARAM16)hmenu, 0L);
/* adjust its size */
SetWindowPos32( menu->hWnd, 0, x, y, width, height,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
}
uSubPWndLevel++; /* menu level counter */
/* Display the window */
SetWindowPos32( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
UpdateWindow32( menu->hWnd );
return TRUE;
}
return FALSE;
}
/***********************************************************************
* MENU_SelectItem
*/
static void MENU_SelectItem( HWND32 hwndOwner, HMENU32 hmenu, UINT32 wIndex,
BOOL32 sendMenuSelect )
{
LPPOPUPMENU lppop;
HDC32 hdc;
lppop = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
if (!lppop->nItems) return;
if ((wIndex != NO_SELECTED_ITEM) &&
(lppop->items[wIndex].fType & MF_SEPARATOR))
wIndex = NO_SELECTED_ITEM;
if (lppop->FocusedItem == wIndex) return;
if (lppop->wFlags & MF_POPUP) hdc = GetDC32( lppop->hWnd );
else hdc = GetDCEx32( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
/* Clear previous highlighted item */
if (lppop->FocusedItem != NO_SELECTED_ITEM)
{
lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
MENU_DrawMenuItem(lppop->hWnd,hdc,&lppop->items[lppop->FocusedItem],
lppop->Height, !(lppop->wFlags & MF_POPUP) );
}
/* Highlight new item (if any) */
lppop->FocusedItem = wIndex;
if (lppop->FocusedItem != NO_SELECTED_ITEM)
{
lppop->items[lppop->FocusedItem].fState |= MF_HILITE;
MENU_DrawMenuItem( lppop->hWnd, hdc, &lppop->items[lppop->FocusedItem],
lppop->Height, !(lppop->wFlags & MF_POPUP) );
if (sendMenuSelect)
{
MENUITEM *ip = &lppop->items[lppop->FocusedItem];
SendMessage16( hwndOwner, WM_MENUSELECT, ip->wID,
MAKELONG(ip->fType | (ip->fState | MF_MOUSESELECT),
hmenu) );
}
}
else if (sendMenuSelect)
SendMessage16( hwndOwner, WM_MENUSELECT, hmenu,
MAKELONG( lppop->wFlags | MF_MOUSESELECT, hmenu ) );
ReleaseDC32( lppop->hWnd, hdc );
}
/***********************************************************************
* MENU_MoveSelection
*
* 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.
*/
static void MENU_MoveSelection( HWND32 hwndOwner, HMENU32 hmenu, INT32 offset )
{
INT32 i;
POPUPMENU *menu;
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
if (!menu->items) return;
if ( menu->FocusedItem != NO_SELECTED_ITEM )
{
if( menu->nItems == 1 ) return; else
for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
; i += offset)
if (!(menu->items[i].fType & MF_SEPARATOR))
{
MENU_SelectItem( hwndOwner, hmenu, i, TRUE );
return;
}
}
for ( i = (offset > 0) ? 0 : menu->nItems - 1;
i >= 0 && i < menu->nItems ; i += offset)
if (!(menu->items[i].fType & MF_SEPARATOR))
{
MENU_SelectItem( hwndOwner, hmenu, i, TRUE );
return;
}
}
/**********************************************************************
* MENU_SetItemData
*
* Set an item flags, id and text ptr. Called by InsertMenu() and
* ModifyMenu().
*/
static BOOL32 MENU_SetItemData( MENUITEM *item, UINT32 flags, UINT32 id,
LPCSTR str )
{
LPSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
debug_print_menuitem("MENU_SetItemData from: ", item, "");
if (IS_STRING_ITEM(flags))
{
if (!str || !*str)
{
flags |= MF_SEPARATOR;
item->text = NULL;
}
else
{
LPSTR text;
/* Item beginning with a backspace is a help item */
if (*str == '\b')
{
flags |= MF_HELP;
str++;
}
if (!(text = HEAP_strdupA( SystemHeap, 0, str ))) return FALSE;
item->text = text;
}
}
else if (flags & MF_BITMAP) item->text = (LPSTR)(HBITMAP32)LOWORD(str);
else if (flags & MF_OWNERDRAW) item->text = (LPSTR)str;
else item->text = NULL;
if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) )
DestroyMenu32( item->hSubMenu ); /* ModifyMenu() spec */
if (flags & MF_POPUP)
{
POPUPMENU *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR((UINT16)id);
if (IS_A_MENU(menu)) menu->wFlags |= MF_POPUP;
else
{
item->wID = 0;
item->hSubMenu = 0;
item->fType = 0;
item->fState = 0;
return FALSE;
}
}
item->wID = id;
if (flags & MF_POPUP)
item->hSubMenu = id;
if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
flags |= MF_POPUP; /* keep popup */
item->fType = flags & TYPE_MASK;
item->fState = (flags & STATE_MASK) &
~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
SetRectEmpty32( &item->rect );
if (prevText) HeapFree( SystemHeap, 0, prevText );
debug_print_menuitem("MENU_SetItemData to : ", item, "");
return TRUE;
}
/**********************************************************************
* MENU_InsertItem
*
* Insert a new item into a menu.
*/
static MENUITEM *MENU_InsertItem( HMENU32 hMenu, UINT32 pos, UINT32 flags )
{
MENUITEM *newItems;
POPUPMENU *menu;
if (!(menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu)))
{
WARN(menu, "%04x not a menu handle\n",
hMenu );
return NULL;
}
/* Find where to insert new item */
if ((flags & MF_BYPOSITION) &&
((pos == (UINT32)-1) || (pos == menu->nItems)))
{
/* Special case: append to menu */
/* Some programs specify the menu length to do that */
pos = menu->nItems;
}
else
{
if (!MENU_FindItem( &hMenu, &pos, flags ))
{
WARN(menu, "item %x not found\n",
pos );
return NULL;
}
if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu)))
{
WARN(menu,"%04x not a menu handle\n",
hMenu);
return NULL;
}
}
/* Create new items array */
newItems = HeapAlloc( SystemHeap, 0, sizeof(MENUITEM) * (menu->nItems+1) );
if (!newItems)
{
WARN(menu, "allocation failed\n" );
return NULL;
}
if (menu->nItems > 0)
{
/* Copy the old array into the new */
if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
(menu->nItems-pos)*sizeof(MENUITEM) );
HeapFree( SystemHeap, 0, menu->items );
}
menu->items = newItems;
menu->nItems++;
memset( &newItems[pos], 0, sizeof(*newItems) );
return &newItems[pos];
}
/**********************************************************************
* MENU_ParseResource
*
* Parse a standard menu resource and add items to the menu.
* Return a pointer to the end of the resource.
*/
static LPCSTR MENU_ParseResource( LPCSTR res, HMENU32 hMenu, BOOL32 unicode )
{
WORD flags, id = 0;
LPCSTR str;
do
{
flags = GET_WORD(res);
res += sizeof(WORD);
if (!(flags & MF_POPUP))
{
id = GET_WORD(res);
res += sizeof(WORD);
}
if (!IS_STRING_ITEM(flags))
ERR(menu, "not a string item %04x\n", flags );
str = res;
if (!unicode) res += strlen(str) + 1;
else res += (lstrlen32W((LPCWSTR)str) + 1) * sizeof(WCHAR);
if (flags & MF_POPUP)
{
HMENU32 hSubMenu = CreatePopupMenu32();
if (!hSubMenu) return NULL;
if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
return NULL;
if (!unicode) AppendMenu32A( hMenu, flags, (UINT32)hSubMenu, str );
else AppendMenu32W( hMenu, flags, (UINT32)hSubMenu, (LPCWSTR)str );
}
else /* Not a popup */
{
if (!unicode) AppendMenu32A( hMenu, flags, id, *str ? str : NULL );
else AppendMenu32W( hMenu, flags, id,
*(LPCWSTR)str ? (LPCWSTR)str : NULL );
}
} while (!(flags & MF_END));
return res;
}
/**********************************************************************
* MENUEX_ParseResource
*
* Parse an extended menu resource and add items to the menu.
* Return a pointer to the end of the resource.
*/
static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU32 hMenu)
{
WORD resinfo;
do {
MENUITEMINFO32W mii;
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
mii.fType = GET_DWORD(res);
res += sizeof(DWORD);
mii.fState = GET_DWORD(res);
res += sizeof(DWORD);
mii.wID = GET_DWORD(res);
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;
mii.dwTypeData = (LPWSTR) res;
res += (1 + lstrlen32W(mii.dwTypeData)) * sizeof(WCHAR);
/* Align the following fields on a dword boundary. */
res += (~((int)res - 1)) & 3;
/* FIXME: This is inefficient and cannot be optimised away by gcc. */
{
LPSTR newstr = HEAP_strdupWtoA(GetProcessHeap(),
0, mii.dwTypeData);
TRACE(menu, "Menu item: [%08x,%08x,%04x,%04x,%s]\n",
mii.fType, mii.fState, mii.wID, resinfo, newstr);
HeapFree( GetProcessHeap(), 0, newstr );
}
if (resinfo & 1) { /* Pop-up? */
DWORD helpid = GET_DWORD(res); /* FIXME: use this. */
res += sizeof(DWORD);
mii.hSubMenu = CreatePopupMenu32();
if (!mii.hSubMenu)
return NULL;
if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
DestroyMenu32(mii.hSubMenu);
return NULL;
}
mii.fMask |= MIIM_SUBMENU;
mii.fType |= MF_POPUP;
}
InsertMenuItem32W(hMenu, -1, MF_BYPOSITION, &mii);
} while (!(resinfo & MF_END));
return res;
}
/***********************************************************************
* MENU_GetSubPopup
*
* Return the handle of the selected sub-popup menu (if any).
*/
static HMENU32 MENU_GetSubPopup( HMENU32 hmenu )
{
POPUPMENU *menu;
MENUITEM *item;
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
if (menu->FocusedItem == NO_SELECTED_ITEM) return 0;
item = &menu->items[menu->FocusedItem];
if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
return item->hSubMenu;
return 0;
}
/***********************************************************************
* MENU_HideSubPopups
*
* Hide the sub-popup menus of this menu.
*/
static void MENU_HideSubPopups( HWND32 hwndOwner, HMENU32 hmenu,
BOOL32 sendMenuSelect )
{
POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR( hmenu );;
if (menu && uSubPWndLevel)
{
HMENU32 hsubmenu;
POPUPMENU *submenu;
MENUITEM *item;
if (menu->FocusedItem != NO_SELECTED_ITEM)
{
item = &menu->items[menu->FocusedItem];
if (!(item->fType & MF_POPUP) ||
!(item->fState & MF_MOUSESELECT)) return;
item->fState &= ~MF_MOUSESELECT;
hsubmenu = item->hSubMenu;
} else return;
submenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hsubmenu );
MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect );
if (submenu->hWnd == pTopPopupWnd->hwndSelf )
{
ShowWindow32( submenu->hWnd, SW_HIDE );
uSubPWndLevel = 0;
}
else
{
DestroyWindow32( submenu->hWnd );
submenu->hWnd = 0;
}
}
}
/***********************************************************************
* 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.
*/
static HMENU32 MENU_ShowSubPopup( HWND32 hwndOwner, HMENU32 hmenu,
BOOL32 selectFirst )
{
RECT32 rect;
POPUPMENU *menu;
MENUITEM *item;
WND *wndPtr;
HDC32 hdc;
if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return hmenu;
if (!(wndPtr = WIN_FindWndPtr( menu->hWnd )) ||
(menu->FocusedItem == NO_SELECTED_ITEM)) return hmenu;
item = &menu->items[menu->FocusedItem];
if (!(item->fType & MF_POPUP) ||
(item->fState & (MF_GRAYED | MF_DISABLED))) return hmenu;
/* message must be send before using item,
because nearly everything may by changed by the application ! */
rect = item->rect;
SendMessage16( hwndOwner, WM_INITMENUPOPUP, (WPARAM16)item->hSubMenu,
MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
/* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
if (!(item->fState & MF_HILITE))
{
if (menu->wFlags & MF_POPUP) hdc = GetDC32( menu->hWnd );
else hdc = GetDCEx32( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
item->fState |= MF_HILITE;
MENU_DrawMenuItem( menu->hWnd, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP) );
ReleaseDC32( menu->hWnd, hdc );
}
if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
item->rect = rect;
item->fState |= MF_MOUSESELECT;
if (IS_SYSTEM_MENU(menu))
{
MENU_InitSysMenuPopup(item->hSubMenu, wndPtr->dwStyle, wndPtr->class->style);
NC_GetSysPopupPos( wndPtr, &rect );
rect.top = rect.bottom;
rect.right = SYSMETRICS_CXSIZE;
rect.bottom = SYSMETRICS_CYSIZE;
}
else
{
if (menu->wFlags & MF_POPUP)
{
rect.left = wndPtr->rectWindow.left + item->rect.right-arrow_bitmap_width;
rect.top = wndPtr->rectWindow.top + item->rect.top;
rect.right = item->rect.left - item->rect.right + 2*arrow_bitmap_width;
rect.bottom = item->rect.top - item->rect.bottom;
}
else
{
rect.left = wndPtr->rectWindow.left + item->rect.left;
rect.top = wndPtr->rectWindow.top + item->rect.bottom;
rect.right = item->rect.right - item->rect.left;
rect.bottom = item->rect.bottom - item->rect.top;
}
}
MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
rect.left, rect.top, rect.right, rect.bottom );
if (selectFirst)
MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
return item->hSubMenu;
}
/***********************************************************************
* MENU_PtMenu
*
* Walks menu chain trying to find a menu pt maps to.
*/
static HMENU32 MENU_PtMenu( HMENU32 hMenu, POINT16 pt )
{
POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hMenu );
register UINT32 ht = menu->FocusedItem;
/* try subpopup first (if any) */
ht = (ht != NO_SELECTED_ITEM &&
(menu->items[ht].fType & MF_POPUP) &&
(menu->items[ht].fState & MF_MOUSESELECT))
? (UINT32) MENU_PtMenu(menu->items[ht].hSubMenu, pt) : 0;
if( !ht ) /* check the current window (avoiding WM_HITTEST) */
{
ht = (UINT32)NC_HandleNCHitTest( menu->hWnd, pt );
if( menu->wFlags & MF_POPUP )
ht = (ht != (UINT32)HTNOWHERE &&
ht != (UINT32)HTERROR) ? (UINT32)hMenu : 0;
else
{
WND* wndPtr = WIN_FindWndPtr(menu->hWnd);
ht = ( ht == HTSYSMENU ) ? (UINT32)(wndPtr->hSysMenu)
: ( ht == HTMENU ) ? (UINT32)(wndPtr->wIDmenu) : 0;
}
}
return (HMENU32)ht;
}
/***********************************************************************
* MENU_ExecFocusedItem
*
* Execute a menu item (for instance when user pressed Enter).
* Return TRUE if we can go on with menu tracking.
*/
static BOOL32 MENU_ExecFocusedItem( MTRACKER* pmt, HMENU32 hMenu )
{
MENUITEM *item;
POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hMenu );
if (!menu || !menu->nItems ||
(menu->FocusedItem == NO_SELECTED_ITEM)) return TRUE;
item = &menu->items[menu->FocusedItem];
TRACE(menu, "%08x %08x %08x\n",
hMenu, item->wID, item->hSubMenu);
if (!(item->fType & MF_POPUP))
{
if (!(item->fState & (MF_GRAYED | MF_DISABLED)))
{
if( menu->wFlags & MF_SYSMENU )
{
PostMessage16( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
}
else
PostMessage16( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
return FALSE;
}
else return TRUE;
}
else
{
pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hMenu, TRUE );
return TRUE;
}
}
/***********************************************************************
* MENU_SwitchTracking
*
* Helper function for menu navigation routines.
*/
static void MENU_SwitchTracking( MTRACKER* pmt, HMENU32 hPtMenu, UINT32 id )
{
POPUPMENU *ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
POPUPMENU *topmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( pmt->hTopMenu );
if( pmt->hTopMenu != hPtMenu &&
!((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
{
/* both are top level menus (system and menu-bar) */
MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE );
pmt->hTopMenu = hPtMenu;
}
else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE );
}
/***********************************************************************
* MENU_ButtonDown
*
* Return TRUE if we can go on with menu tracking.
*/
static BOOL32 MENU_ButtonDown( MTRACKER* pmt, HMENU32 hPtMenu )
{
if (hPtMenu)
{
UINT32 id = 0;
POPUPMENU *ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
MENUITEM *item;
if( IS_SYSTEM_MENU(ptmenu) )
item = ptmenu->items;
else
item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
if( item )
{
if( ptmenu->FocusedItem == id )
{
/* nothing to do with already selected non-popup */
if( !(item->fType & MF_POPUP) ) return TRUE;
if( item->fState & MF_MOUSESELECT )
{
if( ptmenu->wFlags & MF_POPUP )
{
/* hide selected subpopup */
MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, TRUE );
pmt->hCurrentMenu = hPtMenu;
return TRUE;
}
return FALSE; /* shouldn't get here */
}
}
else MENU_SwitchTracking( pmt, hPtMenu, id );
/* try to display a subpopup */
pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE );
return TRUE;
}
else WARN(menu, "\tunable to find clicked item!\n");
}
return FALSE;
}
/***********************************************************************
* MENU_ButtonUp
*
* Return TRUE if we can go on with menu tracking.
*/
static BOOL32 MENU_ButtonUp( MTRACKER* pmt, HMENU32 hPtMenu )
{
if (hPtMenu)
{
UINT32 id = 0;
POPUPMENU *ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
MENUITEM *item;
if( IS_SYSTEM_MENU(ptmenu) )
item = ptmenu->items;
else
item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
if( item && (ptmenu->FocusedItem == id ))
{
if( !(item->fType & MF_POPUP) )
return MENU_ExecFocusedItem( pmt, hPtMenu );
hPtMenu = item->hSubMenu;
if( hPtMenu == pmt->hCurrentMenu )
{
/* Select first item of sub-popup */
MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, NO_SELECTED_ITEM, FALSE );
MENU_MoveSelection( pmt->hOwnerWnd, hPtMenu, ITEM_NEXT );
}
return TRUE;
}
}
return FALSE;
}
/***********************************************************************
* MENU_MouseMove
*
* Return TRUE if we can go on with menu tracking.
*/
static BOOL32 MENU_MouseMove( MTRACKER* pmt, HMENU32 hPtMenu )
{
UINT32 id = NO_SELECTED_ITEM;
POPUPMENU *ptmenu = NULL;
if( hPtMenu )
{
ptmenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hPtMenu );
if( IS_SYSTEM_MENU(ptmenu) )
id = 0;
else
MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
}
if( id == NO_SELECTED_ITEM )
{
MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
NO_SELECTED_ITEM, TRUE );
}
else if( ptmenu->FocusedItem != id )
{
MENU_SwitchTracking( pmt, hPtMenu, id );
pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE );
}
return TRUE;
}
/***********************************************************************
* MENU_DoNextMenu
*
* NOTE: WM_NEXTMENU documented in Win32 is a bit different.
*/
static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT32 vk )
{
POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( pmt->hTopMenu );
if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
(vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
{
WND* wndPtr;
HMENU32 hNewMenu;
HWND32 hNewWnd;
UINT32 id = 0;
LRESULT l = SendMessage16( pmt->hOwnerWnd, WM_NEXTMENU, (WPARAM16)vk,
(IS_SYSTEM_MENU(menu)) ? GetSubMenu16(pmt->hTopMenu,0) : pmt->hTopMenu );
TRACE(menu,"%04x [%04x] -> %04x [%04x]\n",
(UINT16)pmt->hCurrentMenu, (UINT16)pmt->hOwnerWnd, LOWORD(l), HIWORD(l) );
if( l == 0 )
{
wndPtr = WIN_FindWndPtr(pmt->hOwnerWnd);
hNewWnd = pmt->hOwnerWnd;
if( IS_SYSTEM_MENU(menu) )
{
/* switch to the menu bar */
if( wndPtr->dwStyle & WS_CHILD || !wndPtr->wIDmenu )
return FALSE;
hNewMenu = wndPtr->wIDmenu;
if( vk == VK_LEFT )
{
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hNewMenu );
id = menu->nItems - 1;
}
}
else if( wndPtr->dwStyle & WS_SYSMENU )
{
/* switch to the system menu */
hNewMenu = wndPtr->hSysMenu;
}
else return FALSE;
}
else /* application returned a new menu to switch to */
{
hNewMenu = LOWORD(l); hNewWnd = HIWORD(l);
if( IsMenu32(hNewMenu) && IsWindow32(hNewWnd) )
{
wndPtr = WIN_FindWndPtr(hNewWnd);
if( wndPtr->dwStyle & WS_SYSMENU &&
GetSubMenu16(wndPtr->hSysMenu, 0) == hNewMenu )
{
/* get the real system menu */
hNewMenu = wndPtr->hSysMenu;
}
else if( wndPtr->dwStyle & WS_CHILD || wndPtr->wIDmenu != hNewMenu )
{
/* FIXME: Not sure what to do here, perhaps,
* try to track hNewMenu as a popup? */
TRACE(menu," -- got confused.\n");
return FALSE;
}
}
else return FALSE;
}
if( hNewMenu != pmt->hTopMenu )
{
MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE );
if( pmt->hCurrentMenu != pmt->hTopMenu )
MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
}
if( hNewWnd != pmt->hOwnerWnd )
{
ReleaseCapture();
pmt->hOwnerWnd = hNewWnd;
EVENT_Capture( pmt->hOwnerWnd, HTMENU );
}
pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE );
return TRUE;
}
return FALSE;
}
/***********************************************************************
* MENU_SuspendPopup
*
* The idea is not to show the popup if the next input message is
* going to hide it anyway.
*/
static BOOL32 MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
{
MSG16 msg;
msg.hwnd = pmt->hOwnerWnd;
PeekMessage16( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
pmt->trackFlags |= TF_SKIPREMOVE;
switch( uMsg )
{
case WM_KEYDOWN:
PeekMessage16( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
{
PeekMessage16( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
PeekMessage16( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
if( msg.message == WM_KEYDOWN &&
(msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
{
pmt->trackFlags |= TF_SUSPENDPOPUP;
return TRUE;
}
}
break;
}
/* failures go through this */
pmt->trackFlags &= ~TF_SUSPENDPOPUP;
return FALSE;
}
/***********************************************************************
* MENU_KeyLeft
*
* Handle a VK_LEFT key event in a menu.
*/
static void MENU_KeyLeft( MTRACKER* pmt )
{
POPUPMENU *menu;
HMENU32 hmenutmp, hmenuprev;
UINT32 prevcol;
hmenuprev = hmenutmp = pmt->hTopMenu;
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenutmp );
/* Try to move 1 column left (if possible) */
if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
NO_SELECTED_ITEM ) {
MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
prevcol, TRUE );
return;
}
/* close topmost popup */
while (hmenutmp != pmt->hCurrentMenu)
{
hmenuprev = hmenutmp;
hmenutmp = MENU_GetSubPopup( hmenuprev );
}
MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
pmt->hCurrentMenu = hmenuprev;
if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
{
/* move menu bar selection if no more popups are left */
if( !MENU_DoNextMenu( pmt, VK_LEFT) )
MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
{
/* A sublevel menu was displayed - display the next one
* unless there is another displacement coming up */
if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd,
pmt->hTopMenu, TRUE );
}
}
}
/***********************************************************************
* MENU_KeyRight
*
* Handle a VK_RIGHT key event in a menu.
*/
static void MENU_KeyRight( MTRACKER* pmt )
{
HMENU32 hmenutmp;
POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( pmt->hTopMenu );
UINT32 nextcol;
TRACE(menu, "MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
pmt->hCurrentMenu,
((POPUPMENU *)USER_HEAP_LIN_ADDR(pmt->hCurrentMenu))->
items[0].text,
pmt->hTopMenu, menu->items[0].text );
if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
{
/* If already displaying a popup, try to display sub-popup */
hmenutmp = pmt->hCurrentMenu;
pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hmenutmp, TRUE );
/* if subpopup was displayed then we are done */
if (hmenutmp != pmt->hCurrentMenu) return;
}
/* Check to see if there's another column */
if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
NO_SELECTED_ITEM ) {
TRACE(menu, "Going to %d.\n", nextcol );
MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
nextcol, TRUE );
return;
}
if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
{
if( pmt->hCurrentMenu != pmt->hTopMenu )
{
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) )
pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd,
pmt->hTopMenu, TRUE );
}
}
/***********************************************************************
* MENU_TrackMenu
*
* Menu tracking code.
*/
static BOOL32 MENU_TrackMenu( HMENU32 hmenu, UINT32 wFlags, INT32 x, INT32 y,
HWND32 hwnd, const RECT32 *lprect )
{
MSG16 msg;
POPUPMENU *menu;
BOOL32 fRemove;
MTRACKER mt = { 0, hmenu, hmenu, hwnd, {x, y} }; /* control struct */
fEndMenu = FALSE;
if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
if (wFlags & TPM_BUTTONDOWN) MENU_ButtonDown( &mt, hmenu );
EVENT_Capture( mt.hOwnerWnd, HTMENU );
while (!fEndMenu)
{
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( mt.hCurrentMenu );
msg.hwnd = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
/* we have to keep the message in the queue until it's
* clear that menu loop is not over yet. */
if (!MSG_InternalGetMessage( &msg, msg.hwnd, mt.hOwnerWnd,
MSGF_MENU, PM_NOREMOVE, TRUE )) break;
TranslateMessage16( &msg );
CONV_POINT16TO32( &msg.pt, &mt.pt );
fRemove = FALSE;
if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
{
/* Find a menu for this mouse event */
hmenu = MENU_PtMenu( mt.hTopMenu, msg.pt );
switch(msg.message)
{
/* no WM_NC... messages in captured state */
case WM_RBUTTONDBLCLK:
case WM_RBUTTONDOWN:
if (!(wFlags & TPM_RIGHTBUTTON)) break;
/* fall through */
case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN:
fEndMenu |= !MENU_ButtonDown( &mt, hmenu );
break;
case WM_RBUTTONUP:
if (!(wFlags & TPM_RIGHTBUTTON)) break;
/* fall through */
case WM_LBUTTONUP:
/* If outside all menus but inside lprect, ignore it */
if (hmenu || !lprect || !PtInRect32(lprect, mt.pt))
{
fEndMenu |= !MENU_ButtonUp( &mt, hmenu );
fRemove = TRUE;
}
break;
case WM_MOUSEMOVE:
if ((msg.wParam & MK_LBUTTON) || ((wFlags & TPM_RIGHTBUTTON)
&& (msg.wParam & MK_RBUTTON)))
{
fEndMenu |= !MENU_MouseMove( &mt, hmenu );
}
} /* switch(msg.message) - mouse */
}
else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
{
fRemove = TRUE; /* Keyboard messages are always removed */
switch(msg.message)
{
case WM_KEYDOWN:
switch(msg.wParam)
{
case VK_HOME:
case VK_END:
MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
NO_SELECTED_ITEM, FALSE );
/* fall through */
case VK_UP:
MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
(msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
break;
case VK_DOWN: /* If on menu bar, pull-down the menu */
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( mt.hCurrentMenu );
if (!(menu->wFlags & MF_POPUP))
mt.hCurrentMenu = MENU_ShowSubPopup( mt.hOwnerWnd, mt.hTopMenu, TRUE );
else /* otherwise try to move selection */
MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
break;
case VK_LEFT:
MENU_KeyLeft( &mt );
break;
case VK_RIGHT:
MENU_KeyRight( &mt );
break;
case VK_SPACE:
case VK_RETURN:
fEndMenu |= !MENU_ExecFocusedItem( &mt, mt.hCurrentMenu );
break;
case VK_ESCAPE:
fEndMenu = TRUE;
break;
default:
break;
}
break; /* WM_KEYDOWN */
case WM_SYSKEYDOWN:
switch(msg.wParam)
{
case VK_MENU:
fEndMenu = TRUE;
break;
}
break; /* WM_SYSKEYDOWN */
case WM_CHAR:
{
UINT32 pos;
/* Hack to avoid control chars. */
/* We will find a better way real soon... */
if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
msg.wParam, FALSE );
if (pos == (UINT32)-2) fEndMenu = TRUE;
else if (pos == (UINT32)-1) MessageBeep32(0);
else
{
MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos, TRUE );
fEndMenu |= !MENU_ExecFocusedItem( &mt, mt.hCurrentMenu );
}
}
break;
} /* switch(msg.message) - kbd */
}
else
{
DispatchMessage16( &msg );
}
if (!fEndMenu) fRemove = TRUE;
/* finally remove message from the queue */
if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
PeekMessage16( &msg, 0, msg.message, msg.message, PM_REMOVE );
else mt.trackFlags &= ~TF_SKIPREMOVE;
}
ReleaseCapture();
if( IsWindow32( mt.hOwnerWnd ) )
{
MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( mt.hTopMenu );
if (menu && menu->wFlags & MF_POPUP)
{
ShowWindow32( menu->hWnd, SW_HIDE );
uSubPWndLevel = 0;
}
MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE );
SendMessage16( mt.hOwnerWnd, WM_MENUSELECT, 0, MAKELONG( 0xffff, 0 ) );
}
fEndMenu = FALSE;
return TRUE;
}
/***********************************************************************
* MENU_InitTracking
*/
static BOOL32 MENU_InitTracking(HWND32 hWnd, HMENU32 hMenu)
{
HideCaret32(0);
SendMessage16( hWnd, WM_ENTERMENULOOP, 0, 0 );
SendMessage16( hWnd, WM_SETCURSOR, hWnd, HTCAPTION );
SendMessage16( hWnd, WM_INITMENU, hMenu, 0 );
return TRUE;
}
/***********************************************************************
* MENU_TrackMouseMenuBar
*
* Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
*/
void MENU_TrackMouseMenuBar( WND* wndPtr, INT32 ht, POINT32 pt )
{
HWND32 hWnd = wndPtr->hwndSelf;
HMENU32 hMenu = (ht == HTSYSMENU) ? wndPtr->hSysMenu : wndPtr->wIDmenu;
if (IsMenu32(hMenu))
{
MENU_InitTracking( hWnd, hMenu );
MENU_TrackMenu( hMenu, TPM_ENTERIDLEEX | TPM_BUTTONDOWN |
TPM_LEFTALIGN | TPM_LEFTBUTTON, pt.x, pt.y, hWnd, NULL );
SendMessage16( hWnd, WM_EXITMENULOOP, 0, 0 );
ShowCaret32(0);
}
}
/***********************************************************************
* MENU_TrackKbdMenuBar
*
* Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
*/
void MENU_TrackKbdMenuBar( WND* wndPtr, UINT32 wParam, INT32 vkey)
{
UINT32 uItem = NO_SELECTED_ITEM;
HMENU32 hTrackMenu;
/* find window that has a menu */
while( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwStyle & WS_SYSMENU) )
if( !(wndPtr = wndPtr->parent) ) return;
/* check if we have to track a system menu */
if( (wndPtr->dwStyle & (WS_CHILD | WS_MINIMIZE)) ||
!wndPtr->wIDmenu || vkey == VK_SPACE )
{
if( !(wndPtr->dwStyle & WS_SYSMENU) ) return;
hTrackMenu = wndPtr->hSysMenu;
uItem = 0;
wParam |= HTSYSMENU; /* prevent item lookup */
}
else
hTrackMenu = wndPtr->wIDmenu;
if (IsMenu32( hTrackMenu ))
{
MENU_InitTracking( wndPtr->hwndSelf, hTrackMenu );
if( vkey && vkey != VK_SPACE )
{
uItem = MENU_FindItemByKey( wndPtr->hwndSelf, hTrackMenu,
vkey, (wParam & HTSYSMENU) );
if( uItem >= (UINT32)(-2) )
{
if( uItem == (UINT32)(-1) ) MessageBeep32(0);
hTrackMenu = 0;
}
}
if( hTrackMenu )
{
MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE );
if( uItem == NO_SELECTED_ITEM )
MENU_MoveSelection( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT );
else if( vkey )
PostMessage16( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );
MENU_TrackMenu( hTrackMenu, TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON,
0, 0, wndPtr->hwndSelf, NULL );
}
SendMessage16( wndPtr->hwndSelf, WM_EXITMENULOOP, 0, 0 );
ShowCaret32(0);
}
}
/**********************************************************************
* TrackPopupMenu16 (USER.416)
*/
BOOL16 WINAPI TrackPopupMenu16( HMENU16 hMenu, UINT16 wFlags, INT16 x, INT16 y,
INT16 nReserved, HWND16 hWnd, const RECT16 *lpRect )
{
RECT32 r;
if (lpRect)
CONV_RECT16TO32( lpRect, &r );
return TrackPopupMenu32( hMenu, wFlags, x, y, nReserved, hWnd,
lpRect ? &r : NULL );
}
/**********************************************************************
* TrackPopupMenu32 (USER32.548)
*/
BOOL32 WINAPI TrackPopupMenu32( HMENU32 hMenu, UINT32 wFlags, INT32 x, INT32 y,
INT32 nReserved, HWND32 hWnd, const RECT32 *lpRect )
{
BOOL32 ret = FALSE;
HideCaret32(0);
SendMessage16( hWnd, WM_INITMENUPOPUP, (WPARAM16)hMenu, 0);
if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
ret = MENU_TrackMenu( hMenu, wFlags & ~TPM_INTERNAL, 0, 0, hWnd, lpRect );
ShowCaret32(0);
return ret;
}
/**********************************************************************
* TrackPopupMenuEx (USER32.549)
*/
BOOL32 WINAPI TrackPopupMenuEx( HMENU32 hMenu, UINT32 wFlags, INT32 x, INT32 y,
HWND32 hWnd, LPTPMPARAMS lpTpm )
{
FIXME(menu, "not fully implemented\n" );
return TrackPopupMenu32( hMenu, wFlags, x, y, 0, hWnd,
lpTpm ? &lpTpm->rcExclude : NULL );
}
/***********************************************************************
* PopupMenuWndProc
*
* NOTE: Windows has totally different (and undocumented) popup wndproc.
*/
LRESULT WINAPI PopupMenuWndProc( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
LPARAM lParam )
{
WND* wndPtr = WIN_FindWndPtr(hwnd);
switch(message)
{
case WM_CREATE:
{
CREATESTRUCT32A *cs = (CREATESTRUCT32A*)lParam;
SetWindowLong32A( hwnd, 0, (LONG)cs->lpCreateParams );
return 0;
}
case WM_MOUSEACTIVATE: /* We don't want to be activated */
return MA_NOACTIVATE;
case WM_PAINT:
{
PAINTSTRUCT32 ps;
BeginPaint32( hwnd, &ps );
MENU_DrawPopupMenu( hwnd, ps.hdc,
(HMENU32)GetWindowLong32A( hwnd, 0 ) );
EndPaint32( hwnd, &ps );
return 0;
}
case WM_ERASEBKGND:
return 1;
case WM_DESTROY:
/* zero out global pointer in case resident popup window
* was somehow destroyed. */
if( hwnd == pTopPopupWnd->hwndSelf )
{
ERR(menu, "resident popup destroyed!\n");
pTopPopupWnd = NULL;
uSubPWndLevel = 0;
}
else
uSubPWndLevel--;
break;
case WM_SHOWWINDOW:
if( wParam )
{
if( !(*(HMENU32*)wndPtr->wExtra) )
ERR(menu,"no menu to display\n");
}
else
*(HMENU32*)wndPtr->wExtra = 0;
break;
case MM_SETMENUHANDLE:
*(HMENU32*)wndPtr->wExtra = (HMENU32)wParam;
break;
case MM_GETMENUHANDLE:
return *(HMENU32*)wndPtr->wExtra;
default:
return DefWindowProc32A( hwnd, message, wParam, lParam );
}
return 0;
}
/***********************************************************************
* MENU_GetMenuBarHeight
*
* Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
*/
UINT32 MENU_GetMenuBarHeight( HWND32 hwnd, UINT32 menubarWidth,
INT32 orgX, INT32 orgY )
{
HDC32 hdc;
RECT32 rectBar;
WND *wndPtr;
LPPOPUPMENU lppop;
TRACE(menu, "HWND 0x%x, width %d, "
"at (%d, %d).\n", hwnd, menubarWidth, orgX, orgY );
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
if (!(lppop = (LPPOPUPMENU)USER_HEAP_LIN_ADDR((HMENU16)wndPtr->wIDmenu)))
return 0;
hdc = GetDCEx32( hwnd, 0, DCX_CACHE | DCX_WINDOW );
SetRect32(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+SYSMETRICS_CYMENU);
MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
ReleaseDC32( hwnd, hdc );
return lppop->Height;
}
/*******************************************************************
* ChangeMenu16 (USER.153)
*/
BOOL16 WINAPI ChangeMenu16( HMENU16 hMenu, UINT16 pos, SEGPTR data,
UINT16 id, UINT16 flags )
{
TRACE(menu,"menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
hMenu, pos, (DWORD)data, id, flags );
if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
id, data );
/* 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?). */
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,
flags & MF_BYPOSITION ? pos : id,
flags & ~MF_REMOVE );
/* Default: MF_INSERT */
return InsertMenu16( hMenu, pos, flags, id, data );
}
/*******************************************************************
* ChangeMenu32A (USER32.22)
*/
BOOL32 WINAPI ChangeMenu32A( HMENU32 hMenu, UINT32 pos, LPCSTR data,
UINT32 id, UINT32 flags )
{
TRACE(menu,"menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
hMenu, pos, (DWORD)data, id, flags );
if (flags & MF_APPEND) return AppendMenu32A( hMenu, flags & ~MF_APPEND,
id, data );
if (flags & MF_DELETE) return DeleteMenu32(hMenu, pos, flags & ~MF_DELETE);
if (flags & MF_CHANGE) return ModifyMenu32A(hMenu, pos, flags & ~MF_CHANGE,
id, data );
if (flags & MF_REMOVE) return RemoveMenu32( hMenu,
flags & MF_BYPOSITION ? pos : id,
flags & ~MF_REMOVE );
/* Default: MF_INSERT */
return InsertMenu32A( hMenu, pos, flags, id, data );
}
/*******************************************************************
* ChangeMenu32W (USER32.23)
*/
BOOL32 WINAPI ChangeMenu32W( HMENU32 hMenu, UINT32 pos, LPCWSTR data,
UINT32 id, UINT32 flags )
{
TRACE(menu,"menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
hMenu, pos, (DWORD)data, id, flags );
if (flags & MF_APPEND) return AppendMenu32W( hMenu, flags & ~MF_APPEND,
id, data );
if (flags & MF_DELETE) return DeleteMenu32(hMenu, pos, flags & ~MF_DELETE);
if (flags & MF_CHANGE) return ModifyMenu32W(hMenu, pos, flags & ~MF_CHANGE,
id, data );
if (flags & MF_REMOVE) return RemoveMenu32( hMenu,
flags & MF_BYPOSITION ? pos : id,
flags & ~MF_REMOVE );
/* Default: MF_INSERT */
return InsertMenu32W( hMenu, pos, flags, id, data );
}
/*******************************************************************
* CheckMenuItem16 (USER.154)
*/
BOOL16 WINAPI CheckMenuItem16( HMENU16 hMenu, UINT16 id, UINT16 flags )
{
return (BOOL16)CheckMenuItem32( hMenu, id, flags );
}
/*******************************************************************
* CheckMenuItem32 (USER32.45)
*/
DWORD WINAPI CheckMenuItem32( HMENU32 hMenu, UINT32 id, UINT32 flags )
{
MENUITEM *item;
DWORD ret;
TRACE(menu,"%04x %04x %04x\n", hMenu, id, flags );
if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
ret = item->fState & MF_CHECKED;
if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
else item->fState &= ~MF_CHECKED;
return ret;
}
/**********************************************************************
* EnableMenuItem16 (USER.155)
*/
BOOL16 WINAPI EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
{
return EnableMenuItem32( hMenu, wItemID, wFlags );
}
/**********************************************************************
* EnableMenuItem32 (USER32.169)
*/
BOOL32 WINAPI EnableMenuItem32( HMENU32 hMenu, UINT32 wItemID, UINT32 wFlags )
{
BOOL32 bRet = FALSE;
MENUITEM *item, *first = NULL;
TRACE(menu,"(%04x, %04X, %04X) !\n",
hMenu, wItemID, wFlags);
while( (item = MENU_FindItem( &hMenu, &wItemID, wFlags )) )
{
if( !(item->fType & MF_POPUP) )
{
/* We can't have MF_GRAYED and MF_DISABLED together */
if (wFlags & MF_GRAYED)
{
item->fState = (item->fState & ~MF_DISABLED) | MF_GRAYED;
}
else if (wFlags & MF_DISABLED)
{
item->fState = (item->fState & ~MF_GRAYED) | MF_DISABLED;
}
else /* MF_ENABLED */
{
item->fState &= ~(MF_GRAYED | MF_DISABLED);
}
bRet = TRUE;
break;
}
if( !first ) first = item;
else if( first == item ) break;
}
return bRet;
}
/*******************************************************************
* GetMenuString16 (USER.161)
*/
INT16 WINAPI GetMenuString16( HMENU16 hMenu, UINT16 wItemID,
LPSTR str, INT16 nMaxSiz, UINT16 wFlags )
{
return GetMenuString32A( hMenu, wItemID, str, nMaxSiz, wFlags );
}
/*******************************************************************
* GetMenuString32A (USER32.267)
*/
INT32 WINAPI GetMenuString32A( HMENU32 hMenu, UINT32 wItemID,
LPSTR str, INT32 nMaxSiz, UINT32 wFlags )
{
MENUITEM *item;
TRACE(menu, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
hMenu, wItemID, str, nMaxSiz, wFlags );
if (!str || !nMaxSiz) return 0;
str[0] = '\0';
if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
if (!IS_STRING_ITEM(item->fType)) return 0;
lstrcpyn32A( str, item->text, nMaxSiz );
TRACE(menu, "returning '%s'\n", str );
return strlen(str);
}
/*******************************************************************
* GetMenuString32W (USER32.268)
*/
INT32 WINAPI GetMenuString32W( HMENU32 hMenu, UINT32 wItemID,
LPWSTR str, INT32 nMaxSiz, UINT32 wFlags )
{
MENUITEM *item;
TRACE(menu, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
hMenu, wItemID, str, nMaxSiz, wFlags );
if (!str || !nMaxSiz) return 0;
str[0] = '\0';
if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
if (!IS_STRING_ITEM(item->fType)) return 0;
lstrcpynAtoW( str, item->text, nMaxSiz );
return lstrlen32W(str);
}
/**********************************************************************
* HiliteMenuItem16 (USER.162)
*/
BOOL16 WINAPI HiliteMenuItem16( HWND16 hWnd, HMENU16 hMenu, UINT16 wItemID,
UINT16 wHilite )
{
return HiliteMenuItem32( hWnd, hMenu, wItemID, wHilite );
}
/**********************************************************************
* HiliteMenuItem32 (USER32.317)
*/
BOOL32 WINAPI HiliteMenuItem32( HWND32 hWnd, HMENU32 hMenu, UINT32 wItemID,
UINT32 wHilite )
{
LPPOPUPMENU menu;
TRACE(menu,"(%04x, %04x, %04x, %04x);\n",
hWnd, hMenu, wItemID, wHilite);
if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
if (menu->FocusedItem == wItemID) return TRUE;
MENU_HideSubPopups( hWnd, hMenu, FALSE );
MENU_SelectItem( hWnd, hMenu, wItemID, TRUE );
return TRUE;
}
/**********************************************************************
* GetMenuState16 (USER.250)
*/
UINT16 WINAPI GetMenuState16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
{
return GetMenuState32( hMenu, wItemID, wFlags );
}
/**********************************************************************
* GetMenuState32 (USER32.266)
*/
UINT32 WINAPI GetMenuState32( HMENU32 hMenu, UINT32 wItemID, UINT32 wFlags )
{
MENUITEM *item;
TRACE(menu,"(%04x, %04x, %04x);\n",
hMenu, wItemID, wFlags);
if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
debug_print_menuitem (" item: ", item, "");
if (item->fType & MF_POPUP)
{
POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( item->hSubMenu );
if (!menu) return -1;
else return (menu->nItems << 8) | (menu->wFlags & 0xff);
}
else
{
/* 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);
}
}
/**********************************************************************
* GetMenuItemCount16 (USER.263)
*/
INT16 WINAPI GetMenuItemCount16( HMENU16 hMenu )
{
LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
if (!IS_A_MENU(menu)) return -1;
TRACE(menu,"(%04x) returning %d\n",
hMenu, menu->nItems );
return menu->nItems;
}
/**********************************************************************
* GetMenuItemCount32 (USER32.261)
*/
INT32 WINAPI GetMenuItemCount32( HMENU32 hMenu )
{
LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
if (!IS_A_MENU(menu)) return -1;
TRACE(menu,"(%04x) returning %d\n",
hMenu, menu->nItems );
return menu->nItems;
}
/**********************************************************************
* GetMenuItemID16 (USER.264)
*/
UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
{
LPPOPUPMENU menu;
if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return -1;
if ((nPos < 0) || ((UINT16) nPos >= menu->nItems)) return -1;
if (menu->items[nPos].fType & MF_POPUP) return -1;
return menu->items[nPos].wID;
}
/**********************************************************************
* GetMenuItemID32 (USER32.262)
*/
UINT32 WINAPI GetMenuItemID32( HMENU32 hMenu, INT32 nPos )
{
LPPOPUPMENU menu;
if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return -1;
if ((nPos < 0) || (nPos >= menu->nItems)) return -1;
return menu->items[nPos].wID;
}
/*******************************************************************
* InsertMenu16 (USER.410)
*/
BOOL16 WINAPI InsertMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
UINT16 id, SEGPTR data )
{
UINT32 pos32 = (UINT32)pos;
if ((pos == (UINT16)-1) && (flags & MF_BYPOSITION)) pos32 = (UINT32)-1;
if (IS_STRING_ITEM(flags) && data)
return InsertMenu32A( hMenu, pos32, flags, id,
(LPSTR)PTR_SEG_TO_LIN(data) );
return InsertMenu32A( hMenu, pos32, flags, id, (LPSTR)data );
}
/*******************************************************************
* InsertMenu32A (USER32.321)
*/
BOOL32 WINAPI InsertMenu32A( HMENU32 hMenu, UINT32 pos, UINT32 flags,
UINT32 id, LPCSTR str )
{
MENUITEM *item;
if (IS_STRING_ITEM(flags) && str)
TRACE(menu, "hMenu %04x, pos %d, flags %08x, "
"id %04x, str '%s'\n",
hMenu, pos, flags, id, str );
else TRACE(menu, "hMenu %04x, pos %d, flags %08x, "
"id %04x, str %08lx (not a string)\n",
hMenu, pos, flags, id, (DWORD)str );
if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
if (!(MENU_SetItemData( item, flags, id, str )))
{
RemoveMenu32( hMenu, pos, flags );
return FALSE;
}
if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
((POPUPMENU *)USER_HEAP_LIN_ADDR((HMENU16)id))->wFlags |= MF_POPUP;
item->hCheckBit = item->hUnCheckBit = 0;
item->dwItemData = 0;
return TRUE;
}
/*******************************************************************
* InsertMenu32W (USER32.324)
*/
BOOL32 WINAPI InsertMenu32W( HMENU32 hMenu, UINT32 pos, UINT32 flags,
UINT32 id, LPCWSTR str )
{
BOOL32 ret;
if (IS_STRING_ITEM(flags) && str)
{
LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
ret = InsertMenu32A( hMenu, pos, flags, id, newstr );
HeapFree( GetProcessHeap(), 0, newstr );
return ret;
}
else return InsertMenu32A( hMenu, pos, flags, id, (LPCSTR)str );
}
/*******************************************************************
* AppendMenu16 (USER.411)
*/
BOOL16 WINAPI AppendMenu16(HMENU16 hMenu, UINT16 flags, UINT16 id, SEGPTR data)
{
return InsertMenu16( hMenu, -1, flags | MF_BYPOSITION, id, data );
}
/*******************************************************************
* AppendMenu32A (USER32.4)
*/
BOOL32 WINAPI AppendMenu32A( HMENU32 hMenu, UINT32 flags,
UINT32 id, LPCSTR data )
{
return InsertMenu32A( hMenu, -1, flags | MF_BYPOSITION, id, data );
}
/*******************************************************************
* AppendMenu32W (USER32.5)
*/
BOOL32 WINAPI AppendMenu32W( HMENU32 hMenu, UINT32 flags,
UINT32 id, LPCWSTR data )
{
return InsertMenu32W( hMenu, -1, flags | MF_BYPOSITION, id, data );
}
/**********************************************************************
* RemoveMenu16 (USER.412)
*/
BOOL16 WINAPI RemoveMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
{
return RemoveMenu32( hMenu, nPos, wFlags );
}
/**********************************************************************
* RemoveMenu32 (USER32.440)
*/
BOOL32 WINAPI RemoveMenu32( HMENU32 hMenu, UINT32 nPos, UINT32 wFlags )
{
LPPOPUPMENU menu;
MENUITEM *item;
TRACE(menu,"(%04x, %04x, %04x)\n",hMenu, nPos, wFlags);
if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
/* Remove item */
MENU_FreeItemData( item );
if (--menu->nItems == 0)
{
HeapFree( SystemHeap, 0, menu->items );
menu->items = NULL;
}
else
{
while(nPos < menu->nItems)
{
*item = *(item+1);
item++;
nPos++;
}
menu->items = HeapReAlloc( SystemHeap, 0, menu->items,
menu->nItems * sizeof(MENUITEM) );
}
return TRUE;
}
/**********************************************************************
* DeleteMenu16 (USER.413)
*/
BOOL16 WINAPI DeleteMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
{
return DeleteMenu32( hMenu, nPos, wFlags );
}
/**********************************************************************
* DeleteMenu32 (USER32.128)
*/
BOOL32 WINAPI DeleteMenu32( HMENU32 hMenu, UINT32 nPos, UINT32 wFlags )
{
MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
if (!item) return FALSE;
if (item->fType & MF_POPUP) DestroyMenu32( item->hSubMenu );
/* nPos is now the position of the item */
RemoveMenu32( hMenu, nPos, wFlags | MF_BYPOSITION );
return TRUE;
}
/*******************************************************************
* ModifyMenu16 (USER.414)
*/
BOOL16 WINAPI ModifyMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
UINT16 id, SEGPTR data )
{
if (IS_STRING_ITEM(flags))
return ModifyMenu32A( hMenu, pos, flags, id,
(LPSTR)PTR_SEG_TO_LIN(data) );
return ModifyMenu32A( hMenu, pos, flags, id, (LPSTR)data );
}
/*******************************************************************
* ModifyMenu32A (USER32.396)
*/
BOOL32 WINAPI ModifyMenu32A( HMENU32 hMenu, UINT32 pos, UINT32 flags,
UINT32 id, LPCSTR str )
{
MENUITEM *item;
if (IS_STRING_ITEM(flags))
{
TRACE(menu, "%04x %d %04x %04x '%s'\n",
hMenu, pos, flags, id, str ? str : "#NULL#" );
if (!str) return FALSE;
}
else
{
TRACE(menu, "%04x %d %04x %04x %08lx\n",
hMenu, pos, flags, id, (DWORD)str );
}
if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
return MENU_SetItemData( item, flags, id, str );
}
/*******************************************************************
* ModifyMenu32W (USER32.397)
*/
BOOL32 WINAPI ModifyMenu32W( HMENU32 hMenu, UINT32 pos, UINT32 flags,
UINT32 id, LPCWSTR str )
{
BOOL32 ret;
if (IS_STRING_ITEM(flags) && str)
{
LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
ret = ModifyMenu32A( hMenu, pos, flags, id, newstr );
HeapFree( GetProcessHeap(), 0, newstr );
return ret;
}
else return ModifyMenu32A( hMenu, pos, flags, id, (LPCSTR)str );
}
/**********************************************************************
* CreatePopupMenu16 (USER.415)
*/
HMENU16 WINAPI CreatePopupMenu16(void)
{
return CreatePopupMenu32();
}
/**********************************************************************
* CreatePopupMenu32 (USER32.81)
*/
HMENU32 WINAPI CreatePopupMenu32(void)
{
HMENU32 hmenu;
POPUPMENU *menu;
if (!(hmenu = CreateMenu32())) return 0;
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
menu->wFlags |= MF_POPUP;
return hmenu;
}
/**********************************************************************
* GetMenuCheckMarkDimensions (USER.417) (USER32.257)
*/
DWORD WINAPI GetMenuCheckMarkDimensions(void)
{
return MAKELONG( check_bitmap_width, check_bitmap_height );
}
/**********************************************************************
* SetMenuItemBitmaps16 (USER.418)
*/
BOOL16 WINAPI SetMenuItemBitmaps16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags,
HBITMAP16 hNewUnCheck, HBITMAP16 hNewCheck)
{
return SetMenuItemBitmaps32( hMenu, nPos, wFlags, hNewUnCheck, hNewCheck );
}
/**********************************************************************
* SetMenuItemBitmaps32 (USER32.489)
*/
BOOL32 WINAPI SetMenuItemBitmaps32( HMENU32 hMenu, UINT32 nPos, UINT32 wFlags,
HBITMAP32 hNewUnCheck, HBITMAP32 hNewCheck)
{
MENUITEM *item;
TRACE(menu,"(%04x, %04x, %04x, %04x, %04x)\n",
hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
if (!hNewCheck && !hNewUnCheck)
{
item->fState &= ~MF_USECHECKBITMAPS;
}
else /* Install new bitmaps */
{
item->hCheckBit = hNewCheck;
item->hUnCheckBit = hNewUnCheck;
item->fState |= MF_USECHECKBITMAPS;
}
return TRUE;
}
/**********************************************************************
* CreateMenu16 (USER.151)
*/
HMENU16 WINAPI CreateMenu16(void)
{
return CreateMenu32();
}
/**********************************************************************
* CreateMenu32 (USER32.80)
*/
HMENU32 WINAPI CreateMenu32(void)
{
HMENU32 hMenu;
LPPOPUPMENU menu;
if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
menu->wFlags = 0;
menu->wMagic = MENU_MAGIC;
menu->hTaskQ = 0;
menu->Width = 0;
menu->Height = 0;
menu->nItems = 0;
menu->hWnd = 0;
menu->items = NULL;
menu->FocusedItem = NO_SELECTED_ITEM;
TRACE(menu, "return %04x\n", hMenu );
return hMenu;
}
/**********************************************************************
* DestroyMenu16 (USER.152)
*/
BOOL16 WINAPI DestroyMenu16( HMENU16 hMenu )
{
return DestroyMenu32( hMenu );
}
/**********************************************************************
* DestroyMenu32 (USER32.133)
*/
BOOL32 WINAPI DestroyMenu32( HMENU32 hMenu )
{
TRACE(menu,"(%04x)\n", hMenu);
/* Silently ignore attempts to destroy default system popup */
if (hMenu && hMenu != MENU_DefSysPopup)
{
LPPOPUPMENU lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
if( pTopPopupWnd && (hMenu == *(HMENU32*)pTopPopupWnd->wExtra) )
*(UINT32*)pTopPopupWnd->wExtra = 0;
if (IS_A_MENU( lppop ))
{
lppop->wMagic = 0; /* Mark it as destroyed */
if ((lppop->wFlags & MF_POPUP) && lppop->hWnd &&
(!pTopPopupWnd || (lppop->hWnd != pTopPopupWnd->hwndSelf)))
DestroyWindow32( lppop->hWnd );
if (lppop->items) /* recursively destroy submenus */
{
int i;
MENUITEM *item = lppop->items;
for (i = lppop->nItems; i > 0; i--, item++)
{
if (item->fType & MF_POPUP) DestroyMenu32(item->hSubMenu);
MENU_FreeItemData( item );
}
HeapFree( SystemHeap, 0, lppop->items );
}
USER_HEAP_FREE( hMenu );
}
else return FALSE;
}
return (hMenu != MENU_DefSysPopup);
}
/**********************************************************************
* GetSystemMenu16 (USER.156)
*/
HMENU16 WINAPI GetSystemMenu16( HWND16 hWnd, BOOL16 bRevert )
{
return GetSystemMenu32( hWnd, bRevert );
}
/**********************************************************************
* GetSystemMenu32 (USER32.290)
*/
HMENU32 WINAPI GetSystemMenu32( HWND32 hWnd, BOOL32 bRevert )
{
WND *wndPtr = WIN_FindWndPtr( hWnd );
if (wndPtr)
{
if( wndPtr->hSysMenu )
{
if( bRevert )
{
DestroyMenu32(wndPtr->hSysMenu);
wndPtr->hSysMenu = 0;
}
else
{
POPUPMENU *menu = (POPUPMENU*)
USER_HEAP_LIN_ADDR(wndPtr->hSysMenu);
if( menu->items[0].hSubMenu == MENU_DefSysPopup )
menu->items[0].hSubMenu = MENU_CopySysPopup();
}
}
if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU32)(-1) );
if( wndPtr->hSysMenu )
return GetSubMenu16(wndPtr->hSysMenu, 0);
}
return 0;
}
/*******************************************************************
* SetSystemMenu16 (USER.280)
*/
BOOL16 WINAPI SetSystemMenu16( HWND16 hwnd, HMENU16 hMenu )
{
return SetSystemMenu32( hwnd, hMenu );
}
/*******************************************************************
* SetSystemMenu32 (USER32.507)
*/
BOOL32 WINAPI SetSystemMenu32( HWND32 hwnd, HMENU32 hMenu )
{
WND *wndPtr = WIN_FindWndPtr(hwnd);
if (wndPtr)
{
if (wndPtr->hSysMenu) DestroyMenu32( wndPtr->hSysMenu );
wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
return TRUE;
}
return FALSE;
}
/**********************************************************************
* GetMenu16 (USER.157)
*/
HMENU16 WINAPI GetMenu16( HWND16 hWnd )
{
WND * wndPtr = WIN_FindWndPtr(hWnd);
if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
return (HMENU16)wndPtr->wIDmenu;
return 0;
}
/**********************************************************************
* GetMenu32 (USER32.256)
*/
HMENU32 WINAPI GetMenu32( HWND32 hWnd )
{
WND * wndPtr = WIN_FindWndPtr(hWnd);
if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
return (HMENU32)wndPtr->wIDmenu;
return 0;
}
/**********************************************************************
* SetMenu16 (USER.158)
*/
BOOL16 WINAPI SetMenu16( HWND16 hWnd, HMENU16 hMenu )
{
return SetMenu32( hWnd, hMenu );
}
/**********************************************************************
* SetMenu32 (USER32.486)
*/
BOOL32 WINAPI SetMenu32( HWND32 hWnd, HMENU32 hMenu )
{
WND * wndPtr = WIN_FindWndPtr(hWnd);
TRACE(menu,"(%04x, %04x);\n", hWnd, hMenu);
if (wndPtr && !(wndPtr->dwStyle & WS_CHILD))
{
if (GetCapture32() == hWnd) ReleaseCapture();
wndPtr->wIDmenu = (UINT32)hMenu;
if (hMenu != 0)
{
LPPOPUPMENU lpmenu;
if (!(lpmenu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
lpmenu->hWnd = hWnd;
lpmenu->wFlags &= ~MF_POPUP; /* Can't be a popup */
lpmenu->Height = 0; /* Make sure we recalculate the size */
}
if (IsWindowVisible32(hWnd))
SetWindowPos32( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
return TRUE;
}
return FALSE;
}
/**********************************************************************
* GetSubMenu16 (USER.159)
*/
HMENU16 WINAPI GetSubMenu16( HMENU16 hMenu, INT16 nPos )
{
return GetSubMenu32( hMenu, nPos );
}
/**********************************************************************
* GetSubMenu32 (USER32.287)
*/
HMENU32 WINAPI GetSubMenu32( HMENU32 hMenu, INT32 nPos )
{
LPPOPUPMENU lppop;
if (!(lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return 0;
if ((UINT32)nPos >= lppop->nItems) return 0;
if (!(lppop->items[nPos].fType & MF_POPUP)) return 0;
return lppop->items[nPos].hSubMenu;
}
/**********************************************************************
* DrawMenuBar16 (USER.160)
*/
void WINAPI DrawMenuBar16( HWND16 hWnd )
{
DrawMenuBar32( hWnd );
}
/**********************************************************************
* DrawMenuBar32 (USER32.160)
*/
BOOL32 WINAPI DrawMenuBar32( HWND32 hWnd )
{
LPPOPUPMENU lppop;
WND *wndPtr = WIN_FindWndPtr(hWnd);
if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && wndPtr->wIDmenu)
{
lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR((HMENU16)wndPtr->wIDmenu);
if (lppop == NULL) return FALSE;
lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
SetWindowPos32( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
return TRUE;
}
return FALSE;
}
/***********************************************************************
* EndMenu (USER.187) (USER32.174)
*/
void WINAPI EndMenu(void)
{
fEndMenu = TRUE;
}
/***********************************************************************
* LookupMenuHandle (USER.217)
*/
HMENU16 WINAPI LookupMenuHandle( HMENU16 hmenu, INT16 id )
{
HMENU32 hmenu32 = hmenu;
INT32 id32 = id;
if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
else return hmenu32;
}
/**********************************************************************
* LoadMenu16 (USER.150)
*/
HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, SEGPTR name )
{
HRSRC16 hRsrc;
HGLOBAL16 handle;
HMENU16 hMenu;
if (HIWORD(name))
{
char *str = (char *)PTR_SEG_TO_LIN( name );
TRACE(menu, "(%04x,'%s')\n", instance, str );
if (str[0] == '#') name = (SEGPTR)atoi( str + 1 );
}
else
TRACE(resource,"(%04x,%04x)\n",instance,LOWORD(name));
if (!name) return 0;
/* check for Win32 module */
if (HIWORD(instance))
return LoadMenu32A(instance,PTR_SEG_TO_LIN(name));
instance = GetExePtr( instance );
if (!(hRsrc = FindResource16( instance, name, RT_MENU ))) return 0;
if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
hMenu = LoadMenuIndirect16(LockResource16(handle));
FreeResource16( handle );
return hMenu;
}
/*****************************************************************
* LoadMenu32A (USER32.370)
*/
HMENU32 WINAPI LoadMenu32A( HINSTANCE32 instance, LPCSTR name )
{
HRSRC32 hrsrc = FindResource32A( instance, name, (LPSTR)RT_MENU );
if (!hrsrc) return 0;
return LoadMenuIndirect32A( (LPCVOID)LoadResource32( instance, hrsrc ));
}
/*****************************************************************
* LoadMenu32W (USER32.372)
*/
HMENU32 WINAPI LoadMenu32W( HINSTANCE32 instance, LPCWSTR name )
{
HRSRC32 hrsrc = FindResource32W( instance, name, (LPWSTR)RT_MENU );
if (!hrsrc) return 0;
return LoadMenuIndirect32W( (LPCVOID)LoadResource32( instance, hrsrc ));
}
/**********************************************************************
* LoadMenuIndirect16 (USER.220)
*/
HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
{
HMENU16 hMenu;
WORD version, offset;
LPCSTR p = (LPCSTR)template;
TRACE(menu,"(%p)\n", template );
version = GET_WORD(p);
p += sizeof(WORD);
if (version)
{
WARN(menu, "version must be 0 for Win16\n" );
return 0;
}
offset = GET_WORD(p);
p += sizeof(WORD) + offset;
if (!(hMenu = CreateMenu32())) return 0;
if (!MENU_ParseResource( p, hMenu, FALSE ))
{
DestroyMenu32( hMenu );
return 0;
}
return hMenu;
}
/**********************************************************************
* LoadMenuIndirect32A (USER32.370)
*/
HMENU32 WINAPI LoadMenuIndirect32A( LPCVOID template )
{
HMENU16 hMenu;
WORD version, offset;
LPCSTR p = (LPCSTR)template;
TRACE(menu,"%p\n", template );
version = GET_WORD(p);
p += sizeof(WORD);
switch (version)
{
case 0:
offset = GET_WORD(p);
p += sizeof(WORD) + offset;
if (!(hMenu = CreateMenu32())) return 0;
if (!MENU_ParseResource( p, hMenu, TRUE ))
{
DestroyMenu32( hMenu );
return 0;
}
return hMenu;
case 1:
offset = GET_WORD(p);
p += sizeof(WORD) + offset;
if (!(hMenu = CreateMenu32())) return 0;
if (!MENUEX_ParseResource( p, hMenu))
{
DestroyMenu32( hMenu );
return 0;
}
return hMenu;
default:
ERR(menu, "version %d not supported.\n", version);
return 0;
}
}
/**********************************************************************
* LoadMenuIndirect32W (USER32.371)
*/
HMENU32 WINAPI LoadMenuIndirect32W( LPCVOID template )
{
/* FIXME: is there anything different between A and W? */
return LoadMenuIndirect32A( template );
}
/**********************************************************************
* IsMenu16 (USER.358)
*/
BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
{
LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
return IS_A_MENU(menu);
}
/**********************************************************************
* IsMenu32 (USER32.345)
*/
BOOL32 WINAPI IsMenu32(HMENU32 hmenu)
{
LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu);
return IS_A_MENU(menu);
}
/**********************************************************************
* GetMenuItemInfo32_common
*/
static BOOL32 GetMenuItemInfo32_common ( HMENU32 hmenu, UINT32 item,
BOOL32 bypos,
LPMENUITEMINFO32A lpmii,
BOOL32 unicode)
{
MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos);
debug_print_menuitem("GetMenuItemInfo32_common: ", menu, "");
if (!menu)
return FALSE;
if (lpmii->fMask & MIIM_TYPE) {
lpmii->fType = menu->fType;
switch (MENU_ITEM_TYPE(menu->fType)) {
case MF_STRING:
if (menu->text && lpmii->dwTypeData && lpmii->cch) {
if (unicode)
lstrcpynAtoW((LPWSTR) lpmii->dwTypeData,
menu->text,
lpmii->cch);
else
lstrcpyn32A(lpmii->dwTypeData,
menu->text,
lpmii->cch);
}
break;
case MF_OWNERDRAW:
case MF_BITMAP:
lpmii->dwTypeData = menu->text;
break;
default:
break;
}
}
if (lpmii->fMask & MIIM_STATE)
lpmii->fState = menu->fState;
if (lpmii->fMask & MIIM_ID)
lpmii->wID = menu->wID;
if (lpmii->fMask & MIIM_SUBMENU)
lpmii->hSubMenu = menu->hSubMenu;
if (lpmii->fMask & MIIM_CHECKMARKS) {
lpmii->hbmpChecked = menu->hCheckBit;
lpmii->hbmpUnchecked = menu->hUnCheckBit;
}
if (lpmii->fMask & MIIM_DATA)
lpmii->dwItemData = menu->dwItemData;
return TRUE;
}
/**********************************************************************
* GetMenuItemInfo32A (USER32.263)
*/
BOOL32 WINAPI GetMenuItemInfo32A( HMENU32 hmenu, UINT32 item, BOOL32 bypos,
LPMENUITEMINFO32A lpmii)
{
return GetMenuItemInfo32_common (hmenu, item, bypos, lpmii, FALSE);
}
/**********************************************************************
* GetMenuItemInfo32W (USER32.264)
*/
BOOL32 WINAPI GetMenuItemInfo32W( HMENU32 hmenu, UINT32 item, BOOL32 bypos,
LPMENUITEMINFO32W lpmii)
{
return GetMenuItemInfo32_common (hmenu, item, bypos,
(LPMENUITEMINFO32A)lpmii, TRUE);
}
/**********************************************************************
* SetMenuItemInfo32_common
*/
static BOOL32 SetMenuItemInfo32_common(MENUITEM * menu,
const MENUITEMINFO32A *lpmii,
BOOL32 unicode)
{
if (!menu) return FALSE;
if (lpmii->fMask & MIIM_TYPE) {
/* Get rid of old string. */
if (IS_STRING_ITEM(menu->fType) && menu->text)
HeapFree(SystemHeap, 0, menu->text);
menu->fType = lpmii->fType;
menu->text = lpmii->dwTypeData;
if (IS_STRING_ITEM(menu->fType) && menu->text) {
menu->text =
unicode
? HEAP_strdupWtoA(SystemHeap, 0,
(LPWSTR) lpmii->dwTypeData)
: HEAP_strdupA(SystemHeap, 0, lpmii->dwTypeData);
}
}
if (lpmii->fMask & MIIM_STATE)
menu->fState = lpmii->fState;
if (lpmii->fMask & MIIM_ID)
menu->wID = lpmii->wID;
if (lpmii->fMask & MIIM_SUBMENU)
menu->hSubMenu = lpmii->hSubMenu;
if (lpmii->fMask & MIIM_CHECKMARKS)
{
menu->hCheckBit = lpmii->hbmpChecked;
menu->hUnCheckBit = lpmii->hbmpUnchecked;
}
if (lpmii->fMask & MIIM_DATA)
menu->dwItemData = lpmii->dwItemData;
debug_print_menuitem("SetMenuItemInfo32_common: ", menu, "");
return TRUE;
}
/**********************************************************************
* SetMenuItemInfo32A (USER32.490)
*/
BOOL32 WINAPI SetMenuItemInfo32A(HMENU32 hmenu, UINT32 item, BOOL32 bypos,
const MENUITEMINFO32A *lpmii)
{
return SetMenuItemInfo32_common(MENU_FindItem(&hmenu, &item, bypos),
lpmii, FALSE);
}
/**********************************************************************
* SetMenuItemInfo32W (USER32.491)
*/
BOOL32 WINAPI SetMenuItemInfo32W(HMENU32 hmenu, UINT32 item, BOOL32 bypos,
const MENUITEMINFO32W *lpmii)
{
return SetMenuItemInfo32_common(MENU_FindItem(&hmenu, &item, bypos),
(const MENUITEMINFO32A*)lpmii, TRUE);
}
/**********************************************************************
* SetMenuDefaultItem32 (USER32.488)
*/
BOOL32 WINAPI SetMenuDefaultItem32(HMENU32 hmenu, UINT32 item, BOOL32 bypos)
{
MENUITEM *menu = MENU_FindItem(&hmenu, &item, bypos);
if (!menu) return FALSE;
debug_print_menuitem("SetMenuDefaultItem32: ", menu, "");
FIXME(menu, "(0x%x,%d,%d), empty stub!\n",
hmenu, item, bypos);
return TRUE;
}
/*******************************************************************
* InsertMenuItem16 (USER.441)
*
* FIXME: untested
*/
BOOL16 WINAPI InsertMenuItem16( HMENU16 hmenu, UINT16 pos, BOOL16 byposition,
const MENUITEMINFO16 *mii )
{
MENUITEMINFO32A miia;
miia.cbSize = sizeof(miia);
miia.fMask = mii->fMask;
miia.dwTypeData = mii->dwTypeData;
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))
miia.dwTypeData = PTR_SEG_TO_LIN(miia.dwTypeData);
return InsertMenuItem32A( hmenu, pos, byposition, &miia );
}
/**********************************************************************
* InsertMenuItem32A (USER32.322)
*/
BOOL32 WINAPI InsertMenuItem32A(HMENU32 hMenu, UINT32 uItem, BOOL32 bypos,
const MENUITEMINFO32A *lpmii)
{
MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
return SetMenuItemInfo32_common(item, lpmii, FALSE);
}
/**********************************************************************
* InsertMenuItem32W (USER32.323)
*/
BOOL32 WINAPI InsertMenuItem32W(HMENU32 hMenu, UINT32 uItem, BOOL32 bypos,
const MENUITEMINFO32W *lpmii)
{
MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
return SetMenuItemInfo32_common(item, (const MENUITEMINFO32A*)lpmii, TRUE);
}
/**********************************************************************
* CheckMenuRadioItem32 (USER32.47)
*/
BOOL32 WINAPI CheckMenuRadioItem32(HMENU32 hMenu,
UINT32 first, UINT32 last, UINT32 check,
BOOL32 bypos)
{
MENUITEM *mifirst, *milast, *micheck;
HMENU32 mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
TRACE(menu, "ox%x: %d-%d, check %d, bypos=%d\n",
hMenu, first, last, check, bypos);
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;
}
/**********************************************************************
* CheckMenuRadioItem16 (not a Windows API)
*/
BOOL16 WINAPI CheckMenuRadioItem16(HMENU16 hMenu,
UINT16 first, UINT16 last, UINT16 check,
BOOL16 bypos)
{
return CheckMenuRadioItem32 (hMenu, first, last, check, bypos);
}
/**********************************************************************
* GetMenuItemRect32 (USER32.266)
*/
BOOL32 WINAPI GetMenuItemRect32 (HWND32 hwnd, HMENU32 hMenu, UINT32 uItem,
LPRECT32 rect)
{
RECT32 saverect, clientrect;
BOOL32 barp;
HDC32 hdc;
WND *wndPtr;
MENUITEM *item;
HMENU32 orghMenu = hMenu;
TRACE(menu, "(0x%x,0x%x,%d,%p)\n",
hwnd, hMenu, uItem, rect);
item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
wndPtr = WIN_FindWndPtr (hwnd);
if (!rect || !item || !wndPtr) return FALSE;
GetClientRect32( hwnd, &clientrect );
hdc = GetDCEx32( hwnd, 0, DCX_CACHE | DCX_WINDOW );
barp = (hMenu == orghMenu);
saverect = item->rect;
MENU_CalcItemSize (hdc, item, hwnd,
clientrect.left, clientrect.top, barp);
*rect = item->rect;
item->rect = saverect;
ReleaseDC32( hwnd, hdc );
return TRUE;
}
/**********************************************************************
* GetMenuItemRect16 (USER.665)
*/
BOOL16 WINAPI GetMenuItemRect16 (HWND16 hwnd, HMENU16 hMenu, UINT16 uItem,
LPRECT16 rect)
{
RECT32 r32;
BOOL32 res;
if (!rect) return FALSE;
res = GetMenuItemRect32 (hwnd, hMenu, uItem, &r32);
CONV_RECT32TO16 (&r32, rect);
return res;
}