[CMAKE]
[reactos.git] / subsystems / win32 / win32k / ntuser / cursoricon.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19
20 /*
21 * We handle two types of cursors/icons:
22 * - Private
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
27 * - Shared
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.
37 */
38
39 #include <win32k.h>
40
41 #define NDEBUG
42 #include <debug.h>
43
44 static PAGED_LOOKASIDE_LIST gProcessLookasideList;
45 static LIST_ENTRY gCurIconList;
46
47 SYSTEM_CURSORINFO gSysCursorInfo;
48
49 BOOL
50 InitCursorImpl()
51 {
52 ExInitializePagedLookasideList(&gProcessLookasideList,
53 NULL,
54 NULL,
55 0,
56 sizeof(CURICON_PROCESS),
57 TAG_DIB,
58 128);
59 InitializeListHead(&gCurIconList);
60
61 gSysCursorInfo.Enabled = FALSE;
62 gSysCursorInfo.ButtonsDown = 0;
63 gSysCursorInfo.bClipped = FALSE;
64 gSysCursorInfo.LastBtnDown = 0;
65 gSysCursorInfo.CurrentCursorObject = NULL;
66 gSysCursorInfo.ShowingCursor = 0;
67 gSysCursorInfo.ClickLockActive = FALSE;
68 gSysCursorInfo.ClickLockTime = 0;
69
70 return TRUE;
71 }
72
73 PSYSTEM_CURSORINFO
74 IntGetSysCursorInfo()
75 {
76 return &gSysCursorInfo;
77 }
78
79 /* This function creates a reference for the object! */
80 PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
81 {
82 PCURICON_OBJECT CurIcon;
83
84 if (!hCurIcon)
85 {
86 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
87 return NULL;
88 }
89
90 CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, otCursorIcon);
91 if (!CurIcon)
92 {
93 /* we never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
94 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
95 return NULL;
96 }
97
98 ASSERT(CurIcon->head.cLockObj >= 1);
99 return CurIcon;
100 }
101
102 PCURICON_OBJECT
103 FASTCALL
104 UserSetCursor(
105 PCURICON_OBJECT NewCursor,
106 BOOL ForceChange)
107 {
108 PSYSTEM_CURSORINFO CurInfo;
109 PCURICON_OBJECT OldCursor;
110 HDC hdcScreen;
111
112 CurInfo = IntGetSysCursorInfo();
113
114 OldCursor = CurInfo->CurrentCursorObject;
115
116 /* Is the new cursor the same as the old cursor? */
117 if (OldCursor == NewCursor)
118 {
119 /* Nothing to to do in this case */
120 return OldCursor;
121 }
122
123 /* Get the screen DC */
124 if(!(hdcScreen = IntGetScreenDC()))
125 {
126 return (HCURSOR)0;
127 }
128
129 /* Do we have a new cursor? */
130 if (NewCursor)
131 {
132 CurInfo->ShowingCursor = 1;
133 CurInfo->CurrentCursorObject = NewCursor;
134
135 /* Call GDI to set the new screen cursor */
136 GreSetPointerShape(hdcScreen,
137 NewCursor->IconInfo.hbmMask,
138 NewCursor->IconInfo.hbmColor,
139 NewCursor->IconInfo.xHotspot,
140 NewCursor->IconInfo.yHotspot,
141 gpsi->ptCursor.x,
142 gpsi->ptCursor.y);
143 }
144 else
145 {
146 /* Check if were diplaying a cursor */
147 if (OldCursor && CurInfo->ShowingCursor)
148 {
149 /* Remove the cursor */
150 GreMovePointer(hdcScreen, -1, -1);
151 DPRINT("Removing pointer!\n");
152 }
153
154 CurInfo->CurrentCursorObject = NULL;
155 CurInfo->ShowingCursor = 0;
156 }
157
158 /* Return the old cursor */
159 return OldCursor;
160 }
161
162 BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
163 {
164 PWND DesktopWindow;
165 PSYSTEM_CURSORINFO CurInfo;
166 HDC hDC;
167 MSG Msg;
168 RECTL rcClip;
169 POINT pt;
170
171 if(!(hDC = IntGetScreenDC()))
172 {
173 return FALSE;
174 }
175
176 if(!(DesktopWindow = UserGetDesktopWindow()))
177 {
178 return FALSE;
179 }
180
181 CurInfo = IntGetSysCursorInfo();
182
183 /* Clip cursor position */
184 if (!CurInfo->bClipped)
185 rcClip = DesktopWindow->rcClient;
186 else
187 rcClip = CurInfo->rcClip;
188
189 if(x >= rcClip.right) x = rcClip.right - 1;
190 if(x < rcClip.left) x = rcClip.left;
191 if(y >= rcClip.bottom) y = rcClip.bottom - 1;
192 if(y < rcClip.top) y = rcClip.top;
193
194 pt.x = x;
195 pt.y = y;
196
197 /* 3. Generate a mouse move message, this sets the htEx and Track Window too. */
198 Msg.message = WM_MOUSEMOVE;
199 Msg.wParam = CurInfo->ButtonsDown;
200 Msg.lParam = MAKELPARAM(x, y);
201 Msg.pt = pt;
202 co_MsqInsertMouseMessage(&Msg, flags, dwExtraInfo, Hook);
203
204 /* 1. Store the new cursor position */
205 gpsi->ptCursor = pt;
206
207 /* 2. Move the mouse pointer */
208 GreMovePointer(hDC, x, y);
209
210 return TRUE;
211 }
212
213 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
214 * User32 macro NtUserShowCursor */
215 int UserShowCursor(BOOL bShow)
216 {
217 PSYSTEM_CURSORINFO CurInfo = IntGetSysCursorInfo();
218 HDC hdcScreen;
219
220 if (!(hdcScreen = IntGetScreenDC()))
221 {
222 return 0; /* No mouse */
223 }
224
225 if (bShow == FALSE)
226 {
227 /* Check if were diplaying a cursor */
228 if (CurInfo->ShowingCursor == 1)
229 {
230 /* Remove the pointer */
231 GreMovePointer(hdcScreen, -1, -1);
232 DPRINT("Removing pointer!\n");
233 }
234 CurInfo->ShowingCursor--;
235 }
236 else
237 {
238 if (CurInfo->ShowingCursor == 0)
239 {
240 /*Show the pointer*/
241 GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y);
242 }
243 CurInfo->ShowingCursor++;
244 }
245
246 return CurInfo->ShowingCursor;
247 }
248
249 /*
250 * We have to register that this object is in use by the current
251 * process. The only way to do that seems to be to walk the list
252 * of cursor/icon objects starting at W32Process->CursorIconListHead.
253 * If the object is already present in the list, we don't have to do
254 * anything, if it's not present we add it and inc the ProcessCount
255 * in the object. Having to walk the list kind of sucks, but that's
256 * life...
257 */
258 static BOOLEAN FASTCALL
259 ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
260 {
261 PPROCESSINFO Win32Process;
262 PCURICON_PROCESS Current;
263
264 Win32Process = PsGetCurrentProcessWin32Process();
265
266 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
267 {
268 if (Current->Process == Win32Process)
269 {
270 /* Already registered for this process */
271 return TRUE;
272 }
273 }
274
275 /* Not registered yet */
276 Current = ExAllocateFromPagedLookasideList(&gProcessLookasideList);
277 if (NULL == Current)
278 {
279 return FALSE;
280 }
281 InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
282 Current->Process = Win32Process;
283
284 return TRUE;
285 }
286
287 PCURICON_OBJECT FASTCALL
288 IntFindExistingCurIconObject(HMODULE hModule,
289 HRSRC hRsrc, LONG cx, LONG cy)
290 {
291 PCURICON_OBJECT CurIcon;
292
293 LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
294 {
295
296 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
297 // UserReferenceObject( CurIcon);
298 // {
299 if ((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
300 {
301 if (cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
302 {
303 // UserDereferenceObject(CurIcon);
304 continue;
305 }
306 if (! ReferenceCurIconByProcess(CurIcon))
307 {
308 return NULL;
309 }
310
311 return CurIcon;
312 }
313 // }
314 // UserDereferenceObject(CurIcon);
315
316 }
317
318 return NULL;
319 }
320
321 PCURICON_OBJECT
322 IntCreateCurIconHandle()
323 {
324 PCURICON_OBJECT CurIcon;
325 HANDLE hCurIcon;
326
327 CurIcon = UserCreateObject(gHandleTable, NULL, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));
328
329 if (!CurIcon)
330 {
331 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
332 return FALSE;
333 }
334
335 CurIcon->Self = hCurIcon;
336 InitializeListHead(&CurIcon->ProcessList);
337
338 if (! ReferenceCurIconByProcess(CurIcon))
339 {
340 DPRINT1("Failed to add process\n");
341 UserDeleteObject(hCurIcon, otCursorIcon);
342 UserDereferenceObject(CurIcon);
343 return NULL;
344 }
345
346 InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
347
348 return CurIcon;
349 }
350
351 BOOLEAN FASTCALL
352 IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, BOOL ProcessCleanup)
353 {
354 PSYSTEM_CURSORINFO CurInfo;
355 HBITMAP bmpMask, bmpColor;
356 BOOLEAN Ret;
357 PCURICON_PROCESS Current = NULL;
358 PPROCESSINFO W32Process = PsGetCurrentProcessWin32Process();
359
360 /* Private objects can only be destroyed by their own process */
361 if (NULL == CurIcon->hModule)
362 {
363 ASSERT(CurIcon->ProcessList.Flink->Flink == &CurIcon->ProcessList);
364 Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
365 if (Current->Process != W32Process)
366 {
367 DPRINT1("Trying to destroy private icon/cursor of another process\n");
368 return FALSE;
369 }
370 }
371 else if (! ProcessCleanup)
372 {
373 DPRINT("Trying to destroy shared icon/cursor\n");
374 return FALSE;
375 }
376
377 /* Now find this process in the list of processes referencing this object and
378 remove it from that list */
379 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
380 {
381 if (Current->Process == W32Process)
382 {
383 RemoveEntryList(&Current->ListEntry);
384 break;
385 }
386 }
387
388 ExFreeToPagedLookasideList(&gProcessLookasideList, Current);
389
390 /* If there are still processes referencing this object we can't destroy it yet */
391 if (! IsListEmpty(&CurIcon->ProcessList))
392 {
393 return TRUE;
394 }
395
396
397 if (! ProcessCleanup)
398 {
399 RemoveEntryList(&CurIcon->ListEntry);
400 }
401
402 CurInfo = IntGetSysCursorInfo();
403
404 if (CurInfo->CurrentCursorObject == CurIcon)
405 {
406 /* Hide the cursor if we're destroying the current cursor */
407 UserSetCursor(NULL, TRUE);
408 }
409
410 bmpMask = CurIcon->IconInfo.hbmMask;
411 bmpColor = CurIcon->IconInfo.hbmColor;
412
413 /* delete bitmaps */
414 if (bmpMask)
415 {
416 GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
417 GreDeleteObject(bmpMask);
418 CurIcon->IconInfo.hbmMask = NULL;
419 }
420 if (bmpColor)
421 {
422 GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
423 GreDeleteObject(bmpColor);
424 CurIcon->IconInfo.hbmColor = NULL;
425 }
426
427 /* We were given a pointer, no need to keep the reference anylonger! */
428 UserDereferenceObject(CurIcon);
429 Ret = UserDeleteObject(CurIcon->Self, otCursorIcon);
430
431 return Ret;
432 }
433
434 VOID FASTCALL
435 IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
436 {
437 PCURICON_OBJECT CurIcon, tmp;
438 PCURICON_PROCESS ProcessData;
439
440 LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
441 {
442 UserReferenceObject(CurIcon);
443 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon)))
444 {
445 LIST_FOR_EACH(ProcessData, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
446 {
447 if (Win32Process == ProcessData->Process)
448 {
449 RemoveEntryList(&CurIcon->ListEntry);
450 IntDestroyCurIconObject(CurIcon, TRUE);
451 CurIcon = NULL;
452 break;
453 }
454 }
455
456 // UserDereferenceObject(Object);
457 }
458
459 if (CurIcon)
460 {
461 UserDereferenceObject(CurIcon);
462 }
463 }
464
465 }
466
467
468 /*
469 * @implemented
470 */
471 BOOL
472 APIENTRY
473 NtUserGetIconInfo(
474 HANDLE hCurIcon,
475 PICONINFO IconInfo,
476 PUNICODE_STRING lpInstName, // optional
477 PUNICODE_STRING lpResName, // optional
478 LPDWORD pbpp, // optional
479 BOOL bInternal)
480 {
481 ICONINFO ii;
482 PCURICON_OBJECT CurIcon;
483 NTSTATUS Status = STATUS_SUCCESS;
484 BOOL Ret = FALSE;
485 DWORD colorBpp = 0;
486
487 DPRINT("Enter NtUserGetIconInfo\n");
488 UserEnterExclusive();
489
490 if (!IconInfo)
491 {
492 EngSetLastError(ERROR_INVALID_PARAMETER);
493 goto leave;
494 }
495
496 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
497 {
498 goto leave;
499 }
500
501 RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO));
502
503 /* Copy bitmaps */
504 ii.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
505 ii.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
506
507 if (pbpp)
508 {
509 PSURFACE psurfBmp;
510
511 psurfBmp = SURFACE_ShareLockSurface(CurIcon->IconInfo.hbmColor);
512 if (psurfBmp)
513 {
514 colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
515 SURFACE_ShareUnlockSurface(psurfBmp);
516 }
517 }
518
519 /* Copy fields */
520 _SEH2_TRY
521 {
522 ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
523 RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
524
525 if (pbpp)
526 {
527 ProbeForWrite(pbpp, sizeof(DWORD), 1);
528 *pbpp = colorBpp;
529 }
530 }
531 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
532 {
533 Status = _SEH2_GetExceptionCode();
534 }
535 _SEH2_END
536
537 if (NT_SUCCESS(Status))
538 Ret = TRUE;
539 else
540 SetLastNtError(Status);
541
542 UserDereferenceObject(CurIcon);
543
544 leave:
545 DPRINT("Leave NtUserGetIconInfo, ret=%i\n", Ret);
546 UserLeave();
547
548 return Ret;
549 }
550
551
552 /*
553 * @implemented
554 */
555 BOOL
556 APIENTRY
557 NtUserGetIconSize(
558 HANDLE hCurIcon,
559 UINT istepIfAniCur,
560 PLONG plcx, // &size.cx
561 PLONG plcy) // &size.cy
562 {
563 PCURICON_OBJECT CurIcon;
564 NTSTATUS Status = STATUS_SUCCESS;
565 BOOL bRet = FALSE;
566
567 DPRINT("Enter NtUserGetIconSize\n");
568 UserEnterExclusive();
569
570 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
571 {
572 goto cleanup;
573 }
574
575 _SEH2_TRY
576 {
577 ProbeForWrite(plcx, sizeof(LONG), 1);
578 RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
579 ProbeForWrite(plcy, sizeof(LONG), 1);
580 RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
581 }
582 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
583 {
584 Status = _SEH2_GetExceptionCode();
585 }
586 _SEH2_END
587
588 if (NT_SUCCESS(Status))
589 bRet = TRUE;
590 else
591 SetLastNtError(Status); // maybe not, test this
592
593 UserDereferenceObject(CurIcon);
594
595 cleanup:
596 DPRINT("Leave NtUserGetIconSize, ret=%i\n", bRet);
597 UserLeave();
598 return bRet;
599 }
600
601
602 /*
603 * @implemented
604 */
605 BOOL
606 APIENTRY
607 NtUserGetCursorInfo(
608 PCURSORINFO pci)
609 {
610 CURSORINFO SafeCi;
611 PSYSTEM_CURSORINFO CurInfo;
612 NTSTATUS Status = STATUS_SUCCESS;
613 PCURICON_OBJECT CurIcon;
614 BOOL Ret = FALSE;
615 DECLARE_RETURN(BOOL);
616
617 DPRINT("Enter NtUserGetCursorInfo\n");
618 UserEnterExclusive();
619
620 CurInfo = IntGetSysCursorInfo();
621 CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
622
623 SafeCi.cbSize = sizeof(CURSORINFO);
624 SafeCi.flags = ((CurInfo->ShowingCursor && CurIcon) ? CURSOR_SHOWING : 0);
625 SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
626
627 SafeCi.ptScreenPos = gpsi->ptCursor;
628
629 _SEH2_TRY
630 {
631 if (pci->cbSize == sizeof(CURSORINFO))
632 {
633 ProbeForWrite(pci, sizeof(CURSORINFO), 1);
634 RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
635 Ret = TRUE;
636 }
637 else
638 {
639 EngSetLastError(ERROR_INVALID_PARAMETER);
640 }
641 }
642 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
643 {
644 Status = _SEH2_GetExceptionCode();
645 }
646 _SEH2_END;
647 if (!NT_SUCCESS(Status))
648 {
649 SetLastNtError(Status);
650 }
651
652 RETURN(Ret);
653
654 CLEANUP:
655 DPRINT("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
656 UserLeave();
657 END_CLEANUP;
658 }
659
660 BOOL
661 APIENTRY
662 UserClipCursor(
663 RECTL *prcl)
664 {
665 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
666 PSYSTEM_CURSORINFO CurInfo;
667 PWND DesktopWindow = NULL;
668
669 CurInfo = IntGetSysCursorInfo();
670
671 DesktopWindow = UserGetDesktopWindow();
672
673 if (prcl != NULL &&
674 (prcl->right > prcl->left) &&
675 (prcl->bottom > prcl->top) &&
676 DesktopWindow != NULL)
677 {
678 CurInfo->bClipped = TRUE;
679 RECTL_bIntersectRect(&CurInfo->rcClip, prcl, &DesktopWindow->rcWindow);
680 UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, 0, 0, FALSE);
681 }
682 else
683 {
684 CurInfo->bClipped = FALSE;
685 }
686
687 return TRUE;
688 }
689
690 /*
691 * @implemented
692 */
693 BOOL
694 APIENTRY
695 NtUserClipCursor(
696 RECTL *prcl)
697 {
698 RECTL rclLocal;
699 BOOL bResult;
700
701 if (prcl)
702 {
703 _SEH2_TRY
704 {
705 /* Probe and copy rect */
706 ProbeForRead(prcl, sizeof(RECTL), 1);
707 rclLocal = *prcl;
708 }
709 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
710 {
711 EngSetLastError(ERROR_INVALID_PARAMETER);
712 _SEH2_YIELD(return FALSE;)
713 }
714 _SEH2_END
715
716 prcl = &rclLocal;
717 }
718
719 UserEnterExclusive();
720
721 /* Call the internal function */
722 bResult = UserClipCursor(prcl);
723
724 UserLeave();
725
726 return bResult;
727 }
728
729
730 /*
731 * @implemented
732 */
733 BOOL
734 APIENTRY
735 NtUserDestroyCursor(
736 HANDLE hCurIcon,
737 DWORD Unknown)
738 {
739 PCURICON_OBJECT CurIcon;
740 BOOL ret;
741 DECLARE_RETURN(BOOL);
742
743 DPRINT("Enter NtUserDestroyCursorIcon\n");
744 UserEnterExclusive();
745
746 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
747 {
748 RETURN(FALSE);
749 }
750
751 ret = IntDestroyCurIconObject(CurIcon, FALSE);
752 /* Note: IntDestroyCurIconObject will remove our reference for us! */
753
754 RETURN(ret);
755
756 CLEANUP:
757 DPRINT("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
758 UserLeave();
759 END_CLEANUP;
760 }
761
762
763 /*
764 * @implemented
765 */
766 HICON
767 APIENTRY
768 NtUserFindExistingCursorIcon(
769 HMODULE hModule,
770 HRSRC hRsrc,
771 LONG cx,
772 LONG cy)
773 {
774 PCURICON_OBJECT CurIcon;
775 HANDLE Ret = (HANDLE)0;
776 DECLARE_RETURN(HICON);
777
778 DPRINT("Enter NtUserFindExistingCursorIcon\n");
779 UserEnterExclusive();
780
781 CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy);
782 if (CurIcon)
783 {
784 Ret = CurIcon->Self;
785
786 // IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
787 RETURN(Ret);
788 }
789
790 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
791 RETURN((HANDLE)0);
792
793 CLEANUP:
794 DPRINT("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_);
795 UserLeave();
796 END_CLEANUP;
797 }
798
799
800 /*
801 * @implemented
802 */
803 BOOL
804 APIENTRY
805 NtUserGetClipCursor(
806 RECTL *lpRect)
807 {
808 /* FIXME - check if process has WINSTA_READATTRIBUTES */
809 PSYSTEM_CURSORINFO CurInfo;
810 RECTL Rect;
811 NTSTATUS Status;
812 DECLARE_RETURN(BOOL);
813
814 DPRINT("Enter NtUserGetClipCursor\n");
815 UserEnterExclusive();
816
817 if (!lpRect)
818 RETURN(FALSE);
819
820 CurInfo = IntGetSysCursorInfo();
821 if (CurInfo->bClipped)
822 {
823 Rect = CurInfo->rcClip;
824 }
825 else
826 {
827 Rect.left = 0;
828 Rect.top = 0;
829 Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
830 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
831 }
832
833 Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT));
834 if (!NT_SUCCESS(Status))
835 {
836 SetLastNtError(Status);
837 RETURN(FALSE);
838 }
839
840 RETURN(TRUE);
841
842 CLEANUP:
843 DPRINT("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
844 UserLeave();
845 END_CLEANUP;
846 }
847
848
849 /*
850 * @implemented
851 */
852 HCURSOR
853 APIENTRY
854 NtUserSetCursor(
855 HCURSOR hCursor)
856 {
857 PCURICON_OBJECT pcurOld, pcurNew;
858 HCURSOR hOldCursor = NULL;
859
860 DPRINT("Enter NtUserSetCursor\n");
861 UserEnterExclusive();
862
863 if (hCursor)
864 {
865 pcurNew = UserGetCurIconObject(hCursor);
866 if (!pcurNew)
867 {
868 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
869 goto leave;
870 }
871 }
872 else
873 {
874 pcurNew = NULL;
875 }
876
877 pcurOld = UserSetCursor(pcurNew, FALSE);
878 if (pcurOld)
879 {
880 hOldCursor = (HCURSOR)pcurOld->Self;
881 UserDereferenceObject(pcurOld);
882 }
883
884 leave:
885 UserLeave();
886 return hOldCursor;
887 }
888
889
890 /*
891 * @implemented
892 */
893 BOOL
894 APIENTRY
895 NtUserSetCursorContents(
896 HANDLE hCurIcon,
897 PICONINFO UnsafeIconInfo)
898 {
899 PCURICON_OBJECT CurIcon;
900 ICONINFO IconInfo;
901 PSURFACE psurfBmp;
902 NTSTATUS Status;
903 BOOL Ret = FALSE;
904 DECLARE_RETURN(BOOL);
905
906 DPRINT("Enter NtUserSetCursorContents\n");
907 UserEnterExclusive();
908
909 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
910 {
911 RETURN(FALSE);
912 }
913
914 /* Copy fields */
915 Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
916 if (!NT_SUCCESS(Status))
917 {
918 SetLastNtError(Status);
919 goto done;
920 }
921
922 /* Delete old bitmaps */
923 if ((CurIcon->IconInfo.hbmColor)
924 && (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor))
925 {
926 GreDeleteObject(CurIcon->IconInfo.hbmColor);
927 }
928 if ((CurIcon->IconInfo.hbmMask)
929 && CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
930 {
931 GreDeleteObject(CurIcon->IconInfo.hbmMask);
932 }
933
934 /* Copy new IconInfo field */
935 CurIcon->IconInfo = IconInfo;
936
937 if (CurIcon->IconInfo.hbmColor)
938 {
939 psurfBmp = SURFACE_ShareLockSurface(CurIcon->IconInfo.hbmColor);
940 if (!psurfBmp)
941 goto done;
942
943 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
944 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
945 SURFACE_ShareUnlockSurface(psurfBmp);
946 GreSetObjectOwner(CurIcon->IconInfo.hbmColor, GDI_OBJ_HMGR_PUBLIC);
947 }
948 else
949 {
950 psurfBmp = SURFACE_ShareLockSurface(CurIcon->IconInfo.hbmMask);
951 if (!psurfBmp)
952 goto done;
953
954 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
955 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
956
957 SURFACE_ShareUnlockSurface(psurfBmp);
958 }
959 GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
960
961 Ret = TRUE;
962
963 done:
964
965 if (CurIcon)
966 {
967 UserDereferenceObject(CurIcon);
968 }
969 RETURN(Ret);
970
971 CLEANUP:
972 DPRINT("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
973 UserLeave();
974 END_CLEANUP;
975 }
976
977
978 /*
979 * @implemented
980 */
981 #if 0
982 BOOL
983 APIENTRY
984 NtUserSetCursorIconData(
985 HANDLE Handle,
986 HMODULE hModule,
987 PUNICODE_STRING pstrResName,
988 PICONINFO pIconInfo)
989 {
990 PCURICON_OBJECT CurIcon;
991 PSURFACE psurfBmp;
992 NTSTATUS Status = STATUS_SUCCESS;
993 BOOL Ret = FALSE;
994 DECLARE_RETURN(BOOL);
995
996 DPRINT("Enter NtUserSetCursorIconData\n");
997 UserEnterExclusive();
998
999 if (!(CurIcon = UserGetCurIconObject(Handle)))
1000 {
1001 RETURN(FALSE);
1002 }
1003
1004 CurIcon->hModule = hModule;
1005 CurIcon->hRsrc = NULL; //hRsrc;
1006 CurIcon->hGroupRsrc = NULL; //hGroupRsrc;
1007
1008 _SEH2_TRY
1009 {
1010 ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
1011 RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO));
1012
1013 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(pIconInfo->hbmMask);
1014 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(pIconInfo->hbmColor);
1015
1016 if (CurIcon->IconInfo.hbmColor)
1017 {
1018 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
1019 {
1020 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1021 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1022 SURFACE_UnlockSurface(psurfBmp);
1023 GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
1024 }
1025 }
1026 if (CurIcon->IconInfo.hbmMask)
1027 {
1028 if (CurIcon->IconInfo.hbmColor == NULL)
1029 {
1030 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
1031 {
1032 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1033 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1034 SURFACE_UnlockSurface(psurfBmp);
1035 }
1036 }
1037 GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
1038 }
1039 }
1040 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1041 {
1042 Status = _SEH2_GetExceptionCode();
1043 }
1044 _SEH2_END
1045
1046 if (!NT_SUCCESS(Status))
1047 SetLastNtError(Status);
1048 else
1049 Ret = TRUE;
1050
1051 UserDereferenceObject(CurIcon);
1052 RETURN(Ret);
1053
1054 CLEANUP:
1055 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1056 UserLeave();
1057 END_CLEANUP;
1058 }
1059 #else
1060 BOOL
1061 APIENTRY
1062 NtUserSetCursorIconData(
1063 HANDLE hCurIcon,
1064 PBOOL fIcon,
1065 POINT *Hotspot,
1066 HMODULE hModule,
1067 HRSRC hRsrc,
1068 HRSRC hGroupRsrc)
1069 {
1070 PCURICON_OBJECT CurIcon;
1071 NTSTATUS Status;
1072 POINT SafeHotspot;
1073 BOOL Ret = FALSE;
1074 DECLARE_RETURN(BOOL);
1075
1076 DPRINT("Enter NtUserSetCursorIconData\n");
1077 UserEnterExclusive();
1078
1079 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1080 {
1081 RETURN(FALSE);
1082 }
1083
1084 CurIcon->hModule = hModule;
1085 CurIcon->hRsrc = hRsrc;
1086 CurIcon->hGroupRsrc = hGroupRsrc;
1087
1088 /* Copy fields */
1089 if (fIcon)
1090 {
1091 Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
1092 if (!NT_SUCCESS(Status))
1093 {
1094 SetLastNtError(Status);
1095 goto done;
1096 }
1097 }
1098 else
1099 {
1100 if (!Hotspot)
1101 Ret = TRUE;
1102 }
1103
1104 if (Hotspot)
1105 {
1106 Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
1107 if (NT_SUCCESS(Status))
1108 {
1109 CurIcon->IconInfo.xHotspot = SafeHotspot.x;
1110 CurIcon->IconInfo.yHotspot = SafeHotspot.y;
1111
1112 Ret = TRUE;
1113 }
1114 else
1115 SetLastNtError(Status);
1116 }
1117
1118 if (!fIcon && !Hotspot)
1119 {
1120 Ret = TRUE;
1121 }
1122
1123 done:
1124 if(Ret)
1125 {
1126 /* This icon is shared now */
1127 GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
1128 if(CurIcon->IconInfo.hbmColor)
1129 {
1130 GreSetObjectOwner(CurIcon->IconInfo.hbmColor, GDI_OBJ_HMGR_PUBLIC);
1131 }
1132 }
1133 UserDereferenceObject(CurIcon);
1134 RETURN(Ret);
1135
1136
1137 CLEANUP:
1138 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1139 UserLeave();
1140 END_CLEANUP;
1141 }
1142 #endif
1143
1144 /* Mostly inspired from wine code */
1145 BOOL
1146 UserDrawIconEx(
1147 HDC hDc,
1148 INT xLeft,
1149 INT yTop,
1150 PCURICON_OBJECT pIcon,
1151 INT cxWidth,
1152 INT cyHeight,
1153 UINT istepIfAniCur,
1154 HBRUSH hbrFlickerFreeDraw,
1155 UINT diFlags)
1156 {
1157 BOOL Ret = FALSE;
1158 HBITMAP hbmMask, hbmColor;
1159 BITMAP bmpColor, bm;
1160 BOOL DoFlickerFree;
1161 INT iOldBkColor = 0, iOldTxtColor = 0;
1162
1163 HDC hMemDC, hDestDC = hDc;
1164 HGDIOBJ hOldOffBrush = 0;
1165 HGDIOBJ hOldOffBmp = 0;
1166 HBITMAP hTmpBmp = 0, hOffBmp = 0;
1167 BOOL bAlpha = FALSE;
1168 INT x=xLeft, y=yTop;
1169
1170 hbmMask = pIcon->IconInfo.hbmMask;
1171 hbmColor = pIcon->IconInfo.hbmColor;
1172
1173 if (istepIfAniCur)
1174 DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1175
1176 if (!hbmMask || !GreGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bm))
1177 {
1178 return FALSE;
1179 }
1180
1181 if (hbmColor && !GreGetObject(hbmColor, sizeof(BITMAP), (PVOID)&bmpColor))
1182 {
1183 return FALSE;
1184 }
1185
1186 if(!(hMemDC = NtGdiCreateCompatibleDC(hDc)))
1187 {
1188 DPRINT1("NtGdiCreateCompatibleDC failed!\n");
1189 return FALSE;
1190 }
1191
1192 /* Check for alpha */
1193 if (hbmColor
1194 && (bmpColor.bmBitsPixel == 32)
1195 && (diFlags & DI_IMAGE))
1196 {
1197 SURFACE *psurfOff = NULL;
1198 PFN_DIB_GetPixel fnSource_GetPixel = NULL;
1199 INT i, j;
1200
1201 /* In order to correctly display 32 bit icons Windows first scans the image,
1202 because information about transparency is not stored in any image's headers */
1203 psurfOff = SURFACE_ShareLockSurface(hbmColor);
1204 if (psurfOff)
1205 {
1206 fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
1207 if (fnSource_GetPixel)
1208 {
1209 for (i = 0; i < psurfOff->SurfObj.sizlBitmap.cx; i++)
1210 {
1211 for (j = 0; j < psurfOff->SurfObj.sizlBitmap.cy; j++)
1212 {
1213 bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, i, j) >> 24) & 0xff);
1214 if (bAlpha)
1215 break;
1216 }
1217 if (bAlpha)
1218 break;
1219 }
1220 }
1221 SURFACE_ShareUnlockSurface(psurfOff);
1222 }
1223 }
1224
1225 if (!cxWidth)
1226 cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
1227 UserGetSystemMetrics(SM_CXICON) : pIcon->Size.cx);
1228
1229 if (!cyHeight)
1230 cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
1231 UserGetSystemMetrics(SM_CYICON) : pIcon->Size.cy);
1232
1233 DoFlickerFree = (hbrFlickerFreeDraw &&
1234 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
1235
1236 if (DoFlickerFree)
1237 {
1238 hDestDC = NtGdiCreateCompatibleDC(hDc);
1239 if(!hDestDC)
1240 {
1241 DPRINT1("NtGdiCreateCompatibleDC failed!\n");
1242 Ret = FALSE;
1243 goto Cleanup ;
1244 }
1245 hOffBmp = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
1246 if(!hOffBmp)
1247 {
1248 DPRINT1("NtGdiCreateCompatibleBitmap failed!\n");
1249 goto Cleanup ;
1250 }
1251 hOldOffBmp = NtGdiSelectBitmap(hDestDC, hOffBmp);
1252 hOldOffBrush = NtGdiSelectBrush(hDestDC, hbrFlickerFreeDraw);
1253 NtGdiPatBlt(hDestDC, 0, 0, cxWidth, cyHeight, PATCOPY);
1254 NtGdiSelectBrush(hDestDC, hOldOffBrush);
1255 x=y=0;
1256 }
1257
1258 /* Set Background/foreground colors */
1259 iOldTxtColor = IntGdiSetTextColor(hDc, 0); //black
1260 iOldBkColor = IntGdiSetBkColor(hDc, 0x00FFFFFF); //white
1261
1262 if(bAlpha && (diFlags & DI_IMAGE))
1263 {
1264 BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
1265 BYTE Alpha;
1266 INT i, j;
1267 PSURFACE psurf;
1268 PBYTE ptr ;
1269 HBITMAP hMemBmp = NULL;
1270
1271 hMemBmp = BITMAP_CopyBitmap(hbmColor);
1272 if(!hMemBmp)
1273 {
1274 DPRINT1("BITMAP_CopyBitmap failed!");
1275 goto CleanupAlpha;
1276 }
1277
1278 psurf = SURFACE_ShareLockSurface(hMemBmp);
1279 if(!psurf)
1280 {
1281 DPRINT1("SURFACE_LockSurface failed!\n");
1282 goto CleanupAlpha;
1283 }
1284
1285 /* premultiply with the alpha channel value */
1286 for (i = 0; i < psurf->SurfObj.sizlBitmap.cy; i++)
1287 {
1288 ptr = (PBYTE)psurf->SurfObj.pvScan0 + i*psurf->SurfObj.lDelta;
1289 for (j = 0; j < psurf->SurfObj.sizlBitmap.cx; j++)
1290 {
1291 Alpha = ptr[3];
1292 ptr[0] = (ptr[0] * Alpha) / 0xff;
1293 ptr[1] = (ptr[1] * Alpha) / 0xff;
1294 ptr[2] = (ptr[2] * Alpha) / 0xff;
1295
1296 ptr += 4;
1297 }
1298 }
1299
1300 SURFACE_ShareUnlockSurface(psurf);
1301
1302 hTmpBmp = NtGdiSelectBitmap(hMemDC, hMemBmp);
1303
1304 Ret = NtGdiAlphaBlend(hDestDC,
1305 x,
1306 y,
1307 cxWidth,
1308 cyHeight,
1309 hMemDC,
1310 0,
1311 0,
1312 pIcon->Size.cx,
1313 pIcon->Size.cy,
1314 pixelblend,
1315 NULL);
1316 NtGdiSelectBitmap(hMemDC, hTmpBmp);
1317 CleanupAlpha:
1318 if(hMemBmp) NtGdiDeleteObjectApp(hMemBmp);
1319 if(Ret) goto done;
1320 }
1321
1322 if (diFlags & DI_MASK)
1323 {
1324 hTmpBmp = NtGdiSelectBitmap(hMemDC, hbmMask);
1325 NtGdiStretchBlt(hDestDC,
1326 x,
1327 y,
1328 cxWidth,
1329 cyHeight,
1330 hMemDC,
1331 0,
1332 0,
1333 pIcon->Size.cx,
1334 pIcon->Size.cy,
1335 SRCAND,
1336 0);
1337 NtGdiSelectBitmap(hMemDC, hTmpBmp);
1338 }
1339
1340 if(diFlags & DI_IMAGE)
1341 {
1342 if (hbmColor)
1343 {
1344 DWORD rop = (diFlags & DI_MASK) ? SRCINVERT : SRCCOPY ;
1345 hTmpBmp = NtGdiSelectBitmap(hMemDC, hbmColor);
1346 NtGdiStretchBlt(hDestDC,
1347 x,
1348 y,
1349 cxWidth,
1350 cyHeight,
1351 hMemDC,
1352 0,
1353 0,
1354 pIcon->Size.cx,
1355 pIcon->Size.cy,
1356 rop,
1357 0);
1358 NtGdiSelectBitmap(hMemDC, hTmpBmp);
1359 }
1360 else
1361 {
1362 /* Mask bitmap holds the information in its second half */
1363 DWORD rop = (diFlags & DI_MASK) ? SRCINVERT : SRCCOPY ;
1364 hTmpBmp = NtGdiSelectBitmap(hMemDC, hbmMask);
1365 NtGdiStretchBlt(hDestDC,
1366 x,
1367 y,
1368 cxWidth,
1369 cyHeight,
1370 hMemDC,
1371 0,
1372 pIcon->Size.cy,
1373 pIcon->Size.cx,
1374 pIcon->Size.cy,
1375 rop,
1376 0);
1377 NtGdiSelectBitmap(hMemDC, hTmpBmp);
1378 }
1379 }
1380
1381 done:
1382 if(hDestDC != hDc)
1383 {
1384 NtGdiBitBlt(hDc, xLeft, yTop, cxWidth, cyHeight, hDestDC, 0, 0, SRCCOPY, 0, 0);
1385 }
1386
1387 /* Restore foreground and background colors */
1388 IntGdiSetBkColor(hDc, iOldBkColor);
1389 IntGdiSetTextColor(hDc, iOldTxtColor);
1390
1391 Ret = TRUE ;
1392
1393 Cleanup:
1394 NtGdiDeleteObjectApp(hMemDC);
1395 if(hDestDC != hDc)
1396 {
1397 if(hOldOffBmp) NtGdiSelectBitmap(hDestDC, hOldOffBmp);
1398 NtGdiDeleteObjectApp(hDestDC);
1399 if(hOffBmp) NtGdiDeleteObjectApp(hOffBmp);
1400 }
1401
1402 return Ret;
1403 }
1404
1405 /*
1406 * @implemented
1407 */
1408 BOOL
1409 APIENTRY
1410 NtUserDrawIconEx(
1411 HDC hdc,
1412 int xLeft,
1413 int yTop,
1414 HICON hIcon,
1415 int cxWidth,
1416 int cyHeight,
1417 UINT istepIfAniCur,
1418 HBRUSH hbrFlickerFreeDraw,
1419 UINT diFlags,
1420 BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32!
1421 PVOID pDIXData)
1422 {
1423 PCURICON_OBJECT pIcon;
1424 BOOL Ret;
1425
1426 DPRINT("Enter NtUserDrawIconEx\n");
1427 UserEnterExclusive();
1428
1429 if (!(pIcon = UserGetCurIconObject(hIcon)))
1430 {
1431 DPRINT1("UserGetCurIconObject() failed!\n");
1432 UserLeave();
1433 return FALSE;
1434 }
1435
1436 Ret = UserDrawIconEx(hdc,
1437 xLeft,
1438 yTop,
1439 pIcon,
1440 cxWidth,
1441 cyHeight,
1442 istepIfAniCur,
1443 hbrFlickerFreeDraw,
1444 diFlags);
1445
1446 UserDereferenceObject(pIcon);
1447
1448 UserLeave();
1449 return Ret;
1450 }
1451