IntSetCursor() don't BSOD in low-resource conditions
[reactos.git] / reactos / subsys / 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 /* $Id: cursoricon.c,v 1.3 2004/12/18 23:55:26 royce Exp $ */
20 #include <w32k.h>
21
22 PCURICON_OBJECT FASTCALL
23 IntGetCurIconObject(PWINSTATION_OBJECT WinStaObject, HANDLE Handle)
24 {
25 PCURICON_OBJECT Object;
26 NTSTATUS Status;
27
28 Status = ObmReferenceObjectByHandle(WinStaObject->HandleTable,
29 Handle, otCursorIcon, (PVOID*)&Object);
30 if (!NT_SUCCESS(Status))
31 {
32 return NULL;
33 }
34 return Object;
35 }
36
37 #define COLORCURSORS_ALLOWED FALSE
38 HCURSOR FASTCALL
39 IntSetCursor(PWINSTATION_OBJECT WinStaObject, PCURICON_OBJECT NewCursor,
40 BOOL ForceChange)
41 {
42 BITMAPOBJ *BitmapObj;
43 SURFOBJ *SurfObj;
44 PDEVINFO DevInfo;
45 PBITMAPOBJ MaskBmpObj = NULL;
46 PSYSTEM_CURSORINFO CurInfo;
47 PCURICON_OBJECT OldCursor;
48 HCURSOR Ret = (HCURSOR)0;
49 HBITMAP dcbmp, hColor = (HBITMAP)0;
50 HBITMAP hMask = 0;
51 SURFOBJ *soMask = NULL, *soColor = NULL;
52 XLATEOBJ *XlateObj = NULL;
53 HDC Screen;
54
55 CurInfo = IntGetSysCursorInfo(WinStaObject);
56 OldCursor = CurInfo->CurrentCursorObject;
57 if (OldCursor)
58 {
59 Ret = (HCURSOR)OldCursor->Self;
60 }
61
62 if (!ForceChange && OldCursor == NewCursor)
63 {
64 return Ret;
65 }
66 else
67 {
68 if(!(Screen = IntGetScreenDC()))
69 {
70 return (HCURSOR)0;
71 }
72 /* FIXME use the desktop's HDC instead of using ScreenDeviceContext */
73 PDC dc = DC_LockDc(Screen);
74
75 if (!dc)
76 {
77 return Ret;
78 }
79 dcbmp = dc->w.hBitmap;
80 DevInfo = dc->DevInfo;
81 DC_UnlockDc(Screen);
82
83 BitmapObj = BITMAPOBJ_LockBitmap(dcbmp);
84 if ( !BitmapObj )
85 return (HCURSOR)0;
86 SurfObj = &BitmapObj->SurfObj;
87 ASSERT(SurfObj);
88 }
89
90 if (!NewCursor && (CurInfo->CurrentCursorObject || ForceChange))
91 {
92 if (NULL != CurInfo->CurrentCursorObject && CurInfo->ShowingCursor)
93 {
94 /* Remove the cursor if it was displayed */
95 if (GDIDEV(SurfObj)->Pointer.MovePointer)
96 GDIDEV(SurfObj)->Pointer.MovePointer(SurfObj, -1, -1, NULL);
97 else
98 EngMovePointer(SurfObj, -1, -1, NULL);
99 GDIDEV(SurfObj)->Pointer.Exclude.right = -1;
100 }
101
102 GDIDEV(SurfObj)->Pointer.Status = SPS_ACCEPT_NOEXCLUDE;
103
104 CurInfo->CurrentCursorObject = NewCursor; /* i.e. CurrentCursorObject = NULL */
105 CurInfo->ShowingCursor = 0;
106 BITMAPOBJ_UnlockBitmap(dcbmp);
107 return Ret;
108 }
109
110 if (!NewCursor)
111 {
112 BITMAPOBJ_UnlockBitmap(dcbmp);
113 return Ret;
114 }
115
116 /* TODO: Fixme. Logic is screwed above */
117
118 ASSERT(NewCursor);
119 MaskBmpObj = BITMAPOBJ_LockBitmap(NewCursor->IconInfo.hbmMask);
120 if (MaskBmpObj)
121 {
122 const int maskBpp = BitsPerFormat(MaskBmpObj->SurfObj.iBitmapFormat);
123 BITMAPOBJ_UnlockBitmap(NewCursor->IconInfo.hbmMask);
124 if (maskBpp != 1)
125 {
126 DPRINT1("SetCursor: The Mask bitmap must have 1BPP!\n");
127 BITMAPOBJ_UnlockBitmap(dcbmp);
128 return Ret;
129 }
130
131 if ((DevInfo->flGraphicsCaps2 & GCAPS2_ALPHACURSOR) &&
132 SurfObj->iBitmapFormat >= BMF_16BPP &&
133 SurfObj->iBitmapFormat <= BMF_32BPP &&
134 NewCursor->Shadow && COLORCURSORS_ALLOWED)
135 {
136 /* FIXME - Create a color pointer, only 32bit bitmap, set alpha bits!
137 Do not pass a mask bitmap to DrvSetPointerShape()!
138 Create a XLATEOBJ that describes the colors of the bitmap. */
139 DPRINT1("SetCursor: (Colored) alpha cursors are not supported!\n");
140 }
141 else
142 {
143 if(NewCursor->IconInfo.hbmColor
144 && COLORCURSORS_ALLOWED)
145 {
146 /* FIXME - Create a color pointer, create only one 32bit bitmap!
147 Do not pass a mask bitmap to DrvSetPointerShape()!
148 Create a XLATEOBJ that describes the colors of the bitmap.
149 (16bit bitmaps are propably allowed) */
150 DPRINT1("SetCursor: Cursors with colors are not supported!\n");
151 }
152 else
153 {
154 MaskBmpObj = BITMAPOBJ_LockBitmap(NewCursor->IconInfo.hbmMask);
155 if(MaskBmpObj)
156 {
157 RECTL DestRect = {0, 0, MaskBmpObj->SurfObj.sizlBitmap.cx, MaskBmpObj->SurfObj.sizlBitmap.cy};
158 POINTL SourcePoint = {0, 0};
159
160 /*
161 * NOTE: For now we create the cursor in top-down bitmap,
162 * because VMware driver rejects it otherwise. This should
163 * be fixed later.
164 */
165 hMask = EngCreateBitmap(
166 MaskBmpObj->SurfObj.sizlBitmap, abs(MaskBmpObj->SurfObj.lDelta),
167 MaskBmpObj->SurfObj.iBitmapFormat, BMF_TOPDOWN,
168 NULL);
169 if ( !hMask )
170 {
171 BITMAPOBJ_UnlockBitmap(NewCursor->IconInfo.hbmMask);
172 BITMAPOBJ_UnlockBitmap(dcbmp);
173 return (HCURSOR)0;
174 }
175 soMask = EngLockSurface((HSURF)hMask);
176 EngCopyBits(soMask, &MaskBmpObj->SurfObj, NULL, NULL,
177 &DestRect, &SourcePoint);
178 BITMAPOBJ_UnlockBitmap(NewCursor->IconInfo.hbmMask);
179 }
180 }
181 }
182 CurInfo->ShowingCursor = CURSOR_SHOWING;
183 CurInfo->CurrentCursorObject = NewCursor;
184 }
185 else
186 {
187 CurInfo->ShowingCursor = 0;
188 CurInfo->CurrentCursorObject = NULL;
189 }
190
191 if (GDIDEVFUNCS(SurfObj).SetPointerShape)
192 {
193 GDIDEV(SurfObj)->Pointer.Status =
194 GDIDEVFUNCS(SurfObj).SetPointerShape(
195 SurfObj, soMask, soColor, XlateObj,
196 NewCursor->IconInfo.xHotspot,
197 NewCursor->IconInfo.yHotspot,
198 CurInfo->x,
199 CurInfo->y,
200 NULL,
201 SPS_CHANGE);
202 DPRINT("SetCursor: DrvSetPointerShape() returned %x\n",
203 GDIDEV(SurfObj)->Pointer.Status);
204 }
205 else
206 {
207 GDIDEV(SurfObj)->Pointer.Status = SPS_DECLINE;
208 }
209
210 if(GDIDEV(SurfObj)->Pointer.Status == SPS_DECLINE)
211 {
212 GDIDEV(SurfObj)->Pointer.Status = EngSetPointerShape(
213 SurfObj, soMask, soColor, XlateObj,
214 NewCursor->IconInfo.xHotspot,
215 NewCursor->IconInfo.yHotspot,
216 CurInfo->x,
217 CurInfo->y,
218 NULL,
219 SPS_CHANGE);
220 GDIDEV(SurfObj)->Pointer.MovePointer = EngMovePointer;
221 }
222 else
223 {
224 GDIDEV(SurfObj)->Pointer.MovePointer = GDIDEVFUNCS(SurfObj).MovePointer;
225 }
226
227 BITMAPOBJ_UnlockBitmap(dcbmp);
228 if(hMask)
229 {
230 EngUnlockSurface(soMask);
231 EngDeleteSurface((HSURF)hMask);
232 }
233 if(hColor)
234 {
235 EngDeleteSurface((HSURF)hColor);
236 }
237 if(XlateObj)
238 {
239 EngDeleteXlate(XlateObj);
240 }
241
242 if(GDIDEV(SurfObj)->Pointer.Status == SPS_ERROR)
243 DPRINT1("SetCursor: DrvSetPointerShape() returned SPS_ERROR\n");
244
245 return Ret;
246 }
247
248 BOOL FASTCALL
249 IntSetupCurIconHandles(PWINSTATION_OBJECT WinStaObject)
250 {
251 return TRUE;
252 }
253
254 PCURICON_OBJECT FASTCALL
255 IntFindExistingCurIconObject(PWINSTATION_OBJECT WinStaObject, HMODULE hModule,
256 HRSRC hRsrc, LONG cx, LONG cy)
257 {
258 PUSER_HANDLE_TABLE HandleTable;
259 PLIST_ENTRY CurrentEntry;
260 PUSER_HANDLE_BLOCK Current;
261 PCURICON_OBJECT Object;
262 ULONG i;
263
264 HandleTable = (PUSER_HANDLE_TABLE)WinStaObject->HandleTable;
265 ObmpLockHandleTable(HandleTable);
266
267 CurrentEntry = HandleTable->ListHead.Flink;
268 while(CurrentEntry != &HandleTable->ListHead)
269 {
270 Current = CONTAINING_RECORD(CurrentEntry, USER_HANDLE_BLOCK, ListEntry);
271 for(i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
272 {
273 Object = (PCURICON_OBJECT)Current->Handles[i].ObjectBody;
274 if(Object && (ObmReferenceObjectByPointer(Object, otCursorIcon) == STATUS_SUCCESS))
275 {
276 if((Object->hModule == hModule) && (Object->hRsrc == hRsrc))
277 {
278 if(cx && ((cx != Object->Size.cx) || (cy != Object->Size.cy)))
279 {
280 ObmDereferenceObject(Object);
281 continue;
282 }
283 ObmpUnlockHandleTable(HandleTable);
284 return Object;
285 }
286 ObmDereferenceObject(Object);
287 }
288 }
289 CurrentEntry = CurrentEntry->Flink;
290 }
291
292 ObmpUnlockHandleTable(HandleTable);
293 return NULL;
294 }
295
296 PCURICON_OBJECT FASTCALL
297 IntCreateCurIconHandle(PWINSTATION_OBJECT WinStaObject)
298 {
299 PCURICON_OBJECT Object;
300 HANDLE Handle;
301 PW32PROCESS Win32Process;
302
303 Object = ObmCreateObject(WinStaObject->HandleTable, &Handle, otCursorIcon, sizeof(CURICON_OBJECT));
304
305 if(!Object)
306 {
307 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
308 return FALSE;
309 }
310
311 Win32Process = PsGetWin32Process();
312
313 IntLockProcessCursorIcons(Win32Process);
314 InsertTailList(&Win32Process->CursorIconListHead, &Object->ListEntry);
315 IntUnLockProcessCursorIcons(Win32Process);
316
317 Object->Self = Handle;
318 Object->Process = PsGetWin32Process();
319
320 return Object;
321 }
322
323 BOOL FASTCALL
324 IntDestroyCurIconObject(PWINSTATION_OBJECT WinStaObject, HANDLE Handle, BOOL RemoveFromProcess)
325 {
326 PSYSTEM_CURSORINFO CurInfo;
327 PCURICON_OBJECT Object;
328 HBITMAP bmpMask, bmpColor;
329 NTSTATUS Status;
330 BOOL Ret;
331
332 Status = ObmReferenceObjectByHandle(WinStaObject->HandleTable, Handle, otCursorIcon, (PVOID*)&Object);
333 if(!NT_SUCCESS(Status))
334 {
335 return FALSE;
336 }
337
338 if (Object->Process != PsGetWin32Process())
339 {
340 ObmDereferenceObject(Object);
341 return FALSE;
342 }
343
344 CurInfo = IntGetSysCursorInfo(WinStaObject);
345
346 if (CurInfo->CurrentCursorObject == Object)
347 {
348 /* Hide the cursor if we're destroying the current cursor */
349 IntSetCursor(WinStaObject, NULL, TRUE);
350 }
351
352 bmpMask = Object->IconInfo.hbmMask;
353 bmpColor = Object->IconInfo.hbmColor;
354
355 if (Object->Process && RemoveFromProcess)
356 {
357 IntLockProcessCursorIcons(Object->Process);
358 RemoveEntryList(&Object->ListEntry);
359 IntUnLockProcessCursorIcons(Object->Process);
360 }
361
362 Ret = NT_SUCCESS(ObmCloseHandle(WinStaObject->HandleTable, Handle));
363
364 /* delete bitmaps */
365 if(bmpMask)
366 {
367 GDIOBJ_SetOwnership(bmpMask, PsGetCurrentProcess());
368 NtGdiDeleteObject(bmpMask);
369 }
370 if(bmpColor)
371 {
372 GDIOBJ_SetOwnership(bmpColor, PsGetCurrentProcess());
373 NtGdiDeleteObject(bmpColor);
374 }
375
376 ObmDereferenceObject(Object);
377
378 return Ret;
379 }
380
381 VOID FASTCALL
382 IntCleanupCurIcons(struct _EPROCESS *Process, PW32PROCESS Win32Process)
383 {
384 PWINSTATION_OBJECT WinStaObject;
385 PCURICON_OBJECT Current;
386 PLIST_ENTRY CurrentEntry, NextEntry;
387
388 WinStaObject = IntGetWinStaObj();
389 if(WinStaObject != NULL)
390 {
391 CurrentEntry = Win32Process->CursorIconListHead.Flink;
392 while(CurrentEntry != &Win32Process->CursorIconListHead)
393 {
394 NextEntry = CurrentEntry->Flink;
395 Current = CONTAINING_RECORD(CurrentEntry, CURICON_OBJECT, ListEntry);
396 RemoveEntryList(&Current->ListEntry);
397 IntDestroyCurIconObject(WinStaObject, Current->Self, FALSE);
398 CurrentEntry = NextEntry;
399 }
400 ObDereferenceObject(WinStaObject);
401 }
402 }
403
404 /*
405 * @implemented
406 */
407 HANDLE
408 STDCALL
409 NtUserCreateCursorIconHandle(PICONINFO IconInfo, BOOL Indirect)
410 {
411 PCURICON_OBJECT CurIconObject;
412 PWINSTATION_OBJECT WinStaObject;
413 PBITMAPOBJ bmp;
414 NTSTATUS Status;
415 HANDLE Ret;
416
417 WinStaObject = IntGetWinStaObj();
418 if(WinStaObject == NULL)
419 {
420 return (HANDLE)0;
421 }
422
423 CurIconObject = IntCreateCurIconHandle(WinStaObject);
424 if(CurIconObject)
425 {
426 Ret = CurIconObject->Self;
427
428 if(IconInfo)
429 {
430 Status = MmCopyFromCaller(&CurIconObject->IconInfo, IconInfo, sizeof(ICONINFO));
431 if(NT_SUCCESS(Status))
432 {
433 if(Indirect)
434 {
435 CurIconObject->IconInfo.hbmMask = BITMAPOBJ_CopyBitmap(CurIconObject->IconInfo.hbmMask);
436 CurIconObject->IconInfo.hbmColor = BITMAPOBJ_CopyBitmap(CurIconObject->IconInfo.hbmColor);
437 }
438 if(CurIconObject->IconInfo.hbmColor &&
439 (bmp = BITMAPOBJ_LockBitmap(CurIconObject->IconInfo.hbmColor)))
440 {
441 CurIconObject->Size.cx = bmp->SurfObj.sizlBitmap.cx;
442 CurIconObject->Size.cy = bmp->SurfObj.sizlBitmap.cy;
443 BITMAPOBJ_UnlockBitmap(CurIconObject->IconInfo.hbmColor);
444 GDIOBJ_SetOwnership(CurIconObject->IconInfo.hbmColor, NULL);
445 }
446 else
447 {
448 if(CurIconObject->IconInfo.hbmMask &&
449 (bmp = BITMAPOBJ_LockBitmap(CurIconObject->IconInfo.hbmMask)))
450 {
451 CurIconObject->Size.cx = bmp->SurfObj.sizlBitmap.cx;
452 CurIconObject->Size.cy = bmp->SurfObj.sizlBitmap.cy / 2;
453 BITMAPOBJ_UnlockBitmap(CurIconObject->IconInfo.hbmMask);
454 GDIOBJ_SetOwnership(CurIconObject->IconInfo.hbmMask, NULL);
455 }
456 }
457 }
458 else
459 {
460 SetLastNtError(Status);
461 /* FIXME - Don't exit here */
462 }
463 }
464
465 ObDereferenceObject(WinStaObject);
466 return Ret;
467 }
468
469 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
470 ObDereferenceObject(WinStaObject);
471 return (HANDLE)0;
472 }
473
474 /*
475 * @implemented
476 */
477 BOOL
478 STDCALL
479 NtUserGetCursorIconInfo(
480 HANDLE Handle,
481 PICONINFO IconInfo)
482 {
483 ICONINFO ii;
484 PCURICON_OBJECT CurIconObject;
485 PWINSTATION_OBJECT WinStaObject;
486 NTSTATUS Status;
487 BOOL Ret = FALSE;
488
489 WinStaObject = IntGetWinStaObj();
490 if(WinStaObject == NULL)
491 {
492 return FALSE;
493 }
494
495 CurIconObject = IntGetCurIconObject(WinStaObject, Handle);
496 if(CurIconObject)
497 {
498 if(IconInfo)
499 {
500 RtlCopyMemory(&ii, &CurIconObject->IconInfo, sizeof(ICONINFO));
501
502 /* Copy bitmaps */
503 ii.hbmMask = BITMAPOBJ_CopyBitmap(ii.hbmMask);
504 ii.hbmColor = BITMAPOBJ_CopyBitmap(ii.hbmColor);
505
506 /* Copy fields */
507 Status = MmCopyToCaller(IconInfo, &ii, sizeof(ICONINFO));
508 if(NT_SUCCESS(Status))
509 Ret = TRUE;
510 else
511 SetLastNtError(Status);
512 }
513 else
514 {
515 SetLastWin32Error(ERROR_INVALID_PARAMETER);
516 }
517
518 IntReleaseCurIconObject(CurIconObject);
519 ObDereferenceObject(WinStaObject);
520 return Ret;
521 }
522
523 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
524 ObDereferenceObject(WinStaObject);
525 return FALSE;
526 }
527
528
529 /*
530 * @implemented
531 */
532 BOOL
533 STDCALL
534 NtUserGetCursorIconSize(
535 HANDLE Handle,
536 BOOL *fIcon,
537 SIZE *Size)
538 {
539 PCURICON_OBJECT CurIconObject;
540 PBITMAPOBJ bmp;
541 PWINSTATION_OBJECT WinStaObject;
542 NTSTATUS Status;
543 BOOL Ret = FALSE;
544 SIZE SafeSize;
545
546 WinStaObject = IntGetWinStaObj();
547 if(WinStaObject == NULL)
548 {
549 return FALSE;
550 }
551
552 CurIconObject = IntGetCurIconObject(WinStaObject, Handle);
553 if(CurIconObject)
554 {
555 /* Copy fields */
556 Status = MmCopyToCaller(fIcon, &CurIconObject->IconInfo.fIcon, sizeof(BOOL));
557 if(!NT_SUCCESS(Status))
558 {
559 SetLastNtError(Status);
560 goto done;
561 }
562
563 bmp = BITMAPOBJ_LockBitmap(CurIconObject->IconInfo.hbmColor);
564 if(!bmp)
565 goto done;
566
567 SafeSize.cx = bmp->SurfObj.sizlBitmap.cx;
568 SafeSize.cy = bmp->SurfObj.sizlBitmap.cy;
569 Status = MmCopyToCaller(Size, &SafeSize, sizeof(SIZE));
570 if(NT_SUCCESS(Status))
571 Ret = TRUE;
572 else
573 SetLastNtError(Status);
574
575 BITMAPOBJ_UnlockBitmap(CurIconObject->IconInfo.hbmColor);
576
577 done:
578 IntReleaseCurIconObject(CurIconObject);
579 ObDereferenceObject(WinStaObject);
580 return Ret;
581 }
582
583 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
584 ObDereferenceObject(WinStaObject);
585 return FALSE;
586 }
587
588
589 /*
590 * @unimplemented
591 */
592 DWORD
593 STDCALL
594 NtUserGetCursorFrameInfo(
595 DWORD Unknown0,
596 DWORD Unknown1,
597 DWORD Unknown2,
598 DWORD Unknown3)
599 {
600 UNIMPLEMENTED
601
602 return 0;
603 }
604
605
606 /*
607 * @implemented
608 */
609 BOOL
610 STDCALL
611 NtUserGetCursorInfo(
612 PCURSORINFO pci)
613 {
614 CURSORINFO SafeCi;
615 PSYSTEM_CURSORINFO CurInfo;
616 PWINSTATION_OBJECT WinStaObject;
617 NTSTATUS Status;
618 PCURICON_OBJECT CursorObject;
619
620 Status = MmCopyFromCaller(&SafeCi.cbSize, pci, sizeof(DWORD));
621 if(!NT_SUCCESS(Status))
622 {
623 SetLastNtError(Status);
624 return FALSE;
625 }
626
627 if(SafeCi.cbSize != sizeof(CURSORINFO))
628 {
629 SetLastWin32Error(ERROR_INVALID_PARAMETER);
630 return FALSE;
631 }
632
633 WinStaObject = IntGetWinStaObj();
634 if(WinStaObject == NULL)
635 {
636 return FALSE;
637 }
638
639 CurInfo = IntGetSysCursorInfo(WinStaObject);
640 CursorObject = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
641
642 SafeCi.flags = ((CurInfo->ShowingCursor && CursorObject) ? CURSOR_SHOWING : 0);
643 SafeCi.hCursor = (CursorObject ? (HCURSOR)CursorObject->Self : (HCURSOR)0);
644 SafeCi.ptScreenPos.x = CurInfo->x;
645 SafeCi.ptScreenPos.y = CurInfo->y;
646
647 Status = MmCopyToCaller(pci, &SafeCi, sizeof(CURSORINFO));
648 if(!NT_SUCCESS(Status))
649 {
650 ObDereferenceObject(WinStaObject);
651 SetLastNtError(Status);
652 return FALSE;
653 }
654
655 ObDereferenceObject(WinStaObject);
656 return TRUE;
657 }
658
659
660 /*
661 * @implemented
662 */
663 BOOL
664 STDCALL
665 NtUserClipCursor(
666 RECT *UnsafeRect)
667 {
668 /* FIXME - check if process has WINSTA_WRITEATTRIBUTES */
669
670 PWINSTATION_OBJECT WinStaObject;
671 PSYSTEM_CURSORINFO CurInfo;
672 RECT Rect;
673 PWINDOW_OBJECT DesktopWindow = NULL;
674
675 WinStaObject = IntGetWinStaObj();
676 if (WinStaObject == NULL)
677 {
678 return FALSE;
679 }
680
681 if (NULL != UnsafeRect && ! NT_SUCCESS(MmCopyFromCaller(&Rect, UnsafeRect, sizeof(RECT))))
682 {
683 ObDereferenceObject(WinStaObject);
684 SetLastWin32Error(ERROR_INVALID_PARAMETER);
685 return FALSE;
686 }
687
688 CurInfo = IntGetSysCursorInfo(WinStaObject);
689 if(WinStaObject->ActiveDesktop)
690 DesktopWindow = IntGetWindowObject(WinStaObject->ActiveDesktop->DesktopWindow);
691
692 if((Rect.right > Rect.left) && (Rect.bottom > Rect.top)
693 && DesktopWindow && UnsafeRect != NULL)
694 {
695 MOUSEINPUT mi;
696
697 CurInfo->CursorClipInfo.IsClipped = TRUE;
698 CurInfo->CursorClipInfo.Left = max(Rect.left, DesktopWindow->WindowRect.left);
699 CurInfo->CursorClipInfo.Top = max(Rect.top, DesktopWindow->WindowRect.top);
700 CurInfo->CursorClipInfo.Right = min(Rect.right - 1, DesktopWindow->WindowRect.right - 1);
701 CurInfo->CursorClipInfo.Bottom = min(Rect.bottom - 1, DesktopWindow->WindowRect.bottom - 1);
702 IntReleaseWindowObject(DesktopWindow);
703
704 mi.dx = CurInfo->x;
705 mi.dy = CurInfo->y;
706 mi.mouseData = 0;
707 mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
708 mi.time = 0;
709 mi.dwExtraInfo = 0;
710 IntMouseInput(&mi);
711
712 return TRUE;
713 }
714
715 CurInfo->CursorClipInfo.IsClipped = FALSE;
716 ObDereferenceObject(WinStaObject);
717
718 return TRUE;
719 }
720
721
722 /*
723 * @implemented
724 */
725 BOOL
726 STDCALL
727 NtUserDestroyCursorIcon(
728 HANDLE Handle,
729 DWORD Unknown)
730 {
731 PWINSTATION_OBJECT WinStaObject;
732
733 WinStaObject = IntGetWinStaObj();
734 if(WinStaObject == NULL)
735 {
736 return FALSE;
737 }
738
739 if(IntDestroyCurIconObject(WinStaObject, Handle, TRUE))
740 {
741 ObDereferenceObject(WinStaObject);
742 return TRUE;
743 }
744
745 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
746 ObDereferenceObject(WinStaObject);
747 return FALSE;
748 }
749
750
751 /*
752 * @implemented
753 */
754 HICON
755 STDCALL
756 NtUserFindExistingCursorIcon(
757 HMODULE hModule,
758 HRSRC hRsrc,
759 LONG cx,
760 LONG cy)
761 {
762 PCURICON_OBJECT CurIconObject;
763 PWINSTATION_OBJECT WinStaObject;
764 HANDLE Ret = (HANDLE)0;
765
766 WinStaObject = IntGetWinStaObj();
767 if(WinStaObject == NULL)
768 {
769 return Ret;
770 }
771
772 CurIconObject = IntFindExistingCurIconObject(WinStaObject, hModule, hRsrc, cx, cy);
773 if(CurIconObject)
774 {
775 Ret = CurIconObject->Self;
776
777 IntReleaseCurIconObject(CurIconObject);
778 ObDereferenceObject(WinStaObject);
779 return Ret;
780 }
781
782 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
783 ObDereferenceObject(WinStaObject);
784 return (HANDLE)0;
785 }
786
787
788 /*
789 * @implemented
790 */
791 BOOL
792 STDCALL
793 NtUserGetClipCursor(
794 RECT *lpRect)
795 {
796 /* FIXME - check if process has WINSTA_READATTRIBUTES */
797 PSYSTEM_CURSORINFO CurInfo;
798 PWINSTATION_OBJECT WinStaObject;
799 RECT Rect;
800 NTSTATUS Status;
801
802 if(!lpRect)
803 return FALSE;
804
805 WinStaObject = IntGetWinStaObj();
806 if (WinStaObject == NULL)
807 {
808 DPRINT("Validation of window station handle (0x%X) failed\n",
809 PROCESS_WINDOW_STATION());
810 return FALSE;
811 }
812
813 CurInfo = IntGetSysCursorInfo(WinStaObject);
814 if(CurInfo->CursorClipInfo.IsClipped)
815 {
816 Rect.left = CurInfo->CursorClipInfo.Left;
817 Rect.top = CurInfo->CursorClipInfo.Top;
818 Rect.right = CurInfo->CursorClipInfo.Right;
819 Rect.bottom = CurInfo->CursorClipInfo.Bottom;
820 }
821 else
822 {
823 Rect.left = 0;
824 Rect.top = 0;
825 Rect.right = NtUserGetSystemMetrics(SM_CXSCREEN);
826 Rect.bottom = NtUserGetSystemMetrics(SM_CYSCREEN);
827 }
828
829 Status = MmCopyToCaller((PRECT)lpRect, &Rect, sizeof(RECT));
830 if(!NT_SUCCESS(Status))
831 {
832 ObDereferenceObject(WinStaObject);
833 SetLastNtError(Status);
834 return FALSE;
835 }
836
837 ObDereferenceObject(WinStaObject);
838
839 return TRUE;
840 }
841
842
843 /*
844 * @implemented
845 */
846 HCURSOR
847 STDCALL
848 NtUserSetCursor(
849 HCURSOR hCursor)
850 {
851 PCURICON_OBJECT CurIconObject;
852 HICON OldCursor = (HCURSOR)0;
853 PWINSTATION_OBJECT WinStaObject;
854
855 WinStaObject = IntGetWinStaObj();
856 if(WinStaObject == NULL)
857 {
858 return (HCURSOR)0;
859 }
860
861 CurIconObject = IntGetCurIconObject(WinStaObject, hCursor);
862 if(CurIconObject)
863 {
864 OldCursor = IntSetCursor(WinStaObject, CurIconObject, FALSE);
865 IntReleaseCurIconObject(CurIconObject);
866 }
867 else
868 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
869
870 ObDereferenceObject(WinStaObject);
871 return OldCursor;
872 }
873
874
875 /*
876 * @implemented
877 */
878 BOOL
879 STDCALL
880 NtUserSetCursorIconContents(
881 HANDLE Handle,
882 PICONINFO IconInfo)
883 {
884 PCURICON_OBJECT CurIconObject;
885 PBITMAPOBJ bmp;
886 PWINSTATION_OBJECT WinStaObject;
887 NTSTATUS Status;
888 BOOL Ret = FALSE;
889
890 WinStaObject = IntGetWinStaObj();
891 if(WinStaObject == NULL)
892 {
893 return FALSE;
894 }
895
896 CurIconObject = IntGetCurIconObject(WinStaObject, Handle);
897 if(CurIconObject)
898 {
899 /* Copy fields */
900 Status = MmCopyFromCaller(&CurIconObject->IconInfo, IconInfo, sizeof(ICONINFO));
901 if(!NT_SUCCESS(Status))
902 {
903 SetLastNtError(Status);
904 goto done;
905 }
906
907 bmp = BITMAPOBJ_LockBitmap(CurIconObject->IconInfo.hbmColor);
908 if(bmp)
909 {
910 CurIconObject->Size.cx = bmp->SurfObj.sizlBitmap.cx;
911 CurIconObject->Size.cy = bmp->SurfObj.sizlBitmap.cy;
912 BITMAPOBJ_UnlockBitmap(CurIconObject->IconInfo.hbmColor);
913 GDIOBJ_SetOwnership(CurIconObject->IconInfo.hbmColor, NULL);
914 }
915 else
916 {
917 bmp = BITMAPOBJ_LockBitmap(CurIconObject->IconInfo.hbmMask);
918 if(!bmp)
919 goto done;
920
921 CurIconObject->Size.cx = bmp->SurfObj.sizlBitmap.cx;
922 CurIconObject->Size.cy = bmp->SurfObj.sizlBitmap.cy / 2;
923
924 BITMAPOBJ_UnlockBitmap(CurIconObject->IconInfo.hbmMask);
925 GDIOBJ_SetOwnership(CurIconObject->IconInfo.hbmMask, NULL);
926 }
927
928 Ret = TRUE;
929
930 done:
931 IntReleaseCurIconObject(CurIconObject);
932 ObDereferenceObject(WinStaObject);
933 return Ret;
934 }
935
936 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
937 ObDereferenceObject(WinStaObject);
938 return FALSE;
939 }
940
941
942 /*
943 * @implemented
944 */
945 BOOL
946 STDCALL
947 NtUserSetCursorIconData(
948 HANDLE Handle,
949 PBOOL fIcon,
950 POINT *Hotspot,
951 HMODULE hModule,
952 HRSRC hRsrc,
953 HRSRC hGroupRsrc)
954 {
955 PCURICON_OBJECT CurIconObject;
956 PWINSTATION_OBJECT WinStaObject;
957 NTSTATUS Status;
958 POINT SafeHotspot;
959 BOOL Ret = FALSE;
960
961 WinStaObject = IntGetWinStaObj();
962 if(WinStaObject == NULL)
963 {
964 return FALSE;
965 }
966
967 CurIconObject = IntGetCurIconObject(WinStaObject, Handle);
968 if(CurIconObject)
969 {
970 CurIconObject->hModule = hModule;
971 CurIconObject->hRsrc = hRsrc;
972 CurIconObject->hGroupRsrc = hGroupRsrc;
973
974 /* Copy fields */
975 if(fIcon)
976 {
977 Status = MmCopyFromCaller(&CurIconObject->IconInfo.fIcon, fIcon, sizeof(BOOL));
978 if(!NT_SUCCESS(Status))
979 {
980 SetLastNtError(Status);
981 goto done;
982 }
983 }
984 else
985 {
986 if(!Hotspot)
987 Ret = TRUE;
988 }
989
990 if(Hotspot)
991 {
992 Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
993 if(NT_SUCCESS(Status))
994 {
995 CurIconObject->IconInfo.xHotspot = SafeHotspot.x;
996 CurIconObject->IconInfo.yHotspot = SafeHotspot.y;
997
998 Ret = TRUE;
999 }
1000 else
1001 SetLastNtError(Status);
1002 }
1003
1004 if(!fIcon && !Hotspot)
1005 {
1006 Ret = TRUE;
1007 }
1008
1009 done:
1010 IntReleaseCurIconObject(CurIconObject);
1011 ObDereferenceObject(WinStaObject);
1012 return Ret;
1013 }
1014
1015 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
1016 ObDereferenceObject(WinStaObject);
1017 return FALSE;
1018 }
1019
1020
1021 /*
1022 * @unimplemented
1023 */
1024 BOOL
1025 STDCALL
1026 NtUserSetSystemCursor(
1027 HCURSOR hcur,
1028 DWORD id)
1029 {
1030 return FALSE;
1031 }
1032
1033
1034 #define CANSTRETCHBLT 0
1035 /*
1036 * @implemented
1037 */
1038 BOOL
1039 STDCALL
1040 NtUserDrawIconEx(
1041 HDC hdc,
1042 int xLeft,
1043 int yTop,
1044 HICON hIcon,
1045 int cxWidth,
1046 int cyWidth,
1047 UINT istepIfAniCur,
1048 HBRUSH hbrFlickerFreeDraw,
1049 UINT diFlags,
1050 DWORD Unknown0,
1051 DWORD Unknown1)
1052 {
1053 PCURICON_OBJECT CurIconObject;
1054 PWINSTATION_OBJECT WinStaObject;
1055 HBITMAP hbmMask, hbmColor;
1056 BITMAP bmpMask, bmpColor;
1057 BOOL DoFlickerFree;
1058 SIZE IconSize;
1059 COLORREF oldFg, oldBg;
1060 HDC hdcMem, hdcOff = (HDC)0;
1061 HBITMAP hbmOff = (HBITMAP)0;
1062 HGDIOBJ hOldOffBrush = 0, hOldOffBmp = 0, hOldMem;
1063 BOOL Ret = FALSE;
1064 #if CANSTRETCHBLT
1065 INT nStretchMode;
1066 #endif
1067
1068 WinStaObject = IntGetWinStaObj();
1069 if(WinStaObject == NULL)
1070 {
1071 return FALSE;
1072 }
1073
1074 CurIconObject = IntGetCurIconObject(WinStaObject, hIcon);
1075 if(CurIconObject)
1076 {
1077 hbmMask = CurIconObject->IconInfo.hbmMask;
1078 hbmColor = CurIconObject->IconInfo.hbmColor;
1079 IntReleaseCurIconObject(CurIconObject);
1080
1081 if(istepIfAniCur)
1082 DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
1083
1084 if(!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), &bmpMask))
1085 goto done;
1086
1087 if(hbmColor && !IntGdiGetObject(hbmColor, sizeof(BITMAP), &bmpColor))
1088 goto done;
1089
1090 if(hbmColor)
1091 {
1092 IconSize.cx = bmpColor.bmWidth;
1093 IconSize.cy = bmpColor.bmHeight;
1094 }
1095 else
1096 {
1097 IconSize.cx = bmpMask.bmWidth;
1098 IconSize.cy = bmpMask.bmHeight / 2;
1099 }
1100
1101 if(!diFlags)
1102 diFlags = DI_NORMAL;
1103
1104 if(!cxWidth)
1105 cxWidth = ((diFlags & DI_DEFAULTSIZE) ? NtUserGetSystemMetrics(SM_CXICON) : IconSize.cx);
1106 if(!cyWidth)
1107 cyWidth = ((diFlags & DI_DEFAULTSIZE) ? NtUserGetSystemMetrics(SM_CYICON) : IconSize.cy);
1108
1109 DoFlickerFree = (hbrFlickerFreeDraw && (NtGdiGetObjectType(hbrFlickerFreeDraw) == OBJ_BRUSH));
1110
1111 if(DoFlickerFree)
1112 {
1113 RECT r;
1114 r.right = cxWidth;
1115 r.bottom = cyWidth;
1116
1117 hdcOff = NtGdiCreateCompatableDC(hdc);
1118 if(!hdcOff)
1119 goto done;
1120
1121 hbmOff = NtGdiCreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1122 if(!hbmOff)
1123 {
1124 NtGdiDeleteDC(hdcOff);
1125 goto done;
1126 }
1127 hOldOffBrush = NtGdiSelectObject(hdcOff, hbrFlickerFreeDraw);
1128 hOldOffBmp = NtGdiSelectObject(hdcOff, hbmOff);
1129 NtGdiPatBlt(hdcOff, 0, 0, r.right, r.bottom, PATCOPY);
1130 NtGdiSelectObject(hdcOff, hbmOff);
1131 }
1132
1133 hdcMem = NtGdiCreateCompatableDC(hdc);
1134 if(!hdcMem)
1135 goto cleanup;
1136
1137 if(!DoFlickerFree)
1138 hdcOff = hdc;
1139
1140 #if CANSTRETCHBLT
1141 nStretchMode = NtGdiSetStretchBltMode(hdcOff, STRETCH_DELETESCANS);
1142 #endif
1143 oldFg = NtGdiSetTextColor(hdcOff, RGB(0, 0, 0));
1144 oldBg = NtGdiSetBkColor(hdcOff, RGB(255, 255, 255));
1145
1146 if(diFlags & DI_MASK)
1147 {
1148 hOldMem = NtGdiSelectObject(hdcMem, hbmMask);
1149 #if CANSTRETCHBLT
1150 NtGdiStretchBlt(hdcOff, (DoFlickerFree ? 0 : xLeft), (DoFlickerFree ? 0 : yTop),
1151 cxWidth, cyWidth, hdcMem, 0, 0, IconSize.cx, IconSize.cy,
1152 ((diFlags & DI_IMAGE) ? SRCAND : SRCCOPY));
1153 #else
1154 NtGdiBitBlt(hdcOff, (DoFlickerFree ? 0 : xLeft), (DoFlickerFree ? 0 : yTop),
1155 cxWidth, cyWidth, hdcMem, 0, 0, ((diFlags & DI_IMAGE) ? SRCAND : SRCCOPY));
1156 #endif
1157 if(!hbmColor && (bmpMask.bmHeight == 2 * bmpMask.bmWidth) && (diFlags & DI_IMAGE))
1158 {
1159 #if CANSTRETCHBLT
1160 NtGdiStretchBlt(hdcOff, (DoFlickerFree ? 0 : xLeft), (DoFlickerFree ? 0 : yTop),
1161 cxWidth, cyWidth, hdcMem, 0, IconSize.cy, IconSize.cx, IconSize.cy, SRCINVERT);
1162 #else
1163 NtGdiBitBlt(hdcOff, (DoFlickerFree ? 0 : xLeft), (DoFlickerFree ? 0 : yTop),
1164 cxWidth, cyWidth, hdcMem, 0, IconSize.cy, SRCINVERT);
1165 #endif
1166 diFlags &= ~DI_IMAGE;
1167 }
1168 NtGdiSelectObject(hdcMem, hOldMem);
1169 }
1170
1171 if(diFlags & DI_IMAGE)
1172 {
1173 hOldMem = NtGdiSelectObject(hdcMem, (hbmColor ? hbmColor : hbmMask));
1174 #if CANSTRETCHBLT
1175 NtGdiStretchBlt(hdcOff, (DoFlickerFree ? 0 : xLeft), (DoFlickerFree ? 0 : yTop),
1176 cxWidth, cyWidth, hdcMem, 0, (hbmColor ? 0 : IconSize.cy),
1177 IconSize.cx, IconSize.cy, ((diFlags & DI_MASK) ? SRCINVERT : SRCCOPY));
1178 #else
1179 NtGdiBitBlt(hdcOff, (DoFlickerFree ? 0 : xLeft), (DoFlickerFree ? 0 : yTop),
1180 cxWidth, cyWidth, hdcMem, 0, (hbmColor ? 0 : IconSize.cy),
1181 ((diFlags & DI_MASK) ? SRCINVERT : SRCCOPY));
1182 #endif
1183 NtGdiSelectObject(hdcMem, hOldMem);
1184 }
1185
1186 if(DoFlickerFree)
1187 NtGdiBitBlt(hdc, xLeft, yTop, cxWidth, cyWidth, hdcOff, 0, 0, SRCCOPY);
1188
1189 NtGdiSetTextColor(hdcOff, oldFg);
1190 NtGdiSetBkColor(hdcOff, oldBg);
1191 #if CANSTRETCHBLT
1192 SetStretchBltMode(hdcOff, nStretchMode);
1193 #endif
1194
1195 Ret = TRUE;
1196
1197 cleanup:
1198 if(DoFlickerFree)
1199 {
1200
1201 NtGdiSelectObject(hdcOff, hOldOffBmp);
1202 NtGdiSelectObject(hdcOff, hOldOffBrush);
1203 NtGdiDeleteObject(hbmOff);
1204 NtGdiDeleteDC(hdcOff);
1205 }
1206 if(hdcMem)
1207 NtGdiDeleteDC(hdcMem);
1208
1209 done:
1210 ObDereferenceObject(WinStaObject);
1211
1212 return Ret;
1213 }
1214
1215 SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
1216 ObDereferenceObject(WinStaObject);
1217 return FALSE;
1218 }
1219