~ubuntu-branches/ubuntu/dapper/tk8.0/dapper-updates

« back to all changes in this revision

Viewing changes to generic/tkGC.c

  • Committer: Bazaar Package Importer
  • Author(s): Mike Markley
  • Date: 2001-07-24 21:57:40 UTC
  • Revision ID: james.westby@ubuntu.com-20010724215740-r70t25rtmbqjil2h
Tags: upstream-8.0.5
ImportĀ upstreamĀ versionĀ 8.0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 (c) 1990-1994 The Regents of the University of California.
 
8
 * Copyright (c) 1994 Sun Microsystems, Inc.
 
9
 *
 
10
 * See the file "license.terms" for information on usage and redistribution
 
11
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 
12
 *
 
13
 * RCS: @(#) $Id: tkGC.c,v 1.2 1998/09/14 18:23:11 stanton Exp $
 
14
 */
 
15
 
 
16
#include "tkPort.h"
 
17
#include "tk.h"
 
18
 
 
19
/*
 
20
 * One of the following data structures exists for each GC that is
 
21
 * currently active.  The structure is indexed with two hash tables,
 
22
 * one based on the values in the graphics context and the other
 
23
 * based on the display and GC identifier.
 
24
 */
 
25
 
 
26
typedef struct {
 
27
    GC gc;                      /* Graphics context. */
 
28
    Display *display;           /* Display to which gc belongs. */
 
29
    int refCount;               /* Number of active uses of gc. */
 
30
    Tcl_HashEntry *valueHashPtr;/* Entry in valueTable (needed when deleting
 
31
                                 * this structure). */
 
32
} TkGC;
 
33
 
 
34
/*
 
35
 * Hash table to map from a GC's values to a TkGC structure describing
 
36
 * a GC with those values (used by Tk_GetGC).
 
37
 */
 
38
 
 
39
static Tcl_HashTable valueTable;
 
40
typedef struct {
 
41
    XGCValues values;           /* Desired values for GC. */
 
42
    Display *display;           /* Display for which GC is valid. */
 
43
    int screenNum;              /* screen number of display */
 
44
    int depth;                  /* and depth for which GC is valid. */
 
45
} ValueKey;
 
46
 
 
47
/*
 
48
 * Hash table for <display + GC> -> TkGC mapping. This table is used by
 
49
 * Tk_FreeGC.
 
50
 */
 
51
 
 
52
static Tcl_HashTable idTable;
 
53
typedef struct {
 
54
    Display *display;           /* Display for which GC was allocated. */
 
55
    GC gc;                      /* X's identifier for GC. */
 
56
} IdKey;
 
57
 
 
58
static int initialized = 0;     /* 0 means static structures haven't been
 
59
                                 * initialized yet. */
 
60
 
 
61
/*
 
62
 * Forward declarations for procedures defined in this file:
 
63
 */
 
64
 
 
65
static void             GCInit _ANSI_ARGS_((void));
 
66
 
 
67
/*
 
68
 *----------------------------------------------------------------------
 
69
 *
 
70
 * Tk_GetGC --
 
71
 *
 
72
 *      Given a desired set of values for a graphics context, find
 
73
 *      a read-only graphics context with the desired values.
 
74
 *
 
75
 * Results:
 
76
 *      The return value is the X identifer for the desired graphics
 
77
 *      context.  The caller should never modify this GC, and should
 
78
 *      call Tk_FreeGC when the GC is no longer needed.
 
79
 *
 
80
 * Side effects:
 
81
 *      The GC is added to an internal database with a reference count.
 
82
 *      For each call to this procedure, there should eventually be a call
 
83
 *      to Tk_FreeGC, so that the database can be cleaned up when GC's
 
84
 *      aren't needed anymore.
 
85
 *
 
86
 *----------------------------------------------------------------------
 
87
 */
 
88
 
 
89
GC
 
90
Tk_GetGC(tkwin, valueMask, valuePtr)
 
91
    Tk_Window tkwin;            /* Window in which GC will be used. */
 
92
    register unsigned long valueMask;
 
93
                                /* 1 bits correspond to values specified
 
94
                                 * in *valuesPtr;  other values are set
 
95
                                 * from defaults. */
 
96
    register XGCValues *valuePtr;
 
97
                                /* Values are specified here for bits set
 
98
                                 * in valueMask. */
 
99
{
 
100
    ValueKey valueKey;
 
101
    IdKey idKey;
 
102
    Tcl_HashEntry *valueHashPtr, *idHashPtr;
 
103
    register TkGC *gcPtr;
 
104
    int new;
 
105
    Drawable d, freeDrawable;
 
106
 
 
107
    if (!initialized) {
 
108
        GCInit();
 
109
    }
 
110
 
 
111
    /*
 
112
     * Must zero valueKey at start to clear out pad bytes that may be
 
113
     * part of structure on some systems.
 
114
     */
 
115
 
 
116
    memset((VOID *) &valueKey, 0, sizeof(valueKey));
 
117
 
 
118
    /*
 
119
     * First, check to see if there's already a GC that will work
 
120
     * for this request (exact matches only, sorry).
 
121
     */
 
122
 
 
123
    if (valueMask & GCFunction) {
 
124
        valueKey.values.function = valuePtr->function;
 
125
    } else {
 
126
        valueKey.values.function = GXcopy;
 
127
    }
 
128
    if (valueMask & GCPlaneMask) {
 
129
        valueKey.values.plane_mask = valuePtr->plane_mask;
 
130
    } else {
 
131
        valueKey.values.plane_mask = (unsigned) ~0;
 
132
    }
 
133
    if (valueMask & GCForeground) {
 
134
        valueKey.values.foreground = valuePtr->foreground;
 
135
    } else {
 
136
        valueKey.values.foreground = 0;
 
137
    }
 
138
    if (valueMask & GCBackground) {
 
139
        valueKey.values.background = valuePtr->background;
 
140
    } else {
 
141
        valueKey.values.background = 1;
 
142
    }
 
143
    if (valueMask & GCLineWidth) {
 
144
        valueKey.values.line_width = valuePtr->line_width;
 
145
    } else {
 
146
        valueKey.values.line_width = 0;
 
147
    }
 
148
    if (valueMask & GCLineStyle) {
 
149
        valueKey.values.line_style = valuePtr->line_style;
 
150
    } else {
 
151
        valueKey.values.line_style = LineSolid;
 
152
    }
 
153
    if (valueMask & GCCapStyle) {
 
154
        valueKey.values.cap_style = valuePtr->cap_style;
 
155
    } else {
 
156
        valueKey.values.cap_style = CapButt;
 
157
    }
 
158
    if (valueMask & GCJoinStyle) {
 
159
        valueKey.values.join_style = valuePtr->join_style;
 
160
    } else {
 
161
        valueKey.values.join_style = JoinMiter;
 
162
    }
 
163
    if (valueMask & GCFillStyle) {
 
164
        valueKey.values.fill_style = valuePtr->fill_style;
 
165
    } else {
 
166
        valueKey.values.fill_style = FillSolid;
 
167
    }
 
168
    if (valueMask & GCFillRule) {
 
169
        valueKey.values.fill_rule = valuePtr->fill_rule;
 
170
    } else {
 
171
        valueKey.values.fill_rule = EvenOddRule;
 
172
    }
 
173
    if (valueMask & GCArcMode) {
 
174
        valueKey.values.arc_mode = valuePtr->arc_mode;
 
175
    } else {
 
176
        valueKey.values.arc_mode = ArcPieSlice;
 
177
    }
 
178
    if (valueMask & GCTile) {
 
179
        valueKey.values.tile = valuePtr->tile;
 
180
    } else {
 
181
        valueKey.values.tile = None;
 
182
    }
 
183
    if (valueMask & GCStipple) {
 
184
        valueKey.values.stipple = valuePtr->stipple;
 
185
    } else {
 
186
        valueKey.values.stipple = None;
 
187
    }
 
188
    if (valueMask & GCTileStipXOrigin) {
 
189
        valueKey.values.ts_x_origin = valuePtr->ts_x_origin;
 
190
    } else {
 
191
        valueKey.values.ts_x_origin = 0;
 
192
    }
 
193
    if (valueMask & GCTileStipYOrigin) {
 
194
        valueKey.values.ts_y_origin = valuePtr->ts_y_origin;
 
195
    } else {
 
196
        valueKey.values.ts_y_origin = 0;
 
197
    }
 
198
    if (valueMask & GCFont) {
 
199
        valueKey.values.font = valuePtr->font;
 
200
    } else {
 
201
        valueKey.values.font = None;
 
202
    }
 
203
    if (valueMask & GCSubwindowMode) {
 
204
        valueKey.values.subwindow_mode = valuePtr->subwindow_mode;
 
205
    } else {
 
206
        valueKey.values.subwindow_mode = ClipByChildren;
 
207
    }
 
208
    if (valueMask & GCGraphicsExposures) {
 
209
        valueKey.values.graphics_exposures = valuePtr->graphics_exposures;
 
210
    } else {
 
211
        valueKey.values.graphics_exposures = True;
 
212
    }
 
213
    if (valueMask & GCClipXOrigin) {
 
214
        valueKey.values.clip_x_origin = valuePtr->clip_x_origin;
 
215
    } else {
 
216
        valueKey.values.clip_x_origin = 0;
 
217
    }
 
218
    if (valueMask & GCClipYOrigin) {
 
219
        valueKey.values.clip_y_origin = valuePtr->clip_y_origin;
 
220
    } else {
 
221
        valueKey.values.clip_y_origin = 0;
 
222
    }
 
223
    if (valueMask & GCClipMask) {
 
224
        valueKey.values.clip_mask = valuePtr->clip_mask;
 
225
    } else {
 
226
        valueKey.values.clip_mask = None;
 
227
    }
 
228
    if (valueMask & GCDashOffset) {
 
229
        valueKey.values.dash_offset = valuePtr->dash_offset;
 
230
    } else {
 
231
        valueKey.values.dash_offset = 0;
 
232
    }
 
233
    if (valueMask & GCDashList) {
 
234
        valueKey.values.dashes = valuePtr->dashes;
 
235
    } else {
 
236
        valueKey.values.dashes = 4;
 
237
    }
 
238
    valueKey.display = Tk_Display(tkwin);
 
239
    valueKey.screenNum = Tk_ScreenNumber(tkwin);
 
240
    valueKey.depth = Tk_Depth(tkwin);
 
241
    valueHashPtr = Tcl_CreateHashEntry(&valueTable, (char *) &valueKey, &new);
 
242
    if (!new) {
 
243
        gcPtr = (TkGC *) Tcl_GetHashValue(valueHashPtr);
 
244
        gcPtr->refCount++;
 
245
        return gcPtr->gc;
 
246
    }
 
247
 
 
248
    /*
 
249
     * No GC is currently available for this set of values.  Allocate a
 
250
     * new GC and add a new structure to the database.
 
251
     */
 
252
 
 
253
    gcPtr = (TkGC *) ckalloc(sizeof(TkGC));
 
254
 
 
255
    /*
 
256
     * Find or make a drawable to use to specify the screen and depth
 
257
     * of the GC.  We may have to make a small pixmap, to avoid doing
 
258
     * Tk_MakeWindowExist on the window.
 
259
     */
 
260
 
 
261
    freeDrawable = None;
 
262
    if (Tk_WindowId(tkwin) != None) {
 
263
        d = Tk_WindowId(tkwin);
 
264
    } else if (valueKey.depth ==
 
265
            DefaultDepth(valueKey.display, valueKey.screenNum)) {
 
266
        d = RootWindow(valueKey.display, valueKey.screenNum);
 
267
    } else {
 
268
        d = Tk_GetPixmap(valueKey.display,
 
269
                RootWindow(valueKey.display, valueKey.screenNum),
 
270
                1, 1, valueKey.depth);
 
271
        freeDrawable = d;
 
272
    }
 
273
 
 
274
    gcPtr->gc = XCreateGC(valueKey.display, d, valueMask, &valueKey.values);
 
275
    gcPtr->display = valueKey.display;
 
276
    gcPtr->refCount = 1;
 
277
    gcPtr->valueHashPtr = valueHashPtr;
 
278
    idKey.display = valueKey.display;
 
279
    idKey.gc = gcPtr->gc;
 
280
    idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new);
 
281
    if (!new) {
 
282
        panic("GC already registered in Tk_GetGC");
 
283
    }
 
284
    Tcl_SetHashValue(valueHashPtr, gcPtr);
 
285
    Tcl_SetHashValue(idHashPtr, gcPtr);
 
286
    if (freeDrawable != None) {
 
287
        Tk_FreePixmap(valueKey.display, freeDrawable);
 
288
    }
 
289
 
 
290
    return gcPtr->gc;
 
291
}
 
