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