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