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