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