361 lines
9.6 KiB
C
361 lines
9.6 KiB
C
|
/******************************Module*Header*******************************\
|
||
|
* Module Name: pointer.c
|
||
|
*
|
||
|
* This module contains the hardware pointer support for the display
|
||
|
* driver.
|
||
|
*
|
||
|
* Copyright (c) 1994-1995 Microsoft Corporation
|
||
|
\**************************************************************************/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
// This should match the miniport definition:
|
||
|
|
||
|
#define VIDEO_MODE_LOCAL_POINTER 0x08
|
||
|
|
||
|
// Look-up table for masking the right edge of the given pointer bitmap:
|
||
|
|
||
|
BYTE gajMask[] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFc, 0xFE };
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* VOID DrvMovePointer
|
||
|
*
|
||
|
* NOTE: Because we have set GCAPS_ASYNCMOVE, this call may occur at any
|
||
|
* time, even while we're executing another drawing call!
|
||
|
*
|
||
|
* Consequently, we have to explicitly synchronize any shared
|
||
|
* resources. In our case, since we touch the CRTC register here
|
||
|
* and in the banking code, we synchronize access using a critical
|
||
|
* section.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
VOID DrvMovePointer(
|
||
|
SURFOBJ* pso,
|
||
|
LONG x,
|
||
|
LONG y,
|
||
|
RECTL* prcl)
|
||
|
{
|
||
|
VIDEO_POINTER_POSITION Position;
|
||
|
PDEV* ppdev;
|
||
|
DWORD returnedDataLength;
|
||
|
|
||
|
ppdev = (PDEV*) pso->dhpdev;
|
||
|
|
||
|
#if MULTI_BOARDS
|
||
|
{
|
||
|
if (x != -1)
|
||
|
{
|
||
|
OH* poh;
|
||
|
|
||
|
poh = ((DSURF*) pso->dhsurf)->poh;
|
||
|
x += poh->x;
|
||
|
y += poh->y;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (x == -1)
|
||
|
{
|
||
|
ppdev->bPointerEnabled = FALSE;
|
||
|
EngDeviceIoControl(ppdev->hDriver,
|
||
|
IOCTL_VIDEO_DISABLE_POINTER,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL,
|
||
|
0,
|
||
|
&returnedDataLength);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Position.Column = (short) (x - ppdev->ptlHotSpot.x);
|
||
|
Position.Row = (short) (y - ppdev->ptlHotSpot.y);
|
||
|
|
||
|
if (ppdev->PointerCapabilities.Flags & VIDEO_MODE_LOCAL_POINTER)
|
||
|
{
|
||
|
// This is rather dumb:
|
||
|
|
||
|
IO_CURSOR_X(ppdev, ppdev->pjIoBase, Position.Column + CURSOR_CX);
|
||
|
IO_CURSOR_Y(ppdev, ppdev->pjIoBase, Position.Row + CURSOR_CY);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EngDeviceIoControl(ppdev->hDriver,
|
||
|
IOCTL_VIDEO_SET_POINTER_POSITION,
|
||
|
&Position,
|
||
|
sizeof(VIDEO_POINTER_POSITION),
|
||
|
NULL,
|
||
|
0,
|
||
|
&returnedDataLength);
|
||
|
}
|
||
|
|
||
|
// Don't forget to turn on the pointer, if it was off:
|
||
|
|
||
|
if (!ppdev->bPointerEnabled)
|
||
|
{
|
||
|
ppdev->bPointerEnabled = TRUE;
|
||
|
EngDeviceIoControl(ppdev->hDriver,
|
||
|
IOCTL_VIDEO_ENABLE_POINTER,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL,
|
||
|
0,
|
||
|
&returnedDataLength);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* VOID DrvSetPointerShape
|
||
|
*
|
||
|
* Sets the new pointer shape.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
ULONG DrvSetPointerShape(
|
||
|
SURFOBJ* pso,
|
||
|
SURFOBJ* psoMsk,
|
||
|
SURFOBJ* psoColor,
|
||
|
XLATEOBJ* pxlo,
|
||
|
LONG xHot,
|
||
|
LONG yHot,
|
||
|
LONG x,
|
||
|
LONG y,
|
||
|
RECTL* prcl,
|
||
|
FLONG fl)
|
||
|
{
|
||
|
VIDEO_POINTER_ATTRIBUTES* pPointerAttributes;
|
||
|
PDEV* ppdev;
|
||
|
ULONG cx;
|
||
|
ULONG cy;
|
||
|
LONG cjWhole;
|
||
|
LONG cjDst;
|
||
|
BYTE* pjSrc;
|
||
|
BYTE* pjDst;
|
||
|
LONG lSrcDelta;
|
||
|
LONG lDstDelta;
|
||
|
LONG i;
|
||
|
DWORD returnedDataLength;
|
||
|
|
||
|
ppdev = (PDEV*) pso->dhpdev;
|
||
|
pPointerAttributes = ppdev->pPointerAttributes;
|
||
|
|
||
|
if (pPointerAttributes == NULL)
|
||
|
{
|
||
|
// There are no hardware pointer capabilities:
|
||
|
|
||
|
return(SPS_DECLINE);
|
||
|
}
|
||
|
|
||
|
cx = psoMsk->sizlBitmap.cx;
|
||
|
cy = psoMsk->sizlBitmap.cy / 2;
|
||
|
|
||
|
if ((cx > ppdev->PointerCapabilities.MaxWidth) ||
|
||
|
(cy > ppdev->PointerCapabilities.MaxHeight) ||
|
||
|
(psoColor != NULL) ||
|
||
|
!(fl & SPS_CHANGE) ||
|
||
|
(cx & 0x7))
|
||
|
{
|
||
|
goto HideAndDecline;
|
||
|
}
|
||
|
|
||
|
#if MULTI_BOARDS
|
||
|
{
|
||
|
if (x != -1)
|
||
|
{
|
||
|
OH* poh;
|
||
|
|
||
|
poh = ((DSURF*) pso->dhsurf)->poh;
|
||
|
x += poh->x;
|
||
|
y += poh->y;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
cjWhole = cx / 8;
|
||
|
|
||
|
cjDst = pPointerAttributes->WidthInBytes * pPointerAttributes->Height;
|
||
|
|
||
|
// Copy AND bits:
|
||
|
|
||
|
pjSrc = psoMsk->pvScan0;
|
||
|
lSrcDelta = psoMsk->lDelta;
|
||
|
pjDst = pPointerAttributes->Pixels;
|
||
|
lDstDelta = pPointerAttributes->WidthInBytes;
|
||
|
|
||
|
memset(pjDst, -1, cjDst); // Pad unused AND bits
|
||
|
|
||
|
for (i = cy; i != 0; i--)
|
||
|
{
|
||
|
memcpy(pjDst, pjSrc, cjWhole);
|
||
|
|
||
|
pjSrc += lSrcDelta;
|
||
|
pjDst += lDstDelta;
|
||
|
}
|
||
|
|
||
|
// Copy XOR bits:
|
||
|
|
||
|
pjDst = pPointerAttributes->Pixels + ppdev->cjXorMaskStartOffset;
|
||
|
|
||
|
memset(pjDst, 0, cjDst); // Pad unused XOR bits
|
||
|
|
||
|
for (i = cy; i != 0; i--)
|
||
|
{
|
||
|
memcpy(pjDst, pjSrc, cjWhole);
|
||
|
|
||
|
pjSrc += lSrcDelta;
|
||
|
pjDst += lDstDelta;
|
||
|
}
|
||
|
|
||
|
// Initialize the pointer attributes:
|
||
|
|
||
|
ppdev->ptlHotSpot.x = xHot;
|
||
|
ppdev->ptlHotSpot.y = yHot;
|
||
|
|
||
|
pPointerAttributes->Column = (short) (x - xHot);
|
||
|
pPointerAttributes->Row = (short) (y - yHot);
|
||
|
pPointerAttributes->Enable = (x != -1);
|
||
|
pPointerAttributes->Flags = VIDEO_MODE_MONO_POINTER;
|
||
|
|
||
|
if (fl & SPS_ANIMATESTART)
|
||
|
pPointerAttributes->Flags |= VIDEO_MODE_ANIMATE_START;
|
||
|
else if (fl & SPS_ANIMATEUPDATE)
|
||
|
pPointerAttributes->Flags |= VIDEO_MODE_ANIMATE_UPDATE;
|
||
|
|
||
|
if (ppdev->PointerCapabilities.Flags & VIDEO_MODE_LOCAL_POINTER)
|
||
|
{
|
||
|
// This is rather dumb:
|
||
|
|
||
|
IO_CURSOR_X(ppdev, ppdev->pjIoBase, pPointerAttributes->Column + CURSOR_CX);
|
||
|
IO_CURSOR_Y(ppdev, ppdev->pjIoBase, pPointerAttributes->Row + CURSOR_CY);
|
||
|
}
|
||
|
|
||
|
// Send the bits to the miniport:
|
||
|
|
||
|
ppdev->bPointerEnabled = pPointerAttributes->Enable;
|
||
|
if (EngDeviceIoControl(ppdev->hDriver,
|
||
|
IOCTL_VIDEO_SET_POINTER_ATTR,
|
||
|
ppdev->pPointerAttributes,
|
||
|
ppdev->cjPointerAttributes,
|
||
|
NULL,
|
||
|
0,
|
||
|
&returnedDataLength))
|
||
|
{
|
||
|
goto HideAndDecline;
|
||
|
}
|
||
|
|
||
|
return(SPS_ACCEPT_NOEXCLUDE);
|
||
|
|
||
|
HideAndDecline:
|
||
|
|
||
|
DrvMovePointer(pso, -1, -1, NULL);
|
||
|
|
||
|
return(SPS_DECLINE);
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* VOID vDisablePointer
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
VOID vDisablePointer(
|
||
|
PDEV* ppdev)
|
||
|
{
|
||
|
// Nothing to do, really
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* VOID vAssertModePointer
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
VOID vAssertModePointer(
|
||
|
PDEV* ppdev,
|
||
|
BOOL bEnable)
|
||
|
{
|
||
|
// Nothing to do, really
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* BOOL bEnablePointer
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
BOOL bEnablePointer(
|
||
|
PDEV* ppdev)
|
||
|
{
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* BOOL bInitializePointer
|
||
|
*
|
||
|
* Initialize pointer during driver PDEV initialization -- early enough
|
||
|
* so that we can affect what 'flGraphicsCaps' are passed back to GDI,
|
||
|
* so that we can set GCAPS_ASYNCMOVE appropriately.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
BOOL bInitializePointer(
|
||
|
PDEV* ppdev)
|
||
|
{
|
||
|
VIDEO_POINTER_ATTRIBUTES* pPointerAttributes;
|
||
|
LONG cjWidth;
|
||
|
LONG cjMaxPointer;
|
||
|
DWORD returnedDataLength;
|
||
|
|
||
|
if (!EngDeviceIoControl(ppdev->hDriver,
|
||
|
IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES,
|
||
|
NULL,
|
||
|
0,
|
||
|
&ppdev->PointerCapabilities,
|
||
|
sizeof(ppdev->PointerCapabilities),
|
||
|
&returnedDataLength))
|
||
|
{
|
||
|
if (ppdev->PointerCapabilities.Flags & VIDEO_MODE_MONO_POINTER)
|
||
|
{
|
||
|
cjWidth = (ppdev->PointerCapabilities.MaxWidth + 7) / 8;
|
||
|
cjMaxPointer = 2 * cjWidth * ppdev->PointerCapabilities.MaxHeight;
|
||
|
|
||
|
ppdev->cjXorMaskStartOffset = cjMaxPointer / 2;
|
||
|
ppdev->cjPointerAttributes = sizeof(VIDEO_POINTER_ATTRIBUTES)
|
||
|
+ cjMaxPointer;
|
||
|
|
||
|
pPointerAttributes = (VIDEO_POINTER_ATTRIBUTES*)
|
||
|
EngAllocMem(0, ppdev->cjPointerAttributes, ALLOC_TAG);
|
||
|
|
||
|
if (pPointerAttributes != NULL)
|
||
|
{
|
||
|
ppdev->pPointerAttributes = pPointerAttributes;
|
||
|
|
||
|
pPointerAttributes->WidthInBytes
|
||
|
= cjWidth;
|
||
|
|
||
|
pPointerAttributes->Width
|
||
|
= ppdev->PointerCapabilities.MaxWidth;
|
||
|
|
||
|
pPointerAttributes->Height
|
||
|
= ppdev->PointerCapabilities.MaxHeight;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// We were successful even if the miniport doesn't support a
|
||
|
// hardware pointer:
|
||
|
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* VOID vUnitializePointer
|
||
|
*
|
||
|
* Undoes bInitializePointer.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
VOID vUninitializePointer(
|
||
|
PDEV* ppdev)
|
||
|
{
|
||
|
EngFreeMem(ppdev->pPointerAttributes);
|
||
|
}
|