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