]> git.sesse.net Git - rdpsrv/blobdiff - Xserver/programs/Xserver/mi/mibstore.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / mi / mibstore.c
diff --git a/Xserver/programs/Xserver/mi/mibstore.c b/Xserver/programs/Xserver/mi/mibstore.c
new file mode 100644 (file)
index 0000000..935f758
--- /dev/null
@@ -0,0 +1,3824 @@
+/* $XConsortium: mibstore.c,v 5.63 94/10/21 20:25:08 dpw Exp $ */
+/***********************************************************
+
+Copyright (c) 1987  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+X CONSORTIUM 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 X Consortium 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 X Consortium.
+
+
+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 X Consortium 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);
+}