mirror of https://github.com/lianthony/NT4.0
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.
1316 lines
36 KiB
1316 lines
36 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 Microsoft Corporation *
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
BOOL SimSetPointerShape
|
|
(
|
|
SURFOBJ*,
|
|
SURFOBJ*,
|
|
SURFOBJ*,
|
|
XLATEOBJ*,
|
|
LONG,
|
|
LONG,
|
|
LONG,
|
|
LONG,
|
|
RECTL*,
|
|
FLONG
|
|
);
|
|
|
|
VOID SimMovePointer(SURFOBJ *pso,LONG x,LONG y,RECTL *prcl);
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreSetPointer
|
|
*
|
|
* Set the cursor shape, position and hot spot.
|
|
*
|
|
* History:
|
|
* 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 GreSetPointer(HDEV hdev, PCURSINFO pci, ULONG fl)
|
|
{
|
|
PDEVOBJ po(hdev);
|
|
|
|
if (po.bDisabled())
|
|
return;
|
|
|
|
fl &= (SPS_ANIMATESTART | SPS_ANIMATEUPDATE);
|
|
|
|
//
|
|
// Perhaps we're being told to tear the pointer down. Just move it off the
|
|
// surface.
|
|
//
|
|
|
|
if (pci == (PCURSINFO) NULL)
|
|
{
|
|
VACQUIREDEVLOCK(po.pDevLock());
|
|
{
|
|
MUTEXOBJ mutP(po.pfmPointer());
|
|
|
|
if (!po.bPtrHidden())
|
|
{
|
|
po.pfnMove()(po.pSurface()->pSurfobj(),-1,-1,NULL); // Hide it.
|
|
|
|
//
|
|
// bPtrHidden is basically bPtrEnabled. This is the only place
|
|
// that sets the cursor to being hidden.
|
|
//
|
|
|
|
po.bPtrHidden(TRUE);
|
|
po.bPtrDirectDrawOccluded(FALSE);
|
|
}
|
|
}
|
|
VRELEASEDEVLOCK(po.pDevLock());
|
|
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))
|
|
{
|
|
WARNING("GreSetPointer failed because of invalid cursor handle\n");
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check that mask is even height.
|
|
//
|
|
|
|
if (soMask.ps->sizl().cy & 0x0001)
|
|
{
|
|
WARNING("GreSetPointer failed odd height mask\n");
|
|
return;
|
|
}
|
|
|
|
//
|
|
// We may have color.
|
|
//
|
|
|
|
XEPALOBJ palSrc;
|
|
XEPALOBJ palDisp;
|
|
XEPALOBJ palDispDC(ppalDefault);
|
|
SURFACE *psoColor = (SURFACE *) NULL;
|
|
|
|
//
|
|
// Lock the target surface and realize the color translation object.
|
|
// If soColor is invalid, this will produce the identity object.
|
|
//
|
|
|
|
XLATEOBJ *pxlo = NULL;
|
|
EXLATEOBJ xlo;
|
|
SURFREF soColor;
|
|
PPALETTE ppalSrc;
|
|
|
|
//
|
|
// We'll have to wait for drawing to complete before the change.
|
|
// So we wait for both semaphores.
|
|
//
|
|
// Note that we don't attempt to change the shape asynchronously,
|
|
// even if the driver sets GCAPS_ASYNCCHANGE.
|
|
//
|
|
|
|
DEVLOCKOBJ dlo(po);
|
|
{
|
|
//
|
|
// We can reference pSurface() only once the Devlock is acquired,
|
|
// for dynamic mode changing.
|
|
//
|
|
|
|
SURFACE* pSurfDisp = po.pSurface();
|
|
|
|
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;
|
|
}
|
|
|
|
PPALETTE ppalSrc;
|
|
|
|
if (!bIsCompatible(&ppalSrc, soColor.ps->ppal(), soColor.ps, po.hdev()))
|
|
{
|
|
WARNING1("GreSetPointer failed - bitmap not compatible with surface\n");
|
|
return;
|
|
}
|
|
|
|
palSrc.ppalSet(ppalSrc);
|
|
palDisp.ppalSet(pSurfDisp->ppal());
|
|
|
|
if (xlo.bInitXlateObj(
|
|
(PCOLORXFORM)NULL,
|
|
palSrc,
|
|
palDisp,
|
|
palDispDC,
|
|
palDispDC,
|
|
0x000000L,
|
|
0xFFFFFFL,
|
|
0
|
|
))
|
|
{
|
|
pxlo = xlo.pxlo();
|
|
psoColor = soColor.ps;
|
|
}
|
|
}
|
|
}
|
|
|
|
ULONG iMode;
|
|
MUTEXOBJ mutP(po.pfmPointer());
|
|
LONG lInitX, lInitY;
|
|
BOOL bDirectDrawOccluded;
|
|
LONG xPointer, yPointer;
|
|
|
|
if (!po.bDisabled())
|
|
{
|
|
//
|
|
// We can't allow a software pointer to be drawn if it will
|
|
// intersect a region of the screen locked by a DirectDraw
|
|
// application. Unfortunately, the DrvSetPointerShape call
|
|
// implicitly expects the pointer to be drawn even if the
|
|
// driver returns SPS_ACCEPT_EXCLUDE (which implies a software
|
|
// pointer). Consequently, if it looks like the pointer might
|
|
// overlap a DirectDraw lock, we tell the driver to create it
|
|
// hidden; then, if it turns out the driver returned
|
|
// SPS_ACCEPT_NOEXCLUDE (meaning it's a hardware pointer), we
|
|
// can turn the pointer back on by making a call to
|
|
// DrvMovePointer.
|
|
//
|
|
// The actual pointer height is always half the mask height.
|
|
// Note that the size of the bitmap is almost always larger
|
|
// than the actual bits contained -- we could trim the size
|
|
// of 'rclPointerOffset' as a result. However, it's the
|
|
// SimSetPointerShape call that usually returns this
|
|
// information to us, and since we haven't called it yet, we
|
|
// don't know what the trimmed size would be! Plus,
|
|
// SimSetPointerShape doesn't returned the trimmed size
|
|
// information if the pointer is created invisible.
|
|
//
|
|
|
|
po.rclPointerOffset().left = -pci->xHotspot;
|
|
po.rclPointerOffset().right = -pci->xHotspot
|
|
+ (soMask.ps->sizl().cx);
|
|
po.rclPointerOffset().top = -pci->yHotspot;
|
|
po.rclPointerOffset().bottom = -pci->yHotspot
|
|
+ (soMask.ps->sizl().cy >> 1);
|
|
|
|
bDirectDrawOccluded = bDdPointerNeedsOccluding(po.hdev());
|
|
|
|
if (bDirectDrawOccluded)
|
|
{
|
|
po.bPtrDirectDrawOccluded(TRUE);
|
|
xPointer = -1;
|
|
yPointer = -1;
|
|
}
|
|
else
|
|
{
|
|
po.bPtrDirectDrawOccluded(FALSE);
|
|
xPointer = po.ptlPointer().x;
|
|
yPointer = po.ptlPointer().y;
|
|
}
|
|
|
|
//
|
|
// Ask the driver if it can support the new shape. We give it an
|
|
// invisible location if engine is simulating so if driver rejects
|
|
// engine can replace it without flash. If driver does accept we
|
|
// remove the engine cursor (flash) and then
|
|
// have driver move pointer to correct position.
|
|
//
|
|
|
|
if (po.bPtrSim())
|
|
{
|
|
lInitX = -1;
|
|
lInitY = -1;
|
|
}
|
|
else
|
|
{
|
|
lInitX = xPointer;
|
|
lInitY = yPointer;
|
|
}
|
|
|
|
if (po.pfnDrvShape())
|
|
{
|
|
iMode = po.pfnDrvShape()
|
|
(
|
|
pSurfDisp->pSurfobj(),
|
|
soMask.pSurfobj(),
|
|
psoColor->pSurfobj(),
|
|
pxlo,
|
|
pci->xHotspot,
|
|
pci->yHotspot,
|
|
lInitX,
|
|
lInitY,
|
|
(lInitX != -1) ? &po.rclPointer() : NULL,
|
|
SPS_CHANGE | fl
|
|
);
|
|
}
|
|
else
|
|
{
|
|
iMode = SPS_DECLINE;
|
|
}
|
|
|
|
//
|
|
// If the driver takes it, just finish up.
|
|
//
|
|
|
|
po.bPtrNeedsExcluding(iMode != SPS_ACCEPT_NOEXCLUDE);
|
|
|
|
if ((iMode == SPS_ACCEPT_EXCLUDE) ||
|
|
(iMode == SPS_ACCEPT_NOEXCLUDE))
|
|
{
|
|
ASSERTGDI(po.pfnDrvMove(),"pfnDrvMove is invalid (NULL)");
|
|
|
|
if (po.bPtrSim())
|
|
{
|
|
//
|
|
// Remove engine simulated pointer.
|
|
//
|
|
|
|
SimSetPointerShape(pSurfDisp->pSurfobj(),NULL,NULL,NULL,
|
|
0,0,0,0,NULL,SPS_CHANGE | fl);
|
|
}
|
|
|
|
if ((po.bPtrSim() && !bDirectDrawOccluded) ||
|
|
((iMode == SPS_ACCEPT_NOEXCLUDE) && (bDirectDrawOccluded)))
|
|
{
|
|
//
|
|
// Unhide the pointer if it was created hidden and no
|
|
// longer has to be.
|
|
//
|
|
|
|
po.bPtrDirectDrawOccluded(FALSE);
|
|
po.pfnDrvMove()(pSurfDisp->pSurfobj(),
|
|
po.ptlPointer().x,
|
|
po.ptlPointer().y,
|
|
&po.rclPointer());
|
|
}
|
|
|
|
po.pfnMove(po.pfnDrvMove());
|
|
po.bPtrHidden(FALSE);
|
|
po.bPtrSim(FALSE);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Let the GDI simulations do it.
|
|
//
|
|
|
|
po.pfnMove(SimMovePointer);
|
|
|
|
iMode = SimSetPointerShape
|
|
(
|
|
pSurfDisp->pSurfobj(),
|
|
soMask.pSurfobj(),
|
|
psoColor->pSurfobj(),
|
|
pxlo,
|
|
pci->xHotspot,
|
|
pci->yHotspot,
|
|
xPointer,
|
|
yPointer,
|
|
(xPointer != -1) ? &po.rclPointer() : NULL,
|
|
SPS_CHANGE | fl
|
|
);
|
|
|
|
//
|
|
// Finish up.
|
|
//
|
|
|
|
if (iMode != SPS_ERROR)
|
|
{
|
|
po.bPtrHidden(FALSE);
|
|
po.bPtrSim(TRUE);
|
|
}
|
|
else
|
|
{
|
|
po.bPtrHidden(TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreMovePointer (hdev,x,y)
|
|
*
|
|
* 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
|
|
*
|
|
* Tue 12-May-1992 02:11:51 -by- Charles Whitmer [chuckwh]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID GreMovePointer(HDEV hdev,int x,int y)
|
|
{
|
|
BOOL bUnlockBoth = FALSE;
|
|
RECTL *prcl;
|
|
PDEVOBJ po(hdev);
|
|
PFN_DrvMovePointer pfnMove;
|
|
SURFOBJ *pso;
|
|
|
|
if (po.bValid())
|
|
{
|
|
if (po.bDisabled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
ASSERTGDI(x != -1, "ERROR GreMovePointer X invalid");
|
|
ASSERTGDI(y != -1, "ERROR GreMovePointer Y invalid");
|
|
|
|
//
|
|
// 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.bPtrNeedsExcluding())
|
|
{
|
|
AcquireGreResource(po.pfmPointer());
|
|
|
|
//
|
|
// Make sure we really got it, bPtrNeedsExcluding may
|
|
// change if you don't hold the DEVLOCK or
|
|
// the POINTER mutex.
|
|
//
|
|
|
|
if (po.bPtrNeedsExcluding())
|
|
{
|
|
//
|
|
// Release and regrab everything, for sure
|
|
// we are safe with both of them.
|
|
//
|
|
|
|
ReleaseGreResource(po.pfmPointer());
|
|
VACQUIREDEVLOCK(po.pDevLock());
|
|
AcquireGreResource(po.pfmPointer());
|
|
bUnlockBoth = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VACQUIREDEVLOCK(po.pDevLock());
|
|
AcquireGreResource(po.pfmPointer());
|
|
bUnlockBoth = TRUE;
|
|
}
|
|
|
|
//
|
|
// bDisabled can't change with pDevLock and pfmPointer both held.
|
|
// bPtrHidden can't change unless pfmPointer is held if the
|
|
// pointer is currently Async and the device supports Async movement.
|
|
// Otherwise pDevLock and bPtrHidden both would be held to
|
|
// change bPtrHidden.
|
|
//
|
|
|
|
if ((po.ptlPointer().x != x) ||
|
|
(po.ptlPointer().y != y))
|
|
{
|
|
po.ptlPointer(x,y);
|
|
|
|
if (!po.bDisabled())
|
|
{
|
|
pso = po.pSurface()->pSurfobj();
|
|
prcl = po.bPtrNeedsExcluding() ? &po.rclPointer() : NULL;
|
|
|
|
if (!po.bPtrHidden())
|
|
{
|
|
if (po.bPtrNeedsExcluding())
|
|
{
|
|
//
|
|
// bDdCalculatePointerExclusions returns TRUE if the
|
|
// pointer should be excluded because of DirectDraw.
|
|
//
|
|
|
|
if (bDdPointerNeedsOccluding(po.hdev()))
|
|
{
|
|
if (!po.bPtrDirectDrawOccluded())
|
|
{
|
|
//
|
|
// The pointer has moved such that it now
|
|
// intersects with a DirectDraw locked region.
|
|
// Consequently, call the driver to turn it off.
|
|
//
|
|
|
|
po.bPtrDirectDrawOccluded(TRUE);
|
|
po.pfnMove()(pso, -1, -1, NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
po.bPtrDirectDrawOccluded(FALSE);
|
|
po.pfnMove()(pso, x, y, prcl);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
po.pfnMove()(pso, x, y, prcl);
|
|
}
|
|
}
|
|
|
|
if (po.flGraphicsCaps() & GCAPS_PANNING)
|
|
{
|
|
//
|
|
// 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':
|
|
//
|
|
|
|
po.pfnDrvMove()(pso,
|
|
x,
|
|
y - pso->sizlBitmap.cy,
|
|
NULL);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING1("GreMovePointer called but position didn't change\n");
|
|
}
|
|
|
|
ReleaseGreResource(po.pfmPointer());
|
|
|
|
if (bUnlockBoth)
|
|
{
|
|
VRELEASEDEVLOCK(po.pDevLock());
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vExclude (hdev,prcl,pco)
|
|
*
|
|
* Does the work for the DEVEXCLUDEOBJ constructors.
|
|
*
|
|
* 1) Obtains the hardware semaphore, if needed.
|
|
* 2) Asks the driver to take down the pointer if it collides with the
|
|
* drawing area.
|
|
* 3) Sets a timer for bringing up an excluded pointer.
|
|
*
|
|
* Thu 14-Apr-1994 -by- Patrick Haluptzok [patrickh]
|
|
* Optimize / make Async pointers work
|
|
*
|
|
* Mon 24-Aug-1992 -by- Patrick Haluptzok [patrickh]
|
|
* Add drag rect exclusion.
|
|
*
|
|
* Thu 07-May-1992 19:32:06 -by- Charles Whitmer [chuckwh]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID DEVEXCLUDEOBJ::vExclude(HDEV hdev_,RECTL *prcl,ECLIPOBJ *pco)
|
|
{
|
|
bRedrawDragRect = FALSE;
|
|
bRedrawCursor = FALSE;
|
|
PDEVOBJ po(hdev_);
|
|
|
|
//
|
|
// If the pointer is hidden or handled in hardware, there's nothing to do.
|
|
//
|
|
|
|
if (po.bPtrNeedsExcluding() &&
|
|
!po.bPtrHidden() &&
|
|
!po.bPtrDirectDrawOccluded())
|
|
{
|
|
//
|
|
// See if we need to tear down the pointer because
|
|
// the pointer lies where we want to draw.
|
|
//
|
|
|
|
if (
|
|
(prcl->bottom > po.rclPointer().top) &&
|
|
(prcl->right > po.rclPointer().left) &&
|
|
(prcl->left < po.rclPointer().right) &&
|
|
(prcl->top < po.rclPointer().bottom) &&
|
|
(pco == NULL ||
|
|
pco->bInside(&po.rclPointer()) == REGION_RECT_INTERSECT)
|
|
)
|
|
{
|
|
//
|
|
// Setting hdev to be non-zero let's us know we have to
|
|
// put the pointer back on the screen when we hit the
|
|
// destructor.
|
|
//
|
|
|
|
hdev = hdev_;
|
|
bRedrawCursor = TRUE;
|
|
|
|
//
|
|
// We know we can move it off the screen because the
|
|
// GreMovePointer must grab pDevLock given the conditions
|
|
// above we just checked, and the conditions above can't
|
|
// change without holding the pDevLock.
|
|
//
|
|
|
|
po.pfnMove()(po.pSurface()->pSurfobj(),-1,-1,NULL);
|
|
}
|
|
}
|
|
|
|
if (po.bHaveDragRect())
|
|
{
|
|
vTearDownDragRect(hdev_, prcl);
|
|
}
|
|
}
|
|
|
|
VOID DEVEXCLUDEOBJ::vExclude2
|
|
(
|
|
HDEV hdev_,
|
|
RECTL *prcl,
|
|
ECLIPOBJ *pco,
|
|
POINTL *pptl
|
|
)
|
|
{
|
|
bRedrawDragRect = 0;
|
|
bRedrawCursor = FALSE;
|
|
RECTL rclOffset;
|
|
PDEVOBJ po(hdev_);
|
|
|
|
//
|
|
// If the pointer is hidden or handled in hardware, there's nothing to do.
|
|
//
|
|
|
|
if (po.bPtrNeedsExcluding() &&
|
|
!po.bPtrHidden() &&
|
|
!po.bPtrDirectDrawOccluded())
|
|
{
|
|
//
|
|
// Calculate an offset version of the pointer rectangle.
|
|
//
|
|
|
|
rclOffset.top = po.rclPointer().top + pptl->y;
|
|
rclOffset.left = po.rclPointer().left + pptl->x;
|
|
rclOffset.right = po.rclPointer().right + pptl->x;
|
|
rclOffset.bottom = po.rclPointer().bottom + pptl->y;
|
|
|
|
//
|
|
// See if we need to tear down the pointer because
|
|
// the pointer lies where we want to draw.
|
|
//
|
|
|
|
if (
|
|
(prcl->bottom > po.rclPointer().top) &&
|
|
(prcl->right > po.rclPointer().left) &&
|
|
(prcl->left < po.rclPointer().right) &&
|
|
(prcl->top < po.rclPointer().bottom) &&
|
|
(
|
|
(pco == (ECLIPOBJ *) NULL) ||
|
|
(pco->bInside(&po.rclPointer()) == REGION_RECT_INTERSECT) ||
|
|
(pco->bInside(&rclOffset) == REGION_RECT_INTERSECT)
|
|
)
|
|
)
|
|
{
|
|
//
|
|
// Tear it down.
|
|
//
|
|
// Setting hdev to be non-zero let's us know we have to
|
|
// something in the destructor.
|
|
//
|
|
|
|
hdev = hdev_;
|
|
bRedrawCursor = TRUE;
|
|
|
|
//
|
|
// We know we can move it off the screen because the
|
|
// GreMovePointer must grab pDevLock given the conditions
|
|
// above we just checked, and the conditions above can't
|
|
// change without holding the pDevLock.
|
|
//
|
|
|
|
po.pfnMove()(po.pSurface()->pSurfobj(),-1,-1,NULL);
|
|
}
|
|
}
|
|
|
|
if (po.bHaveDragRect())
|
|
{
|
|
vTearDownDragRect(hdev_, prcl);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ULONG cIntersect
|
|
*
|
|
* This routine takes a list of rectangles from 'prclIn' and clips them
|
|
* in-place to the rectangle 'prclClip'. The input rectangles don't
|
|
* have to intersect 'prclClip'; the return value will reflect the
|
|
* number of input rectangles that did intersect, and the intersecting
|
|
* rectangles will be densely packed.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG cIntersect(
|
|
RECTL* prclClip,
|
|
RECTL* prclIn, // List of rectangles
|
|
LONG c) // Can be zero
|
|
{
|
|
ULONG cIntersections;
|
|
RECTL* prclOut;
|
|
|
|
cIntersections = 0;
|
|
prclOut = prclIn;
|
|
|
|
for (; c != 0; prclIn++, c--)
|
|
{
|
|
prclOut->left = max(prclIn->left, prclClip->left);
|
|
prclOut->right = min(prclIn->right, prclClip->right);
|
|
|
|
if (prclOut->left < prclOut->right)
|
|
{
|
|
prclOut->top = max(prclIn->top, prclClip->top);
|
|
prclOut->bottom = min(prclIn->bottom, prclClip->bottom);
|
|
|
|
if (prclOut->top < prclOut->bottom)
|
|
{
|
|
prclOut++;
|
|
cIntersections++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(cIntersections);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDrawDragRectangles
|
|
*
|
|
* Creates a list of rectangles describing the drag rect, sticks them in
|
|
* 'po.prclRedraw()' and then draws them.
|
|
*
|
|
* Note: Devlock must already have been acquired.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bDrawDragRectangles(
|
|
PDEVOBJ& po,
|
|
ERECTL *prclClip)
|
|
{
|
|
ULONG ulDimension;
|
|
ULONG crclTemp;
|
|
ULONG i;
|
|
RECTL arclTemp[4];
|
|
REGION* prgn;
|
|
ECLIPOBJ eco;
|
|
ECLIPOBJ* pco;
|
|
ERECTL rclClip;
|
|
|
|
ulDimension = po.ulDragDimension();
|
|
|
|
arclTemp[0].left = po.rclDrag().left;
|
|
arclTemp[0].right = po.rclDrag().left + ulDimension;
|
|
arclTemp[0].top = po.rclDrag().top;
|
|
arclTemp[0].bottom = po.rclDrag().bottom;
|
|
|
|
arclTemp[1].left = po.rclDrag().right - ulDimension;
|
|
arclTemp[1].right = po.rclDrag().right;
|
|
arclTemp[1].top = po.rclDrag().top;
|
|
arclTemp[1].bottom = po.rclDrag().bottom;
|
|
|
|
arclTemp[2].left = po.rclDrag().left + ulDimension;
|
|
arclTemp[2].right = po.rclDrag().right - ulDimension;
|
|
arclTemp[2].top = po.rclDrag().top;
|
|
arclTemp[2].bottom = po.rclDrag().top + ulDimension;
|
|
|
|
arclTemp[3].left = po.rclDrag().left + ulDimension;
|
|
arclTemp[3].right = po.rclDrag().right - ulDimension;
|
|
arclTemp[3].top = po.rclDrag().bottom - ulDimension;
|
|
arclTemp[3].bottom = po.rclDrag().bottom;
|
|
|
|
//
|
|
// First intersect the passed-in clip rectangle with the clip rectangle
|
|
// given to us by USER, and then use the result to trim all the
|
|
// other rectangles:
|
|
//
|
|
|
|
rclClip = *(ERECTL*) prclClip;
|
|
rclClip *= po.rclDragClip();
|
|
|
|
crclTemp = cIntersect(&rclClip, &arclTemp[0], 4);
|
|
|
|
//
|
|
// We can't draw the drag rect over any locked DirectDraw surfaces,
|
|
// so get from DirectDraw a region that describes the unlocked
|
|
// parts of the screen:
|
|
//
|
|
|
|
pco = NULL;
|
|
prgn = prgnDdUnlockedRegion(po.hdev());
|
|
if (prgn != NULL)
|
|
{
|
|
eco.vSetup(prgn, *&rclClip, CLIP_FORCE);
|
|
|
|
if (eco.erclExclude().bEmpty())
|
|
return(FALSE);
|
|
|
|
//
|
|
// If the complexity is DC_RECT, drivers expect the destination
|
|
// rectangle to always intersect the clipping region. However,
|
|
// I can't be bothered to ensure this for each of the 'crclTemp'
|
|
// rectangles, so I will mark the clip object as 'complex' up
|
|
// front:
|
|
//
|
|
|
|
eco.iDComplexity = DC_COMPLEX;
|
|
pco = &eco;
|
|
}
|
|
|
|
for (i = 0; i != crclTemp; i++)
|
|
{
|
|
(*(po.pSurface()->pfnBitBlt()))
|
|
(po.pSurface()->pSurfobj(),
|
|
(SURFOBJ *) NULL,
|
|
(SURFOBJ *) NULL,
|
|
pco,
|
|
NULL,
|
|
&(arclTemp[i]),
|
|
(POINTL *) NULL,
|
|
(POINTL *) NULL,
|
|
po.pbo(),
|
|
&gptl00,
|
|
0x00005A5A);
|
|
}
|
|
|
|
return(crclTemp != 0);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vTearDownDragRect()
|
|
*
|
|
* Tears down the drag rect on a surface.
|
|
*
|
|
* History:
|
|
* 24-Aug-1992 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID DEVEXCLUDEOBJ::vTearDownDragRect(HDEV hdev_, RECTL *prclIn)
|
|
{
|
|
PDEVOBJ po(hdev_);
|
|
|
|
hdev = hdev_;
|
|
|
|
po.rclRedraw() = *(ERECTL*) prclIn;
|
|
|
|
bRedrawDragRect = bDrawDragRectangles(po, (ERECTL*) prclIn);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vReplaceStuff()
|
|
*
|
|
* Slap the drag rect back on screen if we took it down.
|
|
*
|
|
* History:
|
|
* Thu 14-Apr-1994 -by- Patrick Haluptzok [patrickh]
|
|
* Optimize / make Async pointers work
|
|
*
|
|
* 24-Aug-1992 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID DEVEXCLUDEOBJ::vReplaceStuff()
|
|
{
|
|
PDEVOBJ po(hdev);
|
|
|
|
if (bRedrawDragRect)
|
|
{
|
|
bDrawDragRectangles(po, &po.rclRedraw());
|
|
}
|
|
|
|
if (bRedrawCursor)
|
|
{
|
|
po.pfnMove()(po.pSurface()->pSurfobj(),
|
|
po.ptlPointer().x,
|
|
po.ptlPointer().y,
|
|
po.bPtrNeedsExcluding() ? &po.rclPointer() : NULL);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bSetDevDragRect()
|
|
*
|
|
* Called by USER to slap the drag rect on the screen, or to tear it back
|
|
* down.
|
|
*
|
|
* History:
|
|
* 3-Apr-1996 -by- J. Andrew Goossen andrewgo
|
|
* Moved all drag rect drawing to GDI and added DirectDraw support.
|
|
*
|
|
* 24-Aug-1992 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bSetDevDragRect(
|
|
HDEV hdev,
|
|
RECTL* prclDrag,
|
|
RECTL* prclClip)
|
|
{
|
|
RECTL rclScreen;
|
|
RECTL arclDrag[4];
|
|
ULONG crclDrag;
|
|
BOOL bHaveDragRect;
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
VACQUIREDEVLOCK(po.pDevLock());
|
|
|
|
bHaveDragRect = FALSE;
|
|
|
|
if (prclDrag != NULL)
|
|
{
|
|
ASSERTGDI(!po.bHaveDragRect(), "Expected not to have a drag rectangle");
|
|
|
|
bHaveDragRect = TRUE;
|
|
po.rclDrag() = *prclDrag;
|
|
if (prclClip != NULL)
|
|
{
|
|
po.rclDragClip() = *prclClip;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// make rclDragClip empty
|
|
//
|
|
|
|
po.rclDragClip().left = po.rclDragClip().right;
|
|
}
|
|
}
|
|
|
|
{
|
|
DEVEXCLUDEOBJ dxo;
|
|
|
|
rclScreen.left = 0;
|
|
rclScreen.top = 0;
|
|
rclScreen.right = po.sizl().cx;
|
|
rclScreen.bottom = po.sizl().cy;
|
|
|
|
dxo.vExclude(hdev, &rclScreen, NULL);
|
|
|
|
//
|
|
// Force the entire drag rect to be drawn when turning it on.
|
|
//
|
|
|
|
po.bHaveDragRect(bHaveDragRect);
|
|
po.rclRedraw() = rclScreen;
|
|
|
|
//
|
|
// vReplaceStuff will be called automatically when the dxo goes
|
|
// out of scope, and will draw the appropriate state of the drag
|
|
// rectangle. This has to be done before we release the devlock.
|
|
//
|
|
|
|
dxo.vForceDragRectRedraw(po.hdev(), bHaveDragRect);
|
|
}
|
|
|
|
VRELEASEDEVLOCK(po.pDevLock());
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bMoveDevDragRect()
|
|
*
|
|
* Called by USER to move the drag rect on the screen.
|
|
*
|
|
* Note: Devlock must already have been acquired.
|
|
*
|
|
* History:
|
|
* 3-Apr-1996 -by- J. Andrew Goossen andrewgo
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bMoveDevDragRect(
|
|
HDEV hdev,
|
|
RECTL *prclNew)
|
|
{
|
|
RECTL rclScreen;
|
|
PDEVOBJ po(hdev);
|
|
|
|
rclScreen.left = 0;
|
|
rclScreen.top = 0;
|
|
rclScreen.right = po.sizl().cx;
|
|
rclScreen.bottom = po.sizl().cy;
|
|
|
|
DEVEXCLUDEOBJ dxo;
|
|
|
|
dxo.vExclude(hdev, &rclScreen, NULL);
|
|
|
|
po.rclDrag() = *prclNew;
|
|
|
|
// vReplaceStuff will be called automatically when the dxo goes
|
|
// out of scope, and will draw the appropriate state of the drag
|
|
// rectangle.
|
|
|
|
dxo.vForceDragRectRedraw(po.hdev(), TRUE);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bSetDevDragWidth()
|
|
*
|
|
* Called by USER to tell us how wide the drag rectangle should be.
|
|
*
|
|
* 24-Aug-1992 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bSetDevDragWidth(HDEV hdev, ULONG ulWidth)
|
|
{
|
|
PDEVOBJ po(hdev);
|
|
|
|
VACQUIREDEVLOCK(po.pDevLock());
|
|
po.ulDragDimension(ulWidth);
|
|
VRELEASEDEVLOCK(po.pDevLock());
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************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)
|
|
{
|
|
hsemTrg = NULL; // Remember the semaphore we're waiting on.
|
|
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 ((gpsemPalette->OwnerThreads[0].OwnerThread
|
|
!= (ERESOURCE_THREAD)PsGetCurrentThread())
|
|
|| (dco.pDcDevLock()->OwnerThreads[0].OwnerThread
|
|
== (ERESOURCE_THREAD) PsGetCurrentThread()),
|
|
"potential deadlock!\n");
|
|
|
|
//
|
|
// Grab the display semaphore
|
|
//
|
|
|
|
hsemTrg = dco.pDcDevLock();
|
|
VACQUIREDEVLOCK(hsemTrg);
|
|
|
|
if (dco.pdc->bInFullScreen())
|
|
{
|
|
fl = 0;
|
|
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)
|
|
{
|
|
hsemTrg = NULL; // Remember the semaphore we're waiting on.
|
|
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.pDcDevLock();
|
|
VACQUIREDEVLOCK(hsemTrg);
|
|
}
|
|
}
|
|
|
|
/******************************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)
|
|
{
|
|
hsemTrg = NULL; // Remember the semaphore we're waiting on.
|
|
hsemSrc = NULL; // Remember the semaphore we're waiting on.
|
|
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
|
|
//
|
|
|
|
hsemTrg = dco.pDcDevLock();
|
|
VACQUIREDEVLOCK(hsemTrg);
|
|
|
|
//
|
|
// Check if we are in full screen and drawing
|
|
// to the Display, this may just be a DFB.
|
|
//
|
|
|
|
if (dco.bInFullScreen() && dco.bDisplay())
|
|
{
|
|
fl = 0;
|
|
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)
|
|
{
|
|
hsemTrg = NULL;
|
|
hsemSrc = NULL;
|
|
fl = DLO_VALID;
|
|
|
|
if (dcoSrc.bSynchronizeAccess())
|
|
{
|
|
//
|
|
// Grab the display semaphore
|
|
//
|
|
|
|
hsemSrc = dcoSrc.pDcDevLock();
|
|
VACQUIREDEVLOCK(hsemSrc);
|
|
|
|
//
|
|
// Check if we are in full screen and drawing
|
|
// to the Display, this may just be a DFB.
|
|
//
|
|
|
|
if (dcoSrc.bInFullScreen() && dcoSrc.bDisplay())
|
|
{
|
|
fl = 0;
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
if (dcoTrg.bSynchronizeAccess())
|
|
{
|
|
//
|
|
// Grab the display semaphore
|
|
//
|
|
|
|
hsemTrg = dcoTrg.pDcDevLock();
|
|
VACQUIREDEVLOCK(hsemTrg);
|
|
|
|
//
|
|
// Check if we are in full screen and drawing
|
|
// to the Display, this may just be a DFB.
|
|
//
|
|
|
|
if (dcoTrg.bInFullScreen() && dcoTrg.bDisplay())
|
|
{
|
|
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);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DEVLOCK::bAddSource
|
|
*
|
|
* Add a source DC to the DEVLOCK object. This is needed for BitBlt and
|
|
* its kin that take two DC's but already locked down the target.
|
|
*
|
|
* History:
|
|
* Mon 18-Apr-1994 -by- Patrick Haluptzok [patrickh]
|
|
* bSynchronize Checks, rewrote it.
|
|
*
|
|
* 11-Nov-1992 -by- Donald Sidoroff [donalds]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL DEVLOCKBLTOBJ::bAddSource(XDCOBJ& dcoSrc)
|
|
{
|
|
ASSERTGDI(fl & DLO_VALID, "ERROR this is only called after dst is locked");
|
|
|
|
if (dcoSrc.bSynchronizeAccess())
|
|
{
|
|
//
|
|
// Grab the display semaphore
|
|
//
|
|
|
|
hsemSrc = dcoSrc.pDcDevLock();
|
|
VACQUIREDEVLOCK(hsemSrc);
|
|
|
|
//
|
|
// Check if we are in full screen and drawing
|
|
// to the Display, this may just be a DFB.
|
|
//
|
|
|
|
if (dcoSrc.bInFullScreen() && dcoSrc.bDisplay())
|
|
{
|
|
fl &= ~(DLO_VALID);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
if (dcoSrc.pdc->bDirtyRao())
|
|
{
|
|
if (!dcoSrc.pdc->bCompute())
|
|
{
|
|
fl &= ~(DLO_VALID);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|