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