- commit base for new vga display miniport driver, is svn copy of framebuf_new as...
[reactos.git] / reactos / drivers / video / displays / vga_new / pointer.c
diff --git a/reactos/drivers/video/displays/vga_new/pointer.c b/reactos/drivers/video/displays/vga_new/pointer.c
new file mode 100755 (executable)
index 0000000..d3752a2
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * PROJECT:         ReactOS Framebuffer Display Driver
+ * LICENSE:         Microsoft NT4 DDK Sample Code License
+ * FILE:            boot/drivers/video/displays/framebuf/pointer.c
+ * PURPOSE:         Hardware Pointer Support
+ * PROGRAMMERS:     Copyright (c) 1992-1995 Microsoft Corporation
+ */
+
+#include "driver.h"
+
+BOOL bCopyColorPointer(
+PPDEV ppdev,
+SURFOBJ *psoMask,
+SURFOBJ *psoColor,
+XLATEOBJ *pxlo);
+
+BOOL bCopyMonoPointer(
+PPDEV ppdev,
+SURFOBJ *psoMask);
+
+BOOL bSetHardwarePointerShape(
+SURFOBJ  *pso,
+SURFOBJ  *psoMask,
+SURFOBJ  *psoColor,
+XLATEOBJ *pxlo,
+LONG      x,
+LONG      y,
+FLONG     fl);
+
+/******************************Public*Routine******************************\
+* DrvMovePointer
+*
+* Moves the hardware pointer to a new position.
+*
+\**************************************************************************/
+
+VOID DrvMovePointer
+(
+    SURFOBJ *pso,
+    LONG     x,
+    LONG     y,
+    RECTL   *prcl
+)
+{
+    PPDEV ppdev = (PPDEV) pso->dhpdev;
+    DWORD returnedDataLength;
+    VIDEO_POINTER_POSITION NewPointerPosition;
+
+    // We don't use the exclusion rectangle because we only support
+    // hardware Pointers. If we were doing our own Pointer simulations
+    // we would want to update prcl so that the engine would call us
+    // to exclude out pointer before drawing to the pixels in prcl.
+
+    UNREFERENCED_PARAMETER(prcl);
+
+    if (x == -1)
+    {
+        //
+        // A new position of (-1,-1) means hide the pointer.
+        //
+
+        if (EngDeviceIoControl(ppdev->hDriver,
+                               IOCTL_VIDEO_DISABLE_POINTER,
+                               NULL,
+                               0,
+                               NULL,
+                               0,
+                               &returnedDataLength))
+        {
+            //
+            // Not the end of the world, print warning in checked build.
+            //
+
+            DISPDBG((1, "DISP vMoveHardwarePointer failed IOCTL_VIDEO_DISABLE_POINTER\n"));
+        }
+    }
+    else
+    {
+        NewPointerPosition.Column = (SHORT) x - (SHORT) (ppdev->ptlHotSpot.x);
+        NewPointerPosition.Row    = (SHORT) y - (SHORT) (ppdev->ptlHotSpot.y);
+
+        //
+        // Call miniport driver to move Pointer.
+        //
+
+        if (EngDeviceIoControl(ppdev->hDriver,
+                               IOCTL_VIDEO_SET_POINTER_POSITION,
+                               &NewPointerPosition,
+                               sizeof(VIDEO_POINTER_POSITION),
+                               NULL,
+                               0,
+                               &returnedDataLength))
+        {
+            //
+            // Not the end of the world, print warning in checked build.
+            //
+
+            DISPDBG((1, "DISP vMoveHardwarePointer failed IOCTL_VIDEO_SET_POINTER_POSITION\n"));
+        }
+    }
+}
+
+/******************************Public*Routine******************************\
+* DrvSetPointerShape
+*
+* Sets the new pointer shape.
+*
+\**************************************************************************/
+
+ULONG DrvSetPointerShape
+(
+    SURFOBJ  *pso,
+    SURFOBJ  *psoMask,
+    SURFOBJ  *psoColor,
+    XLATEOBJ *pxlo,
+    LONG      xHot,
+    LONG      yHot,
+    LONG      x,
+    LONG      y,
+    RECTL    *prcl,
+    FLONG     fl
+)
+{
+    PPDEV   ppdev = (PPDEV) pso->dhpdev;
+    DWORD   returnedDataLength;
+
+    // We don't use the exclusion rectangle because we only support
+    // hardware Pointers. If we were doing our own Pointer simulations
+    // we would want to update prcl so that the engine would call us
+    // to exclude out pointer before drawing to the pixels in prcl.
+    UNREFERENCED_PARAMETER(prcl);
+
+    if (ppdev->pPointerAttributes == (PVIDEO_POINTER_ATTRIBUTES) NULL)
+    {
+        // Mini-port has no hardware Pointer support.
+        return(SPS_ERROR);
+    }
+
+    // See if we are being asked to hide the pointer
+
+    if (psoMask == (SURFOBJ *) NULL)
+    {
+        if (EngDeviceIoControl(ppdev->hDriver,
+                               IOCTL_VIDEO_DISABLE_POINTER,
+                               NULL,
+                               0,
+                               NULL,
+                               0,
+                               &returnedDataLength))
+        {
+            //
+            // It should never be possible to fail.
+            // Message supplied for debugging.
+            //
+
+            DISPDBG((1, "DISP bSetHardwarePointerShape failed IOCTL_VIDEO_DISABLE_POINTER\n"));
+        }
+
+        return(TRUE);
+    }
+
+    ppdev->ptlHotSpot.x = xHot;
+    ppdev->ptlHotSpot.y = yHot;
+
+    if (!bSetHardwarePointerShape(pso,psoMask,psoColor,pxlo,x,y,fl))
+    {
+            if (ppdev->fHwCursorActive) {
+                ppdev->fHwCursorActive = FALSE;
+
+                if (EngDeviceIoControl(ppdev->hDriver,
+                                       IOCTL_VIDEO_DISABLE_POINTER,
+                                       NULL,
+                                       0,
+                                       NULL,
+                                       0,
+                                       &returnedDataLength)) {
+
+                    DISPDBG((1, "DISP bSetHardwarePointerShape failed IOCTL_VIDEO_DISABLE_POINTER\n"));
+                }
+            }
+
+            //
+            // Mini-port declines to realize this Pointer
+            //
+
+            return(SPS_DECLINE);
+    }
+    else
+    {
+        ppdev->fHwCursorActive = TRUE;
+    }
+
+    return(SPS_ACCEPT_NOEXCLUDE);
+}
+
+/******************************Public*Routine******************************\
+* bSetHardwarePointerShape
+*
+* Changes the shape of the Hardware Pointer.
+*
+* Returns: True if successful, False if Pointer shape can't be hardware.
+*
+\**************************************************************************/
+
+BOOL bSetHardwarePointerShape(
+SURFOBJ  *pso,
+SURFOBJ  *psoMask,
+SURFOBJ  *psoColor,
+XLATEOBJ *pxlo,
+LONG      x,
+LONG      y,
+FLONG     fl)
+{
+    PPDEV     ppdev = (PPDEV) pso->dhpdev;
+    PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = ppdev->pPointerAttributes;
+    DWORD     returnedDataLength;
+
+    if (psoColor != (SURFOBJ *) NULL)
+    {
+        if ((ppdev->PointerCapabilities.Flags & VIDEO_MODE_COLOR_POINTER) &&
+                bCopyColorPointer(ppdev, psoMask, psoColor, pxlo))
+        {
+            pPointerAttributes->Flags |= VIDEO_MODE_COLOR_POINTER;
+        } else {
+            return(FALSE);
+        }
+
+    } else {
+
+        if ((ppdev->PointerCapabilities.Flags & VIDEO_MODE_MONO_POINTER) &&
+                bCopyMonoPointer(ppdev, psoMask))
+        {
+            pPointerAttributes->Flags |= VIDEO_MODE_MONO_POINTER;
+        } else {
+            return(FALSE);
+        }
+    }
+
+    //
+    // Initialize Pointer attributes and position
+    //
+
+    pPointerAttributes->Enable = 1;
+
+    //
+    // if x,y = -1,-1 then pass them directly to the miniport so that
+    // the cursor will be disabled
+
+    pPointerAttributes->Column = (SHORT)(x);
+    pPointerAttributes->Row    = (SHORT)(y);
+
+    if ((x != -1) || (y != -1)) {
+        pPointerAttributes->Column -= (SHORT)(ppdev->ptlHotSpot.x);
+        pPointerAttributes->Row    -= (SHORT)(ppdev->ptlHotSpot.y);
+    }
+
+    //
+    // set animate flags
+    //
+
+    if (fl & SPS_ANIMATESTART) {
+        pPointerAttributes->Flags |= VIDEO_MODE_ANIMATE_START;
+    } else if (fl & SPS_ANIMATEUPDATE) {
+        pPointerAttributes->Flags |= VIDEO_MODE_ANIMATE_UPDATE;
+    }
+
+    //
+    // Set the new Pointer shape.
+    //
+
+    if (EngDeviceIoControl(ppdev->hDriver,
+                           IOCTL_VIDEO_SET_POINTER_ATTR,
+                           pPointerAttributes,
+                           ppdev->cjPointerAttributes,
+                           NULL,
+                           0,
+                           &returnedDataLength)) {
+
+        DISPDBG((1, "DISP:Failed IOCTL_VIDEO_SET_POINTER_ATTR call\n"));
+        return(FALSE);
+    }
+
+    return(TRUE);
+}
+
+/******************************Public*Routine******************************\
+* bCopyMonoPointer
+*
+* Copies two monochrome masks into a buffer of the maximum size handled by the
+* miniport, with any extra bits set to 0.  The masks are converted to topdown
+* form if they aren't already.  Returns TRUE if we can handle this pointer in
+* hardware, FALSE if not.
+*
+\**************************************************************************/
+
+BOOL bCopyMonoPointer(
+    PPDEV    ppdev,
+    SURFOBJ *pso)
+{
+    ULONG cy;
+    PBYTE pjSrcAnd, pjSrcXor;
+    LONG  lDeltaSrc, lDeltaDst;
+    LONG  lSrcWidthInBytes;
+    ULONG cxSrc = pso->sizlBitmap.cx;
+    ULONG cySrc = pso->sizlBitmap.cy;
+    ULONG cxSrcBytes;
+    PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = ppdev->pPointerAttributes;
+    PBYTE pjDstAnd = pPointerAttributes->Pixels;
+    PBYTE pjDstXor = pPointerAttributes->Pixels;
+
+    // Make sure the new pointer isn't too big to handle
+    // (*2 because both masks are in there)
+    if ((cxSrc > ppdev->PointerCapabilities.MaxWidth) ||
+        (cySrc > (ppdev->PointerCapabilities.MaxHeight * 2)))
+    {
+        return(FALSE);
+    }
+
+    pjDstXor += ((ppdev->PointerCapabilities.MaxWidth + 7) / 8) *
+            ppdev->pPointerAttributes->Height;
+
+    // set the desk and mask to 0xff
+    RtlFillMemory(pjDstAnd, ppdev->pPointerAttributes->WidthInBytes *
+            ppdev->pPointerAttributes->Height, 0xFF);
+
+    // Zero the dest XOR mask
+    RtlZeroMemory(pjDstXor, ppdev->pPointerAttributes->WidthInBytes *
+            ppdev->pPointerAttributes->Height);
+
+    cxSrcBytes = (cxSrc + 7) / 8;
+
+    if ((lDeltaSrc = pso->lDelta) < 0)
+    {
+        lSrcWidthInBytes = -lDeltaSrc;
+    } else {
+        lSrcWidthInBytes = lDeltaSrc;
+    }
+
+    pjSrcAnd = (PBYTE) pso->pvBits;
+
+    // If the incoming pointer bitmap is bottomup, we'll flip it to topdown to
+    // save the miniport some work
+    if (!(pso->fjBitmap & BMF_TOPDOWN))
+    {
+        // Copy from the bottom
+        pjSrcAnd += lSrcWidthInBytes * (cySrc - 1);
+    }
+
+    // Height of just AND mask
+    cySrc = cySrc / 2;
+
+    // Point to XOR mask
+    pjSrcXor = pjSrcAnd + (cySrc * lDeltaSrc);
+
+    // Offset from end of one dest scan to start of next
+    lDeltaDst = ppdev->pPointerAttributes->WidthInBytes;
+
+    for (cy = 0; cy < cySrc; ++cy)
+    {
+        RtlCopyMemory(pjDstAnd, pjSrcAnd, cxSrcBytes);
+        RtlCopyMemory(pjDstXor, pjSrcXor, cxSrcBytes);
+
+        // Point to next source and dest scans
+        pjSrcAnd += lDeltaSrc;
+        pjSrcXor += lDeltaSrc;
+        pjDstAnd += lDeltaDst;
+        pjDstXor += lDeltaDst;
+    }
+
+    return(TRUE);
+}
+
+/******************************Public*Routine******************************\
+* bCopyColorPointer
+*
+* Copies the mono and color masks into the buffer of maximum size
+* handled by the miniport with any extra bits set to 0. Color translation
+* is handled at this time. The masks are converted to topdown form if they
+* aren't already.  Returns TRUE if we can handle this pointer in  hardware,
+* FALSE if not.
+*
+\**************************************************************************/
+BOOL bCopyColorPointer(
+PPDEV ppdev,
+SURFOBJ *psoMask,
+SURFOBJ *psoColor,
+XLATEOBJ *pxlo)
+{
+    return(FALSE);
+}
+
+
+/******************************Public*Routine******************************\
+* bInitPointer
+*
+* Initialize the Pointer attributes.
+*
+\**************************************************************************/
+
+BOOL bInitPointer(PPDEV ppdev, DEVINFO *pdevinfo)
+{
+    DWORD    returnedDataLength;
+
+    ppdev->pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES) NULL;
+    ppdev->cjPointerAttributes = 0; // initialized in screen.c
+
+    //
+    // Ask the miniport whether it provides pointer support.
+    //
+
+    if (EngDeviceIoControl(ppdev->hDriver,
+                           IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES,
+                           &ppdev->ulMode,
+                           sizeof(PVIDEO_MODE),
+                           &ppdev->PointerCapabilities,
+                           sizeof(ppdev->PointerCapabilities),
+                           &returnedDataLength))
+    {
+         return(FALSE);
+    }
+
+    //
+    // If neither mono nor color hardware pointer is supported, there's no
+    // hardware pointer support and we're done.
+    //
+
+    if ((!(ppdev->PointerCapabilities.Flags & VIDEO_MODE_MONO_POINTER)) &&
+        (!(ppdev->PointerCapabilities.Flags & VIDEO_MODE_COLOR_POINTER)))
+    {
+        return(TRUE);
+    }
+
+    //
+    // Note: The buffer itself is allocated after we set the
+    // mode. At that time we know the pixel depth and we can
+    // allocate the correct size for the color pointer if supported.
+    //
+
+    //
+    // Set the asynchronous support status (async means miniport is capable of
+    // drawing the Pointer at any time, with no interference with any ongoing
+    // drawing operation)
+    //
+
+    if (ppdev->PointerCapabilities.Flags & VIDEO_MODE_ASYNC_POINTER)
+    {
+       pdevinfo->flGraphicsCaps |= GCAPS_ASYNCMOVE;
+    }
+    else
+    {
+       pdevinfo->flGraphicsCaps &= ~GCAPS_ASYNCMOVE;
+    }
+
+    return(TRUE);
+}