GCManager.c revision 249c3046
1/***********************************************************
2Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
3
4Permission is hereby granted, free of charge, to any person obtaining a
5copy of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation
7the rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the
9Software is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice (including the next
12paragraph) shall be included in all copies or substantial portions of the
13Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21DEALINGS IN THE SOFTWARE.
22
23Copyright 1987, 1988, 1990 by Digital Equipment Corporation, Maynard, Massachusetts.
24
25                        All Rights Reserved
26
27Permission to use, copy, modify, and distribute this software and its
28documentation for any purpose and without fee is hereby granted,
29provided that the above copyright notice appear in all copies and that
30both that copyright notice and this permission notice appear in
31supporting documentation, and that the name of Digital not be
32used in advertising or publicity pertaining to distribution of the
33software without specific, written prior permission.
34
35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41SOFTWARE.
42
43******************************************************************/
44
45/*
46
47Copyright 1987, 1988, 1990, 1994, 1998  The Open Group
48
49Permission to use, copy, modify, distribute, and sell this software and its
50documentation for any purpose is hereby granted without fee, provided that
51the above copyright notice appear in all copies and that both that
52copyright notice and this permission notice appear in supporting
53documentation.
54
55The above copyright notice and this permission notice shall be included in
56all copies or substantial portions of the Software.
57
58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64
65Except as contained in this notice, the name of The Open Group shall not be
66used in advertising or otherwise to promote the sale, use or other dealings
67in this Software without prior written authorization from The Open Group.
68
69*/
70
71#ifdef HAVE_CONFIG_H
72#include <config.h>
73#endif
74#include "IntrinsicI.h"
75
76
77typedef struct _GCrec {
78    unsigned char screen;	/* Screen for GC */
79    unsigned char depth;	/* Depth for GC */
80    char	  dashes;	/* Dashes value */
81    Pixmap	  clip_mask;	/* Clip_mask value */
82    Cardinal	  ref_count;    /* # of shareholders */
83    GC		  gc;		/* The GC itself. */
84    XtGCMask	  dynamic_mask;	/* Writable values */
85    XtGCMask	  unused_mask;	/* Unused values */
86    struct _GCrec *next;	/* Next GC for this widgetkind. */
87} GCrec, *GCptr;
88
89#define GCVAL(bit,mask,val,default) ((bit&mask) ? val : default)
90
91#define CHECK(bit,comp,default) \
92    if ((checkMask & bit) && \
93	(GCVAL(bit,valueMask,v->comp,default) != gcv.comp)) return False
94
95#define ALLGCVALS (GCFunction | GCPlaneMask | GCForeground | \
96		   GCBackground | GCLineWidth | GCLineStyle | \
97		   GCCapStyle | GCJoinStyle | GCFillStyle | \
98		   GCFillRule | GCTile | GCStipple | \
99		   GCTileStipXOrigin | GCTileStipYOrigin | \
100		   GCFont | GCSubwindowMode | GCGraphicsExposures | \
101		   GCClipXOrigin | GCClipYOrigin | GCDashOffset | \
102		   GCArcMode)
103
104static Bool Matches(
105    Display *dpy,
106    GCptr ptr,
107    register XtGCMask valueMask,
108    register XGCValues *v,
109    XtGCMask readOnlyMask,
110    XtGCMask dynamicMask)
111{
112    XGCValues gcv;
113    register XtGCMask checkMask;
114
115    if (readOnlyMask & ptr->dynamic_mask)
116	return False;
117    if (((ptr->dynamic_mask|ptr->unused_mask) & dynamicMask) != dynamicMask)
118	return False;
119    if (!XGetGCValues(dpy, ptr->gc, ALLGCVALS, &gcv))
120	return False;
121    checkMask = readOnlyMask & ~ptr->unused_mask;
122    CHECK(GCForeground, foreground, 0);
123    CHECK(GCBackground, background, 1);
124    CHECK(GCFont, font, ~0UL);
125    CHECK(GCFillStyle, fill_style, FillSolid);
126    CHECK(GCLineWidth, line_width, 0);
127    CHECK(GCFunction, function, GXcopy);
128    CHECK(GCGraphicsExposures, graphics_exposures, True);
129    CHECK(GCTile, tile, ~0UL);
130    CHECK(GCSubwindowMode, subwindow_mode, ClipByChildren);
131    CHECK(GCPlaneMask, plane_mask, AllPlanes);
132    CHECK(GCLineStyle, line_style, LineSolid);
133    CHECK(GCCapStyle, cap_style, CapButt);
134    CHECK(GCJoinStyle, join_style, JoinMiter);
135    CHECK(GCFillRule, fill_rule, EvenOddRule);
136    CHECK(GCArcMode, arc_mode, ArcPieSlice);
137    CHECK(GCStipple, stipple, ~0UL);
138    CHECK(GCTileStipXOrigin, ts_x_origin, 0);
139    CHECK(GCTileStipYOrigin, ts_y_origin, 0);
140    CHECK(GCClipXOrigin, clip_x_origin, 0);
141    CHECK(GCClipYOrigin, clip_y_origin, 0);
142    CHECK(GCDashOffset, dash_offset, 0);
143    gcv.clip_mask = ptr->clip_mask;
144    CHECK(GCClipMask, clip_mask, None);
145    gcv.dashes = ptr->dashes;
146    CHECK(GCDashList, dashes, 4);
147    valueMask &= ptr->unused_mask | dynamicMask;
148    if (valueMask) {
149	XChangeGC(dpy, ptr->gc, valueMask, v);
150	if (valueMask & GCDashList)
151	    ptr->dashes = v->dashes;
152	if (valueMask & GCClipMask)
153	    ptr->clip_mask = v->clip_mask;
154    }
155    ptr->unused_mask &= ~(dynamicMask | readOnlyMask);
156    ptr->dynamic_mask |= dynamicMask;
157    return True;
158} /* Matches */
159
160/* Called by CloseDisplay to free the per-display GC list */
161void _XtGClistFree(
162    Display *dpy,
163    register XtPerDisplay pd)
164{
165    register GCptr GClist, next;
166    register int i;
167
168    GClist = pd->GClist;
169    while (GClist) {
170	next = GClist->next;
171	XtFree((char*)GClist);
172	GClist = next;
173    }
174    if (pd->pixmap_tab) {
175	for (i = ScreenCount(dpy); --i >= 0; ) {
176	    if (pd->pixmap_tab[i])
177		XtFree((char *)pd->pixmap_tab[i]);
178	}
179	XtFree((char *)pd->pixmap_tab);
180    }
181}
182
183
184/*
185 * Return a GC with the given values and characteristics.
186 */
187
188GC XtAllocateGC(
189    register Widget widget,
190    Cardinal	    depth,
191    XtGCMask        valueMask,
192    XGCValues       *values,
193    XtGCMask        dynamicMask,
194    XtGCMask        unusedMask)
195{
196    register GCptr *prev;
197    register GCptr cur;
198    Screen *screen;
199    register Display *dpy;
200    register XtPerDisplay pd;
201    Drawable drawable;
202    Drawable *pixmaps;
203    XtGCMask readOnlyMask;
204    GC retval;
205    WIDGET_TO_APPCON(widget);
206
207    LOCK_APP(app);
208    LOCK_PROCESS;
209    if (!XtIsWidget(widget))
210	widget = _XtWindowedAncestor(widget);
211    if (!depth)
212	depth = widget->core.depth;
213    screen = XtScreen(widget);
214    dpy = DisplayOfScreen(screen);
215    pd = _XtGetPerDisplay(dpy);
216    unusedMask &= ~valueMask;
217    readOnlyMask = ~(dynamicMask | unusedMask);
218
219    /* Search for existing GC that matches exactly */
220    for (prev = &pd->GClist; (cur = *prev); prev = &cur->next) {
221	if (cur->depth == depth &&
222	    ScreenOfDisplay(dpy, cur->screen) == screen &&
223	    Matches(dpy, cur, valueMask, values, readOnlyMask, dynamicMask)) {
224            cur->ref_count++;
225	    /* Move this GC to front of list */
226	    *prev = cur->next;
227	    cur->next = pd->GClist;
228	    pd->GClist = cur;
229	    retval = cur->gc;
230	    UNLOCK_PROCESS;
231	    UNLOCK_APP(app);
232	    return retval;
233	}
234    }
235
236    /* No matches, have to create a new one */
237    cur = XtNew(GCrec);
238    cur->screen = XScreenNumberOfScreen(screen);
239    cur->depth = depth;
240    cur->ref_count = 1;
241    cur->dynamic_mask = dynamicMask;
242    cur->unused_mask = (unusedMask & ~dynamicMask);
243    cur->dashes = GCVAL(GCDashList, valueMask, values->dashes, 4);
244    cur->clip_mask = GCVAL(GCClipMask, valueMask, values->clip_mask, None);
245    drawable = 0;
246    if (depth == widget->core.depth)
247	drawable = XtWindow(widget);
248    if (!drawable && depth == (Cardinal) DefaultDepthOfScreen(screen))
249	drawable = RootWindowOfScreen(screen);
250    if (!drawable) {
251	if (!pd->pixmap_tab) {
252	    int n;
253	    pd->pixmap_tab = (Drawable **)__XtMalloc((unsigned)ScreenCount(dpy) *
254						   sizeof(Drawable *));
255	    for (n = 0; n < ScreenCount(dpy); n++)
256		pd->pixmap_tab[n] = NULL;
257	}
258	pixmaps = pd->pixmap_tab[cur->screen];
259	if (!pixmaps) {
260	    int max, n, *depths;
261	    depths = XListDepths(dpy, cur->screen, &n);
262	    n--;
263	    max = depths[n];
264	    while (n--) {
265		if (depths[n] > max)
266		    max = depths[n];
267	    }
268	    XFree((char *)depths);
269	    pixmaps = (Drawable *)__XtCalloc((unsigned)max, sizeof(Drawable));
270	    pd->pixmap_tab[cur->screen] = pixmaps;
271	}
272	drawable = pixmaps[cur->depth - 1];
273	if (!drawable) {
274	    drawable = XCreatePixmap(dpy, RootWindowOfScreen(screen), 1, 1,
275				     cur->depth);
276	    pixmaps[cur->depth - 1] = drawable;
277	}
278    }
279    cur->gc = XCreateGC(dpy, drawable, valueMask, values);
280    cur->next = pd->GClist;
281    pd->GClist = cur;
282    retval = cur->gc;
283    UNLOCK_PROCESS;
284    UNLOCK_APP(app);
285    return retval;
286} /* XtAllocateGC */
287
288/*
289 * Return a read-only GC with the given values.
290 */
291
292GC XtGetGC(
293    register Widget widget,
294    XtGCMask        valueMask,
295    XGCValues       *values)
296{
297    return XtAllocateGC(widget, 0, valueMask, values, 0, 0);
298} /* XtGetGC */
299
300void  XtReleaseGC(
301    Widget      widget,
302    register GC gc)
303{
304    register GCptr cur, *prev;
305    Display* dpy;
306    XtPerDisplay pd;
307    WIDGET_TO_APPCON(widget);
308
309    LOCK_APP(app);
310    LOCK_PROCESS;
311    dpy = XtDisplayOfObject(widget);
312    pd = _XtGetPerDisplay(dpy);
313
314    for (prev = &pd->GClist; (cur = *prev); prev = &cur->next) {
315	if (cur->gc == gc) {
316	    if (--(cur->ref_count) == 0) {
317		*prev = cur->next;
318		XFreeGC(dpy, gc);
319		XtFree((char *) cur);
320	    }
321	    break;
322	}
323    }
324    UNLOCK_PROCESS;
325    UNLOCK_APP(app);
326} /* XtReleaseGC */
327
328/*  The following interface is broken and supplied only for backwards
329 *  compatibility.  It will work properly in all cases only if there
330 *  is exactly 1 Display created by the application.
331 */
332
333void XtDestroyGC(register GC gc)
334{
335    GCptr cur, *prev;
336    XtAppContext app;
337
338    LOCK_PROCESS;
339    app = _XtGetProcessContext()->appContextList;
340    /* This is awful; we have to search through all the lists
341       to find the GC. */
342    for (; app; app = app->next) {
343	int i;
344	for (i = app->count; i ;) {
345	    Display *dpy = app->list[--i];
346	    XtPerDisplay pd = _XtGetPerDisplay(dpy);
347	    for (prev = &pd->GClist; (cur = *prev); prev = &cur->next) {
348		if (cur->gc == gc) {
349		    if (--(cur->ref_count) == 0) {
350			*prev = cur->next;
351			XFreeGC(dpy, gc);
352			XtFree((char *) cur);
353		    }
354		    UNLOCK_PROCESS;
355		    return;
356		}
357	    }
358	}
359    }
360    UNLOCK_PROCESS;
361} /* XtDestroyGC */
362