]> Pileus Git - ~andy/gtk/blob - gtk/gtkrc.c
don't install an empty icon_set if none of the image files could be found
[~andy/gtk] / gtk / gtkrc.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28
29 #include <locale.h>
30 #include <ctype.h>
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #include <sys/stat.h>
35 #ifdef HAVE_SYS_PARAM_H
36 #include <sys/param.h>
37 #endif
38 #include <fcntl.h>
39 #include <string.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42
43 #ifndef HAVE_LSTAT
44 #define lstat stat
45 #endif
46
47 #include <glib.h>
48 #include "gdkconfig.h"
49
50 #include "gtkversion.h"
51 #include "gtkrc.h"
52 #include "gtkbindings.h"
53 #include "gtkthemes.h"
54 #include "gtkintl.h"
55 #include "gtkiconfactory.h"
56 #include "gtkprivate.h"
57 #include "gtksettings.h"
58 #include "gtkwindow.h"
59
60 #ifdef G_OS_WIN32
61 #include <io.h>
62 #endif
63
64 typedef struct _GtkRcSet    GtkRcSet;
65 typedef struct _GtkRcNode   GtkRcNode;
66 typedef struct _GtkRcFile   GtkRcFile;
67
68 struct _GtkRcSet
69 {
70   GPatternSpec *pspec;
71   GtkRcStyle *rc_style;
72   gint priority;
73 };
74
75 struct _GtkRcFile
76 {
77   time_t mtime;
78   gchar *name;
79   gchar *canonical_name;
80   guint reload;
81 };
82
83 #define GTK_RC_MAX_PIXMAP_PATHS 128
84
85 struct _GtkRcContext
86 {
87   GHashTable *rc_style_ht;
88   GtkSettings *settings;
89   GSList *rc_sets_widget;
90   GSList *rc_sets_widget_class;
91   GSList *rc_sets_class;
92
93   /* The files we have parsed, to reread later if necessary */
94   GSList *rc_files;
95
96   gchar *theme_name;
97   gchar *key_theme_name;
98   
99   gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
100
101   gint default_priority;
102 };
103
104 static GtkRcContext *gtk_rc_context_get              (GtkSettings     *settings);
105
106 static guint       gtk_rc_style_hash                 (const gchar     *name);
107 static gboolean    gtk_rc_style_equal                (const gchar     *a,
108                                                       const gchar     *b);
109 static guint       gtk_rc_styles_hash                (const GSList    *rc_styles);
110 static gboolean    gtk_rc_styles_equal               (const GSList    *a,
111                                                       const GSList    *b);
112 static GtkRcStyle* gtk_rc_style_find                 (GtkRcContext    *context,
113                                                       const gchar     *name);
114 static GSList *    gtk_rc_styles_match               (GSList          *rc_styles,
115                                                       GSList          *sets,
116                                                       guint            path_length,
117                                                       const gchar     *path,
118                                                       const gchar     *path_reversed);
119 static GtkStyle *  gtk_rc_style_to_style             (GtkRcStyle      *rc_style);
120 static GtkStyle*   gtk_rc_init_style                 (GSList          *rc_styles);
121 static void        gtk_rc_parse_default_files        (GtkRcContext    *context);
122 static void        gtk_rc_parse_named                (GtkRcContext    *context,
123                                                       const gchar     *name,
124                                                       const gchar     *type);
125 static void        gtk_rc_parse_file                 (GtkRcContext    *context,
126                                                       const gchar     *filename,
127                                                       gint             priority,
128                                                       gboolean         reload);
129 static void        gtk_rc_parse_any                  (GtkRcContext    *context,
130                                                       const gchar     *input_name,
131                                                       gint             input_fd,
132                                                       const gchar     *input_string);
133 static guint       gtk_rc_parse_statement            (GtkRcContext    *context,
134                                                       GScanner        *scanner);
135 static guint       gtk_rc_parse_style                (GtkRcContext    *context,
136                                                       GScanner        *scanner);
137 static guint       gtk_rc_parse_assignment           (GScanner        *scanner,
138                                                       GtkRcProperty   *prop);
139 static guint       gtk_rc_parse_bg                   (GScanner        *scanner,
140                                                       GtkRcStyle      *style);
141 static guint       gtk_rc_parse_fg                   (GScanner        *scanner,
142                                                       GtkRcStyle      *style);
143 static guint       gtk_rc_parse_text                 (GScanner        *scanner,
144                                                       GtkRcStyle      *style);
145 static guint       gtk_rc_parse_base                 (GScanner        *scanner,
146                                                       GtkRcStyle      *style);
147 static guint       gtk_rc_parse_xthickness           (GScanner        *scanner,
148                                                       GtkRcStyle      *style);
149 static guint       gtk_rc_parse_ythickness           (GScanner        *scanner,
150                                                       GtkRcStyle      *style);
151 static guint       gtk_rc_parse_bg_pixmap            (GtkRcContext    *context,
152                                                       GScanner        *scanner,
153                                                       GtkRcStyle      *rc_style);
154 static guint       gtk_rc_parse_font                 (GScanner        *scanner,
155                                                       GtkRcStyle      *rc_style);
156 static guint       gtk_rc_parse_fontset              (GScanner        *scanner,
157                                                       GtkRcStyle      *rc_style);
158 static guint       gtk_rc_parse_font_name            (GScanner        *scanner,
159                                                       GtkRcStyle      *rc_style);
160 static guint       gtk_rc_parse_engine               (GtkRcContext    *context,
161                                                       GScanner        *scanner,
162                                                       GtkRcStyle     **rc_style);
163 static guint       gtk_rc_parse_pixmap_path          (GtkRcContext    *context,
164                                                       GScanner        *scanner);
165 static void        gtk_rc_parse_pixmap_path_string   (GtkRcContext    *context,
166                                                       GScanner        *scanner,
167                                                       const gchar     *pix_path);
168 static guint       gtk_rc_parse_module_path          (GScanner        *scanner);
169 static void        gtk_rc_parse_module_path_string   (const gchar     *mod_path);
170 static guint       gtk_rc_parse_im_module_path       (GScanner        *scanner);
171 static guint       gtk_rc_parse_im_module_file       (GScanner        *scanner);
172 static guint       gtk_rc_parse_path_pattern         (GtkRcContext    *context,
173                                                       GScanner        *scanner);
174 static guint       gtk_rc_parse_stock                (GtkRcContext    *context,
175                                                       GScanner        *scanner,
176                                                       GtkRcStyle      *rc_style,
177                                                       GtkIconFactory  *factory);
178 static void        gtk_rc_clear_hash_node            (gpointer         key,
179                                                       gpointer         data,
180                                                       gpointer         user_data);
181 static void        gtk_rc_clear_styles               (GtkRcContext    *context);
182 static void        gtk_rc_append_default_module_path (void);
183 static void        gtk_rc_add_initial_default_files  (void);
184
185 static void        gtk_rc_style_init                 (GtkRcStyle      *style);
186 static void        gtk_rc_style_class_init           (GtkRcStyleClass *klass);
187 static void        gtk_rc_style_finalize             (GObject         *object);
188 static void        gtk_rc_style_real_merge           (GtkRcStyle      *dest,
189                                                       GtkRcStyle      *src);
190 static GtkRcStyle* gtk_rc_style_real_create_rc_style (GtkRcStyle      *rc_style);
191 static GtkStyle*   gtk_rc_style_real_create_style    (GtkRcStyle      *rc_style);
192 static gint        gtk_rc_properties_cmp             (gconstpointer    bsearch_node1,
193                                                       gconstpointer    bsearch_node2);
194
195 static gpointer parent_class = NULL;
196
197 static const GScannerConfig gtk_rc_scanner_config =
198 {
199   (
200    " \t\r\n"
201    )                    /* cset_skip_characters */,
202   (
203    G_CSET_a_2_z
204    "_"
205    G_CSET_A_2_Z
206    )                    /* cset_identifier_first */,
207   (
208    G_CSET_a_2_z
209    "_-0123456789"
210    G_CSET_A_2_Z
211    )                    /* cset_identifier_nth */,
212   ( "#\n" )             /* cpair_comment_single */,
213   
214   TRUE                  /* case_sensitive */,
215   
216   TRUE                  /* skip_comment_multi */,
217   TRUE                  /* skip_comment_single */,
218   TRUE                  /* scan_comment_multi */,
219   TRUE                  /* scan_identifier */,
220   FALSE                 /* scan_identifier_1char */,
221   FALSE                 /* scan_identifier_NULL */,
222   TRUE                  /* scan_symbols */,
223   TRUE                  /* scan_binary */,
224   TRUE                  /* scan_octal */,
225   TRUE                  /* scan_float */,
226   TRUE                  /* scan_hex */,
227   TRUE                  /* scan_hex_dollar */,
228   TRUE                  /* scan_string_sq */,
229   TRUE                  /* scan_string_dq */,
230   TRUE                  /* numbers_2_int */,
231   FALSE                 /* int_2_float */,
232   FALSE                 /* identifier_2_string */,
233   TRUE                  /* char_2_token */,
234   TRUE                  /* symbol_2_token */,
235   FALSE                 /* scope_0_fallback */,
236 };
237
238 static const struct
239 {
240   gchar *name;
241   guint token;
242 } symbols[] = {
243   { "include", GTK_RC_TOKEN_INCLUDE },
244   { "NORMAL", GTK_RC_TOKEN_NORMAL },
245   { "ACTIVE", GTK_RC_TOKEN_ACTIVE },
246   { "PRELIGHT", GTK_RC_TOKEN_PRELIGHT },
247   { "SELECTED", GTK_RC_TOKEN_SELECTED },
248   { "INSENSITIVE", GTK_RC_TOKEN_INSENSITIVE },
249   { "fg", GTK_RC_TOKEN_FG },
250   { "bg", GTK_RC_TOKEN_BG },
251   { "text", GTK_RC_TOKEN_TEXT },
252   { "base", GTK_RC_TOKEN_BASE },
253   { "xthickness", GTK_RC_TOKEN_XTHICKNESS },
254   { "ythickness", GTK_RC_TOKEN_YTHICKNESS },
255   { "font", GTK_RC_TOKEN_FONT },
256   { "fontset", GTK_RC_TOKEN_FONTSET },
257   { "font_name", GTK_RC_TOKEN_FONT_NAME },
258   { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP },
259   { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH },
260   { "style", GTK_RC_TOKEN_STYLE },
261   { "binding", GTK_RC_TOKEN_BINDING },
262   { "bind", GTK_RC_TOKEN_BIND },
263   { "widget", GTK_RC_TOKEN_WIDGET },
264   { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS },
265   { "class", GTK_RC_TOKEN_CLASS },
266   { "lowest", GTK_RC_TOKEN_LOWEST },
267   { "gtk", GTK_RC_TOKEN_GTK },
268   { "application", GTK_RC_TOKEN_APPLICATION },
269   { "theme", GTK_RC_TOKEN_THEME },
270   { "rc", GTK_RC_TOKEN_RC },
271   { "highest", GTK_RC_TOKEN_HIGHEST },
272   { "engine", GTK_RC_TOKEN_ENGINE },
273   { "module_path", GTK_RC_TOKEN_MODULE_PATH },
274   { "stock", GTK_RC_TOKEN_STOCK },
275   { "im_module_path", GTK_RC_TOKEN_IM_MODULE_PATH },
276   { "im_module_file", GTK_RC_TOKEN_IM_MODULE_FILE },
277   { "LTR", GTK_RC_TOKEN_LTR },
278   { "RTL", GTK_RC_TOKEN_RTL }
279 };
280
281 static GHashTable *realized_style_ht = NULL;
282
283 static gchar *im_module_path = NULL;
284 static gchar *im_module_file = NULL;
285
286 #define GTK_RC_MAX_DEFAULT_FILES 128
287 static gchar *gtk_rc_default_files[GTK_RC_MAX_DEFAULT_FILES];
288
289 #define GTK_RC_MAX_MODULE_PATHS 128
290 static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
291
292 /* A stack of directories for RC files we are parsing currently.
293  * these are implicitely added to the end of PIXMAP_PATHS
294  */
295 static GSList *rc_dir_stack = NULL;
296
297 /* RC file handling */
298
299 static gchar *
300 gtk_rc_make_default_dir (const gchar *type)
301 {
302   const gchar *var;
303   gchar *path;
304
305   var = g_getenv ("GTK_EXE_PREFIX");
306   if (var)
307     path = g_build_filename (var, "lib", "gtk-2.0", type, GTK_BINARY_VERSION, NULL);
308   else
309     path = g_build_filename (GTK_LIBDIR, "gtk-2.0", type, GTK_BINARY_VERSION, NULL);
310
311   return path;
312 }
313
314 /**
315  * gtk_rc_get_im_module_path:
316  * @returns: a newly-allocated string containing the path in which to 
317  *    look for IM modules.
318  *
319  * Obtains the path in which to look for IM modules. See the documentation
320  * of the <link linkend="im-module-path"><envar>GTK_IM_MODULE_PATH</envar></link>
321  * environment variable for more details.
322  */
323 gchar *
324 gtk_rc_get_im_module_path (void)
325 {
326   const gchar *result = g_getenv ("GTK_IM_MODULE_PATH");
327
328   if (!result)
329     {
330       if (im_module_path)
331         result = im_module_path;
332       else
333         return gtk_rc_make_default_dir ("immodules");
334     }
335
336   return g_strdup (result);
337 }
338
339 /**
340  * gtk_rc_get_im_module_file:
341  * @returns: a newly-allocated string containing the name of the file
342  * listing the IM modules to load
343  *
344  * Obtains the path to the IM modules file. See the documentation
345  * of the <link linkend="im-module-file"><envar>GTK_IM_MODULE_FILE</envar></link>
346  * environment variable for more details.
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         result = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gtk.immodules", NULL);
359     }
360
361   return result;
362 }
363
364 gchar *
365 gtk_rc_get_theme_dir (void)
366 {
367   const gchar *var;
368   gchar *path;
369
370   var = g_getenv ("GTK_DATA_PREFIX");
371   if (var)
372     path = g_build_filename (var, "share", "themes", NULL);
373   else
374     path = g_build_filename (GTK_DATA_PREFIX, "share", "themes", NULL);
375
376   return path;
377 }
378
379 gchar *
380 gtk_rc_get_module_dir (void)
381 {
382   return gtk_rc_make_default_dir ("engines");
383 }
384
385 static void
386 gtk_rc_append_default_module_path (void)
387 {
388   const gchar *var;
389   gchar *path;
390   gint n;
391
392   for (n = 0; module_path[n]; n++) ;
393   if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
394     return;
395   
396   var = g_getenv ("GTK_EXE_PREFIX");
397   if (var)
398     path = g_build_filename (var, "lib", "gtk-2.0", GTK_VERSION, "engines", NULL);
399   else
400     path = g_build_filename (GTK_LIBDIR, "gtk-2.0", GTK_VERSION, "engines", NULL);
401   module_path[n++] = path;
402
403   var = g_get_home_dir ();
404   if (var)
405     {
406       path = g_build_filename (var, ".gtk-2.0", GTK_VERSION, "engines", NULL);
407       module_path[n++] = path;
408     }
409   module_path[n] = NULL;
410 }
411
412 static void
413 gtk_rc_add_initial_default_files (void)
414 {
415   static gint init = FALSE;
416   const gchar *var;
417   gchar *str;
418   gchar **files;
419   gint i;
420
421   if (init)
422     return;
423   
424   gtk_rc_default_files[0] = NULL;
425   init = TRUE;
426
427   var = g_getenv ("GTK_RC_FILES");
428   if (var)
429     {
430       files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
431       i=0;
432       while (files[i])
433         {
434           gtk_rc_add_default_file (files[i]);
435           i++;
436         }
437       g_strfreev (files);
438     }
439   else
440     {
441       str = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gtkrc", NULL);
442
443       gtk_rc_add_default_file (str);
444       g_free (str);
445
446       var = g_get_home_dir ();
447       if (var)
448         {
449           str = g_build_filename (var, ".gtkrc-2.0", NULL);
450           gtk_rc_add_default_file (str);
451           g_free (str);
452         }
453     }
454 }
455
456 /**
457  * gtk_rc_add_default_file:
458  * @filename: the pathname to the file.
459  * 
460  * Adds a file to the list of files to be parsed at the
461  * end of gtk_init().
462  **/
463 void
464 gtk_rc_add_default_file (const gchar *filename)
465 {
466   guint n;
467   
468   gtk_rc_add_initial_default_files ();
469
470   for (n = 0; gtk_rc_default_files[n]; n++) ;
471   if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
472     return;
473   
474   gtk_rc_default_files[n++] = g_strdup (filename);
475   gtk_rc_default_files[n] = NULL;
476 }
477
478 /**
479  * gtk_rc_set_default_files:
480  * @filenames: A %NULL-terminated list of filenames.
481  * 
482  * Sets the list of files that GTK+ will read at the
483  * end of gtk_init().
484  **/
485 void
486 gtk_rc_set_default_files (gchar **filenames)
487 {
488   gint i;
489
490   gtk_rc_add_initial_default_files ();
491
492   i = 0;
493   while (gtk_rc_default_files[i])
494     {
495       g_free (gtk_rc_default_files[i]);
496       i++;
497     }
498     
499   gtk_rc_default_files[0] = NULL;
500
501   i = 0;
502   while (filenames[i] != NULL)
503     {
504       gtk_rc_add_default_file (filenames[i]);
505       i++;
506     }
507 }
508
509 /**
510  * gtk_rc_get_default_files:
511  * 
512  * Retrieves the current list of RC files that will be parsed
513  * at the end of gtk_init().
514  * 
515  * Return value: A %NULL-terminated array of filenames. This memory
516  * is owned by GTK+ and must not be freed by the application.
517  * If you want to store this information, you should make a copy.
518  **/
519 gchar **
520 gtk_rc_get_default_files (void)
521 {
522   gtk_rc_add_initial_default_files ();
523
524   return gtk_rc_default_files;
525 }
526
527 /* The following routine is based on _nl_normalize_codeset from
528  * the GNU C library. Contributed by
529  *
530  * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
531  * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
532  * 
533  * Normalize codeset name.  There is no standard for the codeset
534  * names.  Normalization allows the user to use any of the common
535  * names.
536  */
537 static gchar *
538 _gtk_normalize_codeset (const gchar *codeset, gint name_len)
539 {
540   gint len = 0;
541   gint only_digit = 1;
542   gchar *retval;
543   gchar *wp;
544   gint cnt;
545
546   for (cnt = 0; cnt < name_len; ++cnt)
547     if (isalnum (codeset[cnt]))
548       {
549        ++len;
550
551        if (isalpha (codeset[cnt]))
552          only_digit = 0;
553       }
554
555   retval = g_malloc ((only_digit ? 3 : 0) + len + 1);
556
557   if (only_digit)
558     {
559       memcpy (retval, "iso", 4);
560       wp = retval + 3;
561     }
562   else
563     wp = retval;
564
565   for (cnt = 0; cnt < name_len; ++cnt)
566     if (isalpha (codeset[cnt]))
567       *wp++ = isupper(codeset[cnt]) ? tolower (codeset[cnt]) : codeset[cnt];
568     else if (isdigit (codeset[cnt]))
569       *wp++ = codeset[cnt];
570
571   *wp = '\0';
572
573   return retval;
574 }
575
576 static void
577 gtk_rc_settings_changed (GtkSettings  *settings,
578                          GParamSpec   *pspec,
579                          GtkRcContext *context)
580 {
581   gchar *new_theme_name;
582   gchar *new_key_theme_name;
583
584   g_object_get (settings,
585                 "gtk-theme-name", &new_theme_name,
586                 "gtk-key-theme-name", &new_key_theme_name,
587                 NULL);
588
589   if ((new_theme_name != context->theme_name && 
590        !(new_theme_name && context->theme_name && strcmp (new_theme_name, context->theme_name) == 0)) ||
591       (new_key_theme_name != context->key_theme_name &&
592        !(new_key_theme_name && context->key_theme_name && strcmp (new_key_theme_name, context->key_theme_name) == 0)))
593     {
594       gtk_rc_reparse_all_for_settings (settings, TRUE);
595     }
596
597   g_free (new_theme_name);
598   g_free (new_key_theme_name);
599 }
600
601 static GtkRcContext *
602 gtk_rc_context_get (GtkSettings *settings)
603 {
604   if (!settings->rc_context)
605     {
606       GtkRcContext *context = settings->rc_context = g_new (GtkRcContext, 1);
607
608       context->settings = settings;
609       context->rc_style_ht = NULL;
610       context->rc_sets_widget = NULL;
611       context->rc_sets_widget_class = NULL;
612       context->rc_sets_class = NULL;
613       context->rc_files = NULL;
614
615       g_object_get (settings,
616                     "gtk-theme-name", &context->theme_name,
617                     "gtk-key-theme-name", &context->key_theme_name,
618                     NULL);
619
620       g_signal_connect (settings,
621                         "notify::gtk-theme-name",
622                         G_CALLBACK (gtk_rc_settings_changed),
623                         context);
624       g_signal_connect (settings,
625                         "notify::gtk-key-theme-name",
626                         G_CALLBACK (gtk_rc_settings_changed),
627                         context);
628       
629       context->pixmap_path[0] = NULL;
630
631       context->default_priority = GTK_PATH_PRIO_RC;
632     }
633
634   return settings->rc_context;
635 }
636
637 static void
638 gtk_rc_parse_named (GtkRcContext *context,
639                     const gchar  *name,
640                     const gchar  *type)
641 {
642   gchar *path = NULL;
643   const gchar *home_dir;
644   gchar *subpath;
645
646   if (type)
647     subpath = g_strconcat ("gtk-2.0-", type,
648                            G_DIR_SEPARATOR_S "gtkrc",
649                            NULL);
650   else
651     subpath = g_strdup ("gtk-2.0" G_DIR_SEPARATOR_S "gtkrc");
652   
653   /* First look in the users home directory
654    */
655   home_dir = g_get_home_dir ();
656   if (home_dir)
657     {
658       path = g_build_filename (home_dir, ".themes", name, subpath, NULL);
659       if (!g_file_test (path, G_FILE_TEST_EXISTS))
660         {
661           g_free (path);
662           path = NULL;
663         }
664     }
665
666   if (!path)
667     {
668       gchar *theme_dir = gtk_rc_get_theme_dir ();
669       path = g_build_filename (theme_dir, name, subpath, NULL);
670       g_free (theme_dir);
671       
672       if (!g_file_test (path, G_FILE_TEST_EXISTS))
673         {
674           g_free (path);
675           path = NULL;
676         }
677     }
678
679   if (path)
680     {
681       gtk_rc_parse_file (context, path, GTK_PATH_PRIO_THEME, FALSE);
682       g_free (path);
683     }
684
685   g_free (subpath);
686 }
687
688 static void
689 gtk_rc_parse_default_files (GtkRcContext *context)
690 {
691   gchar *locale_suffixes[3];
692   gint n_locale_suffixes = 0;
693   gint i, j;
694   gint length;
695   gchar *locale;
696   gchar *p;
697
698 #ifdef G_OS_WIN32      
699   locale = g_win32_getlocale ();
700 #else      
701   locale = setlocale (LC_CTYPE, NULL);
702 #endif      
703
704   if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
705     {
706       /* Determine locale-specific suffixes for RC files
707        *
708        * We normalize the charset into a standard form,
709        * which has all '-' and '_' characters removed,
710        * and is lowercase.
711        */
712       gchar *normalized_locale;
713       
714       p = strchr (locale, '@');
715       length = p ? (p - locale) : strlen (locale);
716       
717       p = strchr (locale, '.');
718       if (p)
719         {
720           gchar *tmp1 = g_strndup (locale, p - locale + 1);
721           gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
722           
723           normalized_locale = g_strconcat (tmp1, tmp2, NULL);
724           g_free (tmp1);
725           g_free (tmp2);
726           
727           locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
728           length = p - locale;
729         }
730       else
731         normalized_locale = g_strndup (locale, length);
732       
733       p = strchr (normalized_locale, '_');
734       if (p)
735         {
736           locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
737           length = p - normalized_locale;
738         }
739       
740       locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
741       
742       g_free (normalized_locale);
743     }
744   
745   for (i = 0; gtk_rc_default_files[i] != NULL; i++)
746     {
747       /* Try to find a locale specific RC file corresponding to the
748        * current locale to parse before the default file.
749        */
750       for (j = n_locale_suffixes - 1; j >= 0; j--)
751         {
752           gchar *name = g_strconcat (gtk_rc_default_files[i],
753                                      ".",
754                                      locale_suffixes[j],
755                                      NULL);
756           gtk_rc_parse_file (context, name, GTK_PATH_PRIO_RC, FALSE);
757           g_free (name);
758         }
759       gtk_rc_parse_file (context, gtk_rc_default_files[i], GTK_PATH_PRIO_RC, FALSE);
760     }
761
762   for (j = 0; j < n_locale_suffixes; j++)
763     g_free (locale_suffixes[j]);
764 }
765
766 void
767 _gtk_rc_init (void)
768 {
769   static gboolean initialized = FALSE;
770
771   if (!initialized)
772     {
773       initialized = TRUE;
774       
775       module_path[0] = NULL;
776       gtk_rc_append_default_module_path();
777       
778       gtk_rc_add_initial_default_files ();
779     }
780   
781   gtk_rc_reparse_all_for_settings (gtk_settings_get_default (), TRUE);
782 }
783   
784 void
785 gtk_rc_parse_string (const gchar *rc_string)
786 {
787   g_return_if_fail (rc_string != NULL);
788
789   gtk_rc_parse_any (gtk_rc_context_get (gtk_settings_get_default ()),
790                     "-", -1, rc_string);        /* FIXME */
791 }
792
793 static void
794 gtk_rc_parse_file (GtkRcContext *context,
795                    const gchar  *filename,
796                    gint          priority,
797                    gboolean      reload)
798 {
799   GtkRcFile *rc_file = NULL;
800   struct stat statbuf;
801   GSList *tmp_list;
802   gint saved_priority;
803
804   g_return_if_fail (filename != NULL);
805
806   saved_priority = context->default_priority;
807   context->default_priority = priority;
808   
809   tmp_list = context->rc_files;
810   while (tmp_list)
811     {
812       rc_file = tmp_list->data;
813       if (!strcmp (rc_file->name, filename))
814         break;
815       
816       tmp_list = tmp_list->next;
817     }
818
819   if (!tmp_list)
820     {
821       rc_file = g_new (GtkRcFile, 1);
822       rc_file->name = g_strdup (filename);
823       rc_file->canonical_name = NULL;
824       rc_file->mtime = 0;
825       rc_file->reload = reload;
826
827       context->rc_files = g_slist_append (context->rc_files, rc_file);
828     }
829
830   if (!rc_file->canonical_name)
831     {
832       /* Get the absolute pathname */
833
834       if (g_path_is_absolute (rc_file->name))
835         rc_file->canonical_name = rc_file->name;
836       else
837         {
838           gchar *cwd;
839
840           cwd = g_get_current_dir ();
841           rc_file->canonical_name = g_build_filename (cwd, rc_file->name, NULL);
842           g_free (cwd);
843         }
844     }
845
846   if (!lstat (rc_file->canonical_name, &statbuf))
847     {
848       gint fd;
849       GSList *tmp_list;
850
851       rc_file->mtime = statbuf.st_mtime;
852
853       fd = open (rc_file->canonical_name, O_RDONLY);
854       if (fd < 0)
855         goto out;
856
857       /* Temporarily push directory name for this file on
858        * a stack of directory names while parsing it
859        */
860       rc_dir_stack = 
861         g_slist_prepend (rc_dir_stack,
862                          g_path_get_dirname (rc_file->canonical_name));
863       gtk_rc_parse_any (context, filename, fd, NULL);
864  
865       tmp_list = rc_dir_stack;
866       rc_dir_stack = rc_dir_stack->next;
867  
868       g_free (tmp_list->data);
869       g_slist_free_1 (tmp_list);
870
871       close (fd);
872     }
873
874  out:
875   context->default_priority = saved_priority;
876 }
877
878 void
879 gtk_rc_parse (const gchar *filename)
880 {
881   g_return_if_fail (filename != NULL);
882
883   gtk_rc_parse_file (gtk_rc_context_get (gtk_settings_get_default ()),
884                      filename, GTK_PATH_PRIO_RC, TRUE); /* FIXME */
885 }
886
887 /* Handling of RC styles */
888
889 GType
890 gtk_rc_style_get_type (void)
891 {
892   static GType object_type = 0;
893
894   if (!object_type)
895     {
896       static const GTypeInfo object_info =
897       {
898         sizeof (GtkRcStyleClass),
899         (GBaseInitFunc) NULL,
900         (GBaseFinalizeFunc) NULL,
901         (GClassInitFunc) gtk_rc_style_class_init,
902         NULL,           /* class_finalize */
903         NULL,           /* class_data */
904         sizeof (GtkRcStyle),
905         0,              /* n_preallocs */
906         (GInstanceInitFunc) gtk_rc_style_init,
907       };
908       
909       object_type = g_type_register_static (G_TYPE_OBJECT,
910                                             "GtkRcStyle",
911                                             &object_info, 0);
912     }
913   
914   return object_type;
915 }
916
917 static void
918 gtk_rc_style_init (GtkRcStyle *style)
919 {
920   guint i;
921
922   style->name = NULL;
923   style->font_desc = NULL;
924
925   for (i = 0; i < 5; i++)
926     {
927       static const GdkColor init_color = { 0, 0, 0, 0, };
928
929       style->bg_pixmap_name[i] = NULL;
930       style->color_flags[i] = 0;
931       style->fg[i] = init_color;
932       style->bg[i] = init_color;
933       style->text[i] = init_color;
934       style->base[i] = init_color;
935     }
936   style->xthickness = -1;
937   style->ythickness = -1;
938   style->rc_properties = NULL;
939
940   style->rc_style_lists = NULL;
941   style->icon_factories = NULL;
942 }
943
944 static void
945 gtk_rc_style_class_init (GtkRcStyleClass *klass)
946 {
947   GObjectClass *object_class = G_OBJECT_CLASS (klass);
948   
949   parent_class = g_type_class_peek_parent (klass);
950
951   object_class->finalize = gtk_rc_style_finalize;
952
953   klass->parse = NULL;
954   klass->create_rc_style = gtk_rc_style_real_create_rc_style;
955   klass->merge = gtk_rc_style_real_merge;
956   klass->create_style = gtk_rc_style_real_create_style;
957 }
958
959 static void
960 gtk_rc_style_finalize (GObject *object)
961 {
962   GSList *tmp_list1, *tmp_list2;
963   GtkRcStyle *rc_style;
964   gint i;
965
966   rc_style = GTK_RC_STYLE (object);
967   
968   if (rc_style->name)
969     g_free (rc_style->name);
970   if (rc_style->font_desc)
971     pango_font_description_free (rc_style->font_desc);
972       
973   for (i = 0; i < 5; i++)
974     if (rc_style->bg_pixmap_name[i])
975       g_free (rc_style->bg_pixmap_name[i]);
976   
977   /* Now remove all references to this rc_style from
978    * realized_style_ht
979    */
980   tmp_list1 = rc_style->rc_style_lists;
981   while (tmp_list1)
982     {
983       GSList *rc_styles = tmp_list1->data;
984       GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
985       gtk_style_unref (style);
986
987       /* Remove the list of styles from the other rc_styles
988        * in the list
989        */
990       tmp_list2 = rc_styles;
991       while (tmp_list2)
992         {
993           GtkRcStyle *other_style = tmp_list2->data;
994
995           if (other_style != rc_style)
996             other_style->rc_style_lists = g_slist_remove_all (other_style->rc_style_lists,
997                                                               rc_styles);
998           tmp_list2 = tmp_list2->next;
999         }
1000
1001       /* And from the hash table itself
1002        */
1003       g_hash_table_remove (realized_style_ht, rc_styles);
1004       g_slist_free (rc_styles);
1005
1006       tmp_list1 = tmp_list1->next;
1007     }
1008   g_slist_free (rc_style->rc_style_lists);
1009
1010   if (rc_style->rc_properties)
1011     {
1012       guint i;
1013
1014       for (i = 0; i < rc_style->rc_properties->len; i++)
1015         {
1016           GtkRcProperty *node = &g_array_index (rc_style->rc_properties, GtkRcProperty, i);
1017
1018           g_free (node->origin);
1019           g_value_unset (&node->value);
1020         }
1021       g_array_free (rc_style->rc_properties, TRUE);
1022       rc_style->rc_properties = NULL;
1023     }
1024
1025   tmp_list1 = rc_style->icon_factories;
1026   while (tmp_list1)
1027     {
1028       g_object_unref (G_OBJECT (tmp_list1->data));
1029
1030       tmp_list1 = tmp_list1->next;
1031     }
1032   g_slist_free (rc_style->icon_factories);
1033   
1034   G_OBJECT_CLASS (parent_class)->finalize (object);
1035 }
1036
1037 GtkRcStyle *
1038 gtk_rc_style_new (void)
1039 {
1040   GtkRcStyle *style;
1041   
1042   style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
1043   
1044   return style;
1045 }
1046
1047 /**
1048  * gtk_rc_style_copy:
1049  * @orig: the style to copy
1050  * 
1051  * Makes a copy of the specified #GtkRcStyle. This function
1052  * will correctly copy an RC style that is a member of a class
1053  * derived from #GtkRcStyle.
1054  * 
1055  * Return value: the resulting #GtkRcStyle
1056  **/
1057 GtkRcStyle *
1058 gtk_rc_style_copy (GtkRcStyle *orig)
1059 {
1060   GtkRcStyle *style;
1061
1062   g_return_val_if_fail (GTK_IS_RC_STYLE (orig), NULL);
1063   
1064   style = GTK_RC_STYLE_GET_CLASS (orig)->create_rc_style (orig);
1065   GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
1066
1067   return style;
1068 }
1069
1070 void      
1071 gtk_rc_style_ref (GtkRcStyle  *rc_style)
1072 {
1073   g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1074
1075   g_object_ref (G_OBJECT (rc_style));
1076 }
1077
1078 void      
1079 gtk_rc_style_unref (GtkRcStyle  *rc_style)
1080 {
1081   g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1082
1083   g_object_unref (G_OBJECT (rc_style));
1084 }
1085
1086 static GtkRcStyle *
1087 gtk_rc_style_real_create_rc_style (GtkRcStyle *style)
1088 {
1089   return GTK_RC_STYLE (g_object_new (G_OBJECT_TYPE (style), NULL));
1090 }
1091
1092 static gint
1093 gtk_rc_properties_cmp (gconstpointer bsearch_node1,
1094                        gconstpointer bsearch_node2)
1095 {
1096   const GtkRcProperty *prop1 = bsearch_node1;
1097   const GtkRcProperty *prop2 = bsearch_node2;
1098
1099   if (prop1->type_name == prop2->type_name)
1100     return prop1->property_name < prop2->property_name ? -1 : prop1->property_name == prop2->property_name ? 0 : 1;
1101   else
1102     return prop1->type_name < prop2->type_name ? -1 : 1;
1103 }
1104
1105 static void
1106 insert_rc_property (GtkRcStyle    *style,
1107                     GtkRcProperty *property,
1108                     gboolean       replace)
1109 {
1110   guint i;
1111   GtkRcProperty *new_property = NULL;
1112   GtkRcProperty key = { 0, 0, NULL, { 0, }, };
1113
1114   key.type_name = property->type_name;
1115   key.property_name = property->property_name;
1116
1117   if (!style->rc_properties)
1118     style->rc_properties = g_array_new (FALSE, FALSE, sizeof (GtkRcProperty));
1119
1120   i = 0;
1121   while (i < style->rc_properties->len)
1122     {
1123       gint cmp = gtk_rc_properties_cmp (&key, &g_array_index (style->rc_properties, GtkRcProperty, i));
1124
1125       if (cmp == 0)
1126         {
1127           if (replace)
1128             {
1129               new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
1130               
1131               g_free (new_property->origin);
1132               g_value_unset (&new_property->value);
1133               
1134               *new_property = key;
1135               break;
1136             }
1137           else
1138             return;
1139         }
1140       else if (cmp < 0)
1141         break;
1142
1143       i++;
1144     }
1145
1146   if (!new_property)
1147     {
1148       g_array_insert_val (style->rc_properties, i, key);
1149       new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
1150     }
1151
1152   new_property->origin = g_strdup (property->origin);
1153   g_value_init (&new_property->value, G_VALUE_TYPE (&property->value));
1154   g_value_copy (&property->value, &new_property->value);
1155 }
1156
1157 static void
1158 gtk_rc_style_real_merge (GtkRcStyle *dest,
1159                          GtkRcStyle *src)
1160 {
1161   gint i;
1162   
1163   for (i = 0; i < 5; i++)
1164     {
1165       if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
1166         dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
1167       
1168       if (!(dest->color_flags[i] & GTK_RC_FG) && 
1169           src->color_flags[i] & GTK_RC_FG)
1170         {
1171           dest->fg[i] = src->fg[i];
1172           dest->color_flags[i] |= GTK_RC_FG;
1173         }
1174       if (!(dest->color_flags[i] & GTK_RC_BG) && 
1175           src->color_flags[i] & GTK_RC_BG)
1176         {
1177           dest->bg[i] = src->bg[i];
1178           dest->color_flags[i] |= GTK_RC_BG;
1179         }
1180       if (!(dest->color_flags[i] & GTK_RC_TEXT) && 
1181           src->color_flags[i] & GTK_RC_TEXT)
1182         {
1183           dest->text[i] = src->text[i];
1184           dest->color_flags[i] |= GTK_RC_TEXT;
1185         }
1186       if (!(dest->color_flags[i] & GTK_RC_BASE) && 
1187           src->color_flags[i] & GTK_RC_BASE)
1188         {
1189           dest->base[i] = src->base[i];
1190           dest->color_flags[i] |= GTK_RC_BASE;
1191         }
1192     }
1193
1194   if (dest->xthickness < 0 && src->xthickness >= 0)
1195     dest->xthickness = src->xthickness;
1196   if (dest->ythickness < 0 && src->ythickness >= 0)
1197     dest->ythickness = src->ythickness;
1198
1199   if (src->font_desc)
1200     {
1201       if (!dest->font_desc)
1202         dest->font_desc = pango_font_description_copy (src->font_desc);
1203       else
1204         pango_font_description_merge (dest->font_desc, src->font_desc, FALSE);
1205     }
1206
1207   if (src->rc_properties)
1208     {
1209       guint i;
1210
1211       for (i = 0; i < src->rc_properties->len; i++)
1212         insert_rc_property (dest,
1213                             &g_array_index (src->rc_properties, GtkRcProperty, i),
1214                             FALSE);
1215     }
1216 }
1217
1218 static GtkStyle *
1219 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
1220 {
1221   return gtk_style_new ();
1222 }
1223
1224 static void
1225 gtk_rc_clear_hash_node (gpointer key, 
1226                         gpointer data, 
1227                         gpointer user_data)
1228 {
1229   gtk_rc_style_unref (data);
1230 }
1231
1232 static void
1233 gtk_rc_free_rc_sets (GSList *slist)
1234 {
1235   while (slist)
1236     {
1237       GtkRcSet *rc_set;
1238
1239       rc_set = slist->data;
1240       g_pattern_spec_free (rc_set->pspec);
1241       g_free (rc_set);
1242
1243       slist = slist->next;
1244     }
1245 }
1246
1247 static void
1248 gtk_rc_clear_styles (GtkRcContext *context)
1249 {
1250   /* Clear out all old rc_styles */
1251
1252   if (context->rc_style_ht)
1253     {
1254       g_hash_table_foreach (context->rc_style_ht, gtk_rc_clear_hash_node, NULL);
1255       g_hash_table_destroy (context->rc_style_ht);
1256       context->rc_style_ht = NULL;
1257     }
1258
1259   gtk_rc_free_rc_sets (context->rc_sets_widget);
1260   g_slist_free (context->rc_sets_widget);
1261   context->rc_sets_widget = NULL;
1262
1263   gtk_rc_free_rc_sets (context->rc_sets_widget_class);
1264   g_slist_free (context->rc_sets_widget_class);
1265   context->rc_sets_widget_class = NULL;
1266
1267   gtk_rc_free_rc_sets (context->rc_sets_class);
1268   g_slist_free (context->rc_sets_class);
1269   context->rc_sets_class = NULL;
1270 }
1271
1272 /* Reset all our widgets. Also, we have to invalidate cached icons in
1273  * icon sets so they get re-rendered.
1274  */
1275 static void
1276 gtk_rc_reset_widgets (GtkRcContext *context)
1277 {
1278   GList *list, *toplevels;
1279   
1280   _gtk_icon_set_invalidate_caches ();
1281   
1282   toplevels = gtk_window_list_toplevels ();
1283   g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1284   
1285   for (list = toplevels; list; list = list->next)
1286     {
1287       gtk_widget_reset_rc_styles (list->data);
1288       gtk_widget_unref (list->data);
1289     }
1290   g_list_free (toplevels);
1291 }
1292
1293 /**
1294  * gtk_rc_reparse_all_for_settings:
1295  * @settings: a #GtkSettings
1296  * @force_load: load whether or not anything changed
1297  * 
1298  * If the modification time on any previously read file
1299  * for the given #GtkSettings has changed, discard all style information
1300  * and then reread all previously read RC files.
1301  * 
1302  * Return value: %TRUE if the files were reread.
1303  **/
1304 gboolean
1305 gtk_rc_reparse_all_for_settings (GtkSettings *settings,
1306                                  gboolean     force_load)
1307 {
1308   gboolean mtime_modified = FALSE;
1309   GtkRcFile *rc_file;
1310   GSList *tmp_list;
1311   GtkRcContext *context;
1312
1313   struct stat statbuf;
1314
1315   g_return_val_if_fail (GTK_IS_SETTINGS (settings), FALSE);
1316
1317   context = gtk_rc_context_get (settings);
1318
1319   if (!force_load)
1320     {
1321       /* Check through and see if any of the RC's have had their
1322        * mtime modified. If so, reparse everything.
1323        */
1324       tmp_list = context->rc_files;
1325       while (tmp_list)
1326         {
1327           rc_file = tmp_list->data;
1328           
1329           if (!lstat (rc_file->name, &statbuf) && 
1330               (statbuf.st_mtime > rc_file->mtime))
1331             {
1332               mtime_modified = TRUE;
1333               break;
1334             }
1335           
1336           tmp_list = tmp_list->next;
1337         }
1338     }
1339       
1340   if (force_load || mtime_modified)
1341     {
1342       GSList *old_files;
1343       
1344       gtk_rc_clear_styles (context);
1345       g_object_freeze_notify (G_OBJECT (context->settings));
1346
1347       old_files = context->rc_files;
1348       context->rc_files = NULL;
1349
1350       gtk_rc_parse_default_files (context);
1351
1352       tmp_list = old_files;
1353       while (tmp_list)
1354         {
1355           rc_file = tmp_list->data;
1356           if (rc_file->reload)
1357             gtk_rc_parse_file (context, rc_file->name, GTK_PATH_PRIO_RC, TRUE);
1358
1359           if (rc_file->canonical_name != rc_file->name)
1360             g_free (rc_file->canonical_name);
1361           g_free (rc_file->name);
1362           g_free (rc_file);
1363           
1364           tmp_list = tmp_list->next;
1365         }
1366
1367       g_slist_free (old_files);;
1368
1369       g_free (context->theme_name);
1370       g_free (context->key_theme_name);
1371       g_object_get (context->settings,
1372                     "gtk-theme-name", &context->theme_name,
1373                     "gtk-key-theme-name", &context->key_theme_name,
1374                     NULL);
1375
1376       if (context->theme_name && context->theme_name[0])
1377         gtk_rc_parse_named (context, context->theme_name, NULL);
1378       if (context->key_theme_name && context->key_theme_name[0])
1379         gtk_rc_parse_named (context, context->key_theme_name, "key");
1380       
1381       g_object_thaw_notify (G_OBJECT (context->settings));
1382
1383       gtk_rc_reset_widgets (context);
1384     }
1385
1386   return mtime_modified;
1387 }
1388
1389 /**
1390  * gtk_rc_reparse_all:
1391  * 
1392  * If the modification time on any previously read file for the
1393  * default #GtkSettings has changed, discard all style information
1394  * and then reread all previously read RC files.
1395  * 
1396  * Return value:  %TRUE if the files were reread.
1397  **/
1398 gboolean
1399 gtk_rc_reparse_all (void)
1400 {
1401   return gtk_rc_reparse_all_for_settings (gtk_settings_get_default (), FALSE);
1402 }
1403
1404 static GSList *
1405 gtk_rc_styles_match (GSList       *rc_styles,
1406                      GSList       *sets,
1407                      guint         path_length,
1408                      const gchar  *path,
1409                      const gchar  *path_reversed)
1410                      
1411 {
1412   GtkRcSet *rc_set;
1413
1414   while (sets)
1415     {
1416       rc_set = sets->data;
1417       sets = sets->next;
1418
1419       if (g_pattern_match (rc_set->pspec, path_length, path, path_reversed))
1420         rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
1421     }
1422   
1423   return rc_styles;
1424 }
1425
1426 /**
1427  * gtk_rc_get_style:
1428  * @widget: a #GtkWidget
1429  * 
1430  * Finds all matching RC styles for a given widget,
1431  * composites them together, and then creates a 
1432  * #GtkStyle representing the composite appearance.
1433  * (GTK+ actually keeps a cache of previously 
1434  * created styles, so a new style may not be
1435  * created.)
1436  * 
1437  * Returns: the resulting style. No refcount is added
1438  *   to the returned style, so if you want to save this
1439  *   style around, you should add a reference yourself.
1440  **/
1441 GtkStyle *
1442 gtk_rc_get_style (GtkWidget *widget)
1443 {
1444   GtkRcStyle *widget_rc_style;
1445   GSList *rc_styles = NULL;
1446   GtkRcContext *context;
1447
1448   static guint rc_style_key_id = 0;
1449
1450   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1451
1452   context = gtk_rc_context_get (gtk_widget_get_settings (widget));
1453
1454   /* We allow the specification of a single rc style to be bound
1455    * tightly to a widget, for application modifications
1456    */
1457   if (!rc_style_key_id)
1458     rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1459
1460   widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
1461                                                rc_style_key_id);
1462
1463   if (widget_rc_style)
1464     rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
1465   
1466   if (context->rc_sets_widget)
1467     {
1468       gchar *path, *path_reversed;
1469       guint path_length;
1470
1471       gtk_widget_path (widget, &path_length, &path, &path_reversed);
1472       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, path, path_reversed);
1473       g_free (path);
1474       g_free (path_reversed);
1475     }
1476   
1477   if (context->rc_sets_widget_class)
1478     {
1479       gchar *path, *path_reversed;
1480       guint path_length;
1481
1482       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1483       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, path, path_reversed);
1484       g_free (path);
1485       g_free (path_reversed);
1486     }
1487
1488   if (context->rc_sets_class)
1489     {
1490       GtkType type;
1491
1492       type = GTK_OBJECT_TYPE (widget);
1493       while (type)
1494         {
1495           const gchar *path;
1496           gchar *path_reversed;
1497           guint path_length;
1498
1499           path = gtk_type_name (type);
1500           path_length = strlen (path);
1501           path_reversed = g_strdup (path);
1502           g_strreverse (path_reversed);
1503           
1504           rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
1505           g_free (path_reversed);
1506       
1507           type = gtk_type_parent (type);
1508         }
1509     }
1510   
1511   if (rc_styles)
1512     return gtk_rc_init_style (rc_styles);
1513
1514   return NULL;
1515 }
1516
1517 /**
1518  * gtk_rc_get_style_by_paths:
1519  * @settings: a #GtkSettings object
1520  * @widget_path: the widget path to use when looking up the style, or %NULL
1521  * @class_path: the class path to use when looking up the style, or %NULL
1522  * @type: a type that will be used along with parent types of this type
1523  *        when matching against class styles, or #G_TYPE_NONE
1524  * 
1525  * Creates up a #GtkStyle from styles defined in a RC file by providing
1526  * the raw components used in matching. This function may be useful
1527  * when creating pseudo-widgets that should be themed like widgets but
1528  * don't actually have corresponding GTK+ widgets. An example of this
1529  * would be items inside a GNOME canvas widget.
1530  *
1531  * The action of gtk_rc_get_style() is similar to:
1532  * <informalexample><programlisting>
1533  * <!> gtk_widget_path (widget, NULL, &amp;path, NULL);
1534  * <!> gtk_widget_class_path (widget, NULL, &amp;class_path, NULL);
1535  * <!> gtk_rc_get_style_by_paths (gtk_widget_get_settings (widget), path, class_path,
1536  * <!>                            G_OBJECT_TYPE (widget));
1537  * </programlisting></informalexample>
1538  * 
1539  * Return value: A style created by matching with the supplied paths,
1540  *   or %NULL if nothing matching was specified and the default style should
1541  *   be used. The returned value is owned by GTK+ as part of an internal cache,
1542  *   so you must call g_object_ref() on the returned value if you want to
1543  *   keep a reference to it.
1544  **/
1545 GtkStyle *
1546 gtk_rc_get_style_by_paths (GtkSettings *settings,
1547                            const char  *widget_path,
1548                            const char  *class_path,
1549                            GType        type)
1550 {
1551   /* We duplicate the code from above to avoid slowing down the above
1552    * by generating paths when we don't need them. I don't know if
1553    * this is really worth it.
1554    */
1555   GSList *rc_styles = NULL;
1556   GtkRcContext *context;
1557
1558   g_return_val_if_fail (GTK_IS_SETTINGS (settings), NULL);
1559
1560   context = gtk_rc_context_get (settings);
1561
1562   if (context->rc_sets_widget)
1563     {
1564       gchar *path_reversed;
1565       guint path_length;
1566
1567       path_length = strlen (widget_path);
1568       path_reversed = g_strdup (widget_path);
1569       g_strreverse (path_reversed);
1570
1571       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, widget_path, path_reversed);
1572       g_free (path_reversed);
1573     }
1574   
1575   if (context->rc_sets_widget_class)
1576     {
1577       gchar *path_reversed;
1578       guint path_length;
1579
1580       path_length = strlen (class_path);
1581       path_reversed = g_strdup (class_path);
1582       g_strreverse (path_reversed);
1583
1584       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, class_path, path_reversed);
1585       g_free (path_reversed);
1586     }
1587
1588   if (type != G_TYPE_NONE && context->rc_sets_class)
1589     {
1590       while (type)
1591         {
1592           const gchar *path;
1593           gchar *path_reversed;
1594           guint path_length;
1595
1596           path = g_type_name (type);
1597           path_length = strlen (path);
1598           path_reversed = g_strdup (path);
1599           g_strreverse (path_reversed);
1600           
1601           rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
1602           g_free (path_reversed);
1603       
1604           type = g_type_parent (type);
1605         }
1606     }
1607   
1608   if (rc_styles)
1609     return gtk_rc_init_style (rc_styles);
1610
1611   return NULL;
1612 }
1613
1614 static GSList *
1615 gtk_rc_add_rc_sets (GSList      *slist,
1616                     GtkRcStyle  *rc_style,
1617                     const gchar *pattern)
1618 {
1619   GtkRcStyle *new_style;
1620   GtkRcSet *rc_set;
1621   guint i;
1622   
1623   new_style = gtk_rc_style_new ();
1624   *new_style = *rc_style;
1625   new_style->name = g_strdup (rc_style->name);
1626   if (rc_style->font_desc)
1627     new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
1628   
1629   for (i = 0; i < 5; i++)
1630     new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1631   
1632   rc_set = g_new (GtkRcSet, 1);
1633   rc_set->pspec = g_pattern_spec_new (pattern);
1634   rc_set->rc_style = rc_style;
1635   
1636   return g_slist_prepend (slist, rc_set);
1637 }
1638
1639 void
1640 gtk_rc_add_widget_name_style (GtkRcStyle  *rc_style,
1641                               const gchar *pattern)
1642 {
1643   GtkRcContext *context;
1644   
1645   g_return_if_fail (rc_style != NULL);
1646   g_return_if_fail (pattern != NULL);
1647
1648   context = gtk_rc_context_get (gtk_settings_get_default ());
1649   
1650   context->rc_sets_widget = gtk_rc_add_rc_sets (context->rc_sets_widget, rc_style, pattern);
1651 }
1652
1653 void
1654 gtk_rc_add_widget_class_style (GtkRcStyle  *rc_style,
1655                                const gchar *pattern)
1656 {
1657   GtkRcContext *context;
1658   
1659   g_return_if_fail (rc_style != NULL);
1660   g_return_if_fail (pattern != NULL);
1661
1662   context = gtk_rc_context_get (gtk_settings_get_default ());
1663   
1664   context->rc_sets_widget_class = gtk_rc_add_rc_sets (context->rc_sets_widget_class, rc_style, pattern);
1665 }
1666
1667 void
1668 gtk_rc_add_class_style (GtkRcStyle  *rc_style,
1669                         const gchar *pattern)
1670 {
1671   GtkRcContext *context;
1672   
1673   g_return_if_fail (rc_style != NULL);
1674   g_return_if_fail (pattern != NULL);
1675
1676   context = gtk_rc_context_get (gtk_settings_get_default ());
1677   
1678   context->rc_sets_class = gtk_rc_add_rc_sets (context->rc_sets_class, rc_style, pattern);
1679 }
1680
1681 GScanner*
1682 gtk_rc_scanner_new (void)
1683 {
1684   return g_scanner_new (&gtk_rc_scanner_config);
1685 }
1686
1687 static void
1688 gtk_rc_parse_any (GtkRcContext *context,
1689                   const gchar  *input_name,
1690                   gint          input_fd,
1691                   const gchar  *input_string)
1692 {
1693   GScanner *scanner;
1694   guint    i;
1695   gboolean done;
1696
1697   scanner = gtk_rc_scanner_new ();
1698   
1699   if (input_fd >= 0)
1700     {
1701       g_assert (input_string == NULL);
1702       
1703       g_scanner_input_file (scanner, input_fd);
1704     }
1705   else
1706     {
1707       g_assert (input_string != NULL);
1708       
1709       g_scanner_input_text (scanner, input_string, strlen (input_string));
1710     }
1711   scanner->input_name = input_name;
1712
1713   for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1714     g_scanner_scope_add_symbol (scanner, 0, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1715   
1716   done = FALSE;
1717   while (!done)
1718     {
1719       if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1720         done = TRUE;
1721       else
1722         {
1723           guint expected_token;
1724           
1725           expected_token = gtk_rc_parse_statement (context, scanner);
1726
1727           if (expected_token != G_TOKEN_NONE)
1728             {
1729               gchar *symbol_name;
1730               gchar *msg;
1731               
1732               msg = NULL;
1733               symbol_name = NULL;
1734               if (scanner->scope_id == 0)
1735                 {
1736                   /* if we are in scope 0, we know the symbol names
1737                    * that are associated with certain token values.
1738                    * so we look them up to make the error messages
1739                    * more readable.
1740                    */
1741                   if (expected_token > GTK_RC_TOKEN_INVALID &&
1742                       expected_token < GTK_RC_TOKEN_LAST)
1743                     {
1744                       for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1745                         if (symbols[i].token == expected_token)
1746                           msg = symbols[i].name;
1747                       if (msg)
1748                         msg = g_strconcat ("e.g. `", msg, "'", NULL);
1749                     }
1750                   if (scanner->token > GTK_RC_TOKEN_INVALID &&
1751                       scanner->token < GTK_RC_TOKEN_LAST)
1752                     {
1753                       symbol_name = "???";
1754                       for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1755                         if (symbols[i].token == scanner->token)
1756                           symbol_name = symbols[i].name;
1757                     }
1758                 }
1759               g_scanner_unexp_token (scanner,
1760                                      expected_token,
1761                                      NULL,
1762                                      "keyword",
1763                                      symbol_name,
1764                                      msg,
1765                                      TRUE);
1766               g_free (msg);
1767               done = TRUE;
1768             }
1769         }
1770     }
1771   
1772   g_scanner_destroy (scanner);
1773 }
1774
1775 static guint       
1776 gtk_rc_styles_hash (const GSList *rc_styles)
1777 {
1778   guint result;
1779   
1780   result = 0;
1781   while (rc_styles)
1782     {
1783       result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1784       rc_styles = rc_styles->next;
1785     }
1786   
1787   return result;
1788 }
1789
1790 static gboolean
1791 gtk_rc_styles_equal (const GSList *a,
1792                      const GSList *b)
1793 {
1794   while (a && b)
1795     {
1796       if (a->data != b->data)
1797         return FALSE;
1798       a = a->next;
1799       b = b->next;
1800     }
1801   
1802   return (a == b);
1803 }
1804
1805 static guint
1806 gtk_rc_style_hash (const gchar *name)
1807 {
1808   guint result;
1809   
1810   result = 0;
1811   while (*name)
1812     result += (result << 3) + *name++;
1813   
1814   return result;
1815 }
1816
1817 static gboolean
1818 gtk_rc_style_equal (const gchar *a,
1819                     const gchar *b)
1820 {
1821   return (strcmp (a, b) == 0);
1822 }
1823
1824 static GtkRcStyle*
1825 gtk_rc_style_find (GtkRcContext *context,
1826                    const gchar  *name)
1827 {
1828   if (context->rc_style_ht)
1829     return g_hash_table_lookup (context->rc_style_ht, (gpointer) name);
1830   else
1831     return NULL;
1832 }
1833
1834 static GtkStyle *
1835 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1836 {
1837   GtkStyle *style;
1838
1839   style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
1840
1841   style->rc_style = rc_style;
1842
1843   gtk_rc_style_ref (rc_style);
1844   
1845   GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);  
1846
1847   return style;
1848 }
1849
1850 /* Reuses or frees rc_styles */
1851 static GtkStyle *
1852 gtk_rc_init_style (GSList *rc_styles)
1853 {
1854   GtkStyle *style = NULL;
1855   gint i;
1856
1857   g_return_val_if_fail (rc_styles != NULL, NULL);
1858   
1859   if (!realized_style_ht)
1860     realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
1861  (GEqualFunc) gtk_rc_styles_equal);
1862
1863   style = g_hash_table_lookup (realized_style_ht, rc_styles);
1864
1865   if (!style)
1866     {
1867       GtkRcStyle *base_style = NULL;
1868       GtkRcStyle *proto_style;
1869       GtkRcStyleClass *proto_style_class;
1870       GSList *tmp_styles;
1871       GType rc_style_type = GTK_TYPE_RC_STYLE;
1872
1873       /* Find the first derived style in the list, and use that to
1874        * create the merged style. If we only have raw GtkRcStyles, use
1875        * the first style to create the merged style.
1876        */
1877       base_style = rc_styles->data;
1878       tmp_styles = rc_styles;
1879       while (tmp_styles)
1880         {
1881           GtkRcStyle *rc_style = tmp_styles->data;
1882           
1883           if (G_OBJECT_TYPE (rc_style) != rc_style_type)
1884             {
1885               base_style = rc_style;
1886               break;
1887             }
1888           
1889           tmp_styles = tmp_styles->next;
1890         }
1891       
1892       proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
1893       proto_style = proto_style_class->create_rc_style (base_style);
1894       
1895       tmp_styles = rc_styles;
1896       while (tmp_styles)
1897         {
1898           GtkRcStyle *rc_style = tmp_styles->data;
1899           GSList *factories;
1900           
1901           proto_style_class->merge (proto_style, rc_style);       
1902           
1903           /* Point from each rc_style to the list of styles */
1904           if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
1905             rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
1906
1907           factories = g_slist_copy (rc_style->icon_factories);
1908           if (factories)
1909             {
1910               GSList *iter;
1911               
1912               iter = factories;
1913               while (iter != NULL)
1914                 {
1915                   g_object_ref (G_OBJECT (iter->data));
1916                   iter = g_slist_next (iter);
1917                 }
1918
1919               proto_style->icon_factories = g_slist_concat (proto_style->icon_factories,
1920                                                             factories);
1921
1922             }
1923           
1924           tmp_styles = tmp_styles->next;
1925         }
1926
1927       for (i = 0; i < 5; i++)
1928         if (proto_style->bg_pixmap_name[i] &&
1929             (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1930           {
1931             g_free (proto_style->bg_pixmap_name[i]);
1932             proto_style->bg_pixmap_name[i] = NULL;
1933           }
1934
1935       style = gtk_rc_style_to_style (proto_style);
1936       gtk_rc_style_unref (proto_style);
1937
1938       g_hash_table_insert (realized_style_ht, rc_styles, style);
1939     }
1940   else
1941     g_slist_free (rc_styles);
1942
1943   return style;
1944 }
1945
1946 /*********************
1947  * Parsing functions *
1948  *********************/
1949
1950 static guint
1951 rc_parse_token_or_compound (GScanner  *scanner,
1952                             GString   *gstring,
1953                             GTokenType delimiter)
1954 {
1955   guint token = g_scanner_get_next_token (scanner);
1956
1957   /* we either scan a single token (skipping comments)
1958    * or a compund statement.
1959    * compunds are enclosed in (), [] or {} braces, we read
1960    * them in via deep recursion.
1961    */
1962
1963   switch (token)
1964     {
1965       gchar *string;
1966     case G_TOKEN_INT:
1967       g_string_append_printf (gstring, " 0x%lx", scanner->value.v_int);
1968       break;
1969     case G_TOKEN_FLOAT:
1970       g_string_append_printf (gstring, " %f", scanner->value.v_float);
1971       break;
1972     case G_TOKEN_STRING:
1973       string = g_strescape (scanner->value.v_string, NULL);
1974       g_string_append (gstring, " \"");
1975       g_string_append (gstring, string);
1976       g_string_append_c (gstring, '"');
1977       g_free (string);
1978       break;
1979     case G_TOKEN_IDENTIFIER:
1980       g_string_append_c (gstring, ' ');
1981       g_string_append (gstring, scanner->value.v_identifier);
1982       break;
1983     case G_TOKEN_COMMENT_SINGLE:
1984     case G_TOKEN_COMMENT_MULTI:
1985       return rc_parse_token_or_compound (scanner, gstring, delimiter);
1986     case G_TOKEN_LEFT_PAREN:
1987       g_string_append_c (gstring, ' ');
1988       g_string_append_c (gstring, token);
1989       token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_PAREN);
1990       if (token != G_TOKEN_NONE)
1991         return token;
1992       break;
1993     case G_TOKEN_LEFT_CURLY:
1994       g_string_append_c (gstring, ' ');
1995       g_string_append_c (gstring, token);
1996       token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_CURLY);
1997       if (token != G_TOKEN_NONE)
1998         return token;
1999       break;
2000     case G_TOKEN_LEFT_BRACE:
2001       g_string_append_c (gstring, ' ');
2002       g_string_append_c (gstring, token);
2003       token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_BRACE);
2004       if (token != G_TOKEN_NONE)
2005         return token;
2006       break;
2007     default:
2008       if (token >= 256 || token < 1)
2009         return delimiter ? delimiter : G_TOKEN_STRING;
2010       g_string_append_c (gstring, ' ');
2011       g_string_append_c (gstring, token);
2012       if (token == delimiter)
2013         return G_TOKEN_NONE;
2014       break;
2015     }
2016   if (!delimiter)
2017     return G_TOKEN_NONE;
2018   else
2019     return rc_parse_token_or_compound (scanner, gstring, delimiter);
2020 }
2021
2022 static guint
2023 gtk_rc_parse_assignment (GScanner      *scanner,
2024                          GtkRcProperty *prop)
2025 {
2026   gboolean scan_identifier = scanner->config->scan_identifier;
2027   gboolean scan_symbols = scanner->config->scan_symbols;
2028   gboolean identifier_2_string = scanner->config->identifier_2_string;
2029   gboolean char_2_token = scanner->config->char_2_token;
2030   gboolean scan_identifier_NULL = scanner->config->scan_identifier_NULL;
2031   gboolean numbers_2_int = scanner->config->numbers_2_int;
2032   gboolean negate = FALSE;
2033   guint token;
2034
2035   /* check that this is an assignment */
2036   if (g_scanner_get_next_token (scanner) != '=')
2037     return '=';
2038
2039   /* adjust scanner mode */
2040   scanner->config->scan_identifier = TRUE;
2041   scanner->config->scan_symbols = FALSE;
2042   scanner->config->identifier_2_string = FALSE;
2043   scanner->config->char_2_token = TRUE;
2044   scanner->config->scan_identifier_NULL = FALSE;
2045   scanner->config->numbers_2_int = TRUE;
2046
2047   /* record location */
2048   prop->origin = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
2049
2050   /* parse optional sign */
2051   if (g_scanner_peek_next_token (scanner) == '-')
2052     {
2053       g_scanner_get_next_token (scanner); /* eat sign */
2054       negate = TRUE;
2055     }
2056
2057   /* parse one of LONG, DOUBLE and STRING or, if that fails, create an unparsed compund */
2058   token = g_scanner_peek_next_token (scanner);
2059   switch (token)
2060     {
2061     case G_TOKEN_INT:
2062       g_scanner_get_next_token (scanner);
2063       g_value_init (&prop->value, G_TYPE_LONG);
2064       g_value_set_long (&prop->value, negate ? -scanner->value.v_int : scanner->value.v_int);
2065       token = G_TOKEN_NONE;
2066       break;
2067     case G_TOKEN_FLOAT:
2068       g_scanner_get_next_token (scanner);
2069       g_value_init (&prop->value, G_TYPE_DOUBLE);
2070       g_value_set_double (&prop->value, negate ? -scanner->value.v_float : scanner->value.v_float);
2071       token = G_TOKEN_NONE;
2072       break;
2073     case G_TOKEN_STRING:
2074       g_scanner_get_next_token (scanner);
2075       if (negate)
2076         token = G_TOKEN_INT;
2077       else
2078         {
2079           g_value_init (&prop->value, G_TYPE_STRING);
2080           g_value_set_string (&prop->value, scanner->value.v_string);
2081           token = G_TOKEN_NONE;
2082         }
2083       break;
2084     case G_TOKEN_IDENTIFIER:
2085     case G_TOKEN_LEFT_PAREN:
2086     case G_TOKEN_LEFT_CURLY:
2087     case G_TOKEN_LEFT_BRACE:
2088       if (!negate)
2089         {
2090           GString *gstring = g_string_new ("");
2091
2092           token = rc_parse_token_or_compound (scanner, gstring, 0);
2093           if (token == G_TOKEN_NONE)
2094             {
2095               g_string_append_c (gstring, ' ');
2096               g_value_init (&prop->value, G_TYPE_GSTRING);
2097               g_value_set_static_boxed (&prop->value, gstring);
2098             }
2099           else
2100             g_string_free (gstring, TRUE);
2101           break;
2102         }
2103       /* fall through */
2104     default:
2105       g_scanner_get_next_token (scanner);
2106       token = G_TOKEN_INT;
2107       break;
2108     }
2109
2110   /* restore scanner mode */
2111   scanner->config->scan_identifier = scan_identifier;
2112   scanner->config->scan_symbols = scan_symbols;
2113   scanner->config->identifier_2_string = identifier_2_string;
2114   scanner->config->char_2_token = char_2_token;
2115   scanner->config->scan_identifier_NULL = scan_identifier_NULL;
2116   scanner->config->numbers_2_int = numbers_2_int;
2117
2118   return token;
2119 }
2120
2121 static gboolean
2122 is_c_identifier (const gchar *string)
2123 {
2124   const gchar *p;
2125   gboolean is_varname;
2126
2127   is_varname = strchr (G_CSET_a_2_z G_CSET_A_2_Z "_", string[0]) != NULL;
2128   for (p = string + 1; *p && is_varname; p++)
2129     is_varname &= strchr (G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "_-", *p) != NULL;
2130
2131   return is_varname;
2132 }
2133
2134 static guint
2135 gtk_rc_parse_statement (GtkRcContext *context,
2136                         GScanner     *scanner)
2137 {
2138   guint token;
2139   
2140   token = g_scanner_peek_next_token (scanner);
2141   switch (token)
2142     {
2143     case GTK_RC_TOKEN_INCLUDE:
2144       token = g_scanner_get_next_token (scanner);
2145       if (token != GTK_RC_TOKEN_INCLUDE)
2146         return GTK_RC_TOKEN_INCLUDE;
2147       token = g_scanner_get_next_token (scanner);
2148       if (token != G_TOKEN_STRING)
2149         return G_TOKEN_STRING;
2150       gtk_rc_parse_file (context, scanner->value.v_string, context->default_priority, FALSE);
2151       return G_TOKEN_NONE;
2152       
2153     case GTK_RC_TOKEN_STYLE:
2154       return gtk_rc_parse_style (context, scanner);
2155       
2156     case GTK_RC_TOKEN_BINDING:
2157       return gtk_binding_parse_binding (scanner);
2158       
2159     case GTK_RC_TOKEN_PIXMAP_PATH:
2160       return gtk_rc_parse_pixmap_path (context, scanner);
2161       
2162     case GTK_RC_TOKEN_WIDGET:
2163       return gtk_rc_parse_path_pattern (context, scanner);
2164       
2165     case GTK_RC_TOKEN_WIDGET_CLASS:
2166       return gtk_rc_parse_path_pattern (context, scanner);
2167       
2168     case GTK_RC_TOKEN_CLASS:
2169       return gtk_rc_parse_path_pattern (context, scanner);
2170       
2171     case GTK_RC_TOKEN_MODULE_PATH:
2172       return gtk_rc_parse_module_path (scanner);
2173       
2174     case GTK_RC_TOKEN_IM_MODULE_PATH:
2175       return gtk_rc_parse_im_module_path (scanner);
2176       
2177     case GTK_RC_TOKEN_IM_MODULE_FILE:
2178       return gtk_rc_parse_im_module_file (scanner);
2179
2180     case G_TOKEN_IDENTIFIER:
2181       if (is_c_identifier (scanner->next_value.v_identifier))
2182         {
2183           GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2184           gchar *name;
2185           
2186           g_scanner_get_next_token (scanner); /* eat identifier */
2187           name = g_strdup (scanner->value.v_identifier);
2188           
2189           token = gtk_rc_parse_assignment (scanner, &prop);
2190           if (token == G_TOKEN_NONE)
2191             {
2192               GtkSettingsValue svalue;
2193
2194               svalue.origin = prop.origin;
2195               memcpy (&svalue.value, &prop.value, sizeof (prop.value));
2196               g_strcanon (name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
2197               gtk_settings_set_property_value (context->settings,
2198                                                name,
2199                                                &svalue);
2200             }
2201           g_free (prop.origin);
2202           if (G_VALUE_TYPE (&prop.value))
2203             g_value_unset (&prop.value);
2204           g_free (name);
2205           
2206           return token;
2207         }
2208       else
2209         {
2210           g_scanner_get_next_token (scanner);
2211           return G_TOKEN_IDENTIFIER;
2212         }
2213     default:
2214       g_scanner_get_next_token (scanner);
2215       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
2216     }
2217 }
2218
2219 static void
2220 fixup_rc_set (GSList     *list,
2221               GtkRcStyle *orig,
2222               GtkRcStyle *new)
2223 {
2224   while (list)
2225     {
2226       GtkRcSet *set = list->data;
2227       if (set->rc_style == orig)
2228         set->rc_style = new;
2229       list = list->next;
2230     }
2231 }
2232
2233 static void
2234 fixup_rc_sets (GtkRcContext *context,
2235                GtkRcStyle   *orig,
2236                GtkRcStyle   *new)
2237 {
2238   fixup_rc_set (context->rc_sets_widget, orig, new);
2239   fixup_rc_set (context->rc_sets_widget_class, orig, new);
2240   fixup_rc_set (context->rc_sets_class, orig, new);
2241 }
2242
2243 static guint
2244 gtk_rc_parse_style (GtkRcContext *context,
2245                     GScanner     *scanner)
2246 {
2247   GtkRcStyle *rc_style;
2248   GtkRcStyle *orig_style;
2249   GtkRcStyle *parent_style;
2250   guint token;
2251   gint i;
2252   GtkIconFactory *our_factory = NULL;
2253   
2254   token = g_scanner_get_next_token (scanner);
2255   if (token != GTK_RC_TOKEN_STYLE)
2256     return GTK_RC_TOKEN_STYLE;
2257   
2258   token = g_scanner_get_next_token (scanner);
2259   if (token != G_TOKEN_STRING)
2260     return G_TOKEN_STRING;
2261   
2262   rc_style = gtk_rc_style_find (context, scanner->value.v_string);
2263   if (rc_style)
2264     orig_style = g_object_ref (rc_style);
2265   else
2266     orig_style = NULL;
2267
2268   /* If there's a list, its first member is always the factory belonging
2269    * to this RcStyle
2270    */
2271   if (rc_style && rc_style->icon_factories)
2272     our_factory = rc_style->icon_factories->data;
2273   
2274   if (!rc_style)
2275     {
2276       rc_style = gtk_rc_style_new ();
2277       rc_style->name = g_strdup (scanner->value.v_string);
2278       
2279       for (i = 0; i < 5; i++)
2280         rc_style->bg_pixmap_name[i] = NULL;
2281
2282       for (i = 0; i < 5; i++)
2283         rc_style->color_flags[i] = 0;
2284     }
2285
2286   token = g_scanner_peek_next_token (scanner);
2287   if (token == G_TOKEN_EQUAL_SIGN)
2288     {
2289       token = g_scanner_get_next_token (scanner);
2290       
2291       token = g_scanner_get_next_token (scanner);
2292       if (token != G_TOKEN_STRING)
2293         {
2294           token = G_TOKEN_STRING;
2295           goto err;
2296         }
2297       
2298       parent_style = gtk_rc_style_find (context, scanner->value.v_string);
2299       if (parent_style)
2300         {
2301           GSList *factories;
2302           
2303           for (i = 0; i < 5; i++)
2304             {
2305               rc_style->color_flags[i] = parent_style->color_flags[i];
2306               rc_style->fg[i] = parent_style->fg[i];
2307               rc_style->bg[i] = parent_style->bg[i];
2308               rc_style->text[i] = parent_style->text[i];
2309               rc_style->base[i] = parent_style->base[i];
2310             }
2311
2312           rc_style->xthickness = parent_style->xthickness;
2313           rc_style->ythickness = parent_style->ythickness;
2314           
2315           if (parent_style->font_desc)
2316             {
2317               if (rc_style->font_desc)
2318                 pango_font_description_free (rc_style->font_desc);
2319               rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
2320             }
2321
2322           if (parent_style->rc_properties)
2323             {
2324               guint i;
2325
2326               for (i = 0; i < parent_style->rc_properties->len; i++)
2327                 insert_rc_property (rc_style,
2328                                     &g_array_index (parent_style->rc_properties, GtkRcProperty, i),
2329                                     TRUE);
2330             }
2331           
2332           for (i = 0; i < 5; i++)
2333             {
2334               if (rc_style->bg_pixmap_name[i])
2335                 g_free (rc_style->bg_pixmap_name[i]);
2336               rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
2337             }
2338           
2339           /* Append parent's factories, adding a ref to them */
2340           if (parent_style->icon_factories != NULL)
2341             {
2342               /* Add a factory for ourselves if we have none,
2343                * in case we end up defining more stock icons.
2344                * I see no real way around this; we need to maintain
2345                * the invariant that the first factory in the list
2346                * is always our_factory, the one belonging to us,
2347                * and if we put parent factories in the list we can't
2348                * do that if the style is reopened.
2349                */
2350               if (our_factory == NULL)
2351                 {
2352                   our_factory = gtk_icon_factory_new ();
2353                   rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
2354                                                               our_factory);
2355                 }
2356               
2357               rc_style->icon_factories = g_slist_concat (rc_style->icon_factories,
2358                                                          g_slist_copy (parent_style->icon_factories));
2359               
2360               factories = parent_style->icon_factories;
2361               while (factories != NULL)
2362                 {
2363                   g_object_ref (G_OBJECT (factories->data));
2364                   factories = factories->next;
2365                 }
2366             }
2367         }
2368     }
2369   
2370   token = g_scanner_get_next_token (scanner);
2371   if (token != G_TOKEN_LEFT_CURLY)
2372     {
2373       token = G_TOKEN_LEFT_CURLY;
2374       goto err;
2375     }
2376   
2377   token = g_scanner_peek_next_token (scanner);
2378   while (token != G_TOKEN_RIGHT_CURLY)
2379     {
2380       switch (token)
2381         {
2382         case GTK_RC_TOKEN_BG:
2383           token = gtk_rc_parse_bg (scanner, rc_style);
2384           break;
2385         case GTK_RC_TOKEN_FG:
2386           token = gtk_rc_parse_fg (scanner, rc_style);
2387           break;
2388         case GTK_RC_TOKEN_TEXT:
2389           token = gtk_rc_parse_text (scanner, rc_style);
2390           break;
2391         case GTK_RC_TOKEN_BASE:
2392           token = gtk_rc_parse_base (scanner, rc_style);
2393           break;
2394         case GTK_RC_TOKEN_XTHICKNESS:
2395           token = gtk_rc_parse_xthickness (scanner, rc_style);
2396           break;
2397         case GTK_RC_TOKEN_YTHICKNESS:
2398           token = gtk_rc_parse_ythickness (scanner, rc_style);
2399           break;
2400         case GTK_RC_TOKEN_BG_PIXMAP:
2401           token = gtk_rc_parse_bg_pixmap (context, scanner, rc_style);
2402           break;
2403         case GTK_RC_TOKEN_FONT:
2404           token = gtk_rc_parse_font (scanner, rc_style);
2405           break;
2406         case GTK_RC_TOKEN_FONTSET:
2407           token = gtk_rc_parse_fontset (scanner, rc_style);
2408           break;
2409         case GTK_RC_TOKEN_FONT_NAME:
2410           token = gtk_rc_parse_font_name (scanner, rc_style);
2411           break;
2412         case GTK_RC_TOKEN_ENGINE:
2413           token = gtk_rc_parse_engine (context, scanner, &rc_style);
2414           break;
2415         case GTK_RC_TOKEN_STOCK:
2416           if (our_factory == NULL)
2417             {
2418               our_factory = gtk_icon_factory_new ();
2419               rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
2420                                                           our_factory);
2421             }
2422           token = gtk_rc_parse_stock (context, scanner, rc_style, our_factory);
2423           break;
2424         case G_TOKEN_IDENTIFIER:
2425           if (is_c_identifier (scanner->next_value.v_identifier) &&
2426               scanner->next_value.v_identifier[0] >= 'A' &&
2427               scanner->next_value.v_identifier[0] <= 'Z') /* match namespaced type names */
2428             {
2429               GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2430               
2431               g_scanner_get_next_token (scanner); /* eat type name */
2432               prop.type_name = g_quark_from_string (scanner->value.v_identifier);
2433               if (g_scanner_get_next_token (scanner) != ':' ||
2434                   g_scanner_get_next_token (scanner) != ':')
2435                 {
2436                   token = ':';
2437                   break;
2438                 }
2439               if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER ||
2440                   !is_c_identifier (scanner->value.v_identifier))
2441                 {
2442                   token = G_TOKEN_IDENTIFIER;
2443                   break;
2444                 }
2445
2446               /* it's important that we do the same canonification as GParamSpecPool here */
2447               g_strcanon (scanner->value.v_identifier, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
2448               prop.property_name = g_quark_from_string (scanner->value.v_identifier);
2449
2450               token = gtk_rc_parse_assignment (scanner, &prop);
2451               if (token == G_TOKEN_NONE)
2452                 {
2453                   g_return_val_if_fail (prop.origin != NULL && G_VALUE_TYPE (&prop.value) != 0, G_TOKEN_ERROR);
2454                   insert_rc_property (rc_style, &prop, TRUE);
2455                 }
2456               
2457               g_free (prop.origin);
2458               if (G_VALUE_TYPE (&prop.value))
2459                 g_value_unset (&prop.value);
2460             }
2461           else
2462             {
2463               g_scanner_get_next_token (scanner);
2464               token = G_TOKEN_IDENTIFIER;
2465             }
2466           break;
2467         default:
2468           g_scanner_get_next_token (scanner);
2469           token = G_TOKEN_RIGHT_CURLY;
2470           break;
2471         }
2472
2473       if (token != G_TOKEN_NONE)
2474         goto err;
2475
2476       token = g_scanner_peek_next_token (scanner);
2477     } /* while (token != G_TOKEN_RIGHT_CURLY) */
2478   
2479   token = g_scanner_get_next_token (scanner);
2480   if (token != G_TOKEN_RIGHT_CURLY)
2481     {
2482       token = G_TOKEN_RIGHT_CURLY;
2483       goto err;
2484     }
2485   
2486   if (rc_style != orig_style)
2487     {
2488       if (!context->rc_style_ht)
2489         context->rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
2490                                                  (GEqualFunc) gtk_rc_style_equal);
2491       
2492       g_hash_table_replace (context->rc_style_ht, rc_style->name, rc_style);
2493
2494       /* If we copied the data into a new rc style, fix up references to the old rc style
2495        * in bindings that we have.
2496        */
2497       if (orig_style)
2498         fixup_rc_sets (context, orig_style, rc_style);
2499     }
2500
2501   if (orig_style)
2502     g_object_unref (orig_style);
2503   
2504   return G_TOKEN_NONE;
2505
2506  err:
2507   if (rc_style != orig_style)
2508     gtk_rc_style_unref (rc_style);
2509
2510   if (orig_style)
2511     g_object_unref (orig_style);
2512   
2513   return token;
2514 }
2515
2516 const GtkRcProperty*
2517 _gtk_rc_style_lookup_rc_property (GtkRcStyle *rc_style,
2518                                   GQuark      type_name,
2519                                   GQuark      property_name)
2520 {
2521   GtkRcProperty *node = NULL;
2522
2523   g_return_val_if_fail (GTK_IS_RC_STYLE (rc_style), NULL);
2524
2525   if (rc_style->rc_properties)
2526     {
2527       GtkRcProperty key;
2528
2529       key.type_name = type_name;
2530       key.property_name = property_name;
2531
2532       node = bsearch (&key,
2533                       rc_style->rc_properties->data, rc_style->rc_properties->len,
2534                       sizeof (GtkRcProperty), gtk_rc_properties_cmp);
2535     }
2536
2537   return node;
2538 }
2539
2540 static guint
2541 gtk_rc_parse_bg (GScanner   *scanner,
2542                  GtkRcStyle *style)
2543 {
2544   GtkStateType state;
2545   guint token;
2546   
2547   token = g_scanner_get_next_token (scanner);
2548   if (token != GTK_RC_TOKEN_BG)
2549     return GTK_RC_TOKEN_BG;
2550   
2551   token = gtk_rc_parse_state (scanner, &state);
2552   if (token != G_TOKEN_NONE)
2553     return token;
2554   
2555   token = g_scanner_get_next_token (scanner);
2556   if (token != G_TOKEN_EQUAL_SIGN)
2557     return G_TOKEN_EQUAL_SIGN;
2558
2559   style->color_flags[state] |= GTK_RC_BG;
2560   return gtk_rc_parse_color (scanner, &style->bg[state]);
2561 }
2562
2563 static guint
2564 gtk_rc_parse_fg (GScanner   *scanner,
2565                  GtkRcStyle *style)
2566 {
2567   GtkStateType state;
2568   guint token;
2569   
2570   token = g_scanner_get_next_token (scanner);
2571   if (token != GTK_RC_TOKEN_FG)
2572     return GTK_RC_TOKEN_FG;
2573   
2574   token = gtk_rc_parse_state (scanner, &state);
2575   if (token != G_TOKEN_NONE)
2576     return token;
2577   
2578   token = g_scanner_get_next_token (scanner);
2579   if (token != G_TOKEN_EQUAL_SIGN)
2580     return G_TOKEN_EQUAL_SIGN;
2581   
2582   style->color_flags[state] |= GTK_RC_FG;
2583   return gtk_rc_parse_color (scanner, &style->fg[state]);
2584 }
2585
2586 static guint
2587 gtk_rc_parse_text (GScanner   *scanner,
2588                    GtkRcStyle *style)
2589 {
2590   GtkStateType state;
2591   guint token;
2592   
2593   token = g_scanner_get_next_token (scanner);
2594   if (token != GTK_RC_TOKEN_TEXT)
2595     return GTK_RC_TOKEN_TEXT;
2596   
2597   token = gtk_rc_parse_state (scanner, &state);
2598   if (token != G_TOKEN_NONE)
2599     return token;
2600   
2601   token = g_scanner_get_next_token (scanner);
2602   if (token != G_TOKEN_EQUAL_SIGN)
2603     return G_TOKEN_EQUAL_SIGN;
2604   
2605   style->color_flags[state] |= GTK_RC_TEXT;
2606   return gtk_rc_parse_color (scanner, &style->text[state]);
2607 }
2608
2609 static guint
2610 gtk_rc_parse_base (GScanner   *scanner,
2611                    GtkRcStyle *style)
2612 {
2613   GtkStateType state;
2614   guint token;
2615   
2616   token = g_scanner_get_next_token (scanner);
2617   if (token != GTK_RC_TOKEN_BASE)
2618     return GTK_RC_TOKEN_BASE;
2619   
2620   token = gtk_rc_parse_state (scanner, &state);
2621   if (token != G_TOKEN_NONE)
2622     return token;
2623   
2624   token = g_scanner_get_next_token (scanner);
2625   if (token != G_TOKEN_EQUAL_SIGN)
2626     return G_TOKEN_EQUAL_SIGN;
2627
2628   style->color_flags[state] |= GTK_RC_BASE;
2629   return gtk_rc_parse_color (scanner, &style->base[state]);
2630 }
2631
2632 static guint
2633 gtk_rc_parse_xthickness (GScanner   *scanner,
2634                          GtkRcStyle *style)
2635 {
2636   if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
2637     return GTK_RC_TOKEN_XTHICKNESS;
2638
2639   if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2640     return G_TOKEN_EQUAL_SIGN;
2641
2642   if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2643     return G_TOKEN_INT;
2644
2645   style->xthickness = scanner->value.v_int;
2646
2647   return G_TOKEN_NONE;
2648 }
2649
2650 static guint
2651 gtk_rc_parse_ythickness (GScanner   *scanner,
2652                          GtkRcStyle *style)
2653 {
2654   if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
2655     return GTK_RC_TOKEN_YTHICKNESS;
2656
2657   if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2658     return G_TOKEN_EQUAL_SIGN;
2659
2660   if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2661     return G_TOKEN_INT;
2662
2663   style->ythickness = scanner->value.v_int;
2664
2665   return G_TOKEN_NONE;
2666 }
2667
2668 static guint
2669 gtk_rc_parse_bg_pixmap (GtkRcContext *context,
2670                         GScanner     *scanner,
2671                         GtkRcStyle   *rc_style)
2672 {
2673   GtkStateType state;
2674   guint token;
2675   gchar *pixmap_file;
2676   
2677   token = g_scanner_get_next_token (scanner);
2678   if (token != GTK_RC_TOKEN_BG_PIXMAP)
2679     return GTK_RC_TOKEN_BG_PIXMAP;
2680   
2681   token = gtk_rc_parse_state (scanner, &state);
2682   if (token != G_TOKEN_NONE)
2683     return token;
2684   
2685   token = g_scanner_get_next_token (scanner);
2686   if (token != G_TOKEN_EQUAL_SIGN)
2687     return G_TOKEN_EQUAL_SIGN;
2688   
2689   token = g_scanner_get_next_token (scanner);
2690   if (token != G_TOKEN_STRING)
2691     return G_TOKEN_STRING;
2692   
2693   if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
2694       (strcmp (scanner->value.v_string, "<none>") == 0))
2695     pixmap_file = g_strdup (scanner->value.v_string);
2696   else
2697     pixmap_file = gtk_rc_find_pixmap_in_path (context->settings,
2698                                               scanner, scanner->value.v_string);
2699   
2700   if (pixmap_file)
2701     {
2702       if (rc_style->bg_pixmap_name[state])
2703         g_free (rc_style->bg_pixmap_name[state]);
2704       rc_style->bg_pixmap_name[state] = pixmap_file;
2705     }
2706   
2707   return G_TOKEN_NONE;
2708 }
2709
2710 static gchar*
2711 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
2712 {
2713   gchar *buf;
2714   gint fd;
2715
2716   buf = g_build_filename (dir, pixmap_file, NULL);
2717   
2718   fd = open (buf, O_RDONLY);
2719   if (fd >= 0)
2720     {
2721       close (fd);
2722       return buf;
2723     }
2724    
2725   g_free (buf);
2726  
2727    return NULL;
2728  }
2729
2730 /**
2731  * gtk_rc_find_pixmap_in_path:
2732  * @settings: a #GtkSettings
2733  * @scanner: Scanner used to get line number information for the
2734  *   warning message, or %NULL
2735  * @pixmap_file: name of the pixmap file to locate.
2736  * 
2737  * Looks up a file in pixmap path for the specified #GtkSettings.
2738  * If the file is not found, it outputs a warning message using
2739  * g_warning() and returns %NULL.
2740  *
2741  * Return value: the filename. 
2742  **/
2743 gchar*
2744 gtk_rc_find_pixmap_in_path (GtkSettings  *settings,
2745                             GScanner     *scanner,
2746                             const gchar  *pixmap_file)
2747 {
2748   gint i;
2749   gchar *filename;
2750   GSList *tmp_list;
2751
2752   GtkRcContext *context = gtk_rc_context_get (settings);
2753     
2754   for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (context->pixmap_path[i] != NULL); i++)
2755     {
2756       filename = gtk_rc_check_pixmap_dir (context->pixmap_path[i], pixmap_file);
2757       if (filename)
2758         return filename;
2759     }
2760  
2761   tmp_list = rc_dir_stack;
2762   while (tmp_list)
2763     {
2764       filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
2765       if (filename)
2766         return filename;
2767        
2768       tmp_list = tmp_list->next;
2769     }
2770   
2771   if (scanner)
2772     g_scanner_warn (scanner, 
2773                     _("Unable to locate image file in pixmap_path: \"%s\""),
2774                     pixmap_file);
2775   else
2776     g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
2777                pixmap_file);
2778     
2779   return NULL;
2780 }
2781
2782 gchar*
2783 gtk_rc_find_module_in_path (const gchar *module_file)
2784 {
2785   gint i;
2786   gint fd;
2787   gchar *buf;
2788   
2789   for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
2790     {
2791       buf = g_build_filename (module_path[i], module_file, NULL);
2792       
2793       fd = open (buf, O_RDONLY);
2794       if (fd >= 0)
2795         {
2796           close (fd);
2797           return buf;
2798         }
2799       
2800       g_free (buf);
2801     }
2802     
2803   return NULL;
2804 }
2805
2806 static guint
2807 gtk_rc_parse_font (GScanner   *scanner,
2808                    GtkRcStyle *rc_style)
2809 {
2810   guint token;
2811   
2812   token = g_scanner_get_next_token (scanner);
2813   if (token != GTK_RC_TOKEN_FONT)
2814     return GTK_RC_TOKEN_FONT;
2815   
2816   token = g_scanner_get_next_token (scanner);
2817   if (token != G_TOKEN_EQUAL_SIGN)
2818     return G_TOKEN_EQUAL_SIGN;
2819   
2820   token = g_scanner_get_next_token (scanner);
2821   if (token != G_TOKEN_STRING)
2822     return G_TOKEN_STRING;
2823
2824   /* Ignore, do nothing */
2825   
2826   return G_TOKEN_NONE;
2827 }
2828
2829 static guint
2830 gtk_rc_parse_fontset (GScanner   *scanner,
2831                       GtkRcStyle *rc_style)
2832 {
2833   guint token;
2834   
2835   token = g_scanner_get_next_token (scanner);
2836   if (token != GTK_RC_TOKEN_FONTSET)
2837     return GTK_RC_TOKEN_FONTSET;
2838   
2839   token = g_scanner_get_next_token (scanner);
2840   if (token != G_TOKEN_EQUAL_SIGN)
2841     return G_TOKEN_EQUAL_SIGN;
2842   
2843   token = g_scanner_get_next_token (scanner);
2844   if (token != G_TOKEN_STRING)
2845     return G_TOKEN_STRING;
2846
2847   /* Do nothing - silently ignore */
2848   
2849   return G_TOKEN_NONE;
2850 }
2851
2852 static guint
2853 gtk_rc_parse_font_name (GScanner   *scanner,
2854                         GtkRcStyle *rc_style)
2855 {
2856   guint token;
2857   
2858   token = g_scanner_get_next_token (scanner);
2859   if (token != GTK_RC_TOKEN_FONT_NAME)
2860     return GTK_RC_TOKEN_FONT;
2861   
2862   token = g_scanner_get_next_token (scanner);
2863   if (token != G_TOKEN_EQUAL_SIGN)
2864     return G_TOKEN_EQUAL_SIGN;
2865   
2866   token = g_scanner_get_next_token (scanner);
2867   if (token != G_TOKEN_STRING)
2868     return G_TOKEN_STRING;
2869
2870   rc_style->font_desc = pango_font_description_from_string (scanner->value.v_string);
2871   
2872   return G_TOKEN_NONE;
2873 }
2874
2875 static guint       
2876 gtk_rc_parse_engine (GtkRcContext *context,
2877                      GScanner     *scanner,
2878                      GtkRcStyle  **rc_style)
2879 {
2880   guint token;
2881   GtkThemeEngine *engine;
2882   guint result = G_TOKEN_NONE;
2883   GtkRcStyle *new_style = NULL;
2884   gboolean parsed_curlies = FALSE;
2885   
2886   token = g_scanner_get_next_token (scanner);
2887   if (token != GTK_RC_TOKEN_ENGINE)
2888     return GTK_RC_TOKEN_ENGINE;
2889
2890   token = g_scanner_get_next_token (scanner);
2891   if (token != G_TOKEN_STRING)
2892     return G_TOKEN_STRING;
2893
2894   engine = gtk_theme_engine_get (scanner->value.v_string);
2895   
2896   token = g_scanner_get_next_token (scanner);
2897   if (token != G_TOKEN_LEFT_CURLY)
2898     return G_TOKEN_LEFT_CURLY;
2899
2900   if (engine)
2901     {
2902       GtkRcStyleClass *new_class;
2903       
2904       new_style = gtk_theme_engine_create_rc_style (engine);
2905       g_type_module_unuse (G_TYPE_MODULE (engine));
2906
2907       new_class = GTK_RC_STYLE_GET_CLASS (new_style);
2908
2909       new_class->merge (new_style, *rc_style);
2910       if ((*rc_style)->name)
2911         new_style->name = g_strdup ((*rc_style)->name);
2912       
2913       if (new_class->parse)
2914         {
2915           parsed_curlies = TRUE;
2916           result = new_class->parse (new_style, context->settings, scanner);
2917
2918           if (result != G_TOKEN_NONE)
2919             {
2920               g_object_unref (G_OBJECT (new_style));
2921               new_style = NULL;
2922             }
2923         }
2924     }
2925
2926   if (!parsed_curlies)
2927     {
2928       /* Skip over remainder, looking for nested {}'s
2929        */
2930       guint count = 1;
2931       
2932       result = G_TOKEN_RIGHT_CURLY;
2933       while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
2934         {
2935           if (token == G_TOKEN_LEFT_CURLY)
2936             count++;
2937           else if (token == G_TOKEN_RIGHT_CURLY)
2938             count--;
2939           
2940           if (count == 0)
2941             {
2942               result = G_TOKEN_NONE;
2943               break;
2944             }
2945         }
2946     }
2947
2948   if (new_style)
2949     {
2950       g_object_unref (G_OBJECT (*rc_style));
2951       *rc_style = new_style;
2952     }
2953
2954   return result;
2955 }
2956
2957 guint
2958 gtk_rc_parse_state (GScanner     *scanner,
2959                     GtkStateType *state)
2960 {
2961   guint old_scope;
2962   guint token;
2963
2964   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2965   g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
2966   
2967   /* we don't know where we got called from, so we reset the scope here.
2968    * if we bail out due to errors, we *don't* reset the scope, so the
2969    * error messaging code can make sense of our tokens.
2970    */
2971   old_scope = g_scanner_set_scope (scanner, 0);
2972   
2973   token = g_scanner_get_next_token (scanner);
2974   if (token != G_TOKEN_LEFT_BRACE)
2975     return G_TOKEN_LEFT_BRACE;
2976   
2977   token = g_scanner_get_next_token (scanner);
2978   switch (token)
2979     {
2980     case GTK_RC_TOKEN_ACTIVE:
2981       *state = GTK_STATE_ACTIVE;
2982       break;
2983     case GTK_RC_TOKEN_INSENSITIVE:
2984       *state = GTK_STATE_INSENSITIVE;
2985       break;
2986     case GTK_RC_TOKEN_NORMAL:
2987       *state = GTK_STATE_NORMAL;
2988       break;
2989     case GTK_RC_TOKEN_PRELIGHT:
2990       *state = GTK_STATE_PRELIGHT;
2991       break;
2992     case GTK_RC_TOKEN_SELECTED:
2993       *state = GTK_STATE_SELECTED;
2994       break;
2995     default:
2996       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
2997     }
2998   
2999   token = g_scanner_get_next_token (scanner);
3000   if (token != G_TOKEN_RIGHT_BRACE)
3001     return G_TOKEN_RIGHT_BRACE;
3002   
3003   g_scanner_set_scope (scanner, old_scope);
3004
3005   return G_TOKEN_NONE;
3006 }
3007
3008 guint
3009 gtk_rc_parse_priority (GScanner            *scanner,
3010                        GtkPathPriorityType *priority)
3011 {
3012   guint old_scope;
3013   guint token;
3014
3015   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3016   g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
3017
3018   /* we don't know where we got called from, so we reset the scope here.
3019    * if we bail out due to errors, we *don't* reset the scope, so the
3020    * error messaging code can make sense of our tokens.
3021    */
3022   old_scope = g_scanner_set_scope (scanner, 0);
3023   
3024   token = g_scanner_get_next_token (scanner);
3025   if (token != ':')
3026     return ':';
3027   
3028   token = g_scanner_get_next_token (scanner);
3029   switch (token)
3030     {
3031     case GTK_RC_TOKEN_LOWEST:
3032       *priority = GTK_PATH_PRIO_LOWEST;
3033       break;
3034     case GTK_RC_TOKEN_GTK:
3035       *priority = GTK_PATH_PRIO_GTK;
3036       break;
3037     case GTK_RC_TOKEN_APPLICATION:
3038       *priority = GTK_PATH_PRIO_APPLICATION;
3039       break;
3040     case GTK_RC_TOKEN_THEME:
3041       *priority = GTK_PATH_PRIO_THEME;
3042       break;
3043     case GTK_RC_TOKEN_RC:
3044       *priority = GTK_PATH_PRIO_RC;
3045       break;
3046     case GTK_RC_TOKEN_HIGHEST:
3047       *priority = GTK_PATH_PRIO_HIGHEST;
3048       break;
3049     default:
3050       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
3051     }
3052   
3053   g_scanner_set_scope (scanner, old_scope);
3054
3055   return G_TOKEN_NONE;
3056 }
3057
3058 guint
3059 gtk_rc_parse_color (GScanner *scanner,
3060                     GdkColor *color)
3061 {
3062   guint token;
3063
3064   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3065
3066   /* we don't need to set our own scope here, because
3067    * we don't need own symbols
3068    */
3069   
3070   token = g_scanner_get_next_token (scanner);
3071   switch (token)
3072     {
3073       gint token_int;
3074       
3075     case G_TOKEN_LEFT_CURLY:
3076       token = g_scanner_get_next_token (scanner);
3077       if (token == G_TOKEN_INT)
3078         token_int = scanner->value.v_int;
3079       else if (token == G_TOKEN_FLOAT)
3080         token_int = scanner->value.v_float * 65535.0;
3081       else
3082         return G_TOKEN_FLOAT;
3083       color->red = CLAMP (token_int, 0, 65535);
3084       
3085       token = g_scanner_get_next_token (scanner);
3086       if (token != G_TOKEN_COMMA)
3087         return G_TOKEN_COMMA;
3088       
3089       token = g_scanner_get_next_token (scanner);
3090       if (token == G_TOKEN_INT)
3091         token_int = scanner->value.v_int;
3092       else if (token == G_TOKEN_FLOAT)
3093         token_int = scanner->value.v_float * 65535.0;
3094       else
3095         return G_TOKEN_FLOAT;
3096       color->green = CLAMP (token_int, 0, 65535);
3097       
3098       token = g_scanner_get_next_token (scanner);
3099       if (token != G_TOKEN_COMMA)
3100         return G_TOKEN_COMMA;
3101       
3102       token = g_scanner_get_next_token (scanner);
3103       if (token == G_TOKEN_INT)
3104         token_int = scanner->value.v_int;
3105       else if (token == G_TOKEN_FLOAT)
3106         token_int = scanner->value.v_float * 65535.0;
3107       else
3108         return G_TOKEN_FLOAT;
3109       color->blue = CLAMP (token_int, 0, 65535);
3110       
3111       token = g_scanner_get_next_token (scanner);
3112       if (token != G_TOKEN_RIGHT_CURLY)
3113         return G_TOKEN_RIGHT_CURLY;
3114       return G_TOKEN_NONE;
3115       
3116     case G_TOKEN_STRING:
3117       if (!gdk_color_parse (scanner->value.v_string, color))
3118         {
3119           g_scanner_warn (scanner, "Invalid color constant '%s'",
3120                           scanner->value.v_string);
3121           return G_TOKEN_STRING;
3122         }
3123       else
3124         return G_TOKEN_NONE;
3125       
3126     default:
3127       return G_TOKEN_STRING;
3128     }
3129 }
3130
3131 static guint
3132 gtk_rc_parse_pixmap_path (GtkRcContext *context,
3133                           GScanner     *scanner)
3134 {
3135   guint token;
3136   
3137   token = g_scanner_get_next_token (scanner);
3138   if (token != GTK_RC_TOKEN_PIXMAP_PATH)
3139     return GTK_RC_TOKEN_PIXMAP_PATH;
3140   
3141   token = g_scanner_get_next_token (scanner);
3142   if (token != G_TOKEN_STRING)
3143     return G_TOKEN_STRING;
3144   
3145   gtk_rc_parse_pixmap_path_string (context, scanner, scanner->value.v_string);
3146   
3147   return G_TOKEN_NONE;
3148 }
3149
3150 static void
3151 gtk_rc_parse_pixmap_path_string (GtkRcContext *context,
3152                                  GScanner     *scanner,
3153                                  const gchar  *pix_path)
3154 {
3155   gint end_offset;
3156   gint start_offset = 0;
3157   gint path_len;
3158   gint path_num;
3159   
3160   /* free the old one, or just add to the old one ? */
3161   for (path_num = 0; context->pixmap_path[path_num]; path_num++)
3162     {
3163       g_free (context->pixmap_path[path_num]);
3164       context->pixmap_path[path_num] = NULL;
3165     }
3166   
3167   path_num = 0;
3168   
3169   path_len = strlen (pix_path);
3170   
3171   for (end_offset = 0; end_offset <= path_len; end_offset++)
3172     {
3173       if ((pix_path[end_offset] == G_SEARCHPATH_SEPARATOR) ||
3174           (end_offset == path_len))
3175         {
3176           gchar *path_element = g_strndup (pix_path + start_offset, end_offset - start_offset);
3177           if (g_path_is_absolute (path_element))
3178             {
3179               context->pixmap_path[path_num] = path_element;
3180               path_num++;
3181               context->pixmap_path[path_num] = NULL;
3182             }
3183           else
3184             {
3185               g_warning (_("Pixmap path element: \"%s\" must be absolute, %s, line %d"),
3186                          path_element, scanner->input_name, scanner->line);
3187               g_free (path_element);
3188             }
3189
3190           start_offset = end_offset + 1;
3191         }
3192     }
3193 }
3194
3195 static guint
3196 gtk_rc_parse_module_path (GScanner *scanner)
3197 {
3198   guint token;
3199   
3200   token = g_scanner_get_next_token (scanner);
3201   if (token != GTK_RC_TOKEN_MODULE_PATH)
3202     return GTK_RC_TOKEN_MODULE_PATH;
3203   
3204   token = g_scanner_get_next_token (scanner);
3205   if (token != G_TOKEN_STRING)
3206     return G_TOKEN_STRING;
3207   
3208   gtk_rc_parse_module_path_string (scanner->value.v_string);
3209   
3210   return G_TOKEN_NONE;
3211 }
3212
3213 static guint
3214 gtk_rc_parse_im_module_path (GScanner *scanner)
3215 {
3216   guint token;
3217   
3218   token = g_scanner_get_next_token (scanner);
3219   if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
3220     return GTK_RC_TOKEN_IM_MODULE_FILE;
3221   
3222   token = g_scanner_get_next_token (scanner);
3223   if (token != G_TOKEN_STRING)
3224     return G_TOKEN_STRING;
3225
3226   if (im_module_path)
3227     g_free (im_module_path);
3228     
3229   im_module_path = g_strdup (scanner->value.v_string);
3230
3231   return G_TOKEN_NONE;
3232 }
3233
3234 static guint
3235 gtk_rc_parse_im_module_file (GScanner *scanner)
3236 {
3237   guint token;
3238   
3239   token = g_scanner_get_next_token (scanner);
3240   if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
3241     return GTK_RC_TOKEN_IM_MODULE_FILE;
3242   
3243   token = g_scanner_get_next_token (scanner);
3244   if (token != G_TOKEN_STRING)
3245     return G_TOKEN_STRING;
3246
3247   if (im_module_file)
3248     g_free (im_module_file);
3249     
3250   im_module_file = g_strdup (scanner->value.v_string);
3251
3252   return G_TOKEN_NONE;
3253 }
3254
3255 static void
3256 gtk_rc_parse_module_path_string (const gchar *mod_path)
3257 {
3258   gint end_offset;
3259   gint start_offset = 0;
3260   gint path_len;
3261   gint path_num;
3262   
3263   /* free the old one, or just add to the old one ? */
3264   for (path_num=0; module_path[path_num]; path_num++)
3265     {
3266       g_free (module_path[path_num]);
3267       module_path[path_num] = NULL;
3268     }
3269   
3270   path_num = 0;
3271   
3272   path_len = strlen (mod_path);
3273   
3274   for (end_offset = 0; end_offset <= path_len; end_offset++)
3275     {
3276       if ((mod_path[end_offset] == G_SEARCHPATH_SEPARATOR) ||
3277           (end_offset == path_len))
3278         {
3279           module_path[path_num] = g_strndup (mod_path + start_offset, end_offset - start_offset);
3280           path_num++;
3281           module_path[path_num] = NULL;
3282           start_offset = end_offset + 1;
3283         }
3284     }
3285   gtk_rc_append_default_module_path();
3286 }
3287
3288 static gint
3289 rc_set_compare (gconstpointer a, gconstpointer b)
3290 {
3291   const GtkRcSet *set_a = a;
3292   const GtkRcSet *set_b = b;
3293
3294   return (set_a->priority < set_b->priority) ? 1 : (set_a->priority == set_b->priority ? 0 : -1);
3295 }
3296
3297 static GSList *
3298 insert_rc_set (GSList *list, GtkRcSet *set)
3299 {
3300   return g_slist_insert_sorted (list, set, rc_set_compare);
3301 }
3302
3303 static guint
3304 gtk_rc_parse_path_pattern (GtkRcContext *context,
3305                            GScanner     *scanner)
3306 {
3307   guint token;
3308   GtkPathType path_type;
3309   gchar *pattern;
3310   gboolean is_binding;
3311   GtkPathPriorityType priority = context->default_priority;
3312   
3313   token = g_scanner_get_next_token (scanner);
3314   switch (token)
3315     {
3316     case GTK_RC_TOKEN_WIDGET:
3317       path_type = GTK_PATH_WIDGET;
3318       break;
3319     case GTK_RC_TOKEN_WIDGET_CLASS:
3320       path_type = GTK_PATH_WIDGET_CLASS;
3321       break;
3322     case GTK_RC_TOKEN_CLASS:
3323       path_type = GTK_PATH_CLASS;
3324       break;
3325     default:
3326       return GTK_RC_TOKEN_WIDGET_CLASS;
3327     }
3328
3329   token = g_scanner_get_next_token (scanner);
3330   if (token != G_TOKEN_STRING)
3331     return G_TOKEN_STRING;
3332
3333   pattern = g_strdup (scanner->value.v_string);
3334
3335   token = g_scanner_get_next_token (scanner);
3336   if (token == GTK_RC_TOKEN_STYLE)
3337     is_binding = FALSE;
3338   else if (token == GTK_RC_TOKEN_BINDING)
3339     is_binding = TRUE;
3340   else
3341     {
3342       g_free (pattern);
3343       return GTK_RC_TOKEN_STYLE;
3344     }
3345   
3346   if (g_scanner_peek_next_token (scanner) == ':')
3347     {
3348       token = gtk_rc_parse_priority (scanner, &priority);
3349       if (token != G_TOKEN_NONE)
3350         {
3351           g_free (pattern);
3352           return token;
3353         }
3354     }
3355   
3356   token = g_scanner_get_next_token (scanner);
3357   if (token != G_TOKEN_STRING)
3358     {
3359       g_free (pattern);
3360       return G_TOKEN_STRING;
3361     }
3362
3363   if (is_binding)
3364     {
3365       GtkBindingSet *binding;
3366
3367       binding = gtk_binding_set_find (scanner->value.v_string);
3368       if (!binding)
3369         {
3370           g_free (pattern);
3371           return G_TOKEN_STRING;
3372         }
3373       gtk_binding_set_add_path (binding, path_type, pattern, priority);
3374     }
3375   else
3376     {
3377       GtkRcStyle *rc_style;
3378       GtkRcSet *rc_set;
3379
3380       rc_style = gtk_rc_style_find (context, scanner->value.v_string);
3381       
3382       if (!rc_style)
3383         {
3384           g_free (pattern);
3385           return G_TOKEN_STRING;
3386         }
3387
3388       rc_set = g_new (GtkRcSet, 1);
3389       rc_set->pspec = g_pattern_spec_new (pattern);
3390       rc_set->rc_style = rc_style;
3391       rc_set->priority = priority;
3392
3393       if (path_type == GTK_PATH_WIDGET)
3394         context->rc_sets_widget = insert_rc_set (context->rc_sets_widget, rc_set);
3395       else if (path_type == GTK_PATH_WIDGET_CLASS)
3396         context->rc_sets_widget_class = insert_rc_set (context->rc_sets_widget_class, rc_set);
3397       else
3398         context->rc_sets_class = insert_rc_set (context->rc_sets_class, rc_set);
3399     }
3400
3401   g_free (pattern);
3402   return G_TOKEN_NONE;
3403 }
3404
3405 static guint
3406 gtk_rc_parse_stock_id (GScanner  *scanner,
3407                        gchar    **stock_id)
3408 {
3409   guint token;
3410   
3411   token = g_scanner_get_next_token (scanner);
3412   if (token != G_TOKEN_LEFT_BRACE)
3413     return G_TOKEN_LEFT_BRACE;
3414
3415   token = g_scanner_get_next_token (scanner);
3416   
3417   if (token != G_TOKEN_STRING)
3418     return G_TOKEN_STRING;
3419   
3420   *stock_id = g_strdup (scanner->value.v_string);
3421   
3422   token = g_scanner_get_next_token (scanner);
3423   if (token != G_TOKEN_RIGHT_BRACE)
3424     {
3425       g_free (*stock_id);
3426       return G_TOKEN_RIGHT_BRACE;
3427     }
3428   
3429   return G_TOKEN_NONE;
3430 }
3431
3432 static guint
3433 gtk_rc_parse_icon_source (GtkRcContext   *context,
3434                           GScanner       *scanner,
3435                           GtkIconSet     *icon_set,
3436                           gboolean       *icon_set_valid)
3437 {
3438   guint token;
3439   GtkIconSource *source;
3440   gchar *full_filename;
3441   
3442   token = g_scanner_get_next_token (scanner);
3443   if (token != G_TOKEN_LEFT_CURLY)
3444     return G_TOKEN_LEFT_CURLY;
3445
3446   token = g_scanner_get_next_token (scanner);
3447   
3448   if (token != G_TOKEN_STRING)
3449     return G_TOKEN_STRING;
3450
3451   
3452   source = gtk_icon_source_new ();
3453   
3454   full_filename = gtk_rc_find_pixmap_in_path (context->settings, scanner, scanner->value.v_string);
3455   if (full_filename)
3456     {
3457       gtk_icon_source_set_filename (source, full_filename);
3458       g_free (full_filename);
3459     }
3460
3461   /* We continue parsing even if we didn't find the pixmap so that rest of the
3462    * file is read, even if the syntax is bad. However we don't validate the 
3463    * icon_set so the caller can choose not to install it.
3464    */
3465   token = g_scanner_get_next_token (scanner);
3466
3467   if (token == G_TOKEN_RIGHT_CURLY)
3468     goto done;
3469   else if (token != G_TOKEN_COMMA)
3470     {
3471       gtk_icon_source_free (source);
3472       return G_TOKEN_COMMA;
3473     }
3474
3475   /* Get the direction */
3476   
3477   token = g_scanner_get_next_token (scanner);
3478
3479   switch (token)
3480     {
3481     case GTK_RC_TOKEN_RTL:
3482       gtk_icon_source_set_direction_wildcarded (source, FALSE);
3483       gtk_icon_source_set_direction (source, GTK_TEXT_DIR_RTL);
3484       break;
3485
3486     case GTK_RC_TOKEN_LTR:
3487       gtk_icon_source_set_direction_wildcarded (source, FALSE);
3488       gtk_icon_source_set_direction (source, GTK_TEXT_DIR_LTR);
3489       break;
3490       
3491     case '*':
3492       break;
3493       
3494     default:
3495       gtk_icon_source_free (source);
3496       return GTK_RC_TOKEN_RTL;
3497       break;
3498     }
3499
3500   token = g_scanner_get_next_token (scanner);
3501
3502   if (token == G_TOKEN_RIGHT_CURLY)
3503     goto done;
3504   else if (token != G_TOKEN_COMMA)
3505     {
3506       gtk_icon_source_free (source);
3507       return G_TOKEN_COMMA;
3508     }
3509
3510   /* Get the state */
3511   
3512   token = g_scanner_get_next_token (scanner);
3513   
3514   switch (token)
3515     {
3516     case GTK_RC_TOKEN_NORMAL:
3517       gtk_icon_source_set_state_wildcarded (source, FALSE);
3518       gtk_icon_source_set_state (source, GTK_STATE_NORMAL);
3519       break;
3520
3521     case GTK_RC_TOKEN_PRELIGHT:
3522       gtk_icon_source_set_state_wildcarded (source, FALSE);
3523       gtk_icon_source_set_state (source, GTK_STATE_PRELIGHT);
3524       break;
3525       
3526
3527     case GTK_RC_TOKEN_INSENSITIVE:
3528       gtk_icon_source_set_state_wildcarded (source, FALSE);
3529       gtk_icon_source_set_state (source, GTK_STATE_INSENSITIVE);
3530       break;
3531
3532     case GTK_RC_TOKEN_ACTIVE:
3533       gtk_icon_source_set_state_wildcarded (source, FALSE);
3534       gtk_icon_source_set_state (source, GTK_STATE_ACTIVE);
3535       break;
3536
3537     case GTK_RC_TOKEN_SELECTED:
3538       gtk_icon_source_set_state_wildcarded (source, FALSE);
3539       gtk_icon_source_set_state (source, GTK_STATE_SELECTED);
3540       break;
3541
3542     case '*':
3543       break;
3544       
3545     default:
3546       gtk_icon_source_free (source);
3547       return GTK_RC_TOKEN_PRELIGHT;
3548       break;
3549     }  
3550
3551   token = g_scanner_get_next_token (scanner);
3552
3553   if (token == G_TOKEN_RIGHT_CURLY)
3554     goto done;
3555   else if (token != G_TOKEN_COMMA)
3556     {
3557       gtk_icon_source_free (source);
3558       return G_TOKEN_COMMA;
3559     }
3560   
3561   /* Get the size */
3562   
3563   token = g_scanner_get_next_token (scanner);
3564
3565   if (token != '*')
3566     {
3567       GtkIconSize size;
3568       
3569       if (token != G_TOKEN_STRING)
3570         {
3571           gtk_icon_source_free (source);
3572           return G_TOKEN_STRING;
3573         }
3574
3575       size = gtk_icon_size_from_name (scanner->value.v_string);
3576
3577       if (size != GTK_ICON_SIZE_INVALID)
3578         {
3579           gtk_icon_source_set_size_wildcarded (source, FALSE);
3580           gtk_icon_source_set_size (source, size);
3581         }
3582     }
3583
3584   /* Check the close brace */
3585   
3586   token = g_scanner_get_next_token (scanner);
3587   if (token != G_TOKEN_RIGHT_CURLY)
3588     {
3589       gtk_icon_source_free (source);
3590       return G_TOKEN_RIGHT_CURLY;
3591     }
3592
3593  done:
3594   if (gtk_icon_source_get_filename (source))
3595     {
3596       gtk_icon_set_add_source (icon_set, source);
3597       *icon_set_valid = TRUE;
3598     }
3599   gtk_icon_source_free (source);
3600   
3601   return G_TOKEN_NONE;
3602 }
3603
3604 static guint
3605 gtk_rc_parse_stock (GtkRcContext   *context,
3606                     GScanner       *scanner,
3607                     GtkRcStyle     *rc_style,
3608                     GtkIconFactory *factory)
3609 {
3610   GtkIconSet *icon_set = NULL;
3611   gboolean icon_set_valid = FALSE;
3612   gchar *stock_id = NULL;
3613   guint token;
3614   
3615   token = g_scanner_get_next_token (scanner);
3616   if (token != GTK_RC_TOKEN_STOCK)
3617     return GTK_RC_TOKEN_STOCK;
3618   
3619   token = gtk_rc_parse_stock_id (scanner, &stock_id);
3620   if (token != G_TOKEN_NONE)
3621     return token;
3622   
3623   token = g_scanner_get_next_token (scanner);
3624   if (token != G_TOKEN_EQUAL_SIGN)
3625     {
3626       g_free (stock_id);
3627       return G_TOKEN_EQUAL_SIGN;
3628     }
3629
3630   token = g_scanner_get_next_token (scanner);
3631   if (token != G_TOKEN_LEFT_CURLY)
3632     {
3633       g_free (stock_id);
3634       return G_TOKEN_LEFT_CURLY;
3635     }
3636
3637   token = g_scanner_peek_next_token (scanner);
3638   while (token != G_TOKEN_RIGHT_CURLY)
3639     {
3640       if (icon_set == NULL)
3641         icon_set = gtk_icon_set_new ();
3642       
3643       token = gtk_rc_parse_icon_source (context, 
3644                                         scanner, icon_set, &icon_set_valid);
3645       if (token != G_TOKEN_NONE)
3646         {
3647           g_free (stock_id);
3648           gtk_icon_set_unref (icon_set);
3649           return token;
3650         }
3651
3652       token = g_scanner_get_next_token (scanner);
3653       
3654       if (token != G_TOKEN_COMMA &&
3655           token != G_TOKEN_RIGHT_CURLY)
3656         {
3657           g_free (stock_id);
3658           gtk_icon_set_unref (icon_set);
3659           return G_TOKEN_RIGHT_CURLY;
3660         }
3661     }
3662
3663   if (icon_set && icon_set_valid)
3664     {
3665       gtk_icon_factory_add (factory,
3666                             stock_id,
3667                             icon_set);
3668       
3669       gtk_icon_set_unref (icon_set);
3670     }
3671   
3672   g_free (stock_id);
3673
3674   return G_TOKEN_NONE;
3675 }