First import
[xorg_rtime.git] / xorg-server-1.4 / dix / gc.c
blob7a76dd99da7cfeebd4644cdcac52490d1b2b693c
1 /***********************************************************
3 Copyright 1987, 1998 The Open Group
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.
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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.
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.
26 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
28 All Rights Reserved
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.
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.
46 ******************************************************************/
49 #ifdef HAVE_DIX_CONFIG_H
50 #include <dix-config.h>
51 #endif
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"
64 #include "dix.h"
65 #include <assert.h>
67 extern XID clientErrorValue;
68 extern FontPtr defaultFont;
70 static Bool CreateDefaultTile(GCPtr pGC);
72 static unsigned char DefaultDash[2] = {4, 4};
74 _X_EXPORT void
75 ValidateGC(DrawablePtr pDraw, GC *pGC)
77 (*pGC->funcs->ValidateGC) (pGC, pGC->stateChanges, pDraw);
78 pGC->stateChanges = 0;
79 pGC->serialNumber = pDraw->serialNumber;
83 /* dixChangeGC(client, pGC, mask, pC32, pUnion)
85 * This function was created as part of the Security extension
86 * implementation. The client performing the gc change must be passed so
87 * that access checks can be performed on any tiles, stipples, or fonts
88 * that are specified. ddxen can call this too; they should normally
89 * pass NullClient for the client since any access checking should have
90 * already been done at a higher level.
92 * Since we had to create a new function anyway, we decided to change the
93 * way the list of gc values is passed to eliminate the compiler warnings
94 * caused by the DoChangeGC interface. You can pass the values via pC32
95 * or pUnion, but not both; one of them must be NULL. If you don't need
96 * to pass any pointers, you can use either one:
98 * example calling dixChangeGC using pC32 parameter
100 * CARD32 v[2];
101 * v[0] = foreground;
102 * v[1] = background;
103 * dixChangeGC(client, pGC, GCForeground|GCBackground, v, NULL);
105 * example calling dixChangeGC using pUnion parameter;
106 * same effect as above
108 * ChangeGCVal v[2];
109 * v[0].val = foreground;
110 * v[1].val = background;
111 * dixChangeGC(client, pGC, GCForeground|GCBackground, NULL, v);
113 * However, if you need to pass a pointer to a pixmap or font, you MUST
114 * use the pUnion parameter.
116 * example calling dixChangeGC passing pointers in the value list
117 * v[1].ptr is a pointer to a pixmap
119 * ChangeGCVal v[2];
120 * v[0].val = FillTiled;
121 * v[1].ptr = pPixmap;
122 * dixChangeGC(client, pGC, GCFillStyle|GCTile, NULL, v);
124 * Note: we could have gotten by with just the pUnion parameter, but on
125 * 64 bit machines that would have forced us to copy the value list that
126 * comes in the ChangeGC request.
128 * Ideally, we'd change all the DoChangeGC calls to dixChangeGC, but this
129 * is far too many changes to consider at this time, so we've only
130 * changed the ones that caused compiler warnings. New code should use
131 * dixChangeGC.
133 * dpw
136 #define NEXTVAL(_type, _var) { \
137 if (pC32) _var = (_type)*pC32++; \
138 else { \
139 _var = (_type)(pUnion->val); pUnion++; \
143 #define NEXT_PTR(_type, _var) { \
144 assert(pUnion); _var = (_type)pUnion->ptr; pUnion++; }
146 _X_EXPORT int
147 dixChangeGC(ClientPtr client, GC *pGC, BITS32 mask, CARD32 *pC32, ChangeGCValPtr pUnion)
149 BITS32 index2;
150 int error = 0;
151 PixmapPtr pPixmap;
152 BITS32 maskQ;
154 assert( (pC32 && !pUnion) || (!pC32 && pUnion) );
155 pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
157 maskQ = mask; /* save these for when we walk the GCque */
158 while (mask && !error)
160 index2 = (BITS32) lowbit (mask);
161 mask &= ~index2;
162 pGC->stateChanges |= index2;
163 switch (index2)
165 case GCFunction:
167 CARD8 newalu;
168 NEXTVAL(CARD8, newalu);
169 if (newalu <= GXset)
170 pGC->alu = newalu;
171 else
173 clientErrorValue = newalu;
174 error = BadValue;
176 break;
178 case GCPlaneMask:
179 NEXTVAL(unsigned long, pGC->planemask);
180 break;
181 case GCForeground:
182 NEXTVAL(unsigned long, pGC->fgPixel);
184 * this is for CreateGC
186 if (!pGC->tileIsPixel && !pGC->tile.pixmap)
188 pGC->tileIsPixel = TRUE;
189 pGC->tile.pixel = pGC->fgPixel;
191 break;
192 case GCBackground:
193 NEXTVAL(unsigned long, pGC->bgPixel);
194 break;
195 case GCLineWidth: /* ??? line width is a CARD16 */
196 NEXTVAL(CARD16, pGC->lineWidth);
197 break;
198 case GCLineStyle:
200 unsigned int newlinestyle;
201 NEXTVAL(unsigned int, newlinestyle);
202 if (newlinestyle <= LineDoubleDash)
203 pGC->lineStyle = newlinestyle;
204 else
206 clientErrorValue = newlinestyle;
207 error = BadValue;
209 break;
211 case GCCapStyle:
213 unsigned int newcapstyle;
214 NEXTVAL(unsigned int, newcapstyle);
215 if (newcapstyle <= CapProjecting)
216 pGC->capStyle = newcapstyle;
217 else
219 clientErrorValue = newcapstyle;
220 error = BadValue;
222 break;
224 case GCJoinStyle:
226 unsigned int newjoinstyle;
227 NEXTVAL(unsigned int, newjoinstyle);
228 if (newjoinstyle <= JoinBevel)
229 pGC->joinStyle = newjoinstyle;
230 else
232 clientErrorValue = newjoinstyle;
233 error = BadValue;
235 break;
237 case GCFillStyle:
239 unsigned int newfillstyle;
240 NEXTVAL(unsigned int, newfillstyle);
241 if (newfillstyle <= FillOpaqueStippled)
242 pGC->fillStyle = newfillstyle;
243 else
245 clientErrorValue = newfillstyle;
246 error = BadValue;
248 break;
250 case GCFillRule:
252 unsigned int newfillrule;
253 NEXTVAL(unsigned int, newfillrule);
254 if (newfillrule <= WindingRule)
255 pGC->fillRule = newfillrule;
256 else
258 clientErrorValue = newfillrule;
259 error = BadValue;
261 break;
263 case GCTile:
265 XID newpix = 0;
266 if (pUnion)
268 NEXT_PTR(PixmapPtr, pPixmap);
270 else
272 NEXTVAL(XID, newpix);
273 pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
274 newpix, RT_PIXMAP, DixReadAccess);
276 if (pPixmap)
278 if ((pPixmap->drawable.depth != pGC->depth) ||
279 (pPixmap->drawable.pScreen != pGC->pScreen))
281 error = BadMatch;
283 else
285 pPixmap->refcnt++;
286 if (!pGC->tileIsPixel)
287 (* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
288 pGC->tileIsPixel = FALSE;
289 pGC->tile.pixmap = pPixmap;
292 else
294 clientErrorValue = newpix;
295 error = BadPixmap;
297 break;
299 case GCStipple:
301 XID newstipple = 0;
302 if (pUnion)
304 NEXT_PTR(PixmapPtr, pPixmap);
306 else
308 NEXTVAL(XID, newstipple)
309 pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
310 newstipple, RT_PIXMAP, DixReadAccess);
312 if (pPixmap)
314 if ((pPixmap->drawable.depth != 1) ||
315 (pPixmap->drawable.pScreen != pGC->pScreen))
317 error = BadMatch;
319 else
321 pPixmap->refcnt++;
322 if (pGC->stipple)
323 (* pGC->pScreen->DestroyPixmap)(pGC->stipple);
324 pGC->stipple = pPixmap;
327 else
329 clientErrorValue = newstipple;
330 error = BadPixmap;
332 break;
334 case GCTileStipXOrigin:
335 NEXTVAL(INT16, pGC->patOrg.x);
336 break;
337 case GCTileStipYOrigin:
338 NEXTVAL(INT16, pGC->patOrg.y);
339 break;
340 case GCFont:
342 FontPtr pFont;
343 XID newfont = 0;
344 if (pUnion)
346 NEXT_PTR(FontPtr, pFont);
348 else
350 NEXTVAL(XID, newfont)
351 pFont = (FontPtr)SecurityLookupIDByType(client, newfont,
352 RT_FONT, DixReadAccess);
354 if (pFont)
356 pFont->refcnt++;
357 if (pGC->font)
358 CloseFont(pGC->font, (Font)0);
359 pGC->font = pFont;
361 else
363 clientErrorValue = newfont;
364 error = BadFont;
366 break;
368 case GCSubwindowMode:
370 unsigned int newclipmode;
371 NEXTVAL(unsigned int, newclipmode);
372 if (newclipmode <= IncludeInferiors)
373 pGC->subWindowMode = newclipmode;
374 else
376 clientErrorValue = newclipmode;
377 error = BadValue;
379 break;
381 case GCGraphicsExposures:
383 unsigned int newge;
384 NEXTVAL(unsigned int, newge);
385 if (newge <= xTrue)
386 pGC->graphicsExposures = newge;
387 else
389 clientErrorValue = newge;
390 error = BadValue;
392 break;
394 case GCClipXOrigin:
395 NEXTVAL(INT16, pGC->clipOrg.x);
396 break;
397 case GCClipYOrigin:
398 NEXTVAL(INT16, pGC->clipOrg.y);
399 break;
400 case GCClipMask:
402 Pixmap pid = 0;
403 int clipType = 0;
405 if (pUnion)
407 NEXT_PTR(PixmapPtr, pPixmap);
409 else
411 NEXTVAL(Pixmap, pid)
412 if (pid == None)
414 clipType = CT_NONE;
415 pPixmap = NullPixmap;
417 else
418 pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
419 pid, RT_PIXMAP, DixReadAccess);
422 if (pPixmap)
424 if ((pPixmap->drawable.depth != 1) ||
425 (pPixmap->drawable.pScreen != pGC->pScreen))
427 error = BadMatch;
429 else
431 clipType = CT_PIXMAP;
432 pPixmap->refcnt++;
435 else if (!pUnion && (pid != None))
437 clientErrorValue = pid;
438 error = BadPixmap;
440 if(error == Success)
442 (*pGC->funcs->ChangeClip)(pGC, clipType,
443 (pointer)pPixmap, 0);
445 break;
447 case GCDashOffset:
448 NEXTVAL(INT16, pGC->dashOffset);
449 break;
450 case GCDashList:
452 CARD8 newdash;
453 NEXTVAL(CARD8, newdash);
454 if (newdash == 4)
456 if (pGC->dash != DefaultDash)
458 xfree(pGC->dash);
459 pGC->numInDashList = 2;
460 pGC->dash = DefaultDash;
463 else if (newdash != 0)
465 unsigned char *dash;
467 dash = (unsigned char *)xalloc(2 * sizeof(unsigned char));
468 if (dash)
470 if (pGC->dash != DefaultDash)
471 xfree(pGC->dash);
472 pGC->numInDashList = 2;
473 pGC->dash = dash;
474 dash[0] = newdash;
475 dash[1] = newdash;
477 else
478 error = BadAlloc;
480 else
482 clientErrorValue = newdash;
483 error = BadValue;
485 break;
487 case GCArcMode:
489 unsigned int newarcmode;
490 NEXTVAL(unsigned int, newarcmode);
491 if (newarcmode <= ArcPieSlice)
492 pGC->arcMode = newarcmode;
493 else
495 clientErrorValue = newarcmode;
496 error = BadValue;
498 break;
500 default:
501 clientErrorValue = maskQ;
502 error = BadValue;
503 break;
505 } /* end while mask && !error */
507 if (pGC->fillStyle == FillTiled && pGC->tileIsPixel)
509 if (!CreateDefaultTile (pGC))
511 pGC->fillStyle = FillSolid;
512 error = BadAlloc;
515 (*pGC->funcs->ChangeGC)(pGC, maskQ);
516 return error;
519 #undef NEXTVAL
520 #undef NEXT_PTR
522 /* Publically defined entry to ChangeGC. Just calls dixChangeGC and tells
523 * it that all of the entries are constants or IDs */
524 _X_EXPORT int
525 ChangeGC(GC *pGC, BITS32 mask, XID *pval)
527 return (dixChangeGC(NullClient, pGC, mask, pval, NULL));
530 /* DoChangeGC(pGC, mask, pval, fPointer)
531 mask is a set of bits indicating which values to change.
532 pval contains an appropriate value for each mask.
533 fPointer is true if the values for tiles, stipples, fonts or clipmasks
534 are pointers instead of IDs. Note: if you are passing pointers you
535 MUST declare the array of values as type pointer! Other data types
536 may not be large enough to hold pointers on some machines. Yes,
537 this means you have to cast to (XID *) when you pass the array to
538 DoChangeGC. Similarly, if you are not passing pointers (fPointer = 0) you
539 MUST declare the array as type XID (not unsigned long!), or again the wrong
540 size data type may be used. To avoid this cruftiness, use dixChangeGC
541 above.
543 if there is an error, the value is marked as changed
544 anyway, which is probably wrong, but infrequent.
546 NOTE:
547 all values sent over the protocol for ChangeGC requests are
548 32 bits long
550 _X_EXPORT int
551 DoChangeGC(GC *pGC, BITS32 mask, XID *pval, int fPointer)
553 if (fPointer)
554 /* XXX might be a problem on 64 bit big-endian servers */
555 return dixChangeGC(NullClient, pGC, mask, NULL, (ChangeGCValPtr)pval);
556 else
557 return dixChangeGC(NullClient, pGC, mask, pval, NULL);
561 /* CreateGC(pDrawable, mask, pval, pStatus)
562 creates a default GC for the given drawable, using mask to fill
563 in any non-default values.
564 Returns a pointer to the new GC on success, NULL otherwise.
565 returns status of non-default fields in pStatus
566 BUG:
567 should check for failure to create default tile
571 static GCPtr
572 AllocateGC(ScreenPtr pScreen)
574 GCPtr pGC;
575 char *ptr;
576 DevUnion *ppriv;
577 unsigned *sizes;
578 unsigned size;
579 int i;
581 pGC = (GCPtr)xalloc(pScreen->totalGCSize);
582 if (pGC)
584 ppriv = (DevUnion *)(pGC + 1);
585 pGC->devPrivates = ppriv;
586 sizes = pScreen->GCPrivateSizes;
587 ptr = (char *)(ppriv + pScreen->GCPrivateLen);
588 for (i = pScreen->GCPrivateLen; --i >= 0; ppriv++, sizes++)
590 if ( (size = *sizes) )
592 ppriv->ptr = (pointer)ptr;
593 ptr += size;
595 else
596 ppriv->ptr = (pointer)NULL;
599 return pGC;
602 _X_EXPORT GCPtr
603 CreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus)
605 GCPtr pGC;
607 pGC = AllocateGC(pDrawable->pScreen);
608 if (!pGC)
610 *pStatus = BadAlloc;
611 return (GCPtr)NULL;
614 pGC->pScreen = pDrawable->pScreen;
615 pGC->depth = pDrawable->depth;
616 pGC->alu = GXcopy; /* dst <- src */
617 pGC->planemask = ~0;
618 pGC->serialNumber = GC_CHANGE_SERIAL_BIT;
619 pGC->funcs = 0;
621 pGC->fgPixel = 0;
622 pGC->bgPixel = 1;
623 pGC->lineWidth = 0;
624 pGC->lineStyle = LineSolid;
625 pGC->capStyle = CapButt;
626 pGC->joinStyle = JoinMiter;
627 pGC->fillStyle = FillSolid;
628 pGC->fillRule = EvenOddRule;
629 pGC->arcMode = ArcPieSlice;
630 if (mask & GCForeground)
633 * magic special case -- ChangeGC checks for this condition
634 * and snags the Foreground value to create a pseudo default-tile
636 pGC->tileIsPixel = FALSE;
637 pGC->tile.pixmap = NullPixmap;
639 else
641 pGC->tileIsPixel = TRUE;
642 pGC->tile.pixel = 0;
645 pGC->patOrg.x = 0;
646 pGC->patOrg.y = 0;
647 pGC->subWindowMode = ClipByChildren;
648 pGC->graphicsExposures = TRUE;
649 pGC->clipOrg.x = 0;
650 pGC->clipOrg.y = 0;
651 pGC->clientClipType = CT_NONE;
652 pGC->clientClip = (pointer)NULL;
653 pGC->numInDashList = 2;
654 pGC->dash = DefaultDash;
655 pGC->dashOffset = 0;
656 pGC->lastWinOrg.x = 0;
657 pGC->lastWinOrg.y = 0;
659 /* use the default font and stipple */
660 pGC->font = defaultFont;
661 defaultFont->refcnt++;
662 pGC->stipple = pGC->pScreen->PixmapPerDepth[0];
663 pGC->stipple->refcnt++;
665 pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
666 if (!(*pGC->pScreen->CreateGC)(pGC))
667 *pStatus = BadAlloc;
668 else if (mask)
669 *pStatus = ChangeGC(pGC, mask, pval);
670 else
671 *pStatus = Success;
672 if (*pStatus != Success)
674 if (!pGC->tileIsPixel && !pGC->tile.pixmap)
675 pGC->tileIsPixel = TRUE; /* undo special case */
676 FreeGC(pGC, (XID)0);
677 pGC = (GCPtr)NULL;
680 return (pGC);
683 static Bool
684 CreateDefaultTile (GCPtr pGC)
686 XID tmpval[3];
687 PixmapPtr pTile;
688 GCPtr pgcScratch;
689 xRectangle rect;
690 CARD16 w, h;
692 w = 1;
693 h = 1;
694 (*pGC->pScreen->QueryBestSize)(TileShape, &w, &h, pGC->pScreen);
695 pTile = (PixmapPtr)
696 (*pGC->pScreen->CreatePixmap)(pGC->pScreen,
697 w, h, pGC->depth);
698 pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen);
699 if (!pTile || !pgcScratch)
701 if (pTile)
702 (*pTile->drawable.pScreen->DestroyPixmap)(pTile);
703 if (pgcScratch)
704 FreeScratchGC(pgcScratch);
705 return FALSE;
707 tmpval[0] = GXcopy;
708 tmpval[1] = pGC->tile.pixel;
709 tmpval[2] = FillSolid;
710 (void)ChangeGC(pgcScratch, GCFunction | GCForeground | GCFillStyle,
711 tmpval);
712 ValidateGC((DrawablePtr)pTile, pgcScratch);
713 rect.x = 0;
714 rect.y = 0;
715 rect.width = w;
716 rect.height = h;
717 (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pTile, pgcScratch, 1, &rect);
718 /* Always remember to free the scratch graphics context after use. */
719 FreeScratchGC(pgcScratch);
721 pGC->tileIsPixel = FALSE;
722 pGC->tile.pixmap = pTile;
723 return TRUE;
726 _X_EXPORT int
727 CopyGC(GC *pgcSrc, GC *pgcDst, BITS32 mask)
729 BITS32 index2;
730 BITS32 maskQ;
731 int error = 0;
733 if (pgcSrc == pgcDst)
734 return Success;
735 pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
736 pgcDst->stateChanges |= mask;
737 maskQ = mask;
738 while (mask)
740 index2 = (BITS32) lowbit (mask);
741 mask &= ~index2;
742 switch (index2)
744 case GCFunction:
745 pgcDst->alu = pgcSrc->alu;
746 break;
747 case GCPlaneMask:
748 pgcDst->planemask = pgcSrc->planemask;
749 break;
750 case GCForeground:
751 pgcDst->fgPixel = pgcSrc->fgPixel;
752 break;
753 case GCBackground:
754 pgcDst->bgPixel = pgcSrc->bgPixel;
755 break;
756 case GCLineWidth:
757 pgcDst->lineWidth = pgcSrc->lineWidth;
758 break;
759 case GCLineStyle:
760 pgcDst->lineStyle = pgcSrc->lineStyle;
761 break;
762 case GCCapStyle:
763 pgcDst->capStyle = pgcSrc->capStyle;
764 break;
765 case GCJoinStyle:
766 pgcDst->joinStyle = pgcSrc->joinStyle;
767 break;
768 case GCFillStyle:
769 pgcDst->fillStyle = pgcSrc->fillStyle;
770 break;
771 case GCFillRule:
772 pgcDst->fillRule = pgcSrc->fillRule;
773 break;
774 case GCTile:
776 if (EqualPixUnion(pgcDst->tileIsPixel,
777 pgcDst->tile,
778 pgcSrc->tileIsPixel,
779 pgcSrc->tile))
781 break;
783 if (!pgcDst->tileIsPixel)
784 (* pgcDst->pScreen->DestroyPixmap)(pgcDst->tile.pixmap);
785 pgcDst->tileIsPixel = pgcSrc->tileIsPixel;
786 pgcDst->tile = pgcSrc->tile;
787 if (!pgcDst->tileIsPixel)
788 pgcDst->tile.pixmap->refcnt++;
789 break;
791 case GCStipple:
793 if (pgcDst->stipple == pgcSrc->stipple)
794 break;
795 if (pgcDst->stipple)
796 (* pgcDst->pScreen->DestroyPixmap)(pgcDst->stipple);
797 pgcDst->stipple = pgcSrc->stipple;
798 if (pgcDst->stipple)
799 pgcDst->stipple->refcnt ++;
800 break;
802 case GCTileStipXOrigin:
803 pgcDst->patOrg.x = pgcSrc->patOrg.x;
804 break;
805 case GCTileStipYOrigin:
806 pgcDst->patOrg.y = pgcSrc->patOrg.y;
807 break;
808 case GCFont:
809 if (pgcDst->font == pgcSrc->font)
810 break;
811 if (pgcDst->font)
812 CloseFont(pgcDst->font, (Font)0);
813 if ((pgcDst->font = pgcSrc->font) != NullFont)
814 (pgcDst->font)->refcnt++;
815 break;
816 case GCSubwindowMode:
817 pgcDst->subWindowMode = pgcSrc->subWindowMode;
818 break;
819 case GCGraphicsExposures:
820 pgcDst->graphicsExposures = pgcSrc->graphicsExposures;
821 break;
822 case GCClipXOrigin:
823 pgcDst->clipOrg.x = pgcSrc->clipOrg.x;
824 break;
825 case GCClipYOrigin:
826 pgcDst->clipOrg.y = pgcSrc->clipOrg.y;
827 break;
828 case GCClipMask:
829 (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
830 break;
831 case GCDashOffset:
832 pgcDst->dashOffset = pgcSrc->dashOffset;
833 break;
834 case GCDashList:
835 if (pgcSrc->dash == DefaultDash)
837 if (pgcDst->dash != DefaultDash)
839 xfree(pgcDst->dash);
840 pgcDst->numInDashList = pgcSrc->numInDashList;
841 pgcDst->dash = pgcSrc->dash;
844 else
846 unsigned char *dash;
847 unsigned int i;
849 dash = (unsigned char *)xalloc(pgcSrc->numInDashList *
850 sizeof(unsigned char));
851 if (dash)
853 if (pgcDst->dash != DefaultDash)
854 xfree(pgcDst->dash);
855 pgcDst->numInDashList = pgcSrc->numInDashList;
856 pgcDst->dash = dash;
857 for (i=0; i<pgcSrc->numInDashList; i++)
858 dash[i] = pgcSrc->dash[i];
860 else
861 error = BadAlloc;
863 break;
864 case GCArcMode:
865 pgcDst->arcMode = pgcSrc->arcMode;
866 break;
867 default:
868 clientErrorValue = maskQ;
869 error = BadValue;
870 break;
873 if (pgcDst->fillStyle == FillTiled && pgcDst->tileIsPixel)
875 if (!CreateDefaultTile (pgcDst))
877 pgcDst->fillStyle = FillSolid;
878 error = BadAlloc;
881 (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst);
882 return error;
886 * does the diX part of freeing the characteristics in the GC.
888 * \param value must conform to DeleteType
890 _X_EXPORT int
891 FreeGC(pointer value, XID gid)
893 GCPtr pGC = (GCPtr)value;
895 CloseFont(pGC->font, (Font)0);
896 (* pGC->funcs->DestroyClip)(pGC);
898 if (!pGC->tileIsPixel)
899 (* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
900 if (pGC->stipple)
901 (* pGC->pScreen->DestroyPixmap)(pGC->stipple);
903 (*pGC->funcs->DestroyGC) (pGC);
904 if (pGC->dash != DefaultDash)
905 xfree(pGC->dash);
906 xfree(pGC);
907 return(Success);
910 /* CreateScratchGC(pScreen, depth)
911 like CreateGC, but doesn't do the default tile or stipple,
912 since we can't create them without already having a GC. any code
913 using the tile or stipple has to set them explicitly anyway,
914 since the state of the scratch gc is unknown. This is OK
915 because ChangeGC() has to be able to deal with NULL tiles and
916 stipples anyway (in case the CreateGC() call has provided a
917 value for them -- we can't set the default tile until the
918 client-supplied attributes are installed, since the fgPixel
919 is what fills the default tile. (maybe this comment should
920 go with CreateGC() or ChangeGC().)
923 _X_EXPORT GCPtr
924 CreateScratchGC(ScreenPtr pScreen, unsigned depth)
926 GCPtr pGC;
928 pGC = AllocateGC(pScreen);
929 if (!pGC)
930 return (GCPtr)NULL;
932 pGC->pScreen = pScreen;
933 pGC->depth = depth;
934 pGC->alu = GXcopy; /* dst <- src */
935 pGC->planemask = ~0;
936 pGC->serialNumber = 0;
938 pGC->fgPixel = 0;
939 pGC->bgPixel = 1;
940 pGC->lineWidth = 0;
941 pGC->lineStyle = LineSolid;
942 pGC->capStyle = CapButt;
943 pGC->joinStyle = JoinMiter;
944 pGC->fillStyle = FillSolid;
945 pGC->fillRule = EvenOddRule;
946 pGC->arcMode = ArcPieSlice;
947 pGC->font = defaultFont;
948 if ( pGC->font) /* necessary, because open of default font could fail */
949 pGC->font->refcnt++;
950 pGC->tileIsPixel = TRUE;
951 pGC->tile.pixel = 0;
952 pGC->stipple = NullPixmap;
953 pGC->patOrg.x = 0;
954 pGC->patOrg.y = 0;
955 pGC->subWindowMode = ClipByChildren;
956 pGC->graphicsExposures = TRUE;
957 pGC->clipOrg.x = 0;
958 pGC->clipOrg.y = 0;
959 pGC->clientClipType = CT_NONE;
960 pGC->dashOffset = 0;
961 pGC->numInDashList = 2;
962 pGC->dash = DefaultDash;
963 pGC->lastWinOrg.x = 0;
964 pGC->lastWinOrg.y = 0;
966 pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
967 if (!(*pScreen->CreateGC)(pGC))
969 FreeGC(pGC, (XID)0);
970 pGC = (GCPtr)NULL;
972 return pGC;
975 void
976 FreeGCperDepth(int screenNum)
978 int i;
979 ScreenPtr pScreen;
980 GCPtr *ppGC;
982 pScreen = screenInfo.screens[screenNum];
983 ppGC = pScreen->GCperDepth;
985 for (i = 0; i <= pScreen->numDepths; i++)
986 (void)FreeGC(ppGC[i], (XID)0);
987 pScreen->rgf = ~0L;
991 Bool
992 CreateGCperDepth(int screenNum)
994 int i;
995 ScreenPtr pScreen;
996 DepthPtr pDepth;
997 GCPtr *ppGC;
999 pScreen = screenInfo.screens[screenNum];
1000 pScreen->rgf = 0;
1001 ppGC = pScreen->GCperDepth;
1002 /* do depth 1 separately because it's not included in list */
1003 if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
1004 return FALSE;
1005 ppGC[0]->graphicsExposures = FALSE;
1006 /* Make sure we don't overflow GCperDepth[] */
1007 if( pScreen->numDepths > MAXFORMATS )
1008 return FALSE;
1010 pDepth = pScreen->allowedDepths;
1011 for (i=0; i<pScreen->numDepths; i++, pDepth++)
1013 if (!(ppGC[i+1] = CreateScratchGC(pScreen, pDepth->depth)))
1015 for (; i >= 0; i--)
1016 (void)FreeGC(ppGC[i], (XID)0);
1017 return FALSE;
1019 ppGC[i+1]->graphicsExposures = FALSE;
1021 return TRUE;
1024 Bool
1025 CreateDefaultStipple(int screenNum)
1027 ScreenPtr pScreen;
1028 XID tmpval[3];
1029 xRectangle rect;
1030 CARD16 w, h;
1031 GCPtr pgcScratch;
1033 pScreen = screenInfo.screens[screenNum];
1035 w = 16;
1036 h = 16;
1037 (* pScreen->QueryBestSize)(StippleShape, &w, &h, pScreen);
1038 if (!(pScreen->PixmapPerDepth[0] =
1039 (*pScreen->CreatePixmap)(pScreen, w, h, 1)))
1040 return FALSE;
1041 /* fill stipple with 1 */
1042 tmpval[0] = GXcopy; tmpval[1] = 1; tmpval[2] = FillSolid;
1043 pgcScratch = GetScratchGC(1, pScreen);
1044 if (!pgcScratch)
1046 (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
1047 return FALSE;
1049 (void)ChangeGC(pgcScratch, GCFunction|GCForeground|GCFillStyle, tmpval);
1050 ValidateGC((DrawablePtr)pScreen->PixmapPerDepth[0], pgcScratch);
1051 rect.x = 0;
1052 rect.y = 0;
1053 rect.width = w;
1054 rect.height = h;
1055 (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pScreen->PixmapPerDepth[0],
1056 pgcScratch, 1, &rect);
1057 FreeScratchGC(pgcScratch);
1058 return TRUE;
1061 void
1062 FreeDefaultStipple(int screenNum)
1064 ScreenPtr pScreen = screenInfo.screens[screenNum];
1065 (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
1068 _X_EXPORT int
1069 SetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
1071 long i;
1072 unsigned char *p, *indash;
1073 BITS32 maskQ = 0;
1075 i = ndash;
1076 p = pdash;
1077 while (i--)
1079 if (!*p++)
1081 /* dash segment must be > 0 */
1082 clientErrorValue = 0;
1083 return BadValue;
1087 if (ndash & 1)
1088 p = (unsigned char *)xalloc(2 * ndash * sizeof(unsigned char));
1089 else
1090 p = (unsigned char *)xalloc(ndash * sizeof(unsigned char));
1091 if (!p)
1092 return BadAlloc;
1094 pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
1095 if (offset != pGC->dashOffset)
1097 pGC->dashOffset = offset;
1098 pGC->stateChanges |= GCDashOffset;
1099 maskQ |= GCDashOffset;
1102 if (pGC->dash != DefaultDash)
1103 xfree(pGC->dash);
1104 pGC->numInDashList = ndash;
1105 pGC->dash = p;
1106 if (ndash & 1)
1108 pGC->numInDashList += ndash;
1109 indash = pdash;
1110 i = ndash;
1111 while (i--)
1112 *p++ = *indash++;
1114 while(ndash--)
1115 *p++ = *pdash++;
1116 pGC->stateChanges |= GCDashList;
1117 maskQ |= GCDashList;
1119 if (pGC->funcs->ChangeGC)
1120 (*pGC->funcs->ChangeGC) (pGC, maskQ);
1121 return Success;
1124 _X_EXPORT int
1125 VerifyRectOrder(int nrects, xRectangle *prects, int ordering)
1127 xRectangle *prectP, *prectN;
1128 int i;
1130 switch(ordering)
1132 case Unsorted:
1133 return CT_UNSORTED;
1134 case YSorted:
1135 if(nrects > 1)
1137 for(i = 1, prectP = prects, prectN = prects + 1;
1138 i < nrects;
1139 i++, prectP++, prectN++)
1140 if(prectN->y < prectP->y)
1141 return -1;
1143 return CT_YSORTED;
1144 case YXSorted:
1145 if(nrects > 1)
1147 for(i = 1, prectP = prects, prectN = prects + 1;
1148 i < nrects;
1149 i++, prectP++, prectN++)
1150 if((prectN->y < prectP->y) ||
1151 ( (prectN->y == prectP->y) &&
1152 (prectN->x < prectP->x) ) )
1153 return -1;
1155 return CT_YXSORTED;
1156 case YXBanded:
1157 if(nrects > 1)
1159 for(i = 1, prectP = prects, prectN = prects + 1;
1160 i < nrects;
1161 i++, prectP++, prectN++)
1162 if((prectN->y != prectP->y &&
1163 prectN->y < prectP->y + (int) prectP->height) ||
1164 ((prectN->y == prectP->y) &&
1165 (prectN->height != prectP->height ||
1166 prectN->x < prectP->x + (int) prectP->width)))
1167 return -1;
1169 return CT_YXBANDED;
1171 return -1;
1174 _X_EXPORT int
1175 SetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects,
1176 xRectangle *prects, int ordering)
1178 int newct, size;
1179 xRectangle *prectsNew;
1181 newct = VerifyRectOrder(nrects, prects, ordering);
1182 if (newct < 0)
1183 return(BadMatch);
1184 size = nrects * sizeof(xRectangle);
1185 prectsNew = (xRectangle *) xalloc(size);
1186 if (!prectsNew && size)
1187 return BadAlloc;
1189 pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
1190 pGC->clipOrg.x = xOrigin;
1191 pGC->stateChanges |= GCClipXOrigin;
1193 pGC->clipOrg.y = yOrigin;
1194 pGC->stateChanges |= GCClipYOrigin;
1196 if (size)
1197 memmove((char *)prectsNew, (char *)prects, size);
1198 (*pGC->funcs->ChangeClip)(pGC, newct, (pointer)prectsNew, nrects);
1199 if (pGC->funcs->ChangeGC)
1200 (*pGC->funcs->ChangeGC) (pGC, GCClipXOrigin|GCClipYOrigin|GCClipMask);
1201 return Success;
1206 sets reasonable defaults
1207 if we can get a pre-allocated one, use it and mark it as used.
1208 if we can't, create one out of whole cloth (The Velveteen GC -- if
1209 you use it often enough it will become real.)
1211 _X_EXPORT GCPtr
1212 GetScratchGC(unsigned depth, ScreenPtr pScreen)
1214 int i;
1215 GCPtr pGC;
1217 for (i=0; i<=pScreen->numDepths; i++)
1218 if ( pScreen->GCperDepth[i]->depth == depth &&
1219 !(pScreen->rgf & (1L << (i+1)))
1222 pScreen->rgf |= (1L << (i+1));
1223 pGC = (pScreen->GCperDepth[i]);
1225 pGC->alu = GXcopy;
1226 pGC->planemask = ~0;
1227 pGC->serialNumber = 0;
1228 pGC->fgPixel = 0;
1229 pGC->bgPixel = 1;
1230 pGC->lineWidth = 0;
1231 pGC->lineStyle = LineSolid;
1232 pGC->capStyle = CapButt;
1233 pGC->joinStyle = JoinMiter;
1234 pGC->fillStyle = FillSolid;
1235 pGC->fillRule = EvenOddRule;
1236 pGC->arcMode = ArcChord;
1237 pGC->patOrg.x = 0;
1238 pGC->patOrg.y = 0;
1239 pGC->subWindowMode = ClipByChildren;
1240 pGC->graphicsExposures = FALSE;
1241 pGC->clipOrg.x = 0;
1242 pGC->clipOrg.y = 0;
1243 if (pGC->clientClipType != CT_NONE)
1244 (*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
1245 pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
1246 return pGC;
1248 /* if we make it this far, need to roll our own */
1249 pGC = CreateScratchGC(pScreen, depth);
1250 if (pGC)
1251 pGC->graphicsExposures = FALSE;
1252 return pGC;
1256 if the gc to free is in the table of pre-existing ones,
1257 mark it as available.
1258 if not, free it for real
1260 _X_EXPORT void
1261 FreeScratchGC(GCPtr pGC)
1263 ScreenPtr pScreen = pGC->pScreen;
1264 int i;
1266 for (i=0; i<=pScreen->numDepths; i++)
1268 if ( pScreen->GCperDepth[i] == pGC)
1270 pScreen->rgf &= ~(1L << (i+1));
1271 return;
1274 (void)FreeGC(pGC, (GContext)0);