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