gc.c revision 05b261ec
105b261ecSmrg/***********************************************************
205b261ecSmrg
305b261ecSmrgCopyright 1987, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg
2505b261ecSmrg
2605b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2705b261ecSmrg
2805b261ecSmrg                        All Rights Reserved
2905b261ecSmrg
3005b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3105b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3205b261ecSmrgprovided that the above copyright notice appear in all copies and that
3305b261ecSmrgboth that copyright notice and this permission notice appear in
3405b261ecSmrgsupporting documentation, and that the name of Digital not be
3505b261ecSmrgused in advertising or publicity pertaining to distribution of the
3605b261ecSmrgsoftware without specific, written prior permission.
3705b261ecSmrg
3805b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3905b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
4005b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4105b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4205b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4305b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4405b261ecSmrgSOFTWARE.
4505b261ecSmrg
4605b261ecSmrg******************************************************************/
4705b261ecSmrg
4805b261ecSmrg
4905b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5005b261ecSmrg#include <dix-config.h>
5105b261ecSmrg#endif
5205b261ecSmrg
5305b261ecSmrg#include <X11/X.h>
5405b261ecSmrg#include <X11/Xmd.h>
5505b261ecSmrg#include <X11/Xproto.h>
5605b261ecSmrg#include "misc.h"
5705b261ecSmrg#include "resource.h"
5805b261ecSmrg#include "gcstruct.h"
5905b261ecSmrg#include "pixmapstr.h"
6005b261ecSmrg#include "dixfontstr.h"
6105b261ecSmrg#include "scrnintstr.h"
6205b261ecSmrg#include "region.h"
6305b261ecSmrg
6405b261ecSmrg#include "dix.h"
6505b261ecSmrg#include <assert.h>
6605b261ecSmrg
6705b261ecSmrgextern XID clientErrorValue;
6805b261ecSmrgextern FontPtr defaultFont;
6905b261ecSmrg
7005b261ecSmrgstatic Bool CreateDefaultTile(GCPtr pGC);
7105b261ecSmrg
7205b261ecSmrgstatic unsigned char DefaultDash[2] = {4, 4};
7305b261ecSmrg
7405b261ecSmrg_X_EXPORT void
7505b261ecSmrgValidateGC(DrawablePtr pDraw, GC *pGC)
7605b261ecSmrg{
7705b261ecSmrg    (*pGC->funcs->ValidateGC) (pGC, pGC->stateChanges, pDraw);
7805b261ecSmrg    pGC->stateChanges = 0;
7905b261ecSmrg    pGC->serialNumber = pDraw->serialNumber;
8005b261ecSmrg}
8105b261ecSmrg
8205b261ecSmrg
8305b261ecSmrg/* dixChangeGC(client, pGC, mask, pC32, pUnion)
8405b261ecSmrg *
8505b261ecSmrg * This function was created as part of the Security extension
8605b261ecSmrg * implementation.  The client performing the gc change must be passed so
8705b261ecSmrg * that access checks can be performed on any tiles, stipples, or fonts
8805b261ecSmrg * that are specified.  ddxen can call this too; they should normally
8905b261ecSmrg * pass NullClient for the client since any access checking should have
9005b261ecSmrg * already been done at a higher level.
9105b261ecSmrg *
9205b261ecSmrg * Since we had to create a new function anyway, we decided to change the
9305b261ecSmrg * way the list of gc values is passed to eliminate the compiler warnings
9405b261ecSmrg * caused by the DoChangeGC interface.  You can pass the values via pC32
9505b261ecSmrg * or pUnion, but not both; one of them must be NULL.  If you don't need
9605b261ecSmrg * to pass any pointers, you can use either one:
9705b261ecSmrg *
9805b261ecSmrg *     example calling dixChangeGC using pC32 parameter
9905b261ecSmrg *
10005b261ecSmrg *     CARD32 v[2];
10105b261ecSmrg *     v[0] = foreground;
10205b261ecSmrg *     v[1] = background;
10305b261ecSmrg *     dixChangeGC(client, pGC, GCForeground|GCBackground, v, NULL);
10405b261ecSmrg *
10505b261ecSmrg *     example calling dixChangeGC using pUnion parameter;
10605b261ecSmrg *     same effect as above
10705b261ecSmrg *
10805b261ecSmrg *     ChangeGCVal v[2];
10905b261ecSmrg *     v[0].val = foreground;
11005b261ecSmrg *     v[1].val = background;
11105b261ecSmrg *     dixChangeGC(client, pGC, GCForeground|GCBackground, NULL, v);
11205b261ecSmrg *
11305b261ecSmrg * However, if you need to pass a pointer to a pixmap or font, you MUST
11405b261ecSmrg * use the pUnion parameter.
11505b261ecSmrg *
11605b261ecSmrg *     example calling dixChangeGC passing pointers in the value list
11705b261ecSmrg *     v[1].ptr is a pointer to a pixmap
11805b261ecSmrg *
11905b261ecSmrg *     ChangeGCVal v[2];
12005b261ecSmrg *     v[0].val = FillTiled;
12105b261ecSmrg *     v[1].ptr = pPixmap;
12205b261ecSmrg *     dixChangeGC(client, pGC, GCFillStyle|GCTile, NULL, v);
12305b261ecSmrg *
12405b261ecSmrg * Note: we could have gotten by with just the pUnion parameter, but on
12505b261ecSmrg * 64 bit machines that would have forced us to copy the value list that
12605b261ecSmrg * comes in the ChangeGC request.
12705b261ecSmrg *
12805b261ecSmrg * Ideally, we'd change all the DoChangeGC calls to dixChangeGC, but this
12905b261ecSmrg * is far too many changes to consider at this time, so we've only
13005b261ecSmrg * changed the ones that caused compiler warnings.  New code should use
13105b261ecSmrg * dixChangeGC.
13205b261ecSmrg *
13305b261ecSmrg * dpw
13405b261ecSmrg */
13505b261ecSmrg
13605b261ecSmrg#define NEXTVAL(_type, _var) { \
13705b261ecSmrg      if (pC32) _var = (_type)*pC32++; \
13805b261ecSmrg      else { \
13905b261ecSmrg	_var = (_type)(pUnion->val); pUnion++; \
14005b261ecSmrg      } \
14105b261ecSmrg    }
14205b261ecSmrg
14305b261ecSmrg#define NEXT_PTR(_type, _var) { \
14405b261ecSmrg    assert(pUnion); _var = (_type)pUnion->ptr; pUnion++; }
14505b261ecSmrg
14605b261ecSmrg_X_EXPORT int
14705b261ecSmrgdixChangeGC(ClientPtr client, GC *pGC, BITS32 mask, CARD32 *pC32, ChangeGCValPtr pUnion)
14805b261ecSmrg{
14905b261ecSmrg    BITS32 	index2;
15005b261ecSmrg    int 	error = 0;
15105b261ecSmrg    PixmapPtr 	pPixmap;
15205b261ecSmrg    BITS32	maskQ;
15305b261ecSmrg
15405b261ecSmrg    assert( (pC32 && !pUnion) || (!pC32 && pUnion) );
15505b261ecSmrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
15605b261ecSmrg
15705b261ecSmrg    maskQ = mask;	/* save these for when we walk the GCque */
15805b261ecSmrg    while (mask && !error)
15905b261ecSmrg    {
16005b261ecSmrg	index2 = (BITS32) lowbit (mask);
16105b261ecSmrg	mask &= ~index2;
16205b261ecSmrg	pGC->stateChanges |= index2;
16305b261ecSmrg	switch (index2)
16405b261ecSmrg	{
16505b261ecSmrg	    case GCFunction:
16605b261ecSmrg	    {
16705b261ecSmrg		CARD8 newalu;
16805b261ecSmrg		NEXTVAL(CARD8, newalu);
16905b261ecSmrg		if (newalu <= GXset)
17005b261ecSmrg		    pGC->alu = newalu;
17105b261ecSmrg		else
17205b261ecSmrg		{
17305b261ecSmrg		    clientErrorValue = newalu;
17405b261ecSmrg		    error = BadValue;
17505b261ecSmrg		}
17605b261ecSmrg		break;
17705b261ecSmrg	    }
17805b261ecSmrg	    case GCPlaneMask:
17905b261ecSmrg		NEXTVAL(unsigned long, pGC->planemask);
18005b261ecSmrg		break;
18105b261ecSmrg	    case GCForeground:
18205b261ecSmrg		NEXTVAL(unsigned long, pGC->fgPixel);
18305b261ecSmrg		/*
18405b261ecSmrg		 * this is for CreateGC
18505b261ecSmrg		 */
18605b261ecSmrg		if (!pGC->tileIsPixel && !pGC->tile.pixmap)
18705b261ecSmrg		{
18805b261ecSmrg		    pGC->tileIsPixel = TRUE;
18905b261ecSmrg		    pGC->tile.pixel = pGC->fgPixel;
19005b261ecSmrg		}
19105b261ecSmrg		break;
19205b261ecSmrg	    case GCBackground:
19305b261ecSmrg		NEXTVAL(unsigned long, pGC->bgPixel);
19405b261ecSmrg		break;
19505b261ecSmrg	    case GCLineWidth:		/* ??? line width is a CARD16 */
19605b261ecSmrg		 NEXTVAL(CARD16, pGC->lineWidth);
19705b261ecSmrg		break;
19805b261ecSmrg	    case GCLineStyle:
19905b261ecSmrg	    {
20005b261ecSmrg		unsigned int newlinestyle;
20105b261ecSmrg		NEXTVAL(unsigned int, newlinestyle);
20205b261ecSmrg		if (newlinestyle <= LineDoubleDash)
20305b261ecSmrg		    pGC->lineStyle = newlinestyle;
20405b261ecSmrg		else
20505b261ecSmrg		{
20605b261ecSmrg		    clientErrorValue = newlinestyle;
20705b261ecSmrg		    error = BadValue;
20805b261ecSmrg		}
20905b261ecSmrg		break;
21005b261ecSmrg	    }
21105b261ecSmrg	    case GCCapStyle:
21205b261ecSmrg	    {
21305b261ecSmrg		unsigned int newcapstyle;
21405b261ecSmrg		NEXTVAL(unsigned int, newcapstyle);
21505b261ecSmrg		if (newcapstyle <= CapProjecting)
21605b261ecSmrg		    pGC->capStyle = newcapstyle;
21705b261ecSmrg		else
21805b261ecSmrg		{
21905b261ecSmrg		    clientErrorValue = newcapstyle;
22005b261ecSmrg		    error = BadValue;
22105b261ecSmrg		}
22205b261ecSmrg		break;
22305b261ecSmrg	    }
22405b261ecSmrg	    case GCJoinStyle:
22505b261ecSmrg	    {
22605b261ecSmrg		unsigned int newjoinstyle;
22705b261ecSmrg		NEXTVAL(unsigned int, newjoinstyle);
22805b261ecSmrg		if (newjoinstyle <= JoinBevel)
22905b261ecSmrg		    pGC->joinStyle = newjoinstyle;
23005b261ecSmrg		else
23105b261ecSmrg		{
23205b261ecSmrg		    clientErrorValue = newjoinstyle;
23305b261ecSmrg		    error = BadValue;
23405b261ecSmrg		}
23505b261ecSmrg		break;
23605b261ecSmrg	    }
23705b261ecSmrg	    case GCFillStyle:
23805b261ecSmrg	    {
23905b261ecSmrg		unsigned int newfillstyle;
24005b261ecSmrg		NEXTVAL(unsigned int, newfillstyle);
24105b261ecSmrg		if (newfillstyle <= FillOpaqueStippled)
24205b261ecSmrg		    pGC->fillStyle = newfillstyle;
24305b261ecSmrg		else
24405b261ecSmrg		{
24505b261ecSmrg		    clientErrorValue = newfillstyle;
24605b261ecSmrg		    error = BadValue;
24705b261ecSmrg		}
24805b261ecSmrg		break;
24905b261ecSmrg	    }
25005b261ecSmrg	    case GCFillRule:
25105b261ecSmrg	    {
25205b261ecSmrg		unsigned int newfillrule;
25305b261ecSmrg		NEXTVAL(unsigned int, newfillrule);
25405b261ecSmrg		if (newfillrule <= WindingRule)
25505b261ecSmrg		    pGC->fillRule = newfillrule;
25605b261ecSmrg		else
25705b261ecSmrg		{
25805b261ecSmrg		    clientErrorValue = newfillrule;
25905b261ecSmrg		    error = BadValue;
26005b261ecSmrg		}
26105b261ecSmrg		break;
26205b261ecSmrg	    }
26305b261ecSmrg	    case GCTile:
26405b261ecSmrg	    {
26505b261ecSmrg		XID newpix = 0;
26605b261ecSmrg		if (pUnion)
26705b261ecSmrg		{
26805b261ecSmrg		    NEXT_PTR(PixmapPtr, pPixmap);
26905b261ecSmrg		}
27005b261ecSmrg		else
27105b261ecSmrg		{
27205b261ecSmrg		    NEXTVAL(XID, newpix);
27305b261ecSmrg		    pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
27405b261ecSmrg					newpix, RT_PIXMAP, DixReadAccess);
27505b261ecSmrg		}
27605b261ecSmrg		if (pPixmap)
27705b261ecSmrg		{
27805b261ecSmrg		    if ((pPixmap->drawable.depth != pGC->depth) ||
27905b261ecSmrg			(pPixmap->drawable.pScreen != pGC->pScreen))
28005b261ecSmrg		    {
28105b261ecSmrg			error = BadMatch;
28205b261ecSmrg		    }
28305b261ecSmrg		    else
28405b261ecSmrg		    {
28505b261ecSmrg			pPixmap->refcnt++;
28605b261ecSmrg			if (!pGC->tileIsPixel)
28705b261ecSmrg			    (* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
28805b261ecSmrg			pGC->tileIsPixel = FALSE;
28905b261ecSmrg			pGC->tile.pixmap = pPixmap;
29005b261ecSmrg		    }
29105b261ecSmrg		}
29205b261ecSmrg		else
29305b261ecSmrg		{
29405b261ecSmrg		    clientErrorValue = newpix;
29505b261ecSmrg		    error = BadPixmap;
29605b261ecSmrg		}
29705b261ecSmrg		break;
29805b261ecSmrg	    }
29905b261ecSmrg	    case GCStipple:
30005b261ecSmrg	    {
30105b261ecSmrg		XID newstipple = 0;
30205b261ecSmrg		if (pUnion)
30305b261ecSmrg		{
30405b261ecSmrg		    NEXT_PTR(PixmapPtr, pPixmap);
30505b261ecSmrg		}
30605b261ecSmrg		else
30705b261ecSmrg		{
30805b261ecSmrg		    NEXTVAL(XID, newstipple)
30905b261ecSmrg		    pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
31005b261ecSmrg				newstipple, RT_PIXMAP, DixReadAccess);
31105b261ecSmrg		}
31205b261ecSmrg		if (pPixmap)
31305b261ecSmrg		{
31405b261ecSmrg		    if ((pPixmap->drawable.depth != 1) ||
31505b261ecSmrg			(pPixmap->drawable.pScreen != pGC->pScreen))
31605b261ecSmrg		    {
31705b261ecSmrg			error = BadMatch;
31805b261ecSmrg		    }
31905b261ecSmrg		    else
32005b261ecSmrg		    {
32105b261ecSmrg			pPixmap->refcnt++;
32205b261ecSmrg			if (pGC->stipple)
32305b261ecSmrg			    (* pGC->pScreen->DestroyPixmap)(pGC->stipple);
32405b261ecSmrg			pGC->stipple = pPixmap;
32505b261ecSmrg		    }
32605b261ecSmrg		}
32705b261ecSmrg		else
32805b261ecSmrg		{
32905b261ecSmrg		    clientErrorValue = newstipple;
33005b261ecSmrg		    error = BadPixmap;
33105b261ecSmrg		}
33205b261ecSmrg		break;
33305b261ecSmrg	    }
33405b261ecSmrg	    case GCTileStipXOrigin:
33505b261ecSmrg		NEXTVAL(INT16, pGC->patOrg.x);
33605b261ecSmrg		break;
33705b261ecSmrg	    case GCTileStipYOrigin:
33805b261ecSmrg		NEXTVAL(INT16, pGC->patOrg.y);
33905b261ecSmrg		break;
34005b261ecSmrg	    case GCFont:
34105b261ecSmrg    	    {
34205b261ecSmrg		FontPtr	pFont;
34305b261ecSmrg		XID newfont = 0;
34405b261ecSmrg		if (pUnion)
34505b261ecSmrg		{
34605b261ecSmrg		    NEXT_PTR(FontPtr, pFont);
34705b261ecSmrg		}
34805b261ecSmrg		else
34905b261ecSmrg		{
35005b261ecSmrg		    NEXTVAL(XID, newfont)
35105b261ecSmrg		    pFont = (FontPtr)SecurityLookupIDByType(client, newfont,
35205b261ecSmrg						RT_FONT, DixReadAccess);
35305b261ecSmrg		}
35405b261ecSmrg		if (pFont)
35505b261ecSmrg		{
35605b261ecSmrg		    pFont->refcnt++;
35705b261ecSmrg		    if (pGC->font)
35805b261ecSmrg    		        CloseFont(pGC->font, (Font)0);
35905b261ecSmrg		    pGC->font = pFont;
36005b261ecSmrg		 }
36105b261ecSmrg		else
36205b261ecSmrg		{
36305b261ecSmrg		    clientErrorValue = newfont;
36405b261ecSmrg		    error = BadFont;
36505b261ecSmrg		}
36605b261ecSmrg		break;
36705b261ecSmrg	    }
36805b261ecSmrg	    case GCSubwindowMode:
36905b261ecSmrg	    {
37005b261ecSmrg		unsigned int newclipmode;
37105b261ecSmrg		NEXTVAL(unsigned int, newclipmode);
37205b261ecSmrg		if (newclipmode <= IncludeInferiors)
37305b261ecSmrg		    pGC->subWindowMode = newclipmode;
37405b261ecSmrg		else
37505b261ecSmrg		{
37605b261ecSmrg		    clientErrorValue = newclipmode;
37705b261ecSmrg		    error = BadValue;
37805b261ecSmrg		}
37905b261ecSmrg		break;
38005b261ecSmrg	    }
38105b261ecSmrg	    case GCGraphicsExposures:
38205b261ecSmrg    	    {
38305b261ecSmrg		unsigned int newge;
38405b261ecSmrg		NEXTVAL(unsigned int, newge);
38505b261ecSmrg		if (newge <= xTrue)
38605b261ecSmrg		    pGC->graphicsExposures = newge;
38705b261ecSmrg		else
38805b261ecSmrg		{
38905b261ecSmrg		    clientErrorValue = newge;
39005b261ecSmrg		    error = BadValue;
39105b261ecSmrg		}
39205b261ecSmrg		break;
39305b261ecSmrg	    }
39405b261ecSmrg	    case GCClipXOrigin:
39505b261ecSmrg		NEXTVAL(INT16, pGC->clipOrg.x);
39605b261ecSmrg		break;
39705b261ecSmrg	    case GCClipYOrigin:
39805b261ecSmrg		NEXTVAL(INT16, pGC->clipOrg.y);
39905b261ecSmrg		break;
40005b261ecSmrg	    case GCClipMask:
40105b261ecSmrg	    {
40205b261ecSmrg		Pixmap pid = 0;
40305b261ecSmrg		int    clipType = 0;
40405b261ecSmrg
40505b261ecSmrg		if (pUnion)
40605b261ecSmrg		{
40705b261ecSmrg		    NEXT_PTR(PixmapPtr, pPixmap);
40805b261ecSmrg		}
40905b261ecSmrg		else
41005b261ecSmrg		{
41105b261ecSmrg		    NEXTVAL(Pixmap, pid)
41205b261ecSmrg		    if (pid == None)
41305b261ecSmrg		    {
41405b261ecSmrg			clipType = CT_NONE;
41505b261ecSmrg			pPixmap = NullPixmap;
41605b261ecSmrg		    }
41705b261ecSmrg		    else
41805b261ecSmrg		        pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
41905b261ecSmrg					pid, RT_PIXMAP, DixReadAccess);
42005b261ecSmrg		}
42105b261ecSmrg
42205b261ecSmrg		if (pPixmap)
42305b261ecSmrg		{
42405b261ecSmrg		    if ((pPixmap->drawable.depth != 1) ||
42505b261ecSmrg			(pPixmap->drawable.pScreen != pGC->pScreen))
42605b261ecSmrg		    {
42705b261ecSmrg			error = BadMatch;
42805b261ecSmrg		    }
42905b261ecSmrg		    else
43005b261ecSmrg		    {
43105b261ecSmrg			clipType = CT_PIXMAP;
43205b261ecSmrg			pPixmap->refcnt++;
43305b261ecSmrg		    }
43405b261ecSmrg		}
43505b261ecSmrg		else if (!pUnion && (pid != None))
43605b261ecSmrg		{
43705b261ecSmrg		    clientErrorValue = pid;
43805b261ecSmrg		    error = BadPixmap;
43905b261ecSmrg		}
44005b261ecSmrg		if(error == Success)
44105b261ecSmrg		{
44205b261ecSmrg		    (*pGC->funcs->ChangeClip)(pGC, clipType,
44305b261ecSmrg					      (pointer)pPixmap, 0);
44405b261ecSmrg		}
44505b261ecSmrg		break;
44605b261ecSmrg	    }
44705b261ecSmrg	    case GCDashOffset:
44805b261ecSmrg		NEXTVAL(INT16, pGC->dashOffset);
44905b261ecSmrg		break;
45005b261ecSmrg	    case GCDashList:
45105b261ecSmrg	    {
45205b261ecSmrg		CARD8 newdash;
45305b261ecSmrg		NEXTVAL(CARD8, newdash);
45405b261ecSmrg		if (newdash == 4)
45505b261ecSmrg		{
45605b261ecSmrg		    if (pGC->dash != DefaultDash)
45705b261ecSmrg		    {
45805b261ecSmrg			xfree(pGC->dash);
45905b261ecSmrg			pGC->numInDashList = 2;
46005b261ecSmrg			pGC->dash = DefaultDash;
46105b261ecSmrg		    }
46205b261ecSmrg		}
46305b261ecSmrg		else if (newdash != 0)
46405b261ecSmrg 		{
46505b261ecSmrg		    unsigned char *dash;
46605b261ecSmrg
46705b261ecSmrg		    dash = (unsigned char *)xalloc(2 * sizeof(unsigned char));
46805b261ecSmrg		    if (dash)
46905b261ecSmrg		    {
47005b261ecSmrg			if (pGC->dash != DefaultDash)
47105b261ecSmrg			    xfree(pGC->dash);
47205b261ecSmrg			pGC->numInDashList = 2;
47305b261ecSmrg			pGC->dash = dash;
47405b261ecSmrg			dash[0] = newdash;
47505b261ecSmrg			dash[1] = newdash;
47605b261ecSmrg		    }
47705b261ecSmrg		    else
47805b261ecSmrg			error = BadAlloc;
47905b261ecSmrg		}
48005b261ecSmrg 		else
48105b261ecSmrg		{
48205b261ecSmrg		   clientErrorValue = newdash;
48305b261ecSmrg		   error = BadValue;
48405b261ecSmrg		}
48505b261ecSmrg		break;
48605b261ecSmrg	    }
48705b261ecSmrg	    case GCArcMode:
48805b261ecSmrg	    {
48905b261ecSmrg		unsigned int newarcmode;
49005b261ecSmrg		NEXTVAL(unsigned int, newarcmode);
49105b261ecSmrg		if (newarcmode <= ArcPieSlice)
49205b261ecSmrg		    pGC->arcMode = newarcmode;
49305b261ecSmrg		else
49405b261ecSmrg		{
49505b261ecSmrg		    clientErrorValue = newarcmode;
49605b261ecSmrg		    error = BadValue;
49705b261ecSmrg		}
49805b261ecSmrg		break;
49905b261ecSmrg	    }
50005b261ecSmrg	    default:
50105b261ecSmrg		clientErrorValue = maskQ;
50205b261ecSmrg		error = BadValue;
50305b261ecSmrg		break;
50405b261ecSmrg	}
50505b261ecSmrg    } /* end while mask && !error */
50605b261ecSmrg
50705b261ecSmrg    if (pGC->fillStyle == FillTiled && pGC->tileIsPixel)
50805b261ecSmrg    {
50905b261ecSmrg	if (!CreateDefaultTile (pGC))
51005b261ecSmrg	{
51105b261ecSmrg	    pGC->fillStyle = FillSolid;
51205b261ecSmrg	    error = BadAlloc;
51305b261ecSmrg	}
51405b261ecSmrg    }
51505b261ecSmrg    (*pGC->funcs->ChangeGC)(pGC, maskQ);
51605b261ecSmrg    return error;
51705b261ecSmrg}
51805b261ecSmrg
51905b261ecSmrg#undef NEXTVAL
52005b261ecSmrg#undef NEXT_PTR
52105b261ecSmrg
52205b261ecSmrg/* Publically defined entry to ChangeGC.  Just calls dixChangeGC and tells
52305b261ecSmrg * it that all of the entries are constants or IDs */
52405b261ecSmrg_X_EXPORT int
52505b261ecSmrgChangeGC(GC *pGC, BITS32 mask, XID *pval)
52605b261ecSmrg{
52705b261ecSmrg    return (dixChangeGC(NullClient, pGC, mask, pval, NULL));
52805b261ecSmrg}
52905b261ecSmrg
53005b261ecSmrg/* DoChangeGC(pGC, mask, pval, fPointer)
53105b261ecSmrg   mask is a set of bits indicating which values to change.
53205b261ecSmrg   pval contains an appropriate value for each mask.
53305b261ecSmrg   fPointer is true if the values for tiles, stipples, fonts or clipmasks
53405b261ecSmrg   are pointers instead of IDs.  Note: if you are passing pointers you
53505b261ecSmrg   MUST declare the array of values as type pointer!  Other data types
53605b261ecSmrg   may not be large enough to hold pointers on some machines.  Yes,
53705b261ecSmrg   this means you have to cast to (XID *) when you pass the array to
53805b261ecSmrg   DoChangeGC.  Similarly, if you are not passing pointers (fPointer = 0) you
53905b261ecSmrg   MUST declare the array as type XID (not unsigned long!), or again the wrong
54005b261ecSmrg   size data type may be used.  To avoid this cruftiness, use dixChangeGC
54105b261ecSmrg   above.
54205b261ecSmrg
54305b261ecSmrg   if there is an error, the value is marked as changed
54405b261ecSmrg   anyway, which is probably wrong, but infrequent.
54505b261ecSmrg
54605b261ecSmrgNOTE:
54705b261ecSmrg	all values sent over the protocol for ChangeGC requests are
54805b261ecSmrg32 bits long
54905b261ecSmrg*/
55005b261ecSmrg_X_EXPORT int
55105b261ecSmrgDoChangeGC(GC *pGC, BITS32 mask, XID *pval, int fPointer)
55205b261ecSmrg{
55305b261ecSmrg    if (fPointer)
55405b261ecSmrg    /* XXX might be a problem on 64 bit big-endian servers */
55505b261ecSmrg	return dixChangeGC(NullClient, pGC, mask, NULL, (ChangeGCValPtr)pval);
55605b261ecSmrg    else
55705b261ecSmrg	return dixChangeGC(NullClient, pGC, mask, pval, NULL);
55805b261ecSmrg}
55905b261ecSmrg
56005b261ecSmrg
56105b261ecSmrg/* CreateGC(pDrawable, mask, pval, pStatus)
56205b261ecSmrg   creates a default GC for the given drawable, using mask to fill
56305b261ecSmrg   in any non-default values.
56405b261ecSmrg   Returns a pointer to the new GC on success, NULL otherwise.
56505b261ecSmrg   returns status of non-default fields in pStatus
56605b261ecSmrgBUG:
56705b261ecSmrg   should check for failure to create default tile
56805b261ecSmrg
56905b261ecSmrg*/
57005b261ecSmrg
57105b261ecSmrgstatic GCPtr
57205b261ecSmrgAllocateGC(ScreenPtr pScreen)
57305b261ecSmrg{
57405b261ecSmrg    GCPtr pGC;
57505b261ecSmrg    char *ptr;
57605b261ecSmrg    DevUnion *ppriv;
57705b261ecSmrg    unsigned *sizes;
57805b261ecSmrg    unsigned size;
57905b261ecSmrg    int i;
58005b261ecSmrg
58105b261ecSmrg    pGC = (GCPtr)xalloc(pScreen->totalGCSize);
58205b261ecSmrg    if (pGC)
58305b261ecSmrg    {
58405b261ecSmrg	ppriv = (DevUnion *)(pGC + 1);
58505b261ecSmrg	pGC->devPrivates = ppriv;
58605b261ecSmrg	sizes = pScreen->GCPrivateSizes;
58705b261ecSmrg	ptr = (char *)(ppriv + pScreen->GCPrivateLen);
58805b261ecSmrg	for (i = pScreen->GCPrivateLen; --i >= 0; ppriv++, sizes++)
58905b261ecSmrg	{
59005b261ecSmrg	    if ( (size = *sizes) )
59105b261ecSmrg	    {
59205b261ecSmrg		ppriv->ptr = (pointer)ptr;
59305b261ecSmrg		ptr += size;
59405b261ecSmrg	    }
59505b261ecSmrg	    else
59605b261ecSmrg		ppriv->ptr = (pointer)NULL;
59705b261ecSmrg	}
59805b261ecSmrg    }
59905b261ecSmrg    return pGC;
60005b261ecSmrg}
60105b261ecSmrg
60205b261ecSmrg_X_EXPORT GCPtr
60305b261ecSmrgCreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus)
60405b261ecSmrg{
60505b261ecSmrg    GCPtr pGC;
60605b261ecSmrg
60705b261ecSmrg    pGC = AllocateGC(pDrawable->pScreen);
60805b261ecSmrg    if (!pGC)
60905b261ecSmrg    {
61005b261ecSmrg	*pStatus = BadAlloc;
61105b261ecSmrg	return (GCPtr)NULL;
61205b261ecSmrg    }
61305b261ecSmrg
61405b261ecSmrg    pGC->pScreen = pDrawable->pScreen;
61505b261ecSmrg    pGC->depth = pDrawable->depth;
61605b261ecSmrg    pGC->alu = GXcopy; /* dst <- src */
61705b261ecSmrg    pGC->planemask = ~0;
61805b261ecSmrg    pGC->serialNumber = GC_CHANGE_SERIAL_BIT;
61905b261ecSmrg    pGC->funcs = 0;
62005b261ecSmrg
62105b261ecSmrg    pGC->fgPixel = 0;
62205b261ecSmrg    pGC->bgPixel = 1;
62305b261ecSmrg    pGC->lineWidth = 0;
62405b261ecSmrg    pGC->lineStyle = LineSolid;
62505b261ecSmrg    pGC->capStyle = CapButt;
62605b261ecSmrg    pGC->joinStyle = JoinMiter;
62705b261ecSmrg    pGC->fillStyle = FillSolid;
62805b261ecSmrg    pGC->fillRule = EvenOddRule;
62905b261ecSmrg    pGC->arcMode = ArcPieSlice;
63005b261ecSmrg    if (mask & GCForeground)
63105b261ecSmrg    {
63205b261ecSmrg	/*
63305b261ecSmrg	 * magic special case -- ChangeGC checks for this condition
63405b261ecSmrg	 * and snags the Foreground value to create a pseudo default-tile
63505b261ecSmrg	 */
63605b261ecSmrg	pGC->tileIsPixel = FALSE;
63705b261ecSmrg	pGC->tile.pixmap = NullPixmap;
63805b261ecSmrg    }
63905b261ecSmrg    else
64005b261ecSmrg    {
64105b261ecSmrg	pGC->tileIsPixel = TRUE;
64205b261ecSmrg	pGC->tile.pixel = 0;
64305b261ecSmrg    }
64405b261ecSmrg
64505b261ecSmrg    pGC->patOrg.x = 0;
64605b261ecSmrg    pGC->patOrg.y = 0;
64705b261ecSmrg    pGC->subWindowMode = ClipByChildren;
64805b261ecSmrg    pGC->graphicsExposures = TRUE;
64905b261ecSmrg    pGC->clipOrg.x = 0;
65005b261ecSmrg    pGC->clipOrg.y = 0;
65105b261ecSmrg    pGC->clientClipType = CT_NONE;
65205b261ecSmrg    pGC->clientClip = (pointer)NULL;
65305b261ecSmrg    pGC->numInDashList = 2;
65405b261ecSmrg    pGC->dash = DefaultDash;
65505b261ecSmrg    pGC->dashOffset = 0;
65605b261ecSmrg    pGC->lastWinOrg.x = 0;
65705b261ecSmrg    pGC->lastWinOrg.y = 0;
65805b261ecSmrg
65905b261ecSmrg    /* use the default font and stipple */
66005b261ecSmrg    pGC->font = defaultFont;
66105b261ecSmrg    defaultFont->refcnt++;
66205b261ecSmrg    pGC->stipple = pGC->pScreen->PixmapPerDepth[0];
66305b261ecSmrg    pGC->stipple->refcnt++;
66405b261ecSmrg
66505b261ecSmrg    pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
66605b261ecSmrg    if (!(*pGC->pScreen->CreateGC)(pGC))
66705b261ecSmrg	*pStatus = BadAlloc;
66805b261ecSmrg    else if (mask)
66905b261ecSmrg        *pStatus = ChangeGC(pGC, mask, pval);
67005b261ecSmrg    else
67105b261ecSmrg	*pStatus = Success;
67205b261ecSmrg    if (*pStatus != Success)
67305b261ecSmrg    {
67405b261ecSmrg	if (!pGC->tileIsPixel && !pGC->tile.pixmap)
67505b261ecSmrg	    pGC->tileIsPixel = TRUE; /* undo special case */
67605b261ecSmrg	FreeGC(pGC, (XID)0);
67705b261ecSmrg	pGC = (GCPtr)NULL;
67805b261ecSmrg    }
67905b261ecSmrg
68005b261ecSmrg    return (pGC);
68105b261ecSmrg}
68205b261ecSmrg
68305b261ecSmrgstatic Bool
68405b261ecSmrgCreateDefaultTile (GCPtr pGC)
68505b261ecSmrg{
68605b261ecSmrg    XID		tmpval[3];
68705b261ecSmrg    PixmapPtr 	pTile;
68805b261ecSmrg    GCPtr	pgcScratch;
68905b261ecSmrg    xRectangle	rect;
69005b261ecSmrg    CARD16	w, h;
69105b261ecSmrg
69205b261ecSmrg    w = 1;
69305b261ecSmrg    h = 1;
69405b261ecSmrg    (*pGC->pScreen->QueryBestSize)(TileShape, &w, &h, pGC->pScreen);
69505b261ecSmrg    pTile = (PixmapPtr)
69605b261ecSmrg	    (*pGC->pScreen->CreatePixmap)(pGC->pScreen,
69705b261ecSmrg					  w, h, pGC->depth);
69805b261ecSmrg    pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen);
69905b261ecSmrg    if (!pTile || !pgcScratch)
70005b261ecSmrg    {
70105b261ecSmrg	if (pTile)
70205b261ecSmrg	    (*pTile->drawable.pScreen->DestroyPixmap)(pTile);
70305b261ecSmrg	if (pgcScratch)
70405b261ecSmrg	    FreeScratchGC(pgcScratch);
70505b261ecSmrg	return FALSE;
70605b261ecSmrg    }
70705b261ecSmrg    tmpval[0] = GXcopy;
70805b261ecSmrg    tmpval[1] = pGC->tile.pixel;
70905b261ecSmrg    tmpval[2] = FillSolid;
71005b261ecSmrg    (void)ChangeGC(pgcScratch, GCFunction | GCForeground | GCFillStyle,
71105b261ecSmrg		   tmpval);
71205b261ecSmrg    ValidateGC((DrawablePtr)pTile, pgcScratch);
71305b261ecSmrg    rect.x = 0;
71405b261ecSmrg    rect.y = 0;
71505b261ecSmrg    rect.width = w;
71605b261ecSmrg    rect.height = h;
71705b261ecSmrg    (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pTile, pgcScratch, 1, &rect);
71805b261ecSmrg    /* Always remember to free the scratch graphics context after use. */
71905b261ecSmrg    FreeScratchGC(pgcScratch);
72005b261ecSmrg
72105b261ecSmrg    pGC->tileIsPixel = FALSE;
72205b261ecSmrg    pGC->tile.pixmap = pTile;
72305b261ecSmrg    return TRUE;
72405b261ecSmrg}
72505b261ecSmrg
72605b261ecSmrg_X_EXPORT int
72705b261ecSmrgCopyGC(GC *pgcSrc, GC *pgcDst, BITS32 mask)
72805b261ecSmrg{
72905b261ecSmrg    BITS32	index2;
73005b261ecSmrg    BITS32	maskQ;
73105b261ecSmrg    int 	error = 0;
73205b261ecSmrg
73305b261ecSmrg    if (pgcSrc == pgcDst)
73405b261ecSmrg	return Success;
73505b261ecSmrg    pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
73605b261ecSmrg    pgcDst->stateChanges |= mask;
73705b261ecSmrg    maskQ = mask;
73805b261ecSmrg    while (mask)
73905b261ecSmrg    {
74005b261ecSmrg	index2 = (BITS32) lowbit (mask);
74105b261ecSmrg	mask &= ~index2;
74205b261ecSmrg	switch (index2)
74305b261ecSmrg	{
74405b261ecSmrg	    case GCFunction:
74505b261ecSmrg		pgcDst->alu = pgcSrc->alu;
74605b261ecSmrg		break;
74705b261ecSmrg	    case GCPlaneMask:
74805b261ecSmrg		pgcDst->planemask = pgcSrc->planemask;
74905b261ecSmrg		break;
75005b261ecSmrg	    case GCForeground:
75105b261ecSmrg		pgcDst->fgPixel = pgcSrc->fgPixel;
75205b261ecSmrg		break;
75305b261ecSmrg	    case GCBackground:
75405b261ecSmrg		pgcDst->bgPixel = pgcSrc->bgPixel;
75505b261ecSmrg		break;
75605b261ecSmrg	    case GCLineWidth:
75705b261ecSmrg		pgcDst->lineWidth = pgcSrc->lineWidth;
75805b261ecSmrg		break;
75905b261ecSmrg	    case GCLineStyle:
76005b261ecSmrg		pgcDst->lineStyle = pgcSrc->lineStyle;
76105b261ecSmrg		break;
76205b261ecSmrg	    case GCCapStyle:
76305b261ecSmrg		pgcDst->capStyle = pgcSrc->capStyle;
76405b261ecSmrg		break;
76505b261ecSmrg	    case GCJoinStyle:
76605b261ecSmrg		pgcDst->joinStyle = pgcSrc->joinStyle;
76705b261ecSmrg		break;
76805b261ecSmrg	    case GCFillStyle:
76905b261ecSmrg		pgcDst->fillStyle = pgcSrc->fillStyle;
77005b261ecSmrg		break;
77105b261ecSmrg	    case GCFillRule:
77205b261ecSmrg		pgcDst->fillRule = pgcSrc->fillRule;
77305b261ecSmrg		break;
77405b261ecSmrg	    case GCTile:
77505b261ecSmrg		{
77605b261ecSmrg		    if (EqualPixUnion(pgcDst->tileIsPixel,
77705b261ecSmrg				      pgcDst->tile,
77805b261ecSmrg				      pgcSrc->tileIsPixel,
77905b261ecSmrg				      pgcSrc->tile))
78005b261ecSmrg		    {
78105b261ecSmrg			break;
78205b261ecSmrg		    }
78305b261ecSmrg		    if (!pgcDst->tileIsPixel)
78405b261ecSmrg			(* pgcDst->pScreen->DestroyPixmap)(pgcDst->tile.pixmap);
78505b261ecSmrg		    pgcDst->tileIsPixel = pgcSrc->tileIsPixel;
78605b261ecSmrg		    pgcDst->tile = pgcSrc->tile;
78705b261ecSmrg		    if (!pgcDst->tileIsPixel)
78805b261ecSmrg		       pgcDst->tile.pixmap->refcnt++;
78905b261ecSmrg		    break;
79005b261ecSmrg		}
79105b261ecSmrg	    case GCStipple:
79205b261ecSmrg		{
79305b261ecSmrg		    if (pgcDst->stipple == pgcSrc->stipple)
79405b261ecSmrg			break;
79505b261ecSmrg		    if (pgcDst->stipple)
79605b261ecSmrg			(* pgcDst->pScreen->DestroyPixmap)(pgcDst->stipple);
79705b261ecSmrg		    pgcDst->stipple = pgcSrc->stipple;
79805b261ecSmrg		    if (pgcDst->stipple)
79905b261ecSmrg			pgcDst->stipple->refcnt ++;
80005b261ecSmrg		    break;
80105b261ecSmrg		}
80205b261ecSmrg	    case GCTileStipXOrigin:
80305b261ecSmrg		pgcDst->patOrg.x = pgcSrc->patOrg.x;
80405b261ecSmrg		break;
80505b261ecSmrg	    case GCTileStipYOrigin:
80605b261ecSmrg		pgcDst->patOrg.y = pgcSrc->patOrg.y;
80705b261ecSmrg		break;
80805b261ecSmrg	    case GCFont:
80905b261ecSmrg		if (pgcDst->font == pgcSrc->font)
81005b261ecSmrg		    break;
81105b261ecSmrg		if (pgcDst->font)
81205b261ecSmrg		    CloseFont(pgcDst->font, (Font)0);
81305b261ecSmrg		if ((pgcDst->font = pgcSrc->font) != NullFont)
81405b261ecSmrg		    (pgcDst->font)->refcnt++;
81505b261ecSmrg		break;
81605b261ecSmrg	    case GCSubwindowMode:
81705b261ecSmrg		pgcDst->subWindowMode = pgcSrc->subWindowMode;
81805b261ecSmrg		break;
81905b261ecSmrg	    case GCGraphicsExposures:
82005b261ecSmrg		pgcDst->graphicsExposures = pgcSrc->graphicsExposures;
82105b261ecSmrg		break;
82205b261ecSmrg	    case GCClipXOrigin:
82305b261ecSmrg		pgcDst->clipOrg.x = pgcSrc->clipOrg.x;
82405b261ecSmrg		break;
82505b261ecSmrg	    case GCClipYOrigin:
82605b261ecSmrg		pgcDst->clipOrg.y = pgcSrc->clipOrg.y;
82705b261ecSmrg		break;
82805b261ecSmrg	    case GCClipMask:
82905b261ecSmrg		(* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
83005b261ecSmrg		break;
83105b261ecSmrg	    case GCDashOffset:
83205b261ecSmrg		pgcDst->dashOffset = pgcSrc->dashOffset;
83305b261ecSmrg		break;
83405b261ecSmrg	    case GCDashList:
83505b261ecSmrg		if (pgcSrc->dash == DefaultDash)
83605b261ecSmrg		{
83705b261ecSmrg		    if (pgcDst->dash != DefaultDash)
83805b261ecSmrg		    {
83905b261ecSmrg			xfree(pgcDst->dash);
84005b261ecSmrg			pgcDst->numInDashList = pgcSrc->numInDashList;
84105b261ecSmrg			pgcDst->dash = pgcSrc->dash;
84205b261ecSmrg		    }
84305b261ecSmrg		}
84405b261ecSmrg		else
84505b261ecSmrg		{
84605b261ecSmrg		    unsigned char *dash;
84705b261ecSmrg		    unsigned int i;
84805b261ecSmrg
84905b261ecSmrg		    dash = (unsigned char *)xalloc(pgcSrc->numInDashList *
85005b261ecSmrg						   sizeof(unsigned char));
85105b261ecSmrg		    if (dash)
85205b261ecSmrg		    {
85305b261ecSmrg			if (pgcDst->dash != DefaultDash)
85405b261ecSmrg			    xfree(pgcDst->dash);
85505b261ecSmrg			pgcDst->numInDashList = pgcSrc->numInDashList;
85605b261ecSmrg			pgcDst->dash = dash;
85705b261ecSmrg			for (i=0; i<pgcSrc->numInDashList; i++)
85805b261ecSmrg			    dash[i] = pgcSrc->dash[i];
85905b261ecSmrg		    }
86005b261ecSmrg		    else
86105b261ecSmrg			error = BadAlloc;
86205b261ecSmrg		}
86305b261ecSmrg		break;
86405b261ecSmrg	    case GCArcMode:
86505b261ecSmrg		pgcDst->arcMode = pgcSrc->arcMode;
86605b261ecSmrg		break;
86705b261ecSmrg	    default:
86805b261ecSmrg		clientErrorValue = maskQ;
86905b261ecSmrg		error = BadValue;
87005b261ecSmrg		break;
87105b261ecSmrg	}
87205b261ecSmrg    }
87305b261ecSmrg    if (pgcDst->fillStyle == FillTiled && pgcDst->tileIsPixel)
87405b261ecSmrg    {
87505b261ecSmrg	if (!CreateDefaultTile (pgcDst))
87605b261ecSmrg	{
87705b261ecSmrg	    pgcDst->fillStyle = FillSolid;
87805b261ecSmrg	    error = BadAlloc;
87905b261ecSmrg	}
88005b261ecSmrg    }
88105b261ecSmrg    (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst);
88205b261ecSmrg    return error;
88305b261ecSmrg}
88405b261ecSmrg
88505b261ecSmrg/**
88605b261ecSmrg * does the diX part of freeing the characteristics in the GC.
88705b261ecSmrg *
88805b261ecSmrg *  \param value  must conform to DeleteType
88905b261ecSmrg */
89005b261ecSmrg_X_EXPORT int
89105b261ecSmrgFreeGC(pointer value, XID gid)
89205b261ecSmrg{
89305b261ecSmrg    GCPtr pGC = (GCPtr)value;
89405b261ecSmrg
89505b261ecSmrg    CloseFont(pGC->font, (Font)0);
89605b261ecSmrg    (* pGC->funcs->DestroyClip)(pGC);
89705b261ecSmrg
89805b261ecSmrg    if (!pGC->tileIsPixel)
89905b261ecSmrg	(* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
90005b261ecSmrg    if (pGC->stipple)
90105b261ecSmrg	(* pGC->pScreen->DestroyPixmap)(pGC->stipple);
90205b261ecSmrg
90305b261ecSmrg    (*pGC->funcs->DestroyGC) (pGC);
90405b261ecSmrg    if (pGC->dash != DefaultDash)
90505b261ecSmrg	xfree(pGC->dash);
90605b261ecSmrg    xfree(pGC);
90705b261ecSmrg    return(Success);
90805b261ecSmrg}
90905b261ecSmrg
91005b261ecSmrg/* CreateScratchGC(pScreen, depth)
91105b261ecSmrg    like CreateGC, but doesn't do the default tile or stipple,
91205b261ecSmrgsince we can't create them without already having a GC.  any code
91305b261ecSmrgusing the tile or stipple has to set them explicitly anyway,
91405b261ecSmrgsince the state of the scratch gc is unknown.  This is OK
91505b261ecSmrgbecause ChangeGC() has to be able to deal with NULL tiles and
91605b261ecSmrgstipples anyway (in case the CreateGC() call has provided a
91705b261ecSmrgvalue for them -- we can't set the default tile until the
91805b261ecSmrgclient-supplied attributes are installed, since the fgPixel
91905b261ecSmrgis what fills the default tile.  (maybe this comment should
92005b261ecSmrggo with CreateGC() or ChangeGC().)
92105b261ecSmrg*/
92205b261ecSmrg
92305b261ecSmrg_X_EXPORT GCPtr
92405b261ecSmrgCreateScratchGC(ScreenPtr pScreen, unsigned depth)
92505b261ecSmrg{
92605b261ecSmrg    GCPtr pGC;
92705b261ecSmrg
92805b261ecSmrg    pGC = AllocateGC(pScreen);
92905b261ecSmrg    if (!pGC)
93005b261ecSmrg	return (GCPtr)NULL;
93105b261ecSmrg
93205b261ecSmrg    pGC->pScreen = pScreen;
93305b261ecSmrg    pGC->depth = depth;
93405b261ecSmrg    pGC->alu = GXcopy; /* dst <- src */
93505b261ecSmrg    pGC->planemask = ~0;
93605b261ecSmrg    pGC->serialNumber = 0;
93705b261ecSmrg
93805b261ecSmrg    pGC->fgPixel = 0;
93905b261ecSmrg    pGC->bgPixel = 1;
94005b261ecSmrg    pGC->lineWidth = 0;
94105b261ecSmrg    pGC->lineStyle = LineSolid;
94205b261ecSmrg    pGC->capStyle = CapButt;
94305b261ecSmrg    pGC->joinStyle = JoinMiter;
94405b261ecSmrg    pGC->fillStyle = FillSolid;
94505b261ecSmrg    pGC->fillRule = EvenOddRule;
94605b261ecSmrg    pGC->arcMode = ArcPieSlice;
94705b261ecSmrg    pGC->font = defaultFont;
94805b261ecSmrg    if ( pGC->font)  /* necessary, because open of default font could fail */
94905b261ecSmrg	pGC->font->refcnt++;
95005b261ecSmrg    pGC->tileIsPixel = TRUE;
95105b261ecSmrg    pGC->tile.pixel = 0;
95205b261ecSmrg    pGC->stipple = NullPixmap;
95305b261ecSmrg    pGC->patOrg.x = 0;
95405b261ecSmrg    pGC->patOrg.y = 0;
95505b261ecSmrg    pGC->subWindowMode = ClipByChildren;
95605b261ecSmrg    pGC->graphicsExposures = TRUE;
95705b261ecSmrg    pGC->clipOrg.x = 0;
95805b261ecSmrg    pGC->clipOrg.y = 0;
95905b261ecSmrg    pGC->clientClipType = CT_NONE;
96005b261ecSmrg    pGC->dashOffset = 0;
96105b261ecSmrg    pGC->numInDashList = 2;
96205b261ecSmrg    pGC->dash = DefaultDash;
96305b261ecSmrg    pGC->lastWinOrg.x = 0;
96405b261ecSmrg    pGC->lastWinOrg.y = 0;
96505b261ecSmrg
96605b261ecSmrg    pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
96705b261ecSmrg    if (!(*pScreen->CreateGC)(pGC))
96805b261ecSmrg    {
96905b261ecSmrg	FreeGC(pGC, (XID)0);
97005b261ecSmrg	pGC = (GCPtr)NULL;
97105b261ecSmrg    }
97205b261ecSmrg    return pGC;
97305b261ecSmrg}
97405b261ecSmrg
97505b261ecSmrgvoid
97605b261ecSmrgFreeGCperDepth(int screenNum)
97705b261ecSmrg{
97805b261ecSmrg    int i;
97905b261ecSmrg    ScreenPtr pScreen;
98005b261ecSmrg    GCPtr *ppGC;
98105b261ecSmrg
98205b261ecSmrg    pScreen = screenInfo.screens[screenNum];
98305b261ecSmrg    ppGC = pScreen->GCperDepth;
98405b261ecSmrg
98505b261ecSmrg    for (i = 0; i <= pScreen->numDepths; i++)
98605b261ecSmrg	(void)FreeGC(ppGC[i], (XID)0);
98705b261ecSmrg    pScreen->rgf = ~0L;
98805b261ecSmrg}
98905b261ecSmrg
99005b261ecSmrg
99105b261ecSmrgBool
99205b261ecSmrgCreateGCperDepth(int screenNum)
99305b261ecSmrg{
99405b261ecSmrg    int i;
99505b261ecSmrg    ScreenPtr pScreen;
99605b261ecSmrg    DepthPtr pDepth;
99705b261ecSmrg    GCPtr *ppGC;
99805b261ecSmrg
99905b261ecSmrg    pScreen = screenInfo.screens[screenNum];
100005b261ecSmrg    pScreen->rgf = 0;
100105b261ecSmrg    ppGC = pScreen->GCperDepth;
100205b261ecSmrg    /* do depth 1 separately because it's not included in list */
100305b261ecSmrg    if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
100405b261ecSmrg	return FALSE;
100505b261ecSmrg    ppGC[0]->graphicsExposures = FALSE;
100605b261ecSmrg    /* Make sure we don't overflow GCperDepth[] */
100705b261ecSmrg    if( pScreen->numDepths > MAXFORMATS )
100805b261ecSmrg	    return FALSE;
100905b261ecSmrg
101005b261ecSmrg    pDepth = pScreen->allowedDepths;
101105b261ecSmrg    for (i=0; i<pScreen->numDepths; i++, pDepth++)
101205b261ecSmrg    {
101305b261ecSmrg	if (!(ppGC[i+1] = CreateScratchGC(pScreen, pDepth->depth)))
101405b261ecSmrg	{
101505b261ecSmrg	    for (; i >= 0; i--)
101605b261ecSmrg		(void)FreeGC(ppGC[i], (XID)0);
101705b261ecSmrg	    return FALSE;
101805b261ecSmrg	}
101905b261ecSmrg	ppGC[i+1]->graphicsExposures = FALSE;
102005b261ecSmrg    }
102105b261ecSmrg    return TRUE;
102205b261ecSmrg}
102305b261ecSmrg
102405b261ecSmrgBool
102505b261ecSmrgCreateDefaultStipple(int screenNum)
102605b261ecSmrg{
102705b261ecSmrg    ScreenPtr pScreen;
102805b261ecSmrg    XID tmpval[3];
102905b261ecSmrg    xRectangle rect;
103005b261ecSmrg    CARD16 w, h;
103105b261ecSmrg    GCPtr pgcScratch;
103205b261ecSmrg
103305b261ecSmrg    pScreen = screenInfo.screens[screenNum];
103405b261ecSmrg
103505b261ecSmrg    w = 16;
103605b261ecSmrg    h = 16;
103705b261ecSmrg    (* pScreen->QueryBestSize)(StippleShape, &w, &h, pScreen);
103805b261ecSmrg    if (!(pScreen->PixmapPerDepth[0] =
103905b261ecSmrg			(*pScreen->CreatePixmap)(pScreen, w, h, 1)))
104005b261ecSmrg	return FALSE;
104105b261ecSmrg    /* fill stipple with 1 */
104205b261ecSmrg    tmpval[0] = GXcopy; tmpval[1] = 1; tmpval[2] = FillSolid;
104305b261ecSmrg    pgcScratch = GetScratchGC(1, pScreen);
104405b261ecSmrg    if (!pgcScratch)
104505b261ecSmrg    {
104605b261ecSmrg	(*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
104705b261ecSmrg	return FALSE;
104805b261ecSmrg    }
104905b261ecSmrg    (void)ChangeGC(pgcScratch, GCFunction|GCForeground|GCFillStyle, tmpval);
105005b261ecSmrg    ValidateGC((DrawablePtr)pScreen->PixmapPerDepth[0], pgcScratch);
105105b261ecSmrg    rect.x = 0;
105205b261ecSmrg    rect.y = 0;
105305b261ecSmrg    rect.width = w;
105405b261ecSmrg    rect.height = h;
105505b261ecSmrg    (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pScreen->PixmapPerDepth[0],
105605b261ecSmrg				     pgcScratch, 1, &rect);
105705b261ecSmrg    FreeScratchGC(pgcScratch);
105805b261ecSmrg    return TRUE;
105905b261ecSmrg}
106005b261ecSmrg
106105b261ecSmrgvoid
106205b261ecSmrgFreeDefaultStipple(int screenNum)
106305b261ecSmrg{
106405b261ecSmrg    ScreenPtr pScreen = screenInfo.screens[screenNum];
106505b261ecSmrg    (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
106605b261ecSmrg}
106705b261ecSmrg
106805b261ecSmrg_X_EXPORT int
106905b261ecSmrgSetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
107005b261ecSmrg{
107105b261ecSmrg    long i;
107205b261ecSmrg    unsigned char *p, *indash;
107305b261ecSmrg    BITS32 maskQ = 0;
107405b261ecSmrg
107505b261ecSmrg    i = ndash;
107605b261ecSmrg    p = pdash;
107705b261ecSmrg    while (i--)
107805b261ecSmrg    {
107905b261ecSmrg	if (!*p++)
108005b261ecSmrg	{
108105b261ecSmrg	    /* dash segment must be > 0 */
108205b261ecSmrg	    clientErrorValue = 0;
108305b261ecSmrg	    return BadValue;
108405b261ecSmrg	}
108505b261ecSmrg    }
108605b261ecSmrg
108705b261ecSmrg    if (ndash & 1)
108805b261ecSmrg	p = (unsigned char *)xalloc(2 * ndash * sizeof(unsigned char));
108905b261ecSmrg    else
109005b261ecSmrg	p = (unsigned char *)xalloc(ndash * sizeof(unsigned char));
109105b261ecSmrg    if (!p)
109205b261ecSmrg	return BadAlloc;
109305b261ecSmrg
109405b261ecSmrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
109505b261ecSmrg    if (offset != pGC->dashOffset)
109605b261ecSmrg    {
109705b261ecSmrg	pGC->dashOffset = offset;
109805b261ecSmrg	pGC->stateChanges |= GCDashOffset;
109905b261ecSmrg	maskQ |= GCDashOffset;
110005b261ecSmrg    }
110105b261ecSmrg
110205b261ecSmrg    if (pGC->dash != DefaultDash)
110305b261ecSmrg	xfree(pGC->dash);
110405b261ecSmrg    pGC->numInDashList = ndash;
110505b261ecSmrg    pGC->dash = p;
110605b261ecSmrg    if (ndash & 1)
110705b261ecSmrg    {
110805b261ecSmrg	pGC->numInDashList += ndash;
110905b261ecSmrg	indash = pdash;
111005b261ecSmrg	i = ndash;
111105b261ecSmrg	while (i--)
111205b261ecSmrg	    *p++ = *indash++;
111305b261ecSmrg    }
111405b261ecSmrg    while(ndash--)
111505b261ecSmrg	*p++ = *pdash++;
111605b261ecSmrg    pGC->stateChanges |= GCDashList;
111705b261ecSmrg    maskQ |= GCDashList;
111805b261ecSmrg
111905b261ecSmrg    if (pGC->funcs->ChangeGC)
112005b261ecSmrg	(*pGC->funcs->ChangeGC) (pGC, maskQ);
112105b261ecSmrg    return Success;
112205b261ecSmrg}
112305b261ecSmrg
112405b261ecSmrg_X_EXPORT int
112505b261ecSmrgVerifyRectOrder(int nrects, xRectangle *prects, int ordering)
112605b261ecSmrg{
112705b261ecSmrg    xRectangle	*prectP, *prectN;
112805b261ecSmrg    int	i;
112905b261ecSmrg
113005b261ecSmrg    switch(ordering)
113105b261ecSmrg    {
113205b261ecSmrg      case Unsorted:
113305b261ecSmrg	  return CT_UNSORTED;
113405b261ecSmrg      case YSorted:
113505b261ecSmrg	  if(nrects > 1)
113605b261ecSmrg	  {
113705b261ecSmrg	      for(i = 1, prectP = prects, prectN = prects + 1;
113805b261ecSmrg		  i < nrects;
113905b261ecSmrg		  i++, prectP++, prectN++)
114005b261ecSmrg		  if(prectN->y < prectP->y)
114105b261ecSmrg		      return -1;
114205b261ecSmrg	  }
114305b261ecSmrg	  return CT_YSORTED;
114405b261ecSmrg      case YXSorted:
114505b261ecSmrg	  if(nrects > 1)
114605b261ecSmrg	  {
114705b261ecSmrg	      for(i = 1, prectP = prects, prectN = prects + 1;
114805b261ecSmrg		  i < nrects;
114905b261ecSmrg		  i++, prectP++, prectN++)
115005b261ecSmrg		  if((prectN->y < prectP->y) ||
115105b261ecSmrg		      ( (prectN->y == prectP->y) &&
115205b261ecSmrg		        (prectN->x < prectP->x) ) )
115305b261ecSmrg		      return -1;
115405b261ecSmrg	  }
115505b261ecSmrg	  return CT_YXSORTED;
115605b261ecSmrg      case YXBanded:
115705b261ecSmrg	  if(nrects > 1)
115805b261ecSmrg	  {
115905b261ecSmrg	      for(i = 1, prectP = prects, prectN = prects + 1;
116005b261ecSmrg		  i < nrects;
116105b261ecSmrg		  i++, prectP++, prectN++)
116205b261ecSmrg		  if((prectN->y != prectP->y &&
116305b261ecSmrg 		      prectN->y < prectP->y + (int) prectP->height) ||
116405b261ecSmrg		     ((prectN->y == prectP->y) &&
116505b261ecSmrg		      (prectN->height != prectP->height ||
116605b261ecSmrg		       prectN->x < prectP->x + (int) prectP->width)))
116705b261ecSmrg		      return -1;
116805b261ecSmrg	  }
116905b261ecSmrg	  return CT_YXBANDED;
117005b261ecSmrg    }
117105b261ecSmrg    return -1;
117205b261ecSmrg}
117305b261ecSmrg
117405b261ecSmrg_X_EXPORT int
117505b261ecSmrgSetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects,
117605b261ecSmrg             xRectangle *prects, int ordering)
117705b261ecSmrg{
117805b261ecSmrg    int			newct, size;
117905b261ecSmrg    xRectangle 		*prectsNew;
118005b261ecSmrg
118105b261ecSmrg    newct = VerifyRectOrder(nrects, prects, ordering);
118205b261ecSmrg    if (newct < 0)
118305b261ecSmrg	return(BadMatch);
118405b261ecSmrg    size = nrects * sizeof(xRectangle);
118505b261ecSmrg    prectsNew = (xRectangle *) xalloc(size);
118605b261ecSmrg    if (!prectsNew && size)
118705b261ecSmrg	return BadAlloc;
118805b261ecSmrg
118905b261ecSmrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
119005b261ecSmrg    pGC->clipOrg.x = xOrigin;
119105b261ecSmrg    pGC->stateChanges |= GCClipXOrigin;
119205b261ecSmrg
119305b261ecSmrg    pGC->clipOrg.y = yOrigin;
119405b261ecSmrg    pGC->stateChanges |= GCClipYOrigin;
119505b261ecSmrg
119605b261ecSmrg    if (size)
119705b261ecSmrg	memmove((char *)prectsNew, (char *)prects, size);
119805b261ecSmrg    (*pGC->funcs->ChangeClip)(pGC, newct, (pointer)prectsNew, nrects);
119905b261ecSmrg    if (pGC->funcs->ChangeGC)
120005b261ecSmrg	(*pGC->funcs->ChangeGC) (pGC, GCClipXOrigin|GCClipYOrigin|GCClipMask);
120105b261ecSmrg    return Success;
120205b261ecSmrg}
120305b261ecSmrg
120405b261ecSmrg
120505b261ecSmrg/*
120605b261ecSmrg   sets reasonable defaults
120705b261ecSmrg   if we can get a pre-allocated one, use it and mark it as used.
120805b261ecSmrg   if we can't, create one out of whole cloth (The Velveteen GC -- if
120905b261ecSmrg   you use it often enough it will become real.)
121005b261ecSmrg*/
121105b261ecSmrg_X_EXPORT GCPtr
121205b261ecSmrgGetScratchGC(unsigned depth, ScreenPtr pScreen)
121305b261ecSmrg{
121405b261ecSmrg    int i;
121505b261ecSmrg    GCPtr pGC;
121605b261ecSmrg
121705b261ecSmrg    for (i=0; i<=pScreen->numDepths; i++)
121805b261ecSmrg        if ( pScreen->GCperDepth[i]->depth == depth &&
121905b261ecSmrg	     !(pScreen->rgf & (1L << (i+1)))
122005b261ecSmrg	   )
122105b261ecSmrg	{
122205b261ecSmrg	    pScreen->rgf |= (1L << (i+1));
122305b261ecSmrg            pGC = (pScreen->GCperDepth[i]);
122405b261ecSmrg
122505b261ecSmrg	    pGC->alu = GXcopy;
122605b261ecSmrg	    pGC->planemask = ~0;
122705b261ecSmrg	    pGC->serialNumber = 0;
122805b261ecSmrg	    pGC->fgPixel = 0;
122905b261ecSmrg	    pGC->bgPixel = 1;
123005b261ecSmrg	    pGC->lineWidth = 0;
123105b261ecSmrg	    pGC->lineStyle = LineSolid;
123205b261ecSmrg	    pGC->capStyle = CapButt;
123305b261ecSmrg	    pGC->joinStyle = JoinMiter;
123405b261ecSmrg	    pGC->fillStyle = FillSolid;
123505b261ecSmrg	    pGC->fillRule = EvenOddRule;
123605b261ecSmrg	    pGC->arcMode = ArcChord;
123705b261ecSmrg	    pGC->patOrg.x = 0;
123805b261ecSmrg	    pGC->patOrg.y = 0;
123905b261ecSmrg	    pGC->subWindowMode = ClipByChildren;
124005b261ecSmrg	    pGC->graphicsExposures = FALSE;
124105b261ecSmrg	    pGC->clipOrg.x = 0;
124205b261ecSmrg	    pGC->clipOrg.y = 0;
124305b261ecSmrg	    if (pGC->clientClipType != CT_NONE)
124405b261ecSmrg		(*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
124505b261ecSmrg	    pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
124605b261ecSmrg	    return pGC;
124705b261ecSmrg	}
124805b261ecSmrg    /* if we make it this far, need to roll our own */
124905b261ecSmrg    pGC = CreateScratchGC(pScreen, depth);
125005b261ecSmrg    if (pGC)
125105b261ecSmrg	pGC->graphicsExposures = FALSE;
125205b261ecSmrg    return pGC;
125305b261ecSmrg}
125405b261ecSmrg
125505b261ecSmrg/*
125605b261ecSmrg   if the gc to free is in the table of pre-existing ones,
125705b261ecSmrgmark it as available.
125805b261ecSmrg   if not, free it for real
125905b261ecSmrg*/
126005b261ecSmrg_X_EXPORT void
126105b261ecSmrgFreeScratchGC(GCPtr pGC)
126205b261ecSmrg{
126305b261ecSmrg    ScreenPtr pScreen = pGC->pScreen;
126405b261ecSmrg    int i;
126505b261ecSmrg
126605b261ecSmrg    for (i=0; i<=pScreen->numDepths; i++)
126705b261ecSmrg    {
126805b261ecSmrg        if ( pScreen->GCperDepth[i] == pGC)
126905b261ecSmrg	{
127005b261ecSmrg	    pScreen->rgf &= ~(1L << (i+1));
127105b261ecSmrg	    return;
127205b261ecSmrg	}
127305b261ecSmrg    }
127405b261ecSmrg    (void)FreeGC(pGC, (GContext)0);
127505b261ecSmrg}
1276