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