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