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