435 lines
12 KiB
C
435 lines
12 KiB
C
/******************************Module*Header*******************************\
|
|
* Module Name: pointer.c
|
|
*
|
|
* This module contains the hardware Pointer support.
|
|
*
|
|
* Copyright (c) 1992-1995 Microsoft Corporation
|
|
* Copyright (c) 1993-1995 Weitek Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL 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(
|
|
PDEV* ppdev,
|
|
SURFOBJ* pso)
|
|
{
|
|
ULONG cy;
|
|
BYTE* pjSrcAnd;
|
|
BYTE* pjSrcXor;
|
|
LONG lDeltaSrc;
|
|
LONG lDeltaDst;
|
|
LONG lSrcWidthInBytes;
|
|
ULONG cxSrc;
|
|
ULONG cySrc;
|
|
ULONG cxSrcBytes;
|
|
BYTE* pjDstAnd;
|
|
BYTE* pjDstXor;
|
|
PVIDEO_POINTER_ATTRIBUTES pPointerAttributes;
|
|
|
|
pPointerAttributes = ppdev->pPointerAttributes;
|
|
cxSrc = pso->sizlBitmap.cx;
|
|
cySrc = pso->sizlBitmap.cy;
|
|
pjDstAnd = pPointerAttributes->Pixels;
|
|
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) *
|
|
pPointerAttributes->Height;
|
|
|
|
// Set the desk and mask to 0xff
|
|
|
|
RtlFillMemory(pjDstAnd, pPointerAttributes->WidthInBytes *
|
|
pPointerAttributes->Height, 0xFF);
|
|
|
|
// Zero the dest XOR mask
|
|
|
|
RtlZeroMemory(pjDstXor, pPointerAttributes->WidthInBytes *
|
|
pPointerAttributes->Height);
|
|
|
|
cxSrcBytes = (cxSrc + 7) / 8;
|
|
|
|
if ((lDeltaSrc = pso->lDelta) < 0)
|
|
{
|
|
lSrcWidthInBytes = -lDeltaSrc;
|
|
}
|
|
else
|
|
{
|
|
lSrcWidthInBytes = lDeltaSrc;
|
|
}
|
|
|
|
pjSrcAnd = (BYTE*) pso->pvScan0;
|
|
|
|
// 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 = 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******************************\
|
|
* BOOL 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)
|
|
{
|
|
PDEV* ppdev;
|
|
DWORD returnedDataLength;
|
|
PVIDEO_POINTER_ATTRIBUTES pPointerAttributes;
|
|
|
|
ppdev = (PDEV*) pso->dhpdev;
|
|
|
|
pPointerAttributes = ppdev->pPointerAttributes;
|
|
|
|
// Don't make any assumptions about the pointer flags.
|
|
|
|
pPointerAttributes->Flags = 0;
|
|
|
|
// We don't support color pointers.
|
|
|
|
if (psoColor != NULL)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
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->Column = (SHORT)(x - ppdev->ptlHotSpot.x);
|
|
pPointerAttributes->Row = (SHORT)(y - ppdev->ptlHotSpot.y);
|
|
pPointerAttributes->Enable = 1;
|
|
|
|
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.
|
|
|
|
CP_WAIT(ppdev, ppdev->pjBase);
|
|
|
|
if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_SET_POINTER_ATTR,
|
|
pPointerAttributes, ppdev->cjPointerAttributes, NULL, 0,
|
|
&returnedDataLength))
|
|
{
|
|
|
|
DISPDBG((0, "Failed IOCTL_VIDEO_SET_POINTER_ATTR call"));
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DrvMovePointer
|
|
*
|
|
* Moves the hardware pointer to a new position.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID DrvMovePointer(
|
|
SURFOBJ* pso,
|
|
LONG x,
|
|
LONG y,
|
|
RECTL* prcl)
|
|
{
|
|
PDEV* ppdev;
|
|
DWORD returnedDataLength;
|
|
VIDEO_POINTER_POSITION NewPointerPosition;
|
|
|
|
ppdev = (PDEV*) pso->dhpdev;
|
|
|
|
// 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.
|
|
|
|
CP_WAIT(ppdev, ppdev->pjBase);
|
|
|
|
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((0, "Failed IOCTL_VIDEO_DISABLE_POINTER"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NewPointerPosition.Column = (SHORT) x - (SHORT) (ppdev->ptlHotSpot.x);
|
|
NewPointerPosition.Row = (SHORT) y - (SHORT) (ppdev->ptlHotSpot.y);
|
|
|
|
// Call NT screen 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((0, "Failed IOCTL_VIDEO_SET_POINTER_POSITION"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ULONG 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)
|
|
{
|
|
PDEV* ppdev;
|
|
DWORD returnedDataLength;
|
|
|
|
ppdev = (PDEV*) pso->dhpdev;
|
|
|
|
// 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.
|
|
|
|
if (ppdev->pPointerAttributes == (PVIDEO_POINTER_ATTRIBUTES) NULL)
|
|
{
|
|
// Mini-port has no hardware Pointer support.
|
|
|
|
return(SPS_DECLINE);
|
|
}
|
|
|
|
// See if we are being asked to hide the pointer
|
|
// !!! Wrong
|
|
|
|
if (psoMask == (SURFOBJ *) NULL)
|
|
{
|
|
CP_WAIT(ppdev, ppdev->pjBase);
|
|
|
|
if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_DISABLE_POINTER,
|
|
NULL, 0, NULL, 0, &returnedDataLength))
|
|
{
|
|
// It should never be possible to fail.
|
|
|
|
DISPDBG((0, "Failed IOCTL_VIDEO_DISABLE_POINTER"));
|
|
}
|
|
|
|
return(TRUE); // !!! Wrong
|
|
}
|
|
|
|
ppdev->ptlHotSpot.x = xHot;
|
|
ppdev->ptlHotSpot.y = yHot;
|
|
|
|
if (!bSetHardwarePointerShape(pso,psoMask,psoColor,pxlo,x,y,fl))
|
|
{
|
|
if (ppdev->bHwPointerActive)
|
|
{
|
|
ppdev->bHwPointerActive = FALSE;
|
|
|
|
CP_WAIT(ppdev, ppdev->pjBase);
|
|
|
|
if (EngDeviceIoControl(ppdev->hDriver,
|
|
IOCTL_VIDEO_DISABLE_POINTER, NULL, 0, NULL, 0,
|
|
&returnedDataLength))
|
|
{
|
|
DISPDBG((0, "Failed IOCTL_VIDEO_DISABLE_POINTER"));
|
|
}
|
|
}
|
|
|
|
// Mini-port declines to realize this Pointer
|
|
|
|
return(SPS_DECLINE);
|
|
}
|
|
else
|
|
{
|
|
ppdev->bHwPointerActive = TRUE;
|
|
}
|
|
|
|
return(SPS_ACCEPT_NOEXCLUDE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDisablePointer
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vDisablePointer(
|
|
PDEV* ppdev)
|
|
{
|
|
EngFreeMem(ppdev->pPointerAttributes);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vAssertModePointer
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vAssertModePointer(
|
|
PDEV* ppdev,
|
|
BOOL bEnable)
|
|
{
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bEnablePointer
|
|
*
|
|
* Note: We can return TRUE, as long as pPointerAttributes is set to NULL,
|
|
* and we will make due with a software cursor.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bEnablePointer(
|
|
PDEV* ppdev)
|
|
{
|
|
DWORD returnedDataLength;
|
|
DWORD MaxWidth;
|
|
DWORD MaxHeight;
|
|
VIDEO_POINTER_ATTRIBUTES* pPointerAttributes;
|
|
|
|
ppdev->pPointerAttributes = NULL;
|
|
ppdev->cjPointerAttributes = 0;
|
|
|
|
// 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(TRUE);
|
|
}
|
|
|
|
// 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.
|
|
|
|
// It's a hardware pointer; set up pointer attributes.
|
|
|
|
MaxHeight = ppdev->PointerCapabilities.MaxHeight;
|
|
|
|
// Allocate space for two DIBs (data/mask) for the pointer. If this
|
|
// device supports a color Pointer, we will allocate a larger bitmap.
|
|
// If this is a color bitmap we allocate for the largest possible
|
|
// bitmap because we have no idea of what the pixel depth might be.
|
|
|
|
// Width rounded up to nearest byte multiple
|
|
|
|
if (!(ppdev->PointerCapabilities.Flags & VIDEO_MODE_COLOR_POINTER))
|
|
{
|
|
MaxWidth = (ppdev->PointerCapabilities.MaxWidth + 7) / 8;
|
|
}
|
|
else
|
|
{
|
|
MaxWidth = ppdev->PointerCapabilities.MaxWidth * sizeof(DWORD);
|
|
}
|
|
|
|
ppdev->cjPointerAttributes =
|
|
sizeof(VIDEO_POINTER_ATTRIBUTES) +
|
|
((sizeof(UCHAR) * MaxWidth * MaxHeight) * 2);
|
|
|
|
pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)
|
|
EngAllocMem(FL_ZERO_MEMORY,
|
|
ppdev->cjPointerAttributes, ALLOC_TAG);
|
|
|
|
if (pPointerAttributes == NULL)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
pPointerAttributes->WidthInBytes = MaxWidth;
|
|
pPointerAttributes->Width = ppdev->PointerCapabilities.MaxWidth;
|
|
pPointerAttributes->Height = MaxHeight;
|
|
pPointerAttributes->Column = 0;
|
|
pPointerAttributes->Row = 0;
|
|
pPointerAttributes->Enable = 0;
|
|
|
|
ppdev->pPointerAttributes = pPointerAttributes;
|
|
|
|
return(TRUE);
|
|
}
|