1 /*
2 * style-color.c: Color allocation on the Gnumeric spreadsheet
3 *
4 * Author:
5 * Miguel de Icaza (miguel@kernel.org)
6 *
7 */
8 #include <gnumeric-config.h>
9 #include <gnumeric.h>
10 #include <style-color.h>
11 #include <style-border.h>
12 #include <gui-util.h>
13
14 static GHashTable *style_color_hash;
15 static GnmColor *sc_black;
16 static GnmColor *sc_white;
17 static GnmColor *sc_auto_back;
18 static GnmColor *sc_auto_font;
19 static GnmColor *sc_auto_pattern;
20
21 static GnmColor *
gnm_color_make(GOColor c,gboolean is_auto)22 gnm_color_make (GOColor c, gboolean is_auto)
23 {
24 GnmColor key, *sc;
25
26 is_auto = !!is_auto;
27
28 key.go_color = c;
29 key.is_auto = is_auto;
30
31 sc = g_hash_table_lookup (style_color_hash, &key);
32 if (!sc) {
33 sc = g_new (GnmColor, 1);
34 sc->go_color = c;
35 sc->is_auto = is_auto;
36 sc->ref_count = 1;
37
38 g_hash_table_insert (style_color_hash, sc, sc);
39 } else
40 sc->ref_count++;
41
42 return sc;
43 }
44
45 GnmColor *
gnm_color_new_rgba16(guint16 red,guint16 green,guint16 blue,guint16 alpha)46 gnm_color_new_rgba16 (guint16 red, guint16 green, guint16 blue, guint16 alpha)
47 {
48 return gnm_color_new_rgba8 (red >> 8, green >> 8, blue >> 8, alpha >> 8);
49 }
50
51 GnmColor *
gnm_color_new_pango(PangoColor const * c)52 gnm_color_new_pango (PangoColor const *c)
53 {
54 return gnm_color_new_rgba16 (c->red, c->green, c->blue, 0xffff);
55 }
56
57 GnmColor *
gnm_color_new_gdk(GdkRGBA const * c)58 gnm_color_new_gdk (GdkRGBA const *c)
59 {
60 /*
61 * The important property here is that a color #rrggbb
62 * (i.e., an 8-bit color) roundtrips correctly when
63 * translated into GdkRGBA using /255 and back. Using
64 * multiplication by 256 here makes rounding unnecessary.
65 */
66
67 guint8 r8 = CLAMP (c->red * 256, 0, 255);
68 guint8 g8 = CLAMP (c->green * 256, 0, 255);
69 guint8 b8 = CLAMP (c->blue * 256, 0, 255);
70 guint8 a8 = CLAMP (c->alpha * 256, 0, 255);
71
72 return gnm_color_new_rgba8 (r8, g8, b8, a8);
73 }
74
75 GnmColor *
gnm_color_new_rgba8(guint8 red,guint8 green,guint8 blue,guint8 alpha)76 gnm_color_new_rgba8 (guint8 red, guint8 green, guint8 blue, guint8 alpha)
77 {
78 return gnm_color_new_go (GO_COLOR_FROM_RGBA (red, green, blue, alpha));
79 }
80
81 GnmColor *
gnm_color_new_rgb8(guint8 red,guint8 green,guint8 blue)82 gnm_color_new_rgb8 (guint8 red, guint8 green, guint8 blue)
83 {
84 return gnm_color_new_rgba8 (red, green, blue, 0xff);
85 }
86
87 GnmColor *
gnm_color_new_go(GOColor c)88 gnm_color_new_go (GOColor c)
89 {
90 return gnm_color_make (c, FALSE);
91 }
92
93 GnmColor *
gnm_color_new_auto(GOColor c)94 gnm_color_new_auto (GOColor c)
95 {
96 return gnm_color_make (c, TRUE);
97 }
98
99 GnmColor *
style_color_black(void)100 style_color_black (void)
101 {
102 if (!sc_black)
103 sc_black = gnm_color_new_rgb8 (0, 0, 0);
104 return style_color_ref (sc_black);
105 }
106
107 GnmColor *
style_color_white(void)108 style_color_white (void)
109 {
110 if (!sc_white)
111 sc_white = gnm_color_new_rgb8 (0xff, 0xff, 0xff);
112 return style_color_ref (sc_white);
113 }
114
115 GnmColor *
style_color_grid(GtkStyleContext * context)116 style_color_grid (GtkStyleContext *context)
117 {
118 if (context) {
119 GdkRGBA color;
120 gtk_style_context_save (context);
121 gtk_style_context_add_class (context, "grid");
122 gnm_style_context_get_color (context, GTK_STATE_FLAG_NORMAL,
123 &color);
124 gnm_css_debug_color ("grid.color", &color);
125 gtk_style_context_restore (context);
126 return gnm_color_new_gdk (&color);
127 } else
128 return gnm_color_new_rgb8 (0xc7, 0xc7, 0xc7);
129 }
130
131 /*
132 * Support for Excel auto-colors.
133 */
134
135 /**
136 * style_color_auto_font:
137 *
138 * Always black, as far as we know.
139 */
140 GnmColor *
style_color_auto_font(void)141 style_color_auto_font (void)
142 {
143 if (!sc_auto_font)
144 sc_auto_font = gnm_color_new_auto (GO_COLOR_BLACK);
145 return style_color_ref (sc_auto_font);
146 }
147
148 /**
149 * style_color_auto_back:
150 *
151 * Always white, as far as we know.
152 */
153 GnmColor *
style_color_auto_back(void)154 style_color_auto_back (void)
155 {
156 if (!sc_auto_back)
157 sc_auto_back = gnm_color_new_auto (GO_COLOR_WHITE);
158 return style_color_ref (sc_auto_back);
159 }
160
161 /**
162 * style_color_auto_pattern:
163 *
164 * Normally black, but follows grid color if so told.
165 */
166 GnmColor *
style_color_auto_pattern(void)167 style_color_auto_pattern (void)
168 {
169 if (!sc_auto_pattern)
170 sc_auto_pattern = gnm_color_new_auto (GO_COLOR_BLACK);
171 return style_color_ref (sc_auto_pattern);
172 }
173
174 GnmColor *
style_color_ref(GnmColor * sc)175 style_color_ref (GnmColor *sc)
176 {
177 if (sc != NULL)
178 sc->ref_count++;
179
180 return sc;
181 }
182
183 void
style_color_unref(GnmColor * sc)184 style_color_unref (GnmColor *sc)
185 {
186 if (sc == NULL)
187 return;
188
189 g_return_if_fail (sc->ref_count > 0);
190
191 sc->ref_count--;
192 if (sc->ref_count != 0)
193 return;
194
195 g_hash_table_remove (style_color_hash, sc);
196 g_free (sc);
197 }
198
199 GType
gnm_color_get_type(void)200 gnm_color_get_type (void)
201 {
202 static GType t = 0;
203
204 if (t == 0)
205 t = g_boxed_type_register_static ("GnmColor",
206 (GBoxedCopyFunc)style_color_ref,
207 (GBoxedFreeFunc)style_color_unref);
208 return t;
209 }
210
211 gint
style_color_equal(GnmColor const * k1,GnmColor const * k2)212 style_color_equal (GnmColor const *k1, GnmColor const *k2)
213 {
214 return (k1->go_color == k2->go_color &&
215 k1->is_auto == k2->is_auto);
216 }
217
218 static guint
color_hash(gconstpointer v)219 color_hash (gconstpointer v)
220 {
221 GnmColor const *k = (GnmColor const *)v;
222 return k->go_color ^ k->is_auto;
223 }
224
225 /**
226 * gnm_color_init: (skip)
227 */
228 void
gnm_color_init(void)229 gnm_color_init (void)
230 {
231 style_color_hash = g_hash_table_new (color_hash,
232 (GEqualFunc)style_color_equal);
233 }
234
235 static void
cb_color_leak(gpointer key,gpointer value,gpointer user_data)236 cb_color_leak (gpointer key, gpointer value, gpointer user_data)
237 {
238 GnmColor *color = value;
239
240 g_printerr ("Leaking style-color at %p [%08x].\n",
241 (void *)color,
242 color->go_color);
243 }
244
245 /**
246 * gnm_color_shutdown: (skip)
247 */
248 void
gnm_color_shutdown(void)249 gnm_color_shutdown (void)
250 {
251 style_color_unref (sc_black);
252 sc_black = NULL;
253
254 style_color_unref (sc_white);
255 sc_white = NULL;
256
257 style_color_unref (sc_auto_back);
258 sc_auto_back = NULL;
259
260 style_color_unref (sc_auto_font);
261 sc_auto_font = NULL;
262
263 style_color_unref (sc_auto_pattern);
264 sc_auto_pattern = NULL;
265
266 g_hash_table_foreach (style_color_hash, cb_color_leak, NULL);
267 g_hash_table_destroy (style_color_hash);
268 style_color_hash = NULL;
269 }
270