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