Simplify error-handling in dixChangeGC.
[meego-developer-tools:meego-simulator-xephyr.git] / dix / gc.c
1 /***********************************************************
2
3 Copyright 1987, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24
25
26 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                         All Rights Reserved
29
30 Permission to use, copy, modify, and distribute this software and its 
31 documentation for any purpose and without fee is hereby granted, 
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in 
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.  
37
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44 SOFTWARE.
45
46 ******************************************************************/
47
48
49 #ifdef HAVE_DIX_CONFIG_H
50 #include <dix-config.h>
51 #endif
52
53 #include <X11/X.h>
54 #include <X11/Xmd.h>
55 #include <X11/Xproto.h>
56 #include "misc.h"
57 #include "resource.h"
58 #include "gcstruct.h"
59 #include "pixmapstr.h"
60 #include "dixfontstr.h"
61 #include "scrnintstr.h"
62 #include "region.h"
63
64 #include "privates.h"
65 #include "dix.h"
66 #include "xace.h"
67 #include <assert.h>
68
69 extern XID clientErrorValue;
70 extern FontPtr defaultFont;
71
72 static Bool CreateDefaultTile(GCPtr pGC);
73
74 static unsigned char DefaultDash[2] = {4, 4};
75
76 void
77 ValidateGC(DrawablePtr pDraw, GC *pGC)
78 {
79     (*pGC->funcs->ValidateGC) (pGC, pGC->stateChanges, pDraw);
80     pGC->stateChanges = 0;
81     pGC->serialNumber = pDraw->serialNumber;
82 }
83
84
85 /* dixChangeGC(client, pGC, mask, pC32, pUnion)
86  * 
87  * This function was created as part of the Security extension
88  * implementation.  The client performing the gc change must be passed so
89  * that access checks can be performed on any tiles, stipples, or fonts
90  * that are specified.  ddxen can call this too; they should normally
91  * pass NullClient for the client since any access checking should have
92  * already been done at a higher level.
93  * 
94  * Since we had to create a new function anyway, we decided to change the
95  * way the list of gc values is passed to eliminate the compiler warnings
96  * caused by the DoChangeGC interface.  You can pass the values via pC32
97  * or pUnion, but not both; one of them must be NULL.  If you don't need
98  * to pass any pointers, you can use either one:
99  * 
100  *     example calling dixChangeGC using pC32 parameter
101  *
102  *     CARD32 v[2];
103  *     v[0] = foreground;
104  *     v[1] = background;
105  *     dixChangeGC(client, pGC, GCForeground|GCBackground, v, NULL);
106  * 
107  *     example calling dixChangeGC using pUnion parameter;
108  *     same effect as above
109  *
110  *     ChangeGCVal v[2];
111  *     v[0].val = foreground;
112  *     v[1].val = background;
113  *     dixChangeGC(client, pGC, GCForeground|GCBackground, NULL, v);
114  * 
115  * However, if you need to pass a pointer to a pixmap or font, you MUST
116  * use the pUnion parameter.
117  * 
118  *     example calling dixChangeGC passing pointers in the value list
119  *     v[1].ptr is a pointer to a pixmap
120  *
121  *     ChangeGCVal v[2];
122  *     v[0].val = FillTiled;
123  *     v[1].ptr = pPixmap;
124  *     dixChangeGC(client, pGC, GCFillStyle|GCTile, NULL, v);
125  * 
126  * Note: we could have gotten by with just the pUnion parameter, but on
127  * 64 bit machines that would have forced us to copy the value list that
128  * comes in the ChangeGC request.
129  * 
130  * Ideally, we'd change all the DoChangeGC calls to dixChangeGC, but this
131  * is far too many changes to consider at this time, so we've only
132  * changed the ones that caused compiler warnings.  New code should use
133  * dixChangeGC.
134  * 
135  * dpw
136  */
137
138 #define NEXTVAL(_type, _var) { \
139       if (pC32) _var = (_type)*pC32++; \
140       else { \
141         _var = (_type)(pUnion->val); pUnion++; \
142       } \
143     }
144
145 #define NEXT_PTR(_type, _var) { \
146     assert(pUnion); _var = (_type)pUnion->ptr; pUnion++; }
147
148 int
149 dixChangeGC(ClientPtr client, GC *pGC, BITS32 mask, CARD32 *pC32, ChangeGCValPtr pUnion)
150 {
151     BITS32      index2;
152     int         rc, error = 0;
153     PixmapPtr   pPixmap;
154     BITS32      maskQ;
155
156     assert( (pC32 && !pUnion) || (!pC32 && pUnion) );
157     pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
158
159     maskQ = mask;       /* save these for when we walk the GCque */
160     while (mask && !error) 
161     {
162         index2 = (BITS32) lowbit (mask);
163         mask &= ~index2;
164         pGC->stateChanges |= index2;
165         switch (index2)
166         {
167             case GCFunction:
168             {
169                 CARD8 newalu;
170                 NEXTVAL(CARD8, newalu);
171                 if (newalu <= GXset)
172                     pGC->alu = newalu;
173                 else
174                 {
175                     clientErrorValue = newalu;
176                     error = BadValue;
177                 }
178                 break;
179             }
180             case GCPlaneMask:
181                 NEXTVAL(unsigned long, pGC->planemask);
182                 break;
183             case GCForeground:
184                 NEXTVAL(unsigned long, pGC->fgPixel);
185                 /*
186                  * this is for CreateGC
187                  */
188                 if (!pGC->tileIsPixel && !pGC->tile.pixmap)
189                 {
190                     pGC->tileIsPixel = TRUE;
191                     pGC->tile.pixel = pGC->fgPixel;
192                 }
193                 break;
194             case GCBackground:
195                 NEXTVAL(unsigned long, pGC->bgPixel);
196                 break;
197             case GCLineWidth:           /* ??? line width is a CARD16 */
198                  NEXTVAL(CARD16, pGC->lineWidth);
199                 break;
200             case GCLineStyle:
201             {
202                 unsigned int newlinestyle;
203                 NEXTVAL(unsigned int, newlinestyle);
204                 if (newlinestyle <= LineDoubleDash)
205                     pGC->lineStyle = newlinestyle;
206                 else
207                 {
208                     clientErrorValue = newlinestyle;
209                     error = BadValue;
210                 }
211                 break;
212             }
213             case GCCapStyle:
214             {
215                 unsigned int newcapstyle;
216                 NEXTVAL(unsigned int, newcapstyle);
217                 if (newcapstyle <= CapProjecting)
218                     pGC->capStyle = newcapstyle;
219                 else
220                 {
221                     clientErrorValue = newcapstyle;
222                     error = BadValue;
223                 }
224                 break;
225             }
226             case GCJoinStyle:
227             {
228                 unsigned int newjoinstyle;
229                 NEXTVAL(unsigned int, newjoinstyle);
230                 if (newjoinstyle <= JoinBevel)
231                     pGC->joinStyle = newjoinstyle;
232                 else
233                 {
234                     clientErrorValue = newjoinstyle;
235                     error = BadValue;
236                 }
237                 break;
238             }
239             case GCFillStyle:
240             {
241                 unsigned int newfillstyle;
242                 NEXTVAL(unsigned int, newfillstyle);
243                 if (newfillstyle <= FillOpaqueStippled)
244                     pGC->fillStyle = newfillstyle;
245                 else
246                 {
247                     clientErrorValue = newfillstyle;
248                     error = BadValue;
249                 }
250                 break;
251             }
252             case GCFillRule:
253             {
254                 unsigned int newfillrule;
255                 NEXTVAL(unsigned int, newfillrule);
256                 if (newfillrule <= WindingRule)
257                     pGC->fillRule = newfillrule;
258                 else
259                 {
260                     clientErrorValue = newfillrule;
261                     error = BadValue;
262                 }
263                 break;
264             }
265             case GCTile:
266                 if (pUnion)
267                 {
268                     NEXT_PTR(PixmapPtr, pPixmap);
269                 }
270                 else
271                 {
272                     XID newpix;
273                     NEXTVAL(XID, newpix);
274                     rc = dixLookupResourceByType((pointer *)&pPixmap, newpix,
275                                            RT_PIXMAP, client, DixReadAccess);
276                     if (rc != Success)
277                     {
278                         clientErrorValue = newpix;
279                         error = (rc == BadValue) ? BadPixmap : rc;
280                         break;
281                     }
282                 }
283                 if ((pPixmap->drawable.depth != pGC->depth) ||
284                     (pPixmap->drawable.pScreen != pGC->pScreen))
285                 {
286                     error = BadMatch;
287                 }
288                 else
289                 {
290                     pPixmap->refcnt++;
291                     if (!pGC->tileIsPixel)
292                         (* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
293                     pGC->tileIsPixel = FALSE;
294                     pGC->tile.pixmap = pPixmap;
295                 }
296                 break;
297             case GCStipple:
298                 if (pUnion)
299                 {
300                     NEXT_PTR(PixmapPtr, pPixmap);
301                 }
302                 else
303                 {
304                     XID newstipple;
305                     NEXTVAL(XID, newstipple)
306                     rc = dixLookupResourceByType((pointer *)&pPixmap, newstipple,
307                                            RT_PIXMAP, client, DixReadAccess);
308                     if (rc != Success)
309                     {
310                         clientErrorValue = newstipple;
311                         error = (rc == BadValue) ? BadPixmap : rc;
312                         break;
313                     }
314                 }
315                 if ((pPixmap->drawable.depth != 1) ||
316                     (pPixmap->drawable.pScreen != pGC->pScreen))
317                 {
318                     error = BadMatch;
319                 }
320                 else
321                 {
322                     pPixmap->refcnt++;
323                     if (pGC->stipple)
324                         (* pGC->pScreen->DestroyPixmap)(pGC->stipple);
325                     pGC->stipple = pPixmap;
326                 }
327                 break;
328             case GCTileStipXOrigin:
329                 NEXTVAL(INT16, pGC->patOrg.x);
330                 break;
331             case GCTileStipYOrigin:
332                 NEXTVAL(INT16, pGC->patOrg.y);
333                 break;
334             case GCFont:
335             {
336                 FontPtr pFont;
337                 if (pUnion)
338                 {
339                     NEXT_PTR(FontPtr, pFont);
340                 }
341                 else
342                 {
343                     XID newfont;
344                     NEXTVAL(XID, newfont)
345                     rc = dixLookupResourceByType((pointer *)&pFont, newfont,
346                                            RT_FONT, client, DixUseAccess);
347                     if (rc != Success)
348                     {
349                         clientErrorValue = newfont;
350                         error = (rc == BadValue) ? BadFont : rc;
351                         break;
352                     }
353                 }
354                 pFont->refcnt++;
355                 if (pGC->font)
356                     CloseFont(pGC->font, (Font)0);
357                 pGC->font = pFont;
358                 break;
359             }
360             case GCSubwindowMode:
361             {
362                 unsigned int newclipmode;
363                 NEXTVAL(unsigned int, newclipmode);
364                 if (newclipmode <= IncludeInferiors)
365                     pGC->subWindowMode = newclipmode;
366                 else
367                 {
368                     clientErrorValue = newclipmode;
369                     error = BadValue;
370                 }
371                 break;
372             }
373             case GCGraphicsExposures:
374             {
375                 unsigned int newge;
376                 NEXTVAL(unsigned int, newge);
377                 if (newge <= xTrue)
378                     pGC->graphicsExposures = newge;
379                 else
380                 {
381                     clientErrorValue = newge;
382                     error = BadValue;
383                 }
384                 break;
385             }
386             case GCClipXOrigin:
387                 NEXTVAL(INT16, pGC->clipOrg.x);
388                 break;
389             case GCClipYOrigin:
390                 NEXTVAL(INT16, pGC->clipOrg.y);
391                 break;
392             case GCClipMask:
393                 if (pUnion)
394                 {
395                     NEXT_PTR(PixmapPtr, pPixmap);
396                 }
397                 else
398                 {
399                     Pixmap pid;
400                     NEXTVAL(Pixmap, pid)
401                     if (pid == None)
402                         pPixmap = NullPixmap;
403                     else {
404                         rc = dixLookupResourceByType((pointer *)&pPixmap, pid,
405                                                RT_PIXMAP, client,
406                                                DixReadAccess);
407                         if (rc != Success) {
408                             clientErrorValue = pid;
409                             error = (rc == BadValue) ? BadPixmap : rc;
410                             break;
411                         }
412                     }
413                 }
414
415                 if (pPixmap)
416                 {
417                     if ((pPixmap->drawable.depth != 1) ||
418                         (pPixmap->drawable.pScreen != pGC->pScreen))
419                     {
420                         error = BadMatch;
421                         break;
422                     }
423                     pPixmap->refcnt++;
424                 }
425                 (*pGC->funcs->ChangeClip)(pGC, pPixmap ? CT_PIXMAP : CT_NONE,
426                                           (pointer)pPixmap, 0);
427                 break;
428             case GCDashOffset:
429                 NEXTVAL(INT16, pGC->dashOffset);
430                 break;
431             case GCDashList:
432             {
433                 CARD8 newdash;
434                 NEXTVAL(CARD8, newdash);
435                 if (newdash == 4)
436                 {
437                     if (pGC->dash != DefaultDash)
438                     {
439                         xfree(pGC->dash);
440                         pGC->numInDashList = 2;
441                         pGC->dash = DefaultDash;
442                     }
443                 }
444                 else if (newdash != 0)
445                 {
446                     unsigned char *dash;
447
448                     dash = xalloc(2 * sizeof(unsigned char));
449                     if (dash)
450                     {
451                         if (pGC->dash != DefaultDash)
452                             xfree(pGC->dash);
453                         pGC->numInDashList = 2;
454                         pGC->dash = dash;
455                         dash[0] = newdash;
456                         dash[1] = newdash;
457                     }
458                     else
459                         error = BadAlloc;
460                 }
461                 else
462                 {
463                    clientErrorValue = newdash;
464                    error = BadValue;
465                 }
466                 break;
467             }
468             case GCArcMode:
469             {
470                 unsigned int newarcmode;
471                 NEXTVAL(unsigned int, newarcmode);
472                 if (newarcmode <= ArcPieSlice)
473                     pGC->arcMode = newarcmode;
474                 else
475                 {
476                     clientErrorValue = newarcmode;
477                     error = BadValue;
478                 }
479                 break;
480             }
481             default:
482                 clientErrorValue = maskQ;
483                 error = BadValue;
484                 break;
485         }
486     } /* end while mask && !error */
487
488     if (pGC->fillStyle == FillTiled && pGC->tileIsPixel)
489     {
490         if (!CreateDefaultTile (pGC))
491         {
492             pGC->fillStyle = FillSolid;
493             error = BadAlloc;
494         }
495     }
496     (*pGC->funcs->ChangeGC)(pGC, maskQ);
497     return error;
498 }
499
500 #undef NEXTVAL
501 #undef NEXT_PTR
502
503 /* Publically defined entry to ChangeGC.  Just calls dixChangeGC and tells
504  * it that all of the entries are constants or IDs */
505 int
506 ChangeGC(GC *pGC, BITS32 mask, XID *pval)
507 {
508     return (dixChangeGC(NullClient, pGC, mask, pval, NULL));
509 }
510
511 /* DoChangeGC(pGC, mask, pval, fPointer)
512    mask is a set of bits indicating which values to change.
513    pval contains an appropriate value for each mask.
514    fPointer is true if the values for tiles, stipples, fonts or clipmasks
515    are pointers instead of IDs.  Note: if you are passing pointers you
516    MUST declare the array of values as type pointer!  Other data types
517    may not be large enough to hold pointers on some machines.  Yes,
518    this means you have to cast to (XID *) when you pass the array to
519    DoChangeGC.  Similarly, if you are not passing pointers (fPointer = 0) you
520    MUST declare the array as type XID (not unsigned long!), or again the wrong
521    size data type may be used.  To avoid this cruftiness, use dixChangeGC
522    above.
523
524    if there is an error, the value is marked as changed 
525    anyway, which is probably wrong, but infrequent.
526
527 NOTE:
528         all values sent over the protocol for ChangeGC requests are
529 32 bits long
530 */
531 int
532 DoChangeGC(GC *pGC, BITS32 mask, XID *pval, int fPointer)
533 {
534     if (fPointer)
535     /* XXX might be a problem on 64 bit big-endian servers */
536         return dixChangeGC(NullClient, pGC, mask, NULL, (ChangeGCValPtr)pval);
537     else
538         return dixChangeGC(NullClient, pGC, mask, pval, NULL);
539 }
540
541
542 /* CreateGC(pDrawable, mask, pval, pStatus)
543    creates a default GC for the given drawable, using mask to fill
544    in any non-default values.
545    Returns a pointer to the new GC on success, NULL otherwise.
546    returns status of non-default fields in pStatus
547 BUG:
548    should check for failure to create default tile
549
550 */
551 GCPtr
552 CreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus,
553          XID gcid, ClientPtr client)
554 {
555     GCPtr pGC;
556
557     pGC = xalloc(sizeof(GC));
558     if (!pGC)
559     {
560         *pStatus = BadAlloc;
561         return (GCPtr)NULL;
562     }
563
564     pGC->pScreen = pDrawable->pScreen;
565     pGC->depth = pDrawable->depth;
566     pGC->alu = GXcopy; /* dst <- src */
567     pGC->planemask = ~0;
568     pGC->serialNumber = GC_CHANGE_SERIAL_BIT;
569     pGC->funcs = 0;
570     pGC->devPrivates = NULL;
571     pGC->fgPixel = 0;
572     pGC->bgPixel = 1;
573     pGC->lineWidth = 0;
574     pGC->lineStyle = LineSolid;
575     pGC->capStyle = CapButt;
576     pGC->joinStyle = JoinMiter;
577     pGC->fillStyle = FillSolid;
578     pGC->fillRule = EvenOddRule;
579     pGC->arcMode = ArcPieSlice;
580     pGC->tile.pixel = 0;
581     pGC->tile.pixmap = NullPixmap;
582     if (mask & GCForeground)
583     {
584         /*
585          * magic special case -- ChangeGC checks for this condition
586          * and snags the Foreground value to create a pseudo default-tile
587          */
588         pGC->tileIsPixel = FALSE;
589     }
590     else
591     {
592         pGC->tileIsPixel = TRUE;
593     }
594
595     pGC->patOrg.x = 0;
596     pGC->patOrg.y = 0;
597     pGC->subWindowMode = ClipByChildren;
598     pGC->graphicsExposures = TRUE;
599     pGC->clipOrg.x = 0;
600     pGC->clipOrg.y = 0;
601     pGC->clientClipType = CT_NONE;
602     pGC->clientClip = (pointer)NULL;
603     pGC->numInDashList = 2;
604     pGC->dash = DefaultDash;
605     pGC->dashOffset = 0;
606     pGC->lastWinOrg.x = 0;
607     pGC->lastWinOrg.y = 0;
608
609     /* use the default font and stipple */
610     pGC->font = defaultFont;
611     defaultFont->refcnt++;
612     pGC->stipple = pGC->pScreen->PixmapPerDepth[0];
613     pGC->stipple->refcnt++;
614
615     /* security creation/labeling check */
616     *pStatus = XaceHook(XACE_RESOURCE_ACCESS, client, gcid, RT_GC, pGC,
617                         RT_NONE, NULL, DixCreateAccess|DixSetAttrAccess);
618     if (*pStatus != Success)
619         goto out;
620
621     pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
622     if (!(*pGC->pScreen->CreateGC)(pGC))
623         *pStatus = BadAlloc;
624     else if (mask)
625         *pStatus = ChangeGC(pGC, mask, pval);
626     else
627         *pStatus = Success;
628
629 out:
630     if (*pStatus != Success)
631     {
632         if (!pGC->tileIsPixel && !pGC->tile.pixmap)
633             pGC->tileIsPixel = TRUE; /* undo special case */
634         FreeGC(pGC, (XID)0);
635         pGC = (GCPtr)NULL;
636     }
637
638     return (pGC);
639 }
640
641 static Bool
642 CreateDefaultTile (GCPtr pGC)
643 {
644     XID         tmpval[3];
645     PixmapPtr   pTile;
646     GCPtr       pgcScratch;
647     xRectangle  rect;
648     CARD16      w, h;
649
650     w = 1;
651     h = 1;
652     (*pGC->pScreen->QueryBestSize)(TileShape, &w, &h, pGC->pScreen);
653     pTile = (PixmapPtr)
654             (*pGC->pScreen->CreatePixmap)(pGC->pScreen,
655                                           w, h, pGC->depth, 0);
656     pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen);
657     if (!pTile || !pgcScratch)
658     {
659         if (pTile)
660             (*pTile->drawable.pScreen->DestroyPixmap)(pTile);
661         if (pgcScratch)
662             FreeScratchGC(pgcScratch);
663         return FALSE;
664     }
665     tmpval[0] = GXcopy;
666     tmpval[1] = pGC->tile.pixel;
667     tmpval[2] = FillSolid;
668     (void)ChangeGC(pgcScratch, GCFunction | GCForeground | GCFillStyle, 
669                    tmpval);
670     ValidateGC((DrawablePtr)pTile, pgcScratch);
671     rect.x = 0;
672     rect.y = 0;
673     rect.width = w;
674     rect.height = h;
675     (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pTile, pgcScratch, 1, &rect);
676     /* Always remember to free the scratch graphics context after use. */
677     FreeScratchGC(pgcScratch);
678
679     pGC->tileIsPixel = FALSE;
680     pGC->tile.pixmap = pTile;
681     return TRUE;
682 }
683
684 int
685 CopyGC(GC *pgcSrc, GC *pgcDst, BITS32 mask)
686 {
687     BITS32      index2;
688     BITS32      maskQ;
689     int         error = 0;
690
691     if (pgcSrc == pgcDst)
692         return Success;
693     pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
694     pgcDst->stateChanges |= mask;
695     maskQ = mask;
696     while (mask)
697     {
698         index2 = (BITS32) lowbit (mask);
699         mask &= ~index2;
700         switch (index2)
701         {
702             case GCFunction:
703                 pgcDst->alu = pgcSrc->alu;
704                 break;
705             case GCPlaneMask:
706                 pgcDst->planemask = pgcSrc->planemask;
707                 break;
708             case GCForeground:
709                 pgcDst->fgPixel = pgcSrc->fgPixel;
710                 break;
711             case GCBackground:
712                 pgcDst->bgPixel = pgcSrc->bgPixel;
713                 break;
714             case GCLineWidth:
715                 pgcDst->lineWidth = pgcSrc->lineWidth;
716                 break;
717             case GCLineStyle:
718                 pgcDst->lineStyle = pgcSrc->lineStyle;
719                 break;
720             case GCCapStyle:
721                 pgcDst->capStyle = pgcSrc->capStyle;
722                 break;
723             case GCJoinStyle:
724                 pgcDst->joinStyle = pgcSrc->joinStyle;
725                 break;
726             case GCFillStyle:
727                 pgcDst->fillStyle = pgcSrc->fillStyle;
728                 break;
729             case GCFillRule:
730                 pgcDst->fillRule = pgcSrc->fillRule;
731                 break;
732             case GCTile:
733                 {
734                     if (EqualPixUnion(pgcDst->tileIsPixel,
735                                       pgcDst->tile,
736                                       pgcSrc->tileIsPixel,
737                                       pgcSrc->tile))
738                     {
739                         break;
740                     }
741                     if (!pgcDst->tileIsPixel)
742                         (* pgcDst->pScreen->DestroyPixmap)(pgcDst->tile.pixmap);
743                     pgcDst->tileIsPixel = pgcSrc->tileIsPixel;
744                     pgcDst->tile = pgcSrc->tile;
745                     if (!pgcDst->tileIsPixel)
746                        pgcDst->tile.pixmap->refcnt++;
747                     break;
748                 }
749             case GCStipple:
750                 {
751                     if (pgcDst->stipple == pgcSrc->stipple)
752                         break;
753                     if (pgcDst->stipple)
754                         (* pgcDst->pScreen->DestroyPixmap)(pgcDst->stipple);
755                     pgcDst->stipple = pgcSrc->stipple;
756                     if (pgcDst->stipple)
757                         pgcDst->stipple->refcnt ++;
758                     break;
759                 }
760             case GCTileStipXOrigin:
761                 pgcDst->patOrg.x = pgcSrc->patOrg.x;
762                 break;
763             case GCTileStipYOrigin:
764                 pgcDst->patOrg.y = pgcSrc->patOrg.y;
765                 break;
766             case GCFont:
767                 if (pgcDst->font == pgcSrc->font)
768                     break;
769                 if (pgcDst->font)
770                     CloseFont(pgcDst->font, (Font)0);
771                 if ((pgcDst->font = pgcSrc->font) != NullFont)
772                     (pgcDst->font)->refcnt++;
773                 break;
774             case GCSubwindowMode:
775                 pgcDst->subWindowMode = pgcSrc->subWindowMode;
776                 break;
777             case GCGraphicsExposures:
778                 pgcDst->graphicsExposures = pgcSrc->graphicsExposures;
779                 break;
780             case GCClipXOrigin:
781                 pgcDst->clipOrg.x = pgcSrc->clipOrg.x;
782                 break;
783             case GCClipYOrigin:
784                 pgcDst->clipOrg.y = pgcSrc->clipOrg.y;
785                 break;
786             case GCClipMask:
787                 (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
788                 break;
789             case GCDashOffset:
790                 pgcDst->dashOffset = pgcSrc->dashOffset;
791                 break;
792             case GCDashList:
793                 if (pgcSrc->dash == DefaultDash)
794                 {
795                     if (pgcDst->dash != DefaultDash)
796                     {
797                         xfree(pgcDst->dash);
798                         pgcDst->numInDashList = pgcSrc->numInDashList;
799                         pgcDst->dash = pgcSrc->dash;
800                     }
801                 }
802                 else
803                 {
804                     unsigned char *dash;
805                     unsigned int i;
806
807                     dash = xalloc(pgcSrc->numInDashList * sizeof(unsigned char));
808                     if (dash)
809                     {
810                         if (pgcDst->dash != DefaultDash)
811                             xfree(pgcDst->dash);
812                         pgcDst->numInDashList = pgcSrc->numInDashList;
813                         pgcDst->dash = dash;
814                         for (i=0; i<pgcSrc->numInDashList; i++)
815                             dash[i] = pgcSrc->dash[i];
816                     }
817                     else
818                         error = BadAlloc;
819                 }
820                 break;
821             case GCArcMode:
822                 pgcDst->arcMode = pgcSrc->arcMode;
823                 break;
824             default:
825                 clientErrorValue = maskQ;
826                 error = BadValue;
827                 break;
828         }
829     }
830     if (pgcDst->fillStyle == FillTiled && pgcDst->tileIsPixel)
831     {
832         if (!CreateDefaultTile (pgcDst))
833         {
834             pgcDst->fillStyle = FillSolid;
835             error = BadAlloc;
836         }
837     }
838     (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst);
839     return error;
840 }
841
842 /**
843  * does the diX part of freeing the characteristics in the GC.
844  *
845  *  \param value  must conform to DeleteType
846  */
847 int
848 FreeGC(pointer value, XID gid)
849 {
850     GCPtr pGC = (GCPtr)value;
851
852     CloseFont(pGC->font, (Font)0);
853     (* pGC->funcs->DestroyClip)(pGC);
854
855     if (!pGC->tileIsPixel)
856         (* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
857     if (pGC->stipple)
858         (* pGC->pScreen->DestroyPixmap)(pGC->stipple);
859
860     (*pGC->funcs->DestroyGC) (pGC);
861     if (pGC->dash != DefaultDash)
862         xfree(pGC->dash);
863     dixFreePrivates(pGC->devPrivates);
864     xfree(pGC);
865     return(Success);
866 }
867
868 /* CreateScratchGC(pScreen, depth)
869     like CreateGC, but doesn't do the default tile or stipple,
870 since we can't create them without already having a GC.  any code
871 using the tile or stipple has to set them explicitly anyway,
872 since the state of the scratch gc is unknown.  This is OK
873 because ChangeGC() has to be able to deal with NULL tiles and
874 stipples anyway (in case the CreateGC() call has provided a 
875 value for them -- we can't set the default tile until the
876 client-supplied attributes are installed, since the fgPixel
877 is what fills the default tile.  (maybe this comment should
878 go with CreateGC() or ChangeGC().)
879 */
880
881 GCPtr
882 CreateScratchGC(ScreenPtr pScreen, unsigned depth)
883 {
884     GCPtr pGC;
885
886     pGC = xalloc(sizeof(GC));
887     if (!pGC)
888         return (GCPtr)NULL;
889
890     pGC->pScreen = pScreen;
891     pGC->depth = depth;
892     pGC->alu = GXcopy; /* dst <- src */
893     pGC->planemask = ~0;
894     pGC->serialNumber = 0;
895     pGC->devPrivates = NULL;
896     pGC->fgPixel = 0;
897     pGC->bgPixel = 1;
898     pGC->lineWidth = 0;
899     pGC->lineStyle = LineSolid;
900     pGC->capStyle = CapButt;
901     pGC->joinStyle = JoinMiter;
902     pGC->fillStyle = FillSolid;
903     pGC->fillRule = EvenOddRule;
904     pGC->arcMode = ArcPieSlice;
905     pGC->font = defaultFont;
906     if ( pGC->font)  /* necessary, because open of default font could fail */
907         pGC->font->refcnt++;
908     pGC->tileIsPixel = TRUE;
909     pGC->tile.pixel = 0;
910     pGC->tile.pixmap = NullPixmap;
911     pGC->stipple = NullPixmap;
912     pGC->patOrg.x = 0;
913     pGC->patOrg.y = 0;
914     pGC->subWindowMode = ClipByChildren;
915     pGC->graphicsExposures = TRUE;
916     pGC->clipOrg.x = 0;
917     pGC->clipOrg.y = 0;
918     pGC->clientClipType = CT_NONE;
919     pGC->dashOffset = 0;
920     pGC->numInDashList = 2;
921     pGC->dash = DefaultDash;
922     pGC->lastWinOrg.x = 0;
923     pGC->lastWinOrg.y = 0;
924
925     pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
926     if (!(*pScreen->CreateGC)(pGC))
927     {
928         FreeGC(pGC, (XID)0);
929         pGC = (GCPtr)NULL;
930     }
931     return pGC;
932 }
933
934 void
935 FreeGCperDepth(int screenNum)
936 {
937     int i;
938     ScreenPtr pScreen;
939     GCPtr *ppGC;
940
941     pScreen = screenInfo.screens[screenNum];
942     ppGC = pScreen->GCperDepth;
943
944     for (i = 0; i <= pScreen->numDepths; i++)
945         (void)FreeGC(ppGC[i], (XID)0);
946     pScreen->rgf = ~0L;
947 }
948
949
950 Bool
951 CreateGCperDepth(int screenNum)
952 {
953     int i;
954     ScreenPtr pScreen;
955     DepthPtr pDepth;
956     GCPtr *ppGC;
957
958     pScreen = screenInfo.screens[screenNum];
959     pScreen->rgf = 0;
960     ppGC = pScreen->GCperDepth;
961     /* do depth 1 separately because it's not included in list */
962     if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
963         return FALSE;
964     ppGC[0]->graphicsExposures = FALSE;
965     /* Make sure we don't overflow GCperDepth[] */
966     if( pScreen->numDepths > MAXFORMATS )
967             return FALSE;
968
969     pDepth = pScreen->allowedDepths;
970     for (i=0; i<pScreen->numDepths; i++, pDepth++)
971     {
972         if (!(ppGC[i+1] = CreateScratchGC(pScreen, pDepth->depth)))
973         {
974             for (; i >= 0; i--)
975                 (void)FreeGC(ppGC[i], (XID)0);
976             return FALSE;
977         }
978         ppGC[i+1]->graphicsExposures = FALSE;
979     }
980     return TRUE;
981 }
982
983 Bool
984 CreateDefaultStipple(int screenNum)
985 {
986     ScreenPtr pScreen;
987     XID tmpval[3];
988     xRectangle rect;
989     CARD16 w, h;
990     GCPtr pgcScratch;
991
992     pScreen = screenInfo.screens[screenNum];
993
994     w = 16;
995     h = 16;
996     (* pScreen->QueryBestSize)(StippleShape, &w, &h, pScreen);
997     if (!(pScreen->PixmapPerDepth[0] =
998                         (*pScreen->CreatePixmap)(pScreen, w, h, 1, 0)))
999         return FALSE;
1000     /* fill stipple with 1 */
1001     tmpval[0] = GXcopy; tmpval[1] = 1; tmpval[2] = FillSolid;
1002     pgcScratch = GetScratchGC(1, pScreen);
1003     if (!pgcScratch)
1004     {
1005         (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
1006         return FALSE;
1007     }
1008     (void)ChangeGC(pgcScratch, GCFunction|GCForeground|GCFillStyle, tmpval);
1009     ValidateGC((DrawablePtr)pScreen->PixmapPerDepth[0], pgcScratch);
1010     rect.x = 0;
1011     rect.y = 0;
1012     rect.width = w;
1013     rect.height = h;
1014     (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pScreen->PixmapPerDepth[0], 
1015                                      pgcScratch, 1, &rect);
1016     FreeScratchGC(pgcScratch);
1017     return TRUE;
1018 }
1019
1020 void
1021 FreeDefaultStipple(int screenNum)
1022 {
1023     ScreenPtr pScreen = screenInfo.screens[screenNum];
1024     (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
1025 }
1026
1027 int
1028 SetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
1029 {
1030     long i;
1031     unsigned char *p, *indash;
1032     BITS32 maskQ = 0;
1033
1034     i = ndash;
1035     p = pdash;
1036     while (i--)
1037     {
1038         if (!*p++)
1039         {
1040             /* dash segment must be > 0 */
1041             clientErrorValue = 0;
1042             return BadValue;
1043         }
1044     }
1045
1046     if (ndash & 1)
1047         p = xalloc(2 * ndash * sizeof(unsigned char));
1048     else
1049         p = xalloc(ndash * sizeof(unsigned char));
1050     if (!p)
1051         return BadAlloc;
1052
1053     pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
1054     if (offset != pGC->dashOffset)
1055     {
1056         pGC->dashOffset = offset;
1057         pGC->stateChanges |= GCDashOffset;
1058         maskQ |= GCDashOffset;
1059     }
1060
1061     if (pGC->dash != DefaultDash)
1062         xfree(pGC->dash);
1063     pGC->numInDashList = ndash;
1064     pGC->dash = p;
1065     if (ndash & 1)
1066     {
1067         pGC->numInDashList += ndash;
1068         indash = pdash;
1069         i = ndash;
1070         while (i--)
1071             *p++ = *indash++;
1072     }
1073     while(ndash--)
1074         *p++ = *pdash++;
1075     pGC->stateChanges |= GCDashList;
1076     maskQ |= GCDashList;
1077
1078     if (pGC->funcs->ChangeGC)
1079         (*pGC->funcs->ChangeGC) (pGC, maskQ);
1080     return Success;
1081 }
1082
1083 int
1084 VerifyRectOrder(int nrects, xRectangle *prects, int ordering)
1085 {
1086     xRectangle  *prectP, *prectN;
1087     int i;
1088
1089     switch(ordering)
1090     {
1091       case Unsorted:
1092           return CT_UNSORTED;
1093       case YSorted:
1094           if(nrects > 1)
1095           {
1096               for(i = 1, prectP = prects, prectN = prects + 1;
1097                   i < nrects;
1098                   i++, prectP++, prectN++)
1099                   if(prectN->y < prectP->y)
1100                       return -1;
1101           }
1102           return CT_YSORTED;
1103       case YXSorted:
1104           if(nrects > 1)
1105           {
1106               for(i = 1, prectP = prects, prectN = prects + 1;
1107                   i < nrects;
1108                   i++, prectP++, prectN++)
1109                   if((prectN->y < prectP->y) ||
1110                       ( (prectN->y == prectP->y) &&
1111                         (prectN->x < prectP->x) ) )
1112                       return -1;
1113           }
1114           return CT_YXSORTED;
1115       case YXBanded:
1116           if(nrects > 1)
1117           {
1118               for(i = 1, prectP = prects, prectN = prects + 1;
1119                   i < nrects;
1120                   i++, prectP++, prectN++)
1121                   if((prectN->y != prectP->y &&
1122                       prectN->y < prectP->y + (int) prectP->height) ||
1123                      ((prectN->y == prectP->y) &&
1124                       (prectN->height != prectP->height ||
1125                        prectN->x < prectP->x + (int) prectP->width)))
1126                       return -1;
1127           }
1128           return CT_YXBANDED;
1129     }
1130     return -1;
1131 }
1132
1133 int
1134 SetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects, 
1135              xRectangle *prects, int ordering)
1136 {
1137     int                 newct, size;
1138     xRectangle          *prectsNew;
1139
1140     newct = VerifyRectOrder(nrects, prects, ordering);
1141     if (newct < 0)
1142         return(BadMatch);
1143     size = nrects * sizeof(xRectangle);
1144     prectsNew = xalloc(size);
1145     if (!prectsNew && size)
1146         return BadAlloc;
1147
1148     pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
1149     pGC->clipOrg.x = xOrigin;
1150     pGC->stateChanges |= GCClipXOrigin;
1151                  
1152     pGC->clipOrg.y = yOrigin;
1153     pGC->stateChanges |= GCClipYOrigin;
1154
1155     if (size)
1156         memmove((char *)prectsNew, (char *)prects, size);
1157     (*pGC->funcs->ChangeClip)(pGC, newct, (pointer)prectsNew, nrects);
1158     if (pGC->funcs->ChangeGC)
1159         (*pGC->funcs->ChangeGC) (pGC, GCClipXOrigin|GCClipYOrigin|GCClipMask);
1160     return Success;
1161 }
1162
1163
1164 /*
1165    sets reasonable defaults 
1166    if we can get a pre-allocated one, use it and mark it as used.
1167    if we can't, create one out of whole cloth (The Velveteen GC -- if
1168    you use it often enough it will become real.)
1169 */
1170 GCPtr
1171 GetScratchGC(unsigned depth, ScreenPtr pScreen)
1172 {
1173     int i;
1174     GCPtr pGC;
1175
1176     for (i=0; i<=pScreen->numDepths; i++)
1177         if ( pScreen->GCperDepth[i]->depth == depth &&
1178              !(pScreen->rgf & (1L << (i+1)))
1179            )
1180         {
1181             pScreen->rgf |= (1L << (i+1));
1182             pGC = (pScreen->GCperDepth[i]);
1183
1184             pGC->alu = GXcopy;
1185             pGC->planemask = ~0;
1186             pGC->serialNumber = 0;
1187             pGC->fgPixel = 0;
1188             pGC->bgPixel = 1;
1189             pGC->lineWidth = 0;
1190             pGC->lineStyle = LineSolid;
1191             pGC->capStyle = CapButt;
1192             pGC->joinStyle = JoinMiter;
1193             pGC->fillStyle = FillSolid;
1194             pGC->fillRule = EvenOddRule;
1195             pGC->arcMode = ArcChord;
1196             pGC->patOrg.x = 0;
1197             pGC->patOrg.y = 0;
1198             pGC->subWindowMode = ClipByChildren;
1199             pGC->graphicsExposures = FALSE;
1200             pGC->clipOrg.x = 0;
1201             pGC->clipOrg.y = 0;
1202             if (pGC->clientClipType != CT_NONE)
1203                 (*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
1204             pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
1205             return pGC;
1206         }
1207     /* if we make it this far, need to roll our own */
1208     pGC = CreateScratchGC(pScreen, depth);
1209     if (pGC)
1210         pGC->graphicsExposures = FALSE;
1211     return pGC;
1212 }
1213
1214 /*
1215    if the gc to free is in the table of pre-existing ones,
1216 mark it as available.
1217    if not, free it for real
1218 */
1219 void
1220 FreeScratchGC(GCPtr pGC)
1221 {
1222     ScreenPtr pScreen = pGC->pScreen;
1223     int i;
1224
1225     for (i=0; i<=pScreen->numDepths; i++)
1226     {
1227         if ( pScreen->GCperDepth[i] == pGC)
1228         {
1229             pScreen->rgf &= ~(1L << (i+1));
1230             return;
1231         }
1232     }
1233     (void)FreeGC(pGC, (GContext)0);
1234 }