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