Sun Jan 14 13:45:22 1996 Alexandre Julliard <julliard@sunsite.unc.edu> * [configure.in] Added check for gcc strength-reduce bug. * [controls/listbox.c] Changed ListBoxDirectory() to use the new DOS file functions. * [controls/menu.c] Fixed parameters for DeleteMenu() call in ChangeMenu(). * [debugger/stack.c] Also display current frame in back-trace. * [files/directory.c] [files/dos_fs.c] [files/drive.c] [files/file.c] Complete rewrite of the DOS file handling. Implemented per-task file handles. Removed default Z: drive; needs to be put explicitely in wine.ini if desired. * [loader/module.c] Fixed file descriptor leak in LoadModule(). * [loader/task.c] Initialise PDB file handle table in TASK_CreateTask(). Close file handles on task termination. Implemented SetErrorMode(). * [misc/network.c] Fixed WNetGetConnection() to use GetDriveType(). * [misc/xmalloc.c] Added function xstrdup(). * [miscemu/int21.c] Many changes for new DOS file functions. * [miscemu/interrupts.c] Moved DOS_GetEquipment() function into INT_Int11Handler(). * [windows/win.c] Bug fix: create system menu before sending WM_NCCREATE. * [*/*.c] Replaced strcasecmp and strncasecmp by lstrcmpi and lstrncmpi for better portability. Sat Jan 13 16:13:02 1996 Jim Peterson <jspeter@birch.ee.vt.edu> * [include/wintypes.h] Added 'typedef HGLOBAL GOBALHANDLE;'. This is not precisely in line with the true windows 'typedef HANDLE GLOBALHANDLE;', but I believe it should suffice. * [include/winsock.h] Added '#include <arpa/inet.h>' for various declarations. '#ifdef'-ed out some old style internet address #define's. * [loader/task.c] Made MakeProcInstance() return first parameter #ifdef WINELIB32. Made FreeProcInstance() do nothing #ifdef WINELIB32. '#ifdef'-ed out TASK_AllocThunk(), as it was unused in WINELIB32. * [library/miscstubs.c] Made GetWndProcEntry16() return ACTIVATEAPP_callback() when called with name="ActivateAppProc". This hardly seems correct, but it's my best guess as to how the emulator responds. Sat Jan 6 17:57:45 1996 Martin von Loewis <loewis@informatik.hu-berlin.de> * [if1632/kernel32.spec][win32/process.c] WIN32_GetProcAddress, LoadLibraryA: new functions * [if1632/relay32.c] RELAY32_GetEntryPoint: Removed code to load PE DLLs * [include/pe_image.h][include/pe_exe.h] struct pe_data: new fields base_addr,load_addr,vma_size,pe_reloc struct PE_Reloc_Block: new structure * [loader/module.c] MODULE_RegisterModule: new function * [loader/pe_image.c] PE_FindExportedFunction,PE_GetProcAddress: new functions fixup_imports: expect struct w_files* now, fill dlls_to_init, load PE DLLs do_relocations: new functions calc_vma_size: renamed from dump_table PE_LoadImage: use malloc to allocate memory for image PE_InitDLL: expect HMODULE PE_InitializeDLLs: new function * [loader/task.c] NE_InitializeDLLs: branch to PE_InitializeDLLs for PE modules GetExePtr: Accept PE modules * [misc/commdlg.c] FILEDLG_WMCommand: unpack WIN32 WM_COMMAND appropriately for WineLib Thu Jan 4 11:36:21 1996 Manfred Weichel <Manfred.Weichel@mch.sni.de> * [misc/port.c] New file with usleep() function for SVR4. * [configure.in] Check for usleep() function. Tue Jan 02 14:00:00 1996 Anand Kumria <akumria@ozemail.com.au> * [if1632/toolhelp.spec] [include/toolhelp.h] [misc/user.c] [windows/message.c] Implement TOOLHELP.80 TimerCount. Fix GetTickCount. * [winsocket.c] Fixed ENOENT error. * [miscemu/dpmi.c] Implement DPMI Get Page Size (AX=0604, INT 31) * [memory/global.c] Implement TOOLHELP.72 GetMemManInfo. Mon Jan 2 10:33:00 1996 Thomas Sandford <t.d.g.sandford@prds-grn.demon.co.uk> * [if1632/callback.c] CallWindowProc() - When calling RELAY32_CallWindowProc, check whether lParam should be a SEGPTR, and if so convert it to one. * [if1632/gdi.spec] [if1632/kernel32.spec] [if1632/user32.spec] Numerous functions added, mostly calls to original (win16) functions. Note that some (many) of these are probably not strictly correct, but with these additions freecell will at least display its main window though it is garbled. * [if1632/winprocs.spec] Completely rewritten - all WndProcs now have win32 versions to help with the lparam SEGPTR fix in callback.c * [include/kernel32.h] LPTCSTR defined. * [include/peexe.h] Definition of PE_Export_Directory amended. * [include/resource32.h] New file. * [include/stackframe.h] Definition of MAKE_SEGPTR macro #ifdef'd out and replaced with prototype for replacement function in memory/selector.c which can operate on any given memory address. This is currently required for win32 support. It is a dreadful cludge, and will certainly slow down other programs. If you are not interested in win32 development you may wish to reverse this patch. * [include/windows.h] Definition of SW_SHOWDEFAULT added. * [loader/pe_image.c] Extensive rewrites of xmmap() fixup_imports(). PE_LoadImage() - initialisation of bss added, extraction of module name fixed, initialisation of DLL added. PE_InitDLL() - now does something. PE_Win32CallToStart() - initialisation of TEB pointed to by fs added. PE_InitTEB() created to perform TEB initialisation. * [memory/selector.c] New function MAKE_SEGPTR() - see include/stackframe.h above. * [misc/user32.c] USER32_RegisterClassA(), CreateWindowExA() memory allocation method changed. This is probably now unnecessary with the new MAKE_SEGPTR handling code. USER32_DefWndProcA() removed to win32/winprocs.c USER32_TranslateMessage added. * [tools/build.c] handling of win32 spec files changed to support gcc2.6.X this requires optimisations to be disabled. * [win32/resource.c] [win32/newfns.c] [win32/heap.c] [win32/winprocs.c] New files. * [win32/Makefile.in] New files heap.c, newfns.c, resource.c and winprocs.c added to build. * [win32/file.c] New function W32_SetHandleCount. * [win32/init.c] WIN32_GetModuleHandle() - now returns handle of running process if called with NULL. GetStartupInfoA() - set cbReserved2 to 0. * [win32/memory.c] VirtualAlloc() - set mmap() file parameter to -1 instead of 0 to make it work with FreeBSD. Also check for return value. Removed extra return. * [windows/winpos.c] ShowWindow() - SW_SHOWDEFAULT handling kludged in.
2257 lines
65 KiB
C
2257 lines
65 KiB
C
/*
|
|
* Menu functions
|
|
*
|
|
* Copyright 1993 Martin Ayotte
|
|
* Copyright 1994 Alexandre Julliard
|
|
*/
|
|
|
|
/*
|
|
* 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 <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "windows.h"
|
|
#include "syscolor.h"
|
|
#include "sysmetrics.h"
|
|
#include "menu.h"
|
|
#include "user.h"
|
|
#include "win.h"
|
|
#include "message.h"
|
|
#include "graphics.h"
|
|
#include "resource.h"
|
|
#include "stddebug.h"
|
|
#include "debug.h"
|
|
|
|
/* 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;
|
|
|
|
/* Flag set by EndMenu() to force an exit from menu tracking */
|
|
static BOOL fEndMenuCalled = FALSE;
|
|
|
|
/* Space between 2 menu bar items */
|
|
#define MENU_BAR_ITEMS_SPACE 16
|
|
|
|
/* Minimum width of a tab character */
|
|
#define MENU_TAB_SPACE 8
|
|
|
|
/* Height of a separator item */
|
|
#define SEPARATOR_HEIGHT 5
|
|
|
|
/* Values for menu->FocusedItem */
|
|
/* (other values give the position of the focused item) */
|
|
#define NO_SELECTED_ITEM 0xffff
|
|
#define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
|
|
|
|
#define IS_STRING_ITEM(flags) (!((flags) & (MF_BITMAP | MF_OWNERDRAW | \
|
|
MF_MENUBARBREAK | MF_MENUBREAK | MF_SEPARATOR)))
|
|
|
|
|
|
extern void NC_DrawSysButton(HWND hwnd, HDC hdc, BOOL down); /* nonclient.c */
|
|
|
|
static HBITMAP hStdCheck = 0;
|
|
static HBITMAP hStdMnArrow = 0;
|
|
|
|
WORD * ParseMenuResource(WORD *first_item, int level, HMENU hMenu);
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_Init
|
|
*
|
|
* Menus initialisation.
|
|
*/
|
|
BOOL MENU_Init()
|
|
{
|
|
BITMAP bm;
|
|
|
|
/* Load bitmaps */
|
|
|
|
if (!(hStdCheck = LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECK) )))
|
|
return FALSE;
|
|
GetObject( hStdCheck, sizeof(BITMAP), (LPSTR)&bm );
|
|
check_bitmap_width = bm.bmWidth;
|
|
check_bitmap_height = bm.bmHeight;
|
|
if (!(hStdMnArrow = LoadBitmap( 0, MAKEINTRESOURCE(OBM_MNARROW) )))
|
|
return FALSE;
|
|
GetObject( hStdMnArrow, sizeof(BITMAP), (LPSTR)&bm );
|
|
arrow_bitmap_width = bm.bmWidth;
|
|
arrow_bitmap_height = bm.bmHeight;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_HasSysMenu
|
|
*
|
|
* Check whether the window owning the menu bar has a system menu.
|
|
*/
|
|
static BOOL MENU_HasSysMenu( POPUPMENU *menu )
|
|
{
|
|
WND *wndPtr;
|
|
|
|
if (menu->wFlags & MF_POPUP) return FALSE;
|
|
if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
|
|
return (wndPtr->dwStyle & WS_SYSMENU) != 0;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* MENU_CopySysMenu
|
|
*/
|
|
static HMENU MENU_CopySysMenu(void)
|
|
{
|
|
HMENU hMenu;
|
|
HGLOBAL handle;
|
|
POPUPMENU *menu;
|
|
|
|
if (!(handle = SYSRES_LoadResource( SYSRES_MENU_SYSMENU ))) return 0;
|
|
hMenu = LoadMenuIndirect( GlobalLock( handle ) );
|
|
SYSRES_FreeResource( handle );
|
|
if (!hMenu)
|
|
{
|
|
dprintf_menu(stddeb,"No SYSMENU\n");
|
|
return 0;
|
|
}
|
|
menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
|
|
menu->wFlags |= MF_SYSMENU | MF_POPUP;
|
|
dprintf_menu(stddeb,"CopySysMenu hMenu="NPFMT" !\n", hMenu);
|
|
return hMenu;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_IsInSysMenu
|
|
*
|
|
* Check whether the point (in screen coords) is in the system menu
|
|
* of the window owning the given menu.
|
|
*/
|
|
static BOOL MENU_IsInSysMenu( POPUPMENU *menu, POINT pt )
|
|
{
|
|
WND *wndPtr;
|
|
|
|
if (menu->wFlags & MF_POPUP) return FALSE;
|
|
if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
|
|
if (!(wndPtr->dwStyle & WS_SYSMENU)) return FALSE;
|
|
if ((pt.x < wndPtr->rectClient.left) ||
|
|
(pt.x >= wndPtr->rectClient.left+SYSMETRICS_CXSIZE+SYSMETRICS_CXBORDER))
|
|
return FALSE;
|
|
if ((pt.y >= wndPtr->rectClient.top - menu->Height) ||
|
|
(pt.y < wndPtr->rectClient.top - menu->Height -
|
|
SYSMETRICS_CYSIZE - SYSMETRICS_CYBORDER)) return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* 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( HMENU *hmenu, UINT *nPos, UINT wFlags )
|
|
{
|
|
POPUPMENU *menu;
|
|
MENUITEM *item;
|
|
int i;
|
|
|
|
if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(*hmenu))) return NULL;
|
|
item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
|
|
if (wFlags & MF_BYPOSITION)
|
|
{
|
|
if (*nPos >= menu->nItems) return NULL;
|
|
return &item[*nPos];
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < menu->nItems; i++, item++)
|
|
{
|
|
if (item->item_id == *nPos)
|
|
{
|
|
*nPos = i;
|
|
return item;
|
|
}
|
|
else if (item->item_flags & MF_POPUP)
|
|
{
|
|
HMENU hsubmenu = (HMENU)item->item_id;
|
|
MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
|
|
if (subitem)
|
|
{
|
|
*hmenu = hsubmenu;
|
|
return subitem;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_FindItemByCoords
|
|
*
|
|
* Find the item at the specified coordinates (screen coords).
|
|
*/
|
|
static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu, int x, int y, UINT *pos )
|
|
{
|
|
MENUITEM *item;
|
|
WND *wndPtr;
|
|
int i;
|
|
|
|
if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return NULL;
|
|
x -= wndPtr->rectWindow.left;
|
|
y -= wndPtr->rectWindow.top;
|
|
item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
|
|
for (i = 0; i < menu->nItems; i++, item++)
|
|
{
|
|
if ((x >= item->rect.left) && (x < item->rect.right) &&
|
|
(y >= item->rect.top) && (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 UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu, UINT key )
|
|
{
|
|
POPUPMENU *menu;
|
|
LPMENUITEM lpitem;
|
|
int i;
|
|
LONG menuchar;
|
|
|
|
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
lpitem = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
|
|
key = toupper(key);
|
|
for (i = 0; i < menu->nItems; i++, lpitem++)
|
|
{
|
|
if (IS_STRING_ITEM(lpitem->item_flags))
|
|
{
|
|
char *p = strchr( lpitem->item_text, '&' );
|
|
if (p && (p[1] != '&') && (toupper(p[1]) == key)) return i;
|
|
}
|
|
}
|
|
#ifdef WINELIB32
|
|
menuchar = SendMessage( hwndOwner, WM_MENUCHAR,
|
|
MAKEWPARAM(key,menu->wFlags), (LPARAM)hmenu );
|
|
#else
|
|
menuchar = SendMessage( hwndOwner, WM_MENUCHAR, key,
|
|
MAKELONG( menu->wFlags, hmenu ) );
|
|
#endif
|
|
if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
|
|
if (HIWORD(menuchar) == 1) return -2;
|
|
return -1;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_CalcItemSize
|
|
*
|
|
* Calculate the size of the menu item and store it in lpitem->rect.
|
|
*/
|
|
static void MENU_CalcItemSize( HDC hdc, LPMENUITEM lpitem, HWND hwndOwner,
|
|
int orgX, int orgY, BOOL menuBar )
|
|
{
|
|
DWORD dwSize;
|
|
char *p;
|
|
|
|
SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
|
|
lpitem->xTab = 0;
|
|
if (lpitem->item_flags & MF_OWNERDRAW) {
|
|
static HANDLE mistrh = 0;
|
|
static SEGPTR mistrsegp = 0;
|
|
static LPMEASUREITEMSTRUCT mistruct=NULL;
|
|
if (mistruct == NULL) {
|
|
mistrh = GlobalAlloc(0,sizeof(MEASUREITEMSTRUCT));
|
|
mistrsegp = (SEGPTR)WIN16_GlobalLock(mistrh);
|
|
mistruct = PTR_SEG_TO_LIN(mistrsegp);
|
|
}
|
|
mistruct->CtlType = ODT_MENU;
|
|
mistruct->itemID = lpitem->item_id;
|
|
mistruct->itemData = (long int)lpitem->item_text;
|
|
mistruct->itemHeight = 16;
|
|
mistruct->itemWidth = 30;
|
|
SendMessage(hwndOwner,WM_MEASUREITEM,0,(LPARAM)mistrsegp);
|
|
lpitem->rect.bottom += mistruct->itemHeight;
|
|
lpitem->rect.right += mistruct->itemWidth;
|
|
dprintf_menu(stddeb,"DrawMenuItem: MeasureItem %04x %d:%d!\n",
|
|
lpitem->item_id,mistruct->itemWidth, mistruct->itemHeight);
|
|
return;
|
|
}
|
|
|
|
if (lpitem->item_flags & MF_SEPARATOR)
|
|
{
|
|
lpitem->rect.bottom += SEPARATOR_HEIGHT;
|
|
return;
|
|
}
|
|
|
|
if (!menuBar)
|
|
{
|
|
lpitem->rect.right += 2 * check_bitmap_width;
|
|
if (lpitem->item_flags & MF_POPUP)
|
|
lpitem->rect.right += arrow_bitmap_width;
|
|
}
|
|
|
|
if (lpitem->item_flags & MF_BITMAP)
|
|
{
|
|
BITMAP bm;
|
|
GetObject( (HBITMAP)lpitem->hText, sizeof(BITMAP), (LPSTR)&bm );
|
|
lpitem->rect.right += bm.bmWidth;
|
|
lpitem->rect.bottom += bm.bmHeight;
|
|
return;
|
|
}
|
|
|
|
/* If we get here, then it is a text item */
|
|
|
|
dwSize = (lpitem->item_text == NULL) ? 0 : GetTextExtent( hdc, lpitem->item_text, strlen(lpitem->item_text));
|
|
lpitem->rect.right += LOWORD(dwSize);
|
|
lpitem->rect.bottom += MAX( HIWORD(dwSize), SYSMETRICS_CYMENU );
|
|
|
|
if (menuBar) lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
|
|
else if ( ( lpitem->item_text != NULL ) && (p = strchr( lpitem->item_text, '\t' )) != NULL)
|
|
{
|
|
/* Item contains a tab (only meaningful in popup menus) */
|
|
lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE +
|
|
LOWORD( GetTextExtent( hdc, lpitem->item_text,
|
|
(int)(p - lpitem->item_text) ));
|
|
lpitem->rect.right += MENU_TAB_SPACE;
|
|
}
|
|
else
|
|
{
|
|
if( ( lpitem->item_text != NULL ) && strchr( lpitem->item_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, HWND hwndOwner )
|
|
{
|
|
LPMENUITEM items, lpitem;
|
|
HDC hdc;
|
|
int start, i;
|
|
int orgX, orgY, maxX, maxTab, maxTabWidth;
|
|
|
|
lppop->Width = lppop->Height = 0;
|
|
if (lppop->nItems == 0) return;
|
|
items = (MENUITEM *)USER_HEAP_LIN_ADDR( lppop->hItems );
|
|
hdc = GetDC( 0 );
|
|
maxX = start = 0;
|
|
while (start < lppop->nItems)
|
|
{
|
|
lpitem = &items[start];
|
|
orgX = maxX;
|
|
orgY = 0;
|
|
maxTab = maxTabWidth = 0;
|
|
|
|
/* Parse items until column break or end of menu */
|
|
for (i = start; i < lppop->nItems; i++, lpitem++)
|
|
{
|
|
if ((i != start) &&
|
|
(lpitem->item_flags & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
|
|
MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
|
|
if (lpitem->item_flags & MF_MENUBARBREAK) orgX++;
|
|
maxX = MAX( maxX, lpitem->rect.right );
|
|
orgY = lpitem->rect.bottom;
|
|
if (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 = &items[start]; start < i; start++, lpitem++)
|
|
{
|
|
lpitem->rect.right = maxX;
|
|
if (lpitem->xTab) lpitem->xTab = maxTab;
|
|
}
|
|
lppop->Height = MAX( lppop->Height, orgY );
|
|
}
|
|
|
|
lppop->Width = maxX;
|
|
ReleaseDC( 0, hdc );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_MenuBarCalcSize
|
|
*
|
|
* Calculate the size of the menu bar.
|
|
*/
|
|
static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, LPPOPUPMENU lppop,
|
|
HWND hwndOwner )
|
|
{
|
|
LPMENUITEM lpitem, items;
|
|
int start, i, orgX, orgY, maxY, helpPos;
|
|
|
|
if ((lprect == NULL) || (lppop == NULL)) return;
|
|
if (lppop->nItems == 0) return;
|
|
dprintf_menucalc(stddeb,"MenuBarCalcSize left=%ld top=%ld right=%ld bottom=%ld !\n",
|
|
(LONG)lprect->left, (LONG)lprect->top, (LONG)lprect->right, (LONG)lprect->bottom);
|
|
items = (MENUITEM *)USER_HEAP_LIN_ADDR( lppop->hItems );
|
|
lppop->Width = lprect->right - lprect->left;
|
|
lppop->Height = 0;
|
|
maxY = lprect->top;
|
|
start = 0;
|
|
helpPos = -1;
|
|
while (start < lppop->nItems)
|
|
{
|
|
lpitem = &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->item_flags & MF_HELP)) helpPos = i;
|
|
if ((i != start) &&
|
|
(lpitem->item_flags & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
|
|
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) 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 = &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( HWND hwnd, HDC hdc, LPMENUITEM lpitem,
|
|
UINT height, BOOL menuBar )
|
|
{
|
|
RECT rect;
|
|
|
|
if (lpitem->item_flags & MF_OWNERDRAW) {
|
|
static HANDLE distrh = 0;
|
|
static SEGPTR distrsegp = 0;
|
|
static LPDRAWITEMSTRUCT distruct=NULL;
|
|
if (distruct == NULL) {
|
|
distrh = GlobalAlloc(0,sizeof(DRAWITEMSTRUCT));
|
|
distrsegp = (SEGPTR)WIN16_GlobalLock(distrh);
|
|
distruct = PTR_SEG_TO_LIN(distrsegp);
|
|
}
|
|
dprintf_menu(stddeb,"DrawMenuItem: Ownerdraw!\n");
|
|
distruct->CtlType = ODT_MENU;
|
|
distruct->itemID = lpitem->item_id;
|
|
distruct->itemData = (long int)lpitem->item_text;
|
|
distruct->itemState = 0;
|
|
if (lpitem->item_flags & MF_CHECKED) distruct->itemState |= ODS_CHECKED;
|
|
if (lpitem->item_flags & MF_GRAYED) distruct->itemState |= ODS_GRAYED;
|
|
if (lpitem->item_flags & MF_HILITE) distruct->itemState |= ODS_SELECTED;
|
|
distruct->itemAction = ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS;
|
|
distruct->hwndItem = hwnd;
|
|
distruct->hDC = hdc;
|
|
distruct->rcItem = lpitem->rect;
|
|
SendMessage(hwnd,WM_DRAWITEM,0,(LPARAM)distrsegp);
|
|
return;
|
|
}
|
|
if (menuBar && (lpitem->item_flags & MF_SEPARATOR)) return;
|
|
rect = lpitem->rect;
|
|
|
|
/* Draw the background */
|
|
|
|
if (lpitem->item_flags & MF_HILITE)
|
|
FillRect( hdc, &rect, sysColorObjects.hbrushHighlight );
|
|
else FillRect( hdc, &rect, sysColorObjects.hbrushMenu );
|
|
SetBkMode( hdc, TRANSPARENT );
|
|
|
|
/* Draw the separator bar (if any) */
|
|
|
|
if (!menuBar && (lpitem->item_flags & MF_MENUBARBREAK))
|
|
{
|
|
SelectObject( hdc, sysColorObjects.hpenWindowFrame );
|
|
MoveTo( hdc, rect.left, 0 );
|
|
LineTo( hdc, rect.left, height );
|
|
}
|
|
if (lpitem->item_flags & MF_SEPARATOR)
|
|
{
|
|
SelectObject( hdc, sysColorObjects.hpenWindowFrame );
|
|
MoveTo( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2 );
|
|
LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
|
|
return;
|
|
}
|
|
|
|
/* Setup colors */
|
|
|
|
if (lpitem->item_flags & MF_HILITE)
|
|
{
|
|
if (lpitem->item_flags & MF_GRAYED)
|
|
SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
|
|
else
|
|
SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
|
|
SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
|
|
}
|
|
else
|
|
{
|
|
if (lpitem->item_flags & MF_GRAYED)
|
|
SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
|
|
else
|
|
SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
|
|
SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
|
|
}
|
|
|
|
if (!menuBar)
|
|
{
|
|
/* Draw the check mark */
|
|
|
|
if (lpitem->item_flags & MF_CHECKED)
|
|
{
|
|
GRAPH_DrawBitmap(hdc, lpitem->hCheckBit ? lpitem->hCheckBit :
|
|
hStdCheck, rect.left,
|
|
(rect.top+rect.bottom-check_bitmap_height) / 2,
|
|
0, 0, check_bitmap_width, check_bitmap_height );
|
|
}
|
|
else if (lpitem->hUnCheckBit != 0) /* Not checked */
|
|
{
|
|
GRAPH_DrawBitmap(hdc, lpitem->hUnCheckBit, rect.left,
|
|
(rect.top+rect.bottom-check_bitmap_height) / 2,
|
|
0, 0, check_bitmap_width, check_bitmap_height );
|
|
}
|
|
|
|
/* Draw the popup-menu arrow */
|
|
|
|
if (lpitem->item_flags & MF_POPUP)
|
|
{
|
|
GRAPH_DrawBitmap( hdc, hStdMnArrow,
|
|
rect.right-arrow_bitmap_width-1,
|
|
(rect.top+rect.bottom-arrow_bitmap_height) / 2,
|
|
0, 0, arrow_bitmap_width, arrow_bitmap_height );
|
|
}
|
|
|
|
rect.left += check_bitmap_width;
|
|
rect.right -= arrow_bitmap_width;
|
|
}
|
|
|
|
/* Draw the item text or bitmap */
|
|
|
|
if (lpitem->item_flags & MF_BITMAP)
|
|
{
|
|
GRAPH_DrawBitmap( hdc, (HBITMAP)lpitem->hText, rect.left, rect.top,
|
|
0, 0, rect.right-rect.left, rect.bottom-rect.top );
|
|
return;
|
|
}
|
|
/* No bitmap - process text if present */
|
|
else if ((lpitem->item_text) != ((char *) NULL))
|
|
{
|
|
register int i;
|
|
|
|
if (menuBar)
|
|
{
|
|
rect.left += MENU_BAR_ITEMS_SPACE / 2;
|
|
rect.right -= MENU_BAR_ITEMS_SPACE / 2;
|
|
i = strlen( lpitem->item_text );
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; lpitem->item_text[i]; i++)
|
|
if ((lpitem->item_text[i] == '\t') ||
|
|
(lpitem->item_text[i] == '\b')) break;
|
|
}
|
|
|
|
DrawText( hdc, lpitem->item_text, i, &rect,
|
|
DT_LEFT | DT_VCENTER | DT_SINGLELINE );
|
|
|
|
if (lpitem->item_text[i]) /* There's a tab or flush-right char */
|
|
{
|
|
if (lpitem->item_text[i] == '\t')
|
|
{
|
|
rect.left = lpitem->xTab;
|
|
DrawText( hdc, lpitem->item_text + i + 1, -1, &rect,
|
|
DT_LEFT | DT_VCENTER | DT_SINGLELINE );
|
|
}
|
|
else DrawText( hdc, lpitem->item_text + i + 1, -1, &rect,
|
|
DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_DrawPopupMenu
|
|
*
|
|
* Paint a popup menu.
|
|
*/
|
|
static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
|
|
{
|
|
POPUPMENU *menu;
|
|
MENUITEM *item;
|
|
RECT rect;
|
|
int i;
|
|
|
|
GetClientRect( hwnd, &rect );
|
|
FillRect( hdc, &rect, sysColorObjects.hbrushMenu );
|
|
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
if (!menu || !menu->nItems) return;
|
|
item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
|
|
for (i = menu->nItems; i > 0; i--, item++)
|
|
MENU_DrawMenuItem( hwnd, hdc, item, menu->Height, FALSE );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_DrawMenuBar
|
|
*
|
|
* Paint a menu bar. Returns the height of the menu bar.
|
|
*/
|
|
UINT MENU_DrawMenuBar(HDC hDC, LPRECT lprect, HWND hwnd, BOOL suppress_draw)
|
|
{
|
|
LPPOPUPMENU lppop;
|
|
LPMENUITEM lpitem;
|
|
int i;
|
|
WND *wndPtr = WIN_FindWndPtr( hwnd );
|
|
|
|
lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( (HMENU)wndPtr->wIDmenu );
|
|
if (lppop == NULL || lprect == NULL) return SYSMETRICS_CYMENU;
|
|
dprintf_menu(stddeb,"MENU_DrawMenuBar("NPFMT", %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;
|
|
|
|
FillRect(hDC, lprect, sysColorObjects.hbrushMenu );
|
|
SelectObject( hDC, sysColorObjects.hpenWindowFrame );
|
|
MoveTo( hDC, lprect->left, lprect->bottom );
|
|
LineTo( hDC, lprect->right, lprect->bottom );
|
|
|
|
if (lppop->nItems == 0) return SYSMETRICS_CYMENU;
|
|
lpitem = (MENUITEM *) USER_HEAP_LIN_ADDR( lppop->hItems );
|
|
for (i = 0; i < lppop->nItems; i++, lpitem++)
|
|
{
|
|
MENU_DrawMenuItem( hwnd, hDC, lpitem, lppop->Height, TRUE );
|
|
}
|
|
return lppop->Height;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_ShowPopup
|
|
*
|
|
* Display a popup menu.
|
|
*/
|
|
static BOOL MENU_ShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, int x, int y)
|
|
{
|
|
POPUPMENU *menu;
|
|
|
|
if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
|
|
if (menu->FocusedItem != NO_SELECTED_ITEM)
|
|
{
|
|
MENUITEM *item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
|
|
item[menu->FocusedItem].item_flags &= ~(MF_HILITE | MF_MOUSESELECT);
|
|
menu->FocusedItem = NO_SELECTED_ITEM;
|
|
}
|
|
SendMessage( hwndOwner, WM_INITMENUPOPUP, (WPARAM)hmenu,
|
|
MAKELONG( id, (menu->wFlags & MF_SYSMENU) ? 1 : 0 ));
|
|
MENU_PopupMenuCalcSize( menu, hwndOwner );
|
|
if (!menu->hWnd)
|
|
{
|
|
WND *wndPtr = WIN_FindWndPtr( hwndOwner );
|
|
if (!wndPtr) return FALSE;
|
|
menu->hWnd = CreateWindow( POPUPMENU_CLASS_ATOM, (SEGPTR)0,
|
|
WS_POPUP | WS_BORDER, x, y,
|
|
menu->Width + 2*SYSMETRICS_CXBORDER,
|
|
menu->Height + 2*SYSMETRICS_CYBORDER,
|
|
0, 0, wndPtr->hInstance, (SEGPTR)hmenu );
|
|
if (!menu->hWnd) return FALSE;
|
|
}
|
|
else SetWindowPos( menu->hWnd, 0, x, y,
|
|
menu->Width + 2*SYSMETRICS_CXBORDER,
|
|
menu->Height + 2*SYSMETRICS_CYBORDER,
|
|
SWP_NOACTIVATE | SWP_NOZORDER );
|
|
|
|
/* Display the window */
|
|
|
|
SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
|
|
SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
|
|
UpdateWindow( menu->hWnd );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_SelectItem
|
|
*/
|
|
static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex )
|
|
{
|
|
MENUITEM *items;
|
|
LPPOPUPMENU lppop;
|
|
HDC hdc;
|
|
|
|
lppop = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
if (!lppop->nItems) return;
|
|
items = (MENUITEM *) USER_HEAP_LIN_ADDR( lppop->hItems );
|
|
if ((wIndex != NO_SELECTED_ITEM) &&
|
|
(wIndex != SYSMENU_SELECTED) &&
|
|
(items[wIndex].item_flags & MF_SEPARATOR))
|
|
wIndex = NO_SELECTED_ITEM;
|
|
if (lppop->FocusedItem == wIndex) return;
|
|
if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
|
|
else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
|
|
|
|
/* Clear previous highlighted item */
|
|
if (lppop->FocusedItem != NO_SELECTED_ITEM)
|
|
{
|
|
if (lppop->FocusedItem == SYSMENU_SELECTED)
|
|
NC_DrawSysButton( lppop->hWnd, hdc, FALSE );
|
|
else
|
|
{
|
|
items[lppop->FocusedItem].item_flags &=~(MF_HILITE|MF_MOUSESELECT);
|
|
MENU_DrawMenuItem( lppop->hWnd, hdc, &items[lppop->FocusedItem], lppop->Height,
|
|
!(lppop->wFlags & MF_POPUP) );
|
|
}
|
|
}
|
|
|
|
/* Highlight new item (if any) */
|
|
lppop->FocusedItem = wIndex;
|
|
if (lppop->FocusedItem != NO_SELECTED_ITEM)
|
|
{
|
|
if (lppop->FocusedItem == SYSMENU_SELECTED)
|
|
{
|
|
NC_DrawSysButton( lppop->hWnd, hdc, TRUE );
|
|
#ifdef WINELIB32
|
|
/* FIX: LostInfo */
|
|
SendMessage( hwndOwner, WM_MENUSELECT,
|
|
MAKEWPARAM( (DWORD)GetSystemMenu( lppop->hWnd, FALSE ),
|
|
lppop->wFlags | MF_MOUSESELECT ),
|
|
(LPARAM)hmenu );
|
|
#else
|
|
SendMessage( hwndOwner, WM_MENUSELECT,
|
|
GetSystemMenu( lppop->hWnd, FALSE ),
|
|
MAKELONG( lppop->wFlags | MF_MOUSESELECT, hmenu ) );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
items[lppop->FocusedItem].item_flags |= MF_HILITE;
|
|
MENU_DrawMenuItem( lppop->hWnd, hdc, &items[lppop->FocusedItem], lppop->Height,
|
|
!(lppop->wFlags & MF_POPUP) );
|
|
#ifdef WINELIB32
|
|
SendMessage( hwndOwner, WM_MENUSELECT,
|
|
MAKEWPARAM( items[lppop->FocusedItem].item_id,
|
|
items[lppop->FocusedItem].item_flags |
|
|
MF_MOUSESELECT ),
|
|
(LPARAM) hmenu );
|
|
#else
|
|
SendMessage( hwndOwner, WM_MENUSELECT,
|
|
items[lppop->FocusedItem].item_id,
|
|
MAKELONG( items[lppop->FocusedItem].item_flags | MF_MOUSESELECT, hmenu));
|
|
#endif
|
|
}
|
|
}
|
|
#ifdef WINELIB32
|
|
/* FIX: Lost Info */
|
|
else SendMessage( hwndOwner, WM_MENUSELECT,
|
|
MAKEWPARAM( (DWORD)hmenu, lppop->wFlags | MF_MOUSESELECT),
|
|
(LPARAM)hmenu );
|
|
#else
|
|
else SendMessage( hwndOwner, WM_MENUSELECT, hmenu,
|
|
MAKELONG( lppop->wFlags | MF_MOUSESELECT, hmenu ) );
|
|
#endif
|
|
|
|
ReleaseDC( lppop->hWnd, hdc );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_SelectNextItem
|
|
*/
|
|
static void MENU_SelectNextItem( HWND hwndOwner, HMENU hmenu )
|
|
{
|
|
int i;
|
|
MENUITEM *items;
|
|
POPUPMENU *menu;
|
|
|
|
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
if (!menu->nItems) return;
|
|
items = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
|
|
if ((menu->FocusedItem != NO_SELECTED_ITEM) &&
|
|
(menu->FocusedItem != SYSMENU_SELECTED))
|
|
{
|
|
for (i = menu->FocusedItem+1; i < menu->nItems; i++)
|
|
{
|
|
if (!(items[i].item_flags & MF_SEPARATOR))
|
|
{
|
|
MENU_SelectItem( hwndOwner, hmenu, i );
|
|
return;
|
|
}
|
|
}
|
|
if (MENU_HasSysMenu( menu ))
|
|
{
|
|
MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED );
|
|
return;
|
|
}
|
|
}
|
|
for (i = 0; i < menu->nItems; i++)
|
|
{
|
|
if (!(items[i].item_flags & MF_SEPARATOR))
|
|
{
|
|
MENU_SelectItem( hwndOwner, hmenu, i );
|
|
return;
|
|
}
|
|
}
|
|
if (MENU_HasSysMenu( menu ))
|
|
MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_SelectPrevItem
|
|
*/
|
|
static void MENU_SelectPrevItem( HWND hwndOwner, HMENU hmenu )
|
|
{
|
|
int i;
|
|
MENUITEM *items;
|
|
POPUPMENU *menu;
|
|
|
|
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
if (!menu->nItems) return;
|
|
items = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
|
|
if ((menu->FocusedItem != NO_SELECTED_ITEM) &&
|
|
(menu->FocusedItem != SYSMENU_SELECTED))
|
|
{
|
|
for (i = menu->FocusedItem - 1; i >= 0; i--)
|
|
{
|
|
if (!(items[i].item_flags & MF_SEPARATOR))
|
|
{
|
|
MENU_SelectItem( hwndOwner, hmenu, i );
|
|
return;
|
|
}
|
|
}
|
|
if (MENU_HasSysMenu( menu ))
|
|
{
|
|
MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED );
|
|
return;
|
|
}
|
|
}
|
|
for (i = menu->nItems - 1; i > 0; i--)
|
|
{
|
|
if (!(items[i].item_flags & MF_SEPARATOR))
|
|
{
|
|
MENU_SelectItem( hwndOwner, hmenu, i );
|
|
return;
|
|
}
|
|
}
|
|
if (MENU_HasSysMenu( menu ))
|
|
MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_GetSubPopup
|
|
*
|
|
* Return the handle of the selected sub-popup menu (if any).
|
|
*/
|
|
static HMENU MENU_GetSubPopup( HMENU hmenu )
|
|
{
|
|
POPUPMENU *menu;
|
|
MENUITEM *item;
|
|
|
|
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
if (menu->FocusedItem == NO_SELECTED_ITEM) return 0;
|
|
else if (menu->FocusedItem == SYSMENU_SELECTED)
|
|
return GetSystemMenu( menu->hWnd, FALSE );
|
|
|
|
item = ((MENUITEM *)USER_HEAP_LIN_ADDR(menu->hItems)) + menu->FocusedItem;
|
|
if (!(item->item_flags & MF_POPUP) || !(item->item_flags & MF_MOUSESELECT))
|
|
return 0;
|
|
return (HMENU)item->item_id;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_HideSubPopups
|
|
*
|
|
* Hide the sub-popup menus of this menu.
|
|
*/
|
|
static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu )
|
|
{
|
|
MENUITEM *item;
|
|
POPUPMENU *menu, *submenu;
|
|
HMENU hsubmenu;
|
|
|
|
if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return;
|
|
if (menu->FocusedItem == NO_SELECTED_ITEM) return;
|
|
if (menu->FocusedItem == SYSMENU_SELECTED)
|
|
{
|
|
hsubmenu = GetSystemMenu( menu->hWnd, FALSE );
|
|
}
|
|
else
|
|
{
|
|
item = ((MENUITEM *)USER_HEAP_LIN_ADDR(menu->hItems)) + menu->FocusedItem;
|
|
if (!(item->item_flags & MF_POPUP) ||
|
|
!(item->item_flags & MF_MOUSESELECT)) return;
|
|
item->item_flags &= ~MF_MOUSESELECT;
|
|
hsubmenu = (HMENU)item->item_id;
|
|
}
|
|
submenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hsubmenu );
|
|
MENU_HideSubPopups( hwndOwner, hsubmenu );
|
|
if (submenu->hWnd) ShowWindow( submenu->hWnd, SW_HIDE );
|
|
MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* 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 HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu, BOOL selectFirst )
|
|
{
|
|
POPUPMENU *menu;
|
|
MENUITEM *item;
|
|
WND *wndPtr;
|
|
|
|
if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return hmenu;
|
|
if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return hmenu;
|
|
if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
|
|
if (menu->FocusedItem == SYSMENU_SELECTED)
|
|
{
|
|
MENU_ShowPopup(hwndOwner, wndPtr->hSysMenu, 0, wndPtr->rectClient.left,
|
|
wndPtr->rectClient.top - menu->Height - 2*SYSMETRICS_CYBORDER);
|
|
if (selectFirst) MENU_SelectNextItem( hwndOwner, wndPtr->hSysMenu );
|
|
return wndPtr->hSysMenu;
|
|
}
|
|
item = ((MENUITEM *)USER_HEAP_LIN_ADDR(menu->hItems)) + menu->FocusedItem;
|
|
if (!(item->item_flags & MF_POPUP) ||
|
|
(item->item_flags & (MF_GRAYED | MF_DISABLED))) return hmenu;
|
|
item->item_flags |= MF_MOUSESELECT;
|
|
if (menu->wFlags & MF_POPUP)
|
|
{
|
|
MENU_ShowPopup( hwndOwner, (HMENU)item->item_id, menu->FocusedItem,
|
|
wndPtr->rectWindow.left + item->rect.right-arrow_bitmap_width,
|
|
wndPtr->rectWindow.top + item->rect.top );
|
|
}
|
|
else
|
|
{
|
|
MENU_ShowPopup( hwndOwner, (HMENU)item->item_id, menu->FocusedItem,
|
|
wndPtr->rectWindow.left + item->rect.left,
|
|
wndPtr->rectWindow.top + item->rect.bottom );
|
|
}
|
|
if (selectFirst) MENU_SelectNextItem( hwndOwner, (HMENU)item->item_id );
|
|
return (HMENU)item->item_id;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_FindMenuByCoords
|
|
*
|
|
* Find the menu containing a given point (in screen coords).
|
|
*/
|
|
static HMENU MENU_FindMenuByCoords( HMENU hmenu, POINT pt )
|
|
{
|
|
POPUPMENU *menu;
|
|
HWND hwnd;
|
|
|
|
if (!(hwnd = WindowFromPoint( pt ))) return 0;
|
|
while (hmenu)
|
|
{
|
|
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
if (menu->hWnd == hwnd)
|
|
{
|
|
if (!(menu->wFlags & MF_POPUP))
|
|
{
|
|
/* Make sure it's in the menu bar (or in system menu) */
|
|
WND *wndPtr = WIN_FindWndPtr( menu->hWnd );
|
|
if ((pt.x < wndPtr->rectClient.left) ||
|
|
(pt.x >= wndPtr->rectClient.right) ||
|
|
(pt.y >= wndPtr->rectClient.top)) return 0;
|
|
if (pt.y < wndPtr->rectClient.top - menu->Height)
|
|
{
|
|
if (!MENU_IsInSysMenu( menu, pt )) return 0;
|
|
}
|
|
/* else it's in the menu bar */
|
|
}
|
|
return hmenu;
|
|
}
|
|
hmenu = MENU_GetSubPopup( hmenu );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_ExecFocusedItem
|
|
*
|
|
* Execute a menu item (for instance when user pressed Enter).
|
|
* Return TRUE if we can go on with menu tracking.
|
|
*/
|
|
static BOOL MENU_ExecFocusedItem( HWND hwndOwner, HMENU hmenu,
|
|
HMENU *hmenuCurrent )
|
|
{
|
|
MENUITEM *item;
|
|
POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
if (!menu || !menu->nItems || (menu->FocusedItem == NO_SELECTED_ITEM) ||
|
|
(menu->FocusedItem == SYSMENU_SELECTED)) return TRUE;
|
|
item = ((MENUITEM *)USER_HEAP_LIN_ADDR(menu->hItems)) + menu->FocusedItem;
|
|
if (!(item->item_flags & MF_POPUP))
|
|
{
|
|
if (!(item->item_flags & (MF_GRAYED | MF_DISABLED)))
|
|
{
|
|
PostMessage( hwndOwner, (menu->wFlags & MF_SYSMENU) ?
|
|
WM_SYSCOMMAND : WM_COMMAND, item->item_id, 0 );
|
|
return FALSE;
|
|
}
|
|
else return TRUE;
|
|
}
|
|
else
|
|
{
|
|
*hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_ButtonDown
|
|
*
|
|
* Handle a button-down event in a menu. Point is in screen coords.
|
|
* hmenuCurrent is the top-most visible popup.
|
|
* Return TRUE if we can go on with menu tracking.
|
|
*/
|
|
static BOOL MENU_ButtonDown( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent,
|
|
POINT pt )
|
|
{
|
|
POPUPMENU *menu;
|
|
MENUITEM *item;
|
|
UINT id;
|
|
|
|
if (!hmenu) return FALSE; /* Outside all menus */
|
|
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
|
|
if (!item) /* Maybe in system menu */
|
|
{
|
|
if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
|
|
id = SYSMENU_SELECTED;
|
|
}
|
|
|
|
if (menu->FocusedItem == id)
|
|
{
|
|
if (id == SYSMENU_SELECTED) return FALSE;
|
|
if (item->item_flags & MF_POPUP)
|
|
{
|
|
if (item->item_flags & MF_MOUSESELECT)
|
|
{
|
|
if (menu->wFlags & MF_POPUP)
|
|
{
|
|
MENU_HideSubPopups( hwndOwner, hmenu );
|
|
*hmenuCurrent = hmenu;
|
|
}
|
|
else return FALSE;
|
|
}
|
|
else *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MENU_HideSubPopups( hwndOwner, hmenu );
|
|
MENU_SelectItem( hwndOwner, hmenu, id );
|
|
*hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_ButtonUp
|
|
*
|
|
* Handle a button-up event in a menu. Point is in screen coords.
|
|
* hmenuCurrent is the top-most visible popup.
|
|
* Return TRUE if we can go on with menu tracking.
|
|
*/
|
|
static BOOL MENU_ButtonUp( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent,
|
|
POINT pt )
|
|
{
|
|
POPUPMENU *menu;
|
|
MENUITEM *item;
|
|
HMENU hsubmenu = 0;
|
|
UINT id;
|
|
|
|
if (!hmenu) return FALSE; /* Outside all menus */
|
|
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
|
|
if (!item) /* Maybe in system menu */
|
|
{
|
|
if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
|
|
id = SYSMENU_SELECTED;
|
|
hsubmenu = GetSystemMenu( menu->hWnd, FALSE );
|
|
}
|
|
|
|
if (menu->FocusedItem != id) return FALSE;
|
|
|
|
if (id != SYSMENU_SELECTED)
|
|
{
|
|
if (!(item->item_flags & MF_POPUP))
|
|
{
|
|
return MENU_ExecFocusedItem( hwndOwner, hmenu, hmenuCurrent );
|
|
}
|
|
hsubmenu = (HMENU)item->item_id;
|
|
}
|
|
/* Select first item of sub-popup */
|
|
MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM );
|
|
MENU_SelectNextItem( hwndOwner, hsubmenu );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_MouseMove
|
|
*
|
|
* Handle a motion event in a menu. Point is in screen coords.
|
|
* hmenuCurrent is the top-most visible popup.
|
|
* Return TRUE if we can go on with menu tracking.
|
|
*/
|
|
static BOOL MENU_MouseMove( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent,
|
|
POINT pt )
|
|
{
|
|
MENUITEM *item;
|
|
POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
UINT id = NO_SELECTED_ITEM;
|
|
|
|
if (hmenu)
|
|
{
|
|
item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
|
|
if (!item) /* Maybe in system menu */
|
|
{
|
|
if (!MENU_IsInSysMenu( menu, pt ))
|
|
id = NO_SELECTED_ITEM; /* Outside all items */
|
|
else id = SYSMENU_SELECTED;
|
|
}
|
|
}
|
|
if (id == NO_SELECTED_ITEM)
|
|
{
|
|
MENU_SelectItem( hwndOwner, *hmenuCurrent, NO_SELECTED_ITEM );
|
|
}
|
|
else if (menu->FocusedItem != id)
|
|
{
|
|
MENU_HideSubPopups( hwndOwner, hmenu );
|
|
MENU_SelectItem( hwndOwner, hmenu, id );
|
|
*hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_KeyLeft
|
|
*
|
|
* Handle a VK_LEFT key event in a menu.
|
|
* hmenuCurrent is the top-most visible popup.
|
|
*/
|
|
static void MENU_KeyLeft( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent )
|
|
{
|
|
POPUPMENU *menu;
|
|
HMENU hmenutmp, hmenuprev;
|
|
|
|
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
hmenuprev = hmenutmp = hmenu;
|
|
while (hmenutmp != *hmenuCurrent)
|
|
{
|
|
hmenutmp = MENU_GetSubPopup( hmenuprev );
|
|
if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
|
|
}
|
|
MENU_HideSubPopups( hwndOwner, hmenuprev );
|
|
|
|
if ((hmenuprev == hmenu) && !(menu->wFlags & MF_POPUP))
|
|
{
|
|
/* Select previous item on the menu bar */
|
|
MENU_SelectPrevItem( hwndOwner, hmenu );
|
|
if (*hmenuCurrent != hmenu)
|
|
{
|
|
/* A popup menu was displayed -> display the next one */
|
|
*hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
|
|
}
|
|
}
|
|
else *hmenuCurrent = hmenuprev;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_KeyRight
|
|
*
|
|
* Handle a VK_RIGHT key event in a menu.
|
|
* hmenuCurrent is the top-most visible popup.
|
|
*/
|
|
static void MENU_KeyRight( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent )
|
|
{
|
|
POPUPMENU *menu;
|
|
HMENU hmenutmp;
|
|
|
|
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
|
|
if ((menu->wFlags & MF_POPUP) || (*hmenuCurrent != hmenu))
|
|
{
|
|
/* If already displaying a popup, try to display sub-popup */
|
|
hmenutmp = MENU_ShowSubPopup( hwndOwner, *hmenuCurrent, TRUE );
|
|
if (hmenutmp != *hmenuCurrent) /* Sub-popup displayed */
|
|
{
|
|
*hmenuCurrent = hmenutmp;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* If on menu-bar, go to next item */
|
|
if (!(menu->wFlags & MF_POPUP))
|
|
{
|
|
MENU_HideSubPopups( hwndOwner, hmenu );
|
|
MENU_SelectNextItem( hwndOwner, hmenu );
|
|
if (*hmenuCurrent != hmenu)
|
|
{
|
|
/* A popup menu was displayed -> display the next one */
|
|
*hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
|
|
}
|
|
}
|
|
else if (*hmenuCurrent != hmenu) /* Hide last level popup */
|
|
{
|
|
HMENU hmenuprev;
|
|
hmenuprev = hmenutmp = hmenu;
|
|
while (hmenutmp != *hmenuCurrent)
|
|
{
|
|
hmenutmp = MENU_GetSubPopup( hmenuprev );
|
|
if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
|
|
}
|
|
MENU_HideSubPopups( hwndOwner, hmenuprev );
|
|
*hmenuCurrent = hmenuprev;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_TrackMenu
|
|
*
|
|
* Menu tracking code.
|
|
* If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
|
|
* before beginning tracking. This is to help menu-bar tracking.
|
|
*/
|
|
static BOOL MENU_TrackMenu( HMENU hmenu, UINT wFlags, int x, int y,
|
|
HWND hwnd, LPRECT lprect )
|
|
{
|
|
MSG *msg;
|
|
HLOCAL hMsg;
|
|
POPUPMENU *menu;
|
|
HMENU hmenuCurrent = hmenu;
|
|
BOOL fClosed = FALSE, fRemove;
|
|
UINT pos;
|
|
|
|
fEndMenuCalled = FALSE;
|
|
if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
|
|
if (x && y)
|
|
{
|
|
POINT pt = { x, y };
|
|
MENU_ButtonDown( hwnd, hmenu, &hmenuCurrent, pt );
|
|
}
|
|
SetCapture( hwnd );
|
|
hMsg = USER_HEAP_ALLOC( sizeof(MSG) );
|
|
msg = (MSG *)USER_HEAP_LIN_ADDR( hMsg );
|
|
while (!fClosed)
|
|
{
|
|
if (!MSG_InternalGetMessage( (SEGPTR)USER_HEAP_SEG_ADDR(hMsg), 0,
|
|
hwnd, MSGF_MENU, 0, TRUE ))
|
|
break;
|
|
|
|
fRemove = FALSE;
|
|
if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
|
|
{
|
|
/* Find the sub-popup for this mouse event (if any) */
|
|
HMENU hsubmenu = MENU_FindMenuByCoords( hmenu, msg->pt );
|
|
|
|
switch(msg->message)
|
|
{
|
|
case WM_RBUTTONDOWN:
|
|
case WM_NCRBUTTONDOWN:
|
|
if (!(wFlags & TPM_RIGHTBUTTON)) break;
|
|
/* fall through */
|
|
case WM_LBUTTONDOWN:
|
|
case WM_NCLBUTTONDOWN:
|
|
fClosed = !MENU_ButtonDown( hwnd, hsubmenu,
|
|
&hmenuCurrent, msg->pt );
|
|
break;
|
|
|
|
case WM_RBUTTONUP:
|
|
case WM_NCRBUTTONUP:
|
|
if (!(wFlags & TPM_RIGHTBUTTON)) break;
|
|
/* fall through */
|
|
case WM_LBUTTONUP:
|
|
case WM_NCLBUTTONUP:
|
|
/* If outside all menus but inside lprect, ignore it */
|
|
if (!hsubmenu && lprect && PtInRect( lprect, msg->pt )) break;
|
|
fClosed = !MENU_ButtonUp( hwnd, hsubmenu,
|
|
&hmenuCurrent, msg->pt );
|
|
fRemove = TRUE; /* Remove event even if outside menu */
|
|
break;
|
|
|
|
case WM_MOUSEMOVE:
|
|
case WM_NCMOUSEMOVE:
|
|
if ((msg->wParam & MK_LBUTTON) ||
|
|
((wFlags & TPM_RIGHTBUTTON) && (msg->wParam & MK_RBUTTON)))
|
|
{
|
|
fClosed = !MENU_MouseMove( hwnd, hsubmenu,
|
|
&hmenuCurrent, msg->pt );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
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:
|
|
MENU_SelectItem( hwnd, hmenuCurrent, NO_SELECTED_ITEM );
|
|
MENU_SelectNextItem( hwnd, hmenuCurrent );
|
|
break;
|
|
|
|
case VK_END:
|
|
MENU_SelectItem( hwnd, hmenuCurrent, NO_SELECTED_ITEM );
|
|
MENU_SelectPrevItem( hwnd, hmenuCurrent );
|
|
break;
|
|
|
|
case VK_UP:
|
|
MENU_SelectPrevItem( hwnd, hmenuCurrent );
|
|
break;
|
|
|
|
case VK_DOWN:
|
|
/* If on menu bar, pull-down the menu */
|
|
if (!(menu->wFlags & MF_POPUP) && (hmenuCurrent == hmenu))
|
|
hmenuCurrent = MENU_ShowSubPopup( hwnd, hmenu, TRUE );
|
|
else
|
|
MENU_SelectNextItem( hwnd, hmenuCurrent );
|
|
break;
|
|
|
|
case VK_LEFT:
|
|
MENU_KeyLeft( hwnd, hmenu, &hmenuCurrent );
|
|
break;
|
|
|
|
case VK_RIGHT:
|
|
MENU_KeyRight( hwnd, hmenu, &hmenuCurrent );
|
|
break;
|
|
|
|
case VK_SPACE:
|
|
case VK_RETURN:
|
|
fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
|
|
&hmenuCurrent );
|
|
break;
|
|
|
|
case VK_ESCAPE:
|
|
fClosed = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break; /* WM_KEYDOWN */
|
|
|
|
case WM_SYSKEYDOWN:
|
|
switch(msg->wParam)
|
|
{
|
|
case VK_MENU:
|
|
fClosed = TRUE;
|
|
break;
|
|
|
|
}
|
|
break; /* WM_SYSKEYDOWN */
|
|
|
|
case WM_CHAR:
|
|
{
|
|
/* Hack to avoid control chars. */
|
|
/* We will find a better way real soon... */
|
|
if ((msg->wParam <= 32) || (msg->wParam >= 127)) break;
|
|
pos = MENU_FindItemByKey( hwnd, hmenuCurrent, msg->wParam );
|
|
if (pos == (UINT)-2) fClosed = TRUE;
|
|
else if (pos == (UINT)-1) MessageBeep(0);
|
|
else
|
|
{
|
|
MENU_SelectItem( hwnd, hmenuCurrent, pos );
|
|
fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
|
|
&hmenuCurrent );
|
|
|
|
}
|
|
}
|
|
break; /* WM_CHAR */
|
|
} /* switch(msg->message) */
|
|
}
|
|
else
|
|
{
|
|
DispatchMessage( msg );
|
|
}
|
|
if (fEndMenuCalled) fClosed = TRUE;
|
|
if (!fClosed) fRemove = TRUE;
|
|
|
|
if (fRemove) /* Remove the message from the queue */
|
|
PeekMessage( msg, 0, msg->message, msg->message, PM_REMOVE );
|
|
}
|
|
USER_HEAP_FREE( hMsg );
|
|
ReleaseCapture();
|
|
MENU_HideSubPopups( hwnd, hmenu );
|
|
if (menu->wFlags & MF_POPUP) ShowWindow( menu->hWnd, SW_HIDE );
|
|
MENU_SelectItem( hwnd, hmenu, NO_SELECTED_ITEM );
|
|
SendMessage( hwnd, WM_MENUSELECT, 0, MAKELONG( 0xffff, 0 ) );
|
|
fEndMenuCalled = FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_TrackMouseMenuBar
|
|
*
|
|
* Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
|
|
*/
|
|
void MENU_TrackMouseMenuBar( HWND hwnd, POINT pt )
|
|
{
|
|
WND *wndPtr = WIN_FindWndPtr( hwnd );
|
|
SendMessage( hwnd, WM_ENTERMENULOOP, 0, 0 );
|
|
SendMessage( hwnd, WM_INITMENU, wndPtr->wIDmenu, 0 );
|
|
MENU_TrackMenu( (HMENU)wndPtr->wIDmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
|
|
pt.x, pt.y, hwnd, NULL );
|
|
SendMessage( hwnd, WM_EXITMENULOOP, 0, 0 );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_TrackKbdMenuBar
|
|
*
|
|
* Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
|
|
*/
|
|
void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam )
|
|
{
|
|
WND *wndPtr = WIN_FindWndPtr( hwnd );
|
|
if (!wndPtr->wIDmenu) return;
|
|
SendMessage( hwnd, WM_ENTERMENULOOP, 0, 0 );
|
|
SendMessage( hwnd, WM_INITMENU, wndPtr->wIDmenu, 0 );
|
|
/* Select first selectable item */
|
|
MENU_SelectItem( hwnd, (HMENU)wndPtr->wIDmenu, NO_SELECTED_ITEM );
|
|
MENU_SelectNextItem( hwnd, (HMENU)wndPtr->wIDmenu );
|
|
MENU_TrackMenu( (HMENU)wndPtr->wIDmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
|
|
0, 0, hwnd, NULL );
|
|
SendMessage( hwnd, WM_EXITMENULOOP, 0, 0 );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* TrackPopupMenu (USER.416)
|
|
*/
|
|
BOOL TrackPopupMenu( HMENU hMenu, UINT wFlags, short x, short y,
|
|
short nReserved, HWND hWnd, LPRECT lpRect )
|
|
{
|
|
if (!MENU_ShowPopup( hWnd, hMenu, 0, x, y )) return FALSE;
|
|
return MENU_TrackMenu( hMenu, wFlags, 0, 0, hWnd, lpRect );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* PopupMenuWndProc
|
|
*/
|
|
LRESULT PopupMenuWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
|
|
{
|
|
switch(message)
|
|
{
|
|
case WM_CREATE:
|
|
{
|
|
CREATESTRUCT *createStruct = (CREATESTRUCT*)PTR_SEG_TO_LIN(lParam);
|
|
#ifdef WINELIB32
|
|
HMENU hmenu = (HMENU) (createStruct->lpCreateParams);
|
|
SetWindowLong( hwnd, 0, (LONG)hmenu );
|
|
#else
|
|
HMENU hmenu = (HMENU) ((int)createStruct->lpCreateParams & 0xffff);
|
|
SetWindowWord( hwnd, 0, hmenu );
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
case WM_MOUSEACTIVATE: /* We don't want to be activated */
|
|
return MA_NOACTIVATE;
|
|
|
|
case WM_PAINT:
|
|
{
|
|
PAINTSTRUCT ps;
|
|
BeginPaint( hwnd, &ps );
|
|
MENU_DrawPopupMenu( hwnd, ps.hdc,
|
|
#ifdef WINELIB32
|
|
(HMENU)GetWindowLong( hwnd, 0 )
|
|
#else
|
|
(HMENU)GetWindowWord( hwnd, 0 )
|
|
#endif
|
|
);
|
|
EndPaint( hwnd, &ps );
|
|
return 0;
|
|
}
|
|
|
|
default:
|
|
return DefWindowProc(hwnd, message, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MENU_GetMenuBarHeight
|
|
*
|
|
* Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
|
|
*/
|
|
UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth, int orgX, int orgY )
|
|
{
|
|
HDC hdc;
|
|
RECT rectBar;
|
|
WND *wndPtr;
|
|
LPPOPUPMENU lppop;
|
|
|
|
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
|
|
if (!(lppop = (LPPOPUPMENU)USER_HEAP_LIN_ADDR((HMENU)wndPtr->wIDmenu)))
|
|
return 0;
|
|
hdc = GetDC( hwnd );
|
|
SetRect( &rectBar, orgX, orgY, orgX+menubarWidth, orgY+SYSMETRICS_CYMENU );
|
|
MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
|
|
ReleaseDC( hwnd, hdc );
|
|
return lppop->Height;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* ChangeMenu [USER.153]
|
|
*/
|
|
BOOL ChangeMenu(HMENU hMenu, UINT nPos, LPSTR lpNewItem,
|
|
UINT wItemID, UINT wFlags)
|
|
{
|
|
dprintf_menu(stddeb,"ChangeMenu: menu="NPFMT" pos=%d ptr=%p item=%04x flags=%04x\n",
|
|
hMenu, nPos, lpNewItem, wItemID, wFlags);
|
|
if (wFlags & MF_APPEND) {
|
|
return AppendMenu(hMenu, wFlags & ~MF_APPEND, wItemID, lpNewItem);
|
|
}
|
|
if (wFlags & MF_DELETE) {
|
|
/* FIXME: Word passes the item id in nPos 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?). */
|
|
return DeleteMenu(hMenu, nPos, wFlags & ~MF_DELETE);
|
|
}
|
|
if (wFlags & MF_CHANGE) {
|
|
return ModifyMenu(hMenu, nPos, wFlags & ~MF_CHANGE, wItemID, lpNewItem);
|
|
}
|
|
if (wFlags & MF_REMOVE) {
|
|
return RemoveMenu(hMenu, wFlags & MF_BYPOSITION ? nPos : wItemID,
|
|
wFlags & ~MF_REMOVE);
|
|
}
|
|
/* Default: MF_INSERT */
|
|
return InsertMenu(hMenu, nPos, wFlags, wItemID, lpNewItem);
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* CheckMenuItem [USER.154]
|
|
*/
|
|
BOOL CheckMenuItem(HMENU hMenu, UINT wItemID, UINT wFlags)
|
|
{
|
|
LPMENUITEM lpitem;
|
|
dprintf_menu(stddeb,"CheckMenuItem ("NPFMT", %04X, %04X) !\n",
|
|
hMenu, wItemID, wFlags);
|
|
if (!(lpitem = MENU_FindItem(&hMenu, &wItemID, wFlags))) return FALSE;
|
|
if (wFlags & MF_CHECKED) lpitem->item_flags |= MF_CHECKED;
|
|
else lpitem->item_flags &= ~MF_CHECKED;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* EnableMenuItem [USER.155]
|
|
*/
|
|
BOOL EnableMenuItem(HMENU hMenu, UINT wItemID, UINT wFlags)
|
|
{
|
|
LPMENUITEM lpitem;
|
|
dprintf_menu(stddeb,"EnableMenuItem ("NPFMT", %04X, %04X) !\n",
|
|
hMenu, wItemID, wFlags);
|
|
if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return FALSE;
|
|
|
|
/* We can't have MF_GRAYED and MF_DISABLED together */
|
|
if (wFlags & MF_GRAYED)
|
|
{
|
|
lpitem->item_flags = (lpitem->item_flags & ~MF_DISABLED) | MF_GRAYED;
|
|
}
|
|
else if (wFlags & MF_DISABLED)
|
|
{
|
|
lpitem->item_flags = (lpitem->item_flags & ~MF_GRAYED) | MF_DISABLED;
|
|
}
|
|
else /* MF_ENABLED */
|
|
{
|
|
lpitem->item_flags &= ~(MF_GRAYED | MF_DISABLED);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
* GetMenuString (USER.161)
|
|
*/
|
|
int GetMenuString( HMENU hMenu, UINT wItemID,
|
|
LPSTR str, short nMaxSiz, UINT wFlags )
|
|
{
|
|
LPMENUITEM lpitem;
|
|
|
|
dprintf_menu( stddeb, "GetMenuString: menu="NPFMT" item=%04x ptr=%p len=%d flags=%04x\n",
|
|
hMenu, wItemID, str, nMaxSiz, wFlags );
|
|
if (!str || !nMaxSiz) return 0;
|
|
str[0] = '\0';
|
|
if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
|
|
if (!lpitem->item_text || !IS_STRING_ITEM(lpitem->item_flags)) return 0;
|
|
nMaxSiz = MIN( nMaxSiz-1, strlen(lpitem->item_text) );
|
|
strncpy( str, lpitem->item_text, nMaxSiz );
|
|
str[nMaxSiz] = '\0';
|
|
dprintf_menu( stddeb, "GetMenuString: returning '%s'\n", str );
|
|
return nMaxSiz;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* HiliteMenuItem [USER.162]
|
|
*/
|
|
BOOL HiliteMenuItem(HWND hWnd, HMENU hMenu, UINT wItemID, UINT wHilite)
|
|
{
|
|
LPPOPUPMENU menu;
|
|
LPMENUITEM lpitem;
|
|
dprintf_menu(stddeb,"HiliteMenuItem("NPFMT", "NPFMT", %04X, %04X);\n",
|
|
hWnd, hMenu, wItemID, wHilite);
|
|
if (!(lpitem = 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 );
|
|
MENU_SelectItem( hWnd, hMenu, wItemID );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetMenuState [USER.250]
|
|
*/
|
|
UINT GetMenuState(HMENU hMenu, UINT wItemID, UINT wFlags)
|
|
{
|
|
LPMENUITEM lpitem;
|
|
dprintf_menu(stddeb,"GetMenuState("NPFMT", %04X, %04X);\n",
|
|
hMenu, wItemID, wFlags);
|
|
if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
|
|
if (lpitem->item_flags & MF_POPUP)
|
|
{
|
|
POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( (HMENU)lpitem->item_id );
|
|
if (!menu) return -1;
|
|
else return (menu->nItems << 8) | (menu->wFlags & 0xff);
|
|
}
|
|
else return lpitem->item_flags;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetMenuItemCount [USER.263]
|
|
*/
|
|
INT GetMenuItemCount(HMENU hMenu)
|
|
{
|
|
LPPOPUPMENU menu;
|
|
dprintf_menu(stddeb,"GetMenuItemCount("NPFMT");\n", hMenu);
|
|
menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
|
|
if (menu == NULL) return (UINT)-1;
|
|
dprintf_menu(stddeb,"GetMenuItemCount("NPFMT") return %d \n",
|
|
hMenu, menu->nItems);
|
|
return menu->nItems;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetMenuItemID [USER.264]
|
|
*/
|
|
UINT GetMenuItemID(HMENU hMenu, int nPos)
|
|
{
|
|
LPPOPUPMENU menu;
|
|
MENUITEM *item;
|
|
|
|
dprintf_menu(stddeb,"GetMenuItemID("NPFMT", %d);\n", hMenu, nPos);
|
|
if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return -1;
|
|
if ((nPos < 0) || (nPos >= menu->nItems)) return -1;
|
|
item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
|
|
if (item[nPos].item_flags & MF_POPUP) return -1;
|
|
return item[nPos].item_id;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* InsertMenu [USER.410]
|
|
*/
|
|
BOOL InsertMenu(HMENU hMenu, UINT nPos, UINT wFlags, UINT wItemID, LPSTR lpNewItem)
|
|
{
|
|
HANDLE hNewItems;
|
|
MENUITEM *lpitem, *newItems;
|
|
LPPOPUPMENU menu;
|
|
|
|
if (IS_STRING_ITEM(wFlags))
|
|
{
|
|
dprintf_menu(stddeb,"InsertMenu ("NPFMT", %04X, %04X, %04X, '%s') !\n",
|
|
hMenu, nPos, wFlags, wItemID,
|
|
lpNewItem ? lpNewItem : "(null)");
|
|
if (!lpNewItem) return FALSE;
|
|
}
|
|
else
|
|
dprintf_menu(stddeb,"InsertMenu ("NPFMT", %04X, %04X, %04X, %p) !\n",
|
|
hMenu, nPos, wFlags, wItemID, lpNewItem);
|
|
|
|
/* Find where to insert new item */
|
|
|
|
if ((wFlags & MF_BYPOSITION) &&
|
|
((nPos == (UINT)-1) || (nPos == (UINT)GetMenuItemCount(hMenu))))
|
|
{
|
|
/* Special case: append to menu
|
|
Some programs specify the menu length to do that */
|
|
if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu)))
|
|
{
|
|
dprintf_menu(stddeb,"InsertMenu: "NPFMT" not a menu handle\n", hMenu);
|
|
return FALSE;
|
|
}
|
|
nPos = menu->nItems;
|
|
}
|
|
else
|
|
{
|
|
if (!MENU_FindItem( &hMenu, &nPos, wFlags ))
|
|
{
|
|
dprintf_menu(stddeb,"InsertMenu: Item %X not found\n", nPos);
|
|
return FALSE;
|
|
}
|
|
if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu)))
|
|
{
|
|
dprintf_menu(stddeb,"InsertMenu: "NPFMT" not a menu handle\n", hMenu);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* Create new items array */
|
|
|
|
hNewItems = USER_HEAP_ALLOC( sizeof(MENUITEM) * (menu->nItems+1) );
|
|
if (!hNewItems)
|
|
{
|
|
dprintf_menu(stddeb,"InsertMenu: allocation failed\n");
|
|
return FALSE;
|
|
}
|
|
newItems = (MENUITEM *) USER_HEAP_LIN_ADDR( hNewItems );
|
|
if (menu->nItems > 0)
|
|
{
|
|
/* Copy the old array into the new */
|
|
MENUITEM *oldItems = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
|
|
if (nPos > 0) memcpy( newItems, oldItems, nPos * sizeof(MENUITEM) );
|
|
if (nPos < menu->nItems) memcpy( &newItems[nPos+1], &oldItems[nPos],
|
|
(menu->nItems-nPos)*sizeof(MENUITEM) );
|
|
|
|
USER_HEAP_FREE( menu->hItems );
|
|
}
|
|
menu->hItems = hNewItems;
|
|
menu->nItems++;
|
|
|
|
/* Store the new item data */
|
|
|
|
lpitem = &newItems[nPos];
|
|
lpitem->item_flags = wFlags & ~(MF_HILITE | MF_MOUSESELECT);
|
|
lpitem->item_id = wItemID;
|
|
|
|
if (IS_STRING_ITEM(wFlags))
|
|
{
|
|
/* Item beginning with a backspace is a help item */
|
|
if (lpNewItem[0] == '\b')
|
|
{
|
|
lpitem->item_flags |= MF_HELP;
|
|
lpNewItem++;
|
|
}
|
|
lpitem->hText = USER_HEAP_ALLOC( strlen(lpNewItem)+1 );
|
|
lpitem->item_text = (char *)USER_HEAP_LIN_ADDR( lpitem->hText );
|
|
strcpy( lpitem->item_text, lpNewItem );
|
|
}
|
|
#ifdef WINELIB32
|
|
else if (wFlags & MF_BITMAP) lpitem->hText = (HANDLE)lpNewItem;
|
|
#else
|
|
else if (wFlags & MF_BITMAP) lpitem->hText = LOWORD((DWORD)lpNewItem);
|
|
#endif
|
|
else lpitem->item_text = lpNewItem;
|
|
|
|
if (wFlags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
|
|
((POPUPMENU *)USER_HEAP_LIN_ADDR((HMENU)wItemID))->wFlags |= MF_POPUP;
|
|
|
|
SetRectEmpty( &lpitem->rect );
|
|
lpitem->hCheckBit = hStdCheck;
|
|
lpitem->hUnCheckBit = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* AppendMenu [USER.411]
|
|
*/
|
|
BOOL AppendMenu(HMENU hMenu, UINT wFlags, UINT wItemID, LPSTR lpNewItem)
|
|
{
|
|
return InsertMenu( hMenu, -1, wFlags | MF_BYPOSITION, wItemID, lpNewItem );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* RemoveMenu [USER.412]
|
|
*/
|
|
BOOL RemoveMenu(HMENU hMenu, UINT nPos, UINT wFlags)
|
|
{
|
|
LPPOPUPMENU menu;
|
|
LPMENUITEM lpitem;
|
|
dprintf_menu(stddeb,"RemoveMenu ("NPFMT", %04X, %04X) !\n",
|
|
hMenu, nPos, wFlags);
|
|
if (!(lpitem = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
|
|
if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
|
|
|
|
/* Remove item */
|
|
|
|
if (IS_STRING_ITEM(lpitem->item_flags)) USER_HEAP_FREE( lpitem->hText );
|
|
if (--menu->nItems == 0)
|
|
{
|
|
USER_HEAP_FREE( menu->hItems );
|
|
menu->hItems = 0;
|
|
}
|
|
else
|
|
{
|
|
while(nPos < menu->nItems)
|
|
{
|
|
*lpitem = *(lpitem+1);
|
|
lpitem++;
|
|
nPos++;
|
|
}
|
|
menu->hItems = USER_HEAP_REALLOC( menu->hItems,
|
|
menu->nItems * sizeof(MENUITEM) );
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* DeleteMenu [USER.413]
|
|
*/
|
|
BOOL DeleteMenu(HMENU hMenu, UINT nPos, UINT wFlags)
|
|
{
|
|
MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
|
|
if (!item) return FALSE;
|
|
if (item->item_flags & MF_POPUP) DestroyMenu( (HMENU)item->item_id );
|
|
/* nPos is now the position of the item */
|
|
RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* ModifyMenu [USER.414]
|
|
*/
|
|
BOOL ModifyMenu(HMENU hMenu, UINT nPos, UINT wFlags, UINT wItemID, LPSTR lpNewItem)
|
|
{
|
|
LPMENUITEM lpitem;
|
|
if (IS_STRING_ITEM(wFlags))
|
|
{
|
|
dprintf_menu(stddeb,"ModifyMenu ("NPFMT", %04X, %04X, %04X, '%s') !\n",
|
|
hMenu, nPos, wFlags, wItemID, lpNewItem ? lpNewItem : "(null)");
|
|
if (!lpNewItem) return FALSE;
|
|
}
|
|
else
|
|
dprintf_menu(stddeb,"ModifyMenu ("NPFMT", %04X, %04X, %04X, %p) !\n",
|
|
hMenu, nPos, wFlags, wItemID, lpNewItem);
|
|
if (!(lpitem = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
|
|
|
|
if (IS_STRING_ITEM(lpitem->item_flags)) USER_HEAP_FREE( lpitem->hText );
|
|
lpitem->item_flags = wFlags & ~(MF_HILITE | MF_MOUSESELECT);
|
|
lpitem->item_id = wItemID;
|
|
|
|
if (IS_STRING_ITEM(wFlags))
|
|
{
|
|
lpitem->hText = USER_HEAP_ALLOC( strlen(lpNewItem)+1 );
|
|
lpitem->item_text = (char *)USER_HEAP_LIN_ADDR( lpitem->hText );
|
|
strcpy( lpitem->item_text, lpNewItem );
|
|
}
|
|
#ifdef WINELIB32
|
|
else if (wFlags & MF_BITMAP) lpitem->hText = (HANDLE)lpNewItem;
|
|
#else
|
|
else if (wFlags & MF_BITMAP) lpitem->hText = LOWORD((DWORD)lpNewItem);
|
|
#endif
|
|
else lpitem->item_text = lpNewItem;
|
|
SetRectEmpty( &lpitem->rect );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* CreatePopupMenu [USER.415]
|
|
*/
|
|
HMENU CreatePopupMenu()
|
|
{
|
|
HMENU hmenu;
|
|
POPUPMENU *menu;
|
|
|
|
if (!(hmenu = CreateMenu())) return 0;
|
|
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
|
|
menu->wFlags |= MF_POPUP;
|
|
return hmenu;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetMenuCheckMarkDimensions [USER.417]
|
|
*/
|
|
DWORD GetMenuCheckMarkDimensions()
|
|
{
|
|
return MAKELONG( check_bitmap_width, check_bitmap_height );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* SetMenuItemBitmaps [USER.418]
|
|
*/
|
|
BOOL SetMenuItemBitmaps(HMENU hMenu, UINT nPos, UINT wFlags,
|
|
HBITMAP hNewCheck, HBITMAP hNewUnCheck)
|
|
{
|
|
LPMENUITEM lpitem;
|
|
dprintf_menu(stddeb,"SetMenuItemBitmaps ("NPFMT", %04X, %04X, "NPFMT", %08lX) !\n",
|
|
hMenu, nPos, wFlags, hNewCheck, (DWORD)hNewUnCheck);
|
|
if (!(lpitem = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
|
|
|
|
if (!hNewCheck && !hNewUnCheck)
|
|
{
|
|
/* If both are NULL, restore default bitmaps */
|
|
lpitem->hCheckBit = hStdCheck;
|
|
lpitem->hUnCheckBit = 0;
|
|
lpitem->item_flags &= ~MF_USECHECKBITMAPS;
|
|
}
|
|
else /* Install new bitmaps */
|
|
{
|
|
lpitem->hCheckBit = hNewCheck;
|
|
lpitem->hUnCheckBit = hNewUnCheck;
|
|
lpitem->item_flags |= MF_USECHECKBITMAPS;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* CreateMenu [USER.151]
|
|
*/
|
|
HMENU CreateMenu()
|
|
{
|
|
HMENU hMenu;
|
|
LPPOPUPMENU menu;
|
|
dprintf_menu(stddeb,"CreateMenu !\n");
|
|
if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) )))
|
|
return 0;
|
|
menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
|
|
menu->hNext = 0;
|
|
menu->wFlags = 0;
|
|
menu->wMagic = MENU_MAGIC;
|
|
menu->hTaskQ = 0;
|
|
menu->Width = 0;
|
|
menu->Height = 0;
|
|
menu->nItems = 0;
|
|
menu->hWnd = 0;
|
|
menu->hItems = 0;
|
|
menu->FocusedItem = NO_SELECTED_ITEM;
|
|
dprintf_menu(stddeb,"CreateMenu // return "NPFMT"\n", hMenu);
|
|
return hMenu;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* DestroyMenu [USER.152]
|
|
*/
|
|
BOOL DestroyMenu(HMENU hMenu)
|
|
{
|
|
LPPOPUPMENU lppop;
|
|
dprintf_menu(stddeb,"DestroyMenu ("NPFMT") !\n", hMenu);
|
|
if (hMenu == 0) return FALSE;
|
|
lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
|
|
if (!lppop || (lppop->wMagic != MENU_MAGIC)) return FALSE;
|
|
lppop->wMagic = 0; /* Mark it as destroyed */
|
|
if ((lppop->wFlags & MF_POPUP) && lppop->hWnd)
|
|
DestroyWindow( lppop->hWnd );
|
|
|
|
if (lppop->hItems)
|
|
{
|
|
int i;
|
|
MENUITEM *item = (MENUITEM *) USER_HEAP_LIN_ADDR( lppop->hItems );
|
|
for (i = lppop->nItems; i > 0; i--, item++)
|
|
{
|
|
if (item->item_flags & MF_POPUP)
|
|
DestroyMenu( (HMENU)item->item_id );
|
|
}
|
|
USER_HEAP_FREE( lppop->hItems );
|
|
}
|
|
USER_HEAP_FREE( hMenu );
|
|
dprintf_menu(stddeb,"DestroyMenu ("NPFMT") // End !\n", hMenu);
|
|
return TRUE;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* GetSystemMenu [USER.156]
|
|
*/
|
|
HMENU GetSystemMenu(HWND hWnd, BOOL bRevert)
|
|
{
|
|
WND *wndPtr = WIN_FindWndPtr( hWnd );
|
|
if (!wndPtr) return 0;
|
|
|
|
if (!bRevert) return wndPtr->hSysMenu;
|
|
if (wndPtr->hSysMenu) DestroyMenu(wndPtr->hSysMenu);
|
|
wndPtr->hSysMenu = MENU_CopySysMenu();
|
|
return wndPtr->hSysMenu;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* SetSystemMenu [USER.280]
|
|
*/
|
|
BOOL SetSystemMenu(HWND hWnd, HMENU newHmenu)
|
|
{
|
|
WND *wndPtr;
|
|
|
|
if ((wndPtr = WIN_FindWndPtr(hWnd)) != NULL) wndPtr->hSysMenu = newHmenu;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetMenu [USER.157]
|
|
*/
|
|
HMENU GetMenu(HWND hWnd)
|
|
{
|
|
WND * wndPtr = WIN_FindWndPtr(hWnd);
|
|
if (wndPtr == NULL) return 0;
|
|
return (HMENU)wndPtr->wIDmenu;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* SetMenu [USER.158]
|
|
*/
|
|
BOOL SetMenu(HWND hWnd, HMENU hMenu)
|
|
{
|
|
LPPOPUPMENU lpmenu;
|
|
WND * wndPtr = WIN_FindWndPtr(hWnd);
|
|
if (wndPtr == NULL) {
|
|
fprintf(stderr,"SetMenu("NPFMT", "NPFMT") // Bad window handle !\n",
|
|
hWnd, hMenu);
|
|
return FALSE;
|
|
}
|
|
dprintf_menu(stddeb,"SetMenu("NPFMT", "NPFMT");\n", hWnd, hMenu);
|
|
if (GetCapture() == hWnd) ReleaseCapture();
|
|
wndPtr->wIDmenu = (UINT)hMenu;
|
|
if (hMenu != 0)
|
|
{
|
|
lpmenu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
|
|
if (lpmenu == NULL) {
|
|
fprintf(stderr,"SetMenu("NPFMT", "NPFMT") // Bad menu handle !\n",
|
|
hWnd, hMenu);
|
|
return FALSE;
|
|
}
|
|
lpmenu->hWnd = hWnd;
|
|
lpmenu->wFlags &= ~MF_POPUP; /* Can't be a popup */
|
|
lpmenu->Height = 0; /* Make sure we recalculate the size */
|
|
}
|
|
SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
|
|
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
* GetSubMenu [USER.159]
|
|
*/
|
|
HMENU GetSubMenu(HMENU hMenu, short nPos)
|
|
{
|
|
LPPOPUPMENU lppop;
|
|
LPMENUITEM lpitem;
|
|
dprintf_menu(stddeb,"GetSubMenu ("NPFMT", %04X) !\n", hMenu, nPos);
|
|
if (!(lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return 0;
|
|
if ((UINT)nPos >= lppop->nItems) return 0;
|
|
lpitem = (MENUITEM *) USER_HEAP_LIN_ADDR( lppop->hItems );
|
|
if (!(lpitem[nPos].item_flags & MF_POPUP)) return 0;
|
|
return (HMENU)lpitem[nPos].item_id;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* DrawMenuBar [USER.160]
|
|
*/
|
|
void DrawMenuBar(HWND hWnd)
|
|
{
|
|
WND *wndPtr;
|
|
LPPOPUPMENU lppop;
|
|
dprintf_menu(stddeb,"DrawMenuBar ("NPFMT")\n", hWnd);
|
|
wndPtr = WIN_FindWndPtr(hWnd);
|
|
if (wndPtr != NULL && (wndPtr->dwStyle & WS_CHILD) == 0 &&
|
|
wndPtr->wIDmenu != 0) {
|
|
dprintf_menu(stddeb,"DrawMenuBar wIDmenu=%04X \n",
|
|
wndPtr->wIDmenu);
|
|
lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR((HMENU)wndPtr->wIDmenu);
|
|
if (lppop == NULL) return;
|
|
|
|
lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
|
|
SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
|
|
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* EndMenu (USER.187)
|
|
*/
|
|
void EndMenu(void)
|
|
{
|
|
/* Note: this won't work when we have multiple tasks... */
|
|
fEndMenuCalled = TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LookupMenuHandle (USER.217)
|
|
*/
|
|
HMENU LookupMenuHandle( HMENU hmenu, INT id )
|
|
{
|
|
if (!MENU_FindItem( &hmenu, &id, MF_BYCOMMAND )) return 0;
|
|
else return hmenu;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* LoadMenu (USER.150)
|
|
*/
|
|
HMENU LoadMenu( HINSTANCE instance, SEGPTR name )
|
|
{
|
|
HRSRC hRsrc;
|
|
HGLOBAL handle;
|
|
HMENU hMenu;
|
|
|
|
if (HIWORD(name))
|
|
{
|
|
char *str = (char *)PTR_SEG_TO_LIN( name );
|
|
dprintf_menu( stddeb, "LoadMenu("NPFMT",'%s')\n", instance, str );
|
|
if (str[0] == '#') name = (SEGPTR)atoi( str + 1 );
|
|
}
|
|
else
|
|
dprintf_resource(stddeb,"LoadMenu("NPFMT",%04x)\n",instance,LOWORD(name));
|
|
|
|
if (!name) return 0;
|
|
|
|
if (!(hRsrc = FindResource( instance, name, RT_MENU ))) return 0;
|
|
if (!(handle = LoadResource( instance, hRsrc ))) return 0;
|
|
hMenu = LoadMenuIndirect( LockResource(handle) );
|
|
FreeResource( handle );
|
|
return hMenu;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* LoadMenuIndirect [USER.220]
|
|
*/
|
|
HMENU LoadMenuIndirect(LPSTR menu_template)
|
|
{
|
|
HMENU hMenu;
|
|
MENU_HEADER *menu_desc;
|
|
dprintf_menu(stddeb,"LoadMenuIndirect: menu_template '%p'\n",
|
|
menu_template);
|
|
hMenu = CreateMenu();
|
|
menu_desc = (MENU_HEADER *)menu_template;
|
|
ParseMenuResource((WORD *)(menu_desc + 1), 0, hMenu);
|
|
return hMenu;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* ParseMenuResource (from Resource or Template)
|
|
*/
|
|
WORD * ParseMenuResource(WORD *first_item, int level, HMENU hMenu)
|
|
{
|
|
WORD *item;
|
|
WORD *next_item;
|
|
HMENU hSubMenu;
|
|
int i;
|
|
|
|
level++;
|
|
next_item = first_item;
|
|
i = 0;
|
|
do {
|
|
i++;
|
|
item = next_item;
|
|
if (*item & MF_POPUP) {
|
|
MENU_POPUPITEM *popup_item = (MENU_POPUPITEM *) item;
|
|
next_item = (WORD *) (popup_item->item_text +
|
|
strlen(popup_item->item_text) + 1);
|
|
hSubMenu = CreatePopupMenu();
|
|
next_item = ParseMenuResource(next_item, level, hSubMenu);
|
|
AppendMenu(hMenu, popup_item->item_flags,
|
|
(UINT)hSubMenu, popup_item->item_text);
|
|
}
|
|
else
|
|
{
|
|
MENUITEMTEMPLATE *normal_item = (MENUITEMTEMPLATE *) item;
|
|
WORD flags = normal_item->item_flags;
|
|
next_item = (WORD *) (normal_item->item_text +
|
|
strlen(normal_item->item_text) + 1);
|
|
if (!normal_item->item_text[0] && !normal_item->item_id)
|
|
flags |= MF_SEPARATOR; /* FIXME: do this in InsertMenu? */
|
|
AppendMenu( hMenu, flags, normal_item->item_id,
|
|
normal_item->item_text );
|
|
}
|
|
} while (!(*item & MF_END));
|
|
return next_item;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* IsMenu (USER.358)
|
|
*/
|
|
BOOL IsMenu( HMENU hmenu )
|
|
{
|
|
LPPOPUPMENU menu;
|
|
if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
|
|
return (menu->wMagic == MENU_MAGIC);
|
|
}
|