]> git.zerfleddert.de Git - micropolis/blob - src/tk/tkgc.c
Import Micropolis from http://www.donhopkins.com/home/micropolis/
[micropolis] / src / tk / tkgc.c
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 \f
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 \f
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 \f
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 }
Impressum, Datenschutz