GCManager.c revision fdf6a26f
11.5Snat/***********************************************************
21.1SnatCopyright (c) 1993, Oracle and/or its affiliates.
31.1Snat
41.5SnatPermission is hereby granted, free of charge, to any person obtaining a
51.1Snatcopy of this software and associated documentation files (the "Software"),
61.1Snatto deal in the Software without restriction, including without limitation
71.1Snatthe rights to use, copy, modify, merge, publish, distribute, sublicense,
81.1Snatand/or sell copies of the Software, and to permit persons to whom the
91.1SnatSoftware is furnished to do so, subject to the following conditions:
101.1Snat
111.1SnatThe above copyright notice and this permission notice (including the next
121.1Snatparagraph) shall be included in all copies or substantial portions of the
131.1SnatSoftware.
141.1Snat
151.1SnatTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161.1SnatIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171.1SnatFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
181.1SnatTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
191.1SnatLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
201.1SnatFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
211.1SnatDEALINGS IN THE SOFTWARE.
221.1Snat
231.1SnatCopyright 1987, 1988, 1990 by Digital Equipment Corporation, Maynard, Massachusetts.
241.1Snat
251.1Snat                        All Rights Reserved
261.1Snat
271.1SnatPermission to use, copy, modify, and distribute this software and its
281.1Snatdocumentation for any purpose and without fee is hereby granted,
291.1Snatprovided that the above copyright notice appear in all copies and that
301.1Snatboth that copyright notice and this permission notice appear in
311.1Snatsupporting documentation, and that the name of Digital not be
321.1Snatused in advertising or publicity pertaining to distribution of the
331.1Snatsoftware without specific, written prior permission.
341.1Snat
351.1SnatDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
361.1SnatALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
371.5SnatDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
381.3SjmcneillANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
391.3SjmcneillWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
401.1SnatARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
411.1SnatSOFTWARE.
421.1Snat
431.1Snat******************************************************************/
441.1Snat
451.1Snat/*
461.1Snat
471.1SnatCopyright 1987, 1988, 1990, 1994, 1998  The Open Group
481.1Snat
491.1SnatPermission to use, copy, modify, distribute, and sell this software and its
501.1Snatdocumentation for any purpose is hereby granted without fee, provided that
511.3Sjmcneillthe above copyright notice appear in all copies and that both that
521.1Snatcopyright notice and this permission notice appear in supporting
531.1Snatdocumentation.
541.1Snat
551.1SnatThe above copyright notice and this permission notice shall be included in
561.1Snatall copies or substantial portions of the Software.
571.1Snat
581.1SnatTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
591.4SnatIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
601.4SnatFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
611.4SnatOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
621.1SnatAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
631.1SnatCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
641.1Snat
651.3SjmcneillExcept as contained in this notice, the name of The Open Group shall not be
661.3Sjmcneillused in advertising or otherwise to promote the sale, use or other dealings
671.4Snatin this Software without prior written authorization from The Open Group.
681.4Snat
691.4Snat*/
701.3Sjmcneill
711.3Sjmcneill#ifdef HAVE_CONFIG_H
721.3Sjmcneill#include <config.h>
731.3Sjmcneill#endif
741.3Sjmcneill#include "IntrinsicI.h"
751.3Sjmcneill
761.3Sjmcneilltypedef struct _GCrec {
771.3Sjmcneill    unsigned char screen;       /* Screen for GC */
781.3Sjmcneill    unsigned char depth;        /* Depth for GC */
791.3Sjmcneill    char dashes;                /* Dashes value */
801.3Sjmcneill    Pixmap clip_mask;           /* Clip_mask value */
811.3Sjmcneill    Cardinal ref_count;         /* # of shareholders */
821.3Sjmcneill    GC gc;                      /* The GC itself. */
831.3Sjmcneill    XtGCMask dynamic_mask;      /* Writable values */
841.3Sjmcneill    XtGCMask unused_mask;       /* Unused values */
851.3Sjmcneill    struct _GCrec *next;        /* Next GC for this widgetkind. */
861.3Sjmcneill} GCrec, *GCptr;
871.3Sjmcneill
881.3Sjmcneill#define GCVAL(bit,mask,val,default) ((bit&mask) ? val : default)
891.3Sjmcneill
901.3Sjmcneill#define CHECK(bit,comp,default) \
911.1Snat    if ((checkMask & bit) && \
921.1Snat        (GCVAL(bit,valueMask,v->comp,default) != gcv.comp)) return False
931.1Snat
941.4Snat#define ALLGCVALS (GCFunction | GCPlaneMask | GCForeground | \
951.1Snat                   GCBackground | GCLineWidth | GCLineStyle | \
961.2Sjakllsch                   GCCapStyle | GCJoinStyle | GCFillStyle | \
971.1Snat                   GCFillRule | GCTile | GCStipple | \
981.1Snat                   GCTileStipXOrigin | GCTileStipYOrigin | \
991.3Sjmcneill                   GCFont | GCSubwindowMode | GCGraphicsExposures | \
1001.3Sjmcneill                   GCClipXOrigin | GCClipYOrigin | GCDashOffset | \
1011.1Snat                   GCArcMode)
1021.1Snat
1031.3Sjmcneillstatic Bool
1041.1SnatMatches(Display *dpy,
1051.1Snat        GCptr ptr,
1061.1Snat        register XtGCMask valueMask,
1071.1Snat        register XGCValues *v,
1081.1Snat        XtGCMask readOnlyMask,
1091.3Sjmcneill        XtGCMask dynamicMask)
1101.3Sjmcneill{
1111.3Sjmcneill    XGCValues gcv;
1121.3Sjmcneill    register XtGCMask checkMask;
1131.3Sjmcneill
1141.3Sjmcneill    if (readOnlyMask & ptr->dynamic_mask)
1151.3Sjmcneill        return False;
1161.1Snat    if (((ptr->dynamic_mask | ptr->unused_mask) & dynamicMask) != dynamicMask)
1171.3Sjmcneill        return False;
1181.3Sjmcneill    if (!XGetGCValues(dpy, ptr->gc, ALLGCVALS, &gcv))
1191.1Snat        return False;
1201.1Snat    checkMask = readOnlyMask & ~ptr->unused_mask;
1211.1Snat    CHECK(GCForeground, foreground, 0);
1221.1Snat    CHECK(GCBackground, background, 1);
1231.1Snat    CHECK(GCFont, font, ~0UL);
1241.1Snat    CHECK(GCFillStyle, fill_style, FillSolid);
1251.1Snat    CHECK(GCLineWidth, line_width, 0);
1261.1Snat    CHECK(GCFunction, function, GXcopy);
1271.1Snat    CHECK(GCGraphicsExposures, graphics_exposures, True);
1281.1Snat    CHECK(GCTile, tile, ~0UL);
1291.1Snat    CHECK(GCSubwindowMode, subwindow_mode, ClipByChildren);
1301.1Snat    CHECK(GCPlaneMask, plane_mask, AllPlanes);
1311.1Snat    CHECK(GCLineStyle, line_style, LineSolid);
1321.1Snat    CHECK(GCCapStyle, cap_style, CapButt);
1331.1Snat    CHECK(GCJoinStyle, join_style, JoinMiter);
1341.1Snat    CHECK(GCFillRule, fill_rule, EvenOddRule);
1351.1Snat    CHECK(GCArcMode, arc_mode, ArcPieSlice);
1361.1Snat    CHECK(GCStipple, stipple, ~0UL);
1371.1Snat    CHECK(GCTileStipXOrigin, ts_x_origin, 0);
1381.1Snat    CHECK(GCTileStipYOrigin, ts_y_origin, 0);
1391.1Snat    CHECK(GCClipXOrigin, clip_x_origin, 0);
1401.1Snat    CHECK(GCClipYOrigin, clip_y_origin, 0);
1411.1Snat    CHECK(GCDashOffset, dash_offset, 0);
1421.1Snat    gcv.clip_mask = ptr->clip_mask;
1431.4Snat    CHECK(GCClipMask, clip_mask, None);
1441.4Snat    gcv.dashes = ptr->dashes;
1451.4Snat    CHECK(GCDashList, dashes, 4);
1461.4Snat    valueMask &= ptr->unused_mask | dynamicMask;
1471.4Snat    if (valueMask) {
1481.4Snat        XChangeGC(dpy, ptr->gc, valueMask, v);
1491.4Snat        if (valueMask & GCDashList)
1501.4Snat            ptr->dashes = v->dashes;
1511.1Snat        if (valueMask & GCClipMask)
1521.1Snat            ptr->clip_mask = v->clip_mask;
1531.1Snat    }
1541.1Snat    ptr->unused_mask &= ~(dynamicMask | readOnlyMask);
1551.1Snat    ptr->dynamic_mask |= dynamicMask;
1561.1Snat    return True;
1571.1Snat}                               /* Matches */
1581.1Snat
159/* Called by CloseDisplay to free the per-display GC list */
160void
161_XtGClistFree(Display *dpy, register XtPerDisplay pd)
162{
163    GCptr GClist, next;
164
165    GClist = pd->GClist;
166    while (GClist) {
167        next = GClist->next;
168        XtFree((char *) GClist);
169        GClist = next;
170    }
171    if (pd->pixmap_tab) {
172        int i;
173
174        for (i = ScreenCount(dpy); --i >= 0;) {
175            if (pd->pixmap_tab[i])
176                XtFree((char *) pd->pixmap_tab[i]);
177        }
178        XtFree((char *) pd->pixmap_tab);
179    }
180}
181
182/*
183 * Return a GC with the given values and characteristics.
184 */
185
186GC
187XtAllocateGC(register Widget widget,
188             Cardinal depth,
189             XtGCMask valueMask,
190             XGCValues *values,
191             XtGCMask dynamicMask,
192             XtGCMask unusedMask)
193{
194    register GCptr *prev;
195    register GCptr cur;
196    Screen *screen;
197    register Display *dpy;
198    register XtPerDisplay pd;
199    Drawable drawable;
200    Drawable *pixmaps;
201    XtGCMask readOnlyMask;
202    GC retval;
203
204    WIDGET_TO_APPCON(widget);
205
206    LOCK_APP(app);
207    LOCK_PROCESS;
208    if (!XtIsWidget(widget))
209        widget = _XtWindowedAncestor(widget);
210    if (!depth)
211        depth = widget->core.depth;
212    screen = XtScreen(widget);
213    dpy = DisplayOfScreen(screen);
214    pd = _XtGetPerDisplay(dpy);
215    unusedMask &= ~valueMask;
216    readOnlyMask = ~(dynamicMask | unusedMask);
217
218    /* Search for existing GC that matches exactly */
219    for (prev = &pd->GClist; (cur = *prev); prev = &cur->next) {
220        if (cur->depth == depth &&
221            ScreenOfDisplay(dpy, cur->screen) == screen &&
222            Matches(dpy, cur, valueMask, values, readOnlyMask, dynamicMask)) {
223            cur->ref_count++;
224            /* Move this GC to front of list */
225            *prev = cur->next;
226            cur->next = pd->GClist;
227            pd->GClist = cur;
228            retval = cur->gc;
229            UNLOCK_PROCESS;
230            UNLOCK_APP(app);
231            return retval;
232        }
233    }
234
235    /* No matches, have to create a new one */
236    cur = XtNew(GCrec);
237    cur->screen = (unsigned char) XScreenNumberOfScreen(screen);
238    cur->depth = (unsigned char) depth;
239    cur->ref_count = 1;
240    cur->dynamic_mask = dynamicMask;
241    cur->unused_mask = (unusedMask & ~dynamicMask);
242    cur->dashes = GCVAL(GCDashList, valueMask, values->dashes, 4);
243    cur->clip_mask = GCVAL(GCClipMask, valueMask, values->clip_mask, None);
244    drawable = 0;
245    if (depth == widget->core.depth)
246        drawable = XtWindow(widget);
247    if (!drawable && depth == (Cardinal) DefaultDepthOfScreen(screen))
248        drawable = RootWindowOfScreen(screen);
249    if (!drawable) {
250        if (!pd->pixmap_tab) {
251            int n;
252
253            pd->pixmap_tab = XtMallocArray((Cardinal) ScreenCount(dpy),
254                                           (Cardinal) 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
262            depths = XListDepths(dpy, cur->screen, &n);
263            n--;
264            max = depths[n];
265            while (n--) {
266                if (depths[n] > max)
267                    max = depths[n];
268            }
269            XFree((char *) depths);
270            pixmaps = (Drawable *) __XtCalloc((unsigned) max, sizeof(Drawable));
271            pd->pixmap_tab[cur->screen] = pixmaps;
272        }
273        drawable = pixmaps[cur->depth - 1];
274        if (!drawable) {
275            drawable = XCreatePixmap(dpy, RootWindowOfScreen(screen), 1, 1,
276                                     cur->depth);
277            pixmaps[cur->depth - 1] = drawable;
278        }
279    }
280    cur->gc = XCreateGC(dpy, drawable, valueMask, values);
281    cur->next = pd->GClist;
282    pd->GClist = cur;
283    retval = cur->gc;
284    UNLOCK_PROCESS;
285    UNLOCK_APP(app);
286    return retval;
287}                               /* XtAllocateGC */
288
289/*
290 * Return a read-only GC with the given values.
291 */
292
293GC
294XtGetGC(register Widget widget, XtGCMask valueMask, XGCValues *values)
295{
296    return XtAllocateGC(widget, 0, valueMask, values, 0, 0);
297}                               /* XtGetGC */
298
299void
300XtReleaseGC(Widget widget, register GC gc)
301{
302    register GCptr cur, *prev;
303    Display *dpy;
304    XtPerDisplay pd;
305
306    WIDGET_TO_APPCON(widget);
307
308    LOCK_APP(app);
309    LOCK_PROCESS;
310    dpy = XtDisplayOfObject(widget);
311    pd = _XtGetPerDisplay(dpy);
312
313    for (prev = &pd->GClist; (cur = *prev); prev = &cur->next) {
314        if (cur->gc == gc) {
315            if (--(cur->ref_count) == 0) {
316                *prev = cur->next;
317                XFreeGC(dpy, gc);
318                XtFree((char *) cur);
319            }
320            break;
321        }
322    }
323    UNLOCK_PROCESS;
324    UNLOCK_APP(app);
325}                               /* XtReleaseGC */
326
327/*  The following interface is broken and supplied only for backwards
328 *  compatibility.  It will work properly in all cases only if there
329 *  is exactly 1 Display created by the application.
330 */
331
332void
333XtDestroyGC(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
345        for (i = app->count; i;) {
346            Display *dpy = app->list[--i];
347            XtPerDisplay pd = _XtGetPerDisplay(dpy);
348
349            for (prev = &pd->GClist; (cur = *prev); prev = &cur->next) {
350                if (cur->gc == gc) {
351                    if (--(cur->ref_count) == 0) {
352                        *prev = cur->next;
353                        XFreeGC(dpy, gc);
354                        XtFree((char *) cur);
355                    }
356                    UNLOCK_PROCESS;
357                    return;
358                }
359            }
360        }
361    }
362    UNLOCK_PROCESS;
363}                               /* XtDestroyGC */
364