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