292
 
 
293
/*
 
294
 *----------------------------------------------------------------------
 
295
 *
 
296
 * Tk_FreeGC --
 
297
 *
 
298
 *      This procedure is called to release a graphics context allocated by
 
299
 *      Tk_GetGC.
 
300
 *
 
301
 * Results:
 
302
 *      None.
 
303
 *
 
304
 * Side effects:
 
305
 *      The reference count associated with gc is decremented, and
 
306
 *      gc is officially deallocated if no-one is using it anymore.
 
307
 *
 
308
 *----------------------------------------------------------------------
 
309
 */
 
310
 
 
311
void
 
312
Tk_FreeGC(display, gc)
 
313
    Display *display;           /* Display for which gc was allocated. */
 
314
    GC gc;                      /* Graphics context to be released. */
 
315
{
 
316
    IdKey idKey;
 
317
    Tcl_HashEntry *idHashPtr;
 
318
    register TkGC *gcPtr;
 
319
 
 
320
    if (!initialized) {
 
321
        panic("Tk_FreeGC called before Tk_GetGC");
 
322
    }
 
323
 
 
324
    idKey.display = display;
 
325
    idKey.gc = gc;
 
326
    idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey);
 
327
    if (idHashPtr == NULL) {
 
328
        panic("Tk_FreeGC received unknown gc argument");
 
329
    }
 
