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