1706f2543Smrg/***********************************************************
2706f2543Smrg
3706f2543SmrgCopyright 1987, 1998  The Open Group
4706f2543Smrg
5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that
7706f2543Smrgthe above copyright notice appear in all copies and that both that
8706f2543Smrgcopyright notice and this permission notice appear in supporting
9706f2543Smrgdocumentation.
10706f2543Smrg
11706f2543SmrgThe above copyright notice and this permission notice shall be included in
12706f2543Smrgall copies or substantial portions of the Software.
13706f2543Smrg
14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20706f2543Smrg
21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be
22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings
23706f2543Smrgin this Software without prior written authorization from The Open Group.
24706f2543Smrg
25706f2543Smrg
26706f2543SmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27706f2543Smrg
28706f2543Smrg                        All Rights Reserved
29706f2543Smrg
30706f2543SmrgPermission to use, copy, modify, and distribute this software and its
31706f2543Smrgdocumentation for any purpose and without fee is hereby granted,
32706f2543Smrgprovided that the above copyright notice appear in all copies and that
33706f2543Smrgboth that copyright notice and this permission notice appear in
34706f2543Smrgsupporting documentation, and that the name of Digital not be
35706f2543Smrgused in advertising or publicity pertaining to distribution of the
36706f2543Smrgsoftware without specific, written prior permission.
37706f2543Smrg
38706f2543SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39706f2543SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40706f2543SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41706f2543SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42706f2543SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43706f2543SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44706f2543SmrgSOFTWARE.
45706f2543Smrg
46706f2543Smrg******************************************************************/
47706f2543Smrg
48706f2543Smrg
49706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
50706f2543Smrg#include <dix-config.h>
51706f2543Smrg#endif
52706f2543Smrg
53706f2543Smrg#include <X11/X.h>
54706f2543Smrg#include <X11/Xmd.h>
55706f2543Smrg#include <X11/Xproto.h>
56706f2543Smrg#include "misc.h"
57706f2543Smrg#include "resource.h"
58706f2543Smrg#include "gcstruct.h"
59706f2543Smrg#include "pixmapstr.h"
60706f2543Smrg#include "dixfontstr.h"
61706f2543Smrg#include "scrnintstr.h"
62706f2543Smrg#include "region.h"
63706f2543Smrg#include "dixstruct.h"
64706f2543Smrg
65706f2543Smrg#include "privates.h"
66706f2543Smrg#include "dix.h"
67706f2543Smrg#include "xace.h"
68706f2543Smrg#include <assert.h>
69706f2543Smrg
70706f2543Smrgextern FontPtr defaultFont;
71706f2543Smrg
72706f2543Smrgstatic Bool CreateDefaultTile(GCPtr pGC);
73706f2543Smrg
74706f2543Smrgstatic unsigned char DefaultDash[2] = {4, 4};
75706f2543Smrg
76706f2543Smrgvoid
77706f2543SmrgValidateGC(DrawablePtr pDraw, GC *pGC)
78706f2543Smrg{
79706f2543Smrg    (*pGC->funcs->ValidateGC) (pGC, pGC->stateChanges, pDraw);
80706f2543Smrg    pGC->stateChanges = 0;
81706f2543Smrg    pGC->serialNumber = pDraw->serialNumber;
82706f2543Smrg}
83706f2543Smrg
84706f2543Smrg
85706f2543Smrg/*
86706f2543Smrg * ChangeGC/ChangeGCXIDs:
87706f2543Smrg *
88706f2543Smrg * The client performing the gc change must be passed so that access
89706f2543Smrg * checks can be performed on any tiles, stipples, or fonts that are
90706f2543Smrg * specified.  ddxen can call this too; they should normally pass
91706f2543Smrg * NullClient for the client since any access checking should have
92706f2543Smrg * already been done at a higher level.
93706f2543Smrg *
94706f2543Smrg * If you have any XIDs, you must use ChangeGCXIDs:
95706f2543Smrg *
96706f2543Smrg *     CARD32 v[2];
97706f2543Smrg *     v[0] = FillTiled;
98706f2543Smrg *     v[1] = pid;
99706f2543Smrg *     ChangeGCXIDs(client, pGC, GCFillStyle|GCTile, v);
100706f2543Smrg *
101706f2543Smrg * However, if you need to pass a pointer to a pixmap or font, you must
102706f2543Smrg * use ChangeGC:
103706f2543Smrg *
104706f2543Smrg *     ChangeGCVal v[2];
105706f2543Smrg *     v[0].val = FillTiled;
106706f2543Smrg *     v[1].ptr = pPixmap;
107706f2543Smrg *     ChangeGC(client, pGC, GCFillStyle|GCTile, v);
108706f2543Smrg *
109706f2543Smrg * If you have neither XIDs nor pointers, you can use either function,
110706f2543Smrg * but ChangeGC will do less work.
111706f2543Smrg *
112706f2543Smrg *     ChangeGCVal v[2];
113706f2543Smrg *     v[0].val = foreground;
114706f2543Smrg *     v[1].val = background;
115706f2543Smrg *     ChangeGC(client, pGC, GCForeground|GCBackground, v);
116706f2543Smrg */
117706f2543Smrg
118706f2543Smrg#define NEXTVAL(_type, _var) { \
119706f2543Smrg	_var = (_type)(pUnion->val); pUnion++; \
120706f2543Smrg    }
121706f2543Smrg
122706f2543Smrg#define NEXT_PTR(_type, _var) { \
123706f2543Smrg    _var = (_type)pUnion->ptr; pUnion++; }
124706f2543Smrg
125706f2543Smrgint
126706f2543SmrgChangeGC(ClientPtr client, GC *pGC, BITS32 mask, ChangeGCValPtr pUnion)
127706f2543Smrg{
128706f2543Smrg    BITS32 	index2;
129706f2543Smrg    int 	error = 0;
130706f2543Smrg    PixmapPtr 	pPixmap;
131706f2543Smrg    BITS32	maskQ;
132706f2543Smrg
133706f2543Smrg    assert(pUnion);
134706f2543Smrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
135706f2543Smrg
136706f2543Smrg    maskQ = mask;	/* save these for when we walk the GCque */
137706f2543Smrg    while (mask && !error)
138706f2543Smrg    {
139706f2543Smrg	index2 = (BITS32) lowbit (mask);
140706f2543Smrg	mask &= ~index2;
141706f2543Smrg	pGC->stateChanges |= index2;
142706f2543Smrg	switch (index2)
143706f2543Smrg	{
144706f2543Smrg	    case GCFunction:
145706f2543Smrg	    {
146706f2543Smrg		CARD8 newalu;
147706f2543Smrg		NEXTVAL(CARD8, newalu);
148706f2543Smrg		if (newalu <= GXset)
149706f2543Smrg		    pGC->alu = newalu;
150706f2543Smrg		else
151706f2543Smrg		{
152706f2543Smrg		    if (client)
153706f2543Smrg			client->errorValue = newalu;
154706f2543Smrg		    error = BadValue;
155706f2543Smrg		}
156706f2543Smrg		break;
157706f2543Smrg	    }
158706f2543Smrg	    case GCPlaneMask:
159706f2543Smrg		NEXTVAL(unsigned long, pGC->planemask);
160706f2543Smrg		break;
161706f2543Smrg	    case GCForeground:
162706f2543Smrg		NEXTVAL(unsigned long, pGC->fgPixel);
163706f2543Smrg		/*
164706f2543Smrg		 * this is for CreateGC
165706f2543Smrg		 */
166706f2543Smrg		if (!pGC->tileIsPixel && !pGC->tile.pixmap)
167706f2543Smrg		{
168706f2543Smrg		    pGC->tileIsPixel = TRUE;
169706f2543Smrg		    pGC->tile.pixel = pGC->fgPixel;
170706f2543Smrg		}
171706f2543Smrg		break;
172706f2543Smrg	    case GCBackground:
173706f2543Smrg		NEXTVAL(unsigned long, pGC->bgPixel);
174706f2543Smrg		break;
175706f2543Smrg	    case GCLineWidth:		/* ??? line width is a CARD16 */
176706f2543Smrg		 NEXTVAL(CARD16, pGC->lineWidth);
177706f2543Smrg		break;
178706f2543Smrg	    case GCLineStyle:
179706f2543Smrg	    {
180706f2543Smrg		unsigned int newlinestyle;
181706f2543Smrg		NEXTVAL(unsigned int, newlinestyle);
182706f2543Smrg		if (newlinestyle <= LineDoubleDash)
183706f2543Smrg		    pGC->lineStyle = newlinestyle;
184706f2543Smrg		else
185706f2543Smrg		{
186706f2543Smrg		    if (client)
187706f2543Smrg			client->errorValue = newlinestyle;
188706f2543Smrg		    error = BadValue;
189706f2543Smrg		}
190706f2543Smrg		break;
191706f2543Smrg	    }
192706f2543Smrg	    case GCCapStyle:
193706f2543Smrg	    {
194706f2543Smrg		unsigned int newcapstyle;
195706f2543Smrg		NEXTVAL(unsigned int, newcapstyle);
196706f2543Smrg		if (newcapstyle <= CapProjecting)
197706f2543Smrg		    pGC->capStyle = newcapstyle;
198706f2543Smrg		else
199706f2543Smrg		{
200706f2543Smrg		    if (client)
201706f2543Smrg			client->errorValue = newcapstyle;
202706f2543Smrg		    error = BadValue;
203706f2543Smrg		}
204706f2543Smrg		break;
205706f2543Smrg	    }
206706f2543Smrg	    case GCJoinStyle:
207706f2543Smrg	    {
208706f2543Smrg		unsigned int newjoinstyle;
209706f2543Smrg		NEXTVAL(unsigned int, newjoinstyle);
210706f2543Smrg		if (newjoinstyle <= JoinBevel)
211706f2543Smrg		    pGC->joinStyle = newjoinstyle;
212706f2543Smrg		else
213706f2543Smrg		{
214706f2543Smrg		    if (client)
215706f2543Smrg			client->errorValue = newjoinstyle;
216706f2543Smrg		    error = BadValue;
217706f2543Smrg		}
218706f2543Smrg		break;
219706f2543Smrg	    }
220706f2543Smrg	    case GCFillStyle:
221706f2543Smrg	    {
222706f2543Smrg		unsigned int newfillstyle;
223706f2543Smrg		NEXTVAL(unsigned int, newfillstyle);
224706f2543Smrg		if (newfillstyle <= FillOpaqueStippled)
225706f2543Smrg		    pGC->fillStyle = newfillstyle;
226706f2543Smrg		else
227706f2543Smrg		{
228706f2543Smrg		    if (client)
229706f2543Smrg			client->errorValue = newfillstyle;
230706f2543Smrg		    error = BadValue;
231706f2543Smrg		}
232706f2543Smrg		break;
233706f2543Smrg	    }
234706f2543Smrg	    case GCFillRule:
235706f2543Smrg	    {
236706f2543Smrg		unsigned int newfillrule;
237706f2543Smrg		NEXTVAL(unsigned int, newfillrule);
238706f2543Smrg		if (newfillrule <= WindingRule)
239706f2543Smrg		    pGC->fillRule = newfillrule;
240706f2543Smrg		else
241706f2543Smrg		{
242706f2543Smrg		    if (client)
243706f2543Smrg			client->errorValue = newfillrule;
244706f2543Smrg		    error = BadValue;
245706f2543Smrg		}
246706f2543Smrg		break;
247706f2543Smrg	    }
248706f2543Smrg	    case GCTile:
249706f2543Smrg		NEXT_PTR(PixmapPtr, pPixmap);
250706f2543Smrg		if ((pPixmap->drawable.depth != pGC->depth) ||
251706f2543Smrg		    (pPixmap->drawable.pScreen != pGC->pScreen))
252706f2543Smrg		{
253706f2543Smrg		    error = BadMatch;
254706f2543Smrg		}
255706f2543Smrg		else
256706f2543Smrg		{
257706f2543Smrg		    pPixmap->refcnt++;
258706f2543Smrg		    if (!pGC->tileIsPixel)
259706f2543Smrg			(* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
260706f2543Smrg		    pGC->tileIsPixel = FALSE;
261706f2543Smrg		    pGC->tile.pixmap = pPixmap;
262706f2543Smrg		}
263706f2543Smrg		break;
264706f2543Smrg	    case GCStipple:
265706f2543Smrg		NEXT_PTR(PixmapPtr, pPixmap);
266706f2543Smrg		if ((pPixmap->drawable.depth != 1) ||
267706f2543Smrg		    (pPixmap->drawable.pScreen != pGC->pScreen))
268706f2543Smrg		{
269706f2543Smrg		    error = BadMatch;
270706f2543Smrg		}
271706f2543Smrg		else
272706f2543Smrg		{
273706f2543Smrg		    pPixmap->refcnt++;
274706f2543Smrg		    if (pGC->stipple)
275706f2543Smrg			(* pGC->pScreen->DestroyPixmap)(pGC->stipple);
276706f2543Smrg		    pGC->stipple = pPixmap;
277706f2543Smrg		}
278706f2543Smrg		break;
279706f2543Smrg	    case GCTileStipXOrigin:
280706f2543Smrg		NEXTVAL(INT16, pGC->patOrg.x);
281706f2543Smrg		break;
282706f2543Smrg	    case GCTileStipYOrigin:
283706f2543Smrg		NEXTVAL(INT16, pGC->patOrg.y);
284706f2543Smrg		break;
285706f2543Smrg	    case GCFont:
286706f2543Smrg    	    {
287706f2543Smrg		FontPtr	pFont;
288706f2543Smrg		NEXT_PTR(FontPtr, pFont);
289706f2543Smrg		pFont->refcnt++;
290706f2543Smrg		if (pGC->font)
291706f2543Smrg		    CloseFont(pGC->font, (Font)0);
292706f2543Smrg		pGC->font = pFont;
293706f2543Smrg		break;
294706f2543Smrg	    }
295706f2543Smrg	    case GCSubwindowMode:
296706f2543Smrg	    {
297706f2543Smrg		unsigned int newclipmode;
298706f2543Smrg		NEXTVAL(unsigned int, newclipmode);
299706f2543Smrg		if (newclipmode <= IncludeInferiors)
300706f2543Smrg		    pGC->subWindowMode = newclipmode;
301706f2543Smrg		else
302706f2543Smrg		{
303706f2543Smrg		    if (client)
304706f2543Smrg			client->errorValue = newclipmode;
305706f2543Smrg		    error = BadValue;
306706f2543Smrg		}
307706f2543Smrg		break;
308706f2543Smrg	    }
309706f2543Smrg	    case GCGraphicsExposures:
310706f2543Smrg    	    {
311706f2543Smrg		unsigned int newge;
312706f2543Smrg		NEXTVAL(unsigned int, newge);
313706f2543Smrg		if (newge <= xTrue)
314706f2543Smrg		    pGC->graphicsExposures = newge;
315706f2543Smrg		else
316706f2543Smrg		{
317706f2543Smrg		    if (client)
318706f2543Smrg			client->errorValue = newge;
319706f2543Smrg		    error = BadValue;
320706f2543Smrg		}
321706f2543Smrg		break;
322706f2543Smrg	    }
323706f2543Smrg	    case GCClipXOrigin:
324706f2543Smrg		NEXTVAL(INT16, pGC->clipOrg.x);
325706f2543Smrg		break;
326706f2543Smrg	    case GCClipYOrigin:
327706f2543Smrg		NEXTVAL(INT16, pGC->clipOrg.y);
328706f2543Smrg		break;
329706f2543Smrg	    case GCClipMask:
330706f2543Smrg		NEXT_PTR(PixmapPtr, pPixmap);
331706f2543Smrg		if (pPixmap)
332706f2543Smrg		{
333706f2543Smrg		    if ((pPixmap->drawable.depth != 1) ||
334706f2543Smrg			(pPixmap->drawable.pScreen != pGC->pScreen))
335706f2543Smrg		    {
336706f2543Smrg			error = BadMatch;
337706f2543Smrg			break;
338706f2543Smrg		    }
339706f2543Smrg		    pPixmap->refcnt++;
340706f2543Smrg		}
341706f2543Smrg		(*pGC->funcs->ChangeClip)(pGC, pPixmap ? CT_PIXMAP : CT_NONE,
342706f2543Smrg					  (pointer)pPixmap, 0);
343706f2543Smrg		break;
344706f2543Smrg	    case GCDashOffset:
345706f2543Smrg		NEXTVAL(INT16, pGC->dashOffset);
346706f2543Smrg		break;
347706f2543Smrg	    case GCDashList:
348706f2543Smrg	    {
349706f2543Smrg		CARD8 newdash;
350706f2543Smrg		NEXTVAL(CARD8, newdash);
351706f2543Smrg		if (newdash == 4)
352706f2543Smrg		{
353706f2543Smrg		    if (pGC->dash != DefaultDash)
354706f2543Smrg		    {
355706f2543Smrg			free(pGC->dash);
356706f2543Smrg			pGC->numInDashList = 2;
357706f2543Smrg			pGC->dash = DefaultDash;
358706f2543Smrg		    }
359706f2543Smrg		}
360706f2543Smrg		else if (newdash != 0)
361706f2543Smrg 		{
362706f2543Smrg		    unsigned char *dash;
363706f2543Smrg
364706f2543Smrg		    dash = malloc(2 * sizeof(unsigned char));
365706f2543Smrg		    if (dash)
366706f2543Smrg		    {
367706f2543Smrg			if (pGC->dash != DefaultDash)
368706f2543Smrg			    free(pGC->dash);
369706f2543Smrg			pGC->numInDashList = 2;
370706f2543Smrg			pGC->dash = dash;
371706f2543Smrg			dash[0] = newdash;
372706f2543Smrg			dash[1] = newdash;
373706f2543Smrg		    }
374706f2543Smrg		    else
375706f2543Smrg			error = BadAlloc;
376706f2543Smrg		}
377706f2543Smrg 		else
378706f2543Smrg		{
379706f2543Smrg		   if (client)
380706f2543Smrg			client->errorValue = newdash;
381706f2543Smrg		   error = BadValue;
382706f2543Smrg		}
383706f2543Smrg		break;
384706f2543Smrg	    }
385706f2543Smrg	    case GCArcMode:
386706f2543Smrg	    {
387706f2543Smrg		unsigned int newarcmode;
388706f2543Smrg		NEXTVAL(unsigned int, newarcmode);
389706f2543Smrg		if (newarcmode <= ArcPieSlice)
390706f2543Smrg		    pGC->arcMode = newarcmode;
391706f2543Smrg		else
392706f2543Smrg		{
393706f2543Smrg		    if (client)
394706f2543Smrg			client->errorValue = newarcmode;
395706f2543Smrg		    error = BadValue;
396706f2543Smrg		}
397706f2543Smrg		break;
398706f2543Smrg	    }
399706f2543Smrg	    default:
400706f2543Smrg		if (client)
401706f2543Smrg		    client->errorValue = maskQ;
402706f2543Smrg		error = BadValue;
403706f2543Smrg		break;
404706f2543Smrg	}
405706f2543Smrg    } /* end while mask && !error */
406706f2543Smrg
407706f2543Smrg    if (pGC->fillStyle == FillTiled && pGC->tileIsPixel)
408706f2543Smrg    {
409706f2543Smrg	if (!CreateDefaultTile (pGC))
410706f2543Smrg	{
411706f2543Smrg	    pGC->fillStyle = FillSolid;
412706f2543Smrg	    error = BadAlloc;
413706f2543Smrg	}
414706f2543Smrg    }
415706f2543Smrg    (*pGC->funcs->ChangeGC)(pGC, maskQ);
416706f2543Smrg    return error;
417706f2543Smrg}
418706f2543Smrg
419706f2543Smrg#undef NEXTVAL
420706f2543Smrg#undef NEXT_PTR
421706f2543Smrg
422706f2543Smrgstatic const struct {
423706f2543Smrg    BITS32 mask;
424706f2543Smrg    RESTYPE type;
425706f2543Smrg    Mask access_mode;
426706f2543Smrg} xidfields[] = {
427706f2543Smrg    { GCTile, RT_PIXMAP, DixReadAccess },
428706f2543Smrg    { GCStipple, RT_PIXMAP, DixReadAccess },
429706f2543Smrg    { GCFont, RT_FONT, DixUseAccess },
430706f2543Smrg    { GCClipMask, RT_PIXMAP, DixReadAccess },
431706f2543Smrg};
432706f2543Smrg
433706f2543Smrgint
434706f2543SmrgChangeGCXIDs(ClientPtr client, GC *pGC, BITS32 mask, CARD32 *pC32)
435706f2543Smrg{
436706f2543Smrg    ChangeGCVal vals[GCLastBit + 1];
437706f2543Smrg    int i;
438706f2543Smrg    if (mask & ~GCAllBits)
439706f2543Smrg    {
440706f2543Smrg	client->errorValue = mask;
441706f2543Smrg	return BadValue;
442706f2543Smrg    }
443706f2543Smrg    for (i = Ones(mask); i--; )
444706f2543Smrg	vals[i].val = pC32[i];
445706f2543Smrg    for (i = 0; i < sizeof(xidfields) / sizeof(*xidfields); ++i)
446706f2543Smrg    {
447706f2543Smrg	int offset, rc;
448706f2543Smrg	if (!(mask & xidfields[i].mask))
449706f2543Smrg	    continue;
450706f2543Smrg	offset = Ones(mask & (xidfields[i].mask - 1));
451706f2543Smrg	if (xidfields[i].mask == GCClipMask && vals[offset].val == None)
452706f2543Smrg	{
453706f2543Smrg	    vals[offset].ptr = NullPixmap;
454706f2543Smrg	    continue;
455706f2543Smrg	}
456706f2543Smrg	rc = dixLookupResourceByType(&vals[offset].ptr, vals[offset].val,
457706f2543Smrg		xidfields[i].type, client, xidfields[i].access_mode);
458706f2543Smrg	if (rc != Success)
459706f2543Smrg	{
460706f2543Smrg	    client->errorValue = vals[offset].val;
461706f2543Smrg	    return rc;
462706f2543Smrg	}
463706f2543Smrg    }
464706f2543Smrg    return ChangeGC(client, pGC, mask, vals);
465706f2543Smrg}
466706f2543Smrg
467706f2543Smrg/* CreateGC(pDrawable, mask, pval, pStatus)
468706f2543Smrg   creates a default GC for the given drawable, using mask to fill
469706f2543Smrg   in any non-default values.
470706f2543Smrg   Returns a pointer to the new GC on success, NULL otherwise.
471706f2543Smrg   returns status of non-default fields in pStatus
472706f2543SmrgBUG:
473706f2543Smrg   should check for failure to create default tile
474706f2543Smrg
475706f2543Smrg*/
476706f2543SmrgGCPtr
477706f2543SmrgCreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus,
478706f2543Smrg	 XID gcid, ClientPtr client)
479706f2543Smrg{
480706f2543Smrg    GCPtr pGC;
481706f2543Smrg
482706f2543Smrg    pGC = dixAllocateObjectWithPrivates(GC, PRIVATE_GC);
483706f2543Smrg    if (!pGC)
484706f2543Smrg    {
485706f2543Smrg	*pStatus = BadAlloc;
486706f2543Smrg	return (GCPtr)NULL;
487706f2543Smrg    }
488706f2543Smrg
489706f2543Smrg    pGC->pScreen = pDrawable->pScreen;
490706f2543Smrg    pGC->depth = pDrawable->depth;
491706f2543Smrg    pGC->alu = GXcopy; /* dst <- src */
492706f2543Smrg    pGC->planemask = ~0;
493706f2543Smrg    pGC->serialNumber = GC_CHANGE_SERIAL_BIT;
494706f2543Smrg    pGC->funcs = 0;
495706f2543Smrg    pGC->fgPixel = 0;
496706f2543Smrg    pGC->bgPixel = 1;
497706f2543Smrg    pGC->lineWidth = 0;
498706f2543Smrg    pGC->lineStyle = LineSolid;
499706f2543Smrg    pGC->capStyle = CapButt;
500706f2543Smrg    pGC->joinStyle = JoinMiter;
501706f2543Smrg    pGC->fillStyle = FillSolid;
502706f2543Smrg    pGC->fillRule = EvenOddRule;
503706f2543Smrg    pGC->arcMode = ArcPieSlice;
504706f2543Smrg    pGC->tile.pixel = 0;
505706f2543Smrg    pGC->tile.pixmap = NullPixmap;
506706f2543Smrg    if (mask & GCForeground)
507706f2543Smrg    {
508706f2543Smrg	/*
509706f2543Smrg	 * magic special case -- ChangeGC checks for this condition
510706f2543Smrg	 * and snags the Foreground value to create a pseudo default-tile
511706f2543Smrg	 */
512706f2543Smrg	pGC->tileIsPixel = FALSE;
513706f2543Smrg    }
514706f2543Smrg    else
515706f2543Smrg    {
516706f2543Smrg	pGC->tileIsPixel = TRUE;
517706f2543Smrg    }
518706f2543Smrg
519706f2543Smrg    pGC->patOrg.x = 0;
520706f2543Smrg    pGC->patOrg.y = 0;
521706f2543Smrg    pGC->subWindowMode = ClipByChildren;
522706f2543Smrg    pGC->graphicsExposures = TRUE;
523706f2543Smrg    pGC->clipOrg.x = 0;
524706f2543Smrg    pGC->clipOrg.y = 0;
525706f2543Smrg    pGC->clientClipType = CT_NONE;
526706f2543Smrg    pGC->clientClip = (pointer)NULL;
527706f2543Smrg    pGC->numInDashList = 2;
528706f2543Smrg    pGC->dash = DefaultDash;
529706f2543Smrg    pGC->dashOffset = 0;
530706f2543Smrg
531706f2543Smrg    /* use the default font and stipple */
532706f2543Smrg    pGC->font = defaultFont;
533706f2543Smrg    defaultFont->refcnt++;
534706f2543Smrg    pGC->stipple = pGC->pScreen->PixmapPerDepth[0];
535706f2543Smrg    pGC->stipple->refcnt++;
536706f2543Smrg
537706f2543Smrg    /* this is not a scratch GC */
538706f2543Smrg    pGC->scratch_inuse = FALSE;
539706f2543Smrg
540706f2543Smrg    /* security creation/labeling check */
541706f2543Smrg    *pStatus = XaceHook(XACE_RESOURCE_ACCESS, client, gcid, RT_GC, pGC,
542706f2543Smrg			RT_NONE, NULL, DixCreateAccess|DixSetAttrAccess);
543706f2543Smrg    if (*pStatus != Success)
544706f2543Smrg	goto out;
545706f2543Smrg
546706f2543Smrg    pGC->stateChanges = GCAllBits;
547706f2543Smrg    if (!(*pGC->pScreen->CreateGC)(pGC))
548706f2543Smrg	*pStatus = BadAlloc;
549706f2543Smrg    else if (mask)
550706f2543Smrg        *pStatus = ChangeGCXIDs(client, pGC, mask, pval);
551706f2543Smrg    else
552706f2543Smrg	*pStatus = Success;
553706f2543Smrg
554706f2543Smrgout:
555706f2543Smrg    if (*pStatus != Success)
556706f2543Smrg    {
557706f2543Smrg	if (!pGC->tileIsPixel && !pGC->tile.pixmap)
558706f2543Smrg	    pGC->tileIsPixel = TRUE; /* undo special case */
559706f2543Smrg	FreeGC(pGC, (XID)0);
560706f2543Smrg	pGC = (GCPtr)NULL;
561706f2543Smrg    }
562706f2543Smrg
563706f2543Smrg    return pGC;
564706f2543Smrg}
565706f2543Smrg
566706f2543Smrgstatic Bool
567706f2543SmrgCreateDefaultTile (GCPtr pGC)
568706f2543Smrg{
569706f2543Smrg    ChangeGCVal	tmpval[3];
570706f2543Smrg    PixmapPtr 	pTile;
571706f2543Smrg    GCPtr	pgcScratch;
572706f2543Smrg    xRectangle	rect;
573706f2543Smrg    CARD16	w, h;
574706f2543Smrg
575706f2543Smrg    w = 1;
576706f2543Smrg    h = 1;
577706f2543Smrg    (*pGC->pScreen->QueryBestSize)(TileShape, &w, &h, pGC->pScreen);
578706f2543Smrg    pTile = (PixmapPtr)
579706f2543Smrg	    (*pGC->pScreen->CreatePixmap)(pGC->pScreen,
580706f2543Smrg					  w, h, pGC->depth, 0);
581706f2543Smrg    pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen);
582706f2543Smrg    if (!pTile || !pgcScratch)
583706f2543Smrg    {
584706f2543Smrg	if (pTile)
585706f2543Smrg	    (*pTile->drawable.pScreen->DestroyPixmap)(pTile);
586706f2543Smrg	if (pgcScratch)
587706f2543Smrg	    FreeScratchGC(pgcScratch);
588706f2543Smrg	return FALSE;
589706f2543Smrg    }
590706f2543Smrg    tmpval[0].val = GXcopy;
591706f2543Smrg    tmpval[1].val = pGC->tile.pixel;
592706f2543Smrg    tmpval[2].val = FillSolid;
593706f2543Smrg    (void)ChangeGC(NullClient, pgcScratch, GCFunction | GCForeground | GCFillStyle, tmpval);
594706f2543Smrg    ValidateGC((DrawablePtr)pTile, pgcScratch);
595706f2543Smrg    rect.x = 0;
596706f2543Smrg    rect.y = 0;
597706f2543Smrg    rect.width = w;
598706f2543Smrg    rect.height = h;
599706f2543Smrg    (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pTile, pgcScratch, 1, &rect);
600706f2543Smrg    /* Always remember to free the scratch graphics context after use. */
601706f2543Smrg    FreeScratchGC(pgcScratch);
602706f2543Smrg
603706f2543Smrg    pGC->tileIsPixel = FALSE;
604706f2543Smrg    pGC->tile.pixmap = pTile;
605706f2543Smrg    return TRUE;
606706f2543Smrg}
607706f2543Smrg
608706f2543Smrgint
609706f2543SmrgCopyGC(GC *pgcSrc, GC *pgcDst, BITS32 mask)
610706f2543Smrg{
611706f2543Smrg    BITS32	index2;
612706f2543Smrg    BITS32	maskQ;
613706f2543Smrg    int 	error = 0;
614706f2543Smrg
615706f2543Smrg    if (pgcSrc == pgcDst)
616706f2543Smrg	return Success;
617706f2543Smrg    pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
618706f2543Smrg    pgcDst->stateChanges |= mask;
619706f2543Smrg    maskQ = mask;
620706f2543Smrg    while (mask)
621706f2543Smrg    {
622706f2543Smrg	index2 = (BITS32) lowbit (mask);
623706f2543Smrg	mask &= ~index2;
624706f2543Smrg	switch (index2)
625706f2543Smrg	{
626706f2543Smrg	    case GCFunction:
627706f2543Smrg		pgcDst->alu = pgcSrc->alu;
628706f2543Smrg		break;
629706f2543Smrg	    case GCPlaneMask:
630706f2543Smrg		pgcDst->planemask = pgcSrc->planemask;
631706f2543Smrg		break;
632706f2543Smrg	    case GCForeground:
633706f2543Smrg		pgcDst->fgPixel = pgcSrc->fgPixel;
634706f2543Smrg		break;
635706f2543Smrg	    case GCBackground:
636706f2543Smrg		pgcDst->bgPixel = pgcSrc->bgPixel;
637706f2543Smrg		break;
638706f2543Smrg	    case GCLineWidth:
639706f2543Smrg		pgcDst->lineWidth = pgcSrc->lineWidth;
640706f2543Smrg		break;
641706f2543Smrg	    case GCLineStyle:
642706f2543Smrg		pgcDst->lineStyle = pgcSrc->lineStyle;
643706f2543Smrg		break;
644706f2543Smrg	    case GCCapStyle:
645706f2543Smrg		pgcDst->capStyle = pgcSrc->capStyle;
646706f2543Smrg		break;
647706f2543Smrg	    case GCJoinStyle:
648706f2543Smrg		pgcDst->joinStyle = pgcSrc->joinStyle;
649706f2543Smrg		break;
650706f2543Smrg	    case GCFillStyle:
651706f2543Smrg		pgcDst->fillStyle = pgcSrc->fillStyle;
652706f2543Smrg		break;
653706f2543Smrg	    case GCFillRule:
654706f2543Smrg		pgcDst->fillRule = pgcSrc->fillRule;
655706f2543Smrg		break;
656706f2543Smrg	    case GCTile:
657706f2543Smrg		{
658706f2543Smrg		    if (EqualPixUnion(pgcDst->tileIsPixel,
659706f2543Smrg				      pgcDst->tile,
660706f2543Smrg				      pgcSrc->tileIsPixel,
661706f2543Smrg				      pgcSrc->tile))
662706f2543Smrg		    {
663706f2543Smrg			break;
664706f2543Smrg		    }
665706f2543Smrg		    if (!pgcDst->tileIsPixel)
666706f2543Smrg			(* pgcDst->pScreen->DestroyPixmap)(pgcDst->tile.pixmap);
667706f2543Smrg		    pgcDst->tileIsPixel = pgcSrc->tileIsPixel;
668706f2543Smrg		    pgcDst->tile = pgcSrc->tile;
669706f2543Smrg		    if (!pgcDst->tileIsPixel)
670706f2543Smrg		       pgcDst->tile.pixmap->refcnt++;
671706f2543Smrg		    break;
672706f2543Smrg		}
673706f2543Smrg	    case GCStipple:
674706f2543Smrg		{
675706f2543Smrg		    if (pgcDst->stipple == pgcSrc->stipple)
676706f2543Smrg			break;
677706f2543Smrg		    if (pgcDst->stipple)
678706f2543Smrg			(* pgcDst->pScreen->DestroyPixmap)(pgcDst->stipple);
679706f2543Smrg		    pgcDst->stipple = pgcSrc->stipple;
680706f2543Smrg		    if (pgcDst->stipple)
681706f2543Smrg			pgcDst->stipple->refcnt ++;
682706f2543Smrg		    break;
683706f2543Smrg		}
684706f2543Smrg	    case GCTileStipXOrigin:
685706f2543Smrg		pgcDst->patOrg.x = pgcSrc->patOrg.x;
686706f2543Smrg		break;
687706f2543Smrg	    case GCTileStipYOrigin:
688706f2543Smrg		pgcDst->patOrg.y = pgcSrc->patOrg.y;
689706f2543Smrg		break;
690706f2543Smrg	    case GCFont:
691706f2543Smrg		if (pgcDst->font == pgcSrc->font)
692706f2543Smrg		    break;
693706f2543Smrg		if (pgcDst->font)
694706f2543Smrg		    CloseFont(pgcDst->font, (Font)0);
695706f2543Smrg		if ((pgcDst->font = pgcSrc->font) != NullFont)
696706f2543Smrg		    (pgcDst->font)->refcnt++;
697706f2543Smrg		break;
698706f2543Smrg	    case GCSubwindowMode:
699706f2543Smrg		pgcDst->subWindowMode = pgcSrc->subWindowMode;
700706f2543Smrg		break;
701706f2543Smrg	    case GCGraphicsExposures:
702706f2543Smrg		pgcDst->graphicsExposures = pgcSrc->graphicsExposures;
703706f2543Smrg		break;
704706f2543Smrg	    case GCClipXOrigin:
705706f2543Smrg		pgcDst->clipOrg.x = pgcSrc->clipOrg.x;
706706f2543Smrg		break;
707706f2543Smrg	    case GCClipYOrigin:
708706f2543Smrg		pgcDst->clipOrg.y = pgcSrc->clipOrg.y;
709706f2543Smrg		break;
710706f2543Smrg	    case GCClipMask:
711706f2543Smrg		(* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
712706f2543Smrg		break;
713706f2543Smrg	    case GCDashOffset:
714706f2543Smrg		pgcDst->dashOffset = pgcSrc->dashOffset;
715706f2543Smrg		break;
716706f2543Smrg	    case GCDashList:
717706f2543Smrg		if (pgcSrc->dash == DefaultDash)
718706f2543Smrg		{
719706f2543Smrg		    if (pgcDst->dash != DefaultDash)
720706f2543Smrg		    {
721706f2543Smrg			free(pgcDst->dash);
722706f2543Smrg			pgcDst->numInDashList = pgcSrc->numInDashList;
723706f2543Smrg			pgcDst->dash = pgcSrc->dash;
724706f2543Smrg		    }
725706f2543Smrg		}
726706f2543Smrg		else
727706f2543Smrg		{
728706f2543Smrg		    unsigned char *dash;
729706f2543Smrg		    unsigned int i;
730706f2543Smrg
731706f2543Smrg		    dash = malloc(pgcSrc->numInDashList * sizeof(unsigned char));
732706f2543Smrg		    if (dash)
733706f2543Smrg		    {
734706f2543Smrg			if (pgcDst->dash != DefaultDash)
735706f2543Smrg			    free(pgcDst->dash);
736706f2543Smrg			pgcDst->numInDashList = pgcSrc->numInDashList;
737706f2543Smrg			pgcDst->dash = dash;
738706f2543Smrg			for (i=0; i<pgcSrc->numInDashList; i++)
739706f2543Smrg			    dash[i] = pgcSrc->dash[i];
740706f2543Smrg		    }
741706f2543Smrg		    else
742706f2543Smrg			error = BadAlloc;
743706f2543Smrg		}
744706f2543Smrg		break;
745706f2543Smrg	    case GCArcMode:
746706f2543Smrg		pgcDst->arcMode = pgcSrc->arcMode;
747706f2543Smrg		break;
748706f2543Smrg	    default:
749706f2543Smrg		FatalError ("CopyGC: Unhandled mask!\n");
750706f2543Smrg	}
751706f2543Smrg    }
752706f2543Smrg    if (pgcDst->fillStyle == FillTiled && pgcDst->tileIsPixel)
753706f2543Smrg    {
754706f2543Smrg	if (!CreateDefaultTile (pgcDst))
755706f2543Smrg	{
756706f2543Smrg	    pgcDst->fillStyle = FillSolid;
757706f2543Smrg	    error = BadAlloc;
758706f2543Smrg	}
759706f2543Smrg    }
760706f2543Smrg    (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst);
761706f2543Smrg    return error;
762706f2543Smrg}
763706f2543Smrg
764706f2543Smrg/**
765706f2543Smrg * does the diX part of freeing the characteristics in the GC.
766706f2543Smrg *
767706f2543Smrg *  \param value  must conform to DeleteType
768706f2543Smrg */
769706f2543Smrgint
770706f2543SmrgFreeGC(pointer value, XID gid)
771706f2543Smrg{
772706f2543Smrg    GCPtr pGC = (GCPtr)value;
773706f2543Smrg
774706f2543Smrg    CloseFont(pGC->font, (Font)0);
775706f2543Smrg    (* pGC->funcs->DestroyClip)(pGC);
776706f2543Smrg
777706f2543Smrg    if (!pGC->tileIsPixel)
778706f2543Smrg	(* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
779706f2543Smrg    if (pGC->stipple)
780706f2543Smrg	(* pGC->pScreen->DestroyPixmap)(pGC->stipple);
781706f2543Smrg
782706f2543Smrg    (*pGC->funcs->DestroyGC) (pGC);
783706f2543Smrg    if (pGC->dash != DefaultDash)
784706f2543Smrg	free(pGC->dash);
785706f2543Smrg    dixFreeObjectWithPrivates(pGC, PRIVATE_GC);
786706f2543Smrg    return Success;
787706f2543Smrg}
788706f2543Smrg
789706f2543Smrg/* CreateScratchGC(pScreen, depth)
790706f2543Smrg    like CreateGC, but doesn't do the default tile or stipple,
791706f2543Smrgsince we can't create them without already having a GC.  any code
792706f2543Smrgusing the tile or stipple has to set them explicitly anyway,
793706f2543Smrgsince the state of the scratch gc is unknown.  This is OK
794706f2543Smrgbecause ChangeGC() has to be able to deal with NULL tiles and
795706f2543Smrgstipples anyway (in case the CreateGC() call has provided a
796706f2543Smrgvalue for them -- we can't set the default tile until the
797706f2543Smrgclient-supplied attributes are installed, since the fgPixel
798706f2543Smrgis what fills the default tile.  (maybe this comment should
799706f2543Smrggo with CreateGC() or ChangeGC().)
800706f2543Smrg*/
801706f2543Smrg
802706f2543Smrgstatic GCPtr
803706f2543SmrgCreateScratchGC(ScreenPtr pScreen, unsigned depth)
804706f2543Smrg{
805706f2543Smrg    GCPtr pGC;
806706f2543Smrg
807706f2543Smrg    pGC = dixAllocateObjectWithPrivates(GC, PRIVATE_GC);
808706f2543Smrg    if (!pGC)
809706f2543Smrg	return (GCPtr)NULL;
810706f2543Smrg
811706f2543Smrg    pGC->pScreen = pScreen;
812706f2543Smrg    pGC->depth = depth;
813706f2543Smrg    pGC->alu = GXcopy; /* dst <- src */
814706f2543Smrg    pGC->planemask = ~0;
815706f2543Smrg    pGC->serialNumber = 0;
816706f2543Smrg    pGC->fgPixel = 0;
817706f2543Smrg    pGC->bgPixel = 1;
818706f2543Smrg    pGC->lineWidth = 0;
819706f2543Smrg    pGC->lineStyle = LineSolid;
820706f2543Smrg    pGC->capStyle = CapButt;
821706f2543Smrg    pGC->joinStyle = JoinMiter;
822706f2543Smrg    pGC->fillStyle = FillSolid;
823706f2543Smrg    pGC->fillRule = EvenOddRule;
824706f2543Smrg    pGC->arcMode = ArcPieSlice;
825706f2543Smrg    pGC->font = defaultFont;
826706f2543Smrg    if ( pGC->font)  /* necessary, because open of default font could fail */
827706f2543Smrg	pGC->font->refcnt++;
828706f2543Smrg    pGC->tileIsPixel = TRUE;
829706f2543Smrg    pGC->tile.pixel = 0;
830706f2543Smrg    pGC->tile.pixmap = NullPixmap;
831706f2543Smrg    pGC->stipple = NullPixmap;
832706f2543Smrg    pGC->patOrg.x = 0;
833706f2543Smrg    pGC->patOrg.y = 0;
834706f2543Smrg    pGC->subWindowMode = ClipByChildren;
835706f2543Smrg    pGC->graphicsExposures = TRUE;
836706f2543Smrg    pGC->clipOrg.x = 0;
837706f2543Smrg    pGC->clipOrg.y = 0;
838706f2543Smrg    pGC->clientClipType = CT_NONE;
839706f2543Smrg    pGC->dashOffset = 0;
840706f2543Smrg    pGC->numInDashList = 2;
841706f2543Smrg    pGC->dash = DefaultDash;
842706f2543Smrg
843706f2543Smrg    /* scratch GCs in the GCperDepth pool start off unused */
844706f2543Smrg    pGC->scratch_inuse = FALSE;
845706f2543Smrg
846706f2543Smrg    pGC->stateChanges = GCAllBits;
847706f2543Smrg    if (!(*pScreen->CreateGC)(pGC))
848706f2543Smrg    {
849706f2543Smrg	FreeGC(pGC, (XID)0);
850706f2543Smrg	pGC = (GCPtr)NULL;
851706f2543Smrg    }
852706f2543Smrg    return pGC;
853706f2543Smrg}
854706f2543Smrg
855706f2543Smrgvoid
856706f2543SmrgFreeGCperDepth(int screenNum)
857706f2543Smrg{
858706f2543Smrg    int i;
859706f2543Smrg    ScreenPtr pScreen;
860706f2543Smrg    GCPtr *ppGC;
861706f2543Smrg
862706f2543Smrg    pScreen = screenInfo.screens[screenNum];
863706f2543Smrg    ppGC = pScreen->GCperDepth;
864706f2543Smrg
865706f2543Smrg    for (i = 0; i <= pScreen->numDepths; i++)
866706f2543Smrg    {
867706f2543Smrg	(void)FreeGC(ppGC[i], (XID)0);
868706f2543Smrg	ppGC[i] = NULL;
869706f2543Smrg    }
870706f2543Smrg}
871706f2543Smrg
872706f2543Smrg
873706f2543SmrgBool
874706f2543SmrgCreateGCperDepth(int screenNum)
875706f2543Smrg{
876706f2543Smrg    int i;
877706f2543Smrg    ScreenPtr pScreen;
878706f2543Smrg    DepthPtr pDepth;
879706f2543Smrg    GCPtr *ppGC;
880706f2543Smrg
881706f2543Smrg    pScreen = screenInfo.screens[screenNum];
882706f2543Smrg    ppGC = pScreen->GCperDepth;
883706f2543Smrg    /* do depth 1 separately because it's not included in list */
884706f2543Smrg    if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
885706f2543Smrg	return FALSE;
886706f2543Smrg    ppGC[0]->graphicsExposures = FALSE;
887706f2543Smrg    /* Make sure we don't overflow GCperDepth[] */
888706f2543Smrg    if( pScreen->numDepths > MAXFORMATS )
889706f2543Smrg	    return FALSE;
890706f2543Smrg
891706f2543Smrg    pDepth = pScreen->allowedDepths;
892706f2543Smrg    for (i=0; i<pScreen->numDepths; i++, pDepth++)
893706f2543Smrg    {
894706f2543Smrg	if (!(ppGC[i+1] = CreateScratchGC(pScreen, pDepth->depth)))
895706f2543Smrg	{
896706f2543Smrg	    for (; i >= 0; i--)
897706f2543Smrg		(void)FreeGC(ppGC[i], (XID)0);
898706f2543Smrg	    return FALSE;
899706f2543Smrg	}
900706f2543Smrg	ppGC[i+1]->graphicsExposures = FALSE;
901706f2543Smrg    }
902706f2543Smrg    return TRUE;
903706f2543Smrg}
904706f2543Smrg
905706f2543SmrgBool
906706f2543SmrgCreateDefaultStipple(int screenNum)
907706f2543Smrg{
908706f2543Smrg    ScreenPtr pScreen;
909706f2543Smrg    ChangeGCVal tmpval[3];
910706f2543Smrg    xRectangle rect;
911706f2543Smrg    CARD16 w, h;
912706f2543Smrg    GCPtr pgcScratch;
913706f2543Smrg
914706f2543Smrg    pScreen = screenInfo.screens[screenNum];
915706f2543Smrg
916706f2543Smrg    w = 16;
917706f2543Smrg    h = 16;
918706f2543Smrg    (* pScreen->QueryBestSize)(StippleShape, &w, &h, pScreen);
919706f2543Smrg    if (!(pScreen->PixmapPerDepth[0] =
920706f2543Smrg			(*pScreen->CreatePixmap)(pScreen, w, h, 1, 0)))
921706f2543Smrg	return FALSE;
922706f2543Smrg    /* fill stipple with 1 */
923706f2543Smrg    tmpval[0].val = GXcopy;
924706f2543Smrg    tmpval[1].val = 1;
925706f2543Smrg    tmpval[2].val = FillSolid;
926706f2543Smrg    pgcScratch = GetScratchGC(1, pScreen);
927706f2543Smrg    if (!pgcScratch)
928706f2543Smrg    {
929706f2543Smrg	(*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
930706f2543Smrg	return FALSE;
931706f2543Smrg    }
932706f2543Smrg    (void)ChangeGC(NullClient, pgcScratch, GCFunction|GCForeground|GCFillStyle, tmpval);
933706f2543Smrg    ValidateGC((DrawablePtr)pScreen->PixmapPerDepth[0], pgcScratch);
934706f2543Smrg    rect.x = 0;
935706f2543Smrg    rect.y = 0;
936706f2543Smrg    rect.width = w;
937706f2543Smrg    rect.height = h;
938706f2543Smrg    (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pScreen->PixmapPerDepth[0],
939706f2543Smrg				     pgcScratch, 1, &rect);
940706f2543Smrg    FreeScratchGC(pgcScratch);
941706f2543Smrg    return TRUE;
942706f2543Smrg}
943706f2543Smrg
944706f2543Smrgvoid
945706f2543SmrgFreeDefaultStipple(int screenNum)
946706f2543Smrg{
947706f2543Smrg    ScreenPtr pScreen = screenInfo.screens[screenNum];
948706f2543Smrg    (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
949706f2543Smrg}
950706f2543Smrg
951706f2543Smrgint
952706f2543SmrgSetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
953706f2543Smrg{
954706f2543Smrg    long i;
955706f2543Smrg    unsigned char *p, *indash;
956706f2543Smrg    BITS32 maskQ = 0;
957706f2543Smrg
958706f2543Smrg    i = ndash;
959706f2543Smrg    p = pdash;
960706f2543Smrg    while (i--)
961706f2543Smrg    {
962706f2543Smrg	if (!*p++)
963706f2543Smrg	{
964706f2543Smrg	    /* dash segment must be > 0 */
965706f2543Smrg	    return BadValue;
966706f2543Smrg	}
967706f2543Smrg    }
968706f2543Smrg
969706f2543Smrg    if (ndash & 1)
970706f2543Smrg	p = malloc(2 * ndash * sizeof(unsigned char));
971706f2543Smrg    else
972706f2543Smrg	p = malloc(ndash * sizeof(unsigned char));
973706f2543Smrg    if (!p)
974706f2543Smrg	return BadAlloc;
975706f2543Smrg
976706f2543Smrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
977706f2543Smrg    if (offset != pGC->dashOffset)
978706f2543Smrg    {
979706f2543Smrg	pGC->dashOffset = offset;
980706f2543Smrg	pGC->stateChanges |= GCDashOffset;
981706f2543Smrg	maskQ |= GCDashOffset;
982706f2543Smrg    }
983706f2543Smrg
984706f2543Smrg    if (pGC->dash != DefaultDash)
985706f2543Smrg	free(pGC->dash);
986706f2543Smrg    pGC->numInDashList = ndash;
987706f2543Smrg    pGC->dash = p;
988706f2543Smrg    if (ndash & 1)
989706f2543Smrg    {
990706f2543Smrg	pGC->numInDashList += ndash;
991706f2543Smrg	indash = pdash;
992706f2543Smrg	i = ndash;
993706f2543Smrg	while (i--)
994706f2543Smrg	    *p++ = *indash++;
995706f2543Smrg    }
996706f2543Smrg    while(ndash--)
997706f2543Smrg	*p++ = *pdash++;
998706f2543Smrg    pGC->stateChanges |= GCDashList;
999706f2543Smrg    maskQ |= GCDashList;
1000706f2543Smrg
1001706f2543Smrg    if (pGC->funcs->ChangeGC)
1002706f2543Smrg	(*pGC->funcs->ChangeGC) (pGC, maskQ);
1003706f2543Smrg    return Success;
1004706f2543Smrg}
1005706f2543Smrg
1006706f2543Smrgint
1007706f2543SmrgVerifyRectOrder(int nrects, xRectangle *prects, int ordering)
1008706f2543Smrg{
1009706f2543Smrg    xRectangle	*prectP, *prectN;
1010706f2543Smrg    int	i;
1011706f2543Smrg
1012706f2543Smrg    switch(ordering)
1013706f2543Smrg    {
1014706f2543Smrg      case Unsorted:
1015706f2543Smrg	  return CT_UNSORTED;
1016706f2543Smrg      case YSorted:
1017706f2543Smrg	  if(nrects > 1)
1018706f2543Smrg	  {
1019706f2543Smrg	      for(i = 1, prectP = prects, prectN = prects + 1;
1020706f2543Smrg		  i < nrects;
1021706f2543Smrg		  i++, prectP++, prectN++)
1022706f2543Smrg		  if(prectN->y < prectP->y)
1023706f2543Smrg		      return -1;
1024706f2543Smrg	  }
1025706f2543Smrg	  return CT_YSORTED;
1026706f2543Smrg      case YXSorted:
1027706f2543Smrg	  if(nrects > 1)
1028706f2543Smrg	  {
1029706f2543Smrg	      for(i = 1, prectP = prects, prectN = prects + 1;
1030706f2543Smrg		  i < nrects;
1031706f2543Smrg		  i++, prectP++, prectN++)
1032706f2543Smrg		  if((prectN->y < prectP->y) ||
1033706f2543Smrg		      ( (prectN->y == prectP->y) &&
1034706f2543Smrg		        (prectN->x < prectP->x) ) )
1035706f2543Smrg		      return -1;
1036706f2543Smrg	  }
1037706f2543Smrg	  return CT_YXSORTED;
1038706f2543Smrg      case YXBanded:
1039706f2543Smrg	  if(nrects > 1)
1040706f2543Smrg	  {
1041706f2543Smrg	      for(i = 1, prectP = prects, prectN = prects + 1;
1042706f2543Smrg		  i < nrects;
1043706f2543Smrg		  i++, prectP++, prectN++)
1044706f2543Smrg		  if((prectN->y != prectP->y &&
1045706f2543Smrg 		      prectN->y < prectP->y + (int) prectP->height) ||
1046706f2543Smrg		     ((prectN->y == prectP->y) &&
1047706f2543Smrg		      (prectN->height != prectP->height ||
1048706f2543Smrg		       prectN->x < prectP->x + (int) prectP->width)))
1049706f2543Smrg		      return -1;
1050706f2543Smrg	  }
1051706f2543Smrg	  return CT_YXBANDED;
1052706f2543Smrg    }
1053706f2543Smrg    return -1;
1054706f2543Smrg}
1055706f2543Smrg
1056706f2543Smrgint
1057706f2543SmrgSetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects,
1058706f2543Smrg             xRectangle *prects, int ordering)
1059706f2543Smrg{
1060706f2543Smrg    int			newct, size;
1061706f2543Smrg    xRectangle 		*prectsNew;
1062706f2543Smrg
1063706f2543Smrg    newct = VerifyRectOrder(nrects, prects, ordering);
1064706f2543Smrg    if (newct < 0)
1065706f2543Smrg	return BadMatch;
1066706f2543Smrg    size = nrects * sizeof(xRectangle);
1067706f2543Smrg    prectsNew = malloc(size);
1068706f2543Smrg    if (!prectsNew && size)
1069706f2543Smrg	return BadAlloc;
1070706f2543Smrg
1071706f2543Smrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
1072706f2543Smrg    pGC->clipOrg.x = xOrigin;
1073706f2543Smrg    pGC->stateChanges |= GCClipXOrigin;
1074706f2543Smrg
1075706f2543Smrg    pGC->clipOrg.y = yOrigin;
1076706f2543Smrg    pGC->stateChanges |= GCClipYOrigin;
1077706f2543Smrg
1078706f2543Smrg    if (size)
1079706f2543Smrg	memmove((char *)prectsNew, (char *)prects, size);
1080706f2543Smrg    (*pGC->funcs->ChangeClip)(pGC, newct, (pointer)prectsNew, nrects);
1081706f2543Smrg    if (pGC->funcs->ChangeGC)
1082706f2543Smrg	(*pGC->funcs->ChangeGC) (pGC, GCClipXOrigin|GCClipYOrigin|GCClipMask);
1083706f2543Smrg    return Success;
1084706f2543Smrg}
1085706f2543Smrg
1086706f2543Smrg
1087706f2543Smrg/*
1088706f2543Smrg   sets reasonable defaults
1089706f2543Smrg   if we can get a pre-allocated one, use it and mark it as used.
1090706f2543Smrg   if we can't, create one out of whole cloth (The Velveteen GC -- if
1091706f2543Smrg   you use it often enough it will become real.)
1092706f2543Smrg*/
1093706f2543SmrgGCPtr
1094706f2543SmrgGetScratchGC(unsigned depth, ScreenPtr pScreen)
1095706f2543Smrg{
1096706f2543Smrg    int i;
1097706f2543Smrg    GCPtr pGC;
1098706f2543Smrg
1099706f2543Smrg    for (i=0; i<=pScreen->numDepths; i++)
1100706f2543Smrg    {
1101706f2543Smrg	pGC = pScreen->GCperDepth[i];
1102706f2543Smrg	if (pGC && pGC->depth == depth && !pGC->scratch_inuse)
1103706f2543Smrg	{
1104706f2543Smrg	    pGC->scratch_inuse = TRUE;
1105706f2543Smrg
1106706f2543Smrg	    pGC->alu = GXcopy;
1107706f2543Smrg	    pGC->planemask = ~0;
1108706f2543Smrg	    pGC->serialNumber = 0;
1109706f2543Smrg	    pGC->fgPixel = 0;
1110706f2543Smrg	    pGC->bgPixel = 1;
1111706f2543Smrg	    pGC->lineWidth = 0;
1112706f2543Smrg	    pGC->lineStyle = LineSolid;
1113706f2543Smrg	    pGC->capStyle = CapButt;
1114706f2543Smrg	    pGC->joinStyle = JoinMiter;
1115706f2543Smrg	    pGC->fillStyle = FillSolid;
1116706f2543Smrg	    pGC->fillRule = EvenOddRule;
1117706f2543Smrg	    pGC->arcMode = ArcChord;
1118706f2543Smrg	    pGC->patOrg.x = 0;
1119706f2543Smrg	    pGC->patOrg.y = 0;
1120706f2543Smrg	    pGC->subWindowMode = ClipByChildren;
1121706f2543Smrg	    pGC->graphicsExposures = FALSE;
1122706f2543Smrg	    pGC->clipOrg.x = 0;
1123706f2543Smrg	    pGC->clipOrg.y = 0;
1124706f2543Smrg	    if (pGC->clientClipType != CT_NONE)
1125706f2543Smrg		(*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
1126706f2543Smrg	    pGC->stateChanges = GCAllBits;
1127706f2543Smrg	    return pGC;
1128706f2543Smrg	}
1129706f2543Smrg    }
1130706f2543Smrg    /* if we make it this far, need to roll our own */
1131706f2543Smrg    pGC = CreateScratchGC(pScreen, depth);
1132706f2543Smrg    if (pGC)
1133706f2543Smrg	pGC->graphicsExposures = FALSE;
1134706f2543Smrg    return pGC;
1135706f2543Smrg}
1136706f2543Smrg
1137706f2543Smrg/*
1138706f2543Smrg   if the gc to free is in the table of pre-existing ones,
1139706f2543Smrgmark it as available.
1140706f2543Smrg   if not, free it for real
1141706f2543Smrg*/
1142706f2543Smrgvoid
1143706f2543SmrgFreeScratchGC(GCPtr pGC)
1144706f2543Smrg{
1145706f2543Smrg    if (pGC->scratch_inuse)
1146706f2543Smrg	pGC->scratch_inuse = FALSE;
1147706f2543Smrg    else
1148706f2543Smrg	FreeGC(pGC, (GContext)0);
1149706f2543Smrg}
1150