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