2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Cursor and icon functions
5 * FILE: subsystems/win32/win32k/ntuser/cursoricon.c
6 * PROGRAMER: ReactOS Team
9 * We handle two types of cursors/icons:
11 * Loaded without LR_SHARED flag
12 * Private to a process
13 * Can be deleted by calling NtDestroyCursorIcon()
14 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
16 * Loaded with LR_SHARED flag
17 * Possibly shared by multiple processes
18 * Immune to NtDestroyCursorIcon()
19 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
20 * There's a M:N relationship between processes and (shared) cursor/icons.
21 * A process can have multiple cursor/icons and a cursor/icon can be used
22 * by multiple processes. To keep track of this we keep a list of all
23 * cursor/icons (CurIconList) and per cursor/icon we keep a list of
24 * CURICON_PROCESS structs starting at CurIcon->ProcessList.
28 DBG_DEFAULT_CHANNEL(UserIcon
);
30 static PPAGED_LOOKASIDE_LIST pgProcessLookasideList
;
31 static LIST_ENTRY gCurIconList
;
33 SYSTEM_CURSORINFO gSysCursorInfo
;
38 pgProcessLookasideList
= ExAllocatePool(NonPagedPool
, sizeof(PAGED_LOOKASIDE_LIST
));
39 if(!pgProcessLookasideList
)
42 ExInitializePagedLookasideList(pgProcessLookasideList
,
46 sizeof(CURICON_PROCESS
),
49 InitializeListHead(&gCurIconList
);
51 gSysCursorInfo
.Enabled
= FALSE
;
52 gSysCursorInfo
.ButtonsDown
= 0;
53 gSysCursorInfo
.bClipped
= FALSE
;
54 gSysCursorInfo
.LastBtnDown
= 0;
55 gSysCursorInfo
.CurrentCursorObject
= NULL
;
56 gSysCursorInfo
.ShowingCursor
= -1;
57 gSysCursorInfo
.ClickLockActive
= FALSE
;
58 gSysCursorInfo
.ClickLockTime
= 0;
66 return &gSysCursorInfo
;
69 /* This function creates a reference for the object! */
70 PCURICON_OBJECT FASTCALL
UserGetCurIconObject(HCURSOR hCurIcon
)
72 PCURICON_OBJECT CurIcon
;
76 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
80 CurIcon
= (PCURICON_OBJECT
)UserReferenceObjectByHandle(hCurIcon
, otCursorIcon
);
83 /* We never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
84 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
88 ASSERT(CurIcon
->head
.cLockObj
>= 1);
92 BOOL
UserSetCursorPos( INT x
, INT y
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
95 PSYSTEM_CURSORINFO CurInfo
;
100 if(!(DesktopWindow
= UserGetDesktopWindow()))
105 CurInfo
= IntGetSysCursorInfo();
107 /* Clip cursor position */
108 if (!CurInfo
->bClipped
)
109 rcClip
= DesktopWindow
->rcClient
;
111 rcClip
= CurInfo
->rcClip
;
113 if(x
>= rcClip
.right
) x
= rcClip
.right
- 1;
114 if(x
< rcClip
.left
) x
= rcClip
.left
;
115 if(y
>= rcClip
.bottom
) y
= rcClip
.bottom
- 1;
116 if(y
< rcClip
.top
) y
= rcClip
.top
;
121 /* 1. Generate a mouse move message, this sets the htEx and Track Window too. */
122 Msg
.message
= WM_MOUSEMOVE
;
123 Msg
.wParam
= UserGetMouseButtonsState();
124 Msg
.lParam
= MAKELPARAM(x
, y
);
126 co_MsqInsertMouseMessage(&Msg
, flags
, dwExtraInfo
, Hook
);
128 /* 2. Store the new cursor position */
135 * We have to register that this object is in use by the current
136 * process. The only way to do that seems to be to walk the list
137 * of cursor/icon objects starting at W32Process->CursorIconListHead.
138 * If the object is already present in the list, we don't have to do
139 * anything, if it's not present we add it and inc the ProcessCount
140 * in the object. Having to walk the list kind of sucks, but that's
143 static BOOLEAN FASTCALL
144 ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon
)
146 PPROCESSINFO Win32Process
;
147 PCURICON_PROCESS Current
;
149 Win32Process
= PsGetCurrentProcessWin32Process();
151 LIST_FOR_EACH(Current
, &CurIcon
->ProcessList
, CURICON_PROCESS
, ListEntry
)
153 if (Current
->Process
== Win32Process
)
155 /* Already registered for this process */
160 /* Not registered yet */
161 Current
= ExAllocateFromPagedLookasideList(pgProcessLookasideList
);
166 InsertHeadList(&CurIcon
->ProcessList
, &Current
->ListEntry
);
167 Current
->Process
= Win32Process
;
172 PCURICON_OBJECT FASTCALL
173 IntFindExistingCurIconObject(HMODULE hModule
,
174 HRSRC hRsrc
, LONG cx
, LONG cy
)
176 PCURICON_OBJECT CurIcon
;
178 LIST_FOR_EACH(CurIcon
, &gCurIconList
, CURICON_OBJECT
, ListEntry
)
181 // if (NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) // <- huh????
182 // UserReferenceObject( CurIcon);
184 if ((CurIcon
->hModule
== hModule
) && (CurIcon
->hRsrc
== hRsrc
))
186 if (cx
&& ((cx
!= CurIcon
->Size
.cx
) || (cy
!= CurIcon
->Size
.cy
)))
188 // UserDereferenceObject(CurIcon);
191 if (! ReferenceCurIconByProcess(CurIcon
))
199 // UserDereferenceObject(CurIcon);
207 IntCreateCurIconHandle()
209 PCURICON_OBJECT CurIcon
;
212 CurIcon
= UserCreateObject(gHandleTable
, NULL
, NULL
, &hCurIcon
, otCursorIcon
, sizeof(CURICON_OBJECT
));
216 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
220 CurIcon
->Self
= hCurIcon
;
221 InitializeListHead(&CurIcon
->ProcessList
);
223 if (! ReferenceCurIconByProcess(CurIcon
))
225 ERR("Failed to add process\n");
226 UserDeleteObject(hCurIcon
, otCursorIcon
);
227 UserDereferenceObject(CurIcon
);
231 InsertHeadList(&gCurIconList
, &CurIcon
->ListEntry
);
237 IntDestroyCurIconObject(PCURICON_OBJECT CurIcon
, PPROCESSINFO ppi
)
239 PSYSTEM_CURSORINFO CurInfo
;
240 HBITMAP bmpMask
, bmpColor
, bmpAlpha
;
241 BOOLEAN Ret
, bListEmpty
, bFound
= FALSE
;
242 PCURICON_PROCESS Current
= NULL
;
244 /* For handles created without any data (error handling) */
245 if(IsListEmpty(&CurIcon
->ProcessList
))
248 /* Now find this process in the list of processes referencing this object and
249 remove it from that list */
250 LIST_FOR_EACH(Current
, &CurIcon
->ProcessList
, CURICON_PROCESS
, ListEntry
)
252 if (Current
->Process
== ppi
)
255 bListEmpty
= RemoveEntryList(&Current
->ListEntry
);
262 /* This object doesn't belong to this process */
263 EngSetLastError(ERROR_INVALID_HANDLE
);
267 ExFreeToPagedLookasideList(pgProcessLookasideList
, Current
);
269 /* If there are still processes referencing this object we can't destroy it yet */
272 if(CurIcon
->head
.ppi
== ppi
)
274 /* Set the first process of the list as owner */
275 Current
= CONTAINING_RECORD(CurIcon
->ProcessList
.Flink
, CURICON_PROCESS
, ListEntry
);
276 UserSetObjectOwner(CurIcon
, otCursorIcon
, Current
->Process
);
278 UserDereferenceObject(CurIcon
);
283 /* Remove it from the list */
284 RemoveEntryList(&CurIcon
->ListEntry
);
286 CurInfo
= IntGetSysCursorInfo();
288 if (CurInfo
->CurrentCursorObject
== CurIcon
)
290 /* Hide the cursor if we're destroying the current cursor */
291 UserSetCursor(NULL
, TRUE
);
294 bmpMask
= CurIcon
->aFrame
[0].hbmMask
;
295 bmpColor
= CurIcon
->aFrame
[0].hbmColor
;
296 bmpAlpha
= CurIcon
->aFrame
[0].hbmAlpha
;
301 GreSetObjectOwner(bmpMask
, GDI_OBJ_HMGR_POWNED
);
302 GreDeleteObject(bmpMask
);
303 CurIcon
->aFrame
[0].hbmMask
= NULL
;
307 GreSetObjectOwner(bmpColor
, GDI_OBJ_HMGR_POWNED
);
308 GreDeleteObject(bmpColor
);
309 CurIcon
->aFrame
[0].hbmColor
= NULL
;
313 GreSetObjectOwner(bmpAlpha
, GDI_OBJ_HMGR_POWNED
);
314 GreDeleteObject(bmpAlpha
);
315 CurIcon
->aFrame
[0].hbmAlpha
= NULL
;
318 /* We were given a pointer, no need to keep the reference anylonger! */
319 UserDereferenceObject(CurIcon
);
320 Ret
= UserDeleteObject(CurIcon
->Self
, otCursorIcon
);
326 IntCleanupCurIcons(struct _EPROCESS
*Process
, PPROCESSINFO Win32Process
)
328 PCURICON_OBJECT CurIcon
, tmp
;
330 /* Run through the list of icon objects */
331 LIST_FOR_EACH_SAFE(CurIcon
, tmp
, &gCurIconList
, CURICON_OBJECT
, ListEntry
)
333 UserReferenceObject(CurIcon
);
334 IntDestroyCurIconObject(CurIcon
, Win32Process
);
347 PUNICODE_STRING lpInstName
, // Optional
348 PUNICODE_STRING lpResName
, // Optional
349 LPDWORD pbpp
, // Optional
353 PCURICON_OBJECT CurIcon
;
354 NTSTATUS Status
= STATUS_SUCCESS
;
358 TRACE("Enter NtUserGetIconInfo\n");
359 UserEnterExclusive();
363 EngSetLastError(ERROR_INVALID_PARAMETER
);
367 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
373 ii
.fIcon
= CurIcon
->bIcon
;
374 ii
.xHotspot
= CurIcon
->ptlHotspot
.x
;
375 ii
.yHotspot
= CurIcon
->ptlHotspot
.y
;
378 ii
.hbmMask
= BITMAP_CopyBitmap(CurIcon
->aFrame
[0].hbmMask
);
379 ii
.hbmColor
= BITMAP_CopyBitmap(CurIcon
->aFrame
[0].hbmColor
);
385 psurfBmp
= SURFACE_ShareLockSurface(CurIcon
->aFrame
[0].hbmColor
);
388 colorBpp
= BitsPerFormat(psurfBmp
->SurfObj
.iBitmapFormat
);
389 SURFACE_ShareUnlockSurface(psurfBmp
);
396 ProbeForWrite(IconInfo
, sizeof(ICONINFO
), 1);
397 RtlCopyMemory(IconInfo
, &ii
, sizeof(ICONINFO
));
401 ProbeForWrite(pbpp
, sizeof(DWORD
), 1);
405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
407 Status
= _SEH2_GetExceptionCode();
411 if (NT_SUCCESS(Status
))
414 SetLastNtError(Status
);
416 UserDereferenceObject(CurIcon
);
419 TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret
);
434 PLONG plcx
, // &size.cx
435 PLONG plcy
) // &size.cy
437 PCURICON_OBJECT CurIcon
;
438 NTSTATUS Status
= STATUS_SUCCESS
;
441 TRACE("Enter NtUserGetIconSize\n");
442 UserEnterExclusive();
444 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
451 ProbeForWrite(plcx
, sizeof(LONG
), 1);
452 RtlCopyMemory(plcx
, &CurIcon
->Size
.cx
, sizeof(LONG
));
453 ProbeForWrite(plcy
, sizeof(LONG
), 1);
454 RtlCopyMemory(plcy
, &CurIcon
->Size
.cy
, sizeof(LONG
));
456 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
458 Status
= _SEH2_GetExceptionCode();
462 if (NT_SUCCESS(Status
))
465 SetLastNtError(Status
); // Maybe not, test this
467 UserDereferenceObject(CurIcon
);
470 TRACE("Leave NtUserGetIconSize, ret=%i\n", bRet
);
485 PSYSTEM_CURSORINFO CurInfo
;
486 NTSTATUS Status
= STATUS_SUCCESS
;
487 PCURICON_OBJECT CurIcon
;
489 DECLARE_RETURN(BOOL
);
491 TRACE("Enter NtUserGetCursorInfo\n");
492 UserEnterExclusive();
494 CurInfo
= IntGetSysCursorInfo();
495 CurIcon
= (PCURICON_OBJECT
)CurInfo
->CurrentCursorObject
;
497 SafeCi
.cbSize
= sizeof(CURSORINFO
);
498 SafeCi
.flags
= ((CurIcon
&& CurInfo
->ShowingCursor
>= 0) ? CURSOR_SHOWING
: 0);
499 SafeCi
.hCursor
= (CurIcon
? (HCURSOR
)CurIcon
->Self
: (HCURSOR
)0);
501 SafeCi
.ptScreenPos
= gpsi
->ptCursor
;
505 if (pci
->cbSize
== sizeof(CURSORINFO
))
507 ProbeForWrite(pci
, sizeof(CURSORINFO
), 1);
508 RtlCopyMemory(pci
, &SafeCi
, sizeof(CURSORINFO
));
513 EngSetLastError(ERROR_INVALID_PARAMETER
);
516 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
518 Status
= _SEH2_GetExceptionCode();
521 if (!NT_SUCCESS(Status
))
523 SetLastNtError(Status
);
529 TRACE("Leave NtUserGetCursorInfo, ret=%i\n",_ret_
);
539 /* FIXME: Check if process has WINSTA_WRITEATTRIBUTES */
540 PSYSTEM_CURSORINFO CurInfo
;
541 PWND DesktopWindow
= NULL
;
543 CurInfo
= IntGetSysCursorInfo();
545 DesktopWindow
= UserGetDesktopWindow();
547 if (prcl
!= NULL
&& DesktopWindow
!= NULL
)
549 if (prcl
->right
< prcl
->left
|| prcl
->bottom
< prcl
->top
)
551 EngSetLastError(ERROR_INVALID_PARAMETER
);
555 CurInfo
->bClipped
= TRUE
;
557 /* Set nw cliping region. Note: we can't use RECTL_bIntersectRect because
558 it sets rect to 0 0 0 0 when it's empty. For more info see monitor winetest */
559 CurInfo
->rcClip
.left
= max(prcl
->left
, DesktopWindow
->rcWindow
.left
);
560 CurInfo
->rcClip
.right
= min(prcl
->right
, DesktopWindow
->rcWindow
.right
);
561 if (CurInfo
->rcClip
.right
< CurInfo
->rcClip
.left
)
562 CurInfo
->rcClip
.right
= CurInfo
->rcClip
.left
;
564 CurInfo
->rcClip
.top
= max(prcl
->top
, DesktopWindow
->rcWindow
.top
);
565 CurInfo
->rcClip
.bottom
= min(prcl
->bottom
, DesktopWindow
->rcWindow
.bottom
);
566 if (CurInfo
->rcClip
.bottom
< CurInfo
->rcClip
.top
)
567 CurInfo
->rcClip
.bottom
= CurInfo
->rcClip
.top
;
569 /* Make sure cursor is in clipping region */
570 UserSetCursorPos(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
, 0, 0, FALSE
);
574 CurInfo
->bClipped
= FALSE
;
595 /* Probe and copy rect */
596 ProbeForRead(prcl
, sizeof(RECTL
), 1);
599 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
601 EngSetLastError(ERROR_INVALID_PARAMETER
);
602 _SEH2_YIELD(return FALSE
;)
609 UserEnterExclusive();
611 /* Call the internal function */
612 bResult
= UserClipCursor(prcl
);
629 PCURICON_OBJECT CurIcon
;
631 DECLARE_RETURN(BOOL
);
633 TRACE("Enter NtUserDestroyCursorIcon\n");
634 UserEnterExclusive();
636 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
641 ret
= IntDestroyCurIconObject(CurIcon
, PsGetCurrentProcessWin32Process());
642 /* Note: IntDestroyCurIconObject will remove our reference for us! */
647 TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_
);
658 NtUserFindExistingCursorIcon(
664 PCURICON_OBJECT CurIcon
;
665 HANDLE Ret
= (HANDLE
)0;
666 DECLARE_RETURN(HICON
);
668 TRACE("Enter NtUserFindExistingCursorIcon\n");
669 UserEnterExclusive();
671 CurIcon
= IntFindExistingCurIconObject(hModule
, hRsrc
, cx
, cy
);
676 // IntReleaseCurIconObject(CurIcon); // FIXME: Is this correct? Does IntFindExistingCurIconObject add a ref?
680 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
684 TRACE("Leave NtUserFindExistingCursorIcon, ret=%p\n",_ret_
);
698 /* FIXME: Check if process has WINSTA_READATTRIBUTES */
699 PSYSTEM_CURSORINFO CurInfo
;
702 DECLARE_RETURN(BOOL
);
704 TRACE("Enter NtUserGetClipCursor\n");
705 UserEnterExclusive();
710 CurInfo
= IntGetSysCursorInfo();
711 if (CurInfo
->bClipped
)
713 Rect
= CurInfo
->rcClip
;
719 Rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
720 Rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
723 Status
= MmCopyToCaller(lpRect
, &Rect
, sizeof(RECT
));
724 if (!NT_SUCCESS(Status
))
726 SetLastNtError(Status
);
733 TRACE("Leave NtUserGetClipCursor, ret=%i\n",_ret_
);
747 PCURICON_OBJECT pcurOld
, pcurNew
;
748 HCURSOR hOldCursor
= NULL
;
750 TRACE("Enter NtUserSetCursor\n");
751 UserEnterExclusive();
755 pcurNew
= UserGetCurIconObject(hCursor
);
758 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
767 pcurOld
= UserSetCursor(pcurNew
, FALSE
);
770 hOldCursor
= (HCURSOR
)pcurOld
->Self
;
771 UserDereferenceObject(pcurOld
);
785 NtUserSetCursorContents(
787 PICONINFO UnsafeIconInfo
)
789 PCURICON_OBJECT CurIcon
;
794 DECLARE_RETURN(BOOL
);
796 TRACE("Enter NtUserSetCursorContents\n");
797 UserEnterExclusive();
799 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
805 Status
= MmCopyFromCaller(&IconInfo
, UnsafeIconInfo
, sizeof(ICONINFO
));
806 if (!NT_SUCCESS(Status
))
808 SetLastNtError(Status
);
813 /* Check if we get valid information */
814 if(IconInfo
.fIcon
!= CurInfo
->bIcon
)
816 EngSetLastError(ERROR_INVALID_PARAMETER
);
821 /* Delete old bitmaps */
822 if (CurIcon
->aFrame
[0].hbmColor
)
823 GreDeleteObject(CurIcon
->aFrame
[0].hbmColor
);
824 if (CurIcon
->aFrame
[0].hbmMask
)
825 GreDeleteObject(CurIcon
->aFrame
[0].hbmMask
);
826 if(CurIcon
->aFrame
[0].hbmAlpha
)
827 GreDeleteObject(CurIcon
->aFrame
[0].hbmAlpha
);
830 CurIcon
->bIcon
= IconInfo
.fIcon
;
831 CurIcon
->ptlHotspot
.x
= IconInfo
.xHotspot
;
832 CurIcon
->ptlHotspot
.y
= IconInfo
.yHotspot
;
833 CurIcon
->aFrame
[0].hbmMask
= IconInfo
.hbmMask
;
834 CurIcon
->aFrame
[0].hbmColor
= IconInfo
.hbmColor
;
835 CurIcon
->aFrame
[0].hbmAlpha
= NULL
;
837 if (IconInfo
.hbmColor
)
839 BOOLEAN bAlpha
= FALSE
;
840 psurfBmp
= SURFACE_ShareLockSurface(IconInfo
.hbmColor
);
843 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
844 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
846 /* 32bpp bitmap is likely to have an alpha channel */
847 if(psurfBmp
->SurfObj
.iBitmapFormat
== BMF_32BPP
)
849 PFN_DIB_GetPixel fn_GetPixel
= DibFunctionsForBitmapFormat
[BMF_32BPP
].DIB_GetPixel
;
852 fn_GetPixel
= DibFunctionsForBitmapFormat
[BMF_32BPP
].DIB_GetPixel
;
853 for (i
= 0; i
< psurfBmp
->SurfObj
.sizlBitmap
.cx
; i
++)
855 for (j
= 0; j
< psurfBmp
->SurfObj
.sizlBitmap
.cy
; j
++)
857 bAlpha
= ((BYTE
)(fn_GetPixel(&psurfBmp
->SurfObj
, i
, j
) >> 24)) != 0;
865 /* We're done with this one */
866 SURFACE_ShareUnlockSurface(psurfBmp
);
867 GreSetObjectOwner(IconInfo
.hbmColor
, GDI_OBJ_HMGR_PUBLIC
);
874 /* Copy the bitmap */
875 CurIcon
->aFrame
[0].hbmAlpha
= BITMAP_CopyBitmap(IconInfo
.hbmColor
);
876 if(!CurIcon
->aFrame
[0].hbmAlpha
)
878 ERR("BITMAP_CopyBitmap failed!");
882 psurfBmp
= SURFACE_ShareLockSurface(CurIcon
->aFrame
[0].hbmAlpha
);
885 ERR("SURFACE_LockSurface failed!\n");
889 /* Premultiply with the alpha channel value */
890 for (i
= 0; i
< psurfBmp
->SurfObj
.sizlBitmap
.cy
; i
++)
892 ptr
= (PBYTE
)psurfBmp
->SurfObj
.pvScan0
+ i
*psurfBmp
->SurfObj
.lDelta
;
893 for (j
= 0; j
< psurfBmp
->SurfObj
.sizlBitmap
.cx
; j
++)
896 ptr
[0] = (ptr
[0] * Alpha
) / 0xff;
897 ptr
[1] = (ptr
[1] * Alpha
) / 0xff;
898 ptr
[2] = (ptr
[2] * Alpha
) / 0xff;
902 SURFACE_ShareUnlockSurface(psurfBmp
);
903 GreSetObjectOwner(CurIcon
->aFrame
[0].hbmAlpha
, GDI_OBJ_HMGR_PUBLIC
);
908 psurfBmp
= SURFACE_ShareLockSurface(IconInfo
.hbmMask
);
912 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
913 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
/ 2;
915 SURFACE_ShareUnlockSurface(psurfBmp
);
917 GreSetObjectOwner(IconInfo
.hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
925 IntDestroyCurIconObject(CurIcon
, PsGetCurrentProcessWin32Process());
931 UserDereferenceObject(CurIcon
);
936 TRACE("Leave NtUserSetCursorContents, ret=%i\n",_ret_
);
945 #ifdef NEW_CURSORICON
948 NtUserSetCursorIconData(
950 _In_ HINSTANCE hinst
,
952 _In_ PICONINFO pIconInfo
)
954 PCURICON_OBJECT CurIcon
;
956 NTSTATUS Status
= STATUS_SUCCESS
;
958 DECLARE_RETURN(BOOL
);
961 TRACE("Enter NtUserSetCursorIconData\n");
962 UserEnterExclusive();
964 if (!(CurIcon
= UserGetCurIconObject(Handle
)))
969 CurIcon
->hModule
= hinst
;
970 CurIcon
->hRsrc
=hrsrc
;
974 ProbeForRead(pIconInfo
, sizeof(ICONINFO
), 1);
977 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
979 Status
= _SEH2_GetExceptionCode();
983 if (!NT_SUCCESS(Status
))
985 SetLastNtError(Status
);
989 /* This is probably not what windows does, but consistency checks can't hurt */
990 if(CurIcon
->bIcon
!= ii
.fIcon
)
992 EngSetLastError(ERROR_INVALID_PARAMETER
);
995 CurIcon
->ptlHotspot
.x
= ii
.xHotspot
;
996 CurIcon
->ptlHotspot
.y
= ii
.yHotspot
;
1000 EngSetLastError(ERROR_INVALID_PARAMETER
);
1004 CurIcon
->aFrame
[0].hbmMask
= BITMAP_CopyBitmap(ii
.hbmMask
);
1005 if(!CurIcon
->aFrame
[0].hbmMask
)
1010 CurIcon
->aFrame
[0].hbmColor
= BITMAP_CopyBitmap(ii
.hbmColor
);
1011 if(!CurIcon
->aFrame
[0].hbmColor
)
1015 if (CurIcon
->aFrame
[0].hbmColor
)
1017 if ((psurfBmp
= SURFACE_ShareLockSurface(CurIcon
->aFrame
[0].hbmColor
)))
1019 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
1020 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
1021 SURFACE_ShareUnlockSurface(psurfBmp
);
1022 GreSetObjectOwner(CurIcon
->aFrame
[0].hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
1029 if ((psurfBmp
= SURFACE_ShareLockSurface(CurIcon
->aFrame
[0].hbmMask
)))
1031 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
1032 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
/2;
1033 SURFACE_ShareUnlockSurface(psurfBmp
);
1038 GreSetObjectOwner(CurIcon
->aFrame
[0].hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
1043 UserDereferenceObject(CurIcon
);
1046 if (CurIcon
->aFrame
[0].hbmMask
)
1048 GreSetObjectOwner(CurIcon
->aFrame
[0].hbmMask
, GDI_OBJ_HMGR_POWNED
);
1049 GreDeleteObject(CurIcon
->aFrame
[0].hbmMask
);
1050 CurIcon
->aFrame
[0].hbmMask
= NULL
;
1052 if (CurIcon
->aFrame
[0].hbmColor
)
1054 GreSetObjectOwner(CurIcon
->aFrame
[0].hbmColor
, GDI_OBJ_HMGR_POWNED
);
1055 GreDeleteObject(CurIcon
->aFrame
[0].hbmColor
);
1056 CurIcon
->aFrame
[0].hbmColor
= NULL
;
1062 TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_
);
1069 NtUserSetCursorIconData(
1077 PCURICON_OBJECT CurIcon
;
1080 DECLARE_RETURN(BOOL
);
1082 TRACE("Enter NtUserSetCursorIconData\n");
1083 UserEnterExclusive();
1085 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
1090 CurIcon
->hModule
= hModule
;
1091 CurIcon
->hRsrc
= hRsrc
;
1092 CurIcon
->hGroupRsrc
= hGroupRsrc
;
1097 Status
= MmCopyFromCaller(&CurIcon
->bIcon
, fIcon
, sizeof(BOOL
));
1098 if (!NT_SUCCESS(Status
))
1100 SetLastNtError(Status
);
1112 Status
= MmCopyFromCaller(&CurIcon
->ptlHotspot
, Hotspot
, sizeof(POINT
));
1113 if (!NT_SUCCESS(Status
))
1115 SetLastNtError(Status
);
1120 if (!fIcon
&& !Hotspot
)
1128 /* This icon is shared now */
1129 GreSetObjectOwner(CurIcon
->aFrame
[0].hbmMask
, GDI_OBJ_HMGR_PUBLIC
);
1130 if(CurIcon
->aFrame
[0].hbmColor
)
1132 GreSetObjectOwner(CurIcon
->aFrame
[0].hbmColor
, GDI_OBJ_HMGR_PUBLIC
);
1134 if(CurIcon
->aFrame
[0].hbmAlpha
)
1136 GreSetObjectOwner(CurIcon
->aFrame
[0].hbmAlpha
, GDI_OBJ_HMGR_PUBLIC
);
1139 UserDereferenceObject(CurIcon
);
1144 TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_
);
1150 /* Mostly inspired from wine code.
1151 * We use low level functions because:
1152 * - at this point, the icon bitmap could have a different bit depth than the DC,
1153 * making it thus impossible to use NtCreateCompatibleDC and selecting the bitmap.
1154 * This happens after a mode setting change.
1155 * - it avoids massive GDI objects locking when only the destination surface needs it.
1156 * - It makes (small) performance gains.
1163 PCURICON_OBJECT pIcon
,
1167 HBRUSH hbrFlickerFreeDraw
,
1170 PSURFACE psurfDest
, psurfMask
, psurfColor
, psurfOffScreen
;
1173 HBITMAP hbmMask
, hbmColor
, hbmAlpha
;
1175 RECTL rcDest
, rcSrc
;
1176 CLIPOBJ
* pdcClipObj
= NULL
;
1180 if((diFlags
& DI_NORMAL
) == 0)
1182 ERR("DrawIconEx called without mask or color bitmap to draw.\n");
1186 hbmMask
= pIcon
->aFrame
[0].hbmMask
;
1187 hbmColor
= pIcon
->aFrame
[0].hbmColor
;
1188 hbmAlpha
= pIcon
->aFrame
[0].hbmAlpha
;
1191 ERR("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1195 * Shared locks are enough, we are only reading those bitmaps
1197 psurfMask
= SURFACE_ShareLockSurface(hbmMask
);
1198 if(psurfMask
== NULL
)
1200 ERR("Unable to lock the mask surface.\n");
1204 /* Color bitmap is not mandatory */
1205 if(hbmColor
== NULL
)
1207 /* But then the mask bitmap must have the information in it's bottom half */
1208 ASSERT(psurfMask
->SurfObj
.sizlBitmap
.cy
== 2*pIcon
->Size
.cy
);
1211 else if ((psurfColor
= SURFACE_ShareLockSurface(hbmColor
)) == NULL
)
1213 ERR("Unable to lock the color bitmap.\n");
1214 SURFACE_ShareUnlockSurface(psurfMask
);
1218 /* Set source rect */
1219 RECTL_vSetRect(&rcSrc
, 0, 0, pIcon
->Size
.cx
, pIcon
->Size
.cy
);
1221 /* Fix width parameter, if needed */
1224 if(diFlags
& DI_DEFAULTSIZE
)
1225 cxWidth
= pIcon
->bIcon
?
1226 UserGetSystemMetrics(SM_CXICON
) : UserGetSystemMetrics(SM_CXCURSOR
);
1228 cxWidth
= pIcon
->Size
.cx
;
1231 /* Fix height parameter, if needed */
1234 if(diFlags
& DI_DEFAULTSIZE
)
1235 cyHeight
= pIcon
->bIcon
?
1236 UserGetSystemMetrics(SM_CYICON
) : UserGetSystemMetrics(SM_CYCURSOR
);
1238 cyHeight
= pIcon
->Size
.cy
;
1241 /* Should we render off-screen? */
1242 bOffScreen
= hbrFlickerFreeDraw
&& (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw
) == GDI_OBJECT_TYPE_BRUSH
);
1246 /* Yes: Allocate and paint the offscreen surface */
1248 PBRUSH pbrush
= BRUSH_ShareLockBrush(hbrFlickerFreeDraw
);
1250 TRACE("Performing off-screen rendering.\n");
1254 ERR("Failed to get brush object.\n");
1255 SURFACE_ShareUnlockSurface(psurfMask
);
1256 if(psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1260 psurfOffScreen
= SURFACE_AllocSurface(STYPE_BITMAP
,
1261 cxWidth
, cyHeight
, psurfColor
->SurfObj
.iBitmapFormat
,
1265 ERR("Failed to allocate the off-screen surface.\n");
1266 SURFACE_ShareUnlockSurface(psurfMask
);
1267 if(psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1268 BRUSH_ShareUnlockBrush(pbrush
);
1272 /* Paint the brush */
1273 EBRUSHOBJ_vInit(&eboFill
, pbrush
, psurfOffScreen
, 0x00FFFFFF, 0, NULL
);
1274 RECTL_vSetRect(&rcDest
, 0, 0, cxWidth
, cyHeight
);
1276 Ret
= IntEngBitBlt(&psurfOffScreen
->SurfObj
,
1284 &eboFill
.BrushObject
,
1288 /* Clean up everything */
1289 EBRUSHOBJ_vCleanup(&eboFill
);
1290 BRUSH_ShareUnlockBrush(pbrush
);
1294 ERR("Failed to paint the off-screen surface.\n");
1295 SURFACE_ShareUnlockSurface(psurfMask
);
1296 if(psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1297 GDIOBJ_vDeleteObject(&psurfOffScreen
->BaseObject
);
1301 /* We now have our destination surface */
1302 psurfDest
= psurfOffScreen
;
1306 /* We directly draw to the DC */
1307 TRACE("Performing on screen rendering.\n");
1309 psurfOffScreen
= NULL
;
1310 pdc
= DC_LockDc(hDc
);
1313 ERR("Could not lock the destination DC.\n");
1314 SURFACE_ShareUnlockSurface(psurfMask
);
1315 if(psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1318 /* Calculate destination rectangle */
1319 RECTL_vSetRect(&rcDest
, xLeft
, yTop
, xLeft
+ cxWidth
, yTop
+ cyHeight
);
1320 IntLPtoDP(pdc
, (LPPOINT
)&rcDest
, 2);
1321 RECTL_vOffsetRect(&rcDest
, pdc
->ptlDCOrig
.x
, pdc
->ptlDCOrig
.y
);
1323 /* Prepare the underlying surface */
1324 DC_vPrepareDCsForBlit(pdc
, rcDest
, NULL
, rcDest
);
1326 /* Get the clip object */
1327 pdcClipObj
= pdc
->rosdc
.CombinedClip
;
1329 /* We now have our destination surface and rectangle */
1330 psurfDest
= pdc
->dclevel
.pSurface
;
1332 if(psurfDest
== NULL
)
1335 DC_vFinishBlit(pdc
, NULL
);
1337 SURFACE_ShareUnlockSurface(psurfMask
);
1338 if(psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1343 /* Now do the rendering */
1344 if(hbmAlpha
&& (diFlags
& DI_IMAGE
))
1346 BLENDOBJ blendobj
= { {AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
} };
1347 PSURFACE psurf
= NULL
;
1349 psurf
= SURFACE_ShareLockSurface(hbmAlpha
);
1352 ERR("SURFACE_LockSurface failed!\n");
1356 /* Initialize color translation object */
1357 EXLATEOBJ_vInitialize(&exlo
, psurf
->ppal
, psurfDest
->ppal
, 0xFFFFFFFF, 0xFFFFFFFF, 0);
1360 Ret
= IntEngAlphaBlend(&psurfDest
->SurfObj
,
1368 EXLATEOBJ_vCleanup(&exlo
);
1369 SURFACE_ShareUnlockSurface(psurf
);
1371 ERR("NtGdiAlphaBlend failed!\n");
1374 if (diFlags
& DI_MASK
)
1376 DWORD rop4
= (diFlags
& DI_IMAGE
) ? ROP4_SRCAND
: ROP4_SRCCOPY
;
1378 EXLATEOBJ_vInitSrcMonoXlate(&exlo
, psurfDest
->ppal
, 0x00FFFFFF, 0);
1380 Ret
= IntEngStretchBlt(&psurfDest
->SurfObj
,
1381 &psurfMask
->SurfObj
,
1393 EXLATEOBJ_vCleanup(&exlo
);
1397 ERR("Failed to mask the bitmap data.\n");
1402 if(diFlags
& DI_IMAGE
)
1406 DWORD rop4
= (diFlags
& DI_MASK
) ? ROP4_SRCINVERT
: ROP4_SRCCOPY
;
1408 EXLATEOBJ_vInitialize(&exlo
, psurfColor
->ppal
, psurfDest
->ppal
, 0x00FFFFFF, 0x00FFFFFF, 0);
1410 Ret
= IntEngStretchBlt(&psurfDest
->SurfObj
,
1411 &psurfColor
->SurfObj
,
1423 EXLATEOBJ_vCleanup(&exlo
);
1427 ERR("Failed to render the icon bitmap.\n");
1433 /* Mask bitmap holds the information in its bottom half */
1434 DWORD rop4
= (diFlags
& DI_MASK
) ? ROP4_SRCINVERT
: ROP4_SRCCOPY
;
1435 RECTL_vOffsetRect(&rcSrc
, 0, pIcon
->Size
.cy
);
1437 EXLATEOBJ_vInitSrcMonoXlate(&exlo
, psurfDest
->ppal
, 0x00FFFFFF, 0);
1439 Ret
= IntEngStretchBlt(&psurfDest
->SurfObj
,
1440 &psurfMask
->SurfObj
,
1452 EXLATEOBJ_vCleanup(&exlo
);
1456 ERR("Failed to render the icon bitmap.\n");
1463 /* We're done. Was it a double buffered draw ? */
1466 /* Yes. Draw it back to our DC */
1467 POINTL ptSrc
= {0, 0};
1468 pdc
= DC_LockDc(hDc
);
1471 ERR("Could not lock the destination DC.\n");
1474 /* Calculate destination rectangle */
1475 RECTL_vSetRect(&rcDest
, xLeft
, yTop
, xLeft
+ cxWidth
, yTop
+ cyHeight
);
1476 IntLPtoDP(pdc
, (LPPOINT
)&rcDest
, 2);
1477 RECTL_vOffsetRect(&rcDest
, pdc
->ptlDCOrig
.x
, pdc
->ptlDCOrig
.y
);
1479 /* Prepare the underlying surface */
1480 DC_vPrepareDCsForBlit(pdc
, rcDest
, NULL
, rcDest
);
1482 /* Get the clip object */
1483 pdcClipObj
= pdc
->rosdc
.CombinedClip
;
1485 /* We now have our destination surface and rectangle */
1486 psurfDest
= pdc
->dclevel
.pSurface
;
1489 /* So, you did all of this for an empty DC. */
1494 /* Color translation */
1495 EXLATEOBJ_vInitialize(&exlo
, psurfOffScreen
->ppal
, psurfDest
->ppal
, 0x00FFFFFF, 0x00FFFFFF, 0);
1498 Ret
= IntEngBitBlt(&psurfDest
->SurfObj
,
1499 &psurfOffScreen
->SurfObj
,
1510 EXLATEOBJ_vCleanup(&exlo
);
1515 DC_vFinishBlit(pdc
, NULL
);
1520 /* Delete off screen rendering surface */
1522 GDIOBJ_vDeleteObject(&psurfOffScreen
->BaseObject
);
1524 /* Unlock other surfaces */
1525 SURFACE_ShareUnlockSurface(psurfMask
);
1526 if(psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
1544 HBRUSH hbrFlickerFreeDraw
,
1546 BOOL bMetaHDC
, // When TRUE, GDI functions need to be handled in User32!
1549 PCURICON_OBJECT pIcon
;
1552 TRACE("Enter NtUserDrawIconEx\n");
1553 UserEnterExclusive();
1555 if (!(pIcon
= UserGetCurIconObject(hIcon
)))
1557 ERR("UserGetCurIconObject() failed!\n");
1562 Ret
= UserDrawIconEx(hdc
,
1572 UserDereferenceObject(pIcon
);