Files
xserver/miext/cw/cw.c
Eric Anholt bfbb40c28c Major improvements to Composite wrapper. Several issues remain, but it now
appears stable in limited testing.
- Allocate the picture private, avoiding segfault.
- Wrap PaintWindow to draw the background/border to the backing pixmap
    (based on Deron Johnson's comptran.c).
- Set the x_off/y_off returns to translate coordinates properly.
- Don't bother allocating temporary areas for the modified coordinates.
    Layers above are responsible for handling lower layers changing the
    arguments, so cw doesn't have to worry about it. mibstore.c has to do
    the allocation because it calls down twice (front buffer and backing
    store). (Suggested by keithp)
- Handle the mode argument to PolyPoint, Polylines, and FillPolygon.
- Remove some dead elements in the cw privates.
- Kill a prototype warning in compinit.c by adding the cw.h header.
2004-08-03 05:49:48 +00:00

723 lines
18 KiB
C

/*
* Copyright © 2004 Eric Anholt
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Eric Anholt not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Eric Anholt makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Header$ */
#include "gcstruct.h"
#include "windowstr.h"
#include "cw.h"
#define CW_DEBUG 1
#if CW_DEBUG
#define CW_ASSERT(x) do { \
if (!(x)) { \
ErrorF("composite wrapper: assertion failed at %s:%d\n", __FUNC__, \
__LINE__); \
} \
} while (0)
#else
#define CW_ASSERT(x) do {} while (0)
#endif
int cwGCIndex;
int cwScreenIndex;
#ifdef RENDER
int cwPictureIndex;
#endif
static unsigned long cwGeneration = 0;
extern GCOps cwGCOps;
static Bool
cwCloseScreen (int i, ScreenPtr pScreen);
static void
cwValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable);
static void
cwChangeGC(GCPtr pGC, unsigned long mask);
static void
cwCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
static void
cwDestroyGC(GCPtr pGC);
static void
cwChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects);
static void
cwCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
static void
cwDestroyClip(GCPtr pGC);
static void
cwCheapValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable);
static void
cwCheapChangeGC(GCPtr pGC, unsigned long mask);
static void
cwCheapCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
static void
cwCheapDestroyGC(GCPtr pGC);
static void
cwCheapChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects);
static void
cwCheapCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
static void
cwCheapDestroyClip(GCPtr pGC);
static GCFuncs cwGCFuncs = {
cwValidateGC,
cwChangeGC,
cwCopyGC,
cwDestroyGC,
cwChangeClip,
cwDestroyClip,
cwCopyClip,
};
static GCFuncs cwCheapGCFuncs = {
cwCheapValidateGC,
cwCheapChangeGC,
cwCheapCopyGC,
cwCheapDestroyGC,
cwCheapChangeClip,
cwCheapDestroyClip,
cwCheapCopyClip,
};
/* Find the real drawable to draw to, and provide offsets that will translate
* window coordinates to backing pixmap coordinates.
*/
DrawablePtr
cwGetBackingDrawable(DrawablePtr pDrawable, int *x_off, int *y_off)
{
if (cwDrawableIsRedirWindow(pDrawable)) {
WindowPtr pWin = (WindowPtr)pDrawable;
PixmapPtr pPixmap = (*pDrawable->pScreen->GetWindowPixmap)(pWin);
*x_off = pDrawable->x - pPixmap->screen_x;
*y_off = pDrawable->y - pPixmap->screen_y;
return &pPixmap->drawable;
} else {
*x_off = *y_off = 0;
return pDrawable;
}
}
/*
* create the full func/op wrappers for a GC
*/
static Bool
cwCreateGCPrivate(GCPtr pGC, DrawablePtr pDrawable)
{
cwGCRec *pPriv;
int status, x_off, y_off;
XID noexpose = xFalse;
DrawablePtr pBackingDrawable;
pPriv = (cwGCRec *)xalloc(sizeof (cwGCRec));
if (!pPriv)
return FALSE;
pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off);
pPriv->pBackingGC = CreateGC(pBackingDrawable, GCGraphicsExposures,
&noexpose, &status);
if (status != Success) {
xfree(pPriv);
return FALSE;
}
pPriv->serialNumber = 0;
pPriv->stateChanges = (1 << (GCLastBit + 1)) - 1;
pPriv->wrapOps = pGC->ops;
pPriv->wrapFuncs = pGC->funcs;
pGC->funcs = &cwGCFuncs;
pGC->ops = &cwGCOps;
setCwGC (pGC, pPriv);
return TRUE;
}
static void
cwDestroyGCPrivate(GCPtr pGC)
{
cwGCPtr pPriv;
pPriv = (cwGCPtr) getCwGC (pGC);
pGC->funcs = &cwCheapGCFuncs;
pGC->ops = pPriv->wrapOps;
if (pPriv->pBackingGC)
FreeGC(pPriv->pBackingGC, (XID)0);
setCwGC (pGC, pPriv->wrapFuncs);
xfree((pointer)pPriv);
}
/* GCFuncs wrappers. These only get used when the drawable is a window with a
* backing pixmap, to avoid the overhead in the non-window-backing-pixmap case.
*/
#define FUNC_PROLOGUE(pGC, pPriv) \
((pGC)->funcs = pPriv->wrapFuncs), \
((pGC)->ops = pPriv->wrapOps)
#define FUNC_EPILOGUE(pGC, pPriv) \
((pGC)->funcs = &cwGCFuncs), \
((pGC)->ops = &cwGCOps)
static void
cwValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable)
{
GCPtr pBackingGC;
cwGCPtr pPriv;
DrawablePtr pBackingDrawable;
int x_off, y_off;
pPriv = (cwGCPtr) getCwGC (pGC);
FUNC_PROLOGUE(pGC, pPriv);
if (pDrawable->serialNumber != pPriv->serialNumber &&
!cwDrawableIsRedirWindow(pDrawable))
{
/* The drawable is no longer a window with backing store, so kill the
* private and go back to cheap functions.
*/
cwDestroyGCPrivate(pGC);
(*pGC->funcs->ValidateGC)(pGC, stateChanges, pDrawable);
return;
}
(*pGC->funcs->ValidateGC)(pGC, stateChanges, pDrawable);
/*
* rewrap funcs and ops as Validate may have changed them
*/
pPriv->wrapFuncs = pGC->funcs;
pPriv->wrapOps = pGC->ops;
pBackingGC = pPriv->pBackingGC;
pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off);
pPriv->stateChanges |= stateChanges;
if (pPriv->stateChanges) {
CopyGC(pGC, pBackingGC, pPriv->stateChanges);
pPriv->stateChanges = 0;
}
if ((pGC->patOrg.x + x_off) != pBackingGC->patOrg.x ||
(pGC->patOrg.y + y_off) != pBackingGC->patOrg.y)
{
XID vals[2];
vals[0] = pGC->patOrg.x + x_off;
vals[1] = pGC->patOrg.y + y_off;
DoChangeGC(pBackingGC, GCTileStipXOrigin|GCTileStipYOrigin, vals, 0);
}
if (pDrawable->serialNumber != pPriv->serialNumber) {
XID vals[2];
/* Either the drawable has changed, or the clip list in the drawable has
* changed. Copy the new clip list over and set the new translated
* offset for it.
*/
(*pBackingGC->funcs->DestroyClip)(pBackingGC);
(*pBackingGC->funcs->CopyClip)(pBackingGC, pGC);
vals[0] = pGC->clipOrg.x + x_off;
vals[1] = pGC->clipOrg.y + y_off;
DoChangeGC(pBackingGC, GCClipXOrigin|GCClipYOrigin, vals, 0);
ValidateGC(pBackingDrawable, pBackingGC);
pPriv->serialNumber = pDrawable->serialNumber;
}
FUNC_EPILOGUE(pGC, pPriv);
}
static void
cwChangeGC(GCPtr pGC, unsigned long mask)
{
cwGCPtr pPriv = (cwGCPtr)(pGC)->devPrivates[cwGCIndex].ptr;
FUNC_PROLOGUE(pGC, pPriv);
(*pGC->funcs->ChangeGC) (pGC, mask);
FUNC_EPILOGUE(pGC, pPriv);
}
static void
cwCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
{
cwGCPtr pPriv = (cwGCPtr)(pGCDst)->devPrivates[cwGCIndex].ptr;
FUNC_PROLOGUE(pGCDst, pPriv);
(*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
FUNC_EPILOGUE(pGCDst, pPriv);
}
static void
cwDestroyGC(GCPtr pGC)
{
cwGCPtr pPriv = (cwGCPtr)(pGC)->devPrivates[cwGCIndex].ptr;
FUNC_PROLOGUE(pGC, pPriv);
cwDestroyGCPrivate(pGC);
(*pGC->funcs->DestroyGC) (pGC);
/* leave it unwrapped */
}
static void
cwChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects)
{
cwGCPtr pPriv = (cwGCPtr)(pGC)->devPrivates[cwGCIndex].ptr;
FUNC_PROLOGUE(pGC, pPriv);
(*pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects);
FUNC_EPILOGUE(pGC, pPriv);
}
static void
cwCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
{
cwGCPtr pPriv = (cwGCPtr)(pgcDst)->devPrivates[cwGCIndex].ptr;
FUNC_PROLOGUE(pgcDst, pPriv);
(*pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
FUNC_EPILOGUE(pgcDst, pPriv);
}
static void
cwDestroyClip(GCPtr pGC)
{
cwGCPtr pPriv = (cwGCPtr)(pGC)->devPrivates[cwGCIndex].ptr;
FUNC_PROLOGUE(pGC, pPriv);
(*pGC->funcs->DestroyClip)(pGC);
FUNC_EPILOGUE(pGC, pPriv);
}
/*
* Cheap GC func wrappers. Pass everything through unless we find a window with
* a backing pixmap, then turn on the real wrappers.
*/
#define CHEAP_FUNC_PROLOGUE(pGC) \
((pGC)->funcs = (GCFuncs *)(pGC)->devPrivates[cwGCIndex].ptr)
#define CHEAP_FUNC_EPILOGUE(pGC) \
((pGC)->funcs = &cwCheapGCFuncs)
static void
cwCheapValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable)
{
CHEAP_FUNC_PROLOGUE(pGC);
/* Check if the drawable is a window with backing pixmap. If so,
* cwCreateGCPrivate will wrap with the backing-pixmap GC funcs and we won't
* re-wrap on return.
*/
if (pDrawable->type == DRAWABLE_WINDOW &&
cwDrawableIsRedirWindow(pDrawable) &&
cwCreateGCPrivate(pGC, pDrawable))
{
(*pGC->funcs->ValidateGC)(pGC, stateChanges, pDrawable);
}
else
{
(*pGC->funcs->ValidateGC)(pGC, stateChanges, pDrawable);
/* rewrap funcs as Validate may have changed them */
pGC->devPrivates[cwGCIndex].ptr = (pointer) pGC->funcs;
CHEAP_FUNC_EPILOGUE(pGC);
}
}
static void
cwCheapChangeGC(GCPtr pGC, unsigned long mask)
{
CHEAP_FUNC_PROLOGUE(pGC);
(*pGC->funcs->ChangeGC)(pGC, mask);
CHEAP_FUNC_EPILOGUE(pGC);
}
static void
cwCheapCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
{
CHEAP_FUNC_PROLOGUE(pGCDst);
(*pGCDst->funcs->CopyGC)(pGCSrc, mask, pGCDst);
CHEAP_FUNC_EPILOGUE(pGCDst);
}
static void
cwCheapDestroyGC(GCPtr pGC)
{
CHEAP_FUNC_PROLOGUE(pGC);
(*pGC->funcs->DestroyGC)(pGC);
/* leave it unwrapped */
}
static void
cwCheapChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects)
{
CHEAP_FUNC_PROLOGUE(pGC);
(*pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects);
CHEAP_FUNC_EPILOGUE(pGC);
}
static void
cwCheapCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
{
CHEAP_FUNC_PROLOGUE(pgcDst);
(*pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
CHEAP_FUNC_EPILOGUE(pgcDst);
}
static void
cwCheapDestroyClip(GCPtr pGC)
{
CHEAP_FUNC_PROLOGUE(pGC);
(*pGC->funcs->DestroyClip)(pGC);
CHEAP_FUNC_EPILOGUE(pGC);
}
/*
* GC Create wrapper. Set up the cheap GC func wrappers to track
* GC validation on BackingStore windows.
*/
#define SCREEN_PROLOGUE(pScreen, field)\
((pScreen)->field = ((cwScreenPtr) \
(pScreen)->devPrivates[cwScreenIndex].ptr)->field)
#define SCREEN_EPILOGUE(pScreen, field, wrapper)\
((pScreen)->field = wrapper)
static Bool
cwCreateGC(GCPtr pGC)
{
ScreenPtr pScreen = pGC->pScreen;
Bool ret;
SCREEN_PROLOGUE(pScreen, CreateGC);
if ( (ret = (*pScreen->CreateGC)(pGC)) )
{
pGC->devPrivates[cwGCIndex].ptr = (pointer)pGC->funcs;
pGC->funcs = &cwCheapGCFuncs;
}
SCREEN_EPILOGUE(pScreen, CreateGC, cwCreateGC);
return ret;
}
static void
cwGetImage(DrawablePtr pSrc, int x, int y, int w, int h, unsigned int format,
unsigned long planemask, char *pdstLine)
{
ScreenPtr pScreen = pSrc->pScreen;
DrawablePtr pBackingDrawable;
int src_off_x, src_off_y;
SCREEN_PROLOGUE(pScreen, GetImage);
pBackingDrawable = cwGetBackingDrawable(pSrc, &src_off_x, &src_off_y);
CW_OFFSET_XY_SRC(x, y);
(*pScreen->GetImage)(pBackingDrawable, x, y, w, h, format, planemask,
pdstLine);
SCREEN_EPILOGUE(pScreen, GetImage, cwGetImage);
}
static void
cwGetSpans(DrawablePtr pSrc, int wMax, DDXPointPtr ppt, int *pwidth,
int nspans, char *pdstStart)
{
ScreenPtr pScreen = pSrc->pScreen;
DrawablePtr pBackingDrawable;
int i;
int src_off_x, src_off_y;
SCREEN_PROLOGUE(pScreen, GetSpans);
pBackingDrawable = cwGetBackingDrawable(pSrc, &src_off_x, &src_off_y);
for (i = 0; i < nspans; i++)
CW_OFFSET_XY_SRC(ppt[i].x, ppt[i].y);
(*pScreen->GetSpans)(pBackingDrawable, wMax, ppt, pwidth, nspans,
pdstStart);
SCREEN_EPILOGUE(pScreen, GetSpans, cwGetSpans);
}
static void
cwFillRegionSolid(DrawablePtr pDrawable, RegionPtr pRegion, unsigned long pixel)
{
ScreenPtr pScreen = pDrawable->pScreen;
GCPtr pGC;
BoxPtr pBox;
int nbox, i;
ChangeGCVal v[3];
pGC = GetScratchGC(pDrawable->depth, pScreen);
v[0].val = GXcopy;
v[1].val = pixel;
v[2].val = FillSolid;
DoChangeGC(pGC, (GCFunction | GCForeground | GCFillStyle), (XID*)v, 1);
ValidateGC(pDrawable, pGC);
pBox = REGION_RECTS(pRegion);
nbox = REGION_NUM_RECTS(pRegion);
for (i = 0; i < nbox; i++, pBox++) {
xRectangle rect;
rect.x = pBox->x1;
rect.y = pBox->y1;
rect.width = pBox->x2 - pBox->x1;
rect.height = pBox->y2 - pBox->y1;
(*pGC->ops->PolyFillRect)(pDrawable, pGC, 1, &rect);
}
FreeScratchGC(pGC);
}
static void
cwFillRegionTiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile)
{
ScreenPtr pScreen = pDrawable->pScreen;
GCPtr pGC;
BoxPtr pBox;
int nbox, i;
ChangeGCVal v[5];
pGC = GetScratchGC(pDrawable->depth, pScreen);
v[0].val = GXcopy;
v[1].val = FillSolid;
v[2].ptr = (pointer) pTile;
v[3].val = 0;
v[4].val = 0;
DoChangeGC(pGC, (GCFunction | GCFillStyle | GCTile | GCTileStipXOrigin |
GCTileStipYOrigin),
(XID*)v, 1);
ValidateGC(pDrawable, pGC);
pBox = REGION_RECTS(pRegion);
nbox = REGION_NUM_RECTS(pRegion);
for (i = 0; i < nbox; i++, pBox++) {
xRectangle rect;
rect.x = pBox->x1;
rect.y = pBox->y1;
rect.width = pBox->x2 - pBox->x1;
rect.height = pBox->y2 - pBox->y1;
(*pGC->ops->PolyFillRect)(pDrawable, pGC, 1, &rect);
}
FreeScratchGC(pGC);
}
static void
cwPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, int what)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
int x_off, y_off;
SCREEN_PROLOGUE(pScreen, PaintWindowBackground);
if (!cwDrawableIsRedirWindow((DrawablePtr)pWin)) {
(*pScreen->PaintWindowBackground)(pWin, pRegion, what);
} else {
DrawablePtr pBackingDrawable;
pBackingDrawable = cwGetBackingDrawable((DrawablePtr)pWin, &x_off,
&y_off);
/* The region is already in screen coordinates, so don't offset by the
* window's coordinates in screen space.
*/
x_off -= pWin->drawable.x;
y_off -= pWin->drawable.y;
if (pWin->backgroundState == ParentRelative) {
do {
pWin = pWin->parent;
} while (pWin && pWin->backgroundState == ParentRelative);
}
if (pWin && (pWin->backgroundState == BackgroundPixel ||
pWin->backgroundState == BackgroundPixmap))
{
REGION_TRANSLATE(pScreen, pRegion, x_off, y_off);
if (pWin->backgroundState == BackgroundPixel) {
cwFillRegionSolid(pBackingDrawable, pRegion,
pWin->background.pixel);
} else {
cwFillRegionTiled(pBackingDrawable, pRegion,
pWin->background.pixmap);
}
REGION_TRANSLATE(pScreen, pRegion, -x_off, -y_off);
}
}
SCREEN_EPILOGUE(pScreen, PaintWindowBackground, cwPaintWindowBackground);
}
static void
cwPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, int what)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
int x_off, y_off;
SCREEN_PROLOGUE(pScreen, PaintWindowBorder);
if (!cwDrawableIsRedirWindow((DrawablePtr)pWin)) {
(*pScreen->PaintWindowBorder)(pWin, pRegion, what);
} else {
DrawablePtr pBackingDrawable;
pBackingDrawable = cwGetBackingDrawable((DrawablePtr)pWin, &x_off,
&y_off);
/* The region is already in screen coordinates, so don't offset by the
* window's coordinates in screen space.
*/
x_off -= pWin->drawable.x;
y_off -= pWin->drawable.y;
REGION_TRANSLATE(pScreen, pRegion, x_off, y_off);
if (pWin->borderIsPixel) {
cwFillRegionSolid(pBackingDrawable, pRegion, pWin->border.pixel);
} else {
cwFillRegionTiled(pBackingDrawable, pRegion, pWin->border.pixmap);
}
REGION_TRANSLATE(pScreen, pRegion, -x_off, -y_off);
}
SCREEN_EPILOGUE(pScreen, PaintWindowBorder, cwPaintWindowBorder);
}
/* Screen initialization/teardown */
void
miInitializeCompositeWrapper(ScreenPtr pScreen)
{
cwScreenPtr pScreenPriv;
if (cwGeneration != serverGeneration)
{
cwScreenIndex = AllocateScreenPrivateIndex();
if (cwScreenIndex < 0)
return;
cwGCIndex = AllocateGCPrivateIndex();
#ifdef RENDER
cwPictureIndex = AllocatePicturePrivateIndex();
#endif
cwGeneration = serverGeneration;
}
if (!AllocateGCPrivate(pScreen, cwGCIndex, 0))
return;
pScreenPriv = (cwScreenPtr)xalloc(sizeof(cwScreenRec));
if (!pScreenPriv)
return;
pScreenPriv->CloseScreen = pScreen->CloseScreen;
pScreenPriv->GetImage = pScreen->GetImage;
pScreenPriv->GetSpans = pScreen->GetSpans;
pScreenPriv->CreateGC = pScreen->CreateGC;
pScreenPriv->PaintWindowBackground = pScreen->PaintWindowBackground;
pScreenPriv->PaintWindowBorder = pScreen->PaintWindowBorder;
pScreen->CloseScreen = cwCloseScreen;
pScreen->GetImage = cwGetImage;
pScreen->GetSpans = cwGetSpans;
pScreen->CreateGC = cwCreateGC;
pScreen->PaintWindowBackground = cwPaintWindowBackground;
pScreen->PaintWindowBorder = cwPaintWindowBorder;
pScreen->devPrivates[cwScreenIndex].ptr = (pointer)pScreenPriv;
#ifdef RENDER
if (GetPictureScreen (pScreen))
{
if (!cwInitializeRender (pScreen))
/* FIXME */;
}
#endif
ErrorF("Initialized composite wrapper\n");
}
static Bool
cwCloseScreen (int i, ScreenPtr pScreen)
{
cwScreenPtr pScreenPriv;
#ifdef RENDER
PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
#endif
pScreenPriv = (cwScreenPtr)pScreen->devPrivates[cwScreenIndex].ptr;
pScreen->CloseScreen = pScreenPriv->CloseScreen;
pScreen->GetImage = pScreenPriv->GetImage;
pScreen->GetSpans = pScreenPriv->GetSpans;
pScreen->CreateGC = pScreenPriv->CreateGC;
pScreen->PaintWindowBackground = pScreenPriv->PaintWindowBackground;
pScreen->PaintWindowBorder = pScreenPriv->PaintWindowBorder;
#ifdef RENDER
if (ps) {
ps->Composite = pScreenPriv->Composite;
ps->Glyphs = pScreenPriv->Glyphs;
}
#endif
xfree((pointer)pScreenPriv);
return (*pScreen->CloseScreen)(i, pScreen);
}