GCManager.c revision a3bd7f05
1444c061aSmrg/*********************************************************** 2249c3046SmrgCopyright (c) 1993, Oracle and/or its affiliates. All rights reserved. 31477040fSmrg 41477040fSmrgPermission is hereby granted, free of charge, to any person obtaining a 51477040fSmrgcopy of this software and associated documentation files (the "Software"), 61477040fSmrgto deal in the Software without restriction, including without limitation 71477040fSmrgthe rights to use, copy, modify, merge, publish, distribute, sublicense, 81477040fSmrgand/or sell copies of the Software, and to permit persons to whom the 91477040fSmrgSoftware is furnished to do so, subject to the following conditions: 101477040fSmrg 111477040fSmrgThe above copyright notice and this permission notice (including the next 121477040fSmrgparagraph) shall be included in all copies or substantial portions of the 131477040fSmrgSoftware. 141477040fSmrg 151477040fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 161477040fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 171477040fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 181477040fSmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 191477040fSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 201477040fSmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 211477040fSmrgDEALINGS IN THE SOFTWARE. 221477040fSmrg 231477040fSmrgCopyright 1987, 1988, 1990 by Digital Equipment Corporation, Maynard, Massachusetts. 24444c061aSmrg 25444c061aSmrg All Rights Reserved 26444c061aSmrg 27444c061aSmrgPermission to use, copy, modify, and distribute this software and its 28444c061aSmrgdocumentation for any purpose and without fee is hereby granted, 29444c061aSmrgprovided that the above copyright notice appear in all copies and that 30444c061aSmrgboth that copyright notice and this permission notice appear in 311477040fSmrgsupporting documentation, and that the name of Digital not be 32444c061aSmrgused in advertising or publicity pertaining to distribution of the 33444c061aSmrgsoftware without specific, written prior permission. 34444c061aSmrg 35444c061aSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 36444c061aSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 37444c061aSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 38444c061aSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 39444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 40444c061aSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 41444c061aSmrgSOFTWARE. 42444c061aSmrg 43444c061aSmrg******************************************************************/ 44444c061aSmrg 45444c061aSmrg/* 46444c061aSmrg 47444c061aSmrgCopyright 1987, 1988, 1990, 1994, 1998 The Open Group 48444c061aSmrg 49444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its 50444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that 51444c061aSmrgthe above copyright notice appear in all copies and that both that 52444c061aSmrgcopyright notice and this permission notice appear in supporting 53444c061aSmrgdocumentation. 54444c061aSmrg 55444c061aSmrgThe above copyright notice and this permission notice shall be included in 56444c061aSmrgall copies or substantial portions of the Software. 57444c061aSmrg 58444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 59444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 60444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 61444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 62444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 63444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 64444c061aSmrg 65444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be 66444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings 67444c061aSmrgin this Software without prior written authorization from The Open Group. 68444c061aSmrg 69444c061aSmrg*/ 70444c061aSmrg 71444c061aSmrg#ifdef HAVE_CONFIG_H 72444c061aSmrg#include <config.h> 73444c061aSmrg#endif 74444c061aSmrg#include "IntrinsicI.h" 75444c061aSmrg 76444c061aSmrgtypedef struct _GCrec { 77a3bd7f05Smrg unsigned char screen; /* Screen for GC */ 78a3bd7f05Smrg unsigned char depth; /* Depth for GC */ 79a3bd7f05Smrg char dashes; /* Dashes value */ 80a3bd7f05Smrg Pixmap clip_mask; /* Clip_mask value */ 81a3bd7f05Smrg Cardinal ref_count; /* # of shareholders */ 82a3bd7f05Smrg GC gc; /* The GC itself. */ 83a3bd7f05Smrg XtGCMask dynamic_mask; /* Writable values */ 84a3bd7f05Smrg XtGCMask unused_mask; /* Unused values */ 85a3bd7f05Smrg struct _GCrec *next; /* Next GC for this widgetkind. */ 86444c061aSmrg} GCrec, *GCptr; 87444c061aSmrg 88444c061aSmrg#define GCVAL(bit,mask,val,default) ((bit&mask) ? val : default) 89444c061aSmrg 90444c061aSmrg#define CHECK(bit,comp,default) \ 91444c061aSmrg if ((checkMask & bit) && \ 92a3bd7f05Smrg (GCVAL(bit,valueMask,v->comp,default) != gcv.comp)) return False 93444c061aSmrg 94444c061aSmrg#define ALLGCVALS (GCFunction | GCPlaneMask | GCForeground | \ 95a3bd7f05Smrg GCBackground | GCLineWidth | GCLineStyle | \ 96a3bd7f05Smrg GCCapStyle | GCJoinStyle | GCFillStyle | \ 97a3bd7f05Smrg GCFillRule | GCTile | GCStipple | \ 98a3bd7f05Smrg GCTileStipXOrigin | GCTileStipYOrigin | \ 99a3bd7f05Smrg GCFont | GCSubwindowMode | GCGraphicsExposures | \ 100a3bd7f05Smrg GCClipXOrigin | GCClipYOrigin | GCDashOffset | \ 101a3bd7f05Smrg GCArcMode) 102a3bd7f05Smrg 103a3bd7f05Smrgstatic Bool 104a3bd7f05SmrgMatches(Display *dpy, 105a3bd7f05Smrg GCptr ptr, 106a3bd7f05Smrg register XtGCMask valueMask, 107a3bd7f05Smrg register XGCValues *v, 108a3bd7f05Smrg XtGCMask readOnlyMask, 109a3bd7f05Smrg XtGCMask dynamicMask) 110444c061aSmrg{ 111444c061aSmrg XGCValues gcv; 112444c061aSmrg register XtGCMask checkMask; 113444c061aSmrg 114444c061aSmrg if (readOnlyMask & ptr->dynamic_mask) 115a3bd7f05Smrg return False; 116a3bd7f05Smrg if (((ptr->dynamic_mask | ptr->unused_mask) & dynamicMask) != dynamicMask) 117a3bd7f05Smrg return False; 118444c061aSmrg if (!XGetGCValues(dpy, ptr->gc, ALLGCVALS, &gcv)) 119a3bd7f05Smrg return False; 120444c061aSmrg checkMask = readOnlyMask & ~ptr->unused_mask; 121444c061aSmrg CHECK(GCForeground, foreground, 0); 122444c061aSmrg CHECK(GCBackground, background, 1); 123444c061aSmrg CHECK(GCFont, font, ~0UL); 124444c061aSmrg CHECK(GCFillStyle, fill_style, FillSolid); 125444c061aSmrg CHECK(GCLineWidth, line_width, 0); 126444c061aSmrg CHECK(GCFunction, function, GXcopy); 127444c061aSmrg CHECK(GCGraphicsExposures, graphics_exposures, True); 128444c061aSmrg CHECK(GCTile, tile, ~0UL); 129444c061aSmrg CHECK(GCSubwindowMode, subwindow_mode, ClipByChildren); 130444c061aSmrg CHECK(GCPlaneMask, plane_mask, AllPlanes); 131444c061aSmrg CHECK(GCLineStyle, line_style, LineSolid); 132444c061aSmrg CHECK(GCCapStyle, cap_style, CapButt); 133444c061aSmrg CHECK(GCJoinStyle, join_style, JoinMiter); 134444c061aSmrg CHECK(GCFillRule, fill_rule, EvenOddRule); 135444c061aSmrg CHECK(GCArcMode, arc_mode, ArcPieSlice); 136444c061aSmrg CHECK(GCStipple, stipple, ~0UL); 137444c061aSmrg CHECK(GCTileStipXOrigin, ts_x_origin, 0); 138444c061aSmrg CHECK(GCTileStipYOrigin, ts_y_origin, 0); 139444c061aSmrg CHECK(GCClipXOrigin, clip_x_origin, 0); 140444c061aSmrg CHECK(GCClipYOrigin, clip_y_origin, 0); 141444c061aSmrg CHECK(GCDashOffset, dash_offset, 0); 142444c061aSmrg gcv.clip_mask = ptr->clip_mask; 143444c061aSmrg CHECK(GCClipMask, clip_mask, None); 144444c061aSmrg gcv.dashes = ptr->dashes; 145444c061aSmrg CHECK(GCDashList, dashes, 4); 146444c061aSmrg valueMask &= ptr->unused_mask | dynamicMask; 147444c061aSmrg if (valueMask) { 148a3bd7f05Smrg XChangeGC(dpy, ptr->gc, valueMask, v); 149a3bd7f05Smrg if (valueMask & GCDashList) 150a3bd7f05Smrg ptr->dashes = v->dashes; 151a3bd7f05Smrg if (valueMask & GCClipMask) 152a3bd7f05Smrg ptr->clip_mask = v->clip_mask; 153444c061aSmrg } 154444c061aSmrg ptr->unused_mask &= ~(dynamicMask | readOnlyMask); 155444c061aSmrg ptr->dynamic_mask |= dynamicMask; 156444c061aSmrg return True; 157a3bd7f05Smrg} /* Matches */ 158444c061aSmrg 159444c061aSmrg/* Called by CloseDisplay to free the per-display GC list */ 160a3bd7f05Smrgvoid 161a3bd7f05Smrg_XtGClistFree(Display *dpy, register XtPerDisplay pd) 162444c061aSmrg{ 1630568f49bSmrg GCptr GClist, next; 164444c061aSmrg 165444c061aSmrg GClist = pd->GClist; 166444c061aSmrg while (GClist) { 167a3bd7f05Smrg next = GClist->next; 168a3bd7f05Smrg XtFree((char *) GClist); 169a3bd7f05Smrg GClist = next; 170444c061aSmrg } 171444c061aSmrg if (pd->pixmap_tab) { 172a3bd7f05Smrg int i; 173a3bd7f05Smrg 174a3bd7f05Smrg for (i = ScreenCount(dpy); --i >= 0;) { 175a3bd7f05Smrg if (pd->pixmap_tab[i]) 176a3bd7f05Smrg XtFree((char *) pd->pixmap_tab[i]); 177a3bd7f05Smrg } 178a3bd7f05Smrg XtFree((char *) pd->pixmap_tab); 179444c061aSmrg } 180444c061aSmrg} 181444c061aSmrg 182444c061aSmrg/* 183444c061aSmrg * Return a GC with the given values and characteristics. 184444c061aSmrg */ 185444c061aSmrg 186a3bd7f05SmrgGC 187a3bd7f05SmrgXtAllocateGC(register Widget widget, 188a3bd7f05Smrg Cardinal depth, 189a3bd7f05Smrg XtGCMask valueMask, 190a3bd7f05Smrg XGCValues *values, 191a3bd7f05Smrg XtGCMask dynamicMask, 192a3bd7f05Smrg XtGCMask unusedMask) 193444c061aSmrg{ 194444c061aSmrg register GCptr *prev; 195444c061aSmrg register GCptr cur; 196444c061aSmrg Screen *screen; 197444c061aSmrg register Display *dpy; 198444c061aSmrg register XtPerDisplay pd; 199444c061aSmrg Drawable drawable; 200444c061aSmrg Drawable *pixmaps; 201444c061aSmrg XtGCMask readOnlyMask; 202444c061aSmrg GC retval; 203a3bd7f05Smrg 204444c061aSmrg WIDGET_TO_APPCON(widget); 205444c061aSmrg 206444c061aSmrg LOCK_APP(app); 207444c061aSmrg LOCK_PROCESS; 208444c061aSmrg if (!XtIsWidget(widget)) 209a3bd7f05Smrg widget = _XtWindowedAncestor(widget); 210444c061aSmrg if (!depth) 211a3bd7f05Smrg depth = widget->core.depth; 212444c061aSmrg screen = XtScreen(widget); 213444c061aSmrg dpy = DisplayOfScreen(screen); 214444c061aSmrg pd = _XtGetPerDisplay(dpy); 215444c061aSmrg unusedMask &= ~valueMask; 216444c061aSmrg readOnlyMask = ~(dynamicMask | unusedMask); 217444c061aSmrg 218444c061aSmrg /* Search for existing GC that matches exactly */ 219444c061aSmrg for (prev = &pd->GClist; (cur = *prev); prev = &cur->next) { 220a3bd7f05Smrg if (cur->depth == depth && 221a3bd7f05Smrg ScreenOfDisplay(dpy, cur->screen) == screen && 222a3bd7f05Smrg Matches(dpy, cur, valueMask, values, readOnlyMask, dynamicMask)) { 223444c061aSmrg cur->ref_count++; 224a3bd7f05Smrg /* Move this GC to front of list */ 225a3bd7f05Smrg *prev = cur->next; 226a3bd7f05Smrg cur->next = pd->GClist; 227a3bd7f05Smrg pd->GClist = cur; 228a3bd7f05Smrg retval = cur->gc; 229a3bd7f05Smrg UNLOCK_PROCESS; 230a3bd7f05Smrg UNLOCK_APP(app); 231a3bd7f05Smrg return retval; 232a3bd7f05Smrg } 233444c061aSmrg } 234444c061aSmrg 235444c061aSmrg /* No matches, have to create a new one */ 236444c061aSmrg cur = XtNew(GCrec); 2370568f49bSmrg cur->screen = (unsigned char) XScreenNumberOfScreen(screen); 2380568f49bSmrg cur->depth = (unsigned char) depth; 239444c061aSmrg cur->ref_count = 1; 240444c061aSmrg cur->dynamic_mask = dynamicMask; 241444c061aSmrg cur->unused_mask = (unusedMask & ~dynamicMask); 242444c061aSmrg cur->dashes = GCVAL(GCDashList, valueMask, values->dashes, 4); 243444c061aSmrg cur->clip_mask = GCVAL(GCClipMask, valueMask, values->clip_mask, None); 244444c061aSmrg drawable = 0; 245444c061aSmrg if (depth == widget->core.depth) 246a3bd7f05Smrg drawable = XtWindow(widget); 247444c061aSmrg if (!drawable && depth == (Cardinal) DefaultDepthOfScreen(screen)) 248a3bd7f05Smrg drawable = RootWindowOfScreen(screen); 249444c061aSmrg if (!drawable) { 250a3bd7f05Smrg if (!pd->pixmap_tab) { 251a3bd7f05Smrg int n; 252a3bd7f05Smrg 253a3bd7f05Smrg pd->pixmap_tab = 254a3bd7f05Smrg (Drawable **) 255a3bd7f05Smrg __XtMalloc((Cardinal) 256a3bd7f05Smrg ((unsigned) ScreenCount(dpy) * sizeof(Drawable *))); 257a3bd7f05Smrg for (n = 0; n < ScreenCount(dpy); n++) 258a3bd7f05Smrg pd->pixmap_tab[n] = NULL; 259a3bd7f05Smrg } 260a3bd7f05Smrg pixmaps = pd->pixmap_tab[cur->screen]; 261a3bd7f05Smrg if (!pixmaps) { 262a3bd7f05Smrg int max, n, *depths; 263a3bd7f05Smrg 264a3bd7f05Smrg depths = XListDepths(dpy, cur->screen, &n); 265a3bd7f05Smrg n--; 266a3bd7f05Smrg max = depths[n]; 267a3bd7f05Smrg while (n--) { 268a3bd7f05Smrg if (depths[n] > max) 269a3bd7f05Smrg max = depths[n]; 270a3bd7f05Smrg } 271a3bd7f05Smrg XFree((char *) depths); 272a3bd7f05Smrg pixmaps = (Drawable *) __XtCalloc((unsigned) max, sizeof(Drawable)); 273a3bd7f05Smrg pd->pixmap_tab[cur->screen] = pixmaps; 274a3bd7f05Smrg } 275a3bd7f05Smrg drawable = pixmaps[cur->depth - 1]; 276a3bd7f05Smrg if (!drawable) { 277a3bd7f05Smrg drawable = XCreatePixmap(dpy, RootWindowOfScreen(screen), 1, 1, 278a3bd7f05Smrg cur->depth); 279a3bd7f05Smrg pixmaps[cur->depth - 1] = drawable; 280a3bd7f05Smrg } 281444c061aSmrg } 282444c061aSmrg cur->gc = XCreateGC(dpy, drawable, valueMask, values); 283444c061aSmrg cur->next = pd->GClist; 284444c061aSmrg pd->GClist = cur; 285444c061aSmrg retval = cur->gc; 286444c061aSmrg UNLOCK_PROCESS; 287444c061aSmrg UNLOCK_APP(app); 288444c061aSmrg return retval; 289a3bd7f05Smrg} /* XtAllocateGC */ 290444c061aSmrg 291444c061aSmrg/* 292444c061aSmrg * Return a read-only GC with the given values. 293444c061aSmrg */ 294444c061aSmrg 295a3bd7f05SmrgGC 296a3bd7f05SmrgXtGetGC(register Widget widget, XtGCMask valueMask, XGCValues *values) 297444c061aSmrg{ 298444c061aSmrg return XtAllocateGC(widget, 0, valueMask, values, 0, 0); 299a3bd7f05Smrg} /* XtGetGC */ 300444c061aSmrg 301a3bd7f05Smrgvoid 302a3bd7f05SmrgXtReleaseGC(Widget widget, register GC gc) 303444c061aSmrg{ 304444c061aSmrg register GCptr cur, *prev; 305a3bd7f05Smrg Display *dpy; 306444c061aSmrg XtPerDisplay pd; 307a3bd7f05Smrg 308444c061aSmrg WIDGET_TO_APPCON(widget); 309444c061aSmrg 310444c061aSmrg LOCK_APP(app); 311444c061aSmrg LOCK_PROCESS; 312444c061aSmrg dpy = XtDisplayOfObject(widget); 313444c061aSmrg pd = _XtGetPerDisplay(dpy); 314444c061aSmrg 315444c061aSmrg for (prev = &pd->GClist; (cur = *prev); prev = &cur->next) { 316a3bd7f05Smrg if (cur->gc == gc) { 317a3bd7f05Smrg if (--(cur->ref_count) == 0) { 318a3bd7f05Smrg *prev = cur->next; 319a3bd7f05Smrg XFreeGC(dpy, gc); 320a3bd7f05Smrg XtFree((char *) cur); 321a3bd7f05Smrg } 322a3bd7f05Smrg break; 323a3bd7f05Smrg } 324444c061aSmrg } 325444c061aSmrg UNLOCK_PROCESS; 326444c061aSmrg UNLOCK_APP(app); 327a3bd7f05Smrg} /* XtReleaseGC */ 328444c061aSmrg 329444c061aSmrg/* The following interface is broken and supplied only for backwards 330444c061aSmrg * compatibility. It will work properly in all cases only if there 331444c061aSmrg * is exactly 1 Display created by the application. 332444c061aSmrg */ 333444c061aSmrg 334a3bd7f05Smrgvoid 335a3bd7f05SmrgXtDestroyGC(register GC gc) 336444c061aSmrg{ 337444c061aSmrg GCptr cur, *prev; 338444c061aSmrg XtAppContext app; 339444c061aSmrg 340444c061aSmrg LOCK_PROCESS; 341444c061aSmrg app = _XtGetProcessContext()->appContextList; 342444c061aSmrg /* This is awful; we have to search through all the lists 343444c061aSmrg to find the GC. */ 344444c061aSmrg for (; app; app = app->next) { 345a3bd7f05Smrg int i; 346a3bd7f05Smrg 347a3bd7f05Smrg for (i = app->count; i;) { 348a3bd7f05Smrg Display *dpy = app->list[--i]; 349a3bd7f05Smrg XtPerDisplay pd = _XtGetPerDisplay(dpy); 350a3bd7f05Smrg 351a3bd7f05Smrg for (prev = &pd->GClist; (cur = *prev); prev = &cur->next) { 352a3bd7f05Smrg if (cur->gc == gc) { 353a3bd7f05Smrg if (--(cur->ref_count) == 0) { 354a3bd7f05Smrg *prev = cur->next; 355a3bd7f05Smrg XFreeGC(dpy, gc); 356a3bd7f05Smrg XtFree((char *) cur); 357a3bd7f05Smrg } 358a3bd7f05Smrg UNLOCK_PROCESS; 359a3bd7f05Smrg return; 360a3bd7f05Smrg } 361a3bd7f05Smrg } 362a3bd7f05Smrg } 363444c061aSmrg } 364444c061aSmrg UNLOCK_PROCESS; 365a3bd7f05Smrg} /* XtDestroyGC */ 366