2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 * We handle two types of cursors/icons:
23 * Loaded without LR_SHARED flag
24 * Private to a process
25 * Can be deleted by calling NtDestroyCursorIcon()
26 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
28 * Loaded with LR_SHARED flag
29 * Possibly shared by multiple processes
30 * Immune to NtDestroyCursorIcon()
31 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
32 * There's a M:N relationship between processes and (shared) cursor/icons.
33 * A process can have multiple cursor/icons and a cursor/icon can be used
34 * by multiple processes. To keep track of this we keep a list of all
35 * cursor/icons (CurIconList) and per cursor/icon we keep a list of
36 * CURICON_PROCESS structs starting at CurIcon->ProcessList.
44 static PAGED_LOOKASIDE_LIST gProcessLookasideList
;
45 static LIST_ENTRY gCurIconList
;
47 SYSTEM_CURSORINFO gSysCursorInfo
;
52 ExInitializePagedLookasideList(&gProcessLookasideList
,
56 sizeof(CURICON_PROCESS
),
59 InitializeListHead(&gCurIconList
);
61 gSysCursorInfo
.Enabled
= FALSE
;
62 gSysCursorInfo
.ButtonsDown
= 0;
63 gSysCursorInfo
.CursorClipInfo
.IsClipped
= FALSE
;
64 gSysCursorInfo
.LastBtnDown
= 0;
65 gSysCursorInfo
.CurrentCursorObject
= NULL
;
66 gSysCursorInfo
.ShowingCursor
= 0;
67 gSysCursorInfo
.ClickLockActive
= FALSE
;
68 gSysCursorInfo
.ClickLockTime
= 0;
76 return &gSysCursorInfo
;
79 /* This function creates a reference for the object! */
80 PCURICON_OBJECT FASTCALL
UserGetCurIconObject(HCURSOR hCurIcon
)
82 PCURICON_OBJECT CurIcon
;
86 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE
);
90 CurIcon
= (PCURICON_OBJECT
)UserReferenceObjectByHandle(hCurIcon
, otCursorIcon
);
93 /* we never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
94 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE
);
98 ASSERT(CurIcon
->head
.cLockObj
>= 1);
105 PCURICON_OBJECT NewCursor
,
108 PSYSTEM_CURSORINFO CurInfo
;
109 PCURICON_OBJECT OldCursor
;
110 HCURSOR hOldCursor
= (HCURSOR
)0;
114 CurInfo
= IntGetSysCursorInfo();
116 OldCursor
= CurInfo
->CurrentCursorObject
;
119 hOldCursor
= (HCURSOR
)OldCursor
->Self
;
122 /* Is the new cursor the same as the old cursor? */
123 if (OldCursor
== NewCursor
)
125 /* Nothing to to do in this case */
129 /* Get the screen DC */
130 if(!(hdcScreen
= IntGetScreenDC()))
135 /* Do we have a new cursor? */
138 UserReferenceObject(NewCursor
);
140 CurInfo
->ShowingCursor
= 1;
141 CurInfo
->CurrentCursorObject
= NewCursor
;
143 /* Call GDI to set the new screen cursor */
144 bResult
= GreSetPointerShape(hdcScreen
,
145 NewCursor
->IconInfo
.hbmMask
,
146 NewCursor
->IconInfo
.hbmColor
,
147 NewCursor
->IconInfo
.xHotspot
,
148 NewCursor
->IconInfo
.yHotspot
,
156 /* Check if were diplaying a cursor */
157 if (OldCursor
&& CurInfo
->ShowingCursor
)
159 /* Remove the cursor */
160 GreMovePointer(hdcScreen
, -1, -1);
161 DPRINT("Removing pointer!\n");
164 CurInfo
->CurrentCursorObject
= NULL
;
165 CurInfo
->ShowingCursor
= 0;
168 /* OldCursor is not in use anymore */
171 UserDereferenceObject(OldCursor
);
174 /* Return handle of the old cursor */
178 BOOL
UserSetCursorPos( INT x
, INT y
, BOOL SendMouseMoveMsg
)
180 PWINDOW_OBJECT DesktopWindow
;
181 PSYSTEM_CURSORINFO CurInfo
;
185 if(!(hDC
= IntGetScreenDC()))
190 CurInfo
= IntGetSysCursorInfo();
192 DesktopWindow
= UserGetDesktopWindow();
196 if(x
>= DesktopWindow
->Wnd
->rcClient
.right
)
197 x
= DesktopWindow
->Wnd
->rcClient
.right
- 1;
198 if(y
>= DesktopWindow
->Wnd
->rcClient
.bottom
)
199 y
= DesktopWindow
->Wnd
->rcClient
.bottom
- 1;
207 //Clip cursor position
208 if(CurInfo
->CursorClipInfo
.IsClipped
)
210 if(x
>= (LONG
)CurInfo
->CursorClipInfo
.Right
)
211 x
= (LONG
)CurInfo
->CursorClipInfo
.Right
- 1;
212 if(x
< (LONG
)CurInfo
->CursorClipInfo
.Left
)
213 x
= (LONG
)CurInfo
->CursorClipInfo
.Left
;
214 if(y
>= (LONG
)CurInfo
->CursorClipInfo
.Bottom
)
215 y
= (LONG
)CurInfo
->CursorClipInfo
.Bottom
- 1;
216 if(y
< (LONG
)CurInfo
->CursorClipInfo
.Top
)
217 y
= (LONG
)CurInfo
->CursorClipInfo
.Top
;
220 //Store the new cursor position
221 gpsi
->ptCursor
.x
= x
;
222 gpsi
->ptCursor
.y
= y
;
224 //Move the mouse pointer
225 GreMovePointer(hDC
, x
, y
);
227 if (!SendMouseMoveMsg
)
230 //Generate a mouse move message
231 Msg
.message
= WM_MOUSEMOVE
;
232 Msg
.wParam
= CurInfo
->ButtonsDown
;
233 Msg
.lParam
= MAKELPARAM(x
, y
);
234 Msg
.pt
= gpsi
->ptCursor
;
235 MsqInsertSystemMessage(&Msg
);
240 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
241 * User32 macro NtUserShowCursor */
242 int UserShowCursor(BOOL bShow
)
244 PSYSTEM_CURSORINFO CurInfo
= IntGetSysCursorInfo();
247 if (!(hdcScreen
= IntGetScreenDC()))
249 return 0; /* No mouse */
254 /* Check if were diplaying a cursor */
255 if (CurInfo
->ShowingCursor
== 1)
257 /* Remove the pointer */
258 GreMovePointer(hdcScreen
, -1, -1);
259 DPRINT("Removing pointer!\n");
261 CurInfo
->ShowingCursor
--;
265 if (CurInfo
->ShowingCursor
== 0)
268 GreMovePointer(hdcScreen
, gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
270 CurInfo
->ShowingCursor
++;
273 return CurInfo
->ShowingCursor
;
277 * We have to register that this object is in use by the current
278 * process. The only way to do that seems to be to walk the list
279 * of cursor/icon objects starting at W32Process->CursorIconListHead.
280 * If the object is already present in the list, we don't have to do
281 * anything, if it's not present we add it and inc the ProcessCount
282 * in the object. Having to walk the list kind of sucks, but that's
285 static BOOLEAN FASTCALL
286 ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon
)
288 PPROCESSINFO Win32Process
;
289 PCURICON_PROCESS Current
;
291 Win32Process
= PsGetCurrentProcessWin32Process();
293 LIST_FOR_EACH(Current
, &CurIcon
->ProcessList
, CURICON_PROCESS
, ListEntry
)
295 if (Current
->Process
== Win32Process
)
297 /* Already registered for this process */
302 /* Not registered yet */
303 Current
= ExAllocateFromPagedLookasideList(&gProcessLookasideList
);
308 InsertHeadList(&CurIcon
->ProcessList
, &Current
->ListEntry
);
309 Current
->Process
= Win32Process
;
314 PCURICON_OBJECT FASTCALL
315 IntFindExistingCurIconObject(HMODULE hModule
,
316 HRSRC hRsrc
, LONG cx
, LONG cy
)
318 PCURICON_OBJECT CurIcon
;
320 LIST_FOR_EACH(CurIcon
, &gCurIconList
, CURICON_OBJECT
, ListEntry
)
323 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
324 // UserReferenceObject( CurIcon);
326 if ((CurIcon
->hModule
== hModule
) && (CurIcon
->hRsrc
== hRsrc
))
328 if (cx
&& ((cx
!= CurIcon
->Size
.cx
) || (cy
!= CurIcon
->Size
.cy
)))
330 // UserDereferenceObject(CurIcon);
333 if (! ReferenceCurIconByProcess(CurIcon
))
341 // UserDereferenceObject(CurIcon);
349 IntCreateCurIconHandle()
351 PCURICON_OBJECT CurIcon
;
354 CurIcon
= UserCreateObject(gHandleTable
, NULL
, &hCurIcon
, otCursorIcon
, sizeof(CURICON_OBJECT
));
358 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
362 CurIcon
->Self
= hCurIcon
;
363 InitializeListHead(&CurIcon
->ProcessList
);
365 if (! ReferenceCurIconByProcess(CurIcon
))
367 DPRINT1("Failed to add process\n");
368 UserDeleteObject(hCurIcon
, otCursorIcon
);
369 UserDereferenceObject(CurIcon
);
373 InsertHeadList(&gCurIconList
, &CurIcon
->ListEntry
);
379 IntDestroyCurIconObject(PCURICON_OBJECT CurIcon
, BOOL ProcessCleanup
)
381 PSYSTEM_CURSORINFO CurInfo
;
382 HBITMAP bmpMask
, bmpColor
;
384 PCURICON_PROCESS Current
= NULL
;
385 PPROCESSINFO W32Process
= PsGetCurrentProcessWin32Process();
387 /* Private objects can only be destroyed by their own process */
388 if (NULL
== CurIcon
->hModule
)
390 ASSERT(CurIcon
->ProcessList
.Flink
->Flink
== &CurIcon
->ProcessList
);
391 Current
= CONTAINING_RECORD(CurIcon
->ProcessList
.Flink
, CURICON_PROCESS
, ListEntry
);
392 if (Current
->Process
!= W32Process
)
394 DPRINT1("Trying to destroy private icon/cursor of another process\n");
398 else if (! ProcessCleanup
)
400 DPRINT("Trying to destroy shared icon/cursor\n");
404 /* Now find this process in the list of processes referencing this object and
405 remove it from that list */
406 LIST_FOR_EACH(Current
, &CurIcon
->ProcessList
, CURICON_PROCESS
, ListEntry
)
408 if (Current
->Process
== W32Process
)
410 RemoveEntryList(&Current
->ListEntry
);
415 ExFreeToPagedLookasideList(&gProcessLookasideList
, Current
);
417 /* If there are still processes referencing this object we can't destroy it yet */
418 if (! IsListEmpty(&CurIcon
->ProcessList
))
424 if (! ProcessCleanup
)
426 RemoveEntryList(&CurIcon
->ListEntry
);
429 CurInfo
= IntGetSysCursorInfo();
431 if (CurInfo
->CurrentCursorObject
== CurIcon
)
433 /* Hide the cursor if we're destroying the current cursor */
434 UserSetCursor(NULL
, TRUE
);
437 bmpMask
= CurIcon
->IconInfo
.hbmMask
;
438 bmpColor
= CurIcon
->IconInfo
.hbmColor
;
443 GDIOBJ_SetOwnership(bmpMask
, PsGetCurrentProcess());
444 GreDeleteObject(bmpMask
);
445 CurIcon
->IconInfo
.hbmMask
= NULL
;
449 GDIOBJ_SetOwnership(bmpColor
, PsGetCurrentProcess());
450 GreDeleteObject(bmpColor
);
451 CurIcon
->IconInfo
.hbmColor
= NULL
;
454 /* We were given a pointer, no need to keep the reference anylonger! */
455 UserDereferenceObject(CurIcon
);
456 Ret
= UserDeleteObject(CurIcon
->Self
, otCursorIcon
);
462 IntCleanupCurIcons(struct _EPROCESS
*Process
, PPROCESSINFO Win32Process
)
464 PCURICON_OBJECT CurIcon
, tmp
;
465 PCURICON_PROCESS ProcessData
;
467 LIST_FOR_EACH_SAFE(CurIcon
, tmp
, &gCurIconList
, CURICON_OBJECT
, ListEntry
)
469 UserReferenceObject(CurIcon
);
470 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon)))
472 LIST_FOR_EACH(ProcessData
, &CurIcon
->ProcessList
, CURICON_PROCESS
, ListEntry
)
474 if (Win32Process
== ProcessData
->Process
)
476 RemoveEntryList(&CurIcon
->ListEntry
);
477 IntDestroyCurIconObject(CurIcon
, TRUE
);
483 // UserDereferenceObject(Object);
488 UserDereferenceObject(CurIcon
);
503 PUNICODE_STRING lpInstName
, // optional
504 PUNICODE_STRING lpResName
, // optional
505 LPDWORD pbpp
, // optional
509 PCURICON_OBJECT CurIcon
;
510 NTSTATUS Status
= STATUS_SUCCESS
;
514 DPRINT("Enter NtUserGetIconInfo\n");
515 UserEnterExclusive();
519 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
523 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
528 RtlCopyMemory(&ii
, &CurIcon
->IconInfo
, sizeof(ICONINFO
));
531 ii
.hbmMask
= BITMAP_CopyBitmap(CurIcon
->IconInfo
.hbmMask
);
532 ii
.hbmColor
= BITMAP_CopyBitmap(CurIcon
->IconInfo
.hbmColor
);
538 psurfBmp
= SURFACE_LockSurface(CurIcon
->IconInfo
.hbmColor
);
541 colorBpp
= BitsPerFormat(psurfBmp
->SurfObj
.iBitmapFormat
);
542 SURFACE_UnlockSurface(psurfBmp
);
549 ProbeForWrite(IconInfo
, sizeof(ICONINFO
), 1);
550 RtlCopyMemory(IconInfo
, &ii
, sizeof(ICONINFO
));
554 ProbeForWrite(pbpp
, sizeof(DWORD
), 1);
558 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
560 Status
= _SEH2_GetExceptionCode();
564 if (NT_SUCCESS(Status
))
567 SetLastNtError(Status
);
569 UserDereferenceObject(CurIcon
);
572 DPRINT("Leave NtUserGetIconInfo, ret=%i\n", Ret
);
587 PLONG plcx
, // &size.cx
588 PLONG plcy
) // &size.cy
590 PCURICON_OBJECT CurIcon
;
591 NTSTATUS Status
= STATUS_SUCCESS
;
594 DPRINT("Enter NtUserGetIconSize\n");
595 UserEnterExclusive();
597 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
604 ProbeForWrite(plcx
, sizeof(LONG
), 1);
605 RtlCopyMemory(plcx
, &CurIcon
->Size
.cx
, sizeof(LONG
));
606 ProbeForWrite(plcy
, sizeof(LONG
), 1);
607 RtlCopyMemory(plcy
, &CurIcon
->Size
.cy
, sizeof(LONG
));
609 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
611 Status
= _SEH2_GetExceptionCode();
615 if (NT_SUCCESS(Status
))
618 SetLastNtError(Status
); // maybe not, test this
620 UserDereferenceObject(CurIcon
);
623 DPRINT("Leave NtUserGetIconSize, ret=%i\n", bRet
);
634 NtUserGetCursorFrameInfo(
655 PSYSTEM_CURSORINFO CurInfo
;
656 NTSTATUS Status
= STATUS_SUCCESS
;
657 PCURICON_OBJECT CurIcon
;
659 DECLARE_RETURN(BOOL
);
661 DPRINT("Enter NtUserGetCursorInfo\n");
662 UserEnterExclusive();
664 CurInfo
= IntGetSysCursorInfo();
665 CurIcon
= (PCURICON_OBJECT
)CurInfo
->CurrentCursorObject
;
667 SafeCi
.cbSize
= sizeof(CURSORINFO
);
668 SafeCi
.flags
= ((CurInfo
->ShowingCursor
&& CurIcon
) ? CURSOR_SHOWING
: 0);
669 SafeCi
.hCursor
= (CurIcon
? (HCURSOR
)CurIcon
->Self
: (HCURSOR
)0);
671 SafeCi
.ptScreenPos
= gpsi
->ptCursor
;
675 if (pci
->cbSize
== sizeof(CURSORINFO
))
677 ProbeForWrite(pci
, sizeof(CURSORINFO
), 1);
678 RtlCopyMemory(pci
, &SafeCi
, sizeof(CURSORINFO
));
683 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
686 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
688 Status
= _SEH2_GetExceptionCode();
691 if (!NT_SUCCESS(Status
))
693 SetLastNtError(Status
);
699 DPRINT("Leave NtUserGetCursorInfo, ret=%i\n",_ret_
);
709 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
710 PSYSTEM_CURSORINFO CurInfo
;
711 PWINDOW_OBJECT DesktopWindow
= NULL
;
713 CurInfo
= IntGetSysCursorInfo();
715 DesktopWindow
= UserGetDesktopWindow();
718 (prcl
->right
> prcl
->left
) &&
719 (prcl
->bottom
> prcl
->top
) &&
720 DesktopWindow
!= NULL
)
722 CurInfo
->CursorClipInfo
.IsClipped
= TRUE
;
723 CurInfo
->CursorClipInfo
.Left
= max(prcl
->left
, DesktopWindow
->Wnd
->rcWindow
.left
);
724 CurInfo
->CursorClipInfo
.Top
= max(prcl
->top
, DesktopWindow
->Wnd
->rcWindow
.top
);
725 CurInfo
->CursorClipInfo
.Right
= min(prcl
->right
, DesktopWindow
->Wnd
->rcWindow
.right
);
726 CurInfo
->CursorClipInfo
.Bottom
= min(prcl
->bottom
, DesktopWindow
->Wnd
->rcWindow
.bottom
);
728 UserSetCursorPos(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
, FALSE
);
732 CurInfo
->CursorClipInfo
.IsClipped
= FALSE
;
746 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
754 /* Probe and copy rect */
755 ProbeForRead(prcl
, sizeof(RECTL
), 1);
758 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
760 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
761 _SEH2_YIELD(return FALSE
;)
768 UserEnterExclusive();
770 /* Call the internal function */
771 bResult
= UserClipCursor(prcl
);
788 PCURICON_OBJECT CurIcon
;
790 DECLARE_RETURN(BOOL
);
792 DPRINT("Enter NtUserDestroyCursorIcon\n");
793 UserEnterExclusive();
795 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
800 ret
= IntDestroyCurIconObject(CurIcon
, FALSE
);
801 /* Note: IntDestroyCurIconObject will remove our reference for us! */
806 DPRINT("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_
);
817 NtUserFindExistingCursorIcon(
823 PCURICON_OBJECT CurIcon
;
824 HANDLE Ret
= (HANDLE
)0;
825 DECLARE_RETURN(HICON
);
827 DPRINT("Enter NtUserFindExistingCursorIcon\n");
828 UserEnterExclusive();
830 CurIcon
= IntFindExistingCurIconObject(hModule
, hRsrc
, cx
, cy
);
835 // IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
839 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE
);
843 DPRINT("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_
);
857 /* FIXME - check if process has WINSTA_READATTRIBUTES */
858 PSYSTEM_CURSORINFO CurInfo
;
861 DECLARE_RETURN(BOOL
);
863 DPRINT("Enter NtUserGetClipCursor\n");
864 UserEnterExclusive();
869 CurInfo
= IntGetSysCursorInfo();
870 if (CurInfo
->CursorClipInfo
.IsClipped
)
872 Rect
.left
= CurInfo
->CursorClipInfo
.Left
;
873 Rect
.top
= CurInfo
->CursorClipInfo
.Top
;
874 Rect
.right
= CurInfo
->CursorClipInfo
.Right
;
875 Rect
.bottom
= CurInfo
->CursorClipInfo
.Bottom
;
881 Rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
882 Rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
885 Status
= MmCopyToCaller(lpRect
, &Rect
, sizeof(RECT
));
886 if (!NT_SUCCESS(Status
))
888 SetLastNtError(Status
);
895 DPRINT("Leave NtUserGetClipCursor, ret=%i\n",_ret_
);
909 PCURICON_OBJECT CurIcon
;
911 DECLARE_RETURN(HCURSOR
);
913 DPRINT("Enter NtUserSetCursor\n");
914 UserEnterExclusive();
918 if (!(CurIcon
= UserGetCurIconObject(hCursor
)))
928 OldCursor
= UserSetCursor(CurIcon
, FALSE
);
932 UserDereferenceObject(CurIcon
);
938 DPRINT("Leave NtUserSetCursor, ret=%i\n",_ret_
);
949 NtUserSetCursorContents(
951 PICONINFO UnsafeIconInfo
)
953 PCURICON_OBJECT CurIcon
;
958 DECLARE_RETURN(BOOL
);
960 DPRINT("Enter NtUserSetCursorContents\n");
961 UserEnterExclusive();
963 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
969 Status
= MmCopyFromCaller(&IconInfo
, UnsafeIconInfo
, sizeof(ICONINFO
));
970 if (!NT_SUCCESS(Status
))
972 SetLastNtError(Status
);
976 /* Delete old bitmaps */
977 if ((CurIcon
->IconInfo
.hbmColor
)
978 && (CurIcon
->IconInfo
.hbmColor
!= IconInfo
.hbmColor
))
980 GreDeleteObject(CurIcon
->IconInfo
.hbmColor
);
982 if ((CurIcon
->IconInfo
.hbmMask
)
983 && CurIcon
->IconInfo
.hbmMask
!= IconInfo
.hbmMask
)
985 GreDeleteObject(CurIcon
->IconInfo
.hbmMask
);
988 /* Copy new IconInfo field */
989 CurIcon
->IconInfo
= IconInfo
;
991 psurfBmp
= SURFACE_LockSurface(CurIcon
->IconInfo
.hbmColor
);
994 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
995 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
996 SURFACE_UnlockSurface(psurfBmp
);
997 GDIOBJ_SetOwnership(CurIcon
->IconInfo
.hbmColor
, NULL
);
1001 psurfBmp
= SURFACE_LockSurface(CurIcon
->IconInfo
.hbmMask
);
1005 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
1006 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
/ 2;
1008 SURFACE_UnlockSurface(psurfBmp
);
1009 GDIOBJ_SetOwnership(CurIcon
->IconInfo
.hbmMask
, NULL
);
1018 UserDereferenceObject(CurIcon
);
1023 DPRINT("Leave NtUserSetCursorContents, ret=%i\n",_ret_
);
1035 NtUserSetCursorIconData(
1038 PUNICODE_STRING pstrResName
,
1039 PICONINFO pIconInfo
)
1041 PCURICON_OBJECT CurIcon
;
1043 NTSTATUS Status
= STATUS_SUCCESS
;
1045 DECLARE_RETURN(BOOL
);
1047 DPRINT("Enter NtUserSetCursorIconData\n");
1048 UserEnterExclusive();
1050 if (!(CurIcon
= UserGetCurIconObject(Handle
)))
1055 CurIcon
->hModule
= hModule
;
1056 CurIcon
->hRsrc
= NULL
; //hRsrc;
1057 CurIcon
->hGroupRsrc
= NULL
; //hGroupRsrc;
1061 ProbeForRead(pIconInfo
, sizeof(ICONINFO
), 1);
1062 RtlCopyMemory(&CurIcon
->IconInfo
, pIconInfo
, sizeof(ICONINFO
));
1064 CurIcon
->IconInfo
.hbmMask
= BITMAP_CopyBitmap(pIconInfo
->hbmMask
);
1065 CurIcon
->IconInfo
.hbmColor
= BITMAP_CopyBitmap(pIconInfo
->hbmColor
);
1067 if (CurIcon
->IconInfo
.hbmColor
)
1069 if ((psurfBmp
= SURFACE_LockSurface(CurIcon
->IconInfo
.hbmColor
)))
1071 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
1072 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
1073 SURFACE_UnlockSurface(psurfBmp
);
1074 GDIOBJ_SetOwnership(GdiHandleTable
, CurIcon
->IconInfo
.hbmMask
, NULL
);
1077 if (CurIcon
->IconInfo
.hbmMask
)
1079 if (CurIcon
->IconInfo
.hbmColor
== NULL
)
1081 if ((psurfBmp
= SURFACE_LockSurface(CurIcon
->IconInfo
.hbmMask
)))
1083 CurIcon
->Size
.cx
= psurfBmp
->SurfObj
.sizlBitmap
.cx
;
1084 CurIcon
->Size
.cy
= psurfBmp
->SurfObj
.sizlBitmap
.cy
;
1085 SURFACE_UnlockSurface(psurfBmp
);
1088 GDIOBJ_SetOwnership(GdiHandleTable
, CurIcon
->IconInfo
.hbmMask
, NULL
);
1091 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1093 Status
= _SEH2_GetExceptionCode();
1097 if (!NT_SUCCESS(Status
))
1098 SetLastNtError(Status
);
1102 UserDereferenceObject(CurIcon
);
1106 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_
);
1113 NtUserSetCursorIconData(
1121 PCURICON_OBJECT CurIcon
;
1125 DECLARE_RETURN(BOOL
);
1127 DPRINT("Enter NtUserSetCursorIconData\n");
1128 UserEnterExclusive();
1130 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
1135 CurIcon
->hModule
= hModule
;
1136 CurIcon
->hRsrc
= hRsrc
;
1137 CurIcon
->hGroupRsrc
= hGroupRsrc
;
1142 Status
= MmCopyFromCaller(&CurIcon
->IconInfo
.fIcon
, fIcon
, sizeof(BOOL
));
1143 if (!NT_SUCCESS(Status
))
1145 SetLastNtError(Status
);
1157 Status
= MmCopyFromCaller(&SafeHotspot
, Hotspot
, sizeof(POINT
));
1158 if (NT_SUCCESS(Status
))
1160 CurIcon
->IconInfo
.xHotspot
= SafeHotspot
.x
;
1161 CurIcon
->IconInfo
.yHotspot
= SafeHotspot
.y
;
1166 SetLastNtError(Status
);
1169 if (!fIcon
&& !Hotspot
)
1177 /* This icon is shared now */
1178 GDIOBJ_SetOwnership(CurIcon
->IconInfo
.hbmMask
, NULL
);
1179 if(CurIcon
->IconInfo
.hbmColor
)
1181 GDIOBJ_SetOwnership(CurIcon
->IconInfo
.hbmColor
, NULL
);
1184 UserDereferenceObject(CurIcon
);
1189 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_
);
1200 NtUserSetSystemCursor(
1207 /* Mostly inspired from wine code */
1213 PCURICON_OBJECT pIcon
,
1217 HBRUSH hbrFlickerFreeDraw
,
1220 PSURFACE psurfColor
= NULL
, psurfMask
, psurfDst
= NULL
;
1225 HSURF hsurfDst
= NULL
;
1229 BOOL bAlpha
= FALSE
, Ret
= FALSE
, bStretch
;
1232 DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1234 DPRINT("Flags : 0x%08x\n", diFlags
);
1236 hObjs
[0] = pIcon
->IconInfo
.hbmMask
;
1237 hObjs
[1] = pIcon
->IconInfo
.hbmColor
;
1239 GDIOBJ_LockMultipleObjs(3, hObjs
, pObjs
);
1240 psurfMask
= pObjs
[0];
1241 psurfColor
= pObjs
[1];
1244 if (!pIcon
->IconInfo
.hbmMask
1247 DPRINT1("No hbmMask?!\n");
1248 if(pdc
) DC_UnlockDc(pdc
);
1249 if(psurfColor
) SURFACE_UnlockSurface(psurfColor
);
1253 if (pIcon
->IconInfo
.hbmColor
1256 DPRINT1("Unable to lock the color Bitmap?!\n");
1257 SURFACE_UnlockSurface(psurfMask
);
1258 if(pdc
) DC_UnlockDc(pdc
);
1264 DPRINT("Monochrome Icon\n");
1265 psurfColor
= psurfMask
;
1266 RECTL_vSetRect(&rcSrc
, 0, pIcon
->Size
.cy
, pIcon
->Size
.cx
, 2*pIcon
->Size
.cy
);
1270 DPRINT("Color Icon\n");
1271 RECTL_vSetRect(&rcSrc
, 0, 0, pIcon
->Size
.cx
, pIcon
->Size
.cy
);
1276 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1277 SURFACE_UnlockSurface(psurfMask
);
1278 if(psurfColor
!= psurfMask
) SURFACE_UnlockSurface(psurfColor
);
1279 DPRINT1("Invalid DC!\n");
1283 /* Check for alpha */
1284 if ((BitsPerFormat(psurfColor
->SurfObj
.iBitmapFormat
) == 32)
1285 && (diFlags
& DI_IMAGE
))
1287 PFN_DIB_GetPixel fnSource_GetPixel
= NULL
;
1290 /* In order to correctly display 32 bit icons Windows first scans the image,
1291 because information about transparency is not stored in any image's headers */
1292 fnSource_GetPixel
= DibFunctionsForBitmapFormat
[psurfColor
->SurfObj
.iBitmapFormat
].DIB_GetPixel
;
1293 if (fnSource_GetPixel
)
1295 for (i
= 0; i
< psurfColor
->SurfObj
.sizlBitmap
.cx
; i
++)
1297 for (j
= 0; j
< psurfColor
->SurfObj
.sizlBitmap
.cy
; j
++)
1299 bAlpha
= ((BYTE
)(fnSource_GetPixel(&psurfColor
->SurfObj
, i
, j
) >> 24) & 0xff);
1310 cxWidth
= ((diFlags
& DI_DEFAULTSIZE
) ?
1311 UserGetSystemMetrics(SM_CXICON
) : pIcon
->Size
.cx
);
1314 cyHeight
= ((diFlags
& DI_DEFAULTSIZE
) ?
1315 UserGetSystemMetrics(SM_CYICON
) : pIcon
->Size
.cy
);
1317 /* Check stretching */
1318 bStretch
= (pIcon
->Size
.cx
!= cxWidth
) || (pIcon
->Size
.cy
!= cyHeight
);
1320 DoFlickerFree
= (hbrFlickerFreeDraw
&&
1321 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw
) == GDI_OBJECT_TYPE_BRUSH
));
1329 pBrush
= BRUSH_LockBrush(hbrFlickerFreeDraw
);
1332 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1333 DPRINT1("Invalid brush!\n");
1337 hsurfDst
= IntCreateCompatibleBitmap(pdc
, cxWidth
, cyHeight
);
1340 DPRINT1("Error : Failed to allocate the offscreen surface\n");
1343 psurfDst
= SURFACE_LockSurface(hsurfDst
);
1346 DPRINT1("Error : Failed to lock the offScreen bitmap\n");
1349 RECTL_vSetRect(&rcDst
, 0, 0, cxWidth
, cyHeight
);
1351 ptBrushOrig
.x
= pBrush
->ptOrigin
.x
;
1352 ptBrushOrig
.y
= pBrush
->ptOrigin
.y
;
1354 EBRUSHOBJ_vInit(&ebo
, pBrush
, pdc
);
1356 clo
.iDComplexity
= DC_TRIVIAL
;
1359 IntEngBitBlt(&psurfDst
->SurfObj
, NULL
, NULL
, pclo
, NULL
, &rcDst
, NULL
,
1360 NULL
, &ebo
.BrushObject
, &ptBrushOrig
, ROP3_TO_ROP4(PATCOPY
));
1362 EBRUSHOBJ_vCleanup(&ebo
);
1363 BRUSH_UnlockBrush(pBrush
);
1368 RECTL_vSetRect(&rcDst
, xLeft
, yTop
, xLeft
+ cxWidth
, yTop
+ cyHeight
);
1369 IntLPtoDP(pdc
, (LPPOINT
)&rcDst
, 2);
1370 RECTL_vOffsetRect(&rcDst
, pdc
->ptlDCOrig
.x
, pdc
->ptlDCOrig
.y
);
1372 DC_vPrepareDCsForBlit(pdc
, rcDst
, NULL
, rcDst
);
1374 if (pdc
->pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
1375 DC_vUpdateFillBrush(pdc
);
1377 psurfDst
= pdc
->dclevel
.pSurface
;
1378 pclo
= pdc
->rosdc
.CombinedClip
;
1379 RECTL_vSetRect(&rcBmp
, 0, 0, psurfDst
->SurfObj
.sizlBitmap
.cx
, psurfDst
->SurfObj
.sizlBitmap
.cy
);
1380 if(!RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcBmp
))
1387 /* Optimization : use directly the palette of the DC,
1388 * so we XLATE only once, and then we directly copy bits */
1389 EXLATEOBJ_vInitialize(&exlo
, psurfColor
->ppal
, pdc
->dclevel
.pSurface
->ppal
, 0, 0, 0xFFFFFFFF);
1391 if(bAlpha
&& (diFlags
& DI_IMAGE
))
1393 BLENDFUNCTION pixelblend
= { AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
1396 PSURFACE psurf
= NULL
;
1398 HBITMAP hMemBmp
= NULL
;
1400 hMemBmp
= BITMAP_CopyBitmap(pIcon
->IconInfo
.hbmColor
);
1403 DPRINT1("BITMAP_CopyBitmap failed!");
1407 psurf
= SURFACE_LockSurface(hMemBmp
);
1410 DPRINT1("SURFACE_LockSurface failed!\n");
1414 /* premultiply with the alpha channel value */
1415 for (i
= 0; i
< psurf
->SurfObj
.sizlBitmap
.cy
; i
++)
1417 ptr
= (PBYTE
)psurf
->SurfObj
.pvScan0
+ i
*psurf
->SurfObj
.lDelta
;
1418 for (j
= 0; j
< psurf
->SurfObj
.sizlBitmap
.cx
; j
++)
1421 ptr
[0] = (ptr
[0] * Alpha
) / 0xff;
1422 ptr
[1] = (ptr
[1] * Alpha
) / 0xff;
1423 ptr
[2] = (ptr
[2] * Alpha
) / 0xff;
1429 DPRINT("Performing alpha blending\n");
1430 Ret
= IntEngAlphaBlend(&psurfDst
->SurfObj
,
1436 (BLENDOBJ
*)&pixelblend
);
1439 if(psurf
) SURFACE_UnlockSurface(psurf
);
1440 if(hMemBmp
) NtGdiDeleteObjectApp(hMemBmp
);
1442 else DPRINT1("IntEngAlphaBlend failed!\n");
1445 if (diFlags
& DI_IMAGE
)
1447 POINTL ptMaskOrig
= {0,0};
1450 DPRINT("Stretching\n");
1451 Ret
= IntEngStretchBlt(&psurfDst
->SurfObj
,
1452 &psurfColor
->SurfObj
,
1453 (diFlags
& DI_MASK
) ? &psurfMask
->SurfObj
: NULL
,
1458 (diFlags
& DI_MASK
) ? &ptMaskOrig
: NULL
,
1461 (diFlags
& DI_MASK
) ? R4_MASK
: ROP3_TO_ROP4(SRCCOPY
));
1462 if(!Ret
) DPRINT1("IntEngStretchBlt Failed\n");
1467 Ret
= IntEngBitBlt(&psurfDst
->SurfObj
,
1468 &psurfColor
->SurfObj
,
1469 (diFlags
& DI_MASK
) ? &psurfMask
->SurfObj
: NULL
,
1474 (diFlags
& DI_MASK
) ? &ptMaskOrig
: NULL
,
1477 (diFlags
& DI_MASK
) ? R4_MASK
: ROP3_TO_ROP4(SRCCOPY
));
1478 if(!Ret
) DPRINT1("IntEngBitBlt Failed\n");
1483 DPRINT1("Uh? Calling DrawIcon without anything to draw? diFlags %d\n", diFlags
);
1487 if(DoFlickerFree
&& Ret
)
1489 POINTL ptSrc
= {0,0};
1492 RECTL_vSetRect(&rcDst
, xLeft
, yTop
, xLeft
+ cxWidth
, yTop
+ cyHeight
);
1494 IntLPtoDP(pdc
, (LPPOINT
)&rcDst
, 2);
1496 RECTL_vOffsetRect(&rcDst
, pdc
->ptlDCOrig
.x
, pdc
->ptlDCOrig
.y
);
1497 DC_vPrepareDCsForBlit(pdc
, rcDst
, NULL
, rcDst
);
1499 if (pdc
->pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
1500 DC_vUpdateFillBrush(pdc
);
1502 RECTL_vSetRect(&rcBmp
, 0, 0,
1503 pdc
->dclevel
.pSurface
->SurfObj
.sizlBitmap
.cx
,
1504 pdc
->dclevel
.pSurface
->SurfObj
.sizlBitmap
.cy
);
1506 if(RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcBmp
))
1508 /* Copy everything */
1509 DPRINT("Copying bits from offscreen buffer\n");
1510 Ret
= IntEngCopyBits(&pdc
->dclevel
.pSurface
->SurfObj
,
1512 pdc
->rosdc
.CombinedClip
,
1516 if(!Ret
) DPRINT1("IntEngCopyBits Failed\n");
1519 DC_vFinishBlit(pdc
, NULL
);
1522 if(!DoFlickerFree
) DC_vFinishBlit(pdc
, NULL
);
1523 EXLATEOBJ_vCleanup(&exlo
);
1526 if(psurfColor
!= psurfMask
)
1527 SURFACE_UnlockSurface(psurfColor
);
1528 SURFACE_UnlockSurface(psurfMask
);
1531 if(psurfDst
) SURFACE_UnlockSurface(psurfDst
);
1532 GreDeleteObject(hsurfDst
);
1536 DPRINT("return %s\n", Ret
? "TRUE" : "FALSE") ;
1554 HBRUSH hbrFlickerFreeDraw
,
1556 BOOL bMetaHDC
, // When TRUE, GDI functions need to be handled in User32!
1559 PCURICON_OBJECT pIcon
;
1562 DPRINT("Enter NtUserDrawIconEx\n");
1563 UserEnterExclusive();
1565 if (!(pIcon
= UserGetCurIconObject(hIcon
)))
1567 DPRINT1("UserGetCurIconObject() failed!\n");
1572 Ret
= UserDrawIconEx(hdc
,
1582 UserDereferenceObject(pIcon
);