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