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