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