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