1 /* High Contrast - a cairo based GTK+ engine
2 * Copyright (C) 2003 Sun Microsystems Inc.
3 * Copyright (C) 2006 Andrew Johnson <acjgenius@earthlink.net>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * Project contact: <gnome-themes-list@gnome.org>
20 *
21 */
22
23
24 #include "hc_gtk2_engine.h"
25 #include "hc_gtk2_support.h"
26 #include "hc_gtk2_drawing.h"
27
28
29 /**********************************/
30 /* Parse RC Style */
31 /**********************************/
32 enum {
33 TOKEN_EDGE_THICKNESS = G_TOKEN_LAST + 1,
34 TOKEN_CELL_INDICATOR_SIZE
35 };
36
37 static struct {
38 const gchar *name;
39 guint token;
40 } hc_rc_symbols[] = {
41 { "edge_thickness", TOKEN_EDGE_THICKNESS },
42 { "cell_indicator_size", TOKEN_CELL_INDICATOR_SIZE }
43 };
44
45 static guint
hc_rc_parse_int(GScanner * scanner,GTokenType wanted_token,guint return_default,gint * retval,gint lower_limit,gint upper_limit)46 hc_rc_parse_int (GScanner *scanner,
47 GTokenType wanted_token,
48 guint return_default,
49 gint *retval,
50 gint lower_limit,
51 gint upper_limit)
52 {
53 guint token;
54 gboolean negate=FALSE;
55
56 token = g_scanner_cur_token (scanner);
57 if (token != wanted_token)
58 {
59 token = g_scanner_get_next_token (scanner);
60 if (token != wanted_token)
61 {
62 return wanted_token;
63 }
64 }
65
66 if (token != G_TOKEN_EQUAL_SIGN)
67 {
68 token = g_scanner_get_next_token (scanner);
69 if (token != G_TOKEN_EQUAL_SIGN)
70 {
71 return G_TOKEN_EQUAL_SIGN;
72 }
73 }
74
75 if (g_scanner_peek_next_token (scanner) == '-')
76 {
77 g_scanner_get_next_token (scanner); /* eat sign */
78 negate = TRUE;
79 }
80
81 token = g_scanner_get_next_token (scanner);
82
83 if (token != G_TOKEN_INT)
84 *retval = return_default;
85 else
86 *retval = (guint) scanner->value.v_int;
87
88 if (negate) *retval = -(*retval);
89
90 if (*retval < lower_limit) *retval = lower_limit;
91 if ((*retval > upper_limit) && (upper_limit > lower_limit)) *retval = upper_limit;
92
93 return G_TOKEN_NONE;
94 }
95
96 static guint
hc_rc_style_parse(GtkRcStyle * rc_style,GtkSettings * settings,GScanner * scanner)97 hc_rc_style_parse (GtkRcStyle *rc_style,
98 GtkSettings *settings,
99 GScanner *scanner)
100 {
101 HcRcStyle *hc_rc_style = HC_RC_STYLE (rc_style);
102
103 static GQuark scope_id = 0;
104 guint old_scope;
105 guint token;
106 guint i;
107
108 /* Set up a new scope in this scanner. */
109
110 if (!scope_id)
111 scope_id = g_quark_from_string ("hc_theme_engine");
112
113 /* If we bail out due to errors, we *don't* reset the scope, so the
114 * error messaging code can make sense of our tokens.
115 */
116 old_scope = g_scanner_set_scope (scanner, scope_id);
117
118 if (!g_scanner_lookup_symbol (scanner, hc_rc_symbols[0].name)) {
119 for (i = 0; i < G_N_ELEMENTS (hc_rc_symbols); i++)
120 g_scanner_scope_add_symbol (scanner, scope_id, hc_rc_symbols[i].name,
121 GINT_TO_POINTER (hc_rc_symbols[i].token));
122 }
123
124 token = g_scanner_peek_next_token (scanner);
125 while (token != G_TOKEN_RIGHT_CURLY) {
126 switch (token) {
127 case TOKEN_EDGE_THICKNESS:
128 token = hc_rc_parse_int (scanner, TOKEN_EDGE_THICKNESS, 2, &hc_rc_style->edge_thickness, 1, 25);
129 hc_rc_style->flags |= HC_RC_FLAG_EDGE_THICKNESS;
130 break;
131 case TOKEN_CELL_INDICATOR_SIZE:
132 token = hc_rc_parse_int (scanner, TOKEN_CELL_INDICATOR_SIZE, 12, &hc_rc_style->cell_indicator_size, 1, 100);
133 hc_rc_style->flags |= HC_RC_FLAG_CELL_INDICATOR_SIZE;
134 break;
135 default:
136 g_scanner_get_next_token (scanner);
137 token = G_TOKEN_RIGHT_CURLY;
138 break;
139 }
140
141 if (token != G_TOKEN_NONE)
142 return token;
143
144 token = g_scanner_peek_next_token (scanner);
145 }
146
147 g_scanner_get_next_token (scanner);
148
149 g_scanner_set_scope (scanner, old_scope);
150
151 return G_TOKEN_NONE;
152 }
153
154 /**********************************/
155 /* Register & Initialize RC Style */
156 /**********************************/
157
158
G_DEFINE_DYNAMIC_TYPE(HcRcStyle,hc_rc_style,GTK_TYPE_RC_STYLE)159 G_DEFINE_DYNAMIC_TYPE (HcRcStyle, hc_rc_style, GTK_TYPE_RC_STYLE)
160
161 /* Create an empty style suitable to this RC style */
162 static GtkStyle *
163 hc_rc_style_create_style (GtkRcStyle *rc_style)
164 {
165 return GTK_STYLE (g_object_new (HC_TYPE_STYLE, NULL));;
166 }
167
168 static void
hc_rc_style_merge(GtkRcStyle * dest,GtkRcStyle * src)169 hc_rc_style_merge (GtkRcStyle *dest,
170 GtkRcStyle *src)
171 {
172 HcRcFlags flags;
173 HcRcStyle *dest_w, *src_w;
174
175 GTK_RC_STYLE_CLASS (hc_rc_style_parent_class)->merge (dest, src);
176
177 if (!HC_IS_RC_STYLE (src))
178 return;
179
180 src_w = HC_RC_STYLE (src);
181 dest_w = HC_RC_STYLE (dest);
182
183 flags = (~dest_w->flags) & src_w->flags;
184
185 if (flags & HC_RC_FLAG_EDGE_THICKNESS)
186 dest_w->edge_thickness = src_w->edge_thickness;
187 if (flags & HC_RC_FLAG_CELL_INDICATOR_SIZE)
188 dest_w->cell_indicator_size = src_w->cell_indicator_size;
189
190 dest_w->flags = dest_w->flags | src_w->flags;
191 }
192
hc_rc_style_class_init(HcRcStyleClass * klass)193 static void hc_rc_style_class_init (HcRcStyleClass *klass)
194 {
195 GtkRcStyleClass *rc_style_class = GTK_RC_STYLE_CLASS (klass);
196
197 rc_style_class->create_style = hc_rc_style_create_style;
198 rc_style_class->parse = hc_rc_style_parse;
199 rc_style_class->merge = hc_rc_style_merge;
200 }
201
202 static void
hc_rc_style_init(HcRcStyle * hc_rc_style)203 hc_rc_style_init (HcRcStyle *hc_rc_style)
204 {
205 hc_rc_style->flags = 0;
206 hc_rc_style->edge_thickness = -1;
207 hc_rc_style->cell_indicator_size = -1;
208 }
209
210 static void
hc_rc_style_class_finalize(HcRcStyleClass * klass)211 hc_rc_style_class_finalize (HcRcStyleClass *klass)
212 {
213 }
214
215 /***************************************/
216 /* Register & Initialize Drawing Style */
217 /***************************************/
218
G_DEFINE_DYNAMIC_TYPE(HcStyle,hc_style,GTK_TYPE_STYLE)219 G_DEFINE_DYNAMIC_TYPE (HcStyle, hc_style, GTK_TYPE_STYLE)
220
221 static void
222 hc_style_realize (GtkStyle *style)
223 {
224 HcStyle *hc_style = HC_STYLE (style);
225
226 GdkGCValues gc_values;
227 GdkGCValuesMask gc_values_mask;
228
229 gint i;
230
231 for (i = 0; i < 5; i++)
232 {
233 style->light[i].red = MIN (65535, style->bg[i].red + 0.5 * 65535);
234 style->light[i].green = MIN (65535, style->bg[i].green + 0.5 * 65535);
235 style->light[i].blue = MIN (65535, style->bg[i].blue + 0.5 * 65535);
236
237 style->dark[i].red = MAX (0, style->bg[i].red - 0.5 * 65535);
238 style->dark[i].green = MAX (0, style->bg[i].green - 0.5 * 65535);
239 style->dark[i].blue = MAX (0, style->bg[i].blue - 0.5 * 65535);
240
241 style->mid[i].red = (style->light[i].red + style->dark[i].red) / 2;
242 style->mid[i].green = (style->light[i].green + style->dark[i].green) / 2;
243 style->mid[i].blue = (style->light[i].blue + style->dark[i].blue) / 2;
244
245 style->text_aa[i].red = (style->text[i].red + style->base[i].red) / 2;
246 style->text_aa[i].green = (style->text[i].green + style->base[i].green) / 2;
247 style->text_aa[i].blue = (style->text[i].blue + style->base[i].blue) / 2;
248 }
249
250 style->black.red = 0x0000;
251 style->black.green = 0x0000;
252 style->black.blue = 0x0000;
253 gdk_colormap_alloc_color (style->colormap, &style->black, FALSE, TRUE);
254
255 style->white.red = 0xffff;
256 style->white.green = 0xffff;
257 style->white.blue = 0xffff;
258 gdk_colormap_alloc_color (style->colormap, &style->white, FALSE, TRUE);
259
260 gc_values_mask = GDK_GC_FOREGROUND;
261
262 gc_values.foreground = style->black;
263 style->black_gc = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
264
265 gc_values.foreground = style->white;
266 style->white_gc = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
267
268 for (i = 0; i < 5; i++)
269 {
270 if (!gdk_colormap_alloc_color (style->colormap, &style->fg[i], FALSE, TRUE))
271 g_warning ("unable to allocate color: ( %d %d %d )",
272 style->fg[i].red, style->fg[i].green, style->fg[i].blue);
273 if (!gdk_colormap_alloc_color (style->colormap, &style->bg[i], FALSE, TRUE))
274 g_warning ("unable to allocate color: ( %d %d %d )",
275 style->bg[i].red, style->bg[i].green, style->bg[i].blue);
276 if (!gdk_colormap_alloc_color (style->colormap, &style->light[i], FALSE, TRUE))
277 g_warning ("unable to allocate color: ( %d %d %d )",
278 style->light[i].red, style->light[i].green, style->light[i].blue);
279 if (!gdk_colormap_alloc_color (style->colormap, &style->dark[i], FALSE, TRUE))
280 g_warning ("unable to allocate color: ( %d %d %d )",
281 style->dark[i].red, style->dark[i].green, style->dark[i].blue);
282 if (!gdk_colormap_alloc_color (style->colormap, &style->mid[i], FALSE, TRUE))
283 g_warning ("unable to allocate color: ( %d %d %d )",
284 style->mid[i].red, style->mid[i].green, style->mid[i].blue);
285 if (!gdk_colormap_alloc_color (style->colormap, &style->text[i], FALSE, TRUE))
286 g_warning ("unable to allocate color: ( %d %d %d )",
287 style->text[i].red, style->text[i].green, style->text[i].blue);
288 if (!gdk_colormap_alloc_color (style->colormap, &style->base[i], FALSE, TRUE))
289 g_warning ("unable to allocate color: ( %d %d %d )",
290 style->base[i].red, style->base[i].green, style->base[i].blue);
291 if (!gdk_colormap_alloc_color (style->colormap, &style->text_aa[i], FALSE, TRUE))
292 g_warning ("unable to allocate color: ( %d %d %d )",
293 style->text_aa[i].red, style->text_aa[i].green, style->text_aa[i].blue);
294
295 gc_values.foreground = style->fg[i];
296 style->fg_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
297
298 gc_values.foreground = style->bg[i];
299 style->bg_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
300
301 gc_values.foreground = style->light[i];
302 style->light_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
303
304 gc_values.foreground = style->dark[i];
305 style->dark_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
306
307 gc_values.foreground = style->mid[i];
308 style->mid_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
309
310 gc_values.foreground = style->text[i];
311 style->text_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
312
313 gc_values.foreground = style->base[i];
314 style->base_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
315
316 gc_values.foreground = style->text_aa[i];
317 style->text_aa_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
318 }
319
320 ge_gtk_style_to_cairo_color_cube (style, &hc_style->color_cube);
321 }
322
323 static void
hc_style_copy(GtkStyle * style,GtkStyle * src)324 hc_style_copy (GtkStyle * style, GtkStyle * src)
325 {
326 HcStyle *hc_style = HC_STYLE (style);
327 HcStyle *hc_src = HC_STYLE (src);
328
329 hc_style->edge_thickness = hc_src->edge_thickness;
330 hc_style->cell_indicator_size = hc_src->cell_indicator_size;
331
332 GTK_STYLE_CLASS (hc_style_parent_class)->copy (style, src);
333 }
334
335 static void
hc_style_init_from_rc(GtkStyle * style,GtkRcStyle * rc_style)336 hc_style_init_from_rc (GtkStyle * style, GtkRcStyle * rc_style)
337 {
338 HcStyle *hc_style = HC_STYLE (style);
339
340 GTK_STYLE_CLASS (hc_style_parent_class)->init_from_rc (style, rc_style);
341
342 if (HC_RC_STYLE (rc_style)->edge_thickness > 0)
343 {
344 hc_style->edge_thickness = HC_RC_STYLE (rc_style)->edge_thickness;
345 }
346
347 if (HC_RC_STYLE (rc_style)->cell_indicator_size > 0)
348 {
349 hc_style->cell_indicator_size = HC_RC_STYLE (rc_style)->cell_indicator_size;
350 }
351 }
352
353 static void
hc_style_class_init(HcStyleClass * klass)354 hc_style_class_init (HcStyleClass *klass)
355 {
356 GtkStyleClass *style_class = GTK_STYLE_CLASS (klass);
357
358 style_class->realize = hc_style_realize;
359 style_class->copy = hc_style_copy;
360 style_class->init_from_rc = hc_style_init_from_rc;
361
362 style_class->draw_shadow = hc_draw_shadow;
363 style_class->realize = hc_style_realize;
364 style_class->draw_check = hc_draw_check;
365 style_class->draw_option = hc_draw_option;
366 style_class->draw_layout = hc_draw_layout;
367 style_class->draw_extension = hc_draw_extension;
368 style_class->draw_tab = hc_draw_tab;
369 style_class->draw_shadow_gap = hc_draw_shadow_gap;
370 style_class->draw_arrow = hc_draw_arrow;
371 style_class->draw_flat_box = hc_draw_flat_box;
372 style_class->draw_box = hc_draw_box;
373 style_class->draw_box_gap = hc_draw_box_gap;
374 style_class->draw_handle = hc_draw_handle;
375 style_class->draw_slider = hc_draw_slider;
376 style_class->draw_hline = hc_draw_hline;
377 style_class->draw_vline = hc_draw_vline;
378 style_class->draw_expander = hc_draw_expander;
379 style_class->draw_diamond = hc_draw_diamond;
380 style_class->draw_polygon = hc_draw_polygon;
381 }
382
383 static void
hc_style_init(HcStyle * style)384 hc_style_init (HcStyle * style)
385 {
386 style->edge_thickness = floor(MIN(GTK_STYLE(style)->xthickness,GTK_STYLE(style)->ythickness));
387 style->cell_indicator_size = 12;
388 }
389
390 static void
hc_style_class_finalize(HcStyleClass * klass)391 hc_style_class_finalize (HcStyleClass *klass)
392 {
393 }
394
395 /****************/
396 /* Engine Hooks */
397 /****************/
398 GE_EXPORT void
theme_init(GTypeModule * module)399 theme_init (GTypeModule * module)
400 {
401 hc_rc_style_register_type (module);
402 hc_style_register_type (module);
403 }
404
405 GE_EXPORT void
theme_exit(void)406 theme_exit (void)
407 {
408 }
409
410 GE_EXPORT GtkRcStyle *
theme_create_rc_style(void)411 theme_create_rc_style (void)
412 {
413 return GTK_RC_STYLE (g_object_new (HC_TYPE_RC_STYLE, NULL));
414 }
415