Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1688 lines
52 KiB

/******************************Module*Header*******************************\
* Module Name: curseng.cxx
*
* Engine cursor support. These routines are only called by USER to
* set the cursor shape and move it about the screen. This is not the
* engine simulation of the pointer.
*
* Created: 18-Mar-1991 11:39:40
* Author: Tue 12-May-1992 01:49:04 -by- Charles Whitmer [chuckwh]
*
* Copyright (c) 1991-1999 Microsoft Corporation
\**************************************************************************/
#include "precomp.hxx"
// We always create the alpha bitmap from the master shape with two
// rows of pixels on every side to give room for two pixels of blur and
// for an edge of work space.
#define ALPHA_EDGE 3
// Some constants defining the shadow cursor:
#define SHADOW_X_OFFSET 3
#define SHADOW_Y_OFFSET 1
#define SHADOW_ALPHA 0x40000000
/******************************Public*Routine******************************\
* vDetermineSurfaceBounds
*
* Calculate a tight bounds for the surface, given a byte-value that is
* evaluated as the 'space' on the edges.
*
* History:
* 20-Oct-1996 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
LONG galBitsPerPixel[] = { 0, 1, 4, 8, 16, 24, 32 };
VOID vDetermineSurfaceBounds(
SURFOBJ* pso,
BYTE jBlank,
LONG yTop, // Start scan
LONG yBottom, // End scan
RECTL* prclBounds) // Output
{
LONG lDelta;
BYTE* pjScan0;
BYTE* pj;
ULONG cj;
ULONG cy;
ULONG i;
BYTE* pjTop;
BYTE* pjBottom;
BYTE* pjLeft;
BYTE* pjRight;
BYTE jStamp;
LONG iLeft;
LONG iRight;
LONG xRight;
LONG cBitsPerPixel;
ASSERTGDI(pso->iType == STYPE_BITMAP,
"Can directly access only STYPE_BITMAP surfaces");
lDelta = pso->lDelta;
cBitsPerPixel = galBitsPerPixel[pso->iBitmapFormat];
xRight = pso->sizlBitmap.cx;
cj = (xRight * cBitsPerPixel + 7) >> 3;
pjScan0 = (BYTE*) pso->pvScan0;
iLeft = 0;
iRight = cj;
// Blank the right bits up to the byte multiple:
if ((pso->iBitmapFormat == BMF_1BPP) && (xRight & 7))
{
jStamp = (0x100 >> (xRight & 7)) - 1; // 1 -> 0x7f, 2 -> 0x3f ...7 -> 0x01
pjRight = pjScan0 + lDelta * yTop + cj - 1;
if (jBlank)
{
for (pj = pjRight, i = (yBottom - yTop); i != 0; pj += lDelta, i--)
{
*pj |= jStamp;
}
}
else
{
jStamp = ~jStamp;
for (pj = pjRight, i = (yBottom - yTop); i != 0; pj += lDelta, i--)
{
*pj &= jStamp;
}
}
}
// Trim the top:
pjTop = pjScan0 + lDelta * yTop;
while (TRUE)
{
for (pj = pjTop, i = cj; i != 0; pj++, i--)
{
if (*pj != jBlank)
goto Done_Top_Trim;
}
pjTop += lDelta;
yTop++;
// Catch the case where the surface is completely empty:
if (yTop >= yBottom)
{
prclBounds->left = LONG_MAX;
prclBounds->top = LONG_MAX;
prclBounds->right = LONG_MIN;
prclBounds->bottom = LONG_MIN;
return;
}
}
Done_Top_Trim:
// Trim the bottom:
pjBottom = pjScan0 + lDelta * (yBottom - 1);
while (TRUE)
{
for (pj = pjBottom, i = cj; i != 0; pj++, i--)
{
if (*pj != jBlank)
goto Done_Bottom_Trim;
}
pjBottom -= lDelta;
yBottom--;
ASSERTGDI(yTop < yBottom, "Empty cursor should have been caught above");
}
Done_Bottom_Trim:
// Trim the left side:
cy = yBottom - yTop;
pjLeft = pjTop;
while (TRUE)
{
for (pj = pjLeft, i = cy; i != 0; pj += lDelta, i--)
{
if (*pj != jBlank)
goto Done_Left_Trim;
}
pjLeft++;
iLeft++;
ASSERTGDI(iLeft < iRight, "Empty cursor should have been caught above");
}
Done_Left_Trim:
// Trim the right side:
pjRight = pjTop + cj - 1;
while (TRUE)
{
for (pj = pjRight, i = cy; i != 0; pj += lDelta, i--)
{
if (*pj != jBlank)
goto Done_Right_Trim;
}
pjRight--;
iRight--;
ASSERTGDI(iLeft < iRight, "Empty cursor should have been caught above");
}
Done_Right_Trim:
prclBounds->top = yTop;
prclBounds->bottom = yBottom;
prclBounds->left = (8 * iLeft) / cBitsPerPixel; // Floor
prclBounds->right = (8 * iRight + cBitsPerPixel - 1) / cBitsPerPixel; // Ceiling
// Account for the fact that we are checking on bytes worth at a time, and
// so might actually end up somewhat past the right edge of the bitmap:
prclBounds->right = min(prclBounds->right, pso->sizlBitmap.cx);
}
/******************************Public*Routine******************************\
* vCalculateCursorBounds
*
* Calculate a tight bounds for the specified cursor shape.
*
* History:
* 20-Oct-1996 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID vCalculateCursorBounds(
SURFOBJ* psoMask,
SURFOBJ* psoColor,
RECTL* prclBounds)
{
LONG cyMask;
ERECTL erclBounds;
ERECTL erclMask;
cyMask = psoMask->sizlBitmap.cy >> 1;
vDetermineSurfaceBounds(psoMask, 0xff, 0, cyMask, &erclMask);
if (psoColor == NULL)
{
vDetermineSurfaceBounds(psoMask, 0x00, cyMask, 2 * cyMask, &erclBounds);
if (!erclBounds.bWrapped())
{
erclBounds.top -= cyMask;
erclBounds.bottom -= cyMask;
}
}
else
{
vDetermineSurfaceBounds(psoColor, 0x00, 0, cyMask, &erclBounds);
}
// The bounds are the union of the AND mask bounds and the OR mask bounds:
erclBounds |= erclMask;
if (erclBounds.bWrapped())
{
erclBounds.left = 0;
erclBounds.top = 0;
erclBounds.right = 1;
erclBounds.bottom = 1;
}
// KdPrint((">> Cursor bounds: (%li, %li, %li, %li)\n",
// erclBounds.left, erclBounds.top, erclBounds.right, erclBounds.bottom));
//
// Stash the bounds away for next time:
*prclBounds = erclBounds;
}
/******************************Public*Routine******************************\
* bBlurCursorShadow
*
* Do an in-place blur of the cursor shadow (i.e., the blurred image will
* replace the image passed in).
*
* This is done by applying an approximation of a 3x3 boxcar convolution.
*
* The cursor shadow is assumed to be in the MSB of the surface. The surface
* is assumed to be a 32bpp BGRA surface.
*
* History:
* 03-Mar-1998 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
BOOL bBlurCursorShadow(
SURFOBJ* pso)
{
USHORT aus0[64];
USHORT aus1[64];
USHORT aus2[64];
PUSHORT apus[3];
// Function assumes caller will pass a 32bpp surface.
ASSERTGDI(pso->iBitmapFormat == BMF_32BPP,
"bBlurCursorShadow: bad iBitmapFormat\n");
// Must at least be 3x3. Don't bother if it's too small.
if ((pso->sizlBitmap.cx < 3) || (pso->sizlBitmap.cy < 3))
{
WARNING("bBlurCursorShadow: bitmap too small\n");
return(FALSE);
}
// Setup temporary scanline memory. If it will fit, use the stack
// buffer. Otherwise allocate pool memory.
if (pso->sizlBitmap.cx > 64)
{
apus[0] = (PUSHORT) PALLOCMEM(pso->sizlBitmap.cx * sizeof(USHORT) * 3, 'pmtG');
if (apus[0])
{
apus[1] = apus[0] + pso->sizlBitmap.cx;
apus[2] = apus[1] + pso->sizlBitmap.cx;
}
}
else
{
apus[0] = aus0;
apus[1] = aus1;
apus[2] = aus2;
}
if (apus[0] == NULL)
{
WARNING("bBlurCursorShadow: mem alloc failure\n");
return(FALSE);
}
// Fill up the scanline memory with 3x1 boxcar sums for the
// first three scanlines.
PULONG pulIn = (PULONG) pso->pvScan0;
PULONG pulTmp;
USHORT usLast;
USHORT *pus, *pusEnd;
ULONG j;
for (j = 0; j < 3; j++)
{
// Compute the scanline sum. Note that output is two pixels
// smaller than the input.
pus = apus[j];
pusEnd = pus + (pso->sizlBitmap.cx - 2);
pulTmp = pulIn;
while (pus < pusEnd)
{
*pus = (USHORT) ((pulTmp[0] >> 24) + (pulTmp[1] >> 24) + (pulTmp[2] >> 24));
pus += 1;
pulTmp += 1;
}
// Next scanline.
pulIn = (PULONG) (((PBYTE) pulIn) + pso->lDelta);
}
// Compute the average (3x3 boxcar convolution) for each output
// scanline.
PULONG pulOut = ((PULONG) (((PBYTE) pso->pvScan0) + pso->lDelta)) + 1;
ULONG ulNumScans = pso->sizlBitmap.cy - 2;
ULONG ulNext = 0;
while (ulNumScans--)
{
// Setup output pointers.
PULONG pulAvg = pulOut;
PULONG pulAvgEnd = pulAvg + (pso->sizlBitmap.cx - 2);
// Setup pointers to run the scanline 3x1 sums.
PUSHORT pusTmp[3];
pusTmp[0] = apus[0];
pusTmp[1] = apus[1];
pusTmp[2] = apus[2];
// Compute the average scanline.
while (pulAvg < pulAvgEnd)
{
USHORT usSum;
// Strictly speaking we should divide the sum by 9, but since
// this is just for looks, we can approximate as a divide by 8
// minus a divide by 64 (will produce in a slightly too small
// result).
//
// 1/9 = 0.111111111... in decimal
// = 0.000111000111... in binary
//
// Approximations:
//
// 1/8 - 1/64 = 0.109375
// 1/8 - 1/64 + 1/512 = 0.111328125
// 1/8 - 1/64 + 1/512 - 1/4096 = 0.111083984
usSum = *pusTmp[0] + *pusTmp[1] + *pusTmp[2];
//*pulAvg = (usSum / 9) << 24;
//*pulAvg = ((usSum >> 3) - (usSum >> 6)) << 24;
*pulAvg = (usSum >> 3) << 24;
pulAvg += 1;
pusTmp[0] += 1;
pusTmp[1] += 1;
pusTmp[2] += 1;
}
// Next output scanline.
pulOut = (PULONG) (((PBYTE) pulOut) + pso->lDelta);
// Need to compute 3x1 boxcar sum for the next scanline.
if (ulNumScans)
{
// Compute the scanline sum. Note that output is two pixels
// smaller than the input.
pus = apus[ulNext];
pusEnd = pus + (pso->sizlBitmap.cx - 2);
pulTmp = pulIn;
while (pus < pusEnd)
{
*pus = (USHORT) ((pulTmp[0] >> 24) + (pulTmp[1] >> 24) + (pulTmp[2] >> 24));
pus += 1;
pulTmp += 1;
}
// Next scanline.
pulIn = (PULONG) (((PBYTE) pulIn) + pso->lDelta);
// Next scanline summation buffer.
ulNext++;
if (ulNext >= 3)
ulNext = 0;
}
}
// Cleanup temporary memory.
if (apus[0] != aus0)
{
VFREEMEM(apus[0]);
}
return(TRUE);
}
/******************************Public*Routine******************************\
* bApplicationAlphaCursor
*
* This routine will create a pre-muliplied alpha version of the specified
* cursor if the cursor has non-pre-mulitplied alpha values in it.
*
* History:
* 20-Oct-1996 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL bApplicationAlphaCursor(
SURFOBJ* psoAlpha,
SURFOBJ* psoColor,
RECTL* prclBounds)
{
ULONG ulAlpha;
ULONG ul;
ULONG* pulScan0;
ULONG* pul;
ULONG cPixels;
BOOL bPerPixelAlpha;
ULONG i;
RECTL rclDst;
ASSERTGDI(psoColor->iBitmapFormat == BMF_32BPP,
"Expected only BGRA 32-bpp bitmaps");
// Copy the cursor to our alpha surface, accounting for the same
// offset that is needed for shadowed cursors:
rclDst.left = ALPHA_EDGE;
rclDst.top = ALPHA_EDGE;
rclDst.right = ALPHA_EDGE + prclBounds->right;
rclDst.bottom = ALPHA_EDGE + prclBounds->bottom;
EngCopyBits(psoAlpha, psoColor, NULL, NULL, &rclDst, &gptlZero);
// Check for any pixels with non-zero alpha:
cPixels = psoAlpha->sizlBitmap.cx * psoAlpha->sizlBitmap.cy;
pulScan0 = (ULONG*) psoAlpha->pvBits;
bPerPixelAlpha = FALSE;
for (pul = pulScan0, i = cPixels; i != 0; pul++, i--)
{
if ((*pul & 0xff000000) != 0)
{
bPerPixelAlpha = TRUE;
break;
}
}
if (bPerPixelAlpha)
{
// Okay, we can now assume that the application gave us a per-pixel
// alpha cursor shape. Now go through and convert it to pre-multiplied
// alpha.
for (pul = pulScan0, i = cPixels; i != 0; pul++, i--)
{
ul = *pul;
ulAlpha = (ul & 0xff000000) >> 24;
*pul = (((ul & 0xff000000)))
| ((((ul & 0xff0000) * ulAlpha) >> 8) & 0xff0000)
| ((((ul & 0xff00) * ulAlpha) >> 8) & 0xff00)
| ((((ul & 0xff) * ulAlpha) >> 8) & 0xff);
}
}
return(bPerPixelAlpha);
}
/******************************Public*Routine******************************\
* bShadowAlphaCursor
*
* This routine will create a pre-multiplied alpha version of the specified
* cursor along with a shadow mask, assuming that the specified cursor does
* not try to do 'XOR'.
*
* History:
* 20-Oct-1996 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL bShadowAlphaCursor(
SURFOBJ* psoAlpha,
SURFOBJ* psoMask,
SURFOBJ* psoColor,
XLATEOBJ* pxloMask,
XLATEOBJ* pxloColor,
RECTL* prclBounds)
{
BOOL bRet = FALSE; // Assume failure
ULONG cxMask;
ULONG cyMask;
RECTL rclDst;
XLATEOBJ xlo;
ULONG aulXlate[2];
ULONG* pul;
ULONG i;
POINTL ptlSrc;
cyMask = psoMask->sizlBitmap.cy >> 1;
cxMask = psoMask->sizlBitmap.cx;
xlo.pulXlate = aulXlate;
// We can only generate a shadow cursor if there are no XOR pixels
// in the definition of the cursor (because we use an AlphaBlend
// function which has no concept of XOR). So check if there are
// any XOR pixels. We do this by ANDing the XOR mask with the AND
// mask; if any part of the result is non-zero, then there is an
// XOR component to the cursor.
//
// First, make a copy of the AND bits, converting it to 32bpp for
// convenience:
rclDst.left = 0;
rclDst.top = 0;
rclDst.right = cxMask;
rclDst.bottom = cyMask;
if (psoColor != NULL)
{
EngBitBlt(psoAlpha, psoColor, NULL, NULL, pxloColor, &rclDst,
&gptlZero, NULL, NULL, NULL, 0xeeee); // SRCPAINT
}
else
{
ptlSrc.x = 0;
ptlSrc.y = cyMask;
EngBitBlt(psoAlpha, psoMask, NULL, NULL, pxloMask, &rclDst,
&ptlSrc, NULL, NULL, NULL, 0xeeee); // SRCPAINT
}
// Now, AND in the XOR mask. Use a fake XLATEOBJ to do the color
// expansion:
aulXlate[0] = 0x00000000;
aulXlate[1] = 0xffffffff;
EngBitBlt(psoAlpha, psoMask, NULL, NULL, &xlo, &rclDst, &gptlZero,
NULL, NULL, NULL, 0x8888); // SRCAND
// Now check for any non-zero resulting pixels:
pul = (ULONG*) psoAlpha->pvBits;
i = psoAlpha->sizlBitmap.cy * abs(psoAlpha->lDelta) / 4;
for (; i != 0; pul++, i--)
{
if (*pul != 0)
{
return(FALSE);
}
}
// Okay, we're golden for adding the shadow. First, construct a
// rectangle that represents the shadow's position:
rclDst.left = ALPHA_EDGE + SHADOW_X_OFFSET;
rclDst.top = ALPHA_EDGE + SHADOW_Y_OFFSET;
rclDst.right = ALPHA_EDGE + SHADOW_X_OFFSET + prclBounds->right;
rclDst.bottom = ALPHA_EDGE + SHADOW_Y_OFFSET + prclBounds->bottom;
// Create a copy of the mask, giving the mask a particular alpha
// value:
aulXlate[0] = SHADOW_ALPHA;
aulXlate[1] = 0x0;
EngCopyBits(psoAlpha, psoMask, NULL, &xlo, &rclDst, &gptlZero);
// Create the blur from the copy. We invoke the 3x3 blur twice
// to get a better blur (note that we changed ALPHA_EDGE to
// accomodate this).
if (bBlurCursorShadow(psoAlpha) && bBlurCursorShadow(psoAlpha))
{
rclDst.left = ALPHA_EDGE;
rclDst.top = ALPHA_EDGE;
rclDst.right = ALPHA_EDGE + prclBounds->right;
rclDst.bottom = ALPHA_EDGE + prclBounds->bottom;
// Now, zero the opaque pixels:
aulXlate[0] = 0x00000000;
aulXlate[1] = 0xffffffff;
EngBitBlt(psoAlpha, psoMask, NULL, NULL, &xlo, &rclDst, &gptlZero,
NULL, NULL, NULL, 0x8888); // SRCAND
// Now, give all the opaque pixels an alpha value of 0xff:
aulXlate[0] = 0xff000000;
aulXlate[1] = 0x00000000;
EngBitBlt(psoAlpha, psoMask, NULL, NULL, &xlo, &rclDst, &gptlZero,
NULL, NULL, NULL, 0xeeee); // SRCPAINT
// Finally, OR in the opaque bits on top of the shadow:
if (psoColor != NULL)
{
EngBitBlt(psoAlpha, psoColor, NULL, NULL, pxloColor, &rclDst,
&gptlZero, NULL, NULL, NULL, 0xeeee); // SRCPAINT
}
else
{
ptlSrc.x = 0;
ptlSrc.y = cyMask;
EngBitBlt(psoAlpha, psoMask, NULL, NULL, pxloMask, &rclDst,
&ptlSrc, NULL, NULL, NULL, 0xeeee); // SRCPAINT
}
bRet = TRUE;
}
return(bRet);
}
/******************************Public*Routine******************************\
* vProcessCursorShape
*
* This routine will:
*
* 1. Calculate the bounds on the cursor shape;
* 2. Create a pre-multiplied alpha surface if the cursor shape has per-
* pixel alpha;
* 3. Create a pre-multiplied alpha shadow surface for the cursor if
* we've been asked to create a 'shadow'.
*
* History:
* 20-Oct-1996 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID vProcessCursorShape(
HDEV hdev,
BOOL bShadow,
SURFOBJ* psoMask,
SURFOBJ* psoColor,
PALETTE* ppalColor,
RECTL* prclBounds,
HBITMAP* phbmAlpha)
{
SPRITESTATE* pSpriteState;
SURFACE* psurfColor;
SURFMEM SurfDimo;
BOOL bAlpha;
DEVBITMAPINFO dbmi;
SURFOBJ* psoAlpha;
RECTL rclAlpha;
RECTL rclColor;
// Delete the existing hbmAlpha, so that it can be regenerated.
if (*phbmAlpha != NULL)
{
GreDeleteObject(*phbmAlpha);
*phbmAlpha = NULL;
}
// Do a first-pass bounds calculation taking into account only
// the monochrome mask:
vCalculateCursorBounds(psoMask, NULL, prclBounds);
// Create a 32bpp DIB to hold the alpha bits. We add in 4 to
// the dimensions to account for the one pixel extra on every
// side that the blurring result needs, plus the one extra
// pixel on every side that the blurring process needs as work-
// space.
rclAlpha.left = 0;
rclAlpha.top = 0;
rclAlpha.right = SHADOW_X_OFFSET + (2 * ALPHA_EDGE)
+ (psoMask->sizlBitmap.cx);
rclAlpha.bottom = SHADOW_Y_OFFSET + (2 * ALPHA_EDGE)
+ (psoMask->sizlBitmap.cy >> 1);
dbmi.cxBitmap = rclAlpha.right;
dbmi.cyBitmap = rclAlpha.bottom;
dbmi.iFormat = BMF_32BPP;
dbmi.fl = BMF_TOPDOWN;
dbmi.hpal = NULL;
if (SurfDimo.bCreateDIB(&dbmi, NULL))
{
psoAlpha = SurfDimo.pSurfobj();
psurfColor = SURFOBJ_TO_SURFACE_NOT_NULL(psoColor);
EXLATEOBJ xloMono;
EXLATEOBJ xloColor;
XEPALOBJ palColor(ppalColor);
XEPALOBJ palDefault(ppalDefault);
XEPALOBJ palRGB(gppalRGB);
XEPALOBJ palMono(ppalMono);
if (xloMono.bInitXlateObj(NULL, DC_ICM_OFF, palMono, palRGB,
palDefault, palDefault, 0, 0xffffff, 0))
{
if ((psoColor == NULL) ||
(xloColor.bInitXlateObj(NULL, DC_ICM_OFF, palColor, palRGB,
palDefault, palDefault, 0, 0, 0)))
{
bAlpha = FALSE;
if (psoColor != NULL)
{
// Do a second-pass bounds accumulation, taking into
// account both the monochrome and color masks. We
// use the Alpha surface to create a directly-readable
// copy of 'psoColor' (it might be STYPE_DEVBITMAP):
rclColor.left = 0;
rclColor.top = 0;
rclColor.right = psoMask->sizlBitmap.cx;
rclColor.bottom = psoMask->sizlBitmap.cy >> 1;
EngCopyBits(psoAlpha,
psoColor,
NULL,
xloColor.pxlo(),
&rclColor,
&gptlZero);
vCalculateCursorBounds(psoMask, psoAlpha, prclBounds);
}
if ((psoColor != NULL) &&
(xloColor.pxlo()->flXlate & XO_TRIVIAL) &&
(psoColor->iBitmapFormat == BMF_32BPP))
{
EngEraseSurface(psoAlpha, &rclAlpha, 0);
bAlpha = bApplicationAlphaCursor(psoAlpha,
psoColor,
prclBounds);
}
if ((!bAlpha) && (bShadow))
{
EngEraseSurface(psoAlpha, &rclAlpha, 0);
bAlpha = bShadowAlphaCursor(psoAlpha,
psoMask,
psoColor,
xloMono.pxlo(),
xloColor.pxlo(),
prclBounds);
}
if (bAlpha)
{
SurfDimo.vKeepIt();
SurfDimo.vSetPID(OBJECT_OWNER_PUBLIC);
*phbmAlpha = (HBITMAP) SurfDimo.ps->hsurf();
}
}
}
}
}
/******************************Public*Routine******************************\
* vSetPointer
*
* Set the cursor shape, position and hot spot.
*
* History:
* Sat 25-Apr-1998 -by- J. Andrew Goossen [andrewgo]
* Re-wrote it to handle sprites, shadows, and alpha cursors.
*
* Sun 09-Aug-1992 -by- Patrick Haluptzok [patrickh]
* add engine pointer simulations, validate data from USER.
*
* Tue 12-May-1992 01:49:04 -by- Charles Whitmer [chuckwh]
* Wrote it.
\**************************************************************************/
VOID vSetPointer(HDEV hdev, PCURSINFO pci, ULONG fl, ULONG ulTrailLength, ULONG ulFreq)
{
BOOL bShadow = (fl & SPS_ALPHA);
PDEVOBJ po(hdev);
ASSERTGDI(po.bValid() && !po.bMetaDriver(), "Invalid HDEV");
if (po.bDisabled())
return;
// Perhaps we're being told to tear the pointer down.
if (pci == (PCURSINFO) NULL)
{
if (po.bSoftwarePointer())
{
EngSetPointerShape(po.pSurface()->pSurfobj(), NULL, NULL,
NULL, 0, 0, 0, 0, NULL, 0);
}
if (po.bHardwarePointer())
{
PPFNDRV(po, MovePointer)(po.pSurface()->pSurfobj(), -1, -1, NULL);
}
po.bHardwarePointer(FALSE);
po.bSoftwarePointer(FALSE);
po.bMouseTrails(FALSE);
return;
}
// OK, now we have some serious work to be done. We have to have a mask.
// Lock down and validate the cursor.
SURFREF soMask((HSURF) pci->hbmMask);
if (!soMask.bValid() ||
(soMask.ps->iFormat() != BMF_1BPP) ||
(soMask.ps->sizl().cy & 0x0001))
{
WARNING("GreSetPointer failed because of weird cursor\n");
return;
}
XEPALOBJ palSrc;
XEPALOBJ palDisp;
XEPALOBJ palDispDC(ppalDefault);
SURFACE *psurfColor = NULL;
SURFACE *psurfAlpha = NULL;
XLATEOBJ *pxlo = NULL;
EXLATEOBJ xlo;
SURFREF soColor;
SURFREF soAlpha;
PPALETTE ppalSrc;
FLONG flDriver;
RECTL* prclOpaqueBounds;
RECTL rclAlphaBounds;
// We can reference pSurface() only once the Devlock is acquired,
// for dynamic mode changing.
SURFOBJ* psoDisplay = po.pSurface()->pSurfobj();
if (pci->hbmColor)
{
soColor.vAltCheckLock((HSURF) pci->hbmColor);
if (soColor.bValid())
{
if (soColor.ps->sizl().cy != (soMask.ps->sizl().cy >> 1))
{
WARNING("GreSetPointer failed color not half height mask\n");
return;
}
// Handle the weird case where we get a compatible bitmap created
// for the parent:
ppalSrc = soColor.ps->ppal();
if ((ppalSrc == NULL) && (po.hdevParent() != po.hdev()))
{
PDEVOBJ poParent(po.hdevParent());
ppalSrc = poParent.ppalSurf();
}
if (!bIsCompatible(&ppalSrc, ppalSrc, soColor.ps, po.hdev()))
{
WARNING("GreSetPointer failed - bitmap not compatible with surface\n");
return;
}
palSrc.ppalSet(ppalSrc);
palDisp.ppalSet(po.ppalSurf());
if (xlo.bInitXlateObj(NULL, DC_ICM_OFF, palSrc, palDisp, palDispDC,
palDispDC, 0x000000L, 0xFFFFFFL, 0))
{
pxlo = xlo.pxlo();
psurfColor = soColor.ps;
}
}
}
// If we've never seen this cursor before, compute the bounds and
// create the alpha shadow if necessary.
prclOpaqueBounds = (RECTL*) &pci->rcBounds;
if ((prclOpaqueBounds->bottom == 0) ||
((pci->CURSORF_flags & CURSORF_SHADOW) && !bShadow) ||
(!(pci->CURSORF_flags & CURSORF_SHADOW) && bShadow))
{
vProcessCursorShape(hdev,
bShadow,
soMask.pSurfobj(),
psurfColor->pSurfobj(),
ppalSrc,
(RECTL*) &pci->rcBounds,
(HBITMAP*) &pci->hbmAlpha);
if (bShadow)
{
pci->CURSORF_flags |= CURSORF_SHADOW;
}
else
{
pci->CURSORF_flags &= ~CURSORF_SHADOW;
}
}
// Ignore the alpha flag now and use the existence of 'hbmAlpha' to
// determine whether the cursor should use the pre-generated alpha
// surface.
fl &= ~SPS_ALPHA;
if ((pci->hbmAlpha != NULL) && (po.iDitherFormat() > BMF_8BPP))
{
soAlpha.vAltCheckLock((HSURF) pci->hbmAlpha);
psurfAlpha = soAlpha.ps;
rclAlphaBounds.left = pci->rcBounds.left;
rclAlphaBounds.top = pci->rcBounds.top;
rclAlphaBounds.right = pci->rcBounds.right
+ SHADOW_X_OFFSET + (2 * ALPHA_EDGE);
rclAlphaBounds.bottom = pci->rcBounds.bottom
+ SHADOW_Y_OFFSET + (2 * ALPHA_EDGE);
// Trim off the outside edge on all sides, which was used only
// temporarily by the bBlurCursorShadow routine.
rclAlphaBounds.left++;
rclAlphaBounds.top++;
rclAlphaBounds.right--;
rclAlphaBounds.bottom--;
}
ULONG iMode;
LONG xPointer;
LONG yPointer;
RECTL rclBoundsCopy;
BOOL bHardwarePointer;
BOOL bSoftwarePointer;
BOOL bSynchronousPointer;
BOOL bMouseTrails;
if (!po.bDisabled())
{
po.ptlHotSpot(pci->xHotspot, pci->yHotspot);
xPointer = po.ptlPointer().x;
yPointer = po.ptlPointer().y;
flDriver = SPS_CHANGE | (fl & (SPS_ANIMATESTART | SPS_ANIMATEUPDATE));
bHardwarePointer = FALSE;
bSoftwarePointer = TRUE;
bMouseTrails = FALSE;
bSynchronousPointer = FALSE;
if(ulTrailLength != 0 && ulFreq != 0)
{
ulTrailLength = MIN(ulTrailLength, 16);
ulFreq = MIN(ulFreq, 255);
flDriver |= ((ulTrailLength << 8) & SPS_LENGTHMASK);
flDriver |= ((ulFreq <<12) & SPS_FREQMASK);
bMouseTrails = TRUE;
}
if (PPFNVALID(po, SetPointerShape) &&
(!bMouseTrails || (po.flGraphicsCaps2() & GCAPS2_MOUSETRAILS)) )
{
// Give the hardware the first crack at the alpha surface (if
// there is one).
if (psurfAlpha != NULL)
{
if (po.flGraphicsCaps2() & GCAPS2_ALPHACURSOR)
{
rclBoundsCopy = rclAlphaBounds;
iMode = PPFNDRV(po, SetPointerShape)
(psoDisplay,
NULL,
psurfAlpha->pSurfobj(),
NULL,
pci->xHotspot + ALPHA_EDGE,
pci->yHotspot + ALPHA_EDGE,
xPointer,
yPointer,
&rclBoundsCopy,
flDriver | SPS_ALPHA);
// SPS_ACCEPT_EXCLUDE is obsolete ... force software
// iMode is now treated as a set of flags
if(iMode == SPS_ACCEPT_EXCLUDE)
bHardwarePointer = FALSE;
else
bHardwarePointer = (iMode & SPS_ACCEPT_NOEXCLUDE ? TRUE : FALSE);
bSoftwarePointer = !bHardwarePointer;
bSynchronousPointer = (iMode & SPS_ACCEPT_SYNCHRONOUS ? TRUE : FALSE);
}
}
else
{
// Handle the normal, no-alpha, cursor case:
rclBoundsCopy = *prclOpaqueBounds;
iMode = PPFNDRV(po, SetPointerShape)
(psoDisplay,
soMask.pSurfobj(),
psurfColor->pSurfobj(),
pxlo,
pci->xHotspot,
pci->yHotspot,
xPointer,
yPointer,
&rclBoundsCopy,
flDriver);
// Since the introduction of 'sprites', we no longer
// support SPS_ACCEPT_EXCLUDE.
if (iMode == SPS_ACCEPT_EXCLUDE)
{
PPFNDRV(po, MovePointer)(psoDisplay, -1, -1, NULL);
iMode = SPS_DECLINE;
}
bHardwarePointer = (iMode & SPS_ACCEPT_NOEXCLUDE ? TRUE : FALSE);
bSoftwarePointer = !bHardwarePointer;
bSynchronousPointer = (iMode & SPS_ACCEPT_SYNCHRONOUS ? TRUE : FALSE);
}
}
if (bSoftwarePointer)
{
if (psurfAlpha != NULL)
{
EngSetPointerShape(psoDisplay,
NULL,
psurfAlpha->pSurfobj(),
NULL,
pci->xHotspot + ALPHA_EDGE,
pci->yHotspot + ALPHA_EDGE,
xPointer,
yPointer,
&rclAlphaBounds,
flDriver | SPS_ALPHA);
}
else
{
EngSetPointerShape(psoDisplay,
soMask.pSurfobj(),
psurfColor->pSurfobj(),
pxlo,
pci->xHotspot,
pci->yHotspot,
xPointer,
yPointer,
prclOpaqueBounds,
flDriver);
}
}
if ((!bSoftwarePointer) && (po.bSoftwarePointer()))
{
// Turn off software cursor:
EngMovePointer(psoDisplay, -1, -1, NULL);
}
if ((!bHardwarePointer) && (po.bHardwarePointer()))
{
// Turn off hardware cursor:
PPFNDRV(po, MovePointer)(psoDisplay, -1, -1, NULL);
}
po.bSoftwarePointer(bSoftwarePointer);
po.bHardwarePointer(bHardwarePointer);
po.bMouseTrails(bMouseTrails);
// Synchronous pointer flag forces synchronization of pointer even if
// GCAPS_ASYNCMOVE was specified allowing drivers to accept some pointers
// but have them drawn synchronously.
po.bSynchronousPointer(bSynchronousPointer);
}
}
/******************************Public*Routine******************************\
* vMovePointer
*
* Move the Pointer to the specified location. This is called only by
* USER.
*
* History:
* Thu 14-Apr-1994 -by- Patrick Haluptzok [patrickh]
* Optimize / make Async pointers work
*
* See GreMovePointer for info on ulFlags
*
* Tue 12-May-1992 02:11:51 -by- Charles Whitmer [chuckwh]
* Wrote it.
\**************************************************************************/
VOID vMovePointer(HDEV hdev, int x, int y, LONG ulFlags)
{
RECTL *prcl;
SURFOBJ *pso;
PDEVOBJ po(hdev);
ASSERTGDI(po.bValid() && !po.bMetaDriver(), "Invalid HDEV");
// bDisabled can't change with hsemDevLock and hsemPointer both held.
// bPtrHidden can't change unless hsemPointer is held if the
// pointer is currently Async and the device supports Async movement.
if ((po.ptlPointer().x != x) || (po.ptlPointer().y != y) || po.bMouseTrails())
{
po.ptlPointer(x, y);
if (!po.bDisabled())
{
pso = po.pSurface()->pSurfobj();
if (po.bHardwarePointer())
{
if (!PPFNVALID(po, MovePointerEx))
{
PPFNDRV(po, MovePointer)(pso, x, y, NULL);
}
else
{
// Use the Ex entry point to pass additional info
// to the driver. E.g. TS uses this to pass source
// information about mouse moves so that programmatic
// mouse moves that originate at the server are always
// sent down to the client.
PPFNDRV(po, MovePointerEx)(pso, x, y, ulFlags);
}
}
if (po.bSoftwarePointer())
{
EngMovePointer(pso, x, y, NULL);
}
// Panning drivers want to see the pointer update even
// if the pointer isn't enabled, because the position
// is used to update the visible rectangle within the
// virtual desktop space.
//
// Note: There are cases where ntuser will turn off the
// cursor expecting us to ignore pointer moves.
// Unfortunately, this can happen during mode changes where
// ntuser may have a temporarily bigger desktop than
// physically exists in ntgdi. Therefore, we must check
// the pointer position against the virtual desktop bounds.
if ((po.flGraphicsCaps() & GCAPS_PANNING) && (y != -1) &&
(x < pso->sizlBitmap.cx) && (y < pso->sizlBitmap.cy))
{
// The driver wants to be notified of the pointer
// position even if a pointer isn't actually visible
// (invisible panning!). Let it know the pointer is
// still turned off by giving it a negative 'y':
PPFNDRV(po, MovePointer)(pso, x, y - pso->sizlBitmap.cy, NULL);
}
}
}
}
/******************************Public*Routine******************************\
* GreSetPointer
*
* Set the cursor shape and hot spot.
*
\**************************************************************************/
VOID GreSetPointer(HDEV hdev, PCURSINFO pci, ULONG fl, ULONG ulTrailLength, ULONG ulFreq)
{
PVDEV pvdev;
PDISPSURF pds;
LONG csurf;
PDEVOBJ po(hdev);
DEVLOCKOBJ dlo(po);
SEMOBJ so(po.hsemPointer());
// Just pass directly to 'bSetPointer' when not running multi-mon:
if (!po.bMetaDriver())
{
vSetPointer(hdev, pci, fl, ulTrailLength, ulFreq);
}
else
{
// Okay, we've got work to do.
pvdev = (VDEV*) po.dhpdev();
pds = pvdev->pds;
csurf = pvdev->cSurfaces;
do {
vSetPointer(pds->hdev, pci, fl, ulTrailLength, ulFreq);
pds = pds->pdsNext;
} while (--csurf);
}
}
/******************************Public*Routine******************************\
* GreMovePointer
*
* Set the cursor position.
*
*
* ulFlags specified additional information about the move.
* E.g. Termsrv uses this to determine when to send updates to the client.
*
* If you make a programmatic mouse move that originates at the server
* use MP_PROCEDURAL
*
*
\**************************************************************************/
VOID GreMovePointer(HDEV hdev, int x, int y, ULONG ulFlags)
{
GDIFunctionID(GreMovePointer);
PVDEV pvdev;
PDISPSURF pds;
LONG csurf;
BOOL bUnlockBoth = FALSE;
PDEVOBJ po(hdev);
// If the driver has indicated it has bAsyncPointerMove capabilities
// and it currently is managing the pointer, and the pointer is
// supported in hardware so it doesn't need to be excluded
// (indicated by bPtrNeedsExcluding) then we only need to grab the pointer
// mutex which is only grabbed by people trying to make the pointer
// shape change and a few other odd ball places.
//
// Otherwise we grab the DEVLOCK and the pointer mutex which
// ensures nobody else is drawing, changing the pointer shape,
// etc.
if (po.bAsyncPointerMove() && !po.bSoftwarePointer())
{
//
// Note: We pass in NULL for parent semaphore here because we have
// no yet acquired the dev lock and thus under global ordering
// restrictions.
//
GreAcquireSemaphoreEx(po.hsemPointer(), SEMORDER_POINTER, NULL);
// Make sure we really got it, bAsyncPointerMove may change if you
// don't hold the DEVLOCK or the POINTER mutex.
if (!po.bAsyncPointerMove() || po.bSoftwarePointer())
{
// Release and regrab everything, for sure we are safe with
// both of them.
GreReleaseSemaphoreEx(po.hsemPointer());
GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
GreAcquireSemaphoreEx(po.hsemPointer(), SEMORDER_POINTER, po.hsemDevLock());
bUnlockBoth = TRUE;
}
}
else
{
GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
GreAcquireSemaphoreEx(po.hsemPointer(), SEMORDER_POINTER, po.hsemDevLock());
bUnlockBoth = TRUE;
}
GreEnterMonitoredSection(po.ppdev, WD_POINTER);
// Just pass directly to 'vMovePointer' when not running multi-mon:
if (!po.bMetaDriver())
{
vMovePointer(hdev, x, y, ulFlags);
}
else
{
// Okay, we've got work to do.
pvdev = (VDEV*) po.dhpdev();
pds = pvdev->pds;
csurf = pvdev->cSurfaces;
do {
if ((x >= pds->rcl.left) &&
(x < pds->rcl.right) &&
(y >= pds->rcl.top) &&
(y < pds->rcl.bottom))
{
vMovePointer(pds->hdev, x - pds->rcl.left, y - pds->rcl.top,
ulFlags);
}
else
{
vMovePointer(pds->hdev, -1, -1,
ulFlags);
}
pds = pds->pdsNext;
} while (--csurf);
}
po.ptlPointer(x, y);
GreExitMonitoredSection(po.ppdev, WD_POINTER);
GreReleaseSemaphoreEx(po.hsemPointer());
if (bUnlockBoth)
{
GreReleaseSemaphoreEx(po.hsemDevLock());
}
}
/******************************Public*Routine******************************\
* EngSetPointerTag
*
* This is the engine entry point that allows device drivers to create a
* 'tag' that will be combined with the pointer shape whenever it's sent
* to other drivers in the DDML chain via the DrvSetPointerShape call.
*
* This functionality is primarily intended to allow remoting DDML drivers
* to allow a name be added to the pointer to signify who owns 'control' of
* the machine's input. But they don't want to transmit the shape with the
* name over the wire, which is why we adopt the convention that this applies
* to every *other* device in the DDML chain.
*
* History:
* 20-Oct-1996 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL EngSetPointerTag(
HDEV hdev, // Identifies device's PDEV. This is not the MDEV!
SURFOBJ* psoInputMask, // May be NULL when resetting the tag
SURFOBJ* psoInputColor, // Will be NULL if monochrome
XLATEOBJ* pxlo, // Reserved, must be NULL for now
FLONG fl) // Reserved, must be zero for now
{
// We shipped NT4 SP3 with this functionality, but it's obsolete as
// of NT5.
return(FALSE);
}
/******************************Public*Routine******************************\
* DEVLOCKOBJ::bLock
*
* Device locking object. Optionally computes the Rao region.
*
* History:
* Sun 30-Aug-1992 -by- Patrick Haluptzok [patrickh]
* change to boolean return
*
* Mon 27-Apr-1992 22:46:41 -by- Charles Whitmer [chuckwh]
* Clean up again.
*
* Tue 16-Jul-1991 -by- Patrick Haluptzok [patrickh]
* Clean up.
*
* 15-Sep-1990 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
BOOL DEVLOCKOBJ::bLock(XDCOBJ& dco)
{
GDIFunctionID(DEVLOCKOBJ::bLock);
hsemTrg = NULL; // Remember the semaphore we're waiting on.
ppdevTrg = NULL; // Remember pdev we're monitoring.
fl = DLO_VALID; // Remember if it is valid.
// We lock the semphore on direct display DCs and DFB's if
// the device has set GCAPS_SYNCHRONIZEACCESS set.
if (dco.bSynchronizeAccess())
{
// make sure we don't have any wrong sequence of acquiring locks
// should always acquire a DEVLOCK before we have the palette semaphore
ASSERTGDI ( (!GreIsSemaphoreOwnedByCurrentThread(ghsemPalette))
|| (GreIsSemaphoreOwnedByCurrentThread(dco.hsemDcDevLock())),
"potential deadlock!\n");
// Grab the display semaphore
if(dco.bShareAccess())
{
GreAcquireSemaphoreShared(ghsemShareDevLock);
fl |= DLO_SHAREDACCESS;
}
else
{
hsemTrg = dco.hsemDcDevLock();
ppdevTrg = dco.pdc->ppdev();
GreAcquireSemaphoreEx(hsemTrg, SEMORDER_DEVLOCK, NULL);
GreEnterMonitoredSection(ppdevTrg, WD_DEVLOCK);
}
if (dco.pdc->bInFullScreen())
{
fl &= ~(DLO_VALID);
return(FALSE);
}
}
// Compute the new Rao region if it's dirty.
if (dco.pdc->bDirtyRao())
{
if (!dco.pdc->bCompute())
{
fl &= ~(DLO_VALID);
return(FALSE);
}
}
return(TRUE);
}
/******************************Public*Routine******************************\
* DEVLOCKOBJ::vLockNoDrawing
*
* Device locking object for when no drawing will take place.
*
* Used primarily to protect against dynamic mode changing when looking at
* surface fields. Because no drawing will take place, the rao region
* computations and full-screen checks need not be made.
*
* History:
* Thu 8-Feb-1996 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID DEVLOCKOBJ::vLockNoDrawing(XDCOBJ& dco)
{
GDIFunctionID(DEVLOCKOBJ::vLockNoDrawing);
hsemTrg = NULL; // Remember the semaphore we're waiting on.
ppdevTrg = NULL; // Remember pdev we're monitoring.
fl = DLO_VALID; // Remember if it is valid.
// We lock display DC's even if bSynchronizeAccess() isn't set so that
// the surface palette will still be locked down even for device-
// dependent-bitmaps.
PDEVOBJ po(dco.hdev());
if (po.bDisplayPDEV())
{
// Grab the display semaphore
hsemTrg = dco.hsemDcDevLock();
ppdevTrg = dco.pdc->ppdev();
GreAcquireSemaphoreEx(hsemTrg, SEMORDER_DEVLOCK, NULL);
GreEnterMonitoredSection(ppdevTrg, WD_DEVLOCK);
}
}
/******************************Public*Routine******************************\
* DEVLOCKBLTOBJ::bLock
*
* Device locking object. Optionally computes the Rao region.
*
* History:
* Sun 30-Aug-1992 -by- Patrick Haluptzok [patrickh]
* change to boolean return
*
* Mon 27-Apr-1992 22:46:41 -by- Charles Whitmer [chuckwh]
* Clean up again.
*
* Tue 16-Jul-1991 -by- Patrick Haluptzok [patrickh]
* Clean up.
*
* 15-Sep-1990 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
BOOL DEVLOCKBLTOBJ::bLock(XDCOBJ& dco)
{
GDIFunctionID(DEVLOCKBLTOBJ::bLock);
hsemTrg = NULL; // Remember the semaphore we're waiting on.
hsemSrc = NULL; // Remember the semaphore we're waiting on.
ppdevTrg = NULL; // Remember pdev we're monitoring.
ppdevSrc = NULL; // Remember pdev we're monitoring.
fl = DLO_VALID; // Remember if it is valid.
// We lock the semphore on direct display DCs and DFB's if
// the device has set GCAPS_SYNCHRONIZEACCESS set.
if (dco.bSynchronizeAccess())
{
// Grab the display semaphore
if(dco.bShareAccess())
{
GreAcquireSemaphoreShared(ghsemShareDevLock);
fl |= DLO_SHAREDACCESS;
}
else
{
hsemTrg = dco.hsemDcDevLock();
ppdevTrg = dco.pdc->ppdev();
GreAcquireSemaphoreEx(hsemTrg, SEMORDER_DEVLOCK, NULL);
GreEnterMonitoredSection(ppdevTrg, WD_DEVLOCK);
}
// Check if we are in full screen and drawing
// to the Display, this may just be a DFB.
if (dco.bInFullScreen())
{
fl &= ~(DLO_VALID);
return(FALSE);
}
}
// Compute the new Rao region if it's dirty.
if (dco.pdc->bDirtyRao())
{
if (!dco.pdc->bCompute())
{
fl &= ~(DLO_VALID);
return(FALSE);
}
}
return(TRUE);
}
/******************************Public*Routine******************************\
* DEVLOCKBLTOBJ::bLock
*
* Lock both a source and target DC. Used by StretchBlt, PlgBlt and such.
*
* We must check to see if we are in full screen and fail if we are.
*
* History:
* Mon 18-Apr-1994 -by- Patrick Haluptzok [patrickh]
* bSynchronize Checks
*
* 16-Feb-1993 -by- Eric Kutter [erick]
* Added full screen checks
*
* 11-Nov-1992 -by- Donald Sidoroff [donalds]
* Wrote it.
\**************************************************************************/
BOOL DEVLOCKBLTOBJ::bLock(XDCOBJ& dcoTrg, XDCOBJ& dcoSrc)
{
GDIFunctionID(DEVLOCKBLTOBJ::bLock);
hsemTrg = NULL;
hsemSrc = NULL;
ppdevTrg = NULL; // Remember pdev we're monitoring.
ppdevSrc = NULL; // Remember pdev we're monitoring.
fl = DLO_VALID;
if(dcoSrc.bShareAccess() || dcoTrg.bShareAccess())
{
GreAcquireSemaphoreShared(ghsemShareDevLock);
fl |= DLO_SHAREDACCESS;
}
if (dcoSrc.bSynchronizeAccess())
{
// Grab the display semaphore
if(!dcoSrc.bShareAccess())
{
hsemSrc = dcoSrc.hsemDcDevLock();
ppdevSrc = dcoSrc.pdc->ppdev();
GreAcquireSemaphoreEx(hsemSrc, SEMORDER_DEVLOCK, NULL);
GreEnterMonitoredSection(ppdevSrc, WD_DEVLOCK);
}
// Check if we are in full screen and drawing
// to the Display, this may just be a DFB.
if (dcoSrc.bInFullScreen())
{
fl &= ~(DLO_VALID);
return(FALSE);
}
}
if (dcoTrg.bSynchronizeAccess())
{
// Grab the display semaphore
if(!dcoTrg.bShareAccess())
{
hsemTrg = dcoTrg.hsemDcDevLock();
ppdevTrg = dcoTrg.pdc->ppdev();
GreAcquireSemaphoreEx(hsemTrg, SEMORDER_DEVLOCK, NULL);
GreEnterMonitoredSection(ppdevTrg, WD_DEVLOCK);
}
// Check if we are in full screen and drawing
// to the Display, this may just be a DFB.
if (dcoTrg.bInFullScreen())
{
fl = 0;
return(FALSE);
}
}
// Compute the new Rao regions.
if (dcoTrg.pdc->bDirtyRao())
{
if (!dcoTrg.pdc->bCompute())
{
fl &= ~(DLO_VALID);
return(FALSE);
}
}
if (dcoSrc.pdc->bDirtyRao())
{
if (!dcoSrc.pdc->bCompute())
{
fl &= ~(DLO_VALID);
return(FALSE);
}
}
return(TRUE);
}