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