]> Pileus Git - ~andy/gtk/blob - gtk/gtkrc.c
changed scrolled window inheritance, it inherits from GtkBin now.
[~andy/gtk] / gtk / gtkrc.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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 #include <ctype.h>
20 #include <unistd.h>
21 #include <sys/stat.h>
22 #include <sys/param.h>
23 #include <fcntl.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include "gtkrc.h"
27 #include "gtkbindings.h"
28 #include "gtkthemes.h"
29
30 typedef struct _GtkRcSet    GtkRcSet;
31 typedef struct _GtkRcNode   GtkRcNode;
32 typedef struct _GtkRcFile   GtkRcFile;
33
34 struct _GtkRcSet
35 {
36   GtkPatternSpec pspec;
37   GtkRcStyle    *rc_style;
38 };
39
40 struct _GtkRcFile
41 {
42   time_t mtime;
43   gchar *name;
44   gchar *canonical_name;
45   gboolean reload;
46 };
47
48 static guint       gtk_rc_style_hash               (const char   *name);
49 static gint        gtk_rc_style_compare            (const char   *a,
50                                                     const char   *b);
51 static guint       gtk_rc_styles_hash              (const GSList *rc_styles);
52 static gint        gtk_rc_styles_compare           (const GSList *a,
53                                                     const GSList *b);
54 static GtkRcStyle* gtk_rc_style_find               (const char   *name);
55 static GSList *    gtk_rc_styles_match             (GSList       *rc_styles,
56                                                     GSList       *sets,
57                                                     guint         path_length,
58                                                     gchar        *path,
59                                                     gchar        *path_reversed);
60 static GtkStyle *  gtk_rc_style_to_style           (GtkRcStyle   *rc_style);
61 static GtkStyle*   gtk_rc_style_init               (GSList       *rc_styles);
62 static void        gtk_rc_parse_file               (const gchar  *filename,
63                                                     gboolean      reload);
64
65 static void        gtk_rc_parse_any                (const gchar  *input_name,
66                                                     gint          input_fd,
67                                                     const gchar  *input_string);
68 static guint       gtk_rc_parse_statement          (GScanner     *scanner);
69 static guint       gtk_rc_parse_style              (GScanner     *scanner);
70 static guint       gtk_rc_parse_base               (GScanner     *scanner,
71                                                     GtkRcStyle   *style);
72 static guint       gtk_rc_parse_bg                 (GScanner     *scanner,
73                                                     GtkRcStyle   *style);
74 static guint       gtk_rc_parse_fg                 (GScanner     *scanner,
75                                                     GtkRcStyle   *style);
76 static guint       gtk_rc_parse_text               (GScanner     *scanner,
77                                                     GtkRcStyle   *style);
78 static guint       gtk_rc_parse_bg_pixmap          (GScanner     *scanner,
79                                                     GtkRcStyle   *rc_style);
80 static guint       gtk_rc_parse_font               (GScanner     *scanner,
81                                                     GtkRcStyle   *rc_style);
82 static guint       gtk_rc_parse_fontset            (GScanner     *scanner,
83                                                     GtkRcStyle   *rc_style);
84 static guint       gtk_rc_parse_engine             (GScanner     *scanner,
85                                                     GtkRcStyle   *rc_style);
86 static guint       gtk_rc_parse_pixmap_path        (GScanner     *scanner);
87 static void        gtk_rc_parse_pixmap_path_string (gchar *pix_path);
88 static guint       gtk_rc_parse_module_path        (GScanner     *scanner);
89 static void        gtk_rc_parse_module_path_string (gchar *mod_path);
90 static guint       gtk_rc_parse_path_pattern       (GScanner     *scanner);
91 static void        gtk_rc_clear_hash_node          (gpointer   key, 
92                                                     gpointer   data, 
93                                                     gpointer   user_data);
94 static void        gtk_rc_clear_styles               (void);
95 static void        gtk_rc_append_default_pixmap_path (void);
96 static void        gtk_rc_append_default_module_path (void);
97 static void        gtk_rc_append_pixmap_path         (gchar *dir);
98
99
100 static  GScannerConfig  gtk_rc_scanner_config =
101 {
102   (
103    " \t\n"
104    )                    /* cset_skip_characters */,
105   (
106    G_CSET_a_2_z
107    "_"
108    G_CSET_A_2_Z
109    )                    /* cset_identifier_first */,
110   (
111    G_CSET_a_2_z
112    "_-0123456789"
113    G_CSET_A_2_Z
114    )                    /* cset_identifier_nth */,
115   ( "#\n" )             /* cpair_comment_single */,
116   
117   TRUE                  /* case_sensitive */,
118   
119   TRUE                  /* skip_comment_multi */,
120   TRUE                  /* skip_comment_single */,
121   TRUE                  /* scan_comment_multi */,
122   TRUE                  /* scan_identifier */,
123   FALSE                 /* scan_identifier_1char */,
124   FALSE                 /* scan_identifier_NULL */,
125   TRUE                  /* scan_symbols */,
126   TRUE                  /* scan_binary */,
127   TRUE                  /* scan_octal */,
128   TRUE                  /* scan_float */,
129   TRUE                  /* scan_hex */,
130   TRUE                  /* scan_hex_dollar */,
131   TRUE                  /* scan_string_sq */,
132   TRUE                  /* scan_string_dq */,
133   TRUE                  /* numbers_2_int */,
134   FALSE                 /* int_2_float */,
135   FALSE                 /* identifier_2_string */,
136   TRUE                  /* char_2_token */,
137   TRUE                  /* symbol_2_token */,
138   FALSE                 /* scope_0_fallback */,
139 };
140
141 static struct
142 {
143   gchar *name;
144   guint token;
145 } symbols[] = {
146   { "include", GTK_RC_TOKEN_INCLUDE },
147   { "NORMAL", GTK_RC_TOKEN_NORMAL },
148   { "ACTIVE", GTK_RC_TOKEN_ACTIVE },
149   { "PRELIGHT", GTK_RC_TOKEN_PRELIGHT },
150   { "SELECTED", GTK_RC_TOKEN_SELECTED },
151   { "INSENSITIVE", GTK_RC_TOKEN_INSENSITIVE },
152   { "fg", GTK_RC_TOKEN_FG },
153   { "bg", GTK_RC_TOKEN_BG },
154   { "base", GTK_RC_TOKEN_BASE },
155   { "text", GTK_RC_TOKEN_TEXT },
156   { "font", GTK_RC_TOKEN_FONT },
157   { "fontset", GTK_RC_TOKEN_FONTSET },
158   { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP },
159   { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH },
160   { "style", GTK_RC_TOKEN_STYLE },
161   { "binding", GTK_RC_TOKEN_BINDING },
162   { "bind", GTK_RC_TOKEN_BIND },
163   { "widget", GTK_RC_TOKEN_WIDGET },
164   { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS },
165   { "class", GTK_RC_TOKEN_CLASS },
166   { "lowest", GTK_RC_TOKEN_LOWEST },
167   { "gtk", GTK_RC_TOKEN_GTK },
168   { "application", GTK_RC_TOKEN_APPLICATION },
169   { "rc", GTK_RC_TOKEN_RC },
170   { "highest", GTK_RC_TOKEN_HIGHEST },
171   { "engine", GTK_RC_TOKEN_ENGINE },
172   { "module_path", GTK_RC_TOKEN_MODULE_PATH },
173 };
174
175 static guint n_symbols = sizeof (symbols) / sizeof (symbols[0]);
176
177 static GHashTable *rc_style_ht = NULL;
178 static GHashTable *realized_style_ht = NULL;
179 static GSList *gtk_rc_sets_widget = NULL;
180 static GSList *gtk_rc_sets_widget_class = NULL;
181 static GSList *gtk_rc_sets_class = NULL;
182
183 #define GTK_RC_MAX_PIXMAP_PATHS 128
184 static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
185 #define GTK_RC_MAX_MODULE_PATHS 128
186 static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
187
188 /* The files we have parsed, to reread later if necessary */
189 GSList *rc_files = NULL;
190
191 static GtkImageLoader image_loader = NULL;
192
193 /* RC file handling */
194
195
196 gchar *
197 gtk_rc_get_theme_dir(void)
198 {
199   gchar *var, *path;
200
201   var = getenv("GTK_DATA_PREFIX");
202   if (var)
203     {
204       path = g_malloc(strlen(var) + strlen("/share/themes") +1);
205       sprintf(path, "%s%s", var, "/share/themes");
206     }
207   else
208     {
209       path = g_malloc(strlen(GTK_DATA_PREFIX) + strlen("/share/themes") +1);
210       sprintf(path, "%s%s", GTK_DATA_PREFIX, "/share/themes");
211     }
212   return path;
213 }
214
215 gchar *
216 gtk_rc_get_module_dir(void)
217 {
218   gchar *var, *path;
219
220   var = getenv("GTK_EXE_PREFIX");
221   if (var)
222     {
223       path = g_malloc(strlen(var) + strlen("/lib/gtk/themes/engines") +1);
224       sprintf(path, "%s%s", var, "/lib/gtk/themes/engines");
225     }
226   else
227     {
228       path = g_malloc(strlen(GTK_EXE_PREFIX) + strlen("/lib/gtk/themes/engines") +1);
229       sprintf(path, "%s%s", GTK_EXE_PREFIX, "/lib/gtk/themes/engines");
230     }
231   return path;
232 }
233
234 static void
235 gtk_rc_append_default_pixmap_path(void)
236 {
237   gchar *var, *path;
238   gint n;
239
240   var = getenv("GTK_DATA_PREFIX");
241   if (var)
242     {
243       path = g_malloc(strlen(var) + strlen("/share/gtk/themes") +1);
244       sprintf(path, "%s%s", var, "/share/gtk/themes");
245     }
246   else
247     {
248       path = g_malloc(strlen(GTK_DATA_PREFIX) + strlen("/share/gtk/themes") +1);
249       sprintf(path, "%s%s", GTK_DATA_PREFIX, "/share/gtk/themes");
250     }
251   
252   for (n = 0; pixmap_path[n]; n++) ;
253   if (n >= GTK_RC_MAX_PIXMAP_PATHS - 1)
254     return;
255   pixmap_path[n++] = g_strdup(path);
256   pixmap_path[n] = NULL;
257   g_free(path);
258 }
259
260 static void
261 gtk_rc_append_pixmap_path(gchar *dir)
262 {
263   gint n;
264
265   for (n = 0; pixmap_path[n]; n++) ;
266   if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
267     return;
268   pixmap_path[n++] = g_strdup(dir);
269   pixmap_path[n] = NULL;
270 }
271
272 static void
273 gtk_rc_append_default_module_path(void)
274 {
275   gchar *var, *path;
276   gint n;
277
278   for (n = 0; module_path[n]; n++) ;
279   if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
280     return;
281   
282   var = getenv("GTK_EXE_PREFIX");
283   if (var)
284     {
285       path = g_malloc(strlen(var) + strlen("/lib/gtk/themes/engines") +1);
286       sprintf(path, "%s%s", var, "/lib/gtk/themes/engines");
287     }
288   else
289     {
290       path = g_malloc(strlen(GTK_EXE_PREFIX) + strlen("/lib/gtk/themes/engines") +1);
291       sprintf(path, "%s%s", GTK_EXE_PREFIX, "/lib/gtk/themes/engines");
292     }
293   module_path[n++] = g_strdup(path);
294   g_free(path);
295   var = getenv("HOME");
296   if (var)
297     {
298       path = g_malloc(strlen(var) + strlen(".gtk/lib/themes/engines") +1);
299       sprintf(path, "%s%s", var, ".gtk/lib/themes/engines");
300     }
301   module_path[n++] = g_strdup(path);
302   module_path[n] = NULL;
303   g_free(path);
304 }
305
306 void
307 gtk_rc_init (void)
308 {
309   rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
310                                   (GCompareFunc) gtk_rc_style_compare);
311   pixmap_path[0] = NULL;
312   module_path[0] = NULL;
313   gtk_rc_append_default_pixmap_path();
314   gtk_rc_append_default_module_path();
315 }
316
317 void
318 gtk_rc_parse_string (const gchar *rc_string)
319 {
320   g_return_if_fail (rc_string != NULL);
321
322   gtk_rc_parse_any ("-", -1, rc_string);
323 }
324
325 static void
326 gtk_rc_parse_file (const gchar *filename, gboolean reload)
327 {
328   GtkRcFile *rc_file = NULL;
329   struct stat statbuf;
330   GSList *tmp_list;
331
332   g_return_if_fail (filename != NULL);
333
334   tmp_list = rc_files;
335   while (tmp_list)
336     {
337       rc_file = tmp_list->data;
338       if (!strcmp (rc_file->name, filename))
339         break;
340       
341       tmp_list = tmp_list->next;
342     }
343
344   if (!tmp_list)
345     {
346       rc_file = g_new (GtkRcFile, 1);
347       rc_file->name = g_strdup (filename);
348       rc_file->canonical_name = NULL;
349       rc_file->mtime = 0;
350       rc_file->reload = reload;
351
352       rc_files = g_slist_append (rc_files, rc_file);
353     }
354
355   if (!rc_file->canonical_name)
356     {
357       /* Get the absolute pathname */
358
359       if (rc_file->name[0] == '/')
360         rc_file->canonical_name = rc_file->name;
361       else
362         {
363           GString *str;
364           gchar *cwd;
365
366           cwd = g_get_current_dir ();
367
368           str = g_string_new (cwd);
369           g_free (cwd);
370           g_string_append_c (str, '/');
371           g_string_append (str, rc_file->name);
372           
373           rc_file->canonical_name = str->str;
374           g_string_free (str, FALSE);
375         }
376     }
377
378   if (!lstat (rc_file->canonical_name, &statbuf))
379     {
380       gint fd;
381
382       rc_file->mtime = statbuf.st_mtime;
383
384       fd = open (rc_file->canonical_name, O_RDONLY);
385       if (fd < 0)
386         return;
387
388         {
389           gint i;
390           gchar *dir;
391           
392           dir = g_strdup(rc_file->canonical_name);
393           for (i = strlen(dir) - 1; (i >= 0) && (dir[i] != '/'); i--)
394             dir[i] = 0;
395           gtk_rc_append_pixmap_path(dir);
396           g_free(dir);
397         }
398       gtk_rc_parse_any (filename, fd, NULL);
399
400       close (fd);
401     }
402 }
403
404 void
405 gtk_rc_parse (const gchar *filename)
406 {
407   g_return_if_fail (filename != NULL);
408
409   gtk_rc_parse_file (filename, TRUE);
410 }
411
412 /* Handling of RC styles */
413
414 GtkRcStyle *
415 gtk_rc_style_new              (void)
416 {
417   GtkRcStyle *new_style;
418
419   new_style = g_new0 (GtkRcStyle, 1);
420   new_style->ref_count = 1;
421
422   return new_style;
423 }
424
425 void      
426 gtk_rc_style_ref (GtkRcStyle  *rc_style)
427 {
428   g_return_if_fail (rc_style != NULL);
429
430   rc_style->ref_count++;
431 }
432
433 void      
434 gtk_rc_style_unref (GtkRcStyle  *rc_style)
435 {
436   gint i;
437
438   g_return_if_fail (rc_style != NULL);
439
440   rc_style->ref_count--;
441
442   if (rc_style->ref_count == 0)
443     {
444       if (rc_style->engine)
445         {
446           rc_style->engine->destroy_rc_style (rc_style);
447           gtk_theme_engine_unref (rc_style->engine);
448         }
449
450       if (rc_style->name)
451         g_free (rc_style->name);
452       if (rc_style->fontset_name)
453         g_free (rc_style->fontset_name);
454       if (rc_style->font_name)
455         g_free (rc_style->font_name);
456       
457       for (i=0 ; i<5 ; i++)
458         if (rc_style->bg_pixmap_name[i])
459           g_free (rc_style->bg_pixmap_name[i]);
460       
461       g_free (rc_style);
462     }
463 }
464
465 static void
466 gtk_rc_clear_realized_node (gpointer key,
467                             gpointer data,
468                             gpointer user_data)
469 {
470   gtk_style_unref (data);
471 }
472
473 static void
474 gtk_rc_clear_hash_node (gpointer key, 
475                         gpointer data, 
476                         gpointer user_data)
477 {
478   gtk_rc_style_unref (data);
479 }
480
481 static void
482 gtk_rc_free_rc_sets (GSList *slist)
483 {
484   while (slist)
485     {
486       GtkRcSet *rc_set;
487
488       rc_set = slist->data;
489       gtk_pattern_spec_free_segs (&rc_set->pspec);
490       g_free (rc_set);
491
492       slist = slist->next;
493     }
494 }
495
496 static void
497 gtk_rc_clear_styles (void)
498 {
499   /* Clear out all old rc_styles */
500
501   if (rc_style_ht)
502     {
503       g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
504       g_hash_table_destroy (rc_style_ht);
505       rc_style_ht = NULL;
506     }
507
508   if (realized_style_ht)
509     {
510       g_hash_table_foreach (realized_style_ht, gtk_rc_clear_realized_node, NULL);
511       g_hash_table_destroy (realized_style_ht);
512       realized_style_ht = NULL;
513     }
514
515   gtk_rc_free_rc_sets (gtk_rc_sets_widget);
516   g_slist_free (gtk_rc_sets_widget);
517   gtk_rc_sets_widget = NULL;
518
519   gtk_rc_free_rc_sets (gtk_rc_sets_widget_class);
520   g_slist_free (gtk_rc_sets_widget_class);
521   gtk_rc_sets_widget_class = NULL;
522
523   gtk_rc_free_rc_sets (gtk_rc_sets_class);
524   g_slist_free (gtk_rc_sets_class);
525   gtk_rc_sets_class = NULL;
526
527   gtk_rc_init ();
528 }
529
530 gboolean
531 gtk_rc_reparse_all (void)
532 {
533   GSList *tmp_list;
534   gboolean mtime_modified = FALSE;
535   GtkRcFile *rc_file;
536
537   struct stat statbuf;
538
539   /* Check through and see if any of the RC's have had their
540    * mtime modified. If so, reparse everything.
541    */
542   tmp_list = rc_files;
543   while (tmp_list)
544     {
545       rc_file = tmp_list->data;
546       
547       if (!lstat (rc_file->name, &statbuf) && 
548           (statbuf.st_mtime > rc_file->mtime))
549         {
550           mtime_modified = TRUE;
551           break;
552         }
553       
554       tmp_list = tmp_list->next;
555     }
556
557   if (mtime_modified)
558     {
559       gtk_rc_clear_styles();
560
561       tmp_list = rc_files;
562       while (tmp_list)
563         {
564           rc_file = tmp_list->data;
565           if (rc_file->reload)
566             gtk_rc_parse_file (rc_file->name, FALSE);
567           
568           tmp_list = tmp_list->next;
569         }
570     }
571
572   return mtime_modified;
573 }
574
575 static GSList *
576 gtk_rc_styles_match (GSList       *rc_styles,
577                      GSList       *sets,
578                      guint         path_length,
579                      gchar        *path,
580                      gchar        *path_reversed)
581                      
582 {
583   GtkRcSet *rc_set;
584
585   while (sets)
586     {
587       rc_set = sets->data;
588       sets = sets->next;
589
590       if (gtk_pattern_match (&rc_set->pspec, path_length, path, path_reversed))
591         rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
592     }
593   
594   return rc_styles;
595 }
596
597 GtkStyle*
598 gtk_rc_get_style (GtkWidget *widget)
599 {
600   GtkRcStyle *widget_rc_style;
601   GSList *rc_styles = NULL;
602
603   static guint rc_style_key_id = 0;
604
605   /* We allow the specification of a single rc style to be bound
606    * tightly to a widget, for application modifications
607    */
608   if (!rc_style_key_id)
609     rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
610
611   widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
612                                                rc_style_key_id);
613
614   if (widget_rc_style)
615     rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
616   
617   if (gtk_rc_sets_widget)
618     {
619       gchar *path, *path_reversed;
620       guint path_length;
621
622       gtk_widget_path (widget, &path_length, &path, &path_reversed);
623       rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget, path_length, path, path_reversed);
624       g_free (path);
625       g_free (path_reversed);
626       
627     }
628   
629   if (gtk_rc_sets_widget_class)
630     {
631       gchar *path, *path_reversed;
632       guint path_length;
633
634       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
635       rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget_class, path_length, path, path_reversed);
636       g_free (path);
637       g_free (path_reversed);
638     }
639
640   if (gtk_rc_sets_class)
641     {
642       GtkType type;
643
644       type = GTK_OBJECT_TYPE (widget);
645       while (type)
646         {
647           gchar *path, *path_reversed;
648           guint path_length;
649
650           path = gtk_type_name (type);
651           path_length = strlen (path);
652           path_reversed = g_strdup (path);
653           g_strreverse (path_reversed);
654           
655           rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_class, path_length, path, path_reversed);
656           g_free (path_reversed);
657       
658           type = gtk_type_parent (type);
659         }
660     }
661   
662   if (rc_styles)
663     return gtk_rc_style_init (rc_styles);
664
665   return NULL;
666 }
667
668 static GSList*
669 gtk_rc_add_rc_sets (GSList     *slist,
670                     GtkRcStyle *rc_style,
671                     const char *pattern)
672 {
673   GtkRcStyle *new_style;
674   GtkRcSet *rc_set;
675   guint i;
676   
677   new_style = gtk_rc_style_new ();
678   *new_style = *rc_style;
679   new_style->name = g_strdup (rc_style->name);
680   new_style->font_name = g_strdup (rc_style->font_name);
681   new_style->fontset_name = g_strdup (rc_style->fontset_name);
682   
683   for (i = 0; i < 5; i++)
684     new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
685   
686   rc_set = g_new (GtkRcSet, 1);
687   gtk_pattern_spec_init (&rc_set->pspec, pattern);
688   rc_set->rc_style = rc_style;
689   
690   return g_slist_prepend (slist, rc_set);
691 }
692
693 void
694 gtk_rc_add_widget_name_style (GtkRcStyle  *rc_style,
695                               const gchar *pattern)
696 {
697   g_return_if_fail (rc_style != NULL);
698   g_return_if_fail (pattern != NULL);
699
700   gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, rc_style, pattern);
701 }
702
703 void
704 gtk_rc_add_widget_class_style (GtkRcStyle  *rc_style,
705                                const gchar *pattern)
706 {
707   g_return_if_fail (rc_style != NULL);
708   g_return_if_fail (pattern != NULL);
709
710   gtk_rc_sets_widget_class = gtk_rc_add_rc_sets (gtk_rc_sets_widget_class, rc_style, pattern);
711 }
712
713 void
714 gtk_rc_add_class_style (GtkRcStyle  *rc_style,
715                         const gchar *pattern)
716 {
717   g_return_if_fail (rc_style != NULL);
718   g_return_if_fail (pattern != NULL);
719
720   gtk_rc_sets_class = gtk_rc_add_rc_sets (gtk_rc_sets_class, rc_style, pattern);
721 }
722
723 static void
724 gtk_rc_parse_any (const gchar  *input_name,
725                   gint          input_fd,
726                   const gchar  *input_string)
727 {
728   GScanner *scanner;
729   guint    i;
730   gboolean done;
731   
732   scanner = g_scanner_new (&gtk_rc_scanner_config);
733   
734   if (input_fd >= 0)
735     {
736       g_assert (input_string == NULL);
737       
738       g_scanner_input_file (scanner, input_fd);
739     }
740   else
741     {
742       g_assert (input_string != NULL);
743       
744       g_scanner_input_text (scanner, input_string, strlen (input_string));
745     }
746   scanner->input_name = input_name;
747
748   g_scanner_freeze_symbol_table (scanner);
749   for (i = 0; i < n_symbols; i++)
750     g_scanner_add_symbol (scanner, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
751   g_scanner_thaw_symbol_table (scanner);
752   
753   done = FALSE;
754   while (!done)
755     {
756       if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
757         done = TRUE;
758       else
759         {
760           guint expected_token;
761           
762           expected_token = gtk_rc_parse_statement (scanner);
763
764           if (expected_token != G_TOKEN_NONE)
765             {
766               gchar *symbol_name;
767               gchar *msg;
768               
769               msg = NULL;
770               symbol_name = NULL;
771               if (scanner->scope_id == 0)
772                 {
773                   /* if we are in scope 0, we know the symbol names
774                    * that are associated with certaintoken values.
775                    * so we look them up to make the error messages
776                    * more readable.
777                    */
778                   if (expected_token > GTK_RC_TOKEN_INVALID &&
779                       expected_token < GTK_RC_TOKEN_LAST)
780                     {
781                       for (i = 0; i < n_symbols; i++)
782                         if (symbols[i].token == expected_token)
783                           msg = symbols[i].name;
784                       if (msg)
785                         msg = g_strconcat ("e.g. `", msg, "'", NULL);
786                     }
787                   if (scanner->token > GTK_RC_TOKEN_INVALID &&
788                       scanner->token < GTK_RC_TOKEN_LAST)
789                     {
790                       symbol_name = "???";
791                       for (i = 0; i < n_symbols; i++)
792                         if (symbols[i].token == scanner->token)
793                           symbol_name = symbols[i].name;
794                     }
795                 }
796               g_scanner_unexp_token (scanner,
797                                      expected_token,
798                                      NULL,
799                                      "keyword",
800                                      symbol_name,
801                                      msg,
802                                      TRUE);
803               g_free (msg);
804               done = TRUE;
805             }
806         }
807     }
808   
809   g_scanner_destroy (scanner);
810 }
811
812 static guint       
813 gtk_rc_styles_hash (const GSList *rc_styles)
814 {
815   guint result;
816   
817   result = 0;
818   while (rc_styles)
819     {
820       result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
821       rc_styles = rc_styles->next;
822     }
823   
824   return result;
825 }
826
827 static gint        
828 gtk_rc_styles_compare (const GSList *a,
829                        const GSList *b)
830 {
831   while (a && b)
832     {
833       if (a->data != b->data)
834         return FALSE;
835       a = a->next;
836       b = b->next;
837     }
838   
839   return (a == b);
840 }
841
842 static guint
843 gtk_rc_style_hash (const char *name)
844 {
845   guint result;
846   
847   result = 0;
848   while (*name)
849     result += (result << 3) + *name++;
850   
851   return result;
852 }
853
854 static gint
855 gtk_rc_style_compare (const char *a,
856                       const char *b)
857 {
858   return (strcmp (a, b) == 0);
859 }
860
861 static GtkRcStyle*
862 gtk_rc_style_find (const char *name)
863 {
864   GtkRcStyle *rc_style;
865   
866   rc_style = g_hash_table_lookup (rc_style_ht, (gpointer) name);
867   
868   return rc_style;
869 }
870
871 /* Assumes ownership of rc_style */
872 static GtkStyle *
873 gtk_rc_style_to_style (GtkRcStyle *rc_style)
874 {
875   GtkStyle *style;
876   GdkFont *old_font;
877   gint i;
878
879   style = gtk_style_new ();
880
881   style->rc_style = rc_style;
882   
883   if (rc_style->fontset_name)
884     {
885       old_font = style->font;
886       style->font = gdk_fontset_load (rc_style->fontset_name);
887       if (style->font)
888         gdk_font_unref (old_font);
889       else
890         style->font = old_font;
891     }
892   else if (rc_style->font_name)
893     {
894       old_font = style->font;
895       style->font = gdk_font_load (rc_style->font_name);
896       if (style->font)
897         gdk_font_unref (old_font);
898       else
899         style->font = old_font;
900     }
901   
902   for (i = 0; i < 5; i++)
903     {
904       if (rc_style->color_flags[i] & GTK_RC_FG)
905         style->fg[i] = rc_style->fg[i];
906       if (rc_style->color_flags[i] & GTK_RC_BG)
907         style->bg[i] = rc_style->bg[i];
908       if (rc_style->color_flags[i] & GTK_RC_TEXT)
909         style->text[i] = rc_style->text[i];
910       if (rc_style->color_flags[i] & GTK_RC_BASE)
911         style->base[i] = rc_style->base[i];
912     }
913
914   if (rc_style->engine)
915     {
916       style->engine = rc_style->engine;
917       gtk_theme_engine_ref (style->engine);
918       rc_style->engine->rc_style_to_style (style, rc_style);
919     }
920
921   return style;
922 }
923
924 /* Reuses or frees rc_styles */
925 static GtkStyle *
926 gtk_rc_style_init (GSList *rc_styles)
927 {
928   gint i;
929
930   GtkStyle *style = NULL;
931   GtkRcStyle *proto_style;
932
933   if (!realized_style_ht)
934     realized_style_ht = g_hash_table_new ((GHashFunc)gtk_rc_styles_hash,
935                                            (GCompareFunc)gtk_rc_styles_compare);
936
937   style = g_hash_table_lookup (realized_style_ht, rc_styles);
938
939   if (!style)
940     {
941       GSList *tmp_styles = rc_styles;
942       
943       proto_style = gtk_rc_style_new ();
944
945       while (tmp_styles)
946         {
947           GtkRcStyle *rc_style = tmp_styles->data;
948
949           for (i=0; i<5; i++)
950             {
951               if (!proto_style->bg_pixmap_name[i] && rc_style->bg_pixmap_name[i])
952                 proto_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
953
954               if (!(proto_style->color_flags[i] & GTK_RC_FG) && 
955                     rc_style->color_flags[i] & GTK_RC_FG)
956                 {
957                   proto_style->fg[i] = rc_style->fg[i];
958                   proto_style->color_flags[i] |= GTK_RC_FG;
959                 }
960               if (!(proto_style->color_flags[i] & GTK_RC_BG) && 
961                     rc_style->color_flags[i] & GTK_RC_BG)
962                 {
963                   proto_style->bg[i] = rc_style->bg[i];
964                   proto_style->color_flags[i] |= GTK_RC_BG;
965                 }
966               if (!(proto_style->color_flags[i] & GTK_RC_TEXT) && 
967                     rc_style->color_flags[i] & GTK_RC_TEXT)
968                 {
969                   proto_style->text[i] = rc_style->text[i];
970                   proto_style->color_flags[i] |= GTK_RC_TEXT;
971                 }
972               if (!(proto_style->color_flags[i] & GTK_RC_BASE) && 
973                     rc_style->color_flags[i] & GTK_RC_BASE)
974                 {
975                   proto_style->base[i] = rc_style->base[i];
976                   proto_style->color_flags[i] |= GTK_RC_BASE;
977                 }
978             }
979
980           if (!proto_style->font_name && rc_style->font_name)
981             proto_style->font_name = g_strdup (rc_style->font_name);
982           if (!proto_style->fontset_name && rc_style->fontset_name)
983             proto_style->fontset_name = g_strdup (rc_style->fontset_name);
984
985           if (!proto_style->engine && rc_style->engine)
986             {
987               proto_style->engine = rc_style->engine;
988               gtk_theme_engine_ref (proto_style->engine);
989             }
990           
991           if (proto_style->engine &&
992               (proto_style->engine == rc_style->engine))
993             proto_style->engine->merge_rc_style (proto_style, rc_style);
994
995           tmp_styles = tmp_styles->next;
996         }
997
998       style = gtk_rc_style_to_style (proto_style);
999
1000       g_hash_table_insert (realized_style_ht, rc_styles, style);
1001     }
1002
1003   return style;
1004 }
1005
1006 /*********************
1007  * Parsing functions *
1008  *********************/
1009
1010 static guint
1011 gtk_rc_parse_statement (GScanner *scanner)
1012 {
1013   guint token;
1014   
1015   token = g_scanner_peek_next_token (scanner);
1016
1017   switch (token)
1018     {
1019     case GTK_RC_TOKEN_INCLUDE:
1020       token = g_scanner_get_next_token (scanner);
1021       if (token != GTK_RC_TOKEN_INCLUDE)
1022         return GTK_RC_TOKEN_INCLUDE;
1023
1024       token = g_scanner_get_next_token (scanner);
1025       if (token != G_TOKEN_STRING)
1026         return G_TOKEN_STRING;
1027
1028       gtk_rc_parse_file (scanner->value.v_string, FALSE);
1029       return G_TOKEN_NONE;
1030
1031     case GTK_RC_TOKEN_STYLE:
1032       return gtk_rc_parse_style (scanner);
1033
1034     case GTK_RC_TOKEN_BINDING:
1035       return gtk_binding_parse_binding (scanner);
1036
1037     case GTK_RC_TOKEN_PIXMAP_PATH:
1038       return gtk_rc_parse_pixmap_path (scanner);
1039
1040     case GTK_RC_TOKEN_WIDGET:
1041       return gtk_rc_parse_path_pattern (scanner);
1042
1043     case GTK_RC_TOKEN_WIDGET_CLASS:
1044       return gtk_rc_parse_path_pattern (scanner);
1045
1046     case GTK_RC_TOKEN_CLASS:
1047       return gtk_rc_parse_path_pattern (scanner);
1048
1049     case GTK_RC_TOKEN_MODULE_PATH:
1050       return gtk_rc_parse_module_path (scanner);
1051        
1052     default:
1053       g_scanner_get_next_token (scanner);
1054       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
1055     }
1056 }
1057
1058 static guint
1059 gtk_rc_parse_style (GScanner *scanner)
1060 {
1061   GtkRcStyle *rc_style;
1062   GtkRcStyle *parent_style;
1063   guint token;
1064   gint insert;
1065   gint i;
1066   
1067   token = g_scanner_get_next_token (scanner);
1068   if (token != GTK_RC_TOKEN_STYLE)
1069     return GTK_RC_TOKEN_STYLE;
1070   
1071   token = g_scanner_get_next_token (scanner);
1072   if (token != G_TOKEN_STRING)
1073     return G_TOKEN_STRING;
1074   
1075   insert = FALSE;
1076   rc_style = g_hash_table_lookup (rc_style_ht, scanner->value.v_string);
1077   
1078   if (!rc_style)
1079     {
1080       insert = TRUE;
1081       rc_style = gtk_rc_style_new ();
1082       rc_style->name = g_strdup (scanner->value.v_string);
1083       
1084       for (i = 0; i < 5; i++)
1085         rc_style->bg_pixmap_name[i] = NULL;
1086
1087       for (i = 0; i < 5; i++)
1088         rc_style->color_flags[i] = 0;
1089
1090       rc_style->engine = NULL;
1091       rc_style->engine_data = NULL;
1092     }
1093   
1094   token = g_scanner_peek_next_token (scanner);
1095   if (token == G_TOKEN_EQUAL_SIGN)
1096     {
1097       token = g_scanner_get_next_token (scanner);
1098       
1099       token = g_scanner_get_next_token (scanner);
1100       if (token != G_TOKEN_STRING)
1101         {
1102           if (insert)
1103             g_free (rc_style);
1104
1105           return G_TOKEN_STRING;
1106         }
1107       
1108       parent_style = g_hash_table_lookup (rc_style_ht, scanner->value.v_string);
1109       if (parent_style)
1110         {
1111           for (i = 0; i < 5; i++)
1112             {
1113               rc_style->color_flags[i] = parent_style->color_flags[i];
1114               rc_style->fg[i] = parent_style->fg[i];
1115               rc_style->bg[i] = parent_style->bg[i];
1116               rc_style->text[i] = parent_style->text[i];
1117               rc_style->base[i] = parent_style->base[i];
1118             }
1119           
1120           if (parent_style->fontset_name)
1121             {
1122               if (rc_style->fontset_name)
1123                 g_free (rc_style->fontset_name);
1124               rc_style->fontset_name = g_strdup (parent_style->fontset_name);
1125             }
1126           else if (parent_style->font_name)
1127             {
1128               if (rc_style->font_name)
1129                 g_free (rc_style->font_name);
1130               rc_style->font_name = g_strdup (parent_style->font_name);
1131             }
1132           
1133           for (i = 0; i < 5; i++)
1134             {
1135               if (rc_style->bg_pixmap_name[i])
1136                 g_free (rc_style->bg_pixmap_name[i]);
1137               rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
1138             }
1139         }
1140     }
1141   
1142   token = g_scanner_get_next_token (scanner);
1143   if (token != G_TOKEN_LEFT_CURLY)
1144     {
1145       if (insert)
1146         g_free (rc_style);
1147
1148       return G_TOKEN_LEFT_CURLY;
1149     }
1150   
1151   token = g_scanner_peek_next_token (scanner);
1152   while (token != G_TOKEN_RIGHT_CURLY)
1153     {
1154       switch (token)
1155         {
1156         case GTK_RC_TOKEN_BASE:
1157           token = gtk_rc_parse_base (scanner, rc_style);
1158           break;
1159         case GTK_RC_TOKEN_BG:
1160           token = gtk_rc_parse_bg (scanner, rc_style);
1161           break;
1162         case GTK_RC_TOKEN_FG:
1163           token = gtk_rc_parse_fg (scanner, rc_style);
1164           break;
1165         case GTK_RC_TOKEN_TEXT:
1166           token = gtk_rc_parse_text (scanner, rc_style);
1167           break;
1168         case GTK_RC_TOKEN_BG_PIXMAP:
1169           token = gtk_rc_parse_bg_pixmap (scanner, rc_style);
1170           break;
1171         case GTK_RC_TOKEN_FONT:
1172           token = gtk_rc_parse_font (scanner, rc_style);
1173           break;
1174         case GTK_RC_TOKEN_FONTSET:
1175           token = gtk_rc_parse_fontset (scanner, rc_style);
1176           break;
1177         case GTK_RC_TOKEN_ENGINE:
1178           token = gtk_rc_parse_engine (scanner, rc_style);
1179           break;
1180         default:
1181           g_scanner_get_next_token (scanner);
1182           token = G_TOKEN_RIGHT_CURLY;
1183           break;
1184         }
1185
1186       if (token != G_TOKEN_NONE)
1187         {
1188           if (insert)
1189             {
1190               if (rc_style->fontset_name)
1191                 g_free (rc_style->fontset_name);
1192               if (rc_style->font_name)
1193                 g_free (rc_style->font_name);
1194               for (i = 0; i < 5; i++)
1195                 if (rc_style->bg_pixmap_name[i])
1196                   g_free (rc_style->bg_pixmap_name[i]);
1197               g_free (rc_style);
1198             }
1199           return token;
1200         }
1201       token = g_scanner_peek_next_token (scanner);
1202     }
1203   
1204   token = g_scanner_get_next_token (scanner);
1205   if (token != G_TOKEN_RIGHT_CURLY)
1206     {
1207       if (insert)
1208         {
1209           if (rc_style->fontset_name)
1210             g_free (rc_style->fontset_name);
1211           if (rc_style->font_name)
1212             g_free (rc_style->font_name);
1213           
1214           for (i = 0; i < 5; i++)
1215             if (rc_style->bg_pixmap_name[i])
1216               g_free (rc_style->bg_pixmap_name[i]);
1217           
1218           g_free (rc_style);
1219         }
1220       return G_TOKEN_RIGHT_CURLY;
1221     }
1222   
1223   if (insert)
1224     g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
1225   
1226   return G_TOKEN_NONE;
1227 }
1228
1229 static guint
1230 gtk_rc_parse_base (GScanner   *scanner,
1231                    GtkRcStyle *style)
1232 {
1233   GtkStateType state;
1234   guint token;
1235   
1236   token = g_scanner_get_next_token (scanner);
1237   if (token != GTK_RC_TOKEN_BASE)
1238     return GTK_RC_TOKEN_BASE;
1239   
1240   token = gtk_rc_parse_state (scanner, &state);
1241   if (token != G_TOKEN_NONE)
1242     return token;
1243   
1244   token = g_scanner_get_next_token (scanner);
1245   if (token != G_TOKEN_EQUAL_SIGN)
1246     return G_TOKEN_EQUAL_SIGN;
1247
1248   style->color_flags[state] |= GTK_RC_BASE;
1249   return gtk_rc_parse_color (scanner, &style->base[state]);
1250 }
1251
1252 static guint
1253 gtk_rc_parse_bg (GScanner   *scanner,
1254                  GtkRcStyle *style)
1255 {
1256   GtkStateType state;
1257   guint token;
1258   
1259   token = g_scanner_get_next_token (scanner);
1260   if (token != GTK_RC_TOKEN_BG)
1261     return GTK_RC_TOKEN_BG;
1262   
1263   token = gtk_rc_parse_state (scanner, &state);
1264   if (token != G_TOKEN_NONE)
1265     return token;
1266   
1267   token = g_scanner_get_next_token (scanner);
1268   if (token != G_TOKEN_EQUAL_SIGN)
1269     return G_TOKEN_EQUAL_SIGN;
1270
1271   style->color_flags[state] |= GTK_RC_BG;
1272   return gtk_rc_parse_color (scanner, &style->bg[state]);
1273 }
1274
1275 static guint
1276 gtk_rc_parse_fg (GScanner   *scanner,
1277                  GtkRcStyle *style)
1278 {
1279   GtkStateType state;
1280   guint token;
1281   
1282   token = g_scanner_get_next_token (scanner);
1283   if (token != GTK_RC_TOKEN_FG)
1284     return GTK_RC_TOKEN_FG;
1285   
1286   token = gtk_rc_parse_state (scanner, &state);
1287   if (token != G_TOKEN_NONE)
1288     return token;
1289   
1290   token = g_scanner_get_next_token (scanner);
1291   if (token != G_TOKEN_EQUAL_SIGN)
1292     return G_TOKEN_EQUAL_SIGN;
1293   
1294   style->color_flags[state] |= GTK_RC_FG;
1295   return gtk_rc_parse_color (scanner, &style->fg[state]);
1296 }
1297
1298 static guint
1299 gtk_rc_parse_text (GScanner   *scanner,
1300                    GtkRcStyle *style)
1301 {
1302   GtkStateType state;
1303   guint token;
1304   
1305   token = g_scanner_get_next_token (scanner);
1306   if (token != GTK_RC_TOKEN_TEXT)
1307     return GTK_RC_TOKEN_TEXT;
1308   
1309   token = gtk_rc_parse_state (scanner, &state);
1310   if (token != G_TOKEN_NONE)
1311     return token;
1312   
1313   token = g_scanner_get_next_token (scanner);
1314   if (token != G_TOKEN_EQUAL_SIGN)
1315     return G_TOKEN_EQUAL_SIGN;
1316   
1317   style->color_flags[state] |= GTK_RC_TEXT;
1318   return gtk_rc_parse_color (scanner, &style->text[state]);
1319 }
1320
1321 static guint
1322 gtk_rc_parse_bg_pixmap (GScanner   *scanner,
1323                         GtkRcStyle *rc_style)
1324 {
1325   GtkStateType state;
1326   guint token;
1327   gchar *pixmap_file;
1328   
1329   token = g_scanner_get_next_token (scanner);
1330   if (token != GTK_RC_TOKEN_BG_PIXMAP)
1331     return GTK_RC_TOKEN_BG_PIXMAP;
1332   
1333   token = gtk_rc_parse_state (scanner, &state);
1334   if (token != G_TOKEN_NONE)
1335     return token;
1336   
1337   token = g_scanner_get_next_token (scanner);
1338   if (token != G_TOKEN_EQUAL_SIGN)
1339     return G_TOKEN_EQUAL_SIGN;
1340   
1341   token = g_scanner_get_next_token (scanner);
1342   if (token != G_TOKEN_STRING)
1343     return G_TOKEN_STRING;
1344   
1345   if (strcmp (scanner->value.v_string, "<parent>"))
1346     pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
1347   else
1348     pixmap_file = g_strdup (scanner->value.v_string);
1349   
1350   if (pixmap_file)
1351     {
1352       if (rc_style->bg_pixmap_name[state])
1353         g_free (rc_style->bg_pixmap_name[state]);
1354       rc_style->bg_pixmap_name[state] = pixmap_file;
1355     }
1356   
1357   return G_TOKEN_NONE;
1358 }
1359
1360 gchar*
1361 gtk_rc_find_pixmap_in_path (GScanner *scanner,
1362                             const gchar *pixmap_file)
1363 {
1364   gint i;
1365   gint fd;
1366   gchar *buf;
1367   
1368   for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
1369     {
1370       buf = g_malloc (strlen (pixmap_path[i]) + strlen (pixmap_file) + 2);
1371       sprintf (buf, "%s%c%s", pixmap_path[i], '/', pixmap_file);
1372       
1373       fd = open (buf, O_RDONLY);
1374       if (fd >= 0)
1375         {
1376           close (fd);
1377           return buf;
1378         }
1379       
1380       g_free (buf);
1381     }
1382
1383   if (scanner)
1384     g_warning ("Unable to locate image file in pixmap_path: \"%s\" line %d",
1385                pixmap_file, scanner->line);
1386   else
1387     g_warning ("Unable to locate image file in pixmap_path: \"%s\"",
1388                pixmap_file);
1389     
1390   return NULL;
1391 }
1392
1393 gchar*
1394 gtk_rc_find_module_in_path (const gchar *module_file)
1395 {
1396   gint i;
1397   gint fd;
1398   gchar *buf;
1399   
1400   for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
1401     {
1402       buf = g_malloc (strlen (module_path[i]) + strlen (module_file) + 2);
1403       sprintf (buf, "%s%c%s", module_path[i], '/', module_file);
1404       
1405       fd = open (buf, O_RDONLY);
1406       if (fd >= 0)
1407         {
1408           close (fd);
1409           return buf;
1410         }
1411       
1412       g_free (buf);
1413     }
1414     
1415   return NULL;
1416 }
1417
1418 static guint
1419 gtk_rc_parse_font (GScanner   *scanner,
1420                    GtkRcStyle *rc_style)
1421 {
1422   guint token;
1423   
1424   token = g_scanner_get_next_token (scanner);
1425   if (token != GTK_RC_TOKEN_FONT)
1426     return GTK_RC_TOKEN_FONT;
1427   
1428   token = g_scanner_get_next_token (scanner);
1429   if (token != G_TOKEN_EQUAL_SIGN)
1430     return G_TOKEN_EQUAL_SIGN;
1431   
1432   token = g_scanner_get_next_token (scanner);
1433   if (token != G_TOKEN_STRING)
1434     return G_TOKEN_STRING;
1435   
1436   if (rc_style->font_name)
1437     g_free (rc_style->font_name);
1438   rc_style->font_name = g_strdup (scanner->value.v_string);
1439   
1440   return G_TOKEN_NONE;
1441 }
1442
1443 static guint
1444 gtk_rc_parse_fontset (GScanner   *scanner,
1445                       GtkRcStyle *rc_style)
1446 {
1447   guint token;
1448   
1449   token = g_scanner_get_next_token (scanner);
1450   if (token != GTK_RC_TOKEN_FONTSET)
1451     return GTK_RC_TOKEN_FONTSET;
1452   
1453   token = g_scanner_get_next_token (scanner);
1454   if (token != G_TOKEN_EQUAL_SIGN)
1455     return G_TOKEN_EQUAL_SIGN;
1456   
1457   token = g_scanner_get_next_token (scanner);
1458   if (token != G_TOKEN_STRING)
1459     return G_TOKEN_STRING;
1460   
1461   if (rc_style->fontset_name)
1462     g_free (rc_style->fontset_name);
1463   rc_style->fontset_name = g_strdup (scanner->value.v_string);
1464   
1465   return G_TOKEN_NONE;
1466 }
1467
1468 static guint       
1469 gtk_rc_parse_engine (GScanner    *scanner,
1470                      GtkRcStyle  *rc_style)
1471 {
1472   guint token;
1473
1474   token = g_scanner_get_next_token (scanner);
1475   if (token != GTK_RC_TOKEN_ENGINE)
1476     return GTK_RC_TOKEN_ENGINE;
1477
1478   token = g_scanner_get_next_token (scanner);
1479   if (token != G_TOKEN_STRING)
1480     return G_TOKEN_STRING;
1481
1482   rc_style->engine = gtk_theme_engine_get (scanner->value.v_string);
1483
1484   token = g_scanner_get_next_token (scanner);
1485   if (token != G_TOKEN_LEFT_CURLY)
1486     return G_TOKEN_LEFT_CURLY;
1487
1488   if (rc_style->engine)
1489     return rc_style->engine->parse_rc_style (scanner, rc_style);
1490   else
1491     {
1492       /* Skip over remainder, looking for nested {}'s */
1493       guint count = 1;
1494       
1495       while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
1496         {
1497           if (token == G_TOKEN_LEFT_CURLY)
1498             count++;
1499           else if (token == G_TOKEN_RIGHT_CURLY)
1500             count--;
1501
1502           if (count == 0)
1503             return G_TOKEN_NONE;
1504         }
1505
1506       return G_TOKEN_RIGHT_CURLY;
1507     }
1508 }
1509
1510 guint
1511 gtk_rc_parse_state (GScanner     *scanner,
1512                     GtkStateType *state)
1513 {
1514   guint old_scope;
1515   guint token;
1516
1517   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1518   g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
1519   
1520   /* we don't know where we got called from, so we reset the scope here.
1521    * if we bail out due to errors, we *don't* reset the scope, so the
1522    * error messaging code can make sense of our tokens.
1523    */
1524   old_scope = g_scanner_set_scope (scanner, 0);
1525   
1526   token = g_scanner_get_next_token (scanner);
1527   if (token != G_TOKEN_LEFT_BRACE)
1528     return G_TOKEN_LEFT_BRACE;
1529   
1530   token = g_scanner_get_next_token (scanner);
1531   switch (token)
1532     {
1533     case GTK_RC_TOKEN_ACTIVE:
1534       *state = GTK_STATE_ACTIVE;
1535       break;
1536     case GTK_RC_TOKEN_INSENSITIVE:
1537       *state = GTK_STATE_INSENSITIVE;
1538       break;
1539     case GTK_RC_TOKEN_NORMAL:
1540       *state = GTK_STATE_NORMAL;
1541       break;
1542     case GTK_RC_TOKEN_PRELIGHT:
1543       *state = GTK_STATE_PRELIGHT;
1544       break;
1545     case GTK_RC_TOKEN_SELECTED:
1546       *state = GTK_STATE_SELECTED;
1547       break;
1548     default:
1549       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
1550     }
1551   
1552   token = g_scanner_get_next_token (scanner);
1553   if (token != G_TOKEN_RIGHT_BRACE)
1554     return G_TOKEN_RIGHT_BRACE;
1555   
1556   g_scanner_set_scope (scanner, old_scope);
1557
1558   return G_TOKEN_NONE;
1559 }
1560
1561 guint
1562 gtk_rc_parse_priority (GScanner            *scanner,
1563                        GtkPathPriorityType *priority)
1564 {
1565   guint old_scope;
1566   guint token;
1567
1568   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1569   g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
1570
1571   /* we don't know where we got called from, so we reset the scope here.
1572    * if we bail out due to errors, we *don't* reset the scope, so the
1573    * error messaging code can make sense of our tokens.
1574    */
1575   old_scope = g_scanner_set_scope (scanner, 0);
1576   
1577   token = g_scanner_get_next_token (scanner);
1578   if (token != ':')
1579     return ':';
1580   
1581   token = g_scanner_get_next_token (scanner);
1582   switch (token)
1583     {
1584     case GTK_RC_TOKEN_LOWEST:
1585       *priority = GTK_PATH_PRIO_LOWEST;
1586       break;
1587     case GTK_RC_TOKEN_GTK:
1588       *priority = GTK_PATH_PRIO_GTK;
1589       break;
1590     case GTK_RC_TOKEN_APPLICATION:
1591       *priority = GTK_PATH_PRIO_APPLICATION;
1592       break;
1593     case GTK_RC_TOKEN_RC:
1594       *priority = GTK_PATH_PRIO_RC;
1595       break;
1596     case GTK_RC_TOKEN_HIGHEST:
1597       *priority = GTK_PATH_PRIO_HIGHEST;
1598       break;
1599     default:
1600       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
1601     }
1602   
1603   g_scanner_set_scope (scanner, old_scope);
1604
1605   return G_TOKEN_NONE;
1606 }
1607
1608 guint
1609 gtk_rc_parse_color (GScanner *scanner,
1610                     GdkColor *color)
1611 {
1612   guint token;
1613
1614   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1615
1616   /* we don't need to set our own scop here, because
1617    * we don't need own symbols
1618    */
1619   
1620   token = g_scanner_get_next_token (scanner);
1621   switch (token)
1622     {
1623       gint token_int;
1624       gint length;
1625       gint temp;
1626       gchar buf[9];
1627       gint i, j;
1628       
1629     case G_TOKEN_LEFT_CURLY:
1630       token = g_scanner_get_next_token (scanner);
1631       if (token == G_TOKEN_INT)
1632         token_int = scanner->value.v_int;
1633       else if (token == G_TOKEN_FLOAT)
1634         token_int = scanner->value.v_float * 65535.0;
1635       else
1636         return G_TOKEN_FLOAT;
1637       color->red = CLAMP (token_int, 0, 65535);
1638       
1639       token = g_scanner_get_next_token (scanner);
1640       if (token != G_TOKEN_COMMA)
1641         return G_TOKEN_COMMA;
1642       
1643       token = g_scanner_get_next_token (scanner);
1644       if (token == G_TOKEN_INT)
1645         token_int = scanner->value.v_int;
1646       else if (token == G_TOKEN_FLOAT)
1647         token_int = scanner->value.v_float * 65535.0;
1648       else
1649         return G_TOKEN_FLOAT;
1650       color->green = CLAMP (token_int, 0, 65535);
1651       
1652       token = g_scanner_get_next_token (scanner);
1653       if (token != G_TOKEN_COMMA)
1654         return G_TOKEN_COMMA;
1655       
1656       token = g_scanner_get_next_token (scanner);
1657       if (token == G_TOKEN_INT)
1658         token_int = scanner->value.v_int;
1659       else if (token == G_TOKEN_FLOAT)
1660         token_int = scanner->value.v_float * 65535.0;
1661       else
1662         return G_TOKEN_FLOAT;
1663       color->blue = CLAMP (token_int, 0, 65535);
1664       
1665       token = g_scanner_get_next_token (scanner);
1666       if (token != G_TOKEN_RIGHT_CURLY)
1667         return G_TOKEN_RIGHT_CURLY;
1668       return G_TOKEN_NONE;
1669       
1670     case G_TOKEN_STRING:
1671       if (scanner->value.v_string[0] != '#')
1672         return G_TOKEN_STRING;
1673       
1674       length = strlen (scanner->value.v_string) - 1;
1675       if (((length % 3) != 0) || (length > 12))
1676         return G_TOKEN_STRING;
1677       length /= 3;
1678       
1679       for (i = 0, j = 1; i < length; i++, j++)
1680         buf[i] = scanner->value.v_string[j];
1681       buf[i] = '\0';
1682       
1683       sscanf (buf, "%x", &temp);
1684       color->red = temp;
1685       
1686       for (i = 0; i < length; i++, j++)
1687         buf[i] = scanner->value.v_string[j];
1688       buf[i] = '\0';
1689       
1690       sscanf (buf, "%x", &temp);
1691       color->green = temp;
1692       
1693       for (i = 0; i < length; i++, j++)
1694         buf[i] = scanner->value.v_string[j];
1695       buf[i] = '\0';
1696       
1697       sscanf (buf, "%x", &temp);
1698       color->blue = temp;
1699       
1700       if (length == 1)
1701         {
1702           color->red *= 4369;
1703           color->green *= 4369;
1704           color->blue *= 4369;
1705         }
1706       else if (length == 2)
1707         {
1708           color->red *= 257;
1709           color->green *= 257;
1710           color->blue *= 257;
1711         }
1712       else if (length == 3)
1713         {
1714           color->red *= 16;
1715           color->green *= 16;
1716           color->blue *= 16;
1717         }
1718       return G_TOKEN_NONE;
1719       
1720     default:
1721       return G_TOKEN_STRING;
1722     }
1723 }
1724
1725 static guint
1726 gtk_rc_parse_pixmap_path (GScanner *scanner)
1727 {
1728   guint token;
1729   
1730   token = g_scanner_get_next_token (scanner);
1731   if (token != GTK_RC_TOKEN_PIXMAP_PATH)
1732     return GTK_RC_TOKEN_PIXMAP_PATH;
1733   
1734   token = g_scanner_get_next_token (scanner);
1735   if (token != G_TOKEN_STRING)
1736     return G_TOKEN_STRING;
1737   
1738   gtk_rc_parse_pixmap_path_string (scanner->value.v_string);
1739   
1740   return G_TOKEN_NONE;
1741 }
1742
1743 static void
1744 gtk_rc_parse_pixmap_path_string (gchar *pix_path)
1745 {
1746   gchar *buf;
1747   gint end_offset;
1748   gint start_offset = 0;
1749   gint path_len;
1750   gint path_num;
1751   
1752   /* free the old one, or just add to the old one ? */
1753   for (path_num=0; pixmap_path[path_num]; path_num++)
1754     {
1755       g_free (pixmap_path[path_num]);
1756       pixmap_path[path_num] = NULL;
1757     }
1758   
1759   path_num = 0;
1760   
1761   path_len = strlen (pix_path);
1762   
1763   buf = g_strdup (pix_path);
1764   
1765   for (end_offset = 0; end_offset <= path_len; end_offset++)
1766     {
1767       if ((buf[end_offset] == ':') ||
1768           (end_offset == path_len))
1769         {
1770           buf[end_offset] = '\0';
1771           pixmap_path[path_num] = g_strdup (buf + start_offset);
1772           path_num++;
1773           pixmap_path[path_num] = NULL;
1774           start_offset = end_offset + 1;
1775         }
1776     }
1777   g_free (buf);
1778   gtk_rc_append_default_pixmap_path();
1779 }
1780
1781 static guint
1782 gtk_rc_parse_module_path (GScanner *scanner)
1783 {
1784   guint token;
1785   
1786   token = g_scanner_get_next_token (scanner);
1787   if (token != GTK_RC_TOKEN_MODULE_PATH)
1788     return GTK_RC_TOKEN_MODULE_PATH;
1789   
1790   token = g_scanner_get_next_token (scanner);
1791   if (token != G_TOKEN_STRING)
1792     return G_TOKEN_STRING;
1793   
1794   gtk_rc_parse_module_path_string (scanner->value.v_string);
1795   
1796   return G_TOKEN_NONE;
1797 }
1798
1799 static void
1800 gtk_rc_parse_module_path_string (gchar *mod_path)
1801 {
1802   gchar *buf;
1803   gint end_offset;
1804   gint start_offset = 0;
1805   gint path_len;
1806   gint path_num;
1807   
1808   /* free the old one, or just add to the old one ? */
1809   for (path_num=0; module_path[path_num]; path_num++)
1810     {
1811       g_free (module_path[path_num]);
1812       module_path[path_num] = NULL;
1813     }
1814   
1815   path_num = 0;
1816   
1817   path_len = strlen (mod_path);
1818   
1819   buf = g_strdup (mod_path);
1820   
1821   for (end_offset = 0; end_offset <= path_len; end_offset++)
1822     {
1823       if ((buf[end_offset] == ':') ||
1824           (end_offset == path_len))
1825         {
1826           buf[end_offset] = '\0';
1827           module_path[path_num] = g_strdup (buf + start_offset);
1828           path_num++;
1829           module_path[path_num] = NULL;
1830           start_offset = end_offset + 1;
1831         }
1832     }
1833   g_free (buf);
1834   gtk_rc_append_default_module_path();
1835 }
1836
1837 static guint
1838 gtk_rc_parse_path_pattern (GScanner   *scanner)
1839 {
1840   guint token;
1841   GtkPathType path_type;
1842   gchar *pattern;
1843   gboolean is_binding;
1844   GtkPathPriorityType priority = GTK_PATH_PRIO_RC;
1845   
1846   token = g_scanner_get_next_token (scanner);
1847   switch (token)
1848     {
1849     case GTK_RC_TOKEN_WIDGET:
1850       path_type = GTK_PATH_WIDGET;
1851       break;
1852     case GTK_RC_TOKEN_WIDGET_CLASS:
1853       path_type = GTK_PATH_WIDGET_CLASS;
1854       break;
1855     case GTK_RC_TOKEN_CLASS:
1856       path_type = GTK_PATH_CLASS;
1857       break;
1858     default:
1859       return GTK_RC_TOKEN_WIDGET_CLASS;
1860     }
1861   
1862   token = g_scanner_get_next_token (scanner);
1863   if (token != G_TOKEN_STRING)
1864     return G_TOKEN_STRING;
1865
1866   pattern = g_strdup (scanner->value.v_string);
1867
1868   token = g_scanner_get_next_token (scanner);
1869   if (token == GTK_RC_TOKEN_STYLE)
1870     is_binding = FALSE;
1871   else if (token == GTK_RC_TOKEN_BINDING)
1872     {
1873       is_binding = TRUE;
1874       if (g_scanner_peek_next_token (scanner) == ':')
1875         {
1876           token = gtk_rc_parse_priority (scanner, &priority);
1877           if (token != G_TOKEN_NONE)
1878             {
1879               g_free (pattern);
1880               return token;
1881             }
1882         }
1883     }
1884   else
1885     {
1886       g_free (pattern);
1887       return GTK_RC_TOKEN_STYLE;
1888     }
1889   
1890   token = g_scanner_get_next_token (scanner);
1891   if (token != G_TOKEN_STRING)
1892     {
1893       g_free (pattern);
1894       return G_TOKEN_STRING;
1895     }
1896
1897   if (is_binding)
1898     {
1899       GtkBindingSet *binding;
1900
1901       binding = gtk_binding_set_find (scanner->value.v_string);
1902       if (!binding)
1903         {
1904           g_free (pattern);
1905           return G_TOKEN_STRING;
1906         }
1907       gtk_binding_set_add_path (binding, path_type, pattern, priority);
1908     }
1909   else
1910     {
1911       GtkRcStyle *rc_style;
1912       GtkRcSet *rc_set;
1913
1914       rc_style = gtk_rc_style_find (scanner->value.v_string);
1915       
1916       if (!rc_style)
1917         {
1918           g_free (pattern);
1919           return G_TOKEN_STRING;
1920         }
1921
1922       rc_set = g_new (GtkRcSet, 1);
1923       gtk_pattern_spec_init (&rc_set->pspec, pattern);
1924       rc_set->rc_style = rc_style;
1925
1926       if (path_type == GTK_PATH_WIDGET)
1927         gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set);
1928       else if (path_type == GTK_PATH_WIDGET_CLASS)
1929         gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set);
1930       else
1931         gtk_rc_sets_class = g_slist_prepend (gtk_rc_sets_class, rc_set);
1932     }
1933
1934   g_free (pattern);
1935   return G_TOKEN_NONE;
1936 }
1937
1938 /*
1939 typedef  GdkPixmap * (*GtkImageLoader) (GdkWindow   *window,
1940                                         GdkColormap *colormap,
1941                                         GdkBitmap  **mask,
1942                                         GdkColor    *transparent_color,
1943                                         const gchar *filename);
1944 */
1945
1946 void
1947 gtk_rc_set_image_loader(GtkImageLoader loader)
1948 {
1949   image_loader = loader;
1950 }
1951
1952 GdkPixmap *
1953 gtk_rc_load_image (GdkColormap *colormap,
1954                    GdkColor    *transparent_color,
1955                    const gchar *filename)
1956 {
1957   if (strcmp (filename, "<parent>") == 0)
1958     return (GdkPixmap*) GDK_PARENT_RELATIVE;
1959   else
1960     {
1961       if(image_loader)
1962         return image_loader(NULL, colormap, NULL,
1963                             transparent_color,
1964                             filename);
1965       else
1966         return gdk_pixmap_colormap_create_from_xpm (NULL, colormap, NULL,
1967                                                     transparent_color,
1968                                                     filename);
1969     }
1970 }