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