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