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