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