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)
9 /* INCLUDES ******************************************************************/
16 /* FUNCTIONS *****************************************************************/
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
34 * FUNCTION: Notify the mouse driver that drawing is about to begin in
35 * a rectangle on a particular surface.
38 MouseSafetyOnDrawStart(
48 ASSERT(ppdev
!= NULL
);
49 ASSERT(ppdev
->pSurface
!= NULL
);
51 pgp
= &ppdev
->Pointer
;
53 if (pgp
->Exclude
.right
== -1)
58 ppdev
->SafetyRemoveCount
++;
60 if (ppdev
->SafetyRemoveLevel
!= 0)
65 if (HazardX1
> HazardX2
)
71 if (HazardY1
> HazardY2
)
78 if (pgp
->Exclude
.right
>= HazardX1
79 && pgp
->Exclude
.left
<= HazardX2
80 && pgp
->Exclude
.bottom
>= HazardY1
81 && pgp
->Exclude
.top
<= HazardY2
)
83 ppdev
->SafetyRemoveLevel
= ppdev
->SafetyRemoveCount
;
84 ppdev
->pfnMovePointer(&ppdev
->pSurface
->SurfObj
, -1, -1, NULL
);
91 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
99 ASSERT(ppdev
!= NULL
);
100 ASSERT(ppdev
->pSurface
!= NULL
);
102 pgp
= &ppdev
->Pointer
;
104 if (pgp
->Exclude
.right
== -1)
109 if (--ppdev
->SafetyRemoveCount
>= ppdev
->SafetyRemoveLevel
)
114 ppdev
->pfnMovePointer(&ppdev
->pSurface
->SurfObj
,
119 ppdev
->SafetyRemoveLevel
= 0;
124 /* SOFTWARE MOUSE POINTER IMPLEMENTATION **************************************/
140 pgp
= &ppdev
->Pointer
;
147 pgp
->Enabled
= FALSE
;
151 DPRINT("No SaveSurface!\n");
155 /* Calculate cursor coordinates */
156 pt
.x
= ppdev
->ptlPointer
.x
- pgp
->HotSpot
.x
;
157 pt
.y
= ppdev
->ptlPointer
.y
- pgp
->HotSpot
.y
;
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
);
164 ptlSave
.x
= rclDest
.left
- pt
.x
;
165 ptlSave
.y
= rclDest
.top
- pt
.y
;
167 IntEngBitBlt(psoDest
,
168 &pgp
->psurfSave
->SurfObj
,
177 ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY
));
182 IntShowMousePointer(PDEVOBJ
*ppdev
, SURFOBJ
*psoDest
)
186 RECTL rclSurf
, rclPointer
;
191 pgp
= &ppdev
->Pointer
;
200 /* Check if we have any mouse pointer */
201 if (!pgp
->psurfSave
) return;
203 /* Calculate pointer coordinates */
204 pt
.x
= ppdev
->ptlPointer
.x
- pgp
->HotSpot
.x
;
205 pt
.y
= ppdev
->ptlPointer
.y
- pgp
->HotSpot
.y
;
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
);
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
);
219 /* Copy the pixels under the cursor to temporary surface. */
220 IntEngBitBlt(&pgp
->psurfSave
->SurfObj
,
230 ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY
));
232 /* Blt the pointer on the screen. */
235 if(!(pgp
->flags
& SPS_ALPHA
))
237 IntEngBitBlt(psoDest
,
238 &pgp
->psurfMask
->SurfObj
,
243 (POINTL
*)&rclPointer
,
249 IntEngBitBlt(psoDest
,
250 &pgp
->psurfColor
->SurfObj
,
255 (POINTL
*)&rclPointer
,
263 BLENDOBJ blendobj
= { {AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
} };
265 EXLATEOBJ_vInitialize(&exlo
,
269 IntEngAlphaBlend(psoDest
,
270 &pgp
->psurfColor
->SurfObj
,
276 EXLATEOBJ_vCleanup(&exlo
);
281 IntEngBitBlt(psoDest
,
282 &pgp
->psurfMask
->SurfObj
,
287 (POINTL
*)&rclPointer
,
291 ROP4_FROM_INDEX(R3_OPINDEX_SRCAND
));
293 rclPointer
.top
+= pgp
->Size
.cy
;
295 IntEngBitBlt(psoDest
,
296 &pgp
->psurfMask
->SurfObj
,
301 (POINTL
*)&rclPointer
,
305 ROP4_FROM_INDEX(R3_OPINDEX_SRCINVERT
));
316 IN SURFOBJ
*psoColor
,
328 HBITMAP hbmSave
= NULL
, hbmColor
= NULL
, hbmMask
= NULL
;
329 PSURFACE psurfSave
= NULL
, psurfColor
= NULL
, psurfMask
= NULL
;
331 SIZEL sizel
= {0, 0};
336 pgp
= &ppdev
->Pointer
;
338 /* Do we have any bitmap at all? */
339 if (psoColor
|| psoMask
)
341 /* Get the size of the new pointer */
344 sizel
.cx
= psoColor
->sizlBitmap
.cx
;
345 sizel
.cy
= psoColor
->sizlBitmap
.cy
;
349 sizel
.cx
= psoMask
->sizlBitmap
.cx
;
350 sizel
.cy
= psoMask
->sizlBitmap
.cy
/ 2;
355 rectl
.right
= sizel
.cx
;
356 rectl
.bottom
= sizel
.cy
;
358 /* Calculate lDelta for our surfaces. */
359 lDelta
= WIDTH_BYTES_ALIGN32(sizel
.cx
,
360 BitsPerFormat(pso
->iBitmapFormat
));
362 /* Create a bitmap for saving the pixels under the cursor. */
363 hbmSave
= EngCreateBitmap(sizel
,
366 BMF_TOPDOWN
| BMF_NOZEROINIT
,
368 psurfSave
= SURFACE_ShareLockSurface(hbmSave
);
369 if (!psurfSave
) goto failure
;
376 /* Always store the alpha cursor in RGB. */
377 EXLATEOBJ exloSrcRGB
;
380 pexlo
= CONTAINING_RECORD(pxlo
, EXLATEOBJ
, xlo
);
381 EXLATEOBJ_vInitialize(&exloSrcRGB
, pexlo
->ppalSrc
, &gpalRGB
, 0, 0, 0);
383 hbmColor
= EngCreateBitmap(psoColor
->sizlBitmap
,
384 WIDTH_BYTES_ALIGN32(sizel
.cx
, 32),
386 BMF_TOPDOWN
| BMF_NOZEROINIT
,
388 psurfColor
= SURFACE_ShareLockSurface(hbmColor
);
389 if (!psurfColor
) goto failure
;
391 /* Now copy the given bitmap. */
392 rectl
.bottom
= psoColor
->sizlBitmap
.cy
;
393 IntEngCopyBits(&psurfColor
->SurfObj
,
400 EXLATEOBJ_vCleanup(&exloSrcRGB
);
404 /* Color bitmap must have the same format as the dest surface */
405 if (psoColor
->iBitmapFormat
!= pso
->iBitmapFormat
)
407 DPRINT1("Screen surface and cursor color bitmap format don't match!.\n");
411 /* Create a bitmap to copy the color bitmap to */
412 hbmColor
= EngCreateBitmap(psoColor
->sizlBitmap
,
415 BMF_TOPDOWN
| BMF_NOZEROINIT
,
417 psurfColor
= SURFACE_ShareLockSurface(hbmColor
);
418 if (!psurfColor
) goto failure
;
420 /* Now copy the given bitmap. */
421 rectl
.bottom
= psoColor
->sizlBitmap
.cy
;
422 IntEngCopyBits(&psurfColor
->SurfObj
,
432 /* Create a mask surface */
438 lDelta
= WIDTH_BYTES_ALIGN32(sizel
.cx
, BitsPerFormat(pso
->iBitmapFormat
));
440 /* Create a bitmap for the mask */
441 hbmMask
= EngCreateBitmap(psoMask
->sizlBitmap
,
444 BMF_TOPDOWN
| BMF_NOZEROINIT
,
446 psurfMask
= SURFACE_ShareLockSurface(hbmMask
);
447 if (!psurfMask
) goto failure
;
449 /* Initialize an EXLATEOBJ */
450 ppal
= PALETTE_ShareLockPalette(ppdev
->devinfo
.hpalDefault
);
451 EXLATEOBJ_vInitialize(&exlo
,
458 /* Copy the mask bitmap */
459 rectl
.bottom
= psoMask
->sizlBitmap
.cy
;
460 IntEngCopyBits(&psurfMask
->SurfObj
,
468 EXLATEOBJ_vCleanup(&exlo
);
469 if (ppal
) PALETTE_ShareUnlockPalette(ppal
);
472 /* Hide mouse pointer */
473 IntHideMousePointer(ppdev
, pso
);
475 /* Free old color bitmap */
478 EngDeleteSurface(pgp
->psurfColor
->BaseObject
.hHmgr
);
479 SURFACE_ShareUnlockSurface(pgp
->psurfColor
);
480 pgp
->psurfColor
= NULL
;
483 /* Free old mask bitmap */
486 EngDeleteSurface(pgp
->psurfMask
->BaseObject
.hHmgr
);
487 SURFACE_ShareUnlockSurface(pgp
->psurfMask
);
488 pgp
->psurfMask
= NULL
;
491 /* Free old save bitmap */
494 EngDeleteSurface(pgp
->psurfSave
->BaseObject
.hHmgr
);
495 SURFACE_ShareUnlockSurface(pgp
->psurfSave
);
496 pgp
->psurfSave
= NULL
;
499 /* See if we are being asked to hide the pointer. */
500 if (psoMask
== NULL
&& psoColor
== NULL
)
503 return SPS_ACCEPT_NOEXCLUDE
;
506 /* Now set the new cursor */
507 pgp
->psurfColor
= psurfColor
;
508 pgp
->psurfMask
= psurfMask
;
509 pgp
->psurfSave
= psurfSave
;
510 pgp
->HotSpot
.x
= xHot
;
511 pgp
->HotSpot
.y
= yHot
;
517 ppdev
->ptlPointer
.x
= x
;
518 ppdev
->ptlPointer
.y
= y
;
520 IntShowMousePointer(ppdev
, pso
);
524 prcl
->left
= x
- pgp
->HotSpot
.x
;
525 prcl
->top
= y
- pgp
->HotSpot
.x
;
526 prcl
->right
= prcl
->left
+ pgp
->Size
.cx
;
527 prcl
->bottom
= prcl
->top
+ pgp
->Size
.cy
;
530 else if (prcl
!= NULL
)
532 prcl
->left
= prcl
->top
= prcl
->right
= prcl
->bottom
= -1;
535 return SPS_ACCEPT_NOEXCLUDE
;
538 /* Cleanup surfaces */
539 if (hbmMask
) EngDeleteSurface((HSURF
)hbmMask
);
540 if (psurfMask
) SURFACE_ShareUnlockSurface(psurfMask
);
541 if (hbmColor
) EngDeleteSurface((HSURF
)hbmColor
);
542 if (psurfColor
) SURFACE_ShareUnlockSurface(psurfColor
);
543 if (hbmSave
) EngDeleteSurface((HSURF
)hbmSave
);
544 if (psurfSave
) SURFACE_ShareUnlockSurface(psurfSave
);
568 pgp
= &ppdev
->Pointer
;
570 IntHideMousePointer(ppdev
, pso
);
572 ppdev
->ptlPointer
.x
= x
;
573 ppdev
->ptlPointer
.y
= y
;
577 IntShowMousePointer(ppdev
, pso
);
580 prcl
->left
= x
- pgp
->HotSpot
.x
;
581 prcl
->top
= y
- pgp
->HotSpot
.y
;
582 prcl
->right
= prcl
->left
+ pgp
->Size
.cx
;
583 prcl
->bottom
= prcl
->top
+ pgp
->Size
.cy
;
586 else if (prcl
!= NULL
)
588 prcl
->left
= prcl
->top
= prcl
->right
= prcl
->bottom
= -1;
593 IntEngSetPointerShape(
596 IN SURFOBJ
*psoColor
,
605 ULONG ulResult
= SPS_DECLINE
;
606 PFN_DrvSetPointerShape pfnSetPointerShape
;
607 PPDEVOBJ ppdev
= GDIDEV(pso
);
609 pfnSetPointerShape
= GDIDEVFUNCS(pso
).SetPointerShape
;
611 if (pfnSetPointerShape
)
613 ulResult
= pfnSetPointerShape(pso
,
625 /* Check if the driver accepted it */
626 if (ulResult
== SPS_ACCEPT_NOEXCLUDE
)
628 /* Set MovePointer to the driver function */
629 ppdev
->pfnMovePointer
= GDIDEVFUNCS(pso
).MovePointer
;
633 /* Set software pointer */
634 ulResult
= EngSetPointerShape(pso
,
644 /* Set MovePointer to the eng function */
645 ppdev
->pfnMovePointer
= EngMovePointer
;
664 PSURFACE psurf
, psurfMask
, psurfColor
;
668 pdc
= DC_LockDc(hdc
);
671 DPRINT1("Failed to lock the DC.\n");
675 ASSERT(pdc
->dctype
== DCTYPE_DIRECT
);
676 EngAcquireSemaphore(pdc
->ppdev
->hsemDevLock
);
677 /* We're not sure DC surface is the good one */
678 psurf
= pdc
->ppdev
->pSurface
;
681 DPRINT1("DC has no surface.\n");
682 EngReleaseSemaphore(pdc
->ppdev
->hsemDevLock
);
687 /* Lock the mask bitmap */
689 psurfMask
= SURFACE_ShareLockSurface(hbmMask
);
692 //ASSERT(fl & SPS_ALPHA);
696 /* Check for color bitmap */
699 /* We have one, lock it */
700 psurfColor
= SURFACE_ShareLockSurface(hbmColor
);
704 /* Create an XLATEOBJ, no mono support */
705 EXLATEOBJ_vInitialize(&exlo
, psurfColor
->ppal
, psurf
->ppal
, 0, 0, 0);
711 /* We must have a valid surface in case of alpha bitmap */
712 ASSERT(((fl
& SPS_ALPHA
) && psurfColor
) || !(fl
& SPS_ALPHA
));
714 /* Call the driver or eng function */
715 ulResult
= IntEngSetPointerShape(&psurf
->SurfObj
,
716 psurfMask
? &psurfMask
->SurfObj
: NULL
,
717 psurfColor
? &psurfColor
->SurfObj
: NULL
,
718 psurfColor
? &exlo
.xlo
: NULL
,
723 &pdc
->ppdev
->Pointer
.Exclude
,
729 EXLATEOBJ_vCleanup(&exlo
);
730 SURFACE_ShareUnlockSurface(psurfColor
);
734 SURFACE_ShareUnlockSurface(psurfMask
);
736 EngReleaseSemaphore(pdc
->ppdev
->hsemDevLock
);
756 pdc
= DC_LockDc(hdc
);
759 DPRINT1("Failed to lock the DC.\n");
762 ASSERT(pdc
->dctype
== DCTYPE_DIRECT
);
764 /* Acquire PDEV lock */
765 EngAcquireSemaphore(pdc
->ppdev
->hsemDevLock
);
767 /* Check if we need to move it */
768 if(pdc
->ppdev
->SafetyRemoveLevel
== 0)
770 /* Store the cursor exclude position in the PDEV */
771 prcl
= &pdc
->ppdev
->Pointer
.Exclude
;
773 /* Call Eng/Drv function */
774 pdc
->ppdev
->pfnMovePointer(&pdc
->ppdev
->pSurface
->SurfObj
, x
, y
, prcl
);
777 /* Release PDEV lock */
778 EngReleaseSemaphore(pdc
->ppdev
->hsemDevLock
);