Sync to trunk head (r40091)
[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 /* FIXME: ReactOS specific hack */
1393 BOOL
1394 UserDrawIconEx(
1395 HDC hDc,
1396 INT xLeft,
1397 INT yTop,
1398 PCURICON_OBJECT pIcon,
1399 INT cxWidth,
1400 INT cyHeight,
1401 UINT istepIfAniCur,
1402 HBRUSH hbrFlickerFreeDraw,
1403 UINT diFlags)
1404 {
1405 BOOL Ret = FALSE;
1406 HBITMAP hbmMask, hbmColor;
1407 BITMAP bmpMask, bmpColor;
1408 COLORREF oldFg, oldBg;
1409 BOOL DoFlickerFree;
1410 SIZE IconSize;
1411
1412 HDC hdcOff;
1413 HGDIOBJ hOldOffBrush = 0;
1414 HGDIOBJ hOldOffBmp = 0;
1415 HBITMAP hbmOff = 0;
1416 HDC hdcMem = 0;
1417 HGDIOBJ hOldMem;
1418 BOOL bAlpha = FALSE;
1419
1420 hbmMask = pIcon->IconInfo.hbmMask;
1421 hbmColor = pIcon->IconInfo.hbmColor;
1422
1423 if (istepIfAniCur)
1424 DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1425
1426 if (!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bmpMask))
1427 {
1428 return FALSE;
1429 }
1430
1431 if (hbmColor && !IntGdiGetObject(hbmColor, sizeof(BITMAP), (PVOID)&bmpColor))
1432 {
1433 return FALSE;
1434 }
1435
1436 if (hbmColor)
1437 {
1438 IconSize.cx = bmpColor.bmWidth;
1439 IconSize.cy = bmpColor.bmHeight;
1440 }
1441 else
1442 {
1443 IconSize.cx = bmpMask.bmWidth;
1444 IconSize.cy = bmpMask.bmHeight / 2;
1445 }
1446
1447 /* NtGdiCreateCompatibleBitmap will create a monochrome bitmap
1448 when cxWidth or cyHeight is 0 */
1449 if ((bmpColor.bmBitsPixel == 32) && (cxWidth != 0) && (cyHeight != 0))
1450 {
1451 SURFACE *psurfOff = NULL;
1452 PFN_DIB_GetPixel fnSource_GetPixel = NULL;
1453 INT x, y;
1454
1455 //Find alpha into icon
1456 psurfOff = SURFACE_LockSurface(hbmColor ? hbmColor : hbmMask);
1457 if (psurfOff)
1458 {
1459 fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
1460 if (fnSource_GetPixel)
1461 {
1462 for (x = 0; x < psurfOff->SurfObj.sizlBitmap.cx; x++)
1463 {
1464 for (y = 0; y < psurfOff->SurfObj.sizlBitmap.cy; y++)
1465 {
1466 bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, x, y) >> 24) & 0xff);
1467 if (bAlpha)
1468 break;
1469 }
1470 if (bAlpha)
1471 break;
1472 }
1473 }
1474 SURFACE_UnlockSurface(psurfOff);
1475 }
1476 }
1477
1478 if (!diFlags)
1479 diFlags = DI_NORMAL;
1480
1481 if (!cxWidth)
1482 cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
1483 UserGetSystemMetrics(SM_CXICON) : IconSize.cx);
1484
1485 if (!cyHeight)
1486 cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
1487 UserGetSystemMetrics(SM_CYICON) : IconSize.cy);
1488
1489 DoFlickerFree = (hbrFlickerFreeDraw &&
1490 (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
1491
1492 if (DoFlickerFree || bAlpha)
1493 {
1494 RECT r;
1495 BITMAP bm;
1496 SURFACE *psurfOff = NULL;
1497
1498 r.right = cxWidth;
1499 r.bottom = cyHeight;
1500
1501 hdcOff = NtGdiCreateCompatibleDC(hDc);
1502 if (!hdcOff)
1503 {
1504 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1505 return FALSE;
1506 }
1507
1508 hbmOff = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
1509 if (!hbmOff)
1510 {
1511 DPRINT1("NtGdiCreateCompatibleBitmap() failed!\n");
1512 goto cleanup;
1513 }
1514
1515 /* make sure we have a 32 bit offscreen bitmap
1516 otherwise we can't do alpha blending */
1517 psurfOff = SURFACE_LockSurface(hbmOff);
1518 if (psurfOff == NULL)
1519 {
1520 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1521 goto cleanup;
1522 }
1523 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1524
1525 if (bm.bmBitsPixel != 32)
1526 bAlpha = FALSE;
1527
1528 SURFACE_UnlockSurface(psurfOff);
1529
1530 hOldOffBmp = NtGdiSelectBitmap(hdcOff, hbmOff);
1531 if (!hOldOffBmp)
1532 {
1533 DPRINT1("NtGdiSelectBitmap() failed!\n");
1534 goto cleanup;
1535 }
1536
1537 if (DoFlickerFree)
1538 {
1539 hOldOffBrush = NtGdiSelectBrush(hdcOff, hbrFlickerFreeDraw);
1540 if (!hOldOffBrush)
1541 {
1542 DPRINT1("NtGdiSelectBrush() failed!\n");
1543 goto cleanup;
1544 }
1545
1546 NtGdiPatBlt(hdcOff, 0, 0, r.right, r.bottom, PATCOPY);
1547 }
1548 }
1549 else
1550 hdcOff = hDc;
1551
1552 hdcMem = NtGdiCreateCompatibleDC(hDc);
1553 if (!hdcMem)
1554 {
1555 DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
1556 goto cleanup;
1557 }
1558
1559 oldFg = IntGdiSetTextColor(hdcOff, RGB(0, 0, 0));
1560 oldBg = IntGdiSetBkColor(hdcOff, RGB(255, 255, 255));
1561
1562 if (diFlags & DI_MASK)
1563 {
1564 hOldMem = NtGdiSelectBitmap(hdcMem, hbmMask);
1565 if (!hOldMem)
1566 {
1567 DPRINT("NtGdiSelectBitmap() failed!\n");
1568 goto cleanup;
1569 }
1570
1571 NtGdiStretchBlt(hdcOff,
1572 (DoFlickerFree || bAlpha ? 0 : xLeft),
1573 (DoFlickerFree || bAlpha ? 0 : yTop),
1574 cxWidth,
1575 cyHeight,
1576 hdcMem,
1577 0,
1578 0,
1579 IconSize.cx,
1580 IconSize.cy,
1581 ((diFlags & DI_IMAGE) ? SRCAND : SRCCOPY),
1582 0);
1583
1584 NtGdiSelectBitmap(hdcMem, hOldMem);
1585 }
1586
1587 if(diFlags & DI_IMAGE)
1588 {
1589 hOldMem = NtGdiSelectBitmap(hdcMem, (hbmColor ? hbmColor : hbmMask));
1590
1591 NtGdiStretchBlt(hdcOff,
1592 (DoFlickerFree || bAlpha ? 0 : xLeft),
1593 (DoFlickerFree || bAlpha ? 0 : yTop),
1594 cxWidth,
1595 cyHeight,
1596 hdcMem,
1597 0,
1598 (hbmColor ? 0 : IconSize.cy),
1599 IconSize.cx,
1600 IconSize.cy,
1601 ((diFlags & DI_MASK) ? SRCINVERT : SRCCOPY),
1602 0);
1603
1604 NtGdiSelectBitmap(hdcMem, hOldMem);
1605 }
1606
1607 if (bAlpha)
1608 {
1609 BITMAP bm;
1610 SURFACE *psurfOff = NULL;
1611 PBYTE pBits = NULL;
1612 BLENDFUNCTION BlendFunc;
1613 DWORD Pixel;
1614 BYTE Red, Green, Blue, Alpha;
1615 DWORD Count = 0;
1616 INT i, j;
1617
1618 psurfOff = SURFACE_LockSurface(hbmOff);
1619 if (psurfOff == NULL)
1620 {
1621 DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
1622 goto cleanup;
1623 }
1624 BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
1625
1626 pBits = ExAllocatePoolWithTag(PagedPool, bm.bmWidthBytes * abs(bm.bmHeight), TAG_BITMAP);
1627 if (pBits == NULL)
1628 {
1629 DPRINT1("ExAllocatePoolWithTag() failed!\n");
1630 SURFACE_UnlockSurface(psurfOff);
1631 goto cleanup;
1632 }
1633
1634 /* get icon bits */
1635 IntGetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1636
1637 /* premultiply with the alpha channel value */
1638 for (i = 0; i < cyHeight; i++)
1639 {
1640 for (j = 0; j < cxWidth; j++)
1641 {
1642 Pixel = *(DWORD *)(pBits + Count);
1643
1644 Alpha = ((BYTE)(Pixel >> 24) & 0xff);
1645
1646 Red = (((BYTE)(Pixel >> 0)) * Alpha) / 0xff;
1647 Green = (((BYTE)(Pixel >> 8)) * Alpha) / 0xff;
1648 Blue = (((BYTE)(Pixel >> 16)) * Alpha) / 0xff;
1649
1650 *(DWORD *)(pBits + Count) = (DWORD)(Red | (Green << 8) | (Blue << 16) | (Alpha << 24));
1651
1652 Count += sizeof (DWORD);
1653 }
1654 }
1655
1656 /* set icon bits */
1657 IntSetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
1658 ExFreePoolWithTag(pBits, TAG_BITMAP);
1659
1660 SURFACE_UnlockSurface(psurfOff);
1661
1662 BlendFunc.BlendOp = AC_SRC_OVER;
1663 BlendFunc.BlendFlags = 0;
1664 BlendFunc.SourceConstantAlpha = 255;
1665 BlendFunc.AlphaFormat = AC_SRC_ALPHA;
1666
1667 NtGdiAlphaBlend(hDc, xLeft, yTop, cxWidth, cyHeight,
1668 hdcOff, 0, 0, cxWidth, cyHeight, BlendFunc, 0);
1669 }
1670 else if (DoFlickerFree)
1671 {
1672 NtGdiBitBlt(hDc, xLeft, yTop, cxWidth,
1673 cyHeight, hdcOff, 0, 0, SRCCOPY, 0, 0);
1674 }
1675
1676 IntGdiSetTextColor(hdcOff, oldFg);
1677 IntGdiSetBkColor(hdcOff, oldBg);
1678
1679 Ret = TRUE;
1680
1681 cleanup:
1682 if(DoFlickerFree || bAlpha)
1683 {
1684 if(hOldOffBmp) NtGdiSelectBitmap(hdcOff, hOldOffBmp);
1685 if(hOldOffBrush) NtGdiSelectBrush(hdcOff, hOldOffBrush);
1686 if(hbmOff) NtGdiDeleteObject(hbmOff);
1687 if(hdcOff) NtGdiDeleteObjectApp(hdcOff);
1688 }
1689
1690 if(hdcMem) NtGdiDeleteObjectApp(hdcMem);
1691 return Ret;
1692 }
1693
1694 /*
1695 * @implemented
1696 */
1697 BOOL
1698 APIENTRY
1699 NtUserDrawIconEx(
1700 HDC hdc,
1701 int xLeft,
1702 int yTop,
1703 HICON hIcon,
1704 int cxWidth,
1705 int cyHeight,
1706 UINT istepIfAniCur,
1707 HBRUSH hbrFlickerFreeDraw,
1708 UINT diFlags,
1709 DWORD Unknown0,
1710 DWORD Unknown1)
1711 {
1712 PCURICON_OBJECT pIcon;
1713 BOOL Ret;
1714
1715 DPRINT("Enter NtUserDrawIconEx\n");
1716 UserEnterExclusive();
1717
1718 if(!(pIcon = UserGetCurIconObject(hIcon)))
1719 {
1720 DPRINT1("UserGetCurIconObject() failed!\n");
1721 UserLeave();
1722 return FALSE;
1723 }
1724
1725 Ret = UserDrawIconEx(hdc,
1726 xLeft,
1727 yTop,
1728 pIcon,
1729 cxWidth,
1730 cyHeight,
1731 istepIfAniCur,
1732 hbrFlickerFreeDraw,
1733 diFlags);
1734
1735 UserDereferenceObject(pIcon);
1736
1737 UserLeave();
1738 return Ret;
1739 }
1740
1741 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
1742 * User32 macro NtUserShowCursor */
1743 int
1744 APIENTRY
1745 UserShowCursor(BOOL bShow)
1746 {
1747 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1748 PWINSTATION_OBJECT WinSta = pti->Desktop->WindowStation;
1749 PSYSTEM_CURSORINFO CurInfo;
1750
1751 HDC Screen;
1752 PDC dc;
1753 HBITMAP hbmpDc;
1754 SURFOBJ *SurfObj;
1755 SURFACE *psurfDc;
1756 GDIDEVICE *ppdev;
1757 GDIPOINTER *pgp;
1758 int showpointer=0;
1759
1760 if(!(Screen = IntGetScreenDC()))
1761 {
1762 return showpointer; /* No mouse */
1763 }
1764
1765 dc = DC_LockDc(Screen);
1766
1767 if (!dc)
1768 {
1769 return showpointer; /* No mouse */
1770 }
1771
1772 hbmpDc = dc->w.hBitmap;
1773 DC_UnlockDc(dc);
1774
1775 psurfDc = SURFACE_LockSurface(hbmpDc);
1776 if ( !psurfDc )
1777 {
1778 return showpointer; /* No Mouse */
1779 }
1780
1781 SurfObj = &psurfDc->SurfObj;
1782 if (SurfObj == NULL)
1783 {
1784 SURFACE_UnlockSurface(psurfDc);
1785 return showpointer; /* No mouse */
1786 }
1787
1788 ppdev = GDIDEV(SurfObj);
1789
1790 if(ppdev == NULL)
1791 {
1792 SURFACE_UnlockSurface(psurfDc);
1793 return showpointer; /* No mouse */
1794 }
1795
1796 pgp = &ppdev->Pointer;
1797
1798 CurInfo = IntGetSysCursorInfo(WinSta);
1799
1800 if (bShow == FALSE)
1801 {
1802 pgp->ShowPointer--;
1803 showpointer = pgp->ShowPointer;
1804
1805 if (showpointer >= 0)
1806 {
1807 //ppdev->SafetyRemoveCount = 1;
1808 //ppdev->SafetyRemoveLevel = 1;
1809 EngMovePointer(SurfObj,-1,-1,NULL);
1810 CurInfo->ShowingCursor = 0;
1811 }
1812
1813 }
1814 else
1815 {
1816 pgp->ShowPointer++;
1817 showpointer = pgp->ShowPointer;
1818
1819 /* Show Cursor */
1820 if (showpointer < 0)
1821 {
1822 //ppdev->SafetyRemoveCount = 0;
1823 //ppdev->SafetyRemoveLevel = 0;
1824 EngMovePointer(SurfObj,-1,-1,NULL);
1825 CurInfo->ShowingCursor = CURSOR_SHOWING;
1826 }
1827 }
1828
1829 SURFACE_UnlockSurface(psurfDc);
1830 return showpointer;
1831 }