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