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