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