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