📄 menu.c
字号:
/*
* ReactOS W32 Subsystem
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: menu.c 27161 2007-06-12 19:35:15Z janderwald $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Menus
* FILE: subsys/win32k/ntuser/menu.c
* PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
* REVISION HISTORY:
* 07/30/2003 CSH Created
*/
/* INCLUDES ******************************************************************/
#include <w32k.h>
#define NDEBUG
#include <debug.h>
PMENU_OBJECT FASTCALL
IntGetSystemMenu(PWINDOW_OBJECT Window, BOOL bRevert, BOOL RetMenu);
/* STATIC FUNCTION ***********************************************************/
static
BOOL FASTCALL
UserMenuItemInfo(
PMENU_OBJECT Menu,
UINT Item,
BOOL ByPosition,
PROSMENUITEMINFO UnsafeItemInfo,
BOOL SetOrGet);
static
BOOL FASTCALL
UserMenuInfo(
PMENU_OBJECT Menu,
PROSMENUINFO UnsafeMenuInfo,
BOOL SetOrGet);
/* INTERNAL ******************************************************************/
/* maximum number of menu items a menu can contain */
#define MAX_MENU_ITEMS (0x4000)
#define MAX_GOINTOSUBMENU (0x10)
#define UpdateMenuItemState(state, change) \
{\
if((change) & MFS_DISABLED) { \
(state) |= MFS_DISABLED; \
} else { \
(state) &= ~MFS_DISABLED; \
} \
if((change) & MFS_CHECKED) { \
(state) |= MFS_CHECKED; \
} else { \
(state) &= ~MFS_CHECKED; \
} \
if((change) & MFS_HILITE) { \
(state) |= MFS_HILITE; \
} else { \
(state) &= ~MFS_HILITE; \
} \
if((change) & MFS_DEFAULT) { \
(state) |= MFS_DEFAULT; \
} else { \
(state) &= ~MFS_DEFAULT; \
} \
if((change) & MF_MOUSESELECT) { \
(state) |= MF_MOUSESELECT; \
} else { \
(state) &= ~MF_MOUSESELECT; \
} \
}
#define FreeMenuText(MenuItem) \
{ \
if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
(MenuItem)->Text.Length) { \
RtlFreeUnicodeString(&(MenuItem)->Text); \
} \
}
#define InRect(r, x, y) \
( ( ((r).right >= x)) && \
( ((r).left <= x)) && \
( ((r).bottom >= y)) && \
( ((r).top <= y)) )
NTSTATUS FASTCALL
InitMenuImpl(VOID)
{
return(STATUS_SUCCESS);
}
NTSTATUS FASTCALL
CleanupMenuImpl(VOID)
{
return(STATUS_SUCCESS);
}
PMENU_OBJECT FASTCALL UserGetMenuObject(HMENU hMenu)
{
PMENU_OBJECT Menu;
if (!hMenu)
{
SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
return NULL;
}
Menu = (PMENU_OBJECT)UserGetObject(gHandleTable, hMenu, otMenu);
if (!Menu)
{
SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
return NULL;
}
ASSERT(USER_BODY_TO_HEADER(Menu)->RefCount >= 0);
return Menu;
}
#if 0
void FASTCALL
DumpMenuItemList(PMENU_ITEM MenuItem)
{
UINT cnt = 0;
while(MenuItem)
{
if(MenuItem->Text.Length)
DbgPrint(" %d. %wZ\n", ++cnt, &MenuItem->Text);
else
DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt, (DWORD)MenuItem->Text.Buffer);
DbgPrint(" fType=");
if(MFT_BITMAP & MenuItem->fType)
DbgPrint("MFT_BITMAP ");
if(MFT_MENUBARBREAK & MenuItem->fType)
DbgPrint("MFT_MENUBARBREAK ");
if(MFT_MENUBREAK & MenuItem->fType)
DbgPrint("MFT_MENUBREAK ");
if(MFT_OWNERDRAW & MenuItem->fType)
DbgPrint("MFT_OWNERDRAW ");
if(MFT_RADIOCHECK & MenuItem->fType)
DbgPrint("MFT_RADIOCHECK ");
if(MFT_RIGHTJUSTIFY & MenuItem->fType)
DbgPrint("MFT_RIGHTJUSTIFY ");
if(MFT_SEPARATOR & MenuItem->fType)
DbgPrint("MFT_SEPARATOR ");
if(MFT_STRING & MenuItem->fType)
DbgPrint("MFT_STRING ");
DbgPrint("\n fState=");
if(MFS_DISABLED & MenuItem->fState)
DbgPrint("MFS_DISABLED ");
else
DbgPrint("MFS_ENABLED ");
if(MFS_CHECKED & MenuItem->fState)
DbgPrint("MFS_CHECKED ");
else
DbgPrint("MFS_UNCHECKED ");
if(MFS_HILITE & MenuItem->fState)
DbgPrint("MFS_HILITE ");
else
DbgPrint("MFS_UNHILITE ");
if(MFS_DEFAULT & MenuItem->fState)
DbgPrint("MFS_DEFAULT ");
if(MFS_GRAYED & MenuItem->fState)
DbgPrint("MFS_GRAYED ");
DbgPrint("\n wId=%d\n", MenuItem->wID);
MenuItem = MenuItem->Next;
}
DbgPrint("Entries: %d\n", cnt);
return;
}
#endif
PMENU_OBJECT FASTCALL
IntGetMenuObject(HMENU hMenu)
{
PMENU_OBJECT Menu = UserGetMenuObject(hMenu);
if (Menu)
{
ASSERT(USER_BODY_TO_HEADER(Menu)->RefCount >= 0);
USER_BODY_TO_HEADER(Menu)->RefCount++;
}
return Menu;
}
BOOL FASTCALL
IntFreeMenuItem(PMENU_OBJECT Menu, PMENU_ITEM MenuItem,
BOOL RemoveFromList, BOOL bRecurse)
{
FreeMenuText(MenuItem);
if(RemoveFromList)
{
PMENU_ITEM CurItem = Menu->MenuItemList;
while(CurItem)
{
if (CurItem->Next == MenuItem)
{
CurItem->Next = MenuItem->Next;
break;
}
else
{
CurItem = CurItem->Next;
}
}
Menu->MenuInfo.MenuItemCount--;
}
if(bRecurse && MenuItem->hSubMenu)
{
PMENU_OBJECT SubMenu;
SubMenu = UserGetMenuObject(MenuItem->hSubMenu );
if(SubMenu)
{
IntDestroyMenuObject(SubMenu, bRecurse, TRUE);
}
}
/* Free memory */
ExFreePool(MenuItem);
return TRUE;
}
BOOL FASTCALL
IntRemoveMenuItem(PMENU_OBJECT Menu, UINT uPosition, UINT uFlags,
BOOL bRecurse)
{
PMENU_ITEM PrevMenuItem, MenuItem;
if(IntGetMenuItemByFlag(Menu, uPosition, uFlags, &MenuItem,
&PrevMenuItem) > -1)
{
if(MenuItem)
{
if(PrevMenuItem)
PrevMenuItem->Next = MenuItem->Next;
else
{
Menu->MenuItemList = MenuItem->Next;
}
return IntFreeMenuItem(Menu, MenuItem, TRUE, bRecurse);
}
}
return FALSE;
}
UINT FASTCALL
IntDeleteMenuItems(PMENU_OBJECT Menu, BOOL bRecurse)
{
UINT res = 0;
PMENU_ITEM NextItem;
PMENU_ITEM CurItem = Menu->MenuItemList;
while(CurItem)
{
NextItem = CurItem->Next;
IntFreeMenuItem(Menu, CurItem, FALSE, bRecurse);
CurItem = NextItem;
res++;
}
Menu->MenuInfo.MenuItemCount = 0;
Menu->MenuItemList = NULL;
return res;
}
BOOL FASTCALL
IntDestroyMenuObject(PMENU_OBJECT Menu,
BOOL bRecurse, BOOL RemoveFromProcess)
{
if(Menu)
{
PWINDOW_OBJECT Window;
PWINSTATION_OBJECT WindowStation;
NTSTATUS Status;
/* remove all menu items */
IntDeleteMenuItems(Menu, bRecurse); /* do not destroy submenus */
if(RemoveFromProcess)
{
RemoveEntryList(&Menu->ListEntry);
}
Status = ObReferenceObjectByHandle(Menu->Process->Win32WindowStation,
0,
ExWindowStationObjectType,
KernelMode,
(PVOID*)&WindowStation,
NULL);
if(NT_SUCCESS(Status))
{
if (Menu->MenuInfo.Wnd)
{
Window = UserGetWindowObject(Menu->MenuInfo.Wnd);
if (Window)
{
Window->IDMenu = 0;
}
}
ObmDeleteObject(Menu->MenuInfo.Self, otMenu);
ObDereferenceObject(WindowStation);
return TRUE;
}
}
return FALSE;
}
PMENU_OBJECT FASTCALL
IntCreateMenu(PHANDLE Handle, BOOL IsMenuBar)
{
PMENU_OBJECT Menu;
Menu = (PMENU_OBJECT)ObmCreateObject(
gHandleTable, Handle,
otMenu, sizeof(MENU_OBJECT));
if(!Menu)
{
*Handle = 0;
return NULL;
}
Menu->Process = PsGetCurrentProcess();
Menu->RtoL = FALSE; /* default */
Menu->MenuInfo.cbSize = sizeof(MENUINFO); /* not used */
Menu->MenuInfo.fMask = 0; /* not used */
Menu->MenuInfo.dwStyle = 0; /* FIXME */
Menu->MenuInfo.cyMax = 0; /* default */
Menu->MenuInfo.hbrBack =
NtGdiCreateSolidBrush(RGB(192, 192, 192), 0); /* FIXME: default background color */
Menu->MenuInfo.dwContextHelpID = 0; /* default */
Menu->MenuInfo.dwMenuData = 0; /* default */
Menu->MenuInfo.Self = *Handle;
Menu->MenuInfo.FocusedItem = NO_SELECTED_ITEM;
Menu->MenuInfo.Flags = (IsMenuBar ? 0 : MF_POPUP);
Menu->MenuInfo.Wnd = NULL;
Menu->MenuInfo.WndOwner = NULL;
Menu->MenuInfo.Height = 0;
Menu->MenuInfo.Width = 0;
Menu->MenuInfo.TimeToHide = FALSE;
Menu->MenuInfo.MenuItemCount = 0;
Menu->MenuItemList = NULL;
/* Insert menu item into process menu handle list */
InsertTailList(&PsGetCurrentProcessWin32Process()->MenuListHead, &Menu->ListEntry);
return Menu;
}
BOOL FASTCALL
IntCloneMenuItems(PMENU_OBJECT Destination, PMENU_OBJECT Source)
{
PMENU_ITEM MenuItem, NewMenuItem = NULL;
PMENU_ITEM Old = NULL;
if(!Source->MenuInfo.MenuItemCount)
return FALSE;
MenuItem = Source->MenuItemList;
while(MenuItem)
{
Old = NewMenuItem;
if(NewMenuItem)
NewMenuItem->Next = MenuItem;
NewMenuItem = ExAllocatePoolWithTag(PagedPool, sizeof(MENU_ITEM), TAG_MENUITEM);
if(!NewMenuItem)
break;
NewMenuItem->fType = MenuItem->fType;
NewMenuItem->fState = MenuItem->fState;
NewMenuItem->wID = MenuItem->wID;
NewMenuItem->hSubMenu = MenuItem->hSubMenu;
NewMenuItem->hbmpChecked = MenuItem->hbmpChecked;
NewMenuItem->hbmpUnchecked = MenuItem->hbmpUnchecked;
NewMenuItem->dwItemData = MenuItem->dwItemData;
if((MENU_ITEM_TYPE(NewMenuItem->fType) == MF_STRING))
{
if(MenuItem->Text.Length)
{
NewMenuItem->Text.Length = 0;
NewMenuItem->Text.MaximumLength = MenuItem->Text.MaximumLength;
NewMenuItem->Text.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, MenuItem->Text.MaximumLength, TAG_STRING);
if(!NewMenuItem->Text.Buffer)
{
ExFreePool(NewMenuItem);
break;
}
RtlCopyUnicodeString(&NewMenuItem->Text, &MenuItem->Text);
}
else
{
NewMenuItem->Text.Buffer = MenuItem->Text.Buffer;
}
}
else
{
NewMenuItem->Text.Buffer = MenuItem->Text.Buffer;
}
NewMenuItem->hbmpItem = MenuItem->hbmpItem;
NewMenuItem->Next = NULL;
if(Old)
Old->Next = NewMenuItem;
else
Destination->MenuItemList = NewMenuItem;
Destination->MenuInfo.MenuItemCount++;
MenuItem = MenuItem->Next;
}
return TRUE;
}
PMENU_OBJECT FASTCALL
IntCloneMenu(PMENU_OBJECT Source)
{
HANDLE hMenu;
PMENU_OBJECT Menu;
if(!Source)
return NULL;
Menu = (PMENU_OBJECT)ObmCreateObject(
gHandleTable, &hMenu,
otMenu, sizeof(MENU_OBJECT));
if(!Menu)
return NULL;
Menu->Process = PsGetCurrentProcess();
Menu->RtoL = Source->RtoL;
Menu->MenuInfo.cbSize = sizeof(MENUINFO); /* not used */
Menu->MenuInfo.fMask = Source->MenuInfo.fMask;
Menu->MenuInfo.dwStyle = Source->MenuInfo.dwStyle;
Menu->MenuInfo.cyMax = Source->MenuInfo.cyMax;
Menu->MenuInfo.hbrBack = Source->MenuInfo.hbrBack;
Menu->MenuInfo.dwContextHelpID = Source->MenuInfo.dwContextHelpID;
Menu->MenuInfo.dwMenuData = Source->MenuInfo.dwMenuData;
Menu->MenuInfo.Self = hMenu;
Menu->MenuInfo.FocusedItem = NO_SELECTED_ITEM;
Menu->MenuInfo.Wnd = NULL;
Menu->MenuInfo.WndOwner = NULL;
Menu->MenuInfo.Height = 0;
Menu->MenuInfo.Width = 0;
Menu->MenuInfo.TimeToHide = FALSE;
Menu->MenuInfo.MenuItemCount = 0;
Menu->MenuItemList = NULL;
/* Insert menu item into process menu handle list */
InsertTailList(&PsGetCurrentProcessWin32Process()->MenuListHead, &Menu->ListEntry);
IntCloneMenuItems(Menu, Source);
return Menu;
}
BOOL FASTCALL
IntSetMenuFlagRtoL(PMENU_OBJECT Menu)
{
Menu->RtoL = TRUE;
return TRUE;
}
BOOL FASTCALL
IntSetMenuContextHelpId(PMENU_OBJECT Menu, DWORD dwContextHelpId)
{
Menu->MenuInfo.dwContextHelpID = dwContextHelpId;
return TRUE;
}
BOOL FASTCALL
IntGetMenuInfo(PMENU_OBJECT Menu, PROSMENUINFO lpmi)
{
if(lpmi->fMask & MIM_BACKGROUND)
lpmi->hbrBack = Menu->MenuInfo.hbrBack;
if(lpmi->fMask & MIM_HELPID)
lpmi->dwContextHelpID = Menu->MenuInfo.dwContextHelpID;
if(lpmi->fMask & MIM_MAXHEIGHT)
lpmi->cyMax = Menu->MenuInfo.cyMax;
if(lpmi->fMask & MIM_MENUDATA)
lpmi->dwMenuData = Menu->MenuInfo.dwMenuData;
if(lpmi->fMask & MIM_STYLE)
lpmi->dwStyle = Menu->MenuInfo.dwStyle;
if (sizeof(MENUINFO) < lpmi->cbSize)
{
RtlCopyMemory((char *) lpmi + sizeof(MENUINFO),
(char *) &Menu->MenuInfo + sizeof(MENUINFO),
lpmi->cbSize - sizeof(MENUINFO));
}
if (sizeof(ROSMENUINFO) == lpmi->cbSize)
{
lpmi->maxBmpSize.cx = Menu->MenuInfo.maxBmpSize.cx;
lpmi->maxBmpSize.cy = Menu->MenuInfo.maxBmpSize.cy;
}
return TRUE;
}
BOOL FASTCALL
IntIsMenu(HMENU hMenu)
{
PMENU_OBJECT Menu;
if((Menu = UserGetMenuObject(hMenu)))
{
return TRUE;
}
return FALSE;
}
BOOL FASTCALL
IntSetMenuInfo(PMENU_OBJECT Menu, PROSMENUINFO lpmi)
{
if(lpmi->fMask & MIM_BACKGROUND)
Menu->MenuInfo.hbrBack = lpmi->hbrBack;
if(lpmi->fMask & MIM_HELPID)
Menu->MenuInfo.dwContextHelpID = lpmi->dwContextHelpID;
if(lpmi->fMask & MIM_MAXHEIGHT)
Menu->MenuInfo.cyMax = lpmi->cyMax;
if(lpmi->fMask & MIM_MENUDATA)
Menu->MenuInfo.dwMenuData = lpmi->dwMenuData;
if(lpmi->fMask & MIM_STYLE)
Menu->MenuInfo.dwStyle = lpmi->dwStyle;
if(lpmi->fMask & MIM_APPLYTOSUBMENUS)
{
/* FIXME */
}
if (sizeof(MENUINFO) < lpmi->cbSize)
{
Menu->MenuInfo.FocusedItem = lpmi->FocusedItem;
Menu->MenuInfo.Height = lpmi->Height;
Menu->MenuInfo.Width = lpmi->Width;
Menu->MenuInfo.Wnd = lpmi->Wnd;
Menu->MenuInfo.WndOwner = lpmi->WndOwner;
Menu->MenuInfo.TimeToHide = lpmi->TimeToHide;
}
if (sizeof(ROSMENUINFO) == lpmi->cbSize)
{
Menu->MenuInfo.maxBmpSize.cx = lpmi->maxBmpSize.cx;
Menu->MenuInfo.maxBmpSize.cy = lpmi->maxBmpSize.cy;
}
return TRUE;
}
int FASTCALL
IntGetMenuItemByFlag(PMENU_OBJECT Menu, UINT uSearchBy, UINT fFlag,
PMENU_ITEM *MenuItem, PMENU_ITEM *PrevMenuItem)
{
PMENU_ITEM PrevItem = NULL;
PMENU_ITEM CurItem = Menu->MenuItemList;
int p;
int ret;
if(MF_BYPOSITION & fFlag)
{
p = uSearchBy;
while(CurItem && (p > 0))
{
PrevItem = CurItem;
CurItem = CurItem->Next;
p--;
}
if(CurItem)
{
if(MenuItem)
*MenuItem = CurItem;
if(PrevMenuItem)
*PrevMenuItem = PrevItem;
}
else
{
if(MenuItem)
*MenuItem = NULL;
if(PrevMenuItem)
*PrevMenuItem = NULL; /* ? */
return -1;
}
return uSearchBy - p;
}
else
{
p = 0;
while(CurItem)
{
if(CurItem->wID == uSearchBy)
{
if(MenuItem)
*MenuItem = CurItem;
if(PrevMenuItem)
*PrevMenuItem = PrevItem;
return p;
}
else if (0 != (CurItem->fType & MF_POPUP))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -