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