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