[WIN32K]
[reactos.git] / subsystems / win32 / win32k / eng / mouse.c
1 /*
2 * PROJECT: ReactOS win32 subsystem
3 * PURPOSE: Mouse pointer functions
4 * FILE: subsystems/win32k/eng/mouse.c
5 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * Timo Kreuzer (timo.kreuzer@reactos.org)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10 /* INCLUDES ******************************************************************/
11
12 #include <w32k.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* FUNCTIONS *****************************************************************/
18
19 BOOL
20 APIENTRY
21 EngSetPointerTag(
22 IN HDEV hdev,
23 IN SURFOBJ *psoMask,
24 IN SURFOBJ *psoColor,
25 IN XLATEOBJ *pxlo,
26 IN FLONG fl)
27 {
28 // This function is obsolete for Windows 2000 and later.
29 // This function is still supported, but always returns FALSE.
30 // www.osr.com/ddk/graphics/gdifncs_4yav.htm
31 return FALSE;
32 }
33
34 /*
35 * FUNCTION: Notify the mouse driver that drawing is about to begin in
36 * a rectangle on a particular surface.
37 */
38 INT INTERNAL_CALL
39 MouseSafetyOnDrawStart(
40 SURFOBJ *pso,
41 LONG HazardX1,
42 LONG HazardY1,
43 LONG HazardX2,
44 LONG HazardY2)
45 {
46 LONG tmp;
47 PDEVOBJ *ppdev;
48 GDIPOINTER *pgp;
49
50 ASSERT(pso != NULL);
51
52 ppdev = GDIDEV(pso);
53 if (ppdev == NULL)
54 {
55 return FALSE;
56 }
57
58 pgp = &ppdev->Pointer;
59
60 if (pgp->Exclude.right == -1)
61 {
62 return FALSE;
63 }
64
65 ppdev->SafetyRemoveCount++;
66
67 if (ppdev->SafetyRemoveLevel != 0)
68 {
69 return FALSE;
70 }
71
72 if (HazardX1 > HazardX2)
73 {
74 tmp = HazardX2;
75 HazardX2 = HazardX1;
76 HazardX1 = tmp;
77 }
78 if (HazardY1 > HazardY2)
79 {
80 tmp = HazardY2;
81 HazardY2 = HazardY1;
82 HazardY1 = tmp;
83 }
84
85 if (pgp->Exclude.right >= HazardX1
86 && pgp->Exclude.left <= HazardX2
87 && pgp->Exclude.bottom >= HazardY1
88 && pgp->Exclude.top <= HazardY2)
89 {
90 ppdev->SafetyRemoveLevel = ppdev->SafetyRemoveCount;
91 ppdev->pfnMovePointer(pso, -1, -1, NULL);
92 }
93
94 return(TRUE);
95 }
96
97 /*
98 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
99 */
100 INT INTERNAL_CALL
101 MouseSafetyOnDrawEnd(
102 SURFOBJ *pso)
103 {
104 PDEVOBJ *ppdev;
105 GDIPOINTER *pgp;
106
107 ASSERT(pso != NULL);
108
109 ppdev = (PDEVOBJ*)pso->hdev;
110
111 if (ppdev == NULL)
112 {
113 return(FALSE);
114 }
115
116 pgp = &ppdev->Pointer;
117
118 if (pgp->Exclude.right == -1)
119 {
120 return FALSE;
121 }
122
123 if (--ppdev->SafetyRemoveCount >= ppdev->SafetyRemoveLevel)
124 {
125 return FALSE;
126 }
127
128 ppdev->pfnMovePointer(pso, gpsi->ptCursor.x, gpsi->ptCursor.y, &pgp->Exclude);
129
130 ppdev->SafetyRemoveLevel = 0;
131
132 return(TRUE);
133 }
134
135 /* SOFTWARE MOUSE POINTER IMPLEMENTATION **************************************/
136
137 VOID
138 INTERNAL_CALL
139 IntHideMousePointer(
140 PDEVOBJ *ppdev,
141 SURFOBJ *psoDest)
142 {
143 GDIPOINTER *pgp;
144 POINTL pt;
145 RECTL rclDest;
146 POINTL ptlSave;
147
148 ASSERT(ppdev);
149 ASSERT(psoDest);
150
151 pgp = &ppdev->Pointer;
152
153 if (!pgp->Enabled)
154 {
155 return;
156 }
157
158 pgp->Enabled = FALSE;
159
160 if (!pgp->psurfSave)
161 {
162 DPRINT1("No SaveSurface!\n");
163 return;
164 }
165
166 /* Calculate cursor coordinates */
167 pt.x = ppdev->ptlPointer.x - pgp->HotSpot.x;
168 pt.y = ppdev->ptlPointer.y - pgp->HotSpot.y;
169
170 rclDest.left = max(pt.x, 0);
171 rclDest.top = max(pt.y, 0);
172 rclDest.right = min(pt.x + pgp->Size.cx, psoDest->sizlBitmap.cx);
173 rclDest.bottom = min(pt.y + pgp->Size.cy, psoDest->sizlBitmap.cy);
174
175 ptlSave.x = rclDest.left - pt.x;
176 ptlSave.y = rclDest.top - pt.y;
177
178 IntEngBitBltEx(psoDest,
179 &pgp->psurfSave->SurfObj,
180 NULL,
181 NULL,
182 NULL,
183 &rclDest,
184 &ptlSave,
185 &ptlSave,
186 NULL,
187 NULL,
188 ROP3_TO_ROP4(SRCCOPY),
189 FALSE);
190 }
191
192 VOID
193 INTERNAL_CALL
194 IntShowMousePointer(PDEVOBJ *ppdev, SURFOBJ *psoDest)
195 {
196 GDIPOINTER *pgp;
197 POINTL pt;
198 RECTL rclSurf, rclPointer;
199
200 ASSERT(ppdev);
201 ASSERT(psoDest);
202
203 pgp = &ppdev->Pointer;
204
205 if (pgp->Enabled)
206 {
207 return;
208 }
209
210 pgp->Enabled = TRUE;
211
212 /* Calculate pointer coordinates */
213 pt.x = ppdev->ptlPointer.x - pgp->HotSpot.x;
214 pt.y = ppdev->ptlPointer.y - pgp->HotSpot.y;
215
216 /* Calculate the rect on the surface */
217 rclSurf.left = max(pt.x, 0);
218 rclSurf.top = max(pt.y, 0);
219 rclSurf.right = min(pt.x + pgp->Size.cx, psoDest->sizlBitmap.cx);
220 rclSurf.bottom = min(pt.y + pgp->Size.cy, psoDest->sizlBitmap.cy);
221
222 /* Calculate the rect in the pointer bitmap */
223 rclPointer.left = rclSurf.left - pt.x;
224 rclPointer.top = rclSurf.top - pt.y;
225 rclPointer.right = min(pgp->Size.cx, psoDest->sizlBitmap.cx - pt.x);
226 rclPointer.bottom = min(pgp->Size.cy, psoDest->sizlBitmap.cy - pt.y);
227
228 /* Copy the pixels under the cursor to temporary surface. */
229 IntEngBitBltEx(&pgp->psurfSave->SurfObj,
230 psoDest,
231 NULL,
232 NULL,
233 NULL,
234 &rclPointer,
235 (POINTL*)&rclSurf,
236 NULL,
237 NULL,
238 NULL,
239 ROP3_TO_ROP4(SRCCOPY),
240 FALSE);
241
242 /* Blt the pointer on the screen. */
243 if (pgp->psurfColor)
244 {
245 IntEngBitBltEx(psoDest,
246 &pgp->psurfMask->SurfObj,
247 NULL,
248 NULL,
249 NULL,
250 &rclSurf,
251 (POINTL*)&rclPointer,
252 NULL,
253 NULL,
254 NULL,
255 ROP3_TO_ROP4(SRCAND),
256 FALSE);
257
258 IntEngBitBltEx(psoDest,
259 &pgp->psurfColor->SurfObj,
260 NULL,
261 NULL,
262 NULL,
263 &rclSurf,
264 (POINTL*)&rclPointer,
265 NULL,
266 NULL,
267 NULL,
268 ROP3_TO_ROP4(SRCINVERT),
269 FALSE);
270 }
271 else
272 {
273 IntEngBitBltEx(psoDest,
274 &pgp->psurfMask->SurfObj,
275 NULL,
276 NULL,
277 NULL,
278 &rclSurf,
279 (POINTL*)&rclPointer,
280 NULL,
281 NULL,
282 NULL,
283 ROP3_TO_ROP4(SRCAND),
284 FALSE);
285
286 rclPointer.top += pgp->Size.cy;
287
288 IntEngBitBltEx(psoDest,
289 &pgp->psurfMask->SurfObj,
290 NULL,
291 NULL,
292 NULL,
293 &rclSurf,
294 (POINTL*)&rclPointer,
295 NULL,
296 NULL,
297 NULL,
298 ROP3_TO_ROP4(SRCINVERT),
299 FALSE);
300 }
301 }
302
303 /*
304 * @implemented
305 */
306 ULONG APIENTRY
307 EngSetPointerShape(
308 IN SURFOBJ *pso,
309 IN SURFOBJ *psoMask,
310 IN SURFOBJ *psoColor,
311 IN XLATEOBJ *pxlo,
312 IN LONG xHot,
313 IN LONG yHot,
314 IN LONG x,
315 IN LONG y,
316 IN RECTL *prcl,
317 IN FLONG fl)
318 {
319 PDEVOBJ *ppdev;
320 GDIPOINTER *pgp;
321 LONG lDelta;
322 HBITMAP hbmp;
323 RECTL rcl;
324
325 ASSERT(pso);
326
327 ppdev = GDIDEV(pso);
328 pgp = &ppdev->Pointer;
329
330 if (psoColor)
331 {
332 pgp->Size.cx = psoColor->sizlBitmap.cx;
333 pgp->Size.cy = psoColor->sizlBitmap.cy;
334 if (psoMask)
335 {
336 // CHECKME: Is this really required? if we have a color surface,
337 // we only need the AND part of the mask.
338 /* Check if the sizes match as they should */
339 if (psoMask->sizlBitmap.cx != psoColor->sizlBitmap.cx ||
340 psoMask->sizlBitmap.cy != psoColor->sizlBitmap.cy * 2)
341 {
342 DPRINT("Sizes of mask (%ld,%ld) and color (%ld,%ld) don't match\n",
343 psoMask->sizlBitmap.cx, psoMask->sizlBitmap.cy,
344 psoColor->sizlBitmap.cx, psoColor->sizlBitmap.cy);
345 // return SPS_ERROR;
346 }
347 }
348 }
349 else if (psoMask)
350 {
351 pgp->Size.cx = psoMask->sizlBitmap.cx;
352 pgp->Size.cy = psoMask->sizlBitmap.cy / 2;
353 }
354
355 IntHideMousePointer(ppdev, pso);
356
357 if (pgp->psurfColor)
358 {
359 EngDeleteSurface(pgp->psurfColor->BaseObject.hHmgr);
360 SURFACE_ShareUnlockSurface(pgp->psurfColor);
361 pgp->psurfColor = NULL;
362 }
363
364 if (pgp->psurfMask)
365 {
366 EngDeleteSurface(pgp->psurfMask->BaseObject.hHmgr);
367 SURFACE_ShareUnlockSurface(pgp->psurfMask);
368 pgp->psurfMask = NULL;
369 }
370
371 if (pgp->psurfSave != NULL)
372 {
373 EngDeleteSurface(pgp->psurfSave->BaseObject.hHmgr);
374 SURFACE_ShareUnlockSurface(pgp->psurfSave);
375 pgp->psurfSave = NULL;
376 }
377
378 /* See if we are being asked to hide the pointer. */
379 if (psoMask == NULL && psoColor == NULL)
380 {
381 return SPS_ACCEPT_NOEXCLUDE;
382 }
383
384 pgp->HotSpot.x = xHot;
385 pgp->HotSpot.y = yHot;
386
387 /* Calculate lDelta for our surfaces. */
388 lDelta = DIB_GetDIBWidthBytes(pgp->Size.cx,
389 BitsPerFormat(pso->iBitmapFormat));
390
391 rcl.left = 0;
392 rcl.top = 0;
393 rcl.right = pgp->Size.cx;
394 rcl.bottom = pgp->Size.cy;
395
396 /* Create surface for saving the pixels under the cursor. */
397 hbmp = EngCreateBitmap(pgp->Size,
398 lDelta,
399 pso->iBitmapFormat,
400 BMF_TOPDOWN | BMF_NOZEROINIT,
401 NULL);
402 pgp->psurfSave = SURFACE_ShareLockSurface(hbmp);
403
404 /* Create a mask surface */
405 if (psoMask)
406 {
407 EXLATEOBJ exlo;
408 PPALETTE ppal;
409
410 hbmp = EngCreateBitmap(psoMask->sizlBitmap,
411 lDelta,
412 pso->iBitmapFormat,
413 BMF_TOPDOWN | BMF_NOZEROINIT,
414 NULL);
415 pgp->psurfMask = SURFACE_ShareLockSurface(hbmp);
416
417 if(pgp->psurfMask)
418 {
419 ppal = PALETTE_LockPalette(ppdev->devinfo.hpalDefault);
420 EXLATEOBJ_vInitialize(&exlo,
421 &gpalMono,
422 ppal,
423 0,
424 RGB(0xff,0xff,0xff),
425 RGB(0,0,0));
426
427 rcl.bottom = psoMask->sizlBitmap.cy;
428 IntEngCopyBits(&pgp->psurfMask->SurfObj,
429 psoMask,
430 NULL,
431 &exlo.xlo,
432 &rcl,
433 (POINTL*)&rcl);
434
435 EXLATEOBJ_vCleanup(&exlo);
436 if (ppal)
437 PALETTE_UnlockPalette(ppal);
438 }
439 }
440 else
441 {
442 pgp->psurfMask = NULL;
443 }
444
445 /* Create a color surface */
446 if (psoColor)
447 {
448 hbmp = EngCreateBitmap(psoColor->sizlBitmap,
449 lDelta,
450 pso->iBitmapFormat,
451 BMF_TOPDOWN | BMF_NOZEROINIT,
452 NULL);
453 pgp->psurfColor = SURFACE_ShareLockSurface(hbmp);
454 if (pgp->psurfColor)
455 {
456 rcl.bottom = psoColor->sizlBitmap.cy;
457 IntEngCopyBits(&pgp->psurfColor->SurfObj,
458 psoColor,
459 NULL,
460 pxlo,
461 &rcl,
462 (POINTL*)&rcl);
463 }
464 }
465 else
466 {
467 pgp->psurfColor = NULL;
468 }
469
470 if (x != -1)
471 {
472 ppdev->ptlPointer.x = x;
473 ppdev->ptlPointer.y = y;
474
475 IntShowMousePointer(ppdev, pso);
476
477 if (prcl != NULL)
478 {
479 prcl->left = x - pgp->HotSpot.x;
480 prcl->top = y - pgp->HotSpot.x;
481 prcl->right = prcl->left + pgp->Size.cx;
482 prcl->bottom = prcl->top + pgp->Size.cy;
483 }
484 }
485 else if (prcl != NULL)
486 {
487 prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
488 }
489
490 return SPS_ACCEPT_NOEXCLUDE;
491 }
492
493 /*
494 * @implemented
495 */
496
497 VOID APIENTRY
498 EngMovePointer(
499 IN SURFOBJ *pso,
500 IN LONG x,
501 IN LONG y,
502 IN RECTL *prcl)
503 {
504 PDEVOBJ *ppdev;
505 GDIPOINTER *pgp;
506
507 ASSERT(pso);
508
509 ppdev = GDIDEV(pso);
510 ASSERT(ppdev);
511
512 pgp = &ppdev->Pointer;
513
514 IntHideMousePointer(ppdev, pso);
515
516 ppdev->ptlPointer.x = x;
517 ppdev->ptlPointer.y = y;
518
519 if (x != -1)
520 {
521 IntShowMousePointer(ppdev, pso);
522 if (prcl != NULL)
523 {
524 prcl->left = x - pgp->HotSpot.x;
525 prcl->top = y - pgp->HotSpot.y;
526 prcl->right = prcl->left + pgp->Size.cx;
527 prcl->bottom = prcl->top + pgp->Size.cy;
528 }
529 }
530 else if (prcl != NULL)
531 {
532 prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
533 }
534 }
535
536 VOID APIENTRY
537 IntEngMovePointer(
538 IN SURFOBJ *pso,
539 IN LONG x,
540 IN LONG y,
541 IN RECTL *prcl)
542 {
543 SURFACE *psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj);
544 PPDEVOBJ ppdev = (PPDEVOBJ)pso->hdev;
545 if(ppdev->SafetyRemoveLevel)
546 return ;
547
548 SURFACE_LockBitmapBits(psurf);
549 ppdev->pfnMovePointer(pso, x, y, prcl);
550 SURFACE_UnlockBitmapBits(psurf);
551 }
552
553 ULONG APIENTRY
554 IntEngSetPointerShape(
555 IN SURFOBJ *pso,
556 IN SURFOBJ *psoMask,
557 IN SURFOBJ *psoColor,
558 IN XLATEOBJ *pxlo,
559 IN LONG xHot,
560 IN LONG yHot,
561 IN LONG x,
562 IN LONG y,
563 IN RECTL *prcl,
564 IN FLONG fl)
565 {
566 ULONG ulResult = SPS_DECLINE;
567 SURFACE *psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj);
568 PFN_DrvSetPointerShape pfnSetPointerShape;
569 PPDEVOBJ ppdev = GDIDEV(pso);
570
571 pfnSetPointerShape = GDIDEVFUNCS(pso).SetPointerShape;
572
573 SURFACE_LockBitmapBits(psurf);
574 if (pfnSetPointerShape)
575 {
576 ulResult = pfnSetPointerShape(pso,
577 psoMask,
578 psoColor,
579 pxlo,
580 xHot,
581 yHot,
582 x,
583 y,
584 prcl,
585 fl);
586 }
587
588 /* Check if the driver accepted it */
589 if (ulResult == SPS_ACCEPT_NOEXCLUDE)
590 {
591 /* Set MovePointer to the driver function */
592 ppdev->pfnMovePointer = GDIDEVFUNCS(pso).MovePointer;
593 }
594 else
595 {
596 /* Set software pointer */
597 ulResult = EngSetPointerShape(pso,
598 psoMask,
599 psoColor,
600 pxlo,
601 xHot,
602 yHot,
603 x,
604 y,
605 prcl,
606 fl);
607 /* Set MovePointer to the eng function */
608 ppdev->pfnMovePointer = EngMovePointer;
609 }
610
611 SURFACE_UnlockBitmapBits(psurf);
612
613 return ulResult;
614 }
615
616 ULONG
617 NTAPI
618 GreSetPointerShape(
619 HDC hdc,
620 HBITMAP hbmMask,
621 HBITMAP hbmColor,
622 LONG xHot,
623 LONG yHot,
624 LONG x,
625 LONG y)
626 {
627 PDC pdc;
628 PSURFACE psurf, psurfMask, psurfColor;
629 EXLATEOBJ exlo;
630 FLONG fl = 0;
631 ULONG ulResult = 0;
632
633 pdc = DC_LockDc(hdc);
634 if (!pdc)
635 {
636 DPRINT1("Failed to lock the DC.\n");
637 return 0;
638 }
639
640 psurf = pdc->dclevel.pSurface;
641 if (!psurf)
642 {
643 DPRINT1("DC has no surface.\n");
644 DC_UnlockDc(pdc);
645 return 0;
646 }
647
648 /* Lock the mask bitmap */
649 if (hbmMask)
650 psurfMask = SURFACE_ShareLockSurface(hbmMask);
651 else
652 psurfMask = NULL;
653
654 /* Check for color bitmap */
655 if (hbmColor)
656 {
657 /* We have one, lock it */
658 psurfColor = SURFACE_ShareLockSurface(hbmColor);
659
660 if (psurfColor)
661 {
662 /* Create an XLATEOBJ, no mono support */
663 EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurf->ppal, 0, 0, 0);
664 }
665 }
666 else
667 psurfColor = NULL;
668
669 /* Call the driver or eng function */
670 ulResult = IntEngSetPointerShape(&psurf->SurfObj,
671 psurfMask ? &psurfMask->SurfObj : NULL,
672 psurfColor ? &psurfColor->SurfObj : NULL,
673 psurfColor ? &exlo.xlo : NULL,
674 xHot,
675 yHot,
676 x,
677 y,
678 &pdc->ppdev->Pointer.Exclude,
679 fl | SPS_CHANGE);
680
681 /* Cleanup */
682 if (psurfColor)
683 {
684 EXLATEOBJ_vCleanup(&exlo);
685 SURFACE_ShareUnlockSurface(psurfColor);
686 }
687
688 if (psurfMask)
689 SURFACE_ShareUnlockSurface(psurfMask);
690
691 /* Unlock the DC */
692 DC_UnlockDc(pdc);
693
694 /* Return result */
695 return ulResult;
696 }
697
698 VOID
699 NTAPI
700 GreMovePointer(
701 HDC hdc,
702 LONG x,
703 LONG y)
704 {
705 PDC pdc;
706 PRECTL prcl;
707
708 /* Lock the DC */
709 pdc = DC_LockDc(hdc);
710 if (!pdc)
711 {
712 DPRINT1("Failed to lock the DC.\n");
713 return;
714 }
715
716 /* Store the cursor exclude position in the PDEV */
717 prcl = &pdc->ppdev->Pointer.Exclude;
718
719 /* Call Eng/Drv function */
720 IntEngMovePointer(&pdc->dclevel.pSurface->SurfObj, x, y, prcl);
721
722 /* Unlock the DC */
723 DC_UnlockDc(pdc);
724 }
725
726
727 /* EOF */