[WIN32K]
[reactos.git] / reactos / win32ss / user / ntuser / cursoricon.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Cursor and icon functions
5 * FILE: win32ss/user/ntuser/cursoricon.c
6 * PROGRAMER: ReactOS Team
7 */
8 /*
9 * We handle two types of cursors/icons:
10 * - Private
11 * Loaded without LR_SHARED flag
12 * Private to a process
13 * Can be deleted by calling NtDestroyCursorIcon()
14 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
15 * - Shared
16 * Loaded with LR_SHARED flag
17 * Possibly shared by multiple processes
18 * Immune to NtDestroyCursorIcon()
19 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
20 * There's a M:N relationship between processes and (shared) cursor/icons.
21 * A process can have multiple cursor/icons and a cursor/icon can be used
22 * by multiple processes. To keep track of this we keep a list of all
23 * cursor/icons (CurIconList) and per cursor/icon we keep a list of
24 * CURICON_PROCESS structs starting at CurIcon->ProcessList.
25 */
26
27 #include <win32k.h>
28 DBG_DEFAULT_CHANNEL(UserIcon);
29
30 static PPAGED_LOOKASIDE_LIST pgProcessLookasideList;
31 static LIST_ENTRY gCurIconList;
32
33 SYSTEM_CURSORINFO gSysCursorInfo;
34
35 BOOL
36 InitCursorImpl()
37 {
38 pgProcessLookasideList = ExAllocatePool(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST));
39 if(!pgProcessLookasideList)
40 return FALSE;
41
42 ExInitializePagedLookasideList(pgProcessLookasideList,
43 NULL,
44 NULL,
45 0,
46 sizeof(CURICON_PROCESS),
47 TAG_DIB,
48 128);
49 InitializeListHead(&gCurIconList);
50
51 gSysCursorInfo.Enabled = FALSE;
52 gSysCursorInfo.ButtonsDown = 0;
53 gSysCursorInfo.bClipped = FALSE;
54 gSysCursorInfo.LastBtnDown = 0;
55 gSysCursorInfo.CurrentCursorObject = NULL;
56 gSysCursorInfo.ShowingCursor = -1;
57 gSysCursorInfo.ClickLockActive = FALSE;
58 gSysCursorInfo.ClickLockTime = 0;
59
60 return TRUE;
61 }
62
63 PSYSTEM_CURSORINFO
64 IntGetSysCursorInfo()
65 {
66 return &gSysCursorInfo;
67 }
68
69 /* This function creates a reference for the object! */
70 PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
71 {
72 PCURICON_OBJECT CurIcon;
73
74 if (!hCurIcon)
75 {
76 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
77 return NULL;
78 }
79
80 CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, TYPE_CURSOR);
81 if (!CurIcon)
82 {
83 /* We never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
84 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
85 return NULL;
86 }
87
88 ASSERT(CurIcon->head.cLockObj >= 1);
89 return CurIcon;
90 }
91
92 BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
93 {
94 PWND DesktopWindow;
95 PSYSTEM_CURSORINFO CurInfo;
96 MSG Msg;
97 RECTL rcClip;
98 POINT pt;
99
100 if(!(DesktopWindow = UserGetDesktopWindow()))
101 {
102 return FALSE;
103 }
104
105 CurInfo = IntGetSysCursorInfo();
106
107 /* Clip cursor position */
108 if (!CurInfo->bClipped)
109 rcClip = DesktopWindow->rcClient;
110 else
111 rcClip = CurInfo->rcClip;
112
113 if(x >= rcClip.right) x = rcClip.right - 1;
114 if(x < rcClip.left) x = rcClip.left;
115 if(y >= rcClip.bottom) y = rcClip.bottom - 1;
116 if(y < rcClip.top) y = rcClip.top;
117
118 pt.x = x;
119 pt.y = y;
120
121 /* 1. Generate a mouse move message, this sets the htEx and Track Window too. */
122 Msg.message = WM_MOUSEMOVE;
123 Msg.wParam = UserGetMouseButtonsState();
124 Msg.lParam = MAKELPARAM(x, y);
125 Msg.pt = pt;
126 co_MsqInsertMouseMessage(&Msg, flags, dwExtraInfo, Hook);
127
128 /* 2. Store the new cursor position */
129 gpsi->ptCursor = pt;
130
131 return TRUE;
132 }
133
134 /*
135 * We have to register that this object is in use by the current
136 * process. The only way to do that seems to be to walk the list
137 * of cursor/icon objects starting at W32Process->CursorIconListHead.
138 * If the object is already present in the list, we don't have to do
139 * anything, if it's not present we add it and inc the ProcessCount
140 * in the object. Having to walk the list kind of sucks, but that's
141 * life...
142 */
143 static BOOLEAN FASTCALL
144 ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
145 {
146 PPROCESSINFO Win32Process;
147 PCURICON_PROCESS Current;
148
149 Win32Process = PsGetCurrentProcessWin32Process();
150
151 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
152 {
153 if (Current->Process == Win32Process)
154 {
155 /* Already registered for this process */
156 return TRUE;
157 }
158 }
159
160 /* Not registered yet */
161 Current = ExAllocateFromPagedLookasideList(pgProcessLookasideList);
162 if (NULL == Current)
163 {
164 return FALSE;
165 }
166 InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
167 Current->Process = Win32Process;
168
169 return TRUE;
170 }
171
172 PCURICON_OBJECT FASTCALL
173 IntFindExistingCurIconObject(HMODULE hModule,
174 HRSRC hRsrc, LONG cx, LONG cy)
175 {
176 PCURICON_OBJECT CurIcon;
177
178 LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
179 {
180
181 // if (NT_SUCCESS(UserReferenceObjectByPointer(Object, TYPE_CURSOR))) // <- huh????
182 // UserReferenceObject( CurIcon);
183 // {
184 if ((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
185 {
186 if (cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
187 {
188 // UserDereferenceObject(CurIcon);
189 continue;
190 }
191 if (! ReferenceCurIconByProcess(CurIcon))
192 {
193 return NULL;
194 }
195
196 return CurIcon;
197 }
198 // }
199 // UserDereferenceObject(CurIcon);
200
201 }
202
203 return NULL;
204 }
205
206 HANDLE
207 IntCreateCurIconHandle(BOOLEAN Anim)
208 {
209 PCURICON_OBJECT CurIcon;
210 HANDLE hCurIcon;
211
212 CurIcon = UserCreateObject(
213 gHandleTable,
214 NULL,
215 GetW32ThreadInfo(),
216 &hCurIcon,
217 TYPE_CURSOR,
218 sizeof(CURICON_OBJECT));
219
220 if (!CurIcon)
221 {
222 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
223 return FALSE;
224 }
225
226 CurIcon->Self = hCurIcon;
227 InitializeListHead(&CurIcon->ProcessList);
228
229 if (!ReferenceCurIconByProcess(CurIcon))
230 {
231 ERR("Failed to add process\n");
232 UserDeleteObject(hCurIcon, TYPE_CURSOR);
233 UserDereferenceObject(CurIcon);
234 return NULL;
235 }
236
237 InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
238
239 UserDereferenceObject(CurIcon);
240
241 return hCurIcon;
242 }
243
244 BOOLEAN FASTCALL
245 IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi)
246 {
247 PSYSTEM_CURSORINFO CurInfo;
248 HBITMAP bmpMask, bmpColor;
249 BOOLEAN Ret, bListEmpty, bFound = FALSE;
250 PCURICON_PROCESS Current = NULL;
251
252 /* For handles created without any data (error handling) */
253 if(IsListEmpty(&CurIcon->ProcessList))
254 goto emptyList;
255
256 /* Now find this process in the list of processes referencing this object and
257 remove it from that list */
258 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
259 {
260 if (Current->Process == ppi)
261 {
262 bFound = TRUE;
263 bListEmpty = RemoveEntryList(&Current->ListEntry);
264 break;
265 }
266 }
267
268 if(!bFound)
269 {
270 /* This object doesn't belong to this process */
271 EngSetLastError(ERROR_INVALID_HANDLE);
272 return FALSE;
273 }
274
275 ExFreeToPagedLookasideList(pgProcessLookasideList, Current);
276
277 /* If there are still processes referencing this object we can't destroy it yet */
278 if (!bListEmpty)
279 {
280 if(CurIcon->head.ppi == ppi)
281 {
282 /* Set the first process of the list as owner */
283 Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
284 UserSetObjectOwner(CurIcon, TYPE_CURSOR, Current->Process);
285 }
286 UserDereferenceObject(CurIcon);
287 return TRUE;
288 }
289
290 emptyList:
291 /* Remove it from the list */
292 RemoveEntryList(&CurIcon->ListEntry);
293
294 CurInfo = IntGetSysCursorInfo();
295
296 if (CurInfo->CurrentCursorObject == CurIcon)
297 {
298 /* Hide the cursor if we're destroying the current cursor */
299 UserSetCursor(NULL, TRUE);
300 }
301
302 bmpMask = CurIcon->IconInfo.hbmMask;
303 bmpColor = CurIcon->IconInfo.hbmColor;
304
305 /* Delete bitmaps */
306 if (bmpMask)
307 {
308 GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
309 GreDeleteObject(bmpMask);
310 CurIcon->IconInfo.hbmMask = NULL;
311 }
312 if (bmpColor)
313 {
314 GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
315 GreDeleteObject(bmpColor);
316 CurIcon->IconInfo.hbmColor = NULL;
317 }
318
319 /* We were given a pointer, no need to keep the reference anylonger! */
320 UserDereferenceObject(CurIcon);
321 Ret = UserDeleteObject(CurIcon->Self, TYPE_CURSOR);
322
323 return Ret;
324 }
325
326 HCURSOR FASTCALL
327 IntSetCursor(
328 HCURSOR hCursor)
329 {
330 PCURICON_OBJECT pcurOld, pcurNew;
331 HCURSOR hOldCursor = NULL;
332
333 if (hCursor)
334 {
335 pcurNew = UserGetCurIconObject(hCursor);
336 if (!pcurNew)
337 {
338 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
339 goto leave;
340 }
341 }
342 else
343 {
344 pcurNew = NULL;
345 }
346
347 pcurOld = UserSetCursor(pcurNew, FALSE);
348 if (pcurOld)
349 {
350 hOldCursor = (HCURSOR)pcurOld->Self;
351 UserDereferenceObject(pcurOld);
352 }
353 leave:
354 return hOldCursor;
355 }
356
357 BOOL FASTCALL
358 IntDestroyCursor(
359 HANDLE hCurIcon,
360 BOOL bForce)
361 {
362 PCURICON_OBJECT CurIcon;
363 BOOL ret;
364
365 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
366 {
367 return FALSE;
368 }
369
370 ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process());
371 /* Note: IntDestroyCurIconObject will remove our reference for us! */
372
373 return ret;
374 }
375
376 /*
377 * @implemented
378 */
379 BOOL
380 APIENTRY
381 NtUserGetIconInfo(
382 HANDLE hCurIcon,
383 PICONINFO IconInfo,
384 PUNICODE_STRING lpInstName, // Optional
385 PUNICODE_STRING lpResName, // Optional
386 LPDWORD pbpp, // Optional
387 BOOL bInternal)
388 {
389 ICONINFO ii;
390 PCURICON_OBJECT CurIcon;
391 NTSTATUS Status = STATUS_SUCCESS;
392 BOOL Ret = FALSE;
393 DWORD colorBpp = 0;
394
395 TRACE("Enter NtUserGetIconInfo\n");
396 UserEnterExclusive();
397
398 if (!IconInfo)
399 {
400 EngSetLastError(ERROR_INVALID_PARAMETER);
401 goto leave;
402 }
403
404 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
405 {
406 goto leave;
407 }
408
409 RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO));
410
411 /* Copy bitmaps */
412 ii.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
413 ii.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
414
415 if (pbpp)
416 {
417 PSURFACE psurfBmp;
418
419 psurfBmp = SURFACE_ShareLockSurface(CurIcon->IconInfo.hbmColor);
420 if (psurfBmp)
421 {
422 colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
423 SURFACE_ShareUnlockSurface(psurfBmp);
424 }
425 }
426
427 /* Copy fields */
428 _SEH2_TRY
429 {
430 ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
431 RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
432
433 /// @todo Implement support for lpInstName
434 if (lpInstName)
435 {
436 RtlInitEmptyUnicodeString(lpInstName, NULL, 0);
437 }
438
439 /// @todo Implement support for lpResName
440 if (lpResName)
441 {
442 RtlInitEmptyUnicodeString(lpResName, NULL, 0);
443 }
444
445 if (pbpp)
446 {
447 ProbeForWrite(pbpp, sizeof(DWORD), 1);
448 *pbpp = colorBpp;
449 }
450 }
451 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
452 {
453 Status = _SEH2_GetExceptionCode();
454 }
455 _SEH2_END
456
457 if (NT_SUCCESS(Status))
458 Ret = TRUE;
459 else
460 SetLastNtError(Status);
461
462 UserDereferenceObject(CurIcon);
463
464 leave:
465 TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret);
466 UserLeave();
467
468 return Ret;
469 }
470
471
472 /*
473 * @implemented
474 */
475 BOOL
476 APIENTRY
477 NtUserGetIconSize(
478 HANDLE hCurIcon,
479 UINT istepIfAniCur,
480 PLONG plcx, // &size.cx
481 PLONG plcy) // &size.cy
482 {
483 PCURICON_OBJECT CurIcon;
484 NTSTATUS Status = STATUS_SUCCESS;
485 BOOL bRet = FALSE;
486
487 TRACE("Enter NtUserGetIconSize\n");
488 UserEnterExclusive();
489
490 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
491 {
492 goto cleanup;
493 }
494
495 _SEH2_TRY
496 {
497 ProbeForWrite(plcx, sizeof(LONG), 1);
498 RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
499 ProbeForWrite(plcy, sizeof(LONG), 1);
500 RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
501 }
502 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
503 {
504 Status = _SEH2_GetExceptionCode();
505 }
506 _SEH2_END
507
508 if (NT_SUCCESS(Status))
509 bRet = TRUE;
510 else
511 SetLastNtError(Status); // Maybe not, test this
512
513 UserDereferenceObject(CurIcon);
514
515 cleanup:
516 TRACE("Leave NtUserGetIconSize, ret=%i\n", bRet);
517 UserLeave();
518 return bRet;
519 }
520
521
522 /*
523 * @implemented
524 */
525 BOOL
526 APIENTRY
527 NtUserGetCursorInfo(
528 PCURSORINFO pci)
529 {
530 CURSORINFO SafeCi;
531 PSYSTEM_CURSORINFO CurInfo;
532 NTSTATUS Status = STATUS_SUCCESS;
533 PCURICON_OBJECT CurIcon;
534 BOOL Ret = FALSE;
535 DECLARE_RETURN(BOOL);
536
537 TRACE("Enter NtUserGetCursorInfo\n");
538 UserEnterExclusive();
539
540 CurInfo = IntGetSysCursorInfo();
541 CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
542
543 SafeCi.cbSize = sizeof(CURSORINFO);
544 SafeCi.flags = ((CurIcon && CurInfo->ShowingCursor >= 0) ? CURSOR_SHOWING : 0);
545 SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
546
547 SafeCi.ptScreenPos = gpsi->ptCursor;
548
549 _SEH2_TRY
550 {
551 if (pci->cbSize == sizeof(CURSORINFO))
552 {
553 ProbeForWrite(pci, sizeof(CURSORINFO), 1);
554 RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
555 Ret = TRUE;
556 }
557 else
558 {
559 EngSetLastError(ERROR_INVALID_PARAMETER);
560 }
561 }
562 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
563 {
564 Status = _SEH2_GetExceptionCode();
565 }
566 _SEH2_END;
567 if (!NT_SUCCESS(Status))
568 {
569 SetLastNtError(Status);
570 }
571
572 RETURN(Ret);
573
574 CLEANUP:
575 TRACE("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
576 UserLeave();
577 END_CLEANUP;
578 }
579
580 BOOL
581 APIENTRY
582 UserClipCursor(
583 RECTL *prcl)
584 {
585 /* FIXME: Check if process has WINSTA_WRITEATTRIBUTES */
586 PSYSTEM_CURSORINFO CurInfo;
587 PWND DesktopWindow = NULL;
588
589 CurInfo = IntGetSysCursorInfo();
590
591 DesktopWindow = UserGetDesktopWindow();
592
593 if (prcl != NULL && DesktopWindow != NULL)
594 {
595 if (prcl->right < prcl->left || prcl->bottom < prcl->top)
596 {
597 EngSetLastError(ERROR_INVALID_PARAMETER);
598 return FALSE;
599 }
600
601 CurInfo->bClipped = TRUE;
602
603 /* Set nw cliping region. Note: we can't use RECTL_bIntersectRect because
604 it sets rect to 0 0 0 0 when it's empty. For more info see monitor winetest */
605 CurInfo->rcClip.left = max(prcl->left, DesktopWindow->rcWindow.left);
606 CurInfo->rcClip.right = min(prcl->right, DesktopWindow->rcWindow.right);
607 if (CurInfo->rcClip.right < CurInfo->rcClip.left)
608 CurInfo->rcClip.right = CurInfo->rcClip.left;
609
610 CurInfo->rcClip.top = max(prcl->top, DesktopWindow->rcWindow.top);
611 CurInfo->rcClip.bottom = min(prcl->bottom, DesktopWindow->rcWindow.bottom);
612 if (CurInfo->rcClip.bottom < CurInfo->rcClip.top)
613 CurInfo->rcClip.bottom = CurInfo->rcClip.top;
614
615 /* Make sure cursor is in clipping region */
616 UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, 0, 0, FALSE);
617 }
618 else
619 {
620 CurInfo->bClipped = FALSE;
621 }
622
623 return TRUE;
624 }
625
626 /*
627 * @implemented
628 */
629 BOOL
630 APIENTRY
631 NtUserClipCursor(
632 RECTL *prcl)
633 {
634 RECTL rclLocal;
635 BOOL bResult;
636
637 if (prcl)
638 {
639 _SEH2_TRY
640 {
641 /* Probe and copy rect */
642 ProbeForRead(prcl, sizeof(RECTL), 1);
643 rclLocal = *prcl;
644 }
645 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
646 {
647 EngSetLastError(ERROR_INVALID_PARAMETER);
648 _SEH2_YIELD(return FALSE;)
649 }
650 _SEH2_END
651
652 prcl = &rclLocal;
653 }
654
655 UserEnterExclusive();
656
657 /* Call the internal function */
658 bResult = UserClipCursor(prcl);
659
660 UserLeave();
661
662 return bResult;
663 }
664
665
666 /*
667 * @implemented
668 */
669 BOOL
670 APIENTRY
671 NtUserDestroyCursor(
672 _In_ HANDLE hCurIcon,
673 _In_ BOOL bForce)
674 {
675 PCURICON_OBJECT CurIcon;
676 BOOL ret;
677 DECLARE_RETURN(BOOL);
678
679 TRACE("Enter NtUserDestroyCursorIcon\n");
680 UserEnterExclusive();
681
682 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
683 {
684 RETURN(FALSE);
685 }
686
687 ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process());
688 /* Note: IntDestroyCurIconObject will remove our reference for us! */
689
690 RETURN(ret);
691
692 CLEANUP:
693 TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
694 UserLeave();
695 END_CLEANUP;
696 }
697
698
699 /*
700 * @implemented
701 */
702 HICON
703 APIENTRY
704 NtUserFindExistingCursorIcon(
705 HMODULE hModule,
706 HRSRC hRsrc,
707 LONG cx,
708 LONG cy)
709 {
710 PCURICON_OBJECT CurIcon;
711 HANDLE Ret = (HANDLE)0;
712 DECLARE_RETURN(HICON);
713
714 TRACE("Enter NtUserFindExistingCursorIcon\n");
715 UserEnterExclusive();
716
717 CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy);
718 if (CurIcon)
719 {
720 Ret = CurIcon->Self;
721
722 // IntReleaseCurIconObject(CurIcon); // FIXME: Is this correct? Does IntFindExistingCurIconObject add a ref?
723 RETURN(Ret);
724 }
725
726 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
727 RETURN((HANDLE)0);
728
729 CLEANUP:
730 TRACE("Leave NtUserFindExistingCursorIcon, ret=%p\n",_ret_);
731 UserLeave();
732 END_CLEANUP;
733 }
734
735
736 /*
737 * @implemented
738 */
739 BOOL
740 APIENTRY
741 NtUserGetClipCursor(
742 RECTL *lpRect)
743 {
744 /* FIXME: Check if process has WINSTA_READATTRIBUTES */
745 PSYSTEM_CURSORINFO CurInfo;
746 RECTL Rect;
747 NTSTATUS Status;
748 DECLARE_RETURN(BOOL);
749
750 TRACE("Enter NtUserGetClipCursor\n");
751 UserEnterExclusive();
752
753 if (!lpRect)
754 RETURN(FALSE);
755
756 CurInfo = IntGetSysCursorInfo();
757 if (CurInfo->bClipped)
758 {
759 Rect = CurInfo->rcClip;
760 }
761 else
762 {
763 Rect.left = 0;
764 Rect.top = 0;
765 Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
766 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
767 }
768
769 Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT));
770 if (!NT_SUCCESS(Status))
771 {
772 SetLastNtError(Status);
773 RETURN(FALSE);
774 }
775
776 RETURN(TRUE);
777
778 CLEANUP:
779 TRACE("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
780 UserLeave();
781 END_CLEANUP;
782 }
783
784
785 /*
786 * @implemented
787 */
788 HCURSOR
789 APIENTRY
790 NtUserSetCursor(
791 HCURSOR hCursor)
792 {
793 PCURICON_OBJECT pcurOld, pcurNew;
794 HCURSOR hOldCursor = NULL;
795
796 TRACE("Enter NtUserSetCursor\n");
797 UserEnterExclusive();
798
799 if (hCursor)
800 {
801 pcurNew = UserGetCurIconObject(hCursor);
802 if (!pcurNew)
803 {
804 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
805 goto leave;
806 }
807 }
808 else
809 {
810 pcurNew = NULL;
811 }
812
813 pcurOld = UserSetCursor(pcurNew, FALSE);
814 if (pcurOld)
815 {
816 hOldCursor = (HCURSOR)pcurOld->Self;
817 UserDereferenceObject(pcurOld);
818 }
819
820 leave:
821 UserLeave();
822 return hOldCursor;
823 }
824
825
826 /*
827 * @implemented
828 */
829 BOOL
830 APIENTRY
831 NtUserSetCursorContents(
832 HANDLE hCurIcon,
833 PICONINFO UnsafeIconInfo)
834 {
835 PCURICON_OBJECT CurIcon;
836 ICONINFO IconInfo;
837 PSURFACE psurfBmp;
838 NTSTATUS Status;
839 BOOL Ret = FALSE;
840 DECLARE_RETURN(BOOL);
841
842 TRACE("Enter NtUserSetCursorContents\n");
843 UserEnterExclusive();
844
845 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
846 {
847 RETURN(FALSE);
848 }
849
850 /* Copy fields */
851 Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
852 if (!NT_SUCCESS(Status))
853 {
854 SetLastNtError(Status);
855 goto done;
856 }
857
858 /* Delete old bitmaps */
859 if ((CurIcon->IconInfo.hbmColor)
860 && (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor))
861 {
862 GreDeleteObject(CurIcon->IconInfo.hbmColor);
863 }
864 if ((CurIcon->IconInfo.hbmMask)
865 && CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
866 {
867 GreDeleteObject(CurIcon->IconInfo.hbmMask);
868 }
869
870 /* Copy new IconInfo field */
871 CurIcon->IconInfo = IconInfo;
872
873 if (CurIcon->IconInfo.hbmColor)
874 {
875 psurfBmp = SURFACE_ShareLockSurface(CurIcon->IconInfo.hbmColor);
876 if (!psurfBmp)
877 goto done;
878
879 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
880 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
881 SURFACE_ShareUnlockSurface(psurfBmp);
882 GreSetObjectOwner(CurIcon->IconInfo.hbmColor, GDI_OBJ_HMGR_PUBLIC);
883 }
884 else
885 {
886 psurfBmp = SURFACE_ShareLockSurface(CurIcon->IconInfo.hbmMask);
887 if (!psurfBmp)
888 goto done;
889
890 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
891 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
892
893 SURFACE_ShareUnlockSurface(psurfBmp);
894 }
895 GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
896
897 Ret = TRUE;
898
899 done:
900
901 if (CurIcon)
902 {
903 UserDereferenceObject(CurIcon);
904 }
905 RETURN(Ret);
906
907 CLEANUP:
908 TRACE("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
909 UserLeave();
910 END_CLEANUP;
911 }
912
913
914 /*
915 * @implemented
916 */
917 #if 0
918 BOOL
919 APIENTRY
920 NtUserSetCursorIconData(
921 HANDLE Handle,
922 HMODULE hModule,
923 PUNICODE_STRING pstrResName,
924 PICONINFO pIconInfo)
925 {
926 PCURICON_OBJECT CurIcon;
927 PSURFACE psurfBmp;
928 NTSTATUS Status = STATUS_SUCCESS;
929 BOOL Ret = FALSE;
930 DECLARE_RETURN(BOOL);
931
932 TRACE("Enter NtUserSetCursorIconData\n");
933 UserEnterExclusive();
934
935 if (!(CurIcon = UserGetCurIconObject(Handle)))
936 {
937 RETURN(FALSE);
938 }
939
940 CurIcon->hModule = hModule;
941 CurIcon->hRsrc = NULL; //hRsrc;
942 CurIcon->hGroupRsrc = NULL; //hGroupRsrc;
943
944 _SEH2_TRY
945 {
946 ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
947 RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO));
948
949 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(pIconInfo->hbmMask);
950 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(pIconInfo->hbmColor);
951
952 if (CurIcon->IconInfo.hbmColor)
953 {
954 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
955 {
956 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
957 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
958 SURFACE_UnlockSurface(psurfBmp);
959 GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
960 }
961 }
962 if (CurIcon->IconInfo.hbmMask)
963 {
964 if (CurIcon->IconInfo.hbmColor == NULL)
965 {
966 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
967 {
968 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
969 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
970 SURFACE_UnlockSurface(psurfBmp);
971 }
972 }
973 GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
974 }
975 }
976 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
977 {
978 Status = _SEH2_GetExceptionCode();
979 }
980 _SEH2_END
981
982 if (!NT_SUCCESS(Status))
983 SetLastNtError(Status);
984 else
985 Ret = TRUE;
986
987 UserDereferenceObject(CurIcon);
988 RETURN(Ret);
989
990 CLEANUP:
991 TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
992 UserLeave();
993 END_CLEANUP;
994 }
995 #else
996 BOOL
997 APIENTRY
998 NtUserSetCursorIconData(
999 HANDLE hCurIcon,
1000 PBOOL fIcon,
1001 POINT *Hotspot,
1002 HMODULE hModule,
1003 HRSRC hRsrc,
1004 HRSRC hGroupRsrc)
1005 {
1006 PCURICON_OBJECT CurIcon;
1007 NTSTATUS Status;
1008 POINT SafeHotspot;
1009 BOOL Ret = FALSE;
1010 DECLARE_RETURN(BOOL);
1011
1012 TRACE("Enter NtUserSetCursorIconData\n");
1013 UserEnterExclusive();
1014
1015 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1016 {
1017 RETURN(FALSE);
1018 }
1019
1020 CurIcon->hModule = hModule;
1021 CurIcon->hRsrc = hRsrc;
1022 CurIcon->hGroupRsrc = hGroupRsrc;
1023
1024 /* Copy fields */
1025 if (fIcon)
1026 {
1027 Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
1028 if (!NT_SUCCESS(Status))
1029 {
1030 SetLastNtError(Status);
1031 goto done;
1032 }
1033 }
1034 else
1035 {
1036 if (!Hotspot)
1037 Ret = TRUE;
1038 }
1039
1040 if (Hotspot)
1041 {
1042 Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
1043 if (NT_SUCCESS(Status))
1044 {
1045 CurIcon->IconInfo.xHotspot = SafeHotspot.x;
1046 CurIcon->IconInfo.yHotspot = SafeHotspot.y;
1047
1048 Ret = TRUE;
1049 }
1050 else
1051 SetLastNtError(Status);
1052 }
1053
1054 if (!fIcon && !Hotspot)
1055 {
1056 Ret = TRUE;
1057 }
1058
1059 done:
1060 if(Ret)
1061 {
1062 /* This icon is shared now */
1063 GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
1064 if(CurIcon->IconInfo.hbmColor)
1065 {
1066 GreSetObjectOwner(CurIcon->IconInfo.hbmColor, GDI_OBJ_HMGR_PUBLIC);
1067 }
1068 }
1069 UserDereferenceObject(CurIcon);
1070 RETURN(Ret);
1071
1072
1073 CLEANUP:
1074 TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1075 UserLeave();
1076 END_CLEANUP;
1077 }
1078 #endif
1079
1080 /* Mostly inspired from wine code.
1081 * We use low level functions because:
1082 * - at this point, the icon bitmap could have a different bit depth than the DC,
1083 * making it thus impossible to use NtCreateCompatibleDC and selecting the bitmap.
1084 * This happens after a mode setting change.
1085 * - it avoids massive GDI objects locking when only the destination surface needs it.
1086 * - It makes (small) performance gains.
1087 */
1088 BOOL
1089 UserDrawIconEx(
1090 HDC hDc,
1091 INT xLeft,
1092 INT yTop,
1093 PCURICON_OBJECT pIcon,
1094 INT cxWidth,
1095 INT cyHeight,
1096 UINT istepIfAniCur,
1097 HBRUSH hbrFlickerFreeDraw,
1098 UINT diFlags)
1099 {
1100 PSURFACE psurfDest, psurfMask, psurfColor, psurfOffScreen;
1101 PDC pdc = NULL;
1102 BOOL Ret = FALSE;
1103 HBITMAP hbmMask, hbmColor;
1104 BOOL bOffScreen, bAlpha = FALSE;
1105 RECTL rcDest, rcSrc;
1106 CLIPOBJ* pdcClipObj = NULL;
1107 EXLATEOBJ exlo;
1108
1109 /* Stupid case */
1110 if((diFlags & DI_NORMAL) == 0)
1111 {
1112 ERR("DrawIconEx called without mask or color bitmap to draw.\n");
1113 return FALSE;
1114 }
1115
1116 hbmMask = pIcon->IconInfo.hbmMask;
1117 hbmColor = pIcon->IconInfo.hbmColor;
1118
1119 if (istepIfAniCur)
1120 ERR("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1121
1122 /*
1123 * Get our objects.
1124 * Shared locks are enough, we are only reading those bitmaps
1125 */
1126 psurfMask = SURFACE_ShareLockSurface(hbmMask);
1127 if(psurfMask == NULL)
1128 {
1129 ERR("Unable to lock the mask surface.\n");
1130 return FALSE;
1131 }
1132
1133 /* Color bitmap is not mandatory */
1134 if(hbmColor == NULL)
1135 {
1136 /* But then the mask bitmap must have the information in it's bottom half */
1137 ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->Size.cy);
1138 psurfColor = NULL;
1139 }
1140 else if ((psurfColor = SURFACE_ShareLockSurface(hbmColor)) == NULL)
1141 {
1142 ERR("Unable to lock the color bitmap.\n");
1143 SURFACE_ShareUnlockSurface(psurfMask);
1144 return FALSE;
1145 }
1146
1147 /* Set source rect */
1148 RECTL_vSetRect(&rcSrc, 0, 0, pIcon->Size.cx, pIcon->Size.cy);
1149
1150 /* Check for alpha */
1151 if (psurfColor &&
1152 (psurfColor->SurfObj.iBitmapFormat == BMF_32BPP) &&
1153 (diFlags & DI_IMAGE))
1154 {
1155 PFN_DIB_GetPixel fnSource_GetPixel = NULL;
1156 INT i, j;
1157
1158 /* In order to correctly display 32 bit icons Windows first scans the image,
1159 because information about transparency is not stored in any image's headers */
1160 fnSource_GetPixel = DibFunctionsForBitmapFormat[BMF_32BPP].DIB_GetPixel;
1161 for (i = 0; i < psurfColor->SurfObj.sizlBitmap.cx; i++)
1162 {
1163 for (j = 0; j < psurfColor->SurfObj.sizlBitmap.cy; j++)
1164 {
1165 bAlpha = ((BYTE)(fnSource_GetPixel(&psurfColor->SurfObj, i, j) >> 24) & 0xff);
1166 if (bAlpha)
1167 break;
1168 }
1169 if (bAlpha)
1170 break;
1171 }
1172 }
1173
1174 /* Fix width parameter, if needed */
1175 if (!cxWidth)
1176 {
1177 if(diFlags & DI_DEFAULTSIZE)
1178 cxWidth = pIcon->IconInfo.fIcon ?
1179 UserGetSystemMetrics(SM_CXICON) : UserGetSystemMetrics(SM_CXCURSOR);
1180 else
1181 cxWidth = pIcon->Size.cx;
1182 }
1183
1184 /* Fix height parameter, if needed */
1185 if (!cyHeight)
1186 {
1187 if(diFlags & DI_DEFAULTSIZE)
1188 cyHeight = pIcon->IconInfo.fIcon ?
1189 UserGetSystemMetrics(SM_CYICON) : UserGetSystemMetrics(SM_CYCURSOR);
1190 else
1191 cyHeight = pIcon->Size.cy;
1192 }
1193
1194 /* Should we render off-screen? */
1195 bOffScreen = hbrFlickerFreeDraw && (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH);
1196
1197 if (bOffScreen)
1198 {
1199 /* Yes: Allocate and paint the offscreen surface */
1200 EBRUSHOBJ eboFill;
1201 PBRUSH pbrush = BRUSH_ShareLockBrush(hbrFlickerFreeDraw);
1202
1203 TRACE("Performing off-screen rendering.\n");
1204
1205 if(!pbrush)
1206 {
1207 ERR("Failed to get brush object.\n");
1208 SURFACE_ShareUnlockSurface(psurfMask);
1209 if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
1210 return FALSE;
1211 }
1212
1213 if (!psurfColor)
1214 {
1215 ERR("Attention HAX FIX API DrawIconEx TEST Line 37: psurfColor is NULL going with Mask!\n");
1216 psurfColor = SURFACE_ShareLockSurface(hbmMask);
1217 }
1218
1219 psurfOffScreen = SURFACE_AllocSurface(STYPE_BITMAP,
1220 cxWidth, cyHeight, psurfColor->SurfObj.iBitmapFormat,
1221 0, 0, NULL);
1222 if(!psurfOffScreen)
1223 {
1224 ERR("Failed to allocate the off-screen surface.\n");
1225 SURFACE_ShareUnlockSurface(psurfMask);
1226 if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
1227 BRUSH_ShareUnlockBrush(pbrush);
1228 return FALSE;
1229 }
1230
1231 /* Paint the brush */
1232 EBRUSHOBJ_vInit(&eboFill, pbrush, psurfOffScreen, 0x00FFFFFF, 0, NULL);
1233 RECTL_vSetRect(&rcDest, 0, 0, cxWidth, cyHeight);
1234
1235 Ret = IntEngBitBlt(&psurfOffScreen->SurfObj,
1236 NULL,
1237 NULL,
1238 NULL,
1239 NULL,
1240 &rcDest,
1241 NULL,
1242 NULL,
1243 &eboFill.BrushObject,
1244 &pbrush->ptOrigin,
1245 ROP4_PATCOPY);
1246
1247 /* Clean up everything */
1248 EBRUSHOBJ_vCleanup(&eboFill);
1249 BRUSH_ShareUnlockBrush(pbrush);
1250
1251 if(!Ret)
1252 {
1253 ERR("Failed to paint the off-screen surface.\n");
1254 SURFACE_ShareUnlockSurface(psurfMask);
1255 if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
1256 GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject);
1257 return FALSE;
1258 }
1259
1260 /* We now have our destination surface */
1261 psurfDest = psurfOffScreen;
1262 }
1263 else
1264 {
1265 /* We directly draw to the DC */
1266 TRACE("Performing on screen rendering.\n");
1267
1268 psurfOffScreen = NULL;
1269 pdc = DC_LockDc(hDc);
1270 if(!pdc)
1271 {
1272 ERR("Could not lock the destination DC.\n");
1273 SURFACE_ShareUnlockSurface(psurfMask);
1274 if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
1275 return FALSE;
1276 }
1277 /* Calculate destination rectangle */
1278 RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
1279 IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
1280 RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
1281
1282 /* Prepare the underlying surface */
1283 DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL);
1284
1285 /* Get the clip object */
1286 pdcClipObj = &pdc->co.ClipObj;
1287
1288 /* We now have our destination surface and rectangle */
1289 psurfDest = pdc->dclevel.pSurface;
1290
1291 if(psurfDest == NULL)
1292 {
1293 /* Empty DC */
1294 DC_vFinishBlit(pdc, NULL);
1295 DC_UnlockDc(pdc);
1296 SURFACE_ShareUnlockSurface(psurfMask);
1297 if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
1298 return FALSE;
1299 }
1300 }
1301
1302 /* Now do the rendering */
1303 if(bAlpha && (diFlags & DI_IMAGE))
1304 {
1305 BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
1306 BYTE Alpha;
1307 INT i, j;
1308 PSURFACE psurf = NULL;
1309 PBYTE ptr ;
1310 HBITMAP hsurfCopy = NULL;
1311
1312 hsurfCopy = BITMAP_CopyBitmap(hbmColor);
1313 if(!hsurfCopy)
1314 {
1315 ERR("BITMAP_CopyBitmap failed!");
1316 goto CleanupAlpha;
1317 }
1318
1319 psurf = SURFACE_ShareLockSurface(hsurfCopy);
1320 if(!psurf)
1321 {
1322 ERR("SURFACE_LockSurface failed!\n");
1323 goto CleanupAlpha;
1324 }
1325
1326 /* Premultiply with the alpha channel value */
1327 for (i = 0; i < psurf->SurfObj.sizlBitmap.cy; i++)
1328 {
1329 ptr = (PBYTE)psurf->SurfObj.pvScan0 + i*psurf->SurfObj.lDelta;
1330 for (j = 0; j < psurf->SurfObj.sizlBitmap.cx; j++)
1331 {
1332 Alpha = ptr[3];
1333 ptr[0] = (ptr[0] * Alpha) / 0xff;
1334 ptr[1] = (ptr[1] * Alpha) / 0xff;
1335 ptr[2] = (ptr[2] * Alpha) / 0xff;
1336
1337 ptr += 4;
1338 }
1339 }
1340
1341 /* Initialize color translation object */
1342 EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xFFFFFFFF, 0xFFFFFFFF, 0);
1343
1344 /* Now do it */
1345 Ret = IntEngAlphaBlend(&psurfDest->SurfObj,
1346 &psurf->SurfObj,
1347 pdcClipObj,
1348 &exlo.xlo,
1349 &rcDest,
1350 &rcSrc,
1351 &blendobj);
1352
1353 EXLATEOBJ_vCleanup(&exlo);
1354
1355 CleanupAlpha:
1356 if(psurf) SURFACE_ShareUnlockSurface(psurf);
1357 if(hsurfCopy) NtGdiDeleteObjectApp(hsurfCopy);
1358 if(Ret) goto done;
1359 ERR("NtGdiAlphaBlend failed!\n");
1360 }
1361
1362 if (diFlags & DI_MASK)
1363 {
1364 DWORD rop4 = (diFlags & DI_IMAGE) ? ROP4_SRCAND : ROP4_SRCCOPY;
1365
1366 EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
1367
1368 Ret = IntEngStretchBlt(&psurfDest->SurfObj,
1369 &psurfMask->SurfObj,
1370 NULL,
1371 pdcClipObj,
1372 &exlo.xlo,
1373 NULL,
1374 &rcDest,
1375 &rcSrc,
1376 NULL,
1377 NULL,
1378 NULL,
1379 rop4);
1380
1381 EXLATEOBJ_vCleanup(&exlo);
1382
1383 if(!Ret)
1384 {
1385 ERR("Failed to mask the bitmap data.\n");
1386 goto Cleanup;
1387 }
1388 }
1389
1390 if(diFlags & DI_IMAGE)
1391 {
1392 if (psurfColor)
1393 {
1394 DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY ;
1395
1396 EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0);
1397
1398 Ret = IntEngStretchBlt(&psurfDest->SurfObj,
1399 &psurfColor->SurfObj,
1400 NULL,
1401 pdcClipObj,
1402 &exlo.xlo,
1403 NULL,
1404 &rcDest,
1405 &rcSrc,
1406 NULL,
1407 NULL,
1408 NULL,
1409 rop4);
1410
1411 EXLATEOBJ_vCleanup(&exlo);
1412
1413 if(!Ret)
1414 {
1415 ERR("Failed to render the icon bitmap.\n");
1416 goto Cleanup;
1417 }
1418 }
1419 else
1420 {
1421 /* Mask bitmap holds the information in its bottom half */
1422 DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY;
1423 RECTL_vOffsetRect(&rcSrc, 0, pIcon->Size.cy);
1424
1425 EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
1426
1427 Ret = IntEngStretchBlt(&psurfDest->SurfObj,
1428 &psurfMask->SurfObj,
1429 NULL,
1430 pdcClipObj,
1431 &exlo.xlo,
1432 NULL,
1433 &rcDest,
1434 &rcSrc,
1435 NULL,
1436 NULL,
1437 NULL,
1438 rop4);
1439
1440 EXLATEOBJ_vCleanup(&exlo);
1441
1442 if(!Ret)
1443 {
1444 ERR("Failed to render the icon bitmap.\n");
1445 goto Cleanup;
1446 }
1447 }
1448 }
1449
1450 done:
1451 /* We're done. Was it a double buffered draw ? */
1452 if(bOffScreen)
1453 {
1454 /* Yes. Draw it back to our DC */
1455 POINTL ptSrc = {0, 0};
1456 pdc = DC_LockDc(hDc);
1457 if(!pdc)
1458 {
1459 ERR("Could not lock the destination DC.\n");
1460 return FALSE;
1461 }
1462 /* Calculate destination rectangle */
1463 RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
1464 IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
1465 RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
1466
1467 /* Prepare the underlying surface */
1468 DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL);
1469
1470 /* Get the clip object */
1471 pdcClipObj = &pdc->co.ClipObj;
1472
1473 /* We now have our destination surface and rectangle */
1474 psurfDest = pdc->dclevel.pSurface;
1475 if(!psurfDest)
1476 {
1477 /* So, you did all of this for an empty DC. */
1478 DC_UnlockDc(pdc);
1479 goto Cleanup2;
1480 }
1481
1482 /* Color translation */
1483 EXLATEOBJ_vInitialize(&exlo, psurfOffScreen->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0);
1484
1485 /* Blt it! */
1486 Ret = IntEngBitBlt(&psurfDest->SurfObj,
1487 &psurfOffScreen->SurfObj,
1488 NULL,
1489 pdcClipObj,
1490 &exlo.xlo,
1491 &rcDest,
1492 &ptSrc,
1493 NULL,
1494 NULL,
1495 NULL,
1496 ROP4_SRCCOPY);
1497
1498 EXLATEOBJ_vCleanup(&exlo);
1499 }
1500 Cleanup:
1501 if(pdc)
1502 {
1503 DC_vFinishBlit(pdc, NULL);
1504 DC_UnlockDc(pdc);
1505 }
1506
1507 Cleanup2:
1508 /* Delete off screen rendering surface */
1509 if(psurfOffScreen)
1510 GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject);
1511
1512 /* Unlock other surfaces */
1513 SURFACE_ShareUnlockSurface(psurfMask);
1514 if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
1515
1516 return Ret;
1517 }
1518
1519 /*
1520 * @implemented
1521 */
1522 BOOL
1523 APIENTRY
1524 NtUserDrawIconEx(
1525 HDC hdc,
1526 int xLeft,
1527 int yTop,
1528 HICON hIcon,
1529 int cxWidth,
1530 int cyHeight,
1531 UINT istepIfAniCur,
1532 HBRUSH hbrFlickerFreeDraw,
1533 UINT diFlags,
1534 BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32!
1535 PVOID pDIXData)
1536 {
1537 PCURICON_OBJECT pIcon;
1538 BOOL Ret;
1539
1540 TRACE("Enter NtUserDrawIconEx\n");
1541 UserEnterExclusive();
1542
1543 if (!(pIcon = UserGetCurIconObject(hIcon)))
1544 {
1545 ERR("UserGetCurIconObject() failed!\n");
1546 UserLeave();
1547 return FALSE;
1548 }
1549
1550 Ret = UserDrawIconEx(hdc,
1551 xLeft,
1552 yTop,
1553 pIcon,
1554 cxWidth,
1555 cyHeight,
1556 istepIfAniCur,
1557 hbrFlickerFreeDraw,
1558 diFlags);
1559
1560 UserDereferenceObject(pIcon);
1561
1562 UserLeave();
1563 return Ret;
1564 }
1565
1566 /*
1567 * @unimplemented
1568 */
1569 HCURSOR
1570 NTAPI
1571 NtUserGetCursorFrameInfo(
1572 HCURSOR hCursor,
1573 DWORD istep,
1574 INT* rate_jiffies,
1575 DWORD* num_steps)
1576 {
1577 STUB
1578
1579 return 0;
1580 }
1581
1582 /* EOF */