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