* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Win32k subsystem
* PURPOSE: Cursor and icon functions
- * FILE: subsystems/win32/win32k/ntuser/cursoricon.c
+ * FILE: win32ss/user/ntuser/cursoricon.c
* PROGRAMER: ReactOS Team
*/
/*
* 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 <win32k.h>
DBG_DEFAULT_CHANNEL(UserIcon);
-static PPAGED_LOOKASIDE_LIST pgProcessLookasideList;
-static LIST_ENTRY gCurIconList;
-
SYSTEM_CURSORINFO gSysCursorInfo;
BOOL
-InitCursorImpl()
+InitCursorImpl(VOID)
{
- pgProcessLookasideList = ExAllocatePool(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST));
- if(!pgProcessLookasideList)
- return FALSE;
-
- ExInitializePagedLookasideList(pgProcessLookasideList,
- NULL,
- NULL,
- 0,
- sizeof(CURICON_PROCESS),
- TAG_DIB,
- 128);
- InitializeListHead(&gCurIconList);
-
- gSysCursorInfo.Enabled = FALSE;
- gSysCursorInfo.ButtonsDown = 0;
- gSysCursorInfo.bClipped = FALSE;
- gSysCursorInfo.LastBtnDown = 0;
- gSysCursorInfo.CurrentCursorObject = NULL;
- gSysCursorInfo.ShowingCursor = -1;
- gSysCursorInfo.ClickLockActive = FALSE;
- gSysCursorInfo.ClickLockTime = 0;
+ gSysCursorInfo.Enabled = FALSE;
+ gSysCursorInfo.ButtonsDown = 0;
+ gSysCursorInfo.bClipped = FALSE;
+ gSysCursorInfo.LastBtnDown = 0;
+ gSysCursorInfo.CurrentCursorObject = NULL;
+ gSysCursorInfo.ShowingCursor = -1;
+ gSysCursorInfo.ClickLockActive = FALSE;
+ gSysCursorInfo.ClickLockTime = 0;
return TRUE;
}
return &gSysCursorInfo;
}
+FORCEINLINE
+BOOL
+is_icon(PCURICON_OBJECT object)
+{
+ return MAKEINTRESOURCE(object->rt) == RT_ICON;
+}
+
/* This function creates a reference for the object! */
PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
{
return NULL;
}
- CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, otCursorIcon);
+ if (UserObjectInDestroy(hCurIcon))
+ {
+ WARN("Requesting invalid/destroyed cursor.\n");
+ EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
+ return NULL;
+ }
+
+ CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, TYPE_CURSOR);
if (!CurIcon)
{
/* We never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
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)
+HANDLE
+IntCreateCurIconHandle(BOOLEAN Animated)
{
- PPROCESSINFO Win32Process;
- PCURICON_PROCESS Current;
-
- Win32Process = PsGetCurrentProcessWin32Process();
+ PCURICON_OBJECT CurIcon;
+ HANDLE hCurIcon;
- LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
- {
- if (Current->Process == Win32Process)
- {
- /* Already registered for this process */
- return TRUE;
- }
- }
+ CurIcon = UserCreateObject(
+ gHandleTable,
+ NULL,
+ GetW32ThreadInfo(),
+ &hCurIcon,
+ TYPE_CURSOR,
+ Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT));
- /* Not registered yet */
- Current = ExAllocateFromPagedLookasideList(pgProcessLookasideList);
- if (NULL == Current)
+ if (!CurIcon)
{
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
- InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
- Current->Process = Win32Process;
- return TRUE;
+ UserDereferenceObject(CurIcon);
+
+ return hCurIcon;
}
-PCURICON_OBJECT FASTCALL
-IntFindExistingCurIconObject(HMODULE hModule,
- HRSRC hRsrc, LONG cx, LONG cy)
+BOOLEAN
+IntDestroyCurIconObject(
+ _In_ PVOID Object)
{
- PCURICON_OBJECT CurIcon;
+ PCURICON_OBJECT CurIcon = Object;
- LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
+ /* Try finding it in its process cache */
+ if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
{
+ PPROCESSINFO ppi;
- // if (NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) // <- huh????
-// UserReferenceObject( CurIcon);
-// {
- if ((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
+ ppi = CurIcon->head.ppi;
+ if (ppi->pCursorCache == CurIcon)
{
- if (cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
- {
-// UserDereferenceObject(CurIcon);
- continue;
- }
- if (! ReferenceCurIconByProcess(CurIcon))
+ ppi->pCursorCache = CurIcon->pcurNext;
+ UserDereferenceObject(CurIcon);
+ }
+ else
+ {
+ PCURICON_OBJECT CacheCurIcon = ppi->pCursorCache;
+ while (CacheCurIcon)
{
- return NULL;
+ if (CacheCurIcon->pcurNext == CurIcon)
+ {
+ CacheCurIcon->pcurNext = CurIcon->pcurNext;
+ break;
+ }
+ CacheCurIcon = CacheCurIcon->pcurNext;
}
- return CurIcon;
+ /* We must have found it! */
+ ASSERT(CacheCurIcon != NULL);
+ UserDereferenceObject(CurIcon);
}
-// }
-// UserDereferenceObject(CurIcon);
-
- }
-
- return NULL;
-}
-
-PCURICON_OBJECT
-IntCreateCurIconHandle()
-{
- PCURICON_OBJECT CurIcon;
- HANDLE hCurIcon;
-
- CurIcon = UserCreateObject(gHandleTable, NULL, NULL, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));
-
- if (!CurIcon)
- {
- EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
-
- CurIcon->Self = hCurIcon;
- InitializeListHead(&CurIcon->ProcessList);
-
- if (! ReferenceCurIconByProcess(CurIcon))
- {
- ERR("Failed to add process\n");
- UserDeleteObject(hCurIcon, otCursorIcon);
- UserDereferenceObject(CurIcon);
- return NULL;
}
- InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
-
- return CurIcon;
+ /* We just mark the handle as being destroyed.
+ * Deleting all the stuff will be deferred to the actual struct free. */
+ return UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
}
-BOOLEAN FASTCALL
-IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi)
+void
+FreeCurIconObject(
+ _In_ PVOID Object)
{
- PSYSTEM_CURSORINFO CurInfo;
- HBITMAP bmpMask, bmpColor, bmpAlpha;
- BOOLEAN Ret, bListEmpty, bFound = FALSE;
- PCURICON_PROCESS Current = NULL;
+ PCURICON_OBJECT CurIcon = Object;
- /* For handles created without any data (error handling) */
- if(IsListEmpty(&CurIcon->ProcessList))
- goto emptyList;
-
- /* 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(!(CurIcon->CURSORF_flags & CURSORF_ACON))
{
- if (Current->Process == ppi)
+ HBITMAP bmpMask = CurIcon->hbmMask;
+ HBITMAP bmpColor = CurIcon->hbmColor;
+ HBITMAP bmpAlpha = CurIcon->hbmAlpha;
+
+ /* Delete bitmaps */
+ if (bmpMask)
{
- bFound = TRUE;
- bListEmpty = RemoveEntryList(&Current->ListEntry);
- break;
+ GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(bmpMask);
+ CurIcon->hbmMask = NULL;
}
- }
-
- if(!bFound)
- {
- /* This object doesn't belong to this process */
- EngSetLastError(ERROR_INVALID_HANDLE);
- return FALSE;
- }
-
- ExFreeToPagedLookasideList(pgProcessLookasideList, Current);
-
- /* If there are still processes referencing this object we can't destroy it yet */
- if (!bListEmpty)
- {
- if(CurIcon->head.ppi == ppi)
+ if (bmpColor)
{
- /* Set the first process of the list as owner */
- Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
- UserSetObjectOwner(CurIcon, otCursorIcon, Current->Process);
+ GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(bmpColor);
+ CurIcon->hbmColor = NULL;
+ }
+ if (bmpAlpha)
+ {
+ GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(bmpAlpha);
+ CurIcon->hbmAlpha = NULL;
}
- UserDereferenceObject(CurIcon);
- return TRUE;
}
-
-emptyList:
- /* Remove it from the list */
- RemoveEntryList(&CurIcon->ListEntry);
-
- CurInfo = IntGetSysCursorInfo();
-
- if (CurInfo->CurrentCursorObject == CurIcon)
+ else
{
- /* Hide the cursor if we're destroying the current cursor */
- UserSetCursor(NULL, TRUE);
- }
-
- bmpMask = CurIcon->aFrame[0].hbmMask;
- bmpColor = CurIcon->aFrame[0].hbmColor;
- bmpAlpha = CurIcon->aFrame[0].hbmAlpha;
+ PACON AniCurIcon = (PACON)CurIcon;
+ UINT i;
- /* Delete bitmaps */
- if (bmpMask)
- {
- GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(bmpMask);
- CurIcon->aFrame[0].hbmMask = NULL;
- }
- if (bmpColor)
- {
- GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(bmpColor);
- CurIcon->aFrame[0].hbmColor = NULL;
+ for(i = 0; i < AniCurIcon->cpcur; i++)
+ IntDestroyCurIconObject(AniCurIcon->aspcur[i]);
+ ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
}
- if (bmpAlpha)
+
+ if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
{
- GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(bmpAlpha);
- CurIcon->aFrame[0].hbmAlpha = NULL;
+ if (!IS_INTRESOURCE(CurIcon->strName.Buffer))
+ ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
+ if (CurIcon->atomModName)
+ RtlDeleteAtomFromAtomTable(gAtomTable, CurIcon->atomModName);
+ CurIcon->strName.Buffer = NULL;
+ CurIcon->atomModName = 0;
}
- /* We were given a pointer, no need to keep the reference anylonger! */
- UserDereferenceObject(CurIcon);
- Ret = UserDeleteObject(CurIcon->Self, otCursorIcon);
-
- return Ret;
+ /* Finally free the thing */
+ FreeProcMarkObject(CurIcon);
}
VOID FASTCALL
-IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
+IntCleanupCurIconCache(PPROCESSINFO Win32Process)
{
- PCURICON_OBJECT CurIcon, tmp;
+ PCURICON_OBJECT CurIcon;
/* Run through the list of icon objects */
- LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
+ while (Win32Process->pCursorCache)
{
- UserReferenceObject(CurIcon);
- IntDestroyCurIconObject(CurIcon, Win32Process);
+ CurIcon = Win32Process->pCursorCache;
+ Win32Process->pCursorCache = CurIcon->pcurNext;
+ UserDereferenceObject(CurIcon);
}
}
-
/*
* @implemented
*/
BOOL
APIENTRY
NtUserGetIconInfo(
- HANDLE hCurIcon,
- PICONINFO IconInfo,
- PUNICODE_STRING lpInstName, // Optional
- PUNICODE_STRING lpResName, // Optional
- LPDWORD pbpp, // Optional
- BOOL bInternal)
+ _In_ HANDLE hCurIcon,
+ _Out_opt_ PICONINFO IconInfo,
+ _Out_opt_ PUNICODE_STRING lpModule, // Optional
+ _Out_opt_ PUNICODE_STRING lpResName, // Optional
+ _Out_opt_ LPDWORD pbpp, // Optional
+ _In_ BOOL bInternal)
{
ICONINFO ii;
PCURICON_OBJECT CurIcon;
DWORD colorBpp = 0;
TRACE("Enter NtUserGetIconInfo\n");
- UserEnterExclusive();
- if (!IconInfo)
+ /* Check if something was actually asked */
+ if (!IconInfo && !lpModule && !lpResName)
{
+ WARN("Nothing to fill.\n");
EngSetLastError(ERROR_INVALID_PARAMETER);
- goto leave;
+ return FALSE;
}
+
+ UserEnterExclusive();
if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
{
- goto leave;
+ WARN("UserGetIconObject(0x%08x) Failed.\n", hCurIcon);
+ UserLeave();
+ return FALSE;
}
- /* Fill data */
- ii.fIcon = CurIcon->bIcon;
- ii.xHotspot = CurIcon->ptlHotspot.x;
- ii.yHotspot = CurIcon->ptlHotspot.y;
-
- /* Copy bitmaps */
- ii.hbmMask = BITMAP_CopyBitmap(CurIcon->aFrame[0].hbmMask);
- ii.hbmColor = BITMAP_CopyBitmap(CurIcon->aFrame[0].hbmColor);
-
- if (pbpp)
+ /* Give back the icon information */
+ if(IconInfo)
{
- PSURFACE psurfBmp;
+ PCURICON_OBJECT FrameCurIcon = CurIcon;
+ if(CurIcon->CURSORF_flags & CURSORF_ACON)
+ {
+ /* Get information from first frame. */
+ FrameCurIcon = ((PACON)CurIcon)->aspcur[0];
+ }
+
+ /* Fill data */
+ ii.fIcon = is_icon(FrameCurIcon);
+ ii.xHotspot = FrameCurIcon->xHotspot;
+ ii.yHotspot = FrameCurIcon->yHotspot;
+
+ /* Copy bitmaps */
+ ii.hbmMask = BITMAP_CopyBitmap(FrameCurIcon->hbmMask);
+ GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED);
+ ii.hbmColor = BITMAP_CopyBitmap(FrameCurIcon->hbmColor);
+ GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED);
+ colorBpp = FrameCurIcon->bpp;
+
+ /* Copy fields */
+ _SEH2_TRY
+ {
+ ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
+ RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
+
+ if (pbpp)
+ {
+ ProbeForWrite(pbpp, sizeof(DWORD), 1);
+ *pbpp = colorBpp;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
- psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmColor);
- if (psurfBmp)
+ if (!NT_SUCCESS(Status))
{
- colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
- SURFACE_ShareUnlockSurface(psurfBmp);
+ WARN("Status: 0x%08x.\n", Status);
+ SetLastNtError(Status);
+ goto leave;
}
}
- /* Copy fields */
- _SEH2_TRY
+ /* Give back the module name */
+ if(lpModule)
{
- ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
- RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
+ ULONG BufLen = 0;
+ if (!CurIcon->atomModName)
+ goto leave;
+
+ RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, NULL, &BufLen);
+ /* Get the module name from the atom table */
+ _SEH2_TRY
+ {
+ if (BufLen > (lpModule->MaximumLength * sizeof(WCHAR)))
+ {
+ lpModule->Length = 0;
+ }
+ else
+ {
+ ProbeForWrite(lpModule->Buffer, lpModule->MaximumLength, 1);
+ BufLen = lpModule->MaximumLength * sizeof(WCHAR);
+ RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, lpModule->Buffer, &BufLen);
+ lpModule->Length = BufLen/sizeof(WCHAR);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
- if (pbpp)
+ if (!NT_SUCCESS(Status))
{
- ProbeForWrite(pbpp, sizeof(DWORD), 1);
- *pbpp = colorBpp;
+ SetLastNtError(Status);
+ goto leave;
}
}
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+
+ if (lpResName)
{
- Status = _SEH2_GetExceptionCode();
+ if (!CurIcon->strName.Buffer)
+ goto leave;
+
+ /* Copy it */
+ _SEH2_TRY
+ {
+ ProbeForWrite(lpResName, sizeof(UNICODE_STRING), 1);
+ if (IS_INTRESOURCE(CurIcon->strName.Buffer))
+ {
+ lpResName->Buffer = CurIcon->strName.Buffer;
+ lpResName->Length = 0;
+ }
+ else if (lpResName->MaximumLength < CurIcon->strName.Length)
+ {
+ lpResName->Length = 0;
+ }
+ else
+ {
+ ProbeForWrite(lpResName->Buffer, lpResName->MaximumLength * sizeof(WCHAR), 1);
+ RtlCopyMemory(lpResName->Buffer, CurIcon->strName.Buffer, lpResName->Length);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
}
- _SEH2_END
- if (NT_SUCCESS(Status))
- Ret = TRUE;
- else
+ if (!NT_SUCCESS(Status))
+ {
SetLastNtError(Status);
+ goto leave;
+ }
+
+ Ret = TRUE;
+leave:
UserDereferenceObject(CurIcon);
-leave:
TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret);
UserLeave();
goto cleanup;
}
+ if(CurIcon->CURSORF_flags & CURSORF_ACON)
+ {
+ /* Use first frame for animated cursors */
+ PACON AniCurIcon = (PACON)CurIcon;
+ CurIcon = AniCurIcon->aspcur[0];
+ UserDereferenceObject(AniCurIcon);
+ UserReferenceObject(CurIcon);
+ }
+
_SEH2_TRY
{
ProbeForWrite(plcx, sizeof(LONG), 1);
- RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
+ *plcx = CurIcon->cx;
ProbeForWrite(plcy, sizeof(LONG), 1);
- RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
+ *plcy = CurIcon->cy;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SafeCi.cbSize = sizeof(CURSORINFO);
SafeCi.flags = ((CurIcon && CurInfo->ShowingCursor >= 0) ? CURSOR_SHOWING : 0);
- SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
+ SafeCi.hCursor = (CurIcon ? CurIcon->head.h : NULL);
SafeCi.ptScreenPos = gpsi->ptCursor;
prcl = &rclLocal;
}
- UserEnterExclusive();
+ UserEnterExclusive();
/* Call the internal function */
bResult = UserClipCursor(prcl);
BOOL
APIENTRY
NtUserDestroyCursor(
- HANDLE hCurIcon,
- DWORD Unknown)
+ _In_ HANDLE hCurIcon,
+ _In_ BOOL bForce)
{
- PCURICON_OBJECT CurIcon;
BOOL ret;
- DECLARE_RETURN(BOOL);
+ PCURICON_OBJECT CurIcon = NULL;
- TRACE("Enter NtUserDestroyCursorIcon\n");
+ TRACE("Enter NtUserDestroyCursorIcon (%p, %u)\n", hCurIcon, bForce);
UserEnterExclusive();
- if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+ CurIcon = UserGetCurIconObject(hCurIcon);
+ if (!CurIcon)
{
- RETURN(FALSE);
+ ret = FALSE;
+ goto leave;
}
- ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process());
- /* Note: IntDestroyCurIconObject will remove our reference for us! */
+ if (!bForce)
+ {
+ /* Maybe we have good reasons not to destroy this object */
+ if (CurIcon->head.ppi != PsGetCurrentProcessWin32Process())
+ {
+ /* No way, you're not touching my cursor */
+ ret = FALSE;
+ goto leave;
+ }
+
+ if (CurIcon->CURSORF_flags & CURSORF_CURRENT)
+ {
+ WARN("Trying to delete current cursor!\n");
+ ret = FALSE;
+ goto leave;
+ }
+
+ if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
+ {
+ WARN("Trying to delete shared cursor.\n");
+ /* This one is not an error */
+ ret = TRUE;
+ goto leave;
+ }
+ }
- RETURN(ret);
+ /* Destroy the handle */
+ ret = IntDestroyCurIconObject(CurIcon);
-CLEANUP:
- TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
+leave:
+ if (CurIcon)
+ UserDereferenceObject(CurIcon);
+ TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n", ret);
UserLeave();
- END_CLEANUP;
+ return ret;
}
* @implemented
*/
HICON
-APIENTRY
+NTAPI
NtUserFindExistingCursorIcon(
- HMODULE hModule,
- HRSRC hRsrc,
- LONG cx,
- LONG cy)
+ _In_ PUNICODE_STRING pustrModule,
+ _In_ PUNICODE_STRING pustrRsrc,
+ _In_ FINDEXISTINGCURICONPARAM* param)
{
PCURICON_OBJECT CurIcon;
- HANDLE Ret = (HANDLE)0;
- DECLARE_RETURN(HICON);
+ HICON Ret = NULL;
+ UNICODE_STRING ustrModuleSafe, ustrRsrcSafe;
+ FINDEXISTINGCURICONPARAM paramSafe;
+ NTSTATUS Status;
+ PPROCESSINFO pProcInfo = PsGetCurrentProcessWin32Process();
+ RTL_ATOM atomModName;
TRACE("Enter NtUserFindExistingCursorIcon\n");
- UserEnterExclusive();
-
- CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy);
- if (CurIcon)
+
+
+ _SEH2_TRY
{
- Ret = CurIcon->Self;
-
-// IntReleaseCurIconObject(CurIcon); // FIXME: Is this correct? Does IntFindExistingCurIconObject add a ref?
- RETURN(Ret);
+ ProbeForRead(param, sizeof(*param), 1);
+ RtlCopyMemory(¶mSafe, param, sizeof(paramSafe));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
}
+ _SEH2_END
- EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
- RETURN((HANDLE)0);
+ /* Capture resource name (it can be an INTRESOURCE == ATOM) */
+ Status = ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrcSafe, pustrRsrc);
+ if(!NT_SUCCESS(Status))
+ return NULL;
+ Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule);
+ if(!NT_SUCCESS(Status))
+ goto done;
+ Status = RtlLookupAtomInAtomTable(gAtomTable, ustrModuleSafe.Buffer, &atomModName);
+ ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode);
+ if(!NT_SUCCESS(Status))
+ {
+ /* The module is not in the atom table. No chance to find the cursor */
+ goto done;
+ }
-CLEANUP:
- TRACE("Leave NtUserFindExistingCursorIcon, ret=%p\n",_ret_);
+ UserEnterExclusive();
+ CurIcon = pProcInfo->pCursorCache;
+ while(CurIcon)
+ {
+ /* Icon/cursor */
+ if (paramSafe.bIcon != is_icon(CurIcon))
+ {
+ CurIcon = CurIcon->pcurNext;
+ continue;
+ }
+ /* See if module names match */
+ if (atomModName == CurIcon->atomModName)
+ {
+ /* They do. Now see if this is the same resource */
+ if (IS_INTRESOURCE(CurIcon->strName.Buffer) != IS_INTRESOURCE(ustrRsrcSafe.Buffer))
+ {
+ /* One is an INT resource and the other is not -> no match */
+ CurIcon = CurIcon->pcurNext;
+ continue;
+ }
+
+ if (IS_INTRESOURCE(CurIcon->strName.Buffer))
+ {
+ if (CurIcon->strName.Buffer == ustrRsrcSafe.Buffer)
+ {
+ /* INT resources match */
+ break;
+ }
+ }
+ else if (RtlCompareUnicodeString(&ustrRsrcSafe, &CurIcon->strName, TRUE) == 0)
+ {
+ /* Resource name strings match */
+ break;
+ }
+ }
+ CurIcon = CurIcon->pcurNext;
+ }
+ if(CurIcon)
+ Ret = CurIcon->head.h;
UserLeave();
- END_CLEANUP;
+
+done:
+ if(!IS_INTRESOURCE(ustrRsrcSafe.Buffer))
+ ExFreePoolWithTag(ustrRsrcSafe.Buffer, TAG_STRING);
+
+ return Ret;
}
PCURICON_OBJECT pcurOld, pcurNew;
HCURSOR hOldCursor = NULL;
- TRACE("Enter NtUserSetCursor\n");
+ TRACE("Enter NtUserSetCursor: %p\n", hCursor);
UserEnterExclusive();
if (hCursor)
EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
goto leave;
}
+ pcurNew->CURSORF_flags |= CURSORF_CURRENT;
}
else
{
pcurOld = UserSetCursor(pcurNew, FALSE);
if (pcurOld)
{
- hOldCursor = (HCURSOR)pcurOld->Self;
+ hOldCursor = pcurOld->head.h;
+ /* See if it was destroyed in the meantime */
+ if (UserObjectInDestroy(hOldCursor))
+ hOldCursor = NULL;
+ pcurOld->CURSORF_flags &= ~CURSORF_CURRENT;
UserDereferenceObject(pcurOld);
}
/*
- * @implemented
+ * @unimplemented
*/
BOOL
APIENTRY
HANDLE hCurIcon,
PICONINFO UnsafeIconInfo)
{
- PCURICON_OBJECT CurIcon;
- ICONINFO IconInfo;
- PSURFACE psurfBmp;
- NTSTATUS Status;
- BOOL Ret = FALSE;
- DECLARE_RETURN(BOOL);
-
- TRACE("Enter NtUserSetCursorContents\n");
- UserEnterExclusive();
-
- if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
- {
- RETURN(FALSE);
- }
-
- /* Copy fields */
- Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
- if (!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- goto done;
- }
-
-#if 0
- /* Check if we get valid information */
- if(IconInfo.fIcon != CurInfo->bIcon)
- {
- EngSetLastError(ERROR_INVALID_PARAMETER);
- goto done;
- }
-#endif
-
- /* Delete old bitmaps */
- if (CurIcon->aFrame[0].hbmColor)
- GreDeleteObject(CurIcon->aFrame[0].hbmColor);
- if (CurIcon->aFrame[0].hbmMask)
- GreDeleteObject(CurIcon->aFrame[0].hbmMask);
- if(CurIcon->aFrame[0].hbmAlpha)
- GreDeleteObject(CurIcon->aFrame[0].hbmAlpha);
-
- /* Set fields */
- CurIcon->bIcon = IconInfo.fIcon;
- CurIcon->ptlHotspot.x = IconInfo.xHotspot;
- CurIcon->ptlHotspot.y = IconInfo.yHotspot;
- CurIcon->aFrame[0].hbmMask = IconInfo.hbmMask;
- CurIcon->aFrame[0].hbmColor = IconInfo.hbmColor;
- CurIcon->aFrame[0].hbmAlpha = NULL;
-
- if (IconInfo.hbmColor)
- {
- BOOLEAN bAlpha = FALSE;
- psurfBmp = SURFACE_ShareLockSurface(IconInfo.hbmColor);
- if (!psurfBmp)
- goto done;
- CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
- CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
-
- /* 32bpp bitmap is likely to have an alpha channel */
- if(psurfBmp->SurfObj.iBitmapFormat == BMF_32BPP)
- {
- PFN_DIB_GetPixel fn_GetPixel = DibFunctionsForBitmapFormat[BMF_32BPP].DIB_GetPixel;
- INT i, j;
-
- fn_GetPixel = DibFunctionsForBitmapFormat[BMF_32BPP].DIB_GetPixel;
- for (i = 0; i < psurfBmp->SurfObj.sizlBitmap.cx; i++)
- {
- for (j = 0; j < psurfBmp->SurfObj.sizlBitmap.cy; j++)
- {
- bAlpha = ((BYTE)(fn_GetPixel(&psurfBmp->SurfObj, i, j) >> 24)) != 0;
- if (bAlpha)
- break;
- }
- if (bAlpha)
- break;
- }
- }
- /* We're done with this one */
- SURFACE_ShareUnlockSurface(psurfBmp);
- GreSetObjectOwner(IconInfo.hbmColor, GDI_OBJ_HMGR_PUBLIC);
-
- if(bAlpha)
- {
- UCHAR Alpha;
- PUCHAR ptr;
- INT i, j;
- /* Copy the bitmap */
- CurIcon->aFrame[0].hbmAlpha = BITMAP_CopyBitmap(IconInfo.hbmColor);
- if(!CurIcon->aFrame[0].hbmAlpha)
- {
- ERR("BITMAP_CopyBitmap failed!");
- goto done;
- }
-
- psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmAlpha);
- if(!psurfBmp)
- {
- ERR("SURFACE_LockSurface failed!\n");
- goto done;
- }
-
- /* Premultiply with the alpha channel value */
- for (i = 0; i < psurfBmp->SurfObj.sizlBitmap.cy; i++)
- {
- ptr = (PBYTE)psurfBmp->SurfObj.pvScan0 + i*psurfBmp->SurfObj.lDelta;
- for (j = 0; j < psurfBmp->SurfObj.sizlBitmap.cx; j++)
- {
- Alpha = ptr[3];
- ptr[0] = (ptr[0] * Alpha) / 0xff;
- ptr[1] = (ptr[1] * Alpha) / 0xff;
- ptr[2] = (ptr[2] * Alpha) / 0xff;
- ptr += 4;
- }
- }
- SURFACE_ShareUnlockSurface(psurfBmp);
- GreSetObjectOwner(CurIcon->aFrame[0].hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
- }
- }
- else
- {
- psurfBmp = SURFACE_ShareLockSurface(IconInfo.hbmMask);
- if (!psurfBmp)
- goto done;
-
- CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
- CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
-
- SURFACE_ShareUnlockSurface(psurfBmp);
- }
- GreSetObjectOwner(IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
-
- Ret = TRUE;
-
-done:
-
- if(!Ret)
- {
- IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process());
- CurIcon = NULL;
- }
-
- if (CurIcon)
- {
- UserDereferenceObject(CurIcon);
- }
- RETURN(Ret);
-
-CLEANUP:
- TRACE("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
- UserLeave();
- END_CLEANUP;
-}
+ FIXME(" is UNIMPLEMENTED.\n");
+ return FALSE;
+}
/*
* @implemented
*/
-#ifdef NEW_CURSORICON
BOOL
APIENTRY
NtUserSetCursorIconData(
- _In_ HCURSOR Handle,
- _In_ HINSTANCE hinst,
- _In_ HRSRC hrsrc,
- _In_ PICONINFO pIconInfo)
+ _In_ HCURSOR Handle,
+ _In_opt_ PUNICODE_STRING pustrModule,
+ _In_opt_ PUNICODE_STRING pustrRsrc,
+ _In_ const CURSORDATA* pCursorData)
{
PCURICON_OBJECT CurIcon;
- PSURFACE psurfBmp;
NTSTATUS Status = STATUS_SUCCESS;
- BOOL Ret = FALSE;
- DECLARE_RETURN(BOOL);
- ICONINFO ii;
-
+ BOOLEAN Ret = FALSE;
+ BOOLEAN IsShared = FALSE, IsAnim = FALSE;
+ DWORD numFrames;
+ UINT i = 0;
+
TRACE("Enter NtUserSetCursorIconData\n");
+
UserEnterExclusive();
if (!(CurIcon = UserGetCurIconObject(Handle)))
{
- RETURN(FALSE);
+ UserLeave();
+ EngSetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
}
- CurIcon->hModule = hinst;
- CurIcon->hRsrc =hrsrc;
-
_SEH2_TRY
{
- ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
- ii = *pIconInfo;
+ ProbeForRead(pCursorData, sizeof(*pCursorData), 1);
+ if(pCursorData->CURSORF_flags & CURSORF_ACON)
+ {
+ /* This is an animated cursor */
+ PACON AniCurIcon = (PACON)CurIcon;
+ DWORD numSteps;
+
+ numFrames = AniCurIcon->cpcur = pCursorData->cpcur;
+ numSteps = AniCurIcon->cicur = pCursorData->cicur;
+ AniCurIcon->iicur = pCursorData->iicur;
+ AniCurIcon->rt = pCursorData->rt;
+
+ /* Calculate size: one cursor object for each frame, and a frame index and jiffies for each "step" */
+ AniCurIcon->aspcur = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, /* Let SEH catch allocation failures */
+ numFrames * sizeof(CURICON_OBJECT*) + numSteps * (sizeof(DWORD) + sizeof(INT)),
+ USERTAG_CURSOR);
+ AniCurIcon->aicur = (DWORD*)(AniCurIcon->aspcur + numFrames);
+ AniCurIcon->ajifRate = (INT*)(AniCurIcon->aicur + numSteps);
+
+ RtlZeroMemory(AniCurIcon->aspcur, numFrames * sizeof(CURICON_OBJECT*));
+
+ ProbeForRead(pCursorData->aicur, numSteps * sizeof(DWORD), 1);
+ RtlCopyMemory(AniCurIcon->aicur, pCursorData->aicur, numSteps * sizeof(DWORD));
+ ProbeForRead(pCursorData->ajifRate, numSteps * sizeof(INT), 1);
+ RtlCopyMemory(AniCurIcon->ajifRate, pCursorData->ajifRate, numSteps * sizeof(INT));
+
+ AniCurIcon->CURSORF_flags = pCursorData->CURSORF_flags;
+ pCursorData = pCursorData->aspcur;
+
+ IsAnim = TRUE;
+ }
+ else
+ {
+ CurIcon->xHotspot = pCursorData->xHotspot;
+ CurIcon->yHotspot = pCursorData->yHotspot;
+ CurIcon->cx = pCursorData->cx;
+ CurIcon->cy = pCursorData->cy;
+ CurIcon->rt = pCursorData->rt;
+ CurIcon->bpp = pCursorData->bpp;
+ CurIcon->hbmMask = pCursorData->hbmMask;
+ CurIcon->hbmColor = pCursorData->hbmColor;
+ CurIcon->hbmAlpha = pCursorData->hbmAlpha;
+ CurIcon->CURSORF_flags = pCursorData->CURSORF_flags;
+ }
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastNtError(Status);
goto done;
}
-
- /* This is probably not what windows does, but consistency checks can't hurt */
- if(CurIcon->bIcon != ii.fIcon)
- {
- EngSetLastError(ERROR_INVALID_PARAMETER);
- goto done;
- }
- CurIcon->ptlHotspot.x = ii.xHotspot;
- CurIcon->ptlHotspot.y = ii.yHotspot;
-
- if(!ii.hbmMask)
- {
- EngSetLastError(ERROR_INVALID_PARAMETER);
- goto done;
- }
-
- CurIcon->aFrame[0].hbmMask = BITMAP_CopyBitmap(ii.hbmMask);
- if(!CurIcon->aFrame[0].hbmMask)
- goto done;
-
- if(ii.hbmColor)
- {
- CurIcon->aFrame[0].hbmColor = BITMAP_CopyBitmap(ii.hbmColor);
- if(!CurIcon->aFrame[0].hbmColor)
- goto done;
- }
- if (CurIcon->aFrame[0].hbmColor)
+ if(IsAnim)
{
- if ((psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmColor)))
+ PACON AniCurIcon = (PACON)CurIcon;
+ /* This is an animated cursor. Create a cursor object for each frame and set up the data */
+ for(i = 0; i < numFrames; i++)
{
- CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
- CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
- SURFACE_ShareUnlockSurface(psurfBmp);
- GreSetObjectOwner(CurIcon->aFrame[0].hbmMask, GDI_OBJ_HMGR_PUBLIC);
+ HANDLE hCurFrame = IntCreateCurIconHandle(FALSE);
+ if(!NtUserSetCursorIconData(hCurFrame, NULL, NULL, pCursorData))
+ goto done;
+ AniCurIcon->aspcur[i] = UserGetCurIconObject(hCurFrame);
+ if(!AniCurIcon->aspcur[i])
+ goto done;
+ pCursorData++;
}
- else
- goto done;
}
- else
+
+ if(CurIcon->CURSORF_flags & CURSORF_LRSHARED)
{
- if ((psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmMask)))
+ IsShared = TRUE;
+ if(pustrRsrc && pustrModule)
{
- CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
- CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy/2;
- SURFACE_ShareUnlockSurface(psurfBmp);
+ UNICODE_STRING ustrModuleSafe;
+ /* We use this convenient function, because INTRESOURCEs and ATOMs are the same */
+ Status = ProbeAndCaptureUnicodeStringOrAtom(&CurIcon->strName, pustrRsrc);
+ if(!NT_SUCCESS(Status))
+ goto done;
+ Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule);
+ if(!NT_SUCCESS(Status))
+ goto done;
+ Status = RtlAddAtomToAtomTable(gAtomTable, ustrModuleSafe.Buffer, &CurIcon->atomModName);
+ ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode);
+ if(!NT_SUCCESS(Status))
+ goto done;
}
- else
- goto done;
}
- GreSetObjectOwner(CurIcon->aFrame[0].hbmMask, GDI_OBJ_HMGR_PUBLIC);
-
- Ret = TRUE;
-done:
- UserDereferenceObject(CurIcon);
- if(!Ret)
+ if(!CurIcon->hbmMask)
{
- if (CurIcon->aFrame[0].hbmMask)
- {
- GreSetObjectOwner(CurIcon->aFrame[0].hbmMask, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(CurIcon->aFrame[0].hbmMask);
- CurIcon->aFrame[0].hbmMask = NULL;
- }
- if (CurIcon->aFrame[0].hbmColor)
- {
- GreSetObjectOwner(CurIcon->aFrame[0].hbmColor, GDI_OBJ_HMGR_POWNED);
- GreDeleteObject(CurIcon->aFrame[0].hbmColor);
- CurIcon->aFrame[0].hbmColor = NULL;
- }
+ ERR("NtUserSetCursorIconData was got no hbmMask.\n");
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
}
- RETURN(Ret);
-CLEANUP:
- TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
- UserLeave();
- END_CLEANUP;
-}
-#else
-BOOL
-APIENTRY
-NtUserSetCursorIconData(
- HANDLE hCurIcon,
- PBOOL fIcon,
- POINT *Hotspot,
- HMODULE hModule,
- HRSRC hRsrc,
- HRSRC hGroupRsrc)
-{
- PCURICON_OBJECT CurIcon;
- NTSTATUS Status;
- BOOL Ret = FALSE;
- DECLARE_RETURN(BOOL);
+ GreSetObjectOwner(CurIcon->hbmMask, GDI_OBJ_HMGR_PUBLIC);
- TRACE("Enter NtUserSetCursorIconData\n");
- UserEnterExclusive();
+ if(CurIcon->hbmColor)
+ GreSetObjectOwner(CurIcon->hbmColor, GDI_OBJ_HMGR_PUBLIC);
+
+ if(CurIcon->hbmAlpha)
+ GreSetObjectOwner(CurIcon->hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
- if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+ if(IsShared)
{
- RETURN(FALSE);
+ /* Update process cache in case of shared cursor */
+ PPROCESSINFO ppi = CurIcon->head.ppi;
+ UserReferenceObject(CurIcon);
+ CurIcon->pcurNext = ppi->pCursorCache;
+ ppi->pCursorCache = CurIcon;
}
+
+ Ret = TRUE;
- CurIcon->hModule = hModule;
- CurIcon->hRsrc = hRsrc;
- CurIcon->hGroupRsrc = hGroupRsrc;
-
- /* Copy fields */
- if (fIcon)
+done:
+ if(!Ret && IsShared)
{
- Status = MmCopyFromCaller(&CurIcon->bIcon, fIcon, sizeof(BOOL));
- if (!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- goto done;
- }
- }
- else
- {
- if (!Hotspot)
- Ret = TRUE;
+ if(!IS_INTRESOURCE(CurIcon->strName.Buffer))
+ ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
}
- if (Hotspot)
+ if(!Ret && IsAnim)
{
- Status = MmCopyFromCaller(&CurIcon->ptlHotspot, Hotspot, sizeof(POINT));
- if (!NT_SUCCESS(Status))
+ PACON AniCurIcon = (PACON)CurIcon;
+ for(i = 0; i < numFrames; i++)
{
- SetLastNtError(Status);
- goto done;
+ if(AniCurIcon->aspcur[i])
+ IntDestroyCurIconObject(AniCurIcon->aspcur[i]);
}
+ AniCurIcon->cicur = 0;
+ AniCurIcon->cpcur = 0;
+ ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
+ AniCurIcon->aspcur = NULL;
+ AniCurIcon->aicur = NULL;
+ AniCurIcon->ajifRate = NULL;
}
- if (!fIcon && !Hotspot)
- {
- Ret = TRUE;
- }
-
-done:
- if(Ret)
- {
- /* This icon is shared now */
- GreSetObjectOwner(CurIcon->aFrame[0].hbmMask, GDI_OBJ_HMGR_PUBLIC);
- if(CurIcon->aFrame[0].hbmColor)
- {
- GreSetObjectOwner(CurIcon->aFrame[0].hbmColor, GDI_OBJ_HMGR_PUBLIC);
- }
- if(CurIcon->aFrame[0].hbmAlpha)
- {
- GreSetObjectOwner(CurIcon->aFrame[0].hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
- }
- }
UserDereferenceObject(CurIcon);
- RETURN(Ret);
-
-
-CLEANUP:
- TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
+ TRACE("Leave NtUserSetCursorIconData, ret=%i\n",Ret);
UserLeave();
- END_CLEANUP;
+
+ return Ret;
}
-#endif
/* Mostly inspired from wine code.
* We use low level functions because:
HBRUSH hbrFlickerFreeDraw,
UINT diFlags)
{
- PSURFACE psurfDest, psurfMask, psurfColor, psurfOffScreen;
+ PSURFACE psurfDest, psurfMask, psurfColor; //, psurfOffScreen = NULL;
PDC pdc = NULL;
BOOL Ret = FALSE;
HBITMAP hbmMask, hbmColor, hbmAlpha;
return FALSE;
}
- hbmMask = pIcon->aFrame[0].hbmMask;
- hbmColor = pIcon->aFrame[0].hbmColor;
- hbmAlpha = pIcon->aFrame[0].hbmAlpha;
-
- if (istepIfAniCur)
- ERR("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
+ if (pIcon->CURSORF_flags & CURSORF_ACON)
+ {
+ ACON* pAcon = (ACON*)pIcon;
+ if(istepIfAniCur >= pAcon->cicur)
+ {
+ ERR("NtUserDrawIconEx: istepIfAniCur too big!\n");
+ return FALSE;
+ }
+ pIcon = pAcon->aspcur[pAcon->aicur[istepIfAniCur]];
+ }
+
+ hbmMask = pIcon->hbmMask;
+ hbmColor = pIcon->hbmColor;
+ hbmAlpha = pIcon->hbmAlpha;
/*
* Get our objects.
if(hbmColor == NULL)
{
/* But then the mask bitmap must have the information in it's bottom half */
- ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->Size.cy);
+ ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->cy);
psurfColor = NULL;
}
else if ((psurfColor = SURFACE_ShareLockSurface(hbmColor)) == NULL)
return FALSE;
}
+ pdc = DC_LockDc(hDc);
+ if(!pdc)
+ {
+ ERR("Could not lock the destination DC.\n");
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+ return FALSE;
+ }
+ /* Calculate destination rectangle */
+ RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
+ IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
+ RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
+
+ /* Prepare the underlying surface */
+ DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL);
+
+ /* We now have our destination surface and rectangle */
+ psurfDest = pdc->dclevel.pSurface;
+
+ if(psurfDest == NULL)
+ {
+ /* Empty DC */
+ DC_vFinishBlit(pdc, NULL);
+ DC_UnlockDc(pdc);
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+ return FALSE;
+ }
+
/* Set source rect */
- RECTL_vSetRect(&rcSrc, 0, 0, pIcon->Size.cx, pIcon->Size.cy);
+ RECTL_vSetRect(&rcSrc, 0, 0, pIcon->cx, pIcon->cy);
/* Fix width parameter, if needed */
if (!cxWidth)
{
if(diFlags & DI_DEFAULTSIZE)
- cxWidth = pIcon->bIcon ?
+ cxWidth = is_icon(pIcon) ?
UserGetSystemMetrics(SM_CXICON) : UserGetSystemMetrics(SM_CXCURSOR);
else
- cxWidth = pIcon->Size.cx;
+ cxWidth = pIcon->cx;
}
/* Fix height parameter, if needed */
if (!cyHeight)
{
if(diFlags & DI_DEFAULTSIZE)
- cyHeight = pIcon->bIcon ?
+ cyHeight = is_icon(pIcon) ?
UserGetSystemMetrics(SM_CYICON) : UserGetSystemMetrics(SM_CYCURSOR);
else
- cyHeight = pIcon->Size.cy;
+ cyHeight = pIcon->cy;
}
/* Should we render off-screen? */
- bOffScreen = hbrFlickerFreeDraw && (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH);
+ bOffScreen = hbrFlickerFreeDraw &&
+ (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH);
if (bOffScreen)
{
if(!pbrush)
{
ERR("Failed to get brush object.\n");
- SURFACE_ShareUnlockSurface(psurfMask);
- if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
- return FALSE;
+ goto Cleanup;
}
+#if 0 //We lock the hdc surface during the whole function it makes no sense to use an offscreen surface for "flicker free" drawing
psurfOffScreen = SURFACE_AllocSurface(STYPE_BITMAP,
- cxWidth, cyHeight, psurfColor->SurfObj.iBitmapFormat,
+ cxWidth, cyHeight, psurfDest->SurfObj.iBitmapFormat,
0, 0, NULL);
if(!psurfOffScreen)
{
ERR("Failed to allocate the off-screen surface.\n");
- SURFACE_ShareUnlockSurface(psurfMask);
- if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
BRUSH_ShareUnlockBrush(pbrush);
- return FALSE;
+ goto Cleanup;
}
/* Paint the brush */
if(!Ret)
{
ERR("Failed to paint the off-screen surface.\n");
- SURFACE_ShareUnlockSurface(psurfMask);
- if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
- GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject);
- return FALSE;
+ goto Cleanup;
}
/* We now have our destination surface */
psurfDest = psurfOffScreen;
+#else
+ pdcClipObj = &pdc->co.ClipObj;
+ /* Paint the brush */
+ EBRUSHOBJ_vInit(&eboFill, pbrush, psurfDest, 0x00FFFFFF, 0, NULL);
+
+ Ret = IntEngBitBlt(&psurfDest->SurfObj,
+ NULL,
+ NULL,
+ pdcClipObj,
+ NULL,
+ &rcDest,
+ NULL,
+ NULL,
+ &eboFill.BrushObject,
+ &pbrush->ptOrigin,
+ ROP4_PATCOPY);
+
+ /* Clean up everything */
+ EBRUSHOBJ_vCleanup(&eboFill);
+ BRUSH_ShareUnlockBrush(pbrush);
+
+ if(!Ret)
+ {
+ ERR("Failed to paint the off-screen surface.\n");
+ goto Cleanup;
+ }
+#endif
}
else
{
/* We directly draw to the DC */
TRACE("Performing on screen rendering.\n");
-
- psurfOffScreen = NULL;
- pdc = DC_LockDc(hDc);
- if(!pdc)
- {
- ERR("Could not lock the destination DC.\n");
- SURFACE_ShareUnlockSurface(psurfMask);
- if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
- return FALSE;
- }
- /* Calculate destination rectangle */
- RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
- IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
- RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
-
- /* Prepare the underlying surface */
- DC_vPrepareDCsForBlit(pdc, rcDest, NULL, rcDest);
-
- /* Get the clip object */
- pdcClipObj = pdc->rosdc.CombinedClip;
-
- /* We now have our destination surface and rectangle */
- psurfDest = pdc->dclevel.pSurface;
-
- if(psurfDest == NULL)
- {
- /* Empty DC */
- DC_vFinishBlit(pdc, NULL);
- DC_UnlockDc(pdc);
- SURFACE_ShareUnlockSurface(psurfMask);
- if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
- return FALSE;
- }
+ pdcClipObj = &pdc->co.ClipObj;
+ // psurfOffScreen = NULL;
}
/* Now do the rendering */
- if(hbmAlpha && (diFlags & DI_IMAGE))
- {
- BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
+ if(hbmAlpha && ((diFlags & DI_NORMAL) == DI_NORMAL))
+ {
+ BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
PSURFACE psurf = NULL;
psurf = SURFACE_ShareLockSurface(hbmAlpha);
EXLATEOBJ_vCleanup(&exlo);
SURFACE_ShareUnlockSurface(psurf);
if(Ret) goto done;
- ERR("NtGdiAlphaBlend failed!\n");
+ ERR("NtGdiAlphaBlend failed!\n");
}
NoAlpha:
if (diFlags & DI_MASK)
if(diFlags & DI_IMAGE)
{
- if (psurfColor)
+ if (psurfColor)
{
DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY ;
{
/* Mask bitmap holds the information in its bottom half */
DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY;
- RECTL_vOffsetRect(&rcSrc, 0, pIcon->Size.cy);
+ RECTL_vOffsetRect(&rcSrc, 0, pIcon->cy);
EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
}
done:
+#if 0
/* We're done. Was it a double buffered draw ? */
if(bOffScreen)
{
/* Yes. Draw it back to our DC */
POINTL ptSrc = {0, 0};
- pdc = DC_LockDc(hDc);
- if(!pdc)
- {
- ERR("Could not lock the destination DC.\n");
- return FALSE;
- }
+
/* Calculate destination rectangle */
RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
- /* Prepare the underlying surface */
- DC_vPrepareDCsForBlit(pdc, rcDest, NULL, rcDest);
-
/* Get the clip object */
pdcClipObj = pdc->rosdc.CombinedClip;
/* We now have our destination surface and rectangle */
psurfDest = pdc->dclevel.pSurface;
- if(!psurfDest)
- {
- /* So, you did all of this for an empty DC. */
- DC_UnlockDc(pdc);
- goto Cleanup2;
- }
/* Color translation */
EXLATEOBJ_vInitialize(&exlo, psurfOffScreen->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0);
EXLATEOBJ_vCleanup(&exlo);
}
+#endif
Cleanup:
if(pdc)
{
DC_vFinishBlit(pdc, NULL);
DC_UnlockDc(pdc);
}
-
-Cleanup2:
+
+#if 0
/* Delete off screen rendering surface */
if(psurfOffScreen)
GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject);
-
+#endif
+
/* Unlock other surfaces */
SURFACE_ShareUnlockSurface(psurfMask);
if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
if (!(pIcon = UserGetCurIconObject(hIcon)))
{
- ERR("UserGetCurIconObject() failed!\n");
+ ERR("UserGetCurIconObject(0x%08x) failed!\n", hIcon);
UserLeave();
return FALSE;
}
return Ret;
}
+/*
+ * @unimplemented
+ */
+HCURSOR
+NTAPI
+NtUserGetCursorFrameInfo(
+ HCURSOR hCursor,
+ DWORD istep,
+ INT* rate_jiffies,
+ DWORD* num_steps)
+{
+ PCURICON_OBJECT CurIcon;
+ HCURSOR ret;
+ INT jiffies = 0;
+ DWORD steps = 1;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ TRACE("Enter NtUserGetCursorFrameInfo\n");
+ UserEnterExclusive();
+
+ if (!(CurIcon = UserGetCurIconObject(hCursor)))
+ {
+ UserLeave();
+ return NULL;
+ }
+
+ ret = CurIcon->head.h;
+
+ if(CurIcon->CURSORF_flags & CURSORF_ACON)
+ {
+ PACON AniCurIcon = (PACON)CurIcon;
+ if(istep >= AniCurIcon->cicur)
+ {
+ UserDereferenceObject(CurIcon);
+ UserLeave();
+ return NULL;
+ }
+ jiffies = AniCurIcon->ajifRate[istep];
+ steps = AniCurIcon->cicur;
+ ret = AniCurIcon->aspcur[AniCurIcon->aicur[istep]]->head.h;
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForWrite(rate_jiffies, sizeof(INT), 1);
+ ProbeForWrite(num_steps, sizeof(DWORD), 1);
+ *rate_jiffies = jiffies;
+ *num_steps = steps;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (!NT_SUCCESS(Status))
+ {
+ WARN("Status: 0x%08x.\n", Status);
+ SetLastNtError(Status);
+ ret = NULL;
+ }
+
+ UserDereferenceObject(CurIcon);
+ UserLeave();
+
+ TRACE("Leaving NtUserGetCursorFrameInfo, ret = 0x%08x\n", ret);
+
+ return ret;
+}
+
/* EOF */