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