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