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