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