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