f486453339c31bb77006d1153b4d128f0e7eb4c0
[ardour.git] / libs / clearlooks / clearlooks_rc_style.c
1 /* Clearlooks theme engine
2  * Copyright (C) 2005 Richard Stellingwerff.
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  * Written by Owen Taylor <otaylor@redhat.com>
20  * and by Alexander Larsson <alexl@redhat.com>
21  * Modified by Richard Stellingwerff <remenic@gmail.com>
22  * Modified by Kulyk Nazar <schamane@myeburg.net>
23  */
24
25 #include "clearlooks_style.h"
26 #include "clearlooks_rc_style.h"
27
28 #include "animation.h"
29
30 static void      clearlooks_rc_style_init         (ClearlooksRcStyle      *style);
31 #ifdef HAVE_ANIMATION
32 static void      clearlooks_rc_style_finalize     (GObject                *object);
33 #endif
34 static void      clearlooks_rc_style_class_init   (ClearlooksRcStyleClass *klass);
35 static GtkStyle *clearlooks_rc_style_create_style (GtkRcStyle             *rc_style);
36 static guint     clearlooks_rc_style_parse        (GtkRcStyle             *rc_style,
37                                                    GtkSettings            *settings,
38                                                    GScanner               *scanner);
39 static void      clearlooks_rc_style_merge        (GtkRcStyle             *dest,
40                                                    GtkRcStyle             *src);
41
42
43 static GtkRcStyleClass *clearlooks_parent_rc_class;
44
45 GType clearlooks_type_rc_style = 0;
46
47 enum
48 {
49         TOKEN_SCROLLBARCOLOR = G_TOKEN_LAST + 1,
50         TOKEN_COLORIZESCROLLBAR,
51         TOKEN_CONTRAST,
52         TOKEN_SUNKENMENU,
53         TOKEN_PROGRESSBARSTYLE,
54         TOKEN_MENUBARSTYLE,
55         TOKEN_TOOLBARSTYLE,
56         TOKEN_MENUITEMSTYLE,
57         TOKEN_LISTVIEWITEMSTYLE,
58         TOKEN_ANIMATION,
59         TOKEN_STYLE,
60         TOKEN_RADIUS,
61
62         TOKEN_CLASSIC,
63         TOKEN_GLOSSY,
64         TOKEN_INVERTED,
65         TOKEN_GUMMY,
66
67         TOKEN_TRUE,
68         TOKEN_FALSE
69 };
70
71 static struct
72 {
73         const gchar        *name;
74         guint               token;
75 }
76 clearlooks_gtk2_rc_symbols[] =
77 {
78         { "scrollbar_color",    TOKEN_SCROLLBARCOLOR  },
79         { "colorize_scrollbar", TOKEN_COLORIZESCROLLBAR },
80         { "contrast",           TOKEN_CONTRAST  },
81         { "sunkenmenubar",      TOKEN_SUNKENMENU },
82         { "progressbarstyle",   TOKEN_PROGRESSBARSTYLE },
83         { "menubarstyle",       TOKEN_MENUBARSTYLE }, 
84         { "toolbarstyle",       TOKEN_TOOLBARSTYLE },
85         { "menuitemstyle",      TOKEN_MENUITEMSTYLE },
86         { "listviewitemstyle",  TOKEN_LISTVIEWITEMSTYLE },
87         { "animation",          TOKEN_ANIMATION },
88         { "style",              TOKEN_STYLE },
89         { "radius",             TOKEN_RADIUS },
90
91         { "CLASSIC",            TOKEN_CLASSIC },
92         { "GLOSSY",             TOKEN_GLOSSY },
93         { "INVERTED",           TOKEN_INVERTED },
94         { "GUMMY",              TOKEN_GUMMY },
95
96         { "TRUE",               TOKEN_TRUE },
97         { "FALSE",              TOKEN_FALSE }
98 };
99
100
101 void
102 clearlooks_rc_style_register_type (GTypeModule *module)
103 {
104         static const GTypeInfo object_info =
105         {
106                 sizeof (ClearlooksRcStyleClass),
107                 (GBaseInitFunc) NULL,
108                 (GBaseFinalizeFunc) NULL,
109                 (GClassInitFunc) clearlooks_rc_style_class_init,
110                 NULL,           /* class_finalize */
111                 NULL,           /* class_data */
112                 sizeof (ClearlooksRcStyle),
113                 0,              /* n_preallocs */
114                 (GInstanceInitFunc) clearlooks_rc_style_init,
115                 NULL
116         };
117
118         clearlooks_type_rc_style = g_type_module_register_type (module,
119                                                      GTK_TYPE_RC_STYLE,
120                                                      "ClearlooksRcStyle",
121                                                      &object_info, 0);
122 }
123
124 static void
125 clearlooks_rc_style_init (ClearlooksRcStyle *clearlooks_rc)
126 {
127         clearlooks_rc->style = CL_STYLE_CLASSIC;
128
129         clearlooks_rc->flags = 0;
130
131         clearlooks_rc->contrast = 1.0;
132         clearlooks_rc->menubarstyle = 0;
133         clearlooks_rc->toolbarstyle = 0;
134         clearlooks_rc->animation = FALSE;
135         clearlooks_rc->colorize_scrollbar = FALSE;
136         clearlooks_rc->radius = 3.0;
137 }
138
139 #ifdef HAVE_ANIMATION
140 static void
141 clearlooks_rc_style_finalize (GObject *object)
142 {
143         /* cleanup all the animation stuff */
144         clearlooks_animation_cleanup ();
145
146         if (G_OBJECT_CLASS (clearlooks_parent_rc_class)->finalize != NULL)
147                 G_OBJECT_CLASS (clearlooks_parent_rc_class)->finalize(object);
148 }
149 #endif
150
151
152 static void
153 clearlooks_rc_style_class_init (ClearlooksRcStyleClass *klass)
154 {
155         GtkRcStyleClass *rc_style_class = GTK_RC_STYLE_CLASS (klass);
156 #ifdef HAVE_ANIMATION
157         GObjectClass    *g_object_class = G_OBJECT_CLASS (klass);
158 #endif
159
160         clearlooks_parent_rc_class = g_type_class_peek_parent (klass);
161
162         rc_style_class->parse = clearlooks_rc_style_parse;
163         rc_style_class->create_style = clearlooks_rc_style_create_style;
164         rc_style_class->merge = clearlooks_rc_style_merge;
165
166 #ifdef HAVE_ANIMATION
167         g_object_class->finalize = clearlooks_rc_style_finalize;
168 #endif
169 }
170
171 static guint
172 clearlooks_gtk2_rc_parse_boolean (GtkSettings *settings,
173                      GScanner     *scanner,
174                      gboolean *retval)
175 {
176         guint token;
177         token = g_scanner_get_next_token(scanner);
178
179         token = g_scanner_get_next_token(scanner);
180         if (token != G_TOKEN_EQUAL_SIGN)
181            return G_TOKEN_EQUAL_SIGN;
182
183         token = g_scanner_get_next_token(scanner);
184         if (token == TOKEN_TRUE)
185            *retval = TRUE;
186         else if (token == TOKEN_FALSE)
187            *retval = FALSE;
188         else
189            return TOKEN_TRUE;
190
191         return G_TOKEN_NONE;
192 }
193
194 static guint
195 clearlooks_gtk2_rc_parse_color(GtkSettings  *settings,
196                   GScanner     *scanner,
197                   GdkColor     *color)
198 {
199         guint token;
200
201         /* Skip 'blah_color' */
202         token = g_scanner_get_next_token(scanner);
203
204         token = g_scanner_get_next_token(scanner);
205         if (token != G_TOKEN_EQUAL_SIGN)
206            return G_TOKEN_EQUAL_SIGN;
207
208         return gtk_rc_parse_color (scanner, color);
209 }
210
211 static guint
212 clearlooks_gtk2_rc_parse_double (GtkSettings  *settings,
213                                  GScanner     *scanner,
214                                  gdouble      *val)
215 {
216         guint token;
217
218         /* Skip 'blah' */
219         token = g_scanner_get_next_token(scanner);
220
221         token = g_scanner_get_next_token(scanner);
222         if (token != G_TOKEN_EQUAL_SIGN)
223            return G_TOKEN_EQUAL_SIGN;
224
225         token = g_scanner_get_next_token(scanner);
226         if (token != G_TOKEN_FLOAT)
227            return G_TOKEN_FLOAT;
228
229         *val = scanner->value.v_float;
230
231         return G_TOKEN_NONE;
232 }
233
234 static guint
235 clearlooks_gtk2_rc_parse_int (GtkSettings  *settings,
236                          GScanner     *scanner,
237                          guint8       *progressbarstyle)
238 {
239         guint token;
240
241         /* Skip 'sunkenmenubar' */
242         token = g_scanner_get_next_token(scanner);
243
244         token = g_scanner_get_next_token(scanner);
245         if (token != G_TOKEN_EQUAL_SIGN)
246            return G_TOKEN_EQUAL_SIGN;
247
248         token = g_scanner_get_next_token(scanner);
249         if (token != G_TOKEN_INT)
250            return G_TOKEN_INT;
251
252         *progressbarstyle = scanner->value.v_int;
253
254         return G_TOKEN_NONE;
255 }
256
257 static guint
258 clearlooks_gtk2_rc_parse_style (GtkSettings      *settings,
259                                 GScanner         *scanner,
260                                 ClearlooksStyles *style)
261 {
262         guint token;
263
264         g_assert (CL_NUM_STYLES == CL_STYLE_GUMMY + 1); /* so that people don't forget ;-) */
265
266         /* Skip 'style' */
267         token = g_scanner_get_next_token (scanner);
268
269         token = g_scanner_get_next_token (scanner);
270         if (token != G_TOKEN_EQUAL_SIGN)
271            return G_TOKEN_EQUAL_SIGN;
272
273         token = g_scanner_get_next_token (scanner);
274   
275         switch (token)
276         {
277                 case TOKEN_CLASSIC:
278                    *style = CL_STYLE_CLASSIC;
279                    break;
280                 case TOKEN_GLOSSY:
281                    *style = CL_STYLE_GLOSSY;
282                    break;
283                 case TOKEN_INVERTED:
284                    *style = CL_STYLE_INVERTED;
285                    break;
286                 case TOKEN_GUMMY:
287                    *style = CL_STYLE_GUMMY;
288                    break;
289                 default:
290                    return TOKEN_CLASSIC;
291         }
292
293         return G_TOKEN_NONE;
294 }
295
296 static guint
297 clearlooks_gtk2_rc_parse_dummy (GtkSettings      *settings,
298                                 GScanner         *scanner,
299                                 gchar            *name)
300 {
301         guint token;
302
303         /* Skip option */
304         token = g_scanner_get_next_token (scanner);
305
306         /* print a warning. Isn't there a way to get the string from the scanner? */
307         g_scanner_warn (scanner, "Clearlooks configuration option \"%s\" is not supported and will be ignored.", name);
308
309         /* equal sign */
310         token = g_scanner_get_next_token (scanner);
311         if (token != G_TOKEN_EQUAL_SIGN)
312            return G_TOKEN_EQUAL_SIGN;
313
314         /* eat whatever comes next */
315         token = g_scanner_get_next_token (scanner);
316
317         return G_TOKEN_NONE;
318 }
319
320 static guint
321 clearlooks_rc_style_parse (GtkRcStyle *rc_style,
322                            GtkSettings  *settings,
323                            GScanner   *scanner)
324                      
325 {
326         static GQuark scope_id = 0;
327         ClearlooksRcStyle *clearlooks_style = CLEARLOOKS_RC_STYLE (rc_style);
328
329         guint old_scope;
330         guint token;
331         guint i;
332
333         /* Set up a new scope in this scanner. */
334
335         if (!scope_id)
336            scope_id = g_quark_from_string("clearlooks_theme_engine");
337
338         /* If we bail out due to errors, we *don't* reset the scope, so the
339         * error messaging code can make sense of our tokens.
340         */
341         old_scope = g_scanner_set_scope(scanner, scope_id);
342
343         /* Now check if we already added our symbols to this scope
344         * (in some previous call to clearlooks_rc_style_parse for the
345         * same scanner.
346         */
347
348         if (!g_scanner_lookup_symbol(scanner, clearlooks_gtk2_rc_symbols[0].name))
349         {
350                 for (i = 0; i < G_N_ELEMENTS (clearlooks_gtk2_rc_symbols); i++)
351                         g_scanner_scope_add_symbol(scanner, scope_id,
352                                         clearlooks_gtk2_rc_symbols[i].name,
353                                         GINT_TO_POINTER(clearlooks_gtk2_rc_symbols[i].token));
354         }
355
356         /* We're ready to go, now parse the top level */
357
358         token = g_scanner_peek_next_token(scanner);
359         while (token != G_TOKEN_RIGHT_CURLY)
360         {
361                 switch (token)
362                 {
363                         case TOKEN_SCROLLBARCOLOR:
364                                 token = clearlooks_gtk2_rc_parse_color (settings, scanner, &clearlooks_style->scrollbar_color);
365                                 clearlooks_style->flags |= CL_FLAG_SCROLLBAR_COLOR;
366                                 break;
367                         case TOKEN_COLORIZESCROLLBAR:
368                                 token = clearlooks_gtk2_rc_parse_boolean (settings, scanner, &clearlooks_style->colorize_scrollbar);
369                                 clearlooks_style->flags |= CL_FLAG_COLORIZE_SCROLLBAR;
370                                 break;
371                         case TOKEN_CONTRAST:
372                                 token = clearlooks_gtk2_rc_parse_double (settings, scanner, &clearlooks_style->contrast);
373                                 clearlooks_style->flags |= CL_FLAG_CONTRAST;
374                                 break;
375                         case TOKEN_MENUBARSTYLE:
376                                 token = clearlooks_gtk2_rc_parse_int (settings, scanner, &clearlooks_style->menubarstyle);
377                                 clearlooks_style->flags |= CL_FLAG_MENUBARSTYLE;
378                                 break;
379                         case TOKEN_TOOLBARSTYLE:
380                                 token = clearlooks_gtk2_rc_parse_int (settings, scanner, &clearlooks_style->toolbarstyle);
381                                 clearlooks_style->flags |= CL_FLAG_TOOLBARSTYLE;
382                                 break;
383                         case TOKEN_ANIMATION:
384                                 token = clearlooks_gtk2_rc_parse_boolean (settings, scanner, &clearlooks_style->animation);
385                                 clearlooks_style->flags |= CL_FLAG_ANIMATION;
386                                 break;
387                         case TOKEN_STYLE:
388                                 token = clearlooks_gtk2_rc_parse_style (settings, scanner, &clearlooks_style->style);
389                                 clearlooks_style->flags |= CL_FLAG_STYLE;
390                                 break;
391                         case TOKEN_RADIUS:
392                                 token = clearlooks_gtk2_rc_parse_double (settings, scanner, &clearlooks_style->radius);
393                                 clearlooks_style->flags |= CL_FLAG_RADIUS;
394                                 break;
395
396                         /* stuff to ignore */
397                         case TOKEN_SUNKENMENU:
398                                 token = clearlooks_gtk2_rc_parse_dummy (settings, scanner, "sunkenmenu");
399                                 break;
400                         case TOKEN_PROGRESSBARSTYLE:
401                                 token = clearlooks_gtk2_rc_parse_dummy (settings, scanner, "progressbarstyle");
402                                 break;
403                         case TOKEN_MENUITEMSTYLE:
404                                 token = clearlooks_gtk2_rc_parse_dummy (settings, scanner, "menuitemstyle");
405                                 break;
406                         case TOKEN_LISTVIEWITEMSTYLE:
407                                 token = clearlooks_gtk2_rc_parse_dummy (settings, scanner, "listviewitemstyle");
408                                 break;
409
410                         default:
411                                 g_scanner_get_next_token(scanner);
412                                 token = G_TOKEN_RIGHT_CURLY;
413                                 break;
414                 }
415
416                 if (token != G_TOKEN_NONE)
417                         return token;
418
419                 token = g_scanner_peek_next_token(scanner);
420         }
421
422         g_scanner_get_next_token(scanner);
423
424         g_scanner_set_scope(scanner, old_scope);
425
426         return G_TOKEN_NONE;
427 }
428
429 static void
430 clearlooks_rc_style_merge (GtkRcStyle *dest,
431                            GtkRcStyle *src)
432 {
433         ClearlooksRcStyle *dest_w, *src_w;
434         ClearlooksRcFlags flags;
435
436         clearlooks_parent_rc_class->merge (dest, src);
437
438         if (!CLEARLOOKS_IS_RC_STYLE (src))
439                 return;
440
441         src_w = CLEARLOOKS_RC_STYLE (src);
442         dest_w = CLEARLOOKS_RC_STYLE (dest);
443
444         flags = (~dest_w->flags) & src_w->flags;
445
446         if (flags & CL_FLAG_STYLE)
447                 dest_w->style = src_w->style;
448         if (flags & CL_FLAG_CONTRAST)
449                 dest_w->contrast = src_w->contrast;
450         if (flags & CL_FLAG_MENUBARSTYLE)
451                 dest_w->menubarstyle = src_w->menubarstyle;
452         if (flags & CL_FLAG_TOOLBARSTYLE)
453                 dest_w->toolbarstyle = src_w->toolbarstyle;
454         if (flags & CL_FLAG_SCROLLBAR_COLOR)
455                 dest_w->scrollbar_color = src_w->scrollbar_color;
456         if (flags & CL_FLAG_COLORIZE_SCROLLBAR)
457                 dest_w->colorize_scrollbar = src_w->colorize_scrollbar;
458         if (flags & CL_FLAG_ANIMATION)
459                 dest_w->animation = src_w->animation;
460         if (flags & CL_FLAG_RADIUS)
461                 dest_w->radius = src_w->radius;
462
463         dest_w->flags |= src_w->flags;
464 }
465
466
467 /* Create an empty style suitable to this RC style
468  */
469 static GtkStyle *
470 clearlooks_rc_style_create_style (GtkRcStyle *rc_style)
471 {
472         return GTK_STYLE (g_object_new (CLEARLOOKS_TYPE_STYLE, NULL));
473 }