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