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