]> Pileus Git - ~andy/gtk/blob - modules/engines/pixbuf/pixbuf-rc-style.c
GtkRcStyle::parse has a GtkSettings parameter now. Pass it through
[~andy/gtk] / modules / engines / pixbuf / pixbuf-rc-style.c
1 /* GTK+ Pixbuf Engine
2  * Copyright (C) 1998-2000 Red Hat, Inc.
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>, based on code by
20  * Carsten Haitzler <raster@rasterman.com>
21  */
22
23 #include "pixbuf.h"
24 #include "pixbuf-style.h"
25 #include "pixbuf-rc-style.h"
26
27 static void      pixbuf_rc_style_init         (PixbufRcStyle      *style);
28 static void      pixbuf_rc_style_class_init   (PixbufRcStyleClass *klass);
29 static void      pixbuf_rc_style_finalize     (GObject            *object);
30 static guint     pixbuf_rc_style_parse        (GtkRcStyle         *rc_style,
31                                                GtkSettings  *settings,
32                                                GScanner           *scanner);
33 static void      pixbuf_rc_style_merge        (GtkRcStyle         *dest,
34                                                GtkRcStyle         *src);
35 static GtkStyle *pixbuf_rc_style_create_style (GtkRcStyle         *rc_style);
36
37 static void theme_image_unref (ThemeImage *data);
38
39 static struct
40   {
41     gchar              *name;
42     guint               token;
43   }
44 theme_symbols[] =
45 {
46   { "image",            TOKEN_IMAGE  },
47   { "function",         TOKEN_FUNCTION },
48   { "file",             TOKEN_FILE },
49   { "stretch",          TOKEN_STRETCH },
50   { "recolorable",      TOKEN_RECOLORABLE },
51   { "border",           TOKEN_BORDER },
52   { "detail",           TOKEN_DETAIL },
53   { "state",            TOKEN_STATE },
54   { "shadow",           TOKEN_SHADOW },
55   { "gap_side",         TOKEN_GAP_SIDE },
56   { "gap_file",         TOKEN_GAP_FILE },
57   { "gap_border",       TOKEN_GAP_BORDER },
58   { "gap_start_file",   TOKEN_GAP_START_FILE },
59   { "gap_start_border", TOKEN_GAP_START_BORDER },
60   { "gap_end_file",     TOKEN_GAP_END_FILE },
61   { "gap_end_border",   TOKEN_GAP_END_BORDER },
62   { "overlay_file",     TOKEN_OVERLAY_FILE },
63   { "overlay_border",   TOKEN_OVERLAY_BORDER },
64   { "overlay_stretch",  TOKEN_OVERLAY_STRETCH },
65   { "arrow_direction",  TOKEN_ARROW_DIRECTION },
66   { "orientation",      TOKEN_ORIENTATION },
67
68   { "HLINE",            TOKEN_D_HLINE },
69   { "VLINE",            TOKEN_D_VLINE },
70   { "SHADOW",           TOKEN_D_SHADOW },
71   { "POLYGON",          TOKEN_D_POLYGON },
72   { "ARROW",            TOKEN_D_ARROW },
73   { "DIAMOND",          TOKEN_D_DIAMOND },
74   { "OVAL",             TOKEN_D_OVAL },
75   { "STRING",           TOKEN_D_STRING },
76   { "BOX",              TOKEN_D_BOX },
77   { "FLAT_BOX",         TOKEN_D_FLAT_BOX },
78   { "CHECK",            TOKEN_D_CHECK },
79   { "OPTION",           TOKEN_D_OPTION },
80   { "CROSS",            TOKEN_D_CROSS },
81   { "RAMP",             TOKEN_D_RAMP },
82   { "TAB",              TOKEN_D_TAB },
83   { "SHADOW_GAP",       TOKEN_D_SHADOW_GAP },
84   { "BOX_GAP",          TOKEN_D_BOX_GAP },
85   { "EXTENSION",        TOKEN_D_EXTENSION },
86   { "FOCUS",            TOKEN_D_FOCUS },
87   { "SLIDER",           TOKEN_D_SLIDER },
88   { "ENTRY",            TOKEN_D_ENTRY },
89   { "HANDLE",           TOKEN_D_HANDLE },
90
91   { "TRUE",             TOKEN_TRUE },
92   { "FALSE",            TOKEN_FALSE },
93
94   { "TOP",              TOKEN_TOP },
95   { "UP",               TOKEN_UP },
96   { "BOTTOM",           TOKEN_BOTTOM },
97   { "DOWN",             TOKEN_DOWN },
98   { "LEFT",             TOKEN_LEFT },
99   { "RIGHT",            TOKEN_RIGHT },
100
101   { "NORMAL",           TOKEN_NORMAL },
102   { "ACTIVE",           TOKEN_ACTIVE },
103   { "PRELIGHT",         TOKEN_PRELIGHT },
104   { "SELECTED",         TOKEN_SELECTED },
105   { "INSENSITIVE",      TOKEN_INSENSITIVE },
106
107   { "NONE",             TOKEN_NONE },
108   { "IN",               TOKEN_IN },
109   { "OUT",              TOKEN_OUT },
110   { "ETCHED_IN",        TOKEN_ETCHED_IN },
111   { "ETCHED_OUT",       TOKEN_ETCHED_OUT },
112   { "HORIZONTAL",       TOKEN_HORIZONTAL },
113   { "VERTICAL",         TOKEN_VERTICAL },
114 };
115
116 static GtkRcStyleClass *parent_class;
117
118 GType pixbuf_type_rc_style = 0;
119
120 void
121 pixbuf_rc_style_register_type (GTypeModule *module)
122 {
123   static const GTypeInfo object_info =
124   {
125     sizeof (PixbufRcStyleClass),
126     (GBaseInitFunc) NULL,
127     (GBaseFinalizeFunc) NULL,
128     (GClassInitFunc) pixbuf_rc_style_class_init,
129     NULL,           /* class_finalize */
130     NULL,           /* class_data */
131     sizeof (PixbufRcStyle),
132     0,              /* n_preallocs */
133     (GInstanceInitFunc) pixbuf_rc_style_init,
134   };
135   
136   pixbuf_type_rc_style = g_type_module_register_type (module,
137                                                       GTK_TYPE_RC_STYLE,
138                                                       "PixbufRcStyle",
139                                                       &object_info, 0);
140 }
141
142 static void
143 pixbuf_rc_style_init (PixbufRcStyle *style)
144 {
145 }
146
147 static void
148 pixbuf_rc_style_class_init (PixbufRcStyleClass *klass)
149 {
150   GtkRcStyleClass *rc_style_class = GTK_RC_STYLE_CLASS (klass);
151   GObjectClass *object_class = G_OBJECT_CLASS (klass);
152
153   parent_class = g_type_class_peek_parent (klass);
154
155   rc_style_class->parse = pixbuf_rc_style_parse;
156   rc_style_class->merge = pixbuf_rc_style_merge;
157   rc_style_class->create_style = pixbuf_rc_style_create_style;
158   
159   object_class->finalize = pixbuf_rc_style_finalize;
160 }
161
162 static void
163 pixbuf_rc_style_finalize (GObject *object)
164 {
165   PixbufRcStyle *rc_style = PIXBUF_RC_STYLE (object);
166   
167   g_list_foreach (rc_style->img_list, (GFunc) theme_image_unref, NULL);
168   g_list_free (rc_style->img_list);
169
170   G_OBJECT_CLASS (parent_class)->finalize (object);
171 }
172
173 static guint
174 theme_parse_file(GtkSettings  *settings,
175                  GScanner     *scanner,
176                  ThemePixbuf **theme_pb)
177 {
178   guint token;
179   gchar *pixmap;
180
181   /* Skip 'blah_file' */
182   token = g_scanner_get_next_token(scanner);
183
184   token = g_scanner_get_next_token(scanner);
185   if (token != G_TOKEN_EQUAL_SIGN)
186     return G_TOKEN_EQUAL_SIGN;
187
188   token = g_scanner_get_next_token(scanner);
189   if (token != G_TOKEN_STRING)
190     return G_TOKEN_STRING;
191
192   if (!*theme_pb)
193     *theme_pb = theme_pixbuf_new ();
194
195   pixmap = gtk_rc_find_pixmap_in_path(settings, scanner, scanner->value.v_string);
196   if (pixmap)
197     {
198       theme_pixbuf_set_filename (*theme_pb, pixmap);
199       g_free (pixmap);
200     }
201
202   return G_TOKEN_NONE;
203 }
204
205 static guint
206 theme_parse_border (GScanner     *scanner,
207                     ThemePixbuf **theme_pb)
208 {
209   guint               token;
210   gint left, right, top, bottom;
211
212   /* Skip 'blah_border' */
213   token = g_scanner_get_next_token(scanner);
214
215   token = g_scanner_get_next_token(scanner);
216   if (token != G_TOKEN_EQUAL_SIGN)
217     return G_TOKEN_EQUAL_SIGN;
218
219   token = g_scanner_get_next_token(scanner);
220   if (token != G_TOKEN_LEFT_CURLY)
221     return G_TOKEN_LEFT_CURLY;
222
223   token = g_scanner_get_next_token(scanner);
224   if (token != G_TOKEN_INT)
225     return G_TOKEN_INT;
226   left = scanner->value.v_int;
227   token = g_scanner_get_next_token(scanner);
228   if (token != G_TOKEN_COMMA)
229     return G_TOKEN_COMMA;
230
231   token = g_scanner_get_next_token(scanner);
232   if (token != G_TOKEN_INT)
233     return G_TOKEN_INT;
234   right = scanner->value.v_int;
235   token = g_scanner_get_next_token(scanner);
236   if (token != G_TOKEN_COMMA)
237     return G_TOKEN_COMMA;
238
239   token = g_scanner_get_next_token(scanner);
240   if (token != G_TOKEN_INT)
241     return G_TOKEN_INT;
242   top = scanner->value.v_int;
243   token = g_scanner_get_next_token(scanner);
244   if (token != G_TOKEN_COMMA)
245     return G_TOKEN_COMMA;
246
247   token = g_scanner_get_next_token(scanner);
248   if (token != G_TOKEN_INT)
249     return G_TOKEN_INT;
250   bottom = scanner->value.v_int;
251
252   token = g_scanner_get_next_token(scanner);
253   if (token != G_TOKEN_RIGHT_CURLY)
254     return G_TOKEN_RIGHT_CURLY;
255
256   if (!*theme_pb)
257     *theme_pb = theme_pixbuf_new ();
258   
259   theme_pixbuf_set_border (*theme_pb, left, right, top, bottom);
260   
261   return G_TOKEN_NONE;
262 }
263
264 static guint
265 theme_parse_stretch(GScanner     *scanner,
266                     ThemePixbuf **theme_pb)
267 {
268   guint token;
269   gboolean stretch;
270
271   /* Skip 'blah_stretch' */
272   token = g_scanner_get_next_token(scanner);
273
274   token = g_scanner_get_next_token(scanner);
275   if (token != G_TOKEN_EQUAL_SIGN)
276     return G_TOKEN_EQUAL_SIGN;
277
278   token = g_scanner_get_next_token(scanner);
279   if (token == TOKEN_TRUE)
280     stretch = TRUE;
281   else if (token == TOKEN_FALSE)
282     stretch = FALSE;
283   else
284     return TOKEN_TRUE;
285
286   if (!*theme_pb)
287     *theme_pb = theme_pixbuf_new ();
288   
289   theme_pixbuf_set_stretch (*theme_pb, stretch);
290   
291   return G_TOKEN_NONE;
292 }
293
294 static guint
295 theme_parse_recolorable(GScanner * scanner,
296                         ThemeImage * data)
297 {
298   guint               token;
299
300   token = g_scanner_get_next_token(scanner);
301   if (token != TOKEN_RECOLORABLE)
302     return TOKEN_RECOLORABLE;
303
304   token = g_scanner_get_next_token(scanner);
305   if (token != G_TOKEN_EQUAL_SIGN)
306     return G_TOKEN_EQUAL_SIGN;
307
308   token = g_scanner_get_next_token(scanner);
309   if (token == TOKEN_TRUE)
310     data->recolorable = 1;
311   else if (token == TOKEN_FALSE)
312     data->recolorable = 0;
313   else
314     return TOKEN_TRUE;
315
316   return G_TOKEN_NONE;
317 }
318
319 static guint
320 theme_parse_function(GScanner * scanner,
321                      ThemeImage *data)
322 {
323   guint               token;
324
325   token = g_scanner_get_next_token(scanner);
326   if (token != TOKEN_FUNCTION)
327     return TOKEN_FUNCTION;
328
329   token = g_scanner_get_next_token(scanner);
330   if (token != G_TOKEN_EQUAL_SIGN)
331     return G_TOKEN_EQUAL_SIGN;
332
333   token = g_scanner_get_next_token(scanner);
334   if ((token >= TOKEN_D_HLINE) && (token <= TOKEN_D_HANDLE))
335     data->match_data.function = token;
336
337   return G_TOKEN_NONE;
338 }
339
340 static guint
341 theme_parse_detail(GScanner * scanner,
342                    ThemeImage * data)
343 {
344   guint               token;
345
346   token = g_scanner_get_next_token(scanner);
347   if (token != TOKEN_DETAIL)
348     return TOKEN_DETAIL;
349
350   token = g_scanner_get_next_token(scanner);
351   if (token != G_TOKEN_EQUAL_SIGN)
352     return G_TOKEN_EQUAL_SIGN;
353
354   token = g_scanner_get_next_token(scanner);
355   if (token != G_TOKEN_STRING)
356     return G_TOKEN_STRING;
357
358   if (data->match_data.detail)
359     g_free (data->match_data.detail);
360   
361   data->match_data.detail = g_strdup(scanner->value.v_string);
362
363   return G_TOKEN_NONE;
364 }
365
366 static guint
367 theme_parse_state(GScanner * scanner,
368                   ThemeImage * data)
369 {
370   guint               token;
371
372   token = g_scanner_get_next_token(scanner);
373   if (token != TOKEN_STATE)
374     return TOKEN_STATE;
375
376   token = g_scanner_get_next_token(scanner);
377   if (token != G_TOKEN_EQUAL_SIGN)
378     return G_TOKEN_EQUAL_SIGN;
379
380   token = g_scanner_get_next_token(scanner);
381   if (token == TOKEN_NORMAL)
382     data->match_data.state = GTK_STATE_NORMAL;
383   else if (token == TOKEN_ACTIVE)
384     data->match_data.state = GTK_STATE_ACTIVE;
385   else if (token == TOKEN_PRELIGHT)
386     data->match_data.state = GTK_STATE_PRELIGHT;
387   else if (token == TOKEN_SELECTED)
388     data->match_data.state = GTK_STATE_SELECTED;
389   else if (token == TOKEN_INSENSITIVE)
390     data->match_data.state = GTK_STATE_INSENSITIVE;
391   else
392     return TOKEN_NORMAL;
393
394   data->match_data.flags |= THEME_MATCH_STATE;
395   
396   return G_TOKEN_NONE;
397 }
398
399 static guint
400 theme_parse_shadow(GScanner * scanner,
401                    ThemeImage * data)
402 {
403   guint               token;
404
405   token = g_scanner_get_next_token(scanner);
406   if (token != TOKEN_SHADOW)
407     return TOKEN_SHADOW;
408
409   token = g_scanner_get_next_token(scanner);
410   if (token != G_TOKEN_EQUAL_SIGN)
411     return G_TOKEN_EQUAL_SIGN;
412
413   token = g_scanner_get_next_token(scanner);
414   if (token == TOKEN_NONE)
415     data->match_data.shadow = GTK_SHADOW_NONE;
416   else if (token == TOKEN_IN)
417     data->match_data.shadow = GTK_SHADOW_IN;
418   else if (token == TOKEN_OUT)
419     data->match_data.shadow = GTK_SHADOW_OUT;
420   else if (token == TOKEN_ETCHED_IN)
421     data->match_data.shadow = GTK_SHADOW_ETCHED_IN;
422   else if (token == TOKEN_ETCHED_OUT)
423     data->match_data.shadow = GTK_SHADOW_ETCHED_OUT;
424   else
425     return TOKEN_NONE;
426
427   data->match_data.flags |= THEME_MATCH_SHADOW;
428   
429   return G_TOKEN_NONE;
430 }
431
432 static guint
433 theme_parse_arrow_direction(GScanner * scanner,
434                             ThemeImage * data)
435 {
436   guint               token;
437
438   token = g_scanner_get_next_token(scanner);
439   if (token != TOKEN_ARROW_DIRECTION)
440     return TOKEN_ARROW_DIRECTION;
441
442   token = g_scanner_get_next_token(scanner);
443   if (token != G_TOKEN_EQUAL_SIGN)
444     return G_TOKEN_EQUAL_SIGN;
445
446   token = g_scanner_get_next_token(scanner);
447   if (token == TOKEN_UP)
448     data->match_data.arrow_direction = GTK_ARROW_UP;
449   else if (token == TOKEN_DOWN)
450     data->match_data.arrow_direction = GTK_ARROW_DOWN;
451   else if (token == TOKEN_LEFT)
452     data->match_data.arrow_direction = GTK_ARROW_LEFT;
453   else if (token == TOKEN_RIGHT)
454     data->match_data.arrow_direction = GTK_ARROW_RIGHT;
455   else
456     return TOKEN_UP;
457
458   data->match_data.flags |= THEME_MATCH_ARROW_DIRECTION;
459   
460   return G_TOKEN_NONE;
461 }
462
463 static guint
464 theme_parse_gap_side(GScanner * scanner,
465                      ThemeImage * data)
466 {
467   guint               token;
468
469   token = g_scanner_get_next_token(scanner);
470   if (token != TOKEN_GAP_SIDE)
471     return TOKEN_GAP_SIDE;
472
473   token = g_scanner_get_next_token(scanner);
474   if (token != G_TOKEN_EQUAL_SIGN)
475     return G_TOKEN_EQUAL_SIGN;
476
477   token = g_scanner_get_next_token(scanner);
478
479   if (token == TOKEN_TOP)
480     data->match_data.gap_side = GTK_POS_TOP;
481   else if (token == TOKEN_BOTTOM)
482     data->match_data.gap_side = GTK_POS_BOTTOM;
483   else if (token == TOKEN_LEFT)
484     data->match_data.gap_side = GTK_POS_LEFT;
485   else if (token == TOKEN_RIGHT)
486     data->match_data.gap_side = GTK_POS_RIGHT;
487   else
488     return TOKEN_TOP;
489
490   data->match_data.flags |= THEME_MATCH_GAP_SIDE;
491   
492   return G_TOKEN_NONE;
493 }
494
495 static guint
496 theme_parse_orientation(GScanner * scanner,
497                         ThemeImage * data)
498 {
499   guint               token;
500
501   token = g_scanner_get_next_token(scanner);
502   if (token != TOKEN_ORIENTATION)
503     return TOKEN_ORIENTATION;
504
505   token = g_scanner_get_next_token(scanner);
506   if (token != G_TOKEN_EQUAL_SIGN)
507     return G_TOKEN_EQUAL_SIGN;
508
509   token = g_scanner_get_next_token(scanner);
510
511   if (token == TOKEN_HORIZONTAL)
512     data->match_data.orientation = GTK_ORIENTATION_HORIZONTAL;
513   else if (token == TOKEN_VERTICAL)
514     data->match_data.orientation = GTK_ORIENTATION_VERTICAL;
515   else
516     return TOKEN_HORIZONTAL;
517
518   data->match_data.flags |= THEME_MATCH_ORIENTATION;
519   
520   return G_TOKEN_NONE;
521 }
522
523 static void
524 theme_image_ref (ThemeImage *data)
525 {
526   data->refcount++;
527 }
528
529 static void
530 theme_image_unref (ThemeImage *data)
531 {
532   data->refcount--;
533   if (data->refcount == 0)
534     {
535       if (data->match_data.detail)
536         g_free (data->match_data.detail);
537       if (data->background)
538         theme_pixbuf_destroy (data->background);
539       if (data->overlay)
540         theme_pixbuf_destroy (data->overlay);
541       if (data->gap_start)
542         theme_pixbuf_destroy (data->gap_start);
543       if (data->gap)
544         theme_pixbuf_destroy (data->gap);
545       if (data->gap_end)
546         theme_pixbuf_destroy (data->gap_end);
547       g_free (data);
548     }
549 }
550
551 static guint
552 theme_parse_image(GtkSettings  *settings,
553                   GScanner      *scanner,
554                   PixbufRcStyle *pixbuf_style,
555                   ThemeImage   **data_return)
556 {
557   guint               token;
558   ThemeImage *data;
559
560   data = NULL;
561   token = g_scanner_get_next_token(scanner);
562   if (token != TOKEN_IMAGE)
563     return TOKEN_IMAGE;
564
565   token = g_scanner_get_next_token(scanner);
566   if (token != G_TOKEN_LEFT_CURLY)
567     return G_TOKEN_LEFT_CURLY;
568
569   data = g_malloc(sizeof(ThemeImage));
570
571   data->refcount = 1;
572
573   data->background = NULL;
574   data->overlay = NULL;
575   data->gap_start = NULL;
576   data->gap = NULL;
577   data->gap_end = NULL;
578
579   data->recolorable = FALSE;
580
581   data->match_data.function = 0;
582   data->match_data.detail = NULL;
583   data->match_data.flags = 0;
584
585   token = g_scanner_peek_next_token(scanner);
586   while (token != G_TOKEN_RIGHT_CURLY)
587     {
588       switch (token)
589         {
590         case TOKEN_FUNCTION:
591           token = theme_parse_function(scanner, data);
592           break;
593         case TOKEN_RECOLORABLE:
594           token = theme_parse_recolorable(scanner, data);
595           break;
596         case TOKEN_DETAIL:
597           token = theme_parse_detail(scanner, data);
598           break;
599         case TOKEN_STATE:
600           token = theme_parse_state(scanner, data);
601           break;
602         case TOKEN_SHADOW:
603           token = theme_parse_shadow(scanner, data);
604           break;
605         case TOKEN_GAP_SIDE:
606           token = theme_parse_gap_side(scanner, data);
607           break;
608         case TOKEN_ARROW_DIRECTION:
609           token = theme_parse_arrow_direction(scanner, data);
610           break;
611         case TOKEN_ORIENTATION:
612           token = theme_parse_orientation(scanner, data);
613           break;
614         case TOKEN_FILE:
615           token = theme_parse_file(settings, scanner, &data->background);
616           break;
617         case TOKEN_BORDER:
618           token = theme_parse_border(scanner, &data->background);
619           break;
620         case TOKEN_STRETCH:
621           token = theme_parse_stretch(scanner, &data->background);
622           break;
623         case TOKEN_GAP_FILE:
624           token = theme_parse_file(settings, scanner, &data->gap);
625           break;
626         case TOKEN_GAP_BORDER:
627           token = theme_parse_border(scanner, &data->gap);
628           break;
629         case TOKEN_GAP_START_FILE:
630           token = theme_parse_file(settings, scanner, &data->gap_start);
631           break;
632         case TOKEN_GAP_START_BORDER:
633           token = theme_parse_border(scanner, &data->gap_start);
634           break;
635         case TOKEN_GAP_END_FILE:
636           token = theme_parse_file(settings, scanner, &data->gap_end);
637           break;
638         case TOKEN_GAP_END_BORDER:
639           token = theme_parse_border(scanner, &data->gap_end);
640           break;
641         case TOKEN_OVERLAY_FILE:
642           token = theme_parse_file(settings, scanner, &data->overlay);
643           break;
644         case TOKEN_OVERLAY_BORDER:
645           token = theme_parse_border(scanner, &data->overlay);
646           break;
647         case TOKEN_OVERLAY_STRETCH:
648           token = theme_parse_stretch(scanner, &data->overlay);
649           break;
650         default:
651           g_scanner_get_next_token(scanner);
652           token = G_TOKEN_RIGHT_CURLY;
653           break;
654         }
655       if (token != G_TOKEN_NONE)
656         {
657           /* error - cleanup for exit */
658           theme_image_unref (data);
659           *data_return = NULL;
660           return token;
661         }
662       token = g_scanner_peek_next_token(scanner);
663     }
664
665   token = g_scanner_get_next_token(scanner);
666
667   if (token != G_TOKEN_RIGHT_CURLY)
668     {
669       /* error - cleanup for exit */
670       theme_image_unref (data);
671       *data_return = NULL;
672       return G_TOKEN_RIGHT_CURLY;
673     }
674
675   /* everything is fine now - insert yer cruft */
676   *data_return = data;
677   return G_TOKEN_NONE;
678 }
679
680 static guint
681 pixbuf_rc_style_parse (GtkRcStyle *rc_style,
682                        GtkSettings  *settings,
683                        GScanner   *scanner)
684                      
685 {
686   static GQuark scope_id = 0;
687   PixbufRcStyle *pixbuf_style = PIXBUF_RC_STYLE (rc_style);
688
689   guint old_scope;
690   guint token;
691   gint i;
692   ThemeImage *img;
693   
694   /* Set up a new scope in this scanner. */
695
696   if (!scope_id)
697     scope_id = g_quark_from_string("pixbuf_theme_engine");
698
699   /* If we bail out due to errors, we *don't* reset the scope, so the
700    * error messaging code can make sense of our tokens.
701    */
702   old_scope = g_scanner_set_scope(scanner, scope_id);
703
704   /* Now check if we already added our symbols to this scope
705    * (in some previous call to theme_parse_rc_style for the
706    * same scanner.
707    */
708
709   if (!g_scanner_lookup_symbol(scanner, theme_symbols[0].name))
710     {
711       g_scanner_freeze_symbol_table(scanner);
712       for (i = 0; i < G_N_ELEMENTS (theme_symbols); i++)
713         g_scanner_scope_add_symbol(scanner, scope_id,
714                                    theme_symbols[i].name,
715                                    GINT_TO_POINTER(theme_symbols[i].token));
716       g_scanner_thaw_symbol_table(scanner);
717     }
718
719   /* We're ready to go, now parse the top level */
720
721   token = g_scanner_peek_next_token(scanner);
722   while (token != G_TOKEN_RIGHT_CURLY)
723     {
724       switch (token)
725         {
726         case TOKEN_IMAGE:
727           img = NULL;
728           token = theme_parse_image(settings, scanner, pixbuf_style, &img);
729           break;
730         default:
731           g_scanner_get_next_token(scanner);
732           token = G_TOKEN_RIGHT_CURLY;
733           break;
734         }
735
736       if (token != G_TOKEN_NONE)
737         return token;
738       else
739         pixbuf_style->img_list = g_list_append(pixbuf_style->img_list, img);
740
741       token = g_scanner_peek_next_token(scanner);
742     }
743
744   g_scanner_get_next_token(scanner);
745
746   g_scanner_set_scope(scanner, old_scope);
747
748   return G_TOKEN_NONE;
749 }
750
751 static void
752 pixbuf_rc_style_merge (GtkRcStyle *dest,
753                        GtkRcStyle *src)
754 {
755   if (PIXBUF_IS_RC_STYLE (src))
756     {
757       PixbufRcStyle *pixbuf_dest = PIXBUF_RC_STYLE (dest);
758       PixbufRcStyle *pixbuf_src = PIXBUF_RC_STYLE (src);
759       GList *tmp_list1, *tmp_list2;
760       
761       if (pixbuf_src->img_list)
762         {
763           /* Copy src image list and append to dest image list */
764           
765           tmp_list2 = g_list_last (pixbuf_dest->img_list);
766           tmp_list1 = pixbuf_src->img_list;
767           
768           while (tmp_list1)
769             {
770               if (tmp_list2)
771                 {
772                   tmp_list2->next = g_list_alloc();
773                   tmp_list2->next->data = tmp_list1->data;
774                   tmp_list2->next->prev = tmp_list2;
775                   
776                   tmp_list2 = tmp_list2->next;
777                 }
778               else
779                 {
780                   pixbuf_dest->img_list = g_list_append (NULL, tmp_list1->data);
781                   tmp_list2 = pixbuf_dest->img_list;
782                 }
783               
784               theme_image_ref (tmp_list1->data);
785               tmp_list1 = tmp_list1->next;
786             }
787         }
788     }
789
790   parent_class->merge (dest, src);
791 }
792
793 /* Create an empty style suitable to this RC style
794  */
795 static GtkStyle *
796 pixbuf_rc_style_create_style (GtkRcStyle *rc_style)
797 {
798   return GTK_STYLE (g_object_new (PIXBUF_TYPE_STYLE, NULL));
799 }
800