📄 menu.c
字号:
}
/***********************************************************************
* MenuDrawPopupMenu
*
* Paint a popup menu.
*/
static void FASTCALL
MenuDrawPopupMenu(HWND Wnd, HDC Dc, HMENU Menu)
{
HBRUSH PrevBrush = NULL;
HPEN PrevPen;
RECT Rect;
ROSMENUINFO MenuInfo;
ROSMENUITEMINFO ItemInfo;
UINT u;
DPRINT("wnd=%x dc=%x menu=%x\n", Wnd, Dc, Menu);
GetClientRect(Wnd, &Rect);
if (NULL != (PrevBrush = SelectObject(Dc, GetSysColorBrush(COLOR_MENU)))
&& NULL != SelectObject(Dc, hMenuFont))
{
Rectangle(Dc, Rect.left, Rect.top, Rect.right, Rect.bottom);
PrevPen = SelectObject(Dc, GetStockObject(NULL_PEN));
if (NULL != PrevPen)
{
BOOL flat_menu = FALSE;
SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
if (flat_menu)
FrameRect(Dc, &Rect, GetSysColorBrush(COLOR_BTNSHADOW));
else
DrawEdge(Dc, &Rect, EDGE_RAISED, BF_RECT);
/* draw menu items */
if (MenuGetRosMenuInfo(&MenuInfo, Menu) && 0 != MenuInfo.MenuItemCount)
{
MenuInitRosMenuItemInfo(&ItemInfo);
for (u = 0; u < MenuInfo.MenuItemCount; u++)
{
if (MenuGetRosMenuItemInfo(MenuInfo.Self, u, &ItemInfo))
{
MenuDrawMenuItem(Wnd, &MenuInfo, MenuInfo.WndOwner, Dc, &ItemInfo,
MenuInfo.Height, FALSE, ODA_DRAWENTIRE);
}
}
MenuCleanupRosMenuItemInfo(&ItemInfo);
}
}
else
{
SelectObject(Dc, PrevBrush);
}
}
}
static LRESULT WINAPI
PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
DPRINT("hwnd=%x msg=0x%04x wp=0x%04x lp=0x%08lx\n", Wnd, Message, wParam, lParam);
switch(Message)
{
case WM_CREATE:
{
CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
SetWindowLongPtrW(Wnd, 0, (LONG) cs->lpCreateParams);
return 0;
}
case WM_MOUSEACTIVATE: /* We don't want to be activated */
return MA_NOACTIVATE;
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(Wnd, &ps);
MenuDrawPopupMenu(Wnd, ps.hdc, (HMENU)GetWindowLongPtrW(Wnd, 0));
EndPaint(Wnd, &ps);
return 0;
}
case WM_ERASEBKGND:
return 1;
case WM_DESTROY:
/* zero out global pointer in case resident popup window was destroyed. */
if (Wnd == TopPopup)
{
TopPopup = NULL;
}
break;
case WM_SHOWWINDOW:
if (0 != wParam)
{
if (0 == GetWindowLongPtrW(Wnd, 0))
{
OutputDebugStringA("no menu to display\n");
}
}
else
{
SetWindowLongPtrW(Wnd, 0, 0);
}
break;
case MM_SETMENUHANDLE:
SetWindowLongPtrW(Wnd, 0, wParam);
break;
case MM_GETMENUHANDLE:
return GetWindowLongPtrW(Wnd, 0);
default:
return DefWindowProcW(Wnd, Message, wParam, lParam);
}
return 0;
}
/**********************************************************************
* MENUEX_ParseResource
*
* Parse an extended menu resource and add items to the menu.
* Return a pointer to the end of the resource.
*
* FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
*/
static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
{
WORD resinfo;
do
{
MENUITEMINFOW mii;
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE;
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);
res += sizeof(WORD);
/* Align the text on a word boundary. */
res += (~((int)res - 1)) & 1;
mii.dwTypeData = (LPWSTR) res;
res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
/* Align the following fields on a dword boundary. */
res += (~((int)res - 1)) & 3;
if (resinfo & 1) /* Pop-up? */
{
/* DWORD helpid = GET_DWORD(res); FIXME: use this. */
res += sizeof(DWORD);
mii.hSubMenu = CreatePopupMenu();
if (!mii.hSubMenu)
return NULL;
if (!(res = MENUEX_ParseResource(res, mii.hSubMenu)))
{
DestroyMenu(mii.hSubMenu);
return NULL;
}
mii.fMask |= MIIM_SUBMENU;
mii.fType |= MF_POPUP;
}
else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
{
mii.fType |= MF_SEPARATOR;
}
InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
}
while (!(resinfo & MF_END));
return res;
}
/**********************************************************************
* MENU_ParseResource
*
* Parse a standard menu resource and add items to the menu.
* Return a pointer to the end of the resource.
*
* NOTE: flags is equivalent to the mtOption field
*/
static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
{
WORD flags, id = 0;
HMENU hSubMenu;
LPCSTR str;
BOOL end = FALSE;
do
{
flags = GET_WORD(res);
/* remove MF_END flag before passing it to AppendMenu()! */
end = (flags & MF_END);
if(end) flags ^= MF_END;
res += sizeof(WORD);
if(!(flags & MF_POPUP))
{
id = GET_WORD(res);
res += sizeof(WORD);
}
str = res;
if(!unicode)
res += strlen(str) + 1;
else
res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
if (flags & MF_POPUP)
{
hSubMenu = CreatePopupMenu();
if(!hSubMenu) return NULL;
if(!(res = MENU_ParseResource(res, hSubMenu, unicode)))
return NULL;
if(!unicode)
AppendMenuA(hMenu, flags, (UINT)hSubMenu, str);
else
AppendMenuW(hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str);
}
else /* Not a popup */
{
if(!unicode)
AppendMenuA(hMenu, flags, id, *str ? str : NULL);
else
AppendMenuW(hMenu, flags, id,
*(LPCWSTR)str ? (LPCWSTR)str : NULL);
}
} while(!end);
return res;
}
NTSTATUS STDCALL
User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength)
{
LRESULT Result;
Result = (LRESULT)LoadMenuW(User32Instance, L"SYSMENU");
return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
}
BOOL
MenuInit(VOID)
{
NONCLIENTMETRICSW ncm;
/* get the menu font */
if(!hMenuFont || !hMenuFontBold)
{
ncm.cbSize = sizeof(ncm);
if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
{
DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
return FALSE;
}
hMenuFont = CreateFontIndirectW(&ncm.lfMenuFont);
if(hMenuFont == NULL)
{
DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
return FALSE;
}
ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
hMenuFontBold = CreateFontIndirectW(&ncm.lfMenuFont);
if(hMenuFontBold == NULL)
{
DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
DeleteObject(hMenuFont);
hMenuFont = NULL;
return FALSE;
}
}
return TRUE;
}
VOID
MenuCleanup(VOID)
{
if (hMenuFont)
{
DeleteObject(hMenuFont);
hMenuFont = NULL;
}
if (hMenuFontBold)
{
DeleteObject(hMenuFontBold);
hMenuFontBold = NULL;
}
}
/***********************************************************************
* MenuCalcItemSize
*
* Calculate the size of the menu item and store it in ItemInfo->rect.
*/
static void FASTCALL
MenuCalcItemSize(HDC Dc, PROSMENUITEMINFO ItemInfo, PROSMENUINFO MenuInfo, HWND WndOwner,
INT OrgX, INT OrgY, BOOL MenuBar)
{
PWCHAR p;
INT itemheight = 0;
UINT CheckBitmapWidth = GetSystemMetrics(SM_CXMENUCHECK);
DPRINT("dc=%x owner=%x (%d,%d)\n", Dc, WndOwner, OrgX, OrgY);
MenuCharSize.cx = GdiGetCharDimensions( Dc, NULL, &MenuCharSize.cy );
SetRect(&ItemInfo->Rect, OrgX, OrgY, OrgX, OrgY);
if (0 != (ItemInfo->fType & MF_OWNERDRAW))
{
/*
** Experimentation under Windows reveals that an owner-drawn
** menu is expected to return the size of the content part of
** the menu item, not including the checkmark nor the submenu
** arrow. Windows adds those values itself and returns the
** enlarged rectangle on subsequent WM_DRAWITEM messages.
*/
MEASUREITEMSTRUCT mis;
mis.CtlType = ODT_MENU;
mis.CtlID = 0;
mis.itemID = ItemInfo->wID;
mis.itemData = (DWORD)ItemInfo->dwItemData;
mis.itemHeight = HIWORD( GetDialogBaseUnits());
mis.itemWidth = 0;
SendMessageW(WndOwner, WM_MEASUREITEM, 0, (LPARAM) &mis);
/* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
* width of a menufont character to the width of an owner-drawn menu.
*/
ItemInfo->Rect.right += mis.itemWidth + 2 * MenuCharSize.cx;
if (MenuBar)
{
/* under at least win95 you seem to be given a standard
height for the menu and the height value is ignored */
ItemInfo->Rect.bottom += GetSystemMetrics(SM_CYMENUSIZE);
}
else
{
ItemInfo->Rect.bottom += mis.itemHeight;
}
DPRINT("id=%04x size=%dx%d\n", ItemInfo->wID, mis.itemWidth, mis.itemHeight);
return;
}
if (0 != (ItemInfo->fType & MF_SEPARATOR))
{
ItemInfo->Rect.bottom += SEPARATOR_HEIGHT;
if( !MenuBar)
ItemInfo->Rect.right += ArrowBitmapWidth + MenuCharSize.cx;
return;
}
ItemInfo->XTab = 0;
if (ItemInfo->hbmpItem)
{
SIZE Size;
if (!MenuBar) /* hbmpItem */
{
MenuGetBitmapItemSize(ItemInfo, &Size, WndOwner );
/* Keep the size of the bitmap in callback mode to be able
* to draw it correctly */
ItemInfo->Rect.right = ItemInfo->Rect.left + Size.cx;
if (MenuInfo->maxBmpSize.cx < abs(Size.cx) + MENU_ITEM_HBMP_SPACE ||
MenuInfo->maxBmpSize.cy < abs(Size.cy))
{
MenuInfo->maxBmpSize.cx = abs(Size.cx) + MENU_ITEM_HBMP_SPACE;
MenuInfo->maxBmpSize.cy = abs(Size.cy);
}
MenuSetRosMenuInfo(MenuInfo);
ItemInfo->Rect.right += Size.cx + 2;
itemheight = Size.cy + 2;
if( !(MenuInfo->dwStyle & MNS_NOCHECK))
ItemInfo->Rect.right += 2 * CheckBitmapWidth;
ItemInfo->Rect.right += 4 + MenuCharSize.cx;
ItemInfo->XTab = ItemInfo->Rect.right;
ItemInfo->Rect.right += ArrowBitmapWidth;
}
else /* hbmpItem & MenuBar */
{
MenuGetBitmapItemSize(ItemInfo, &Size, WndOwner );
ItemInfo->Rect.right += Size.cx;
if( ItemInfo->Text) ItemInfo->Rect.right += 2;
itemheight = Size.cy;
/* Special case: Minimize button doesn't have a space behind it. */
if (ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE ||
ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D)
ItemInfo->Rect.right -= 1;
}
}
else if (!MenuBar)
{
if( !(MenuInfo->dwStyle & MNS_NOCHECK))
ItemInfo->Rect.right += CheckBitmapWidth;
ItemInfo->Rect.right += 4 + MenuCharSize.cx;
ItemInfo->XTab = ItemInfo->Rect.right;
ItemInfo->Rect.right += ArrowBitmapWidth;
}
/* it must be a text item - unless it's the system menu */
if (0 == (ItemInfo->fType & MF_SYSMENU) && ItemInfo->Text)
{
HFONT hfontOld = NULL;
RECT rc = ItemInfo->Rect;
LONG txtheight, txtwidth;
if ( ItemInfo->fState & MFS_DEFAULT )
{
hfontOld = SelectObject( Dc, hMenuFontBold );
}
if (MenuBar)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -