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