[win32k]
[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 <w32k.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 FASTCALL
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.CursorClipInfo.IsClipped = 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 FASTCALL
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 SetLastWin32Error(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 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
95 return NULL;
96 }
97
98 ASSERT(USER_BODY_TO_HEADER(CurIcon)->RefCount >= 1);
99 return CurIcon;
100 }
101
102 HCURSOR
103 FASTCALL
104 UserSetCursor(
105 PCURICON_OBJECT NewCursor,
106 BOOL ForceChange)
107 {
108 PSYSTEM_CURSORINFO CurInfo;
109 PCURICON_OBJECT OldCursor;
110 HCURSOR hOldCursor = (HCURSOR)0;
111 HDC hdcScreen;
112 BOOL bResult;
113
114 CurInfo = IntGetSysCursorInfo();
115
116 OldCursor = CurInfo->CurrentCursorObject;
117 if (OldCursor)
118 {
119 hOldCursor = (HCURSOR)OldCursor->Self;
120 }
121
122 /* Is the new cursor the same as the old cursor? */
123 if (OldCursor == NewCursor)
124 {
125 /* Nothing to to do in this case */
126 return hOldCursor;
127 }
128
129 /* Get the screen DC */
130 if(!(hdcScreen = IntGetScreenDC()))
131 {
132 return (HCURSOR)0;
133 }
134
135 /* Do we have a new cursor? */
136 if (NewCursor)
137 {
138 UserReferenceObject(NewCursor);
139
140 CurInfo->ShowingCursor = CURSOR_SHOWING;
141 CurInfo->CurrentCursorObject = NewCursor;
142
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,
149 gpsi->ptCursor.x,
150 gpsi->ptCursor.y);
151
152
153 }
154 else
155 {
156 /* Check if were diplaying a cursor */
157 if (OldCursor && CurInfo->ShowingCursor)
158 {
159 /* Remove the cursor */
160 GreMovePointer(hdcScreen, -1, -1);
161 DPRINT("Removing pointer!\n");
162 }
163
164 CurInfo->CurrentCursorObject = NULL;
165 CurInfo->ShowingCursor = 0;
166 }
167
168 /* OldCursor is not in use anymore */
169 if (OldCursor)
170 {
171 UserDereferenceObject(OldCursor);
172 }
173
174 /* Return handle of the old cursor */
175 return hOldCursor;
176 }
177
178 /*
179 * We have to register that this object is in use by the current
180 * process. The only way to do that seems to be to walk the list
181 * of cursor/icon objects starting at W32Process->CursorIconListHead.
182 * If the object is already present in the list, we don't have to do
183 * anything, if it's not present we add it and inc the ProcessCount
184 * in the object. Having to walk the list kind of sucks, but that's
185 * life...
186 */
187 static BOOLEAN FASTCALL
188 ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
189 {
190 PPROCESSINFO Win32Process;
191 PCURICON_PROCESS Current;
192
193 Win32Process = PsGetCurrentProcessWin32Process();
194
195 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
196 {
197 if (Current->Process == Win32Process)
198 {
199 /* Already registered for this process */
200 return TRUE;
201 }
202 }
203
204 /* Not registered yet */
205 Current = ExAllocateFromPagedLookasideList(&gProcessLookasideList);
206 if (NULL == Current)
207 {
208 return FALSE;
209 }
210 InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
211 Current->Process = Win32Process;
212
213 return TRUE;
214 }
215
216 PCURICON_OBJECT FASTCALL
217 IntFindExistingCurIconObject(HMODULE hModule,
218 HRSRC hRsrc, LONG cx, LONG cy)
219 {
220 PCURICON_OBJECT CurIcon;
221
222 LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
223 {
224
225 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
226 // UserReferenceObject( CurIcon);
227 // {
228 if ((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
229 {
230 if (cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
231 {
232 // UserDereferenceObject(CurIcon);
233 continue;
234 }
235 if (! ReferenceCurIconByProcess(CurIcon))
236 {
237 return NULL;
238 }
239
240 return CurIcon;
241 }
242 // }
243 // UserDereferenceObject(CurIcon);
244
245 }
246
247 return NULL;
248 }
249
250 PCURICON_OBJECT FASTCALL
251 IntCreateCurIconHandle()
252 {
253 PCURICON_OBJECT CurIcon;
254 HANDLE hCurIcon;
255
256 CurIcon = UserCreateObject(gHandleTable, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));
257
258 if (!CurIcon)
259 {
260 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
261 return FALSE;
262 }
263
264 CurIcon->Self = hCurIcon;
265 InitializeListHead(&CurIcon->ProcessList);
266
267 if (! ReferenceCurIconByProcess(CurIcon))
268 {
269 DPRINT1("Failed to add process\n");
270 UserDeleteObject(hCurIcon, otCursorIcon);
271 UserDereferenceObject(CurIcon);
272 return NULL;
273 }
274
275 InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
276
277 return CurIcon;
278 }
279
280 BOOLEAN FASTCALL
281 IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, BOOL ProcessCleanup)
282 {
283 PSYSTEM_CURSORINFO CurInfo;
284 HBITMAP bmpMask, bmpColor;
285 BOOLEAN Ret;
286 PCURICON_PROCESS Current = NULL;
287 PPROCESSINFO W32Process = PsGetCurrentProcessWin32Process();
288
289 /* Private objects can only be destroyed by their own process */
290 if (NULL == CurIcon->hModule)
291 {
292 ASSERT(CurIcon->ProcessList.Flink->Flink == &CurIcon->ProcessList);
293 Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
294 if (Current->Process != W32Process)
295 {
296 DPRINT1("Trying to destroy private icon/cursor of another process\n");
297 return FALSE;
298 }
299 }
300 else if (! ProcessCleanup)
301 {
302 DPRINT("Trying to destroy shared icon/cursor\n");
303 return FALSE;
304 }
305
306 /* Now find this process in the list of processes referencing this object and
307 remove it from that list */
308 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
309 {
310 if (Current->Process == W32Process)
311 {
312 RemoveEntryList(&Current->ListEntry);
313 break;
314 }
315 }
316
317 ExFreeToPagedLookasideList(&gProcessLookasideList, Current);
318
319 /* If there are still processes referencing this object we can't destroy it yet */
320 if (! IsListEmpty(&CurIcon->ProcessList))
321 {
322 return TRUE;
323 }
324
325
326 if (! ProcessCleanup)
327 {
328 RemoveEntryList(&CurIcon->ListEntry);
329 }
330
331 CurInfo = IntGetSysCursorInfo();
332
333 if (CurInfo->CurrentCursorObject == CurIcon)
334 {
335 /* Hide the cursor if we're destroying the current cursor */
336 UserSetCursor(NULL, TRUE);
337 }
338
339 bmpMask = CurIcon->IconInfo.hbmMask;
340 bmpColor = CurIcon->IconInfo.hbmColor;
341
342 /* delete bitmaps */
343 if (bmpMask)
344 {
345 GDIOBJ_SetOwnership(bmpMask, PsGetCurrentProcess());
346 GreDeleteObject(bmpMask);
347 CurIcon->IconInfo.hbmMask = NULL;
348 }
349 if (bmpColor)
350 {
351 GDIOBJ_SetOwnership(bmpColor, PsGetCurrentProcess());
352 GreDeleteObject(bmpColor);
353 CurIcon->IconInfo.hbmColor = NULL;
354 }
355
356 /* We were given a pointer, no need to keep the reference anylonger! */
357 UserDereferenceObject(CurIcon);
358 Ret = UserDeleteObject(CurIcon->Self, otCursorIcon);
359
360 return Ret;
361 }
362
363 VOID FASTCALL
364 IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
365 {
366 PCURICON_OBJECT CurIcon, tmp;
367 PCURICON_PROCESS ProcessData;
368
369 LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
370 {
371 UserReferenceObject(CurIcon);
372 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon)))
373 {
374 LIST_FOR_EACH(ProcessData, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
375 {
376 if (Win32Process == ProcessData->Process)
377 {
378 RemoveEntryList(&CurIcon->ListEntry);
379 IntDestroyCurIconObject(CurIcon, TRUE);
380 CurIcon = NULL;
381 break;
382 }
383 }
384
385 // UserDereferenceObject(Object);
386 }
387
388 if (CurIcon)
389 {
390 UserDereferenceObject(CurIcon);
391 }
392 }
393
394 }
395
396 /*
397 * @implemented
398 */
399 HANDLE
400 APIENTRY
401 NtUserCreateCursorIconHandle(PICONINFO IconInfo OPTIONAL, BOOL Indirect)
402 {
403 PCURICON_OBJECT CurIcon;
404 PSURFACE psurfBmp;
405 NTSTATUS Status;
406 HANDLE Ret;
407 DECLARE_RETURN(HANDLE);
408
409 DPRINT("Enter NtUserCreateCursorIconHandle\n");
410 UserEnterExclusive();
411
412 if (!(CurIcon = IntCreateCurIconHandle()))
413 {
414 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
415 RETURN((HANDLE)0);
416 }
417
418 Ret = CurIcon->Self;
419
420 if (IconInfo)
421 {
422 Status = MmCopyFromCaller(&CurIcon->IconInfo, IconInfo, sizeof(ICONINFO));
423 if (NT_SUCCESS(Status))
424 {
425 /* Copy bitmaps and size info */
426 if (Indirect)
427 {
428 // FIXME: WTF?
429 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
430 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
431 }
432 if (CurIcon->IconInfo.hbmColor &&
433 (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
434 {
435 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
436 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
437 SURFACE_UnlockSurface(psurfBmp);
438 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
439 }
440 if (CurIcon->IconInfo.hbmMask &&
441 (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
442 {
443 if (CurIcon->IconInfo.hbmColor == NULL)
444 {
445 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
446 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy >> 1;
447 }
448 SURFACE_UnlockSurface(psurfBmp);
449 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
450 }
451
452 /* Calculate icon hotspot */
453 if (CurIcon->IconInfo.fIcon == TRUE)
454 {
455 CurIcon->IconInfo.xHotspot = CurIcon->Size.cx >> 1;
456 CurIcon->IconInfo.yHotspot = CurIcon->Size.cy >> 1;
457 }
458 }
459 else
460 {
461 SetLastNtError(Status);
462 /* FIXME - Don't exit here */
463 }
464 }
465
466 UserDereferenceObject(CurIcon);
467 RETURN(Ret);
468
469 CLEANUP:
470 DPRINT("Leave NtUserCreateCursorIconHandle, ret=%i\n",_ret_);
471 UserLeave();
472 END_CLEANUP;
473 }
474
475 /*
476 * @implemented
477 */
478 BOOL
479 APIENTRY
480 NtUserGetIconInfo(
481 HANDLE hCurIcon,
482 PICONINFO IconInfo,
483 PUNICODE_STRING lpInstName, // optional
484 PUNICODE_STRING lpResName, // optional
485 LPDWORD pbpp, // optional
486 BOOL bInternal)
487 {
488 ICONINFO ii;
489 PCURICON_OBJECT CurIcon;
490 NTSTATUS Status = STATUS_SUCCESS;
491 BOOL Ret = FALSE;
492 DWORD colorBpp = 0;
493
494 DPRINT("Enter NtUserGetIconInfo\n");
495 UserEnterExclusive();
496
497 if (!IconInfo)
498 {
499 SetLastWin32Error(ERROR_INVALID_PARAMETER);
500 goto leave;
501 }
502
503 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
504 {
505 goto leave;
506 }
507
508 RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO));
509
510 /* Copy bitmaps */
511 ii.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
512 ii.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
513
514 if (pbpp)
515 {
516 PSURFACE psurfBmp;
517
518 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
519 if (psurfBmp)
520 {
521 colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
522 SURFACE_UnlockSurface(psurfBmp);
523 }
524 }
525
526 /* Copy fields */
527 _SEH2_TRY
528 {
529 ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
530 RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
531
532 if (pbpp)
533 {
534 ProbeForWrite(pbpp, sizeof(DWORD), 1);
535 *pbpp = colorBpp;
536 }
537 }
538 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
539 {
540 Status = _SEH2_GetExceptionCode();
541 }
542 _SEH2_END
543
544 if (NT_SUCCESS(Status))
545 Ret = TRUE;
546 else
547 SetLastNtError(Status);
548
549 UserDereferenceObject(CurIcon);
550
551 leave:
552 DPRINT("Leave NtUserGetIconInfo, ret=%i\n", Ret);
553 UserLeave();
554
555 return Ret;
556 }
557
558
559 /*
560 * @implemented
561 */
562 BOOL
563 APIENTRY
564 NtUserGetIconSize(
565 HANDLE hCurIcon,
566 UINT istepIfAniCur,
567 PLONG plcx, // &size.cx
568 PLONG plcy) // &size.cy
569 {
570 PCURICON_OBJECT CurIcon;
571 NTSTATUS Status = STATUS_SUCCESS;
572 BOOL bRet = FALSE;
573
574 DPRINT("Enter NtUserGetIconSize\n");
575 UserEnterExclusive();
576
577 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
578 {
579 goto cleanup;
580 }
581
582 _SEH2_TRY
583 {
584 ProbeForWrite(plcx, sizeof(LONG), 1);
585 RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
586 ProbeForWrite(plcy, sizeof(LONG), 1);
587 RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
588 }
589 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
590 {
591 Status = _SEH2_GetExceptionCode();
592 }
593 _SEH2_END
594
595 if (NT_SUCCESS(Status))
596 bRet = TRUE;
597 else
598 SetLastNtError(Status); // maybe not, test this
599
600 UserDereferenceObject(CurIcon);
601
602 cleanup:
603 DPRINT("Leave NtUserGetIconSize, ret=%i\n", bRet);
604 UserLeave();
605 return bRet;
606 }
607
608
609 /*
610 * @unimplemented
611 */
612 DWORD
613 APIENTRY
614 NtUserGetCursorFrameInfo(
615 DWORD Unknown0,
616 DWORD Unknown1,
617 DWORD Unknown2,
618 DWORD Unknown3)
619 {
620 UNIMPLEMENTED
621
622 return 0;
623 }
624
625
626 /*
627 * @implemented
628 */
629 BOOL
630 APIENTRY
631 NtUserGetCursorInfo(
632 PCURSORINFO pci)
633 {
634 CURSORINFO SafeCi;
635 PSYSTEM_CURSORINFO CurInfo;
636 NTSTATUS Status = STATUS_SUCCESS;
637 PCURICON_OBJECT CurIcon;
638 BOOL Ret = FALSE;
639 DECLARE_RETURN(BOOL);
640
641 DPRINT("Enter NtUserGetCursorInfo\n");
642 UserEnterExclusive();
643
644 CurInfo = IntGetSysCursorInfo();
645 CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
646
647 SafeCi.cbSize = sizeof(CURSORINFO);
648 SafeCi.flags = ((CurInfo->ShowingCursor && CurIcon) ? CURSOR_SHOWING : 0);
649 SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
650
651 SafeCi.ptScreenPos = gpsi->ptCursor;
652
653 _SEH2_TRY
654 {
655 if (pci->cbSize == sizeof(CURSORINFO))
656 {
657 ProbeForWrite(pci, sizeof(CURSORINFO), 1);
658 RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
659 Ret = TRUE;
660 }
661 else
662 {
663 SetLastWin32Error(ERROR_INVALID_PARAMETER);
664 }
665 }
666 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
667 {
668 Status = _SEH2_GetExceptionCode();
669 }
670 _SEH2_END;
671 if (!NT_SUCCESS(Status))
672 {
673 SetLastNtError(Status);
674 }
675
676 RETURN(Ret);
677
678 CLEANUP:
679 DPRINT("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
680 UserLeave();
681 END_CLEANUP;
682 }
683
684
685 /*
686 * @implemented
687 */
688 BOOL
689 APIENTRY
690 NtUserClipCursor(
691 RECTL *UnsafeRect)
692 {
693 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
694 PSYSTEM_CURSORINFO CurInfo;
695 RECTL Rect;
696 PWINDOW_OBJECT DesktopWindow = NULL;
697 DECLARE_RETURN(BOOL);
698
699 DPRINT("Enter NtUserClipCursor\n");
700 UserEnterExclusive();
701
702 if (NULL != UnsafeRect && ! NT_SUCCESS(MmCopyFromCaller(&Rect, UnsafeRect, sizeof(RECT))))
703 {
704 SetLastWin32Error(ERROR_INVALID_PARAMETER);
705 RETURN(FALSE);
706 }
707
708 CurInfo = IntGetSysCursorInfo();
709
710 DesktopWindow = UserGetDesktopWindow();
711
712 if ((Rect.right > Rect.left) && (Rect.bottom > Rect.top)
713 && DesktopWindow && UnsafeRect != NULL)
714 {
715 MOUSEINPUT mi;
716
717 CurInfo->CursorClipInfo.IsClipped = TRUE;
718 CurInfo->CursorClipInfo.Left = max(Rect.left, DesktopWindow->Wnd->rcWindow.left);
719 CurInfo->CursorClipInfo.Top = max(Rect.top, DesktopWindow->Wnd->rcWindow.top);
720 CurInfo->CursorClipInfo.Right = min(Rect.right - 1, DesktopWindow->Wnd->rcWindow.right - 1);
721 CurInfo->CursorClipInfo.Bottom = min(Rect.bottom - 1, DesktopWindow->Wnd->rcWindow.bottom - 1);
722
723 mi.dx = gpsi->ptCursor.x;
724 mi.dy = gpsi->ptCursor.y;
725 mi.mouseData = 0;
726 mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
727 mi.time = 0;
728 mi.dwExtraInfo = 0;
729 IntMouseInput(&mi);
730
731 RETURN(TRUE);
732 }
733
734 CurInfo->CursorClipInfo.IsClipped = FALSE;
735 RETURN(TRUE);
736
737 CLEANUP:
738 DPRINT("Leave NtUserClipCursor, ret=%i\n",_ret_);
739 UserLeave();
740 END_CLEANUP;
741 }
742
743
744 /*
745 * @implemented
746 */
747 BOOL
748 APIENTRY
749 NtUserDestroyCursor(
750 HANDLE hCurIcon,
751 DWORD Unknown)
752 {
753 PCURICON_OBJECT CurIcon;
754 BOOL ret;
755 DECLARE_RETURN(BOOL);
756
757 DPRINT("Enter NtUserDestroyCursorIcon\n");
758 UserEnterExclusive();
759
760 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
761 {
762 RETURN(FALSE);
763 }
764
765 ret = IntDestroyCurIconObject(CurIcon, FALSE);
766 /* Note: IntDestroyCurIconObject will remove our reference for us! */
767
768 RETURN(ret);
769
770 CLEANUP:
771 DPRINT("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
772 UserLeave();
773 END_CLEANUP;
774 }
775
776
777 /*
778 * @implemented
779 */
780 HICON
781 APIENTRY
782 NtUserFindExistingCursorIcon(
783 HMODULE hModule,
784 HRSRC hRsrc,
785 LONG cx,
786 LONG cy)
787 {
788 PCURICON_OBJECT CurIcon;
789 HANDLE Ret = (HANDLE)0;
790 DECLARE_RETURN(HICON);
791
792 DPRINT("Enter NtUserFindExistingCursorIcon\n");
793 UserEnterExclusive();
794
795 CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy);
796 if (CurIcon)
797 {
798 Ret = CurIcon->Self;
799
800 // IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
801 RETURN(Ret);
802 }
803
804 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
805 RETURN((HANDLE)0);
806
807 CLEANUP:
808 DPRINT("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_);
809 UserLeave();
810 END_CLEANUP;
811 }
812
813
814 /*
815 * @implemented
816 */
817 BOOL
818 APIENTRY
819 NtUserGetClipCursor(
820 RECTL *lpRect)
821 {
822 /* FIXME - check if process has WINSTA_READATTRIBUTES */
823 PSYSTEM_CURSORINFO CurInfo;
824 RECTL Rect;
825 NTSTATUS Status;
826 DECLARE_RETURN(BOOL);
827
828 DPRINT("Enter NtUserGetClipCursor\n");
829 UserEnterExclusive();
830
831 if (!lpRect)
832 RETURN(FALSE);
833
834 CurInfo = IntGetSysCursorInfo();
835 if (CurInfo->CursorClipInfo.IsClipped)
836 {
837 Rect.left = CurInfo->CursorClipInfo.Left;
838 Rect.top = CurInfo->CursorClipInfo.Top;
839 Rect.right = CurInfo->CursorClipInfo.Right;
840 Rect.bottom = CurInfo->CursorClipInfo.Bottom;
841 }
842 else
843 {
844 Rect.left = 0;
845 Rect.top = 0;
846 Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
847 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
848 }
849
850 Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT));
851 if (!NT_SUCCESS(Status))
852 {
853 SetLastNtError(Status);
854 RETURN(FALSE);
855 }
856
857 RETURN(TRUE);
858
859 CLEANUP:
860 DPRINT("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
861 UserLeave();
862 END_CLEANUP;
863 }
864
865
866 /*
867 * @implemented
868 */
869 HCURSOR
870 APIENTRY
871 NtUserSetCursor(
872 HCURSOR hCursor)
873 {
874 PCURICON_OBJECT CurIcon;
875 HICON OldCursor;
876 DECLARE_RETURN(HCURSOR);
877
878 DPRINT("Enter NtUserSetCursor\n");
879 UserEnterExclusive();
880
881 if (hCursor)
882 {
883 if (!(CurIcon = UserGetCurIconObject(hCursor)))
884 {
885 RETURN(NULL);
886 }
887 }
888 else
889 {
890 CurIcon = NULL;
891 }
892
893 OldCursor = UserSetCursor(CurIcon, FALSE);
894
895 if (CurIcon)
896 {
897 UserDereferenceObject(CurIcon);
898 }
899
900 RETURN(OldCursor);
901
902 CLEANUP:
903 DPRINT("Leave NtUserSetCursor, ret=%i\n",_ret_);
904 UserLeave();
905 END_CLEANUP;
906 }
907
908
909 /*
910 * @implemented
911 */
912 BOOL
913 APIENTRY
914 NtUserSetCursorContents(
915 HANDLE hCurIcon,
916 PICONINFO UnsafeIconInfo)
917 {
918 PCURICON_OBJECT CurIcon;
919 ICONINFO IconInfo;
920 PSURFACE psurfBmp;
921 NTSTATUS Status;
922 BOOL Ret = FALSE;
923 DECLARE_RETURN(BOOL);
924
925 DPRINT("Enter NtUserSetCursorContents\n");
926 UserEnterExclusive();
927
928 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
929 {
930 RETURN(FALSE);
931 }
932
933 /* Copy fields */
934 Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
935 if (!NT_SUCCESS(Status))
936 {
937 SetLastNtError(Status);
938 goto done;
939 }
940
941 /* Delete old bitmaps */
942 if (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor)
943 {
944 GreDeleteObject(CurIcon->IconInfo.hbmColor);
945 }
946 if (CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
947 {
948 GreDeleteObject(CurIcon->IconInfo.hbmMask);
949 }
950
951 /* Copy new IconInfo field */
952 CurIcon->IconInfo = IconInfo;
953
954 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
955 if (psurfBmp)
956 {
957 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
958 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
959 SURFACE_UnlockSurface(psurfBmp);
960 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
961 }
962 else
963 {
964 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask);
965 if (!psurfBmp)
966 goto done;
967
968 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
969 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
970
971 SURFACE_UnlockSurface(psurfBmp);
972 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
973 }
974
975 Ret = TRUE;
976
977 done:
978
979 if (CurIcon)
980 {
981 UserDereferenceObject(CurIcon);
982 }
983 RETURN(Ret);
984
985 CLEANUP:
986 DPRINT("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
987 UserLeave();
988 END_CLEANUP;
989 }
990
991
992 /*
993 * @implemented
994 */
995 #if 0
996 BOOL
997 APIENTRY
998 NtUserSetCursorIconData(
999 HANDLE Handle,
1000 HMODULE hModule,
1001 PUNICODE_STRING pstrResName,
1002 PICONINFO pIconInfo)
1003 {
1004 PCURICON_OBJECT CurIcon;
1005 PSURFACE psurfBmp;
1006 NTSTATUS Status = STATUS_SUCCESS;
1007 BOOL Ret = FALSE;
1008 DECLARE_RETURN(BOOL);
1009
1010 DPRINT("Enter NtUserSetCursorIconData\n");
1011 UserEnterExclusive();
1012
1013 if (!(CurIcon = UserGetCurIconObject(Handle)))
1014 {
1015 RETURN(FALSE);
1016 }
1017
1018 CurIcon->hModule = hModule;
1019 CurIcon->hRsrc = NULL; //hRsrc;
1020 CurIcon->hGroupRsrc = NULL; //hGroupRsrc;
1021
1022 _SEH2_TRY
1023 {
1024 ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
1025 RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO));
1026
1027 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(pIconInfo->hbmMask);
1028 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(pIconInfo->hbmColor);
1029
1030 if (CurIcon->IconInfo.hbmColor)
1031 {
1032 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
1033 {
1034 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1035 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1036 SURFACE_UnlockSurface(psurfBmp);
1037 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1038 }
1039 }
1040 if (CurIcon->IconInfo.hbmMask)
1041 {
1042 if (CurIcon->IconInfo.hbmColor == NULL)
1043 {
1044 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
1045 {
1046 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1047 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1048 SURFACE_UnlockSurface(psurfBmp);
1049 }
1050 }
1051 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1052 }
1053 }
1054 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1055 {
1056 Status = _SEH2_GetExceptionCode();
1057 }
1058 _SEH2_END
1059
1060 if (!NT_SUCCESS(Status))
1061 SetLastNtError(Status);
1062 else
1063 Ret = TRUE;
1064
1065 UserDereferenceObject(CurIcon);
1066 RETURN(Ret);
1067
1068 CLEANUP:
1069 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1070 UserLeave();
1071 END_CLEANUP;
1072 }
1073 #else
1074 BOOL
1075 APIENTRY
1076 NtUserSetCursorIconData(
1077 HANDLE hCurIcon,
1078 PBOOL fIcon,
1079 POINT *Hotspot,
1080 HMODULE hModule,
1081 HRSRC hRsrc,
1082 HRSRC hGroupRsrc)
1083 {
1084 PCURICON_OBJECT CurIcon;
1085 NTSTATUS Status;
1086 POINT SafeHotspot;
1087 BOOL Ret = FALSE;
1088 DECLARE_RETURN(BOOL);
1089
1090 DPRINT("Enter NtUserSetCursorIconData\n");
1091 UserEnterExclusive();
1092
1093 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1094 {
1095 RETURN(FALSE);
1096 }
1097
1098 CurIcon->hModule = hModule;
1099 CurIcon->hRsrc = hRsrc;
1100 CurIcon->hGroupRsrc = hGroupRsrc;
1101
1102 /* Copy fields */
1103 if (fIcon)
1104 {
1105 Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
1106 if (!NT_SUCCESS(Status))
1107 {
1108 SetLastNtError(Status);
1109 goto done;
1110 }
1111 }
1112 else
1113 {
1114 if (!Hotspot)
1115 Ret = TRUE;
1116 }
1117
1118 if (Hotspot)
1119 {
1120 Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
1121 if (NT_SUCCESS(Status))
1122 {
1123 CurIcon->IconInfo.xHotspot = SafeHotspot.x;
1124 CurIcon->IconInfo.yHotspot = SafeHotspot.y;
1125
1126 Ret = TRUE;
1127 }
1128 else
1129 SetLastNtError(Status);
1130 }
1131
1132 if (!fIcon && !Hotspot)
1133 {
1134 Ret = TRUE;
1135 }
1136
1137 done:
1138 UserDereferenceObject(CurIcon);
1139 RETURN(Ret);
1140
1141
1142 CLEANUP:
1143 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1144 UserLeave();
1145 END_CLEANUP;
1146 }
1147 #endif
1148
1149 /*
1150 * @unimplemented
1151 */
1152 BOOL
1153 APIENTRY
1154 NtUserSetSystemCursor(
1155 HCURSOR hcur,
1156 DWORD id)
1157 {
1158 return FALSE;
1159 }
1160
1161 BOOL
1162 UserDrawIconEx(
1163 HDC hDc,
1164 INT xLeft,
1165 INT yTop,
1166 PCURICON_OBJECT pIcon,
1167 INT cxWidth,
1168 INT cyHeight,
1169 UINT istepIfAniCur,
1170 HBRUSH hbrFlickerFreeDraw,
1171 UINT diFlags)
1172 {
1173 BOOL Ret = FALSE;
1174 HBITMAP hbmMask, hbmColor;
1175 BITMAP bmpMask, bmpColor;
1176 BOOL DoFlickerFree;
1177 SIZE IconSize;
1178
1179 HDC hdcOff;
1180 HGDIOBJ hOldOffBrush = 0;
1181 HGDIOBJ hOldOffBmp = 0;
1182 HBITMAP hbmOff = 0;
1183 HDC hdcMask = 0;
1184 HGDIOBJ hOldMask = NULL;
1185 HDC hdcImage = 0;
1186 HGDIOBJ hOldImage = NULL;
1187 BOOL bAlpha = FALSE;
1188
1189 hbmMask = pIcon->IconInfo.hbmMask;
1190 hbmColor = pIcon->IconInfo.hbmColor;
1191
1192 if (istepIfAniCur)
1193 DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1194
1195 if (!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bmpMask))
1196 {
1197 return FALSE;
1198 }
1199
1200 if (hbmColor && !IntGdiGetObject(hbmColor, sizeof(BITMAP), (PVOID)&bmpColor))
1201 {
1202 return FALSE;
1203 }
1204
1205 if (hbmColor)
1206 {
1207 IconSize.cx = bmpColor.bmWidth;
1208 IconSize.cy = bmpColor.bmHeight;
1209 }
1210 else
1211 {
1212 IconSize.cx = bmpMask.bmWidth;
1213 IconSize.cy = bmpMask.bmHeight / 2;
1214 }
1215
1216 /* NtGdiCreateCompatibleBitmap will create a monochrome bitmap
1217 when cxWidth or cyHeight is 0 */
1218 if ((bmpColor.bmBitsPixel == 32) && (cxWidth != 0) && (cyHeight != 0))
1219 {
1220 SURFACE *psurfOff = NULL;
1221 PFN_DIB_GetPixel fnSource_GetPixel = NULL;
1222 INT x, y;
1223
1224 /* In order to correctly display 32 bit icons Windows first scans the image,
1225 because information about transparency is not stored in any image's headers */
1226 psurfOff = SURFACE_LockSurface(hbmColor ? hbmColor : hbmMask);
1227 if (psurfOff)
1228 {
1229 fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
1230 if (fnSource_GetPixel)
1231 {
1232 for (x = 0; x < psurfOff->SurfObj.sizlBitmap.cx; x++)
1233 {
1234 for (y = 0; y < psurfOff->SurfObj.sizlBitmap.cy; y++)
1235 {
1236 bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, x, y) >> 24) & 0xff);
1237 if (bAlpha)
1238 break;
1239 }
1240 if (bAlpha)
1241 break;
1242 }
1243 }
1244 SURFACE_UnlockSurface(psurfOff);
1245 }
1246 }
1247
1248 if (!diFlags)
1249 diFlags = DI_NORMAL;
1250
1251 if (!cxWidth)
1252 cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
1253 UserGetSystemMetrics(SM_CXICON) : IconSize.cx);
1254
1255 if (!cyHeight)
1256 cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
1257 UserGetSystemMetrics(SM_CYICON) : IconSize.cy);
1258
1259 DoFlickerFree = (hbrFlickerFreeDraw &&
1260 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
1261
1262 if (DoFlickerFree || bAlpha)
1263 {
1264 RECTL r;
1265 BITMAP bm;
1266 SURFACE *psurfOff = NULL;
1267
1268 r.right = cxWidth;
1269 r.bottom = cyHeight;
1270
1271 hdcOff = NtGdiCreateCompatibleDC(hDc);
1272 if (!hdcOff)
1273 {
1274 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1275 return FALSE;
1276 }
1277
1278 hbmOff = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
1279 if (!hbmOff)
1280 {
1281 DPRINT1("NtGdiCreateCompatibleBitmap() failed!\n");
1282 goto cleanup;
1283 }
1284
1285 /* make sure we have a 32 bit offscreen bitmap
1286 otherwise we can't do alpha blending */
1287 psurfOff = SURFACE_LockSurface(hbmOff);
1288 if (psurfOff == NULL)
1289 {
1290 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1291 goto cleanup;
1292 }
1293 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1294
1295 if (bm.bmBitsPixel != 32)
1296 bAlpha = FALSE;
1297
1298 SURFACE_UnlockSurface(psurfOff);
1299
1300 hOldOffBmp = NtGdiSelectBitmap(hdcOff, hbmOff);
1301 if (!hOldOffBmp)
1302 {
1303 DPRINT1("NtGdiSelectBitmap() failed!\n");
1304 goto cleanup;
1305 }
1306
1307 if (DoFlickerFree)
1308 {
1309 hOldOffBrush = NtGdiSelectBrush(hdcOff, hbrFlickerFreeDraw);
1310 if (!hOldOffBrush)
1311 {
1312 DPRINT1("NtGdiSelectBrush() failed!\n");
1313 goto cleanup;
1314 }
1315
1316 NtGdiPatBlt(hdcOff, 0, 0, r.right, r.bottom, PATCOPY);
1317 }
1318 }
1319 else
1320 hdcOff = hDc;
1321
1322 if (diFlags & DI_IMAGE)
1323 {
1324 hdcImage = NtGdiCreateCompatibleDC(hDc);
1325 if (!hdcImage)
1326 {
1327 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1328 goto cleanup;
1329 }
1330 hOldImage = NtGdiSelectBitmap(hdcImage, (hbmColor ? hbmColor : hbmMask));
1331 if (!hOldImage)
1332 {
1333 DPRINT("NtGdiSelectBitmap() failed!\n");
1334 goto cleanup;
1335 }
1336 }
1337
1338 /* If DI_IMAGE flag is specified and hbmMask exists, then always use mask for drawing */
1339 if (diFlags & DI_MASK || (diFlags & DI_IMAGE && hbmMask))
1340 {
1341 hdcMask = NtGdiCreateCompatibleDC(hDc);
1342 if (!hdcMask)
1343 {
1344 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1345 goto cleanup;
1346 }
1347
1348 hOldMask = NtGdiSelectBitmap(hdcMask, hbmMask);
1349 if (!hOldMask)
1350 {
1351 DPRINT("NtGdiSelectBitmap() failed!\n");
1352 goto cleanup;
1353 }
1354 }
1355
1356 if (hdcMask || hdcImage)
1357 {
1358 GreStretchBltMask(hdcOff,
1359 (DoFlickerFree || bAlpha) ? 0 : xLeft,
1360 (DoFlickerFree || bAlpha) ? 0 : yTop,
1361 cxWidth,
1362 cyHeight,
1363 hdcImage ? hdcImage : hdcMask,
1364 0,
1365 0,
1366 IconSize.cx,
1367 IconSize.cy,
1368 SRCCOPY,
1369 0,
1370 hdcMask,
1371 0,
1372 hdcImage ? 0 : IconSize.cy);
1373 }
1374
1375 if (hOldMask) NtGdiSelectBitmap(hdcMask, hOldMask);
1376 if (hOldImage) NtGdiSelectBitmap(hdcImage, hOldImage);
1377 if (hdcImage) NtGdiDeleteObjectApp(hdcImage);
1378 if (hdcMask) NtGdiDeleteObjectApp(hdcMask);
1379
1380 if (bAlpha)
1381 {
1382 BITMAP bm;
1383 SURFACE *psurfOff = NULL;
1384 PBYTE pBits = NULL;
1385 BLENDFUNCTION BlendFunc;
1386 DWORD Pixel;
1387 BYTE Red, Green, Blue, Alpha;
1388 DWORD Count = 0;
1389 INT i, j;
1390
1391 psurfOff = SURFACE_LockSurface(hbmOff);
1392 if (psurfOff == NULL)
1393 {
1394 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1395 goto cleanup;
1396 }
1397 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1398
1399 pBits = ExAllocatePoolWithTag(PagedPool, bm.bmWidthBytes * abs(bm.bmHeight), TAG_BITMAP);
1400 if (pBits == NULL)
1401 {
1402 DPRINT1("ExAllocatePoolWithTag() failed!\n");
1403 SURFACE_UnlockSurface(psurfOff);
1404 goto cleanup;
1405 }
1406
1407 /* get icon bits */
1408 IntGetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1409
1410 /* premultiply with the alpha channel value */
1411 for (i = 0; i < cyHeight; i++)
1412 {
1413 for (j = 0; j < cxWidth; j++)
1414 {
1415 Pixel = *(DWORD *)(pBits + Count);
1416
1417 Alpha = ((BYTE)(Pixel >> 24) & 0xff);
1418
1419 Red = (((BYTE)(Pixel >> 0)) * Alpha) / 0xff;
1420 Green = (((BYTE)(Pixel >> 8)) * Alpha) / 0xff;
1421 Blue = (((BYTE)(Pixel >> 16)) * Alpha) / 0xff;
1422
1423 *(DWORD *)(pBits + Count) = (DWORD)(Red | (Green << 8) | (Blue << 16) | (Alpha << 24));
1424
1425 Count += sizeof(DWORD);
1426 }
1427 }
1428
1429 /* set icon bits */
1430 IntSetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1431 ExFreePoolWithTag(pBits, TAG_BITMAP);
1432
1433 SURFACE_UnlockSurface(psurfOff);
1434
1435 BlendFunc.BlendOp = AC_SRC_OVER;
1436 BlendFunc.BlendFlags = 0;
1437 BlendFunc.SourceConstantAlpha = 255;
1438 BlendFunc.AlphaFormat = AC_SRC_ALPHA;
1439
1440 NtGdiAlphaBlend(hDc, xLeft, yTop, cxWidth, cyHeight,
1441 hdcOff, 0, 0, cxWidth, cyHeight, BlendFunc, 0);
1442 }
1443 else if (DoFlickerFree)
1444 {
1445 NtGdiBitBlt(hDc, xLeft, yTop, cxWidth,
1446 cyHeight, hdcOff, 0, 0, SRCCOPY, 0, 0);
1447 }
1448
1449 Ret = TRUE;
1450
1451 cleanup:
1452 if (DoFlickerFree || bAlpha)
1453 {
1454 if (hOldOffBmp) NtGdiSelectBitmap(hdcOff, hOldOffBmp);
1455 if (hOldOffBrush) NtGdiSelectBrush(hdcOff, hOldOffBrush);
1456 if (hbmOff) GreDeleteObject(hbmOff);
1457 if (hdcOff) NtGdiDeleteObjectApp(hdcOff);
1458 }
1459
1460 return Ret;
1461 }
1462
1463 /*
1464 * @implemented
1465 */
1466 BOOL
1467 APIENTRY
1468 NtUserDrawIconEx(
1469 HDC hdc,
1470 int xLeft,
1471 int yTop,
1472 HICON hIcon,
1473 int cxWidth,
1474 int cyHeight,
1475 UINT istepIfAniCur,
1476 HBRUSH hbrFlickerFreeDraw,
1477 UINT diFlags,
1478 DWORD Unknown0,
1479 DWORD Unknown1)
1480 {
1481 PCURICON_OBJECT pIcon;
1482 BOOL Ret;
1483
1484 DPRINT("Enter NtUserDrawIconEx\n");
1485 UserEnterExclusive();
1486
1487 if (!(pIcon = UserGetCurIconObject(hIcon)))
1488 {
1489 DPRINT1("UserGetCurIconObject() failed!\n");
1490 UserLeave();
1491 return FALSE;
1492 }
1493
1494 Ret = UserDrawIconEx(hdc,
1495 xLeft,
1496 yTop,
1497 pIcon,
1498 cxWidth,
1499 cyHeight,
1500 istepIfAniCur,
1501 hbrFlickerFreeDraw,
1502 diFlags);
1503
1504 UserDereferenceObject(pIcon);
1505
1506 UserLeave();
1507 return Ret;
1508 }
1509
1510 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
1511 * User32 macro NtUserShowCursor */
1512 int
1513 APIENTRY
1514 UserShowCursor(BOOL bShow)
1515 {
1516 PSYSTEM_CURSORINFO CurInfo;
1517 HDC Screen;
1518 PDC dc;
1519 SURFOBJ *SurfObj;
1520 SURFACE *psurfDc;
1521 PDEVOBJ *ppdev;
1522 GDIPOINTER *pgp;
1523 int showpointer=0;
1524
1525 CurInfo = IntGetSysCursorInfo();
1526
1527 if (!(Screen = IntGetScreenDC()))
1528 {
1529 return showpointer; /* No mouse */
1530 }
1531
1532 dc = DC_LockDc(Screen);
1533
1534 if (!dc)
1535 {
1536 return showpointer; /* No mouse */
1537 }
1538
1539 psurfDc = dc->dclevel.pSurface;
1540
1541 if (!psurfDc)
1542 {
1543 DC_UnlockDc(dc);
1544 return showpointer; /* No Mouse */
1545 }
1546
1547 SurfObj = &psurfDc->SurfObj;
1548 if (SurfObj == NULL)
1549 {
1550 DC_UnlockDc(dc);
1551 return showpointer; /* No mouse */
1552 }
1553
1554 ppdev = GDIDEV(SurfObj);
1555
1556 if (ppdev == NULL)
1557 {
1558 DC_UnlockDc(dc);
1559 return showpointer; /* No mouse */
1560 }
1561
1562 pgp = &ppdev->Pointer;
1563
1564 if (bShow == FALSE)
1565 {
1566 pgp->ShowPointer--;
1567 showpointer = pgp->ShowPointer;
1568
1569 if (showpointer >= 0)
1570 {
1571 //ppdev->SafetyRemoveCount = 1;
1572 //ppdev->SafetyRemoveLevel = 1;
1573 IntEngMovePointer(SurfObj,-1,-1,NULL);
1574 CurInfo->ShowingCursor = 0;
1575 }
1576
1577 }
1578 else
1579 {
1580 pgp->ShowPointer++;
1581 showpointer = pgp->ShowPointer;
1582
1583 /* Show Cursor */
1584 if (showpointer < 0)
1585 {
1586 //ppdev->SafetyRemoveCount = 0;
1587 //ppdev->SafetyRemoveLevel = 0;
1588 IntEngMovePointer(SurfObj,-1,-1,NULL);
1589 CurInfo->ShowingCursor = CURSOR_SHOWING;
1590 }
1591 }
1592
1593 DC_UnlockDc(dc);
1594 return showpointer;
1595 }