]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/mi/miexpose.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / mi / miexpose.c
1 /***********************************************************
2
3 Copyright (c) 1987  X Consortium
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of the X Consortium shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from the X Consortium.
25
26
27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
28
29                         All Rights Reserved
30
31 Permission to use, copy, modify, and distribute this software and its 
32 documentation for any purpose and without fee is hereby granted, 
33 provided that the above copyright notice appear in all copies and that
34 both that copyright notice and this permission notice appear in 
35 supporting documentation, and that the name of Digital not be
36 used in advertising or publicity pertaining to distribution of the
37 software without specific, written prior permission.  
38
39 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45 SOFTWARE.
46
47 ******************************************************************/
48
49 /* $XConsortium: miexpose.c /main/43 1996/08/01 19:25:26 dpw $ */
50 /* $XFree86: xc/programs/Xserver/mi/miexpose.c,v 3.1 1996/12/23 07:09:44 dawes Exp $ */
51
52 #include "X.h"
53 #define NEED_EVENTS
54 #include "Xproto.h"
55 #include "Xprotostr.h"
56
57 #include "misc.h"
58 #include "regionstr.h"
59 #include "scrnintstr.h"
60 #include "gcstruct.h"
61 #include "windowstr.h"
62 #include "pixmap.h"
63 #include "input.h"
64
65 #include "dixstruct.h"
66 #include "mi.h"
67 #include "Xmd.h"
68
69 extern WindowPtr *WindowTable;
70
71 /*
72     machine-independent graphics exposure code.  any device that uses
73 the region package can call this.
74 */
75
76 #ifndef RECTLIMIT
77 #define RECTLIMIT 25            /* pick a number, any number > 8 */
78 #endif
79
80 /* miHandleExposures 
81     generate a region for exposures for areas that were copied from obscured or
82 non-existent areas to non-obscured areas of the destination.  Paint the
83 background for the region, if the destination is a window.
84
85 NOTE:
86      this should generally be called, even if graphicsExposures is false,
87 because this is where bits get recovered from backing store.
88
89 NOTE:
90      added argument 'plane' is used to indicate how exposures from backing
91 store should be accomplished. If plane is 0 (i.e. no bit plane), CopyArea
92 should be used, else a CopyPlane of the indicated plane will be used. The
93 exposing is done by the backing store's GraphicsExpose function, of course.
94
95 */
96
97 RegionPtr
98 miHandleExposures(pSrcDrawable, pDstDrawable,
99                   pGC, srcx, srcy, width, height, dstx, dsty, plane)
100     register DrawablePtr        pSrcDrawable;
101     register DrawablePtr        pDstDrawable;
102     GCPtr                       pGC;
103     int                         srcx, srcy;
104     int                         width, height;
105     int                         dstx, dsty;
106     unsigned long               plane;
107 {
108     register ScreenPtr pscr = pGC->pScreen;
109     RegionPtr prgnSrcClip;      /* drawable-relative source clip */
110     RegionRec rgnSrcRec;
111     RegionPtr prgnDstClip;      /* drawable-relative dest clip */
112     RegionRec rgnDstRec;
113     BoxRec srcBox;              /* unclipped source */
114     RegionRec rgnExposed;       /* exposed region, calculated source-
115                                    relative, made dst relative to
116                                    intersect with visible parts of
117                                    dest and send events to client, 
118                                    and then screen relative to paint 
119                                    the window background
120                                 */
121     WindowPtr pSrcWin;
122     BoxRec expBox;
123     Bool extents;
124
125     /* avoid work if we can */
126     if (!pGC->graphicsExposures &&
127         (pDstDrawable->type == DRAWABLE_PIXMAP) &&
128         ((pSrcDrawable->type == DRAWABLE_PIXMAP) ||
129          (((WindowPtr)pSrcDrawable)->backStorage == NULL)))
130         return NULL;
131         
132     srcBox.x1 = srcx;
133     srcBox.y1 = srcy;
134     srcBox.x2 = srcx+width;
135     srcBox.y2 = srcy+height;
136
137     if (pSrcDrawable->type != DRAWABLE_PIXMAP)
138     {
139         BoxRec TsrcBox;
140
141         TsrcBox.x1 = srcx + pSrcDrawable->x;
142         TsrcBox.y1 = srcy + pSrcDrawable->y;
143         TsrcBox.x2 = TsrcBox.x1 + width;
144         TsrcBox.y2 = TsrcBox.y1 + height;
145         pSrcWin = (WindowPtr) pSrcDrawable;
146         if (pGC->subWindowMode == IncludeInferiors)
147         {
148             prgnSrcClip = NotClippedByChildren (pSrcWin);
149             if ((RECT_IN_REGION(pscr, prgnSrcClip, &TsrcBox)) == rgnIN)
150             {
151                 REGION_DESTROY(pscr, prgnSrcClip);
152                 return NULL;
153             }
154         }
155         else
156         {
157             if ((RECT_IN_REGION(pscr, &pSrcWin->clipList, &TsrcBox)) == rgnIN)
158                 return NULL;
159             prgnSrcClip = &rgnSrcRec;
160             REGION_INIT(pscr, prgnSrcClip, NullBox, 0);
161             REGION_COPY(pscr, prgnSrcClip, &pSrcWin->clipList);
162         }
163         REGION_TRANSLATE(pscr, prgnSrcClip,
164                                 -pSrcDrawable->x, -pSrcDrawable->y);
165     }
166     else
167     {
168         BoxRec  box;
169
170         if ((srcBox.x1 >= 0) && (srcBox.y1 >= 0) &&
171             (srcBox.x2 <= pSrcDrawable->width) &&
172             (srcBox.y2 <= pSrcDrawable->height))
173             return NULL;
174
175         box.x1 = 0;
176         box.y1 = 0;
177         box.x2 = pSrcDrawable->width;
178         box.y2 = pSrcDrawable->height;
179         prgnSrcClip = &rgnSrcRec;
180         REGION_INIT(pscr, prgnSrcClip, &box, 1);
181         pSrcWin = (WindowPtr)NULL;
182     }
183
184     if (pDstDrawable == pSrcDrawable)
185     {
186         prgnDstClip = prgnSrcClip;
187     }
188     else if (pDstDrawable->type != DRAWABLE_PIXMAP)
189     {
190         if (pGC->subWindowMode == IncludeInferiors)
191         {
192             prgnDstClip = NotClippedByChildren((WindowPtr)pDstDrawable);
193         }
194         else
195         {
196             prgnDstClip = &rgnDstRec;
197             REGION_INIT(pscr, prgnDstClip, NullBox, 0);
198             REGION_COPY(pscr, prgnDstClip,
199                                 &((WindowPtr)pDstDrawable)->clipList);
200         }
201         REGION_TRANSLATE(pscr, prgnDstClip,
202                                  -pDstDrawable->x, -pDstDrawable->y);
203     }
204     else
205     {
206         BoxRec  box;
207
208         box.x1 = 0;
209         box.y1 = 0;
210         box.x2 = pDstDrawable->width;
211         box.y2 = pDstDrawable->height;
212         prgnDstClip = &rgnDstRec;
213         REGION_INIT(pscr, prgnDstClip, &box, 1);
214     }
215
216     /* drawable-relative source region */
217     REGION_INIT(pscr, &rgnExposed, &srcBox, 1);
218
219     /* now get the hidden parts of the source box*/
220     REGION_SUBTRACT(pscr, &rgnExposed, &rgnExposed, prgnSrcClip);
221
222     if (pSrcWin && pSrcWin->backStorage)
223     {
224         /*
225          * Copy any areas from the source backing store. Modifies
226          * rgnExposed.
227          */
228         (* pSrcWin->drawable.pScreen->ExposeCopy) ((WindowPtr)pSrcDrawable,
229                                               pDstDrawable,
230                                               pGC,
231                                               &rgnExposed,
232                                               srcx, srcy,
233                                               dstx, dsty,
234                                               plane);
235     }
236     
237     /* move them over the destination */
238     REGION_TRANSLATE(pscr, &rgnExposed, dstx-srcx, dsty-srcy);
239
240     /* intersect with visible areas of dest */
241     REGION_INTERSECT(pscr, &rgnExposed, &rgnExposed, prgnDstClip);
242
243     /*
244      * If we have LOTS of rectangles, we decide to take the extents
245      * and force an exposure on that.  This should require much less
246      * work overall, on both client and server.  This is cheating, but
247      * isn't prohibited by the protocol ("spontaneous combustion" :-)
248      * for windows.
249      */
250     extents = pGC->graphicsExposures &&
251               (REGION_NUM_RECTS(&rgnExposed) > RECTLIMIT) &&
252               (pDstDrawable->type != DRAWABLE_PIXMAP);
253 #ifdef SHAPE
254     if (pSrcWin)
255     {
256         RegionPtr       region;
257         if (!(region = wClipShape (pSrcWin)))
258             region = wBoundingShape (pSrcWin);
259         /*
260          * If you try to CopyArea the extents of a shaped window, compacting the
261          * exposed region will undo all our work!
262          */
263         if (extents && pSrcWin && region &&
264             (RECT_IN_REGION(pscr, region, &srcBox) != rgnIN))
265                 extents = FALSE;
266     }
267 #endif
268     if (extents)
269     {
270         WindowPtr pWin = (WindowPtr)pDstDrawable;
271
272         expBox = *REGION_EXTENTS(pscr, &rgnExposed);
273         REGION_RESET(pscr, &rgnExposed, &expBox);
274         /* need to clear out new areas of backing store */
275         if (pWin->backStorage)
276             (void) (* pWin->drawable.pScreen->ClearBackingStore)(
277                                          pWin,
278                                          expBox.x1,
279                                          expBox.y1,
280                                          expBox.x2 - expBox.x1,
281                                          expBox.y2 - expBox.y1,
282                                          FALSE);
283     }
284     if ((pDstDrawable->type != DRAWABLE_PIXMAP) &&
285         (((WindowPtr)pDstDrawable)->backgroundState != None))
286     {
287         WindowPtr pWin = (WindowPtr)pDstDrawable;
288
289         /* make the exposed area screen-relative */
290         REGION_TRANSLATE(pscr, &rgnExposed, 
291                                  pDstDrawable->x, pDstDrawable->y);
292
293         if (extents)
294         {
295             /* PaintWindowBackground doesn't clip, so we have to */
296             REGION_INTERSECT(pscr, &rgnExposed, &rgnExposed, &pWin->clipList);
297         }
298         (*pWin->drawable.pScreen->PaintWindowBackground)(
299                         (WindowPtr)pDstDrawable, &rgnExposed, PW_BACKGROUND);
300
301         if (extents)
302         {
303             REGION_RESET(pscr, &rgnExposed, &expBox);
304         }
305         else
306             REGION_TRANSLATE(pscr, &rgnExposed,
307                                      -pDstDrawable->x, -pDstDrawable->y);
308     }
309     if (prgnDstClip == &rgnDstRec)
310     {
311         REGION_UNINIT(pscr, prgnDstClip);
312     }
313     else if (prgnDstClip != prgnSrcClip)
314     {
315         REGION_DESTROY(pscr, prgnDstClip);
316     }
317
318     if (prgnSrcClip == &rgnSrcRec)
319     {
320         REGION_UNINIT(pscr, prgnSrcClip);
321     }
322     else
323     {
324         REGION_DESTROY(pscr, prgnSrcClip);
325     }
326
327     if (pGC->graphicsExposures)
328     {
329         /* don't look */
330         RegionPtr exposed = REGION_CREATE(pscr, NullBox, 0);
331         *exposed = rgnExposed;
332         return exposed;
333     }
334     else
335     {
336         REGION_UNINIT(pscr, &rgnExposed);
337         return NULL;
338     }
339 }
340
341 /* send GraphicsExpose events, or a NoExpose event, based on the region */
342
343 void
344 miSendGraphicsExpose (client, pRgn, drawable, major, minor)
345     ClientPtr   client;
346     RegionPtr   pRgn;
347     XID         drawable;
348     int major;
349     int minor;
350 {
351     if (pRgn && !REGION_NIL(pRgn))
352     {
353         xEvent *pEvent;
354         register xEvent *pe;
355         register BoxPtr pBox;
356         register int i;
357         int numRects;
358
359         numRects = REGION_NUM_RECTS(pRgn);
360         pBox = REGION_RECTS(pRgn);
361         if(!(pEvent = (xEvent *)ALLOCATE_LOCAL(numRects * sizeof(xEvent))))
362                 return;
363         pe = pEvent;
364
365         for (i=1; i<=numRects; i++, pe++, pBox++)
366         {
367             pe->u.u.type = GraphicsExpose;
368             pe->u.graphicsExposure.drawable = drawable;
369             pe->u.graphicsExposure.x = pBox->x1;
370             pe->u.graphicsExposure.y = pBox->y1;
371             pe->u.graphicsExposure.width = pBox->x2 - pBox->x1;
372             pe->u.graphicsExposure.height = pBox->y2 - pBox->y1;
373             pe->u.graphicsExposure.count = numRects - i;
374             pe->u.graphicsExposure.majorEvent = major;
375             pe->u.graphicsExposure.minorEvent = minor;
376         }
377         TryClientEvents(client, pEvent, numRects,
378                             (Mask)0, NoEventMask, NullGrab);
379         DEALLOCATE_LOCAL(pEvent);
380     }
381     else
382     {
383         xEvent event;
384         event.u.u.type = NoExpose;
385         event.u.noExposure.drawable = drawable;
386         event.u.noExposure.majorEvent = major;
387         event.u.noExposure.minorEvent = minor;
388         TryClientEvents(client, &event, 1,
389             (Mask)0, NoEventMask, NullGrab);
390     }
391 }
392
393 void
394 miSendExposures(pWin, pRgn, dx, dy)
395     WindowPtr pWin;
396     RegionPtr pRgn;
397     register int dx, dy;
398 {
399     register BoxPtr pBox;
400     int numRects;
401     register xEvent *pEvent, *pe;
402     register int i;
403
404     pBox = REGION_RECTS(pRgn);
405     numRects = REGION_NUM_RECTS(pRgn);
406     if(!(pEvent = (xEvent *) ALLOCATE_LOCAL(numRects * sizeof(xEvent))))
407         return;
408
409     for (i=numRects, pe = pEvent; --i >= 0; pe++, pBox++)
410     {
411         pe->u.u.type = Expose;
412         pe->u.expose.window = pWin->drawable.id;
413         pe->u.expose.x = pBox->x1 - dx;
414         pe->u.expose.y = pBox->y1 - dy;
415         pe->u.expose.width = pBox->x2 - pBox->x1;
416         pe->u.expose.height = pBox->y2 - pBox->y1;
417         pe->u.expose.count = i;
418     }
419     DeliverEvents(pWin, pEvent, numRects, NullWindow);
420     DEALLOCATE_LOCAL(pEvent);
421 }
422
423 void 
424 miWindowExposures(pWin, prgn, other_exposed)
425     WindowPtr pWin;
426     register RegionPtr prgn, other_exposed;
427 {
428     RegionPtr   exposures = prgn;
429     if (pWin->backStorage && prgn)
430         /*
431          * in some cases, backing store will cause a different
432          * region to be exposed than needs to be repainted
433          * (like when a window is mapped).  RestoreAreas is
434          * allowed to return a region other than prgn,
435          * in which case this routine will free the resultant
436          * region.  If exposures is null, then no events will
437          * be sent to the client; if prgn is empty
438          * no areas will be repainted.
439          */
440         exposures = (*pWin->drawable.pScreen->RestoreAreas)(pWin, prgn);
441     if ((prgn && !REGION_NIL(prgn)) || 
442         (exposures && !REGION_NIL(exposures)) || other_exposed)
443     {
444         RegionRec   expRec;
445         int         clientInterested;
446
447         /*
448          * Restore from backing-store FIRST.
449          */
450         clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) & ExposureMask;
451         if (other_exposed)
452         {
453             if (exposures)
454             {
455                 REGION_UNION(pWin->drawable.pScreen, other_exposed,
456                                                   exposures,
457                                                   other_exposed);
458                 if (exposures != prgn)
459                     REGION_DESTROY(pWin->drawable.pScreen, exposures);
460             }
461             exposures = other_exposed;
462         }
463         if (clientInterested && exposures && (REGION_NUM_RECTS(exposures) > RECTLIMIT))
464         {
465             /*
466              * If we have LOTS of rectangles, we decide to take the extents
467              * and force an exposure on that.  This should require much less
468              * work overall, on both client and server.  This is cheating, but
469              * isn't prohibited by the protocol ("spontaneous combustion" :-).
470              */
471             BoxRec box;
472
473             box = *REGION_EXTENTS( pWin->drawable.pScreen, exposures);
474             if (exposures == prgn) {
475                 exposures = &expRec;
476                 REGION_INIT( pWin->drawable.pScreen, exposures, &box, 1);
477                 REGION_RESET( pWin->drawable.pScreen, prgn, &box);
478             } else {
479                 REGION_RESET( pWin->drawable.pScreen, exposures, &box);
480                 REGION_UNION( pWin->drawable.pScreen, prgn, prgn, exposures);
481             }
482             /* PaintWindowBackground doesn't clip, so we have to */
483             REGION_INTERSECT( pWin->drawable.pScreen, prgn, prgn, &pWin->clipList);
484             /* need to clear out new areas of backing store, too */
485             if (pWin->backStorage)
486                 (void) (* pWin->drawable.pScreen->ClearBackingStore)(
487                                              pWin,
488                                              box.x1 - pWin->drawable.x,
489                                              box.y1 - pWin->drawable.y,
490                                              box.x2 - box.x1,
491                                              box.y2 - box.y1,
492                                              FALSE);
493         }
494         if (prgn && !REGION_NIL(prgn))
495             (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, prgn, PW_BACKGROUND);
496         if (clientInterested && exposures && !REGION_NIL(exposures))
497             miSendExposures(pWin, exposures,
498                             pWin->drawable.x, pWin->drawable.y);
499         if (exposures == &expRec)
500         {
501             REGION_UNINIT( pWin->drawable.pScreen, exposures);
502         }
503         else if (exposures && exposures != prgn && exposures != other_exposed)
504             REGION_DESTROY( pWin->drawable.pScreen, exposures);
505         if (prgn)
506             REGION_EMPTY( pWin->drawable.pScreen, prgn);
507     }
508     else if (exposures && exposures != prgn)
509         REGION_DESTROY( pWin->drawable.pScreen, exposures);
510 }
511
512
513 /*
514     this code is highly unlikely.  it is not haile selassie.
515
516     there is some hair here.  we can't just use the window's
517 clip region as it is, because if we are painting the border,
518 the border is not in the client area and so we will be excluded
519 when we validate the GC, and if we are painting a parent-relative
520 background, the area we want to paint is in some other window.
521 since we trust the code calling us to tell us to paint only areas
522 that are really ours, we will temporarily give the window a
523 clipList the size of the whole screen and an origin at (0,0).
524 this more or less assumes that ddX code will do translation
525 based on the window's absolute position, and that ValidateGC will
526 look at clipList, and that no other fields from the
527 window will be used.  it's not possible to just draw
528 in the root because it may be a different depth.
529
530 to get the tile to align correctly we set the GC's tile origin to
531 be the (x,y) of the window's upper left corner, after which we
532 get the right bits when drawing into the root.
533
534 because the clip_mask is being set to None, we may call DoChangeGC with
535 fPointer set true, thus we no longer need to install the background or
536 border tile in the resource table.
537 */
538
539 static RESTYPE ResType = 0;
540 static int numGCs = 0;
541 static GCPtr    screenContext[MAXSCREENS];
542
543 /*ARGSUSED*/
544 static int
545 tossGC (value, id)
546 pointer value;
547 XID id;
548 {
549     GCPtr pGC = (GCPtr)value;
550     screenContext[pGC->pScreen->myNum] = (GCPtr)NULL;
551     FreeGC (pGC, id);
552     numGCs--;
553     if (!numGCs)
554         ResType = 0;
555 }
556
557
558 void
559 miPaintWindow(pWin, prgn, what)
560 register WindowPtr pWin;
561 RegionPtr prgn;
562 int what;
563 {
564     int status;
565
566     Bool usingScratchGC = FALSE;
567     WindowPtr pRoot;
568         
569 #define FUNCTION        0
570 #define FOREGROUND      1
571 #define TILE            2
572 #define FILLSTYLE       3
573 #define ABSX            4
574 #define ABSY            5
575 #define CLIPMASK        6
576 #define SUBWINDOW       7
577 #define COUNT_BITS      8
578
579     ChangeGCVal gcval[7];
580     ChangeGCVal newValues [COUNT_BITS];
581
582     BITS32 gcmask, index, mask;
583     RegionRec prgnWin;
584     DDXPointRec oldCorner;
585     BoxRec box;
586     WindowPtr   pBgWin;
587     GCPtr pGC;
588     register int i;
589     register BoxPtr pbox;
590     register ScreenPtr pScreen = pWin->drawable.pScreen;
591     register xRectangle *prect;
592     int numRects;
593
594     gcmask = 0;
595
596     if (what == PW_BACKGROUND)
597     {
598         switch (pWin->backgroundState) {
599         case None:
600             return;
601         case ParentRelative:
602             (*pWin->parent->drawable.pScreen->PaintWindowBackground)(pWin->parent, prgn, what);
603             return;
604         case BackgroundPixel:
605             newValues[FOREGROUND].val = pWin->background.pixel;
606             newValues[FILLSTYLE].val  = FillSolid;
607             gcmask |= GCForeground | GCFillStyle;
608             break;
609         case BackgroundPixmap:
610             newValues[TILE].ptr = (pointer)pWin->background.pixmap;
611             newValues[FILLSTYLE].val = FillTiled;
612             gcmask |= GCTile | GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin;
613             break;
614         }
615     }
616     else
617     {
618         if (pWin->borderIsPixel)
619         {
620             newValues[FOREGROUND].val = pWin->border.pixel;
621             newValues[FILLSTYLE].val  = FillSolid;
622             gcmask |= GCForeground | GCFillStyle;
623         }
624         else
625         {
626             newValues[TILE].ptr = (pointer)pWin->border.pixmap;
627             newValues[FILLSTYLE].val = FillTiled;
628             gcmask |= GCTile | GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin;
629         }
630     }
631
632     prect = (xRectangle *)ALLOCATE_LOCAL(REGION_NUM_RECTS(prgn) *
633                                          sizeof(xRectangle));
634     if (!prect)
635         return;
636
637     newValues[FUNCTION].val = GXcopy;
638     gcmask |= GCFunction | GCClipMask;
639
640     i = pScreen->myNum;
641     pRoot = WindowTable[i];
642
643     pBgWin = pWin;
644     if (what == PW_BORDER)
645     {
646         while (pBgWin->backgroundState == ParentRelative)
647             pBgWin = pBgWin->parent;
648     }
649
650     if ((pWin->drawable.depth != pRoot->drawable.depth) ||
651         (pWin->drawable.bitsPerPixel != pRoot->drawable.bitsPerPixel))
652     {
653         usingScratchGC = TRUE;
654         pGC = GetScratchGC(pWin->drawable.depth, pWin->drawable.pScreen);
655         if (!pGC)
656         {
657             DEALLOCATE_LOCAL(prect);
658             return;
659         }
660         /*
661          * mash the clip list so we can paint the border by
662          * mangling the window in place, pretending it
663          * spans the entire screen
664          */
665         if (what == PW_BORDER)
666         {
667             prgnWin = pWin->clipList;
668             oldCorner.x = pWin->drawable.x;
669             oldCorner.y = pWin->drawable.y;
670             pWin->drawable.x = pWin->drawable.y = 0;
671             box.x1 = 0;
672             box.y1 = 0;
673             box.x2 = pScreen->width;
674             box.y2 = pScreen->height;
675             REGION_INIT(pScreen, &pWin->clipList, &box, 1);
676             pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
677             newValues[ABSX].val = pBgWin->drawable.x;
678             newValues[ABSY].val = pBgWin->drawable.y;
679         }
680         else
681         {
682             newValues[ABSX].val = 0;
683             newValues[ABSY].val = 0;
684         }
685     } else {
686         /*
687          * draw the background to the root window
688          */
689         if (screenContext[i] == (GCPtr)NULL)
690         {
691             if (!ResType && !(ResType = CreateNewResourceType(tossGC)))
692                 return;
693             screenContext[i] = CreateGC((DrawablePtr)pWin, (BITS32) 0,
694                                         (XID *)NULL, &status);
695             if (!screenContext[i])
696                 return;
697             numGCs++;
698             if (!AddResource(FakeClientID(0), ResType,
699                              (pointer)screenContext[i]))
700                 return;
701         }
702         pGC = screenContext[i];
703         newValues[SUBWINDOW].val = IncludeInferiors;
704         newValues[ABSX].val = pBgWin->drawable.x;
705         newValues[ABSY].val = pBgWin->drawable.y;
706         gcmask |= GCSubwindowMode;
707         pWin = pRoot;
708     }
709     
710     if (pWin->backStorage)
711         (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack);
712
713     mask = gcmask;
714     gcmask = 0;
715     i = 0;
716     while (mask) {
717         index = lowbit (mask);
718         mask &= ~index;
719         switch (index) {
720         case GCFunction:
721             if (pGC->alu != newValues[FUNCTION].val) {
722                 gcmask |= index;
723                 gcval[i++].val = newValues[FUNCTION].val;
724             }
725             break;
726         case GCTileStipXOrigin:
727             if ( pGC->patOrg.x != newValues[ABSX].val) {
728                 gcmask |= index;
729                 gcval[i++].val = newValues[ABSX].val;
730             }
731             break;
732         case GCTileStipYOrigin:
733             if ( pGC->patOrg.y != newValues[ABSY].val) {
734                 gcmask |= index;
735                 gcval[i++].val = newValues[ABSY].val;
736             }
737             break;
738         case GCClipMask:
739             if ( pGC->clientClipType != CT_NONE) {
740                 gcmask |= index;
741                 gcval[i++].val = CT_NONE;
742             }
743             break;
744         case GCSubwindowMode:
745             if ( pGC->subWindowMode != newValues[SUBWINDOW].val) {
746                 gcmask |= index;
747                 gcval[i++].val = newValues[SUBWINDOW].val;
748             }
749             break;
750         case GCTile:
751             if (pGC->tileIsPixel || pGC->tile.pixmap != newValues[TILE].ptr)
752             {
753                 gcmask |= index;
754                 gcval[i++].ptr = newValues[TILE].ptr;
755             }
756             break;
757         case GCFillStyle:
758             if ( pGC->fillStyle != newValues[FILLSTYLE].val) {
759                 gcmask |= index;
760                 gcval[i++].val = newValues[FILLSTYLE].val;
761             }
762             break;
763         case GCForeground:
764             if ( pGC->fgPixel != newValues[FOREGROUND].val) {
765                 gcmask |= index;
766                 gcval[i++].val = newValues[FOREGROUND].val;
767             }
768             break;
769         }
770     }
771
772     if (gcmask)
773         dixChangeGC(NullClient, pGC, gcmask, NULL, gcval);
774
775     if (pWin->drawable.serialNumber != pGC->serialNumber)
776         ValidateGC((DrawablePtr)pWin, pGC);
777
778     numRects = REGION_NUM_RECTS(prgn);
779     pbox = REGION_RECTS(prgn);
780     for (i= numRects; --i >= 0; pbox++, prect++)
781     {
782         prect->x = pbox->x1 - pWin->drawable.x;
783         prect->y = pbox->y1 - pWin->drawable.y;
784         prect->width = pbox->x2 - pbox->x1;
785         prect->height = pbox->y2 - pbox->y1;
786     }
787     prect -= numRects;
788     (*pGC->ops->PolyFillRect)((DrawablePtr)pWin, pGC, numRects, prect);
789     DEALLOCATE_LOCAL(prect);
790
791     if (pWin->backStorage)
792         (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeNothing);
793
794     if (usingScratchGC)
795     {
796         if (what == PW_BORDER)
797         {
798             REGION_UNINIT(pScreen, &pWin->clipList);
799             pWin->clipList = prgnWin;
800             pWin->drawable.x = oldCorner.x;
801             pWin->drawable.y = oldCorner.y;
802             pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
803         }
804         FreeScratchGC(pGC);
805     }
806 }
807
808
809 /* MICLEARDRAWABLE -- sets the entire drawable to the background color of
810  * the GC.  Useful when we have a scratch drawable and need to initialize 
811  * it. */
812 miClearDrawable(pDraw, pGC)
813     DrawablePtr pDraw;
814     GCPtr       pGC;
815 {
816     XID fg = pGC->fgPixel;
817     XID bg = pGC->bgPixel;
818     xRectangle rect;
819
820     rect.x = 0;
821     rect.y = 0;
822     rect.width = pDraw->width;
823     rect.height = pDraw->height;
824     DoChangeGC(pGC, GCForeground, &bg, 0);
825     ValidateGC(pDraw, pGC);
826     (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
827     DoChangeGC(pGC, GCForeground, &fg, 0);
828     ValidateGC(pDraw, pGC);
829 }