|
|
1.1 root 1: /*
2: * tkGC.c --
3: *
4: * This file maintains a database of read-only graphics contexts
5: * for the Tk toolkit, in order to allow GC's to be shared.
6: *
7: * Copyright 1990 Regents of the University of California
8: * Permission to use, copy, modify, and distribute this
9: * software and its documentation for any purpose and without
10: * fee is hereby granted, provided that the above copyright
11: * notice appear in all copies. The University of California
12: * makes no representations about the suitability of this
13: * software for any purpose. It is provided "as is" without
14: * express or implied warranty.
15: */
16:
17: #ifndef lint
18: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkGC.c,v 1.9 92/05/13 08:48:45 ouster Exp $ SPRITE (Berkeley)";
19: #endif /* not lint */
20:
21: #include "tkconfig.h"
22: #include "tk.h"
23:
24: /*
25: * One of the following data structures exists for each GC that is
26: * currently active. The structure is indexed with two hash tables,
27: * one based on font name and one based on XFontStruct address.
28: */
29:
30: typedef struct {
31: GC gc; /* Graphics context. */
32: Display *display; /* Display to which gc belongs. */
33: int refCount; /* Number of active uses of gc. */
34: Tcl_HashEntry *valueHashPtr;/* Entry in valueTable (needed when deleting
35: * this structure). */
36: } TkGC;
37:
38: /*
39: * Hash table to map from a GC's values to a TkGC structure describing
40: * a GC with those values (used by Tk_GetGC).
41: */
42:
43: static Tcl_HashTable valueTable;
44: typedef struct {
45: XGCValues values; /* Desired values for GC. */
46: Screen *screen; /* Screen for which GC is valid. */
47: } ValueKey;
48:
49: /*
50: * Hash table for GC -> TkGC mapping. This table is indexed by the
51: * GC identifier, and is used by Tk_FreeGC.
52: */
53:
54: static Tcl_HashTable idTable;
55:
56: static int initialized = 0; /* 0 means static structures haven't been
57: * initialized yet. */
58:
59: /*
60: * Forward declarations for procedures defined in this file:
61: */
62:
63: static void GCInit _ANSI_ARGS_((void));
64:
65: /*
66: *----------------------------------------------------------------------
67: *
68: * Tk_GetGC --
69: *
70: * Given a desired set of values for a graphics context, find
71: * a read-only graphics context with the desired values.
72: *
73: * Results:
74: * The return value is the X identifer for the desired graphics
75: * context. The caller should never modify this GC, and should
76: * call Tk_FreeGC when the GC is no longer needed.
77: *
78: * Side effects:
79: * The GC is added to an internal database with a reference count.
80: * For each call to this procedure, there should eventually be a call
81: * to Tk_FreeGC, so that the database can be cleaned up when GC's
82: * aren't needed anymore.
83: *
84: *----------------------------------------------------------------------
85: */
86:
87: GC
88: Tk_GetGC(tkwin, valueMask, valuePtr)
89: Tk_Window tkwin; /* Window in which GC will be used. */
90: register unsigned long valueMask;
91: /* 1 bits correspond to values specified
92: * in *valuesPtr; other values are set
93: * from defaults. */
94: register XGCValues *valuePtr;
95: /* Values are specified here for bits set
96: * in valueMask. */
97: {
98: ValueKey key;
99: Tcl_HashEntry *valueHashPtr, *idHashPtr;
100: register TkGC *gcPtr;
101: int new;
102:
103: if (!initialized) {
104: GCInit();
105: }
106:
107: /*
108: * Must zero key at start to clear out pad bytes that may be
109: * part of structure on some systems.
110: */
111:
112: memset((VOID *) &key, 0, sizeof(key));
113:
114: /*
115: * First, check to see if there's already a GC that will work
116: * for this request (exact matches only, sorry).
117: */
118:
119: if (valueMask & GCFunction) {
120: key.values.function = valuePtr->function;
121: } else {
122: key.values.function = GXcopy;
123: }
124: if (valueMask & GCPlaneMask) {
125: key.values.plane_mask = valuePtr->plane_mask;
126: } else {
127: key.values.plane_mask = ~0;
128: }
129: if (valueMask & GCForeground) {
130: key.values.foreground = valuePtr->foreground;
131: } else {
132: key.values.foreground = 0;
133: }
134: if (valueMask & GCBackground) {
135: key.values.background = valuePtr->background;
136: } else {
137: key.values.background = 1;
138: }
139: if (valueMask & GCLineWidth) {
140: key.values.line_width = valuePtr->line_width;
141: } else {
142: key.values.line_width = 0;
143: }
144: if (valueMask & GCLineStyle) {
145: key.values.line_style = valuePtr->line_style;
146: } else {
147: key.values.line_style = LineSolid;
148: }
149: if (valueMask & GCCapStyle) {
150: key.values.cap_style = valuePtr->cap_style;
151: } else {
152: key.values.cap_style = CapButt;
153: }
154: if (valueMask & GCJoinStyle) {
155: key.values.join_style = valuePtr->join_style;
156: } else {
157: key.values.join_style = JoinMiter;
158: }
159: if (valueMask & GCFillStyle) {
160: key.values.fill_style = valuePtr->fill_style;
161: } else {
162: key.values.fill_style = FillSolid;
163: }
164: if (valueMask & GCFillRule) {
165: key.values.fill_rule = valuePtr->fill_rule;
166: } else {
167: key.values.fill_rule = EvenOddRule;
168: }
169: if (valueMask & GCArcMode) {
170: key.values.arc_mode = valuePtr->arc_mode;
171: } else {
172: key.values.arc_mode = ArcPieSlice;
173: }
174: if (valueMask & GCTile) {
175: key.values.tile = valuePtr->tile;
176: } else {
177: key.values.tile = None;
178: }
179: if (valueMask & GCStipple) {
180: key.values.stipple = valuePtr->stipple;
181: } else {
182: key.values.stipple = None;
183: }
184: if (valueMask & GCTileStipXOrigin) {
185: key.values.ts_x_origin = valuePtr->ts_x_origin;
186: } else {
187: key.values.ts_x_origin = 0;
188: }
189: if (valueMask & GCTileStipYOrigin) {
190: key.values.ts_y_origin = valuePtr->ts_y_origin;
191: } else {
192: key.values.ts_y_origin = 0;
193: }
194: if (valueMask & GCFont) {
195: key.values.font = valuePtr->font;
196: } else {
197: key.values.font = None;
198: }
199: if (valueMask & GCSubwindowMode) {
200: key.values.subwindow_mode = valuePtr->subwindow_mode;
201: } else {
202: key.values.subwindow_mode = ClipByChildren;
203: }
204: if (valueMask & GCGraphicsExposures) {
205: key.values.graphics_exposures = valuePtr->graphics_exposures;
206: } else {
207: key.values.graphics_exposures = True;
208: }
209: if (valueMask & GCClipXOrigin) {
210: key.values.clip_x_origin = valuePtr->clip_x_origin;
211: } else {
212: key.values.clip_x_origin = 0;
213: }
214: if (valueMask & GCClipYOrigin) {
215: key.values.clip_y_origin = valuePtr->clip_y_origin;
216: } else {
217: key.values.clip_y_origin = 0;
218: }
219: if (valueMask & GCClipMask) {
220: key.values.clip_mask = valuePtr->clip_mask;
221: } else {
222: key.values.clip_mask = None;
223: }
224: if (valueMask & GCDashOffset) {
225: key.values.dash_offset = valuePtr->dash_offset;
226: } else {
227: key.values.dash_offset = 0;
228: }
229: if (valueMask & GCDashList) {
230: key.values.dashes = valuePtr->dashes;
231: } else {
232: key.values.dashes = 4;
233: }
234: key.screen = Tk_Screen(tkwin);
235: valueHashPtr = Tcl_CreateHashEntry(&valueTable, (char *) &key, &new);
236: if (!new) {
237: gcPtr = (TkGC *) Tcl_GetHashValue(valueHashPtr);
238: gcPtr->refCount++;
239: return gcPtr->gc;
240: }
241:
242: /*
243: * No GC is currently available for this set of values. Allocate a
244: * new GC and add a new structure to the database.
245: */
246:
247: gcPtr = (TkGC *) ckalloc(sizeof(TkGC));
248: #if 0
249: gcPtr->gc = XCreateGC(Tk_Display(tkwin),
250: RootWindowOfScreen(Tk_Screen(tkwin)),
251: valueMask, &key.values);
252: #else
253: gcPtr->gc = XCreateGC(Tk_Display(tkwin),
254: Tk_DefaultPixmap(Tk_Screen(tkwin)),
255: valueMask, &key.values);
256: #endif
257: gcPtr->display = Tk_Display(tkwin);
258: gcPtr->refCount = 1;
259: gcPtr->valueHashPtr = valueHashPtr;
260: idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) gcPtr->gc, &new);
261: if (!new) {
262: panic("GC already registered in Tk_GetGC");
263: }
264: Tcl_SetHashValue(valueHashPtr, gcPtr);
265: Tcl_SetHashValue(idHashPtr, gcPtr);
266: return gcPtr->gc;
267: }
268:
269: /*
270: *----------------------------------------------------------------------
271: *
272: * Tk_FreeGC --
273: *
274: * This procedure is called to release a font allocated by
275: * Tk_GetGC.
276: *
277: * Results:
278: * None.
279: *
280: * Side effects:
281: * The reference count associated with gc is decremented, and
282: * gc is officially deallocated if no-one is using it anymore.
283: *
284: *----------------------------------------------------------------------
285: */
286:
287: void
288: Tk_FreeGC(gc)
289: GC gc; /* Graphics context to be released. */
290: {
291: Tcl_HashEntry *idHashPtr;
292: register TkGC *gcPtr;
293:
294: if (!initialized) {
295: panic("Tk_FreeGC called before Tk_GetGC");
296: }
297:
298: idHashPtr = Tcl_FindHashEntry(&idTable, (char *) gc);
299: if (idHashPtr == NULL) {
300: panic("Tk_FreeGC received unknown gc argument");
301: }
302: gcPtr = (TkGC *) Tcl_GetHashValue(idHashPtr);
303: gcPtr->refCount--;
304: if (gcPtr->refCount == 0) {
305: XFreeGC(gcPtr->display, gcPtr->gc);
306: Tcl_DeleteHashEntry(gcPtr->valueHashPtr);
307: Tcl_DeleteHashEntry(idHashPtr);
308: ckfree((char *) gcPtr);
309: }
310: }
311:
312: /*
313: *----------------------------------------------------------------------
314: *
315: * GCInit --
316: *
317: * Initialize the structures used for GC management.
318: *
319: * Results:
320: * None.
321: *
322: * Side effects:
323: * Read the code.
324: *
325: *----------------------------------------------------------------------
326: */
327:
328: static void
329: GCInit()
330: {
331: initialized = 1;
332: Tcl_InitHashTable(&valueTable, sizeof(ValueKey)/sizeof(int));
333: Tcl_InitHashTable(&idTable, TCL_ONE_WORD_KEYS);
334: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.