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