📄 cursoricon.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.
*/
/*
* We handle two types of cursors/icons:
* - Private
* Loaded without LR_SHARED flag
* Private to a process
* Can be deleted by calling NtDestroyCursorIcon()
* CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
* - Shared
* Loaded with LR_SHARED flag
* Possibly shared by multiple processes
* Immune to NtDestroyCursorIcon()
* CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
* There's a M:N relationship between processes and (shared) cursor/icons.
* A process can have multiple cursor/icons and a cursor/icon can be used
* by multiple processes. To keep track of this we keep a list of all
* cursor/icons (CurIconList) and per cursor/icon we keep a list of
* CURICON_PROCESS structs starting at CurIcon->ProcessList.
*/
#include <w32k.h>
#define NDEBUG
#include <debug.h>
static PAGED_LOOKASIDE_LIST gProcessLookasideList;
static LIST_ENTRY gCurIconList;
/* Look up the location of the cursor in the GDIDEVICE structure
* when all we know is the window station object
* Actually doesn't use the window station, but should... */
BOOL FASTCALL
IntGetCursorLocation(PWINSTATION_OBJECT WinSta, POINT *loc)
{
HDC hDC;
PDC dc;
GDIDEVICE *GDIDevice;
#if 1
/* FIXME - get the screen dc from the window station or desktop */
if (!(hDC = IntGetScreenDC()))
return FALSE;
#endif
if (!(dc = DC_LockDc(hDC)))
return FALSE;
GDIDevice = (GDIDEVICE *)dc->GDIDevice;
DC_UnlockDc(dc);
loc->x = GDIDevice->Pointer.Pos.x;
loc->y = GDIDevice->Pointer.Pos.y;
return TRUE;
}
PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
{
PCURICON_OBJECT CurIcon;
if (!hCurIcon)
{
SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
return NULL;
}
CurIcon = (PCURICON_OBJECT)UserGetObject(gHandleTable, hCurIcon, otCursorIcon);
if (!CurIcon)
{
/* we never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
return NULL;
}
ASSERT(USER_BODY_TO_HEADER(CurIcon)->RefCount >= 0);
return CurIcon;
}
#define COLORCURSORS_ALLOWED FALSE
HCURSOR FASTCALL
IntSetCursor(PWINSTATION_OBJECT WinSta, PCURICON_OBJECT NewCursor,
BOOL ForceChange)
{
BITMAPOBJ *BitmapObj;
SURFOBJ *SurfObj;
PDEVINFO DevInfo;
PBITMAPOBJ MaskBmpObj = NULL;
PSYSTEM_CURSORINFO CurInfo;
PCURICON_OBJECT OldCursor;
HCURSOR Ret = (HCURSOR)0;
HBITMAP dcbmp, hColor = (HBITMAP)0;
HBITMAP hMask = 0;
SURFOBJ *soMask = NULL, *soColor = NULL;
XLATEOBJ *XlateObj = NULL;
HDC Screen;
PDC dc;
CurInfo = IntGetSysCursorInfo(WinSta);
OldCursor = CurInfo->CurrentCursorObject;
if (OldCursor)
{
Ret = (HCURSOR)OldCursor->Self;
}
if (!ForceChange && OldCursor == NewCursor)
{
return Ret;
}
else
{
if(!(Screen = IntGetScreenDC()))
{
return (HCURSOR)0;
}
/* FIXME use the desktop's HDC instead of using ScreenDeviceContext */
dc = DC_LockDc(Screen);
if (!dc)
{
return Ret;
}
dcbmp = dc->w.hBitmap;
DevInfo = dc->DevInfo;
DC_UnlockDc(dc);
BitmapObj = BITMAPOBJ_LockBitmap(dcbmp);
if ( !BitmapObj )
return (HCURSOR)0;
SurfObj = &BitmapObj->SurfObj;
ASSERT(SurfObj);
}
if (!NewCursor && (CurInfo->CurrentCursorObject || ForceChange))
{
if (NULL != CurInfo->CurrentCursorObject && CurInfo->ShowingCursor)
{
/* Remove the cursor if it was displayed */
IntEngMovePointer(SurfObj, -1, -1, &GDIDEV(SurfObj)->Pointer.Exclude);
}
GDIDEV(SurfObj)->Pointer.Status = SPS_ACCEPT_NOEXCLUDE;
CurInfo->CurrentCursorObject = NewCursor; /* i.e. CurrentCursorObject = NULL */
CurInfo->ShowingCursor = 0;
BITMAPOBJ_UnlockBitmap(BitmapObj);
return Ret;
}
if (!NewCursor)
{
BITMAPOBJ_UnlockBitmap(BitmapObj);
return Ret;
}
/* TODO: Fixme. Logic is screwed above */
ASSERT(NewCursor);
MaskBmpObj = BITMAPOBJ_LockBitmap(NewCursor->IconInfo.hbmMask);
if (MaskBmpObj)
{
const int maskBpp = BitsPerFormat(MaskBmpObj->SurfObj.iBitmapFormat);
BITMAPOBJ_UnlockBitmap(MaskBmpObj);
if (maskBpp != 1)
{
DPRINT1("SetCursor: The Mask bitmap must have 1BPP!\n");
BITMAPOBJ_UnlockBitmap(BitmapObj);
return Ret;
}
if ((DevInfo->flGraphicsCaps2 & GCAPS2_ALPHACURSOR) &&
SurfObj->iBitmapFormat >= BMF_16BPP &&
SurfObj->iBitmapFormat <= BMF_32BPP &&
NewCursor->Shadow && COLORCURSORS_ALLOWED)
{
/* FIXME - Create a color pointer, only 32bit bitmap, set alpha bits!
Do not pass a mask bitmap to DrvSetPointerShape()!
Create a XLATEOBJ that describes the colors of the bitmap. */
DPRINT1("SetCursor: (Colored) alpha cursors are not supported!\n");
}
else
{
if(NewCursor->IconInfo.hbmColor
&& COLORCURSORS_ALLOWED)
{
/* FIXME - Create a color pointer, create only one 32bit bitmap!
Do not pass a mask bitmap to DrvSetPointerShape()!
Create a XLATEOBJ that describes the colors of the bitmap.
(16bit bitmaps are propably allowed) */
DPRINT1("SetCursor: Cursors with colors are not supported!\n");
}
else
{
MaskBmpObj = BITMAPOBJ_LockBitmap(NewCursor->IconInfo.hbmMask);
if(MaskBmpObj)
{
RECTL DestRect = {0, 0, MaskBmpObj->SurfObj.sizlBitmap.cx, MaskBmpObj->SurfObj.sizlBitmap.cy};
POINTL SourcePoint = {0, 0};
/*
* NOTE: For now we create the cursor in top-down bitmap,
* because VMware driver rejects it otherwise. This should
* be fixed later.
*/
hMask = EngCreateBitmap(
MaskBmpObj->SurfObj.sizlBitmap, abs(MaskBmpObj->SurfObj.lDelta),
MaskBmpObj->SurfObj.iBitmapFormat, BMF_TOPDOWN,
NULL);
if ( !hMask )
{
BITMAPOBJ_UnlockBitmap(MaskBmpObj);
BITMAPOBJ_UnlockBitmap(BitmapObj);
return (HCURSOR)0;
}
soMask = EngLockSurface((HSURF)hMask);
EngCopyBits(soMask, &MaskBmpObj->SurfObj, NULL, NULL,
&DestRect, &SourcePoint);
BITMAPOBJ_UnlockBitmap(MaskBmpObj);
}
}
}
CurInfo->ShowingCursor = CURSOR_SHOWING;
CurInfo->CurrentCursorObject = NewCursor;
}
else
{
CurInfo->ShowingCursor = 0;
CurInfo->CurrentCursorObject = NULL;
}
if (GDIDEVFUNCS(SurfObj).SetPointerShape)
{
GDIDEV(SurfObj)->Pointer.Status =
GDIDEVFUNCS(SurfObj).SetPointerShape(
SurfObj, soMask, soColor, XlateObj,
NewCursor->IconInfo.xHotspot,
NewCursor->IconInfo.yHotspot,
GDIDEV(SurfObj)->Pointer.Pos.x,
GDIDEV(SurfObj)->Pointer.Pos.y,
&(GDIDEV(SurfObj)->Pointer.Exclude),
SPS_CHANGE);
DPRINT("SetCursor: DrvSetPointerShape() returned %x\n",
GDIDEV(SurfObj)->Pointer.Status);
}
else
{
GDIDEV(SurfObj)->Pointer.Status = SPS_DECLINE;
}
if(GDIDEV(SurfObj)->Pointer.Status == SPS_DECLINE)
{
GDIDEV(SurfObj)->Pointer.Status = EngSetPointerShape(
SurfObj, soMask, soColor, XlateObj,
NewCursor->IconInfo.xHotspot,
NewCursor->IconInfo.yHotspot,
GDIDEV(SurfObj)->Pointer.Pos.x,
GDIDEV(SurfObj)->Pointer.Pos.y,
&(GDIDEV(SurfObj)->Pointer.Exclude),
SPS_CHANGE);
GDIDEV(SurfObj)->Pointer.MovePointer = NULL;
}
else
{
GDIDEV(SurfObj)->Pointer.MovePointer = GDIDEVFUNCS(SurfObj).MovePointer;
}
BITMAPOBJ_UnlockBitmap(BitmapObj);
if(hMask)
{
EngUnlockSurface(soMask);
EngDeleteSurface((HSURF)hMask);
}
if(hColor)
{
EngDeleteSurface((HSURF)hColor);
}
if(XlateObj)
{
EngDeleteXlate(XlateObj);
}
if(GDIDEV(SurfObj)->Pointer.Status == SPS_ERROR)
DPRINT1("SetCursor: DrvSetPointerShape() returned SPS_ERROR\n");
return Ret;
}
BOOL FASTCALL
IntSetupCurIconHandles(PWINSTATION_OBJECT WinSta)
{
ExInitializePagedLookasideList(&gProcessLookasideList,
NULL,
NULL,
0,
sizeof(CURICON_PROCESS),
0,
128);
InitializeListHead(&gCurIconList);
return TRUE;
}
/*
* We have to register that this object is in use by the current
* process. The only way to do that seems to be to walk the list
* of cursor/icon objects starting at W32Process->CursorIconListHead.
* If the object is already present in the list, we don't have to do
* anything, if it's not present we add it and inc the ProcessCount
* in the object. Having to walk the list kind of sucks, but that's
* life...
*/
static BOOLEAN FASTCALL
ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
{
PW32PROCESS Win32Process;
PCURICON_PROCESS Current;
Win32Process = PsGetCurrentProcessWin32Process();
LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
{
if (Current->Process == Win32Process)
{
/* Already registered for this process */
return TRUE;
}
}
/* Not registered yet */
Current = ExAllocateFromPagedLookasideList(&gProcessLookasideList);
if (NULL == Current)
{
return FALSE;
}
InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
Current->Process = Win32Process;
return TRUE;
}
PCURICON_OBJECT FASTCALL
IntFindExistingCurIconObject(PWINSTATION_OBJECT WinSta, HMODULE hModule,
HRSRC hRsrc, LONG cx, LONG cy)
{
PCURICON_OBJECT CurIcon;
LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
{
// if(NT_SUCCESS(ObmReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
// ObmReferenceObject( CurIcon);
// {
if((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
{
if(cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
{
// ObmDereferenceObject(CurIcon);
continue;
}
if (! ReferenceCurIconByProcess(CurIcon))
{
return NULL;
}
return CurIcon;
}
// }
// ObmDereferenceObject(CurIcon);
}
return NULL;
}
PCURICON_OBJECT FASTCALL
IntCreateCurIconHandle(PWINSTATION_OBJECT WinSta)
{
PCURICON_OBJECT CurIcon;
HANDLE hCurIcon;
CurIcon = ObmCreateObject(gHandleTable, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));
if(!CurIcon)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
CurIcon->Self = hCurIcon;
InitializeListHead(&CurIcon->ProcessList);
if (! ReferenceCurIconByProcess(CurIcon))
{
DPRINT1("Failed to add process\n");
ObmDeleteObject(hCurIcon, otCursorIcon);
ObmDereferenceObject(CurIcon);
return NULL;
}
InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
ObmDereferenceObject(CurIcon);
return CurIcon;
}
BOOLEAN FASTCALL
IntDestroyCurIconObject(PWINSTATION_OBJECT WinSta, PCURICON_OBJECT CurIcon, BOOL ProcessCleanup)
{
PSYSTEM_CURSORINFO CurInfo;
HBITMAP bmpMask, bmpColor;
BOOLEAN Ret;
PCURICON_PROCESS Current = NULL;
PW32PROCESS W32Process = PsGetCurrentProcessWin32Process();
/* Private objects can only be destroyed by their own process */
if (NULL == CurIcon->hModule)
{
ASSERT(CurIcon->ProcessList.Flink->Flink == &CurIcon->ProcessList);
Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
if (Current->Process != W32Process)
{
DPRINT1("Trying to destroy private icon/cursor of another process\n");
return FALSE;
}
}
else if (! ProcessCleanup)
{
DPRINT("Trying to destroy shared icon/cursor\n");
return FALSE;
}
/* Now find this process in the list of processes referencing this object and
remove it from that list */
LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
{
if (Current->Process == W32Process)
{
RemoveEntryList(&Current->ListEntry);
break;
}
}
ExFreeToPagedLookasideList(&gProcessLookasideList, Current);
/* If there are still processes referencing this object we can't destroy it yet */
if (! IsListEmpty(&CurIcon->ProcessList))
{
return TRUE;
}
if (! ProcessCleanup)
{
RemoveEntryList(&CurIcon->ListEntry);
}
CurInfo = IntGetSysCursorInfo(WinSta);
if (CurInfo->CurrentCursorObject == CurIcon)
{
/* Hide the cursor if we're destroying the current cursor */
IntSetCursor(WinSta, NULL, TRUE);
}
bmpMask = CurIcon->IconInfo.hbmMask;
bmpColor = CurIcon->IconInfo.hbmColor;
Ret = ObmDeleteObject(CurIcon->Self, otCursorIcon);
/* delete bitmaps */
if(bmpMask)
{
GDIOBJ_SetOwnership(GdiHandleTable, bmpMask, PsGetCurrentProcess());
NtGdiDeleteObject(bmpMask);
}
if(bmpColor)
{
GDIOBJ_SetOwnership(GdiHandleTable, bmpColor, PsGetCurrentProcess());
NtGdiDeleteObject(bmpColor);
}
return Ret;
}
VOID FASTCALL
IntCleanupCurIcons(struct _EPROCESS *Process, PW32PROCESS Win32Process)
{
PWINSTATION_OBJECT WinSta;
PCURICON_OBJECT CurIcon, tmp;
PCURICON_PROCESS ProcessData;
WinSta = IntGetWinStaObj();
if(WinSta == NULL)
{
return;
}
LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
{
// ObmReferenceObject(CurIcon);
// if(NT_SUCCESS(ObmReferenceObjectByPointer(Object, otCursorIcon)))
{
LIST_FOR_EACH(ProcessData, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
{
if (Win32Process == ProcessData->Process)
{
RemoveEntryList(&CurIcon->ListEntry);
IntDestroyCurIconObject(WinSta, CurIcon, TRUE);
break;
}
}
// ObmDereferenceObject(Object);
}
}
ObDereferenceObject(WinSta);
}
/*
* @implemented
*/
HANDLE
STDCALL
NtUserCreateCursorIconHandle(PICONINFO IconInfo OPTIONAL, BOOL Indirect)
{
PCURICON_OBJECT CurIcon;
PWINSTATION_OBJECT WinSta;
PBITMAPOBJ bmp;
NTSTATUS Status;
HANDLE Ret;
DECLARE_RETURN(HANDLE);
DPRINT("Enter NtUserCreateCursorIconHandle\n");
UserEnterExclusive();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -