]> Pileus Git - ~andy/gtk/blob - gtk/gtkrc.c
Merge branch 'windows_list'
[~andy/gtk] / gtk / gtkrc.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28
29 #include <locale.h>
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #include <sys/stat.h>
34 #ifdef HAVE_SYS_PARAM_H
35 #include <sys/param.h>
36 #endif
37 #include <fcntl.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41
42
43 #include <glib.h>
44 #include <glib/gstdio.h>
45 #include "gdkconfig.h"
46
47 #include "gtkversion.h"
48 #include "gtkrc.h"
49 #include "gtkbindings.h"
50 #include "gtkthemes.h"
51 #include "gtkintl.h"
52 #include "gtkiconfactory.h"
53 #include "gtkmain.h"
54 #include "gtkmodules.h"
55 #include "gtkprivate.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 enum 
68 {
69   PATH_ELT_PSPEC,
70   PATH_ELT_UNRESOLVED,
71   PATH_ELT_TYPE
72 };
73
74 typedef struct
75 {
76   gint type;
77   union 
78   {
79     GType         class_type;
80     gchar        *class_name;
81     GPatternSpec *pspec;
82   } elt;
83 } PathElt;
84
85 struct _GtkRcSet
86 {
87   GtkPathType   type;
88
89   GPatternSpec *pspec;
90   GSList       *path;
91
92   GtkRcStyle   *rc_style;
93   gint          priority;
94 };
95
96 struct _GtkRcFile
97 {
98   time_t mtime;
99   gchar *name;
100   gchar *canonical_name;
101   gchar *directory;
102   guint  reload    : 1;
103   guint  is_string : 1; /* If TRUE, name is a string to parse with gtk_rc_parse_string() */
104 };
105
106
107 struct _GtkRcContext
108 {
109   GHashTable *rc_style_ht;
110   GtkSettings *settings;
111   GSList *rc_sets_widget;
112   GSList *rc_sets_widget_class;
113   GSList *rc_sets_class;
114
115   /* The files we have parsed, to reread later if necessary */
116   GSList *rc_files;
117
118   gchar    *theme_name;
119   gboolean  prefer_dark_theme;
120   gchar    *key_theme_name;
121   gchar    *font_name;
122   
123   gchar **pixmap_path;
124
125   gint default_priority;
126   GtkStyle *default_style;
127
128   GHashTable *color_hash;
129
130   guint reloading : 1;
131 };
132
133 #define GTK_RC_STYLE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_RC_STYLE, GtkRcStylePrivate))
134
135 typedef struct _GtkRcStylePrivate GtkRcStylePrivate;
136
137 struct _GtkRcStylePrivate
138 {
139   GSList *color_hashes;
140 };
141
142 static GtkRcContext *gtk_rc_context_get              (GtkSettings     *settings);
143
144 static guint       gtk_rc_style_hash                 (const gchar     *name);
145 static gboolean    gtk_rc_style_equal                (const gchar     *a,
146                                                       const gchar     *b);
147 static guint       gtk_rc_styles_hash                (const GSList    *rc_styles);
148 static gboolean    gtk_rc_styles_equal               (const GSList    *a,
149                                                       const GSList    *b);
150 static GtkRcStyle* gtk_rc_style_find                 (GtkRcContext    *context,
151                                                       const gchar     *name);
152 static GSList *    gtk_rc_styles_match               (GSList          *rc_styles,
153                                                       GSList          *sets,
154                                                       guint            path_length,
155                                                       gchar           *path,
156                                                       gchar           *path_reversed);
157 static GtkStyle *  gtk_rc_style_to_style             (GtkRcContext    *context,
158                                                       GtkRcStyle      *rc_style);
159 static GtkStyle*   gtk_rc_init_style                 (GtkRcContext    *context,
160                                                       GSList          *rc_styles);
161 static void        gtk_rc_parse_default_files        (GtkRcContext    *context);
162 static gboolean    gtk_rc_parse_named                (GtkRcContext    *context,
163                                                       const gchar     *name,
164                                                       const gchar     *type,
165                                                       const gchar     *variant);
166 static void        gtk_rc_context_parse_file         (GtkRcContext    *context,
167                                                       const gchar     *filename,
168                                                       gint             priority,
169                                                       gboolean         reload);
170 static void        gtk_rc_parse_any                  (GtkRcContext    *context,
171                                                       const gchar     *input_name,
172                                                       gint             input_fd,
173                                                       const gchar     *input_string);
174 static guint       gtk_rc_parse_statement            (GtkRcContext    *context,
175                                                       GScanner        *scanner);
176 static guint       gtk_rc_parse_style                (GtkRcContext    *context,
177                                                       GScanner        *scanner);
178 static guint       gtk_rc_parse_assignment           (GScanner        *scanner,
179                                                       GtkRcStyle      *style,
180                                                       GtkRcProperty   *prop);
181 static guint       gtk_rc_parse_bg                   (GScanner        *scanner,
182                                                       GtkRcStyle      *style);
183 static guint       gtk_rc_parse_fg                   (GScanner        *scanner,
184                                                       GtkRcStyle      *style);
185 static guint       gtk_rc_parse_text                 (GScanner        *scanner,
186                                                       GtkRcStyle      *style);
187 static guint       gtk_rc_parse_base                 (GScanner        *scanner,
188                                                       GtkRcStyle      *style);
189 static guint       gtk_rc_parse_xthickness           (GScanner        *scanner,
190                                                       GtkRcStyle      *style);
191 static guint       gtk_rc_parse_ythickness           (GScanner        *scanner,
192                                                       GtkRcStyle      *style);
193 static guint       gtk_rc_parse_bg_pixmap            (GtkRcContext    *context,
194                                                       GScanner        *scanner,
195                                                       GtkRcStyle      *rc_style);
196 static guint       gtk_rc_parse_font                 (GScanner        *scanner,
197                                                       GtkRcStyle      *rc_style);
198 static guint       gtk_rc_parse_fontset              (GScanner        *scanner,
199                                                       GtkRcStyle      *rc_style);
200 static guint       gtk_rc_parse_font_name            (GScanner        *scanner,
201                                                       GtkRcStyle      *rc_style);
202 static guint       gtk_rc_parse_engine               (GtkRcContext    *context,
203                                                       GScanner        *scanner,
204                                                       GtkRcStyle     **rc_style);
205 static guint       gtk_rc_parse_pixmap_path          (GtkRcContext    *context,
206                                                       GScanner        *scanner);
207 static void        gtk_rc_parse_pixmap_path_string   (GtkRcContext    *context,
208                                                       GScanner        *scanner,
209                                                       const gchar     *pix_path);
210 static guint       gtk_rc_parse_module_path          (GScanner        *scanner);
211 static guint       gtk_rc_parse_im_module_file       (GScanner        *scanner);
212 static guint       gtk_rc_parse_path_pattern         (GtkRcContext    *context,
213                                                       GScanner        *scanner);
214 static guint       gtk_rc_parse_stock                (GtkRcContext    *context,
215                                                       GScanner        *scanner,
216                                                       GtkRcStyle      *rc_style,
217                                                       GtkIconFactory  *factory);
218 static guint       gtk_rc_parse_logical_color        (GScanner        *scanner,
219                                                       GtkRcStyle      *rc_style,
220                                                       GHashTable      *hash);
221
222 static void        gtk_rc_clear_hash_node            (gpointer         key,
223                                                       gpointer         data,
224                                                       gpointer         user_data);
225 static void        gtk_rc_clear_styles               (GtkRcContext    *context);
226 static void        gtk_rc_add_initial_default_files  (void);
227
228 static void        gtk_rc_style_finalize             (GObject         *object);
229 static void        gtk_rc_style_real_merge           (GtkRcStyle      *dest,
230                                                       GtkRcStyle      *src);
231 static GtkRcStyle* gtk_rc_style_real_create_rc_style (GtkRcStyle      *rc_style);
232 static GtkStyle*   gtk_rc_style_real_create_style    (GtkRcStyle      *rc_style);
233 static void        gtk_rc_style_copy_icons_and_colors(GtkRcStyle      *rc_style,
234                                                       GtkRcStyle      *src_style,
235                                                       GtkRcContext    *context);
236 static gint        gtk_rc_properties_cmp             (gconstpointer    bsearch_node1,
237                                                       gconstpointer    bsearch_node2);
238 static void        gtk_rc_set_free                   (GtkRcSet        *rc_set);
239
240 static void        insert_rc_property                (GtkRcStyle      *style,
241                                                       GtkRcProperty   *property,
242                                                       gboolean         replace);
243
244
245 static const GScannerConfig gtk_rc_scanner_config =
246 {
247   (
248    " \t\r\n"
249    )                    /* cset_skip_characters */,
250   (
251    "_"
252    G_CSET_a_2_z
253    G_CSET_A_2_Z
254    )                    /* cset_identifier_first */,
255   (
256    G_CSET_DIGITS
257    "-_"
258    G_CSET_a_2_z
259    G_CSET_A_2_Z
260    )                    /* cset_identifier_nth */,
261   ( "#\n" )             /* cpair_comment_single */,
262   
263   TRUE                  /* case_sensitive */,
264   
265   TRUE                  /* skip_comment_multi */,
266   TRUE                  /* skip_comment_single */,
267   TRUE                  /* scan_comment_multi */,
268   TRUE                  /* scan_identifier */,
269   FALSE                 /* scan_identifier_1char */,
270   FALSE                 /* scan_identifier_NULL */,
271   TRUE                  /* scan_symbols */,
272   TRUE                  /* scan_binary */,
273   TRUE                  /* scan_octal */,
274   TRUE                  /* scan_float */,
275   TRUE                  /* scan_hex */,
276   TRUE                  /* scan_hex_dollar */,
277   TRUE                  /* scan_string_sq */,
278   TRUE                  /* scan_string_dq */,
279   TRUE                  /* numbers_2_int */,
280   FALSE                 /* int_2_float */,
281   FALSE                 /* identifier_2_string */,
282   TRUE                  /* char_2_token */,
283   TRUE                  /* symbol_2_token */,
284   FALSE                 /* scope_0_fallback */,
285 };
286  
287 static const gchar symbol_names[] = 
288   "include\0"
289   "NORMAL\0"
290   "ACTIVE\0"
291   "PRELIGHT\0"
292   "SELECTED\0"
293   "INSENSITIVE\0"
294   "fg\0"
295   "bg\0"
296   "text\0"
297   "base\0"
298   "xthickness\0"
299   "ythickness\0"
300   "font\0"
301   "fontset\0"
302   "font_name\0"
303   "bg_pixmap\0"
304   "pixmap_path\0"
305   "style\0"
306   "binding\0"
307   "bind\0"
308   "widget\0"
309   "widget_class\0"
310   "class\0"
311   "lowest\0"
312   "gtk\0"
313   "application\0"
314   "theme\0"
315   "rc\0"
316   "highest\0"
317   "engine\0"
318   "module_path\0"
319   "stock\0"
320   "im_module_file\0"
321   "LTR\0"
322   "RTL\0"
323   "color\0"
324   "unbind\0";
325
326 static const struct
327 {
328   guint name_offset;
329   guint token;
330 } symbols[] = {
331   {   0, GTK_RC_TOKEN_INCLUDE },
332   {   8, GTK_RC_TOKEN_NORMAL },
333   {  15, GTK_RC_TOKEN_ACTIVE },
334   {  22, GTK_RC_TOKEN_PRELIGHT },
335   {  31, GTK_RC_TOKEN_SELECTED },
336   {  40, GTK_RC_TOKEN_INSENSITIVE },
337   {  52, GTK_RC_TOKEN_FG },
338   {  55, GTK_RC_TOKEN_BG },
339   {  58, GTK_RC_TOKEN_TEXT },
340   {  63, GTK_RC_TOKEN_BASE },
341   {  68, GTK_RC_TOKEN_XTHICKNESS },
342   {  79, GTK_RC_TOKEN_YTHICKNESS },
343   {  90, GTK_RC_TOKEN_FONT },
344   {  95, GTK_RC_TOKEN_FONTSET },
345   { 103, GTK_RC_TOKEN_FONT_NAME },
346   { 113, GTK_RC_TOKEN_BG_PIXMAP },
347   { 123, GTK_RC_TOKEN_PIXMAP_PATH },
348   { 135, GTK_RC_TOKEN_STYLE },
349   { 141, GTK_RC_TOKEN_BINDING },
350   { 149, GTK_RC_TOKEN_BIND },
351   { 154, GTK_RC_TOKEN_WIDGET },
352   { 161, GTK_RC_TOKEN_WIDGET_CLASS },
353   { 174, GTK_RC_TOKEN_CLASS },
354   { 180, GTK_RC_TOKEN_LOWEST },
355   { 187, GTK_RC_TOKEN_GTK },
356   { 191, GTK_RC_TOKEN_APPLICATION },
357   { 203, GTK_RC_TOKEN_THEME },
358   { 209, GTK_RC_TOKEN_RC },
359   { 212, GTK_RC_TOKEN_HIGHEST },
360   { 220, GTK_RC_TOKEN_ENGINE },
361   { 227, GTK_RC_TOKEN_MODULE_PATH },
362   { 239, GTK_RC_TOKEN_STOCK },
363   { 245, GTK_RC_TOKEN_IM_MODULE_FILE },
364   { 260, GTK_RC_TOKEN_LTR },
365   { 264, GTK_RC_TOKEN_RTL },
366   { 268, GTK_RC_TOKEN_COLOR },
367   { 274, GTK_RC_TOKEN_UNBIND }
368 };
369
370 static GHashTable *realized_style_ht = NULL;
371
372 static gchar *im_module_file = NULL;
373
374 static gint    max_default_files = 0;
375 static gchar **gtk_rc_default_files = NULL;
376
377 /* A stack of information of RC files we are parsing currently.
378  * The directories for these files are implicitely added to the end of
379  * PIXMAP_PATHS.
380  */
381 static GSList *current_files_stack = NULL;
382
383 /* RC files and strings that are parsed for every context
384  */
385 static GSList *global_rc_files = NULL;
386
387 /* Keep list of all current RC contexts for convenience
388  */
389 static GSList *rc_contexts;
390
391 /* RC file handling */
392
393 static gchar *
394 gtk_rc_make_default_dir (const gchar *type)
395 {
396   const gchar *var;
397   gchar *path;
398
399   var = g_getenv ("GTK_EXE_PREFIX");
400
401   if (var)
402     path = g_build_filename (var, "lib", "gtk-3.0", GTK_BINARY_VERSION, type, NULL);
403   else
404     path = g_build_filename (GTK_LIBDIR, "gtk-3.0", GTK_BINARY_VERSION, type, NULL);
405
406   return path;
407 }
408
409 /**
410  * gtk_rc_get_im_module_path:
411  * @returns: a newly-allocated string containing the path in which to 
412  *    look for IM modules.
413  *
414  * Obtains the path in which to look for IM modules. See the documentation
415  * of the <link linkend="im-module-path"><envar>GTK_PATH</envar></link>
416  * environment variable for more details about looking up modules. This
417  * function is useful solely for utilities supplied with GTK+ and should
418  * not be used by applications under normal circumstances.
419  */
420 gchar *
421 gtk_rc_get_im_module_path (void)
422 {
423   gchar **paths = _gtk_get_module_path ("immodules");
424   gchar *result = g_strjoinv (G_SEARCHPATH_SEPARATOR_S, paths);
425   g_strfreev (paths);
426
427   return result;
428 }
429
430 /**
431  * gtk_rc_get_im_module_file:
432  * @returns: a newly-allocated string containing the name of the file
433  * listing the IM modules available for loading
434  *
435  * Obtains the path to the IM modules file. See the documentation
436  * of the <link linkend="im-module-file"><envar>GTK_IM_MODULE_FILE</envar></link>
437  * environment variable for more details.
438  */
439 gchar *
440 gtk_rc_get_im_module_file (void)
441 {
442   const gchar *var = g_getenv ("GTK_IM_MODULE_FILE");
443   gchar *result = NULL;
444
445   if (var)
446     result = g_strdup (var);
447
448   if (!result)
449     {
450       if (im_module_file)
451         result = g_strdup (im_module_file);
452       else
453         result = gtk_rc_make_default_dir ("immodules.cache");
454     }
455
456   return result;
457 }
458
459 gchar *
460 gtk_rc_get_theme_dir (void)
461 {
462   const gchar *var;
463   gchar *path;
464
465   var = g_getenv ("GTK_DATA_PREFIX");
466
467   if (var)
468     path = g_build_filename (var, "share", "themes", NULL);
469   else
470     path = g_build_filename (GTK_DATA_PREFIX, "share", "themes", NULL);
471
472   return path;
473 }
474
475 /**
476  * gtk_rc_get_module_dir:
477  * 
478  * Returns a directory in which GTK+ looks for theme engines.
479  * For full information about the search for theme engines,
480  * see the docs for <envar>GTK_PATH</envar> in
481  * <xref linkend="gtk-running"/>.
482  * 
483  * return value: the directory. (Must be freed with g_free())
484  **/
485 gchar *
486 gtk_rc_get_module_dir (void)
487 {
488   return gtk_rc_make_default_dir ("engines");
489 }
490
491 static void
492 gtk_rc_add_initial_default_files (void)
493 {
494   static gint init = FALSE;
495   const gchar *var;
496   gchar *str;
497   gchar **files;
498   gint i;
499
500   if (init)
501     return;
502  
503   gtk_rc_default_files = g_new (gchar*, 10);
504   max_default_files = 10;
505
506   gtk_rc_default_files[0] = NULL;
507   init = TRUE;
508
509   var = g_getenv ("GTK2_RC_FILES");
510
511   if (var)
512     {
513       files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, -1);
514       i=0;
515       while (files[i])
516         {
517           gtk_rc_add_default_file (files[i]);
518           i++;
519         }
520       g_strfreev (files);
521     }
522   else
523     {
524       const gchar *home;
525       str = g_build_filename (GTK_SYSCONFDIR, "gtk-3.0", "gtkrc", NULL);
526
527       gtk_rc_add_default_file (str);
528       g_free (str);
529
530       home = g_get_home_dir ();
531       if (home)
532         {
533           str = g_build_filename (home, ".gtkrc-3.0", NULL);
534           gtk_rc_add_default_file (str);
535           g_free (str);
536         }
537     }
538 }
539
540 /**
541  * gtk_rc_add_default_file:
542  * @filename: the pathname to the file. If @filename is not absolute, it
543  *    is searched in the current directory.
544  * 
545  * Adds a file to the list of files to be parsed at the
546  * end of gtk_init().
547  **/
548 void
549 gtk_rc_add_default_file (const gchar *filename)
550 {
551   guint n;
552   
553   gtk_rc_add_initial_default_files ();
554
555   for (n = 0; n < max_default_files; n++) 
556     {
557       if (gtk_rc_default_files[n] == NULL)
558         break;
559     }
560
561   if (n == max_default_files)
562     {
563       max_default_files += 10;
564       gtk_rc_default_files = g_renew (gchar*, gtk_rc_default_files, max_default_files);
565     }
566   
567   gtk_rc_default_files[n++] = g_strdup (filename);
568   gtk_rc_default_files[n] = NULL;
569 }
570
571 /**
572  * gtk_rc_set_default_files:
573  * @filenames: A %NULL-terminated list of filenames.
574  * 
575  * Sets the list of files that GTK+ will read at the
576  * end of gtk_init().
577  **/
578 void
579 gtk_rc_set_default_files (gchar **filenames)
580 {
581   gint i;
582
583   gtk_rc_add_initial_default_files ();
584
585   i = 0;
586   while (gtk_rc_default_files[i])
587     {
588       g_free (gtk_rc_default_files[i]);
589       i++;
590     }
591     
592   gtk_rc_default_files[0] = NULL;
593
594   i = 0;
595   while (filenames[i] != NULL)
596     {
597       gtk_rc_add_default_file (filenames[i]);
598       i++;
599     }
600 }
601
602 /**
603  * gtk_rc_get_default_files:
604  * 
605  * Retrieves the current list of RC files that will be parsed
606  * at the end of gtk_init().
607  * 
608  * Return value: A %NULL-terminated array of filenames. This memory
609  * is owned by GTK+ and must not be freed by the application.
610  * If you want to store this information, you should make a copy.
611  **/
612 gchar **
613 gtk_rc_get_default_files (void)
614 {
615   gtk_rc_add_initial_default_files ();
616
617   return gtk_rc_default_files;
618 }
619
620 static void
621 gtk_rc_settings_changed (GtkSettings  *settings,
622                          GParamSpec   *pspec,
623                          GtkRcContext *context)
624 {
625   gchar *new_theme_name;
626   gchar *new_key_theme_name;
627   gboolean new_prefer_dark_theme;
628
629   if (context->reloading)
630     return;
631
632   g_object_get (settings,
633                 "gtk-theme-name", &new_theme_name,
634                 "gtk-key-theme-name", &new_key_theme_name,
635                 "gtk-application-prefer-dark-theme", &new_prefer_dark_theme,
636                 NULL);
637
638   if ((new_theme_name != context->theme_name && 
639        !(new_theme_name && context->theme_name && strcmp (new_theme_name, context->theme_name) == 0)) ||
640       (new_key_theme_name != context->key_theme_name &&
641        !(new_key_theme_name && context->key_theme_name && strcmp (new_key_theme_name, context->key_theme_name) == 0)) ||
642       new_prefer_dark_theme != context->prefer_dark_theme)
643     {
644       gtk_rc_reparse_all_for_settings (settings, TRUE);
645     }
646
647   g_free (new_theme_name);
648   g_free (new_key_theme_name);
649 }
650
651 static void
652 gtk_rc_font_name_changed (GtkSettings  *settings,
653                           GParamSpec   *pspec,
654                           GtkRcContext *context)
655 {
656   if (!context->reloading)
657     _gtk_rc_context_get_default_font_name (settings);
658 }
659
660 static void
661 gtk_rc_color_hash_changed (GtkSettings  *settings,
662                            GParamSpec   *pspec,
663                            GtkRcContext *context)
664 {
665   GHashTable *old_hash;
666
667   old_hash = context->color_hash;
668
669   g_object_get (settings, "color-hash", &context->color_hash, NULL);
670
671   if (old_hash)
672     g_hash_table_unref (old_hash);
673
674   gtk_rc_reparse_all_for_settings (settings, TRUE);
675 }
676
677 static GtkRcContext *
678 gtk_rc_context_get (GtkSettings *settings)
679 {
680   if (!settings->rc_context)
681     {
682       GtkRcContext *context = settings->rc_context = g_new (GtkRcContext, 1);
683
684       context->settings = settings;
685       context->rc_style_ht = NULL;
686       context->rc_sets_widget = NULL;
687       context->rc_sets_widget_class = NULL;
688       context->rc_sets_class = NULL;
689       context->rc_files = NULL;
690       context->default_style = NULL;
691       context->reloading = FALSE;
692
693       g_object_get (settings,
694                     "gtk-theme-name", &context->theme_name,
695                     "gtk-key-theme-name", &context->key_theme_name,
696                     "gtk-font-name", &context->font_name,
697                     "color-hash", &context->color_hash,
698                     "gtk-application-prefer-dark-theme", &context->prefer_dark_theme,
699                     NULL);
700
701       g_signal_connect (settings,
702                         "notify::gtk-theme-name",
703                         G_CALLBACK (gtk_rc_settings_changed),
704                         context);
705       g_signal_connect (settings,
706                         "notify::gtk-key-theme-name",
707                         G_CALLBACK (gtk_rc_settings_changed),
708                         context);
709       g_signal_connect (settings,
710                         "notify::gtk-font-name",
711                         G_CALLBACK (gtk_rc_font_name_changed),
712                         context);
713       g_signal_connect (settings,
714                         "notify::color-hash",
715                         G_CALLBACK (gtk_rc_color_hash_changed),
716                         context);
717       g_signal_connect (settings,
718                         "notify::gtk-application-prefer-dark-theme",
719                         G_CALLBACK (gtk_rc_settings_changed),
720                         context);
721
722       context->pixmap_path = NULL;
723
724       context->default_priority = GTK_PATH_PRIO_RC;
725
726       rc_contexts = g_slist_prepend (rc_contexts, settings->rc_context);
727     }
728
729   return settings->rc_context;
730 }
731
732 static void 
733 gtk_rc_clear_rc_files (GtkRcContext *context)
734 {
735   GSList *list;
736
737   list = context->rc_files;
738   while (list)
739     {
740       GtkRcFile *rc_file = list->data;
741       
742       if (rc_file->canonical_name != rc_file->name)
743         g_free (rc_file->canonical_name);
744       g_free (rc_file->directory);
745       g_free (rc_file->name);
746       g_free (rc_file);
747       
748       list = list->next;
749     }
750   
751   g_slist_free (context->rc_files);
752   context->rc_files = NULL;
753 }
754
755 void
756 _gtk_rc_context_destroy (GtkSettings *settings)
757 {
758   GtkRcContext *context;
759
760   g_return_if_fail (GTK_IS_SETTINGS (settings));
761
762   context = settings->rc_context;
763   if (!context)
764     return;
765
766   _gtk_settings_reset_rc_values (context->settings);
767   gtk_rc_clear_styles (context);
768   gtk_rc_clear_rc_files (context);
769
770   if (context->default_style)
771     g_object_unref (context->default_style);
772
773   g_strfreev (context->pixmap_path);
774
775   g_free (context->theme_name);
776   g_free (context->key_theme_name);
777   g_free (context->font_name);
778
779   if (context->color_hash)
780     g_hash_table_unref (context->color_hash);
781
782   g_signal_handlers_disconnect_by_func (settings,
783                                         gtk_rc_settings_changed, context);
784   g_signal_handlers_disconnect_by_func (settings,
785                                         gtk_rc_font_name_changed, context);
786   g_signal_handlers_disconnect_by_func (settings,
787                                         gtk_rc_color_hash_changed, context);
788
789   rc_contexts = g_slist_remove (rc_contexts, context);
790
791   g_free (context);
792
793   settings->rc_context = NULL;
794 }
795
796 static gboolean
797 gtk_rc_parse_named (GtkRcContext *context,
798                     const gchar  *name,
799                     const gchar  *type,
800                     const gchar  *variant)
801 {
802   gchar *path = NULL;
803   const gchar *home_dir;
804   gchar *subpath;
805   gboolean retval;
806
807   retval = FALSE;
808
809   if (type)
810     subpath = g_strconcat ("gtk-3.0-", type,
811                            G_DIR_SEPARATOR_S "gtkrc",
812                            NULL);
813   else
814     subpath = g_strconcat ("gtk-3.0" G_DIR_SEPARATOR_S "gtkrc",
815                            variant, NULL);
816
817   /* First look in the users home directory
818    */
819   home_dir = g_get_home_dir ();
820   if (home_dir)
821     {
822       path = g_build_filename (home_dir, ".themes", name, subpath, NULL);
823       if (!g_file_test (path, G_FILE_TEST_EXISTS))
824         {
825           g_free (path);
826           path = NULL;
827         }
828     }
829
830   if (!path)
831     {
832       gchar *theme_dir = gtk_rc_get_theme_dir ();
833       path = g_build_filename (theme_dir, name, subpath, NULL);
834       g_free (theme_dir);
835       
836       if (!g_file_test (path, G_FILE_TEST_EXISTS))
837         {
838           g_free (path);
839           path = NULL;
840         }
841     }
842
843   if (path)
844     {
845       gtk_rc_context_parse_file (context, path, GTK_PATH_PRIO_THEME, FALSE);
846       g_free (path);
847       retval = TRUE;
848     }
849
850   g_free (subpath);
851
852   return retval;
853 }
854
855 static void
856 gtk_rc_parse_default_files (GtkRcContext *context)
857 {
858   gint i;
859
860   gtk_rc_add_initial_default_files ();
861
862   for (i = 0; gtk_rc_default_files[i] != NULL; i++)
863     gtk_rc_context_parse_file (context, gtk_rc_default_files[i], GTK_PATH_PRIO_RC, FALSE);
864 }
865
866 void
867 _gtk_rc_init (void)
868 {
869   static gboolean initialized = FALSE;
870
871   if (!initialized)
872     {
873       initialized = TRUE;
874       
875       gtk_rc_add_initial_default_files ();
876     }
877   
878   /* Default RC string */
879   gtk_rc_parse_string ("style \"gtk-default-tooltips-style\" {\n"
880                        "  bg[NORMAL] = \"#eee1b3\"\n"
881                        "  fg[NORMAL] = \"#000000\"\n"
882                        "}\n"
883                        "\n"
884                        "style \"gtk-default-progress-bar-style\" {\n"
885                        "  bg[PRELIGHT] = \"#4b6983\"\n"
886                        "  fg[PRELIGHT] = \"#ffffff\"\n"
887                        "  bg[NORMAL]   = \"#c4c2bd\"\n"
888                        "}\n"
889                        "\n"
890                        "style \"gtk-default-entry-style\" {\n"
891                        "  bg[SELECTED] = \"#b7c3cd\"\n"
892                        "  fg[SELECTED] = \"#000000\"\n"
893                        "}\n"
894                        "\n"
895                        "style \"gtk-default-menu-bar-item-style\" {\n"
896                        "  GtkMenuItem::horizontal_padding = 5\n"
897                        "}\n"
898                        "\n"
899                        "style \"gtk-default-menu-item-style\" {\n"
900                        "  bg[PRELIGHT] = \"#4b6983\"\n"
901                        "  fg[PRELIGHT] = \"#ffffff\"\n"
902                        "  base[PRELIGHT] = \"#4b6983\"\n"
903                        "  text[PRELIGHT] = \"#ffffff\"\n"
904                        "}\n"
905                        "\n"
906                        /* Work around clipping of accelerator underlines */
907                        "style \"gtk-default-label-style\" {\n"
908                        "  GtkWidget::draw-border = {0,0,0,1}\n"
909                        "}\n"
910                        "\n"    
911                        "class \"GtkProgressBar\" style : gtk \"gtk-default-progress-bar-style\"\n"
912                        "class \"GtkEntry\" style : gtk \"gtk-default-entry-style\"\n"
913                        "widget \"gtk-tooltip*\" style : gtk \"gtk-default-tooltips-style\"\n"
914                        "widget_class \"*<GtkMenuItem>*\" style : gtk \"gtk-default-menu-item-style\"\n"
915                        "widget_class \"*<GtkMenuBar>*<GtkMenuItem>\" style : gtk \"gtk-default-menu-bar-item-style\"\n"
916                        "class \"GtkLabel\" style : gtk \"gtk-default-label-style\"\n"
917       );
918 }
919   
920 static void
921 gtk_rc_context_parse_string (GtkRcContext *context,
922                              const gchar  *rc_string)
923 {
924   gtk_rc_parse_any (context, "-", -1, rc_string);
925 }
926
927 void
928 gtk_rc_parse_string (const gchar *rc_string)
929 {
930   GtkRcFile *rc_file;
931   GSList *tmp_list;
932       
933   g_return_if_fail (rc_string != NULL);
934
935   rc_file = g_new (GtkRcFile, 1);
936   rc_file->is_string = TRUE;
937   rc_file->name = g_strdup (rc_string);
938   rc_file->canonical_name = NULL;
939   rc_file->directory = NULL;
940   rc_file->mtime = 0;
941   rc_file->reload = TRUE;
942   
943   global_rc_files = g_slist_append (global_rc_files, rc_file);
944
945   for (tmp_list = rc_contexts; tmp_list; tmp_list = tmp_list->next)
946     gtk_rc_context_parse_string (tmp_list->data, rc_string);
947 }
948
949 static GtkRcFile *
950 add_to_rc_file_list (GSList     **rc_file_list,
951                      const char  *filename,
952                      gboolean     reload)
953 {
954   GSList *tmp_list;
955   GtkRcFile *rc_file;
956   
957   tmp_list = *rc_file_list;
958   while (tmp_list)
959     {
960       rc_file = tmp_list->data;
961       if (!strcmp (rc_file->name, filename))
962         return rc_file;
963       
964       tmp_list = tmp_list->next;
965     }
966
967   rc_file = g_new (GtkRcFile, 1);
968   rc_file->is_string = FALSE;
969   rc_file->name = g_strdup (filename);
970   rc_file->canonical_name = NULL;
971   rc_file->directory = NULL;
972   rc_file->mtime = 0;
973   rc_file->reload = reload;
974   
975   *rc_file_list = g_slist_append (*rc_file_list, rc_file);
976   
977   return rc_file;
978 }
979
980 static void
981 gtk_rc_context_parse_one_file (GtkRcContext *context,
982                                const gchar  *filename,
983                                gint          priority,
984                                gboolean      reload)
985 {
986   GtkRcFile *rc_file;
987   struct stat statbuf;
988   gint saved_priority;
989
990   g_return_if_fail (filename != NULL);
991
992   saved_priority = context->default_priority;
993   context->default_priority = priority;
994
995   rc_file = add_to_rc_file_list (&context->rc_files, filename, reload);
996
997   if (!rc_file->canonical_name)
998     {
999       /* Get the absolute pathname */
1000
1001       if (g_path_is_absolute (rc_file->name))
1002         rc_file->canonical_name = rc_file->name;
1003       else
1004         {
1005           gchar *cwd;
1006
1007           cwd = g_get_current_dir ();
1008           rc_file->canonical_name = g_build_filename (cwd, rc_file->name, NULL);
1009           g_free (cwd);
1010         }
1011       
1012       rc_file->directory = g_path_get_dirname (rc_file->canonical_name);
1013     }
1014
1015   /* If the file is already being parsed (recursion), do nothing
1016    */
1017   if (g_slist_find (current_files_stack, rc_file))
1018     return;
1019
1020   if (!g_lstat (rc_file->canonical_name, &statbuf))
1021     {
1022       gint fd;
1023       
1024       rc_file->mtime = statbuf.st_mtime;
1025
1026       fd = g_open (rc_file->canonical_name, O_RDONLY, 0);
1027       if (fd < 0)
1028         goto out;
1029
1030       /* Temporarily push information for this file on
1031        * a stack of current files while parsing it.
1032        */
1033       current_files_stack = g_slist_prepend (current_files_stack, rc_file);
1034       gtk_rc_parse_any (context, filename, fd, NULL);
1035       current_files_stack = g_slist_delete_link (current_files_stack,
1036                                                  current_files_stack);
1037
1038       close (fd);
1039     }
1040
1041  out:
1042   context->default_priority = saved_priority;
1043 }
1044
1045 static gchar *
1046 strchr_len (const gchar *str, gint len, char c)
1047 {
1048   while (len--)
1049     {
1050       if (*str == c)
1051         return (gchar *)str;
1052
1053       str++;
1054     }
1055
1056   return NULL;
1057 }
1058
1059 static void
1060 gtk_rc_context_parse_file (GtkRcContext *context,
1061                            const gchar  *filename,
1062                            gint          priority,
1063                            gboolean      reload)
1064 {
1065   gchar *locale_suffixes[2];
1066   gint n_locale_suffixes = 0;
1067   gchar *p;
1068   gchar *locale;
1069   gint length, j;
1070   gboolean found = FALSE;
1071
1072   locale = _gtk_get_lc_ctype ();
1073
1074   if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
1075     {
1076       /* Determine locale-specific suffixes for RC files.
1077        */
1078       length = strlen (locale);
1079       
1080       p = strchr (locale, '@');
1081       if (p)
1082         length = p - locale;
1083
1084       p = strchr_len (locale, length, '.');
1085       if (p)
1086         length = p - locale;
1087       
1088       locale_suffixes[n_locale_suffixes++] = g_strndup (locale, length);
1089       
1090       p = strchr_len (locale, length, '_');
1091       if (p)
1092         {
1093           length = p - locale;
1094           locale_suffixes[n_locale_suffixes++] = g_strndup (locale, length);
1095         }
1096     }
1097
1098   g_free (locale);
1099   
1100   gtk_rc_context_parse_one_file (context, filename, priority, reload);
1101   for (j = 0; j < n_locale_suffixes; j++)
1102     {
1103       if (!found)
1104         {
1105           gchar *name = g_strconcat (filename, ".", locale_suffixes[j], NULL);
1106           if (g_file_test (name, G_FILE_TEST_EXISTS))
1107             {
1108               gtk_rc_context_parse_one_file (context, name, priority, FALSE);
1109               found = TRUE;
1110             }
1111               
1112           g_free (name);
1113         }
1114       
1115       g_free (locale_suffixes[j]);
1116     }
1117 }
1118
1119 void
1120 gtk_rc_parse (const gchar *filename)
1121 {
1122   GSList *tmp_list;
1123   
1124   g_return_if_fail (filename != NULL);
1125
1126   add_to_rc_file_list (&global_rc_files, filename, TRUE);
1127   
1128   for (tmp_list = rc_contexts; tmp_list; tmp_list = tmp_list->next)
1129     gtk_rc_context_parse_file (tmp_list->data, filename, GTK_PATH_PRIO_RC, TRUE);
1130 }
1131
1132 /* Handling of RC styles */
1133
1134 G_DEFINE_TYPE (GtkRcStyle, gtk_rc_style, G_TYPE_OBJECT)
1135
1136 static void
1137 gtk_rc_style_init (GtkRcStyle *style)
1138 {
1139   GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (style);
1140   guint i;
1141
1142   style->name = NULL;
1143   style->font_desc = NULL;
1144
1145   for (i = 0; i < 5; i++)
1146     {
1147       static const GdkColor init_color = { 0, 0, 0, 0, };
1148
1149       style->bg_pixmap_name[i] = NULL;
1150       style->color_flags[i] = 0;
1151       style->fg[i] = init_color;
1152       style->bg[i] = init_color;
1153       style->text[i] = init_color;
1154       style->base[i] = init_color;
1155     }
1156   style->xthickness = -1;
1157   style->ythickness = -1;
1158   style->rc_properties = NULL;
1159
1160   style->rc_style_lists = NULL;
1161   style->icon_factories = NULL;
1162
1163   priv->color_hashes = NULL;
1164 }
1165
1166 static void
1167 gtk_rc_style_class_init (GtkRcStyleClass *klass)
1168 {
1169   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1170   
1171   object_class->finalize = gtk_rc_style_finalize;
1172
1173   klass->parse = NULL;
1174   klass->create_rc_style = gtk_rc_style_real_create_rc_style;
1175   klass->merge = gtk_rc_style_real_merge;
1176   klass->create_style = gtk_rc_style_real_create_style;
1177
1178   g_type_class_add_private (object_class, sizeof (GtkRcStylePrivate));
1179 }
1180
1181 static void
1182 gtk_rc_style_finalize (GObject *object)
1183 {
1184   GSList *tmp_list1, *tmp_list2;
1185   GtkRcStyle *rc_style;
1186   GtkRcStylePrivate *rc_priv;
1187   gint i;
1188
1189   rc_style = GTK_RC_STYLE (object);
1190   rc_priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
1191
1192   g_free (rc_style->name);
1193   if (rc_style->font_desc)
1194     pango_font_description_free (rc_style->font_desc);
1195       
1196   for (i = 0; i < 5; i++)
1197     g_free (rc_style->bg_pixmap_name[i]);
1198   
1199   /* Now remove all references to this rc_style from
1200    * realized_style_ht
1201    */
1202   tmp_list1 = rc_style->rc_style_lists;
1203   while (tmp_list1)
1204     {
1205       GSList *rc_styles = tmp_list1->data;
1206       GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
1207       g_object_unref (style);
1208
1209       /* Remove the list of styles from the other rc_styles
1210        * in the list
1211        */
1212       tmp_list2 = rc_styles;
1213       while (tmp_list2)
1214         {
1215           GtkRcStyle *other_style = tmp_list2->data;
1216
1217           if (other_style != rc_style)
1218             other_style->rc_style_lists = g_slist_remove_all (other_style->rc_style_lists,
1219                                                               rc_styles);
1220           tmp_list2 = tmp_list2->next;
1221         }
1222
1223       /* And from the hash table itself
1224        */
1225       g_hash_table_remove (realized_style_ht, rc_styles);
1226       g_slist_free (rc_styles);
1227
1228       tmp_list1 = tmp_list1->next;
1229     }
1230   g_slist_free (rc_style->rc_style_lists);
1231
1232   if (rc_style->rc_properties)
1233     {
1234       guint i;
1235
1236       for (i = 0; i < rc_style->rc_properties->len; i++)
1237         {
1238           GtkRcProperty *node = &g_array_index (rc_style->rc_properties, GtkRcProperty, i);
1239
1240           g_free (node->origin);
1241           g_value_unset (&node->value);
1242         }
1243       g_array_free (rc_style->rc_properties, TRUE);
1244       rc_style->rc_properties = NULL;
1245     }
1246
1247   g_slist_foreach (rc_style->icon_factories, (GFunc) g_object_unref, NULL);
1248   g_slist_free (rc_style->icon_factories);
1249
1250   g_slist_foreach (rc_priv->color_hashes, (GFunc) g_hash_table_unref, NULL);
1251   g_slist_free (rc_priv->color_hashes);
1252
1253   G_OBJECT_CLASS (gtk_rc_style_parent_class)->finalize (object);
1254 }
1255
1256 GtkRcStyle *
1257 gtk_rc_style_new (void)
1258 {
1259   GtkRcStyle *style;
1260   
1261   style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
1262   
1263   return style;
1264 }
1265
1266 /**
1267  * gtk_rc_style_copy:
1268  * @orig: the style to copy
1269  * 
1270  * Makes a copy of the specified #GtkRcStyle. This function
1271  * will correctly copy an RC style that is a member of a class
1272  * derived from #GtkRcStyle.
1273  * 
1274  * Return value: the resulting #GtkRcStyle
1275  **/
1276 GtkRcStyle *
1277 gtk_rc_style_copy (GtkRcStyle *orig)
1278 {
1279   GtkRcStyle *style;
1280
1281   g_return_val_if_fail (GTK_IS_RC_STYLE (orig), NULL);
1282   
1283   style = GTK_RC_STYLE_GET_CLASS (orig)->create_rc_style (orig);
1284   GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
1285
1286   gtk_rc_style_copy_icons_and_colors (style, orig, NULL);
1287
1288   return style;
1289 }
1290
1291 void
1292 _gtk_rc_style_set_rc_property (GtkRcStyle *rc_style,
1293                                GtkRcProperty *property)
1294 {
1295   g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1296   g_return_if_fail (property != NULL);
1297
1298   insert_rc_property (rc_style, property, TRUE);
1299 }
1300
1301 void
1302 _gtk_rc_style_unset_rc_property (GtkRcStyle *rc_style,
1303                                  GQuark      type_name,
1304                                  GQuark      property_name)
1305 {
1306   GtkRcProperty *node;
1307
1308   g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1309
1310   node = (GtkRcProperty *) _gtk_rc_style_lookup_rc_property (rc_style,
1311                                                              type_name,
1312                                                              property_name);
1313
1314   if (node != NULL)
1315     {
1316       guint index = node - (GtkRcProperty *) rc_style->rc_properties->data;
1317       g_value_unset (&node->value);
1318       g_free (node->origin);
1319       g_array_remove_index (rc_style->rc_properties, index);
1320     }
1321 }
1322
1323 static GtkRcStyle *
1324 gtk_rc_style_real_create_rc_style (GtkRcStyle *style)
1325 {
1326   return g_object_new (G_OBJECT_TYPE (style), NULL);
1327 }
1328
1329 GSList *
1330 _gtk_rc_style_get_color_hashes (GtkRcStyle *rc_style)
1331 {
1332   GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
1333
1334   return priv->color_hashes;
1335 }
1336
1337 static void gtk_rc_style_prepend_empty_color_hash (GtkRcStyle *rc_style);
1338
1339 void
1340 _gtk_rc_style_set_symbolic_color (GtkRcStyle     *rc_style,
1341                                   const gchar    *name,
1342                                   const GdkColor *color)
1343 {
1344   GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
1345   GHashTable *our_hash = NULL;
1346
1347   if (priv->color_hashes)
1348     our_hash = priv->color_hashes->data;
1349
1350   if (our_hash == NULL)
1351     {
1352       if (color == NULL)
1353         return;
1354
1355       gtk_rc_style_prepend_empty_color_hash (rc_style);
1356       our_hash = priv->color_hashes->data;
1357     }
1358
1359   if (color)
1360     g_hash_table_insert (our_hash, g_strdup (name), gdk_color_copy (color));
1361   else
1362     g_hash_table_remove (our_hash, name);
1363 }
1364
1365 static gint
1366 gtk_rc_properties_cmp (gconstpointer bsearch_node1,
1367                        gconstpointer bsearch_node2)
1368 {
1369   const GtkRcProperty *prop1 = bsearch_node1;
1370   const GtkRcProperty *prop2 = bsearch_node2;
1371
1372   if (prop1->type_name == prop2->type_name)
1373     return prop1->property_name < prop2->property_name ? -1 : prop1->property_name == prop2->property_name ? 0 : 1;
1374   else
1375     return prop1->type_name < prop2->type_name ? -1 : 1;
1376 }
1377
1378 static void
1379 insert_rc_property (GtkRcStyle    *style,
1380                     GtkRcProperty *property,
1381                     gboolean       replace)
1382 {
1383   guint i;
1384   GtkRcProperty *new_property = NULL;
1385   GtkRcProperty key = { 0, 0, NULL, { 0, }, };
1386
1387   key.type_name = property->type_name;
1388   key.property_name = property->property_name;
1389
1390   if (!style->rc_properties)
1391     style->rc_properties = g_array_new (FALSE, FALSE, sizeof (GtkRcProperty));
1392
1393   i = 0;
1394   while (i < style->rc_properties->len)
1395     {
1396       gint cmp = gtk_rc_properties_cmp (&key, &g_array_index (style->rc_properties, GtkRcProperty, i));
1397
1398       if (cmp == 0)
1399         {
1400           if (replace)
1401             {
1402               new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
1403               
1404               g_free (new_property->origin);
1405               g_value_unset (&new_property->value);
1406               
1407               *new_property = key;
1408               break;
1409             }
1410           else
1411             return;
1412         }
1413       else if (cmp < 0)
1414         break;
1415
1416       i++;
1417     }
1418
1419   if (!new_property)
1420     {
1421       g_array_insert_val (style->rc_properties, i, key);
1422       new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
1423     }
1424
1425   new_property->origin = g_strdup (property->origin);
1426   g_value_init (&new_property->value, G_VALUE_TYPE (&property->value));
1427   g_value_copy (&property->value, &new_property->value);
1428 }
1429
1430 static void
1431 gtk_rc_style_real_merge (GtkRcStyle *dest,
1432                          GtkRcStyle *src)
1433 {
1434   gint i;
1435
1436   for (i = 0; i < 5; i++)
1437     {
1438       if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
1439         dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
1440       
1441       if (!(dest->color_flags[i] & GTK_RC_FG) && 
1442           src->color_flags[i] & GTK_RC_FG)
1443         {
1444           dest->fg[i] = src->fg[i];
1445           dest->color_flags[i] |= GTK_RC_FG;
1446         }
1447       if (!(dest->color_flags[i] & GTK_RC_BG) && 
1448           src->color_flags[i] & GTK_RC_BG)
1449         {
1450           dest->bg[i] = src->bg[i];
1451           dest->color_flags[i] |= GTK_RC_BG;
1452         }
1453       if (!(dest->color_flags[i] & GTK_RC_TEXT) && 
1454           src->color_flags[i] & GTK_RC_TEXT)
1455         {
1456           dest->text[i] = src->text[i];
1457           dest->color_flags[i] |= GTK_RC_TEXT;
1458         }
1459       if (!(dest->color_flags[i] & GTK_RC_BASE) && 
1460           src->color_flags[i] & GTK_RC_BASE)
1461         {
1462           dest->base[i] = src->base[i];
1463           dest->color_flags[i] |= GTK_RC_BASE;
1464         }
1465     }
1466
1467   if (dest->xthickness < 0 && src->xthickness >= 0)
1468     dest->xthickness = src->xthickness;
1469   if (dest->ythickness < 0 && src->ythickness >= 0)
1470     dest->ythickness = src->ythickness;
1471
1472   if (src->font_desc)
1473     {
1474       if (!dest->font_desc)
1475         dest->font_desc = pango_font_description_copy (src->font_desc);
1476       else
1477         pango_font_description_merge (dest->font_desc, src->font_desc, FALSE);
1478     }
1479
1480   if (src->rc_properties)
1481     {
1482       guint i;
1483
1484       for (i = 0; i < src->rc_properties->len; i++)
1485         insert_rc_property (dest,
1486                             &g_array_index (src->rc_properties, GtkRcProperty, i),
1487                             FALSE);
1488     }
1489 }
1490
1491 static GtkStyle *
1492 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
1493 {
1494   return gtk_style_new ();
1495 }
1496
1497 static void
1498 gtk_rc_style_prepend_empty_icon_factory (GtkRcStyle *rc_style)
1499 {
1500   GtkIconFactory *factory = gtk_icon_factory_new ();
1501
1502   rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories, factory);
1503 }
1504
1505 static void
1506 gtk_rc_style_prepend_empty_color_hash (GtkRcStyle *rc_style)
1507 {
1508   GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
1509   GHashTable        *hash = g_hash_table_new_full (g_str_hash, g_str_equal,
1510                                                    g_free,
1511                                                    (GDestroyNotify) gdk_color_free);
1512
1513   priv->color_hashes = g_slist_prepend (priv->color_hashes, hash);
1514 }
1515
1516 static void
1517 gtk_rc_style_append_icon_factories (GtkRcStyle *rc_style,
1518                                     GtkRcStyle *src_style)
1519 {
1520   GSList *concat = g_slist_copy (src_style->icon_factories);
1521
1522   g_slist_foreach (concat, (GFunc) g_object_ref, NULL);
1523
1524   rc_style->icon_factories = g_slist_concat (rc_style->icon_factories, concat);
1525 }
1526
1527 static void
1528 gtk_rc_style_append_color_hashes (GtkRcStyle *rc_style,
1529                                   GtkRcStyle *src_style)
1530 {
1531   GtkRcStylePrivate *priv     = GTK_RC_STYLE_GET_PRIVATE (rc_style);
1532   GtkRcStylePrivate *src_priv = GTK_RC_STYLE_GET_PRIVATE (src_style);
1533   GSList            *concat   = g_slist_copy (src_priv->color_hashes);
1534
1535   g_slist_foreach (concat, (GFunc) g_hash_table_ref, NULL);
1536
1537   priv->color_hashes = g_slist_concat (priv->color_hashes, concat);
1538 }
1539
1540 static void
1541 gtk_rc_style_copy_icons_and_colors (GtkRcStyle   *rc_style,
1542                                     GtkRcStyle   *src_style,
1543                                     GtkRcContext *context)
1544 {
1545   GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
1546
1547   if (src_style)
1548     {
1549       GtkRcStylePrivate *src_priv = GTK_RC_STYLE_GET_PRIVATE (src_style);
1550
1551       /* Append src_style's factories, adding a ref to them */
1552       if (src_style->icon_factories != NULL)
1553         {
1554           /* Add a factory for ourselves if we have none,
1555            * in case we end up defining more stock icons.
1556            * I see no real way around this; we need to maintain
1557            * the invariant that the first factory in the list
1558            * is always our_factory, the one belonging to us,
1559            * and if we put src_style factories in the list we can't
1560            * do that if the style is reopened.
1561            */
1562           if (rc_style->icon_factories == NULL)
1563             gtk_rc_style_prepend_empty_icon_factory (rc_style);
1564
1565           gtk_rc_style_append_icon_factories (rc_style, src_style);
1566         }
1567
1568       /* Also append src_style's color hashes, adding a ref to them */
1569       if (src_priv->color_hashes != NULL)
1570         {
1571           /* See comment above .. */
1572           if (priv->color_hashes == NULL)
1573             gtk_rc_style_prepend_empty_color_hash (rc_style);
1574
1575           gtk_rc_style_append_color_hashes (rc_style, src_style);
1576         }
1577     }
1578
1579   /*  if we didn't get color hashes from the src_style, initialize
1580    *  the list with the settings' color scheme (if it exists)
1581    */
1582   if (priv->color_hashes == NULL && context && context->color_hash != NULL)
1583     {
1584       gtk_rc_style_prepend_empty_color_hash (rc_style);
1585
1586       priv->color_hashes = g_slist_append (priv->color_hashes,
1587                                            g_hash_table_ref (context->color_hash));
1588     }
1589 }
1590
1591 static void
1592 gtk_rc_clear_hash_node (gpointer key, 
1593                         gpointer data, 
1594                         gpointer user_data)
1595 {
1596   g_object_unref (data);
1597 }
1598
1599 static void
1600 gtk_rc_free_rc_sets (GSList *slist)
1601 {
1602   while (slist)
1603     {
1604       GtkRcSet *rc_set;
1605
1606       rc_set = slist->data;
1607       gtk_rc_set_free (rc_set);
1608
1609       slist = slist->next;
1610     }
1611 }
1612
1613 static void
1614 gtk_rc_clear_styles (GtkRcContext *context)
1615 {
1616   /* Clear out all old rc_styles */
1617
1618   if (context->rc_style_ht)
1619     {
1620       g_hash_table_foreach (context->rc_style_ht, gtk_rc_clear_hash_node, NULL);
1621       g_hash_table_destroy (context->rc_style_ht);
1622       context->rc_style_ht = NULL;
1623     }
1624
1625   gtk_rc_free_rc_sets (context->rc_sets_widget);
1626   g_slist_free (context->rc_sets_widget);
1627   context->rc_sets_widget = NULL;
1628
1629   gtk_rc_free_rc_sets (context->rc_sets_widget_class);
1630   g_slist_free (context->rc_sets_widget_class);
1631   context->rc_sets_widget_class = NULL;
1632
1633   gtk_rc_free_rc_sets (context->rc_sets_class);
1634   g_slist_free (context->rc_sets_class);
1635   context->rc_sets_class = NULL;
1636 }
1637
1638 /* Reset all our widgets. Also, we have to invalidate cached icons in
1639  * icon sets so they get re-rendered.
1640  */
1641 static void
1642 gtk_rc_reset_widgets (GtkSettings *settings)
1643 {
1644   GList *list, *toplevels;
1645
1646   _gtk_icon_set_invalidate_caches ();
1647   
1648   toplevels = gtk_window_list_toplevels ();
1649   g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1650   
1651   for (list = toplevels; list; list = list->next)
1652     {
1653       if (gtk_widget_get_screen (list->data) == settings->screen)
1654         {
1655           gtk_widget_reset_rc_styles (list->data);
1656         }
1657
1658       g_object_unref (list->data);
1659     }
1660   g_list_free (toplevels);
1661 }
1662
1663 static void
1664 gtk_rc_clear_realized_style (gpointer key,
1665                              gpointer value,
1666                              gpointer data)
1667 {
1668   GSList *rc_styles = key;
1669   GtkStyle *style = value;
1670   GSList *tmp_list = rc_styles;
1671
1672   g_object_unref (style);
1673  
1674   while (tmp_list)
1675     {
1676       GtkRcStyle *rc_style = tmp_list->data;
1677       
1678       rc_style->rc_style_lists = g_slist_remove_all (rc_style->rc_style_lists,
1679                                                      rc_styles);
1680       tmp_list = tmp_list->next;
1681     }
1682
1683   g_slist_free (rc_styles);
1684 }
1685
1686 /**
1687  * gtk_rc_reset_styles:
1688  * @settings: a #GtkSettings
1689  * 
1690  * This function recomputes the styles for all widgets that use a
1691  * particular #GtkSettings object. (There is one #GtkSettings object
1692  * per #GdkScreen, see gtk_settings_get_for_screen()); It is useful
1693  * when some global parameter has changed that affects the appearance
1694  * of all widgets, because when a widget gets a new style, it will
1695  * both redraw and recompute any cached information about its
1696  * appearance. As an example, it is used when the default font size
1697  * set by the operating system changes. Note that this function
1698  * doesn't affect widgets that have a style set explicitely on them
1699  * with gtk_widget_set_style().
1700  *
1701  * Since: 2.4
1702  **/
1703 void
1704 gtk_rc_reset_styles (GtkSettings *settings)
1705 {
1706   GtkRcContext *context;
1707   gboolean reset = FALSE;
1708
1709   g_return_if_fail (GTK_IS_SETTINGS (settings));
1710
1711   context = gtk_rc_context_get (settings);
1712   
1713   if (context->default_style)
1714     {
1715       g_object_unref (context->default_style);
1716       context->default_style = NULL;
1717       reset = TRUE;
1718     }
1719   
1720   /* Clear out styles that have been looked up already
1721    */
1722   if (realized_style_ht)
1723     {
1724       g_hash_table_foreach (realized_style_ht, gtk_rc_clear_realized_style, NULL);
1725       g_hash_table_destroy (realized_style_ht);
1726       realized_style_ht = NULL;
1727       reset = TRUE;
1728     }
1729   
1730   if (reset)
1731     gtk_rc_reset_widgets (settings);
1732 }
1733
1734 const gchar*
1735 _gtk_rc_context_get_default_font_name (GtkSettings *settings)
1736 {
1737   GtkRcContext *context;
1738   gchar *new_font_name;
1739   
1740   g_return_val_if_fail (GTK_IS_SETTINGS (settings), NULL);
1741
1742   context = gtk_rc_context_get (settings);
1743
1744   g_object_get (context->settings,
1745                 "gtk-font-name", &new_font_name,
1746                 NULL);
1747
1748   if (new_font_name != context->font_name && !(new_font_name && strcmp (context->font_name, new_font_name) == 0))
1749     {
1750        g_free (context->font_name);
1751        context->font_name = g_strdup (new_font_name);
1752  
1753        gtk_rc_reset_styles (settings);
1754     }
1755           
1756   g_free (new_font_name);
1757
1758   return context->font_name;
1759 }
1760
1761 /**
1762  * gtk_rc_reparse_all_for_settings:
1763  * @settings: a #GtkSettings
1764  * @force_load: load whether or not anything changed
1765  * 
1766  * If the modification time on any previously read file
1767  * for the given #GtkSettings has changed, discard all style information
1768  * and then reread all previously read RC files.
1769  * 
1770  * Return value: %TRUE if the files were reread.
1771  **/
1772 gboolean
1773 gtk_rc_reparse_all_for_settings (GtkSettings *settings,
1774                                  gboolean     force_load)
1775 {
1776   gboolean mtime_modified = FALSE;
1777   GtkRcFile *rc_file;
1778   GSList *tmp_list;
1779   GtkRcContext *context;
1780   struct stat statbuf;
1781
1782   g_return_val_if_fail (GTK_IS_SETTINGS (settings), FALSE);
1783
1784   context = gtk_rc_context_get (settings);
1785
1786   if (context->reloading)
1787     return FALSE;
1788
1789   if (!force_load)
1790     {
1791       /* Check through and see if any of the RC's have had their
1792        * mtime modified. If so, reparse everything.
1793        */
1794       tmp_list = context->rc_files;
1795       while (tmp_list)
1796         {
1797           rc_file = tmp_list->data;
1798
1799           if (!rc_file->is_string)
1800             {
1801               if (!g_lstat (rc_file->name, &statbuf) && 
1802                   (statbuf.st_mtime != rc_file->mtime))
1803                 {
1804                   mtime_modified = TRUE;
1805                   break;
1806                 }
1807             }
1808           
1809           tmp_list = tmp_list->next;
1810         }
1811     }
1812       
1813   if (force_load || mtime_modified)
1814     {
1815       _gtk_binding_reset_parsed ();
1816       gtk_rc_clear_styles (context);
1817       context->reloading = TRUE;
1818
1819       _gtk_settings_reset_rc_values (context->settings);
1820       gtk_rc_clear_rc_files (context);
1821
1822       gtk_rc_parse_default_files (context);
1823
1824       tmp_list = global_rc_files;
1825       while (tmp_list)
1826         {
1827           rc_file = tmp_list->data;
1828
1829           if (rc_file->is_string)
1830             gtk_rc_context_parse_string (context, rc_file->name);
1831           else
1832             gtk_rc_context_parse_file (context, rc_file->name, GTK_PATH_PRIO_RC, FALSE);
1833
1834           tmp_list = tmp_list->next;
1835         }
1836
1837       g_free (context->theme_name);
1838       g_free (context->key_theme_name);
1839
1840       g_object_get (context->settings,
1841                     "gtk-theme-name", &context->theme_name,
1842                     "gtk-key-theme-name", &context->key_theme_name,
1843                     "gtk-application-prefer-dark-theme", &context->prefer_dark_theme,
1844                     NULL);
1845
1846       if (context->theme_name && context->theme_name[0])
1847         {
1848           if (context->prefer_dark_theme)
1849             {
1850               if (!gtk_rc_parse_named (context, context->theme_name, NULL, "-dark"))
1851                 gtk_rc_parse_named (context, context->theme_name, NULL, NULL);
1852             }
1853           else
1854             {
1855               gtk_rc_parse_named (context, context->theme_name, NULL, NULL);
1856             }
1857         }
1858       if (context->key_theme_name && context->key_theme_name[0])
1859         gtk_rc_parse_named (context, context->key_theme_name, "key", NULL);
1860
1861       context->reloading = FALSE;
1862
1863       gtk_rc_reset_widgets (context->settings);
1864     }
1865
1866   return force_load || mtime_modified;
1867 }
1868
1869 /**
1870  * gtk_rc_reparse_all:
1871  * 
1872  * If the modification time on any previously read file for the
1873  * default #GtkSettings has changed, discard all style information
1874  * and then reread all previously read RC files.
1875  * 
1876  * Return value:  %TRUE if the files were reread.
1877  **/
1878 gboolean
1879 gtk_rc_reparse_all (void)
1880 {
1881   GSList *tmp_list;
1882   gboolean result = FALSE;
1883
1884   for (tmp_list = rc_contexts; tmp_list; tmp_list = tmp_list->next)
1885     {
1886       GtkRcContext *context = tmp_list->data;
1887       if (gtk_rc_reparse_all_for_settings (context->settings, FALSE))
1888         result = TRUE;
1889     }
1890
1891   return result;
1892 }
1893
1894 static GSList *
1895 gtk_rc_styles_match (GSList       *rc_styles,
1896                      GSList       *sets,
1897                      guint         path_length,
1898                      gchar        *path,
1899                      gchar        *path_reversed)
1900                      
1901 {
1902   GtkRcSet *rc_set;
1903
1904   while (sets)
1905     {
1906       rc_set = sets->data;
1907       sets = sets->next;
1908
1909       if (rc_set->type == GTK_PATH_WIDGET_CLASS)
1910         {
1911           if (_gtk_rc_match_widget_class (rc_set->path, path_length, path, path_reversed))
1912             rc_styles = g_slist_append (rc_styles, rc_set);
1913         }
1914       else
1915         {
1916           if (g_pattern_match (rc_set->pspec, path_length, path, path_reversed))
1917             rc_styles = g_slist_append (rc_styles, rc_set);
1918         }
1919     }
1920
1921   return rc_styles;
1922 }
1923
1924 static gint
1925 rc_set_compare (gconstpointer a, gconstpointer b)
1926 {
1927   const GtkRcSet *set_a = a;
1928   const GtkRcSet *set_b = b;
1929
1930   return (set_a->priority < set_b->priority) ? 1 : (set_a->priority == set_b->priority ? 0 : -1);
1931 }
1932
1933 static GSList *
1934 sort_and_dereference_sets (GSList *styles)
1935 {
1936   GSList *tmp_list;
1937   
1938   /* At this point, the list of sets is ordered by:
1939    *
1940    * a) 'widget' patterns are earlier than 'widget_class' patterns
1941    *    which are ealier than 'class' patterns.
1942    * a) For two matches for class patterns, a match to a child type
1943    *    is before a match to a parent type
1944    * c) a match later in the RC file (or in a later RC file) is before a
1945    *    match earlier in the RC file.
1946    *
1947    * With a) taking precedence over b) which takes precendence over c).
1948    *
1949    * Now sort by priority, which has the highest precendence for sort order
1950    */
1951   styles = g_slist_sort (styles, rc_set_compare);
1952
1953   /* Make styles->data = styles->data->rc_style
1954    */
1955   tmp_list = styles;
1956   while (tmp_list)
1957     {
1958       GtkRcSet *set = tmp_list->data;
1959       tmp_list->data = set->rc_style;
1960       tmp_list = tmp_list->next;
1961     }
1962
1963   return styles;
1964 }
1965
1966 /**
1967  * gtk_rc_get_style:
1968  * @widget: a #GtkWidget
1969  * 
1970  * Finds all matching RC styles for a given widget,
1971  * composites them together, and then creates a 
1972  * #GtkStyle representing the composite appearance.
1973  * (GTK+ actually keeps a cache of previously 
1974  * created styles, so a new style may not be
1975  * created.)
1976  * 
1977  * Returns: the resulting style. No refcount is added
1978  *   to the returned style, so if you want to save this
1979  *   style around, you should add a reference yourself.
1980  **/
1981 GtkStyle *
1982 gtk_rc_get_style (GtkWidget *widget)
1983 {
1984   GtkRcStyle *widget_rc_style;
1985   GSList *rc_styles = NULL;
1986   GtkRcContext *context;
1987
1988   static guint rc_style_key_id = 0;
1989
1990   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1991
1992   context = gtk_rc_context_get (gtk_widget_get_settings (widget));
1993
1994   /* We allow the specification of a single rc style to be bound
1995    * tightly to a widget, for application modifications
1996    */
1997   if (!rc_style_key_id)
1998     rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1999
2000   if (context->rc_sets_widget)
2001     {
2002       gchar *path, *path_reversed;
2003       guint path_length;
2004
2005       gtk_widget_path (widget, &path_length, &path, &path_reversed);
2006       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, path, path_reversed);
2007       g_free (path);
2008       g_free (path_reversed);
2009     }
2010   
2011   if (context->rc_sets_widget_class)
2012     {
2013       gchar *path, *path_reversed;
2014       guint path_length;
2015
2016       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
2017       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, path, path_reversed);
2018       g_free (path);
2019       g_free (path_reversed);
2020     }
2021
2022   if (context->rc_sets_class)
2023     {
2024       GType type;
2025
2026       type = G_TYPE_FROM_INSTANCE (widget);
2027       while (type)
2028         {
2029           gchar *path;
2030           gchar *path_reversed;
2031           guint path_length;
2032
2033           path = g_strdup (g_type_name (type));
2034           path_length = strlen (path);
2035           path_reversed = g_strdup (path);
2036           g_strreverse (path_reversed);
2037           
2038           rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
2039           g_free (path);
2040           g_free (path_reversed);
2041       
2042           type = g_type_parent (type);
2043         }
2044     }
2045   
2046   rc_styles = sort_and_dereference_sets (rc_styles);
2047   
2048   widget_rc_style = g_object_get_qdata (G_OBJECT (widget), rc_style_key_id);
2049
2050   if (widget_rc_style)
2051     rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
2052
2053   if (rc_styles)
2054     return gtk_rc_init_style (context, rc_styles);
2055   else
2056     {
2057       if (!context->default_style)
2058         {
2059           context->default_style = gtk_style_new ();
2060           _gtk_style_init_for_settings (context->default_style, context->settings);
2061         }
2062
2063       return context->default_style;
2064     }
2065 }
2066
2067 /**
2068  * gtk_rc_get_style_by_paths:
2069  * @settings: a #GtkSettings object
2070  * @widget_path: (allow-none): the widget path to use when looking up the style, or %NULL
2071  *               if no matching against the widget path should be done
2072  * @class_path: (allow-none): the class path to use when looking up the style, or %NULL
2073  *               if no matching against the class path should be done.
2074  * @type: a type that will be used along with parent types of this type
2075  *        when matching against class styles, or #G_TYPE_NONE
2076  *
2077  * Creates up a #GtkStyle from styles defined in a RC file by providing
2078  * the raw components used in matching. This function may be useful
2079  * when creating pseudo-widgets that should be themed like widgets but
2080  * don't actually have corresponding GTK+ widgets. An example of this
2081  * would be items inside a GNOME canvas widget.
2082  *
2083  * The action of gtk_rc_get_style() is similar to:
2084  * |[
2085  *  gtk_widget_path (widget, NULL, &path, NULL);
2086  *  gtk_widget_class_path (widget, NULL, &class_path, NULL);
2087  *  gtk_rc_get_style_by_paths (gtk_widget_get_settings (widget), 
2088  *                             path, class_path,
2089  *                             G_OBJECT_TYPE (widget));
2090  * ]|
2091  * 
2092  * Return value: A style created by matching with the supplied paths,
2093  *   or %NULL if nothing matching was specified and the default style should
2094  *   be used. The returned value is owned by GTK+ as part of an internal cache,
2095  *   so you must call g_object_ref() on the returned value if you want to
2096  *   keep a reference to it.
2097  **/
2098 GtkStyle *
2099 gtk_rc_get_style_by_paths (GtkSettings *settings,
2100                            const char  *widget_path,
2101                            const char  *class_path,
2102                            GType        type)
2103 {
2104   /* We duplicate the code from above to avoid slowing down the above
2105    * by generating paths when we don't need them. I don't know if
2106    * this is really worth it.
2107    */
2108   GSList *rc_styles = NULL;
2109   GtkRcContext *context;
2110
2111   g_return_val_if_fail (GTK_IS_SETTINGS (settings), NULL);
2112
2113   context = gtk_rc_context_get (settings);
2114
2115   if (widget_path && context->rc_sets_widget)
2116     {
2117       gchar *path;
2118       gchar *path_reversed;
2119       guint path_length;
2120
2121       path_length = strlen (widget_path);
2122       path = g_strdup (widget_path);
2123       path_reversed = g_strdup (widget_path);
2124       g_strreverse (path_reversed);
2125
2126       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, path, path_reversed);
2127       g_free (path);
2128       g_free (path_reversed);
2129     }
2130   
2131   if (class_path && context->rc_sets_widget_class)
2132     {
2133       gchar *path;
2134       gchar *path_reversed;
2135       guint path_length;
2136
2137       path = g_strdup (class_path);
2138       path_length = strlen (class_path);
2139       path_reversed = g_strdup (class_path);
2140       g_strreverse (path_reversed);
2141
2142       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, path, path_reversed);
2143       g_free (path);
2144       g_free (path_reversed);
2145     }
2146
2147   if (type != G_TYPE_NONE && context->rc_sets_class)
2148     {
2149       while (type)
2150         {
2151           gchar *path;
2152           gchar *path_reversed;
2153           guint path_length;
2154
2155           path = g_strdup (g_type_name (type));
2156           path_length = strlen (path);
2157           path_reversed = g_strdup (path);
2158           g_strreverse (path_reversed);
2159           
2160           rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
2161           g_free (path);
2162           g_free (path_reversed);
2163       
2164           type = g_type_parent (type);
2165         }
2166     }
2167  
2168   rc_styles = sort_and_dereference_sets (rc_styles);
2169   
2170   if (rc_styles)
2171     return gtk_rc_init_style (context, rc_styles);
2172
2173   return NULL;
2174 }
2175
2176 GScanner*
2177 gtk_rc_scanner_new (void)
2178 {
2179   return g_scanner_new (&gtk_rc_scanner_config);
2180 }
2181
2182 static void
2183 gtk_rc_parse_any (GtkRcContext *context,
2184                   const gchar  *input_name,
2185                   gint          input_fd,
2186                   const gchar  *input_string)
2187 {
2188   GScanner *scanner;
2189   guint    i;
2190   gboolean done;
2191
2192   scanner = gtk_rc_scanner_new ();
2193   
2194   if (input_fd >= 0)
2195     {
2196       g_assert (input_string == NULL);
2197       
2198       g_scanner_input_file (scanner, input_fd);
2199     }
2200   else
2201     {
2202       g_assert (input_string != NULL);
2203       
2204       g_scanner_input_text (scanner, input_string, strlen (input_string));
2205     }
2206   scanner->input_name = input_name;
2207
2208   for (i = 0; i < G_N_ELEMENTS (symbols); i++)
2209     g_scanner_scope_add_symbol (scanner, 0, symbol_names + symbols[i].name_offset, GINT_TO_POINTER (symbols[i].token));
2210   done = FALSE;
2211   while (!done)
2212     {
2213       if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
2214         done = TRUE;
2215       else
2216         {
2217           guint expected_token;
2218           
2219           expected_token = gtk_rc_parse_statement (context, scanner);
2220
2221           if (expected_token != G_TOKEN_NONE)
2222             {
2223               const gchar *symbol_name = NULL;
2224               gchar *msg = NULL;
2225
2226               if (scanner->scope_id == 0)
2227                 {
2228                   /* if we are in scope 0, we know the symbol names
2229                    * that are associated with certain token values.
2230                    * so we look them up to make the error messages
2231                    * more readable.
2232                    */
2233                   if (expected_token > GTK_RC_TOKEN_INVALID &&
2234                       expected_token < GTK_RC_TOKEN_LAST)
2235                     {
2236                       const gchar *sym = NULL;
2237
2238                       for (i = 0; i < G_N_ELEMENTS (symbols); i++)
2239                         if (symbols[i].token == expected_token)
2240                           sym = symbol_names + symbols[i].name_offset;
2241
2242                       if (sym)
2243                         msg = g_strconcat ("e.g. `", sym, "'", NULL);
2244                     }
2245
2246                   if (scanner->token > GTK_RC_TOKEN_INVALID &&
2247                       scanner->token < GTK_RC_TOKEN_LAST)
2248                     {
2249                       symbol_name = "???";
2250                       for (i = 0; i < G_N_ELEMENTS (symbols); i++)
2251                         if (symbols[i].token == scanner->token)
2252                           symbol_name = symbol_names + symbols[i].name_offset;
2253                     }
2254                 }
2255
2256               g_scanner_unexp_token (scanner,
2257                                      expected_token,
2258                                      NULL,
2259                                      "keyword",
2260                                      symbol_name,
2261                                      msg,
2262                                      TRUE);
2263               g_free (msg);
2264               done = TRUE;
2265             }
2266         }
2267     }
2268   
2269   g_scanner_destroy (scanner);
2270 }
2271
2272 static guint       
2273 gtk_rc_styles_hash (const GSList *rc_styles)
2274 {
2275   guint result;
2276   
2277   result = 0;
2278   while (rc_styles)
2279     {
2280       result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
2281       rc_styles = rc_styles->next;
2282     }
2283   
2284   return result;
2285 }
2286
2287 static gboolean
2288 gtk_rc_styles_equal (const GSList *a,
2289                      const GSList *b)
2290 {
2291   while (a && b)
2292     {
2293       if (a->data != b->data)
2294         return FALSE;
2295       a = a->next;
2296       b = b->next;
2297     }
2298   
2299   return (a == b);
2300 }
2301
2302 static guint
2303 gtk_rc_style_hash (const gchar *name)
2304 {
2305   guint result;
2306   
2307   result = 0;
2308   while (*name)
2309     result += (result << 3) + *name++;
2310   
2311   return result;
2312 }
2313
2314 static gboolean
2315 gtk_rc_style_equal (const gchar *a,
2316                     const gchar *b)
2317 {
2318   return (strcmp (a, b) == 0);
2319 }
2320
2321 static GtkRcStyle*
2322 gtk_rc_style_find (GtkRcContext *context,
2323                    const gchar  *name)
2324 {
2325   if (context->rc_style_ht)
2326     return g_hash_table_lookup (context->rc_style_ht, (gpointer) name);
2327   else
2328     return NULL;
2329 }
2330
2331 static GtkStyle *
2332 gtk_rc_style_to_style (GtkRcContext *context,
2333                        GtkRcStyle   *rc_style)
2334 {
2335   GtkStyle *style;
2336
2337   style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
2338   _gtk_style_init_for_settings (style, context->settings);
2339
2340   style->rc_style = g_object_ref (rc_style);
2341   
2342   GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);  
2343
2344   return style;
2345 }
2346
2347 /* Reuses or frees rc_styles */
2348 static GtkStyle *
2349 gtk_rc_init_style (GtkRcContext *context,
2350                    GSList       *rc_styles)
2351 {
2352   GtkStyle *style = NULL;
2353   gint i;
2354
2355   g_return_val_if_fail (rc_styles != NULL, NULL);
2356   
2357   if (!realized_style_ht)
2358     realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
2359  (GEqualFunc) gtk_rc_styles_equal);
2360
2361   style = g_hash_table_lookup (realized_style_ht, rc_styles);
2362
2363   if (!style)
2364     {
2365       GtkRcStyle *base_style = NULL;
2366       GtkRcStyle *proto_style;
2367       GtkRcStyleClass *proto_style_class;
2368       GSList *tmp_styles;
2369       GType rc_style_type = GTK_TYPE_RC_STYLE;
2370
2371       /* Find the first style where the RC file specified engine "" {}
2372        * or the first derived style and use that to create the
2373        * merged style. If we only have raw GtkRcStyles, use the first
2374        * style to create the merged style.
2375        */
2376       base_style = rc_styles->data;
2377       tmp_styles = rc_styles;
2378       while (tmp_styles)
2379         {
2380           GtkRcStyle *rc_style = tmp_styles->data;
2381           
2382           if (rc_style->engine_specified ||
2383               G_OBJECT_TYPE (rc_style) != rc_style_type)
2384             {
2385               base_style = rc_style;
2386               break;
2387             }
2388           
2389           tmp_styles = tmp_styles->next;
2390         }
2391       
2392       proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
2393       proto_style = proto_style_class->create_rc_style (base_style);
2394
2395       tmp_styles = rc_styles;
2396       while (tmp_styles)
2397         {
2398           GtkRcStyle *rc_style = tmp_styles->data;
2399
2400           proto_style_class->merge (proto_style, rc_style);       
2401           
2402           /* Point from each rc_style to the list of styles */
2403           if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
2404             rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
2405
2406           gtk_rc_style_append_icon_factories (proto_style, rc_style);
2407           gtk_rc_style_append_color_hashes (proto_style, rc_style);
2408
2409           tmp_styles = tmp_styles->next;
2410         }
2411
2412       for (i = 0; i < 5; i++)
2413         if (proto_style->bg_pixmap_name[i] &&
2414             (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
2415           {
2416             g_free (proto_style->bg_pixmap_name[i]);
2417             proto_style->bg_pixmap_name[i] = NULL;
2418           }
2419
2420       style = gtk_rc_style_to_style (context, proto_style);
2421       g_object_unref (proto_style);
2422
2423       g_hash_table_insert (realized_style_ht, rc_styles, style);
2424     }
2425   else
2426     g_slist_free (rc_styles);
2427
2428   return style;
2429 }
2430
2431 /*********************
2432  * Parsing functions *
2433  *********************/
2434
2435 static gboolean
2436 lookup_color (GtkRcStyle *style,
2437               const char *color_name,
2438               GdkColor   *color)
2439 {
2440   GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (style);
2441   GSList *iter;
2442
2443   for (iter = priv->color_hashes; iter != NULL; iter = iter->next)
2444     {
2445       GHashTable *hash  = iter->data;
2446       GdkColor   *match = g_hash_table_lookup (hash, color_name);
2447
2448       if (match)
2449         {
2450           color->red = match->red;
2451           color->green = match->green;
2452           color->blue = match->blue;
2453           return TRUE;
2454         }
2455     }
2456
2457   return FALSE;
2458 }
2459
2460 static guint
2461 rc_parse_token_or_compound (GScanner   *scanner,
2462                             GtkRcStyle *style,
2463                             GString    *gstring,
2464                             GTokenType  delimiter)
2465 {
2466   guint token = g_scanner_get_next_token (scanner);
2467
2468   /* we either scan a single token (skipping comments)
2469    * or a compund statement.
2470    * compunds are enclosed in (), [] or {} braces, we read
2471    * them in via deep recursion.
2472    */
2473
2474   switch (token)
2475     {
2476       gchar *string;
2477     case G_TOKEN_INT:
2478       g_string_append_printf (gstring, " 0x%lx", scanner->value.v_int);
2479       break;
2480     case G_TOKEN_FLOAT:
2481       g_string_append_printf (gstring, " %f", scanner->value.v_float);
2482       break;
2483     case G_TOKEN_STRING:
2484       string = g_strescape (scanner->value.v_string, NULL);
2485       g_string_append (gstring, " \"");
2486       g_string_append (gstring, string);
2487       g_string_append_c (gstring, '"');
2488       g_free (string);
2489       break;
2490     case G_TOKEN_IDENTIFIER:
2491       g_string_append_c (gstring, ' ');
2492       g_string_append (gstring, scanner->value.v_identifier);
2493       break;
2494     case G_TOKEN_COMMENT_SINGLE:
2495     case G_TOKEN_COMMENT_MULTI:
2496       return rc_parse_token_or_compound (scanner, style, gstring, delimiter);
2497     case G_TOKEN_LEFT_PAREN:
2498       g_string_append_c (gstring, ' ');
2499       g_string_append_c (gstring, token);
2500       token = rc_parse_token_or_compound (scanner, style, gstring, G_TOKEN_RIGHT_PAREN);
2501       if (token != G_TOKEN_NONE)
2502         return token;
2503       break;
2504     case G_TOKEN_LEFT_CURLY:
2505       g_string_append_c (gstring, ' ');
2506       g_string_append_c (gstring, token);
2507       token = rc_parse_token_or_compound (scanner, style, gstring, G_TOKEN_RIGHT_CURLY);
2508       if (token != G_TOKEN_NONE)
2509         return token;
2510       break;
2511     case G_TOKEN_LEFT_BRACE:
2512       g_string_append_c (gstring, ' ');
2513       g_string_append_c (gstring, token);
2514       token = rc_parse_token_or_compound (scanner, style, gstring, G_TOKEN_RIGHT_BRACE);
2515       if (token != G_TOKEN_NONE)
2516         return token;
2517       break;
2518     case '@':
2519       if (g_scanner_peek_next_token (scanner) == G_TOKEN_IDENTIFIER)
2520         {
2521           GdkColor color;
2522           gchar    rbuf[G_ASCII_DTOSTR_BUF_SIZE];
2523           gchar    gbuf[G_ASCII_DTOSTR_BUF_SIZE];
2524           gchar    bbuf[G_ASCII_DTOSTR_BUF_SIZE];
2525
2526           g_scanner_get_next_token (scanner);
2527
2528           if (!style || !lookup_color (style, scanner->value.v_identifier,
2529                                        &color))
2530             {
2531               g_scanner_warn (scanner, "Invalid symbolic color '%s'",
2532                               scanner->value.v_identifier);
2533               return G_TOKEN_IDENTIFIER;
2534             }
2535
2536
2537           g_string_append_printf (gstring, " { %s, %s, %s }",
2538                                   g_ascii_formatd (rbuf, sizeof (rbuf),
2539                                                    "%0.4f",
2540                                                    color.red / 65535.0),
2541                                   g_ascii_formatd (gbuf, sizeof (gbuf),
2542                                                    "%0.4f",
2543                                                    color.green / 65535.0),
2544                                   g_ascii_formatd (bbuf, sizeof (bbuf),
2545                                                    "%0.4f",
2546                                                    color.blue / 65535.0));
2547           break;
2548         }
2549       else
2550         return G_TOKEN_IDENTIFIER;
2551     default:
2552       if (token >= 256 || token < 1)
2553         return delimiter ? delimiter : G_TOKEN_STRING;
2554       g_string_append_c (gstring, ' ');
2555       g_string_append_c (gstring, token);
2556       if (token == delimiter)
2557         return G_TOKEN_NONE;
2558       break;
2559     }
2560   if (!delimiter)
2561     return G_TOKEN_NONE;
2562   else
2563     return rc_parse_token_or_compound (scanner, style, gstring, delimiter);
2564 }
2565
2566 static guint
2567 gtk_rc_parse_assignment (GScanner      *scanner,
2568                          GtkRcStyle    *style,
2569                          GtkRcProperty *prop)
2570 {
2571 #define MY_SCAN_IDENTIFIER      TRUE
2572 #define MY_SCAN_SYMBOLS         FALSE
2573 #define MY_IDENTIFIER_2_STRING  FALSE
2574 #define MY_CHAR_2_TOKEN         TRUE
2575 #define MY_SCAN_IDENTIFIER_NULL FALSE
2576 #define MY_NUMBERS_2_INT        TRUE
2577
2578   gboolean scan_identifier      = scanner->config->scan_identifier;
2579   gboolean scan_symbols         = scanner->config->scan_symbols;
2580   gboolean identifier_2_string  = scanner->config->identifier_2_string;
2581   gboolean char_2_token         = scanner->config->char_2_token;
2582   gboolean scan_identifier_NULL = scanner->config->scan_identifier_NULL;
2583   gboolean numbers_2_int        = scanner->config->numbers_2_int;
2584   gboolean negate = FALSE;
2585   gboolean is_color = FALSE;
2586   guint    token;
2587
2588   /* check that this is an assignment */
2589   if (g_scanner_get_next_token (scanner) != '=')
2590     return '=';
2591
2592   /* adjust scanner mode */
2593   scanner->config->scan_identifier      = MY_SCAN_IDENTIFIER;
2594   scanner->config->scan_symbols         = MY_SCAN_SYMBOLS;
2595   scanner->config->identifier_2_string  = MY_IDENTIFIER_2_STRING;
2596   scanner->config->char_2_token         = MY_CHAR_2_TOKEN;
2597   scanner->config->scan_identifier_NULL = MY_SCAN_IDENTIFIER_NULL;
2598   scanner->config->numbers_2_int        = MY_NUMBERS_2_INT;
2599
2600   /* record location */
2601   if (g_getenv ("GTK_DEBUG"))
2602     prop->origin = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
2603   else
2604     prop->origin = NULL;
2605
2606   /* parse optional symbolic color prefix */
2607   if (g_scanner_peek_next_token (scanner) == '@')
2608     {
2609       g_scanner_get_next_token (scanner); /* eat color prefix */
2610       is_color = TRUE;
2611     }
2612
2613   /* parse optional sign */
2614   if (!is_color && g_scanner_peek_next_token (scanner) == '-')
2615     {
2616       g_scanner_get_next_token (scanner); /* eat sign */
2617       negate = TRUE;
2618     }
2619
2620   /* parse one of LONG, DOUBLE and STRING or, if that fails, create an
2621    * unparsed compund
2622    */
2623   token = g_scanner_peek_next_token (scanner);
2624
2625   if (is_color && token != G_TOKEN_IDENTIFIER)
2626     {
2627       token = G_TOKEN_IDENTIFIER;
2628       goto out;
2629     }
2630
2631   switch (token)
2632     {
2633     case G_TOKEN_INT:
2634       g_scanner_get_next_token (scanner);
2635       g_value_init (&prop->value, G_TYPE_LONG);
2636       g_value_set_long (&prop->value, negate ? -scanner->value.v_int : scanner->value.v_int);
2637       token = G_TOKEN_NONE;
2638       break;
2639     case G_TOKEN_FLOAT:
2640       g_scanner_get_next_token (scanner);
2641       g_value_init (&prop->value, G_TYPE_DOUBLE);
2642       g_value_set_double (&prop->value, negate ? -scanner->value.v_float : scanner->value.v_float);
2643       token = G_TOKEN_NONE;
2644       break;
2645     case G_TOKEN_STRING:
2646       g_scanner_get_next_token (scanner);
2647       if (negate)
2648         token = G_TOKEN_INT;
2649       else
2650         {
2651           g_value_init (&prop->value, G_TYPE_STRING);
2652           g_value_set_string (&prop->value, scanner->value.v_string);
2653           token = G_TOKEN_NONE;
2654         }
2655       break;
2656     case G_TOKEN_IDENTIFIER:
2657       if (is_color)
2658         {
2659           GdkColor  color;
2660           gchar     rbuf[G_ASCII_DTOSTR_BUF_SIZE];
2661           gchar     gbuf[G_ASCII_DTOSTR_BUF_SIZE];
2662           gchar     bbuf[G_ASCII_DTOSTR_BUF_SIZE];
2663           GString  *gstring;
2664
2665           g_scanner_get_next_token (scanner);
2666
2667           if (!style || !lookup_color (style, scanner->value.v_identifier,
2668                                        &color))
2669             {
2670               g_scanner_warn (scanner, "Invalid symbolic color '%s'",
2671                               scanner->value.v_identifier);
2672               token = G_TOKEN_IDENTIFIER;
2673               break;
2674             }
2675
2676           gstring = g_string_new (NULL);
2677
2678           g_string_append_printf (gstring, " { %s, %s, %s }",
2679                                   g_ascii_formatd (rbuf, sizeof (rbuf),
2680                                                    "%0.4f",
2681                                                    color.red / 65535.0),
2682                                   g_ascii_formatd (gbuf, sizeof (gbuf),
2683                                                    "%0.4f",
2684                                                    color.green / 65535.0),
2685                                   g_ascii_formatd (bbuf, sizeof (bbuf),
2686                                                    "%0.4f",
2687                                                    color.blue / 65535.0));
2688
2689           g_value_init (&prop->value, G_TYPE_GSTRING);
2690           g_value_take_boxed (&prop->value, gstring);
2691           token = G_TOKEN_NONE;
2692           break;
2693         }
2694       /* fall through */
2695     case G_TOKEN_LEFT_PAREN:
2696     case G_TOKEN_LEFT_CURLY:
2697     case G_TOKEN_LEFT_BRACE:
2698       if (!negate)
2699         {
2700           GString  *gstring  = g_string_new (NULL);
2701           gboolean  parse_on = TRUE;
2702
2703           /*  allow identifier(foobar) to support color expressions  */
2704           if (token == G_TOKEN_IDENTIFIER)
2705             {
2706               g_scanner_get_next_token (scanner);
2707
2708               g_string_append_c (gstring, ' ');
2709               g_string_append (gstring, scanner->value.v_identifier);
2710
2711               /* temporarily reset scanner mode to default, so we
2712                * don't peek the next token in a mode that only makes
2713                * sense in this function; because if anything but
2714                * G_TOKEN_LEFT_PAREN follows, the next token will be
2715                * parsed by our caller.
2716                *
2717                * FIXME: right fix would be to call g_scanner_unget()
2718                *        but that doesn't exist
2719                */
2720               scanner->config->scan_identifier      = scan_identifier;
2721               scanner->config->scan_symbols         = scan_symbols;
2722               scanner->config->identifier_2_string  = identifier_2_string;
2723               scanner->config->char_2_token         = char_2_token;
2724               scanner->config->scan_identifier_NULL = scan_identifier_NULL;
2725               scanner->config->numbers_2_int        = numbers_2_int;
2726
2727               token = g_scanner_peek_next_token (scanner);
2728
2729               /* restore adjusted scanner mode */
2730               scanner->config->scan_identifier      = MY_SCAN_IDENTIFIER;
2731               scanner->config->scan_symbols         = MY_SCAN_SYMBOLS;
2732               scanner->config->identifier_2_string  = MY_IDENTIFIER_2_STRING;
2733               scanner->config->char_2_token         = MY_CHAR_2_TOKEN;
2734               scanner->config->scan_identifier_NULL = MY_SCAN_IDENTIFIER_NULL;
2735               scanner->config->numbers_2_int        = MY_NUMBERS_2_INT;
2736
2737               if (token != G_TOKEN_LEFT_PAREN)
2738                 {
2739                   token = G_TOKEN_NONE;
2740                   parse_on = FALSE;
2741                 }
2742             }
2743
2744           if (parse_on)
2745             token = rc_parse_token_or_compound (scanner, style, gstring, 0);
2746
2747           if (token == G_TOKEN_NONE)
2748             {
2749               g_string_append_c (gstring, ' ');
2750               g_value_init (&prop->value, G_TYPE_GSTRING);
2751               g_value_take_boxed (&prop->value, gstring);
2752             }
2753           else
2754             g_string_free (gstring, TRUE);
2755           break;
2756         }
2757       /* fall through */
2758     default:
2759       g_scanner_get_next_token (scanner);
2760       token = G_TOKEN_INT;
2761       break;
2762     }
2763
2764  out:
2765
2766   /* restore scanner mode */
2767   scanner->config->scan_identifier      = scan_identifier;
2768   scanner->config->scan_symbols         = scan_symbols;
2769   scanner->config->identifier_2_string  = identifier_2_string;
2770   scanner->config->char_2_token         = char_2_token;
2771   scanner->config->scan_identifier_NULL = scan_identifier_NULL;
2772   scanner->config->numbers_2_int        = numbers_2_int;
2773
2774   return token;
2775 }
2776
2777 static gboolean
2778 is_c_identifier (const gchar *string)
2779 {
2780   const gchar *p;
2781   gboolean is_varname;
2782
2783   is_varname = strchr ("_" G_CSET_a_2_z G_CSET_A_2_Z, string[0]) != NULL;
2784   for (p = string + 1; *p && is_varname; p++)
2785     is_varname &= strchr (G_CSET_DIGITS "-_" G_CSET_a_2_z G_CSET_A_2_Z, *p) != NULL;
2786
2787   return is_varname;
2788 }
2789
2790 static void
2791 parse_include_file (GtkRcContext *context,
2792                     GScanner     *scanner,
2793                     const gchar  *filename)
2794 {
2795   char *to_parse = NULL;
2796   
2797   if (g_path_is_absolute (filename))
2798     {
2799       /* For abolute paths, we call gtk_rc_context_parse_file unconditionally. We
2800        * don't print an error in this case.
2801        */
2802       to_parse = g_strdup (filename);
2803     }
2804   else
2805     {
2806       /* if a relative path, we look relative to all the RC files in the
2807        * include stack. We require the file to be found in this case
2808        * so we can give meaningful error messages, and because on reparsing
2809        * non-absolute paths don't make sense.
2810        */
2811       GSList *tmp_list = current_files_stack;
2812       while (tmp_list)
2813         {
2814           GtkRcFile *curfile = tmp_list->data;
2815           gchar *tmpname = g_build_filename (curfile->directory, filename, NULL);
2816
2817           if (g_file_test (tmpname, G_FILE_TEST_EXISTS))
2818             {
2819               to_parse = tmpname;
2820               break;
2821             }
2822
2823           g_free (tmpname);
2824           
2825           tmp_list = tmp_list->next;
2826         }
2827     }
2828
2829   if (to_parse)
2830     {
2831       gtk_rc_context_parse_file (context, to_parse, context->default_priority, FALSE);
2832       g_free (to_parse);
2833     }
2834   else
2835     {
2836       g_scanner_warn (scanner, 
2837                       _("Unable to find include file: \"%s\""),
2838                       filename);
2839     }
2840
2841 }
2842
2843 static guint
2844 gtk_rc_parse_statement (GtkRcContext *context,
2845                         GScanner     *scanner)
2846 {
2847   guint token;
2848   
2849   token = g_scanner_peek_next_token (scanner);
2850   switch (token)
2851     {
2852     case GTK_RC_TOKEN_INCLUDE:
2853       token = g_scanner_get_next_token (scanner);
2854       if (token != GTK_RC_TOKEN_INCLUDE)
2855         return GTK_RC_TOKEN_INCLUDE;
2856       token = g_scanner_get_next_token (scanner);
2857       if (token != G_TOKEN_STRING)
2858         return G_TOKEN_STRING;
2859       parse_include_file (context, scanner, scanner->value.v_string);
2860       return G_TOKEN_NONE;
2861       
2862     case GTK_RC_TOKEN_STYLE:
2863       return gtk_rc_parse_style (context, scanner);
2864       
2865     case GTK_RC_TOKEN_BINDING:
2866       return _gtk_binding_parse_binding (scanner);
2867       
2868     case GTK_RC_TOKEN_PIXMAP_PATH:
2869       return gtk_rc_parse_pixmap_path (context, scanner);
2870       
2871     case GTK_RC_TOKEN_WIDGET:
2872       return gtk_rc_parse_path_pattern (context, scanner);
2873       
2874     case GTK_RC_TOKEN_WIDGET_CLASS:
2875       return gtk_rc_parse_path_pattern (context, scanner);
2876       
2877     case GTK_RC_TOKEN_CLASS:
2878       return gtk_rc_parse_path_pattern (context, scanner);
2879       
2880     case GTK_RC_TOKEN_MODULE_PATH:
2881       return gtk_rc_parse_module_path (scanner);
2882       
2883     case GTK_RC_TOKEN_IM_MODULE_FILE:
2884       return gtk_rc_parse_im_module_file (scanner);
2885
2886     case G_TOKEN_IDENTIFIER:
2887       if (is_c_identifier (scanner->next_value.v_identifier))
2888         {
2889           GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2890           gchar *name;
2891           
2892           g_scanner_get_next_token (scanner); /* eat identifier */
2893           name = g_strdup (scanner->value.v_identifier);
2894           
2895           token = gtk_rc_parse_assignment (scanner, NULL, &prop);
2896           if (token == G_TOKEN_NONE)
2897             {
2898               GtkSettingsValue svalue;
2899
2900               svalue.origin = prop.origin;
2901               memcpy (&svalue.value, &prop.value, sizeof (prop.value));
2902               g_strcanon (name, G_CSET_DIGITS "-" G_CSET_a_2_z G_CSET_A_2_Z, '-');
2903               _gtk_settings_set_property_value_from_rc (context->settings,
2904                                                         name,
2905                                                         &svalue);
2906             }
2907           g_free (prop.origin);
2908           if (G_VALUE_TYPE (&prop.value))
2909             g_value_unset (&prop.value);
2910           g_free (name);
2911           
2912           return token;
2913         }
2914       else
2915         {
2916           g_scanner_get_next_token (scanner);
2917           return G_TOKEN_IDENTIFIER;
2918         }
2919     default:
2920       g_scanner_get_next_token (scanner);
2921       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
2922     }
2923 }
2924
2925 static void
2926 fixup_rc_set (GSList     *list,
2927               GtkRcStyle *orig,
2928               GtkRcStyle *new)
2929 {
2930   while (list)
2931     {
2932       GtkRcSet *set = list->data;
2933       if (set->rc_style == orig)
2934         set->rc_style = new;
2935       list = list->next;
2936     }
2937 }
2938
2939 static void
2940 fixup_rc_sets (GtkRcContext *context,
2941                GtkRcStyle   *orig,
2942                GtkRcStyle   *new)
2943 {
2944   fixup_rc_set (context->rc_sets_widget, orig, new);
2945   fixup_rc_set (context->rc_sets_widget_class, orig, new);
2946   fixup_rc_set (context->rc_sets_class, orig, new);
2947 }
2948
2949 static guint
2950 gtk_rc_parse_style (GtkRcContext *context,
2951                     GScanner     *scanner)
2952 {
2953   GtkRcStyle *rc_style;
2954   GtkRcStyle *orig_style;
2955   GtkRcStyle *parent_style = NULL;
2956   GtkRcStylePrivate *rc_priv = NULL;
2957   guint token;
2958   gint i;
2959   GtkIconFactory *our_factory = NULL;
2960   GHashTable *our_hash = NULL;
2961
2962   token = g_scanner_get_next_token (scanner);
2963   if (token != GTK_RC_TOKEN_STYLE)
2964     return GTK_RC_TOKEN_STYLE;
2965   
2966   token = g_scanner_get_next_token (scanner);
2967   if (token != G_TOKEN_STRING)
2968     return G_TOKEN_STRING;
2969   
2970   rc_style = gtk_rc_style_find (context, scanner->value.v_string);
2971   if (rc_style)
2972     orig_style = g_object_ref (rc_style);
2973   else
2974     orig_style = NULL;
2975
2976   if (!rc_style)
2977     {
2978       rc_style = gtk_rc_style_new ();
2979       rc_style->name = g_strdup (scanner->value.v_string);
2980       
2981       for (i = 0; i < 5; i++)
2982         rc_style->bg_pixmap_name[i] = NULL;
2983
2984       for (i = 0; i < 5; i++)
2985         rc_style->color_flags[i] = 0;
2986     }
2987
2988   rc_priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
2989
2990   /* If there's a list, its first member is always the factory belonging
2991    * to this RcStyle
2992    */
2993   if (rc_style->icon_factories)
2994     our_factory = rc_style->icon_factories->data;
2995   if (rc_priv->color_hashes)
2996     our_hash = rc_priv->color_hashes->data;
2997
2998   token = g_scanner_peek_next_token (scanner);
2999   if (token == G_TOKEN_EQUAL_SIGN)
3000     {
3001       token = g_scanner_get_next_token (scanner);
3002       
3003       token = g_scanner_get_next_token (scanner);
3004       if (token != G_TOKEN_STRING)
3005         {
3006           token = G_TOKEN_STRING;
3007           goto err;
3008         }
3009       
3010       parent_style = gtk_rc_style_find (context, scanner->value.v_string);
3011       if (parent_style)
3012         {
3013           for (i = 0; i < 5; i++)
3014             {
3015               rc_style->color_flags[i] = parent_style->color_flags[i];
3016               rc_style->fg[i] = parent_style->fg[i];
3017               rc_style->bg[i] = parent_style->bg[i];
3018               rc_style->text[i] = parent_style->text[i];
3019               rc_style->base[i] = parent_style->base[i];
3020             }
3021
3022           rc_style->xthickness = parent_style->xthickness;
3023           rc_style->ythickness = parent_style->ythickness;
3024           
3025           if (parent_style->font_desc)
3026             {
3027               if (rc_style->font_desc)
3028                 pango_font_description_free (rc_style->font_desc);
3029               rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
3030             }
3031
3032           if (parent_style->rc_properties)
3033             {
3034               guint i;
3035
3036               for (i = 0; i < parent_style->rc_properties->len; i++)
3037                 insert_rc_property (rc_style,
3038                                     &g_array_index (parent_style->rc_properties, GtkRcProperty, i),
3039                                     TRUE);
3040             }
3041           
3042           for (i = 0; i < 5; i++)
3043             {
3044               g_free (rc_style->bg_pixmap_name[i]);
3045               rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
3046             }
3047         }
3048     }
3049
3050   /*  get icon_factories and color_hashes from the parent style;
3051    *  if the parent_style doesn't have color_hashes, initializes
3052    *  the color_hashes with the settings' color scheme (if it exists)
3053    */
3054   gtk_rc_style_copy_icons_and_colors (rc_style, parent_style, context);
3055
3056   if (rc_style->icon_factories)
3057     our_factory = rc_style->icon_factories->data;
3058   if (rc_priv->color_hashes)
3059     our_hash = rc_priv->color_hashes->data;
3060
3061   token = g_scanner_get_next_token (scanner);
3062   if (token != G_TOKEN_LEFT_CURLY)
3063     {
3064       token = G_TOKEN_LEFT_CURLY;
3065       goto err;
3066     }
3067   
3068   token = g_scanner_peek_next_token (scanner);
3069   while (token != G_TOKEN_RIGHT_CURLY)
3070     {
3071       switch (token)
3072         {
3073         case GTK_RC_TOKEN_BG:
3074           token = gtk_rc_parse_bg (scanner, rc_style);
3075           break;
3076         case GTK_RC_TOKEN_FG:
3077           token = gtk_rc_parse_fg (scanner, rc_style);
3078           break;
3079         case GTK_RC_TOKEN_TEXT:
3080           token = gtk_rc_parse_text (scanner, rc_style);
3081           break;
3082         case GTK_RC_TOKEN_BASE:
3083           token = gtk_rc_parse_base (scanner, rc_style);
3084           break;
3085         case GTK_RC_TOKEN_XTHICKNESS:
3086           token = gtk_rc_parse_xthickness (scanner, rc_style);
3087           break;
3088         case GTK_RC_TOKEN_YTHICKNESS:
3089           token = gtk_rc_parse_ythickness (scanner, rc_style);
3090           break;
3091         case GTK_RC_TOKEN_BG_PIXMAP:
3092           token = gtk_rc_parse_bg_pixmap (context, scanner, rc_style);
3093           break;
3094         case GTK_RC_TOKEN_FONT:
3095           token = gtk_rc_parse_font (scanner, rc_style);
3096           break;
3097         case GTK_RC_TOKEN_FONTSET:
3098           token = gtk_rc_parse_fontset (scanner, rc_style);
3099           break;
3100         case GTK_RC_TOKEN_FONT_NAME:
3101           token = gtk_rc_parse_font_name (scanner, rc_style);
3102           break;
3103         case GTK_RC_TOKEN_ENGINE:
3104           token = gtk_rc_parse_engine (context, scanner, &rc_style);
3105           break;
3106         case GTK_RC_TOKEN_STOCK:
3107           if (our_factory == NULL)
3108             gtk_rc_style_prepend_empty_icon_factory (rc_style);
3109           our_factory = rc_style->icon_factories->data;
3110           token = gtk_rc_parse_stock (context, scanner, rc_style, our_factory);
3111           break;
3112         case GTK_RC_TOKEN_COLOR:
3113           if (our_hash == NULL)
3114             {
3115               gtk_rc_style_prepend_empty_color_hash (rc_style);
3116               our_hash = rc_priv->color_hashes->data;
3117             }
3118           token = gtk_rc_parse_logical_color (scanner, rc_style, our_hash);
3119           break;
3120         case G_TOKEN_IDENTIFIER:
3121           if (is_c_identifier (scanner->next_value.v_identifier))
3122             {
3123               GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
3124               gchar *name;
3125
3126               g_scanner_get_next_token (scanner); /* eat type name */
3127               prop.type_name = g_quark_from_string (scanner->value.v_identifier);
3128               if (g_scanner_get_next_token (scanner) != ':' ||
3129                   g_scanner_get_next_token (scanner) != ':')
3130                 {
3131                   token = ':';
3132                   break;
3133                 }
3134               if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER ||
3135                   !is_c_identifier (scanner->value.v_identifier))
3136                 {
3137                   token = G_TOKEN_IDENTIFIER;
3138                   break;
3139                 }
3140
3141               /* it's important that we do the same canonification as GParamSpecPool here */
3142               name = g_strdup (scanner->value.v_identifier);
3143               g_strcanon (name, G_CSET_DIGITS "-" G_CSET_a_2_z G_CSET_A_2_Z, '-');
3144               prop.property_name = g_quark_from_string (name);
3145               g_free (name);
3146
3147               token = gtk_rc_parse_assignment (scanner, rc_style, &prop);
3148               if (token == G_TOKEN_NONE)
3149                 {
3150                   g_return_val_if_fail (G_VALUE_TYPE (&prop.value) != 0, G_TOKEN_ERROR);
3151                   insert_rc_property (rc_style, &prop, TRUE);
3152                 }
3153               
3154               g_free (prop.origin);
3155               if (G_VALUE_TYPE (&prop.value))
3156                 g_value_unset (&prop.value);
3157             }
3158           else
3159             {
3160               g_scanner_get_next_token (scanner);
3161               token = G_TOKEN_IDENTIFIER;
3162             }
3163           break;
3164         default:
3165           g_scanner_get_next_token (scanner);
3166           token = G_TOKEN_RIGHT_CURLY;
3167           break;
3168         }
3169
3170       if (token != G_TOKEN_NONE)
3171         goto err;
3172
3173       token = g_scanner_peek_next_token (scanner);
3174     } /* while (token != G_TOKEN_RIGHT_CURLY) */
3175   
3176   token = g_scanner_get_next_token (scanner);
3177   if (token != G_TOKEN_RIGHT_CURLY)
3178     {
3179       token = G_TOKEN_RIGHT_CURLY;
3180       goto err;
3181     }
3182   
3183   if (rc_style != orig_style)
3184     {
3185       if (!context->rc_style_ht)
3186         context->rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
3187                                                  (GEqualFunc) gtk_rc_style_equal);
3188       
3189       g_hash_table_replace (context->rc_style_ht, rc_style->name, rc_style);
3190
3191       /* If we copied the data into a new rc style, fix up references to the old rc style
3192        * in bindings that we have.
3193        */
3194       if (orig_style)
3195         fixup_rc_sets (context, orig_style, rc_style);
3196     }
3197
3198   if (orig_style)
3199     g_object_unref (orig_style);
3200   
3201   return G_TOKEN_NONE;
3202
3203  err:
3204   if (rc_style != orig_style)
3205     g_object_unref (rc_style);
3206
3207   if (orig_style)
3208     g_object_unref (orig_style);
3209   
3210   return token;
3211 }
3212
3213 const GtkRcProperty*
3214 _gtk_rc_style_lookup_rc_property (GtkRcStyle *rc_style,
3215                                   GQuark      type_name,
3216                                   GQuark      property_name)
3217 {
3218   GtkRcProperty *node = NULL;
3219
3220   g_return_val_if_fail (GTK_IS_RC_STYLE (rc_style), NULL);
3221
3222   if (rc_style->rc_properties)
3223     {
3224       GtkRcProperty key;
3225
3226       key.type_name = type_name;
3227       key.property_name = property_name;
3228
3229       node = bsearch (&key,
3230                       rc_style->rc_properties->data, rc_style->rc_properties->len,
3231                       sizeof (GtkRcProperty), gtk_rc_properties_cmp);
3232     }
3233
3234   return node;
3235 }
3236
3237 static guint
3238 gtk_rc_parse_bg (GScanner   *scanner,
3239                  GtkRcStyle *style)
3240 {
3241   GtkStateType state;
3242   guint token;
3243   
3244   token = g_scanner_get_next_token (scanner);
3245   if (token != GTK_RC_TOKEN_BG)
3246     return GTK_RC_TOKEN_BG;
3247   
3248   token = gtk_rc_parse_state (scanner, &state);
3249   if (token != G_TOKEN_NONE)
3250     return token;
3251   
3252   token = g_scanner_get_next_token (scanner);
3253   if (token != G_TOKEN_EQUAL_SIGN)
3254     return G_TOKEN_EQUAL_SIGN;
3255
3256   style->color_flags[state] |= GTK_RC_BG;
3257   return gtk_rc_parse_color_full (scanner, style, &style->bg[state]);
3258 }
3259
3260 static guint
3261 gtk_rc_parse_fg (GScanner   *scanner,
3262                  GtkRcStyle *style)
3263 {
3264   GtkStateType state;
3265   guint token;
3266   
3267   token = g_scanner_get_next_token (scanner);
3268   if (token != GTK_RC_TOKEN_FG)
3269     return GTK_RC_TOKEN_FG;
3270   
3271   token = gtk_rc_parse_state (scanner, &state);
3272   if (token != G_TOKEN_NONE)
3273     return token;
3274   
3275   token = g_scanner_get_next_token (scanner);
3276   if (token != G_TOKEN_EQUAL_SIGN)
3277     return G_TOKEN_EQUAL_SIGN;
3278   
3279   style->color_flags[state] |= GTK_RC_FG;
3280   return gtk_rc_parse_color_full (scanner, style, &style->fg[state]);
3281 }
3282
3283 static guint
3284 gtk_rc_parse_text (GScanner   *scanner,
3285                    GtkRcStyle *style)
3286 {
3287   GtkStateType state;
3288   guint token;
3289   
3290   token = g_scanner_get_next_token (scanner);
3291   if (token != GTK_RC_TOKEN_TEXT)
3292     return GTK_RC_TOKEN_TEXT;
3293   
3294   token = gtk_rc_parse_state (scanner, &state);
3295   if (token != G_TOKEN_NONE)
3296     return token;
3297   
3298   token = g_scanner_get_next_token (scanner);
3299   if (token != G_TOKEN_EQUAL_SIGN)
3300     return G_TOKEN_EQUAL_SIGN;
3301   
3302   style->color_flags[state] |= GTK_RC_TEXT;
3303   return gtk_rc_parse_color_full (scanner, style, &style->text[state]);
3304 }
3305
3306 static guint
3307 gtk_rc_parse_base (GScanner   *scanner,
3308                    GtkRcStyle *style)
3309 {
3310   GtkStateType state;
3311   guint token;
3312   
3313   token = g_scanner_get_next_token (scanner);
3314   if (token != GTK_RC_TOKEN_BASE)
3315     return GTK_RC_TOKEN_BASE;
3316   
3317   token = gtk_rc_parse_state (scanner, &state);
3318   if (token != G_TOKEN_NONE)
3319     return token;
3320   
3321   token = g_scanner_get_next_token (scanner);
3322   if (token != G_TOKEN_EQUAL_SIGN)
3323     return G_TOKEN_EQUAL_SIGN;
3324
3325   style->color_flags[state] |= GTK_RC_BASE;
3326   return gtk_rc_parse_color_full (scanner, style, &style->base[state]);
3327 }
3328
3329 static guint
3330 gtk_rc_parse_xthickness (GScanner   *scanner,
3331                          GtkRcStyle *style)
3332 {
3333   if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
3334     return GTK_RC_TOKEN_XTHICKNESS;
3335
3336   if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
3337     return G_TOKEN_EQUAL_SIGN;
3338
3339   if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
3340     return G_TOKEN_INT;
3341
3342   style->xthickness = scanner->value.v_int;
3343
3344   return G_TOKEN_NONE;
3345 }
3346
3347 static guint
3348 gtk_rc_parse_ythickness (GScanner   *scanner,
3349                          GtkRcStyle *style)
3350 {
3351   if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
3352     return GTK_RC_TOKEN_YTHICKNESS;
3353
3354   if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
3355     return G_TOKEN_EQUAL_SIGN;
3356
3357   if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
3358     return G_TOKEN_INT;
3359
3360   style->ythickness = scanner->value.v_int;
3361
3362   return G_TOKEN_NONE;
3363 }
3364
3365 static guint
3366 gtk_rc_parse_bg_pixmap (GtkRcContext *context,
3367                         GScanner     *scanner,
3368                         GtkRcStyle   *rc_style)
3369 {
3370   GtkStateType state;
3371   guint token;
3372   gchar *pixmap_file;
3373   
3374   token = g_scanner_get_next_token (scanner);
3375   if (token != GTK_RC_TOKEN_BG_PIXMAP)
3376     return GTK_RC_TOKEN_BG_PIXMAP;
3377   
3378   token = gtk_rc_parse_state (scanner, &state);
3379   if (token != G_TOKEN_NONE)
3380     return token;
3381   
3382   token = g_scanner_get_next_token (scanner);
3383   if (token != G_TOKEN_EQUAL_SIGN)
3384     return G_TOKEN_EQUAL_SIGN;
3385   
3386   token = g_scanner_get_next_token (scanner);
3387   if (token != G_TOKEN_STRING)
3388     return G_TOKEN_STRING;
3389   
3390   if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
3391       (strcmp (scanner->value.v_string, "<none>") == 0))
3392     pixmap_file = g_strdup (scanner->value.v_string);
3393   else
3394     pixmap_file = gtk_rc_find_pixmap_in_path (context->settings,
3395                                               scanner, scanner->value.v_string);
3396   
3397   if (pixmap_file)
3398     {
3399       g_free (rc_style->bg_pixmap_name[state]);
3400       rc_style->bg_pixmap_name[state] = pixmap_file;
3401     }
3402   
3403   return G_TOKEN_NONE;
3404 }
3405
3406 static gchar*
3407 gtk_rc_check_pixmap_dir (const gchar *dir, 
3408                          const gchar *pixmap_file)
3409 {
3410   gchar *buf;
3411
3412   buf = g_build_filename (dir, pixmap_file, NULL);
3413
3414   if (g_file_test (buf, G_FILE_TEST_EXISTS))
3415     return buf;
3416    
3417   g_free (buf);
3418  
3419    return NULL;
3420  }
3421
3422 /**
3423  * gtk_rc_find_pixmap_in_path:
3424  * @settings: a #GtkSettings
3425  * @scanner: Scanner used to get line number information for the
3426  *   warning message, or %NULL
3427  * @pixmap_file: name of the pixmap file to locate.
3428  * 
3429  * Looks up a file in pixmap path for the specified #GtkSettings.
3430  * If the file is not found, it outputs a warning message using
3431  * g_warning() and returns %NULL.
3432  *
3433  * Return value: the filename. 
3434  **/
3435 gchar*
3436 gtk_rc_find_pixmap_in_path (GtkSettings  *settings,
3437                             GScanner     *scanner,
3438                             const gchar  *pixmap_file)
3439 {
3440   gint i;
3441   gchar *filename;
3442   GSList *tmp_list;
3443
3444   GtkRcContext *context = gtk_rc_context_get (settings);
3445     
3446   if (context->pixmap_path)
3447     for (i = 0; context->pixmap_path[i] != NULL; i++)
3448       {
3449         filename = gtk_rc_check_pixmap_dir (context->pixmap_path[i], pixmap_file);
3450         if (filename)
3451           return filename;
3452       }
3453   
3454   tmp_list = current_files_stack;
3455   while (tmp_list)
3456     {
3457       GtkRcFile *curfile = tmp_list->data;
3458       filename = gtk_rc_check_pixmap_dir (curfile->directory, pixmap_file);
3459       if (filename)
3460         return filename;
3461        
3462       tmp_list = tmp_list->next;
3463     }
3464   
3465   if (scanner)
3466     g_scanner_warn (scanner, 
3467                     _("Unable to locate image file in pixmap_path: \"%s\""),
3468                     pixmap_file);
3469   else
3470     g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
3471                pixmap_file);
3472     
3473   return NULL;
3474 }
3475
3476 /**
3477  * gtk_rc_find_module_in_path:
3478  * @module_file: name of a theme engine
3479  * 
3480  * Searches for a theme engine in the GTK+ search path. This function
3481  * is not useful for applications and should not be used.
3482  * 
3483  * Return value: The filename, if found (must be freed with g_free()),
3484  *   otherwise %NULL.
3485  **/
3486 gchar*
3487 gtk_rc_find_module_in_path (const gchar *module_file)
3488 {
3489   return _gtk_find_module (module_file, "engines");
3490 }
3491
3492 static guint
3493 gtk_rc_parse_font (GScanner   *scanner,
3494                    GtkRcStyle *rc_style)
3495 {
3496   guint token;
3497   
3498   token = g_scanner_get_next_token (scanner);
3499   if (token != GTK_RC_TOKEN_FONT)
3500     return GTK_RC_TOKEN_FONT;
3501   
3502   token = g_scanner_get_next_token (scanner);
3503   if (token != G_TOKEN_EQUAL_SIGN)
3504     return G_TOKEN_EQUAL_SIGN;
3505   
3506   token = g_scanner_get_next_token (scanner);
3507   if (token != G_TOKEN_STRING)
3508     return G_TOKEN_STRING;
3509
3510   /* Ignore, do nothing */
3511   
3512   return G_TOKEN_NONE;
3513 }
3514
3515 static guint
3516 gtk_rc_parse_fontset (GScanner   *scanner,
3517                       GtkRcStyle *rc_style)
3518 {
3519   guint token;
3520   
3521   token = g_scanner_get_next_token (scanner);
3522   if (token != GTK_RC_TOKEN_FONTSET)
3523     return GTK_RC_TOKEN_FONTSET;
3524   
3525   token = g_scanner_get_next_token (scanner);
3526   if (token != G_TOKEN_EQUAL_SIGN)
3527     return G_TOKEN_EQUAL_SIGN;
3528   
3529   token = g_scanner_get_next_token (scanner);
3530   if (token != G_TOKEN_STRING)
3531     return G_TOKEN_STRING;
3532
3533   /* Do nothing - silently ignore */
3534   
3535   return G_TOKEN_NONE;
3536 }
3537
3538 static guint
3539 gtk_rc_parse_font_name (GScanner   *scanner,
3540                         GtkRcStyle *rc_style)
3541 {
3542   guint token;
3543   
3544   token = g_scanner_get_next_token (scanner);
3545   if (token != GTK_RC_TOKEN_FONT_NAME)
3546     return GTK_RC_TOKEN_FONT;
3547   
3548   token = g_scanner_get_next_token (scanner);
3549   if (token != G_TOKEN_EQUAL_SIGN)
3550     return G_TOKEN_EQUAL_SIGN;
3551   
3552   token = g_scanner_get_next_token (scanner);
3553   if (token != G_TOKEN_STRING)
3554     return G_TOKEN_STRING;
3555
3556   if (rc_style->font_desc)
3557     pango_font_description_free (rc_style->font_desc);
3558
3559   rc_style->font_desc = 
3560     pango_font_description_from_string (scanner->value.v_string);
3561   
3562   return G_TOKEN_NONE;
3563 }
3564
3565 static guint       
3566 gtk_rc_parse_engine (GtkRcContext *context,
3567                      GScanner     *scanner,
3568                      GtkRcStyle  **rc_style)
3569 {
3570   guint token;
3571   GtkThemeEngine *engine;
3572   guint result = G_TOKEN_NONE;
3573   GtkRcStyle *new_style = NULL;
3574   gboolean parsed_curlies = FALSE;
3575   GtkRcStylePrivate *rc_priv, *new_priv;
3576   
3577   token = g_scanner_get_next_token (scanner);
3578   if (token != GTK_RC_TOKEN_ENGINE)
3579     return GTK_RC_TOKEN_ENGINE;
3580
3581   token = g_scanner_get_next_token (scanner);
3582   if (token != G_TOKEN_STRING)
3583     return G_TOKEN_STRING;
3584
3585   if (!scanner->value.v_string[0])
3586     {
3587       /* Support engine "" {} to mean override to the default engine
3588        */
3589       token = g_scanner_get_next_token (scanner);
3590       if (token != G_TOKEN_LEFT_CURLY)
3591         return G_TOKEN_LEFT_CURLY;
3592       
3593       token = g_scanner_get_next_token (scanner);
3594       if (token != G_TOKEN_RIGHT_CURLY)
3595         return G_TOKEN_RIGHT_CURLY;
3596
3597       parsed_curlies = TRUE;
3598
3599       rc_priv = GTK_RC_STYLE_GET_PRIVATE (*rc_style);
3600
3601       if (G_OBJECT_TYPE (*rc_style) != GTK_TYPE_RC_STYLE)
3602         {
3603           new_style = gtk_rc_style_new ();
3604           gtk_rc_style_real_merge (new_style, *rc_style);
3605
3606           new_style->name = g_strdup ((*rc_style)->name);
3607
3608           /* take over icon factories and color hashes 
3609            * from the to-be-deleted style
3610            */
3611           new_style->icon_factories = (*rc_style)->icon_factories;
3612           (*rc_style)->icon_factories = NULL;
3613           new_priv = GTK_RC_STYLE_GET_PRIVATE (new_style);
3614           new_priv->color_hashes = rc_priv->color_hashes;
3615           rc_priv->color_hashes = NULL;
3616         }
3617       else
3618         (*rc_style)->engine_specified = TRUE;
3619     }
3620   else
3621     {
3622       engine = gtk_theme_engine_get (scanner->value.v_string);
3623       
3624       token = g_scanner_get_next_token (scanner);
3625       if (token != G_TOKEN_LEFT_CURLY)
3626         return G_TOKEN_LEFT_CURLY;
3627       
3628       if (engine)
3629         {
3630           GtkRcStyleClass *new_class;
3631           
3632           rc_priv = GTK_RC_STYLE_GET_PRIVATE (*rc_style);
3633           new_style = gtk_theme_engine_create_rc_style (engine);
3634           g_type_module_unuse (G_TYPE_MODULE (engine));
3635           
3636           new_class = GTK_RC_STYLE_GET_CLASS (new_style);
3637
3638           new_class->merge (new_style, *rc_style);
3639
3640           new_style->name = g_strdup ((*rc_style)->name);
3641
3642           /* take over icon factories and color hashes 
3643            * from the to-be-deleted style
3644            */
3645           new_style->icon_factories = (*rc_style)->icon_factories;
3646           (*rc_style)->icon_factories = NULL;
3647           new_priv = GTK_RC_STYLE_GET_PRIVATE (new_style);
3648           new_priv->color_hashes = rc_priv->color_hashes;
3649           rc_priv->color_hashes = NULL;
3650           
3651           if (new_class->parse)
3652             {
3653               parsed_curlies = TRUE;
3654               result = new_class->parse (new_style, context->settings, scanner);
3655               
3656               if (result != G_TOKEN_NONE)
3657                 {
3658                   /* copy icon factories and color hashes back
3659                    */
3660                   (*rc_style)->icon_factories = new_style->icon_factories;
3661                   new_style->icon_factories = NULL;
3662                   rc_priv->color_hashes = new_priv->color_hashes;
3663                   new_priv->color_hashes = NULL;
3664
3665                   g_object_unref (new_style);
3666                   new_style = NULL;
3667                 }
3668             }
3669         }
3670     }
3671
3672   if (!parsed_curlies)
3673     {
3674       /* Skip over remainder, looking for nested {}'s
3675        */
3676       guint count = 1;
3677       
3678       result = G_TOKEN_RIGHT_CURLY;
3679       while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
3680         {
3681           if (token == G_TOKEN_LEFT_CURLY)
3682             count++;
3683           else if (token == G_TOKEN_RIGHT_CURLY)
3684             count--;
3685           
3686           if (count == 0)
3687             {
3688               result = G_TOKEN_NONE;
3689               break;
3690             }
3691         }
3692     }
3693
3694   if (new_style)
3695     {
3696       new_style->engine_specified = TRUE;
3697
3698       g_object_unref (*rc_style);
3699       *rc_style = new_style;
3700     }
3701
3702   return result;
3703 }
3704
3705 guint
3706 gtk_rc_parse_state (GScanner     *scanner,
3707                     GtkStateType *state)
3708 {
3709   guint old_scope;
3710   guint token;
3711
3712   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3713   g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
3714   
3715   /* we don't know where we got called from, so we reset the scope here.
3716    * if we bail out due to errors, we *don't* reset the scope, so the
3717    * error messaging code can make sense of our tokens.
3718    */
3719   old_scope = g_scanner_set_scope (scanner, 0);
3720   
3721   token = g_scanner_get_next_token (scanner);
3722   if (token != G_TOKEN_LEFT_BRACE)
3723     return G_TOKEN_LEFT_BRACE;
3724   
3725   token = g_scanner_get_next_token (scanner);
3726   switch (token)
3727     {
3728     case GTK_RC_TOKEN_ACTIVE:
3729       *state = GTK_STATE_ACTIVE;
3730       break;
3731     case GTK_RC_TOKEN_INSENSITIVE:
3732       *state = GTK_STATE_INSENSITIVE;
3733       break;
3734     case GTK_RC_TOKEN_NORMAL:
3735       *state = GTK_STATE_NORMAL;
3736       break;
3737     case GTK_RC_TOKEN_PRELIGHT:
3738       *state = GTK_STATE_PRELIGHT;
3739       break;
3740     case GTK_RC_TOKEN_SELECTED:
3741       *state = GTK_STATE_SELECTED;
3742       break;
3743     default:
3744       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
3745     }
3746   
3747   token = g_scanner_get_next_token (scanner);
3748   if (token != G_TOKEN_RIGHT_BRACE)
3749     return G_TOKEN_RIGHT_BRACE;
3750   
3751   g_scanner_set_scope (scanner, old_scope);
3752
3753   return G_TOKEN_NONE;
3754 }
3755
3756 guint
3757 gtk_rc_parse_priority (GScanner            *scanner,
3758                        GtkPathPriorityType *priority)
3759 {
3760   guint old_scope;
3761   guint token;
3762
3763   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3764   g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
3765
3766   /* we don't know where we got called from, so we reset the scope here.
3767    * if we bail out due to errors, we *don't* reset the scope, so the
3768    * error messaging code can make sense of our tokens.
3769    */
3770   old_scope = g_scanner_set_scope (scanner, 0);
3771   
3772   token = g_scanner_get_next_token (scanner);
3773   if (token != ':')
3774     return ':';
3775   
3776   token = g_scanner_get_next_token (scanner);
3777   switch (token)
3778     {
3779     case GTK_RC_TOKEN_LOWEST:
3780       *priority = GTK_PATH_PRIO_LOWEST;
3781       break;
3782     case GTK_RC_TOKEN_GTK:
3783       *priority = GTK_PATH_PRIO_GTK;
3784       break;
3785     case GTK_RC_TOKEN_APPLICATION:
3786       *priority = GTK_PATH_PRIO_APPLICATION;
3787       break;
3788     case GTK_RC_TOKEN_THEME:
3789       *priority = GTK_PATH_PRIO_THEME;
3790       break;
3791     case GTK_RC_TOKEN_RC:
3792       *priority = GTK_PATH_PRIO_RC;
3793       break;
3794     case GTK_RC_TOKEN_HIGHEST:
3795       *priority = GTK_PATH_PRIO_HIGHEST;
3796       break;
3797     default:
3798       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
3799     }
3800   
3801   g_scanner_set_scope (scanner, old_scope);
3802
3803   return G_TOKEN_NONE;
3804 }
3805
3806 /**
3807  * gtk_rc_parse_color:
3808  * @scanner: a #GScanner
3809  * @color: a pointer to a #GdkColor structure in which to store the result
3810  *
3811  * Parses a color in the <link linkend="color=format">format</link> expected
3812  * in a RC file. 
3813  *
3814  * Note that theme engines should use gtk_rc_parse_color_full() in 
3815  * order to support symbolic colors.
3816  *
3817  * Returns: %G_TOKEN_NONE if parsing succeeded, otherwise the token
3818  *     that was expected but not found
3819  */
3820 guint
3821 gtk_rc_parse_color (GScanner *scanner,
3822                     GdkColor *color)
3823 {
3824   return gtk_rc_parse_color_full (scanner, NULL, color);
3825 }
3826
3827 /**
3828  * gtk_rc_parse_color_full:
3829  * @scanner: a #GScanner
3830  * @style: (allow-none): a #GtkRcStyle, or %NULL
3831  * @color: a pointer to a #GdkColor structure in which to store the result
3832  *
3833  * Parses a color in the <link linkend="color=format">format</link> expected
3834  * in a RC file. If @style is not %NULL, it will be consulted to resolve
3835  * references to symbolic colors.
3836  *
3837  * Returns: %G_TOKEN_NONE if parsing succeeded, otherwise the token
3838  *     that was expected but not found
3839  *
3840  * Since: 2.12
3841  */
3842 guint
3843 gtk_rc_parse_color_full (GScanner   *scanner,
3844                          GtkRcStyle *style,
3845                          GdkColor   *color)
3846 {
3847   guint token;
3848
3849   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3850
3851   /* we don't need to set our own scope here, because
3852    * we don't need own symbols
3853    */
3854   
3855   token = g_scanner_get_next_token (scanner);
3856   switch (token)
3857     {
3858       gint token_int;
3859       GdkColor c1, c2;
3860       gboolean negate;
3861       gdouble l;
3862
3863     case G_TOKEN_LEFT_CURLY:
3864       token = g_scanner_get_next_token (scanner);
3865       if (token == G_TOKEN_INT)
3866         token_int = scanner->value.v_int;
3867       else if (token == G_TOKEN_FLOAT)
3868         token_int = scanner->value.v_float * 65535.0;
3869       else
3870         return G_TOKEN_FLOAT;
3871       color->red = CLAMP (token_int, 0, 65535);
3872       
3873       token = g_scanner_get_next_token (scanner);
3874       if (token != G_TOKEN_COMMA)
3875         return G_TOKEN_COMMA;
3876       
3877       token = g_scanner_get_next_token (scanner);
3878       if (token == G_TOKEN_INT)
3879         token_int = scanner->value.v_int;
3880       else if (token == G_TOKEN_FLOAT)
3881         token_int = scanner->value.v_float * 65535.0;
3882       else
3883         return G_TOKEN_FLOAT;
3884       color->green = CLAMP (token_int, 0, 65535);
3885       
3886       token = g_scanner_get_next_token (scanner);
3887       if (token != G_TOKEN_COMMA)
3888         return G_TOKEN_COMMA;
3889       
3890       token = g_scanner_get_next_token (scanner);
3891       if (token == G_TOKEN_INT)
3892         token_int = scanner->value.v_int;
3893       else if (token == G_TOKEN_FLOAT)
3894         token_int = scanner->value.v_float * 65535.0;
3895       else
3896         return G_TOKEN_FLOAT;
3897       color->blue = CLAMP (token_int, 0, 65535);
3898       
3899       token = g_scanner_get_next_token (scanner);
3900       if (token != G_TOKEN_RIGHT_CURLY)
3901         return G_TOKEN_RIGHT_CURLY;
3902       return G_TOKEN_NONE;
3903       
3904     case G_TOKEN_STRING:
3905       if (!gdk_color_parse (scanner->value.v_string, color))
3906         {
3907           g_scanner_warn (scanner, "Invalid color constant '%s'",
3908                           scanner->value.v_string);
3909           return G_TOKEN_STRING;
3910         }
3911       return G_TOKEN_NONE;
3912
3913     case '@':
3914       token = g_scanner_get_next_token (scanner);
3915       if (token != G_TOKEN_IDENTIFIER)
3916         return G_TOKEN_IDENTIFIER;
3917
3918       if (!style || !lookup_color (style, scanner->value.v_identifier, color))
3919         {
3920           g_scanner_warn (scanner, "Invalid symbolic color '%s'",
3921                           scanner->value.v_identifier);
3922           return G_TOKEN_IDENTIFIER;
3923         }
3924
3925       return G_TOKEN_NONE;
3926
3927     case G_TOKEN_IDENTIFIER:
3928       if (strcmp (scanner->value.v_identifier, "mix") == 0)
3929         {
3930           token = g_scanner_get_next_token (scanner);
3931           if (token != G_TOKEN_LEFT_PAREN)
3932             return G_TOKEN_LEFT_PAREN;
3933
3934           negate = FALSE;
3935           if (g_scanner_peek_next_token (scanner) == '-')
3936             {
3937               g_scanner_get_next_token (scanner); /* eat sign */
3938               negate = TRUE;
3939             }
3940
3941           token = g_scanner_get_next_token (scanner);
3942           if (token != G_TOKEN_FLOAT)
3943             return G_TOKEN_FLOAT;
3944
3945           l = negate ? -scanner->value.v_float : scanner->value.v_float;
3946
3947           token = g_scanner_get_next_token (scanner);
3948           if (token != G_TOKEN_COMMA)
3949             return G_TOKEN_COMMA;
3950
3951           token = gtk_rc_parse_color_full (scanner, style, &c1);
3952           if (token != G_TOKEN_NONE)
3953             return token;
3954
3955           token = g_scanner_get_next_token (scanner);
3956           if (token != G_TOKEN_COMMA)
3957             return G_TOKEN_COMMA;
3958
3959           token = gtk_rc_parse_color_full (scanner, style, &c2);
3960           if (token != G_TOKEN_NONE)
3961             return token;
3962
3963           token = g_scanner_get_next_token (scanner);
3964           if (token != G_TOKEN_RIGHT_PAREN)
3965             return G_TOKEN_RIGHT_PAREN;
3966
3967           color->red   = l * c1.red   + (1.0 - l) * c2.red;
3968           color->green = l * c1.green + (1.0 - l) * c2.green;
3969           color->blue  = l * c1.blue  + (1.0 - l) * c2.blue;
3970
3971           return G_TOKEN_NONE;
3972         }
3973       else if (strcmp (scanner->value.v_identifier, "shade") == 0)
3974         {
3975           token = g_scanner_get_next_token (scanner);
3976           if (token != G_TOKEN_LEFT_PAREN)
3977             return G_TOKEN_LEFT_PAREN;
3978
3979           negate = FALSE;
3980           if (g_scanner_peek_next_token (scanner) == '-')
3981             {
3982               g_scanner_get_next_token (scanner); /* eat sign */
3983               negate = TRUE;
3984             }
3985
3986           token = g_scanner_get_next_token (scanner);
3987           if (token != G_TOKEN_FLOAT)
3988             return G_TOKEN_FLOAT;
3989
3990           l = negate ? -scanner->value.v_float : scanner->value.v_float;
3991
3992           token = g_scanner_get_next_token (scanner);
3993           if (token != G_TOKEN_COMMA)
3994             return G_TOKEN_COMMA;
3995
3996           token = gtk_rc_parse_color_full (scanner, style, &c1);
3997           if (token != G_TOKEN_NONE)
3998             return token;
3999
4000           token = g_scanner_get_next_token (scanner);
4001           if (token != G_TOKEN_RIGHT_PAREN)
4002             return G_TOKEN_RIGHT_PAREN;
4003
4004           _gtk_style_shade (&c1, color, l);
4005
4006           return G_TOKEN_NONE;
4007         }
4008       else if (strcmp (scanner->value.v_identifier, "lighter") == 0 ||
4009                strcmp (scanner->value.v_identifier, "darker") == 0)
4010         {
4011           if (scanner->value.v_identifier[0] == 'l')
4012             l = 1.3;
4013           else
4014             l = 0.7;
4015
4016           token = g_scanner_get_next_token (scanner);
4017           if (token != G_TOKEN_LEFT_PAREN)
4018             return G_TOKEN_LEFT_PAREN;
4019
4020           token = gtk_rc_parse_color_full (scanner, style, &c1);
4021           if (token != G_TOKEN_NONE)
4022             return token;
4023
4024           token = g_scanner_get_next_token (scanner);
4025           if (token != G_TOKEN_RIGHT_PAREN)
4026             return G_TOKEN_RIGHT_PAREN;
4027
4028           _gtk_style_shade (&c1, color, l);
4029
4030           return G_TOKEN_NONE;
4031         }
4032       else
4033         return G_TOKEN_IDENTIFIER;
4034
4035     default:
4036       return G_TOKEN_STRING;
4037     }
4038 }
4039
4040 static guint
4041 gtk_rc_parse_pixmap_path (GtkRcContext *context,
4042                           GScanner     *scanner)
4043 {
4044   guint token;
4045   
4046   token = g_scanner_get_next_token (scanner);
4047   if (token != GTK_RC_TOKEN_PIXMAP_PATH)
4048     return GTK_RC_TOKEN_PIXMAP_PATH;
4049   
4050   token = g_scanner_get_next_token (scanner);
4051   if (token != G_TOKEN_STRING)
4052     return G_TOKEN_STRING;
4053   
4054   gtk_rc_parse_pixmap_path_string (context, scanner, scanner->value.v_string);
4055   
4056   return G_TOKEN_NONE;
4057 }
4058
4059 static void
4060 gtk_rc_parse_pixmap_path_string (GtkRcContext *context,
4061                                  GScanner     *scanner,
4062                                  const gchar  *pix_path)
4063 {
4064   g_strfreev (context->pixmap_path);
4065   context->pixmap_path = g_strsplit (pix_path, G_SEARCHPATH_SEPARATOR_S, -1);
4066 }
4067
4068 static guint
4069 gtk_rc_parse_module_path (GScanner *scanner)
4070 {
4071   guint token;
4072   
4073   token = g_scanner_get_next_token (scanner);
4074   if (token != GTK_RC_TOKEN_MODULE_PATH)
4075     return GTK_RC_TOKEN_MODULE_PATH;
4076   
4077   token = g_scanner_get_next_token (scanner);
4078   if (token != G_TOKEN_STRING)
4079     return G_TOKEN_STRING;
4080
4081   g_warning ("module_path directive is now ignored\n");
4082
4083   return G_TOKEN_NONE;
4084 }
4085
4086 static guint
4087 gtk_rc_parse_im_module_file (GScanner *scanner)
4088 {
4089   guint token;
4090   
4091   token = g_scanner_get_next_token (scanner);
4092   if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
4093     return GTK_RC_TOKEN_IM_MODULE_FILE;
4094   
4095   token = g_scanner_get_next_token (scanner);
4096   if (token != G_TOKEN_STRING)
4097     return G_TOKEN_STRING;
4098
4099   g_free (im_module_file);
4100     
4101   im_module_file = g_strdup (scanner->value.v_string);
4102
4103   return G_TOKEN_NONE;
4104 }
4105
4106 static guint
4107 gtk_rc_parse_path_pattern (GtkRcContext *context,
4108                            GScanner     *scanner)
4109 {
4110   guint token;
4111   GtkPathType path_type;
4112   gchar *pattern;
4113   gboolean is_binding;
4114   GtkPathPriorityType priority = context->default_priority;
4115   
4116   token = g_scanner_get_next_token (scanner);
4117   switch (token)
4118     {
4119     case GTK_RC_TOKEN_WIDGET:
4120       path_type = GTK_PATH_WIDGET;
4121       break;
4122     case GTK_RC_TOKEN_WIDGET_CLASS:
4123       path_type = GTK_PATH_WIDGET_CLASS;
4124       break;
4125     case GTK_RC_TOKEN_CLASS:
4126       path_type = GTK_PATH_CLASS;
4127       break;
4128     default:
4129       return GTK_RC_TOKEN_WIDGET_CLASS;
4130     }
4131
4132   token = g_scanner_get_next_token (scanner);
4133   if (token != G_TOKEN_STRING)
4134     return G_TOKEN_STRING;
4135
4136   pattern = g_strdup (scanner->value.v_string);
4137
4138   token = g_scanner_get_next_token (scanner);
4139   if (token == GTK_RC_TOKEN_STYLE)
4140     is_binding = FALSE;
4141   else if (token == GTK_RC_TOKEN_BINDING)
4142     is_binding = TRUE;
4143   else
4144     {
4145       g_free (pattern);
4146       return GTK_RC_TOKEN_STYLE;
4147     }
4148   
4149   if (g_scanner_peek_next_token (scanner) == ':')
4150     {
4151       token = gtk_rc_parse_priority (scanner, &priority);
4152       if (token != G_TOKEN_NONE)
4153         {
4154           g_free (pattern);
4155           return token;
4156         }
4157     }
4158   
4159   token = g_scanner_get_next_token (scanner);
4160   if (token != G_TOKEN_STRING)
4161     {
4162       g_free (pattern);
4163       return G_TOKEN_STRING;
4164     }
4165
4166   if (is_binding)
4167     {
4168       GtkBindingSet *binding;
4169
4170       binding = gtk_binding_set_find (scanner->value.v_string);
4171       if (!binding)
4172         {
4173           g_free (pattern);
4174           return G_TOKEN_STRING;
4175         }
4176       gtk_binding_set_add_path (binding, path_type, pattern, priority);
4177     }
4178   else
4179     {
4180       GtkRcStyle *rc_style;
4181       GtkRcSet *rc_set;
4182
4183       rc_style = gtk_rc_style_find (context, scanner->value.v_string);
4184       
4185       if (!rc_style)
4186         {
4187           g_free (pattern);
4188           return G_TOKEN_STRING;
4189         }
4190
4191       rc_set = g_new (GtkRcSet, 1);
4192       rc_set->type = path_type;
4193       
4194       if (path_type == GTK_PATH_WIDGET_CLASS)
4195         {
4196           rc_set->pspec = NULL;
4197           rc_set->path = _gtk_rc_parse_widget_class_path (pattern);
4198         }
4199       else
4200         {
4201           rc_set->pspec = g_pattern_spec_new (pattern);
4202           rc_set->path = NULL;
4203         }
4204       
4205       rc_set->rc_style = rc_style;
4206       rc_set->priority = priority;
4207
4208       if (path_type == GTK_PATH_WIDGET)
4209         context->rc_sets_widget = g_slist_prepend (context->rc_sets_widget, rc_set);
4210       else if (path_type == GTK_PATH_WIDGET_CLASS)
4211         context->rc_sets_widget_class = g_slist_prepend (context->rc_sets_widget_class, rc_set);
4212       else
4213         context->rc_sets_class = g_slist_prepend (context->rc_sets_class, rc_set);
4214     }
4215
4216   g_free (pattern);
4217   return G_TOKEN_NONE;
4218 }
4219
4220 static guint
4221 gtk_rc_parse_hash_key (GScanner  *scanner,
4222                        gchar    **hash_key)
4223 {
4224   guint token;
4225   
4226   token = g_scanner_get_next_token (scanner);
4227   if (token != G_TOKEN_LEFT_BRACE)
4228     return G_TOKEN_LEFT_BRACE;
4229
4230   token = g_scanner_get_next_token (scanner);
4231   
4232   if (token != G_TOKEN_STRING)
4233     return G_TOKEN_STRING;
4234   
4235   *hash_key = g_strdup (scanner->value.v_string);
4236   
4237   token = g_scanner_get_next_token (scanner);
4238   if (token != G_TOKEN_RIGHT_BRACE)
4239     {
4240       g_free (*hash_key);
4241       return G_TOKEN_RIGHT_BRACE;
4242     }
4243   
4244   return G_TOKEN_NONE;
4245 }
4246
4247 static guint
4248 gtk_rc_parse_icon_source (GtkRcContext   *context,
4249                           GScanner       *scanner,
4250                           GtkIconSet     *icon_set,
4251                           gboolean       *icon_set_valid)
4252 {
4253   guint token;
4254   gchar *full_filename;
4255   GtkIconSource *source = NULL;
4256
4257   token = g_scanner_get_next_token (scanner);
4258   if (token != G_TOKEN_LEFT_CURLY)
4259     return G_TOKEN_LEFT_CURLY;
4260
4261   token = g_scanner_get_next_token (scanner);
4262   
4263   if (token != G_TOKEN_STRING && token != '@')
4264     return G_TOKEN_STRING;
4265   
4266   if (token == G_TOKEN_STRING)
4267     {
4268       /* Filename */
4269
4270       source = gtk_icon_source_new ();      
4271       full_filename = gtk_rc_find_pixmap_in_path (context->settings, scanner, scanner->value.v_string);
4272       if (full_filename)
4273         {
4274           gtk_icon_source_set_filename (source, full_filename);
4275           g_free (full_filename);
4276         }
4277     }
4278   else
4279     {
4280       /* Icon name */
4281       
4282       token = g_scanner_get_next_token (scanner);
4283   
4284       if (token != G_TOKEN_STRING)
4285         return G_TOKEN_STRING;
4286
4287       source = gtk_icon_source_new ();
4288       gtk_icon_source_set_icon_name (source, scanner->value.v_string);
4289     }
4290
4291   /* We continue parsing even if we didn't find the pixmap so that rest of the
4292    * file is read, even if the syntax is bad. However we don't validate the 
4293    * icon_set so the caller can choose not to install it.
4294    */
4295   token = g_scanner_get_next_token (scanner);
4296
4297   if (token == G_TOKEN_RIGHT_CURLY)
4298     goto done;
4299   else if (token != G_TOKEN_COMMA)
4300     {
4301       gtk_icon_source_free (source);
4302       return G_TOKEN_COMMA;
4303     }
4304
4305   /* Get the direction */
4306   
4307   token = g_scanner_get_next_token (scanner);
4308
4309   switch (token)
4310     {
4311     case GTK_RC_TOKEN_RTL:
4312       gtk_icon_source_set_direction_wildcarded (source, FALSE);
4313       gtk_icon_source_set_direction (source, GTK_TEXT_DIR_RTL);
4314       break;
4315
4316     case GTK_RC_TOKEN_LTR:
4317       gtk_icon_source_set_direction_wildcarded (source, FALSE);
4318       gtk_icon_source_set_direction (source, GTK_TEXT_DIR_LTR);
4319       break;
4320       
4321     case '*':
4322       break;
4323       
4324     default:
4325       gtk_icon_source_free (source);
4326       return GTK_RC_TOKEN_RTL;
4327       break;
4328     }
4329
4330   token = g_scanner_get_next_token (scanner);
4331
4332   if (token == G_TOKEN_RIGHT_CURLY)
4333     goto done;
4334   else if (token != G_TOKEN_COMMA)
4335     {
4336       gtk_icon_source_free (source);
4337       return G_TOKEN_COMMA;
4338     }
4339
4340   /* Get the state */
4341   
4342   token = g_scanner_get_next_token (scanner);
4343   
4344   switch (token)
4345     {
4346     case GTK_RC_TOKEN_NORMAL:
4347       gtk_icon_source_set_state_wildcarded (source, FALSE);
4348       gtk_icon_source_set_state (source, GTK_STATE_NORMAL);
4349       break;
4350
4351     case GTK_RC_TOKEN_PRELIGHT:
4352       gtk_icon_source_set_state_wildcarded (source, FALSE);
4353       gtk_icon_source_set_state (source, GTK_STATE_PRELIGHT);
4354       break;
4355       
4356
4357     case GTK_RC_TOKEN_INSENSITIVE:
4358       gtk_icon_source_set_state_wildcarded (source, FALSE);
4359       gtk_icon_source_set_state (source, GTK_STATE_INSENSITIVE);
4360       break;
4361
4362     case GTK_RC_TOKEN_ACTIVE:
4363       gtk_icon_source_set_state_wildcarded (source, FALSE);
4364       gtk_icon_source_set_state (source, GTK_STATE_ACTIVE);
4365       break;
4366
4367     case GTK_RC_TOKEN_SELECTED:
4368       gtk_icon_source_set_state_wildcarded (source, FALSE);
4369       gtk_icon_source_set_state (source, GTK_STATE_SELECTED);
4370       break;
4371
4372     case '*':
4373       break;
4374       
4375     default:
4376       gtk_icon_source_free (source);
4377       return GTK_RC_TOKEN_PRELIGHT;
4378       break;
4379     }  
4380
4381   token = g_scanner_get_next_token (scanner);
4382
4383   if (token == G_TOKEN_RIGHT_CURLY)
4384     goto done;
4385   else if (token != G_TOKEN_COMMA)
4386     {
4387       gtk_icon_source_free (source);
4388       return G_TOKEN_COMMA;
4389     }
4390   
4391   /* Get the size */
4392   
4393   token = g_scanner_get_next_token (scanner);
4394
4395   if (token != '*')
4396     {
4397       GtkIconSize size;
4398       
4399       if (token != G_TOKEN_STRING)
4400         {
4401           gtk_icon_source_free (source);
4402           return G_TOKEN_STRING;
4403         }
4404
4405       size = gtk_icon_size_from_name (scanner->value.v_string);
4406
4407       if (size != GTK_ICON_SIZE_INVALID)
4408         {
4409           gtk_icon_source_set_size_wildcarded (source, FALSE);
4410           gtk_icon_source_set_size (source, size);
4411         }
4412     }
4413
4414   /* Check the close brace */
4415   
4416   token = g_scanner_get_next_token (scanner);
4417   if (token != G_TOKEN_RIGHT_CURLY)
4418     {
4419       gtk_icon_source_free (source);
4420       return G_TOKEN_RIGHT_CURLY;
4421     }
4422
4423  done:
4424   if (gtk_icon_source_get_filename (source) ||
4425       gtk_icon_source_get_icon_name (source))
4426     {
4427       gtk_icon_set_add_source (icon_set, source);
4428       *icon_set_valid = TRUE;
4429     }
4430   gtk_icon_source_free (source);
4431   
4432   return G_TOKEN_NONE;
4433 }
4434
4435 static guint
4436 gtk_rc_parse_stock (GtkRcContext   *context,
4437                     GScanner       *scanner,
4438                     GtkRcStyle     *rc_style,
4439                     GtkIconFactory *factory)
4440 {
4441   GtkIconSet *icon_set = NULL;
4442   gboolean icon_set_valid = FALSE;
4443   gchar *stock_id = NULL;
4444   guint token;
4445   
4446   token = g_scanner_get_next_token (scanner);
4447   if (token != GTK_RC_TOKEN_STOCK)
4448     return GTK_RC_TOKEN_STOCK;
4449   
4450   token = gtk_rc_parse_hash_key (scanner, &stock_id);
4451   if (token != G_TOKEN_NONE)
4452     return token;
4453   
4454   token = g_scanner_get_next_token (scanner);
4455   if (token != G_TOKEN_EQUAL_SIGN)
4456     {
4457       g_free (stock_id);
4458       return G_TOKEN_EQUAL_SIGN;
4459     }
4460
4461   token = g_scanner_get_next_token (scanner);
4462   if (token != G_TOKEN_LEFT_CURLY)
4463     {
4464       g_free (stock_id);
4465       return G_TOKEN_LEFT_CURLY;
4466     }
4467
4468   token = g_scanner_peek_next_token (scanner);
4469   while (token != G_TOKEN_RIGHT_CURLY)
4470     {
4471       if (icon_set == NULL)
4472         icon_set = gtk_icon_set_new ();
4473       
4474       token = gtk_rc_parse_icon_source (context, 
4475                                         scanner, icon_set, &icon_set_valid);
4476       if (token != G_TOKEN_NONE)
4477         {
4478           g_free (stock_id);
4479           gtk_icon_set_unref (icon_set);
4480           return token;
4481         }
4482
4483       token = g_scanner_get_next_token (scanner);
4484       
4485       if (token != G_TOKEN_COMMA &&
4486           token != G_TOKEN_RIGHT_CURLY)
4487         {
4488           g_free (stock_id);
4489           gtk_icon_set_unref (icon_set);
4490           return G_TOKEN_RIGHT_CURLY;
4491         }
4492     }
4493
4494   if (icon_set)
4495     {
4496       if (icon_set_valid)
4497         gtk_icon_factory_add (factory,
4498                               stock_id,
4499                               icon_set);
4500
4501       gtk_icon_set_unref (icon_set);
4502     }
4503   
4504   g_free (stock_id);
4505
4506   return G_TOKEN_NONE;
4507 }
4508
4509 static guint
4510 gtk_rc_parse_logical_color (GScanner   *scanner,
4511                             GtkRcStyle *rc_style,
4512                             GHashTable *hash)
4513 {
4514   gchar *color_id = NULL;
4515   guint token;
4516   GdkColor color;
4517
4518   token = g_scanner_get_next_token (scanner);
4519   if (token != GTK_RC_TOKEN_COLOR)
4520     return GTK_RC_TOKEN_COLOR;
4521
4522   token = gtk_rc_parse_hash_key (scanner, &color_id);
4523   if (token != G_TOKEN_NONE)
4524     return token;
4525
4526   token = g_scanner_get_next_token (scanner);
4527   if (token != G_TOKEN_EQUAL_SIGN)
4528     {
4529       g_free (color_id);
4530       return G_TOKEN_EQUAL_SIGN;
4531     }
4532
4533   token = gtk_rc_parse_color_full (scanner, rc_style, &color);
4534   if (token != G_TOKEN_NONE)
4535     {
4536       g_free (color_id);
4537       return token;
4538     }
4539
4540   /* Because the hash is created with destroy functions,
4541    * g_hash_table_insert will free any old values for us,
4542    * if a mapping with the specified key already exists.
4543    */
4544   g_hash_table_insert (hash, color_id, gdk_color_copy (&color));
4545
4546   return G_TOKEN_NONE;
4547 }
4548
4549
4550 GSList *
4551 _gtk_rc_parse_widget_class_path (const gchar *pattern)
4552 {
4553   GSList *result;
4554   PathElt *path_elt;
4555   const gchar *current;
4556   const gchar *class_start;
4557   const gchar *class_end;
4558   const gchar *pattern_end;
4559   const gchar *pattern_start;
4560   gchar *sub_pattern;
4561
4562   result = NULL;
4563   current = pattern;
4564   while ((class_start = strchr (current, '<')) && 
4565          (class_end = strchr (class_start, '>')))
4566     {
4567       /* Add patterns, but ignore single dots */
4568       if (!(class_start == current || 
4569             (class_start == current + 1 && current[0] == '.')))
4570         {
4571           pattern_end = class_start - 1;
4572           pattern_start = current;
4573           
4574           path_elt = g_new (PathElt, 1);
4575           
4576           sub_pattern = g_strndup (pattern_start, pattern_end - pattern_start + 1);
4577           path_elt->type = PATH_ELT_PSPEC;
4578           path_elt->elt.pspec = g_pattern_spec_new (sub_pattern);
4579           g_free (sub_pattern);
4580           
4581           result = g_slist_prepend (result, path_elt);
4582         }
4583       
4584       path_elt = g_new (PathElt, 1);
4585       
4586       /* The < > need to be removed from the string. */
4587       sub_pattern = g_strndup (class_start + 1, class_end - class_start - 1);
4588       
4589       path_elt->type = PATH_ELT_UNRESOLVED;
4590       path_elt->elt.class_name = sub_pattern;
4591       
4592       result = g_slist_prepend (result, path_elt);
4593       
4594       current = class_end + 1;
4595     }
4596   
4597   /* Add the rest, if anything is left */
4598   if (strlen (current) > 0)
4599     {
4600       path_elt = g_new (PathElt, 1);
4601       path_elt->type = PATH_ELT_PSPEC;
4602       path_elt->elt.pspec = g_pattern_spec_new (current);
4603       
4604       result = g_slist_prepend (result, path_elt);
4605     }
4606   
4607   return g_slist_reverse (result);
4608 }
4609
4610 static void
4611 free_path_elt (gpointer data, 
4612                gpointer user_data)
4613 {
4614   PathElt *path_elt = data;
4615
4616   switch (path_elt->type)
4617     {
4618     case PATH_ELT_PSPEC:
4619       g_pattern_spec_free (path_elt->elt.pspec);
4620       break;
4621     case PATH_ELT_UNRESOLVED:
4622       g_free (path_elt->elt.class_name);
4623       break;
4624     case PATH_ELT_TYPE:
4625       break;
4626     default:
4627       g_assert_not_reached ();
4628     }
4629
4630   g_free (path_elt);
4631 }
4632
4633 void
4634 _gtk_rc_free_widget_class_path (GSList *list)
4635 {
4636   g_slist_foreach (list, free_path_elt, NULL);
4637   g_slist_free (list);
4638 }
4639
4640 static void
4641 gtk_rc_set_free (GtkRcSet *rc_set)
4642 {
4643   if (rc_set->pspec)
4644     g_pattern_spec_free (rc_set->pspec);
4645
4646   _gtk_rc_free_widget_class_path (rc_set->path);
4647   
4648   g_free (rc_set);
4649 }
4650
4651 static gboolean
4652 match_class (PathElt *path_elt, 
4653              gchar   *type_name)
4654 {
4655   GType type;
4656   
4657   if (path_elt->type == PATH_ELT_UNRESOLVED)
4658     {
4659       type = g_type_from_name (path_elt->elt.class_name);
4660       if (type != G_TYPE_INVALID)
4661         {
4662           g_free (path_elt->elt.class_name);
4663           path_elt->elt.class_type = type;
4664           path_elt->type = PATH_ELT_TYPE;
4665         }
4666       else
4667         return g_str_equal (type_name, path_elt->elt.class_name);
4668     }
4669   
4670   return g_type_is_a (g_type_from_name (type_name), path_elt->elt.class_type);
4671 }
4672
4673 static gboolean
4674 match_widget_class_recursive (GSList *list, 
4675                               guint   length, 
4676                               gchar  *path, 
4677                               gchar  *path_reversed)
4678 {
4679   PathElt *path_elt;
4680   
4681   /* break out if we cannot match anymore. */
4682   if (list == NULL)
4683     {
4684       if (length > 0)
4685         return FALSE;
4686       else
4687         return TRUE;
4688     }
4689
4690   /* there are two possibilities:
4691    *  1. The next pattern should match the class.
4692    *  2. First normal matching, and then maybe a class */
4693   
4694   path_elt = list->data;
4695
4696   if (path_elt->type != PATH_ELT_PSPEC)
4697     {
4698       gchar *class_start = path;
4699       gchar *class_end;
4700       
4701       /* ignore leading dot */
4702       if (class_start[0] == '.')
4703         class_start++;
4704       class_end = strchr (class_start, '.');
4705
4706       if (class_end == NULL)
4707         {
4708           if (!match_class (path_elt, class_start))
4709             return FALSE;
4710           else
4711             return match_widget_class_recursive (list->next, 0, "", "");
4712         }
4713       else
4714         {
4715           class_end[0] = '\0';
4716           if (!match_class (path_elt, class_start))
4717             {
4718               class_end[0] = '.';
4719               return FALSE;
4720             }
4721           else
4722             {
4723               gboolean result;
4724               gint new_length = length - (class_end - path);
4725               gchar old_char = path_reversed[new_length];
4726               
4727               class_end[0] = '.';
4728               
4729               path_reversed[new_length] = '\0';
4730               result = match_widget_class_recursive (list->next, new_length, class_end, path_reversed);
4731               path_reversed[new_length] = old_char;
4732               
4733               return result;
4734             }
4735         }
4736     }
4737   else
4738     {
4739       PathElt *class_elt;
4740       gchar *class_start;
4741       gchar *class_end;
4742       gboolean result = FALSE;
4743       
4744       /* If there is nothing after this (ie. no class match), 
4745        * just compare the pspec. 
4746        */
4747       if (list->next == NULL)
4748         return g_pattern_match (path_elt->elt.pspec, length, path, path_reversed);
4749       
4750       class_elt = (PathElt *)list->next->data;
4751       g_assert (class_elt->type != PATH_ELT_PSPEC);
4752       
4753       class_start = path;
4754       if (class_start[0] == '.')
4755         class_start++;
4756       
4757       while (TRUE)
4758         {
4759           class_end = strchr (class_start, '.');
4760           
4761           /* It should be cheaper to match the class first. (either the pattern
4762            * is simple, and will match most of the times, or it may be complex
4763            * and matching is slow) 
4764            */
4765           if (class_end == NULL)
4766             {
4767               result = match_class (class_elt, class_start);
4768             }
4769           else
4770             {
4771               class_end[0] = '\0';
4772               result = match_class (class_elt, class_start);
4773               class_end[0] = '.';
4774             }
4775           
4776           if (result)
4777             {
4778               gchar old_char;
4779               result = FALSE;
4780               
4781               /* terminate the string in front of the class. It does not matter
4782                * that the class becomes unusable, because it is not needed 
4783                * inside the recursion 
4784                */
4785               old_char = class_start[0];
4786               class_start[0] = '\0';
4787               
4788               if (g_pattern_match (path_elt->elt.pspec, class_start - path, path, path_reversed + length - (class_start - path)))
4789                 {
4790                   if (class_end != NULL)
4791                     {
4792                       gint new_length = length - (class_end - path);
4793                       gchar path_reversed_char = path_reversed[new_length];
4794                       
4795                       path_reversed[new_length] = '\0';
4796                       
4797                       result = match_widget_class_recursive (list->next->next, new_length, class_end, path_reversed);
4798                       
4799                       path_reversed[new_length] = path_reversed_char;
4800                     }
4801                   else
4802                     result = match_widget_class_recursive (list->next->next, 0, "", "");
4803                 }
4804                 
4805               class_start[0] = old_char;
4806             }
4807           
4808           if (result)
4809             return TRUE;
4810           
4811           /* get next class in path, or break out */
4812           if (class_end != NULL)
4813             class_start = class_end + 1;
4814           else
4815             return FALSE;
4816         }
4817     }
4818 }
4819
4820 gboolean
4821 _gtk_rc_match_widget_class (GSList  *list,
4822                             gint     length,
4823                             gchar   *path,
4824                             gchar   *path_reversed)
4825 {
4826   return match_widget_class_recursive (list, length, path, path_reversed);
4827 }
4828
4829 #if defined (G_OS_WIN32) && !defined (_WIN64)
4830
4831 /* DLL ABI stability backward compatibility versions */
4832
4833 #undef gtk_rc_add_default_file
4834
4835 void
4836 gtk_rc_add_default_file (const gchar *filename)
4837 {
4838   gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
4839
4840   gtk_rc_add_default_file_utf8 (utf8_filename);
4841
4842   g_free (utf8_filename);
4843 }
4844
4845 #undef gtk_rc_set_default_files
4846
4847 void
4848 gtk_rc_set_default_files (gchar **filenames)
4849 {
4850   gchar **utf8_filenames;
4851   int n = 0, i;
4852
4853   while (filenames[n++] != NULL)
4854     ;
4855
4856   utf8_filenames = g_new (gchar *, n + 1);
4857
4858   for (i = 0; i < n; i++)
4859     utf8_filenames[i] = g_locale_to_utf8 (filenames[i], -1, NULL, NULL, NULL);
4860
4861   utf8_filenames[n] = NULL;
4862
4863   gtk_rc_set_default_files_utf8 (utf8_filenames);
4864
4865   g_strfreev (utf8_filenames);
4866 }
4867
4868 #undef gtk_rc_parse
4869
4870 void
4871 gtk_rc_parse (const gchar *filename)
4872 {
4873   gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
4874
4875   gtk_rc_parse_utf8 (utf8_filename);
4876
4877   g_free (utf8_filename);
4878 }
4879
4880 #endif