Evgeniy Boltik <bstsoft AT narod DOT ru>
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / cursoricon.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 /*
21 * We handle two types of cursors/icons:
22 * - Private
23 * Loaded without LR_SHARED flag
24 * Private to a process
25 * Can be deleted by calling NtDestroyCursorIcon()
26 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
27 * - Shared
28 * Loaded with LR_SHARED flag
29 * Possibly shared by multiple processes
30 * Immune to NtDestroyCursorIcon()
31 * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
32 * There's a M:N relationship between processes and (shared) cursor/icons.
33 * A process can have multiple cursor/icons and a cursor/icon can be used
34 * by multiple processes. To keep track of this we keep a list of all
35 * cursor/icons (CurIconList) and per cursor/icon we keep a list of
36 * CURICON_PROCESS structs starting at CurIcon->ProcessList.
37 */
38
39 #include <w32k.h>
40
41 #define NDEBUG
42 #include <debug.h>
43
44 static PAGED_LOOKASIDE_LIST gProcessLookasideList;
45 static LIST_ENTRY gCurIconList;
46
47 BOOL FASTCALL
48 IntGetCursorLocation(PWINSTATION_OBJECT WinSta, POINT *loc)
49 {
50 loc->x = gpsi->ptCursor.x;
51 loc->y = gpsi->ptCursor.y;
52
53 return TRUE;
54 }
55
56 /* This function creates a reference for the object! */
57 PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
58 {
59 PCURICON_OBJECT CurIcon;
60
61 if (!hCurIcon)
62 {
63 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
64 return NULL;
65 }
66
67 CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, otCursorIcon);
68 if (!CurIcon)
69 {
70 /* we never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
71 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
72 return NULL;
73 }
74
75 ASSERT(USER_BODY_TO_HEADER(CurIcon)->RefCount >= 1);
76 return CurIcon;
77 }
78
79
80 #define COLORCURSORS_ALLOWED FALSE
81 HCURSOR FASTCALL
82 IntSetCursor(PWINSTATION_OBJECT WinSta, PCURICON_OBJECT NewCursor,
83 BOOL ForceChange)
84 {
85 SURFACE *psurf;
86 SURFOBJ *pso;
87 PDEVINFO DevInfo;
88 PSURFACE MaskBmpObj = NULL;
89 PSYSTEM_CURSORINFO CurInfo;
90 PCURICON_OBJECT OldCursor;
91 HCURSOR Ret = (HCURSOR)0;
92 HBITMAP dcbmp;
93 HBITMAP hMask = 0;
94 SURFOBJ *soMask = NULL, *soColor = NULL;
95 XLATEOBJ *XlateObj = NULL;
96 HDC Screen;
97 PDC dc;
98
99 CurInfo = IntGetSysCursorInfo(WinSta);
100 OldCursor = CurInfo->CurrentCursorObject;
101 if (OldCursor)
102 {
103 Ret = (HCURSOR)OldCursor->Self;
104 }
105
106 if (!ForceChange && OldCursor == NewCursor)
107 {
108 return Ret;
109 }
110
111 if(!(Screen = IntGetScreenDC()))
112 {
113 return (HCURSOR)0;
114 }
115 /* FIXME use the desktop's HDC instead of using ScreenDeviceContext */
116 dc = DC_LockDc(Screen);
117
118 if (!dc)
119 {
120 return Ret;
121 }
122 dcbmp = dc->w.hBitmap;
123 DevInfo = (PDEVINFO)&((GDIDEVICE *)dc->pPDev)->DevInfo;
124 DC_UnlockDc(dc);
125
126 psurf = SURFACE_LockSurface(dcbmp);
127 if (!psurf)
128 return (HCURSOR)0;
129 pso = &psurf->SurfObj;
130
131 if (!NewCursor)
132 {
133 if (CurInfo->CurrentCursorObject || ForceChange)
134 {
135 if (CurInfo->CurrentCursorObject)
136 {
137 UserDereferenceObject(CurInfo->CurrentCursorObject);
138 if (CurInfo->ShowingCursor)
139 {
140 DPRINT1("Removing pointer!\n");
141 /* Remove the cursor if it was displayed */
142 IntEngMovePointer(pso, -1, -1, &GDIDEV(pso)->Pointer.Exclude);
143 }
144 }
145
146 GDIDEV(pso)->Pointer.Status = SPS_ACCEPT_NOEXCLUDE;
147
148 CurInfo->CurrentCursorObject = NewCursor; /* i.e. CurrentCursorObject = NULL */
149 CurInfo->ShowingCursor = 0;
150 }
151
152 SURFACE_UnlockSurface(psurf);
153 return Ret;
154 }
155
156 /* TODO: Fixme. Logic is screwed above */
157
158 MaskBmpObj = SURFACE_LockSurface(NewCursor->IconInfo.hbmMask);
159 if (MaskBmpObj)
160 {
161 const int maskBpp = BitsPerFormat(MaskBmpObj->SurfObj.iBitmapFormat);
162 SURFACE_UnlockSurface(MaskBmpObj);
163 if (maskBpp != 1)
164 {
165 DPRINT1("SetCursor: The Mask bitmap must have 1BPP!\n");
166 SURFACE_UnlockSurface(psurf);
167 return Ret;
168 }
169
170 if ((DevInfo->flGraphicsCaps2 & GCAPS2_ALPHACURSOR) &&
171 pso->iBitmapFormat >= BMF_16BPP &&
172 pso->iBitmapFormat <= BMF_32BPP &&
173 NewCursor->Shadow && COLORCURSORS_ALLOWED)
174 {
175 /* FIXME - Create a color pointer, only 32bit bitmap, set alpha bits!
176 Do not pass a mask bitmap to DrvSetPointerShape()!
177 Create a XLATEOBJ that describes the colors of the bitmap. */
178 DPRINT1("SetCursor: (Colored) alpha cursors are not supported!\n");
179 }
180 else
181 {
182 if(NewCursor->IconInfo.hbmColor
183 && COLORCURSORS_ALLOWED)
184 {
185 /* FIXME - Create a color pointer, create only one 32bit bitmap!
186 Do not pass a mask bitmap to DrvSetPointerShape()!
187 Create a XLATEOBJ that describes the colors of the bitmap.
188 (16bit bitmaps are propably allowed) */
189 DPRINT1("SetCursor: Cursors with colors are not supported!\n");
190 }
191 else
192 {
193 MaskBmpObj = SURFACE_LockSurface(NewCursor->IconInfo.hbmMask);
194 if(MaskBmpObj)
195 {
196 RECTL DestRect = {0, 0, MaskBmpObj->SurfObj.sizlBitmap.cx, MaskBmpObj->SurfObj.sizlBitmap.cy};
197 POINTL SourcePoint = {0, 0};
198
199 /*
200 * NOTE: For now we create the cursor in top-down bitmap,
201 * because VMware driver rejects it otherwise. This should
202 * be fixed later.
203 */
204 hMask = EngCreateBitmap(
205 MaskBmpObj->SurfObj.sizlBitmap, abs(MaskBmpObj->SurfObj.lDelta),
206 MaskBmpObj->SurfObj.iBitmapFormat, BMF_TOPDOWN,
207 NULL);
208 if ( !hMask )
209 {
210 SURFACE_UnlockSurface(MaskBmpObj);
211 SURFACE_UnlockSurface(psurf);
212 return (HCURSOR)0;
213 }
214 soMask = EngLockSurface((HSURF)hMask);
215 EngCopyBits(soMask, &MaskBmpObj->SurfObj, NULL, NULL,
216 &DestRect, &SourcePoint);
217 SURFACE_UnlockSurface(MaskBmpObj);
218 }
219 }
220 }
221 CurInfo->ShowingCursor = CURSOR_SHOWING;
222 CurInfo->CurrentCursorObject = NewCursor;
223 UserReferenceObject(NewCursor);
224 }
225 else
226 {
227 CurInfo->ShowingCursor = 0;
228 CurInfo->CurrentCursorObject = NULL;
229 }
230
231 /* OldCursor is not in use anymore */
232 if (OldCursor)
233 {
234 UserDereferenceObject(OldCursor);
235 }
236
237 if (GDIDEVFUNCS(pso).SetPointerShape)
238 {
239 GDIDEV(pso)->Pointer.Status =
240 GDIDEVFUNCS(pso).SetPointerShape(
241 pso, soMask, soColor, XlateObj,
242 NewCursor->IconInfo.xHotspot,
243 NewCursor->IconInfo.yHotspot,
244 gpsi->ptCursor.x,
245 gpsi->ptCursor.y,
246 &(GDIDEV(pso)->Pointer.Exclude),
247 SPS_CHANGE);
248 DPRINT("SetCursor: DrvSetPointerShape() returned %x\n",
249 GDIDEV(pso)->Pointer.Status);
250 }
251 else
252 {
253 GDIDEV(pso)->Pointer.Status = SPS_DECLINE;
254 }
255
256 if(GDIDEV(pso)->Pointer.Status == SPS_DECLINE)
257 {
258 GDIDEV(pso)->Pointer.Status = EngSetPointerShape(
259 pso, soMask, soColor, XlateObj,
260 NewCursor->IconInfo.xHotspot,
261 NewCursor->IconInfo.yHotspot,
262 gpsi->ptCursor.x,
263 gpsi->ptCursor.y,
264 &(GDIDEV(pso)->Pointer.Exclude),
265 SPS_CHANGE);
266 GDIDEV(pso)->Pointer.MovePointer = NULL;
267 }
268 else
269 {
270 GDIDEV(pso)->Pointer.MovePointer = GDIDEVFUNCS(pso).MovePointer;
271 }
272
273 SURFACE_UnlockSurface(psurf);
274 if(hMask)
275 {
276 EngUnlockSurface(soMask);
277 EngDeleteSurface((HSURF)hMask);
278 }
279 if(XlateObj)
280 {
281 EngDeleteXlate(XlateObj);
282 }
283
284 if(GDIDEV(pso)->Pointer.Status == SPS_ERROR)
285 DPRINT1("SetCursor: DrvSetPointerShape() returned SPS_ERROR\n");
286
287 return Ret;
288 }
289
290 BOOL FASTCALL
291 IntSetupCurIconHandles(PWINSTATION_OBJECT WinSta)
292 {
293 ExInitializePagedLookasideList(&gProcessLookasideList,
294 NULL,
295 NULL,
296 0,
297 sizeof(CURICON_PROCESS),
298 TAG_DIB,
299 128);
300 InitializeListHead(&gCurIconList);
301
302 return TRUE;
303 }
304
305 /*
306 * We have to register that this object is in use by the current
307 * process. The only way to do that seems to be to walk the list
308 * of cursor/icon objects starting at W32Process->CursorIconListHead.
309 * If the object is already present in the list, we don't have to do
310 * anything, if it's not present we add it and inc the ProcessCount
311 * in the object. Having to walk the list kind of sucks, but that's
312 * life...
313 */
314 static BOOLEAN FASTCALL
315 ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
316 {
317 PW32PROCESS Win32Process;
318 PCURICON_PROCESS Current;
319
320 Win32Process = PsGetCurrentProcessWin32Process();
321
322 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
323 {
324 if (Current->Process == Win32Process)
325 {
326 /* Already registered for this process */
327 return TRUE;
328 }
329 }
330
331 /* Not registered yet */
332 Current = ExAllocateFromPagedLookasideList(&gProcessLookasideList);
333 if (NULL == Current)
334 {
335 return FALSE;
336 }
337 InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
338 Current->Process = Win32Process;
339
340 return TRUE;
341 }
342
343 PCURICON_OBJECT FASTCALL
344 IntFindExistingCurIconObject(PWINSTATION_OBJECT WinSta, HMODULE hModule,
345 HRSRC hRsrc, LONG cx, LONG cy)
346 {
347 PCURICON_OBJECT CurIcon;
348
349 LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
350 {
351
352 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
353 // UserReferenceObject( CurIcon);
354 // {
355 if((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
356 {
357 if(cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
358 {
359 // UserDereferenceObject(CurIcon);
360 continue;
361 }
362 if (! ReferenceCurIconByProcess(CurIcon))
363 {
364 return NULL;
365 }
366
367 return CurIcon;
368 }
369 // }
370 // UserDereferenceObject(CurIcon);
371
372 }
373
374 return NULL;
375 }
376
377 PCURICON_OBJECT FASTCALL
378 IntCreateCurIconHandle(PWINSTATION_OBJECT WinSta)
379 {
380 PCURICON_OBJECT CurIcon;
381 HANDLE hCurIcon;
382
383 CurIcon = UserCreateObject(gHandleTable, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));
384
385 if(!CurIcon)
386 {
387 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
388 return FALSE;
389 }
390
391 CurIcon->Self = hCurIcon;
392 InitializeListHead(&CurIcon->ProcessList);
393
394 if (! ReferenceCurIconByProcess(CurIcon))
395 {
396 DPRINT1("Failed to add process\n");
397 UserDeleteObject(hCurIcon, otCursorIcon);
398 UserDereferenceObject(CurIcon);
399 return NULL;
400 }
401
402 InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
403
404 return CurIcon;
405 }
406
407 BOOLEAN FASTCALL
408 IntDestroyCurIconObject(PWINSTATION_OBJECT WinSta, PCURICON_OBJECT CurIcon, BOOL ProcessCleanup)
409 {
410 PSYSTEM_CURSORINFO CurInfo;
411 HBITMAP bmpMask, bmpColor;
412 BOOLEAN Ret;
413 PCURICON_PROCESS Current = NULL;
414 PW32PROCESS W32Process = PsGetCurrentProcessWin32Process();
415
416 /* Private objects can only be destroyed by their own process */
417 if (NULL == CurIcon->hModule)
418 {
419 ASSERT(CurIcon->ProcessList.Flink->Flink == &CurIcon->ProcessList);
420 Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
421 if (Current->Process != W32Process)
422 {
423 DPRINT1("Trying to destroy private icon/cursor of another process\n");
424 return FALSE;
425 }
426 }
427 else if (! ProcessCleanup)
428 {
429 DPRINT("Trying to destroy shared icon/cursor\n");
430 return FALSE;
431 }
432
433 /* Now find this process in the list of processes referencing this object and
434 remove it from that list */
435 LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
436 {
437 if (Current->Process == W32Process)
438 {
439 RemoveEntryList(&Current->ListEntry);
440 break;
441 }
442 }
443
444 ExFreeToPagedLookasideList(&gProcessLookasideList, Current);
445
446 /* If there are still processes referencing this object we can't destroy it yet */
447 if (! IsListEmpty(&CurIcon->ProcessList))
448 {
449 return TRUE;
450 }
451
452
453 if (! ProcessCleanup)
454 {
455 RemoveEntryList(&CurIcon->ListEntry);
456 }
457
458 CurInfo = IntGetSysCursorInfo(WinSta);
459
460 if (CurInfo->CurrentCursorObject == CurIcon)
461 {
462 /* Hide the cursor if we're destroying the current cursor */
463 IntSetCursor(WinSta, NULL, TRUE);
464 }
465
466 bmpMask = CurIcon->IconInfo.hbmMask;
467 bmpColor = CurIcon->IconInfo.hbmColor;
468
469 /* delete bitmaps */
470 if(bmpMask)
471 {
472 GDIOBJ_SetOwnership(bmpMask, PsGetCurrentProcess());
473 NtGdiDeleteObject(bmpMask);
474 CurIcon->IconInfo.hbmMask = NULL;
475 }
476 if(bmpColor)
477 {
478 GDIOBJ_SetOwnership(bmpColor, PsGetCurrentProcess());
479 NtGdiDeleteObject(bmpColor);
480 CurIcon->IconInfo.hbmColor = NULL;
481 }
482
483 /* We were given a pointer, no need to keep the reference anylonger! */
484 UserDereferenceObject(CurIcon);
485 Ret = UserDeleteObject(CurIcon->Self, otCursorIcon);
486
487 return Ret;
488 }
489
490 VOID FASTCALL
491 IntCleanupCurIcons(struct _EPROCESS *Process, PW32PROCESS Win32Process)
492 {
493 PWINSTATION_OBJECT WinSta;
494 PCURICON_OBJECT CurIcon, tmp;
495 PCURICON_PROCESS ProcessData;
496
497 WinSta = IntGetWinStaObj();
498 if(WinSta == NULL)
499 {
500 return;
501 }
502
503 LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
504 {
505 UserReferenceObject(CurIcon);
506 // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon)))
507 {
508 LIST_FOR_EACH(ProcessData, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
509 {
510 if (Win32Process == ProcessData->Process)
511 {
512 RemoveEntryList(&CurIcon->ListEntry);
513 IntDestroyCurIconObject(WinSta, CurIcon, TRUE);
514 CurIcon = NULL;
515 break;
516 }
517 }
518
519 // UserDereferenceObject(Object);
520 }
521
522 if (CurIcon)
523 {
524 UserDereferenceObject(CurIcon);
525 }
526 }
527
528 ObDereferenceObject(WinSta);
529 }
530
531 /*
532 * @implemented
533 */
534 HANDLE
535 APIENTRY
536 NtUserCreateCursorIconHandle(PICONINFO IconInfo OPTIONAL, BOOL Indirect)
537 {
538 PCURICON_OBJECT CurIcon;
539 PWINSTATION_OBJECT WinSta;
540 PSURFACE psurfBmp;
541 NTSTATUS Status;
542 HANDLE Ret;
543 DECLARE_RETURN(HANDLE);
544
545 DPRINT("Enter NtUserCreateCursorIconHandle\n");
546 UserEnterExclusive();
547
548 WinSta = IntGetWinStaObj();
549 if(WinSta == NULL)
550 {
551 RETURN( (HANDLE)0);
552 }
553
554 if (!(CurIcon = IntCreateCurIconHandle(WinSta)))
555 {
556 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
557 ObDereferenceObject(WinSta);
558 RETURN( (HANDLE)0);
559 }
560
561 Ret = CurIcon->Self;
562
563 if(IconInfo)
564 {
565 Status = MmCopyFromCaller(&CurIcon->IconInfo, IconInfo, sizeof(ICONINFO));
566 if(NT_SUCCESS(Status))
567 {
568 if(Indirect)
569 {
570 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
571 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
572 }
573 if(CurIcon->IconInfo.hbmColor &&
574 (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
575 {
576 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
577 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
578 SURFACE_UnlockSurface(psurfBmp);
579 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
580 }
581 if(CurIcon->IconInfo.hbmMask &&
582 (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
583 {
584 if (CurIcon->IconInfo.hbmColor == NULL)
585 {
586 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
587 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
588 }
589 SURFACE_UnlockSurface(psurfBmp);
590 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
591 }
592 }
593 else
594 {
595 SetLastNtError(Status);
596 /* FIXME - Don't exit here */
597 }
598 }
599
600 UserDereferenceObject(CurIcon);
601 ObDereferenceObject(WinSta);
602 RETURN( Ret);
603
604 CLEANUP:
605 DPRINT("Leave NtUserCreateCursorIconHandle, ret=%i\n",_ret_);
606 UserLeave();
607 END_CLEANUP;
608 }
609
610 /*
611 * @implemented
612 */
613 BOOL
614 APIENTRY
615 NtUserGetIconInfo(
616 HANDLE hCurIcon,
617 PICONINFO IconInfo,
618 PUNICODE_STRING lpInstName, // optional
619 PUNICODE_STRING lpResName, // optional
620 LPDWORD pbpp, // optional
621 BOOL bInternal)
622 {
623 ICONINFO ii;
624 PCURICON_OBJECT CurIcon;
625 PWINSTATION_OBJECT WinSta;
626 NTSTATUS Status = STATUS_SUCCESS;
627 BOOL Ret = FALSE;
628 DECLARE_RETURN(BOOL);
629
630 DPRINT("Enter NtUserGetIconInfo\n");
631 UserEnterExclusive();
632
633 if(!IconInfo)
634 {
635 SetLastWin32Error(ERROR_INVALID_PARAMETER);
636 RETURN(FALSE);
637 }
638
639 WinSta = IntGetWinStaObj();
640 if(WinSta == NULL)
641 {
642 RETURN( FALSE);
643 }
644
645 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
646 {
647 ObDereferenceObject(WinSta);
648 RETURN( FALSE);
649 }
650
651 RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO));
652
653 /* Copy bitmaps */
654 ii.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
655 ii.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
656
657 /* Copy fields */
658 _SEH2_TRY
659 {
660 ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
661 RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
662
663 if (pbpp)
664 {
665 PSURFACE psurfBmp;
666 int colorBpp = 0;
667
668 ProbeForWrite(pbpp, sizeof(DWORD), 1);
669
670 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
671 if (psurfBmp)
672 {
673 colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
674 SURFACE_UnlockSurface(psurfBmp);
675 }
676
677 RtlCopyMemory(pbpp, &colorBpp, sizeof(DWORD));
678 }
679
680 }
681 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
682 {
683 Status = _SEH2_GetExceptionCode();
684 }
685 _SEH2_END
686
687 if (NT_SUCCESS(Status))
688 Ret = TRUE;
689 else
690 SetLastNtError(Status);
691
692 UserDereferenceObject(CurIcon);
693 ObDereferenceObject(WinSta);
694 RETURN( Ret);
695
696 CLEANUP:
697 DPRINT("Leave NtUserGetIconInfo, ret=%i\n",_ret_);
698 UserLeave();
699 END_CLEANUP;
700 }
701
702
703 /*
704 * @implemented
705 */
706 BOOL
707 APIENTRY
708 NtUserGetIconSize(
709 HANDLE hCurIcon,
710 UINT istepIfAniCur,
711 PLONG plcx, // &size.cx
712 PLONG plcy) // &size.cy
713 {
714 PCURICON_OBJECT CurIcon;
715 NTSTATUS Status = STATUS_SUCCESS;
716 BOOL bRet = FALSE;
717
718 DPRINT("Enter NtUserGetIconSize\n");
719 UserEnterExclusive();
720
721 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
722 {
723 goto cleanup;
724 }
725
726 _SEH2_TRY
727 {
728 ProbeForWrite(plcx, sizeof(LONG), 1);
729 RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
730 ProbeForWrite(plcy, sizeof(LONG), 1);
731 RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
732 }
733 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
734 {
735 Status = _SEH2_GetExceptionCode();
736 }
737 _SEH2_END
738
739 if(NT_SUCCESS(Status))
740 bRet = TRUE;
741 else
742 SetLastNtError(Status); // maybe not, test this
743
744 UserDereferenceObject(CurIcon);
745
746 cleanup:
747 DPRINT("Leave NtUserGetIconSize, ret=%i\n", bRet);
748 UserLeave();
749 return bRet;
750 }
751
752
753 /*
754 * @unimplemented
755 */
756 DWORD
757 APIENTRY
758 NtUserGetCursorFrameInfo(
759 DWORD Unknown0,
760 DWORD Unknown1,
761 DWORD Unknown2,
762 DWORD Unknown3)
763 {
764 UNIMPLEMENTED
765
766 return 0;
767 }
768
769
770 /*
771 * @implemented
772 */
773 BOOL
774 APIENTRY
775 NtUserGetCursorInfo(
776 PCURSORINFO pci)
777 {
778 CURSORINFO SafeCi;
779 PSYSTEM_CURSORINFO CurInfo;
780 PWINSTATION_OBJECT WinSta;
781 NTSTATUS Status = STATUS_SUCCESS;
782 PCURICON_OBJECT CurIcon;
783 BOOL Ret = FALSE;
784 DECLARE_RETURN(BOOL);
785
786 DPRINT("Enter NtUserGetCursorInfo\n");
787 UserEnterExclusive();
788
789 WinSta = IntGetWinStaObj();
790 if (WinSta == NULL)
791 {
792 RETURN( FALSE);
793 }
794
795 CurInfo = IntGetSysCursorInfo(WinSta);
796 CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
797
798 SafeCi.cbSize = sizeof(CURSORINFO);
799 SafeCi.flags = ((CurInfo->ShowingCursor && CurIcon) ? CURSOR_SHOWING : 0);
800 SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
801
802 IntGetCursorLocation(WinSta, &SafeCi.ptScreenPos);
803
804 _SEH2_TRY
805 {
806 if (pci->cbSize == sizeof(CURSORINFO))
807 {
808 ProbeForWrite(pci, sizeof(CURSORINFO), 1);
809 RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
810 Ret = TRUE;
811 }
812 else
813 {
814 SetLastWin32Error(ERROR_INVALID_PARAMETER);
815 }
816 }
817 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
818 {
819 Status = _SEH2_GetExceptionCode();
820 }
821 _SEH2_END;
822 if (!NT_SUCCESS(Status))
823 {
824 SetLastNtError(Status);
825 }
826
827 ObDereferenceObject(WinSta);
828 RETURN(Ret);
829
830 CLEANUP:
831 DPRINT("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
832 UserLeave();
833 END_CLEANUP;
834 }
835
836
837 /*
838 * @implemented
839 */
840 BOOL
841 APIENTRY
842 NtUserClipCursor(
843 RECT *UnsafeRect)
844 {
845 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
846
847 PWINSTATION_OBJECT WinSta;
848 PSYSTEM_CURSORINFO CurInfo;
849 RECT Rect;
850 PWINDOW_OBJECT DesktopWindow = NULL;
851 POINT MousePos = {0};
852 DECLARE_RETURN(BOOL);
853
854 DPRINT("Enter NtUserClipCursor\n");
855 UserEnterExclusive();
856
857 WinSta = IntGetWinStaObj();
858 if (WinSta == NULL)
859 {
860 RETURN( FALSE);
861 }
862
863 if (NULL != UnsafeRect && ! NT_SUCCESS(MmCopyFromCaller(&Rect, UnsafeRect, sizeof(RECT))))
864 {
865 ObDereferenceObject(WinSta);
866 SetLastWin32Error(ERROR_INVALID_PARAMETER);
867 RETURN( FALSE);
868 }
869
870 CurInfo = IntGetSysCursorInfo(WinSta);
871 IntGetCursorLocation(WinSta, &MousePos);
872
873 if(WinSta->ActiveDesktop)
874 DesktopWindow = UserGetWindowObject(WinSta->ActiveDesktop->DesktopWindow);
875
876 if((Rect.right > Rect.left) && (Rect.bottom > Rect.top)
877 && DesktopWindow && UnsafeRect != NULL)
878 {
879 MOUSEINPUT mi;
880
881 CurInfo->CursorClipInfo.IsClipped = TRUE;
882 CurInfo->CursorClipInfo.Left = max(Rect.left, DesktopWindow->Wnd->WindowRect.left);
883 CurInfo->CursorClipInfo.Top = max(Rect.top, DesktopWindow->Wnd->WindowRect.top);
884 CurInfo->CursorClipInfo.Right = min(Rect.right - 1, DesktopWindow->Wnd->WindowRect.right - 1);
885 CurInfo->CursorClipInfo.Bottom = min(Rect.bottom - 1, DesktopWindow->Wnd->WindowRect.bottom - 1);
886
887 mi.dx = MousePos.x;
888 mi.dy = MousePos.y;
889 mi.mouseData = 0;
890 mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
891 mi.time = 0;
892 mi.dwExtraInfo = 0;
893 IntMouseInput(&mi);
894
895 RETURN( TRUE);
896 }
897
898 CurInfo->CursorClipInfo.IsClipped = FALSE;
899 ObDereferenceObject(WinSta);
900
901 RETURN( TRUE);
902
903 CLEANUP:
904 DPRINT("Leave NtUserClipCursor, ret=%i\n",_ret_);
905 UserLeave();
906 END_CLEANUP;
907 }
908
909
910 /*
911 * @implemented
912 */
913 BOOL
914 APIENTRY
915 NtUserDestroyCursor(
916 HANDLE hCurIcon,
917 DWORD Unknown)
918 {
919 PWINSTATION_OBJECT WinSta;
920 PCURICON_OBJECT CurIcon;
921 BOOL ret;
922 DECLARE_RETURN(BOOL);
923
924 DPRINT("Enter NtUserDestroyCursorIcon\n");
925 UserEnterExclusive();
926
927 WinSta = IntGetWinStaObj();
928 if(WinSta == NULL)
929 {
930 RETURN( FALSE);
931 }
932
933 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
934 {
935 ObDereferenceObject(WinSta);
936 RETURN(FALSE);
937 }
938
939 ret = IntDestroyCurIconObject(WinSta, CurIcon, FALSE);
940 /* Note: IntDestroyCurIconObject will remove our reference for us! */
941
942 ObDereferenceObject(WinSta);
943 RETURN(ret);
944
945 CLEANUP:
946 DPRINT("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
947 UserLeave();
948 END_CLEANUP;
949 }
950
951
952 /*
953 * @implemented
954 */
955 HICON
956 APIENTRY
957 NtUserFindExistingCursorIcon(
958 HMODULE hModule,
959 HRSRC hRsrc,
960 LONG cx,
961 LONG cy)
962 {
963 PCURICON_OBJECT CurIcon;
964 PWINSTATION_OBJECT WinSta;
965 HANDLE Ret = (HANDLE)0;
966 DECLARE_RETURN(HICON);
967
968 DPRINT("Enter NtUserFindExistingCursorIcon\n");
969 UserEnterExclusive();
970
971 WinSta = IntGetWinStaObj();
972 if(WinSta == NULL)
973 {
974 RETURN( Ret);
975 }
976
977 CurIcon = IntFindExistingCurIconObject(WinSta, hModule, hRsrc, cx, cy);
978 if(CurIcon)
979 {
980 Ret = CurIcon->Self;
981
982 // IntReleaseCurIconObject(CurIcon);//faxme: is this correct? does IntFindExistingCurIconObject add a ref?
983 ObDereferenceObject(WinSta);
984 RETURN( Ret);
985 }
986
987 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
988 ObDereferenceObject(WinSta);
989 RETURN( (HANDLE)0);
990
991 CLEANUP:
992 DPRINT("Leave NtUserFindExistingCursorIcon, ret=%i\n",_ret_);
993 UserLeave();
994 END_CLEANUP;
995 }
996
997
998 /*
999 * @implemented
1000 */
1001 BOOL
1002 APIENTRY
1003 NtUserGetClipCursor(
1004 RECT *lpRect)
1005 {
1006 /* FIXME - check if process has WINSTA_READATTRIBUTES */
1007 PSYSTEM_CURSORINFO CurInfo;
1008 PWINSTATION_OBJECT WinSta;
1009 RECT Rect;
1010 NTSTATUS Status;
1011 DECLARE_RETURN(BOOL);
1012
1013 DPRINT("Enter NtUserGetClipCursor\n");
1014 UserEnterExclusive();
1015
1016 if(!lpRect)
1017 RETURN( FALSE);
1018
1019 WinSta = IntGetWinStaObj();
1020 if (WinSta == NULL)
1021 {
1022 RETURN( FALSE);
1023 }
1024
1025 CurInfo = IntGetSysCursorInfo(WinSta);
1026 if(CurInfo->CursorClipInfo.IsClipped)
1027 {
1028 Rect.left = CurInfo->CursorClipInfo.Left;
1029 Rect.top = CurInfo->CursorClipInfo.Top;
1030 Rect.right = CurInfo->CursorClipInfo.Right;
1031 Rect.bottom = CurInfo->CursorClipInfo.Bottom;
1032 }
1033 else
1034 {
1035 Rect.left = 0;
1036 Rect.top = 0;
1037 Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1038 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1039 }
1040
1041 Status = MmCopyToCaller((PRECT)lpRect, &Rect, sizeof(RECT));
1042 if(!NT_SUCCESS(Status))
1043 {
1044 ObDereferenceObject(WinSta);
1045 SetLastNtError(Status);
1046 RETURN( FALSE);
1047 }
1048
1049 ObDereferenceObject(WinSta);
1050
1051 RETURN( TRUE);
1052
1053 CLEANUP:
1054 DPRINT("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
1055 UserLeave();
1056 END_CLEANUP;
1057 }
1058
1059
1060 /*
1061 * @implemented
1062 */
1063 HCURSOR
1064 APIENTRY
1065 NtUserSetCursor(
1066 HCURSOR hCursor)
1067 {
1068 PCURICON_OBJECT CurIcon;
1069 HICON OldCursor;
1070 PWINSTATION_OBJECT WinSta;
1071 DECLARE_RETURN(HCURSOR);
1072
1073 DPRINT("Enter NtUserSetCursor\n");
1074 UserEnterExclusive();
1075
1076 WinSta = IntGetWinStaObj();
1077 if(WinSta == NULL)
1078 {
1079 RETURN(NULL);
1080 }
1081
1082 if(hCursor)
1083 {
1084 if(!(CurIcon = UserGetCurIconObject(hCursor)))
1085 {
1086 ObDereferenceObject(WinSta);
1087 RETURN(NULL);
1088 }
1089 }
1090 else
1091 {
1092 CurIcon = NULL;
1093 }
1094
1095 OldCursor = IntSetCursor(WinSta, CurIcon, FALSE);
1096
1097 if(CurIcon)
1098 {
1099 UserDereferenceObject(CurIcon);
1100 }
1101 ObDereferenceObject(WinSta);
1102
1103 RETURN(OldCursor);
1104
1105 CLEANUP:
1106 DPRINT("Leave NtUserSetCursor, ret=%i\n",_ret_);
1107 UserLeave();
1108 END_CLEANUP;
1109 }
1110
1111
1112 /*
1113 * @implemented
1114 */
1115 BOOL
1116 APIENTRY
1117 NtUserSetCursorContents(
1118 HANDLE hCurIcon,
1119 PICONINFO UnsafeIconInfo)
1120 {
1121 PCURICON_OBJECT CurIcon;
1122 ICONINFO IconInfo;
1123 PSURFACE psurfBmp;
1124 PWINSTATION_OBJECT WinSta;
1125 NTSTATUS Status;
1126 BOOL Ret = FALSE;
1127 DECLARE_RETURN(BOOL);
1128
1129 DPRINT("Enter NtUserSetCursorContents\n");
1130 UserEnterExclusive();
1131
1132 WinSta = IntGetWinStaObj();
1133 if(WinSta == NULL)
1134 {
1135 RETURN( FALSE);
1136 }
1137
1138 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1139 {
1140 ObDereferenceObject(WinSta);
1141 RETURN(FALSE);
1142 }
1143
1144 /* Copy fields */
1145 Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
1146 if(!NT_SUCCESS(Status))
1147 {
1148 SetLastNtError(Status);
1149 goto done;
1150 }
1151
1152 /* Delete old bitmaps */
1153 if (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor)
1154 {
1155 NtGdiDeleteObject(CurIcon->IconInfo.hbmColor);
1156 }
1157 if (CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
1158 {
1159 NtGdiDeleteObject(CurIcon->IconInfo.hbmMask);
1160 }
1161
1162 /* Copy new IconInfo field */
1163 CurIcon->IconInfo = IconInfo;
1164
1165 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor);
1166 if(psurfBmp)
1167 {
1168 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1169 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1170 SURFACE_UnlockSurface(psurfBmp);
1171 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
1172 }
1173 else
1174 {
1175 psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask);
1176 if(!psurfBmp)
1177 goto done;
1178
1179 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1180 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
1181
1182 SURFACE_UnlockSurface(psurfBmp);
1183 GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
1184 }
1185
1186 Ret = TRUE;
1187
1188 done:
1189
1190 if (CurIcon)
1191 {
1192 UserDereferenceObject(CurIcon);
1193 }
1194 ObDereferenceObject(WinSta);
1195 RETURN( Ret);
1196
1197 CLEANUP:
1198 DPRINT("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
1199 UserLeave();
1200 END_CLEANUP;
1201 }
1202
1203
1204 /*
1205 * @implemented
1206 */
1207 #if 0
1208 BOOL
1209 APIENTRY
1210 NtUserSetCursorIconData(
1211 HANDLE Handle,
1212 HMODULE hModule,
1213 PUNICODE_STRING pstrResName,
1214 PICONINFO pIconInfo)
1215 {
1216 PCURICON_OBJECT CurIcon;
1217 PWINSTATION_OBJECT WinSta;
1218 PSURFACE psurfBmp;
1219 NTSTATUS Status = STATUS_SUCCESS;
1220 BOOL Ret = FALSE;
1221 DECLARE_RETURN(BOOL);
1222
1223 DPRINT("Enter NtUserSetCursorIconData\n");
1224 UserEnterExclusive();
1225
1226 WinSta = IntGetWinStaObj();
1227 if(WinSta == NULL)
1228 {
1229 RETURN( FALSE);
1230 }
1231
1232 if(!(CurIcon = UserGetCurIconObject(Handle)))
1233 {
1234 ObDereferenceObject(WinSta);
1235 RETURN(FALSE);
1236 }
1237
1238 CurIcon->hModule = hModule;
1239 CurIcon->hRsrc = NULL; //hRsrc;
1240 CurIcon->hGroupRsrc = NULL; //hGroupRsrc;
1241
1242 _SEH2_TRY
1243 {
1244 ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
1245 RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO));
1246
1247 CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(pIconInfo->hbmMask);
1248 CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(pIconInfo->hbmColor);
1249
1250 if (CurIcon->IconInfo.hbmColor)
1251 {
1252 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
1253 {
1254 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1255 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1256 SURFACE_UnlockSurface(psurfBmp);
1257 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1258 }
1259 }
1260 if (CurIcon->IconInfo.hbmMask)
1261 {
1262 if (CurIcon->IconInfo.hbmColor == NULL)
1263 {
1264 if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
1265 {
1266 CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
1267 CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
1268 SURFACE_UnlockSurface(psurfBmp);
1269 }
1270 }
1271 GDIOBJ_SetOwnership(GdiHandleTable, CurIcon->IconInfo.hbmMask, NULL);
1272 }
1273 }
1274 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1275 {
1276 Status = _SEH2_GetExceptionCode();
1277 }
1278 _SEH2_END
1279
1280 if(!NT_SUCCESS(Status))
1281 SetLastNtError(Status);
1282 else
1283 Ret = TRUE;
1284
1285 UserDereferenceObject(CurIcon);
1286 ObDereferenceObject(WinSta);
1287 RETURN( Ret);
1288
1289 CLEANUP:
1290 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1291 UserLeave();
1292 END_CLEANUP;
1293 }
1294 #else
1295 BOOL
1296 APIENTRY
1297 NtUserSetCursorIconData(
1298 HANDLE hCurIcon,
1299 PBOOL fIcon,
1300 POINT *Hotspot,
1301 HMODULE hModule,
1302 HRSRC hRsrc,
1303 HRSRC hGroupRsrc)
1304 {
1305 PCURICON_OBJECT CurIcon;
1306 PWINSTATION_OBJECT WinSta;
1307 NTSTATUS Status;
1308 POINT SafeHotspot;
1309 BOOL Ret = FALSE;
1310 DECLARE_RETURN(BOOL);
1311
1312 DPRINT("Enter NtUserSetCursorIconData\n");
1313 UserEnterExclusive();
1314
1315 WinSta = IntGetWinStaObj();
1316 if(WinSta == NULL)
1317 {
1318 RETURN( FALSE);
1319 }
1320
1321 if(!(CurIcon = UserGetCurIconObject(hCurIcon)))
1322 {
1323 ObDereferenceObject(WinSta);
1324 RETURN(FALSE);
1325 }
1326
1327 CurIcon->hModule = hModule;
1328 CurIcon->hRsrc = hRsrc;
1329 CurIcon->hGroupRsrc = hGroupRsrc;
1330
1331 /* Copy fields */
1332 if(fIcon)
1333 {
1334 Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
1335 if(!NT_SUCCESS(Status))
1336 {
1337 SetLastNtError(Status);
1338 goto done;
1339 }
1340 }
1341 else
1342 {
1343 if(!Hotspot)
1344 Ret = TRUE;
1345 }
1346
1347 if(Hotspot)
1348 {
1349 Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
1350 if(NT_SUCCESS(Status))
1351 {
1352 CurIcon->IconInfo.xHotspot = SafeHotspot.x;
1353 CurIcon->IconInfo.yHotspot = SafeHotspot.y;
1354
1355 Ret = TRUE;
1356 }
1357 else
1358 SetLastNtError(Status);
1359 }
1360
1361 if(!fIcon && !Hotspot)
1362 {
1363 Ret = TRUE;
1364 }
1365
1366 done:
1367 UserDereferenceObject(CurIcon);
1368 ObDereferenceObject(WinSta);
1369 RETURN( Ret);
1370
1371
1372 CLEANUP:
1373 DPRINT("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
1374 UserLeave();
1375 END_CLEANUP;
1376 }
1377 #endif
1378
1379 /*
1380 * @unimplemented
1381 */
1382 BOOL
1383 APIENTRY
1384 NtUserSetSystemCursor(
1385 HCURSOR hcur,
1386 DWORD id)
1387 {
1388 return FALSE;
1389 }
1390
1391
1392 BOOL
1393 UserDrawIconEx(
1394 HDC hDc,
1395 INT xLeft,
1396 INT yTop,
1397 PCURICON_OBJECT pIcon,
1398 INT cxWidth,
1399 INT cyHeight,
1400 UINT istepIfAniCur,
1401 HBRUSH hbrFlickerFreeDraw,
1402 UINT diFlags)
1403 {
1404 BOOL Ret = FALSE;
1405 HBITMAP hbmMask, hbmColor;
1406 BITMAP bmpMask, bmpColor;
1407 COLORREF oldFg, oldBg;
1408 BOOL DoFlickerFree;
1409 SIZE IconSize;
1410
1411 HDC hdcOff;
1412 HGDIOBJ hOldOffBrush = 0;
1413 HGDIOBJ hOldOffBmp = 0;
1414 HBITMAP hbmOff = 0;
1415 HDC hdcMem = 0;
1416 HGDIOBJ hOldMem;
1417 BOOL bAlpha = FALSE;
1418
1419 hbmMask = pIcon->IconInfo.hbmMask;
1420 hbmColor = pIcon->IconInfo.hbmColor;
1421
1422 if (istepIfAniCur)
1423 DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1424
1425 if (!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bmpMask))
1426 {
1427 return FALSE;
1428 }
1429
1430 if (hbmColor && !IntGdiGetObject(hbmColor, sizeof(BITMAP), (PVOID)&bmpColor))
1431 {
1432 return FALSE;
1433 }
1434
1435 if (hbmColor)
1436 {
1437 IconSize.cx = bmpColor.bmWidth;
1438 IconSize.cy = bmpColor.bmHeight;
1439 }
1440 else
1441 {
1442 IconSize.cx = bmpMask.bmWidth;
1443 IconSize.cy = bmpMask.bmHeight / 2;
1444 }
1445
1446 /* NtGdiCreateCompatibleBitmap will create a monochrome bitmap
1447 when cxWidth or cyHeight is 0 */
1448 if ((bmpColor.bmBitsPixel == 32) && (cxWidth != 0) && (cyHeight != 0))
1449 {
1450 SURFACE *psurfOff = NULL;
1451 PFN_DIB_GetPixel fnSource_GetPixel = NULL;
1452 INT x, y;
1453
1454 //Find alpha into icon
1455 psurfOff = SURFACE_LockSurface(hbmColor ? hbmColor : hbmMask);
1456 if (psurfOff)
1457 {
1458 fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
1459 if (fnSource_GetPixel)
1460 {
1461 for (x = 0; x < psurfOff->SurfObj.sizlBitmap.cx; x++)
1462 {
1463 for (y = 0; y < psurfOff->SurfObj.sizlBitmap.cy; y++)
1464 {
1465 bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, x, y) >> 24) & 0xff);
1466 if (bAlpha)
1467 break;
1468 }
1469 if (bAlpha)
1470 break;
1471 }
1472 }
1473 SURFACE_UnlockSurface(psurfOff);
1474 }
1475 }
1476
1477 if (!diFlags)
1478 diFlags = DI_NORMAL;
1479
1480 if (!cxWidth)
1481 cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
1482 UserGetSystemMetrics(SM_CXICON) : IconSize.cx);
1483
1484 if (!cyHeight)
1485 cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
1486 UserGetSystemMetrics(SM_CYICON) : IconSize.cy);
1487
1488 DoFlickerFree = (hbrFlickerFreeDraw &&
1489 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
1490
1491 if (DoFlickerFree || bAlpha)
1492 {
1493 RECT r;
1494 BITMAP bm;
1495 SURFACE *psurfOff = NULL;
1496
1497 r.right = cxWidth;
1498 r.bottom = cyHeight;
1499
1500 hdcOff = NtGdiCreateCompatibleDC(hDc);
1501 if (!hdcOff)
1502 {
1503 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1504 return FALSE;
1505 }
1506
1507 hbmOff = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
1508 if (!hbmOff)
1509 {
1510 DPRINT1("NtGdiCreateCompatibleBitmap() failed!\n");
1511 goto cleanup;
1512 }
1513
1514 /* make sure we have a 32 bit offscreen bitmap
1515 otherwise we can't do alpha blending */
1516 psurfOff = SURFACE_LockSurface(hbmOff);
1517 if (psurfOff == NULL)
1518 {
1519 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1520 goto cleanup;
1521 }
1522 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1523
1524 if (bm.bmBitsPixel != 32)
1525 bAlpha = FALSE;
1526
1527 SURFACE_UnlockSurface(psurfOff);
1528
1529 hOldOffBmp = NtGdiSelectBitmap(hdcOff, hbmOff);
1530 if (!hOldOffBmp)
1531 {
1532 DPRINT1("NtGdiSelectBitmap() failed!\n");
1533 goto cleanup;
1534 }
1535
1536 if (DoFlickerFree)
1537 {
1538 hOldOffBrush = NtGdiSelectBrush(hdcOff, hbrFlickerFreeDraw);
1539 if (!hOldOffBrush)
1540 {
1541 DPRINT1("NtGdiSelectBrush() failed!\n");
1542 goto cleanup;
1543 }
1544
1545 NtGdiPatBlt(hdcOff, 0, 0, r.right, r.bottom, PATCOPY);
1546 }
1547 }
1548 else
1549 hdcOff = hDc;
1550
1551 hdcMem = NtGdiCreateCompatibleDC(hDc);
1552 if (!hdcMem)
1553 {
1554 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1555 goto cleanup;
1556 }
1557
1558 oldFg = IntGdiSetTextColor(hdcOff, RGB(0, 0, 0));
1559 oldBg = IntGdiSetBkColor(hdcOff, RGB(255, 255, 255));
1560
1561 if (diFlags & DI_MASK)
1562 {
1563 hOldMem = NtGdiSelectBitmap(hdcMem, hbmMask);
1564 if (!hOldMem)
1565 {
1566 DPRINT("NtGdiSelectBitmap() failed!\n");
1567 goto cleanup;
1568 }
1569
1570 NtGdiStretchBlt(hdcOff,
1571 (DoFlickerFree || bAlpha ? 0 : xLeft),
1572 (DoFlickerFree || bAlpha ? 0 : yTop),
1573 cxWidth,
1574 cyHeight,
1575 hdcMem,
1576 0,
1577 0,
1578 IconSize.cx,
1579 IconSize.cy,
1580 ((diFlags & DI_IMAGE) ? SRCAND : SRCCOPY),
1581 0);
1582
1583 NtGdiSelectBitmap(hdcMem, hOldMem);
1584 }
1585
1586 if(diFlags & DI_IMAGE)
1587 {
1588 hOldMem = NtGdiSelectBitmap(hdcMem, (hbmColor ? hbmColor : hbmMask));
1589
1590 NtGdiStretchBlt(hdcOff,
1591 (DoFlickerFree || bAlpha ? 0 : xLeft),
1592 (DoFlickerFree || bAlpha ? 0 : yTop),
1593 cxWidth,
1594 cyHeight,
1595 hdcMem,
1596 0,
1597 (hbmColor ? 0 : IconSize.cy),
1598 IconSize.cx,
1599 IconSize.cy,
1600 ((diFlags & DI_MASK) ? SRCINVERT : SRCCOPY),
1601 0);
1602
1603 NtGdiSelectBitmap(hdcMem, hOldMem);
1604 }
1605
1606 if (bAlpha)
1607 {
1608 BITMAP bm;
1609 SURFACE *psurfOff = NULL;
1610 PBYTE pBits = NULL;
1611 BLENDFUNCTION BlendFunc;
1612 DWORD Pixel;
1613 BYTE Red, Green, Blue, Alpha;
1614 DWORD Count = 0;
1615 INT i, j;
1616
1617 psurfOff = SURFACE_LockSurface(hbmOff);
1618 if (psurfOff == NULL)
1619 {
1620 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1621 goto cleanup;
1622 }
1623 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1624
1625 pBits = ExAllocatePoolWithTag(PagedPool, bm.bmWidthBytes * abs(bm.bmHeight), TAG_BITMAP);
1626 if (pBits == NULL)
1627 {
1628 DPRINT1("ExAllocatePoolWithTag() failed!\n");
1629 SURFACE_UnlockSurface(psurfOff);
1630 goto cleanup;
1631 }
1632
1633 /* get icon bits */
1634 IntGetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1635
1636 /* premultiply with the alpha channel value */
1637 for (i = 0; i < cyHeight; i++)
1638 {
1639 for (j = 0; j < cxWidth; j++)
1640 {
1641 Pixel = *(DWORD *)(pBits + Count);
1642
1643 Alpha = ((BYTE)(Pixel >> 24) & 0xff);
1644
1645 Red = (((BYTE)(Pixel >> 0)) * Alpha) / 0xff;
1646 Green = (((BYTE)(Pixel >> 8)) * Alpha) / 0xff;
1647 Blue = (((BYTE)(Pixel >> 16)) * Alpha) / 0xff;
1648
1649 *(DWORD *)(pBits + Count) = (DWORD)(Red | (Green << 8) | (Blue << 16) | (Alpha << 24));
1650
1651 Count += sizeof (DWORD);
1652 }
1653 }
1654
1655 /* set icon bits */
1656 IntSetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1657 ExFreePoolWithTag(pBits, TAG_BITMAP);
1658
1659 SURFACE_UnlockSurface(psurfOff);
1660
1661 BlendFunc.BlendOp = AC_SRC_OVER;
1662 BlendFunc.BlendFlags = 0;
1663 BlendFunc.SourceConstantAlpha = 255;
1664 BlendFunc.AlphaFormat = AC_SRC_ALPHA;
1665
1666 NtGdiAlphaBlend(hDc, xLeft, yTop, cxWidth, cyHeight,
1667 hdcOff, 0, 0, cxWidth, cyHeight, BlendFunc, 0);
1668 }
1669 else if (DoFlickerFree)
1670 {
1671 NtGdiBitBlt(hDc, xLeft, yTop, cxWidth,
1672 cyHeight, hdcOff, 0, 0, SRCCOPY, 0, 0);
1673 }
1674
1675 IntGdiSetTextColor(hdcOff, oldFg);
1676 IntGdiSetBkColor(hdcOff, oldBg);
1677
1678 Ret = TRUE;
1679
1680 cleanup:
1681 if(DoFlickerFree || bAlpha)
1682 {
1683 if(hOldOffBmp) NtGdiSelectBitmap(hdcOff, hOldOffBmp);
1684 if(hOldOffBrush) NtGdiSelectBrush(hdcOff, hOldOffBrush);
1685 if(hbmOff) NtGdiDeleteObject(hbmOff);
1686 if(hdcOff) NtGdiDeleteObjectApp(hdcOff);
1687 }
1688
1689 if(hdcMem) NtGdiDeleteObjectApp(hdcMem);
1690 return Ret;
1691 }
1692
1693 /*
1694 * @implemented
1695 */
1696 BOOL
1697 APIENTRY
1698 NtUserDrawIconEx(
1699 HDC hdc,
1700 int xLeft,
1701 int yTop,
1702 HICON hIcon,
1703 int cxWidth,
1704 int cyHeight,
1705 UINT istepIfAniCur,
1706 HBRUSH hbrFlickerFreeDraw,
1707 UINT diFlags,
1708 DWORD Unknown0,
1709 DWORD Unknown1)
1710 {
1711 PCURICON_OBJECT pIcon;
1712 BOOL Ret;
1713
1714 DPRINT("Enter NtUserDrawIconEx\n");
1715 UserEnterExclusive();
1716
1717 if(!(pIcon = UserGetCurIconObject(hIcon)))
1718 {
1719 DPRINT1("UserGetCurIconObject() failed!\n");
1720 UserLeave();
1721 return FALSE;
1722 }
1723
1724 Ret = UserDrawIconEx(hdc,
1725 xLeft,
1726 yTop,
1727 pIcon,
1728 cxWidth,
1729 cyHeight,
1730 istepIfAniCur,
1731 hbrFlickerFreeDraw,
1732 diFlags);
1733
1734 UserDereferenceObject(pIcon);
1735
1736 UserLeave();
1737 return Ret;
1738 }
1739
1740 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
1741 * User32 macro NtUserShowCursor */
1742 int
1743 APIENTRY
1744 UserShowCursor(BOOL bShow)
1745 {
1746 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1747 PWINSTATION_OBJECT WinSta = pti->Desktop->WindowStation;
1748 PSYSTEM_CURSORINFO CurInfo;
1749
1750 HDC Screen;
1751 PDC dc;
1752 HBITMAP hbmpDc;
1753 SURFOBJ *SurfObj;
1754 SURFACE *psurfDc;
1755 GDIDEVICE *ppdev;
1756 GDIPOINTER *pgp;
1757 int showpointer=0;
1758
1759 if(!(Screen = IntGetScreenDC()))
1760 {
1761 return showpointer; /* No mouse */
1762 }
1763
1764 dc = DC_LockDc(Screen);
1765
1766 if (!dc)
1767 {
1768 return showpointer; /* No mouse */
1769 }
1770
1771 hbmpDc = dc->w.hBitmap;
1772 DC_UnlockDc(dc);
1773
1774 psurfDc = SURFACE_LockSurface(hbmpDc);
1775 if ( !psurfDc )
1776 {
1777 return showpointer; /* No Mouse */
1778 }
1779
1780 SurfObj = &psurfDc->SurfObj;
1781 if (SurfObj == NULL)
1782 {
1783 SURFACE_UnlockSurface(psurfDc);
1784 return showpointer; /* No mouse */
1785 }
1786
1787 ppdev = GDIDEV(SurfObj);
1788
1789 if(ppdev == NULL)
1790 {
1791 SURFACE_UnlockSurface(psurfDc);
1792 return showpointer; /* No mouse */
1793 }
1794
1795 pgp = &ppdev->Pointer;
1796
1797 CurInfo = IntGetSysCursorInfo(WinSta);
1798
1799 if (bShow == FALSE)
1800 {
1801 pgp->ShowPointer--;
1802 showpointer = pgp->ShowPointer;
1803
1804 if (showpointer >= 0)
1805 {
1806 //ppdev->SafetyRemoveCount = 1;
1807 //ppdev->SafetyRemoveLevel = 1;
1808 EngMovePointer(SurfObj,-1,-1,NULL);
1809 CurInfo->ShowingCursor = 0;
1810 }
1811
1812 }
1813 else
1814 {
1815 pgp->ShowPointer++;
1816 showpointer = pgp->ShowPointer;
1817
1818 /* Show Cursor */
1819 if (showpointer < 0)
1820 {
1821 //ppdev->SafetyRemoveCount = 0;
1822 //ppdev->SafetyRemoveLevel = 0;
1823 EngMovePointer(SurfObj,-1,-1,NULL);
1824 CurInfo->ShowingCursor = CURSOR_SHOWING;
1825 }
1826 }
1827
1828 SURFACE_UnlockSurface(psurfDc);
1829 return showpointer;
1830 }