📄 menu.c
字号:
/* $Id: menu.c 23579 2006-08-14 14:44:40Z jimtabor $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS user32.dll
* FILE: user32/windows/menu.c
* PURPOSE: Menus
*
* PROGRAMMERS: Casper S. Hornstrup
* James Tabor
*/
/* INCLUDES ******************************************************************/
#include <user32.h>
#include <wine/debug.h>
/* internal popup menu window messages */
#define MM_SETMENUHANDLE (WM_USER + 0)
#define MM_GETMENUHANDLE (WM_USER + 1)
/* Internal MenuTrackMenu() flags */
#define TPM_INTERNAL 0xF0000000
#define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
#define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
#define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
/* TYPES *********************************************************************/
#define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
#define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
#define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
#define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
#define IS_SYSTEM_MENU(MenuInfo) \
(0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
#define IS_SYSTEM_POPUP(MenuInfo) \
(0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
#define IS_MAGIC_ITEM(Bmp) ((int) Bmp <12)
#define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
#define MENU_ITEM_HBMP_SPACE (5)
#define MENU_BAR_ITEMS_SPACE (12)
#define SEPARATOR_HEIGHT (5)
#define MENU_TAB_SPACE (8)
#define ITEM_PREV -1
#define ITEM_NEXT 1
#define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
#define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
#define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */
#define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */
/* internal flags for menu tracking */
#define TF_ENDMENU 0x0001
#define TF_SUSPENDPOPUP 0x0002
#define TF_SKIPREMOVE 0x0004
typedef struct
{
UINT TrackFlags;
HMENU CurrentMenu; /* current submenu (can be equal to hTopMenu)*/
HMENU TopMenu; /* initial menu */
HWND OwnerWnd; /* where notifications are sent */
POINT Pt;
} MTRACKER;
static LRESULT WINAPI PopupMenuWndProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
/*********************************************************************
* PopupMenu class descriptor
*/
const struct builtin_class_descr POPUPMENU_builtin_class =
{
POPUPMENU_CLASS_ATOMW, /* name */
CS_SAVEBITS | CS_DBLCLKS, /* style */
(WNDPROC) PopupMenuWndProcW, /* FIXME - procW */
(WNDPROC) NULL, /* FIXME - procA */
sizeof(MENUINFO *), /* extra */
(LPCWSTR) IDC_ARROW, /* cursor */
(HBRUSH)(COLOR_MENU + 1) /* brush */
};
/* INTERNAL FUNCTIONS ********************************************************/
/* Rip the fun and easy to use and fun WINE unicode string manipulation routines.
* Of course I didnt copy the ASM code because we want this to be portable
* and it needs to go away.
*/
#ifndef GET_WORD
#define GET_WORD(ptr) (*(WORD *)(ptr))
#endif
#ifndef GET_DWORD
#define GET_DWORD(ptr) (*(DWORD *)(ptr))
#endif
HFONT hMenuFont = NULL;
HFONT hMenuFontBold = NULL;
/* Flag set by EndMenu() to force an exit from menu tracking */
static BOOL fEndMenu = FALSE;
/* Use global popup window because there's no way 2 menus can
* be tracked at the same time. */
static HWND TopPopup;
/* Dimension of the menu bitmaps */
static WORD ArrowBitmapWidth = 0, ArrowBitmapHeight = 0;
static HBITMAP StdMnArrow = NULL;
static HBITMAP BmpSysMenu = NULL;
static SIZE MenuCharSize;
/***********************************************************************
* MenuGetRosMenuInfo
*
* Get full information about menu
*/
static BOOL FASTCALL
MenuGetRosMenuInfo(PROSMENUINFO MenuInfo, HMENU Menu)
{
MenuInfo->cbSize = sizeof(ROSMENUINFO);
MenuInfo->fMask = MIM_BACKGROUND | MIM_HELPID | MIM_MAXHEIGHT | MIM_MENUDATA | MIM_STYLE;
return NtUserMenuInfo(Menu, MenuInfo, FALSE);
}
/***********************************************************************
* MenuSetRosMenuInfo
*
* Set full information about menu
*/
static BOOL FASTCALL
MenuSetRosMenuInfo(PROSMENUINFO MenuInfo)
{
MenuInfo->cbSize = sizeof(ROSMENUINFO);
MenuInfo->fMask = MIM_BACKGROUND | MIM_HELPID | MIM_MAXHEIGHT | MIM_MENUDATA | MIM_STYLE;
return NtUserMenuInfo(MenuInfo->Self, MenuInfo, TRUE);
}
/***********************************************************************
* MenuInitRosMenuItemInfo
*
* Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
*/
static VOID FASTCALL
MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
{
ZeroMemory(ItemInfo, sizeof(ROSMENUITEMINFO));
ItemInfo->cbSize = sizeof(ROSMENUITEMINFO);
}
/***********************************************************************
* MenuGetRosMenuItemInfo
*
* Get full information about a menu item
*/
static BOOL FASTCALL
MenuGetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
{
UINT Save_Mask = ItemInfo->fMask; /* Save the org mask bits. */
if (ItemInfo->dwTypeData != NULL)
{
HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
}
ItemInfo->fMask = MIIM_BITMAP | MIIM_CHECKMARKS | MIIM_DATA | MIIM_FTYPE
| MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU | MIIM_TYPE;
ItemInfo->dwTypeData = NULL;
if (! NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, FALSE))
{
ItemInfo->fType = 0;
return FALSE;
}
if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING)
{
ItemInfo->cch++;
ItemInfo->dwTypeData = HeapAlloc(GetProcessHeap(), 0,
ItemInfo->cch * sizeof(WCHAR));
if (NULL == ItemInfo->dwTypeData)
{
return FALSE;
}
if (! NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, FALSE))
{
ItemInfo->fType = 0;
return FALSE;
}
}
ItemInfo->fMask = Save_Mask;
return TRUE;
}
/***********************************************************************
* MenuSetRosMenuItemInfo
*
* Set selected information about a menu item, need to set the mask bits.
*/
static BOOL FASTCALL
MenuSetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
{
BOOL Ret;
if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING &&
ItemInfo->dwTypeData != NULL)
{
ItemInfo->cch = strlenW(ItemInfo->dwTypeData);
}
Ret = NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, TRUE);
return Ret;
}
/***********************************************************************
* MenuCleanupRosMenuItemInfo
*
* Cleanup after use of MenuGet/SetRosMenuItemInfo
*/
static VOID FASTCALL
MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
{
if (ItemInfo->dwTypeData != NULL)
{
HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
}
}
/***********************************************************************
* MenuGetAllRosMenuItemInfo
*
* Get full information about all menu items
*/
static INT FASTCALL
MenuGetAllRosMenuItemInfo(HMENU Menu, PROSMENUITEMINFO *ItemInfo)
{
DWORD BufSize;
BufSize = NtUserBuildMenuItemList(Menu, (VOID *) 1, 0, 0);
if (BufSize <= 0)
{
return -1;
}
*ItemInfo = HeapAlloc(GetProcessHeap(), 0, BufSize);
if (NULL == *ItemInfo)
{
return -1;
}
return NtUserBuildMenuItemList(Menu, *ItemInfo, BufSize, 0);
}
/***********************************************************************
* MenuCleanupAllRosMenuItemInfo
*
* Cleanup after use of MenuGetAllRosMenuItemInfo
*/
static VOID FASTCALL
MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
{
HeapFree(GetProcessHeap(), 0, ItemInfo);
}
/***********************************************************************
* MenuLoadBitmaps
*
* Load the arrow bitmap. We can't do this from MenuInit since user32
* can also be used (and thus initialized) from text-mode.
*/
static void FASTCALL
MenuLoadBitmaps(VOID)
{
/* Load menu bitmaps */
if (NULL == StdMnArrow)
{
StdMnArrow = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW));
if (NULL != StdMnArrow)
{
BITMAP bm;
GetObjectW(StdMnArrow, sizeof(BITMAP), &bm);
ArrowBitmapWidth = bm.bmWidth;
ArrowBitmapHeight = bm.bmHeight;
}
}
/* Load system buttons bitmaps */
if (NULL == BmpSysMenu)
{
BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
}
}
/***********************************************************************
* MenuGetBitmapItemSize
*
* Get the size of a bitmap item.
*/
static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *Size, HWND WndOwner)
{
BITMAP Bm;
HBITMAP Bmp = lpitem->hbmpItem;
Size->cx = Size->cy = 0;
/* check if there is a magic menu item associated with this item */
if (0 != Bmp && IS_MAGIC_ITEM((INT)(Bmp)))
{
switch((INT_PTR) Bmp)
{
case (INT_PTR)HBMMENU_CALLBACK:
{
MEASUREITEMSTRUCT measItem;
measItem.CtlType = ODT_MENU;
measItem.CtlID = 0;
measItem.itemID = lpitem->wID;
measItem.itemWidth = lpitem->Rect.right - lpitem->Rect.left;
measItem.itemHeight = lpitem->Rect.bottom - lpitem->Rect.top;
measItem.itemData = lpitem->dwItemData;
SendMessageW( WndOwner, WM_MEASUREITEM, lpitem->wID, (LPARAM)&measItem);
Size->cx = measItem.itemWidth;
Size->cy = measItem.itemHeight;
return;
}
break;
case (INT_PTR) HBMMENU_SYSTEM:
if (0 != lpitem->dwItemData)
{
Bmp = (HBITMAP) lpitem->dwItemData;
break;
}
/* fall through */
case (INT_PTR) HBMMENU_MBAR_RESTORE:
case (INT_PTR) HBMMENU_MBAR_MINIMIZE:
case (INT_PTR) HBMMENU_MBAR_CLOSE:
case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D:
case (INT_PTR) HBMMENU_MBAR_CLOSE_D:
/* FIXME: Why we need to subtract these magic values? */
/* to make them smaller than the menu bar? */
Size->cx = GetSystemMetrics(SM_CXSIZE) - 2;
Size->cy = GetSystemMetrics(SM_CYSIZE) - 4;
return;
case (INT_PTR) HBMMENU_POPUP_CLOSE:
case (INT_PTR) HBMMENU_POPUP_RESTORE:
case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
default:
DPRINT("Magic menu bitmap not implemented\n");
return;
}
}
if (GetObjectW(Bmp, sizeof(BITMAP), &Bm))
{
Size->cx = Bm.bmWidth;
Size->cy = Bm.bmHeight;
}
}
/***********************************************************************
* MenuDrawBitmapItem
*
* Draw a bitmap item.
*/
static void FASTCALL
MenuDrawBitmapItem(HDC Dc, PROSMENUITEMINFO Item, const RECT *Rect,
HMENU hmenu, HWND WndOwner, UINT odaction, BOOL MenuBar)
{
BITMAP Bm;
DWORD Rop;
HDC DcMem;
HBITMAP Bmp;
int w = Rect->right - Rect->left;
int h = Rect->bottom - Rect->top;
int BmpXoffset = 0;
int Left, Top;
HBITMAP hbmpToDraw = (HBITMAP) Item->hbmpItem;
Bmp = hbmpToDraw;
/* Check if there is a magic menu item associated with this item */
if (IS_MAGIC_ITEM(hbmpToDraw))
{
UINT Flags = 0;
RECT r;
r = *Rect;
switch ((INT_PTR)hbmpToDraw)
{
case (INT_PTR) HBMMENU_SYSTEM:
if (NULL != Item->dwTypeData)
{
Bmp = (HBITMAP)Item->dwTypeData;
if (! GetObjectW(Bmp, sizeof(BITMAP), &Bm))
{
return;
}
}
else
{
if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
Bmp = BmpSysMenu;
if (! GetObjectW(Bmp, sizeof(BITMAP), &Bm))
{
return;
}
/* only use right half of the bitmap */
BmpXoffset = Bm.bmWidth / 2;
Bm.bmWidth -= BmpXoffset;
}
goto got_bitmap;
case (INT_PTR) HBMMENU_MBAR_RESTORE:
Flags = DFCS_CAPTIONRESTORE;
break;
case (INT_PTR) HBMMENU_MBAR_MINIMIZE:
r.right += 1;
Flags = DFCS_CAPTIONMIN;
break;
case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D:
r.right += 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -