Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

688 lines
21 KiB

/******************************Module*Header*******************************\
* Module Name: cursor.c *
* *
* Cursor management. *
* *
* Copyright (c) 1992-1995 Microsoft Corporation *
\**************************************************************************/
#include "driver.h"
VOID vShowCursor(PPDEV ppdev);
VOID vHideCursor(PPDEV ppdev);
VOID vComputePointerRect(PPDEV ppdev,RECTL *prcl);
VOID vYankPointer(PPDEV,BOOL); // POINTER.ASM
VOID vDrawPointer(PPDEV,LONG,LONG,BOOL); // POINTER.ASM
ULONG xyCreateMasks // POINTER.ASM
(
PPDEV ppdev,
PVOID pvMask,
PVOID pvColor,
LONG cy,
ULONG *pulXlate,
FSHORT fs,
ULONG fIsDFB
);
BOOL bSetHardwarePointerShape
(
SURFOBJ *pso,
SURFOBJ *psoMask,
SURFOBJ *psoColor,
FLONG fl);
BOOL bCopyInNewCursor(
PPDEV ppdev,
SURFOBJ *pso);
/******************************Public*Routine******************************\
* DrvMovePointer (pso,x,y,prcl) *
* *
* Move the cursor to the specified location. *
* *
\**************************************************************************/
VOID DrvMovePointer(SURFOBJ *pso,LONG x,LONG y,RECTL *prcl)
{
PPDEV ppdev = (PPDEV) pso->dhpdev;
// (-1,-1) indicates that the cursor should be torn down.
if (x == -1)
{
vHideCursor(ppdev);
return;
}
// Note where we want it to be drawn and do it.
ppdev->xyCursor.x = (USHORT) x;
ppdev->xyCursor.y = (USHORT) y;
vShowCursor(ppdev);
// Return the new rectangle occupied by the pointer.
if (prcl != (RECTL *) NULL)
vComputePointerRect(ppdev,prcl);
return;
}
/******************************Public*Routine******************************\
* DrvSetPointerShape (pso,psoMask,psoColor,pxlo,xHot,yHot,x,y,prcl,fl) *
* *
* Set a 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;
PDEVSURF pdsurf = (PDEVSURF) ppdev->pdsurf;
XYPAIR xy;
PVOID pvMask;
PVOID pvColor;
FSHORT fsFlags;
ULONG ulTmp;
ULONG *pulXlate = (PULONG) NULL; // Assume no color translation.
LONG cy;
ULONG fIsDFB ;
// Set the new cursor position
ppdev->xyCursor.x = (USHORT) x;
ppdev->xyCursor.y = (USHORT) y;
// Set the hot spot information
ppdev->xyHotSpot.x = (USHORT) xHot;
ppdev->xyHotSpot.y = (USHORT) yHot;
if (x == -1)
vHideCursor(ppdev);
// If we have a hardware cursor, let the miniport try to realize it
if (ppdev->flCursor & CURSOR_HW)
{
if (bSetHardwarePointerShape(pso,psoMask,psoColor,fl))
{
// We are using the HW cursor and it is enabled.
// Mark out state flag and leave.
ppdev->flCursor |= CURSOR_HW_ACTIVE;
ppdev->flCursor &= ~(CURSOR_DOWN|CURSOR_ANIMATE);
if (fl & SPS_ANIMATEUPDATE)
ppdev->flCursor |= CURSOR_ANIMATE;
return(SPS_ACCEPT_NOEXCLUDE);
}
}
// If we are not in an animation sequence, hide the pointer. Also,
// if we are coming from a hw pointer to a sw pointer, hide the
// hw pointer regardless of animation state.
if ((!(ppdev->flCursor & CURSOR_ANIMATE)) ||
(ppdev->flCursor & CURSOR_HW_ACTIVE)) {
vHideCursor(ppdev);
}
fsFlags = 0;
if (fl & SPS_ANIMATEUPDATE) {
fsFlags |= PTRI_ANIMATE;
ppdev->flCursor |= CURSOR_ANIMATE;
} else {
ppdev->flCursor &= ~CURSOR_ANIMATE;
// Hide the pointer again just in case we are ending an
// animation sequence.
vHideCursor(ppdev);
}
ppdev->flCursor &= ~CURSOR_HW_ACTIVE;
// We can't handle software pointers on 1 R/W adapters.
if (pdsurf->vbtBankingType == VideoBanked1RW) {
goto DeclineCursor;
}
// If the VGA doesn't support usable offscreen memory, we can't use our
// nifty cursor code, which uses offscreen memory for saving under the
// cursor, so we'll have to let the engine handle it.
if (!(ppdev->fl & DRIVER_OFFSCREEN_REFRESHED)) {
goto DeclineCursor;
}
// If the mask is too big, we just can't handle it on the VGA.
if ((psoMask->sizlBitmap.cx > 32) || (psoMask->sizlBitmap.cy > 64)) {
vHideCursor(ppdev); // get the old software cursor off the screen, if
// there is one
goto DeclineCursor;
}
// Since there is a mask, get its data for xyCreateMasks().
pvMask = psoMask->pvBits;
cy = psoMask->sizlBitmap.cy / 2;
if (!(psoMask->fjBitmap & BMF_TOPDOWN))
fsFlags |= PTRI_INVERT;
// There may be some color. Get the pointer or NULL and set the
// color cursor flag in the PDEV accordingly.
if (psoColor == (SURFOBJ *) NULL)
{
pvColor = (PVOID) NULL;
ppdev->flCursor &= ~CURSOR_COLOR;
}
else
{
if ( (psoColor->iType == STYPE_DEVBITMAP) ) {
fIsDFB = 1 ;
}
else {
fIsDFB = 0 ;
if ( psoColor->iBitmapFormat != BMF_4BPP ) {
goto DeclineCursor;
}
}
if ( psoColor->iType == STYPE_DEVBITMAP ) {
pvColor = ((PDEVSURF)(psoColor->dhsurf))->pvBitmapStart ;
// flag for both pointers coming in TOP_DOWN.
// DFBs always come in TOP DOWN
if (psoMask->fjBitmap & BMF_TOPDOWN)
fsFlags |= 0x80;
}
else {
pvColor = psoColor->pvBits; // only works for DIBS
// flag for both pointers coming in TOP_DOWN.
if ((psoMask->fjBitmap & BMF_TOPDOWN) &&
(psoColor->fjBitmap & BMF_TOPDOWN))
fsFlags |= 0x80;
// flag for mask coming in TOP_DOWN, but color coming in
// BOTTOM_UP
if ((psoMask->fjBitmap & BMF_TOPDOWN) &&
!(psoColor->fjBitmap & BMF_TOPDOWN))
fsFlags |= 0x40;
}
ppdev->flCursor |= CURSOR_COLOR;
cy = psoColor->sizlBitmap.cy;
// bitmaps currently may come in 2x high, so we might have to
// compute where the AND mask really starts in an inverted
// bitmap.
if (fsFlags & PTRI_INVERT)
pvMask = (BYTE *)psoMask->pvScan0 + (psoMask->lDelta * (cy - 1));
if (pxlo->flXlate & XO_TABLE)
pulXlate = pxlo->pulXlate;
}
// Create the masks for the cursor
ulTmp = xyCreateMasks(ppdev,pvMask,pvColor,cy,pulXlate,fsFlags,fIsDFB);
// It is valid for ulTmp to be zero. Some applications set the
// pointer shape to be blank and our pointer code optimizes this
// down to the smallest possible drawing area which in this case
// is an empty rect. But this is still a valid pointer.
if (ulTmp == 0) {
xy.x = 32;
xy.y = 32;
} else
xy = *((XYPAIR *)&ulTmp);
// Set up hit testing information in the PDEV
ppdev->ptlExtent.x = xy.x;
ppdev->ptlExtent.y = xy.y;
// This tells us how many aligned pels we need to exclude.
// If POINTER_ROUNDING_SIZE is 8, then a common extent of xy.x=16 will
// give cExtent=24, i.e. we always have to protect 3 bytes.
ppdev->cExtent = (xy.x + 2 * POINTER_ROUNDING_SIZE - 2) & POINTER_MASK;
// Enable drawing functions and mark cursor as down
ppdev->flCursor |= CURSOR_DOWN;
// Draw the cursor.
if (x != -1)
{
vShowCursor(ppdev);
// Set the new rectangle occupied by the pointer, and return the exclusion
// status
vComputePointerRect(ppdev,prcl);
}
return(SPS_ACCEPT_EXCLUDE);
//
// We choose not to handle this particular cursor bitmap.
//
DeclineCursor:
return(SPS_DECLINE);
}
/******************************Public*Routine******************************\
* vComputePointerRect (ppdev,prcl) *
* *
* Computes the boundary around the pointer that GDI should avoid writing *
* on. *
* *
\**************************************************************************/
VOID vComputePointerRect(PPDEV ppdev,RECTL *prcl)
{
XYPAIR xy;
XYPAIR xyHotSpot;
xy = ppdev->xyCursor;
xyHotSpot = ppdev->xyHotSpot;
prcl->left = (xy.x - xyHotSpot.x) & POINTER_MASK;
prcl->right = prcl->left + ppdev->cExtent;
prcl->top = xy.y - xyHotSpot.y;
prcl->bottom = prcl->top + ppdev->ptlExtent.y;
}
/*****************************Private*Routine******************************\
* VOID vShowCursor(ppdev) *
* *
* Try to draw the cursor. *
* *
\**************************************************************************/
VOID vShowCursor(PPDEV ppdev)
{
XYPAIR xy;
XYPAIR xyHotSpot;
xy = ppdev->xyCursor;
xyHotSpot = ppdev->xyHotSpot;
if (ppdev->flCursor & CURSOR_HW_ACTIVE)
{
DWORD returnedDataLength;
VIDEO_POINTER_POSITION PointerPosition;
PointerPosition.Column = ppdev->pPointerAttributes->Column =
(SHORT)(xy.x - xyHotSpot.x);
PointerPosition.Row = ppdev->pPointerAttributes->Row =
(SHORT)(xy.y - xyHotSpot.y);
//
// Call miniport to move pointer.
//
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_SET_POINTER_POSITION,
&PointerPosition,
sizeof(VIDEO_POINTER_POSITION),
NULL,
0,
&returnedDataLength))
{
DISPDBG((0, "vShowCursor fail IOCTL_VIDEO_SET_POINTER_POSITION\n"));
}
}
else
{
vDrawPointer(ppdev, (LONG) (xy.x - xyHotSpot.x),
(LONG) (xy.y - xyHotSpot.y),
ppdev->flCursor & CURSOR_COLOR);
}
ppdev->flCursor &= ~CURSOR_DOWN;
}
/*****************************Private*Routine******************************\
* VOID vHideCursor(ppdev) *
* *
* Try to hide the cursor *
* *
\**************************************************************************/
VOID vHideCursor(PPDEV ppdev)
{
if (ppdev->flCursor & CURSOR_DOWN)
return;
//
// if this is a hardware cursor, hide it by moving it off the
// screen.
//
if (ppdev->flCursor & CURSOR_HW_ACTIVE)
{
DWORD returnedDataLength;
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_DISABLE_POINTER,
NULL,
0,
NULL,
0,
&returnedDataLength))
{
//
// It should never be possible to fail.
//
DISPDBG((0, "vHideCursor failed IOCTL_VIDEO_DISABLE_POINTER\n"));
}
}
else
{
vYankPointer(ppdev, ppdev->flCursor & CURSOR_COLOR);
}
ppdev->flCursor |= CURSOR_DOWN;
}
/******************************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,
FLONG fl)
{
PPDEV ppdev = (PPDEV) pso->dhpdev;
PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = ppdev->pPointerAttributes;
DWORD returnedDataLength;
pPointerAttributes->Flags = 0;
// BUGBUG only supports monochrome cursor for now
if (psoColor != (SURFOBJ *) NULL)
{
return(FALSE);
} else {
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;
}
// Copy the pixels into the buffer.
if (!bCopyInNewCursor(ppdev, psoMask))
{
return(FALSE);
}
// Initialize cursor attributes and position
pPointerAttributes->Column = ppdev->xyCursor.x - ppdev->xyHotSpot.x;
pPointerAttributes->Row = ppdev->xyCursor.y - ppdev->xyHotSpot.y;
pPointerAttributes->Enable = 1;
if (!(ppdev->flCursor & CURSOR_HW_ACTIVE)) {
vHideCursor(ppdev);
}
// Set the new cursor shape.
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_SET_POINTER_ATTR,
pPointerAttributes,
ppdev->cjPointerAttributes,
NULL,
0,
&returnedDataLength)) {
return(FALSE);
}
return(TRUE);
}
/******************************Public*Routine******************************\
* bCopyInNewCursor
*
* 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 bCopyInNewCursor(
PPDEV ppdev,
SURFOBJ *pso)
{
ULONG cx;
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 + ppdev->XorMaskStartOffset;
// 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);
}
// Pad the XOR mask with -1's
memset(pjDstXor, 0xFFFFFFFF, ppdev->pPointerAttributes->WidthInBytes *
ppdev->pPointerAttributes->Height);
// Pad the AND mask with 0's
memset(pjDstAnd, 0, 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 to next source scan line
lDeltaSrc -= cxSrcBytes;
// Offset from end of one dest scan to start of next
lDeltaDst = ppdev->pPointerAttributes->WidthInBytes - cxSrcBytes;
for (cy = 0; cy < cySrc; ++cy)
{
// Copy however many mask bytes are on this scan line
for (cx = 0; cx < cxSrcBytes; ++cx)
{
*pjDstAnd++ = *pjSrcAnd++;
*pjDstXor++ = *pjSrcXor++;
}
// Point to next source and dest scans
pjSrcAnd += lDeltaSrc;
pjSrcXor += lDeltaSrc;
pjDstAnd += lDeltaDst;
pjDstXor += lDeltaDst;
}
return(TRUE);
}
/******************************Public*Routine******************************\
* bInitPointer
*
* Initialize the Cursor attributes.
*
\**************************************************************************/
BOOL bInitPointer(PPDEV ppdev)
{
DWORD returnedDataLength;
ULONG MaxWidthB, MaxHeight;
ppdev->flCursor &= ~CURSOR_HW; // assume there's no hardware pointer
ppdev->pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES) NULL;
// Ask the miniport whether it provides pointer support.
// If it fails assume there is no hardware pointer.
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES,
NULL,
0,
&ppdev->PointerCapabilities,
sizeof(ppdev->PointerCapabilities),
&returnedDataLength))
{
// miniport does not support a hardware pointer.
ppdev->PointerCapabilities.Flags = 0;
ppdev->PointerCapabilities.MaxWidth = 0;
ppdev->PointerCapabilities.MaxHeight = 0;
ppdev->PointerCapabilities.HWPtrBitmapStart = 0;
ppdev->PointerCapabilities.HWPtrBitmapEnd = 0;
}
// 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);
}
// It's a hardware pointer; set up pointer attributes.
MaxHeight = ppdev->PointerCapabilities.MaxHeight;
if (ppdev->PointerCapabilities.Flags & VIDEO_MODE_COLOR_POINTER)
{
// If color supported, allocate space for two 4-bpp DIBs (data/mask;
// mask is actually 1-bpp, but it has the same width in bytes as the
// data for convenience)
// Width rounded up to nearest byte multiple
MaxWidthB = (ppdev->PointerCapabilities.MaxWidth + 1) / 2;
}
else
{
// If color not supported, must be mono, allocate space for two 1-bpp
// DIBs (data/mask).
// Width rounded up to nearest byte multiple
MaxWidthB = (ppdev->PointerCapabilities.MaxWidth + 7) / 8;
}
ppdev->cjPointerAttributes =
sizeof(VIDEO_POINTER_ATTRIBUTES) +
((sizeof(UCHAR) * MaxWidthB * MaxHeight) * 2);
ppdev->pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)
EngAllocMem(0, ppdev->cjPointerAttributes, ALLOC_TAG);
if (ppdev->pPointerAttributes == NULL) {
DISPDBG((0, "bInitPointer EngAllocMem failed\n"));
return(FALSE);
}
ppdev->XorMaskStartOffset = MaxWidthB * MaxHeight;
ppdev->pPointerAttributes->Flags = ppdev->PointerCapabilities.Flags;
ppdev->pPointerAttributes->WidthInBytes = MaxWidthB;
ppdev->pPointerAttributes->Width = ppdev->PointerCapabilities.MaxWidth;
ppdev->pPointerAttributes->Height = MaxHeight;
ppdev->pPointerAttributes->Column = 0;
ppdev->pPointerAttributes->Row = 0;
ppdev->pPointerAttributes->Enable = 0;
// Set the asynchronous support status (async means miniport is capable of
// drawing the cursor at any time, with no interference with any ongoing
// drawing operation)
if (ppdev->PointerCapabilities.Flags & VIDEO_MODE_ASYNC_POINTER)
{
ppdev->devinfo.flGraphicsCaps |= GCAPS_ASYNCMOVE;
}
else
{
ppdev->devinfo.flGraphicsCaps &= ~GCAPS_ASYNCMOVE;
}
// set flag in flCursor that says HW cursor is present and clear flag in
// fl that says offscreen video memory is usable
ppdev->flCursor |= CURSOR_HW;
ppdev->fl &= ~DRIVER_OFFSCREEN_REFRESHED;
return(TRUE);
}