]> Pileus Git - ~andy/gtk/blob - gtk/gtkrc.c
Updates.
[~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 "gtksettings.h"
57 #include "gtkwindow.h"
58
59 #ifdef G_OS_WIN32
60 #include <io.h>
61 #endif
62
63 typedef struct _GtkRcSet    GtkRcSet;
64 typedef struct _GtkRcNode   GtkRcNode;
65 typedef struct _GtkRcFile   GtkRcFile;
66
67 struct _GtkRcSet
68 {
69   GPatternSpec *pspec;
70   GtkRcStyle *rc_style;
71   gint priority;
72 };
73
74 struct _GtkRcFile
75 {
76   time_t mtime;
77   gchar *name;
78   gchar *canonical_name;
79   guint reload;
80 };
81
82 #define GTK_RC_MAX_PIXMAP_PATHS 128
83
84 struct _GtkRcContext
85 {
86   GHashTable *rc_style_ht;
87   GtkSettings *settings;
88   GSList *rc_sets_widget;
89   GSList *rc_sets_widget_class;
90   GSList *rc_sets_class;
91
92   /* The files we have parsed, to reread later if necessary */
93   GSList *rc_files;
94
95   gchar *theme_name;
96   gchar *key_theme_name;
97   
98   gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
99
100   gint default_priority;
101 };
102
103 static GtkRcContext *gtk_rc_context_get              (GtkSettings     *settings);
104
105 static guint       gtk_rc_style_hash                 (const gchar     *name);
106 static gboolean    gtk_rc_style_equal                (const gchar     *a,
107                                                       const gchar     *b);
108 static guint       gtk_rc_styles_hash                (const GSList    *rc_styles);
109 static gboolean    gtk_rc_styles_equal               (const GSList    *a,
110                                                       const GSList    *b);
111 static GtkRcStyle* gtk_rc_style_find                 (GtkRcContext    *context,
112                                                       const gchar     *name);
113 static GSList *    gtk_rc_styles_match               (GSList          *rc_styles,
114                                                       GSList          *sets,
115                                                       guint            path_length,
116                                                       const gchar     *path,
117                                                       const gchar     *path_reversed);
118 static GtkStyle *  gtk_rc_style_to_style             (GtkRcStyle      *rc_style);
119 static GtkStyle*   gtk_rc_init_style                 (GSList          *rc_styles);
120 static void        gtk_rc_parse_default_files        (GtkRcContext    *context);
121 static void        gtk_rc_parse_named                (GtkRcContext    *context,
122                                                       const gchar     *name,
123                                                       const gchar     *type);
124 static void        gtk_rc_parse_file                 (GtkRcContext    *context,
125                                                       const gchar     *filename,
126                                                       gint             priority,
127                                                       gboolean         reload);
128 static void        gtk_rc_parse_any                  (GtkRcContext    *context,
129                                                       const gchar     *input_name,
130                                                       gint             input_fd,
131                                                       const gchar     *input_string);
132 static guint       gtk_rc_parse_statement            (GtkRcContext    *context,
133                                                       GScanner        *scanner);
134 static guint       gtk_rc_parse_style                (GtkRcContext    *context,
135                                                       GScanner        *scanner);
136 static guint       gtk_rc_parse_assignment           (GScanner        *scanner,
137                                                       GtkRcProperty   *prop);
138 static guint       gtk_rc_parse_bg                   (GScanner        *scanner,
139                                                       GtkRcStyle      *style);
140 static guint       gtk_rc_parse_fg                   (GScanner        *scanner,
141                                                       GtkRcStyle      *style);
142 static guint       gtk_rc_parse_text                 (GScanner        *scanner,
143                                                       GtkRcStyle      *style);
144 static guint       gtk_rc_parse_base                 (GScanner        *scanner,
145                                                       GtkRcStyle      *style);
146 static guint       gtk_rc_parse_xthickness           (GScanner        *scanner,
147                                                       GtkRcStyle      *style);
148 static guint       gtk_rc_parse_ythickness           (GScanner        *scanner,
149                                                       GtkRcStyle      *style);
150 static guint       gtk_rc_parse_bg_pixmap            (GtkRcContext    *context,
151                                                       GScanner        *scanner,
152                                                       GtkRcStyle      *rc_style);
153 static guint       gtk_rc_parse_font                 (GScanner        *scanner,
154                                                       GtkRcStyle      *rc_style);
155 static guint       gtk_rc_parse_fontset              (GScanner        *scanner,
156                                                       GtkRcStyle      *rc_style);
157 static guint       gtk_rc_parse_font_name            (GScanner        *scanner,
158                                                       GtkRcStyle      *rc_style);
159 static guint       gtk_rc_parse_engine               (GtkRcContext    *context,
160                                                       GScanner        *scanner,
161                                                       GtkRcStyle     **rc_style);
162 static guint       gtk_rc_parse_pixmap_path          (GtkRcContext    *context,
163                                                       GScanner        *scanner);
164 static void        gtk_rc_parse_pixmap_path_string   (GtkRcContext    *context,
165                                                       GScanner        *scanner,
166                                                       const gchar     *pix_path);
167 static guint       gtk_rc_parse_module_path          (GScanner        *scanner);
168 static void        gtk_rc_parse_module_path_string   (const gchar     *mod_path);
169 static guint       gtk_rc_parse_im_module_path       (GScanner        *scanner);
170 static guint       gtk_rc_parse_im_module_file       (GScanner        *scanner);
171 static guint       gtk_rc_parse_path_pattern         (GtkRcContext    *context,
172                                                       GScanner        *scanner);
173 static guint       gtk_rc_parse_stock                (GtkRcContext    *context,
174                                                       GScanner        *scanner,
175                                                       GtkRcStyle      *rc_style,
176                                                       GtkIconFactory  *factory);
177 static void        gtk_rc_clear_hash_node            (gpointer         key,
178                                                       gpointer         data,
179                                                       gpointer         user_data);
180 static void        gtk_rc_clear_styles               (GtkRcContext    *context);
181 static void        gtk_rc_append_default_module_path (void);
182 static void        gtk_rc_add_initial_default_files  (void);
183
184 static void        gtk_rc_style_init                 (GtkRcStyle      *style);
185 static void        gtk_rc_style_class_init           (GtkRcStyleClass *klass);
186 static void        gtk_rc_style_finalize             (GObject         *object);
187 static void        gtk_rc_style_real_merge           (GtkRcStyle      *dest,
188                                                       GtkRcStyle      *src);
189 static GtkRcStyle* gtk_rc_style_real_create_rc_style (GtkRcStyle      *rc_style);
190 static GtkStyle*   gtk_rc_style_real_create_style    (GtkRcStyle      *rc_style);
191 static gint        gtk_rc_properties_cmp             (gconstpointer    bsearch_node1,
192                                                       gconstpointer    bsearch_node2);
193
194 static gpointer parent_class = NULL;
195
196 static const GScannerConfig gtk_rc_scanner_config =
197 {
198   (
199    " \t\r\n"
200    )                    /* cset_skip_characters */,
201   (
202    G_CSET_a_2_z
203    "_"
204    G_CSET_A_2_Z
205    )                    /* cset_identifier_first */,
206   (
207    G_CSET_a_2_z
208    "_-0123456789"
209    G_CSET_A_2_Z
210    )                    /* cset_identifier_nth */,
211   ( "#\n" )             /* cpair_comment_single */,
212   
213   TRUE                  /* case_sensitive */,
214   
215   TRUE                  /* skip_comment_multi */,
216   TRUE                  /* skip_comment_single */,
217   TRUE                  /* scan_comment_multi */,
218   TRUE                  /* scan_identifier */,
219   FALSE                 /* scan_identifier_1char */,
220   FALSE                 /* scan_identifier_NULL */,
221   TRUE                  /* scan_symbols */,
222   TRUE                  /* scan_binary */,
223   TRUE                  /* scan_octal */,
224   TRUE                  /* scan_float */,
225   TRUE                  /* scan_hex */,
226   TRUE                  /* scan_hex_dollar */,
227   TRUE                  /* scan_string_sq */,
228   TRUE                  /* scan_string_dq */,
229   TRUE                  /* numbers_2_int */,
230   FALSE                 /* int_2_float */,
231   FALSE                 /* identifier_2_string */,
232   TRUE                  /* char_2_token */,
233   TRUE                  /* symbol_2_token */,
234   FALSE                 /* scope_0_fallback */,
235 };
236
237 static const struct
238 {
239   gchar *name;
240   guint token;
241 } symbols[] = {
242   { "include", GTK_RC_TOKEN_INCLUDE },
243   { "NORMAL", GTK_RC_TOKEN_NORMAL },
244   { "ACTIVE", GTK_RC_TOKEN_ACTIVE },
245   { "PRELIGHT", GTK_RC_TOKEN_PRELIGHT },
246   { "SELECTED", GTK_RC_TOKEN_SELECTED },
247   { "INSENSITIVE", GTK_RC_TOKEN_INSENSITIVE },
248   { "fg", GTK_RC_TOKEN_FG },
249   { "bg", GTK_RC_TOKEN_BG },
250   { "text", GTK_RC_TOKEN_TEXT },
251   { "base", GTK_RC_TOKEN_BASE },
252   { "xthickness", GTK_RC_TOKEN_XTHICKNESS },
253   { "ythickness", GTK_RC_TOKEN_YTHICKNESS },
254   { "font", GTK_RC_TOKEN_FONT },
255   { "fontset", GTK_RC_TOKEN_FONTSET },
256   { "font_name", GTK_RC_TOKEN_FONT_NAME },
257   { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP },
258   { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH },
259   { "style", GTK_RC_TOKEN_STYLE },
260   { "binding", GTK_RC_TOKEN_BINDING },
261   { "bind", GTK_RC_TOKEN_BIND },
262   { "widget", GTK_RC_TOKEN_WIDGET },
263   { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS },
264   { "class", GTK_RC_TOKEN_CLASS },
265   { "lowest", GTK_RC_TOKEN_LOWEST },
266   { "gtk", GTK_RC_TOKEN_GTK },
267   { "application", GTK_RC_TOKEN_APPLICATION },
268   { "theme", GTK_RC_TOKEN_THEME },
269   { "rc", GTK_RC_TOKEN_RC },
270   { "highest", GTK_RC_TOKEN_HIGHEST },
271   { "engine", GTK_RC_TOKEN_ENGINE },
272   { "module_path", GTK_RC_TOKEN_MODULE_PATH },
273   { "stock", GTK_RC_TOKEN_STOCK },
274   { "im_module_path", GTK_RC_TOKEN_IM_MODULE_PATH },
275   { "im_module_file", GTK_RC_TOKEN_IM_MODULE_FILE },
276   { "LTR", GTK_RC_TOKEN_LTR },
277   { "RTL", GTK_RC_TOKEN_RTL }
278 };
279
280 static GHashTable *realized_style_ht = NULL;
281
282 static gchar *im_module_path = NULL;
283 static gchar *im_module_file = NULL;
284
285 #define GTK_RC_MAX_DEFAULT_FILES 128
286 static gchar *gtk_rc_default_files[GTK_RC_MAX_DEFAULT_FILES];
287
288 #define GTK_RC_MAX_MODULE_PATHS 128
289 static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
290
291 /* A stack of directories for RC files we are parsing currently.
292  * these are implicitely added to the end of PIXMAP_PATHS
293  */
294 static GSList *rc_dir_stack = NULL;
295
296 /* RC file handling */
297
298 static gchar *
299 gtk_rc_make_default_dir (const gchar *type)
300 {
301   gchar *var, *path;
302
303   var = getenv("GTK_EXE_PREFIX");
304   if (var)
305     path = g_build_filename (var, "lib", "gtk-2.0", type, GTK_BINARY_VERSION, NULL);
306   else
307     path = g_build_filename (GTK_LIBDIR, "gtk-2.0,", type, GTK_BINARY_VERSION, NULL);
308
309   return path;
310 }
311
312 gchar *
313 gtk_rc_get_im_module_path (void)
314 {
315   const gchar *result = g_getenv ("GTK_IM_MODULE_PATH");
316
317   if (!result)
318     {
319       if (im_module_path)
320         result = im_module_path;
321       else
322         return gtk_rc_make_default_dir ("immodules");
323     }
324
325   return g_strdup (result);
326 }
327
328 gchar *
329 gtk_rc_get_im_module_file (void)
330 {
331   gchar *result = g_strdup (g_getenv ("GTK_IM_MODULE_FILE"));
332
333   if (!result)
334     {
335       if (im_module_file)
336         result = g_strdup (im_module_file);
337       else
338         result = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gtk.immodules", NULL);
339     }
340
341   return result;
342 }
343
344 gchar *
345 gtk_rc_get_theme_dir(void)
346 {
347   gchar *var, *path;
348
349   var = getenv("GTK_DATA_PREFIX");
350   if (var)
351     path = g_build_filename (var, "share", "themes", NULL);
352   else
353     path = g_build_filename (GTK_DATA_PREFIX, "share", "themes", NULL);
354
355   return path;
356 }
357
358 gchar *
359 gtk_rc_get_module_dir(void)
360 {
361   return gtk_rc_make_default_dir ("engines");
362 }
363
364 static void
365 gtk_rc_append_default_module_path(void)
366 {
367   const gchar *var;
368   gchar *path;
369   gint n;
370
371   for (n = 0; module_path[n]; n++) ;
372   if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
373     return;
374   
375   var = getenv("GTK_EXE_PREFIX");
376   if (var)
377     path = g_build_filename (var, "lib", "gtk-2.0", GTK_VERSION, "engines", NULL);
378   else
379     path = g_build_filename (GTK_LIBDIR, "gtk-2.0", GTK_VERSION, "engines", NULL);
380   module_path[n++] = path;
381
382   var = g_get_home_dir ();
383   if (var)
384     {
385       path = g_build_filename (var, ".gtk-2.0", GTK_VERSION, "engines", NULL);
386       module_path[n++] = path;
387     }
388   module_path[n] = NULL;
389 }
390
391 static void
392 gtk_rc_add_initial_default_files (void)
393 {
394   static gint init = FALSE;
395   const gchar *var;
396   gchar *str;
397   gchar **files;
398   gint i;
399
400   if (init)
401     return;
402   
403   gtk_rc_default_files[0] = NULL;
404   init = TRUE;
405
406   var = g_getenv("GTK_RC_FILES");
407   if (var)
408     {
409       files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
410       i=0;
411       while (files[i])
412         {
413           gtk_rc_add_default_file (files[i]);
414           i++;
415         }
416       g_strfreev (files);
417     }
418   else
419     {
420       str = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gtkrc", NULL);
421
422       gtk_rc_add_default_file (str);
423       g_free (str);
424
425       var = g_get_home_dir ();
426       if (var)
427         {
428           str = g_build_filename (var, ".gtkrc-2.0", NULL);
429           gtk_rc_add_default_file (str);
430           g_free (str);
431         }
432     }
433 }
434
435 /**
436  * gtk_rc_add_default_file:
437  * @filename: the pathname to the file.
438  * 
439  * Adds a file to the list of files to be parsed at the
440  * end of gtk_init().
441  **/
442 void
443 gtk_rc_add_default_file (const gchar *filename)
444 {
445   guint n;
446   
447   gtk_rc_add_initial_default_files ();
448
449   for (n = 0; gtk_rc_default_files[n]; n++) ;
450   if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
451     return;
452   
453   gtk_rc_default_files[n++] = g_strdup (filename);
454   gtk_rc_default_files[n] = NULL;
455 }
456
457 /**
458  * gtk_rc_set_default_files:
459  * @filenames: A %NULL terminated list of filenames.
460  * 
461  * Sets the list of files that GTK+ will read at the
462  * end of gtk_init()
463  **/
464 void
465 gtk_rc_set_default_files (gchar **filenames)
466 {
467   gint i;
468
469   gtk_rc_add_initial_default_files ();
470
471   i = 0;
472   while (gtk_rc_default_files[i])
473     {
474       g_free (gtk_rc_default_files[i]);
475       i++;
476     }
477     
478   gtk_rc_default_files[0] = NULL;
479
480   i = 0;
481   while (filenames[i] != NULL)
482     {
483       gtk_rc_add_default_file (filenames[i]);
484       i++;
485     }
486 }
487
488 /**
489  * gtk_rc_get_default_files:
490  * 
491  * Retrieves the current list of RC files that will be parsed
492  * at the end of gtk_init()
493  * 
494  * Return value: A NULL terminated array of filenames. This memory
495  * is owned by GTK+ and must not be freed by the application.
496  *  If you want to store this information, you should make a 
497  * 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  * Make 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 (!dest->font_desc && src->font_desc)
1180     dest->font_desc = pango_font_description_copy (src->font_desc);
1181
1182   if (src->rc_properties)
1183     {
1184       guint i;
1185
1186       for (i = 0; i < src->rc_properties->len; i++)
1187         insert_rc_property (dest,
1188                             &g_array_index (src->rc_properties, GtkRcProperty, i),
1189                             FALSE);
1190     }
1191 }
1192
1193 static GtkStyle *
1194 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
1195 {
1196   return gtk_style_new ();
1197 }
1198
1199 static void
1200 gtk_rc_clear_hash_node (gpointer key, 
1201                         gpointer data, 
1202                         gpointer user_data)
1203 {
1204   gtk_rc_style_unref (data);
1205 }
1206
1207 static void
1208 gtk_rc_free_rc_sets (GSList *slist)
1209 {
1210   while (slist)
1211     {
1212       GtkRcSet *rc_set;
1213
1214       rc_set = slist->data;
1215       g_pattern_spec_free (rc_set->pspec);
1216       g_free (rc_set);
1217
1218       slist = slist->next;
1219     }
1220 }
1221
1222 static void
1223 gtk_rc_clear_styles (GtkRcContext *context)
1224 {
1225   /* Clear out all old rc_styles */
1226
1227   if (context->rc_style_ht)
1228     {
1229       g_hash_table_foreach (context->rc_style_ht, gtk_rc_clear_hash_node, NULL);
1230       g_hash_table_destroy (context->rc_style_ht);
1231       context->rc_style_ht = NULL;
1232     }
1233
1234   gtk_rc_free_rc_sets (context->rc_sets_widget);
1235   g_slist_free (context->rc_sets_widget);
1236   context->rc_sets_widget = NULL;
1237
1238   gtk_rc_free_rc_sets (context->rc_sets_widget_class);
1239   g_slist_free (context->rc_sets_widget_class);
1240   context->rc_sets_widget_class = NULL;
1241
1242   gtk_rc_free_rc_sets (context->rc_sets_class);
1243   g_slist_free (context->rc_sets_class);
1244   context->rc_sets_class = NULL;
1245 }
1246
1247 /* Reset all our widgets. Also, we have to invalidate cached icons in
1248  * icon sets so they get re-rendered.
1249  */
1250 static void
1251 gtk_rc_reset_widgets (GtkRcContext *context)
1252 {
1253   GList *list, *toplevels;
1254   
1255   _gtk_icon_set_invalidate_caches ();
1256   
1257   toplevels = gtk_window_list_toplevels ();
1258   g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1259   
1260   for (list = toplevels; list; list = list->next)
1261     {
1262       gtk_widget_reset_rc_styles (list->data);
1263       gtk_widget_unref (list->data);
1264     }
1265   g_list_free (toplevels);
1266 }
1267
1268 /**
1269  * gtk_rc_reparse_all_for_settings:
1270  * @settings: a #GtkSettings
1271  * @force_load: load whether or not anything changed
1272  * 
1273  * If the modification time on any previously read file
1274  * for the given GtkSettings has changed, discard all style information
1275  * and then reread all previously read RC files.
1276  * 
1277  * Return value: %TRUE if the files were reread.
1278  **/
1279 gboolean
1280 gtk_rc_reparse_all_for_settings (GtkSettings *settings,
1281                                  gboolean     force_load)
1282 {
1283   gboolean mtime_modified = FALSE;
1284   GtkRcFile *rc_file;
1285   GSList *tmp_list;
1286   GtkRcContext *context;
1287
1288   struct stat statbuf;
1289
1290   g_return_val_if_fail (GTK_IS_SETTINGS (settings), FALSE);
1291
1292   context = gtk_rc_context_get (settings);
1293
1294   if (!force_load)
1295     {
1296       /* Check through and see if any of the RC's have had their
1297        * mtime modified. If so, reparse everything.
1298        */
1299       tmp_list = context->rc_files;
1300       while (tmp_list)
1301         {
1302           rc_file = tmp_list->data;
1303           
1304           if (!lstat (rc_file->name, &statbuf) && 
1305               (statbuf.st_mtime > rc_file->mtime))
1306             {
1307               mtime_modified = TRUE;
1308               break;
1309             }
1310           
1311           tmp_list = tmp_list->next;
1312         }
1313     }
1314       
1315   if (force_load || mtime_modified)
1316     {
1317       GSList *old_files;
1318       
1319       gtk_rc_clear_styles (context);
1320       g_object_freeze_notify (G_OBJECT (context->settings));
1321
1322       old_files = context->rc_files;
1323       context->rc_files = NULL;
1324
1325       gtk_rc_parse_default_files (context);
1326
1327       tmp_list = old_files;
1328       while (tmp_list)
1329         {
1330           rc_file = tmp_list->data;
1331           if (rc_file->reload)
1332             gtk_rc_parse_file (context, rc_file->name, GTK_PATH_PRIO_RC, TRUE);
1333
1334           if (rc_file->canonical_name != rc_file->name)
1335             g_free (rc_file->canonical_name);
1336           g_free (rc_file->name);
1337           g_free (rc_file);
1338           
1339           tmp_list = tmp_list->next;
1340         }
1341
1342       g_slist_free (old_files);;
1343
1344       g_free (context->theme_name);
1345       g_free (context->key_theme_name);
1346       g_object_get (context->settings,
1347                     "gtk-theme-name", &context->theme_name,
1348                     "gtk-key-theme-name", &context->key_theme_name,
1349                     NULL);
1350
1351       if (context->theme_name && context->theme_name[0])
1352         gtk_rc_parse_named (context, context->theme_name, NULL);
1353       if (context->key_theme_name && context->key_theme_name[0])
1354         gtk_rc_parse_named (context, context->key_theme_name, "key");
1355       
1356       g_object_thaw_notify (G_OBJECT (context->settings));
1357
1358       gtk_rc_reset_widgets (context);
1359     }
1360
1361   return mtime_modified;
1362 }
1363
1364 /**
1365  * gtk_rc_reparse_all:
1366  * 
1367  * If the modification time on any previously read file for the
1368  * default #GtkSettings has changed, discard all style information
1369  * and then reread all previously read RC files.
1370  * 
1371  * Return value:  %TRUE if the files were reread.
1372  **/
1373 gboolean
1374 gtk_rc_reparse_all (void)
1375 {
1376   return gtk_rc_reparse_all_for_settings (gtk_settings_get_default (), FALSE);
1377 }
1378
1379 static GSList *
1380 gtk_rc_styles_match (GSList       *rc_styles,
1381                      GSList       *sets,
1382                      guint         path_length,
1383                      const gchar  *path,
1384                      const gchar  *path_reversed)
1385                      
1386 {
1387   GtkRcSet *rc_set;
1388
1389   while (sets)
1390     {
1391       rc_set = sets->data;
1392       sets = sets->next;
1393
1394       if (g_pattern_match (rc_set->pspec, path_length, path, path_reversed))
1395         rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
1396     }
1397   
1398   return rc_styles;
1399 }
1400
1401 /**
1402  * gtk_rc_get_style:
1403  * @widget: a #GtkWidget
1404  * 
1405  * Finds all matching RC styles for a given widget,
1406  * composites them together, and then creates a 
1407  * #GtkStyle representing the composite appearance.
1408  * (GTK+ actually keeps a cache of previously 
1409  * created styles, so a new style may not be
1410  * created.)
1411  * 
1412  * Returns: the resulting style. No refcount is added
1413  *   to the returned style, so if you want to save this
1414  *   style around, you should add a reference yourself.
1415  **/
1416 GtkStyle *
1417 gtk_rc_get_style (GtkWidget *widget)
1418 {
1419   GtkRcStyle *widget_rc_style;
1420   GSList *rc_styles = NULL;
1421   GtkRcContext *context;
1422
1423   static guint rc_style_key_id = 0;
1424
1425   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1426
1427   context = gtk_rc_context_get (gtk_widget_get_settings (widget));
1428
1429   /* We allow the specification of a single rc style to be bound
1430    * tightly to a widget, for application modifications
1431    */
1432   if (!rc_style_key_id)
1433     rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1434
1435   widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
1436                                                rc_style_key_id);
1437
1438   if (widget_rc_style)
1439     rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
1440   
1441   if (context->rc_sets_widget)
1442     {
1443       gchar *path, *path_reversed;
1444       guint path_length;
1445
1446       gtk_widget_path (widget, &path_length, &path, &path_reversed);
1447       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, path, path_reversed);
1448       g_free (path);
1449       g_free (path_reversed);
1450     }
1451   
1452   if (context->rc_sets_widget_class)
1453     {
1454       gchar *path, *path_reversed;
1455       guint path_length;
1456
1457       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1458       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, path, path_reversed);
1459       g_free (path);
1460       g_free (path_reversed);
1461     }
1462
1463   if (context->rc_sets_class)
1464     {
1465       GtkType type;
1466
1467       type = GTK_OBJECT_TYPE (widget);
1468       while (type)
1469         {
1470           const gchar *path;
1471           gchar *path_reversed;
1472           guint path_length;
1473
1474           path = gtk_type_name (type);
1475           path_length = strlen (path);
1476           path_reversed = g_strdup (path);
1477           g_strreverse (path_reversed);
1478           
1479           rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
1480           g_free (path_reversed);
1481       
1482           type = gtk_type_parent (type);
1483         }
1484     }
1485   
1486   if (rc_styles)
1487     return gtk_rc_init_style (rc_styles);
1488
1489   return NULL;
1490 }
1491
1492 /**
1493  * gtk_rc_get_style_by_paths:
1494  * @settings: a #GtkSettings object
1495  * @widget_path: the widget path to use when looking up the style, or %NULL
1496  * @class_path: the class path to use when looking up the style, or %NULL
1497  * @type: a type that will be used along with parent types of this type
1498  *        when matching against class styles, or G_TYPE_NONE
1499  * 
1500  * Creates up a #GtkStyle from styles defined in a RC file by providing
1501  * the raw components used in matching. This function may be useful
1502  * when creating pseudo-widgets that should be themed like widgets but
1503  * don't actually have corresponding GTK+ widgets. An example of this
1504  * would be items inside a GNOME canvas widget.
1505  *
1506  * The action of gtk_rc_get_style() is similar to:
1507  *
1508  *  gtk_widget_path (widget, NULL, &path, NULL);
1509  *  gtk_widget_class_path (widget, NULL, &class_path, NULL);
1510  *  gtk_rc_get_style_by_paths (gtk_widget_get_settings (widget), path, class_path,
1511  *                             G_OBJECT_TYPE (widget));
1512  * 
1513  * Return value: A style created by matching with the supplied paths,
1514  *   or %NULL if nothign matching was specified and the  default style should
1515  *   be used. The returned value is owned by GTK+ as part of an internal cache,
1516  *   so you must call g_object_ref() on the returned value if you want to
1517  *   keep a reference to it.
1518  **/
1519 GtkStyle *
1520 gtk_rc_get_style_by_paths (GtkSettings *settings,
1521                            const char  *widget_path,
1522                            const char  *class_path,
1523                            GType        type)
1524 {
1525   /* We duplicate the code from above to avoid slowing down the above
1526    * by generating paths when we don't need them. I don't know if
1527    * this is really worth it.
1528    */
1529   GSList *rc_styles = NULL;
1530   GtkRcContext *context;
1531
1532   g_return_val_if_fail (GTK_IS_SETTINGS (settings), NULL);
1533
1534   context = gtk_rc_context_get (settings);
1535
1536   if (context->rc_sets_widget)
1537     {
1538       gchar *path_reversed;
1539       guint path_length;
1540
1541       path_length = strlen (widget_path);
1542       path_reversed = g_strdup (widget_path);
1543       g_strreverse (path_reversed);
1544
1545       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, widget_path, path_reversed);
1546       g_free (path_reversed);
1547     }
1548   
1549   if (context->rc_sets_widget_class)
1550     {
1551       gchar *path_reversed;
1552       guint path_length;
1553
1554       path_length = strlen (class_path);
1555       path_reversed = g_strdup (class_path);
1556       g_strreverse (path_reversed);
1557
1558       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, class_path, path_reversed);
1559       g_free (path_reversed);
1560     }
1561
1562   if (type != G_TYPE_NONE && context->rc_sets_class)
1563     {
1564       while (type)
1565         {
1566           const gchar *path;
1567           gchar *path_reversed;
1568           guint path_length;
1569
1570           path = g_type_name (type);
1571           path_length = strlen (path);
1572           path_reversed = g_strdup (path);
1573           g_strreverse (path_reversed);
1574           
1575           rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
1576           g_free (path_reversed);
1577       
1578           type = g_type_parent (type);
1579         }
1580     }
1581   
1582   if (rc_styles)
1583     return gtk_rc_init_style (rc_styles);
1584
1585   return NULL;
1586 }
1587
1588 static GSList *
1589 gtk_rc_add_rc_sets (GSList      *slist,
1590                     GtkRcStyle  *rc_style,
1591                     const gchar *pattern)
1592 {
1593   GtkRcStyle *new_style;
1594   GtkRcSet *rc_set;
1595   guint i;
1596   
1597   new_style = gtk_rc_style_new ();
1598   *new_style = *rc_style;
1599   new_style->name = g_strdup (rc_style->name);
1600   if (rc_style->font_desc)
1601     new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
1602   
1603   for (i = 0; i < 5; i++)
1604     new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1605   
1606   rc_set = g_new (GtkRcSet, 1);
1607   rc_set->pspec = g_pattern_spec_new (pattern);
1608   rc_set->rc_style = rc_style;
1609   
1610   return g_slist_prepend (slist, rc_set);
1611 }
1612
1613 void
1614 gtk_rc_add_widget_name_style (GtkRcStyle  *rc_style,
1615                               const gchar *pattern)
1616 {
1617   GtkRcContext *context;
1618   
1619   g_return_if_fail (rc_style != NULL);
1620   g_return_if_fail (pattern != NULL);
1621
1622   context = gtk_rc_context_get (gtk_settings_get_default ());
1623   
1624   context->rc_sets_widget = gtk_rc_add_rc_sets (context->rc_sets_widget, rc_style, pattern);
1625 }
1626
1627 void
1628 gtk_rc_add_widget_class_style (GtkRcStyle  *rc_style,
1629                                const gchar *pattern)
1630 {
1631   GtkRcContext *context;
1632   
1633   g_return_if_fail (rc_style != NULL);
1634   g_return_if_fail (pattern != NULL);
1635
1636   context = gtk_rc_context_get (gtk_settings_get_default ());
1637   
1638   context->rc_sets_widget_class = gtk_rc_add_rc_sets (context->rc_sets_widget_class, rc_style, pattern);
1639 }
1640
1641 void
1642 gtk_rc_add_class_style (GtkRcStyle  *rc_style,
1643                         const gchar *pattern)
1644 {
1645   GtkRcContext *context;
1646   
1647   g_return_if_fail (rc_style != NULL);
1648   g_return_if_fail (pattern != NULL);
1649
1650   context = gtk_rc_context_get (gtk_settings_get_default ());
1651   
1652   context->rc_sets_class = gtk_rc_add_rc_sets (context->rc_sets_class, rc_style, pattern);
1653 }
1654
1655 GScanner*
1656 gtk_rc_scanner_new (void)
1657 {
1658   return g_scanner_new (&gtk_rc_scanner_config);
1659 }
1660
1661 static void
1662 gtk_rc_parse_any (GtkRcContext *context,
1663                   const gchar  *input_name,
1664                   gint          input_fd,
1665                   const gchar  *input_string)
1666 {
1667   GScanner *scanner;
1668   guint    i;
1669   gboolean done;
1670
1671   scanner = gtk_rc_scanner_new ();
1672   
1673   if (input_fd >= 0)
1674     {
1675       g_assert (input_string == NULL);
1676       
1677       g_scanner_input_file (scanner, input_fd);
1678     }
1679   else
1680     {
1681       g_assert (input_string != NULL);
1682       
1683       g_scanner_input_text (scanner, input_string, strlen (input_string));
1684     }
1685   scanner->input_name = input_name;
1686
1687   for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1688     g_scanner_scope_add_symbol (scanner, 0, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1689   
1690   done = FALSE;
1691   while (!done)
1692     {
1693       if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1694         done = TRUE;
1695       else
1696         {
1697           guint expected_token;
1698           
1699           expected_token = gtk_rc_parse_statement (context, scanner);
1700
1701           if (expected_token != G_TOKEN_NONE)
1702             {
1703               gchar *symbol_name;
1704               gchar *msg;
1705               
1706               msg = NULL;
1707               symbol_name = NULL;
1708               if (scanner->scope_id == 0)
1709                 {
1710                   /* if we are in scope 0, we know the symbol names
1711                    * that are associated with certaintoken values.
1712                    * so we look them up to make the error messages
1713                    * more readable.
1714                    */
1715                   if (expected_token > GTK_RC_TOKEN_INVALID &&
1716                       expected_token < GTK_RC_TOKEN_LAST)
1717                     {
1718                       for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1719                         if (symbols[i].token == expected_token)
1720                           msg = symbols[i].name;
1721                       if (msg)
1722                         msg = g_strconcat ("e.g. `", msg, "'", NULL);
1723                     }
1724                   if (scanner->token > GTK_RC_TOKEN_INVALID &&
1725                       scanner->token < GTK_RC_TOKEN_LAST)
1726                     {
1727                       symbol_name = "???";
1728                       for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1729                         if (symbols[i].token == scanner->token)
1730                           symbol_name = symbols[i].name;
1731                     }
1732                 }
1733               g_scanner_unexp_token (scanner,
1734                                      expected_token,
1735                                      NULL,
1736                                      "keyword",
1737                                      symbol_name,
1738                                      msg,
1739                                      TRUE);
1740               g_free (msg);
1741               done = TRUE;
1742             }
1743         }
1744     }
1745   
1746   g_scanner_destroy (scanner);
1747 }
1748
1749 static guint       
1750 gtk_rc_styles_hash (const GSList *rc_styles)
1751 {
1752   guint result;
1753   
1754   result = 0;
1755   while (rc_styles)
1756     {
1757       result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1758       rc_styles = rc_styles->next;
1759     }
1760   
1761   return result;
1762 }
1763
1764 static gboolean
1765 gtk_rc_styles_equal (const GSList *a,
1766                      const GSList *b)
1767 {
1768   while (a && b)
1769     {
1770       if (a->data != b->data)
1771         return FALSE;
1772       a = a->next;
1773       b = b->next;
1774     }
1775   
1776   return (a == b);
1777 }
1778
1779 static guint
1780 gtk_rc_style_hash (const gchar *name)
1781 {
1782   guint result;
1783   
1784   result = 0;
1785   while (*name)
1786     result += (result << 3) + *name++;
1787   
1788   return result;
1789 }
1790
1791 static gboolean
1792 gtk_rc_style_equal (const gchar *a,
1793                     const gchar *b)
1794 {
1795   return (strcmp (a, b) == 0);
1796 }
1797
1798 static GtkRcStyle*
1799 gtk_rc_style_find (GtkRcContext *context,
1800                    const gchar  *name)
1801 {
1802   if (context->rc_style_ht)
1803     return g_hash_table_lookup (context->rc_style_ht, (gpointer) name);
1804   else
1805     return NULL;
1806 }
1807
1808 static GtkStyle *
1809 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1810 {
1811   GtkStyle *style;
1812
1813   style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
1814
1815   style->rc_style = rc_style;
1816
1817   gtk_rc_style_ref (rc_style);
1818   
1819   GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);  
1820
1821   return style;
1822 }
1823
1824 /* Reuses or frees rc_styles */
1825 static GtkStyle *
1826 gtk_rc_init_style (GSList *rc_styles)
1827 {
1828   GtkStyle *style = NULL;
1829   gint i;
1830
1831   g_return_val_if_fail (rc_styles != NULL, NULL);
1832   
1833   if (!realized_style_ht)
1834     realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
1835  (GEqualFunc) gtk_rc_styles_equal);
1836
1837   style = g_hash_table_lookup (realized_style_ht, rc_styles);
1838
1839   if (!style)
1840     {
1841       GtkRcStyle *base_style = NULL;
1842       GtkRcStyle *proto_style;
1843       GtkRcStyleClass *proto_style_class;
1844       GSList *tmp_styles;
1845       GType rc_style_type = GTK_TYPE_RC_STYLE;
1846
1847       /* Find the first derived style in the list, and use that to
1848        * create the merged style. If we only have raw GtkRcStyles, use
1849        * the first style to create the merged style.
1850        */
1851       base_style = rc_styles->data;
1852       tmp_styles = rc_styles;
1853       while (tmp_styles)
1854         {
1855           GtkRcStyle *rc_style = tmp_styles->data;
1856           
1857           if (G_OBJECT_TYPE (rc_style) != rc_style_type)
1858             {
1859               base_style = rc_style;
1860               break;
1861             }
1862           
1863           tmp_styles = tmp_styles->next;
1864         }
1865       
1866       proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
1867       proto_style = proto_style_class->create_rc_style (base_style);
1868       
1869       tmp_styles = rc_styles;
1870       while (tmp_styles)
1871         {
1872           GtkRcStyle *rc_style = tmp_styles->data;
1873           GSList *factories;
1874           
1875           proto_style_class->merge (proto_style, rc_style);       
1876           
1877           /* Point from each rc_style to the list of styles */
1878           if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
1879             rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
1880
1881           factories = g_slist_copy (rc_style->icon_factories);
1882           if (factories)
1883             {
1884               GSList *iter;
1885               
1886               iter = factories;
1887               while (iter != NULL)
1888                 {
1889                   g_object_ref (G_OBJECT (iter->data));
1890                   iter = g_slist_next (iter);
1891                 }
1892
1893               proto_style->icon_factories = g_slist_concat (proto_style->icon_factories,
1894                                                             factories);
1895
1896             }
1897           
1898           tmp_styles = tmp_styles->next;
1899         }
1900
1901       for (i = 0; i < 5; i++)
1902         if (proto_style->bg_pixmap_name[i] &&
1903             (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1904           {
1905             g_free (proto_style->bg_pixmap_name[i]);
1906             proto_style->bg_pixmap_name[i] = NULL;
1907           }
1908
1909       style = gtk_rc_style_to_style (proto_style);
1910       gtk_rc_style_unref (proto_style);
1911
1912       g_hash_table_insert (realized_style_ht, rc_styles, style);
1913     }
1914   else
1915     g_slist_free (rc_styles);
1916
1917   return style;
1918 }
1919
1920 /*********************
1921  * Parsing functions *
1922  *********************/
1923
1924 static guint
1925 rc_parse_token_or_compound (GScanner  *scanner,
1926                             GString   *gstring,
1927                             GTokenType delimiter)
1928 {
1929   guint token = g_scanner_get_next_token (scanner);
1930
1931   /* we either scan a single token (skipping comments)
1932    * or a compund statement.
1933    * compunds are enclosed in (), [] or {} braces, we read
1934    * them in via deep recursion.
1935    */
1936
1937   switch (token)
1938     {
1939       gchar *string;
1940     case G_TOKEN_INT:
1941       g_string_append_printf (gstring, " 0x%lx", scanner->value.v_int);
1942       break;
1943     case G_TOKEN_FLOAT:
1944       g_string_append_printf (gstring, " %f", scanner->value.v_float);
1945       break;
1946     case G_TOKEN_STRING:
1947       string = g_strescape (scanner->value.v_string, NULL);
1948       g_string_append (gstring, " \"");
1949       g_string_append (gstring, string);
1950       g_string_append_c (gstring, '"');
1951       g_free (string);
1952       break;
1953     case G_TOKEN_IDENTIFIER:
1954       g_string_append_c (gstring, ' ');
1955       g_string_append (gstring, scanner->value.v_identifier);
1956       break;
1957     case G_TOKEN_COMMENT_SINGLE:
1958     case G_TOKEN_COMMENT_MULTI:
1959       return rc_parse_token_or_compound (scanner, gstring, delimiter);
1960     case G_TOKEN_LEFT_PAREN:
1961       g_string_append_c (gstring, ' ');
1962       g_string_append_c (gstring, token);
1963       token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_PAREN);
1964       if (token != G_TOKEN_NONE)
1965         return token;
1966       break;
1967     case G_TOKEN_LEFT_CURLY:
1968       g_string_append_c (gstring, ' ');
1969       g_string_append_c (gstring, token);
1970       token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_CURLY);
1971       if (token != G_TOKEN_NONE)
1972         return token;
1973       break;
1974     case G_TOKEN_LEFT_BRACE:
1975       g_string_append_c (gstring, ' ');
1976       g_string_append_c (gstring, token);
1977       token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_BRACE);
1978       if (token != G_TOKEN_NONE)
1979         return token;
1980       break;
1981     default:
1982       if (token >= 256 || token < 1)
1983         return delimiter ? delimiter : G_TOKEN_STRING;
1984       g_string_append_c (gstring, ' ');
1985       g_string_append_c (gstring, token);
1986       if (token == delimiter)
1987         return G_TOKEN_NONE;
1988       break;
1989     }
1990   if (!delimiter)
1991     return G_TOKEN_NONE;
1992   else
1993     return rc_parse_token_or_compound (scanner, gstring, delimiter);
1994 }
1995
1996 static guint
1997 gtk_rc_parse_assignment (GScanner      *scanner,
1998                          GtkRcProperty *prop)
1999 {
2000   gboolean scan_identifier = scanner->config->scan_identifier;
2001   gboolean scan_symbols = scanner->config->scan_symbols;
2002   gboolean identifier_2_string = scanner->config->identifier_2_string;
2003   gboolean char_2_token = scanner->config->char_2_token;
2004   gboolean scan_identifier_NULL = scanner->config->scan_identifier_NULL;
2005   gboolean numbers_2_int = scanner->config->numbers_2_int;
2006   gboolean negate = FALSE;
2007   guint token;
2008
2009   /* check that this is an assignment */
2010   if (g_scanner_get_next_token (scanner) != '=')
2011     return '=';
2012
2013   /* adjust scanner mode */
2014   scanner->config->scan_identifier = TRUE;
2015   scanner->config->scan_symbols = FALSE;
2016   scanner->config->identifier_2_string = FALSE;
2017   scanner->config->char_2_token = TRUE;
2018   scanner->config->scan_identifier_NULL = FALSE;
2019   scanner->config->numbers_2_int = TRUE;
2020
2021   /* record location */
2022   prop->origin = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
2023
2024   /* parse optional sign */
2025   if (g_scanner_peek_next_token (scanner) == '-')
2026     {
2027       g_scanner_get_next_token (scanner); /* eat sign */
2028       negate = TRUE;
2029     }
2030
2031   /* parse one of LONG, DOUBLE and STRING or, if that fails, create an unparsed compund */
2032   token = g_scanner_peek_next_token (scanner);
2033   switch (token)
2034     {
2035     case G_TOKEN_INT:
2036       g_scanner_get_next_token (scanner);
2037       g_value_init (&prop->value, G_TYPE_LONG);
2038       g_value_set_long (&prop->value, negate ? -scanner->value.v_int : scanner->value.v_int);
2039       token = G_TOKEN_NONE;
2040       break;
2041     case G_TOKEN_FLOAT:
2042       g_scanner_get_next_token (scanner);
2043       g_value_init (&prop->value, G_TYPE_DOUBLE);
2044       g_value_set_double (&prop->value, negate ? -scanner->value.v_float : scanner->value.v_float);
2045       token = G_TOKEN_NONE;
2046       break;
2047     case G_TOKEN_STRING:
2048       g_scanner_get_next_token (scanner);
2049       if (negate)
2050         token = G_TOKEN_INT;
2051       else
2052         {
2053           g_value_init (&prop->value, G_TYPE_STRING);
2054           g_value_set_string (&prop->value, scanner->value.v_string);
2055           token = G_TOKEN_NONE;
2056         }
2057       break;
2058     case G_TOKEN_IDENTIFIER:
2059     case G_TOKEN_LEFT_PAREN:
2060     case G_TOKEN_LEFT_CURLY:
2061     case G_TOKEN_LEFT_BRACE:
2062       if (!negate)
2063         {
2064           GString *gstring = g_string_new ("");
2065
2066           token = rc_parse_token_or_compound (scanner, gstring, 0);
2067           if (token == G_TOKEN_NONE)
2068             {
2069               g_string_append_c (gstring, ' ');
2070               g_value_init (&prop->value, G_TYPE_GSTRING);
2071               g_value_set_static_boxed (&prop->value, gstring);
2072             }
2073           else
2074             g_string_free (gstring, TRUE);
2075           break;
2076         }
2077       /* fall through */
2078     default:
2079       g_scanner_get_next_token (scanner);
2080       token = G_TOKEN_INT;
2081       break;
2082     }
2083
2084   /* restore scanner mode */
2085   scanner->config->scan_identifier = scan_identifier;
2086   scanner->config->scan_symbols = scan_symbols;
2087   scanner->config->identifier_2_string = identifier_2_string;
2088   scanner->config->char_2_token = char_2_token;
2089   scanner->config->scan_identifier_NULL = scan_identifier_NULL;
2090   scanner->config->numbers_2_int = numbers_2_int;
2091
2092   return token;
2093 }
2094
2095 static gboolean
2096 is_c_identifier (const gchar *string)
2097 {
2098   const gchar *p;
2099   gboolean is_varname;
2100
2101   is_varname = strchr (G_CSET_a_2_z G_CSET_A_2_Z "_", string[0]) != NULL;
2102   for (p = string + 1; *p && is_varname; p++)
2103     is_varname &= strchr (G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "_-", *p) != NULL;
2104
2105   return is_varname;
2106 }
2107
2108 static guint
2109 gtk_rc_parse_statement (GtkRcContext *context,
2110                         GScanner     *scanner)
2111 {
2112   guint token;
2113   
2114   token = g_scanner_peek_next_token (scanner);
2115   switch (token)
2116     {
2117     case GTK_RC_TOKEN_INCLUDE:
2118       token = g_scanner_get_next_token (scanner);
2119       if (token != GTK_RC_TOKEN_INCLUDE)
2120         return GTK_RC_TOKEN_INCLUDE;
2121       token = g_scanner_get_next_token (scanner);
2122       if (token != G_TOKEN_STRING)
2123         return G_TOKEN_STRING;
2124       gtk_rc_parse_file (context, scanner->value.v_string, context->default_priority, FALSE);
2125       return G_TOKEN_NONE;
2126       
2127     case GTK_RC_TOKEN_STYLE:
2128       return gtk_rc_parse_style (context, scanner);
2129       
2130     case GTK_RC_TOKEN_BINDING:
2131       return gtk_binding_parse_binding (scanner);
2132       
2133     case GTK_RC_TOKEN_PIXMAP_PATH:
2134       return gtk_rc_parse_pixmap_path (context, scanner);
2135       
2136     case GTK_RC_TOKEN_WIDGET:
2137       return gtk_rc_parse_path_pattern (context, scanner);
2138       
2139     case GTK_RC_TOKEN_WIDGET_CLASS:
2140       return gtk_rc_parse_path_pattern (context, scanner);
2141       
2142     case GTK_RC_TOKEN_CLASS:
2143       return gtk_rc_parse_path_pattern (context, scanner);
2144       
2145     case GTK_RC_TOKEN_MODULE_PATH:
2146       return gtk_rc_parse_module_path (scanner);
2147       
2148     case GTK_RC_TOKEN_IM_MODULE_PATH:
2149       return gtk_rc_parse_im_module_path (scanner);
2150       
2151     case GTK_RC_TOKEN_IM_MODULE_FILE:
2152       return gtk_rc_parse_im_module_file (scanner);
2153
2154     case G_TOKEN_IDENTIFIER:
2155       if (is_c_identifier (scanner->next_value.v_identifier))
2156         {
2157           GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2158           gchar *name;
2159           
2160           g_scanner_get_next_token (scanner); /* eat identifier */
2161           name = g_strdup (scanner->value.v_identifier);
2162           
2163           token = gtk_rc_parse_assignment (scanner, &prop);
2164           if (token == G_TOKEN_NONE)
2165             {
2166               GtkSettingsValue svalue;
2167
2168               svalue.origin = prop.origin;
2169               memcpy (&svalue.value, &prop.value, sizeof (prop.value));
2170               g_strcanon (name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
2171               gtk_settings_set_property_value (context->settings,
2172                                                name,
2173                                                &svalue);
2174             }
2175           g_free (prop.origin);
2176           if (G_VALUE_TYPE (&prop.value))
2177             g_value_unset (&prop.value);
2178           g_free (name);
2179           
2180           return token;
2181         }
2182       else
2183         {
2184           g_scanner_get_next_token (scanner);
2185           return G_TOKEN_IDENTIFIER;
2186         }
2187     default:
2188       g_scanner_get_next_token (scanner);
2189       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
2190     }
2191 }
2192
2193 static guint
2194 gtk_rc_parse_style (GtkRcContext *context,
2195                     GScanner     *scanner)
2196 {
2197   GtkRcStyle *rc_style;
2198   GtkRcStyle *parent_style;
2199   guint token;
2200   gint insert;
2201   gint i;
2202   GtkIconFactory *our_factory = NULL;
2203   
2204   token = g_scanner_get_next_token (scanner);
2205   if (token != GTK_RC_TOKEN_STYLE)
2206     return GTK_RC_TOKEN_STYLE;
2207   
2208   token = g_scanner_get_next_token (scanner);
2209   if (token != G_TOKEN_STRING)
2210     return G_TOKEN_STRING;
2211   
2212   insert = FALSE;
2213   rc_style = gtk_rc_style_find (context, scanner->value.v_string);
2214
2215   /* If there's a list, its first member is always the factory belonging
2216    * to this RcStyle
2217    */
2218   if (rc_style && rc_style->icon_factories)
2219     our_factory = rc_style->icon_factories->data;
2220   
2221   if (!rc_style)
2222     {
2223       insert = TRUE;
2224       rc_style = gtk_rc_style_new ();
2225       rc_style->name = g_strdup (scanner->value.v_string);
2226       
2227       for (i = 0; i < 5; i++)
2228         rc_style->bg_pixmap_name[i] = NULL;
2229
2230       for (i = 0; i < 5; i++)
2231         rc_style->color_flags[i] = 0;
2232     }
2233
2234   token = g_scanner_peek_next_token (scanner);
2235   if (token == G_TOKEN_EQUAL_SIGN)
2236     {
2237       token = g_scanner_get_next_token (scanner);
2238       
2239       token = g_scanner_get_next_token (scanner);
2240       if (token != G_TOKEN_STRING)
2241         {
2242           if (insert)
2243             g_free (rc_style);
2244
2245           return G_TOKEN_STRING;
2246         }
2247       
2248       parent_style = gtk_rc_style_find (context, scanner->value.v_string);
2249       if (parent_style)
2250         {
2251           GSList *factories;
2252           
2253           for (i = 0; i < 5; i++)
2254             {
2255               rc_style->color_flags[i] = parent_style->color_flags[i];
2256               rc_style->fg[i] = parent_style->fg[i];
2257               rc_style->bg[i] = parent_style->bg[i];
2258               rc_style->text[i] = parent_style->text[i];
2259               rc_style->base[i] = parent_style->base[i];
2260             }
2261
2262           rc_style->xthickness = parent_style->xthickness;
2263           rc_style->ythickness = parent_style->ythickness;
2264           
2265           if (parent_style->font_desc)
2266             {
2267               if (rc_style->font_desc)
2268                 pango_font_description_free (rc_style->font_desc);
2269               rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
2270             }
2271
2272           if (parent_style->rc_properties)
2273             {
2274               guint i;
2275
2276               for (i = 0; i < parent_style->rc_properties->len; i++)
2277                 insert_rc_property (rc_style,
2278                                     &g_array_index (parent_style->rc_properties, GtkRcProperty, i),
2279                                     TRUE);
2280             }
2281           
2282           for (i = 0; i < 5; i++)
2283             {
2284               if (rc_style->bg_pixmap_name[i])
2285                 g_free (rc_style->bg_pixmap_name[i]);
2286               rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
2287             }
2288           
2289           /* Append parent's factories, adding a ref to them */
2290           if (parent_style->icon_factories != NULL)
2291             {
2292               /* Add a factory for ourselves if we have none,
2293                * in case we end up defining more stock icons.
2294                * I see no real way around this; we need to maintain
2295                * the invariant that the first factory in the list
2296                * is always our_factory, the one belonging to us,
2297                * and if we put parent factories in the list we can't
2298                * do that if the style is reopened.
2299                */
2300               if (our_factory == NULL)
2301                 {
2302                   our_factory = gtk_icon_factory_new ();
2303                   rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
2304                                                               our_factory);
2305                 }
2306               
2307               rc_style->icon_factories = g_slist_concat (rc_style->icon_factories,
2308                                                          g_slist_copy (parent_style->icon_factories));
2309               
2310               factories = parent_style->icon_factories;
2311               while (factories != NULL)
2312                 {
2313                   g_object_ref (G_OBJECT (factories->data));
2314                   factories = factories->next;
2315                 }
2316             }
2317         }
2318     }
2319   
2320   token = g_scanner_get_next_token (scanner);
2321   if (token != G_TOKEN_LEFT_CURLY)
2322     {
2323       if (insert)
2324         g_free (rc_style);
2325
2326       return G_TOKEN_LEFT_CURLY;
2327     }
2328   
2329   token = g_scanner_peek_next_token (scanner);
2330   while (token != G_TOKEN_RIGHT_CURLY)
2331     {
2332       switch (token)
2333         {
2334         case GTK_RC_TOKEN_BG:
2335           token = gtk_rc_parse_bg (scanner, rc_style);
2336           break;
2337         case GTK_RC_TOKEN_FG:
2338           token = gtk_rc_parse_fg (scanner, rc_style);
2339           break;
2340         case GTK_RC_TOKEN_TEXT:
2341           token = gtk_rc_parse_text (scanner, rc_style);
2342           break;
2343         case GTK_RC_TOKEN_BASE:
2344           token = gtk_rc_parse_base (scanner, rc_style);
2345           break;
2346         case GTK_RC_TOKEN_XTHICKNESS:
2347           token = gtk_rc_parse_xthickness (scanner, rc_style);
2348           break;
2349         case GTK_RC_TOKEN_YTHICKNESS:
2350           token = gtk_rc_parse_ythickness (scanner, rc_style);
2351           break;
2352         case GTK_RC_TOKEN_BG_PIXMAP:
2353           token = gtk_rc_parse_bg_pixmap (context, scanner, rc_style);
2354           break;
2355         case GTK_RC_TOKEN_FONT:
2356           token = gtk_rc_parse_font (scanner, rc_style);
2357           break;
2358         case GTK_RC_TOKEN_FONTSET:
2359           token = gtk_rc_parse_fontset (scanner, rc_style);
2360           break;
2361         case GTK_RC_TOKEN_FONT_NAME:
2362           token = gtk_rc_parse_font_name (scanner, rc_style);
2363           break;
2364         case GTK_RC_TOKEN_ENGINE:
2365           token = gtk_rc_parse_engine (context, scanner, &rc_style);
2366           break;
2367         case GTK_RC_TOKEN_STOCK:
2368           if (our_factory == NULL)
2369             {
2370               our_factory = gtk_icon_factory_new ();
2371               rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
2372                                                           our_factory);
2373             }
2374           token = gtk_rc_parse_stock (context, scanner, rc_style, our_factory);
2375           break;
2376         case G_TOKEN_IDENTIFIER:
2377           if (is_c_identifier (scanner->next_value.v_identifier) &&
2378               scanner->next_value.v_identifier[0] >= 'A' &&
2379               scanner->next_value.v_identifier[0] <= 'Z') /* match namespaced type names */
2380             {
2381               GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2382               
2383               g_scanner_get_next_token (scanner); /* eat type name */
2384               prop.type_name = g_quark_from_string (scanner->value.v_identifier);
2385               if (g_scanner_get_next_token (scanner) != ':' ||
2386                   g_scanner_get_next_token (scanner) != ':')
2387                 {
2388                   token = ':';
2389                   break;
2390                 }
2391               if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER ||
2392                   !is_c_identifier (scanner->value.v_identifier))
2393                 {
2394                   token = G_TOKEN_IDENTIFIER;
2395                   break;
2396                 }
2397
2398               /* it's important that we do the same canonification as GParamSpecPool here */
2399               g_strcanon (scanner->value.v_identifier, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
2400               prop.property_name = g_quark_from_string (scanner->value.v_identifier);
2401
2402               token = gtk_rc_parse_assignment (scanner, &prop);
2403               if (token == G_TOKEN_NONE)
2404                 {
2405                   g_return_val_if_fail (prop.origin != NULL && G_VALUE_TYPE (&prop.value) != 0, G_TOKEN_ERROR);
2406                   insert_rc_property (rc_style, &prop, TRUE);
2407                 }
2408               
2409               g_free (prop.origin);
2410               if (G_VALUE_TYPE (&prop.value))
2411                 g_value_unset (&prop.value);
2412             }
2413           else
2414             {
2415               g_scanner_get_next_token (scanner);
2416               token = G_TOKEN_IDENTIFIER;
2417             }
2418           break;
2419         default:
2420           g_scanner_get_next_token (scanner);
2421           token = G_TOKEN_RIGHT_CURLY;
2422           break;
2423         }
2424
2425       if (token != G_TOKEN_NONE)
2426         {
2427           if (insert)
2428             gtk_rc_style_unref (rc_style);
2429
2430           return token;
2431         }
2432       token = g_scanner_peek_next_token (scanner);
2433     } /* while (token != G_TOKEN_RIGHT_CURLY) */
2434   
2435   token = g_scanner_get_next_token (scanner);
2436   if (token != G_TOKEN_RIGHT_CURLY)
2437     {
2438       if (insert)
2439         {
2440           if (rc_style->font_desc)
2441             pango_font_description_free (rc_style->font_desc);
2442           
2443           for (i = 0; i < 5; i++)
2444             if (rc_style->bg_pixmap_name[i])
2445               g_free (rc_style->bg_pixmap_name[i]);
2446           
2447           g_free (rc_style);
2448         }
2449       return G_TOKEN_RIGHT_CURLY;
2450     }
2451   
2452   if (insert)
2453     {
2454       if (!context->rc_style_ht)
2455         context->rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
2456                                                  (GEqualFunc) gtk_rc_style_equal);
2457       
2458       g_hash_table_insert (context->rc_style_ht, rc_style->name, rc_style);
2459     }
2460   
2461   return G_TOKEN_NONE;
2462 }
2463
2464 const GtkRcProperty*
2465 _gtk_rc_style_lookup_rc_property (GtkRcStyle *rc_style,
2466                                   GQuark      type_name,
2467                                   GQuark      property_name)
2468 {
2469   GtkRcProperty *node = NULL;
2470
2471   g_return_val_if_fail (GTK_IS_RC_STYLE (rc_style), NULL);
2472
2473   if (rc_style->rc_properties)
2474     {
2475       GtkRcProperty key;
2476
2477       key.type_name = type_name;
2478       key.property_name = property_name;
2479
2480       node = bsearch (&key,
2481                       rc_style->rc_properties->data, rc_style->rc_properties->len,
2482                       sizeof (GtkRcProperty), gtk_rc_properties_cmp);
2483     }
2484
2485   return node;
2486 }
2487
2488 static guint
2489 gtk_rc_parse_bg (GScanner   *scanner,
2490                  GtkRcStyle *style)
2491 {
2492   GtkStateType state;
2493   guint token;
2494   
2495   token = g_scanner_get_next_token (scanner);
2496   if (token != GTK_RC_TOKEN_BG)
2497     return GTK_RC_TOKEN_BG;
2498   
2499   token = gtk_rc_parse_state (scanner, &state);
2500   if (token != G_TOKEN_NONE)
2501     return token;
2502   
2503   token = g_scanner_get_next_token (scanner);
2504   if (token != G_TOKEN_EQUAL_SIGN)
2505     return G_TOKEN_EQUAL_SIGN;
2506
2507   style->color_flags[state] |= GTK_RC_BG;
2508   return gtk_rc_parse_color (scanner, &style->bg[state]);
2509 }
2510
2511 static guint
2512 gtk_rc_parse_fg (GScanner   *scanner,
2513                  GtkRcStyle *style)
2514 {
2515   GtkStateType state;
2516   guint token;
2517   
2518   token = g_scanner_get_next_token (scanner);
2519   if (token != GTK_RC_TOKEN_FG)
2520     return GTK_RC_TOKEN_FG;
2521   
2522   token = gtk_rc_parse_state (scanner, &state);
2523   if (token != G_TOKEN_NONE)
2524     return token;
2525   
2526   token = g_scanner_get_next_token (scanner);
2527   if (token != G_TOKEN_EQUAL_SIGN)
2528     return G_TOKEN_EQUAL_SIGN;
2529   
2530   style->color_flags[state] |= GTK_RC_FG;
2531   return gtk_rc_parse_color (scanner, &style->fg[state]);
2532 }
2533
2534 static guint
2535 gtk_rc_parse_text (GScanner   *scanner,
2536                    GtkRcStyle *style)
2537 {
2538   GtkStateType state;
2539   guint token;
2540   
2541   token = g_scanner_get_next_token (scanner);
2542   if (token != GTK_RC_TOKEN_TEXT)
2543     return GTK_RC_TOKEN_TEXT;
2544   
2545   token = gtk_rc_parse_state (scanner, &state);
2546   if (token != G_TOKEN_NONE)
2547     return token;
2548   
2549   token = g_scanner_get_next_token (scanner);
2550   if (token != G_TOKEN_EQUAL_SIGN)
2551     return G_TOKEN_EQUAL_SIGN;
2552   
2553   style->color_flags[state] |= GTK_RC_TEXT;
2554   return gtk_rc_parse_color (scanner, &style->text[state]);
2555 }
2556
2557 static guint
2558 gtk_rc_parse_base (GScanner   *scanner,
2559                    GtkRcStyle *style)
2560 {
2561   GtkStateType state;
2562   guint token;
2563   
2564   token = g_scanner_get_next_token (scanner);
2565   if (token != GTK_RC_TOKEN_BASE)
2566     return GTK_RC_TOKEN_BASE;
2567   
2568   token = gtk_rc_parse_state (scanner, &state);
2569   if (token != G_TOKEN_NONE)
2570     return token;
2571   
2572   token = g_scanner_get_next_token (scanner);
2573   if (token != G_TOKEN_EQUAL_SIGN)
2574     return G_TOKEN_EQUAL_SIGN;
2575
2576   style->color_flags[state] |= GTK_RC_BASE;
2577   return gtk_rc_parse_color (scanner, &style->base[state]);
2578 }
2579
2580 static guint
2581 gtk_rc_parse_xthickness (GScanner   *scanner,
2582                          GtkRcStyle *style)
2583 {
2584   if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
2585     return GTK_RC_TOKEN_XTHICKNESS;
2586
2587   if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2588     return G_TOKEN_EQUAL_SIGN;
2589
2590   if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2591     return G_TOKEN_INT;
2592
2593   style->xthickness = scanner->value.v_int;
2594
2595   return G_TOKEN_NONE;
2596 }
2597
2598 static guint
2599 gtk_rc_parse_ythickness (GScanner   *scanner,
2600                          GtkRcStyle *style)
2601 {
2602   if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
2603     return GTK_RC_TOKEN_YTHICKNESS;
2604
2605   if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2606     return G_TOKEN_EQUAL_SIGN;
2607
2608   if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2609     return G_TOKEN_INT;
2610
2611   style->ythickness = scanner->value.v_int;
2612
2613   return G_TOKEN_NONE;
2614 }
2615
2616 static guint
2617 gtk_rc_parse_bg_pixmap (GtkRcContext *context,
2618                         GScanner     *scanner,
2619                         GtkRcStyle   *rc_style)
2620 {
2621   GtkStateType state;
2622   guint token;
2623   gchar *pixmap_file;
2624   
2625   token = g_scanner_get_next_token (scanner);
2626   if (token != GTK_RC_TOKEN_BG_PIXMAP)
2627     return GTK_RC_TOKEN_BG_PIXMAP;
2628   
2629   token = gtk_rc_parse_state (scanner, &state);
2630   if (token != G_TOKEN_NONE)
2631     return token;
2632   
2633   token = g_scanner_get_next_token (scanner);
2634   if (token != G_TOKEN_EQUAL_SIGN)
2635     return G_TOKEN_EQUAL_SIGN;
2636   
2637   token = g_scanner_get_next_token (scanner);
2638   if (token != G_TOKEN_STRING)
2639     return G_TOKEN_STRING;
2640   
2641   if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
2642       (strcmp (scanner->value.v_string, "<none>") == 0))
2643     pixmap_file = g_strdup (scanner->value.v_string);
2644   else
2645     pixmap_file = gtk_rc_find_pixmap_in_path (context->settings,
2646                                               scanner, scanner->value.v_string);
2647   
2648   if (pixmap_file)
2649     {
2650       if (rc_style->bg_pixmap_name[state])
2651         g_free (rc_style->bg_pixmap_name[state]);
2652       rc_style->bg_pixmap_name[state] = pixmap_file;
2653     }
2654   
2655   return G_TOKEN_NONE;
2656 }
2657
2658 static gchar*
2659 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
2660 {
2661   gchar *buf;
2662   gint fd;
2663
2664   buf = g_build_filename (dir, pixmap_file, NULL);
2665   
2666   fd = open (buf, O_RDONLY);
2667   if (fd >= 0)
2668     {
2669       close (fd);
2670       return buf;
2671     }
2672    
2673   g_free (buf);
2674  
2675    return NULL;
2676  }
2677
2678 /**
2679  * gtk_rc_context_find_pixmap_in_path:
2680  * @settings: a #GtkSettinsg
2681  * @scanner: Scanner used to get line number information for the
2682  *   warning message, or %NULL
2683  * @pixmap_file: name of the pixmap file to locate.
2684  * 
2685  * Looks up a file in pixmap path for the specified #GtkSettings.
2686  * If the file is not found, it outputs a warning message using
2687  * g_warning() and returns %NULL.
2688  *
2689  * Return value: 
2690  **/
2691 gchar*
2692 gtk_rc_find_pixmap_in_path (GtkSettings  *settings,
2693                             GScanner     *scanner,
2694                             const gchar  *pixmap_file)
2695 {
2696   gint i;
2697   gchar *filename;
2698   GSList *tmp_list;
2699
2700   GtkRcContext *context = gtk_rc_context_get (settings);
2701     
2702   for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (context->pixmap_path[i] != NULL); i++)
2703     {
2704       filename = gtk_rc_check_pixmap_dir (context->pixmap_path[i], pixmap_file);
2705       if (filename)
2706         return filename;
2707     }
2708  
2709   tmp_list = rc_dir_stack;
2710   while (tmp_list)
2711     {
2712       filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
2713       if (filename)
2714         return filename;
2715        
2716       tmp_list = tmp_list->next;
2717     }
2718   
2719   if (scanner)
2720     g_warning (_("Unable to locate image file in pixmap_path: \"%s\" line %d"),
2721                pixmap_file, scanner->line);
2722   else
2723     g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
2724                pixmap_file);
2725     
2726   return NULL;
2727 }
2728
2729 gchar*
2730 gtk_rc_find_module_in_path (const gchar *module_file)
2731 {
2732   gint i;
2733   gint fd;
2734   gchar *buf;
2735   
2736   for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
2737     {
2738       buf = g_build_filename (module_path[i], module_file, NULL);
2739       
2740       fd = open (buf, O_RDONLY);
2741       if (fd >= 0)
2742         {
2743           close (fd);
2744           return buf;
2745         }
2746       
2747       g_free (buf);
2748     }
2749     
2750   return NULL;
2751 }
2752
2753 static guint
2754 gtk_rc_parse_font (GScanner   *scanner,
2755                    GtkRcStyle *rc_style)
2756 {
2757   guint token;
2758   
2759   token = g_scanner_get_next_token (scanner);
2760   if (token != GTK_RC_TOKEN_FONT)
2761     return GTK_RC_TOKEN_FONT;
2762   
2763   token = g_scanner_get_next_token (scanner);
2764   if (token != G_TOKEN_EQUAL_SIGN)
2765     return G_TOKEN_EQUAL_SIGN;
2766   
2767   token = g_scanner_get_next_token (scanner);
2768   if (token != G_TOKEN_STRING)
2769     return G_TOKEN_STRING;
2770
2771   /* Ignore, do nothing */
2772   
2773   return G_TOKEN_NONE;
2774 }
2775
2776 static guint
2777 gtk_rc_parse_fontset (GScanner   *scanner,
2778                       GtkRcStyle *rc_style)
2779 {
2780   guint token;
2781   
2782   token = g_scanner_get_next_token (scanner);
2783   if (token != GTK_RC_TOKEN_FONTSET)
2784     return GTK_RC_TOKEN_FONTSET;
2785   
2786   token = g_scanner_get_next_token (scanner);
2787   if (token != G_TOKEN_EQUAL_SIGN)
2788     return G_TOKEN_EQUAL_SIGN;
2789   
2790   token = g_scanner_get_next_token (scanner);
2791   if (token != G_TOKEN_STRING)
2792     return G_TOKEN_STRING;
2793
2794   /* Do nothing - silently ignore */
2795   
2796   return G_TOKEN_NONE;
2797 }
2798
2799 static guint
2800 gtk_rc_parse_font_name (GScanner   *scanner,
2801                         GtkRcStyle *rc_style)
2802 {
2803   guint token;
2804   
2805   token = g_scanner_get_next_token (scanner);
2806   if (token != GTK_RC_TOKEN_FONT_NAME)
2807     return GTK_RC_TOKEN_FONT;
2808   
2809   token = g_scanner_get_next_token (scanner);
2810   if (token != G_TOKEN_EQUAL_SIGN)
2811     return G_TOKEN_EQUAL_SIGN;
2812   
2813   token = g_scanner_get_next_token (scanner);
2814   if (token != G_TOKEN_STRING)
2815     return G_TOKEN_STRING;
2816
2817   rc_style->font_desc = pango_font_description_from_string (scanner->value.v_string);
2818   
2819   return G_TOKEN_NONE;
2820 }
2821
2822 static guint       
2823 gtk_rc_parse_engine (GtkRcContext *context,
2824                      GScanner     *scanner,
2825                      GtkRcStyle  **rc_style)
2826 {
2827   guint token;
2828   GtkThemeEngine *engine;
2829   guint result = G_TOKEN_NONE;
2830   GtkRcStyle *new_style = NULL;
2831   gboolean parsed_curlies = FALSE;
2832   
2833   token = g_scanner_get_next_token (scanner);
2834   if (token != GTK_RC_TOKEN_ENGINE)
2835     return GTK_RC_TOKEN_ENGINE;
2836
2837   token = g_scanner_get_next_token (scanner);
2838   if (token != G_TOKEN_STRING)
2839     return G_TOKEN_STRING;
2840
2841   engine = gtk_theme_engine_get (scanner->value.v_string);
2842   
2843   token = g_scanner_get_next_token (scanner);
2844   if (token != G_TOKEN_LEFT_CURLY)
2845     return G_TOKEN_LEFT_CURLY;
2846
2847   if (engine)
2848     {
2849       GtkRcStyleClass *new_class;
2850       
2851       new_style = gtk_theme_engine_create_rc_style (engine);
2852       g_type_module_unuse (G_TYPE_MODULE (engine));
2853
2854       new_class = GTK_RC_STYLE_GET_CLASS (new_style);
2855
2856       new_class->merge (new_style, *rc_style);
2857       if ((*rc_style)->name)
2858         new_style->name = g_strdup ((*rc_style)->name);
2859       
2860       if (new_class->parse)
2861         {
2862           parsed_curlies = TRUE;
2863           result = new_class->parse (new_style, context->settings, scanner);
2864
2865           if (result != G_TOKEN_NONE)
2866             {
2867               g_object_unref (G_OBJECT (new_style));
2868               new_style = NULL;
2869             }
2870         }
2871     }
2872
2873   if (!parsed_curlies)
2874     {
2875       /* Skip over remainder, looking for nested {}'s
2876        */
2877       guint count = 1;
2878       
2879       result = G_TOKEN_RIGHT_CURLY;
2880       while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
2881         {
2882           if (token == G_TOKEN_LEFT_CURLY)
2883             count++;
2884           else if (token == G_TOKEN_RIGHT_CURLY)
2885             count--;
2886           
2887           if (count == 0)
2888             {
2889               result = G_TOKEN_NONE;
2890               break;
2891             }
2892         }
2893     }
2894
2895   if (new_style)
2896     {
2897       g_object_unref (G_OBJECT (*rc_style));
2898       *rc_style = new_style;
2899     }
2900
2901   return result;
2902 }
2903
2904 guint
2905 gtk_rc_parse_state (GScanner     *scanner,
2906                     GtkStateType *state)
2907 {
2908   guint old_scope;
2909   guint token;
2910
2911   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2912   g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
2913   
2914   /* we don't know where we got called from, so we reset the scope here.
2915    * if we bail out due to errors, we *don't* reset the scope, so the
2916    * error messaging code can make sense of our tokens.
2917    */
2918   old_scope = g_scanner_set_scope (scanner, 0);
2919   
2920   token = g_scanner_get_next_token (scanner);
2921   if (token != G_TOKEN_LEFT_BRACE)
2922     return G_TOKEN_LEFT_BRACE;
2923   
2924   token = g_scanner_get_next_token (scanner);
2925   switch (token)
2926     {
2927     case GTK_RC_TOKEN_ACTIVE:
2928       *state = GTK_STATE_ACTIVE;
2929       break;
2930     case GTK_RC_TOKEN_INSENSITIVE:
2931       *state = GTK_STATE_INSENSITIVE;
2932       break;
2933     case GTK_RC_TOKEN_NORMAL:
2934       *state = GTK_STATE_NORMAL;
2935       break;
2936     case GTK_RC_TOKEN_PRELIGHT:
2937       *state = GTK_STATE_PRELIGHT;
2938       break;
2939     case GTK_RC_TOKEN_SELECTED:
2940       *state = GTK_STATE_SELECTED;
2941       break;
2942     default:
2943       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
2944     }
2945   
2946   token = g_scanner_get_next_token (scanner);
2947   if (token != G_TOKEN_RIGHT_BRACE)
2948     return G_TOKEN_RIGHT_BRACE;
2949   
2950   g_scanner_set_scope (scanner, old_scope);
2951
2952   return G_TOKEN_NONE;
2953 }
2954
2955 guint
2956 gtk_rc_parse_priority (GScanner            *scanner,
2957                        GtkPathPriorityType *priority)
2958 {
2959   guint old_scope;
2960   guint token;
2961
2962   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2963   g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
2964
2965   /* we don't know where we got called from, so we reset the scope here.
2966    * if we bail out due to errors, we *don't* reset the scope, so the
2967    * error messaging code can make sense of our tokens.
2968    */
2969   old_scope = g_scanner_set_scope (scanner, 0);
2970   
2971   token = g_scanner_get_next_token (scanner);
2972   if (token != ':')
2973     return ':';
2974   
2975   token = g_scanner_get_next_token (scanner);
2976   switch (token)
2977     {
2978     case GTK_RC_TOKEN_LOWEST:
2979       *priority = GTK_PATH_PRIO_LOWEST;
2980       break;
2981     case GTK_RC_TOKEN_GTK:
2982       *priority = GTK_PATH_PRIO_GTK;
2983       break;
2984     case GTK_RC_TOKEN_APPLICATION:
2985       *priority = GTK_PATH_PRIO_APPLICATION;
2986       break;
2987     case GTK_RC_TOKEN_THEME:
2988       *priority = GTK_PATH_PRIO_THEME;
2989       break;
2990     case GTK_RC_TOKEN_RC:
2991       *priority = GTK_PATH_PRIO_RC;
2992       break;
2993     case GTK_RC_TOKEN_HIGHEST:
2994       *priority = GTK_PATH_PRIO_HIGHEST;
2995       break;
2996     default:
2997       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
2998     }
2999   
3000   g_scanner_set_scope (scanner, old_scope);
3001
3002   return G_TOKEN_NONE;
3003 }
3004
3005 guint
3006 gtk_rc_parse_color (GScanner *scanner,
3007                     GdkColor *color)
3008 {
3009   guint token;
3010
3011   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3012
3013   /* we don't need to set our own scope here, because
3014    * we don't need own symbols
3015    */
3016   
3017   token = g_scanner_get_next_token (scanner);
3018   switch (token)
3019     {
3020       gint token_int;
3021       
3022     case G_TOKEN_LEFT_CURLY:
3023       token = g_scanner_get_next_token (scanner);
3024       if (token == G_TOKEN_INT)
3025         token_int = scanner->value.v_int;
3026       else if (token == G_TOKEN_FLOAT)
3027         token_int = scanner->value.v_float * 65535.0;
3028       else
3029         return G_TOKEN_FLOAT;
3030       color->red = CLAMP (token_int, 0, 65535);
3031       
3032       token = g_scanner_get_next_token (scanner);
3033       if (token != G_TOKEN_COMMA)
3034         return G_TOKEN_COMMA;
3035       
3036       token = g_scanner_get_next_token (scanner);
3037       if (token == G_TOKEN_INT)
3038         token_int = scanner->value.v_int;
3039       else if (token == G_TOKEN_FLOAT)
3040         token_int = scanner->value.v_float * 65535.0;
3041       else
3042         return G_TOKEN_FLOAT;
3043       color->green = CLAMP (token_int, 0, 65535);
3044       
3045       token = g_scanner_get_next_token (scanner);
3046       if (token != G_TOKEN_COMMA)
3047         return G_TOKEN_COMMA;
3048       
3049       token = g_scanner_get_next_token (scanner);
3050       if (token == G_TOKEN_INT)
3051         token_int = scanner->value.v_int;
3052       else if (token == G_TOKEN_FLOAT)
3053         token_int = scanner->value.v_float * 65535.0;
3054       else
3055         return G_TOKEN_FLOAT;
3056       color->blue = CLAMP (token_int, 0, 65535);
3057       
3058       token = g_scanner_get_next_token (scanner);
3059       if (token != G_TOKEN_RIGHT_CURLY)
3060         return G_TOKEN_RIGHT_CURLY;
3061       return G_TOKEN_NONE;
3062       
3063     case G_TOKEN_STRING:
3064       if (!gdk_color_parse (scanner->value.v_string, color))
3065         {
3066           g_scanner_warn (scanner, "Invalid color constant '%s'",
3067                           scanner->value.v_string);
3068           return G_TOKEN_STRING;
3069         }
3070       else
3071         return G_TOKEN_NONE;
3072       
3073     default:
3074       return G_TOKEN_STRING;
3075     }
3076 }
3077
3078 static guint
3079 gtk_rc_parse_pixmap_path (GtkRcContext *context,
3080                           GScanner     *scanner)
3081 {
3082   guint token;
3083   
3084   token = g_scanner_get_next_token (scanner);
3085   if (token != GTK_RC_TOKEN_PIXMAP_PATH)
3086     return GTK_RC_TOKEN_PIXMAP_PATH;
3087   
3088   token = g_scanner_get_next_token (scanner);
3089   if (token != G_TOKEN_STRING)
3090     return G_TOKEN_STRING;
3091   
3092   gtk_rc_parse_pixmap_path_string (context, scanner, scanner->value.v_string);
3093   
3094   return G_TOKEN_NONE;
3095 }
3096
3097 static void
3098 gtk_rc_parse_pixmap_path_string (GtkRcContext *context,
3099                                  GScanner     *scanner,
3100                                  const gchar  *pix_path)
3101 {
3102   gint end_offset;
3103   gint start_offset = 0;
3104   gint path_len;
3105   gint path_num;
3106   
3107   /* free the old one, or just add to the old one ? */
3108   for (path_num = 0; context->pixmap_path[path_num]; path_num++)
3109     {
3110       g_free (context->pixmap_path[path_num]);
3111       context->pixmap_path[path_num] = NULL;
3112     }
3113   
3114   path_num = 0;
3115   
3116   path_len = strlen (pix_path);
3117   
3118   for (end_offset = 0; end_offset <= path_len; end_offset++)
3119     {
3120       if ((pix_path[end_offset] == G_SEARCHPATH_SEPARATOR) ||
3121           (end_offset == path_len))
3122         {
3123           gchar *path_element = g_strndup (pix_path + start_offset, end_offset - start_offset);
3124           if (g_path_is_absolute (path_element))
3125             {
3126               context->pixmap_path[path_num] = path_element;
3127               path_num++;
3128               context->pixmap_path[path_num] = NULL;
3129             }
3130           else
3131             {
3132               g_warning (_("Pixmap path element: \"%s\" must be absolute, %s, line %d"),
3133                          path_element, scanner->input_name, scanner->line);
3134               g_free (path_element);
3135             }
3136
3137           start_offset = end_offset + 1;
3138         }
3139     }
3140 }
3141
3142 static guint
3143 gtk_rc_parse_module_path (GScanner *scanner)
3144 {
3145   guint token;
3146   
3147   token = g_scanner_get_next_token (scanner);
3148   if (token != GTK_RC_TOKEN_MODULE_PATH)
3149     return GTK_RC_TOKEN_MODULE_PATH;
3150   
3151   token = g_scanner_get_next_token (scanner);
3152   if (token != G_TOKEN_STRING)
3153     return G_TOKEN_STRING;
3154   
3155   gtk_rc_parse_module_path_string (scanner->value.v_string);
3156   
3157   return G_TOKEN_NONE;
3158 }
3159
3160 static guint
3161 gtk_rc_parse_im_module_path (GScanner *scanner)
3162 {
3163   guint token;
3164   
3165   token = g_scanner_get_next_token (scanner);
3166   if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
3167     return GTK_RC_TOKEN_IM_MODULE_FILE;
3168   
3169   token = g_scanner_get_next_token (scanner);
3170   if (token != G_TOKEN_STRING)
3171     return G_TOKEN_STRING;
3172
3173   if (im_module_path)
3174     g_free (im_module_path);
3175     
3176   im_module_path = g_strdup (scanner->value.v_string);
3177
3178   return G_TOKEN_NONE;
3179 }
3180
3181 static guint
3182 gtk_rc_parse_im_module_file (GScanner *scanner)
3183 {
3184   guint token;
3185   
3186   token = g_scanner_get_next_token (scanner);
3187   if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
3188     return GTK_RC_TOKEN_IM_MODULE_FILE;
3189   
3190   token = g_scanner_get_next_token (scanner);
3191   if (token != G_TOKEN_STRING)
3192     return G_TOKEN_STRING;
3193
3194   if (im_module_file)
3195     g_free (im_module_file);
3196     
3197   im_module_file = g_strdup (scanner->value.v_string);
3198
3199   return G_TOKEN_NONE;
3200 }
3201
3202 static void
3203 gtk_rc_parse_module_path_string (const gchar *mod_path)
3204 {
3205   gint end_offset;
3206   gint start_offset = 0;
3207   gint path_len;
3208   gint path_num;
3209   
3210   /* free the old one, or just add to the old one ? */
3211   for (path_num=0; module_path[path_num]; path_num++)
3212     {
3213       g_free (module_path[path_num]);
3214       module_path[path_num] = NULL;
3215     }
3216   
3217   path_num = 0;
3218   
3219   path_len = strlen (mod_path);
3220   
3221   for (end_offset = 0; end_offset <= path_len; end_offset++)
3222     {
3223       if ((mod_path[end_offset] == G_SEARCHPATH_SEPARATOR) ||
3224           (end_offset == path_len))
3225         {
3226           module_path[path_num] = g_strndup (mod_path + start_offset, end_offset - start_offset);
3227           path_num++;
3228           module_path[path_num] = NULL;
3229           start_offset = end_offset + 1;
3230         }
3231     }
3232   gtk_rc_append_default_module_path();
3233 }
3234
3235 static gint
3236 rc_set_compare (gconstpointer a, gconstpointer b)
3237 {
3238   const GtkRcSet *set_a = a;
3239   const GtkRcSet *set_b = b;
3240
3241   return (set_a->priority < set_b->priority) ? 1 : (set_a->priority == set_b->priority ? 0 : -1);
3242 }
3243
3244 static GSList *
3245 insert_rc_set (GSList *list, GtkRcSet *set)
3246 {
3247   return g_slist_insert_sorted (list, set, rc_set_compare);
3248 }
3249
3250 static guint
3251 gtk_rc_parse_path_pattern (GtkRcContext *context,
3252                            GScanner     *scanner)
3253 {
3254   guint token;
3255   GtkPathType path_type;
3256   gchar *pattern;
3257   gboolean is_binding;
3258   GtkPathPriorityType priority = context->default_priority;
3259   
3260   token = g_scanner_get_next_token (scanner);
3261   switch (token)
3262     {
3263     case GTK_RC_TOKEN_WIDGET:
3264       path_type = GTK_PATH_WIDGET;
3265       break;
3266     case GTK_RC_TOKEN_WIDGET_CLASS:
3267       path_type = GTK_PATH_WIDGET_CLASS;
3268       break;
3269     case GTK_RC_TOKEN_CLASS:
3270       path_type = GTK_PATH_CLASS;
3271       break;
3272     default:
3273       return GTK_RC_TOKEN_WIDGET_CLASS;
3274     }
3275
3276   token = g_scanner_get_next_token (scanner);
3277   if (token != G_TOKEN_STRING)
3278     return G_TOKEN_STRING;
3279
3280   pattern = g_strdup (scanner->value.v_string);
3281
3282   token = g_scanner_get_next_token (scanner);
3283   if (token == GTK_RC_TOKEN_STYLE)
3284     is_binding = FALSE;
3285   else if (token == GTK_RC_TOKEN_BINDING)
3286     is_binding = TRUE;
3287   else
3288     {
3289       g_free (pattern);
3290       return GTK_RC_TOKEN_STYLE;
3291     }
3292   
3293   if (g_scanner_peek_next_token (scanner) == ':')
3294     {
3295       token = gtk_rc_parse_priority (scanner, &priority);
3296       if (token != G_TOKEN_NONE)
3297         {
3298           g_free (pattern);
3299           return token;
3300         }
3301     }
3302   
3303   token = g_scanner_get_next_token (scanner);
3304   if (token != G_TOKEN_STRING)
3305     {
3306       g_free (pattern);
3307       return G_TOKEN_STRING;
3308     }
3309
3310   if (is_binding)
3311     {
3312       GtkBindingSet *binding;
3313
3314       binding = gtk_binding_set_find (scanner->value.v_string);
3315       if (!binding)
3316         {
3317           g_free (pattern);
3318           return G_TOKEN_STRING;
3319         }
3320       gtk_binding_set_add_path (binding, path_type, pattern, priority);
3321     }
3322   else
3323     {
3324       GtkRcStyle *rc_style;
3325       GtkRcSet *rc_set;
3326
3327       rc_style = gtk_rc_style_find (context, scanner->value.v_string);
3328       
3329       if (!rc_style)
3330         {
3331           g_free (pattern);
3332           return G_TOKEN_STRING;
3333         }
3334
3335       rc_set = g_new (GtkRcSet, 1);
3336       rc_set->pspec = g_pattern_spec_new (pattern);
3337       rc_set->rc_style = rc_style;
3338       rc_set->priority = priority;
3339
3340       if (path_type == GTK_PATH_WIDGET)
3341         context->rc_sets_widget = insert_rc_set (context->rc_sets_widget, rc_set);
3342       else if (path_type == GTK_PATH_WIDGET_CLASS)
3343         context->rc_sets_widget_class = insert_rc_set (context->rc_sets_widget_class, rc_set);
3344       else
3345         context->rc_sets_class = insert_rc_set (context->rc_sets_class, rc_set);
3346     }
3347
3348   g_free (pattern);
3349   return G_TOKEN_NONE;
3350 }
3351
3352 static guint
3353 gtk_rc_parse_stock_id (GScanner  *scanner,
3354                        gchar    **stock_id)
3355 {
3356   guint token;
3357   
3358   token = g_scanner_get_next_token (scanner);
3359   if (token != G_TOKEN_LEFT_BRACE)
3360     return G_TOKEN_LEFT_BRACE;
3361
3362   token = g_scanner_get_next_token (scanner);
3363   
3364   if (token != G_TOKEN_STRING)
3365     return G_TOKEN_STRING;
3366   
3367   *stock_id = g_strdup (scanner->value.v_string);
3368   
3369   token = g_scanner_get_next_token (scanner);
3370   if (token != G_TOKEN_RIGHT_BRACE)
3371     {
3372       g_free (*stock_id);
3373       return G_TOKEN_RIGHT_BRACE;
3374     }
3375   
3376   return G_TOKEN_NONE;
3377 }
3378
3379 static guint
3380 gtk_rc_parse_icon_source (GtkRcContext   *context,
3381                           GScanner       *scanner,
3382                           GtkIconSet     *icon_set)
3383 {
3384   guint token;
3385   GtkIconSource *source;
3386   gchar *full_filename;
3387   
3388   token = g_scanner_get_next_token (scanner);
3389   if (token != G_TOKEN_LEFT_CURLY)
3390     return G_TOKEN_LEFT_CURLY;
3391
3392   token = g_scanner_get_next_token (scanner);
3393   
3394   if (token != G_TOKEN_STRING)
3395     return G_TOKEN_STRING;
3396
3397   
3398   source = gtk_icon_source_new ();
3399   
3400   full_filename = gtk_rc_find_pixmap_in_path (context->settings, scanner, scanner->value.v_string);
3401   if (full_filename)
3402     {
3403       gtk_icon_source_set_filename (source, full_filename);
3404       g_free (full_filename);
3405     }
3406
3407   /* We continue parsing even if we didn't find the pixmap so that rest of the
3408    * file is read, even if the syntax is bad
3409    */
3410   token = g_scanner_get_next_token (scanner);
3411
3412   if (token == G_TOKEN_RIGHT_CURLY)
3413     goto done;
3414   else if (token != G_TOKEN_COMMA)
3415     {
3416       gtk_icon_source_free (source);
3417       return G_TOKEN_COMMA;
3418     }
3419
3420   /* Get the direction */
3421   
3422   token = g_scanner_get_next_token (scanner);
3423
3424   switch (token)
3425     {
3426     case GTK_RC_TOKEN_RTL:
3427       gtk_icon_source_set_direction_wildcarded (source, FALSE);
3428       gtk_icon_source_set_direction (source, GTK_TEXT_DIR_RTL);
3429       break;
3430
3431     case GTK_RC_TOKEN_LTR:
3432       gtk_icon_source_set_direction_wildcarded (source, FALSE);
3433       gtk_icon_source_set_direction (source, GTK_TEXT_DIR_LTR);
3434       break;
3435       
3436     case '*':
3437       break;
3438       
3439     default:
3440       gtk_icon_source_free (source);
3441       return GTK_RC_TOKEN_RTL;
3442       break;
3443     }
3444
3445   token = g_scanner_get_next_token (scanner);
3446
3447   if (token == G_TOKEN_RIGHT_CURLY)
3448     goto done;
3449   else if (token != G_TOKEN_COMMA)
3450     {
3451       gtk_icon_source_free (source);
3452       return G_TOKEN_COMMA;
3453     }
3454
3455   /* Get the state */
3456   
3457   token = g_scanner_get_next_token (scanner);
3458   
3459   switch (token)
3460     {
3461     case GTK_RC_TOKEN_NORMAL:
3462       gtk_icon_source_set_state_wildcarded (source, FALSE);
3463       gtk_icon_source_set_state (source, GTK_STATE_NORMAL);
3464       break;
3465
3466     case GTK_RC_TOKEN_PRELIGHT:
3467       gtk_icon_source_set_state_wildcarded (source, FALSE);
3468       gtk_icon_source_set_state (source, GTK_STATE_PRELIGHT);
3469       break;
3470       
3471
3472     case GTK_RC_TOKEN_INSENSITIVE:
3473       gtk_icon_source_set_state_wildcarded (source, FALSE);
3474       gtk_icon_source_set_state (source, GTK_STATE_INSENSITIVE);
3475       break;
3476
3477     case GTK_RC_TOKEN_ACTIVE:
3478       gtk_icon_source_set_state_wildcarded (source, FALSE);
3479       gtk_icon_source_set_state (source, GTK_STATE_ACTIVE);
3480       break;
3481
3482     case GTK_RC_TOKEN_SELECTED:
3483       gtk_icon_source_set_state_wildcarded (source, FALSE);
3484       gtk_icon_source_set_state (source, GTK_STATE_SELECTED);
3485       break;
3486
3487     case '*':
3488       break;
3489       
3490     default:
3491       gtk_icon_source_free (source);
3492       return GTK_RC_TOKEN_PRELIGHT;
3493       break;
3494     }  
3495
3496   token = g_scanner_get_next_token (scanner);
3497
3498   if (token == G_TOKEN_RIGHT_CURLY)
3499     goto done;
3500   else if (token != G_TOKEN_COMMA)
3501     {
3502       gtk_icon_source_free (source);
3503       return G_TOKEN_COMMA;
3504     }
3505   
3506   /* Get the size */
3507   
3508   token = g_scanner_get_next_token (scanner);
3509
3510   if (token != '*')
3511     {
3512       GtkIconSize size;
3513       
3514       if (token != G_TOKEN_STRING)
3515         {
3516           gtk_icon_source_free (source);
3517           return G_TOKEN_STRING;
3518         }
3519
3520       size = gtk_icon_size_from_name (scanner->value.v_string);
3521
3522       if (size != GTK_ICON_SIZE_INVALID)
3523         {
3524           gtk_icon_source_set_size_wildcarded (source, FALSE);
3525           gtk_icon_source_set_size (source, size);
3526         }
3527     }
3528
3529   /* Check the close brace */
3530   
3531   token = g_scanner_get_next_token (scanner);
3532   if (token != G_TOKEN_RIGHT_CURLY)
3533     {
3534       gtk_icon_source_free (source);
3535       return G_TOKEN_RIGHT_CURLY;
3536     }
3537
3538  done:
3539   if (gtk_icon_source_get_filename (source))
3540     gtk_icon_set_add_source (icon_set, source);
3541   gtk_icon_source_free (source);
3542   
3543   return G_TOKEN_NONE;
3544 }
3545
3546 static guint
3547 gtk_rc_parse_stock (GtkRcContext   *context,
3548                     GScanner       *scanner,
3549                     GtkRcStyle     *rc_style,
3550                     GtkIconFactory *factory)
3551 {
3552   GtkIconSet *icon_set = NULL;
3553   gchar *stock_id = NULL;
3554   guint token;
3555   
3556   token = g_scanner_get_next_token (scanner);
3557   if (token != GTK_RC_TOKEN_STOCK)
3558     return GTK_RC_TOKEN_STOCK;
3559   
3560   token = gtk_rc_parse_stock_id (scanner, &stock_id);
3561   if (token != G_TOKEN_NONE)
3562     return token;
3563   
3564   token = g_scanner_get_next_token (scanner);
3565   if (token != G_TOKEN_EQUAL_SIGN)
3566     {
3567       g_free (stock_id);
3568       return G_TOKEN_EQUAL_SIGN;
3569     }
3570
3571   token = g_scanner_get_next_token (scanner);
3572   if (token != G_TOKEN_LEFT_CURLY)
3573     {
3574       g_free (stock_id);
3575       return G_TOKEN_LEFT_CURLY;
3576     }
3577
3578   token = g_scanner_peek_next_token (scanner);
3579   while (token != G_TOKEN_RIGHT_CURLY)
3580     {
3581       if (icon_set == NULL)
3582         icon_set = gtk_icon_set_new ();
3583       
3584       token = gtk_rc_parse_icon_source (context, scanner, icon_set);
3585       if (token != G_TOKEN_NONE)
3586         {
3587           g_free (stock_id);
3588           gtk_icon_set_unref (icon_set);
3589           return token;
3590         }
3591
3592       token = g_scanner_get_next_token (scanner);
3593       
3594       if (token != G_TOKEN_COMMA &&
3595           token != G_TOKEN_RIGHT_CURLY)
3596         {
3597           g_free (stock_id);
3598           gtk_icon_set_unref (icon_set);
3599           return G_TOKEN_RIGHT_CURLY;
3600         }
3601     }
3602
3603   if (icon_set)
3604     {
3605       gtk_icon_factory_add (factory,
3606                             stock_id,
3607                             icon_set);
3608       
3609       gtk_icon_set_unref (icon_set);
3610     }
3611   
3612   g_free (stock_id);
3613
3614   return G_TOKEN_NONE;
3615 }