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