diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:54 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:54 +0000 |
commit | ded6147bfb5d75ff1e67c858040a628b61bc17d1 (patch) | |
tree | 82355105e93cdac89ef7d987424351c77545faf0 /mi/mibstore.c | |
parent | cb6ef07bf01e72d1a6e6e83ceb7f76d6534da941 (diff) |
R6.6 is the Xorg base-lineXORG-MAIN
Diffstat (limited to 'mi/mibstore.c')
-rw-r--r-- | mi/mibstore.c | 3823 |
1 files changed, 3823 insertions, 0 deletions
diff --git a/mi/mibstore.c b/mi/mibstore.c new file mode 100644 index 000000000..f8a4cc891 --- /dev/null +++ b/mi/mibstore.c @@ -0,0 +1,3823 @@ +/* $Xorg: mibstore.c,v 1.4 2001/02/09 02:05:20 xorgcvs Exp $ */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +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. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by the Regents of the University of California + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, 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 The Open Group not be used in advertising or publicity +pertaining to distribution of the software without specific, written prior +permission. + +The University of California makes no representations about the suitability +of this software for any purpose. It is provided "as is" without express or +implied warranty. + +******************************************************************/ + +#define NEED_EVENTS +#include "X.h" +#include "Xmd.h" +#include "Xproto.h" +#include "misc.h" +#include "regionstr.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "extnsionst.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "fontstruct.h" +#include "dixfontstr.h" +#include "dixstruct.h" /* For requestingClient */ +#include "mi.h" +#include "mibstorest.h" + +/* + * When the server fails to allocate a backing store pixmap, if you want + * it to dynamically retry to allocate backing store on every subsequent + * graphics op, you can enable BSEAGER; otherwise, backing store will be + * disabled on the window until it is unmapped and then remapped. + */ +/* #define BSEAGER */ + +/*- + * NOTES ON USAGE: + * + * The functions in this file implement a machine-independent backing-store + * scheme. To use it, the output library must do the following: + * - Provide a SaveAreas function that takes a destination pixmap, a + * region of the areas to save (in the pixmap's coordinate system) + * and the screen origin of the region. It should copy the areas from + * the screen into the pixmap. + * - Provide a RestoreAreas function that takes a source pixmap, a region + * of the areas to restore (in the screen's coordinate system) and the + * origin of the pixmap on the screen. It should copy the areas from + * the pixmap into the screen. + * - Provide a SetClipmaskRgn function that takes a gc and a region + * and merges the region into any CT_PIXMAP client clip that + * is specified in the GC. This routine is only needed if + * miValidateBackingStore will see CT_PIXMAP clip lists; not + * true for any of the sample servers (which convert the PIXMAP + * clip lists into CT_REGION clip lists; an expensive but simple + * to code option). + * - The function placed in a window's ClearToBackground vector must call + * pScreen->ClearBackingStore with the window, followed by + * the window-relative x and y coordinates, followed by the width and + * height of the area to be cleared, followed by the generateExposures + * flag. This has been taken care of in miClearToBackground. + * - Whatever determines GraphicsExpose events for the CopyArea and + * CopyPlane requests should call pWin->backStorage->ExposeCopy + * with the source and destination drawables, the GC used, a source- + * window-relative region of exposed areas, the source and destination + * coordinates and the bitplane copied, if CopyPlane, or 0, if + * CopyArea. + * + * JUSTIFICATION + * This is a cross between saving everything and just saving the + * obscued areas (as in Pike's layers.) This method has the advantage + * of only doing each output operation once per pixel, visible or + * invisible, and avoids having to do all the crufty storage + * management of keeping several separate rectangles. Since the + * ddx layer ouput primitives are required to draw through clipping + * rectangles anyway, sending multiple drawing requests for each of + * several rectangles isn't necessary. (Of course, it could be argued + * that the ddx routines should just take one rectangle each and + * get called multiple times, but that would make taking advantage of + * smart hardware harder, and probably be slower as well.) + */ + +#define SETUP_BACKING_TERSE(pGC) \ + miBSGCPtr pGCPrivate = (miBSGCPtr)(pGC)->devPrivates[miBSGCIndex].ptr; \ + GCFuncs *oldFuncs = pGC->funcs; + +#define SETUP_BACKING(pDrawable,pGC) \ + miBSWindowPtr pBackingStore = \ + (miBSWindowPtr)((WindowPtr)(pDrawable))->backStorage; \ + DrawablePtr pBackingDrawable = (DrawablePtr) \ + pBackingStore->pBackingPixmap; \ + SETUP_BACKING_TERSE(pGC) \ + GCPtr pBackingGC = pGCPrivate->pBackingGC; + +#define PROLOGUE(pGC) { \ + pGC->ops = pGCPrivate->wrapOps;\ + pGC->funcs = pGCPrivate->wrapFuncs; \ + } + +#define EPILOGUE(pGC) { \ + pGCPrivate->wrapOps = (pGC)->ops; \ + (pGC)->ops = &miBSGCOps; \ + (pGC)->funcs = oldFuncs; \ + } + +static void miCreateBSPixmap(); +static void miDestroyBSPixmap(); +static void miTileVirtualBS(); +static void miBSAllocate(), miBSFree(); +static Bool miBSCreateGCPrivate (); +static void miBSClearBackingRegion (); + +#define MoreCopy0 ; +#define MoreCopy2 *dstCopy++ = *srcCopy++; *dstCopy++ = *srcCopy++; +#define MoreCopy4 MoreCopy2 MoreCopy2 + +#define copyData(src,dst,n,morecopy) \ +{ \ + register short *srcCopy = (short *)(src); \ + register short *dstCopy = (short *)(dst); \ + register int i; \ + register int bsx = pBackingStore->x; \ + register int bsy = pBackingStore->y; \ + for (i = n; --i >= 0; ) \ + { \ + *dstCopy++ = *srcCopy++ - bsx; \ + *dstCopy++ = *srcCopy++ - bsy; \ + morecopy \ + } \ +} + +#define copyPoints(src,dst,n,mode) \ +if (mode == CoordModeOrigin) \ +{ \ + copyData(src,dst,n,MoreCopy0); \ +} \ +else \ +{ \ + memmove((char *)(dst), (char *)(src), (n) << 2); \ + *((short *)(dst)) -= pBackingStore->x; \ + *((short *)(dst) + 1) -= pBackingStore->y; \ +} + +/* + * wrappers for screen funcs + */ + +static int miBSScreenIndex; +static unsigned long miBSGeneration = 0; + +static Bool miBSCloseScreen(); +static void miBSGetImage(); +static void miBSGetSpans(); +static Bool miBSChangeWindowAttributes(); +static Bool miBSCreateGC(); +static Bool miBSDestroyWindow(); + +/* + * backing store screen functions + */ + +static void miBSSaveDoomedAreas(); +static RegionPtr miBSRestoreAreas(); +static void miBSExposeCopy(); +static RegionPtr miBSTranslateBackingStore(), miBSClearBackingStore(); +static void miBSDrawGuarantee(); + +/* + * wrapper vectors for GC funcs and ops + */ + +static int miBSGCIndex; + +static void miBSValidateGC (), miBSCopyGC (), miBSDestroyGC(); +static void miBSChangeGC(); +static void miBSChangeClip(), miBSDestroyClip(), miBSCopyClip(); + +static GCFuncs miBSGCFuncs = { + miBSValidateGC, + miBSChangeGC, + miBSCopyGC, + miBSDestroyGC, + miBSChangeClip, + miBSDestroyClip, + miBSCopyClip, +}; + +static void miBSFillSpans(), miBSSetSpans(), miBSPutImage(); +static RegionPtr miBSCopyArea(), miBSCopyPlane(); +static void miBSPolyPoint(), miBSPolylines(), miBSPolySegment(); +static void miBSPolyRectangle(),miBSPolyArc(), miBSFillPolygon(); +static void miBSPolyFillRect(), miBSPolyFillArc(); +static int miBSPolyText8(), miBSPolyText16(); +static void miBSImageText8(), miBSImageText16(); +static void miBSImageGlyphBlt(),miBSPolyGlyphBlt(); +static void miBSPushPixels(); +#ifdef NEED_LINEHELPER +static void miBSLineHelper(); +#endif + +static GCOps miBSGCOps = { + miBSFillSpans, miBSSetSpans, miBSPutImage, + miBSCopyArea, miBSCopyPlane, miBSPolyPoint, + miBSPolylines, miBSPolySegment, miBSPolyRectangle, + miBSPolyArc, miBSFillPolygon, miBSPolyFillRect, + miBSPolyFillArc, miBSPolyText8, miBSPolyText16, + miBSImageText8, miBSImageText16, miBSImageGlyphBlt, + miBSPolyGlyphBlt, miBSPushPixels +#ifdef NEED_LINEHELPER + , miBSLineHelper +#endif +}; + +#define FUNC_PROLOGUE(pGC, pPriv) \ + ((pGC)->funcs = pPriv->wrapFuncs),\ + ((pGC)->ops = pPriv->wrapOps) + +#define FUNC_EPILOGUE(pGC, pPriv) \ + ((pGC)->funcs = &miBSGCFuncs),\ + ((pGC)->ops = &miBSGCOps) + +/* + * every GC in the server is initially wrapped with these + * "cheap" functions. This allocates no memory and is used + * to discover GCs used with windows which have backing + * store enabled + */ + +static void miBSCheapValidateGC(), miBSCheapCopyGC(), miBSCheapDestroyGC(); +static void miBSCheapChangeGC (); +static void miBSCheapChangeClip(), miBSCheapDestroyClip(); +static void miBSCheapCopyClip(); + +static GCFuncs miBSCheapGCFuncs = { + miBSCheapValidateGC, + miBSCheapChangeGC, + miBSCheapCopyGC, + miBSCheapDestroyGC, + miBSCheapChangeClip, + miBSCheapDestroyClip, + miBSCheapCopyClip, +}; + +#define CHEAP_FUNC_PROLOGUE(pGC) \ + ((pGC)->funcs = (GCFuncs *) (pGC)->devPrivates[miBSGCIndex].ptr) + +#define CHEAP_FUNC_EPILOGUE(pGC) \ + ((pGC)->funcs = &miBSCheapGCFuncs) + +/* + * called from device screen initialization proc. Gets a GCPrivateIndex + * and wraps appropriate per-screen functions + */ + +void +miInitializeBackingStore (pScreen, funcs) + ScreenPtr pScreen; + miBSFuncPtr funcs; +{ + miBSScreenPtr pScreenPriv; + + if (miBSGeneration != serverGeneration) + { + miBSScreenIndex = AllocateScreenPrivateIndex (); + if (miBSScreenIndex < 0) + return; + miBSGCIndex = AllocateGCPrivateIndex (); + miBSGeneration = serverGeneration; + } + if (!AllocateGCPrivate(pScreen, miBSGCIndex, 0)) + return; + pScreenPriv = (miBSScreenPtr) xalloc (sizeof (miBSScreenRec)); + if (!pScreenPriv) + return; + + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreenPriv->GetImage = pScreen->GetImage; + pScreenPriv->GetSpans = pScreen->GetSpans; + pScreenPriv->ChangeWindowAttributes = pScreen->ChangeWindowAttributes; + pScreenPriv->CreateGC = pScreen->CreateGC; + pScreenPriv->DestroyWindow = pScreen->DestroyWindow; + pScreenPriv->funcs = funcs; + + pScreen->CloseScreen = miBSCloseScreen; + pScreen->GetImage = miBSGetImage; + pScreen->GetSpans = miBSGetSpans; + pScreen->ChangeWindowAttributes = miBSChangeWindowAttributes; + pScreen->CreateGC = miBSCreateGC; + pScreen->DestroyWindow = miBSDestroyWindow; + + pScreen->SaveDoomedAreas = miBSSaveDoomedAreas; + pScreen->RestoreAreas = miBSRestoreAreas; + pScreen->ExposeCopy = miBSExposeCopy; + pScreen->TranslateBackingStore = miBSTranslateBackingStore; + pScreen->ClearBackingStore = miBSClearBackingStore; + pScreen->DrawGuarantee = miBSDrawGuarantee; + + pScreen->devPrivates[miBSScreenIndex].ptr = (pointer) pScreenPriv; +} + +/* + * Screen function wrappers + */ + +#define SCREEN_PROLOGUE(pScreen, field)\ + ((pScreen)->field = \ + ((miBSScreenPtr) \ + (pScreen)->devPrivates[miBSScreenIndex].ptr)->field) + +#define SCREEN_EPILOGUE(pScreen, field, wrapper)\ + ((pScreen)->field = wrapper) + +/* + * CloseScreen wrapper -- unwrap everything, free the private data + * and call the wrapped function + */ + +static Bool +miBSCloseScreen (i, pScreen) + int i; + ScreenPtr pScreen; +{ + miBSScreenPtr pScreenPriv; + + pScreenPriv = (miBSScreenPtr) pScreen->devPrivates[miBSScreenIndex].ptr; + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->GetImage = pScreenPriv->GetImage; + pScreen->GetSpans = pScreenPriv->GetSpans; + pScreen->ChangeWindowAttributes = pScreenPriv->ChangeWindowAttributes; + pScreen->CreateGC = pScreenPriv->CreateGC; + + xfree ((pointer) pScreenPriv); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +static void miBSFillVirtualBits(); + +static void +miBSGetImage (pDrawable, sx, sy, w, h, format, planemask, pdstLine) + DrawablePtr pDrawable; + int sx, sy, w, h; + unsigned int format; + unsigned long planemask; + char *pdstLine; +{ + ScreenPtr pScreen = pDrawable->pScreen; + BoxRec bounds; + unsigned char depth; + + SCREEN_PROLOGUE (pScreen, GetImage); + + if (pDrawable->type != DRAWABLE_PIXMAP && + ((WindowPtr) pDrawable)->visibility != VisibilityUnobscured) + { + PixmapPtr pPixmap; + miBSWindowPtr pWindowPriv; + GCPtr pGC; + WindowPtr pWin, pSrcWin; + int xoff, yoff; + RegionRec Remaining; + RegionRec Border; + RegionRec Inside; + BoxPtr pBox; + int n; + + pWin = (WindowPtr) pDrawable; + pPixmap = 0; + depth = pDrawable->depth; + bounds.x1 = sx + pDrawable->x; + bounds.y1 = sy + pDrawable->y; + bounds.x2 = bounds.x1 + w; + bounds.y2 = bounds.y1 + h; + REGION_INIT(pScreen, &Remaining, &bounds, 0); + for (;;) + { + bounds.x1 = sx + pDrawable->x - pWin->drawable.x; + bounds.y1 = sy + pDrawable->y - pWin->drawable.y; + bounds.x2 = bounds.x1 + w; + bounds.y2 = bounds.y1 + h; + if (pWin->viewable && pWin->backStorage && + pWin->drawable.depth == depth && + (RECT_IN_REGION(pScreen, &(pWindowPriv = + (miBSWindowPtr) pWin->backStorage)->SavedRegion, + &bounds) != rgnOUT || + RECT_IN_REGION(pScreen, &Remaining, + REGION_EXTENTS(pScreen, &pWin->borderSize)) != rgnOUT)) + { + if (!pPixmap) + { + XID subWindowMode = IncludeInferiors; + int x, y; + + pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, depth); + if (!pPixmap) + goto punt; + pGC = GetScratchGC (depth, pScreen); + if (!pGC) + { + (*pScreen->DestroyPixmap) (pPixmap); + goto punt; + } + ChangeGC (pGC, GCSubwindowMode, &subWindowMode); + ValidateGC ((DrawablePtr)pPixmap, pGC); + REGION_INIT(pScreen, &Border, NullBox, 0); + REGION_INIT(pScreen, &Inside, NullBox, 0); + pSrcWin = (WindowPtr) pDrawable; + x = sx; + y = sy; + if (pSrcWin->parent) + { + x += pSrcWin->origin.x; + y += pSrcWin->origin.y; + pSrcWin = pSrcWin->parent; + } + (*pGC->ops->CopyArea) ((DrawablePtr)pSrcWin, + (DrawablePtr)pPixmap, pGC, + x, y, w, h, + 0, 0); + REGION_SUBTRACT(pScreen, &Remaining, &Remaining, + &((WindowPtr) pDrawable)->borderClip); + } + + REGION_INTERSECT(pScreen, &Inside, &Remaining, &pWin->winSize); + REGION_TRANSLATE(pScreen, &Inside, + -pWin->drawable.x, + -pWin->drawable.y); + REGION_INTERSECT(pScreen, &Inside, &Inside, + &pWindowPriv->SavedRegion); + + /* offset of sub-window in GetImage pixmap */ + xoff = pWin->drawable.x - pDrawable->x - sx; + yoff = pWin->drawable.y - pDrawable->y - sy; + + if (REGION_NUM_RECTS(&Inside) > 0) + { + switch (pWindowPriv->status) + { + case StatusContents: + pBox = REGION_RECTS(&Inside); + for (n = REGION_NUM_RECTS(&Inside); --n >= 0;) + { + (*pGC->ops->CopyArea) ( + (DrawablePtr)pWindowPriv->pBackingPixmap, + (DrawablePtr)pPixmap, pGC, + pBox->x1 - pWindowPriv->x, + pBox->y1 - pWindowPriv->y, + pBox->x2 - pBox->x1, + pBox->y2 - pBox->y1, + pBox->x1 + xoff, + pBox->y1 + yoff); + ++pBox; + } + break; + case StatusVirtual: + case StatusVDirty: + if (pWindowPriv->backgroundState == BackgroundPixmap || + pWindowPriv->backgroundState == BackgroundPixel) + miBSFillVirtualBits ((DrawablePtr) pPixmap, pGC, &Inside, + xoff, yoff, + (int) pWindowPriv->backgroundState, + pWindowPriv->background, ~0L); + break; + } + } + REGION_SUBTRACT(pScreen, &Border, &pWin->borderSize, + &pWin->winSize); + REGION_INTERSECT(pScreen, &Border, &Border, &Remaining); + if (REGION_NUM_RECTS(&Border) > 0) + { + REGION_TRANSLATE(pScreen, &Border, -pWin->drawable.x, + -pWin->drawable.y); + miBSFillVirtualBits ((DrawablePtr) pPixmap, pGC, &Border, + xoff, yoff, + pWin->borderIsPixel ? (int)BackgroundPixel : (int)BackgroundPixmap, + pWin->border, ~0L); + } + } + + if (pWin->viewable && pWin->firstChild) + pWin = pWin->firstChild; + else + { + while (!pWin->nextSib && pWin != (WindowPtr) pDrawable) + pWin = pWin->parent; + if (pWin == (WindowPtr) pDrawable) + break; + pWin = pWin->nextSib; + } + } + + REGION_UNINIT(pScreen, &Remaining); + + if (pPixmap) + { + REGION_UNINIT(pScreen, &Border); + REGION_UNINIT(pScreen, &Inside); + (*pScreen->GetImage) ((DrawablePtr) pPixmap, + 0, 0, w, h, format, planemask, pdstLine); + (*pScreen->DestroyPixmap) (pPixmap); + FreeScratchGC (pGC); + } + else + { + goto punt; + } + } + else + { +punt: ; + (*pScreen->GetImage) (pDrawable, sx, sy, w, h, + format, planemask, pdstLine); + } + + SCREEN_EPILOGUE (pScreen, GetImage, miBSGetImage); +} + +static void +miBSGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart) + DrawablePtr pDrawable; + int wMax; + DDXPointPtr ppt; + int *pwidth; + int nspans; + char *pdstStart; +{ + ScreenPtr pScreen = pDrawable->pScreen; + BoxRec bounds; + int i; + WindowPtr pWin; + int dx, dy; + + SCREEN_PROLOGUE (pScreen, GetSpans); + + if (pDrawable->type != DRAWABLE_PIXMAP && ((WindowPtr) pDrawable)->backStorage) + { + PixmapPtr pPixmap; + miBSWindowPtr pWindowPriv; + GCPtr pGC; + + pWin = (WindowPtr) pDrawable; + pWindowPriv = (miBSWindowPtr) pWin->backStorage; + pPixmap = pWindowPriv->pBackingPixmap; + + bounds.x1 = ppt->x; + bounds.y1 = ppt->y; + bounds.x2 = bounds.x1 + *pwidth; + bounds.y2 = ppt->y; + for (i = 0; i < nspans; i++) + { + if (ppt[i].x < bounds.x1) + bounds.x1 = ppt[i].x; + if (ppt[i].x + pwidth[i] > bounds.x2) + bounds.x2 = ppt[i].x + pwidth[i]; + if (ppt[i].y < bounds.y1) + bounds.y1 = ppt[i].y; + else if (ppt[i].y > bounds.y2) + bounds.y2 = ppt[i].y; + } + + switch (RECT_IN_REGION(pScreen, &pWindowPriv->SavedRegion, &bounds)) + { + case rgnPART: + if (!pPixmap) + { + miCreateBSPixmap (pWin, NullBox); + if (!(pPixmap = pWindowPriv->pBackingPixmap)) + break; + } + pWindowPriv->status = StatusNoPixmap; + pGC = GetScratchGC(pPixmap->drawable.depth, + pPixmap->drawable.pScreen); + if (pGC) + { + ValidateGC ((DrawablePtr) pPixmap, pGC); + (*pGC->ops->CopyArea) + (pDrawable, (DrawablePtr) pPixmap, pGC, + bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, bounds.y2 - bounds.y1, + bounds.x1 + pPixmap->drawable.x - pWin->drawable.x - + pWindowPriv->x, + bounds.y1 + pPixmap->drawable.y - pWin->drawable.y - + pWindowPriv->y); + FreeScratchGC(pGC); + } + pWindowPriv->status = StatusContents; + /* fall through */ + case rgnIN: + if (!pPixmap) + { + miCreateBSPixmap (pWin, NullBox); + if (!(pPixmap = pWindowPriv->pBackingPixmap)) + break; + } + dx = pPixmap->drawable.x - pWin->drawable.x - pWindowPriv->x; + dy = pPixmap->drawable.y - pWin->drawable.y - pWindowPriv->y; + for (i = 0; i < nspans; i++) + { + ppt[i].x += dx; + ppt[i].y += dy; + } + (*pScreen->GetSpans) ((DrawablePtr) pPixmap, wMax, ppt, pwidth, + nspans, pdstStart); + break; + case rgnOUT: + (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, + pdstStart); + break; + } + } + else + { + (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + } + + SCREEN_EPILOGUE (pScreen, GetSpans, miBSGetSpans); +} + +static Bool +miBSChangeWindowAttributes (pWin, mask) + WindowPtr pWin; + unsigned long mask; +{ + ScreenPtr pScreen; + Bool ret; + + pScreen = pWin->drawable.pScreen; + + SCREEN_PROLOGUE (pScreen, ChangeWindowAttributes); + + ret = (*pScreen->ChangeWindowAttributes) (pWin, mask); + + if (ret && (mask & CWBackingStore)) + { + if (pWin->backingStore != NotUseful || pWin->DIXsaveUnder) + miBSAllocate (pWin); + else + miBSFree (pWin); + } + + SCREEN_EPILOGUE (pScreen, ChangeWindowAttributes, miBSChangeWindowAttributes); + + return ret; +} + +/* + * GC Create wrapper. Set up the cheap GC func wrappers to track + * GC validation on BackingStore windows + */ + +static Bool +miBSCreateGC (pGC) + GCPtr pGC; +{ + ScreenPtr pScreen = pGC->pScreen; + Bool ret; + + SCREEN_PROLOGUE (pScreen, CreateGC); + + if ( (ret = (*pScreen->CreateGC) (pGC)) ) + { + pGC->devPrivates[miBSGCIndex].ptr = (pointer) pGC->funcs; + pGC->funcs = &miBSCheapGCFuncs; + } + + SCREEN_EPILOGUE (pScreen, CreateGC, miBSCreateGC); + + return ret; +} + +static Bool +miBSDestroyWindow (pWin) + WindowPtr pWin; +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + Bool ret; + + SCREEN_PROLOGUE (pScreen, DestroyWindow); + + ret = (*pScreen->DestroyWindow) (pWin); + + miBSFree (pWin); + + SCREEN_EPILOGUE (pScreen, DestroyWindow, miBSDestroyWindow); + + return ret; +} + +/* + * cheap GC func wrappers. Simply track validation on windows + * with backing store to enable the real func/op wrappers + */ + +static void +miBSCheapValidateGC (pGC, stateChanges, pDrawable) + GCPtr pGC; + unsigned long stateChanges; + DrawablePtr pDrawable; +{ + CHEAP_FUNC_PROLOGUE (pGC); + + if (pDrawable->type != DRAWABLE_PIXMAP && + ((WindowPtr) pDrawable)->backStorage != NULL && + miBSCreateGCPrivate (pGC)) + { + (*pGC->funcs->ValidateGC) (pGC, stateChanges, pDrawable); + } + else + { + (*pGC->funcs->ValidateGC) (pGC, stateChanges, pDrawable); + + /* rewrap funcs as Validate may have changed them */ + pGC->devPrivates[miBSGCIndex].ptr = (pointer) pGC->funcs; + + CHEAP_FUNC_EPILOGUE (pGC); + } +} + +static void +miBSCheapChangeGC (pGC, mask) + GCPtr pGC; + unsigned long mask; +{ + CHEAP_FUNC_PROLOGUE (pGC); + + (*pGC->funcs->ChangeGC) (pGC, mask); + + CHEAP_FUNC_EPILOGUE (pGC); +} + +static void +miBSCheapCopyGC (pGCSrc, mask, pGCDst) + GCPtr pGCSrc, pGCDst; + unsigned long mask; +{ + CHEAP_FUNC_PROLOGUE (pGCDst); + + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + + CHEAP_FUNC_EPILOGUE (pGCDst); +} + +static void +miBSCheapDestroyGC (pGC) + GCPtr pGC; +{ + CHEAP_FUNC_PROLOGUE (pGC); + + (*pGC->funcs->DestroyGC) (pGC); + + /* leave it unwrapped */ +} + +static void +miBSCheapChangeClip (pGC, type, pvalue, nrects) + 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 +miBSCheapCopyClip(pgcDst, pgcSrc) + GCPtr pgcDst, pgcSrc; +{ + CHEAP_FUNC_PROLOGUE (pgcDst); + + (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + + CHEAP_FUNC_EPILOGUE (pgcDst); +} + +static void +miBSCheapDestroyClip(pGC) + GCPtr pGC; +{ + CHEAP_FUNC_PROLOGUE (pGC); + + (* pGC->funcs->DestroyClip)(pGC); + + CHEAP_FUNC_EPILOGUE (pGC); +} + +/* + * create the full func/op wrappers for a GC + */ + +static Bool +miBSCreateGCPrivate (pGC) + GCPtr pGC; +{ + miBSGCRec *pPriv; + + pPriv = (miBSGCRec *) xalloc (sizeof (miBSGCRec)); + if (!pPriv) + return FALSE; + pPriv->pBackingGC = NULL; + pPriv->guarantee = GuaranteeNothing; + pPriv->serialNumber = 0; + pPriv->stateChanges = (1 << (GCLastBit + 1)) - 1; + pPriv->wrapOps = pGC->ops; + pPriv->wrapFuncs = pGC->funcs; + pGC->funcs = &miBSGCFuncs; + pGC->ops = &miBSGCOps; + pGC->devPrivates[miBSGCIndex].ptr = (pointer) pPriv; + return TRUE; +} + +static void +miBSDestroyGCPrivate (pGC) + GCPtr pGC; +{ + miBSGCRec *pPriv; + + pPriv = (miBSGCRec *) pGC->devPrivates[miBSGCIndex].ptr; + if (pPriv) + { + pGC->devPrivates[miBSGCIndex].ptr = (pointer) pPriv->wrapFuncs; + pGC->funcs = &miBSCheapGCFuncs; + pGC->ops = pPriv->wrapOps; + if (pPriv->pBackingGC) + FreeGC (pPriv->pBackingGC, (GContext) 0); + xfree ((pointer) pPriv); + } +} + +/* + * GC ops -- wrap each GC operation with our own function + */ + +/*- + *----------------------------------------------------------------------- + * miBSFillSpans -- + * Perform a FillSpans, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted) + DrawablePtr pDrawable; + GCPtr pGC; + int nInit; /* number of spans to fill */ + DDXPointPtr pptInit; /* pointer to list of start points */ + int *pwidthInit; /* pointer to list of n widths */ + int fSorted; +{ + DDXPointPtr pptCopy, pptReset; + int *pwidthCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pptCopy = (DDXPointPtr)ALLOCATE_LOCAL(nInit*sizeof(DDXPointRec)); + pwidthCopy=(int *)ALLOCATE_LOCAL(nInit*sizeof(int)); + if (pptCopy && pwidthCopy) + { + copyData(pptInit, pptCopy, nInit, MoreCopy0); + memmove((char *)pwidthCopy,(char *)pwidthInit,nInit*sizeof(int)); + + (* pGC->ops->FillSpans)(pDrawable, pGC, nInit, pptInit, + pwidthInit, fSorted); + if (pGC->miTranslate) + { + int dx, dy; + int nReset; + + pptReset = pptCopy; + dx = pDrawable->x - pBackingDrawable->x; + dy = pDrawable->y - pBackingDrawable->y; + nReset = nInit; + while (nReset--) + { + pptReset->x -= dx; + pptReset->y -= dy; + ++pptReset; + } + } + (* pBackingGC->ops->FillSpans)(pBackingDrawable, + pBackingGC, nInit, pptCopy, pwidthCopy, + fSorted); + } + if (pwidthCopy) DEALLOCATE_LOCAL(pwidthCopy); + if (pptCopy) DEALLOCATE_LOCAL(pptCopy); + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSSetSpans -- + * Perform a SetSpans, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted) + DrawablePtr pDrawable; + GCPtr pGC; + char *psrc; + register DDXPointPtr ppt; + int *pwidth; + int nspans; + int fSorted; +{ + DDXPointPtr pptCopy, pptReset; + int *pwidthCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pptCopy = (DDXPointPtr)ALLOCATE_LOCAL(nspans*sizeof(DDXPointRec)); + pwidthCopy=(int *)ALLOCATE_LOCAL(nspans*sizeof(int)); + if (pptCopy && pwidthCopy) + { + copyData(ppt, pptCopy, nspans, MoreCopy0); + memmove((char *)pwidthCopy,(char *)pwidth,nspans*sizeof(int)); + + (* pGC->ops->SetSpans)(pDrawable, pGC, psrc, ppt, pwidth, + nspans, fSorted); + if (pGC->miTranslate) + { + int dx, dy; + int nReset; + + pptReset = pptCopy; + dx = pDrawable->x - pBackingDrawable->x; + dy = pDrawable->y - pBackingDrawable->y; + nReset = nspans; + while (nReset--) + { + pptReset->x -= dx; + pptReset->y -= dy; + ++pptReset; + } + } + (* pBackingGC->ops->SetSpans)(pBackingDrawable, pBackingGC, + psrc, pptCopy, pwidthCopy, nspans, fSorted); + } + if (pwidthCopy) DEALLOCATE_LOCAL(pwidthCopy); + if (pptCopy) DEALLOCATE_LOCAL(pptCopy); + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPutImage -- + * Perform a PutImage, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits) + DrawablePtr pDrawable; + GCPtr pGC; + int depth; + int x; + int y; + int w; + int h; + int leftPad; + int format; + char *pBits; +{ + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + (*pGC->ops->PutImage)(pDrawable, pGC, + depth, x, y, w, h, leftPad, format, pBits); + (*pBackingGC->ops->PutImage)(pBackingDrawable, pBackingGC, + depth, x - pBackingStore->x, y - pBackingStore->y, + w, h, leftPad, format, pBits); + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSDoCopy -- + * Perform a CopyArea or CopyPlane within a window that has backing + * store enabled. + * + * Results: + * TRUE if the copy was performed or FALSE if a regular one should + * be done. + * + * Side Effects: + * Things are copied (no s***!) + * + * Notes: + * The idea here is to form two regions that cover the source box. + * One contains the exposed rectangles while the other contains + * the obscured ones. An array of <box, drawable> pairs is then + * formed where the <box> indicates the area to be copied and the + * <drawable> indicates from where it is to be copied (exposed regions + * come from the screen while obscured ones come from the backing + * pixmap). The array 'sequence' is then filled with the indices of + * the pairs in the order in which they should be copied to prevent + * things from getting screwed up. A call is also made through the + * backingGC to take care of any copying into the backing pixmap. + * + *----------------------------------------------------------------------- + */ +static Bool +miBSDoCopy(pWin, pGC, srcx, srcy, w, h, dstx, dsty, plane, copyProc, ppRgn) + WindowPtr pWin; /* Window being scrolled */ + GCPtr pGC; /* GC we're called through */ + int srcx; /* X of source rectangle */ + int srcy; /* Y of source rectangle */ + int w; /* Width of source rectangle */ + int h; /* Height of source rectangle */ + int dstx; /* X of destination rectangle */ + int dsty; /* Y of destination rectangle */ + unsigned long plane; /* Plane to copy (0 for CopyArea) */ + RegionPtr (*copyProc)(); /* Procedure to call to perform the copy */ + RegionPtr *ppRgn; /* resultant Graphics Expose region */ +{ + RegionPtr pRgnExp; /* Exposed region */ + RegionPtr pRgnObs; /* Obscured region */ + BoxRec box; /* Source box (screen coord) */ + struct BoxDraw { + BoxPtr pBox; /* Source box */ + enum { + win, pix + } source; /* Place from which to copy */ + } *boxes; /* Array of box/drawable pairs covering + * source box. */ + int *sequence; /* Sequence of boxes to move */ + register int i, j, k, l, y; + register BoxPtr pBox; + int dx, dy, nrects; + Bool graphicsExposures; + RegionPtr (*pixCopyProc)(); + int numRectsExp, numRectsObs; + BoxPtr pBoxExp, pBoxObs; + + SETUP_BACKING (pWin, pGC); + + /* + * Create a region of exposed boxes in pRgnExp. + */ + box.x1 = srcx + pWin->drawable.x; + box.x2 = box.x1 + w; + box.y1 = srcy + pWin->drawable.y; + box.y2 = box.y1 + h; + + pRgnExp = REGION_CREATE(pGC->pScreen, &box, 1); + REGION_INTERSECT(pGC->pScreen, pRgnExp, pRgnExp, &pWin->clipList); + pRgnObs = REGION_CREATE(pGC->pScreen, NULL, 1); + REGION_INVERSE( pGC->pScreen, pRgnObs, pRgnExp, &box); + + /* + * Translate regions into window coordinates for proper calls + * to the copyProc, then make sure none of the obscured region sticks + * into invalid areas of the backing pixmap. + */ + REGION_TRANSLATE(pGC->pScreen, pRgnExp, + -pWin->drawable.x, + -pWin->drawable.y); + REGION_TRANSLATE(pGC->pScreen, pRgnObs, + -pWin->drawable.x, + -pWin->drawable.y); + REGION_INTERSECT(pGC->pScreen, pRgnObs, pRgnObs, &pBackingStore->SavedRegion); + + /* + * If the obscured region is empty, there's no point being fancy. + */ + if (!REGION_NOTEMPTY(pGC->pScreen, pRgnObs)) + { + REGION_DESTROY(pGC->pScreen, pRgnExp); + REGION_DESTROY(pGC->pScreen, pRgnObs); + + return (FALSE); + } + + numRectsExp = REGION_NUM_RECTS(pRgnExp); + pBoxExp = REGION_RECTS(pRgnExp); + pBoxObs = REGION_RECTS(pRgnObs); + numRectsObs = REGION_NUM_RECTS(pRgnObs); + nrects = numRectsExp + numRectsObs; + + boxes = (struct BoxDraw *)ALLOCATE_LOCAL(nrects * sizeof(struct BoxDraw)); + sequence = (int *) ALLOCATE_LOCAL(nrects * sizeof(int)); + *ppRgn = NULL; + + if (!boxes || !sequence) + { + if (sequence) DEALLOCATE_LOCAL(sequence); + if (boxes) DEALLOCATE_LOCAL(boxes); + REGION_DESTROY(pGC->pScreen, pRgnExp); + REGION_DESTROY(pGC->pScreen, pRgnObs); + + return(TRUE); + } + + /* + * Order the boxes in the two regions so we know from which drawable + * to copy which box, storing the result in the boxes array + */ + for (i = 0, j = 0, k = 0; + (i < numRectsExp) && (j < numRectsObs); + k++) + { + if (pBoxExp[i].y1 < pBoxObs[j].y1) + { + boxes[k].pBox = &pBoxExp[i]; + boxes[k].source = win; + i++; + } + else if ((pBoxObs[j].y1 < pBoxExp[i].y1) || + (pBoxObs[j].x1 < pBoxExp[i].x1)) + { + boxes[k].pBox = &pBoxObs[j]; + boxes[k].source = pix; + j++; + } + else + { + boxes[k].pBox = &pBoxExp[i]; + boxes[k].source = win; + i++; + } + } + + /* + * Catch any leftover boxes from either region (note that only + * one can have leftover boxes...) + */ + if (i != numRectsExp) + { + do + { + boxes[k].pBox = &pBoxExp[i]; + boxes[k].source = win; + i++; + k++; + } while (i < numRectsExp); + + } + else + { + do + { + boxes[k].pBox = &pBoxObs[j]; + boxes[k].source = pix; + j++; + k++; + } while (j < numRectsObs); + } + + if (dsty <= srcy) + { + /* + * Scroll up or vertically stationary, so vertical order is ok. + */ + if (dstx <= srcx) + { + /* + * Scroll left or horizontally stationary, so horizontal order + * is ok as well. + */ + for (i = 0; i < nrects; i++) + { + sequence[i] = i; + } + } + else + { + /* + * Scroll right. Need to reverse the rectangles within each + * band. + */ + for (i = 0, j = 1, k = 0; + i < nrects; + j = i + 1, k = i) + { + y = boxes[i].pBox->y1; + while ((j < nrects) && (boxes[j].pBox->y1 == y)) + { + j++; + } + for (j--; j >= k; j--, i++) + { + sequence[i] = j; + } + } + } + } + else + { + /* + * Scroll down. Must reverse vertical banding, at least. + */ + if (dstx < srcx) + { + /* + * Scroll left. Horizontal order is ok. + */ + for (i = nrects - 1, j = i - 1, k = i, l = 0; + i >= 0; + j = i - 1, k = i) + { + /* + * Find extent of current horizontal band, then reverse + * the order of the whole band. + */ + y = boxes[i].pBox->y1; + while ((j >= 0) && (boxes[j].pBox->y1 == y)) + { + j--; + } + for (j++; j <= k; j++, i--, l++) + { + sequence[l] = j; + } + } + } + else + { + /* + * Scroll right or horizontal stationary. + * Reverse horizontal order as well (if stationary, horizontal + * order can be swapped without penalty and this is faster + * to compute). + */ + for (i = 0, j = nrects - 1; i < nrects; i++, j--) + { + sequence[i] = j; + } + } + } + + /* + * XXX: To avoid getting multiple NoExpose events from this operation, + * we turn OFF graphicsExposures in the gc and deal with any uncopied + * areas later, if there's something not in backing-store. + */ + + graphicsExposures = pGC->graphicsExposures; + pGC->graphicsExposures = FALSE; + + dx = dstx - srcx; + dy = dsty - srcy; + + /* + * Figure out which copy procedure to use from the backing GC. Note we + * must do this because some implementations (sun's, e.g.) have + * pBackingGC a fake GC with the real one below it, thus the devPriv for + * pBackingGC won't be what the output library expects. + */ + if (plane != 0) + { + pixCopyProc = pBackingGC->ops->CopyPlane; + } + else + { + pixCopyProc = pBackingGC->ops->CopyArea; + } + + for (i = 0; i < nrects; i++) + { + pBox = boxes[sequence[i]].pBox; + + /* + * If we're copying from the pixmap, we need to place its contents + * onto the screen before scrolling the pixmap itself. If we're copying + * from the window, we need to copy its contents into the pixmap before + * we scroll the window itself. + */ + if (boxes[sequence[i]].source == pix) + { + (void) (* copyProc) (pBackingDrawable, pWin, pGC, + pBox->x1 - pBackingStore->x, + pBox->y1 - pBackingStore->y, + pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, + pBox->x1 + dx, pBox->y1 + dy, plane); + (void) (* pixCopyProc) (pBackingDrawable, pBackingDrawable, pBackingGC, + pBox->x1 - pBackingStore->x, + pBox->y1 - pBackingStore->y, + pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, + pBox->x1 + dx - pBackingStore->x, + pBox->y1 + dy - pBackingStore->y, plane); + } + else + { + (void) (* pixCopyProc) (pWin, pBackingDrawable, pBackingGC, + pBox->x1, pBox->y1, + pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, + pBox->x1 + dx - pBackingStore->x, + pBox->y1 + dy - pBackingStore->y, plane); + (void) (* copyProc) (pWin, pWin, pGC, + pBox->x1, pBox->y1, + pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, + pBox->x1 + dx, pBox->y1 + dy, plane); + } + } + DEALLOCATE_LOCAL(sequence); + DEALLOCATE_LOCAL(boxes); + + pGC->graphicsExposures = graphicsExposures; + /* + * Form union of rgnExp and rgnObs and see if covers entire area + * to be copied. Store the resultant region for miBSCopyArea + * to return to dispatch which will send the appropriate expose + * events. + */ + REGION_UNION(pGC->pScreen, pRgnExp, pRgnExp, pRgnObs); + box.x1 = srcx; + box.x2 = srcx + w; + box.y1 = srcy; + box.y2 = srcy + h; + if (RECT_IN_REGION(pGC->pScreen, pRgnExp, &box) == rgnIN) + { + REGION_EMPTY(pGC->pScreen, pRgnExp); + } + else + { + REGION_INVERSE( pGC->pScreen, pRgnExp, pRgnExp, &box); + REGION_TRANSLATE( pGC->pScreen, pRgnExp, + dx + pWin->drawable.x, + dy + pWin->drawable.y); + REGION_INTERSECT( pGC->pScreen, pRgnObs, pRgnExp, &pWin->clipList); + (*pWin->drawable.pScreen->PaintWindowBackground) (pWin, + pRgnObs, PW_BACKGROUND); + REGION_TRANSLATE( pGC->pScreen, pRgnExp, + -pWin->drawable.x, + -pWin->drawable.y); + miBSClearBackingRegion (pWin, pRgnExp); + } + if (graphicsExposures) + *ppRgn = pRgnExp; + else + REGION_DESTROY(pGC->pScreen, pRgnExp); + REGION_DESTROY(pGC->pScreen, pRgnObs); + + return (TRUE); +} + +/*- + *----------------------------------------------------------------------- + * miBSCopyArea -- + * Perform a CopyArea from the source to the destination, extracting + * from the source's backing-store and storing into the destination's + * backing-store without messing anything up. If the source and + * destination are different, there's not too much to worry about: + * we can just issue several calls to the regular CopyArea function. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static RegionPtr +miBSCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty) + DrawablePtr pSrc; + DrawablePtr pDst; + GCPtr pGC; + int srcx; + int srcy; + int w; + int h; + int dstx; + int dsty; +{ + BoxPtr pExtents; + long dx, dy; + int bsrcx, bsrcy, bw, bh, bdstx, bdsty; + RegionPtr pixExposed = 0, winExposed = 0; + + SETUP_BACKING(pDst, pGC); + + PROLOGUE(pGC); + + if ((pSrc != pDst) || + (!miBSDoCopy((WindowPtr)pSrc, pGC, srcx, srcy, w, h, dstx, dsty, + (unsigned long) 0, pGC->ops->CopyArea, &winExposed))) + { + /* + * always copy to the backing store first, miBSDoCopy + * returns FALSE if the *source* region is disjoint + * from the backing store saved region. So, copying + * *to* the backing store is always safe + */ + if (pGC->clientClipType != CT_PIXMAP) + { + /* + * adjust srcx, srcy, w, h, dstx, dsty to be clipped to + * the backing store. An unnecessary optimisation, + * but a useful one when GetSpans is slow. + */ + pExtents = REGION_EXTENTS(pDst->pScreen, + (RegionPtr)pBackingGC->clientClip); + bsrcx = srcx; + bsrcy = srcy; + bw = w; + bh = h; + bdstx = dstx; + bdsty = dsty; + dx = pExtents->x1 - bdstx; + if (dx > 0) + { + bsrcx += dx; + bdstx += dx; + bw -= dx; + } + dy = pExtents->y1 - bdsty; + if (dy > 0) + { + bsrcy += dy; + bdsty += dy; + bh -= dy; + } + dx = (bdstx + bw) - pExtents->x2; + if (dx > 0) + bw -= dx; + dy = (bdsty + bh) - pExtents->y2; + if (dy > 0) + bh -= dy; + if (bw > 0 && bh > 0) + pixExposed = (* pBackingGC->ops->CopyArea) (pSrc, + pBackingDrawable, pBackingGC, + bsrcx, bsrcy, bw, bh, bdstx - pBackingStore->x, + bdsty - pBackingStore->y); + } + else + pixExposed = (* pBackingGC->ops->CopyArea) (pSrc, + pBackingDrawable, pBackingGC, + srcx, srcy, w, h, + dstx - pBackingStore->x, dsty - pBackingStore->y); + + winExposed = (* pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); + } + + /* + * compute the composite graphics exposure region + */ + if (winExposed) + { + if (pixExposed){ + REGION_UNION(pDst->pScreen, winExposed, winExposed, pixExposed); + REGION_DESTROY(pDst->pScreen, pixExposed); + } + } else + winExposed = pixExposed; + + EPILOGUE (pGC); + + return winExposed; +} + +/*- + *----------------------------------------------------------------------- + * miBSCopyPlane -- + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static RegionPtr +miBSCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane) + DrawablePtr pSrc; + DrawablePtr pDst; + register GC *pGC; + int srcx, + srcy; + int w, + h; + int dstx, + dsty; + unsigned long plane; +{ + BoxPtr pExtents; + long dx, dy; + int bsrcx, bsrcy, bw, bh, bdstx, bdsty; + RegionPtr winExposed = 0, pixExposed = 0; + SETUP_BACKING(pDst, pGC); + + PROLOGUE(pGC); + + if ((pSrc != pDst) || + (!miBSDoCopy((WindowPtr)pSrc, pGC, srcx, srcy, w, h, dstx, dsty, + plane, pGC->ops->CopyPlane, &winExposed))) + { + /* + * always copy to the backing store first, miBSDoCopy + * returns FALSE if the *source* region is disjoint + * from the backing store saved region. So, copying + * *to* the backing store is always safe + */ + if (pGC->clientClipType != CT_PIXMAP) + { + /* + * adjust srcx, srcy, w, h, dstx, dsty to be clipped to + * the backing store. An unnecessary optimisation, + * but a useful one when GetSpans is slow. + */ + pExtents = REGION_EXTENTS(pDst->pScreen, + (RegionPtr)pBackingGC->clientClip); + bsrcx = srcx; + bsrcy = srcy; + bw = w; + bh = h; + bdstx = dstx; + bdsty = dsty; + dx = pExtents->x1 - bdstx; + if (dx > 0) + { + bsrcx += dx; + bdstx += dx; + bw -= dx; + } + dy = pExtents->y1 - bdsty; + if (dy > 0) + { + bsrcy += dy; + bdsty += dy; + bh -= dy; + } + dx = (bdstx + bw) - pExtents->x2; + if (dx > 0) + bw -= dx; + dy = (bdsty + bh) - pExtents->y2; + if (dy > 0) + bh -= dy; + if (bw > 0 && bh > 0) + pixExposed = (* pBackingGC->ops->CopyPlane) (pSrc, + pBackingDrawable, + pBackingGC, bsrcx, bsrcy, bw, bh, + bdstx - pBackingStore->x, + bdsty - pBackingStore->y, plane); + } + else + pixExposed = (* pBackingGC->ops->CopyPlane) (pSrc, + pBackingDrawable, + pBackingGC, srcx, srcy, w, h, + dstx - pBackingStore->x, + dsty - pBackingStore->y, plane); + + winExposed = (* pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h, + dstx, dsty, plane); + + } + + /* + * compute the composite graphics exposure region + */ + if (winExposed) + { + if (pixExposed) + { + REGION_UNION(pDst->pScreen, winExposed, winExposed, pixExposed); + REGION_DESTROY(pDst->pScreen, pixExposed); + } + } else + winExposed = pixExposed; + + EPILOGUE (pGC); + + return winExposed; +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyPoint -- + * Perform a PolyPoint, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolyPoint (pDrawable, pGC, mode, npt, pptInit) + DrawablePtr pDrawable; + GCPtr pGC; + int mode; /* Origin or Previous */ + int npt; + xPoint *pptInit; +{ + xPoint *pptCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pptCopy = (xPoint *)ALLOCATE_LOCAL(npt*sizeof(xPoint)); + if (pptCopy) + { + copyPoints(pptInit, pptCopy, npt, mode); + + (* pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pptInit); + + (* pBackingGC->ops->PolyPoint) (pBackingDrawable, + pBackingGC, mode, npt, pptCopy); + + DEALLOCATE_LOCAL(pptCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyLines -- + * Perform a Polylines, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolylines (pDrawable, pGC, mode, npt, pptInit) + DrawablePtr pDrawable; + GCPtr pGC; + int mode; + int npt; + DDXPointPtr pptInit; +{ + DDXPointPtr pptCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pptCopy = (DDXPointPtr)ALLOCATE_LOCAL(npt*sizeof(DDXPointRec)); + if (pptCopy) + { + copyPoints(pptInit, pptCopy, npt, mode); + + (* pGC->ops->Polylines)(pDrawable, pGC, mode, npt, pptInit); + (* pBackingGC->ops->Polylines)(pBackingDrawable, + pBackingGC, mode, npt, pptCopy); + DEALLOCATE_LOCAL(pptCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolySegment -- + * Perform a PolySegment, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolySegment(pDrawable, pGC, nseg, pSegs) + DrawablePtr pDrawable; + GCPtr pGC; + int nseg; + xSegment *pSegs; +{ + xSegment *pSegsCopy; + + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pSegsCopy = (xSegment *)ALLOCATE_LOCAL(nseg*sizeof(xSegment)); + if (pSegsCopy) + { + copyData(pSegs, pSegsCopy, nseg << 1, MoreCopy0); + + (* pGC->ops->PolySegment)(pDrawable, pGC, nseg, pSegs); + (* pBackingGC->ops->PolySegment)(pBackingDrawable, + pBackingGC, nseg, pSegsCopy); + + DEALLOCATE_LOCAL(pSegsCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyRectangle -- + * Perform a PolyRectangle, routing output to backing-store as needed. + * + * Results: + * None + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolyRectangle(pDrawable, pGC, nrects, pRects) + DrawablePtr pDrawable; + GCPtr pGC; + int nrects; + xRectangle *pRects; +{ + xRectangle *pRectsCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pRectsCopy =(xRectangle *)ALLOCATE_LOCAL(nrects*sizeof(xRectangle)); + if (pRectsCopy) + { + copyData(pRects, pRectsCopy, nrects, MoreCopy2); + + (* pGC->ops->PolyRectangle)(pDrawable, pGC, nrects, pRects); + (* pBackingGC->ops->PolyRectangle)(pBackingDrawable, + pBackingGC, nrects, pRectsCopy); + + DEALLOCATE_LOCAL(pRectsCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyArc -- + * Perform a PolyArc, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolyArc(pDrawable, pGC, narcs, parcs) + DrawablePtr pDrawable; + GCPtr pGC; + int narcs; + xArc *parcs; +{ + xArc *pArcsCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pArcsCopy = (xArc *)ALLOCATE_LOCAL(narcs*sizeof(xArc)); + if (pArcsCopy) + { + copyData(parcs, pArcsCopy, narcs, MoreCopy4); + + (* pGC->ops->PolyArc)(pDrawable, pGC, narcs, parcs); + (* pBackingGC->ops->PolyArc)(pBackingDrawable, pBackingGC, + narcs, pArcsCopy); + + DEALLOCATE_LOCAL(pArcsCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSFillPolygon -- + * Perform a FillPolygon, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSFillPolygon(pDrawable, pGC, shape, mode, count, pPts) + DrawablePtr pDrawable; + register GCPtr pGC; + int shape, mode; + register int count; + DDXPointPtr pPts; +{ + DDXPointPtr pPtsCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pPtsCopy = (DDXPointPtr)ALLOCATE_LOCAL(count*sizeof(DDXPointRec)); + if (pPtsCopy) + { + copyPoints(pPts, pPtsCopy, count, mode); + (* pGC->ops->FillPolygon)(pDrawable, pGC, shape, mode, count, pPts); + (* pBackingGC->ops->FillPolygon)(pBackingDrawable, + pBackingGC, shape, mode, + count, pPtsCopy); + + DEALLOCATE_LOCAL(pPtsCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyFillRect -- + * Perform a PolyFillRect, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolyFillRect(pDrawable, pGC, nrectFill, prectInit) + DrawablePtr pDrawable; + GCPtr pGC; + int nrectFill; /* number of rectangles to fill */ + xRectangle *prectInit; /* Pointer to first rectangle to fill */ +{ + xRectangle *pRectCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pRectCopy = + (xRectangle *)ALLOCATE_LOCAL(nrectFill*sizeof(xRectangle)); + if (pRectCopy) + { + copyData(prectInit, pRectCopy, nrectFill, MoreCopy2); + + (* pGC->ops->PolyFillRect)(pDrawable, pGC, nrectFill, prectInit); + (* pBackingGC->ops->PolyFillRect)(pBackingDrawable, + pBackingGC, nrectFill, pRectCopy); + + DEALLOCATE_LOCAL(pRectCopy); + } + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyFillArc -- + * Perform a PolyFillArc, routing output to backing-store as needed. + * + * Results: + * None. + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolyFillArc(pDrawable, pGC, narcs, parcs) + DrawablePtr pDrawable; + GCPtr pGC; + int narcs; + xArc *parcs; +{ + xArc *pArcsCopy; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + pArcsCopy = (xArc *)ALLOCATE_LOCAL(narcs*sizeof(xArc)); + if (pArcsCopy) + { + copyData(parcs, pArcsCopy, narcs, MoreCopy4); + (* pGC->ops->PolyFillArc)(pDrawable, pGC, narcs, parcs); + (* pBackingGC->ops->PolyFillArc)(pBackingDrawable, + pBackingGC, narcs, pArcsCopy); + DEALLOCATE_LOCAL(pArcsCopy); + } + + EPILOGUE (pGC); +} + + +/*- + *----------------------------------------------------------------------- + * miBSPolyText8 -- + * Perform a PolyText8, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static int +miBSPolyText8(pDrawable, pGC, x, y, count, chars) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + int count; + char *chars; +{ + int result; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + result = (* pGC->ops->PolyText8)(pDrawable, pGC, x, y, count, chars); + (* pBackingGC->ops->PolyText8)(pBackingDrawable, pBackingGC, + x - pBackingStore->x, y - pBackingStore->y, + count, chars); + + EPILOGUE (pGC); + return result; +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyText16 -- + * Perform a PolyText16, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static int +miBSPolyText16(pDrawable, pGC, x, y, count, chars) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + int count; + unsigned short *chars; +{ + int result; + SETUP_BACKING (pDrawable, pGC); + + PROLOGUE(pGC); + + result = (* pGC->ops->PolyText16)(pDrawable, pGC, x, y, count, chars); + (* pBackingGC->ops->PolyText16)(pBackingDrawable, pBackingGC, + x - pBackingStore->x, y - pBackingStore->y, + count, chars); + + EPILOGUE (pGC); + + return result; +} + +/*- + *----------------------------------------------------------------------- + * miBSImageText8 -- + * Perform a ImageText8, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSImageText8(pDrawable, pGC, x, y, count, chars) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + int count; + char *chars; +{ + SETUP_BACKING (pDrawable, pGC); + PROLOGUE(pGC); + + (* pGC->ops->ImageText8)(pDrawable, pGC, x, y, count, chars); + (* pBackingGC->ops->ImageText8)(pBackingDrawable, pBackingGC, + x - pBackingStore->x, y - pBackingStore->y, + count, chars); + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSImageText16 -- + * Perform a ImageText16, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSImageText16(pDrawable, pGC, x, y, count, chars) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + int count; + unsigned short *chars; +{ + SETUP_BACKING (pDrawable, pGC); + PROLOGUE(pGC); + + (* pGC->ops->ImageText16)(pDrawable, pGC, x, y, count, chars); + (* pBackingGC->ops->ImageText16)(pBackingDrawable, pBackingGC, + x - pBackingStore->x, y - pBackingStore->y, + count, chars); + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSImageGlyphBlt -- + * Perform a ImageGlyphBlt, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + unsigned int nglyph; + CharInfoPtr *ppci; /* array of character info */ + pointer pglyphBase; /* start of array of glyphs */ +{ + SETUP_BACKING (pDrawable, pGC); + PROLOGUE(pGC); + + (* pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, nglyph, ppci, + pglyphBase); + (* pBackingGC->ops->ImageGlyphBlt)(pBackingDrawable, pBackingGC, + x - pBackingStore->x, y - pBackingStore->y, + nglyph, ppci, pglyphBase); + + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPolyGlyphBlt -- + * Perform a PolyGlyphBlt, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + unsigned int nglyph; + CharInfoPtr *ppci; /* array of character info */ + pointer pglyphBase; /* start of array of glyphs */ +{ + SETUP_BACKING (pDrawable, pGC); + PROLOGUE(pGC); + + (* pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph, + ppci, pglyphBase); + (* pBackingGC->ops->PolyGlyphBlt)(pBackingDrawable, pBackingGC, + x - pBackingStore->x, y - pBackingStore->y, + nglyph, ppci, pglyphBase); + EPILOGUE (pGC); +} + +/*- + *----------------------------------------------------------------------- + * miBSPushPixels -- + * Perform a PushPixels, routing output to backing-store as needed. + * + * Results: + * + * Side Effects: + * + *----------------------------------------------------------------------- + */ +static void +miBSPushPixels(pGC, pBitMap, pDst, w, h, x, y) + GCPtr pGC; + PixmapPtr pBitMap; + DrawablePtr pDst; + int w, h, x, y; +{ + SETUP_BACKING (pDst, pGC); + PROLOGUE(pGC); + + (* pGC->ops->PushPixels)(pGC, pBitMap, pDst, w, h, x, y); + if (pGC->miTranslate) { + x -= pDst->x; + y -= pDst->y; + } + (* pBackingGC->ops->PushPixels)(pBackingGC, pBitMap, + pBackingDrawable, w, h, + x - pBackingStore->x, y - pBackingStore->y); + + EPILOGUE (pGC); +} + +#ifdef NEED_LINEHELPER +/*- + *----------------------------------------------------------------------- + * miBSLineHelper -- + * + * Results: should never be called + * + * Side Effects: server dies + * + *----------------------------------------------------------------------- + */ +static void +miBSLineHelper() +{ + FatalError("miBSLineHelper called\n"); +} +#endif + +/*- + *----------------------------------------------------------------------- + * miBSClearBackingStore -- + * Clear the given area of the backing pixmap with the background of + * the window, whatever it is. If generateExposures is TRUE, generate + * exposure events for the area. Note that if the area has any + * part outside the saved portions of the window, we do not allow the + * count in the expose events to be 0, since there will be more + * expose events to come. + * + * Results: + * None. + * + * Side Effects: + * Areas of pixmap are cleared and Expose events are generated. + * + *----------------------------------------------------------------------- + */ +static RegionPtr +miBSClearBackingStore(pWin, x, y, w, h, generateExposures) + WindowPtr pWin; + int x; + int y; + int w; + int h; + Bool generateExposures; +{ + RegionPtr pRgn; + int i; + miBSWindowPtr pBackingStore; + ScreenPtr pScreen; + GCPtr pGC; + int ts_x_origin, + ts_y_origin; + pointer gcvalues[4]; + unsigned long gcmask; + xRectangle *rects; + BoxPtr pBox; + BoxRec box; + PixUnion background; + char backgroundState; + int numRects; + + pBackingStore = (miBSWindowPtr)pWin->backStorage; + pScreen = pWin->drawable.pScreen; + + if ((pBackingStore->status == StatusNoPixmap) || + (pBackingStore->status == StatusBadAlloc)) + return NullRegion; + + if (w == 0) + w = (int) pWin->drawable.width - x; + if (h == 0) + h = (int) pWin->drawable.height - y; + + box.x1 = x; + box.y1 = y; + box.x2 = x + w; + box.y2 = y + h; + pRgn = REGION_CREATE(pWin->drawable.pScreen, &box, 1); + if (!pRgn) + return NullRegion; + REGION_INTERSECT( pScreen, pRgn, pRgn, &pBackingStore->SavedRegion); + + if (REGION_NOTEMPTY( pScreen, pRgn)) + { + /* + * if clearing entire window, simply make new virtual + * tile. For the root window, we also destroy the pixmap + * to save a pile of memory + */ + if (x == 0 && y == 0 && + w == pWin->drawable.width && + h == pWin->drawable.height) + { + if (!pWin->parent) + miDestroyBSPixmap (pWin); + if (pBackingStore->status != StatusContents) + miTileVirtualBS (pWin); + } + + ts_x_origin = ts_y_origin = 0; + + backgroundState = pWin->backgroundState; + background = pWin->background; + if (backgroundState == ParentRelative) { + WindowPtr pParent; + + pParent = pWin; + while (pParent->backgroundState == ParentRelative) { + ts_x_origin -= pParent->origin.x; + ts_y_origin -= pParent->origin.y; + pParent = pParent->parent; + } + backgroundState = pParent->backgroundState; + background = pParent->background; + } + + if ((backgroundState != None) && + ((pBackingStore->status == StatusContents) || + !SameBackground (pBackingStore->backgroundState, + pBackingStore->background, + backgroundState, + background))) + { + if (!pBackingStore->pBackingPixmap) + miCreateBSPixmap(pWin, NullBox); + + pGC = GetScratchGC(pWin->drawable.depth, pScreen); + if (pGC && pBackingStore->pBackingPixmap) + { + /* + * First take care of any ParentRelative stuff by altering the + * tile/stipple origin to match the coordinates of the upper-left + * corner of the first ancestor without a ParentRelative background. + * This coordinate is, of course, negative. + */ + + if (backgroundState == BackgroundPixel) + { + gcvalues[0] = (pointer) background.pixel; + gcvalues[1] = (pointer)FillSolid; + gcmask = GCForeground|GCFillStyle; + } + else + { + gcvalues[0] = (pointer)FillTiled; + gcvalues[1] = (pointer) background.pixmap; + gcmask = GCFillStyle|GCTile; + } + gcvalues[2] = (pointer)(ts_x_origin - pBackingStore->x); + gcvalues[3] = (pointer)(ts_y_origin - pBackingStore->y); + gcmask |= GCTileStipXOrigin|GCTileStipYOrigin; + DoChangeGC(pGC, gcmask, (XID *)gcvalues, TRUE); + ValidateGC((DrawablePtr)pBackingStore->pBackingPixmap, pGC); + + /* + * Figure out the array of rectangles to fill and fill them with + * PolyFillRect in the proper mode, as set in the GC above. + */ + numRects = REGION_NUM_RECTS(pRgn); + rects = (xRectangle *)ALLOCATE_LOCAL(numRects*sizeof(xRectangle)); + + if (rects) + { + for (i = 0, pBox = REGION_RECTS(pRgn); + i < numRects; + i++, pBox++) + { + rects[i].x = pBox->x1 - pBackingStore->x; + rects[i].y = pBox->y1 - pBackingStore->y; + rects[i].width = pBox->x2 - pBox->x1; + rects[i].height = pBox->y2 - pBox->y1; + } + (* pGC->ops->PolyFillRect) ( + (DrawablePtr)pBackingStore->pBackingPixmap, + pGC, numRects, rects); + DEALLOCATE_LOCAL(rects); + } + FreeScratchGC(pGC); + } + } + + if (!generateExposures) + { + REGION_DESTROY(pScreen, pRgn); + pRgn = NULL; + } + else + { + /* + * result must be screen relative, but is currently + * drawable relative. + */ + REGION_TRANSLATE(pScreen, pRgn, pWin->drawable.x, + pWin->drawable.y); + } + } + else + { + REGION_DESTROY( pScreen, pRgn); + pRgn = NULL; + } + return pRgn; +} + +static void +miBSClearBackingRegion (pWin, pRgn) + WindowPtr pWin; + RegionPtr pRgn; +{ + BoxPtr pBox; + int i; + + i = REGION_NUM_RECTS(pRgn); + pBox = REGION_RECTS(pRgn); + while (i--) + { + (void) miBSClearBackingStore(pWin, pBox->x1, pBox->y1, + pBox->x2 - pBox->x1, + pBox->y2 - pBox->y1, + FALSE); + pBox++; + } +} + +/* + * fill a region of the destination with virtual bits + * + * pRgn is to be translated by (x,y) + */ + +static void +miBSFillVirtualBits (pDrawable, pGC, pRgn, x, y, state, pixunion, planeMask) + DrawablePtr pDrawable; + GCPtr pGC; + RegionPtr pRgn; + int x, y; + int state; + PixUnion pixunion; + unsigned long planeMask; +{ + int i; + BITS32 gcmask; + pointer gcval[5]; + xRectangle *pRect; + BoxPtr pBox; + WindowPtr pWin; + int numRects; + + if (state == None) + return; + numRects = REGION_NUM_RECTS(pRgn); + pRect = (xRectangle *)ALLOCATE_LOCAL(numRects * sizeof(xRectangle)); + if (!pRect) + return; + pWin = 0; + if (pDrawable->type != DRAWABLE_PIXMAP) + { + pWin = (WindowPtr) pDrawable; + if (!pWin->backStorage) + pWin = 0; + } + i = 0; + gcmask = 0; + gcval[i++] = (pointer)planeMask; + gcmask |= GCPlaneMask; + if (state == BackgroundPixel) + { + if (pGC->fgPixel != pixunion.pixel) + { + gcval[i++] = (pointer)pixunion.pixel; + gcmask |= GCForeground; + } + if (pGC->fillStyle != FillSolid) + { + gcval[i++] = (pointer)FillSolid; + gcmask |= GCFillStyle; + } + } + else + { + if (pGC->fillStyle != FillTiled) + { + gcval[i++] = (pointer)FillTiled; + gcmask |= GCFillStyle; + } + if (pGC->tileIsPixel || pGC->tile.pixmap != pixunion.pixmap) + { + gcval[i++] = (pointer)pixunion.pixmap; + gcmask |= GCTile; + } + if (pGC->patOrg.x != x) + { + gcval[i++] = (pointer)x; + gcmask |= GCTileStipXOrigin; + } + if (pGC->patOrg.y != y) + { + gcval[i++] = (pointer)y; + gcmask |= GCTileStipYOrigin; + } + } + if (gcmask) + DoChangeGC (pGC, gcmask, (XID *)gcval, 1); + + if (pWin) + (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack); + + if (pDrawable->serialNumber != pGC->serialNumber) + ValidateGC (pDrawable, pGC); + + pBox = REGION_RECTS(pRgn); + for (i = numRects; --i >= 0; pBox++, pRect++) + { + pRect->x = pBox->x1 + x; + pRect->y = pBox->y1 + y; + pRect->width = pBox->x2 - pBox->x1; + pRect->height = pBox->y2 - pBox->y1; + } + pRect -= numRects; + (*pGC->ops->PolyFillRect) (pDrawable, pGC, numRects, pRect); + if (pWin) + (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeNothing); + DEALLOCATE_LOCAL (pRect); +} + +/*- + *----------------------------------------------------------------------- + * miBSAllocate -- + * Create and install backing store info for a window + * + *----------------------------------------------------------------------- + */ + +static void +miBSAllocate(pWin) + WindowPtr pWin; +{ + register miBSWindowPtr pBackingStore; + register ScreenPtr pScreen; + + if (pWin->drawable.pScreen->backingStoreSupport == NotUseful) + return; + pScreen = pWin->drawable.pScreen; + if (!(pBackingStore = (miBSWindowPtr)pWin->backStorage)) + { + + pBackingStore = (miBSWindowPtr)xalloc(sizeof(miBSWindowRec)); + if (!pBackingStore) + return; + + pBackingStore->pBackingPixmap = NullPixmap; + pBackingStore->x = 0; + pBackingStore->y = 0; + REGION_INIT( pScreen, &pBackingStore->SavedRegion, NullBox, 1); + pBackingStore->viewable = (char)pWin->viewable; + pBackingStore->status = StatusNoPixmap; + pBackingStore->backgroundState = None; + pWin->backStorage = (pointer) pBackingStore; + } + + /* + * Now want to initialize the backing pixmap and SavedRegion if + * necessary. The initialization consists of finding all the + * currently-obscured regions, by taking the inverse of the window's + * clip list, storing the result in SavedRegion, and exposing those + * areas of the window. + */ + + if (pBackingStore->status == StatusNoPixmap && + ((pWin->backingStore == WhenMapped && pWin->viewable) || + (pWin->backingStore == Always))) + { + BoxRec box; + RegionPtr pSavedRegion; + + pSavedRegion = &pBackingStore->SavedRegion; + + box.x1 = pWin->drawable.x; + box.x2 = box.x1 + (int) pWin->drawable.width; + box.y1 = pWin->drawable.y; + box.y2 = pWin->drawable.y + (int) pWin->drawable.height; + + REGION_INVERSE( pScreen, pSavedRegion, &pWin->clipList, &box); + REGION_TRANSLATE( pScreen, pSavedRegion, + -pWin->drawable.x, + -pWin->drawable.y); +#ifdef SHAPE + if (wBoundingShape (pWin)) + REGION_INTERSECT(pScreen, pSavedRegion, pSavedRegion, + wBoundingShape (pWin)); + if (wClipShape (pWin)) + REGION_INTERSECT(pScreen, pSavedRegion, pSavedRegion, + wClipShape (pWin)); +#endif + /* if window is already on-screen, assume it has been drawn to */ + if (pWin->viewable) + pBackingStore->status = StatusVDirty; + miTileVirtualBS (pWin); + + /* + * deliver all the newly available regions + * as exposure events to the window + */ + + miSendExposures(pWin, pSavedRegion, 0, 0); + } + else if (!pWin->viewable) + { + /* + * Turn off backing store when we're not supposed to + * be saving anything + */ + if (pBackingStore->status != StatusNoPixmap) + { + REGION_EMPTY( pScreen, &pBackingStore->SavedRegion); + miDestroyBSPixmap (pWin); + } + } +} + +/*- + *----------------------------------------------------------------------- + * miBSFree -- + * Destroy and free all the stuff associated with the backing-store + * for the given window. + * + * Results: + * None. + * + * Side Effects: + * The backing pixmap and all the regions and GC's are destroyed. + * + *----------------------------------------------------------------------- + */ +static void +miBSFree(pWin) + WindowPtr pWin; +{ + miBSWindowPtr pBackingStore; + register ScreenPtr pScreen = pWin->drawable.pScreen; + + pBackingStore = (miBSWindowPtr)pWin->backStorage; + if (pBackingStore) + { + miDestroyBSPixmap (pWin); + + REGION_UNINIT( pScreen, &pBackingStore->SavedRegion); + + xfree(pBackingStore); + pWin->backStorage = NULL; + } +} + +/*- + *----------------------------------------------------------------------- + * miResizeBackingStore -- + * Alter the size of the backing pixmap as necessary when the + * SavedRegion changes size. The contents of the old pixmap are + * copied/shifted into the new/same pixmap. + * + * Results: + * The new Pixmap is created as necessary. + * + * Side Effects: + * The old pixmap is destroyed. + * + *----------------------------------------------------------------------- + */ +static void +miResizeBackingStore(pWin, dx, dy, saveBits) + WindowPtr pWin; + int dx, dy; /* bits are moving this far */ + Bool saveBits; /* bits are useful */ +{ + miBSWindowPtr pBackingStore; + PixmapPtr pBackingPixmap; + ScreenPtr pScreen; + GC *pGC; + BoxPtr extents; + PixmapPtr pNewPixmap; + int nx, ny; + int nw, nh; + + pBackingStore = (miBSWindowPtr)(pWin->backStorage); + pBackingPixmap = pBackingStore->pBackingPixmap; + if (!pBackingPixmap) + return; + pScreen = pWin->drawable.pScreen; + extents = REGION_EXTENTS(pScreen, &pBackingStore->SavedRegion); + pNewPixmap = pBackingPixmap; + + nw = extents->x2 - extents->x1; + nh = extents->y2 - extents->y1; + + /* the policy here could be more sophisticated */ + if (nw != pBackingPixmap->drawable.width || + nh != pBackingPixmap->drawable.height) + { + if (!saveBits) + { + pNewPixmap = NullPixmap; + pBackingStore->status = StatusNoPixmap; + } + else + { + pNewPixmap = (PixmapPtr)(*pScreen->CreatePixmap) + (pScreen, + nw, nh, + pWin->drawable.depth); + if (!pNewPixmap) + { +#ifdef BSEAGER + pBackingStore->status = StatusNoPixmap; +#else + pBackingStore->status = StatusBadAlloc; +#endif + } + } + } + if (!pNewPixmap) + { + pBackingStore->x = 0; + pBackingStore->y = 0; + } + else + { + nx = pBackingStore->x - extents->x1 + dx; + ny = pBackingStore->y - extents->y1 + dy; + pBackingStore->x = extents->x1; + pBackingStore->y = extents->y1; + + if (saveBits && (pNewPixmap != pBackingPixmap || nx != 0 || ny != 0)) + { + pGC = GetScratchGC(pNewPixmap->drawable.depth, pScreen); + if (pGC) + { + ValidateGC((DrawablePtr)pNewPixmap, pGC); + /* if we implement a policy where the pixmap can be larger than + * the region extents, we might want to optimize this copyarea + * by only copying the old extents, rather than the entire + * pixmap + */ + (*pGC->ops->CopyArea)((DrawablePtr)pBackingPixmap, + (DrawablePtr)pNewPixmap, pGC, + 0, 0, + pBackingPixmap->drawable.width, + pBackingPixmap->drawable.height, + nx, ny); + FreeScratchGC(pGC); + } + } + } + /* SavedRegion is used in the backingGC clip; force an update */ + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + if (pNewPixmap != pBackingPixmap) + { + (* pScreen->DestroyPixmap)(pBackingPixmap); + pBackingStore->pBackingPixmap = pNewPixmap; + } +} + +/*- + *----------------------------------------------------------------------- + * miBSSaveDoomedAreas -- + * Saved the areas of the given window that are about to be + * obscured. If the window has moved, pObscured is expected to + * be at the new screen location and (dx,dy) is expected to be the offset + * to the window's previous location. + * + * Results: + * None. + * + * Side Effects: + * The region is copied from the screen into pBackingPixmap and + * SavedRegion is updated. + * + *----------------------------------------------------------------------- + */ +static void +miBSSaveDoomedAreas(pWin, pObscured, dx, dy) + register WindowPtr pWin; + RegionPtr pObscured; + int dx, dy; +{ + miBSWindowPtr pBackingStore; + ScreenPtr pScreen; + int x, y; + + pBackingStore = (miBSWindowPtr)pWin->backStorage; + pScreen = pWin->drawable.pScreen; + + /* + * If the window isn't realized, it's being unmapped, thus we don't + * want to save anything if backingStore isn't Always. + */ + if (!pWin->realized) + { + pBackingStore->viewable = (char)pWin->viewable; + if (pWin->backingStore != Always) + { + REGION_EMPTY( pScreen, &pBackingStore->SavedRegion); + miDestroyBSPixmap (pWin); + return; + } + if (pBackingStore->status == StatusBadAlloc) + pBackingStore->status = StatusNoPixmap; + } + + /* Don't even pretend to save anything for a virtual background None */ + if ((pBackingStore->status == StatusVirtual) && + (pBackingStore->backgroundState == None)) + return; + + if (REGION_NOTEMPTY(pScreen, pObscured)) + { + BoxRec oldExtents; + x = pWin->drawable.x; + y = pWin->drawable.y; + REGION_TRANSLATE(pScreen, pObscured, -x, -y); + oldExtents = *REGION_EXTENTS(pScreen, &pBackingStore->SavedRegion); + REGION_UNION( pScreen, &pBackingStore->SavedRegion, + &pBackingStore->SavedRegion, + pObscured); + /* + * only save the bits if we've actually + * started using backing store + */ + if (pBackingStore->status != StatusVirtual) + { + miBSScreenPtr pScreenPriv; + + pScreenPriv = (miBSScreenPtr) pScreen->devPrivates[miBSScreenIndex].ptr; + if (!pBackingStore->pBackingPixmap) + miCreateBSPixmap (pWin, &oldExtents); + else + miResizeBackingStore(pWin, 0, 0, TRUE); + + if (pBackingStore->pBackingPixmap) { + if (pBackingStore->x | pBackingStore->y) + { + REGION_TRANSLATE( pScreen, pObscured, + -pBackingStore->x, + -pBackingStore->y); + x += pBackingStore->x; + y += pBackingStore->y; + } + (* pScreenPriv->funcs->SaveAreas) (pBackingStore->pBackingPixmap, + pObscured, x - dx, y - dy, pWin); + } + } + REGION_TRANSLATE(pScreen, pObscured, x, y); + } +} + +/*- + *----------------------------------------------------------------------- + * miBSRestoreAreas -- + * Restore areas from backing-store that are no longer obscured. + * expects prgnExposed to contain a screen-relative area. + * + * Results: + * The region to generate exposure events on (which may be + * different from the region to paint). + * + * Side Effects: + * Areas are copied from pBackingPixmap to the screen. prgnExposed + * is altered to contain the region that could not be restored from + * backing-store. + * + * Notes: + * This is called before sending any exposure events to the client, + * and so might be called if the window has grown. Changing the backing + * pixmap doesn't require revalidating the backingGC because the + * client's next output request will result in a call to ValidateGC, + * since the window clip region has changed, which will in turn call + * miValidateBackingStore. + *----------------------------------------------------------------------- + */ +static RegionPtr +miBSRestoreAreas(pWin, prgnExposed) + register WindowPtr pWin; + RegionPtr prgnExposed; +{ + PixmapPtr pBackingPixmap; + miBSWindowPtr pBackingStore; + RegionPtr prgnSaved; + RegionPtr prgnRestored; + register ScreenPtr pScreen; + RegionPtr exposures = prgnExposed; + + pScreen = pWin->drawable.pScreen; + pBackingStore = (miBSWindowPtr)pWin->backStorage; + pBackingPixmap = pBackingStore->pBackingPixmap; + + prgnSaved = &pBackingStore->SavedRegion; + + if (pBackingStore->status == StatusContents) + { + REGION_TRANSLATE(pScreen, prgnSaved, pWin->drawable.x, + pWin->drawable.y); + + prgnRestored = REGION_CREATE( pScreen, (BoxPtr)NULL, 1); + REGION_INTERSECT( pScreen, prgnRestored, prgnExposed, prgnSaved); + + /* + * Since prgnExposed is no longer obscured, we no longer + * will have a valid copy of it in backing-store, but there is a valid + * copy of it on screen, so subtract the area we just restored from + * from the area to be exposed. + */ + + if (REGION_NOTEMPTY( pScreen, prgnRestored)) + { + miBSScreenPtr pScreenPriv; + + REGION_SUBTRACT( pScreen, prgnSaved, prgnSaved, prgnExposed); + REGION_SUBTRACT( pScreen, prgnExposed, prgnExposed, prgnRestored); + + /* + * Do the actual restoration + */ + + pScreenPriv = (miBSScreenPtr) + pScreen->devPrivates[miBSScreenIndex].ptr; + (* pScreenPriv->funcs->RestoreAreas) (pBackingPixmap, + prgnRestored, + pWin->drawable.x + pBackingStore->x, + pWin->drawable.y + pBackingStore->y, pWin); + /* + * if the saved region is completely empty, dispose of the + * backing pixmap, otherwise, retranslate the saved + * region to window relative + */ + + if (REGION_NOTEMPTY(pScreen, prgnSaved)) + { + REGION_TRANSLATE(pScreen, prgnSaved, + -pWin->drawable.x, + -pWin->drawable.y); + miResizeBackingStore(pWin, 0, 0, TRUE); + } + else + miDestroyBSPixmap (pWin); + } + else + REGION_TRANSLATE(pScreen, prgnSaved, + -pWin->drawable.x, -pWin->drawable.y); + REGION_DESTROY( pScreen, prgnRestored); + + } + else if ((pBackingStore->status == StatusVirtual) || + (pBackingStore->status == StatusVDirty)) + { + REGION_TRANSLATE(pScreen, prgnSaved, + pWin->drawable.x, pWin->drawable.y); + exposures = REGION_CREATE( pScreen, NullBox, 1); + if (SameBackground (pBackingStore->backgroundState, + pBackingStore->background, + pWin->backgroundState, + pWin->background)) + { + REGION_SUBTRACT( pScreen, exposures, prgnExposed, prgnSaved); + } + else + { + miTileVirtualBS(pWin); + + /* we need to expose all we have (virtually) retiled */ + REGION_UNION( pScreen, exposures, prgnExposed, prgnSaved); + } + REGION_SUBTRACT( pScreen, prgnSaved, prgnSaved, prgnExposed); + REGION_TRANSLATE(pScreen, prgnSaved, + -pWin->drawable.x, -pWin->drawable.y); + } + else if (pWin->viewable && !pBackingStore->viewable && + pWin->backingStore != Always) + { + /* + * The window was just mapped and nothing has been saved in + * backing-store from the last time it was mapped. We want to capture + * any output to regions that are already obscured but there are no + * bits to snag off the screen, so we initialize things just as we did + * in miBSAllocate, above. + */ + BoxRec box; + + prgnSaved = &pBackingStore->SavedRegion; + + box.x1 = pWin->drawable.x; + box.x2 = box.x1 + (int) pWin->drawable.width; + box.y1 = pWin->drawable.y; + box.y2 = box.y1 + (int) pWin->drawable.height; + + REGION_INVERSE( pScreen, prgnSaved, &pWin->clipList, &box); + REGION_TRANSLATE( pScreen, prgnSaved, + -pWin->drawable.x, + -pWin->drawable.y); +#ifdef SHAPE + if (wBoundingShape (pWin)) + REGION_INTERSECT(pScreen, prgnSaved, prgnSaved, + wBoundingShape (pWin)); + if (wClipShape (pWin)) + REGION_INTERSECT(pScreen, prgnSaved, prgnSaved, + wClipShape (pWin)); +#endif + miTileVirtualBS(pWin); + + exposures = REGION_CREATE( pScreen, &box, 1); + } + pBackingStore->viewable = (char)pWin->viewable; + return exposures; +} + + +/*- + *----------------------------------------------------------------------- + * miBSTranslateBackingStore -- + * Shift the backing-store in the given direction. Called when bit + * gravity is shifting things around. + * + * Results: + * An occluded region of the window which should be sent exposure events. + * This region should be in absolute coordinates (i.e. include + * new window position). + * + * Side Effects: + * If the window changed size as well as position, the backing pixmap + * is resized. The contents of the backing pixmap are shifted + * + * Warning: + * Bob and I have rewritten this routine quite a few times, each + * time it gets a few more cases correct, and introducing some + * interesting bugs. Naturally, I think the code is correct this + * time. + * + * Let me try to explain what this routine is for: + * + * It's called from SlideAndSizeWindow whenever a window + * with backing store is resized. There are two separate + * possibilities: + * + * a) The window has ForgetGravity + * + * In this case, windx, windy will be 0 and oldClip will + * be NULL. This indicates that all of the window contents + * currently saved offscreen should be discarded, and the + * entire window exposed. TranslateBackingStore, then, should + * prepare a completely new backing store region based on the + * new window clipList and return that region for exposure. + * + * b) The window has some other gravity + * + * In this case, windx, windy will be set to the distance + * that the bits should move within the window. oldClip + * will be set to the old visible portion of the window. + * TranslateBackingStore, then, should adjust the backing + * store to accommodate the portion of the existing backing + * store bits which coorespond to backing store bits which + * will still be occluded in the new configuration. oldx,oldy + * are set to the old position of the window on the screen. + * + * Furthermore, in this case any contents of the screen which + * are about to become occluded should be fetched from the screen + * and placed in backing store. This is to avoid the eventual + * occlusion by the win gravity shifting the child window bits around + * on top of this window, and potentially losing information + * + * It's also called from SetShape, but I think (he says not + * really knowing for sure) that this code will even work + * in that case. + *----------------------------------------------------------------------- + */ + +static RegionPtr +miBSTranslateBackingStore(pWin, windx, windy, oldClip, oldx, oldy) + WindowPtr pWin; + int windx; /* bit translation distance in window */ + int windy; + RegionPtr oldClip; /* Region being copied */ + int oldx; /* old window position */ + int oldy; +{ + register miBSWindowPtr pBackingStore; + register RegionPtr pSavedRegion; + register RegionPtr newSaved, doomed; + register ScreenPtr pScreen; + BoxRec extents; + int scrdx; /* bit translation distance on screen */ + int scrdy; + int dx; /* distance window moved on screen */ + int dy; + + pScreen = pWin->drawable.pScreen; + pBackingStore = (miBSWindowPtr)(pWin->backStorage); + if ((pBackingStore->status == StatusNoPixmap) || + (pBackingStore->status == StatusBadAlloc)) + return NullRegion; + + /* + * Compute the new saved region + */ + + newSaved = REGION_CREATE( pScreen, NullBox, 1); + extents.x1 = pWin->drawable.x; + extents.x2 = pWin->drawable.x + (int) pWin->drawable.width; + extents.y1 = pWin->drawable.y; + extents.y2 = pWin->drawable.y + (int) pWin->drawable.height; + REGION_INVERSE( pScreen, newSaved, &pWin->clipList, &extents); + + REGION_TRANSLATE( pScreen, newSaved, + -pWin->drawable.x, -pWin->drawable.y); +#ifdef SHAPE + if (wBoundingShape (pWin) || wClipShape (pWin)) { + if (wBoundingShape (pWin)) + REGION_INTERSECT( pScreen, newSaved, newSaved, + wBoundingShape (pWin)); + if (wClipShape (pWin)) + REGION_INTERSECT( pScreen, newSaved, newSaved, wClipShape (pWin)); + } +#endif + + pSavedRegion = &pBackingStore->SavedRegion; + + /* now find any visible areas we can save from the screen */ + /* and then translate newSaved to old local coordinates */ + if (oldClip) + { + /* bit gravity makes things virtually too hard, punt */ + if (((windx != 0) || (windy != 0)) && + (pBackingStore->status != StatusContents)) + miCreateBSPixmap(pWin, NullBox); + + /* + * The window is moving this far on the screen + */ + dx = pWin->drawable.x - oldx; + dy = pWin->drawable.y - oldy; + /* + * The bits will be moving on the screen by the + * amount the window is moving + the amount the + * bits are moving within the window + */ + scrdx = windx + dx; + scrdy = windy + dy; + + /* + * intersect at old bit position to discover the + * bits on the screen which can be put into the + * new backing store + */ + REGION_TRANSLATE( pScreen, oldClip, windx - oldx, windy - oldy); + doomed = REGION_CREATE( pScreen, NullBox, 1); + REGION_INTERSECT( pScreen, doomed, oldClip, newSaved); + REGION_TRANSLATE( pScreen, oldClip, oldx - windx, oldy - windy); + + /* + * Translate the old saved region to the position in the + * window where it will appear to be + */ + REGION_TRANSLATE( pScreen, pSavedRegion, windx, windy); + + /* + * Add the old saved region to the new saved region, so + * that calls to RestoreAreas will be able to fetch those + * bits back + */ + REGION_UNION( pScreen, newSaved, newSaved, pSavedRegion); + + /* + * Swap the new saved region into the window + */ + { + RegionRec tmp; + + tmp = *pSavedRegion; + *pSavedRegion = *newSaved; + *newSaved = tmp; + } + miResizeBackingStore (pWin, windx, windy, TRUE); + + /* + * Compute the newly enabled region + * of backing store. This region will be + * set to background in the backing pixmap and + * sent as exposure events to the client. + */ + REGION_SUBTRACT( pScreen, newSaved, pSavedRegion, newSaved); + + /* + * Fetch bits which will be obscured from + * the screen + */ + if (REGION_NOTEMPTY( pScreen, doomed)) + { + /* + * Don't clear regions which have bits on the + * screen + */ + REGION_SUBTRACT( pScreen, newSaved, newSaved, doomed); + + /* + * Make the region to SaveDoomedAreas absolute, instead + * of window relative. + */ + REGION_TRANSLATE( pScreen, doomed, + pWin->drawable.x, pWin->drawable.y); + (* pScreen->SaveDoomedAreas) (pWin, doomed, scrdx, scrdy); + } + + REGION_DESTROY(pScreen, doomed); + + /* + * and clear whatever there is that's new + */ + if (REGION_NOTEMPTY( pScreen, newSaved)) + { + miBSClearBackingRegion (pWin, newSaved); + /* + * Make the exposed region absolute + */ + REGION_TRANSLATE(pScreen, newSaved, + pWin->drawable.x, + pWin->drawable.y); + } + else + { + REGION_DESTROY(pScreen, newSaved); + newSaved = NullRegion; + } + } + else + { + /* + * ForgetGravity: just reset backing store and + * expose the whole mess + */ + REGION_COPY( pScreen, pSavedRegion, newSaved); + REGION_TRANSLATE( pScreen, newSaved, + pWin->drawable.x, pWin->drawable.y); + + miResizeBackingStore (pWin, 0, 0, FALSE); + (void) miBSClearBackingStore (pWin, 0, 0, 0, 0, FALSE); + } + + return newSaved; +} + +/* + * Inform the backing store layer that you are about to validate + * a gc with a window, and that subsequent output to the window + * is (or is not) guaranteed to be already clipped to the visible + * regions of the window. + */ + +static void +miBSDrawGuarantee (pWin, pGC, guarantee) + WindowPtr pWin; + GCPtr pGC; + int guarantee; +{ + miBSGCPtr pPriv; + + if (pWin->backStorage) + { + pPriv = (miBSGCPtr)pGC->devPrivates[miBSGCIndex].ptr; + if (!pPriv) + (void) miBSCreateGCPrivate (pGC); + pPriv = (miBSGCPtr)pGC->devPrivates[miBSGCIndex].ptr; + if (pPriv) + { + /* + * XXX KLUDGE ALERT + * + * when the GC is Cheap pPriv will point + * at some device's gc func structure. guarantee + * will point at the ChangeGC entry of that struct + * and will never match a valid guarantee value. + */ + switch (pPriv->guarantee) + { + case GuaranteeNothing: + case GuaranteeVisBack: + pPriv->guarantee = guarantee; + break; + } + } + } +} + +#define noBackingCopy (GCGraphicsExposures|GCClipXOrigin|GCClipYOrigin| \ + GCClipMask|GCSubwindowMode| \ + GCTileStipXOrigin|GCTileStipYOrigin) + +/*- + *----------------------------------------------------------------------- + * miBSValidateGC -- + * Wrapper around output-library's ValidateGC routine + * + * Results: + * None. + * + * Side Effects: + * + * Notes: + * The idea here is to perform several functions: + * - All the output calls must be intercepted and routed to + * backing-store as necessary. + * - pGC in the window's devBackingStore must be set up with the + * clip list appropriate for writing to pBackingPixmap (i.e. + * the inverse of the window's clipList intersected with the + * clientClip of the GC). Since the destination for this GC is + * a pixmap, it is sufficient to set the clip list as its + * clientClip. + *----------------------------------------------------------------------- + */ + +static void +miBSValidateGC (pGC, stateChanges, pDrawable) + GCPtr pGC; + unsigned long stateChanges; + DrawablePtr pDrawable; +{ + GCPtr pBackingGC; + miBSWindowPtr pWindowPriv; + miBSGCPtr pPriv; + WindowPtr pWin; + int lift_functions; + RegionPtr backingCompositeClip = NULL; + + if (pDrawable->type != DRAWABLE_PIXMAP) + { + pWin = (WindowPtr) pDrawable; + pWindowPriv = (miBSWindowPtr) pWin->backStorage; + lift_functions = (pWindowPriv == (miBSWindowPtr) NULL); + } + else + { + pWin = (WindowPtr) NULL; + lift_functions = TRUE; + } + + pPriv = (miBSGCPtr)pGC->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pGC, pPriv); + + (*pGC->funcs->ValidateGC) (pGC, stateChanges, pDrawable); + + /* + * rewrap funcs and ops as Validate may have changed them + */ + + pPriv->wrapFuncs = pGC->funcs; + pPriv->wrapOps = pGC->ops; + + if (!lift_functions && ((pPriv->guarantee == GuaranteeVisBack) || + (pWindowPriv->status == StatusNoPixmap) || + (pWindowPriv->status == StatusBadAlloc))) + lift_functions = TRUE; + + /* + * check to see if a new backingCompositeClip region must + * be generated + */ + + if (!lift_functions && + ((pDrawable->serialNumber != pPriv->serialNumber) || + (stateChanges&(GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)))) + { + if (REGION_NOTEMPTY(pGC->pScreen, &pWindowPriv->SavedRegion)) + { + backingCompositeClip = REGION_CREATE(pGC->pScreen, NULL, 1); + if ((pGC->clientClipType == CT_NONE) || + (pGC->clientClipType == CT_PIXMAP)) + { + REGION_COPY(pGC->pScreen, backingCompositeClip, + &pWindowPriv->SavedRegion); + } + else + { + /* + * Make a new copy of the client clip, translated to + * its proper origin. + */ + + REGION_COPY(pGC->pScreen, backingCompositeClip, + pGC->clientClip); + REGION_TRANSLATE(pGC->pScreen, backingCompositeClip, + pGC->clipOrg.x, + pGC->clipOrg.y); + REGION_INTERSECT(pGC->pScreen, backingCompositeClip, + backingCompositeClip, + &pWindowPriv->SavedRegion); + } + if (pGC->subWindowMode == IncludeInferiors) + { + RegionPtr translatedClip; + + /* XXX + * any output in IncludeInferiors mode will not + * be redirected to Inferiors backing store. This + * can be fixed only at great cost to the shadow routines. + */ + translatedClip = NotClippedByChildren (pWin); + REGION_TRANSLATE(pGC->pScreen, translatedClip, + -pDrawable->x, + -pDrawable->y); + REGION_SUBTRACT(pGC->pScreen, backingCompositeClip, + backingCompositeClip, translatedClip); + REGION_DESTROY(pGC->pScreen, translatedClip); + } + if (!REGION_NOTEMPTY(pGC->pScreen, backingCompositeClip)) + lift_functions = TRUE; + } + else + { + lift_functions = TRUE; + } + + /* Reset the status when drawing to an unoccluded window so that + * future SaveAreas will actually copy bits from the screen. Note that + * output to root window in IncludeInferiors mode will not cause this + * to change. This causes all transient graphics by the window + * manager to the root window to not enable backing store. + */ + if (lift_functions && (pWindowPriv->status == StatusVirtual) && + (pWin->parent || pGC->subWindowMode != IncludeInferiors)) + pWindowPriv->status = StatusVDirty; + } + + /* + * if no backing store has been allocated, and it's needed, + * create it now. + */ + + if (!lift_functions && !pWindowPriv->pBackingPixmap) + { + miCreateBSPixmap (pWin, NullBox); + if (!pWindowPriv->pBackingPixmap) + lift_functions = TRUE; + } + + /* + * create the backing GC if needed, lift functions + * if the creation fails + */ + + if (!lift_functions && !pPriv->pBackingGC) + { + int status; + XID noexpose = xFalse; + + /* We never want ops with the backingGC to generate GraphicsExpose */ + pBackingGC = CreateGC ((DrawablePtr)pWindowPriv->pBackingPixmap, + GCGraphicsExposures, &noexpose, &status); + if (status != Success) + lift_functions = TRUE; + else + pPriv->pBackingGC = pBackingGC; + } + + pBackingGC = pPriv->pBackingGC; + + pPriv->stateChanges |= stateChanges; + + if (lift_functions) + { + if (backingCompositeClip) + REGION_DESTROY( pGC->pScreen, backingCompositeClip); + + /* unwrap the GC again */ + miBSDestroyGCPrivate (pGC); + + return; + } + + /* + * the rest of this function gets the pBackingGC + * into shape for possible draws + */ + + pPriv->stateChanges &= ~noBackingCopy; + if (pPriv->stateChanges) + CopyGC(pGC, pBackingGC, pPriv->stateChanges); + if ((pGC->patOrg.x - pWindowPriv->x) != pBackingGC->patOrg.x || + (pGC->patOrg.y - pWindowPriv->y) != pBackingGC->patOrg.y) + { + XID vals[2]; + vals[0] = pGC->patOrg.x - pWindowPriv->x; + vals[1] = pGC->patOrg.y - pWindowPriv->y; + DoChangeGC(pBackingGC, GCTileStipXOrigin|GCTileStipYOrigin, vals, 0); + } + pPriv->stateChanges = 0; + + if (backingCompositeClip) + { + XID vals[2]; + + if (pGC->clientClipType == CT_PIXMAP) + { + miBSScreenPtr pScreenPriv; + + (*pBackingGC->funcs->CopyClip)(pBackingGC, pGC); + REGION_TRANSLATE(pGC->pScreen, backingCompositeClip, + -pGC->clipOrg.x, -pGC->clipOrg.y); + vals[0] = pGC->clipOrg.x - pWindowPriv->x; + vals[1] = pGC->clipOrg.y - pWindowPriv->y; + DoChangeGC(pBackingGC, GCClipXOrigin|GCClipYOrigin, vals, 0); + pScreenPriv = (miBSScreenPtr) + pGC->pScreen->devPrivates[miBSScreenIndex].ptr; + (* pScreenPriv->funcs->SetClipmaskRgn) + (pBackingGC, backingCompositeClip); + REGION_DESTROY( pGC->pScreen, backingCompositeClip); + } + else + { + vals[0] = -pWindowPriv->x; + vals[1] = -pWindowPriv->y; + DoChangeGC(pBackingGC, GCClipXOrigin|GCClipYOrigin, vals, 0); + (*pBackingGC->funcs->ChangeClip) (pBackingGC, CT_REGION, backingCompositeClip, 0); + } + pPriv->serialNumber = pDrawable->serialNumber; + } + + if (pWindowPriv->pBackingPixmap->drawable.serialNumber + != pBackingGC->serialNumber) + { + ValidateGC((DrawablePtr)pWindowPriv->pBackingPixmap, pBackingGC); + } + + if (pBackingGC->clientClip == 0) + ErrorF ("backing store clip list nil"); + + FUNC_EPILOGUE (pGC, pPriv); +} + +static void +miBSChangeGC (pGC, mask) + GCPtr pGC; + unsigned long mask; +{ + miBSGCPtr pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pGC, pPriv); + + (*pGC->funcs->ChangeGC) (pGC, mask); + + FUNC_EPILOGUE (pGC, pPriv); +} + +static void +miBSCopyGC (pGCSrc, mask, pGCDst) + GCPtr pGCSrc, pGCDst; + unsigned long mask; +{ + miBSGCPtr pPriv = (miBSGCPtr) (pGCDst)->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pGCDst, pPriv); + + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + + FUNC_EPILOGUE (pGCDst, pPriv); +} + +static void +miBSDestroyGC (pGC) + GCPtr pGC; +{ + miBSGCPtr pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pGC, pPriv); + + if (pPriv->pBackingGC) + FreeGC(pPriv->pBackingGC, (GContext)0); + + (*pGC->funcs->DestroyGC) (pGC); + + FUNC_EPILOGUE (pGC, pPriv); + + xfree(pPriv); +} + +static void +miBSChangeClip(pGC, type, pvalue, nrects) + GCPtr pGC; + int type; + pointer pvalue; + int nrects; +{ + miBSGCPtr pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pGC, pPriv); + + (* pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects); + + FUNC_EPILOGUE (pGC, pPriv); +} + +static void +miBSCopyClip(pgcDst, pgcSrc) + GCPtr pgcDst, pgcSrc; +{ + miBSGCPtr pPriv = (miBSGCPtr) (pgcDst)->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pgcDst, pPriv); + + (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + + FUNC_EPILOGUE (pgcDst, pPriv); +} + +static void +miBSDestroyClip(pGC) + GCPtr pGC; +{ + miBSGCPtr pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr; + + FUNC_PROLOGUE (pGC, pPriv); + + (* pGC->funcs->DestroyClip)(pGC); + + FUNC_EPILOGUE (pGC, pPriv); +} + +static void +miDestroyBSPixmap (pWin) + WindowPtr pWin; +{ + miBSWindowPtr pBackingStore; + ScreenPtr pScreen; + + pScreen = pWin->drawable.pScreen; + pBackingStore = (miBSWindowPtr) pWin->backStorage; + if (pBackingStore->pBackingPixmap) + (* pScreen->DestroyPixmap)(pBackingStore->pBackingPixmap); + pBackingStore->pBackingPixmap = NullPixmap; + pBackingStore->x = 0; + pBackingStore->y = 0; + if (pBackingStore->backgroundState == BackgroundPixmap) + (* pScreen->DestroyPixmap)(pBackingStore->background.pixmap); + pBackingStore->backgroundState = None; + pBackingStore->status = StatusNoPixmap; + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; +} + +static void +miTileVirtualBS (pWin) + WindowPtr pWin; +{ + miBSWindowPtr pBackingStore; + + pBackingStore = (miBSWindowPtr) pWin->backStorage; + if (pBackingStore->backgroundState == BackgroundPixmap) + (* pWin->drawable.pScreen->DestroyPixmap) + (pBackingStore->background.pixmap); + pBackingStore->backgroundState = pWin->backgroundState; + pBackingStore->background = pWin->background; + if (pBackingStore->backgroundState == BackgroundPixmap) + pBackingStore->background.pixmap->refcnt++; + + if (pBackingStore->status != StatusVDirty) + pBackingStore->status = StatusVirtual; + + /* + * punt parent relative tiles and do it now + */ + if (pBackingStore->backgroundState == ParentRelative) + miCreateBSPixmap (pWin, NullBox); +} + +#ifdef DEBUG +static int BSAllocationsFailed = 0; +#define FAILEDSIZE 32 +static struct { int w, h; } failedRecord[FAILEDSIZE]; +static int failedIndex; +#endif + +static void +miCreateBSPixmap (pWin, pExtents) + WindowPtr pWin; + BoxPtr pExtents; +{ + miBSWindowPtr pBackingStore; + ScreenPtr pScreen; + PixUnion background; + char backgroundState; + BoxPtr extents; + Bool backSet; + + pScreen = pWin->drawable.pScreen; + pBackingStore = (miBSWindowPtr) pWin->backStorage; + if (pBackingStore->status == StatusBadAlloc) + return; + backSet = ((pBackingStore->status == StatusVirtual) || + (pBackingStore->status == StatusVDirty)); + + extents = REGION_EXTENTS( pScreen, &pBackingStore->SavedRegion); + + if (!pBackingStore->pBackingPixmap) + { + /* the policy here could be more sophisticated */ + pBackingStore->x = extents->x1; + pBackingStore->y = extents->y1; + pBackingStore->pBackingPixmap = + (PixmapPtr)(* pScreen->CreatePixmap) + (pScreen, + extents->x2 - extents->x1, + extents->y2 - extents->y1, + pWin->drawable.depth); + } + if (!pBackingStore->pBackingPixmap) + { +#ifdef DEBUG + BSAllocationsFailed++; + /* + * record failed allocations + */ + failedRecord[failedIndex].w = pWin->drawable.width; + failedRecord[failedIndex].h = pWin->drawable.height; + failedIndex++; + if (failedIndex == FAILEDSIZE) + failedIndex = 0; +#endif +#ifdef BSEAGER + pBackingStore->status = StatusNoPixmap; +#else + pBackingStore->status = StatusBadAlloc; +#endif + return; + } + + pBackingStore->status = StatusContents; + + if (backSet) + { + backgroundState = pWin->backgroundState; + background = pWin->background; + + pWin->backgroundState = pBackingStore->backgroundState; + pWin->background = pBackingStore->background; + if (pWin->backgroundState == BackgroundPixmap) + pWin->background.pixmap->refcnt++; + } + + if (!pExtents) + pExtents = extents; + + if (pExtents->y1 != pExtents->y2) + { + RegionPtr exposed; + + exposed = miBSClearBackingStore(pWin, + pExtents->x1, pExtents->y1, + pExtents->x2 - pExtents->x1, + pExtents->y2 - pExtents->y1, + !backSet); + if (exposed) + { + miSendExposures(pWin, exposed, pWin->drawable.x, pWin->drawable.y); + REGION_DESTROY( pScreen, exposed); + } + } + + if (backSet) + { + if (pWin->backgroundState == BackgroundPixmap) + (* pScreen->DestroyPixmap) (pWin->background.pixmap); + pWin->backgroundState = backgroundState; + pWin->background = background; + if (pBackingStore->backgroundState == BackgroundPixmap) + (* pScreen->DestroyPixmap) (pBackingStore->background.pixmap); + pBackingStore->backgroundState = None; + } +} + +/*- + *----------------------------------------------------------------------- + * miBSExposeCopy -- + * Handle the restoration of areas exposed by graphics operations. + * + * Results: + * None. + * + * Side Effects: + * prgnExposed has the areas exposed from backing-store removed + * from it. + * + *----------------------------------------------------------------------- + */ +static void +miBSExposeCopy (pSrc, pDst, pGC, prgnExposed, srcx, srcy, dstx, dsty, plane) + WindowPtr pSrc; + DrawablePtr pDst; + GCPtr pGC; + RegionPtr prgnExposed; + int srcx, srcy; + int dstx, dsty; + unsigned long plane; +{ + RegionRec tempRgn; + miBSWindowPtr pBackingStore; + RegionPtr (*copyProc)(); + GCPtr pScratchGC; + register BoxPtr pBox; + register int i; + register int dx, dy; + BITS32 gcMask; + + if (!REGION_NOTEMPTY(pGC->pScreen, prgnExposed)) + return; + pBackingStore = (miBSWindowPtr)pSrc->backStorage; + + if ((pBackingStore->status == StatusNoPixmap) || + (pBackingStore->status == StatusBadAlloc)) + return; + + REGION_INIT( pGC->pScreen, &tempRgn, NullBox, 0); + REGION_INTERSECT( pGC->pScreen, &tempRgn, prgnExposed, + &pBackingStore->SavedRegion); + REGION_SUBTRACT( pGC->pScreen, prgnExposed, prgnExposed, &tempRgn); + + if (plane != 0) { + copyProc = pGC->ops->CopyPlane; + } else { + copyProc = pGC->ops->CopyArea; + } + + dx = dstx - srcx; + dy = dsty - srcy; + + switch (pBackingStore->status) { + case StatusVirtual: + case StatusVDirty: + pScratchGC = GetScratchGC (pDst->depth, pDst->pScreen); + if (pScratchGC) + { + gcMask = 0; + if (pGC->alu != pScratchGC->alu) + gcMask = GCFunction; + if (pGC->planemask != pScratchGC->planemask) + gcMask |= GCPlaneMask; + if (gcMask) + CopyGC (pGC, pScratchGC, gcMask); + miBSFillVirtualBits (pDst, pScratchGC, &tempRgn, dx, dy, + (int) pBackingStore->backgroundState, + pBackingStore->background, + ~0L); + FreeScratchGC (pScratchGC); + } + break; + case StatusContents: + for (i = REGION_NUM_RECTS(&tempRgn), pBox = REGION_RECTS(&tempRgn); + --i >= 0; + pBox++) + { + (* copyProc) (pBackingStore->pBackingPixmap, pDst, pGC, + pBox->x1 - pBackingStore->x, + pBox->y1 - pBackingStore->y, + pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, + pBox->x1 + dx, pBox->y1 + dy, plane); + } + break; + } + REGION_UNINIT( pGC->pScreen, &tempRgn); +} |