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