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