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