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