]> Pileus Git - ~andy/gtk/blob - gtk/gtkgc.c
Added gdk_text/string_extents() - too calculate all the metrics at once of
[~andy/gtk] / gtk / gtkgc.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include "gtkgc.h"
20
21
22 typedef struct _GtkGCKey       GtkGCKey;
23 typedef struct _GtkGCDrawable  GtkGCDrawable;
24
25 struct _GtkGCKey
26 {
27   gint depth;
28   GdkColormap *colormap;
29   GdkGCValues values;
30   GdkGCValuesMask mask;
31 };
32
33 struct _GtkGCDrawable
34 {
35   gint depth;
36   GdkPixmap *drawable;
37 };
38
39
40 static void      gtk_gc_init             (void);
41 static GtkGCKey* gtk_gc_key_dup          (GtkGCKey      *key);
42 static void      gtk_gc_key_destroy      (GtkGCKey      *key);
43 static gpointer  gtk_gc_new              (gpointer       key);
44 static void      gtk_gc_destroy          (gpointer       value);
45 static guint     gtk_gc_key_hash         (gpointer       key);
46 static guint     gtk_gc_value_hash       (gpointer       value);
47 static gint      gtk_gc_key_compare      (gpointer       a,
48                                           gpointer       b);
49 static guint     gtk_gc_drawable_hash    (GtkGCDrawable *d);
50 static gint      gtk_gc_drawable_compare (GtkGCDrawable *a,
51                                           GtkGCDrawable *b);
52
53
54 static gint initialize = TRUE;
55 static GCache *gc_cache = NULL;
56 static GHashTable *gc_drawable_ht = NULL;
57
58 static GMemChunk *key_mem_chunk = NULL;
59
60
61 GdkGC*
62 gtk_gc_get (gint             depth,
63             GdkColormap     *colormap,
64             GdkGCValues     *values,
65             GdkGCValuesMask  values_mask)
66 {
67   GtkGCKey key;
68   GdkGC *gc;
69
70   if (initialize)
71     gtk_gc_init ();
72
73   key.depth = depth;
74   key.colormap = colormap;
75   key.values = *values;
76   key.mask = values_mask;
77
78   gc = g_cache_insert (gc_cache, &key);
79
80   return gc;
81 }
82
83 void
84 gtk_gc_release (GdkGC *gc)
85 {
86   if (initialize)
87     gtk_gc_init ();
88
89   g_cache_remove (gc_cache, gc);
90 }
91
92
93 static void
94 gtk_gc_init (void)
95 {
96   initialize = FALSE;
97
98   gc_cache = g_cache_new ((GCacheNewFunc) gtk_gc_new,
99                           (GCacheDestroyFunc) gtk_gc_destroy,
100                           (GCacheDupFunc) gtk_gc_key_dup,
101                           (GCacheDestroyFunc) gtk_gc_key_destroy,
102                           (GHashFunc) gtk_gc_key_hash,
103                           (GHashFunc) gtk_gc_value_hash,
104                           (GCompareFunc) gtk_gc_key_compare);
105
106   gc_drawable_ht = g_hash_table_new ((GHashFunc) gtk_gc_drawable_hash,
107                                      (GCompareFunc) gtk_gc_drawable_compare);
108 }
109
110 static GtkGCKey*
111 gtk_gc_key_dup (GtkGCKey *key)
112 {
113   GtkGCKey *new_key;
114
115   if (!key_mem_chunk)
116     key_mem_chunk = g_mem_chunk_new ("key mem chunk", sizeof (GtkGCKey),
117                                      1024, G_ALLOC_AND_FREE);
118
119   new_key = g_chunk_new (GtkGCKey, key_mem_chunk);
120
121   *new_key = *key;
122
123   return new_key;
124 }
125
126 static void
127 gtk_gc_key_destroy (GtkGCKey *key)
128 {
129   g_mem_chunk_free (key_mem_chunk, key);
130 }
131
132 static gpointer
133 gtk_gc_new (gpointer key)
134 {
135   GtkGCKey *keyval;
136   GtkGCDrawable *drawable;
137   GdkGC *gc;
138
139   keyval = key;
140
141   drawable = g_hash_table_lookup (gc_drawable_ht, &keyval->depth);
142   if (!drawable)
143     {
144       drawable = g_new (GtkGCDrawable, 1);
145       drawable->depth = keyval->depth;
146       drawable->drawable = gdk_pixmap_new (NULL, 1, 1, drawable->depth);
147
148       g_hash_table_insert (gc_drawable_ht, &drawable->depth, drawable);
149     }
150
151   gc = gdk_gc_new_with_values (drawable->drawable, &keyval->values, keyval->mask);
152
153   return (gpointer) gc;
154 }
155
156 static void
157 gtk_gc_destroy (gpointer value)
158 {
159   gdk_gc_destroy ((GdkGC*) value);
160 }
161
162 static guint
163 gtk_gc_key_hash (gpointer key)
164 {
165   GtkGCKey *keyval;
166   guint hash_val;
167
168   keyval = key;
169   hash_val = 0;
170
171   if (keyval->mask & GDK_GC_FOREGROUND)
172     {
173       hash_val += keyval->values.foreground.pixel;
174     }
175   if (keyval->mask & GDK_GC_BACKGROUND)
176     {
177       hash_val += keyval->values.background.pixel;
178     }
179   if (keyval->mask & GDK_GC_FONT)
180     {
181       hash_val += gdk_font_id (keyval->values.font);
182     }
183   if (keyval->mask & GDK_GC_FUNCTION)
184     {
185       hash_val += (gint) keyval->values.function;
186     }
187   if (keyval->mask & GDK_GC_FILL)
188     {
189       hash_val += (gint) keyval->values.fill;
190     }
191   if (keyval->mask & GDK_GC_TILE)
192     {
193       hash_val += (glong) keyval->values.tile;
194     }
195   if (keyval->mask & GDK_GC_STIPPLE)
196     {
197       hash_val += (glong) keyval->values.stipple;
198     }
199   if (keyval->mask & GDK_GC_CLIP_MASK)
200     {
201       hash_val += (glong) keyval->values.clip_mask;
202     }
203   if (keyval->mask & GDK_GC_SUBWINDOW)
204     {
205       hash_val += (gint) keyval->values.subwindow_mode;
206     }
207   if (keyval->mask & GDK_GC_TS_X_ORIGIN)
208     {
209       hash_val += (gint) keyval->values.ts_x_origin;
210     }
211   if (keyval->mask & GDK_GC_TS_Y_ORIGIN)
212     {
213       hash_val += (gint) keyval->values.ts_y_origin;
214     }
215   if (keyval->mask & GDK_GC_CLIP_X_ORIGIN)
216     {
217       hash_val += (gint) keyval->values.clip_x_origin;
218     }
219   if (keyval->mask & GDK_GC_CLIP_Y_ORIGIN)
220     {
221       hash_val += (gint) keyval->values.clip_y_origin;
222     }
223   if (keyval->mask & GDK_GC_EXPOSURES)
224     {
225       hash_val += (gint) keyval->values.graphics_exposures;
226     }
227   if (keyval->mask & GDK_GC_LINE_WIDTH)
228     {
229       hash_val += (gint) keyval->values.line_width;
230     }
231   if (keyval->mask & GDK_GC_LINE_STYLE)
232     {
233       hash_val += (gint) keyval->values.line_style;
234     }
235   if (keyval->mask & GDK_GC_CAP_STYLE)
236     {
237       hash_val += (gint) keyval->values.cap_style;
238     }
239   if (keyval->mask & GDK_GC_JOIN_STYLE)
240     {
241       hash_val += (gint) keyval->values.join_style;
242     }
243
244   return hash_val;
245 }
246
247 static guint
248 gtk_gc_value_hash (gpointer value)
249 {
250   return (gulong) value;
251 }
252
253 static gint
254 gtk_gc_key_compare (gpointer a,
255                     gpointer b)
256 {
257   GtkGCKey *akey;
258   GtkGCKey *bkey;
259   GdkGCValues *avalues;
260   GdkGCValues *bvalues;
261
262   akey = a;
263   bkey = b;
264
265   avalues = &akey->values;
266   bvalues = &bkey->values;
267
268   if (akey->mask != bkey->mask)
269     return FALSE;
270
271   if (akey->depth != bkey->depth)
272     return FALSE;
273
274   if (akey->colormap != bkey->colormap)
275     return FALSE;
276
277   if (akey->mask & GDK_GC_FOREGROUND)
278     {
279       if (avalues->foreground.pixel != bvalues->foreground.pixel)
280         return FALSE;
281     }
282   if (akey->mask & GDK_GC_BACKGROUND)
283     {
284       if (avalues->background.pixel != bvalues->background.pixel)
285         return FALSE;
286     }
287   if (akey->mask & GDK_GC_FONT)
288     {
289       if (!gdk_font_equal (avalues->font, bvalues->font))
290         return FALSE;
291     }
292   if (akey->mask & GDK_GC_FUNCTION)
293     {
294       if (avalues->function != bvalues->function)
295         return FALSE;
296     }
297   if (akey->mask & GDK_GC_FILL)
298     {
299       if (avalues->fill != bvalues->fill)
300         return FALSE;
301     }
302   if (akey->mask & GDK_GC_TILE)
303     {
304       if (avalues->tile != bvalues->tile)
305         return FALSE;
306     }
307   if (akey->mask & GDK_GC_STIPPLE)
308     {
309       if (avalues->stipple != bvalues->stipple)
310         return FALSE;
311     }
312   if (akey->mask & GDK_GC_CLIP_MASK)
313     {
314       if (avalues->clip_mask != bvalues->clip_mask)
315         return FALSE;
316     }
317   if (akey->mask & GDK_GC_SUBWINDOW)
318     {
319       if (avalues->subwindow_mode != bvalues->subwindow_mode)
320         return FALSE;
321     }
322   if (akey->mask & GDK_GC_TS_X_ORIGIN)
323     {
324       if (avalues->ts_x_origin != bvalues->ts_x_origin)
325         return FALSE;
326     }
327   if (akey->mask & GDK_GC_TS_Y_ORIGIN)
328     {
329       if (avalues->ts_y_origin != bvalues->ts_y_origin)
330         return FALSE;
331     }
332   if (akey->mask & GDK_GC_CLIP_X_ORIGIN)
333     {
334       if (avalues->clip_x_origin != bvalues->clip_x_origin)
335         return FALSE;
336     }
337   if (akey->mask & GDK_GC_CLIP_Y_ORIGIN)
338     {
339       if (avalues->clip_y_origin != bvalues->clip_y_origin)
340         return FALSE;
341     }
342   if (akey->mask & GDK_GC_EXPOSURES)
343     {
344       if (avalues->graphics_exposures != bvalues->graphics_exposures)
345         return FALSE;
346     }
347   if (akey->mask & GDK_GC_LINE_WIDTH)
348     {
349       if (avalues->line_width != bvalues->line_width)
350         return FALSE;
351     }
352   if (akey->mask & GDK_GC_LINE_STYLE)
353     {
354       if (avalues->line_style != bvalues->line_style)
355         return FALSE;
356     }
357   if (akey->mask & GDK_GC_CAP_STYLE)
358     {
359       if (avalues->cap_style != bvalues->cap_style)
360         return FALSE;
361     }
362   if (akey->mask & GDK_GC_JOIN_STYLE)
363     {
364       if (avalues->join_style != bvalues->join_style)
365         return FALSE;
366     }
367
368   return TRUE;
369 }
370
371
372 static guint
373 gtk_gc_drawable_hash (GtkGCDrawable *d)
374 {
375   return d->depth;
376 }
377
378 static gint
379 gtk_gc_drawable_compare (GtkGCDrawable *a,
380                          GtkGCDrawable *b)
381 {
382   return (a->depth == b->depth);
383 }