]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/mi/mibstore.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / mi / mibstore.c
1 /* $XConsortium: mibstore.c,v 5.63 94/10/21 20:25:08 dpw Exp $ */
2 /***********************************************************
3
4 Copyright (c) 1987  X Consortium
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 Except as contained in this notice, the name of the X Consortium shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from the X Consortium.
26
27
28 Copyright 1987 by the Regents of the University of California
29
30                         All Rights Reserved
31
32 Permission to use, copy, modify, and distribute this software and its
33 documentation for any purpose and without fee is hereby granted, provided
34 that the above copyright notice appear in all copies and that both that
35 copyright notice and this permission notice appear in supporting
36 documentation, and that the name X Consortium not be used in advertising or publicity
37 pertaining to distribution of the software without specific, written prior
38 permission.  
39
40 The University of California makes no representations about the suitability
41 of this software for any purpose.  It is provided "as is" without express or
42 implied warranty.
43
44 ******************************************************************/
45
46 #define NEED_EVENTS
47 #include "X.h"
48 #include "Xmd.h"
49 #include "Xproto.h"
50 #include "misc.h"
51 #include "regionstr.h"
52 #include "scrnintstr.h"
53 #include "gcstruct.h"
54 #include "extnsionst.h"
55 #include "windowstr.h"
56 #include "pixmapstr.h"
57 #include "fontstruct.h"
58 #include "dixfontstr.h"
59 #include "dixstruct.h"          /* For requestingClient */
60 #include "mi.h"
61 #include "mibstorest.h"
62
63 /*
64  * When the server fails to allocate a backing store pixmap, if you want
65  * it to dynamically retry to allocate backing store on every subsequent
66  * graphics op, you can enable BSEAGER; otherwise, backing store will be
67  * disabled on the window until it is unmapped and then remapped.
68  */
69 /* #define BSEAGER */
70
71 /*-
72  * NOTES ON USAGE:
73  *
74  * The functions in this file implement a machine-independent backing-store
75  * scheme. To use it, the output library must do the following:
76  *      - Provide a SaveAreas function that takes a destination pixmap, a
77  *          region of the areas to save (in the pixmap's coordinate system)
78  *          and the screen origin of the region. It should copy the areas from
79  *          the screen into the pixmap.
80  *      - Provide a RestoreAreas function that takes a source pixmap, a region
81  *          of the areas to restore (in the screen's coordinate system) and the
82  *          origin of the pixmap on the screen. It should copy the areas from
83  *          the pixmap into the screen.
84  *      - Provide a SetClipmaskRgn function that takes a gc and a region
85  *          and merges the region into any CT_PIXMAP client clip that
86  *          is specified in the GC.  This routine is only needed if
87  *          miValidateBackingStore will see CT_PIXMAP clip lists; not
88  *          true for any of the sample servers (which convert the PIXMAP
89  *          clip lists into CT_REGION clip lists; an expensive but simple
90  *          to code option).
91  *      - The function placed in a window's ClearToBackground vector must call
92  *          pScreen->ClearBackingStore with the window, followed by
93  *          the window-relative x and y coordinates, followed by the width and
94  *          height of the area to be cleared, followed by the generateExposures
95  *          flag. This has been taken care of in miClearToBackground.
96  *      - Whatever determines GraphicsExpose events for the CopyArea and
97  *          CopyPlane requests should call pWin->backStorage->ExposeCopy
98  *          with the source and destination drawables, the GC used, a source-
99  *          window-relative region of exposed areas, the source and destination
100  *          coordinates and the bitplane copied, if CopyPlane, or 0, if
101  *          CopyArea.
102  *
103  * JUSTIFICATION
104  *    This is a cross between saving everything and just saving the
105  * obscued areas (as in Pike's layers.)  This method has the advantage
106  * of only doing each output operation once per pixel, visible or
107  * invisible, and avoids having to do all the crufty storage
108  * management of keeping several separate rectangles.  Since the
109  * ddx layer ouput primitives are required to draw through clipping
110  * rectangles anyway, sending multiple drawing requests for each of
111  * several rectangles isn't necessary.  (Of course, it could be argued
112  * that the ddx routines should just take one rectangle each and
113  * get called multiple times, but that would make taking advantage of
114  * smart hardware harder, and probably be slower as well.)
115  */
116
117 #define SETUP_BACKING_TERSE(pGC) \
118     miBSGCPtr   pGCPrivate = (miBSGCPtr)(pGC)->devPrivates[miBSGCIndex].ptr; \
119     GCFuncs     *oldFuncs = pGC->funcs;
120
121 #define SETUP_BACKING(pDrawable,pGC) \
122     miBSWindowPtr pBackingStore = \
123         (miBSWindowPtr)((WindowPtr)(pDrawable))->backStorage; \
124     DrawablePtr   pBackingDrawable = (DrawablePtr) \
125         pBackingStore->pBackingPixmap; \
126     SETUP_BACKING_TERSE(pGC) \
127     GCPtr       pBackingGC = pGCPrivate->pBackingGC;
128
129 #define PROLOGUE(pGC) { \
130     pGC->ops = pGCPrivate->wrapOps;\
131     pGC->funcs = pGCPrivate->wrapFuncs; \
132     }
133
134 #define EPILOGUE(pGC) { \
135     pGCPrivate->wrapOps = (pGC)->ops; \
136     (pGC)->ops = &miBSGCOps; \
137     (pGC)->funcs = oldFuncs; \
138     }
139    
140 static void         miCreateBSPixmap();
141 static void         miDestroyBSPixmap();
142 static void         miTileVirtualBS();
143 static void         miBSAllocate(), miBSFree();
144 static Bool         miBSCreateGCPrivate ();
145 static void         miBSClearBackingRegion ();
146
147 #define MoreCopy0 ;
148 #define MoreCopy2 *dstCopy++ = *srcCopy++; *dstCopy++ = *srcCopy++;
149 #define MoreCopy4 MoreCopy2 MoreCopy2
150
151 #define copyData(src,dst,n,morecopy) \
152 { \
153     register short *srcCopy = (short *)(src); \
154     register short *dstCopy = (short *)(dst); \
155     register int i; \
156     register int bsx = pBackingStore->x; \
157     register int bsy = pBackingStore->y; \
158     for (i = n; --i >= 0; ) \
159     { \
160         *dstCopy++ = *srcCopy++ - bsx; \
161         *dstCopy++ = *srcCopy++ - bsy; \
162         morecopy \
163     } \
164 }
165
166 #define copyPoints(src,dst,n,mode) \
167 if (mode == CoordModeOrigin) \
168 { \
169     copyData(src,dst,n,MoreCopy0); \
170 } \
171 else \
172 { \
173     memmove((char *)(dst), (char *)(src), (n) << 2); \
174     *((short *)(dst)) -= pBackingStore->x; \
175     *((short *)(dst) + 1) -= pBackingStore->y; \
176 }
177
178 /*
179  * wrappers for screen funcs
180  */
181
182 static int  miBSScreenIndex;
183 static unsigned long miBSGeneration = 0;
184
185 static Bool         miBSCloseScreen();
186 static void         miBSGetImage();
187 static void         miBSGetSpans();
188 static Bool         miBSChangeWindowAttributes();
189 static Bool         miBSCreateGC();
190 static Bool         miBSDestroyWindow();
191
192 /*
193  * backing store screen functions
194  */
195
196 static void         miBSSaveDoomedAreas();
197 static RegionPtr    miBSRestoreAreas();
198 static void         miBSExposeCopy();
199 static RegionPtr    miBSTranslateBackingStore(), miBSClearBackingStore();
200 static void         miBSDrawGuarantee();
201
202 /*
203  * wrapper vectors for GC funcs and ops
204  */
205
206 static int  miBSGCIndex;
207
208 static void miBSValidateGC (),  miBSCopyGC (),      miBSDestroyGC();
209 static void miBSChangeGC();
210 static void miBSChangeClip(),   miBSDestroyClip(),  miBSCopyClip();
211
212 static GCFuncs  miBSGCFuncs = {
213     miBSValidateGC,
214     miBSChangeGC,
215     miBSCopyGC,
216     miBSDestroyGC,
217     miBSChangeClip,
218     miBSDestroyClip,
219     miBSCopyClip,
220 };
221
222 static void         miBSFillSpans(),    miBSSetSpans(),     miBSPutImage();
223 static RegionPtr    miBSCopyArea(),     miBSCopyPlane();
224 static void         miBSPolyPoint(),    miBSPolylines(),    miBSPolySegment();
225 static void         miBSPolyRectangle(),miBSPolyArc(),      miBSFillPolygon();
226 static void         miBSPolyFillRect(), miBSPolyFillArc();
227 static int          miBSPolyText8(),    miBSPolyText16();
228 static void         miBSImageText8(),   miBSImageText16();
229 static void         miBSImageGlyphBlt(),miBSPolyGlyphBlt();
230 static void         miBSPushPixels();
231 #ifdef NEED_LINEHELPER
232 static void         miBSLineHelper();
233 #endif
234
235 static GCOps miBSGCOps = {
236     miBSFillSpans,      miBSSetSpans,       miBSPutImage,       
237     miBSCopyArea,       miBSCopyPlane,      miBSPolyPoint,
238     miBSPolylines,      miBSPolySegment,    miBSPolyRectangle,
239     miBSPolyArc,        miBSFillPolygon,    miBSPolyFillRect,
240     miBSPolyFillArc,    miBSPolyText8,      miBSPolyText16,
241     miBSImageText8,     miBSImageText16,    miBSImageGlyphBlt,
242     miBSPolyGlyphBlt,   miBSPushPixels
243 #ifdef NEED_LINEHELPER
244     , miBSLineHelper
245 #endif
246 };
247
248 #define FUNC_PROLOGUE(pGC, pPriv) \
249     ((pGC)->funcs = pPriv->wrapFuncs),\
250     ((pGC)->ops = pPriv->wrapOps)
251
252 #define FUNC_EPILOGUE(pGC, pPriv) \
253     ((pGC)->funcs = &miBSGCFuncs),\
254     ((pGC)->ops = &miBSGCOps)
255
256 /*
257  * every GC in the server is initially wrapped with these
258  * "cheap" functions.  This allocates no memory and is used
259  * to discover GCs used with windows which have backing
260  * store enabled
261  */
262
263 static void miBSCheapValidateGC(),  miBSCheapCopyGC(),  miBSCheapDestroyGC();
264 static void miBSCheapChangeGC ();
265 static void miBSCheapChangeClip(),  miBSCheapDestroyClip();
266 static void miBSCheapCopyClip();
267
268 static GCFuncs miBSCheapGCFuncs = {
269     miBSCheapValidateGC,
270     miBSCheapChangeGC,
271     miBSCheapCopyGC,
272     miBSCheapDestroyGC,
273     miBSCheapChangeClip,
274     miBSCheapDestroyClip,
275     miBSCheapCopyClip,
276 };
277
278 #define CHEAP_FUNC_PROLOGUE(pGC) \
279     ((pGC)->funcs = (GCFuncs *) (pGC)->devPrivates[miBSGCIndex].ptr)
280
281 #define CHEAP_FUNC_EPILOGUE(pGC) \
282     ((pGC)->funcs = &miBSCheapGCFuncs)
283
284 /*
285  * called from device screen initialization proc.  Gets a GCPrivateIndex
286  * and wraps appropriate per-screen functions
287  */
288
289 void
290 miInitializeBackingStore (pScreen, funcs)
291     ScreenPtr   pScreen;
292     miBSFuncPtr funcs;
293 {
294     miBSScreenPtr    pScreenPriv;
295
296     if (miBSGeneration != serverGeneration)
297     {
298         miBSScreenIndex = AllocateScreenPrivateIndex ();
299         if (miBSScreenIndex < 0)
300             return;
301         miBSGCIndex = AllocateGCPrivateIndex ();
302         miBSGeneration = serverGeneration;
303     }
304     if (!AllocateGCPrivate(pScreen, miBSGCIndex, 0))
305         return;
306     pScreenPriv = (miBSScreenPtr) xalloc (sizeof (miBSScreenRec));
307     if (!pScreenPriv)
308         return;
309
310     pScreenPriv->CloseScreen = pScreen->CloseScreen;
311     pScreenPriv->GetImage = pScreen->GetImage;
312     pScreenPriv->GetSpans = pScreen->GetSpans;
313     pScreenPriv->ChangeWindowAttributes = pScreen->ChangeWindowAttributes;
314     pScreenPriv->CreateGC = pScreen->CreateGC;
315     pScreenPriv->DestroyWindow = pScreen->DestroyWindow;
316     pScreenPriv->funcs = funcs;
317
318     pScreen->CloseScreen = miBSCloseScreen;
319     pScreen->GetImage = miBSGetImage;
320     pScreen->GetSpans = miBSGetSpans;
321     pScreen->ChangeWindowAttributes = miBSChangeWindowAttributes;
322     pScreen->CreateGC = miBSCreateGC;
323     pScreen->DestroyWindow = miBSDestroyWindow;
324
325     pScreen->SaveDoomedAreas = miBSSaveDoomedAreas;
326     pScreen->RestoreAreas = miBSRestoreAreas;
327     pScreen->ExposeCopy = miBSExposeCopy;
328     pScreen->TranslateBackingStore = miBSTranslateBackingStore;
329     pScreen->ClearBackingStore = miBSClearBackingStore;
330     pScreen->DrawGuarantee = miBSDrawGuarantee;
331
332     pScreen->devPrivates[miBSScreenIndex].ptr = (pointer) pScreenPriv;
333 }
334
335 /*
336  * Screen function wrappers
337  */
338
339 #define SCREEN_PROLOGUE(pScreen, field)\
340   ((pScreen)->field = \
341    ((miBSScreenPtr) \
342     (pScreen)->devPrivates[miBSScreenIndex].ptr)->field)
343
344 #define SCREEN_EPILOGUE(pScreen, field, wrapper)\
345     ((pScreen)->field = wrapper)
346
347 /*
348  * CloseScreen wrapper -- unwrap everything, free the private data
349  * and call the wrapped function
350  */
351
352 static Bool
353 miBSCloseScreen (i, pScreen)
354     int         i;
355     ScreenPtr   pScreen;
356 {
357     miBSScreenPtr   pScreenPriv;
358
359     pScreenPriv = (miBSScreenPtr) pScreen->devPrivates[miBSScreenIndex].ptr;
360
361     pScreen->CloseScreen = pScreenPriv->CloseScreen;
362     pScreen->GetImage = pScreenPriv->GetImage;
363     pScreen->GetSpans = pScreenPriv->GetSpans;
364     pScreen->ChangeWindowAttributes = pScreenPriv->ChangeWindowAttributes;
365     pScreen->CreateGC = pScreenPriv->CreateGC;
366
367     xfree ((pointer) pScreenPriv);
368
369     return (*pScreen->CloseScreen) (i, pScreen);
370 }
371
372 static void miBSFillVirtualBits();
373
374 static void
375 miBSGetImage (pDrawable, sx, sy, w, h, format, planemask, pdstLine)
376     DrawablePtr     pDrawable;
377     int             sx, sy, w, h;
378     unsigned int    format;
379     unsigned long   planemask;
380     char            *pdstLine;
381 {
382     ScreenPtr               pScreen = pDrawable->pScreen;
383     BoxRec                  bounds;
384     unsigned char           depth;
385     
386     SCREEN_PROLOGUE (pScreen, GetImage);
387
388     if (pDrawable->type != DRAWABLE_PIXMAP &&
389         ((WindowPtr) pDrawable)->visibility != VisibilityUnobscured)
390     {
391         PixmapPtr       pPixmap;
392         miBSWindowPtr   pWindowPriv;
393         GCPtr           pGC;
394         WindowPtr       pWin, pSrcWin;
395         int             xoff, yoff;
396         RegionRec       Remaining;
397         RegionRec       Border;
398         RegionRec       Inside;
399         BoxPtr          pBox;
400         int             n;
401
402         pWin = (WindowPtr) pDrawable;
403         pPixmap = 0;
404         depth = pDrawable->depth;
405         bounds.x1 = sx + pDrawable->x;
406         bounds.y1 = sy + pDrawable->y;
407         bounds.x2 = bounds.x1 + w;
408         bounds.y2 = bounds.y1 + h;
409         REGION_INIT(pScreen, &Remaining, &bounds, 0);
410         for (;;)
411         {
412             bounds.x1 = sx + pDrawable->x - pWin->drawable.x;
413             bounds.y1 = sy + pDrawable->y - pWin->drawable.y;
414             bounds.x2 = bounds.x1 + w;
415             bounds.y2 = bounds.y1 + h;
416             if (pWin->viewable && pWin->backStorage &&
417                 pWin->drawable.depth == depth &&
418                 (RECT_IN_REGION(pScreen, &(pWindowPriv =
419                     (miBSWindowPtr) pWin->backStorage)->SavedRegion,
420                     &bounds) != rgnOUT ||
421                  RECT_IN_REGION(pScreen, &Remaining,
422                   REGION_EXTENTS(pScreen, &pWin->borderSize)) != rgnOUT))
423             {
424                 if (!pPixmap)
425                 {
426                     XID subWindowMode = IncludeInferiors;
427                     int x, y;
428
429                     pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, depth);
430                     if (!pPixmap)
431                         goto punt;
432                     pGC = GetScratchGC (depth, pScreen);
433                     if (!pGC)
434                     {
435                         (*pScreen->DestroyPixmap) (pPixmap);
436                         goto punt;
437                     }
438                     ChangeGC (pGC, GCSubwindowMode, &subWindowMode);
439                     ValidateGC ((DrawablePtr)pPixmap, pGC);
440                     REGION_INIT(pScreen, &Border, NullBox, 0);
441                     REGION_INIT(pScreen, &Inside, NullBox, 0);
442                     pSrcWin = (WindowPtr) pDrawable;
443                     x = sx;
444                     y = sy;
445                     if (pSrcWin->parent)
446                     {
447                         x += pSrcWin->origin.x;
448                         y += pSrcWin->origin.y;
449                         pSrcWin = pSrcWin->parent;
450                     }
451                     (*pGC->ops->CopyArea) ((DrawablePtr)pSrcWin,
452                                             (DrawablePtr)pPixmap, pGC,
453                                             x, y, w, h,
454                                             0, 0);
455                     REGION_SUBTRACT(pScreen, &Remaining, &Remaining,
456                                     &((WindowPtr) pDrawable)->borderClip);
457                 }
458
459                 REGION_INTERSECT(pScreen, &Inside, &Remaining, &pWin->winSize);
460                 REGION_TRANSLATE(pScreen, &Inside,
461                                              -pWin->drawable.x,
462                                              -pWin->drawable.y);
463                 REGION_INTERSECT(pScreen, &Inside, &Inside,
464                                  &pWindowPriv->SavedRegion);
465
466                 /* offset of sub-window in GetImage pixmap */
467                 xoff = pWin->drawable.x - pDrawable->x - sx;
468                 yoff = pWin->drawable.y - pDrawable->y - sy;
469
470                 if (REGION_NUM_RECTS(&Inside) > 0)
471                 {
472                     switch (pWindowPriv->status)
473                     {
474                     case StatusContents:
475                         pBox = REGION_RECTS(&Inside);
476                         for (n = REGION_NUM_RECTS(&Inside); --n >= 0;)
477                         {
478                             (*pGC->ops->CopyArea) (
479                                 (DrawablePtr)pWindowPriv->pBackingPixmap,
480                                                    (DrawablePtr)pPixmap, pGC,
481                                                    pBox->x1 - pWindowPriv->x,
482                                                    pBox->y1 - pWindowPriv->y,
483                                                    pBox->x2 - pBox->x1,
484                                                    pBox->y2 - pBox->y1,
485                                                    pBox->x1 + xoff,
486                                                    pBox->y1 + yoff);
487                             ++pBox;
488                         }
489                         break;
490                     case StatusVirtual:
491                     case StatusVDirty:
492                         if (pWindowPriv->backgroundState == BackgroundPixmap ||
493                             pWindowPriv->backgroundState == BackgroundPixel)
494                         miBSFillVirtualBits ((DrawablePtr) pPixmap, pGC, &Inside,
495                                             xoff, yoff,
496                                             (int) pWindowPriv->backgroundState,
497                                             pWindowPriv->background, ~0L);
498                         break;
499                     }
500                 }
501                 REGION_SUBTRACT(pScreen, &Border, &pWin->borderSize,
502                                 &pWin->winSize);
503                 REGION_INTERSECT(pScreen, &Border, &Border, &Remaining);
504                 if (REGION_NUM_RECTS(&Border) > 0)
505                 {
506                     REGION_TRANSLATE(pScreen, &Border, -pWin->drawable.x,
507                                                   -pWin->drawable.y);
508                     miBSFillVirtualBits ((DrawablePtr) pPixmap, pGC, &Border,
509                                         xoff, yoff,
510                                         pWin->borderIsPixel ? (int)BackgroundPixel : (int)BackgroundPixmap,
511                                         pWin->border, ~0L);
512                 }
513             }
514
515             if (pWin->viewable && pWin->firstChild)
516                 pWin = pWin->firstChild;
517             else
518             {
519                 while (!pWin->nextSib && pWin != (WindowPtr) pDrawable)
520                     pWin = pWin->parent;
521                 if (pWin == (WindowPtr) pDrawable)
522                     break;
523                 pWin = pWin->nextSib;
524             }
525         }
526
527         REGION_UNINIT(pScreen, &Remaining);
528
529         if (pPixmap)
530         {
531             REGION_UNINIT(pScreen, &Border);
532             REGION_UNINIT(pScreen, &Inside);
533             (*pScreen->GetImage) ((DrawablePtr) pPixmap,
534                 0, 0, w, h, format, planemask, pdstLine);
535             (*pScreen->DestroyPixmap) (pPixmap);
536             FreeScratchGC (pGC);
537         }
538         else
539         {
540             goto punt;
541         }
542     }
543     else
544     {
545 punt:   ;
546         (*pScreen->GetImage) (pDrawable, sx, sy, w, h,
547                               format, planemask, pdstLine);
548     }
549
550     SCREEN_EPILOGUE (pScreen, GetImage, miBSGetImage);
551 }
552
553 static void
554 miBSGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart)
555     DrawablePtr pDrawable;
556     int         wMax;
557     DDXPointPtr ppt;
558     int         *pwidth;
559     int         nspans;
560     char        *pdstStart;
561 {
562     ScreenPtr               pScreen = pDrawable->pScreen;
563     BoxRec                  bounds;
564     int                     i;
565     WindowPtr               pWin;
566     int                     dx, dy;
567     
568     SCREEN_PROLOGUE (pScreen, GetSpans);
569
570     if (pDrawable->type != DRAWABLE_PIXMAP && ((WindowPtr) pDrawable)->backStorage)
571     {
572         PixmapPtr       pPixmap;
573         miBSWindowPtr   pWindowPriv;
574         GCPtr           pGC;
575
576         pWin = (WindowPtr) pDrawable;
577         pWindowPriv = (miBSWindowPtr) pWin->backStorage;
578         pPixmap = pWindowPriv->pBackingPixmap;
579
580         bounds.x1 = ppt->x;
581         bounds.y1 = ppt->y;
582         bounds.x2 = bounds.x1 + *pwidth;
583         bounds.y2 = ppt->y;
584         for (i = 0; i < nspans; i++)
585         {
586             if (ppt[i].x < bounds.x1)
587                 bounds.x1 = ppt[i].x;
588             if (ppt[i].x + pwidth[i] > bounds.x2)
589                 bounds.x2 = ppt[i].x + pwidth[i];
590             if (ppt[i].y < bounds.y1)
591                 bounds.y1 = ppt[i].y;
592             else if (ppt[i].y > bounds.y2)
593                 bounds.y2 = ppt[i].y;
594         }
595     
596         switch (RECT_IN_REGION(pScreen, &pWindowPriv->SavedRegion, &bounds))
597         {
598         case rgnPART:
599             if (!pPixmap)
600             {
601                 miCreateBSPixmap (pWin, NullBox);
602                 if (!(pPixmap = pWindowPriv->pBackingPixmap))
603                     break;
604             }
605             pWindowPriv->status = StatusNoPixmap;
606             pGC = GetScratchGC(pPixmap->drawable.depth,
607                                pPixmap->drawable.pScreen);
608             if (pGC)
609             {
610                 ValidateGC ((DrawablePtr) pPixmap, pGC);
611                 (*pGC->ops->CopyArea)
612                     (pDrawable, (DrawablePtr) pPixmap, pGC,
613                     bounds.x1, bounds.y1,
614                     bounds.x2 - bounds.x1, bounds.y2 - bounds.y1,
615                     bounds.x1 + pPixmap->drawable.x - pWin->drawable.x -
616                      pWindowPriv->x,
617                     bounds.y1 + pPixmap->drawable.y - pWin->drawable.y -
618                      pWindowPriv->y);
619                 FreeScratchGC(pGC);
620             }
621             pWindowPriv->status = StatusContents;
622             /* fall through */
623         case rgnIN:
624             if (!pPixmap)
625             {
626                 miCreateBSPixmap (pWin, NullBox);
627                 if (!(pPixmap = pWindowPriv->pBackingPixmap))
628                     break;
629             }
630             dx = pPixmap->drawable.x - pWin->drawable.x - pWindowPriv->x;
631             dy = pPixmap->drawable.y - pWin->drawable.y - pWindowPriv->y;
632             for (i = 0; i < nspans; i++)
633             {
634                 ppt[i].x += dx;
635                 ppt[i].y += dy;
636             }
637             (*pScreen->GetSpans) ((DrawablePtr) pPixmap, wMax, ppt, pwidth,
638                                   nspans, pdstStart);
639             break;
640         case rgnOUT:
641             (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans,
642                                   pdstStart);
643             break;
644         }
645     }
646     else
647     {
648         (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
649     }
650
651     SCREEN_EPILOGUE (pScreen, GetSpans, miBSGetSpans);
652 }
653
654 static Bool
655 miBSChangeWindowAttributes (pWin, mask)
656     WindowPtr       pWin;
657     unsigned long   mask;
658 {
659     ScreenPtr   pScreen;
660     Bool        ret;
661
662     pScreen = pWin->drawable.pScreen;
663
664     SCREEN_PROLOGUE (pScreen, ChangeWindowAttributes);
665
666     ret = (*pScreen->ChangeWindowAttributes) (pWin, mask);
667
668     if (ret && (mask & CWBackingStore))
669     {
670         if (pWin->backingStore != NotUseful || pWin->DIXsaveUnder)
671             miBSAllocate (pWin);
672         else
673             miBSFree (pWin);
674     }
675
676     SCREEN_EPILOGUE (pScreen, ChangeWindowAttributes, miBSChangeWindowAttributes);
677
678     return ret;
679 }
680
681 /*
682  * GC Create wrapper.  Set up the cheap GC func wrappers to track
683  * GC validation on BackingStore windows
684  */
685
686 static Bool
687 miBSCreateGC (pGC)
688     GCPtr   pGC;
689 {
690     ScreenPtr   pScreen = pGC->pScreen;
691     Bool        ret;
692
693     SCREEN_PROLOGUE (pScreen, CreateGC);
694     
695     if ( (ret = (*pScreen->CreateGC) (pGC)) )
696     {
697         pGC->devPrivates[miBSGCIndex].ptr = (pointer) pGC->funcs;
698         pGC->funcs = &miBSCheapGCFuncs;
699     }
700
701     SCREEN_EPILOGUE (pScreen, CreateGC, miBSCreateGC);
702
703     return ret;
704 }
705
706 static Bool
707 miBSDestroyWindow (pWin)
708     WindowPtr   pWin;
709 {
710     ScreenPtr   pScreen = pWin->drawable.pScreen;
711     Bool        ret;
712
713     SCREEN_PROLOGUE (pScreen, DestroyWindow);
714     
715     ret = (*pScreen->DestroyWindow) (pWin);
716
717     miBSFree (pWin);
718
719     SCREEN_EPILOGUE (pScreen, DestroyWindow, miBSDestroyWindow);
720
721     return ret;
722 }
723
724 /*
725  * cheap GC func wrappers.  Simply track validation on windows
726  * with backing store to enable the real func/op wrappers
727  */
728
729 static void
730 miBSCheapValidateGC (pGC, stateChanges, pDrawable)
731     GCPtr           pGC;
732     unsigned long   stateChanges;
733     DrawablePtr     pDrawable;
734 {
735     CHEAP_FUNC_PROLOGUE (pGC);
736     
737     if (pDrawable->type != DRAWABLE_PIXMAP &&
738         ((WindowPtr) pDrawable)->backStorage != NULL &&
739         miBSCreateGCPrivate (pGC))
740     {
741         (*pGC->funcs->ValidateGC) (pGC, stateChanges, pDrawable);
742     }
743     else
744     {
745         (*pGC->funcs->ValidateGC) (pGC, stateChanges, pDrawable);
746
747         /* rewrap funcs as Validate may have changed them */
748         pGC->devPrivates[miBSGCIndex].ptr = (pointer) pGC->funcs;
749
750         CHEAP_FUNC_EPILOGUE (pGC);
751     }
752 }
753
754 static void
755 miBSCheapChangeGC (pGC, mask)
756     GCPtr   pGC;
757     unsigned long   mask;
758 {
759     CHEAP_FUNC_PROLOGUE (pGC);
760
761     (*pGC->funcs->ChangeGC) (pGC, mask);
762
763     CHEAP_FUNC_EPILOGUE (pGC);
764 }
765
766 static void
767 miBSCheapCopyGC (pGCSrc, mask, pGCDst)
768     GCPtr   pGCSrc, pGCDst;
769     unsigned long   mask;
770 {
771     CHEAP_FUNC_PROLOGUE (pGCDst);
772
773     (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
774
775     CHEAP_FUNC_EPILOGUE (pGCDst);
776 }
777
778 static void
779 miBSCheapDestroyGC (pGC)
780     GCPtr   pGC;
781 {
782     CHEAP_FUNC_PROLOGUE (pGC);
783
784     (*pGC->funcs->DestroyGC) (pGC);
785
786     /* leave it unwrapped */
787 }
788
789 static void
790 miBSCheapChangeClip (pGC, type, pvalue, nrects)
791     GCPtr   pGC;
792     int         type;
793     pointer     pvalue;
794     int         nrects;
795 {
796     CHEAP_FUNC_PROLOGUE (pGC);
797
798     (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
799
800     CHEAP_FUNC_EPILOGUE (pGC);
801 }
802
803 static void
804 miBSCheapCopyClip(pgcDst, pgcSrc)
805     GCPtr pgcDst, pgcSrc;
806 {
807     CHEAP_FUNC_PROLOGUE (pgcDst);
808
809     (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
810
811     CHEAP_FUNC_EPILOGUE (pgcDst);
812 }
813
814 static void
815 miBSCheapDestroyClip(pGC)
816     GCPtr       pGC;
817 {
818     CHEAP_FUNC_PROLOGUE (pGC);
819
820     (* pGC->funcs->DestroyClip)(pGC);
821
822     CHEAP_FUNC_EPILOGUE (pGC);
823 }
824
825 /*
826  * create the full func/op wrappers for a GC
827  */
828
829 static Bool
830 miBSCreateGCPrivate (pGC)
831     GCPtr   pGC;
832 {
833     miBSGCRec   *pPriv;
834
835     pPriv = (miBSGCRec *) xalloc (sizeof (miBSGCRec));
836     if (!pPriv)
837         return FALSE;
838     pPriv->pBackingGC = NULL;
839     pPriv->guarantee = GuaranteeNothing;
840     pPriv->serialNumber = 0;
841     pPriv->stateChanges = (1 << (GCLastBit + 1)) - 1;
842     pPriv->wrapOps = pGC->ops;
843     pPriv->wrapFuncs = pGC->funcs;
844     pGC->funcs = &miBSGCFuncs;
845     pGC->ops = &miBSGCOps;
846     pGC->devPrivates[miBSGCIndex].ptr = (pointer) pPriv;
847     return TRUE;
848 }
849
850 static void
851 miBSDestroyGCPrivate (pGC)
852     GCPtr   pGC;
853 {
854     miBSGCRec   *pPriv;
855
856     pPriv = (miBSGCRec *) pGC->devPrivates[miBSGCIndex].ptr;
857     if (pPriv)
858     {
859         pGC->devPrivates[miBSGCIndex].ptr = (pointer) pPriv->wrapFuncs;
860         pGC->funcs = &miBSCheapGCFuncs;
861         pGC->ops = pPriv->wrapOps;
862         if (pPriv->pBackingGC)
863             FreeGC (pPriv->pBackingGC, (GContext) 0);
864         xfree ((pointer) pPriv);
865     }
866 }
867
868 /*
869  * GC ops -- wrap each GC operation with our own function
870  */
871
872 /*-
873  *-----------------------------------------------------------------------
874  * miBSFillSpans --
875  *      Perform a FillSpans, routing output to backing-store as needed.
876  *
877  * Results:
878  *      None.
879  *
880  * Side Effects:
881  *
882  *-----------------------------------------------------------------------
883  */
884 static void
885 miBSFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted)
886     DrawablePtr pDrawable;
887     GCPtr       pGC;
888     int         nInit;                  /* number of spans to fill */
889     DDXPointPtr pptInit;                /* pointer to list of start points */
890     int         *pwidthInit;            /* pointer to list of n widths */
891     int         fSorted;
892 {
893     DDXPointPtr pptCopy, pptReset;
894     int         *pwidthCopy;
895     SETUP_BACKING (pDrawable, pGC);
896
897     PROLOGUE(pGC);
898
899     pptCopy = (DDXPointPtr)ALLOCATE_LOCAL(nInit*sizeof(DDXPointRec));
900     pwidthCopy=(int *)ALLOCATE_LOCAL(nInit*sizeof(int));
901     if (pptCopy && pwidthCopy)
902     {
903         copyData(pptInit, pptCopy, nInit, MoreCopy0);
904         memmove((char *)pwidthCopy,(char *)pwidthInit,nInit*sizeof(int));
905
906         (* pGC->ops->FillSpans)(pDrawable, pGC, nInit, pptInit,
907                              pwidthInit, fSorted);
908         if (pGC->miTranslate)
909         {
910             int dx, dy;
911             int nReset;
912
913             pptReset = pptCopy;
914             dx = pDrawable->x - pBackingDrawable->x;
915             dy = pDrawable->y - pBackingDrawable->y;
916             nReset = nInit;
917             while (nReset--)
918             {
919                 pptReset->x -= dx;
920                 pptReset->y -= dy;
921                 ++pptReset;
922             }
923         }
924         (* pBackingGC->ops->FillSpans)(pBackingDrawable,
925                                   pBackingGC, nInit, pptCopy, pwidthCopy,
926                                   fSorted);
927     }
928     if (pwidthCopy) DEALLOCATE_LOCAL(pwidthCopy);
929     if (pptCopy) DEALLOCATE_LOCAL(pptCopy);
930
931     EPILOGUE (pGC);
932 }
933
934 /*-
935  *-----------------------------------------------------------------------
936  * miBSSetSpans --
937  *      Perform a SetSpans, routing output to backing-store as needed.
938  *
939  * Results:
940  *      None.
941  *
942  * Side Effects:
943  *
944  *-----------------------------------------------------------------------
945  */
946 static void
947 miBSSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted)
948     DrawablePtr         pDrawable;
949     GCPtr               pGC;
950     char                *psrc;
951     register DDXPointPtr ppt;
952     int                 *pwidth;
953     int                 nspans;
954     int                 fSorted;
955 {
956     DDXPointPtr pptCopy, pptReset;
957     int         *pwidthCopy;
958     SETUP_BACKING (pDrawable, pGC);
959
960     PROLOGUE(pGC);
961
962     pptCopy = (DDXPointPtr)ALLOCATE_LOCAL(nspans*sizeof(DDXPointRec));
963     pwidthCopy=(int *)ALLOCATE_LOCAL(nspans*sizeof(int));
964     if (pptCopy && pwidthCopy)
965     {
966         copyData(ppt, pptCopy, nspans, MoreCopy0);
967         memmove((char *)pwidthCopy,(char *)pwidth,nspans*sizeof(int));
968
969         (* pGC->ops->SetSpans)(pDrawable, pGC, psrc, ppt, pwidth,
970                                nspans, fSorted);
971         if (pGC->miTranslate)
972         {
973             int dx, dy;
974             int nReset;
975
976             pptReset = pptCopy;
977             dx = pDrawable->x - pBackingDrawable->x;
978             dy = pDrawable->y - pBackingDrawable->y;
979             nReset = nspans;
980             while (nReset--)
981             {
982                 pptReset->x -= dx;
983                 pptReset->y -= dy;
984                 ++pptReset;
985             }
986         }
987         (* pBackingGC->ops->SetSpans)(pBackingDrawable, pBackingGC,
988                                 psrc, pptCopy, pwidthCopy, nspans, fSorted);
989     }
990     if (pwidthCopy) DEALLOCATE_LOCAL(pwidthCopy);
991     if (pptCopy) DEALLOCATE_LOCAL(pptCopy);
992
993     EPILOGUE (pGC);
994 }
995
996 /*-
997  *-----------------------------------------------------------------------
998  * miBSPutImage --
999  *      Perform a PutImage, routing output to backing-store as needed.
1000  *
1001  * Results:
1002  *      None.
1003  *
1004  * Side Effects:
1005  *
1006  *-----------------------------------------------------------------------
1007  */
1008 static void
1009 miBSPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits)
1010     DrawablePtr   pDrawable;
1011     GCPtr         pGC;
1012     int           depth;
1013     int           x;
1014     int           y;
1015     int           w;
1016     int           h;
1017     int           leftPad;
1018     int           format;
1019     char          *pBits;
1020 {
1021     SETUP_BACKING (pDrawable, pGC);
1022
1023     PROLOGUE(pGC);
1024
1025     (*pGC->ops->PutImage)(pDrawable, pGC,
1026                      depth, x, y, w, h, leftPad, format, pBits);
1027     (*pBackingGC->ops->PutImage)(pBackingDrawable, pBackingGC,
1028                      depth, x - pBackingStore->x, y - pBackingStore->y,
1029                      w, h, leftPad, format, pBits);
1030
1031     EPILOGUE (pGC);
1032 }
1033
1034 /*-
1035  *-----------------------------------------------------------------------
1036  * miBSDoCopy --
1037  *      Perform a CopyArea or CopyPlane within a window that has backing
1038  *      store enabled.
1039  *
1040  * Results:
1041  *      TRUE if the copy was performed or FALSE if a regular one should
1042  *      be done.
1043  *
1044  * Side Effects:
1045  *      Things are copied (no s***!)
1046  *
1047  * Notes:
1048  *      The idea here is to form two regions that cover the source box.
1049  *      One contains the exposed rectangles while the other contains
1050  *      the obscured ones. An array of <box, drawable> pairs is then
1051  *      formed where the <box> indicates the area to be copied and the
1052  *      <drawable> indicates from where it is to be copied (exposed regions
1053  *      come from the screen while obscured ones come from the backing
1054  *      pixmap). The array 'sequence' is then filled with the indices of
1055  *      the pairs in the order in which they should be copied to prevent
1056  *      things from getting screwed up. A call is also made through the
1057  *      backingGC to take care of any copying into the backing pixmap.
1058  *
1059  *-----------------------------------------------------------------------
1060  */
1061 static Bool
1062 miBSDoCopy(pWin, pGC, srcx, srcy, w, h, dstx, dsty, plane, copyProc, ppRgn)
1063     WindowPtr     pWin;             /* Window being scrolled */
1064     GCPtr         pGC;              /* GC we're called through */
1065     int           srcx;             /* X of source rectangle */
1066     int           srcy;             /* Y of source rectangle */
1067     int           w;                /* Width of source rectangle */
1068     int           h;                /* Height of source rectangle */
1069     int           dstx;             /* X of destination rectangle */
1070     int           dsty;             /* Y of destination rectangle */
1071     unsigned long plane;            /* Plane to copy (0 for CopyArea) */
1072     RegionPtr     (*copyProc)();    /* Procedure to call to perform the copy */
1073     RegionPtr     *ppRgn;           /* resultant Graphics Expose region */
1074 {
1075     RegionPtr           pRgnExp;    /* Exposed region */
1076     RegionPtr           pRgnObs;    /* Obscured region */
1077     BoxRec              box;        /* Source box (screen coord) */
1078     struct BoxDraw {
1079         BoxPtr          pBox;           /* Source box */
1080         enum {
1081             win, pix
1082         }               source;         /* Place from which to copy */
1083     }                   *boxes;     /* Array of box/drawable pairs covering
1084                                      * source box. */
1085     int                 *sequence;  /* Sequence of boxes to move */
1086     register int        i, j, k, l, y;
1087     register BoxPtr     pBox;
1088     int                 dx, dy, nrects;
1089     Bool                graphicsExposures;
1090     RegionPtr           (*pixCopyProc)();
1091     int                 numRectsExp, numRectsObs;
1092     BoxPtr              pBoxExp, pBoxObs;
1093
1094     SETUP_BACKING (pWin, pGC);
1095
1096     /*
1097      * Create a region of exposed boxes in pRgnExp.
1098      */
1099     box.x1 = srcx + pWin->drawable.x;
1100     box.x2 = box.x1 + w;
1101     box.y1 = srcy + pWin->drawable.y;
1102     box.y2 = box.y1 + h;
1103     
1104     pRgnExp = REGION_CREATE(pGC->pScreen, &box, 1);
1105     REGION_INTERSECT(pGC->pScreen, pRgnExp, pRgnExp, &pWin->clipList);
1106     pRgnObs = REGION_CREATE(pGC->pScreen, NULL, 1);
1107     REGION_INVERSE( pGC->pScreen, pRgnObs, pRgnExp, &box);
1108
1109     /*
1110      * Translate regions into window coordinates for proper calls
1111      * to the copyProc, then make sure none of the obscured region sticks
1112      * into invalid areas of the backing pixmap.
1113      */
1114     REGION_TRANSLATE(pGC->pScreen, pRgnExp,
1115                                       -pWin->drawable.x,
1116                                       -pWin->drawable.y);
1117     REGION_TRANSLATE(pGC->pScreen, pRgnObs,
1118                                       -pWin->drawable.x,
1119                                       -pWin->drawable.y);
1120     REGION_INTERSECT(pGC->pScreen, pRgnObs, pRgnObs, &pBackingStore->SavedRegion);
1121
1122     /*
1123      * If the obscured region is empty, there's no point being fancy.
1124      */
1125     if (!REGION_NOTEMPTY(pGC->pScreen, pRgnObs))
1126     {
1127         REGION_DESTROY(pGC->pScreen, pRgnExp);
1128         REGION_DESTROY(pGC->pScreen, pRgnObs);
1129
1130         return (FALSE);
1131     }
1132
1133     numRectsExp = REGION_NUM_RECTS(pRgnExp);
1134     pBoxExp = REGION_RECTS(pRgnExp);
1135     pBoxObs = REGION_RECTS(pRgnObs);
1136     numRectsObs = REGION_NUM_RECTS(pRgnObs);
1137     nrects = numRectsExp + numRectsObs;
1138     
1139     boxes = (struct BoxDraw *)ALLOCATE_LOCAL(nrects * sizeof(struct BoxDraw));
1140     sequence = (int *) ALLOCATE_LOCAL(nrects * sizeof(int));
1141     *ppRgn = NULL;
1142
1143     if (!boxes || !sequence)
1144     {
1145         if (sequence) DEALLOCATE_LOCAL(sequence);
1146         if (boxes) DEALLOCATE_LOCAL(boxes);
1147         REGION_DESTROY(pGC->pScreen, pRgnExp);
1148         REGION_DESTROY(pGC->pScreen, pRgnObs);
1149
1150         return(TRUE);
1151     }
1152
1153     /*
1154      * Order the boxes in the two regions so we know from which drawable
1155      * to copy which box, storing the result in the boxes array
1156      */
1157     for (i = 0, j = 0, k = 0;
1158          (i < numRectsExp) && (j < numRectsObs);
1159          k++)
1160     {
1161         if (pBoxExp[i].y1 < pBoxObs[j].y1)
1162         {
1163             boxes[k].pBox = &pBoxExp[i];
1164             boxes[k].source = win;
1165             i++;
1166         }
1167         else if ((pBoxObs[j].y1 < pBoxExp[i].y1) ||
1168                  (pBoxObs[j].x1 < pBoxExp[i].x1))
1169         {
1170             boxes[k].pBox = &pBoxObs[j];
1171             boxes[k].source = pix;
1172             j++;
1173         }
1174         else
1175         {
1176             boxes[k].pBox = &pBoxExp[i];
1177             boxes[k].source = win;
1178             i++;
1179         }
1180     }
1181
1182     /*
1183      * Catch any leftover boxes from either region (note that only
1184      * one can have leftover boxes...)
1185      */
1186     if (i != numRectsExp)
1187     {
1188         do
1189         {
1190             boxes[k].pBox = &pBoxExp[i];
1191             boxes[k].source = win;
1192             i++;
1193             k++;
1194         } while (i < numRectsExp);
1195
1196     }
1197     else
1198     {
1199         do
1200         {
1201             boxes[k].pBox = &pBoxObs[j];
1202             boxes[k].source = pix;
1203             j++;
1204             k++;
1205         } while (j < numRectsObs);
1206     }
1207     
1208     if (dsty <= srcy)
1209     {
1210         /*
1211          * Scroll up or vertically stationary, so vertical order is ok.
1212          */
1213         if (dstx <= srcx)
1214         {
1215             /*
1216              * Scroll left or horizontally stationary, so horizontal order
1217              * is ok as well.
1218              */
1219             for (i = 0; i < nrects; i++)
1220             {
1221                 sequence[i] = i;
1222             }
1223         }
1224         else
1225         {
1226             /*
1227              * Scroll right. Need to reverse the rectangles within each
1228              * band.
1229              */
1230             for (i = 0, j = 1, k = 0;
1231                  i < nrects;
1232                  j = i + 1, k = i)
1233             {
1234                 y = boxes[i].pBox->y1;
1235                 while ((j < nrects) && (boxes[j].pBox->y1 == y))
1236                 {
1237                     j++;
1238                 }
1239                 for (j--; j >= k; j--, i++)
1240                 {
1241                     sequence[i] = j;
1242                 }
1243             }
1244         }
1245     }
1246     else
1247     {
1248         /*
1249          * Scroll down. Must reverse vertical banding, at least.
1250          */
1251         if (dstx < srcx)
1252         {
1253             /*
1254              * Scroll left. Horizontal order is ok.
1255              */
1256             for (i = nrects - 1, j = i - 1, k = i, l = 0;
1257                  i >= 0;
1258                  j = i - 1, k = i)
1259             {
1260                 /*
1261                  * Find extent of current horizontal band, then reverse
1262                  * the order of the whole band.
1263                  */
1264                 y = boxes[i].pBox->y1;
1265                 while ((j >= 0) && (boxes[j].pBox->y1 == y))
1266                 {
1267                     j--;
1268                 }
1269                 for (j++; j <= k; j++, i--, l++)
1270                 {
1271                     sequence[l] = j;
1272                 }
1273             }
1274         }
1275         else
1276         {
1277             /*
1278              * Scroll right or horizontal stationary.
1279              * Reverse horizontal order as well (if stationary, horizontal
1280              * order can be swapped without penalty and this is faster
1281              * to compute).
1282              */
1283             for (i = 0, j = nrects - 1; i < nrects; i++, j--)
1284             {
1285                 sequence[i] = j;
1286             }
1287         }
1288     }
1289             
1290     /*
1291      * XXX: To avoid getting multiple NoExpose events from this operation,
1292      * we turn OFF graphicsExposures in the gc and deal with any uncopied
1293      * areas later, if there's something not in backing-store.
1294      */
1295
1296     graphicsExposures = pGC->graphicsExposures;
1297     pGC->graphicsExposures = FALSE;
1298     
1299     dx = dstx - srcx;
1300     dy = dsty - srcy;
1301
1302     /*
1303      * Figure out which copy procedure to use from the backing GC. Note we
1304      * must do this because some implementations (sun's, e.g.) have
1305      * pBackingGC a fake GC with the real one below it, thus the devPriv for
1306      * pBackingGC won't be what the output library expects.
1307      */
1308     if (plane != 0)
1309     {
1310         pixCopyProc = pBackingGC->ops->CopyPlane;
1311     }
1312     else
1313     {
1314         pixCopyProc = pBackingGC->ops->CopyArea;
1315     }
1316     
1317     for (i = 0; i < nrects; i++)
1318     {
1319         pBox = boxes[sequence[i]].pBox;
1320         
1321         /*
1322          * If we're copying from the pixmap, we need to place its contents
1323          * onto the screen before scrolling the pixmap itself. If we're copying
1324          * from the window, we need to copy its contents into the pixmap before
1325          * we scroll the window itself.
1326          */
1327         if (boxes[sequence[i]].source == pix)
1328         {
1329             (void) (* copyProc) (pBackingDrawable, pWin, pGC,
1330                           pBox->x1 - pBackingStore->x,
1331                           pBox->y1 - pBackingStore->y,
1332                           pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
1333                           pBox->x1 + dx, pBox->y1 + dy, plane);
1334             (void) (* pixCopyProc) (pBackingDrawable, pBackingDrawable, pBackingGC,
1335                              pBox->x1 - pBackingStore->x,
1336                              pBox->y1 - pBackingStore->y,
1337                              pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
1338                              pBox->x1 + dx - pBackingStore->x,
1339                              pBox->y1 + dy - pBackingStore->y, plane);
1340         }
1341         else
1342         {
1343             (void) (* pixCopyProc) (pWin, pBackingDrawable, pBackingGC,
1344                              pBox->x1, pBox->y1,
1345                              pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
1346                              pBox->x1 + dx - pBackingStore->x,
1347                              pBox->y1 + dy - pBackingStore->y, plane);
1348             (void) (* copyProc) (pWin, pWin, pGC,
1349                           pBox->x1, pBox->y1,
1350                           pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
1351                           pBox->x1 + dx, pBox->y1 + dy, plane);
1352         }
1353     }
1354     DEALLOCATE_LOCAL(sequence);
1355     DEALLOCATE_LOCAL(boxes);
1356
1357     pGC->graphicsExposures = graphicsExposures;
1358     /*
1359      * Form union of rgnExp and rgnObs and see if covers entire area
1360      * to be copied.  Store the resultant region for miBSCopyArea
1361      * to return to dispatch which will send the appropriate expose
1362      * events.
1363      */
1364     REGION_UNION(pGC->pScreen, pRgnExp, pRgnExp, pRgnObs);
1365     box.x1 = srcx;
1366     box.x2 = srcx + w;
1367     box.y1 = srcy;
1368     box.y2 = srcy + h;
1369     if (RECT_IN_REGION(pGC->pScreen, pRgnExp, &box) == rgnIN)
1370     {
1371         REGION_EMPTY(pGC->pScreen, pRgnExp);
1372     }
1373     else
1374     {
1375         REGION_INVERSE( pGC->pScreen, pRgnExp, pRgnExp, &box);
1376         REGION_TRANSLATE( pGC->pScreen, pRgnExp,
1377                                            dx + pWin->drawable.x,
1378                                            dy + pWin->drawable.y);
1379         REGION_INTERSECT( pGC->pScreen, pRgnObs, pRgnExp, &pWin->clipList);
1380         (*pWin->drawable.pScreen->PaintWindowBackground) (pWin,
1381                                                 pRgnObs, PW_BACKGROUND);
1382         REGION_TRANSLATE( pGC->pScreen, pRgnExp,
1383                                            -pWin->drawable.x,
1384                                            -pWin->drawable.y);
1385         miBSClearBackingRegion (pWin, pRgnExp);
1386     }
1387     if (graphicsExposures)
1388         *ppRgn = pRgnExp;
1389     else
1390         REGION_DESTROY(pGC->pScreen, pRgnExp);
1391     REGION_DESTROY(pGC->pScreen, pRgnObs);
1392
1393     return (TRUE);
1394 }
1395
1396 /*-
1397  *-----------------------------------------------------------------------
1398  * miBSCopyArea --
1399  *      Perform a CopyArea from the source to the destination, extracting
1400  *      from the source's backing-store and storing into the destination's
1401  *      backing-store without messing anything up. If the source and
1402  *      destination are different, there's not too much to worry about:
1403  *      we can just issue several calls to the regular CopyArea function.
1404  *
1405  * Results:
1406  *      None.
1407  *
1408  * Side Effects:
1409  *
1410  *-----------------------------------------------------------------------
1411  */
1412 static RegionPtr
1413 miBSCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty)
1414     DrawablePtr   pSrc;
1415     DrawablePtr   pDst;
1416     GCPtr         pGC;
1417     int           srcx;
1418     int           srcy;
1419     int           w;
1420     int           h;
1421     int           dstx;
1422     int           dsty;
1423 {
1424     BoxPtr      pExtents;
1425     long        dx, dy;
1426     int         bsrcx, bsrcy, bw, bh, bdstx, bdsty;
1427     RegionPtr   pixExposed = 0, winExposed = 0;
1428
1429     SETUP_BACKING(pDst, pGC);
1430
1431     PROLOGUE(pGC);
1432
1433     if ((pSrc != pDst) ||
1434         (!miBSDoCopy((WindowPtr)pSrc, pGC, srcx, srcy, w, h, dstx, dsty,
1435                      (unsigned long) 0, pGC->ops->CopyArea, &winExposed)))
1436     {
1437         /*
1438          * always copy to the backing store first, miBSDoCopy
1439          * returns FALSE if the *source* region is disjoint
1440          * from the backing store saved region.  So, copying
1441          * *to* the backing store is always safe
1442          */
1443         if (pGC->clientClipType != CT_PIXMAP)
1444         {
1445             /*
1446              * adjust srcx, srcy, w, h, dstx, dsty to be clipped to
1447              * the backing store.  An unnecessary optimisation,
1448              * but a useful one when GetSpans is slow.
1449              */
1450             pExtents = REGION_EXTENTS(pDst->pScreen,
1451                                       (RegionPtr)pBackingGC->clientClip);
1452             bsrcx = srcx;
1453             bsrcy = srcy;
1454             bw = w;
1455             bh = h;
1456             bdstx = dstx;
1457             bdsty = dsty;
1458             dx = pExtents->x1 - bdstx;
1459             if (dx > 0)
1460             {
1461                 bsrcx += dx;
1462                 bdstx += dx;
1463                 bw -= dx;
1464             }
1465             dy = pExtents->y1 - bdsty;
1466             if (dy > 0)
1467             {
1468                 bsrcy += dy;
1469                 bdsty += dy;
1470                 bh -= dy;
1471             }
1472             dx = (bdstx + bw) - pExtents->x2;
1473             if (dx > 0)
1474                 bw -= dx;
1475             dy = (bdsty + bh) - pExtents->y2;
1476             if (dy > 0)
1477                 bh -= dy;
1478             if (bw > 0 && bh > 0)
1479                 pixExposed = (* pBackingGC->ops->CopyArea) (pSrc, 
1480                             pBackingDrawable, pBackingGC, 
1481                             bsrcx, bsrcy, bw, bh, bdstx - pBackingStore->x,
1482                             bdsty - pBackingStore->y);
1483         }
1484         else
1485             pixExposed = (* pBackingGC->ops->CopyArea) (pSrc, 
1486                             pBackingDrawable, pBackingGC,
1487                             srcx, srcy, w, h,
1488                             dstx - pBackingStore->x, dsty - pBackingStore->y);
1489
1490         winExposed = (* pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
1491     }
1492
1493     /*
1494      * compute the composite graphics exposure region
1495      */
1496     if (winExposed)
1497     {
1498         if (pixExposed){
1499             REGION_UNION(pDst->pScreen, winExposed, winExposed, pixExposed);
1500             REGION_DESTROY(pDst->pScreen, pixExposed);
1501         }
1502     } else
1503         winExposed = pixExposed;
1504
1505     EPILOGUE (pGC);
1506
1507     return winExposed;
1508 }
1509
1510 /*-
1511  *-----------------------------------------------------------------------
1512  * miBSCopyPlane --
1513  *
1514  * Results:
1515  *      None.
1516  *
1517  * Side Effects:
1518  *
1519  *-----------------------------------------------------------------------
1520  */
1521 static RegionPtr
1522 miBSCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane)
1523     DrawablePtr   pSrc;
1524     DrawablePtr   pDst;
1525     register GC   *pGC;
1526     int           srcx,
1527                   srcy;
1528     int           w,
1529                   h;
1530     int           dstx,
1531                   dsty;
1532     unsigned long  plane;
1533 {
1534     BoxPtr      pExtents;
1535     long        dx, dy;
1536     int         bsrcx, bsrcy, bw, bh, bdstx, bdsty;
1537     RegionPtr   winExposed = 0, pixExposed = 0;
1538     SETUP_BACKING(pDst, pGC);
1539
1540     PROLOGUE(pGC);
1541
1542     if ((pSrc != pDst) ||
1543         (!miBSDoCopy((WindowPtr)pSrc, pGC, srcx, srcy, w, h, dstx, dsty,
1544                      plane,  pGC->ops->CopyPlane, &winExposed)))
1545     {
1546         /*
1547          * always copy to the backing store first, miBSDoCopy
1548          * returns FALSE if the *source* region is disjoint
1549          * from the backing store saved region.  So, copying
1550          * *to* the backing store is always safe
1551          */
1552         if (pGC->clientClipType != CT_PIXMAP)
1553         {
1554             /*
1555              * adjust srcx, srcy, w, h, dstx, dsty to be clipped to
1556              * the backing store.  An unnecessary optimisation,
1557              * but a useful one when GetSpans is slow.
1558              */
1559             pExtents = REGION_EXTENTS(pDst->pScreen,
1560                                       (RegionPtr)pBackingGC->clientClip);
1561             bsrcx = srcx;
1562             bsrcy = srcy;
1563             bw = w;
1564             bh = h;
1565             bdstx = dstx;
1566             bdsty = dsty;
1567             dx = pExtents->x1 - bdstx;
1568             if (dx > 0)
1569             {
1570                 bsrcx += dx;
1571                 bdstx += dx;
1572                 bw -= dx;
1573             }
1574             dy = pExtents->y1 - bdsty;
1575             if (dy > 0)
1576             {
1577                 bsrcy += dy;
1578                 bdsty += dy;
1579                 bh -= dy;
1580             }
1581             dx = (bdstx + bw) - pExtents->x2;
1582             if (dx > 0)
1583                 bw -= dx;
1584             dy = (bdsty + bh) - pExtents->y2;
1585             if (dy > 0)
1586                 bh -= dy;
1587             if (bw > 0 && bh > 0)
1588                 pixExposed = (* pBackingGC->ops->CopyPlane) (pSrc, 
1589                                     pBackingDrawable,
1590                                     pBackingGC, bsrcx, bsrcy, bw, bh,
1591                                     bdstx - pBackingStore->x,
1592                                     bdsty - pBackingStore->y, plane);
1593         }
1594         else
1595             pixExposed = (* pBackingGC->ops->CopyPlane) (pSrc, 
1596                                     pBackingDrawable,
1597                                     pBackingGC, srcx, srcy, w, h,
1598                                     dstx - pBackingStore->x,
1599                                     dsty - pBackingStore->y, plane);
1600
1601         winExposed = (* pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
1602                               dstx, dsty, plane);
1603         
1604     }
1605
1606     /*
1607      * compute the composite graphics exposure region
1608      */
1609     if (winExposed)
1610     {
1611         if (pixExposed)
1612         {
1613             REGION_UNION(pDst->pScreen, winExposed, winExposed, pixExposed);
1614             REGION_DESTROY(pDst->pScreen, pixExposed);
1615         }
1616     } else
1617         winExposed = pixExposed;
1618
1619     EPILOGUE (pGC);
1620
1621     return winExposed;
1622 }
1623
1624 /*-
1625  *-----------------------------------------------------------------------
1626  * miBSPolyPoint --
1627  *      Perform a PolyPoint, routing output to backing-store as needed.
1628  *
1629  * Results:
1630  *      None.
1631  *
1632  * Side Effects:
1633  *
1634  *-----------------------------------------------------------------------
1635  */
1636 static void
1637 miBSPolyPoint (pDrawable, pGC, mode, npt, pptInit)
1638     DrawablePtr pDrawable;
1639     GCPtr       pGC;
1640     int         mode;           /* Origin or Previous */
1641     int         npt;
1642     xPoint      *pptInit;
1643 {
1644     xPoint        *pptCopy;
1645     SETUP_BACKING (pDrawable, pGC);
1646
1647     PROLOGUE(pGC);
1648
1649     pptCopy = (xPoint *)ALLOCATE_LOCAL(npt*sizeof(xPoint));
1650     if (pptCopy)
1651     {
1652         copyPoints(pptInit, pptCopy, npt, mode);
1653
1654         (* pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pptInit);
1655
1656         (* pBackingGC->ops->PolyPoint) (pBackingDrawable,
1657                                    pBackingGC, mode, npt, pptCopy);
1658
1659         DEALLOCATE_LOCAL(pptCopy);
1660     }
1661
1662     EPILOGUE (pGC);
1663 }
1664
1665 /*-
1666  *-----------------------------------------------------------------------
1667  * miBSPolyLines --
1668  *      Perform a Polylines, routing output to backing-store as needed.
1669  *
1670  * Results:
1671  *
1672  * Side Effects:
1673  *
1674  *-----------------------------------------------------------------------
1675  */
1676 static void
1677 miBSPolylines (pDrawable, pGC, mode, npt, pptInit)
1678     DrawablePtr   pDrawable;
1679     GCPtr         pGC;
1680     int           mode;
1681     int           npt;
1682     DDXPointPtr   pptInit;
1683 {
1684     DDXPointPtr pptCopy;
1685     SETUP_BACKING (pDrawable, pGC);
1686
1687     PROLOGUE(pGC);
1688
1689     pptCopy = (DDXPointPtr)ALLOCATE_LOCAL(npt*sizeof(DDXPointRec));
1690     if (pptCopy)
1691     {
1692         copyPoints(pptInit, pptCopy, npt, mode);
1693
1694         (* pGC->ops->Polylines)(pDrawable, pGC, mode, npt, pptInit);
1695         (* pBackingGC->ops->Polylines)(pBackingDrawable,
1696                                   pBackingGC, mode, npt, pptCopy);
1697         DEALLOCATE_LOCAL(pptCopy);
1698     }
1699
1700     EPILOGUE (pGC);
1701 }
1702
1703 /*-
1704  *-----------------------------------------------------------------------
1705  * miBSPolySegment --
1706  *      Perform a PolySegment, routing output to backing-store as needed.
1707  *
1708  * Results:
1709  *      None.
1710  *
1711  * Side Effects:
1712  *
1713  *-----------------------------------------------------------------------
1714  */
1715 static void
1716 miBSPolySegment(pDrawable, pGC, nseg, pSegs)
1717     DrawablePtr pDrawable;
1718     GCPtr       pGC;
1719     int         nseg;
1720     xSegment    *pSegs;
1721 {
1722     xSegment    *pSegsCopy;
1723
1724     SETUP_BACKING (pDrawable, pGC);
1725
1726     PROLOGUE(pGC);
1727
1728     pSegsCopy = (xSegment *)ALLOCATE_LOCAL(nseg*sizeof(xSegment));
1729     if (pSegsCopy)
1730     {
1731         copyData(pSegs, pSegsCopy, nseg << 1, MoreCopy0);
1732
1733         (* pGC->ops->PolySegment)(pDrawable, pGC, nseg, pSegs);
1734         (* pBackingGC->ops->PolySegment)(pBackingDrawable,
1735                                     pBackingGC, nseg, pSegsCopy);
1736
1737         DEALLOCATE_LOCAL(pSegsCopy);
1738     }
1739
1740     EPILOGUE (pGC);
1741 }
1742
1743 /*-
1744  *-----------------------------------------------------------------------
1745  * miBSPolyRectangle --
1746  *      Perform a PolyRectangle, routing output to backing-store as needed.
1747  *
1748  * Results:
1749  *      None
1750  *
1751  * Side Effects:
1752  *
1753  *-----------------------------------------------------------------------
1754  */
1755 static void
1756 miBSPolyRectangle(pDrawable, pGC, nrects, pRects)
1757     DrawablePtr pDrawable;
1758     GCPtr       pGC;
1759     int         nrects;
1760     xRectangle  *pRects;
1761 {
1762     xRectangle  *pRectsCopy;
1763     SETUP_BACKING (pDrawable, pGC);
1764
1765     PROLOGUE(pGC);
1766
1767     pRectsCopy =(xRectangle *)ALLOCATE_LOCAL(nrects*sizeof(xRectangle));
1768     if (pRectsCopy)
1769     {
1770         copyData(pRects, pRectsCopy, nrects, MoreCopy2);
1771
1772         (* pGC->ops->PolyRectangle)(pDrawable, pGC, nrects, pRects);
1773         (* pBackingGC->ops->PolyRectangle)(pBackingDrawable,
1774                                       pBackingGC, nrects, pRectsCopy);
1775
1776         DEALLOCATE_LOCAL(pRectsCopy);
1777     }
1778
1779     EPILOGUE (pGC);
1780 }
1781
1782 /*-
1783  *-----------------------------------------------------------------------
1784  * miBSPolyArc --
1785  *      Perform a PolyArc, routing output to backing-store as needed.
1786  *
1787  * Results:
1788  *
1789  * Side Effects:
1790  *
1791  *-----------------------------------------------------------------------
1792  */
1793 static void
1794 miBSPolyArc(pDrawable, pGC, narcs, parcs)
1795     DrawablePtr pDrawable;
1796     GCPtr       pGC;
1797     int         narcs;
1798     xArc        *parcs;
1799 {
1800     xArc  *pArcsCopy;
1801     SETUP_BACKING (pDrawable, pGC);
1802
1803     PROLOGUE(pGC);
1804
1805     pArcsCopy = (xArc *)ALLOCATE_LOCAL(narcs*sizeof(xArc));
1806     if (pArcsCopy)
1807     {
1808         copyData(parcs, pArcsCopy, narcs, MoreCopy4);
1809
1810         (* pGC->ops->PolyArc)(pDrawable, pGC, narcs, parcs);
1811         (* pBackingGC->ops->PolyArc)(pBackingDrawable, pBackingGC,
1812                                 narcs, pArcsCopy);
1813
1814         DEALLOCATE_LOCAL(pArcsCopy);
1815     }
1816
1817     EPILOGUE (pGC);
1818 }
1819
1820 /*-
1821  *-----------------------------------------------------------------------
1822  * miBSFillPolygon --
1823  *      Perform a FillPolygon, routing output to backing-store as needed.
1824  *
1825  * Results:
1826  *      None.
1827  *
1828  * Side Effects:
1829  *
1830  *-----------------------------------------------------------------------
1831  */
1832 static void
1833 miBSFillPolygon(pDrawable, pGC, shape, mode, count, pPts)
1834     DrawablePtr         pDrawable;
1835     register GCPtr      pGC;
1836     int                 shape, mode;
1837     register int        count;
1838     DDXPointPtr         pPts;
1839 {
1840     DDXPointPtr pPtsCopy;
1841     SETUP_BACKING (pDrawable, pGC);
1842
1843     PROLOGUE(pGC);
1844
1845     pPtsCopy = (DDXPointPtr)ALLOCATE_LOCAL(count*sizeof(DDXPointRec));
1846     if (pPtsCopy)
1847     {
1848         copyPoints(pPts, pPtsCopy, count, mode);
1849         (* pGC->ops->FillPolygon)(pDrawable, pGC, shape, mode, count, pPts);
1850         (* pBackingGC->ops->FillPolygon)(pBackingDrawable,
1851                                     pBackingGC, shape, mode,
1852                                     count, pPtsCopy);
1853
1854         DEALLOCATE_LOCAL(pPtsCopy);
1855     }
1856
1857     EPILOGUE (pGC);
1858 }
1859
1860 /*-
1861  *-----------------------------------------------------------------------
1862  * miBSPolyFillRect --
1863  *      Perform a PolyFillRect, routing output to backing-store as needed.
1864  *
1865  * Results:
1866  *      None.
1867  *
1868  * Side Effects:
1869  *
1870  *-----------------------------------------------------------------------
1871  */
1872 static void
1873 miBSPolyFillRect(pDrawable, pGC, nrectFill, prectInit)
1874     DrawablePtr pDrawable;
1875     GCPtr       pGC;
1876     int         nrectFill;      /* number of rectangles to fill */
1877     xRectangle  *prectInit;     /* Pointer to first rectangle to fill */
1878 {
1879     xRectangle  *pRectCopy;
1880     SETUP_BACKING (pDrawable, pGC);
1881
1882     PROLOGUE(pGC);
1883
1884     pRectCopy =
1885         (xRectangle *)ALLOCATE_LOCAL(nrectFill*sizeof(xRectangle));
1886     if (pRectCopy)
1887     {
1888         copyData(prectInit, pRectCopy, nrectFill, MoreCopy2);
1889
1890         (* pGC->ops->PolyFillRect)(pDrawable, pGC, nrectFill, prectInit);
1891         (* pBackingGC->ops->PolyFillRect)(pBackingDrawable,
1892                                      pBackingGC, nrectFill, pRectCopy);
1893
1894         DEALLOCATE_LOCAL(pRectCopy);
1895     }
1896
1897     EPILOGUE (pGC);
1898 }
1899
1900 /*-
1901  *-----------------------------------------------------------------------
1902  * miBSPolyFillArc --
1903  *      Perform a PolyFillArc, routing output to backing-store as needed.
1904  *
1905  * Results:
1906  *      None.
1907  *
1908  * Side Effects:
1909  *
1910  *-----------------------------------------------------------------------
1911  */
1912 static void
1913 miBSPolyFillArc(pDrawable, pGC, narcs, parcs)
1914     DrawablePtr pDrawable;
1915     GCPtr       pGC;
1916     int         narcs;
1917     xArc        *parcs;
1918 {
1919     xArc  *pArcsCopy;
1920     SETUP_BACKING (pDrawable, pGC);
1921
1922     PROLOGUE(pGC);
1923
1924     pArcsCopy = (xArc *)ALLOCATE_LOCAL(narcs*sizeof(xArc));
1925     if (pArcsCopy)
1926     {
1927         copyData(parcs, pArcsCopy, narcs, MoreCopy4);
1928         (* pGC->ops->PolyFillArc)(pDrawable, pGC, narcs, parcs);
1929         (* pBackingGC->ops->PolyFillArc)(pBackingDrawable,
1930                                     pBackingGC, narcs, pArcsCopy);
1931         DEALLOCATE_LOCAL(pArcsCopy);
1932     }
1933
1934     EPILOGUE (pGC);
1935 }
1936
1937
1938 /*-
1939  *-----------------------------------------------------------------------
1940  * miBSPolyText8 --
1941  *      Perform a PolyText8, routing output to backing-store as needed.
1942  *
1943  * Results:
1944  *
1945  * Side Effects:
1946  *
1947  *-----------------------------------------------------------------------
1948  */
1949 static int
1950 miBSPolyText8(pDrawable, pGC, x, y, count, chars)
1951     DrawablePtr pDrawable;
1952     GCPtr       pGC;
1953     int         x, y;
1954     int         count;
1955     char        *chars;
1956 {
1957     int     result;
1958     SETUP_BACKING (pDrawable, pGC);
1959
1960     PROLOGUE(pGC);
1961
1962     result = (* pGC->ops->PolyText8)(pDrawable, pGC, x, y, count, chars);
1963     (* pBackingGC->ops->PolyText8)(pBackingDrawable, pBackingGC,
1964                                    x - pBackingStore->x, y - pBackingStore->y,
1965                                    count, chars);
1966
1967     EPILOGUE (pGC);
1968     return result;
1969 }
1970
1971 /*-
1972  *-----------------------------------------------------------------------
1973  * miBSPolyText16 --
1974  *      Perform a PolyText16, routing output to backing-store as needed.
1975  *
1976  * Results:
1977  *
1978  * Side Effects:
1979  *
1980  *-----------------------------------------------------------------------
1981  */
1982 static int
1983 miBSPolyText16(pDrawable, pGC, x, y, count, chars)
1984     DrawablePtr pDrawable;
1985     GCPtr       pGC;
1986     int         x, y;
1987     int         count;
1988     unsigned short *chars;
1989 {
1990     int result;
1991     SETUP_BACKING (pDrawable, pGC);
1992
1993     PROLOGUE(pGC);
1994
1995     result = (* pGC->ops->PolyText16)(pDrawable, pGC, x, y, count, chars);
1996     (* pBackingGC->ops->PolyText16)(pBackingDrawable, pBackingGC,
1997                                     x - pBackingStore->x, y - pBackingStore->y,
1998                                     count, chars);
1999
2000     EPILOGUE (pGC);
2001
2002     return result;
2003 }
2004
2005 /*-
2006  *-----------------------------------------------------------------------
2007  * miBSImageText8 --
2008  *      Perform a ImageText8, routing output to backing-store as needed.
2009  *
2010  * Results:
2011  *
2012  * Side Effects:
2013  *
2014  *-----------------------------------------------------------------------
2015  */
2016 static void
2017 miBSImageText8(pDrawable, pGC, x, y, count, chars)
2018     DrawablePtr pDrawable;
2019     GCPtr       pGC;
2020     int         x, y;
2021     int         count;
2022     char        *chars;
2023 {
2024     SETUP_BACKING (pDrawable, pGC);
2025     PROLOGUE(pGC);
2026
2027     (* pGC->ops->ImageText8)(pDrawable, pGC, x, y, count, chars);
2028     (* pBackingGC->ops->ImageText8)(pBackingDrawable, pBackingGC,
2029                                     x - pBackingStore->x, y - pBackingStore->y,
2030                                     count, chars);
2031
2032     EPILOGUE (pGC);
2033 }
2034
2035 /*-
2036  *-----------------------------------------------------------------------
2037  * miBSImageText16 --
2038  *      Perform a ImageText16, routing output to backing-store as needed.
2039  *
2040  * Results:
2041  *
2042  * Side Effects:
2043  *
2044  *-----------------------------------------------------------------------
2045  */
2046 static void
2047 miBSImageText16(pDrawable, pGC, x, y, count, chars)
2048     DrawablePtr pDrawable;
2049     GCPtr       pGC;
2050     int         x, y;
2051     int         count;
2052     unsigned short *chars;
2053 {
2054     SETUP_BACKING (pDrawable, pGC);
2055     PROLOGUE(pGC);
2056
2057     (* pGC->ops->ImageText16)(pDrawable, pGC, x, y, count, chars);
2058     (* pBackingGC->ops->ImageText16)(pBackingDrawable, pBackingGC,
2059                                     x - pBackingStore->x, y - pBackingStore->y,
2060                                      count, chars);
2061
2062     EPILOGUE (pGC);
2063 }
2064
2065 /*-
2066  *-----------------------------------------------------------------------
2067  * miBSImageGlyphBlt --
2068  *      Perform a ImageGlyphBlt, routing output to backing-store as needed.
2069  *
2070  * Results:
2071  *
2072  * Side Effects:
2073  *
2074  *-----------------------------------------------------------------------
2075  */
2076 static void
2077 miBSImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
2078     DrawablePtr pDrawable;
2079     GCPtr       pGC;
2080     int         x, y;
2081     unsigned int nglyph;
2082     CharInfoPtr *ppci;          /* array of character info */
2083     pointer     pglyphBase;     /* start of array of glyphs */
2084 {
2085     SETUP_BACKING (pDrawable, pGC);
2086     PROLOGUE(pGC);
2087
2088     (* pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, nglyph, ppci,
2089                              pglyphBase);
2090     (* pBackingGC->ops->ImageGlyphBlt)(pBackingDrawable, pBackingGC,
2091                                     x - pBackingStore->x, y - pBackingStore->y,
2092                                        nglyph, ppci, pglyphBase);
2093
2094     EPILOGUE (pGC);
2095 }
2096
2097 /*-
2098  *-----------------------------------------------------------------------
2099  * miBSPolyGlyphBlt --
2100  *      Perform a PolyGlyphBlt, routing output to backing-store as needed.
2101  *
2102  * Results:
2103  *
2104  * Side Effects:
2105  *
2106  *-----------------------------------------------------------------------
2107  */
2108 static void
2109 miBSPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
2110     DrawablePtr pDrawable;
2111     GCPtr       pGC;
2112     int         x, y;
2113     unsigned int nglyph;
2114     CharInfoPtr *ppci;          /* array of character info */
2115     pointer     pglyphBase;     /* start of array of glyphs */
2116 {
2117     SETUP_BACKING (pDrawable, pGC);
2118     PROLOGUE(pGC);
2119
2120     (* pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph,
2121                             ppci, pglyphBase);
2122     (* pBackingGC->ops->PolyGlyphBlt)(pBackingDrawable, pBackingGC,
2123                                     x - pBackingStore->x, y - pBackingStore->y,
2124                                       nglyph, ppci, pglyphBase);
2125     EPILOGUE (pGC);
2126 }
2127
2128 /*-
2129  *-----------------------------------------------------------------------
2130  * miBSPushPixels --
2131  *      Perform a PushPixels, routing output to backing-store as needed.
2132  *
2133  * Results:
2134  *
2135  * Side Effects:
2136  *
2137  *-----------------------------------------------------------------------
2138  */
2139 static void
2140 miBSPushPixels(pGC, pBitMap, pDst, w, h, x, y)
2141     GCPtr       pGC;
2142     PixmapPtr   pBitMap;
2143     DrawablePtr pDst;
2144     int         w, h, x, y;
2145 {
2146     SETUP_BACKING (pDst, pGC);
2147     PROLOGUE(pGC);
2148
2149     (* pGC->ops->PushPixels)(pGC, pBitMap, pDst, w, h, x, y);
2150     if (pGC->miTranslate) {
2151         x -= pDst->x;
2152         y -= pDst->y;
2153     }
2154     (* pBackingGC->ops->PushPixels)(pBackingGC, pBitMap,
2155                                pBackingDrawable, w, h,
2156                                x - pBackingStore->x, y - pBackingStore->y);
2157
2158     EPILOGUE (pGC);
2159 }
2160
2161 #ifdef NEED_LINEHELPER
2162 /*-
2163  *-----------------------------------------------------------------------
2164  * miBSLineHelper --
2165  *
2166  * Results: should never be called
2167  *
2168  * Side Effects: server dies
2169  *
2170  *-----------------------------------------------------------------------
2171  */
2172 static void
2173 miBSLineHelper()
2174 {
2175     FatalError("miBSLineHelper called\n");
2176 }
2177 #endif
2178
2179 /*-
2180  *-----------------------------------------------------------------------
2181  * miBSClearBackingStore --
2182  *      Clear the given area of the backing pixmap with the background of
2183  *      the window, whatever it is. If generateExposures is TRUE, generate
2184  *      exposure events for the area. Note that if the area has any
2185  *      part outside the saved portions of the window, we do not allow the
2186  *      count in the expose events to be 0, since there will be more
2187  *      expose events to come.
2188  *
2189  * Results:
2190  *      None.
2191  *
2192  * Side Effects:
2193  *      Areas of pixmap are cleared and Expose events are generated.
2194  *
2195  *-----------------------------------------------------------------------
2196  */
2197 static RegionPtr
2198 miBSClearBackingStore(pWin, x, y, w, h, generateExposures)
2199     WindowPtr           pWin;
2200     int                 x;
2201     int                 y;
2202     int                 w;
2203     int                 h;
2204     Bool                generateExposures;
2205 {
2206     RegionPtr           pRgn;
2207     int                 i;
2208     miBSWindowPtr       pBackingStore;
2209     ScreenPtr           pScreen;
2210     GCPtr               pGC;
2211     int                 ts_x_origin,
2212                         ts_y_origin;
2213     pointer             gcvalues[4];
2214     unsigned long       gcmask;
2215     xRectangle          *rects;
2216     BoxPtr              pBox;
2217     BoxRec              box;
2218     PixUnion            background;
2219     char                backgroundState;
2220     int                 numRects;
2221
2222     pBackingStore = (miBSWindowPtr)pWin->backStorage;
2223     pScreen = pWin->drawable.pScreen;
2224
2225     if ((pBackingStore->status == StatusNoPixmap) ||
2226         (pBackingStore->status == StatusBadAlloc))
2227         return NullRegion;
2228     
2229     if (w == 0)
2230         w = (int) pWin->drawable.width - x;
2231     if (h == 0)
2232         h = (int) pWin->drawable.height - y;
2233
2234     box.x1 = x;
2235     box.y1 = y;
2236     box.x2 = x + w;
2237     box.y2 = y + h;
2238     pRgn = REGION_CREATE(pWin->drawable.pScreen, &box, 1);
2239     if (!pRgn)
2240         return NullRegion;
2241     REGION_INTERSECT( pScreen, pRgn, pRgn, &pBackingStore->SavedRegion);
2242
2243     if (REGION_NOTEMPTY( pScreen, pRgn))
2244     {
2245         /*
2246          * if clearing entire window, simply make new virtual
2247          * tile.  For the root window, we also destroy the pixmap
2248          * to save a pile of memory
2249          */
2250         if (x == 0 && y == 0 &&
2251             w == pWin->drawable.width &&
2252             h == pWin->drawable.height)
2253         {
2254             if (!pWin->parent)
2255                 miDestroyBSPixmap (pWin);
2256             if (pBackingStore->status != StatusContents)
2257                  miTileVirtualBS (pWin);
2258         }
2259
2260         ts_x_origin = ts_y_origin = 0;
2261
2262         backgroundState = pWin->backgroundState;
2263         background = pWin->background;
2264         if (backgroundState == ParentRelative) {
2265             WindowPtr   pParent;
2266
2267             pParent = pWin;
2268             while (pParent->backgroundState == ParentRelative) {
2269                 ts_x_origin -= pParent->origin.x;
2270                 ts_y_origin -= pParent->origin.y;
2271                 pParent = pParent->parent;
2272             }
2273             backgroundState = pParent->backgroundState;
2274             background = pParent->background;
2275         }
2276
2277         if ((backgroundState != None) &&
2278             ((pBackingStore->status == StatusContents) ||
2279              !SameBackground (pBackingStore->backgroundState,
2280                               pBackingStore->background,
2281                               backgroundState,
2282                               background)))
2283         {
2284             if (!pBackingStore->pBackingPixmap)
2285                 miCreateBSPixmap(pWin, NullBox);
2286
2287             pGC = GetScratchGC(pWin->drawable.depth, pScreen);
2288             if (pGC && pBackingStore->pBackingPixmap)
2289             {
2290                 /*
2291                  * First take care of any ParentRelative stuff by altering the
2292                  * tile/stipple origin to match the coordinates of the upper-left
2293                  * corner of the first ancestor without a ParentRelative background.
2294                  * This coordinate is, of course, negative.
2295                  */
2296             
2297                 if (backgroundState == BackgroundPixel)
2298                 {
2299                     gcvalues[0] = (pointer) background.pixel;
2300                     gcvalues[1] = (pointer)FillSolid;
2301                     gcmask = GCForeground|GCFillStyle;
2302                 }
2303                 else
2304                 {
2305                     gcvalues[0] = (pointer)FillTiled;
2306                     gcvalues[1] = (pointer) background.pixmap;
2307                     gcmask = GCFillStyle|GCTile;
2308                 }
2309                 gcvalues[2] = (pointer)(ts_x_origin - pBackingStore->x);
2310                 gcvalues[3] = (pointer)(ts_y_origin - pBackingStore->y);
2311                 gcmask |= GCTileStipXOrigin|GCTileStipYOrigin;
2312                 DoChangeGC(pGC, gcmask, (XID *)gcvalues, TRUE);
2313                 ValidateGC((DrawablePtr)pBackingStore->pBackingPixmap, pGC);
2314     
2315                 /*
2316                  * Figure out the array of rectangles to fill and fill them with
2317                  * PolyFillRect in the proper mode, as set in the GC above.
2318                  */
2319                 numRects = REGION_NUM_RECTS(pRgn);
2320                 rects = (xRectangle *)ALLOCATE_LOCAL(numRects*sizeof(xRectangle));
2321             
2322                 if (rects)
2323                 {
2324                     for (i = 0, pBox = REGION_RECTS(pRgn);
2325                          i < numRects;
2326                          i++, pBox++)
2327                     {
2328                         rects[i].x = pBox->x1 - pBackingStore->x;
2329                         rects[i].y = pBox->y1 - pBackingStore->y;
2330                         rects[i].width = pBox->x2 - pBox->x1;
2331                         rects[i].height = pBox->y2 - pBox->y1;
2332                     }
2333                     (* pGC->ops->PolyFillRect) (
2334                                 (DrawablePtr)pBackingStore->pBackingPixmap,
2335                                        pGC, numRects, rects);
2336                     DEALLOCATE_LOCAL(rects);
2337                 }       
2338                 FreeScratchGC(pGC);
2339             }
2340         }       
2341
2342         if (!generateExposures)
2343         {
2344             REGION_DESTROY(pScreen, pRgn);
2345             pRgn = NULL;
2346         }
2347         else
2348         {
2349             /*
2350              * result must be screen relative, but is currently
2351              * drawable relative.
2352              */
2353             REGION_TRANSLATE(pScreen, pRgn, pWin->drawable.x,
2354                              pWin->drawable.y);
2355         }
2356     }
2357     else
2358     {
2359         REGION_DESTROY( pScreen, pRgn);
2360         pRgn = NULL;
2361     }
2362     return pRgn;
2363 }
2364
2365 static void
2366 miBSClearBackingRegion (pWin, pRgn)
2367     WindowPtr   pWin;
2368     RegionPtr   pRgn;
2369 {
2370     BoxPtr      pBox;
2371     int         i;
2372
2373     i = REGION_NUM_RECTS(pRgn);
2374     pBox = REGION_RECTS(pRgn);
2375     while (i--)
2376     {
2377         (void) miBSClearBackingStore(pWin, pBox->x1, pBox->y1,
2378                                         pBox->x2 - pBox->x1,
2379                                         pBox->y2 - pBox->y1,
2380                                         FALSE);
2381         pBox++;
2382     }
2383 }
2384
2385 /*
2386  * fill a region of the destination with virtual bits
2387  *
2388  * pRgn is to be translated by (x,y)
2389  */
2390
2391 static void
2392 miBSFillVirtualBits (pDrawable, pGC, pRgn, x, y, state, pixunion, planeMask)
2393     DrawablePtr         pDrawable;
2394     GCPtr               pGC;
2395     RegionPtr           pRgn;
2396     int                 x, y;
2397     int                 state;
2398     PixUnion            pixunion;
2399     unsigned long       planeMask;
2400 {
2401     int         i;
2402     BITS32      gcmask;
2403     pointer     gcval[5];
2404     xRectangle  *pRect;
2405     BoxPtr      pBox;
2406     WindowPtr   pWin;
2407     int         numRects;
2408
2409     if (state == None)
2410         return;
2411     numRects = REGION_NUM_RECTS(pRgn);
2412     pRect = (xRectangle *)ALLOCATE_LOCAL(numRects * sizeof(xRectangle));
2413     if (!pRect)
2414         return;
2415     pWin = 0;
2416     if (pDrawable->type != DRAWABLE_PIXMAP)
2417     {
2418         pWin = (WindowPtr) pDrawable;
2419         if (!pWin->backStorage)
2420             pWin = 0;
2421     }
2422     i = 0;
2423     gcmask = 0;
2424     gcval[i++] = (pointer)planeMask;
2425     gcmask |= GCPlaneMask;
2426     if (state == BackgroundPixel)
2427     {
2428         if (pGC->fgPixel != pixunion.pixel)
2429         {
2430             gcval[i++] = (pointer)pixunion.pixel;
2431             gcmask |= GCForeground;
2432         }
2433         if (pGC->fillStyle != FillSolid)
2434         {
2435             gcval[i++] = (pointer)FillSolid;
2436             gcmask |= GCFillStyle;
2437         }
2438     }
2439     else
2440     {
2441         if (pGC->fillStyle != FillTiled)
2442         {
2443             gcval[i++] = (pointer)FillTiled;
2444             gcmask |= GCFillStyle;
2445         }
2446         if (pGC->tileIsPixel || pGC->tile.pixmap != pixunion.pixmap)
2447         {
2448             gcval[i++] = (pointer)pixunion.pixmap;
2449             gcmask |= GCTile;
2450         }
2451         if (pGC->patOrg.x != x)
2452         {
2453             gcval[i++] = (pointer)x;
2454             gcmask |= GCTileStipXOrigin;
2455         }
2456         if (pGC->patOrg.y != y)
2457         {
2458             gcval[i++] = (pointer)y;
2459             gcmask |= GCTileStipYOrigin;
2460         }
2461     }
2462     if (gcmask)
2463         DoChangeGC (pGC, gcmask, (XID *)gcval, 1);
2464
2465     if (pWin)
2466         (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack);
2467
2468     if (pDrawable->serialNumber != pGC->serialNumber)
2469         ValidateGC (pDrawable, pGC);
2470
2471     pBox = REGION_RECTS(pRgn);
2472     for (i = numRects; --i >= 0; pBox++, pRect++)
2473     {
2474         pRect->x = pBox->x1 + x;
2475         pRect->y = pBox->y1 + y;
2476         pRect->width = pBox->x2 - pBox->x1;
2477         pRect->height = pBox->y2 - pBox->y1;
2478     }
2479     pRect -= numRects;
2480     (*pGC->ops->PolyFillRect) (pDrawable, pGC, numRects, pRect);
2481     if (pWin)
2482         (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeNothing);
2483     DEALLOCATE_LOCAL (pRect);
2484 }
2485
2486 /*-
2487  *-----------------------------------------------------------------------
2488  * miBSAllocate --
2489  *      Create and install backing store info for a window
2490  *
2491  *-----------------------------------------------------------------------
2492  */
2493
2494 static void
2495 miBSAllocate(pWin)
2496     WindowPtr     pWin;
2497 {
2498     register miBSWindowPtr  pBackingStore;
2499     register ScreenPtr      pScreen;
2500         
2501     if (pWin->drawable.pScreen->backingStoreSupport == NotUseful)
2502         return;
2503     pScreen = pWin->drawable.pScreen;
2504     if (!(pBackingStore = (miBSWindowPtr)pWin->backStorage))
2505     {
2506
2507         pBackingStore = (miBSWindowPtr)xalloc(sizeof(miBSWindowRec));
2508         if (!pBackingStore)
2509             return;
2510
2511         pBackingStore->pBackingPixmap = NullPixmap;
2512         pBackingStore->x = 0;
2513         pBackingStore->y = 0;
2514         REGION_INIT( pScreen, &pBackingStore->SavedRegion, NullBox, 1);
2515         pBackingStore->viewable = (char)pWin->viewable;
2516         pBackingStore->status = StatusNoPixmap;
2517         pBackingStore->backgroundState = None;
2518         pWin->backStorage = (pointer) pBackingStore;
2519     }
2520         
2521     /*
2522      * Now want to initialize the backing pixmap and SavedRegion if
2523      * necessary. The initialization consists of finding all the
2524      * currently-obscured regions, by taking the inverse of the window's
2525      * clip list, storing the result in SavedRegion, and exposing those
2526      * areas of the window.
2527      */
2528
2529     if (pBackingStore->status == StatusNoPixmap &&
2530         ((pWin->backingStore == WhenMapped && pWin->viewable) ||
2531          (pWin->backingStore == Always)))
2532     {
2533         BoxRec          box;
2534         RegionPtr       pSavedRegion;
2535
2536         pSavedRegion = &pBackingStore->SavedRegion;
2537
2538         box.x1 = pWin->drawable.x;
2539         box.x2 = box.x1 + (int) pWin->drawable.width;
2540         box.y1 = pWin->drawable.y;
2541         box.y2 = pWin->drawable.y + (int) pWin->drawable.height;
2542
2543         REGION_INVERSE( pScreen, pSavedRegion, &pWin->clipList,  &box);
2544         REGION_TRANSLATE( pScreen, pSavedRegion,
2545                                       -pWin->drawable.x,
2546                                       -pWin->drawable.y);
2547 #ifdef SHAPE
2548         if (wBoundingShape (pWin))
2549             REGION_INTERSECT(pScreen, pSavedRegion, pSavedRegion,
2550                              wBoundingShape (pWin));
2551         if (wClipShape (pWin))
2552             REGION_INTERSECT(pScreen, pSavedRegion, pSavedRegion,
2553                              wClipShape (pWin));
2554 #endif
2555         /* if window is already on-screen, assume it has been drawn to */
2556         if (pWin->viewable)
2557             pBackingStore->status = StatusVDirty;
2558         miTileVirtualBS (pWin);
2559         
2560         /*
2561          * deliver all the newly available regions
2562          * as exposure events to the window
2563          */
2564
2565         miSendExposures(pWin, pSavedRegion, 0, 0);
2566     }
2567     else if (!pWin->viewable)
2568     {
2569         /*
2570          * Turn off backing store when we're not supposed to
2571          * be saving anything
2572          */
2573         if (pBackingStore->status != StatusNoPixmap)
2574         {
2575             REGION_EMPTY( pScreen, &pBackingStore->SavedRegion);
2576             miDestroyBSPixmap (pWin);
2577         }
2578     }
2579 }
2580
2581 /*-
2582  *-----------------------------------------------------------------------
2583  * miBSFree --
2584  *      Destroy and free all the stuff associated with the backing-store
2585  *      for the given window.
2586  *
2587  * Results:
2588  *      None.
2589  *
2590  * Side Effects:
2591  *      The backing pixmap and all the regions and GC's are destroyed.
2592  *
2593  *-----------------------------------------------------------------------
2594  */
2595 static void
2596 miBSFree(pWin)
2597     WindowPtr pWin;
2598 {
2599     miBSWindowPtr       pBackingStore;
2600     register ScreenPtr  pScreen = pWin->drawable.pScreen;
2601
2602     pBackingStore = (miBSWindowPtr)pWin->backStorage;
2603     if (pBackingStore)
2604     {
2605         miDestroyBSPixmap (pWin);
2606
2607         REGION_UNINIT( pScreen, &pBackingStore->SavedRegion);
2608
2609         xfree(pBackingStore);
2610         pWin->backStorage = NULL;
2611     }
2612 }
2613
2614 /*-
2615  *-----------------------------------------------------------------------
2616  * miResizeBackingStore --
2617  *      Alter the size of the backing pixmap as necessary when the
2618  *      SavedRegion changes size. The contents of the old pixmap are
2619  *      copied/shifted into the new/same pixmap.
2620  *
2621  * Results:
2622  *      The new Pixmap is created as necessary.
2623  *
2624  * Side Effects:
2625  *      The old pixmap is destroyed.
2626  *
2627  *-----------------------------------------------------------------------
2628  */
2629 static void
2630 miResizeBackingStore(pWin, dx, dy, saveBits)
2631     WindowPtr   pWin;
2632     int         dx, dy;     /* bits are moving this far */
2633     Bool        saveBits;   /* bits are useful */
2634 {
2635     miBSWindowPtr pBackingStore;
2636     PixmapPtr pBackingPixmap;
2637     ScreenPtr pScreen;
2638     GC     *pGC;
2639     BoxPtr  extents;
2640     PixmapPtr pNewPixmap;
2641     int nx, ny;
2642     int nw, nh;
2643
2644     pBackingStore = (miBSWindowPtr)(pWin->backStorage);
2645     pBackingPixmap = pBackingStore->pBackingPixmap;
2646     if (!pBackingPixmap)
2647         return;
2648     pScreen = pWin->drawable.pScreen;
2649     extents = REGION_EXTENTS(pScreen, &pBackingStore->SavedRegion);
2650     pNewPixmap = pBackingPixmap;
2651
2652     nw = extents->x2 - extents->x1;
2653     nh = extents->y2 - extents->y1;
2654
2655     /* the policy here could be more sophisticated */
2656     if (nw != pBackingPixmap->drawable.width ||
2657         nh != pBackingPixmap->drawable.height)
2658     {
2659         if (!saveBits)
2660         {
2661             pNewPixmap = NullPixmap;
2662             pBackingStore->status = StatusNoPixmap;
2663         }
2664         else
2665         {
2666             pNewPixmap = (PixmapPtr)(*pScreen->CreatePixmap)
2667                                             (pScreen,
2668                                              nw, nh,
2669                                              pWin->drawable.depth);
2670             if (!pNewPixmap)
2671             {
2672 #ifdef BSEAGER
2673                 pBackingStore->status = StatusNoPixmap;
2674 #else
2675                 pBackingStore->status = StatusBadAlloc;
2676 #endif
2677             }
2678         }
2679     }
2680     if (!pNewPixmap)
2681     {
2682         pBackingStore->x = 0;
2683         pBackingStore->y = 0;
2684     }
2685     else
2686     {
2687         nx = pBackingStore->x - extents->x1 + dx;
2688         ny = pBackingStore->y - extents->y1 + dy;
2689         pBackingStore->x = extents->x1;
2690         pBackingStore->y = extents->y1;
2691         
2692         if (saveBits && (pNewPixmap != pBackingPixmap || nx != 0 || ny != 0))
2693         {
2694             pGC = GetScratchGC(pNewPixmap->drawable.depth, pScreen);
2695             if (pGC)
2696             {
2697                 ValidateGC((DrawablePtr)pNewPixmap, pGC);
2698                 /* if we implement a policy where the pixmap can be larger than
2699                  * the region extents, we might want to optimize this copyarea
2700                  * by only copying the old extents, rather than the entire
2701                  * pixmap
2702                  */
2703                 (*pGC->ops->CopyArea)((DrawablePtr)pBackingPixmap,
2704                                       (DrawablePtr)pNewPixmap, pGC,
2705                                       0, 0,
2706                                       pBackingPixmap->drawable.width,
2707                                       pBackingPixmap->drawable.height,
2708                                       nx, ny);
2709                 FreeScratchGC(pGC);
2710             }
2711         }
2712     }
2713     /* SavedRegion is used in the backingGC clip; force an update */
2714     pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
2715     if (pNewPixmap != pBackingPixmap)
2716     {
2717         (* pScreen->DestroyPixmap)(pBackingPixmap);
2718         pBackingStore->pBackingPixmap = pNewPixmap;
2719     }
2720 }
2721
2722 /*-
2723  *-----------------------------------------------------------------------
2724  * miBSSaveDoomedAreas --
2725  *      Saved the areas of the given window that are about to be
2726  *      obscured.  If the window has moved, pObscured is expected to
2727  *      be at the new screen location and (dx,dy) is expected to be the offset
2728  *      to the window's previous location.
2729  *
2730  * Results:
2731  *      None.
2732  *
2733  * Side Effects:
2734  *      The region is copied from the screen into pBackingPixmap and
2735  *      SavedRegion is updated.
2736  *
2737  *-----------------------------------------------------------------------
2738  */
2739 static void
2740 miBSSaveDoomedAreas(pWin, pObscured, dx, dy)
2741     register WindowPtr pWin;
2742     RegionPtr          pObscured;
2743     int                dx, dy;
2744 {
2745     miBSWindowPtr       pBackingStore;
2746     ScreenPtr           pScreen;
2747     int                 x, y;
2748
2749     pBackingStore = (miBSWindowPtr)pWin->backStorage;
2750     pScreen = pWin->drawable.pScreen;
2751
2752     /*
2753      * If the window isn't realized, it's being unmapped, thus we don't
2754      * want to save anything if backingStore isn't Always.
2755      */
2756     if (!pWin->realized)
2757     {
2758         pBackingStore->viewable = (char)pWin->viewable;
2759         if (pWin->backingStore != Always)
2760         {
2761             REGION_EMPTY( pScreen, &pBackingStore->SavedRegion);
2762             miDestroyBSPixmap (pWin);
2763             return;
2764         }
2765         if (pBackingStore->status == StatusBadAlloc)
2766             pBackingStore->status = StatusNoPixmap;
2767     }
2768
2769     /* Don't even pretend to save anything for a virtual background None */
2770     if ((pBackingStore->status == StatusVirtual) &&
2771         (pBackingStore->backgroundState == None))
2772         return;
2773
2774     if (REGION_NOTEMPTY(pScreen, pObscured))
2775     {
2776         BoxRec  oldExtents;
2777         x = pWin->drawable.x;
2778         y = pWin->drawable.y;
2779         REGION_TRANSLATE(pScreen, pObscured, -x, -y);
2780         oldExtents = *REGION_EXTENTS(pScreen, &pBackingStore->SavedRegion);
2781         REGION_UNION( pScreen, &pBackingStore->SavedRegion,
2782                            &pBackingStore->SavedRegion,
2783                            pObscured);
2784         /*
2785          * only save the bits if we've actually
2786          * started using backing store
2787          */
2788         if (pBackingStore->status != StatusVirtual)
2789         {
2790             miBSScreenPtr       pScreenPriv;
2791
2792             pScreenPriv = (miBSScreenPtr) pScreen->devPrivates[miBSScreenIndex].ptr;
2793             if (!pBackingStore->pBackingPixmap)
2794                 miCreateBSPixmap (pWin, &oldExtents);
2795             else
2796                 miResizeBackingStore(pWin, 0, 0, TRUE);
2797
2798             if (pBackingStore->pBackingPixmap) {
2799                 if (pBackingStore->x | pBackingStore->y)
2800                 {
2801                     REGION_TRANSLATE( pScreen, pObscured,
2802                                                   -pBackingStore->x,
2803                                                   -pBackingStore->y);
2804                     x += pBackingStore->x;
2805                     y += pBackingStore->y;
2806                 }
2807                 (* pScreenPriv->funcs->SaveAreas) (pBackingStore->pBackingPixmap,
2808                                                    pObscured, x - dx, y - dy, pWin);
2809             }
2810         }
2811         REGION_TRANSLATE(pScreen, pObscured, x, y);
2812     }
2813 }
2814
2815 /*-
2816  *-----------------------------------------------------------------------
2817  * miBSRestoreAreas --
2818  *      Restore areas from backing-store that are no longer obscured.
2819  *      expects prgnExposed to contain a screen-relative area.
2820  *
2821  * Results:
2822  *      The region to generate exposure events on (which may be
2823  *      different from the region to paint).
2824  *
2825  * Side Effects:
2826  *      Areas are copied from pBackingPixmap to the screen. prgnExposed
2827  *      is altered to contain the region that could not be restored from
2828  *      backing-store.
2829  *
2830  * Notes:
2831  *      This is called before sending any exposure events to the client,
2832  *      and so might be called if the window has grown.  Changing the backing
2833  *      pixmap doesn't require revalidating the backingGC because the
2834  *      client's next output request will result in a call to ValidateGC,
2835  *      since the window clip region has changed, which will in turn call
2836  *      miValidateBackingStore.
2837  *-----------------------------------------------------------------------
2838  */
2839 static RegionPtr
2840 miBSRestoreAreas(pWin, prgnExposed)
2841     register WindowPtr pWin;
2842     RegionPtr prgnExposed;
2843 {
2844     PixmapPtr pBackingPixmap;
2845     miBSWindowPtr pBackingStore;
2846     RegionPtr prgnSaved;
2847     RegionPtr prgnRestored;
2848     register ScreenPtr pScreen;
2849     RegionPtr exposures = prgnExposed;
2850
2851     pScreen = pWin->drawable.pScreen;
2852     pBackingStore = (miBSWindowPtr)pWin->backStorage;
2853     pBackingPixmap = pBackingStore->pBackingPixmap;
2854
2855     prgnSaved = &pBackingStore->SavedRegion;
2856
2857     if (pBackingStore->status == StatusContents)
2858     {
2859         REGION_TRANSLATE(pScreen, prgnSaved, pWin->drawable.x,
2860                          pWin->drawable.y);
2861
2862         prgnRestored = REGION_CREATE( pScreen, (BoxPtr)NULL, 1);
2863         REGION_INTERSECT( pScreen, prgnRestored, prgnExposed, prgnSaved);
2864         
2865         /*
2866          * Since prgnExposed is no longer obscured, we no longer
2867          * will have a valid copy of it in backing-store, but there is a valid
2868          * copy of it on screen, so subtract the area we just restored from
2869          * from the area to be exposed.
2870          */
2871
2872         if (REGION_NOTEMPTY( pScreen, prgnRestored))
2873         {
2874             miBSScreenPtr       pScreenPriv;
2875
2876             REGION_SUBTRACT( pScreen, prgnSaved, prgnSaved, prgnExposed);
2877             REGION_SUBTRACT( pScreen, prgnExposed, prgnExposed, prgnRestored);
2878
2879             /*
2880              * Do the actual restoration
2881              */
2882
2883             pScreenPriv = (miBSScreenPtr)
2884                 pScreen->devPrivates[miBSScreenIndex].ptr;
2885             (* pScreenPriv->funcs->RestoreAreas) (pBackingPixmap,
2886                                           prgnRestored,
2887                                           pWin->drawable.x + pBackingStore->x,
2888                                           pWin->drawable.y + pBackingStore->y, pWin);
2889             /*
2890              * if the saved region is completely empty, dispose of the
2891              * backing pixmap, otherwise, retranslate the saved
2892              * region to window relative
2893              */
2894
2895             if (REGION_NOTEMPTY(pScreen, prgnSaved))
2896             {
2897                 REGION_TRANSLATE(pScreen, prgnSaved,
2898                                              -pWin->drawable.x,
2899                                              -pWin->drawable.y);
2900                 miResizeBackingStore(pWin, 0, 0, TRUE);
2901             }
2902             else
2903                 miDestroyBSPixmap (pWin);
2904         }
2905         else
2906             REGION_TRANSLATE(pScreen, prgnSaved,
2907                                 -pWin->drawable.x, -pWin->drawable.y);
2908         REGION_DESTROY( pScreen, prgnRestored);
2909
2910     }
2911     else if ((pBackingStore->status == StatusVirtual) ||
2912              (pBackingStore->status == StatusVDirty))
2913     {
2914         REGION_TRANSLATE(pScreen, prgnSaved,
2915                                      pWin->drawable.x, pWin->drawable.y);
2916         exposures = REGION_CREATE( pScreen, NullBox, 1);
2917         if (SameBackground (pBackingStore->backgroundState,
2918                             pBackingStore->background,
2919                             pWin->backgroundState,
2920                             pWin->background))
2921         {
2922             REGION_SUBTRACT( pScreen, exposures, prgnExposed, prgnSaved);
2923         }
2924         else
2925         {
2926             miTileVirtualBS(pWin);
2927
2928             /* we need to expose all we have (virtually) retiled */
2929             REGION_UNION( pScreen, exposures, prgnExposed, prgnSaved);
2930         }
2931         REGION_SUBTRACT( pScreen, prgnSaved, prgnSaved, prgnExposed);
2932         REGION_TRANSLATE(pScreen, prgnSaved,
2933                                      -pWin->drawable.x, -pWin->drawable.y);
2934     }
2935     else if (pWin->viewable && !pBackingStore->viewable &&
2936              pWin->backingStore != Always)
2937     {
2938         /*
2939          * The window was just mapped and nothing has been saved in
2940          * backing-store from the last time it was mapped. We want to capture
2941          * any output to regions that are already obscured but there are no
2942          * bits to snag off the screen, so we initialize things just as we did
2943          * in miBSAllocate, above.
2944          */
2945         BoxRec  box;
2946         
2947         prgnSaved = &pBackingStore->SavedRegion;
2948
2949         box.x1 = pWin->drawable.x;
2950         box.x2 = box.x1 + (int) pWin->drawable.width;
2951         box.y1 = pWin->drawable.y;
2952         box.y2 = box.y1 + (int) pWin->drawable.height;
2953         
2954         REGION_INVERSE( pScreen, prgnSaved, &pWin->clipList,  &box);
2955         REGION_TRANSLATE( pScreen, prgnSaved,
2956                                       -pWin->drawable.x,
2957                                       -pWin->drawable.y);
2958 #ifdef SHAPE
2959         if (wBoundingShape (pWin))
2960             REGION_INTERSECT(pScreen, prgnSaved, prgnSaved,
2961                              wBoundingShape (pWin));
2962         if (wClipShape (pWin))
2963             REGION_INTERSECT(pScreen, prgnSaved, prgnSaved,
2964                              wClipShape (pWin));
2965 #endif
2966         miTileVirtualBS(pWin);
2967
2968         exposures = REGION_CREATE( pScreen, &box, 1);
2969     }
2970     pBackingStore->viewable = (char)pWin->viewable;
2971     return exposures;
2972 }
2973
2974
2975 /*-
2976  *-----------------------------------------------------------------------
2977  * miBSTranslateBackingStore --
2978  *      Shift the backing-store in the given direction. Called when bit
2979  *      gravity is shifting things around. 
2980  *
2981  * Results:
2982  *      An occluded region of the window which should be sent exposure events.
2983  *      This region should be in absolute coordinates (i.e. include
2984  *      new window position).
2985  *
2986  * Side Effects:
2987  *      If the window changed size as well as position, the backing pixmap
2988  *      is resized. The contents of the backing pixmap are shifted
2989  *
2990  * Warning:
2991  *      Bob and I have rewritten this routine quite a few times, each
2992  *      time it gets a few more cases correct, and introducing some
2993  *      interesting bugs.  Naturally, I think the code is correct this
2994  *      time.
2995  *
2996  *      Let me try to explain what this routine is for:
2997  *
2998  *      It's called from SlideAndSizeWindow whenever a window
2999  *      with backing store is resized.  There are two separate
3000  *      possibilities:
3001  *
3002  *      a)  The window has ForgetGravity
3003  *
3004  *          In this case, windx, windy will be 0 and oldClip will
3005  *          be NULL.  This indicates that all of the window contents
3006  *          currently saved offscreen should be discarded, and the
3007  *          entire window exposed.  TranslateBackingStore, then, should
3008  *          prepare a completely new backing store region based on the
3009  *          new window clipList and return that region for exposure.
3010  *
3011  *      b)  The window has some other gravity
3012  *
3013  *          In this case, windx, windy will be set to the distance
3014  *          that the bits should move within the window.  oldClip
3015  *          will be set to the old visible portion of the window.
3016  *          TranslateBackingStore, then, should adjust the backing
3017  *          store to accommodate the portion of the existing backing
3018  *          store bits which coorespond to backing store bits which
3019  *          will still be occluded in the new configuration.  oldx,oldy
3020  *          are set to the old position of the window on the screen.
3021  *
3022  *          Furthermore, in this case any contents of the screen which
3023  *          are about to become occluded should be fetched from the screen
3024  *          and placed in backing store.  This is to avoid the eventual
3025  *          occlusion by the win gravity shifting the child window bits around
3026  *          on top of this window, and potentially losing information
3027  *
3028  *      It's also called from SetShape, but I think (he says not
3029  *      really knowing for sure) that this code will even work
3030  *      in that case.
3031  *-----------------------------------------------------------------------
3032  */
3033
3034 static RegionPtr
3035 miBSTranslateBackingStore(pWin, windx, windy, oldClip, oldx, oldy)
3036     WindowPtr     pWin;
3037     int           windx;        /* bit translation distance in window */
3038     int           windy;
3039     RegionPtr     oldClip;      /* Region being copied */
3040     int           oldx;         /* old window position */
3041     int           oldy;
3042 {
3043     register miBSWindowPtr      pBackingStore;
3044     register RegionPtr          pSavedRegion;
3045     register RegionPtr          newSaved, doomed;
3046     register ScreenPtr          pScreen;
3047     BoxRec                      extents;
3048     int           scrdx;        /* bit translation distance on screen */
3049     int           scrdy;
3050     int           dx;           /* distance window moved  on screen */
3051     int           dy;
3052
3053     pScreen = pWin->drawable.pScreen;
3054     pBackingStore = (miBSWindowPtr)(pWin->backStorage);
3055     if ((pBackingStore->status == StatusNoPixmap) ||
3056         (pBackingStore->status == StatusBadAlloc))
3057         return NullRegion;
3058
3059     /*
3060      * Compute the new saved region
3061      */
3062
3063     newSaved = REGION_CREATE( pScreen, NullBox, 1);
3064     extents.x1 = pWin->drawable.x;
3065     extents.x2 = pWin->drawable.x + (int) pWin->drawable.width;
3066     extents.y1 = pWin->drawable.y;
3067     extents.y2 = pWin->drawable.y + (int) pWin->drawable.height;
3068     REGION_INVERSE( pScreen, newSaved, &pWin->clipList, &extents);
3069
3070     REGION_TRANSLATE( pScreen, newSaved,
3071                         -pWin->drawable.x, -pWin->drawable.y);
3072 #ifdef SHAPE
3073     if (wBoundingShape (pWin) || wClipShape (pWin)) {
3074         if (wBoundingShape (pWin))
3075             REGION_INTERSECT( pScreen, newSaved, newSaved,
3076                                 wBoundingShape (pWin));
3077         if (wClipShape (pWin))
3078             REGION_INTERSECT( pScreen, newSaved, newSaved, wClipShape (pWin));
3079     }
3080 #endif
3081     
3082     pSavedRegion = &pBackingStore->SavedRegion;
3083
3084     /* now find any visible areas we can save from the screen */
3085     /* and then translate newSaved to old local coordinates */
3086     if (oldClip)
3087     {
3088         /* bit gravity makes things virtually too hard, punt */
3089         if (((windx != 0) || (windy != 0)) &&
3090             (pBackingStore->status != StatusContents))
3091             miCreateBSPixmap(pWin, NullBox);
3092     
3093         /*
3094          * The window is moving this far on the screen
3095          */
3096         dx = pWin->drawable.x - oldx;
3097         dy = pWin->drawable.y - oldy;
3098         /*
3099          * The bits will be moving on the screen by the
3100          * amount the window is moving + the amount the
3101          * bits are moving within the window
3102          */
3103         scrdx = windx + dx;
3104         scrdy = windy + dy;
3105     
3106         /*
3107          * intersect at old bit position to discover the
3108          * bits on the screen which can be put into the
3109          * new backing store
3110          */
3111         REGION_TRANSLATE( pScreen, oldClip, windx - oldx, windy - oldy);
3112         doomed = REGION_CREATE( pScreen, NullBox, 1);
3113         REGION_INTERSECT( pScreen, doomed, oldClip, newSaved);
3114         REGION_TRANSLATE( pScreen, oldClip, oldx - windx, oldy - windy);
3115
3116         /*
3117          * Translate the old saved region to the position in the
3118          * window where it will appear to be
3119          */
3120         REGION_TRANSLATE( pScreen, pSavedRegion, windx, windy);
3121
3122         /*
3123          * Add the old saved region to the new saved region, so
3124          * that calls to RestoreAreas will be able to fetch those
3125          * bits back
3126          */
3127         REGION_UNION( pScreen, newSaved, newSaved, pSavedRegion);
3128
3129         /*
3130          * Swap the new saved region into the window
3131          */
3132         {
3133             RegionRec   tmp;
3134
3135             tmp = *pSavedRegion;
3136             *pSavedRegion = *newSaved;
3137             *newSaved = tmp;
3138         }
3139         miResizeBackingStore (pWin, windx, windy, TRUE);
3140
3141         /*
3142          * Compute the newly enabled region
3143          * of backing store.  This region will be
3144          * set to background in the backing pixmap and
3145          * sent as exposure events to the client.
3146          */
3147         REGION_SUBTRACT( pScreen, newSaved, pSavedRegion, newSaved);
3148
3149         /*
3150          * Fetch bits which will be obscured from
3151          * the screen
3152          */
3153         if (REGION_NOTEMPTY( pScreen, doomed))
3154         {
3155             /*
3156              * Don't clear regions which have bits on the
3157              * screen
3158              */
3159             REGION_SUBTRACT( pScreen, newSaved, newSaved, doomed);
3160
3161             /*
3162              * Make the region to SaveDoomedAreas absolute, instead
3163              * of window relative.
3164              */
3165             REGION_TRANSLATE( pScreen, doomed,
3166                                           pWin->drawable.x, pWin->drawable.y);
3167             (* pScreen->SaveDoomedAreas) (pWin, doomed, scrdx, scrdy);
3168         }
3169         
3170         REGION_DESTROY(pScreen, doomed);
3171
3172         /*
3173          * and clear whatever there is that's new
3174          */
3175         if (REGION_NOTEMPTY( pScreen, newSaved))
3176         {
3177             miBSClearBackingRegion (pWin, newSaved);
3178             /*
3179              * Make the exposed region absolute
3180              */
3181             REGION_TRANSLATE(pScreen, newSaved,
3182                                          pWin->drawable.x,
3183                                          pWin->drawable.y);
3184         }
3185         else
3186         {
3187             REGION_DESTROY(pScreen, newSaved);
3188             newSaved = NullRegion;
3189         }
3190     }
3191     else
3192     {
3193         /*
3194          * ForgetGravity: just reset backing store and
3195          * expose the whole mess
3196          */
3197         REGION_COPY( pScreen, pSavedRegion, newSaved);
3198         REGION_TRANSLATE( pScreen, newSaved,
3199                                       pWin->drawable.x, pWin->drawable.y);
3200
3201         miResizeBackingStore (pWin, 0, 0, FALSE);
3202         (void) miBSClearBackingStore (pWin, 0, 0, 0, 0, FALSE);
3203     }
3204
3205     return newSaved;
3206 }
3207
3208 /*
3209  * Inform the backing store layer that you are about to validate
3210  * a gc with a window, and that subsequent output to the window
3211  * is (or is not) guaranteed to be already clipped to the visible
3212  * regions of the window.
3213  */
3214
3215 static void
3216 miBSDrawGuarantee (pWin, pGC, guarantee)
3217     WindowPtr   pWin;
3218     GCPtr       pGC;
3219     int         guarantee;
3220 {
3221     miBSGCPtr   pPriv;
3222
3223     if (pWin->backStorage)
3224     {
3225         pPriv = (miBSGCPtr)pGC->devPrivates[miBSGCIndex].ptr;
3226         if (!pPriv)
3227             (void) miBSCreateGCPrivate (pGC);
3228         pPriv = (miBSGCPtr)pGC->devPrivates[miBSGCIndex].ptr;
3229         if (pPriv)
3230         {
3231             /*
3232              * XXX KLUDGE ALERT
3233              *
3234              * when the GC is Cheap pPriv will point
3235              * at some device's gc func structure.  guarantee
3236              * will point at the ChangeGC entry of that struct
3237              * and will never match a valid guarantee value.
3238              */
3239             switch (pPriv->guarantee)
3240             {
3241             case GuaranteeNothing:
3242             case GuaranteeVisBack:
3243                 pPriv->guarantee = guarantee;
3244                 break;
3245             }
3246         }
3247     }
3248 }
3249
3250 #define noBackingCopy (GCGraphicsExposures|GCClipXOrigin|GCClipYOrigin| \
3251                        GCClipMask|GCSubwindowMode| \
3252                        GCTileStipXOrigin|GCTileStipYOrigin)
3253
3254 /*-
3255  *-----------------------------------------------------------------------
3256  * miBSValidateGC --
3257  *      Wrapper around output-library's ValidateGC routine
3258  *
3259  * Results:
3260  *      None.
3261  *
3262  * Side Effects:
3263  *
3264  * Notes:
3265  *      The idea here is to perform several functions:
3266  *          - All the output calls must be intercepted and routed to
3267  *            backing-store as necessary.
3268  *          - pGC in the window's devBackingStore must be set up with the
3269  *            clip list appropriate for writing to pBackingPixmap (i.e.
3270  *            the inverse of the window's clipList intersected with the
3271  *            clientClip of the GC). Since the destination for this GC is
3272  *            a pixmap, it is sufficient to set the clip list as its
3273  *            clientClip.
3274  *-----------------------------------------------------------------------
3275  */
3276
3277 static void
3278 miBSValidateGC (pGC, stateChanges, pDrawable)
3279     GCPtr         pGC;
3280     unsigned long stateChanges;
3281     DrawablePtr   pDrawable;
3282 {
3283     GCPtr               pBackingGC;
3284     miBSWindowPtr       pWindowPriv;
3285     miBSGCPtr           pPriv;
3286     WindowPtr           pWin;
3287     int                 lift_functions;
3288     RegionPtr           backingCompositeClip = NULL;
3289
3290     if (pDrawable->type != DRAWABLE_PIXMAP)
3291     {
3292         pWin = (WindowPtr) pDrawable;
3293         pWindowPriv = (miBSWindowPtr) pWin->backStorage;
3294         lift_functions = (pWindowPriv == (miBSWindowPtr) NULL);
3295     }
3296     else
3297     {
3298         pWin = (WindowPtr) NULL;
3299         lift_functions = TRUE;
3300     }
3301
3302     pPriv = (miBSGCPtr)pGC->devPrivates[miBSGCIndex].ptr;
3303
3304     FUNC_PROLOGUE (pGC, pPriv);
3305
3306     (*pGC->funcs->ValidateGC) (pGC, stateChanges, pDrawable);
3307
3308     /*
3309      * rewrap funcs and ops as Validate may have changed them
3310      */
3311
3312     pPriv->wrapFuncs = pGC->funcs;
3313     pPriv->wrapOps = pGC->ops;
3314
3315     if (!lift_functions && ((pPriv->guarantee == GuaranteeVisBack) ||
3316                             (pWindowPriv->status == StatusNoPixmap) ||
3317                             (pWindowPriv->status == StatusBadAlloc)))
3318         lift_functions = TRUE;
3319
3320     /*
3321      * check to see if a new backingCompositeClip region must
3322      * be generated
3323      */
3324
3325     if (!lift_functions && 
3326         ((pDrawable->serialNumber != pPriv->serialNumber) ||
3327          (stateChanges&(GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode))))
3328     {
3329         if (REGION_NOTEMPTY(pGC->pScreen, &pWindowPriv->SavedRegion))
3330         {
3331             backingCompositeClip = REGION_CREATE(pGC->pScreen, NULL, 1);
3332             if ((pGC->clientClipType == CT_NONE) || 
3333                 (pGC->clientClipType == CT_PIXMAP))
3334             {
3335                 REGION_COPY(pGC->pScreen, backingCompositeClip,
3336                                              &pWindowPriv->SavedRegion); 
3337             }
3338             else
3339             {
3340                 /*
3341                  * Make a new copy of the client clip, translated to
3342                  * its proper origin.
3343                  */
3344
3345                 REGION_COPY(pGC->pScreen, backingCompositeClip,
3346                                 pGC->clientClip);
3347                 REGION_TRANSLATE(pGC->pScreen, backingCompositeClip,
3348                                                   pGC->clipOrg.x,
3349                                                   pGC->clipOrg.y);
3350                 REGION_INTERSECT(pGC->pScreen, backingCompositeClip,
3351                                         backingCompositeClip,
3352                                         &pWindowPriv->SavedRegion);
3353             }
3354             if (pGC->subWindowMode == IncludeInferiors)
3355             {
3356                 RegionPtr translatedClip;
3357
3358                 /* XXX
3359                  * any output in IncludeInferiors mode will not
3360                  * be redirected to Inferiors backing store.  This
3361                  * can be fixed only at great cost to the shadow routines.
3362                  */
3363                 translatedClip = NotClippedByChildren (pWin);
3364                 REGION_TRANSLATE(pGC->pScreen, translatedClip,
3365                                                   -pDrawable->x,
3366                                                   -pDrawable->y);
3367                 REGION_SUBTRACT(pGC->pScreen, backingCompositeClip,
3368                                 backingCompositeClip, translatedClip);
3369                 REGION_DESTROY(pGC->pScreen, translatedClip);
3370             }
3371             if (!REGION_NOTEMPTY(pGC->pScreen, backingCompositeClip))
3372                 lift_functions = TRUE;
3373         }
3374         else
3375         {
3376             lift_functions = TRUE;
3377         }
3378
3379         /* Reset the status when drawing to an unoccluded window so that
3380          * future SaveAreas will actually copy bits from the screen.  Note that
3381          * output to root window in IncludeInferiors mode will not cause this
3382          * to change.  This causes all transient graphics by the window
3383          * manager to the root window to not enable backing store.
3384          */
3385         if (lift_functions && (pWindowPriv->status == StatusVirtual) &&
3386             (pWin->parent || pGC->subWindowMode != IncludeInferiors))
3387             pWindowPriv->status = StatusVDirty;
3388     }
3389
3390     /*
3391      * if no backing store has been allocated, and it's needed,
3392      * create it now.
3393      */
3394
3395     if (!lift_functions && !pWindowPriv->pBackingPixmap)
3396     {
3397         miCreateBSPixmap (pWin, NullBox);
3398         if (!pWindowPriv->pBackingPixmap)
3399             lift_functions = TRUE;
3400     }
3401     
3402     /*
3403      * create the backing GC if needed, lift functions
3404      * if the creation fails
3405      */
3406
3407     if (!lift_functions && !pPriv->pBackingGC)
3408     {
3409         int status;
3410         XID noexpose = xFalse;
3411
3412         /* We never want ops with the backingGC to generate GraphicsExpose */
3413         pBackingGC = CreateGC ((DrawablePtr)pWindowPriv->pBackingPixmap,
3414                                GCGraphicsExposures, &noexpose, &status);
3415         if (status != Success)
3416             lift_functions = TRUE;
3417         else
3418             pPriv->pBackingGC = pBackingGC;
3419     }
3420
3421     pBackingGC = pPriv->pBackingGC;
3422
3423     pPriv->stateChanges |= stateChanges;
3424
3425     if (lift_functions)
3426     {
3427         if (backingCompositeClip)
3428             REGION_DESTROY( pGC->pScreen, backingCompositeClip);
3429
3430         /* unwrap the GC again */
3431         miBSDestroyGCPrivate (pGC);
3432
3433         return;
3434     }
3435
3436     /*
3437      * the rest of this function gets the pBackingGC
3438      * into shape for possible draws
3439      */
3440
3441     pPriv->stateChanges &= ~noBackingCopy;
3442     if (pPriv->stateChanges)
3443         CopyGC(pGC, pBackingGC, pPriv->stateChanges);
3444     if ((pGC->patOrg.x - pWindowPriv->x) != pBackingGC->patOrg.x ||
3445         (pGC->patOrg.y - pWindowPriv->y) != pBackingGC->patOrg.y)
3446     {
3447         XID vals[2];
3448         vals[0] = pGC->patOrg.x - pWindowPriv->x;
3449         vals[1] = pGC->patOrg.y - pWindowPriv->y;
3450         DoChangeGC(pBackingGC, GCTileStipXOrigin|GCTileStipYOrigin, vals, 0);
3451     }
3452     pPriv->stateChanges = 0;
3453
3454     if (backingCompositeClip)
3455     {
3456         XID vals[2];
3457
3458         if (pGC->clientClipType == CT_PIXMAP)
3459         {
3460             miBSScreenPtr   pScreenPriv;
3461
3462             (*pBackingGC->funcs->CopyClip)(pBackingGC, pGC);
3463             REGION_TRANSLATE(pGC->pScreen, backingCompositeClip,
3464                                         -pGC->clipOrg.x, -pGC->clipOrg.y);
3465             vals[0] = pGC->clipOrg.x - pWindowPriv->x;
3466             vals[1] = pGC->clipOrg.y - pWindowPriv->y;
3467             DoChangeGC(pBackingGC, GCClipXOrigin|GCClipYOrigin, vals, 0);
3468             pScreenPriv = (miBSScreenPtr) 
3469                 pGC->pScreen->devPrivates[miBSScreenIndex].ptr;
3470             (* pScreenPriv->funcs->SetClipmaskRgn)
3471                 (pBackingGC, backingCompositeClip);
3472             REGION_DESTROY( pGC->pScreen, backingCompositeClip);
3473         }
3474         else
3475         {
3476             vals[0] = -pWindowPriv->x;
3477             vals[1] = -pWindowPriv->y;
3478             DoChangeGC(pBackingGC, GCClipXOrigin|GCClipYOrigin, vals, 0);
3479             (*pBackingGC->funcs->ChangeClip) (pBackingGC, CT_REGION, backingCompositeClip, 0);
3480         }
3481         pPriv->serialNumber = pDrawable->serialNumber;
3482     }
3483     
3484     if (pWindowPriv->pBackingPixmap->drawable.serialNumber
3485         != pBackingGC->serialNumber)
3486     {
3487         ValidateGC((DrawablePtr)pWindowPriv->pBackingPixmap, pBackingGC);
3488     }
3489
3490     if (pBackingGC->clientClip == 0)
3491         ErrorF ("backing store clip list nil");
3492
3493     FUNC_EPILOGUE (pGC, pPriv);
3494 }
3495
3496 static void
3497 miBSChangeGC (pGC, mask)
3498     GCPtr   pGC;
3499     unsigned long   mask;
3500 {
3501     miBSGCPtr   pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr;
3502
3503     FUNC_PROLOGUE (pGC, pPriv);
3504
3505     (*pGC->funcs->ChangeGC) (pGC, mask);
3506
3507     FUNC_EPILOGUE (pGC, pPriv);
3508 }
3509
3510 static void
3511 miBSCopyGC (pGCSrc, mask, pGCDst)
3512     GCPtr   pGCSrc, pGCDst;
3513     unsigned long   mask;
3514 {
3515     miBSGCPtr   pPriv = (miBSGCPtr) (pGCDst)->devPrivates[miBSGCIndex].ptr;
3516
3517     FUNC_PROLOGUE (pGCDst, pPriv);
3518
3519     (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
3520
3521     FUNC_EPILOGUE (pGCDst, pPriv);
3522 }
3523
3524 static void
3525 miBSDestroyGC (pGC)
3526     GCPtr   pGC;
3527 {
3528     miBSGCPtr   pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr;
3529
3530     FUNC_PROLOGUE (pGC, pPriv);
3531
3532     if (pPriv->pBackingGC)
3533         FreeGC(pPriv->pBackingGC, (GContext)0);
3534
3535     (*pGC->funcs->DestroyGC) (pGC);
3536
3537     FUNC_EPILOGUE (pGC, pPriv);
3538
3539     xfree(pPriv);
3540 }
3541
3542 static void
3543 miBSChangeClip(pGC, type, pvalue, nrects)
3544     GCPtr       pGC;
3545     int         type;
3546     pointer     pvalue;
3547     int         nrects;
3548 {
3549     miBSGCPtr   pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr;
3550
3551     FUNC_PROLOGUE (pGC, pPriv);
3552
3553     (* pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects);
3554
3555     FUNC_EPILOGUE (pGC, pPriv);
3556 }
3557
3558 static void
3559 miBSCopyClip(pgcDst, pgcSrc)
3560     GCPtr pgcDst, pgcSrc;
3561 {
3562     miBSGCPtr   pPriv = (miBSGCPtr) (pgcDst)->devPrivates[miBSGCIndex].ptr;
3563
3564     FUNC_PROLOGUE (pgcDst, pPriv);
3565
3566     (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
3567
3568     FUNC_EPILOGUE (pgcDst, pPriv);
3569 }
3570
3571 static void
3572 miBSDestroyClip(pGC)
3573     GCPtr       pGC;
3574 {
3575     miBSGCPtr   pPriv = (miBSGCPtr) (pGC)->devPrivates[miBSGCIndex].ptr;
3576
3577     FUNC_PROLOGUE (pGC, pPriv);
3578
3579     (* pGC->funcs->DestroyClip)(pGC);
3580
3581     FUNC_EPILOGUE (pGC, pPriv);
3582 }
3583
3584 static void
3585 miDestroyBSPixmap (pWin)
3586     WindowPtr   pWin;
3587 {
3588     miBSWindowPtr       pBackingStore;
3589     ScreenPtr           pScreen;
3590     
3591     pScreen = pWin->drawable.pScreen;
3592     pBackingStore = (miBSWindowPtr) pWin->backStorage;
3593     if (pBackingStore->pBackingPixmap)
3594         (* pScreen->DestroyPixmap)(pBackingStore->pBackingPixmap);
3595     pBackingStore->pBackingPixmap = NullPixmap;
3596     pBackingStore->x = 0;
3597     pBackingStore->y = 0;
3598     if (pBackingStore->backgroundState == BackgroundPixmap)
3599         (* pScreen->DestroyPixmap)(pBackingStore->background.pixmap);
3600     pBackingStore->backgroundState = None;
3601     pBackingStore->status = StatusNoPixmap;
3602     pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
3603 }
3604
3605 static void
3606 miTileVirtualBS (pWin)
3607     WindowPtr   pWin;
3608 {
3609     miBSWindowPtr       pBackingStore;
3610
3611     pBackingStore = (miBSWindowPtr) pWin->backStorage;
3612     if (pBackingStore->backgroundState == BackgroundPixmap)
3613         (* pWin->drawable.pScreen->DestroyPixmap)
3614             (pBackingStore->background.pixmap);
3615     pBackingStore->backgroundState = pWin->backgroundState;
3616     pBackingStore->background = pWin->background;
3617     if (pBackingStore->backgroundState == BackgroundPixmap)
3618         pBackingStore->background.pixmap->refcnt++;
3619
3620     if (pBackingStore->status != StatusVDirty)
3621         pBackingStore->status = StatusVirtual;
3622
3623     /*
3624      * punt parent relative tiles and do it now
3625      */
3626     if (pBackingStore->backgroundState == ParentRelative)
3627         miCreateBSPixmap (pWin, NullBox);
3628 }
3629
3630 #ifdef DEBUG
3631 static int BSAllocationsFailed = 0;
3632 #define FAILEDSIZE      32
3633 static struct { int w, h; } failedRecord[FAILEDSIZE];
3634 static int failedIndex;
3635 #endif
3636
3637 static void
3638 miCreateBSPixmap (pWin, pExtents)
3639     WindowPtr   pWin;
3640     BoxPtr      pExtents;
3641 {
3642     miBSWindowPtr       pBackingStore;
3643     ScreenPtr           pScreen;
3644     PixUnion            background;
3645     char                backgroundState;
3646     BoxPtr              extents;
3647     Bool                backSet;
3648
3649     pScreen = pWin->drawable.pScreen;
3650     pBackingStore = (miBSWindowPtr) pWin->backStorage;
3651     if (pBackingStore->status == StatusBadAlloc)
3652         return;
3653     backSet = ((pBackingStore->status == StatusVirtual) ||
3654                (pBackingStore->status == StatusVDirty));
3655
3656     extents = REGION_EXTENTS( pScreen, &pBackingStore->SavedRegion);
3657
3658     if (!pBackingStore->pBackingPixmap)
3659     {
3660         /* the policy here could be more sophisticated */
3661         pBackingStore->x = extents->x1;
3662         pBackingStore->y = extents->y1;
3663         pBackingStore->pBackingPixmap =
3664             (PixmapPtr)(* pScreen->CreatePixmap)
3665                            (pScreen,
3666                             extents->x2 - extents->x1,
3667                             extents->y2 - extents->y1,
3668                             pWin->drawable.depth);
3669     }
3670     if (!pBackingStore->pBackingPixmap)
3671     {
3672 #ifdef DEBUG
3673         BSAllocationsFailed++;
3674         /*
3675          * record failed allocations
3676          */
3677         failedRecord[failedIndex].w = pWin->drawable.width;
3678         failedRecord[failedIndex].h = pWin->drawable.height;
3679         failedIndex++;
3680         if (failedIndex == FAILEDSIZE)
3681                 failedIndex = 0;
3682 #endif
3683 #ifdef BSEAGER
3684         pBackingStore->status = StatusNoPixmap;
3685 #else
3686         pBackingStore->status = StatusBadAlloc;
3687 #endif
3688         return;
3689     }
3690
3691     pBackingStore->status = StatusContents;
3692
3693     if (backSet)
3694     {
3695         backgroundState = pWin->backgroundState;
3696         background = pWin->background;
3697     
3698         pWin->backgroundState = pBackingStore->backgroundState;
3699         pWin->background = pBackingStore->background;
3700         if (pWin->backgroundState == BackgroundPixmap)
3701             pWin->background.pixmap->refcnt++;
3702     }
3703
3704     if (!pExtents)
3705         pExtents = extents;
3706
3707     if (pExtents->y1 != pExtents->y2)
3708     {
3709         RegionPtr exposed;
3710
3711         exposed = miBSClearBackingStore(pWin,
3712                               pExtents->x1, pExtents->y1,
3713                               pExtents->x2 - pExtents->x1,
3714                               pExtents->y2 - pExtents->y1,
3715                               !backSet);
3716         if (exposed)
3717         {
3718             miSendExposures(pWin, exposed, pWin->drawable.x, pWin->drawable.y);
3719             REGION_DESTROY( pScreen, exposed);
3720         }
3721     }
3722
3723     if (backSet)
3724     {
3725         if (pWin->backgroundState == BackgroundPixmap)
3726             (* pScreen->DestroyPixmap) (pWin->background.pixmap);
3727         pWin->backgroundState = backgroundState;
3728         pWin->background = background;
3729         if (pBackingStore->backgroundState == BackgroundPixmap)
3730             (* pScreen->DestroyPixmap) (pBackingStore->background.pixmap);
3731         pBackingStore->backgroundState = None;
3732     }
3733 }
3734
3735 /*-
3736  *-----------------------------------------------------------------------
3737  * miBSExposeCopy --
3738  *      Handle the restoration of areas exposed by graphics operations.
3739  *
3740  * Results:
3741  *      None.
3742  *
3743  * Side Effects:
3744  *      prgnExposed has the areas exposed from backing-store removed
3745  *      from it.
3746  *
3747  *-----------------------------------------------------------------------
3748  */
3749 static void
3750 miBSExposeCopy (pSrc, pDst, pGC, prgnExposed, srcx, srcy, dstx, dsty, plane)
3751     WindowPtr           pSrc;
3752     DrawablePtr         pDst;
3753     GCPtr               pGC;
3754     RegionPtr           prgnExposed;
3755     int                 srcx, srcy;
3756     int                 dstx, dsty;
3757     unsigned long       plane;
3758 {
3759     RegionRec           tempRgn;
3760     miBSWindowPtr       pBackingStore;
3761     RegionPtr           (*copyProc)();
3762     GCPtr               pScratchGC;
3763     register BoxPtr     pBox;
3764     register int        i;
3765     register int        dx, dy;
3766     BITS32              gcMask;
3767
3768     if (!REGION_NOTEMPTY(pGC->pScreen, prgnExposed))
3769         return;
3770     pBackingStore = (miBSWindowPtr)pSrc->backStorage;
3771     
3772     if ((pBackingStore->status == StatusNoPixmap) ||
3773         (pBackingStore->status == StatusBadAlloc))
3774         return;
3775
3776     REGION_INIT( pGC->pScreen, &tempRgn, NullBox, 0);
3777     REGION_INTERSECT( pGC->pScreen, &tempRgn, prgnExposed,
3778                                  &pBackingStore->SavedRegion);
3779     REGION_SUBTRACT( pGC->pScreen, prgnExposed, prgnExposed, &tempRgn);
3780
3781     if (plane != 0) {
3782         copyProc = pGC->ops->CopyPlane;
3783     } else {
3784         copyProc = pGC->ops->CopyArea;
3785     }
3786     
3787     dx = dstx - srcx;
3788     dy = dsty - srcy;
3789     
3790     switch (pBackingStore->status) {
3791     case StatusVirtual:
3792     case StatusVDirty:
3793         pScratchGC = GetScratchGC (pDst->depth, pDst->pScreen);
3794         if (pScratchGC)
3795         {
3796             gcMask = 0;
3797             if (pGC->alu != pScratchGC->alu)
3798                 gcMask = GCFunction;
3799             if (pGC->planemask != pScratchGC->planemask)
3800                 gcMask |= GCPlaneMask;
3801             if (gcMask)
3802                 CopyGC (pGC, pScratchGC, gcMask);
3803             miBSFillVirtualBits (pDst, pScratchGC, &tempRgn, dx, dy,
3804                                  (int) pBackingStore->backgroundState,
3805                                  pBackingStore->background,
3806                                  ~0L);
3807             FreeScratchGC (pScratchGC);
3808         }
3809         break;
3810     case StatusContents:
3811         for (i = REGION_NUM_RECTS(&tempRgn), pBox = REGION_RECTS(&tempRgn);
3812              --i >= 0;
3813              pBox++)
3814         {
3815             (* copyProc) (pBackingStore->pBackingPixmap, pDst, pGC,
3816                           pBox->x1 - pBackingStore->x,
3817                           pBox->y1 - pBackingStore->y,
3818                           pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
3819                           pBox->x1 + dx, pBox->y1 + dy, plane);
3820         }
3821         break;
3822     }
3823     REGION_UNINIT( pGC->pScreen, &tempRgn);
3824 }