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