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