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