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