Sync with trunk (r48545)
[reactos.git] / subsystems / win32 / win32k / ntuser / cursoricon.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 /*
21 * We handle two types of cursors/icons:
22 * - Private
23 * Loaded without LR_SHARED flag
24 * Private to a process
25 * Can be deleted by calling NtDestroyCursorIcon()
26 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
27 * - Shared
28 * Loaded with LR_SHARED flag
29 * Possibly shared by multiple processes
30 * Immune to NtDestroyCursorIcon()
31 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
32 * There's a M:N relationship between processes and (shared) cursor/icons.
33 * A process can have multiple cursor/icons and a cursor/icon can be used
34 * by multiple processes. To keep track of this we keep a list of all
35 * cursor/icons (CurIconList) and per cursor/icon we keep a list of
36 * CURICON_PROCESS structs starting at CurIcon->ProcessList.
37 */
38
39 #include <win32k.h>
40
41 //#define NDEBUG
42 #include <debug.h>
43
44 static PAGED_LOOKASIDE_LIST gProcessLookasideList;
45 static LIST_ENTRY gCurIconList;
46
47 SYSTEM_CURSORINFO gSysCursorInfo;
48
49 BOOL
50 InitCursorImpl()
51 {
52 ExInitializePagedLookasideList(&gProcessLookasideList,
53 NULL,
54 NULL,
55 0,
56 sizeof(CURICON_PROCESS),
57 TAG_DIB,
58 128);
59 InitializeListHead(&gCurIconList);
60
61 gSysCursorInfo.Enabled = FALSE;
62 gSysCursorInfo.ButtonsDown = 0;
63 gSysCursorInfo.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 /*
496 * @implemented
497 */
498 BOOL
499 APIENTRY
500 NtUserGetIconInfo(
501 HANDLE hCurIcon,
502 PICONINFO IconInfo,
503 PUNICODE_STRING lpInstName, // optional
504 PUNICODE_STRING lpResName, // optional
505 LPDWORD pbpp, // optional
506 BOOL bInternal)
507 {
508 ICONINFO ii;
509 PCURICON_OBJECT CurIcon;
510 NTSTATUS Status = STATUS_SUCCESS;
511 BOOL Ret = FALSE;
512 DWORD colorBpp = 0;
513
514 DPRINT("Enter NtUserGetIconInfo\n");
515 UserEnterExclusive();
516
517 if (!IconInfo)
518 {
519 SetLastWin32Error(ERROR_INVALID_PARAMETER);
520 goto leave;
521 }
522
523 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
524 {
525 goto leave;
526 }
527
528 RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO));
529
530 /* Copy bitmaps */
531 ii.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
532 ii.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
533
534 if (pbpp)
535 {
536 PSURFACE psurfBmp;
537
538 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
539 if (psurfBmp)
540 {
541 colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
542 SURFACE_UnlockSurface(psurfBmp);
543 }
544 }
545
546 /* Copy fields */
547 _SEH2_TRY
548 {
549 ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
550 RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
551
552 if (pbpp)
553 {
554 ProbeForWrite(pbpp, sizeof(DWORD), 1);
555 *pbpp = colorBpp;
556 }
557 }
558 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
559 {
560 Status = _SEH2_GetExceptionCode();
561 }
562 _SEH2_END
563
564 if (NT_SUCCESS(Status))
565 Ret = TRUE;
566 else
567 SetLastNtError(Status);
568
569 UserDereferenceObject(CurIcon);
570
571 leave:
572 DPRINT("Leave NtUserGetIconInfo, ret=%i\n", Ret);
573 UserLeave();
574
575 return Ret;
576 }
577
578
579 /*
580 * @implemented
581 */
582 BOOL
583 APIENTRY
584 NtUserGetIconSize(
585 HANDLE hCurIcon,
586 UINT istepIfAniCur,
587 PLONG plcx, // &size.cx
588 PLONG plcy) // &size.cy
589 {
590 PCURICON_OBJECT CurIcon;
591 NTSTATUS Status = STATUS_SUCCESS;
592 BOOL bRet = FALSE;
593
594 DPRINT("Enter NtUserGetIconSize\n");
595 UserEnterExclusive();
596
597 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
598 {
599 goto cleanup;
600 }
601
602 _SEH2_TRY
603 {
604 ProbeForWrite(plcx, sizeof(LONG), 1);
605 RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
606 ProbeForWrite(plcy, sizeof(LONG), 1);
607 RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
608 }
609 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
610 {
611 Status = _SEH2_GetExceptionCode();
612 }
613 _SEH2_END
614
615 if (NT_SUCCESS(Status))
616 bRet = TRUE;
617 else
618 SetLastNtError(Status); // maybe not, test this
619
620 UserDereferenceObject(CurIcon);
621
622 cleanup:
623 DPRINT("Leave NtUserGetIconSize, ret=%i\n", bRet);
624 UserLeave();
625 return bRet;
626 }
627
628
629 /*
630 * @unimplemented
631 */
632 DWORD
633 APIENTRY
634 NtUserGetCursorFrameInfo(
635 DWORD Unknown0,
636 DWORD Unknown1,
637 DWORD Unknown2,
638 DWORD Unknown3)
639 {
640 UNIMPLEMENTED
641
642 return 0;
643 }
644
645
646 /*
647 * @implemented
648 */
649 BOOL
650 APIENTRY
651 NtUserGetCursorInfo(
652 PCURSORINFO pci)
653 {
654 CURSORINFO SafeCi;
655 PSYSTEM_CURSORINFO CurInfo;
656 NTSTATUS Status = STATUS_SUCCESS;
657 PCURICON_OBJECT CurIcon;
658 BOOL Ret = FALSE;
659 DECLARE_RETURN(BOOL);
660
661 DPRINT("Enter NtUserGetCursorInfo\n");
662 UserEnterExclusive();
663
664 CurInfo = IntGetSysCursorInfo();
665 CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
666
667 SafeCi.cbSize = sizeof(CURSORINFO);
668 SafeCi.flags = ((CurInfo->ShowingCursor && CurIcon) ? CURSOR_SHOWING : 0);
669 SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
670
671 SafeCi.ptScreenPos = gpsi->ptCursor;
672
673 _SEH2_TRY
674 {
675 if (pci->cbSize == sizeof(CURSORINFO))
676 {
677 ProbeForWrite(pci, sizeof(CURSORINFO), 1);
678 RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
679 Ret = TRUE;
680 }
681 else
682 {
683 SetLastWin32Error(ERROR_INVALID_PARAMETER);
684 }
685 }
686 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
687 {
688 Status = _SEH2_GetExceptionCode();
689 }
690 _SEH2_END;
691 if (!NT_SUCCESS(Status))
692 {
693 SetLastNtError(Status);
694 }
695
696 RETURN(Ret);
697
698 CLEANUP:
699 DPRINT("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
700 UserLeave();
701 END_CLEANUP;
702 }
703
704 BOOL
705 APIENTRY
706 UserClipCursor(
707 RECTL *prcl)
708 {
709 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
710 PSYSTEM_CURSORINFO CurInfo;
711 PWINDOW_OBJECT DesktopWindow = NULL;
712
713 CurInfo = IntGetSysCursorInfo();
714
715 DesktopWindow = UserGetDesktopWindow();
716
717 if (prcl != NULL &&
718 (prcl->right > prcl->left) &&
719 (prcl->bottom > prcl->top) &&
720 DesktopWindow != NULL)
721 {
722 CurInfo->CursorClipInfo.IsClipped = TRUE;
723 CurInfo->CursorClipInfo.Left = max(prcl->left, DesktopWindow->Wnd->rcWindow.left);
724 CurInfo->CursorClipInfo.Top = max(prcl->top, DesktopWindow->Wnd->rcWindow.top);
725 CurInfo->CursorClipInfo.Right = min(prcl->right, DesktopWindow->Wnd->rcWindow.right);
726 CurInfo->CursorClipInfo.Bottom = min(prcl->bottom, DesktopWindow->Wnd->rcWindow.bottom);
727
728 UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, FALSE);
729 }
730 else
731 {
732 CurInfo->CursorClipInfo.IsClipped = FALSE;
733 }
734
735 return TRUE;
736 }
737
738 /*
739 * @implemented
740 */
741 BOOL
742 APIENTRY
743 NtUserClipCursor(
744 RECTL *prcl)
745 {
746 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
747 RECTL rclLocal;
748 BOOL bResult;
749
750 if (prcl)
751 {
752 _SEH2_TRY
753 {
754 /* Probe and copy rect */
755 ProbeForRead(prcl, sizeof(RECTL), 1);
756 rclLocal = *prcl;
757 }
758 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
759 {
760 SetLastWin32Error(ERROR_INVALID_PARAMETER);
761 _SEH2_YIELD(return FALSE;)
762 }
763 _SEH2_END
764
765 prcl = &rclLocal;
766 }
767
768 UserEnterExclusive();
769
770 /* Call the internal function */
771 bResult = UserClipCursor(prcl);
772
773 UserLeave();
774
775 return bResult;
776 }
777
778
779 /*
780 * @implemented
781 */
782 BOOL
783 APIENTRY
784 NtUserDestroyCursor(
785 HANDLE hCurIcon,
786 DWORD Unknown)
787 {
788 PCURICON_OBJECT CurIcon;
789 BOOL ret;
790 DECLARE_RETURN(BOOL);
791
792 DPRINT("Enter NtUserDestroyCursorIcon\n");
793 UserEnterExclusive();
794
795 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
796 {
797 RETURN(FALSE);
798 }
799
800 ret = IntDestroyCurIconObject(CurIcon, FALSE);
801 /* Note: IntDestroyCurIconObject will remove our reference for us! */
802
803 RETURN(ret);
804
805 CLEANUP:
806 DPRINT("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
807 UserLeave();
808 END_CLEANUP;
809 }
810
811
812 /*
813 * @implemented
814 */
815 HICON
816 APIENTRY
817 NtUserFindExistingCursorIcon(
818 HMODULE hModule,
819 HRSRC hRsrc,
820 LONG cx,
821 LONG cy)
822 {
823 PCURICON_OBJECT CurIcon;
824 HANDLE Ret = (HANDLE)0;
825 DECLARE_RETURN(HICON);
826
827 DPRINT("Enter NtUserFindExistingCursorIcon\n");
828 UserEnterExclusive();
829
830 CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy);
831 if (CurIcon)
832 {
833 Ret = CurIcon->Self;
834
835 // IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
836 RETURN(Ret);
837 }
838
839 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
840 RETURN((HANDLE)0);
841
842 CLEANUP:
843 DPRINT("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_);
844 UserLeave();
845 END_CLEANUP;
846 }
847
848
849 /*
850 * @implemented
851 */
852 BOOL
853 APIENTRY
854 NtUserGetClipCursor(
855 RECTL *lpRect)
856 {
857 /* FIXME - check if process has WINSTA_READATTRIBUTES */
858 PSYSTEM_CURSORINFO CurInfo;
859 RECTL Rect;
860 NTSTATUS Status;
861 DECLARE_RETURN(BOOL);
862
863 DPRINT("Enter NtUserGetClipCursor\n");
864 UserEnterExclusive();
865
866 if (!lpRect)
867 RETURN(FALSE);
868
869 CurInfo = IntGetSysCursorInfo();
870 if (CurInfo->CursorClipInfo.IsClipped)
871 {
872 Rect.left = CurInfo->CursorClipInfo.Left;
873 Rect.top = CurInfo->CursorClipInfo.Top;
874 Rect.right = CurInfo->CursorClipInfo.Right;
875 Rect.bottom = CurInfo->CursorClipInfo.Bottom;
876 }
877 else
878 {
879 Rect.left = 0;
880 Rect.top = 0;
881 Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
882 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
883 }
884
885 Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT));
886 if (!NT_SUCCESS(Status))
887 {
888 SetLastNtError(Status);
889 RETURN(FALSE);
890 }
891
892 RETURN(TRUE);
893
894 CLEANUP:
895 DPRINT("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
896 UserLeave();
897 END_CLEANUP;
898 }
899
900
901 /*
902 * @implemented
903 */
904 HCURSOR
905 APIENTRY
906 NtUserSetCursor(
907 HCURSOR hCursor)
908 {
909 PCURICON_OBJECT CurIcon;
910 HICON OldCursor;
911 DECLARE_RETURN(HCURSOR);
912
913 DPRINT("Enter NtUserSetCursor\n");
914 UserEnterExclusive();
915
916 if (hCursor)
917 {
918 if (!(CurIcon = UserGetCurIconObject(hCursor)))
919 {
920 RETURN(NULL);
921 }
922 }
923 else
924 {
925 CurIcon = NULL;
926 }
927
928 OldCursor = UserSetCursor(CurIcon, FALSE);
929
930 if (CurIcon)
931 {
932 UserDereferenceObject(CurIcon);
933 }
934
935 RETURN(OldCursor);
936
937 CLEANUP:
938 DPRINT("Leave NtUserSetCursor, ret=%i\n",_ret_);
939 UserLeave();
940 END_CLEANUP;
941 }
942
943
944 /*
945 * @implemented
946 */
947 BOOL
948 APIENTRY
949 NtUserSetCursorContents(
950 HANDLE hCurIcon,
951 PICONINFO UnsafeIconInfo)
952 {
953 PCURICON_OBJECT CurIcon;
954 ICONINFO IconInfo;
955 PSURFACE psurfBmp;
956 NTSTATUS Status;
957 BOOL Ret = FALSE;
958 DECLARE_RETURN(BOOL);
959
960 DPRINT("Enter NtUserSetCursorContents\n");
961 UserEnterExclusive();
962
963 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
964 {
965 RETURN(FALSE);
966 }
967
968 /* Copy fields */
969 Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
970 if (!NT_SUCCESS(Status))
971 {
972 SetLastNtError(Status);
973 goto done;
974 }
975
976 /* Delete old bitmaps */
977 if ((CurIcon->IconInfo.hbmColor)
978 && (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor))
979 {
980 GreDeleteObject(CurIcon->IconInfo.hbmColor);
981 }
982 if ((CurIcon->IconInfo.hbmMask)
983 && CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
984 {
985 GreDeleteObject(CurIcon->IconInfo.hbmMask);
986 }
987
988 /* Copy new IconInfo field */
989 CurIcon->IconInfo = IconInfo;
990
991 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
992 if (psurfBmp)
993 {
994 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
995 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
996 SURFACE_UnlockSurface(psurfBmp);
997 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
998 }
999 else
1000 {
1001 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask);
1002 if (!psurfBmp)
1003 goto done;
1004
1005 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1006 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
1007
1008 SURFACE_UnlockSurface(psurfBmp);
1009 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
1010 }
1011
1012 Ret = TRUE;
1013
1014 done:
1015
1016 if (CurIcon)
1017 {
1018 UserDereferenceObject(CurIcon);
1019 }
1020 RETURN(Ret);
1021
1022 CLEANUP:
1023 DPRINT("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
1024 UserLeave();
1025 END_CLEANUP;
1026 }
1027
1028
1029 /*
1030 * @implemented
1031 */
1032 #if 0
1033 BOOL
1034 APIENTRY
1035 NtUserSetCursorIconData(
1036 HANDLE Handle,
1037 HMODULE hModule,
1038 PUNICODE_STRING pstrResName,
1039 PICONINFO pIconInfo)
1040 {
1041 PCURICON_OBJECT CurIcon;
1042 PSURFACE psurfBmp;
1043 NTSTATUS Status = STATUS_SUCCESS;
1044 BOOL Ret = FALSE;
1045 DECLARE_RETURN(BOOL);
1046
1047 DPRINT("Enter NtUserSetCursorIconData\n");
1048 UserEnterExclusive();
1049
1050 if (!(CurIcon = UserGetCurIconObject(Handle)))
1051 {
1052 RETURN(FALSE);
1053 }
1054
1055 CurIcon->hModule = hModule;
1056 CurIcon->hRsrc = NULL; //hRsrc;
1057 CurIcon->hGroupRsrc = NULL; //hGroupRsrc;
1058
1059 _SEH2_TRY
1060 {
1061 ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
1062 RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO));
1063
1064 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(pIconInfo->hbmMask);
1065 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(pIconInfo->hbmColor);
1066
1067 if (CurIcon->IconInfo.hbmColor)
1068 {
1069 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
1070 {
1071 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1072 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1073 SURFACE_UnlockSurface(psurfBmp);
1074 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1075 }
1076 }
1077 if (CurIcon->IconInfo.hbmMask)
1078 {
1079 if (CurIcon->IconInfo.hbmColor == NULL)
1080 {
1081 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
1082 {
1083 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1084 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1085 SURFACE_UnlockSurface(psurfBmp);
1086 }
1087 }
1088 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1089 }
1090 }
1091 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1092 {
1093 Status = _SEH2_GetExceptionCode();
1094 }
1095 _SEH2_END
1096
1097 if (!NT_SUCCESS(Status))
1098 SetLastNtError(Status);
1099 else
1100 Ret = TRUE;
1101
1102 UserDereferenceObject(CurIcon);
1103 RETURN(Ret);
1104
1105 CLEANUP:
1106 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1107 UserLeave();
1108 END_CLEANUP;
1109 }
1110 #else
1111 BOOL
1112 APIENTRY
1113 NtUserSetCursorIconData(
1114 HANDLE hCurIcon,
1115 PBOOL fIcon,
1116 POINT *Hotspot,
1117 HMODULE hModule,
1118 HRSRC hRsrc,
1119 HRSRC hGroupRsrc)
1120 {
1121 PCURICON_OBJECT CurIcon;
1122 NTSTATUS Status;
1123 POINT SafeHotspot;
1124 BOOL Ret = FALSE;
1125 DECLARE_RETURN(BOOL);
1126
1127 DPRINT("Enter NtUserSetCursorIconData\n");
1128 UserEnterExclusive();
1129
1130 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1131 {
1132 RETURN(FALSE);
1133 }
1134
1135 CurIcon->hModule = hModule;
1136 CurIcon->hRsrc = hRsrc;
1137 CurIcon->hGroupRsrc = hGroupRsrc;
1138
1139 /* Copy fields */
1140 if (fIcon)
1141 {
1142 Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
1143 if (!NT_SUCCESS(Status))
1144 {
1145 SetLastNtError(Status);
1146 goto done;
1147 }
1148 }
1149 else
1150 {
1151 if (!Hotspot)
1152 Ret = TRUE;
1153 }
1154
1155 if (Hotspot)
1156 {
1157 Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
1158 if (NT_SUCCESS(Status))
1159 {
1160 CurIcon->IconInfo.xHotspot = SafeHotspot.x;
1161 CurIcon->IconInfo.yHotspot = SafeHotspot.y;
1162
1163 Ret = TRUE;
1164 }
1165 else
1166 SetLastNtError(Status);
1167 }
1168
1169 if (!fIcon && !Hotspot)
1170 {
1171 Ret = TRUE;
1172 }
1173
1174 done:
1175 if(Ret)
1176 {
1177 /* This icon is shared now */
1178 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
1179 if(CurIcon->IconInfo.hbmColor)
1180 {
1181 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
1182 }
1183 }
1184 UserDereferenceObject(CurIcon);
1185 RETURN(Ret);
1186
1187
1188 CLEANUP:
1189 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1190 UserLeave();
1191 END_CLEANUP;
1192 }
1193 #endif
1194
1195 /*
1196 * @unimplemented
1197 */
1198 BOOL
1199 APIENTRY
1200 NtUserSetSystemCursor(
1201 HCURSOR hcur,
1202 DWORD id)
1203 {
1204 return FALSE;
1205 }
1206
1207 /* Mostly inspired from wine code */
1208 BOOL
1209 UserDrawIconEx(
1210 HDC hDc,
1211 INT xLeft,
1212 INT yTop,
1213 PCURICON_OBJECT pIcon,
1214 INT cxWidth,
1215 INT cyHeight,
1216 UINT istepIfAniCur,
1217 HBRUSH hbrFlickerFreeDraw,
1218 UINT diFlags)
1219 {
1220 PSURFACE psurfColor = NULL, psurfMask, psurfDst = NULL;
1221 HGDIOBJ hObjs[3];
1222 PGDIOBJ pObjs[3];
1223 BOOL DoFlickerFree;
1224 PDC pdc;
1225 HSURF hsurfDst = NULL;
1226 RECTL rcSrc, rcDst;
1227 CLIPOBJ clo, *pclo;
1228 EXLATEOBJ exlo;
1229 BOOL bAlpha = FALSE, Ret = FALSE, bStretch;
1230
1231 if (istepIfAniCur)
1232 DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1233
1234 DPRINT("Flags : 0x%08x\n", diFlags);
1235
1236 hObjs[0] = pIcon->IconInfo.hbmMask;
1237 hObjs[1] = pIcon->IconInfo.hbmColor;
1238 hObjs[2] = hDc;
1239 GDIOBJ_LockMultipleObjs(3, hObjs, pObjs);
1240 psurfMask = pObjs[0];
1241 psurfColor = pObjs[1];
1242 pdc = pObjs[2];
1243
1244 if (!pIcon->IconInfo.hbmMask
1245 || !psurfMask)
1246 {
1247 DPRINT1("No hbmMask?!\n");
1248 if(pdc) DC_UnlockDc(pdc);
1249 if(psurfColor) SURFACE_UnlockSurface(psurfColor);
1250 return FALSE;
1251 }
1252
1253 if (pIcon->IconInfo.hbmColor
1254 && !psurfColor)
1255 {
1256 DPRINT1("Unable to lock the color Bitmap?!\n");
1257 SURFACE_UnlockSurface(psurfMask);
1258 if(pdc) DC_UnlockDc(pdc);
1259 return FALSE;
1260 }
1261
1262 if(!psurfColor)
1263 {
1264 DPRINT("Monochrome Icon\n");
1265 psurfColor = psurfMask;
1266 RECTL_vSetRect(&rcSrc, 0, pIcon->Size.cy, pIcon->Size.cx, 2*pIcon->Size.cy);
1267 }
1268 else
1269 {
1270 DPRINT("Color Icon\n");
1271 RECTL_vSetRect(&rcSrc, 0, 0, pIcon->Size.cx, pIcon->Size.cy);
1272 }
1273
1274 if(!pdc)
1275 {
1276 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1277 SURFACE_UnlockSurface(psurfMask);
1278 if(psurfColor != psurfMask) SURFACE_UnlockSurface(psurfColor);
1279 DPRINT1("Invalid DC!\n");
1280 return FALSE;
1281 }
1282
1283 /* Check for alpha */
1284 if ((BitsPerFormat(psurfColor->SurfObj.iBitmapFormat) == 32)
1285 && (diFlags & DI_IMAGE))
1286 {
1287 PFN_DIB_GetPixel fnSource_GetPixel = NULL;
1288 INT i, j;
1289
1290 /* In order to correctly display 32 bit icons Windows first scans the image,
1291 because information about transparency is not stored in any image's headers */
1292 fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfColor->SurfObj.iBitmapFormat].DIB_GetPixel;
1293 if (fnSource_GetPixel)
1294 {
1295 for (i = 0; i < psurfColor->SurfObj.sizlBitmap.cx; i++)
1296 {
1297 for (j = 0; j < psurfColor->SurfObj.sizlBitmap.cy; j++)
1298 {
1299 bAlpha = ((BYTE)(fnSource_GetPixel(&psurfColor->SurfObj, i, j) >> 24) & 0xff);
1300 if (bAlpha)
1301 break;
1302 }
1303 if (bAlpha)
1304 break;
1305 }
1306 }
1307 }
1308
1309 if (!cxWidth)
1310 cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
1311 UserGetSystemMetrics(SM_CXICON) : pIcon->Size.cx);
1312
1313 if (!cyHeight)
1314 cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
1315 UserGetSystemMetrics(SM_CYICON) : pIcon->Size.cy);
1316
1317 /* Check stretching */
1318 bStretch = (pIcon->Size.cx != cxWidth) || (pIcon->Size.cy != cyHeight);
1319
1320 DoFlickerFree = (hbrFlickerFreeDraw &&
1321 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
1322
1323 if (DoFlickerFree)
1324 {
1325 EBRUSHOBJ ebo;
1326 PBRUSH pBrush ;
1327 POINTL ptBrushOrig;
1328
1329 pBrush = BRUSH_LockBrush(hbrFlickerFreeDraw);
1330 if(!pBrush)
1331 {
1332 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1333 DPRINT1("Invalid brush!\n");
1334 goto cleanup;
1335 }
1336
1337 hsurfDst = IntCreateCompatibleBitmap(pdc, cxWidth, cyHeight);
1338 if(!hsurfDst)
1339 {
1340 DPRINT1("Error : Failed to allocate the offscreen surface\n");
1341 goto cleanup;
1342 }
1343 psurfDst = SURFACE_LockSurface(hsurfDst);
1344 if(!psurfDst)
1345 {
1346 DPRINT1("Error : Failed to lock the offScreen bitmap\n");
1347 goto cleanup;
1348 }
1349 RECTL_vSetRect(&rcDst, 0, 0, cxWidth, cyHeight);
1350
1351 ptBrushOrig.x = pBrush->ptOrigin.x;
1352 ptBrushOrig.y = pBrush->ptOrigin.y;
1353
1354 EBRUSHOBJ_vInit(&ebo, pBrush, pdc);
1355
1356 clo.iDComplexity = DC_TRIVIAL;
1357 pclo = &clo;
1358
1359 IntEngBitBlt(&psurfDst->SurfObj, NULL, NULL, pclo, NULL, &rcDst, NULL,
1360 NULL, &ebo.BrushObject, &ptBrushOrig, ROP3_TO_ROP4(PATCOPY));
1361
1362 EBRUSHOBJ_vCleanup(&ebo);
1363 BRUSH_UnlockBrush(pBrush);
1364 }
1365 else
1366 {
1367 RECT rcBmp;
1368 RECTL_vSetRect(&rcDst, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
1369 IntLPtoDP(pdc, (LPPOINT)&rcDst, 2);
1370 RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
1371
1372 DC_vPrepareDCsForBlit(pdc, rcDst, NULL, rcDst );
1373
1374 if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
1375 DC_vUpdateFillBrush(pdc);
1376
1377 psurfDst = pdc->dclevel.pSurface;
1378 pclo = pdc->rosdc.CombinedClip;
1379 RECTL_vSetRect(&rcBmp, 0, 0, psurfDst->SurfObj.sizlBitmap.cx, psurfDst->SurfObj.sizlBitmap.cy);
1380 if(!RECTL_bIntersectRect(&rcDst, &rcDst, &rcBmp))
1381 {
1382 Ret = FALSE;
1383 goto done;
1384 }
1385 }
1386
1387 /* Optimization : use directly the palette of the DC,
1388 * so we XLATE only once, and then we directly copy bits */
1389 EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, pdc->dclevel.pSurface->ppal, 0, 0, 0xFFFFFFFF);
1390
1391 if(bAlpha && (diFlags & DI_IMAGE))
1392 {
1393 BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
1394 BYTE Alpha;
1395 INT i, j;
1396 PSURFACE psurf = NULL;
1397 PBYTE ptr ;
1398 HBITMAP hMemBmp = NULL;
1399
1400 hMemBmp = BITMAP_CopyBitmap(pIcon->IconInfo.hbmColor);
1401 if(!hMemBmp)
1402 {
1403 DPRINT1("BITMAP_CopyBitmap failed!");
1404 goto CleanupAlpha;
1405 }
1406
1407 psurf = SURFACE_LockSurface(hMemBmp);
1408 if(!psurf)
1409 {
1410 DPRINT1("SURFACE_LockSurface failed!\n");
1411 goto CleanupAlpha;
1412 }
1413
1414 /* premultiply with the alpha channel value */
1415 for (i = 0; i < psurf->SurfObj.sizlBitmap.cy; i++)
1416 {
1417 ptr = (PBYTE)psurf->SurfObj.pvScan0 + i*psurf->SurfObj.lDelta;
1418 for (j = 0; j < psurf->SurfObj.sizlBitmap.cx; j++)
1419 {
1420 Alpha = ptr[3];
1421 ptr[0] = (ptr[0] * Alpha) / 0xff;
1422 ptr[1] = (ptr[1] * Alpha) / 0xff;
1423 ptr[2] = (ptr[2] * Alpha) / 0xff;
1424
1425 ptr += 4;
1426 }
1427 }
1428
1429 DPRINT("Performing alpha blending\n");
1430 Ret = IntEngAlphaBlend(&psurfDst->SurfObj,
1431 &psurf->SurfObj,
1432 pclo,
1433 &exlo.xlo,
1434 &rcDst,
1435 &rcSrc,
1436 (BLENDOBJ*)&pixelblend);
1437
1438 CleanupAlpha:
1439 if(psurf) SURFACE_UnlockSurface(psurf);
1440 if(hMemBmp) NtGdiDeleteObjectApp(hMemBmp);
1441 if(Ret) goto done;
1442 else DPRINT1("IntEngAlphaBlend failed!\n");
1443 }
1444
1445 if (diFlags & DI_IMAGE)
1446 {
1447 POINTL ptMaskOrig = {0,0};
1448 if(bStretch)
1449 {
1450 DPRINT("Stretching\n");
1451 Ret = IntEngStretchBlt(&psurfDst->SurfObj,
1452 &psurfColor->SurfObj,
1453 (diFlags & DI_MASK) ? &psurfMask->SurfObj : NULL,
1454 pclo,
1455 &exlo.xlo,
1456 &rcDst,
1457 &rcSrc,
1458 (diFlags & DI_MASK) ? &ptMaskOrig : NULL,
1459 NULL,
1460 NULL,
1461 (diFlags & DI_MASK) ? R4_MASK : ROP3_TO_ROP4(SRCCOPY));
1462 if(!Ret) DPRINT1("IntEngStretchBlt Failed\n");
1463 }
1464 else
1465 {
1466 DPRINT("Blting\n");
1467 Ret = IntEngBitBlt(&psurfDst->SurfObj,
1468 &psurfColor->SurfObj,
1469 (diFlags & DI_MASK) ? &psurfMask->SurfObj : NULL,
1470 pclo,
1471 &exlo.xlo,
1472 &rcDst,
1473 (PPOINTL)&rcSrc,
1474 (diFlags & DI_MASK) ? &ptMaskOrig : NULL,
1475 NULL,
1476 NULL,
1477 (diFlags & DI_MASK) ? R4_MASK : ROP3_TO_ROP4(SRCCOPY));
1478 if(!Ret) DPRINT1("IntEngBitBlt Failed\n");
1479 }
1480 }
1481 else
1482 {
1483 DPRINT1("Uh? Calling DrawIcon without anything to draw? diFlags %d\n", diFlags);
1484 }
1485
1486 done:
1487 if(DoFlickerFree && Ret)
1488 {
1489 POINTL ptSrc = {0,0};
1490 RECTL rcBmp;
1491
1492 RECTL_vSetRect(&rcDst, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
1493
1494 IntLPtoDP(pdc, (LPPOINT)&rcDst, 2);
1495
1496 RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
1497 DC_vPrepareDCsForBlit(pdc, rcDst, NULL, rcDst );
1498
1499 if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
1500 DC_vUpdateFillBrush(pdc);
1501
1502 RECTL_vSetRect(&rcBmp, 0, 0,
1503 pdc->dclevel.pSurface->SurfObj.sizlBitmap.cx,
1504 pdc->dclevel.pSurface->SurfObj.sizlBitmap.cy);
1505
1506 if(RECTL_bIntersectRect(&rcDst, &rcDst, &rcBmp))
1507 {
1508 /* Copy everything */
1509 DPRINT("Copying bits from offscreen buffer\n");
1510 Ret = IntEngCopyBits(&pdc->dclevel.pSurface->SurfObj,
1511 &psurfDst->SurfObj,
1512 pdc->rosdc.CombinedClip,
1513 gpxloTrivial,
1514 &rcDst,
1515 &ptSrc);
1516 if(!Ret) DPRINT1("IntEngCopyBits Failed\n");
1517 }
1518
1519 DC_vFinishBlit(pdc, NULL);
1520 }
1521
1522 if(!DoFlickerFree) DC_vFinishBlit(pdc, NULL);
1523 EXLATEOBJ_vCleanup(&exlo);
1524
1525 cleanup:
1526 if(psurfColor != psurfMask)
1527 SURFACE_UnlockSurface(psurfColor);
1528 SURFACE_UnlockSurface(psurfMask);
1529 if(hsurfDst)
1530 {
1531 if(psurfDst) SURFACE_UnlockSurface(psurfDst);
1532 GreDeleteObject(hsurfDst);
1533 }
1534 DC_UnlockDc(pdc);
1535
1536 DPRINT("return %s\n", Ret ? "TRUE" : "FALSE") ;
1537
1538 return Ret ;
1539 }
1540
1541 /*
1542 * @implemented
1543 */
1544 BOOL
1545 APIENTRY
1546 NtUserDrawIconEx(
1547 HDC hdc,
1548 int xLeft,
1549 int yTop,
1550 HICON hIcon,
1551 int cxWidth,
1552 int cyHeight,
1553 UINT istepIfAniCur,
1554 HBRUSH hbrFlickerFreeDraw,
1555 UINT diFlags,
1556 BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32!
1557 PVOID pDIXData)
1558 {
1559 PCURICON_OBJECT pIcon;
1560 BOOL Ret;
1561
1562 DPRINT("Enter NtUserDrawIconEx\n");
1563 UserEnterExclusive();
1564
1565 if (!(pIcon = UserGetCurIconObject(hIcon)))
1566 {
1567 DPRINT1("UserGetCurIconObject() failed!\n");
1568 UserLeave();
1569 return FALSE;
1570 }
1571
1572 Ret = UserDrawIconEx(hdc,
1573 xLeft,
1574 yTop,
1575 pIcon,
1576 cxWidth,
1577 cyHeight,
1578 istepIfAniCur,
1579 hbrFlickerFreeDraw,
1580 diFlags);
1581
1582 UserDereferenceObject(pIcon);
1583
1584 UserLeave();
1585 return Ret;
1586 }
1587