330
    gcPtr = (TkGC *) Tcl_GetHashValue(idHashPtr);
 
331
    gcPtr->refCount--;
 
332
    if (gcPtr->refCount == 0) {
 
333
        Tk_FreeXId(gcPtr->display, (XID) XGContextFromGC(gcPtr->gc));
 
334
        XFreeGC(gcPtr->display, gcPtr->gc);
 
335
        Tcl_DeleteHashEntry(gcPtr->valueHashPtr);
 
336
        Tcl_DeleteHashEntry(idHashPtr);
 
337
        ckfree((char *) gcPtr);
 
338
    }
 
339
}
 
340
 
 
341
/*
 
342
 *----------------------------------------------------------------------
 
343
 *
 
344
 * GCInit --
 
345
 *
 
346
 *      Initialize the structures used for GC management.
 
347
 *
 
348
 * Results:
 
349
 *      None.
 
350
 *
 
351
 * Side effects:
 
352
 *      Read the code.
 
353
 *
 
354
 *----------------------------------------------------------------------
 
355
 */
 
356
 
 
357
static void
 
358
GCInit()
 
359
{
 
360
    initialized = 1;
 
361
    Tcl_InitHashTable(&valueTable, sizeof(ValueKey)/sizeof(int));
 
362
    Tcl_InitHashTable(&idTable, sizeof(IdKey)/sizeof(int));
 
363
}