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