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