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.
391 lines
12 KiB
391 lines
12 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: wndobj.hxx
|
|
*
|
|
* Window object. Created for those drivers that want to track changes
|
|
* in the client region.
|
|
*
|
|
* Created: 27-Sep-1993 15:30:05
|
|
* Author: Wendy Wu [wendywu]
|
|
*
|
|
* Copyright (c) 1993-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#define WO_NOTIFIED 0x80000000
|
|
#define WO_NEW_WNDOBJ 0x40000000
|
|
#define WO_SURFACE 0x20000000
|
|
#define WO_HSEM_OWNER 0x10000000
|
|
#define WO_GENERIC_WNDOBJ 0x08000000
|
|
#define WO_NEED_DRAW_NOTIFY 0x04000000
|
|
#define WO_SPRITE_OVERLAP 0x02000000 // At least one sprite overlaps
|
|
// the window area
|
|
#define WO_NOSPRITES 0x01000000 // Don't draw any sprites on
|
|
// top of this window
|
|
|
|
// Internal flag allowed in TRACKOBJ.fl and EWNDOBJ.fl (moved to wglp.h)
|
|
|
|
#define WO_INTERNAL_VALID_FLAGS (WO_NOTIFIED | \
|
|
WO_NEW_WNDOBJ | \
|
|
WO_SURFACE | \
|
|
WO_HSEM_OWNER | \
|
|
WO_NEED_DRAW_NOTIFY | \
|
|
WO_SPRITE_OVERLAP | \
|
|
WO_NOSPRITES)
|
|
|
|
#define WO_VALID_FLAGS (WO_RGN_CLIENT_DELTA | \
|
|
WO_RGN_CLIENT | \
|
|
WO_RGN_SURFACE_DELTA | \
|
|
WO_RGN_SURFACE | \
|
|
WO_RGN_UPDATE_ALL | \
|
|
WO_RGN_WINDOW | \
|
|
WO_RGN_DESKTOP_COORD | \
|
|
WO_GENERIC_WNDOBJ | \
|
|
WO_DRAW_NOTIFY | \
|
|
WO_SPRITE_NOTIFY)
|
|
|
|
// TRACKOBJ and EWNDOBJ identifiers
|
|
|
|
#define TRACKOBJ_IDENTIFIER 0x43415254 // 'TRAC'
|
|
#define EWNDOBJ_IDENTIFIER 0x444E5745 // 'EWND'
|
|
|
|
// Global that indicates whether to notify driver with the new WNDOBJ
|
|
// states following a WNDOBJ creation. User has not changed the window
|
|
// states but this is required to initialize the driver. The update is
|
|
// done in the parent gdi functions (e.g. SetPixelFormat) that allow
|
|
// the DDI to create a WNDOBJ.
|
|
|
|
extern BOOL gbWndobjUpdate;
|
|
|
|
// Maximum region rectangle
|
|
|
|
extern RECTL grclMax;
|
|
|
|
// Global tracking object (TRACKOBJ) pointer.
|
|
// If this is non-null, we are tracking some WNDOBJs in the system.
|
|
|
|
class TRACKOBJ;
|
|
extern TRACKOBJ* gpto;
|
|
|
|
#if DBG
|
|
#define CHECKUSERCRITIN UserAssertUserCritSecIn()
|
|
#define CHECKUSERCRITOUT UserAssertUserCritSecOut()
|
|
#else
|
|
#define CHECKUSERCRITIN
|
|
#define CHECKUSERCRITOUT
|
|
#endif
|
|
|
|
// WINBUG #83114 2-7-2000 bhouse Review and test critical section checks
|
|
// We are leaving the critical section checks in place eventhough they may
|
|
// no longer work if turned on. At some point during code cleanup we should
|
|
// review there use and test.
|
|
|
|
#if DBG
|
|
#if 0
|
|
#define CHECKCRITIN(hsem) \
|
|
ASSERT((ExIsResourceAcquiredExclusiveLite(hsem) == TRUE) || \
|
|
(ExIsResourceAcquiredSharedLite(hsem) == TRUE))
|
|
#define CHECKCRITOUT(hsem) \
|
|
ASSERT(ExIsResourceAcquiredExclusiveLite(hsem) == FALSE)
|
|
#else
|
|
#define CHECKCRITIN(hsem)
|
|
#define CHECKCRITOUT(hsem)
|
|
#endif
|
|
|
|
#define CHECKDEVLOCKIN(dco) \
|
|
CHECKCRITIN((dco).hsemDcDevLock)
|
|
#define CHECKDEVLOCKOUT(dco) \
|
|
CHECKCRITOUT((dco).hsemDcDevLock)
|
|
#define CHECKDEVLOCKIN2(pSurface) \
|
|
{ \
|
|
PDEVOBJ po((pSurface)->hdev()); \
|
|
CHECKCRITIN(po.hsemDevLock()); \
|
|
}
|
|
#define CHECKDEVLOCKOUT2(pSurface) \
|
|
{ \
|
|
PDEVOBJ po((pSurface)->hdev()); \
|
|
CHECKCRITOUT(po.hsemDevLock()); \
|
|
}
|
|
#else
|
|
#define CHECKCRITIN(hsem)
|
|
#define CHECKCRITOUT(hsem)
|
|
#define CHECKDEVLOCKIN(dco)
|
|
#define CHECKDEVLOCKOUT(dco)
|
|
#define CHECKDEVLOCKIN2(pSurface)
|
|
#define CHECKDEVLOCKOUT2(pSurface)
|
|
#endif
|
|
|
|
/******************************Class***************************************\
|
|
* class TRACKOBJ
|
|
*
|
|
* Each tracking object has a unique driver notification function address
|
|
* in the pfn field. There is usually one such object per driver although
|
|
* multiple TRACKOBJs can be created on the same device. For example, a
|
|
* live video driver may track all live video windows while an OpenGL driver
|
|
* tracks all OpenGL windows at the same time. The only restriction is
|
|
* that a window can be tracked by only one TRACKOBJ on the same device.
|
|
*
|
|
* The TRACKOBJ points to a linked list of window objects that is being
|
|
* tracked for a given driver notification function.
|
|
*
|
|
* History:
|
|
* 16-Nov-1993 -by- Wendy Wu [wendywu]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
class TRACKOBJ
|
|
{
|
|
public:
|
|
ULONG ident;
|
|
TRACKOBJ *ptoNext;
|
|
EWNDOBJ *pwoSurf;
|
|
EWNDOBJ *pwo;
|
|
SURFACE *pSurface;
|
|
WNDOBJCHANGEPROC pfn;
|
|
FLONG fl;
|
|
ERECTL erclSurf;
|
|
|
|
public:
|
|
BOOL bValid()
|
|
{
|
|
return(ident == TRACKOBJ_IDENTIFIER);
|
|
}
|
|
|
|
// Update driver function. fl should not have WOC_RGN_CLIENT_DELTA or
|
|
// WOC_RGN_SURFACE_DELTA set.
|
|
|
|
VOID vUpdateDrv(EWNDOBJ *pwo, FLONG fl)
|
|
{
|
|
ASSERTGDI(!(fl & (WOC_RGN_CLIENT_DELTA|WOC_RGN_SURFACE_DELTA)),
|
|
"TRACKOBJ::vUpdateDrv, Bad flags\n");
|
|
(*pfn)((WNDOBJ *)pwo, fl);
|
|
}
|
|
|
|
// Update driver function for delta regions. fl must have
|
|
// WOC_RGN_CLIENT_DELTA or WOC_RGN_SURFACE_DELTA set.
|
|
// Note that if the delta is empty, we do not need to call the driver.
|
|
// The compiler does not allow this function to be inline because of forward
|
|
// reference.
|
|
|
|
VOID vUpdateDrvDelta(EWNDOBJ *pwo, FLONG fl);
|
|
};
|
|
|
|
typedef TRACKOBJ *PTRACKOBJ;
|
|
|
|
/******************************Class***************************************\
|
|
* class EWNDOBJ
|
|
*
|
|
* A EWNDOBJ is a server side window object created by the driver via
|
|
* EngCreateWnd. It is deleted in GreDeletWnd.
|
|
*
|
|
* Once a WNDOBJ is created, a driver may call WNDOBJ_vSetConsumer to
|
|
* set the pvConsumer field to point to its own window data structure.
|
|
*
|
|
* History:
|
|
* 16-Nov-1993 -by- Wendy Wu [wendywu]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
class EWNDOBJ : public XCLIPOBJ
|
|
{
|
|
public:
|
|
ULONG ident;
|
|
EWNDOBJ *pwoNext;
|
|
TRACKOBJ *pto;
|
|
HWND hwnd;
|
|
FLONG fl;
|
|
int ipfd;
|
|
|
|
// per-WNDOBJ semaphore for generic implementation use only. It is not
|
|
// intended for general consumption!
|
|
// The surf WNDOBJ does not have a per-WNDOBJ semaphore.
|
|
|
|
HSEMAPHORE hsem;
|
|
|
|
public:
|
|
|
|
BOOL bValid()
|
|
{
|
|
return(ident == EWNDOBJ_IDENTIFIER && pto->bValid());
|
|
}
|
|
|
|
VOID vSetClip(REGION *prgn, ERECTL erclClient)
|
|
{
|
|
ASSERTGDI(pto->bValid(), "EWNDOBJ::vSetClip: Invalid pto\n");
|
|
|
|
// Force it to have a non-trivial complexity.
|
|
// Otherwise, it will confuse DDI.
|
|
|
|
vSetup(prgn, *(ERECTL *) &grclMax, CLIP_NOFORCE);
|
|
rclClient = erclClient;
|
|
|
|
// If the region is empty, set the complexity to DC_RECT.
|
|
if (erclExclude().bEmpty())
|
|
iDComplexity = DC_RECT;
|
|
}
|
|
|
|
BOOL bDelete()
|
|
{
|
|
if (fl & WO_HSEM_OWNER)
|
|
{
|
|
ASSERTGDI(hsem, "EWNDOBJ::bDelete: invalid hsem\n");
|
|
GreDeleteSemaphore(hsem);
|
|
}
|
|
|
|
return XCLIPOBJ::bDeleteRGNOBJ(); // delete RGNOBJ
|
|
}
|
|
|
|
VOID vOffset(LONG x, LONG y);
|
|
};
|
|
|
|
typedef EWNDOBJ *PEWNDOBJ;
|
|
|
|
/******************************Class***************************************\
|
|
* class USERCRIT
|
|
*
|
|
* The USERCRIT object enters the user vis region critical section.
|
|
*
|
|
* When we are updating the TRACKOBJs and WNDOBJs, we want to be in
|
|
* the user critical section to prevent client regions from changing.
|
|
*
|
|
* Note that the user critical section should not be entered if we hold
|
|
* any of the gdi locks (e.g. devlock). This is to prevent deadlock.
|
|
*
|
|
* History:
|
|
* Thu Jan 13 09:55:23 1994 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
class USERCRIT
|
|
{
|
|
private:
|
|
BOOL bKeep;
|
|
public:
|
|
USERCRIT(BOOL bKeepIt = FALSE)
|
|
{
|
|
CHECKUSERCRITOUT;
|
|
UserEnterUserCritSec();
|
|
bKeep = bKeepIt;
|
|
}
|
|
~USERCRIT()
|
|
{
|
|
if (!bKeep) {
|
|
CHECKUSERCRITIN;
|
|
UserLeaveUserCritSec();
|
|
CHECKUSERCRITOUT;
|
|
}
|
|
}
|
|
};
|
|
|
|
/******************************Class***************************************\
|
|
* class DEVLOCKOBJ_WNDOBJ
|
|
*
|
|
* This class provides a method to get the current WNDOBJ that is associated
|
|
* with a DCOBJ.
|
|
*
|
|
* History:
|
|
* Thu Jan 13 09:55:23 1994 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
class DEVLOCKOBJ_WNDOBJ : public DEVLOCKOBJ
|
|
{
|
|
private:
|
|
PEWNDOBJ _pwo;
|
|
BOOL bKeepUserCrit;
|
|
|
|
public:
|
|
|
|
// Empty constructor
|
|
|
|
DEVLOCKOBJ_WNDOBJ() {bKeepUserCrit = TRUE;}
|
|
|
|
// Constructor - Grab the DEVLOCK and lock down the WNDOBJ.
|
|
//
|
|
// WARNING: This constructor enters the user critical section temporarily
|
|
// to get the current WNDOBJ from user. Therefore, the caller
|
|
// should not hold the display devlock prior to this constructor.
|
|
|
|
VOID vConstructor(XDCOBJ& dco)
|
|
{
|
|
// Assume no WNDOBJ.
|
|
|
|
_pwo = (PEWNDOBJ)NULL;
|
|
|
|
// Make sure that we don't have devlock before entering user critical
|
|
// section. Otherwise, it can cause deadlock.
|
|
|
|
if (dco.bDisplay() && dco.dctp() == DCTYPE_DIRECT)
|
|
{
|
|
CHECKDEVLOCKOUT(dco);
|
|
}
|
|
|
|
// Enter user critical section.
|
|
|
|
USERCRIT usercrit(bKeepUserCrit);
|
|
|
|
// Grab the devlock.
|
|
|
|
DEVLOCKOBJ::bLock(dco);
|
|
|
|
// If it is a display DC, get the pwo that the hdc is associated with.
|
|
// If it is a printer or memory DC, get the pwo from pSurface.
|
|
|
|
if (dco.bDisplay() && dco.dctp() == DCTYPE_DIRECT)
|
|
{
|
|
HWND hwnd;
|
|
if (!UserGetHwnd(dco.hdc(), &hwnd, (PVOID *) &_pwo, FALSE))
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_pwo = dco.pwo();
|
|
}
|
|
}
|
|
|
|
DEVLOCKOBJ_WNDOBJ(XDCOBJ& dco, BOOL bKeep = TRUE)
|
|
{
|
|
bKeepUserCrit = bKeep;
|
|
vConstructor(dco);
|
|
}
|
|
|
|
// Destructor - Free the DEVLOCK.
|
|
|
|
~DEVLOCKOBJ_WNDOBJ()
|
|
{
|
|
// We need to release devlock then user crit in that order
|
|
DEVLOCKOBJ::vDestructorNULL();
|
|
|
|
if (bKeepUserCrit) {
|
|
CHECKUSERCRITIN;
|
|
UserLeaveUserCritSec();
|
|
CHECKUSERCRITOUT;
|
|
}
|
|
}
|
|
|
|
// bValidWndobj - Do we have a WNDOBJ for this DC?
|
|
|
|
BOOL bValidWndobj() { return(_pwo != (PEWNDOBJ)NULL); }
|
|
|
|
// bValidDevlock - Is the devlock valid?
|
|
|
|
BOOL bValidDevlock() { return(DEVLOCKOBJ::bValid()); }
|
|
|
|
// pwo - Get the WNDOBJ pointer for this DC
|
|
|
|
PEWNDOBJ pwo() { return(_pwo); }
|
|
|
|
// vInit - Initialize the stack object
|
|
|
|
VOID vInit()
|
|
{
|
|
_pwo = (PEWNDOBJ) NULL;
|
|
|
|
DEVLOCKOBJ::vInit();
|
|
}
|
|
};
|
|
|
|
|
|
VOID vForceClientRgnUpdate();
|
|
VOID vChangeWndObjs(SURFACE*, HDEV, SURFACE*, HDEV);
|
|
VOID vTransferWndObjs(SURFACE*, HDEV, HDEV);
|