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