2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS win32 subsystem
4 * PURPOSE: Mouse pointer functions
5 * FILE: win32ss/gdi/eng/mouse.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Timo Kreuzer (timo.kreuzer@reactos.org)
9 /* INCLUDES ******************************************************************/
16 /* FUNCTIONS *****************************************************************/
18 __drv_preferredFunction("(see documentation)", "Obsolete, always returns false. ")
23 _In_opt_ SURFOBJ
*psoMask
,
24 _In_opt_ SURFOBJ
*psoColor
,
25 _Reserved_ XLATEOBJ
*pxlo
,
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
35 * FUNCTION: Notify the mouse driver that drawing is about to begin in
36 * a rectangle on a particular surface.
38 _Requires_lock_held_(*ppdev
->hsemDevLock
)
41 MouseSafetyOnDrawStart(
42 _Inout_ PPDEVOBJ ppdev
,
51 ASSERT(ppdev
!= NULL
);
52 ASSERT(ppdev
->pSurface
!= NULL
);
54 pgp
= &ppdev
->Pointer
;
56 if (pgp
->Exclude
.right
== -1)
61 ppdev
->SafetyRemoveCount
++;
63 if (ppdev
->SafetyRemoveLevel
!= 0)
68 if (HazardX1
> HazardX2
)
74 if (HazardY1
> HazardY2
)
81 if (pgp
->Exclude
.right
>= HazardX1
82 && pgp
->Exclude
.left
<= HazardX2
83 && pgp
->Exclude
.bottom
>= HazardY1
84 && pgp
->Exclude
.top
<= HazardY2
)
86 ppdev
->SafetyRemoveLevel
= ppdev
->SafetyRemoveCount
;
87 ppdev
->pfnMovePointer(&ppdev
->pSurface
->SurfObj
, -1, -1, NULL
);
94 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
96 _Requires_lock_held_(*ppdev
->hsemDevLock
)
100 _Inout_ PPDEVOBJ ppdev
)
104 ASSERT(ppdev
!= NULL
);
105 ASSERT(ppdev
->pSurface
!= NULL
);
107 pgp
= &ppdev
->Pointer
;
109 if (pgp
->Exclude
.right
== -1)
114 if (--ppdev
->SafetyRemoveCount
>= ppdev
->SafetyRemoveLevel
)
119 ppdev
->pfnMovePointer(&ppdev
->pSurface
->SurfObj
,
124 ppdev
->SafetyRemoveLevel
= 0;
129 /* SOFTWARE MOUSE POINTER IMPLEMENTATION **************************************/
134 _Inout_ PDEVOBJ
*ppdev
,
135 _Inout_ SURFOBJ
*psoDest
)
145 pgp
= &ppdev
->Pointer
;
152 pgp
->Enabled
= FALSE
;
156 DPRINT("No SaveSurface!\n");
160 /* Calculate cursor coordinates */
161 pt
.x
= ppdev
->ptlPointer
.x
- pgp
->HotSpot
.x
;
162 pt
.y
= ppdev
->ptlPointer
.y
- pgp
->HotSpot
.y
;
164 rclDest
.left
= max(pt
.x
, 0);
165 rclDest
.top
= max(pt
.y
, 0);
166 rclDest
.right
= min(pt
.x
+ pgp
->Size
.cx
, psoDest
->sizlBitmap
.cx
);
167 rclDest
.bottom
= min(pt
.y
+ pgp
->Size
.cy
, psoDest
->sizlBitmap
.cy
);
169 ptlSave
.x
= rclDest
.left
- pt
.x
;
170 ptlSave
.y
= rclDest
.top
- pt
.y
;
172 IntEngBitBlt(psoDest
,
173 &pgp
->psurfSave
->SurfObj
,
182 ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY
));
188 _Inout_ PDEVOBJ
*ppdev
,
189 _Inout_ SURFOBJ
*psoDest
)
193 RECTL rclSurf
, rclPointer
;
198 pgp
= &ppdev
->Pointer
;
207 /* Check if we have any mouse pointer */
208 if (!pgp
->psurfSave
) return;
210 /* Calculate pointer coordinates */
211 pt
.x
= ppdev
->ptlPointer
.x
- pgp
->HotSpot
.x
;
212 pt
.y
= ppdev
->ptlPointer
.y
- pgp
->HotSpot
.y
;
214 /* Calculate the rect on the surface */
215 rclSurf
.left
= max(pt
.x
, 0);
216 rclSurf
.top
= max(pt
.y
, 0);
217 rclSurf
.right
= min(pt
.x
+ pgp
->Size
.cx
, psoDest
->sizlBitmap
.cx
);
218 rclSurf
.bottom
= min(pt
.y
+ pgp
->Size
.cy
, psoDest
->sizlBitmap
.cy
);
220 /* Calculate the rect in the pointer bitmap */
221 rclPointer
.left
= rclSurf
.left
- pt
.x
;
222 rclPointer
.top
= rclSurf
.top
- pt
.y
;
223 rclPointer
.right
= min(pgp
->Size
.cx
, psoDest
->sizlBitmap
.cx
- pt
.x
);
224 rclPointer
.bottom
= min(pgp
->Size
.cy
, psoDest
->sizlBitmap
.cy
- pt
.y
);
226 /* Copy the pixels under the cursor to temporary surface. */
227 IntEngBitBlt(&pgp
->psurfSave
->SurfObj
,
237 ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY
));
239 /* Blt the pointer on the screen. */
242 if(!(pgp
->flags
& SPS_ALPHA
))
244 IntEngBitBlt(psoDest
,
245 &pgp
->psurfMask
->SurfObj
,
250 (POINTL
*)&rclPointer
,
256 IntEngBitBlt(psoDest
,
257 &pgp
->psurfColor
->SurfObj
,
262 (POINTL
*)&rclPointer
,
270 BLENDOBJ blendobj
= { {AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
} };
272 EXLATEOBJ_vInitialize(&exlo
,
276 IntEngAlphaBlend(psoDest
,
277 &pgp
->psurfColor
->SurfObj
,
283 EXLATEOBJ_vCleanup(&exlo
);
288 IntEngBitBlt(psoDest
,
289 &pgp
->psurfMask
->SurfObj
,
294 (POINTL
*)&rclPointer
,
298 ROP4_FROM_INDEX(R3_OPINDEX_SRCAND
));
300 rclPointer
.top
+= pgp
->Size
.cy
;
302 IntEngBitBlt(psoDest
,
303 &pgp
->psurfMask
->SurfObj
,
308 (POINTL
*)&rclPointer
,
312 ROP4_FROM_INDEX(R3_OPINDEX_SRCINVERT
));
323 _In_opt_ SURFOBJ
*psoMask
,
324 _In_opt_ SURFOBJ
*psoColor
,
325 _In_opt_ XLATEOBJ
*pxlo
,
336 HBITMAP hbmSave
= NULL
, hbmColor
= NULL
, hbmMask
= NULL
;
337 PSURFACE psurfSave
= NULL
, psurfColor
= NULL
, psurfMask
= NULL
;
339 SIZEL sizel
= {0, 0};
344 pgp
= &ppdev
->Pointer
;
346 /* Handle the case where we have no XLATEOBJ */
348 pxlo
= &gexloTrivial
.xlo
;
350 /* Do we have any bitmap at all? */
351 if (psoColor
|| psoMask
)
353 /* Get the size of the new pointer */
356 sizel
.cx
= psoColor
->sizlBitmap
.cx
;
357 sizel
.cy
= psoColor
->sizlBitmap
.cy
;
361 sizel
.cx
= psoMask
->sizlBitmap
.cx
;
362 sizel
.cy
= psoMask
->sizlBitmap
.cy
/ 2;
367 rectl
.right
= sizel
.cx
;
368 rectl
.bottom
= sizel
.cy
;
370 /* Calculate lDelta for our surfaces. */
371 lDelta
= WIDTH_BYTES_ALIGN32(sizel
.cx
,
372 BitsPerFormat(pso
->iBitmapFormat
));
374 /* Create a bitmap for saving the pixels under the cursor. */
375 hbmSave
= EngCreateBitmap(sizel
,
378 BMF_TOPDOWN
| BMF_NOZEROINIT
,
380 psurfSave
= SURFACE_ShareLockSurface(hbmSave
);
381 if (!psurfSave
) goto failure
;
388 /* Always store the alpha cursor in RGB. */
389 EXLATEOBJ exloSrcRGB
;
392 pexlo
= CONTAINING_RECORD(pxlo
, EXLATEOBJ
, xlo
);
393 EXLATEOBJ_vInitialize(&exloSrcRGB
, pexlo
->ppalSrc
, &gpalRGB
, 0, 0, 0);
395 hbmColor
= EngCreateBitmap(psoColor
->sizlBitmap
,
396 WIDTH_BYTES_ALIGN32(sizel
.cx
, 32),
398 BMF_TOPDOWN
| BMF_NOZEROINIT
,
400 psurfColor
= SURFACE_ShareLockSurface(hbmColor
);
401 if (!psurfColor
) goto failure
;
403 /* Now copy the given bitmap. */
404 rectl
.bottom
= psoColor
->sizlBitmap
.cy
;
405 IntEngCopyBits(&psurfColor
->SurfObj
,
412 EXLATEOBJ_vCleanup(&exloSrcRGB
);
416 /* Color bitmap must have the same format as the dest surface */
417 if (psoColor
->iBitmapFormat
!= pso
->iBitmapFormat
)
419 DPRINT1("Screen surface and cursor color bitmap format don't match!.\n");
423 /* Create a bitmap to copy the color bitmap to */
424 hbmColor
= EngCreateBitmap(psoColor
->sizlBitmap
,
427 BMF_TOPDOWN
| BMF_NOZEROINIT
,
429 psurfColor
= SURFACE_ShareLockSurface(hbmColor
);
430 if (!psurfColor
) goto failure
;
432 /* Now copy the given bitmap. */
433 rectl
.bottom
= psoColor
->sizlBitmap
.cy
;
434 IntEngCopyBits(&psurfColor
->SurfObj
,
444 /* Create a mask surface */
450 lDelta
= WIDTH_BYTES_ALIGN32(sizel
.cx
, BitsPerFormat(pso
->iBitmapFormat
));
452 /* Create a bitmap for the mask */
453 hbmMask
= EngCreateBitmap(psoMask
->sizlBitmap
,
456 BMF_TOPDOWN
| BMF_NOZEROINIT
,
458 psurfMask
= SURFACE_ShareLockSurface(hbmMask
);
459 if (!psurfMask
) goto failure
;
461 /* Initialize an EXLATEOBJ */
462 ppal
= PALETTE_ShareLockPalette(ppdev
->devinfo
.hpalDefault
);
463 EXLATEOBJ_vInitialize(&exlo
,
470 /* Copy the mask bitmap */
471 rectl
.bottom
= psoMask
->sizlBitmap
.cy
;
472 IntEngCopyBits(&psurfMask
->SurfObj
,
480 EXLATEOBJ_vCleanup(&exlo
);
481 if (ppal
) PALETTE_ShareUnlockPalette(ppal
);
484 /* Hide mouse pointer */
485 IntHideMousePointer(ppdev
, pso
);
487 /* Free old color bitmap */
490 EngDeleteSurface(pgp
->psurfColor
->BaseObject
.hHmgr
);
491 SURFACE_ShareUnlockSurface(pgp
->psurfColor
);
492 pgp
->psurfColor
= NULL
;
495 /* Free old mask bitmap */
498 EngDeleteSurface(pgp
->psurfMask
->BaseObject
.hHmgr
);
499 SURFACE_ShareUnlockSurface(pgp
->psurfMask
);
500 pgp
->psurfMask
= NULL
;
503 /* Free old save bitmap */
506 EngDeleteSurface(pgp
->psurfSave
->BaseObject
.hHmgr
);
507 SURFACE_ShareUnlockSurface(pgp
->psurfSave
);
508 pgp
->psurfSave
= NULL
;
511 /* See if we are being asked to hide the pointer. */
512 if (psoMask
== NULL
&& psoColor
== NULL
)
515 return SPS_ACCEPT_NOEXCLUDE
;
518 /* Now set the new cursor */
519 pgp
->psurfColor
= psurfColor
;
520 pgp
->psurfMask
= psurfMask
;
521 pgp
->psurfSave
= psurfSave
;
522 pgp
->HotSpot
.x
= xHot
;
523 pgp
->HotSpot
.y
= yHot
;
529 ppdev
->ptlPointer
.x
= x
;
530 ppdev
->ptlPointer
.y
= y
;
532 IntShowMousePointer(ppdev
, pso
);
536 prcl
->left
= x
- pgp
->HotSpot
.x
;
537 prcl
->top
= y
- pgp
->HotSpot
.x
;
538 prcl
->right
= prcl
->left
+ pgp
->Size
.cx
;
539 prcl
->bottom
= prcl
->top
+ pgp
->Size
.cy
;
542 else if (prcl
!= NULL
)
544 prcl
->left
= prcl
->top
= prcl
->right
= prcl
->bottom
= -1;
547 return SPS_ACCEPT_NOEXCLUDE
;
550 /* Cleanup surfaces */
551 if (hbmMask
) EngDeleteSurface((HSURF
)hbmMask
);
552 if (psurfMask
) SURFACE_ShareUnlockSurface(psurfMask
);
553 if (hbmColor
) EngDeleteSurface((HSURF
)hbmColor
);
554 if (psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
555 if (hbmSave
) EngDeleteSurface((HSURF
)hbmSave
);
556 if (psurfSave
) SURFACE_ShareUnlockSurface(psurfSave
);
580 pgp
= &ppdev
->Pointer
;
582 IntHideMousePointer(ppdev
, pso
);
584 ppdev
->ptlPointer
.x
= x
;
585 ppdev
->ptlPointer
.y
= y
;
589 IntShowMousePointer(ppdev
, pso
);
592 prcl
->left
= x
- pgp
->HotSpot
.x
;
593 prcl
->top
= y
- pgp
->HotSpot
.y
;
594 prcl
->right
= prcl
->left
+ pgp
->Size
.cx
;
595 prcl
->bottom
= prcl
->top
+ pgp
->Size
.cy
;
598 else if (prcl
!= NULL
)
600 prcl
->left
= prcl
->top
= prcl
->right
= prcl
->bottom
= -1;
606 IntEngSetPointerShape(
608 _In_opt_ SURFOBJ
*psoMask
,
609 _In_opt_ SURFOBJ
*psoColor
,
610 _In_opt_ XLATEOBJ
*pxlo
,
618 ULONG ulResult
= SPS_DECLINE
;
619 PFN_DrvSetPointerShape pfnSetPointerShape
;
620 PPDEVOBJ ppdev
= GDIDEV(pso
);
622 pfnSetPointerShape
= GDIDEVFUNCS(pso
).SetPointerShape
;
624 if (pfnSetPointerShape
)
626 /* Drivers expect to get an XLATEOBJ */
628 pxlo
= &gexloTrivial
.xlo
;
630 /* Call the driver */
631 ulResult
= pfnSetPointerShape(pso
,
643 /* Check if the driver accepted it */
644 if (ulResult
== SPS_ACCEPT_NOEXCLUDE
)
646 /* Set MovePointer to the driver function */
647 ppdev
->pfnMovePointer
= GDIDEVFUNCS(pso
).MovePointer
;
651 /* Set software pointer */
652 ulResult
= EngSetPointerShape(pso
,
662 /* Set MovePointer to the eng function */
663 ppdev
->pfnMovePointer
= EngMovePointer
;
673 _In_opt_ HBITMAP hbmMask
,
674 _In_opt_ HBITMAP hbmColor
,
682 PSURFACE psurf
, psurfMask
, psurfColor
;
686 pdc
= DC_LockDc(hdc
);
689 DPRINT1("Failed to lock the DC.\n");
693 ASSERT(pdc
->dctype
== DCTYPE_DIRECT
);
694 EngAcquireSemaphore(pdc
->ppdev
->hsemDevLock
);
695 /* We're not sure DC surface is the good one */
696 psurf
= pdc
->ppdev
->pSurface
;
699 DPRINT1("DC has no surface.\n");
700 EngReleaseSemaphore(pdc
->ppdev
->hsemDevLock
);
705 /* Lock the mask bitmap */
708 psurfMask
= SURFACE_ShareLockSurface(hbmMask
);
712 //ASSERT(fl & SPS_ALPHA);
716 /* Check for color bitmap */
719 /* We have one, lock it */
720 psurfColor
= SURFACE_ShareLockSurface(hbmColor
);
724 /* Create an XLATEOBJ, no mono support */
725 EXLATEOBJ_vInitialize(&exlo
, psurfColor
->ppal
, psurf
->ppal
, 0, 0, 0);
731 /* We must have a valid surface in case of alpha bitmap */
732 ASSERT(((fl
& SPS_ALPHA
) && psurfColor
) || !(fl
& SPS_ALPHA
));
734 /* Call the driver or eng function */
735 ulResult
= IntEngSetPointerShape(&psurf
->SurfObj
,
736 psurfMask
? &psurfMask
->SurfObj
: NULL
,
737 psurfColor
? &psurfColor
->SurfObj
: NULL
,
738 psurfColor
? &exlo
.xlo
: NULL
,
743 &pdc
->ppdev
->Pointer
.Exclude
,
749 EXLATEOBJ_vCleanup(&exlo
);
750 SURFACE_ShareUnlockSurface(psurfColor
);
754 SURFACE_ShareUnlockSurface(psurfMask
);
756 EngReleaseSemaphore(pdc
->ppdev
->hsemDevLock
);
776 pdc
= DC_LockDc(hdc
);
779 DPRINT1("Failed to lock the DC.\n");
782 ASSERT(pdc
->dctype
== DCTYPE_DIRECT
);
784 /* Acquire PDEV lock */
785 EngAcquireSemaphore(pdc
->ppdev
->hsemDevLock
);
787 /* Check if we need to move it */
788 if(pdc
->ppdev
->SafetyRemoveLevel
== 0)
790 /* Store the cursor exclude position in the PDEV */
791 prcl
= &pdc
->ppdev
->Pointer
.Exclude
;
793 /* Call Eng/Drv function */
794 pdc
->ppdev
->pfnMovePointer(&pdc
->ppdev
->pSurface
->SurfObj
, x
, y
, prcl
);
797 /* Release PDEV lock */
798 EngReleaseSemaphore(pdc
->ppdev
->hsemDevLock
);