]> Pileus Git - ~andy/gtk/blob - gtk/gtkrc.c
Remove deprecation of gtk_window_set_default_size() until patch adding
[~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 #include <ctype.h>
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #include <sys/stat.h>
35 #ifdef HAVE_SYS_PARAM_H
36 #include <sys/param.h>
37 #endif
38 #include <fcntl.h>
39 #include <string.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42
43 #ifndef HAVE_LSTAT
44 #define lstat stat
45 #endif
46
47 #include <glib.h>
48 #include "gdkconfig.h"
49
50 #include "gtkcompat.h"
51 #include "gtkrc.h"
52 #include "gtkbindings.h"
53 #include "gtkthemes.h"
54 #include "gtkintl.h"
55 #include "gtkiconfactory.h"
56 #include "gtksettings.h"
57
58 #ifdef G_OS_WIN32
59 #include <io.h>
60 #endif
61
62 typedef struct _GtkRcSet    GtkRcSet;
63 typedef struct _GtkRcNode   GtkRcNode;
64 typedef struct _GtkRcFile   GtkRcFile;
65
66 struct _GtkRcSet
67 {
68   GPatternSpec *pspec;
69   GtkRcStyle   *rc_style;
70 };
71
72 struct _GtkRcFile
73 {
74   time_t mtime;
75   gchar *name;
76   gchar *canonical_name;
77   gboolean reload;
78 };
79
80 static guint       gtk_rc_style_hash                 (const gchar     *name);
81 static gboolean    gtk_rc_style_equal                (const gchar     *a,
82                                                       const gchar     *b);
83 static guint       gtk_rc_styles_hash                (const GSList    *rc_styles);
84 static gboolean    gtk_rc_styles_equal               (const GSList    *a,
85                                                       const GSList    *b);
86 static GtkRcStyle* gtk_rc_style_find                 (const gchar     *name);
87 static GSList *    gtk_rc_styles_match               (GSList          *rc_styles,
88                                                       GSList          *sets,
89                                                       guint            path_length,
90                                                       const gchar     *path,
91                                                       const gchar     *path_reversed);
92 static GtkStyle *  gtk_rc_style_to_style             (GtkRcStyle      *rc_style);
93 static GtkStyle*   gtk_rc_init_style                 (GSList          *rc_styles);
94 static void        gtk_rc_parse_file                 (const gchar     *filename,
95                                                       gboolean         reload);
96 static void        gtk_rc_parse_any                  (const gchar     *input_name,
97                                                       gint             input_fd,
98                                                       const gchar     *input_string);
99 static guint       gtk_rc_parse_statement            (GScanner        *scanner);
100 static guint       gtk_rc_parse_style                (GScanner        *scanner);
101 static guint       gtk_rc_parse_assignment           (GScanner        *scanner,
102                                                       GtkRcProperty   *prop);
103 static guint       gtk_rc_parse_bg                   (GScanner        *scanner,
104                                                       GtkRcStyle      *style);
105 static guint       gtk_rc_parse_fg                   (GScanner        *scanner,
106                                                       GtkRcStyle      *style);
107 static guint       gtk_rc_parse_text                 (GScanner        *scanner,
108                                                       GtkRcStyle      *style);
109 static guint       gtk_rc_parse_base                 (GScanner        *scanner,
110                                                       GtkRcStyle      *style);
111 static guint       gtk_rc_parse_xthickness           (GScanner        *scanner,
112                                                       GtkRcStyle      *style);
113 static guint       gtk_rc_parse_ythickness           (GScanner        *scanner,
114                                                       GtkRcStyle      *style);
115 static guint       gtk_rc_parse_bg_pixmap            (GScanner        *scanner,
116                                                       GtkRcStyle      *rc_style);
117 static guint       gtk_rc_parse_font                 (GScanner        *scanner,
118                                                       GtkRcStyle      *rc_style);
119 static guint       gtk_rc_parse_fontset              (GScanner        *scanner,
120                                                       GtkRcStyle      *rc_style);
121 static guint       gtk_rc_parse_font_name            (GScanner        *scanner,
122                                                       GtkRcStyle      *rc_style);
123 static guint       gtk_rc_parse_engine               (GScanner        *scanner,
124                                                       GtkRcStyle     **rc_style);
125 static guint       gtk_rc_parse_pixmap_path          (GScanner        *scanner);
126 static void        gtk_rc_parse_pixmap_path_string   (gchar           *pix_path);
127 static guint       gtk_rc_parse_module_path          (GScanner        *scanner);
128 static void        gtk_rc_parse_module_path_string   (gchar           *mod_path);
129 static guint       gtk_rc_parse_im_module_path       (GScanner        *scanner);
130 static guint       gtk_rc_parse_im_module_file       (GScanner        *scanner);
131 static guint       gtk_rc_parse_path_pattern         (GScanner        *scanner);
132 static guint       gtk_rc_parse_stock                (GScanner        *scanner,
133                                                       GtkRcStyle      *rc_style,
134                                                       GtkIconFactory  *factory);
135 static void        gtk_rc_clear_hash_node            (gpointer         key,
136                                                       gpointer         data,
137                                                       gpointer         user_data);
138 static void        gtk_rc_clear_styles               (void);
139 static void        gtk_rc_append_default_module_path (void);
140 static void        gtk_rc_add_initial_default_files  (void);
141
142 static void        gtk_rc_style_init                 (GtkRcStyle      *style);
143 static void        gtk_rc_style_class_init           (GtkRcStyleClass *klass);
144 static void        gtk_rc_style_finalize             (GObject         *object);
145 static void        gtk_rc_style_real_merge           (GtkRcStyle      *dest,
146                                                       GtkRcStyle      *src);
147 static GtkRcStyle* gtk_rc_style_real_create_rc_style (GtkRcStyle      *rc_style);
148 static GtkStyle*   gtk_rc_style_real_create_style    (GtkRcStyle      *rc_style);
149 static gint        gtk_rc_properties_cmp             (gconstpointer    bsearch_node1,
150                                                       gconstpointer    bsearch_node2);
151
152 static gpointer parent_class = NULL;
153
154 static const GScannerConfig gtk_rc_scanner_config =
155 {
156   (
157    " \t\r\n"
158    )                    /* cset_skip_characters */,
159   (
160    G_CSET_a_2_z
161    "_"
162    G_CSET_A_2_Z
163    )                    /* cset_identifier_first */,
164   (
165    G_CSET_a_2_z
166    "_-0123456789"
167    G_CSET_A_2_Z
168    )                    /* cset_identifier_nth */,
169   ( "#\n" )             /* cpair_comment_single */,
170   
171   TRUE                  /* case_sensitive */,
172   
173   TRUE                  /* skip_comment_multi */,
174   TRUE                  /* skip_comment_single */,
175   TRUE                  /* scan_comment_multi */,
176   TRUE                  /* scan_identifier */,
177   FALSE                 /* scan_identifier_1char */,
178   FALSE                 /* scan_identifier_NULL */,
179   TRUE                  /* scan_symbols */,
180   TRUE                  /* scan_binary */,
181   TRUE                  /* scan_octal */,
182   TRUE                  /* scan_float */,
183   TRUE                  /* scan_hex */,
184   TRUE                  /* scan_hex_dollar */,
185   TRUE                  /* scan_string_sq */,
186   TRUE                  /* scan_string_dq */,
187   TRUE                  /* numbers_2_int */,
188   FALSE                 /* int_2_float */,
189   FALSE                 /* identifier_2_string */,
190   TRUE                  /* char_2_token */,
191   TRUE                  /* symbol_2_token */,
192   FALSE                 /* scope_0_fallback */,
193 };
194
195 static const struct
196 {
197   gchar *name;
198   guint token;
199 } symbols[] = {
200   { "include", GTK_RC_TOKEN_INCLUDE },
201   { "NORMAL", GTK_RC_TOKEN_NORMAL },
202   { "ACTIVE", GTK_RC_TOKEN_ACTIVE },
203   { "PRELIGHT", GTK_RC_TOKEN_PRELIGHT },
204   { "SELECTED", GTK_RC_TOKEN_SELECTED },
205   { "INSENSITIVE", GTK_RC_TOKEN_INSENSITIVE },
206   { "fg", GTK_RC_TOKEN_FG },
207   { "bg", GTK_RC_TOKEN_BG },
208   { "text", GTK_RC_TOKEN_TEXT },
209   { "base", GTK_RC_TOKEN_BASE },
210   { "xthickness", GTK_RC_TOKEN_XTHICKNESS },
211   { "ythickness", GTK_RC_TOKEN_YTHICKNESS },
212   { "font", GTK_RC_TOKEN_FONT },
213   { "fontset", GTK_RC_TOKEN_FONTSET },
214   { "font_name", GTK_RC_TOKEN_FONT_NAME },
215   { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP },
216   { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH },
217   { "style", GTK_RC_TOKEN_STYLE },
218   { "binding", GTK_RC_TOKEN_BINDING },
219   { "bind", GTK_RC_TOKEN_BIND },
220   { "widget", GTK_RC_TOKEN_WIDGET },
221   { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS },
222   { "class", GTK_RC_TOKEN_CLASS },
223   { "lowest", GTK_RC_TOKEN_LOWEST },
224   { "gtk", GTK_RC_TOKEN_GTK },
225   { "application", GTK_RC_TOKEN_APPLICATION },
226   { "rc", GTK_RC_TOKEN_RC },
227   { "highest", GTK_RC_TOKEN_HIGHEST },
228   { "engine", GTK_RC_TOKEN_ENGINE },
229   { "module_path", GTK_RC_TOKEN_MODULE_PATH },
230   { "stock", GTK_RC_TOKEN_STOCK },
231   { "im_module_path", GTK_RC_TOKEN_IM_MODULE_PATH },
232   { "im_module_file", GTK_RC_TOKEN_IM_MODULE_FILE },
233   { "LTR", GTK_RC_TOKEN_LTR },
234   { "RTL", GTK_RC_TOKEN_RTL }
235 };
236
237 static const guint n_symbols = sizeof (symbols) / sizeof (symbols[0]);
238
239 static gchar *im_module_path = NULL;
240 static gchar *im_module_file = NULL;
241
242 static GHashTable *rc_style_ht = NULL;
243 static GHashTable *realized_style_ht = NULL;
244 static GSList *gtk_rc_sets_widget = NULL;
245 static GSList *gtk_rc_sets_widget_class = NULL;
246 static GSList *gtk_rc_sets_class = NULL;
247
248 #define GTK_RC_MAX_DEFAULT_FILES 128
249 static gchar *gtk_rc_default_files[GTK_RC_MAX_DEFAULT_FILES];
250 static gboolean gtk_rc_auto_parse = TRUE;
251
252 #define GTK_RC_MAX_PIXMAP_PATHS 128
253 static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
254 #define GTK_RC_MAX_MODULE_PATHS 128
255 static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
256
257 /* A stack of directories for RC files we are parsing currently.
258  * these are implicitely added to the end of PIXMAP_PATHS
259  */
260 GSList *rc_dir_stack = NULL;
261
262 /* The files we have parsed, to reread later if necessary */
263 GSList *rc_files = NULL;
264
265 static GtkImageLoader image_loader = NULL;
266
267 /* RC file handling */
268
269
270 #ifdef G_OS_WIN32
271 static gchar *
272 get_gtk_dll_name (void)
273 {
274   static gchar *gtk_dll = NULL;
275
276   if (!gtk_dll)
277     gtk_dll = g_strdup_printf ("gtk-%d.%d.dll", GTK_MAJOR_VERSION, GTK_MINOR_VERSION);
278
279   return gtk_dll;
280 }
281
282 static gchar *
283 get_themes_directory (void)
284 {
285   return g_win32_get_package_installation_subdirectory (GETTEXT_PACKAGE,
286                                                         get_gtk_dll_name (),
287                                                         "themes");
288 }
289 #endif /* G_OS_WIN32 */
290  
291 static gchar *
292 gtk_rc_make_default_dir (const gchar *type)
293 {
294   gchar *var, *path;
295
296 #ifndef G_OS_WIN32
297   var = getenv("GTK_EXE_PREFIX");
298   if (var)
299     path = g_strconcat (var, "/lib/gtk-2.0/" GTK_VERSION "/", type, NULL);
300   else
301     path = g_strconcat (GTK_LIBDIR "/gtk-2.0/" GTK_VERSION "/", type, NULL);
302 #else
303   path = g_strconcat ("%s\\%s", get_themes_directory (), type);
304 #endif
305
306   return path;
307 }
308
309 gchar *
310 gtk_rc_get_im_module_path (void)
311 {
312   const gchar *result = g_getenv ("GTK_IM_MODULE_PATH");
313
314   if (!result)
315     {
316       if (im_module_path)
317         result = im_module_path;
318       else
319         return gtk_rc_make_default_dir ("immodules");
320     }
321
322   return g_strdup (result);
323 }
324
325 gchar *
326 gtk_rc_get_im_module_file (void)
327 {
328   gchar *result = g_strdup (g_getenv ("GTK_IM_MODULE_FILE"));
329
330   if (!result)
331     {
332       if (im_module_file)
333         result = g_strdup (im_module_file);
334       else
335 #ifndef G_OS_WIN32
336         result = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk-2.0" G_DIR_SEPARATOR_S "gtk.immodules");
337 #else
338         result = g_strdup_printf ("%s\\gtk.immodules", g_win32_get_package_installation_directory (GETTEXT_PACKAGE, get_gtk_dll_name ()));
339 #endif
340     }
341
342   return result;
343 }
344
345 gchar *
346 gtk_rc_get_theme_dir(void)
347 {
348   gchar *var, *path;
349
350 #ifndef G_OS_WIN32
351   var = getenv("GTK_DATA_PREFIX");
352   if (var)
353     path = g_strconcat (var, "/share/themes", NULL);
354   else
355     path = g_strconcat (GTK_DATA_PREFIX, "/share/themes", NULL);
356 #else
357   path = g_strdup (get_themes_directory ());
358 #endif
359
360   return path;
361 }
362
363 gchar *
364 gtk_rc_get_module_dir(void)
365 {
366   return gtk_rc_make_default_dir ("engines");
367 }
368
369 static void
370 gtk_rc_append_default_module_path(void)
371 {
372   const gchar *var;
373   gchar *path;
374   gint n;
375
376   for (n = 0; module_path[n]; n++) ;
377   if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
378     return;
379   
380 #ifndef G_OS_WIN32
381   var = getenv("GTK_EXE_PREFIX");
382   if (var)
383     path = g_strconcat(var, "/lib/gtk-2.0/" GTK_VERSION "/engines", NULL);
384   else
385     path = g_strdup (GTK_LIBDIR "/gtk-2.0/" GTK_VERSION "/engines");
386 #else
387   path = g_strconcat (get_themes_directory (), "\\engines", NULL);
388 #endif
389   module_path[n++] = path;
390
391   var = g_get_home_dir ();
392   if (var)
393     {
394       gchar *sep;
395       /* Don't duplicate the directory separator, causes trouble at
396        * least on Windows.
397        */
398       if (var[strlen (var) -1] != G_DIR_SEPARATOR)
399         sep = G_DIR_SEPARATOR_S;
400       else
401         sep = "";
402       /* This produces something like ~/.gtk-2.0/2.0/engines */
403       path = g_strconcat (var, sep,
404                           ".gtk-2.0" G_DIR_SEPARATOR_S
405                           GTK_VERSION G_DIR_SEPARATOR_S
406                           "engines", NULL);
407       module_path[n++] = path;
408     }
409   module_path[n] = NULL;
410 }
411
412 static void
413 gtk_rc_add_initial_default_files (void)
414 {
415   static gint init = FALSE;
416   const gchar *var;
417   gchar *str;
418   gchar **files;
419   gint i;
420
421   if (init)
422     return;
423   
424   gtk_rc_default_files[0] = NULL;
425   init = TRUE;
426
427   var = g_getenv("GTK_RC_FILES");
428   if (var)
429     {
430       files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
431       i=0;
432       while (files[i])
433         {
434           gtk_rc_add_default_file (files[i]);
435           i++;
436         }
437       g_strfreev (files);
438     }
439   else
440     {
441 #ifndef G_OS_WIN32
442       str = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk-2.0" G_DIR_SEPARATOR_S "gtkrc");
443 #else
444       str = g_strdup_printf ("%s\\gtkrc", g_win32_get_package_installation_directory (GETTEXT_PACKAGE, get_gtk_dll_name ()));
445 #endif
446
447       gtk_rc_add_default_file (str);
448       g_free (str);
449
450       var = g_get_home_dir ();
451       if (var)
452         {
453           gchar *sep;
454           if (var[strlen (var) -1] != G_DIR_SEPARATOR)
455             sep = G_DIR_SEPARATOR_S;
456           else
457             sep = "";
458           str = g_strdup_printf ("%s%s.gtkrc-2.0", var, sep);
459           gtk_rc_add_default_file (str);
460           g_free (str);
461         }
462     }
463 }
464
465 void
466 gtk_rc_add_default_file (const gchar *file)
467 {
468   guint n;
469   
470   gtk_rc_add_initial_default_files ();
471
472   for (n = 0; gtk_rc_default_files[n]; n++) ;
473   if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
474     return;
475   
476   gtk_rc_default_files[n++] = g_strdup (file);
477   gtk_rc_default_files[n] = NULL;
478 }
479
480 void
481 gtk_rc_set_default_files (gchar **files)
482 {
483   gint i;
484
485   gtk_rc_add_initial_default_files ();
486
487   i = 0;
488   while (gtk_rc_default_files[i])
489     {
490       g_free (gtk_rc_default_files[i]);
491       i++;
492     }
493     
494   gtk_rc_default_files[0] = NULL;
495   gtk_rc_auto_parse = FALSE;
496
497   i = 0;
498   while (files[i] != NULL)
499     {
500       gtk_rc_add_default_file (files[i]);
501       i++;
502     }
503 }
504
505 gchar **
506 gtk_rc_get_default_files (void)
507 {
508   gtk_rc_add_initial_default_files ();
509
510   return gtk_rc_default_files;
511 }
512
513  /* The following routine is based on _nl_normalize_codeset from
514   * the GNU C library. Contributed by
515   *
516   * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
517   * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
518   * 
519   * Normalize codeset name.  There is no standard for the codeset
520   * names.  Normalization allows the user to use any of the common
521   * names.
522   */
523  static gchar *
524  _gtk_normalize_codeset (const gchar *codeset, gint name_len)
525  {
526    gint len = 0;
527    gint only_digit = 1;
528    gchar *retval;
529    gchar *wp;
530    gint cnt;
531  
532    for (cnt = 0; cnt < name_len; ++cnt)
533      if (isalnum (codeset[cnt]))
534        {
535         ++len;
536  
537         if (isalpha (codeset[cnt]))
538           only_digit = 0;
539        }
540  
541    retval = g_malloc ((only_digit ? 3 : 0) + len + 1);
542  
543    if (only_digit)
544      {
545        memcpy (retval, "iso", 4);
546        wp = retval + 3;
547      }
548    else
549      wp = retval;
550    
551    for (cnt = 0; cnt < name_len; ++cnt)
552      if (isalpha (codeset[cnt]))
553        *wp++ = isupper(codeset[cnt]) ? tolower (codeset[cnt]) : codeset[cnt];
554      else if (isdigit (codeset[cnt]))
555        *wp++ = codeset[cnt];
556    
557    *wp = '\0';
558  
559    return retval;
560  }
561  
562 void
563 gtk_rc_init (void)
564 {
565   static gboolean initialized = FALSE;
566   static gchar *locale_suffixes[3];
567   static gint n_locale_suffixes = 0;
568   gint i, j;
569
570
571   if (!initialized)
572     {
573       gint length;
574       gchar *locale;
575       gchar *p;
576
577 #ifdef G_OS_WIN32      
578       locale = g_win32_getlocale ();
579 #else      
580       locale = setlocale (LC_CTYPE, NULL);
581 #endif      
582       initialized = TRUE;
583
584       pixmap_path[0] = NULL;
585       module_path[0] = NULL;
586       gtk_rc_append_default_module_path();
587       
588       gtk_rc_add_initial_default_files ();
589
590       if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
591         {
592           /* Determine locale-specific suffixes for RC files
593            *
594            * We normalize the charset into a standard form,
595            * which has all '-' and '_' characters removed,
596            * and is lowercase.
597            */
598           gchar *normalized_locale;
599
600           p = strchr (locale, '@');
601           length = p ? (p -locale) : strlen (locale);
602
603           p = strchr (locale, '.');
604           if (p)
605             {
606               gchar *tmp1 = g_strndup (locale, p - locale + 1);
607               gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
608               
609               normalized_locale = g_strconcat (tmp1, tmp2, NULL);
610               g_free (tmp1);
611               g_free (tmp2);
612                                                  
613               locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
614               length = p - locale;
615             }
616           else
617             normalized_locale = g_strndup (locale, length);
618           
619           p = strchr (normalized_locale, '_');
620           if (p)
621             {
622               locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
623               length = p - normalized_locale;
624             }
625           
626           locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
627
628           g_free (normalized_locale);
629         }
630     }
631   
632   g_object_freeze_notify (G_OBJECT (gtk_settings_get_global ()));
633   for (i = 0; gtk_rc_default_files[i] != NULL; i++)
634     {
635       /* Try to find a locale specific RC file corresponding to the
636        * current locale to parse before the default file.
637        */
638       for (j = n_locale_suffixes - 1; j >= 0; j--)
639         {
640           gchar *name = g_strconcat (gtk_rc_default_files[i],
641                                      ".",
642                                      locale_suffixes[j],
643                                      NULL);
644           gtk_rc_parse (name);
645           g_free (name);
646         }
647       gtk_rc_parse (gtk_rc_default_files[i]);
648     }
649   g_object_thaw_notify (G_OBJECT (gtk_settings_get_global ()));
650 }
651
652 void
653 gtk_rc_parse_string (const gchar *rc_string)
654 {
655   g_return_if_fail (rc_string != NULL);
656
657   gtk_rc_parse_any ("-", -1, rc_string);
658 }
659
660 static void
661 gtk_rc_parse_file (const gchar *filename, gboolean reload)
662 {
663   GtkRcFile *rc_file = NULL;
664   struct stat statbuf;
665   GSList *tmp_list;
666
667   g_return_if_fail (filename != NULL);
668
669   tmp_list = rc_files;
670   while (tmp_list)
671     {
672       rc_file = tmp_list->data;
673       if (!strcmp (rc_file->name, filename))
674         break;
675       
676       tmp_list = tmp_list->next;
677     }
678
679   if (!tmp_list)
680     {
681       rc_file = g_new (GtkRcFile, 1);
682       rc_file->name = g_strdup (filename);
683       rc_file->canonical_name = NULL;
684       rc_file->mtime = 0;
685       rc_file->reload = reload;
686
687       rc_files = g_slist_append (rc_files, rc_file);
688     }
689
690   if (!rc_file->canonical_name)
691     {
692       /* Get the absolute pathname */
693
694       if (g_path_is_absolute (rc_file->name))
695         rc_file->canonical_name = rc_file->name;
696       else
697         {
698           GString *str;
699           gchar *cwd;
700
701           cwd = g_get_current_dir ();
702
703           str = g_string_new (cwd);
704           g_free (cwd);
705           g_string_append_c (str, G_DIR_SEPARATOR);
706           g_string_append (str, rc_file->name);
707           
708           rc_file->canonical_name = str->str;
709           g_string_free (str, FALSE);
710         }
711     }
712
713   if (!lstat (rc_file->canonical_name, &statbuf))
714     {
715       gint fd;
716       GSList *tmp_list;
717
718       rc_file->mtime = statbuf.st_mtime;
719
720       fd = open (rc_file->canonical_name, O_RDONLY);
721       if (fd < 0)
722         return;
723
724       /* Temporarily push directory name for this file on
725        * a stack of directory names while parsing it
726        */
727       rc_dir_stack = 
728         g_slist_prepend (rc_dir_stack,
729                          g_path_get_dirname (rc_file->canonical_name));
730       gtk_rc_parse_any (filename, fd, NULL);
731  
732       tmp_list = rc_dir_stack;
733       rc_dir_stack = rc_dir_stack->next;
734  
735       g_free (tmp_list->data);
736       g_slist_free_1 (tmp_list);
737
738       close (fd);
739     }
740 }
741
742 void
743 gtk_rc_parse (const gchar *filename)
744 {
745   g_return_if_fail (filename != NULL);
746
747   gtk_rc_parse_file (filename, TRUE);
748 }
749
750 /* Handling of RC styles */
751
752 GType
753 gtk_rc_style_get_type (void)
754 {
755   static GType object_type = 0;
756
757   if (!object_type)
758     {
759       static const GTypeInfo object_info =
760       {
761         sizeof (GtkRcStyleClass),
762         (GBaseInitFunc) NULL,
763         (GBaseFinalizeFunc) NULL,
764         (GClassInitFunc) gtk_rc_style_class_init,
765         NULL,           /* class_finalize */
766         NULL,           /* class_data */
767         sizeof (GtkRcStyle),
768         0,              /* n_preallocs */
769         (GInstanceInitFunc) gtk_rc_style_init,
770       };
771       
772       object_type = g_type_register_static (G_TYPE_OBJECT,
773                                             "GtkRcStyle",
774                                             &object_info, 0);
775     }
776   
777   return object_type;
778 }
779
780 static void
781 gtk_rc_style_init (GtkRcStyle *style)
782 {
783   guint i;
784
785   style->name = NULL;
786   style->font_desc = NULL;
787
788   for (i = 0; i < 5; i++)
789     {
790       static const GdkColor init_color = { 0, 0, 0, 0, };
791
792       style->bg_pixmap_name[i] = NULL;
793       style->color_flags[i] = 0;
794       style->fg[i] = init_color;
795       style->bg[i] = init_color;
796       style->text[i] = init_color;
797       style->base[i] = init_color;
798     }
799   style->xthickness = -1;
800   style->ythickness = -1;
801   style->rc_properties = NULL;
802
803   style->rc_style_lists = NULL;
804   style->icon_factories = NULL;
805 }
806
807 static void
808 gtk_rc_style_class_init (GtkRcStyleClass *klass)
809 {
810   GObjectClass *object_class = G_OBJECT_CLASS (klass);
811   
812   parent_class = g_type_class_peek_parent (klass);
813
814   object_class->finalize = gtk_rc_style_finalize;
815
816   klass->parse = NULL;
817   klass->create_rc_style = gtk_rc_style_real_create_rc_style;
818   klass->merge = gtk_rc_style_real_merge;
819   klass->create_style = gtk_rc_style_real_create_style;
820 }
821
822 static void
823 gtk_rc_style_finalize (GObject *object)
824 {
825   GSList *tmp_list1, *tmp_list2;
826   GtkRcStyle *rc_style;
827   gint i;
828
829   rc_style = GTK_RC_STYLE (object);
830   
831   if (rc_style->name)
832     g_free (rc_style->name);
833   if (rc_style->font_desc)
834     pango_font_description_free (rc_style->font_desc);
835       
836   for (i = 0; i < 5; i++)
837     if (rc_style->bg_pixmap_name[i])
838       g_free (rc_style->bg_pixmap_name[i]);
839   
840   /* Now remove all references to this rc_style from
841    * realized_style_ht
842    */
843   tmp_list1 = rc_style->rc_style_lists;
844   while (tmp_list1)
845     {
846       GSList *rc_styles = tmp_list1->data;
847       GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
848       gtk_style_unref (style);
849
850       /* Remove the list of styles from the other rc_styles
851        * in the list
852        */
853       tmp_list2 = rc_styles;
854       while (tmp_list2)
855         {
856           GtkRcStyle *other_style = tmp_list2->data;
857
858           if (other_style != rc_style)
859             other_style->rc_style_lists = g_slist_remove_all (other_style->rc_style_lists,
860                                                               rc_styles);
861           tmp_list2 = tmp_list2->next;
862         }
863
864       /* And from the hash table itself
865        */
866       g_hash_table_remove (realized_style_ht, rc_styles);
867       g_slist_free (rc_styles);
868
869       tmp_list1 = tmp_list1->next;
870     }
871   g_slist_free (rc_style->rc_style_lists);
872
873   if (rc_style->rc_properties)
874     {
875       guint i;
876
877       for (i = 0; i < rc_style->rc_properties->n_nodes; i++)
878         {
879           GtkRcProperty *node = g_bsearch_array_get_nth (rc_style->rc_properties, i);
880
881           g_free (node->origin);
882           g_value_unset (&node->value);
883         }
884       g_bsearch_array_destroy (rc_style->rc_properties);
885       rc_style->rc_properties = NULL;
886     }
887
888   tmp_list1 = rc_style->icon_factories;
889   while (tmp_list1)
890     {
891       g_object_unref (G_OBJECT (tmp_list1->data));
892
893       tmp_list1 = tmp_list1->next;
894     }
895   g_slist_free (rc_style->icon_factories);
896   
897   G_OBJECT_CLASS (parent_class)->finalize (object);
898 }
899
900 GtkRcStyle *
901 gtk_rc_style_new (void)
902 {
903   GtkRcStyle *style;
904   
905   style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
906   
907   return style;
908 }
909
910 /**
911  * gtk_rc_style_copy:
912  * @orig: the style to copy
913  * 
914  * Make a copy of the specified #GtkRcStyle. This function
915  * will correctly copy an rc style that is a member of a class
916  * derived from #GtkRcStyle.
917  * 
918  * Return value: the resulting #GtkRcStyle
919  **/
920 GtkRcStyle *
921 gtk_rc_style_copy (GtkRcStyle *orig)
922 {
923   GtkRcStyle *style;
924
925   g_return_val_if_fail (GTK_IS_RC_STYLE (orig), NULL);
926   
927   style = GTK_RC_STYLE_GET_CLASS (orig)->create_rc_style (orig);
928   GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
929
930   return style;
931 }
932
933 void      
934 gtk_rc_style_ref (GtkRcStyle  *rc_style)
935 {
936   g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
937
938   g_object_ref (G_OBJECT (rc_style));
939 }
940
941 void      
942 gtk_rc_style_unref (GtkRcStyle  *rc_style)
943 {
944   g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
945
946   g_object_unref (G_OBJECT (rc_style));
947 }
948
949 static GtkRcStyle *
950 gtk_rc_style_real_create_rc_style (GtkRcStyle *style)
951 {
952   return GTK_RC_STYLE (g_object_new (G_OBJECT_TYPE (style), NULL));
953 }
954
955 static gint
956 gtk_rc_properties_cmp (gconstpointer bsearch_node1,
957                        gconstpointer bsearch_node2)
958 {
959   const GtkRcProperty *prop1 = bsearch_node1;
960   const GtkRcProperty *prop2 = bsearch_node2;
961   gint cmp;
962
963   cmp = G_BSEARCH_ARRAY_CMP (prop1->type_name, prop2->type_name);
964   if (cmp == 0)
965     cmp = G_BSEARCH_ARRAY_CMP (prop1->property_name, prop2->property_name);
966
967   return cmp;
968 }
969
970 static void
971 gtk_rc_style_real_merge (GtkRcStyle *dest,
972                          GtkRcStyle *src)
973 {
974   gint i;
975   
976   for (i = 0; i < 5; i++)
977     {
978       if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
979         dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
980       
981       if (!(dest->color_flags[i] & GTK_RC_FG) && 
982           src->color_flags[i] & GTK_RC_FG)
983         {
984           dest->fg[i] = src->fg[i];
985           dest->color_flags[i] |= GTK_RC_FG;
986         }
987       if (!(dest->color_flags[i] & GTK_RC_BG) && 
988           src->color_flags[i] & GTK_RC_BG)
989         {
990           dest->bg[i] = src->bg[i];
991           dest->color_flags[i] |= GTK_RC_BG;
992         }
993       if (!(dest->color_flags[i] & GTK_RC_TEXT) && 
994           src->color_flags[i] & GTK_RC_TEXT)
995         {
996           dest->text[i] = src->text[i];
997           dest->color_flags[i] |= GTK_RC_TEXT;
998         }
999       if (!(dest->color_flags[i] & GTK_RC_BASE) && 
1000           src->color_flags[i] & GTK_RC_BASE)
1001         {
1002           dest->base[i] = src->base[i];
1003           dest->color_flags[i] |= GTK_RC_BASE;
1004         }
1005     }
1006
1007   if (dest->xthickness < 0 && src->xthickness >= 0)
1008     dest->xthickness = src->xthickness;
1009   if (dest->ythickness < 0 && src->ythickness >= 0)
1010     dest->ythickness = src->ythickness;
1011
1012   if (!dest->font_desc && src->font_desc)
1013     dest->font_desc = pango_font_description_copy (src->font_desc);
1014
1015   if (src->rc_properties)
1016     {
1017       guint i;
1018
1019       if (!dest->rc_properties)
1020         dest->rc_properties = g_bsearch_array_new (sizeof (GtkRcProperty),
1021                                                    gtk_rc_properties_cmp,
1022                                                    0);
1023       for (i = 0; i < src->rc_properties->n_nodes; i++)
1024         {
1025           GtkRcProperty *node = g_bsearch_array_get_nth (src->rc_properties, i);
1026           GtkRcProperty *prop, key = { 0, 0, NULL, { 0, }, };
1027
1028           key.type_name = node->type_name;
1029           key.property_name = node->property_name;
1030           prop = g_bsearch_array_insert (dest->rc_properties, &key, FALSE);
1031           if (!prop->origin)
1032             {
1033               prop->origin = g_strdup (node->origin);
1034               g_value_init (&prop->value, G_VALUE_TYPE (&node->value));
1035               g_value_copy (&node->value, &prop->value);
1036             }
1037         }
1038     }
1039 }
1040
1041 static GtkStyle *
1042 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
1043 {
1044   return gtk_style_new ();
1045 }
1046
1047 static void
1048 gtk_rc_clear_hash_node (gpointer key, 
1049                         gpointer data, 
1050                         gpointer user_data)
1051 {
1052   gtk_rc_style_unref (data);
1053 }
1054
1055 static void
1056 gtk_rc_free_rc_sets (GSList *slist)
1057 {
1058   while (slist)
1059     {
1060       GtkRcSet *rc_set;
1061
1062       rc_set = slist->data;
1063       g_pattern_spec_free (rc_set->pspec);
1064       g_free (rc_set);
1065
1066       slist = slist->next;
1067     }
1068 }
1069
1070 static void
1071 gtk_rc_clear_styles (void)
1072 {
1073   /* Clear out all old rc_styles */
1074
1075   if (rc_style_ht)
1076     {
1077       g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
1078       g_hash_table_destroy (rc_style_ht);
1079       rc_style_ht = NULL;
1080     }
1081
1082   gtk_rc_free_rc_sets (gtk_rc_sets_widget);
1083   g_slist_free (gtk_rc_sets_widget);
1084   gtk_rc_sets_widget = NULL;
1085
1086   gtk_rc_free_rc_sets (gtk_rc_sets_widget_class);
1087   g_slist_free (gtk_rc_sets_widget_class);
1088   gtk_rc_sets_widget_class = NULL;
1089
1090   gtk_rc_free_rc_sets (gtk_rc_sets_class);
1091   g_slist_free (gtk_rc_sets_class);
1092   gtk_rc_sets_class = NULL;
1093 }
1094
1095 gboolean
1096 gtk_rc_reparse_all (void)
1097 {
1098   GSList *tmp_list;
1099   gboolean mtime_modified = FALSE;
1100   GtkRcFile *rc_file;
1101
1102   struct stat statbuf;
1103
1104   /* Check through and see if any of the RC's have had their
1105    * mtime modified. If so, reparse everything.
1106    */
1107   tmp_list = rc_files;
1108   while (tmp_list)
1109     {
1110       rc_file = tmp_list->data;
1111       
1112       if (!lstat (rc_file->name, &statbuf) && 
1113           (statbuf.st_mtime > rc_file->mtime))
1114         {
1115           mtime_modified = TRUE;
1116           break;
1117         }
1118       
1119       tmp_list = tmp_list->next;
1120     }
1121
1122   if (mtime_modified)
1123     {
1124       gtk_rc_clear_styles();
1125
1126       tmp_list = rc_files;
1127       while (tmp_list)
1128         {
1129           rc_file = tmp_list->data;
1130           if (rc_file->reload)
1131             gtk_rc_parse_file (rc_file->name, FALSE);
1132           
1133           tmp_list = tmp_list->next;
1134         }
1135     }
1136
1137   return mtime_modified;
1138 }
1139
1140 static GSList *
1141 gtk_rc_styles_match (GSList       *rc_styles,
1142                      GSList       *sets,
1143                      guint         path_length,
1144                      const gchar  *path,
1145                      const gchar  *path_reversed)
1146                      
1147 {
1148   GtkRcSet *rc_set;
1149
1150   while (sets)
1151     {
1152       rc_set = sets->data;
1153       sets = sets->next;
1154
1155       if (g_pattern_match (rc_set->pspec, path_length, path, path_reversed))
1156         rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
1157     }
1158   
1159   return rc_styles;
1160 }
1161
1162 GtkStyle *
1163 gtk_rc_get_style (GtkWidget *widget)
1164 {
1165   GtkRcStyle *widget_rc_style;
1166   GSList *rc_styles = NULL;
1167
1168   static guint rc_style_key_id = 0;
1169
1170   /* We allow the specification of a single rc style to be bound
1171    * tightly to a widget, for application modifications
1172    */
1173   if (!rc_style_key_id)
1174     rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1175
1176   widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
1177                                                rc_style_key_id);
1178
1179   if (widget_rc_style)
1180     rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
1181   
1182   if (gtk_rc_sets_widget)
1183     {
1184       gchar *path, *path_reversed;
1185       guint path_length;
1186
1187       gtk_widget_path (widget, &path_length, &path, &path_reversed);
1188       rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget, path_length, path, path_reversed);
1189       g_free (path);
1190       g_free (path_reversed);
1191       
1192     }
1193   
1194   if (gtk_rc_sets_widget_class)
1195     {
1196       gchar *path, *path_reversed;
1197       guint path_length;
1198
1199       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1200       rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget_class, path_length, path, path_reversed);
1201       g_free (path);
1202       g_free (path_reversed);
1203     }
1204
1205   if (gtk_rc_sets_class)
1206     {
1207       GtkType type;
1208
1209       type = GTK_OBJECT_TYPE (widget);
1210       while (type)
1211         {
1212           const gchar *path;
1213           gchar *path_reversed;
1214           guint path_length;
1215
1216           path = gtk_type_name (type);
1217           path_length = strlen (path);
1218           path_reversed = g_strdup (path);
1219           g_strreverse (path_reversed);
1220           
1221           rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_class, path_length, path, path_reversed);
1222           g_free (path_reversed);
1223       
1224           type = gtk_type_parent (type);
1225         }
1226     }
1227   
1228   if (rc_styles)
1229     return gtk_rc_init_style (rc_styles);
1230
1231   return NULL;
1232 }
1233
1234 static GSList *
1235 gtk_rc_add_rc_sets (GSList      *slist,
1236                     GtkRcStyle  *rc_style,
1237                     const gchar *pattern)
1238 {
1239   GtkRcStyle *new_style;
1240   GtkRcSet *rc_set;
1241   guint i;
1242   
1243   new_style = gtk_rc_style_new ();
1244   *new_style = *rc_style;
1245   new_style->name = g_strdup (rc_style->name);
1246   if (rc_style->font_desc)
1247     new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
1248   
1249   for (i = 0; i < 5; i++)
1250     new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1251   
1252   rc_set = g_new (GtkRcSet, 1);
1253   rc_set->pspec = g_pattern_spec_new (pattern);
1254   rc_set->rc_style = rc_style;
1255   
1256   return g_slist_prepend (slist, rc_set);
1257 }
1258
1259 void
1260 gtk_rc_add_widget_name_style (GtkRcStyle  *rc_style,
1261                               const gchar *pattern)
1262 {
1263   g_return_if_fail (rc_style != NULL);
1264   g_return_if_fail (pattern != NULL);
1265
1266   gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, rc_style, pattern);
1267 }
1268
1269 void
1270 gtk_rc_add_widget_class_style (GtkRcStyle  *rc_style,
1271                                const gchar *pattern)
1272 {
1273   g_return_if_fail (rc_style != NULL);
1274   g_return_if_fail (pattern != NULL);
1275
1276   gtk_rc_sets_widget_class = gtk_rc_add_rc_sets (gtk_rc_sets_widget_class, rc_style, pattern);
1277 }
1278
1279 void
1280 gtk_rc_add_class_style (GtkRcStyle  *rc_style,
1281                         const gchar *pattern)
1282 {
1283   g_return_if_fail (rc_style != NULL);
1284   g_return_if_fail (pattern != NULL);
1285
1286   gtk_rc_sets_class = gtk_rc_add_rc_sets (gtk_rc_sets_class, rc_style, pattern);
1287 }
1288
1289 GScanner*
1290 gtk_rc_scanner_new (void)
1291 {
1292   return g_scanner_new (&gtk_rc_scanner_config);
1293 }
1294
1295 static void
1296 gtk_rc_parse_any (const gchar  *input_name,
1297                   gint          input_fd,
1298                   const gchar  *input_string)
1299 {
1300   GScanner *scanner;
1301   guint    i;
1302   gboolean done;
1303
1304   scanner = gtk_rc_scanner_new ();
1305   
1306   if (input_fd >= 0)
1307     {
1308       g_assert (input_string == NULL);
1309       
1310       g_scanner_input_file (scanner, input_fd);
1311     }
1312   else
1313     {
1314       g_assert (input_string != NULL);
1315       
1316       g_scanner_input_text (scanner, input_string, strlen (input_string));
1317     }
1318   scanner->input_name = input_name;
1319
1320   for (i = 0; i < n_symbols; i++)
1321     g_scanner_add_symbol (scanner, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1322   
1323   done = FALSE;
1324   while (!done)
1325     {
1326       if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1327         done = TRUE;
1328       else
1329         {
1330           guint expected_token;
1331           
1332           expected_token = gtk_rc_parse_statement (scanner);
1333
1334           if (expected_token != G_TOKEN_NONE)
1335             {
1336               gchar *symbol_name;
1337               gchar *msg;
1338               
1339               msg = NULL;
1340               symbol_name = NULL;
1341               if (scanner->scope_id == 0)
1342                 {
1343                   /* if we are in scope 0, we know the symbol names
1344                    * that are associated with certaintoken values.
1345                    * so we look them up to make the error messages
1346                    * more readable.
1347                    */
1348                   if (expected_token > GTK_RC_TOKEN_INVALID &&
1349                       expected_token < GTK_RC_TOKEN_LAST)
1350                     {
1351                       for (i = 0; i < n_symbols; i++)
1352                         if (symbols[i].token == expected_token)
1353                           msg = symbols[i].name;
1354                       if (msg)
1355                         msg = g_strconcat ("e.g. `", msg, "'", NULL);
1356                     }
1357                   if (scanner->token > GTK_RC_TOKEN_INVALID &&
1358                       scanner->token < GTK_RC_TOKEN_LAST)
1359                     {
1360                       symbol_name = "???";
1361                       for (i = 0; i < n_symbols; i++)
1362                         if (symbols[i].token == scanner->token)
1363                           symbol_name = symbols[i].name;
1364                     }
1365                 }
1366               g_scanner_unexp_token (scanner,
1367                                      expected_token,
1368                                      NULL,
1369                                      "keyword",
1370                                      symbol_name,
1371                                      msg,
1372                                      TRUE);
1373               g_free (msg);
1374               done = TRUE;
1375             }
1376         }
1377     }
1378   
1379   g_scanner_destroy (scanner);
1380 }
1381
1382 static guint       
1383 gtk_rc_styles_hash (const GSList *rc_styles)
1384 {
1385   guint result;
1386   
1387   result = 0;
1388   while (rc_styles)
1389     {
1390       result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1391       rc_styles = rc_styles->next;
1392     }
1393   
1394   return result;
1395 }
1396
1397 static gboolean
1398 gtk_rc_styles_equal (const GSList *a,
1399                      const GSList *b)
1400 {
1401   while (a && b)
1402     {
1403       if (a->data != b->data)
1404         return FALSE;
1405       a = a->next;
1406       b = b->next;
1407     }
1408   
1409   return (a == b);
1410 }
1411
1412 static guint
1413 gtk_rc_style_hash (const gchar *name)
1414 {
1415   guint result;
1416   
1417   result = 0;
1418   while (*name)
1419     result += (result << 3) + *name++;
1420   
1421   return result;
1422 }
1423
1424 static gboolean
1425 gtk_rc_style_equal (const gchar *a,
1426                     const gchar *b)
1427 {
1428   return (strcmp (a, b) == 0);
1429 }
1430
1431 static GtkRcStyle*
1432 gtk_rc_style_find (const gchar *name)
1433 {
1434   if (rc_style_ht)
1435     return g_hash_table_lookup (rc_style_ht, (gpointer) name);
1436   else
1437     return NULL;
1438 }
1439
1440 static GtkStyle *
1441 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1442 {
1443   GtkStyle *style;
1444
1445   style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
1446
1447   style->rc_style = rc_style;
1448
1449   gtk_rc_style_ref (rc_style);
1450   
1451   GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);  
1452
1453   return style;
1454 }
1455
1456 /* Reuses or frees rc_styles */
1457 static GtkStyle *
1458 gtk_rc_init_style (GSList *rc_styles)
1459 {
1460   GtkStyle *style = NULL;
1461   gint i;
1462
1463   g_return_val_if_fail (rc_styles != NULL, NULL);
1464   
1465   if (!realized_style_ht)
1466     realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
1467                                           (GEqualFunc) gtk_rc_styles_equal);
1468
1469   style = g_hash_table_lookup (realized_style_ht, rc_styles);
1470
1471   if (!style)
1472     {
1473       GtkRcStyle *base_style = NULL;
1474       GtkRcStyle *proto_style;
1475       GtkRcStyleClass *proto_style_class;
1476       GSList *tmp_styles;
1477       GType rc_style_type = GTK_TYPE_RC_STYLE;
1478
1479       /* Find the first derived style in the list, and use that to
1480        * create the merged style. If we only have raw GtkRcStyles, use
1481        * the first style to create the merged style.
1482        */
1483       base_style = rc_styles->data;
1484       tmp_styles = rc_styles;
1485       while (tmp_styles)
1486         {
1487           GtkRcStyle *rc_style = tmp_styles->data;
1488           
1489           if (G_OBJECT_TYPE (rc_style) != rc_style_type)
1490             {
1491               base_style = rc_style;
1492               break;
1493             }
1494           
1495           tmp_styles = tmp_styles->next;
1496         }
1497       
1498       proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
1499       proto_style = proto_style_class->create_rc_style (base_style);
1500       
1501       tmp_styles = rc_styles;
1502       while (tmp_styles)
1503         {
1504           GtkRcStyle *rc_style = tmp_styles->data;
1505           GSList *factories;
1506           
1507           proto_style_class->merge (proto_style, rc_style);       
1508           
1509           /* Point from each rc_style to the list of styles */
1510           if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
1511             rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
1512
1513           factories = g_slist_copy (rc_style->icon_factories);
1514           if (factories)
1515             {
1516               GSList *iter;
1517               
1518               iter = factories;
1519               while (iter != NULL)
1520                 {
1521                   g_object_ref (G_OBJECT (iter->data));
1522                   iter = g_slist_next (iter);
1523                 }
1524
1525               proto_style->icon_factories = g_slist_concat (proto_style->icon_factories,
1526                                                             factories);
1527
1528             }
1529           
1530           tmp_styles = tmp_styles->next;
1531         }
1532
1533       for (i = 0; i < 5; i++)
1534         if (proto_style->bg_pixmap_name[i] &&
1535             (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1536           {
1537             g_free (proto_style->bg_pixmap_name[i]);
1538             proto_style->bg_pixmap_name[i] = NULL;
1539           }
1540
1541       style = gtk_rc_style_to_style (proto_style);
1542       gtk_rc_style_unref (proto_style);
1543
1544       g_hash_table_insert (realized_style_ht, rc_styles, style);
1545     }
1546   else
1547     g_slist_free (rc_styles);
1548
1549   return style;
1550 }
1551
1552 /*********************
1553  * Parsing functions *
1554  *********************/
1555
1556 static guint
1557 rc_parse_token_or_compound (GScanner  *scanner,
1558                             GString   *gstring,
1559                             GTokenType delimiter)
1560 {
1561   guint token = g_scanner_get_next_token (scanner);
1562
1563   /* we either scan a single token (skipping comments)
1564    * or a compund statement.
1565    * compunds are enclosed in (), [] or {} braces, we read
1566    * them in via deep recursion.
1567    */
1568
1569   switch (token)
1570     {
1571       gchar *string;
1572     case G_TOKEN_INT:
1573       g_string_printfa (gstring, " 0x%lx", scanner->value.v_int);
1574       break;
1575     case G_TOKEN_FLOAT:
1576       g_string_printfa (gstring, " %f", scanner->value.v_float);
1577       break;
1578     case G_TOKEN_STRING:
1579       string = g_strescape (scanner->value.v_string, NULL);
1580       g_string_append (gstring, " \"");
1581       g_string_append (gstring, string);
1582       g_string_append_c (gstring, '"');
1583       g_free (string);
1584       break;
1585     case G_TOKEN_IDENTIFIER:
1586       g_string_append_c (gstring, ' ');
1587       g_string_append (gstring, scanner->value.v_identifier);
1588       break;
1589     case G_TOKEN_COMMENT_SINGLE:
1590     case G_TOKEN_COMMENT_MULTI:
1591       return rc_parse_token_or_compound (scanner, gstring, delimiter);
1592     case G_TOKEN_LEFT_PAREN:
1593       g_string_append_c (gstring, ' ');
1594       g_string_append_c (gstring, token);
1595       token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_PAREN);
1596       if (token != G_TOKEN_NONE)
1597         return token;
1598       break;
1599     case G_TOKEN_LEFT_CURLY:
1600       g_string_append_c (gstring, ' ');
1601       g_string_append_c (gstring, token);
1602       token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_CURLY);
1603       if (token != G_TOKEN_NONE)
1604         return token;
1605       break;
1606     case G_TOKEN_LEFT_BRACE:
1607       g_string_append_c (gstring, ' ');
1608       g_string_append_c (gstring, token);
1609       token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_BRACE);
1610       if (token != G_TOKEN_NONE)
1611         return token;
1612       break;
1613     default:
1614       if (token >= 256 || token < 1)
1615         return delimiter ? delimiter : G_TOKEN_STRING;
1616       g_string_append_c (gstring, ' ');
1617       g_string_append_c (gstring, token);
1618       if (token == delimiter)
1619         return G_TOKEN_NONE;
1620       break;
1621     }
1622   if (!delimiter)
1623     return G_TOKEN_NONE;
1624   else
1625     return rc_parse_token_or_compound (scanner, gstring, delimiter);
1626 }
1627
1628 static guint
1629 gtk_rc_parse_assignment (GScanner      *scanner,
1630                          GtkRcProperty *prop)
1631 {
1632   gboolean scan_identifier = scanner->config->scan_identifier;
1633   gboolean scan_symbols = scanner->config->scan_symbols;
1634   gboolean identifier_2_string = scanner->config->identifier_2_string;
1635   gboolean char_2_token = scanner->config->char_2_token;
1636   gboolean scan_identifier_NULL = scanner->config->scan_identifier_NULL;
1637   gboolean numbers_2_int = scanner->config->numbers_2_int;
1638   gboolean negate = FALSE;
1639   guint token;
1640
1641   /* check that this is an assignment */
1642   if (g_scanner_get_next_token (scanner) != '=')
1643     return '=';
1644
1645   /* adjust scanner mode */
1646   scanner->config->scan_identifier = TRUE;
1647   scanner->config->scan_symbols = FALSE;
1648   scanner->config->identifier_2_string = FALSE;
1649   scanner->config->char_2_token = TRUE;
1650   scanner->config->scan_identifier_NULL = FALSE;
1651   scanner->config->numbers_2_int = TRUE;
1652
1653   /* record location */
1654   prop->origin = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
1655
1656   /* parse optional sign */
1657   if (g_scanner_peek_next_token (scanner) == '-')
1658     {
1659       g_scanner_get_next_token (scanner); /* eat sign */
1660       negate = TRUE;
1661     }
1662
1663   /* parse one of LONG, DOUBLE and STRING or, if that fails, create an unparsed compund */
1664   token = g_scanner_peek_next_token (scanner);
1665   switch (token)
1666     {
1667     case G_TOKEN_INT:
1668       g_scanner_get_next_token (scanner);
1669       g_value_init (&prop->value, G_TYPE_LONG);
1670       g_value_set_long (&prop->value, negate ? -scanner->value.v_int : scanner->value.v_int);
1671       token = G_TOKEN_NONE;
1672       break;
1673     case G_TOKEN_FLOAT:
1674       g_scanner_get_next_token (scanner);
1675       g_value_init (&prop->value, G_TYPE_DOUBLE);
1676       g_value_set_double (&prop->value, negate ? -scanner->value.v_float : scanner->value.v_float);
1677       token = G_TOKEN_NONE;
1678       break;
1679     case G_TOKEN_STRING:
1680       g_scanner_get_next_token (scanner);
1681       if (negate)
1682         token = G_TOKEN_INT;
1683       else
1684         {
1685           g_value_init (&prop->value, G_TYPE_STRING);
1686           g_value_set_string (&prop->value, scanner->value.v_string);
1687           token = G_TOKEN_NONE;
1688         }
1689       break;
1690     case G_TOKEN_IDENTIFIER:
1691     case G_TOKEN_LEFT_PAREN:
1692     case G_TOKEN_LEFT_CURLY:
1693     case G_TOKEN_LEFT_BRACE:
1694       if (!negate)
1695         {
1696           GString *gstring = g_string_new ("");
1697
1698           token = rc_parse_token_or_compound (scanner, gstring, 0);
1699           if (token == G_TOKEN_NONE)
1700             {
1701               g_string_append_c (gstring, ' ');
1702               g_value_init (&prop->value, G_TYPE_GSTRING);
1703               g_value_set_static_boxed (&prop->value, gstring);
1704             }
1705           else
1706             g_string_free (gstring, TRUE);
1707           break;
1708         }
1709       /* fall through */
1710     default:
1711       g_scanner_get_next_token (scanner);
1712       token = G_TOKEN_INT;
1713       break;
1714     }
1715
1716   /* restore scanner mode */
1717   scanner->config->scan_identifier = scan_identifier;
1718   scanner->config->scan_symbols = scan_symbols;
1719   scanner->config->identifier_2_string = identifier_2_string;
1720   scanner->config->char_2_token = char_2_token;
1721   scanner->config->scan_identifier_NULL = scan_identifier_NULL;
1722   scanner->config->numbers_2_int = numbers_2_int;
1723
1724   return token;
1725 }
1726
1727 static gboolean
1728 is_c_identifier (const gchar *string)
1729 {
1730   const gchar *p;
1731   gboolean is_varname;
1732
1733   is_varname = strchr (G_CSET_a_2_z G_CSET_A_2_Z "_", string[0]) != NULL;
1734   for (p = string + 1; *p && is_varname; p++)
1735     is_varname &= strchr (G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "_-", *p) != NULL;
1736
1737   return is_varname;
1738 }
1739
1740 static guint
1741 gtk_rc_parse_statement (GScanner *scanner)
1742 {
1743   guint token;
1744   
1745   token = g_scanner_peek_next_token (scanner);
1746   switch (token)
1747     {
1748     case GTK_RC_TOKEN_INCLUDE:
1749       token = g_scanner_get_next_token (scanner);
1750       if (token != GTK_RC_TOKEN_INCLUDE)
1751         return GTK_RC_TOKEN_INCLUDE;
1752       token = g_scanner_get_next_token (scanner);
1753       if (token != G_TOKEN_STRING)
1754         return G_TOKEN_STRING;
1755       gtk_rc_parse_file (scanner->value.v_string, FALSE);
1756       return G_TOKEN_NONE;
1757       
1758     case GTK_RC_TOKEN_STYLE:
1759       return gtk_rc_parse_style (scanner);
1760       
1761     case GTK_RC_TOKEN_BINDING:
1762       return gtk_binding_parse_binding (scanner);
1763       
1764     case GTK_RC_TOKEN_PIXMAP_PATH:
1765       return gtk_rc_parse_pixmap_path (scanner);
1766       
1767     case GTK_RC_TOKEN_WIDGET:
1768       return gtk_rc_parse_path_pattern (scanner);
1769       
1770     case GTK_RC_TOKEN_WIDGET_CLASS:
1771       return gtk_rc_parse_path_pattern (scanner);
1772       
1773     case GTK_RC_TOKEN_CLASS:
1774       return gtk_rc_parse_path_pattern (scanner);
1775       
1776     case GTK_RC_TOKEN_MODULE_PATH:
1777       return gtk_rc_parse_module_path (scanner);
1778       
1779     case GTK_RC_TOKEN_IM_MODULE_PATH:
1780       return gtk_rc_parse_im_module_path (scanner);
1781       
1782     case GTK_RC_TOKEN_IM_MODULE_FILE:
1783       return gtk_rc_parse_im_module_file (scanner);
1784
1785     case G_TOKEN_IDENTIFIER:
1786       if (is_c_identifier (scanner->next_value.v_identifier))
1787         {
1788           GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
1789           gchar *name;
1790           
1791           g_scanner_get_next_token (scanner); /* eat identifier */
1792           name = g_strdup (scanner->value.v_identifier);
1793           
1794           token = gtk_rc_parse_assignment (scanner, &prop);
1795           if (token == G_TOKEN_NONE)
1796             {
1797               GtkSettingsValue svalue;
1798
1799               svalue.origin = prop.origin;
1800               memcpy (&svalue.value, &prop.value, sizeof (prop.value));
1801               g_strcanon (name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
1802               gtk_settings_set_property_value (gtk_settings_get_global (),
1803                                                name,
1804                                                &svalue);
1805             }
1806           g_free (prop.origin);
1807           if (G_VALUE_TYPE (&prop.value))
1808             g_value_unset (&prop.value);
1809           g_free (name);
1810           
1811           return token;
1812         }
1813       else
1814         {
1815           g_scanner_get_next_token (scanner);
1816           return G_TOKEN_IDENTIFIER;
1817         }
1818     default:
1819       g_scanner_get_next_token (scanner);
1820       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
1821     }
1822 }
1823
1824 static guint
1825 gtk_rc_parse_style (GScanner *scanner)
1826 {
1827   GtkRcStyle *rc_style;
1828   GtkRcStyle *parent_style;
1829   guint token;
1830   gint insert;
1831   gint i;
1832   GtkIconFactory *our_factory = NULL;
1833   
1834   token = g_scanner_get_next_token (scanner);
1835   if (token != GTK_RC_TOKEN_STYLE)
1836     return GTK_RC_TOKEN_STYLE;
1837   
1838   token = g_scanner_get_next_token (scanner);
1839   if (token != G_TOKEN_STRING)
1840     return G_TOKEN_STRING;
1841   
1842   insert = FALSE;
1843   rc_style = gtk_rc_style_find (scanner->value.v_string);
1844
1845   /* If there's a list, its first member is always the factory belonging
1846    * to this RcStyle
1847    */
1848   if (rc_style && rc_style->icon_factories)
1849     our_factory = rc_style->icon_factories->data;
1850   
1851   if (!rc_style)
1852     {
1853       insert = TRUE;
1854       rc_style = gtk_rc_style_new ();
1855       rc_style->name = g_strdup (scanner->value.v_string);
1856       
1857       for (i = 0; i < 5; i++)
1858         rc_style->bg_pixmap_name[i] = NULL;
1859
1860       for (i = 0; i < 5; i++)
1861         rc_style->color_flags[i] = 0;
1862     }
1863
1864   token = g_scanner_peek_next_token (scanner);
1865   if (token == G_TOKEN_EQUAL_SIGN)
1866     {
1867       token = g_scanner_get_next_token (scanner);
1868       
1869       token = g_scanner_get_next_token (scanner);
1870       if (token != G_TOKEN_STRING)
1871         {
1872           if (insert)
1873             g_free (rc_style);
1874
1875           return G_TOKEN_STRING;
1876         }
1877       
1878       parent_style = gtk_rc_style_find (scanner->value.v_string);
1879       if (parent_style)
1880         {
1881           GSList *factories;
1882           
1883           for (i = 0; i < 5; i++)
1884             {
1885               rc_style->color_flags[i] = parent_style->color_flags[i];
1886               rc_style->fg[i] = parent_style->fg[i];
1887               rc_style->bg[i] = parent_style->bg[i];
1888               rc_style->text[i] = parent_style->text[i];
1889               rc_style->base[i] = parent_style->base[i];
1890             }
1891
1892           rc_style->xthickness = parent_style->xthickness;
1893           rc_style->ythickness = parent_style->ythickness;
1894           
1895           if (parent_style->font_desc)
1896             {
1897               if (rc_style->font_desc)
1898                 pango_font_description_free (rc_style->font_desc);
1899               rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
1900             }
1901
1902           if (parent_style->rc_properties)
1903             {
1904               guint i;
1905
1906               if (!rc_style->rc_properties)
1907                 rc_style->rc_properties = g_bsearch_array_new (sizeof (GtkRcProperty),
1908                                                                gtk_rc_properties_cmp,
1909                                                                0);
1910               for (i = 0; i < parent_style->rc_properties->n_nodes; i++)
1911                 {
1912                   GtkRcProperty *node = g_bsearch_array_get_nth (parent_style->rc_properties, i);
1913                   GtkRcProperty *prop, key = { 0, 0, NULL, { 0, }, };
1914
1915                   key.type_name = node->type_name;
1916                   key.property_name = node->property_name;
1917                   prop = g_bsearch_array_insert (rc_style->rc_properties, &key, FALSE);
1918                   if (prop->origin)
1919                     {
1920                       g_free (prop->origin);
1921                       g_value_unset (&prop->value);
1922                     }
1923                   prop->origin = g_strdup (node->origin);
1924                   g_value_init (&prop->value, G_VALUE_TYPE (&node->value));
1925                   g_value_copy (&node->value, &prop->value);
1926                 }
1927             }
1928           
1929           for (i = 0; i < 5; i++)
1930             {
1931               if (rc_style->bg_pixmap_name[i])
1932                 g_free (rc_style->bg_pixmap_name[i]);
1933               rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
1934             }
1935           
1936           /* Append parent's factories, adding a ref to them */
1937           if (parent_style->icon_factories != NULL)
1938             {
1939               /* Add a factory for ourselves if we have none,
1940                * in case we end up defining more stock icons.
1941                * I see no real way around this; we need to maintain
1942                * the invariant that the first factory in the list
1943                * is always our_factory, the one belonging to us,
1944                * and if we put parent factories in the list we can't
1945                * do that if the style is reopened.
1946                */
1947               if (our_factory == NULL)
1948                 {
1949                   our_factory = gtk_icon_factory_new ();
1950                   rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
1951                                                               our_factory);
1952                 }
1953               
1954               rc_style->icon_factories = g_slist_concat (rc_style->icon_factories,
1955                                                          g_slist_copy (parent_style->icon_factories));
1956               
1957               factories = parent_style->icon_factories;
1958               while (factories != NULL)
1959                 {
1960                   g_object_ref (G_OBJECT (factories->data));
1961                   factories = factories->next;
1962                 }
1963             }
1964         }
1965     }
1966   
1967   token = g_scanner_get_next_token (scanner);
1968   if (token != G_TOKEN_LEFT_CURLY)
1969     {
1970       if (insert)
1971         g_free (rc_style);
1972
1973       return G_TOKEN_LEFT_CURLY;
1974     }
1975   
1976   token = g_scanner_peek_next_token (scanner);
1977   while (token != G_TOKEN_RIGHT_CURLY)
1978     {
1979       switch (token)
1980         {
1981         case GTK_RC_TOKEN_BG:
1982           token = gtk_rc_parse_bg (scanner, rc_style);
1983           break;
1984         case GTK_RC_TOKEN_FG:
1985           token = gtk_rc_parse_fg (scanner, rc_style);
1986           break;
1987         case GTK_RC_TOKEN_TEXT:
1988           token = gtk_rc_parse_text (scanner, rc_style);
1989           break;
1990         case GTK_RC_TOKEN_BASE:
1991           token = gtk_rc_parse_base (scanner, rc_style);
1992           break;
1993         case GTK_RC_TOKEN_XTHICKNESS:
1994           token = gtk_rc_parse_xthickness (scanner, rc_style);
1995           break;
1996         case GTK_RC_TOKEN_YTHICKNESS:
1997           token = gtk_rc_parse_ythickness (scanner, rc_style);
1998           break;
1999         case GTK_RC_TOKEN_BG_PIXMAP:
2000           token = gtk_rc_parse_bg_pixmap (scanner, rc_style);
2001           break;
2002         case GTK_RC_TOKEN_FONT:
2003           token = gtk_rc_parse_font (scanner, rc_style);
2004           break;
2005         case GTK_RC_TOKEN_FONTSET:
2006           token = gtk_rc_parse_fontset (scanner, rc_style);
2007           break;
2008         case GTK_RC_TOKEN_FONT_NAME:
2009           token = gtk_rc_parse_font_name (scanner, rc_style);
2010           break;
2011         case GTK_RC_TOKEN_ENGINE:
2012           token = gtk_rc_parse_engine (scanner, &rc_style);
2013           break;
2014         case GTK_RC_TOKEN_STOCK:
2015           if (our_factory == NULL)
2016             {
2017               our_factory = gtk_icon_factory_new ();
2018               rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
2019                                                           our_factory);
2020             }
2021           token = gtk_rc_parse_stock (scanner, rc_style, our_factory);
2022           break;
2023         case G_TOKEN_IDENTIFIER:
2024           if (is_c_identifier (scanner->next_value.v_identifier) &&
2025               scanner->next_value.v_identifier[0] >= 'A' &&
2026               scanner->next_value.v_identifier[0] <= 'Z') /* match namespaced type names */
2027             {
2028               GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2029               
2030               g_scanner_get_next_token (scanner); /* eat type name */
2031               prop.type_name = g_quark_from_string (scanner->value.v_identifier);
2032               if (g_scanner_get_next_token (scanner) != ':' ||
2033                   g_scanner_get_next_token (scanner) != ':')
2034                 {
2035                   token = ':';
2036                   break;
2037                 }
2038               if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER ||
2039                   !is_c_identifier (scanner->value.v_identifier))
2040                 {
2041                   token = G_TOKEN_IDENTIFIER;
2042                   break;
2043                 }
2044
2045               /* it's important that we do the same canonification as GParamSpecPool here */
2046               g_strcanon (scanner->value.v_identifier, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
2047               prop.property_name = g_quark_from_string (scanner->value.v_identifier);
2048
2049               token = gtk_rc_parse_assignment (scanner, &prop);
2050               if (token == G_TOKEN_NONE)
2051                 {
2052                   GtkRcProperty *tmp;
2053
2054                   g_return_val_if_fail (prop.origin != NULL && G_VALUE_TYPE (&prop.value) != 0, G_TOKEN_ERROR);
2055
2056                   if (!rc_style->rc_properties)
2057                     rc_style->rc_properties = g_bsearch_array_new (sizeof (GtkRcProperty),
2058                                                                    gtk_rc_properties_cmp,
2059                                                                    0);
2060                   tmp = g_bsearch_array_insert (rc_style->rc_properties, &prop, FALSE);
2061                   if (prop.origin != tmp->origin)
2062                     {
2063                       g_free (tmp->origin);
2064                       g_value_unset (&tmp->value);
2065                       tmp->origin = prop.origin;
2066                       memcpy (&tmp->value, &prop.value, sizeof (prop.value));
2067                     }
2068                 }
2069               else
2070                 {
2071                   g_free (prop.origin);
2072                   if (G_VALUE_TYPE (&prop.value))
2073                     g_value_unset (&prop.value);
2074                 }
2075             }
2076           else
2077             {
2078               g_scanner_get_next_token (scanner);
2079               token = G_TOKEN_IDENTIFIER;
2080             }
2081           break;
2082         default:
2083           g_scanner_get_next_token (scanner);
2084           token = G_TOKEN_RIGHT_CURLY;
2085           break;
2086         }
2087
2088       if (token != G_TOKEN_NONE)
2089         {
2090           if (insert)
2091             gtk_rc_style_unref (rc_style);
2092
2093           return token;
2094         }
2095       token = g_scanner_peek_next_token (scanner);
2096     } /* while (token != G_TOKEN_RIGHT_CURLY) */
2097   
2098   token = g_scanner_get_next_token (scanner);
2099   if (token != G_TOKEN_RIGHT_CURLY)
2100     {
2101       if (insert)
2102         {
2103           if (rc_style->font_desc)
2104             pango_font_description_free (rc_style->font_desc);
2105           
2106           for (i = 0; i < 5; i++)
2107             if (rc_style->bg_pixmap_name[i])
2108               g_free (rc_style->bg_pixmap_name[i]);
2109           
2110           g_free (rc_style);
2111         }
2112       return G_TOKEN_RIGHT_CURLY;
2113     }
2114   
2115   if (insert)
2116     {
2117       if (!rc_style_ht)
2118         rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
2119                                         (GEqualFunc) gtk_rc_style_equal);
2120       
2121       g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
2122     }
2123   
2124   return G_TOKEN_NONE;
2125 }
2126
2127 const GtkRcProperty*
2128 _gtk_rc_style_lookup_rc_property (GtkRcStyle *rc_style,
2129                                   GQuark      type_name,
2130                                   GQuark      property_name)
2131 {
2132   GtkRcProperty *node = NULL;
2133
2134   g_return_val_if_fail (GTK_IS_RC_STYLE (rc_style), NULL);
2135
2136   if (rc_style->rc_properties)
2137     {
2138       GtkRcProperty key;
2139
2140       key.type_name = type_name;
2141       key.property_name = property_name;
2142
2143       node = g_bsearch_array_lookup (rc_style->rc_properties, &key);
2144     }
2145
2146   return node;
2147 }
2148
2149 static guint
2150 gtk_rc_parse_bg (GScanner   *scanner,
2151                  GtkRcStyle *style)
2152 {
2153   GtkStateType state;
2154   guint token;
2155   
2156   token = g_scanner_get_next_token (scanner);
2157   if (token != GTK_RC_TOKEN_BG)
2158     return GTK_RC_TOKEN_BG;
2159   
2160   token = gtk_rc_parse_state (scanner, &state);
2161   if (token != G_TOKEN_NONE)
2162     return token;
2163   
2164   token = g_scanner_get_next_token (scanner);
2165   if (token != G_TOKEN_EQUAL_SIGN)
2166     return G_TOKEN_EQUAL_SIGN;
2167
2168   style->color_flags[state] |= GTK_RC_BG;
2169   return gtk_rc_parse_color (scanner, &style->bg[state]);
2170 }
2171
2172 static guint
2173 gtk_rc_parse_fg (GScanner   *scanner,
2174                  GtkRcStyle *style)
2175 {
2176   GtkStateType state;
2177   guint token;
2178   
2179   token = g_scanner_get_next_token (scanner);
2180   if (token != GTK_RC_TOKEN_FG)
2181     return GTK_RC_TOKEN_FG;
2182   
2183   token = gtk_rc_parse_state (scanner, &state);
2184   if (token != G_TOKEN_NONE)
2185     return token;
2186   
2187   token = g_scanner_get_next_token (scanner);
2188   if (token != G_TOKEN_EQUAL_SIGN)
2189     return G_TOKEN_EQUAL_SIGN;
2190   
2191   style->color_flags[state] |= GTK_RC_FG;
2192   return gtk_rc_parse_color (scanner, &style->fg[state]);
2193 }
2194
2195 static guint
2196 gtk_rc_parse_text (GScanner   *scanner,
2197                    GtkRcStyle *style)
2198 {
2199   GtkStateType state;
2200   guint token;
2201   
2202   token = g_scanner_get_next_token (scanner);
2203   if (token != GTK_RC_TOKEN_TEXT)
2204     return GTK_RC_TOKEN_TEXT;
2205   
2206   token = gtk_rc_parse_state (scanner, &state);
2207   if (token != G_TOKEN_NONE)
2208     return token;
2209   
2210   token = g_scanner_get_next_token (scanner);
2211   if (token != G_TOKEN_EQUAL_SIGN)
2212     return G_TOKEN_EQUAL_SIGN;
2213   
2214   style->color_flags[state] |= GTK_RC_TEXT;
2215   return gtk_rc_parse_color (scanner, &style->text[state]);
2216 }
2217
2218 static guint
2219 gtk_rc_parse_base (GScanner   *scanner,
2220                    GtkRcStyle *style)
2221 {
2222   GtkStateType state;
2223   guint token;
2224   
2225   token = g_scanner_get_next_token (scanner);
2226   if (token != GTK_RC_TOKEN_BASE)
2227     return GTK_RC_TOKEN_BASE;
2228   
2229   token = gtk_rc_parse_state (scanner, &state);
2230   if (token != G_TOKEN_NONE)
2231     return token;
2232   
2233   token = g_scanner_get_next_token (scanner);
2234   if (token != G_TOKEN_EQUAL_SIGN)
2235     return G_TOKEN_EQUAL_SIGN;
2236
2237   style->color_flags[state] |= GTK_RC_BASE;
2238   return gtk_rc_parse_color (scanner, &style->base[state]);
2239 }
2240
2241 static guint
2242 gtk_rc_parse_xthickness (GScanner   *scanner,
2243                          GtkRcStyle *style)
2244 {
2245   if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
2246     return GTK_RC_TOKEN_XTHICKNESS;
2247
2248   if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2249     return G_TOKEN_EQUAL_SIGN;
2250
2251   if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2252     return G_TOKEN_INT;
2253
2254   style->xthickness = scanner->value.v_int;
2255
2256   return G_TOKEN_NONE;
2257 }
2258
2259 static guint
2260 gtk_rc_parse_ythickness (GScanner   *scanner,
2261                          GtkRcStyle *style)
2262 {
2263   if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
2264     return GTK_RC_TOKEN_YTHICKNESS;
2265
2266   if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2267     return G_TOKEN_EQUAL_SIGN;
2268
2269   if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2270     return G_TOKEN_INT;
2271
2272   style->ythickness = scanner->value.v_int;
2273
2274   return G_TOKEN_NONE;
2275 }
2276
2277 static guint
2278 gtk_rc_parse_bg_pixmap (GScanner   *scanner,
2279                         GtkRcStyle *rc_style)
2280 {
2281   GtkStateType state;
2282   guint token;
2283   gchar *pixmap_file;
2284   
2285   token = g_scanner_get_next_token (scanner);
2286   if (token != GTK_RC_TOKEN_BG_PIXMAP)
2287     return GTK_RC_TOKEN_BG_PIXMAP;
2288   
2289   token = gtk_rc_parse_state (scanner, &state);
2290   if (token != G_TOKEN_NONE)
2291     return token;
2292   
2293   token = g_scanner_get_next_token (scanner);
2294   if (token != G_TOKEN_EQUAL_SIGN)
2295     return G_TOKEN_EQUAL_SIGN;
2296   
2297   token = g_scanner_get_next_token (scanner);
2298   if (token != G_TOKEN_STRING)
2299     return G_TOKEN_STRING;
2300   
2301   if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
2302       (strcmp (scanner->value.v_string, "<none>") == 0))
2303     pixmap_file = g_strdup (scanner->value.v_string);
2304   else
2305     pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
2306   
2307   if (pixmap_file)
2308     {
2309       if (rc_style->bg_pixmap_name[state])
2310         g_free (rc_style->bg_pixmap_name[state]);
2311       rc_style->bg_pixmap_name[state] = pixmap_file;
2312     }
2313   
2314   return G_TOKEN_NONE;
2315 }
2316
2317 static gchar*
2318 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
2319 {
2320   gchar *buf;
2321   gint fd;
2322
2323   buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", dir, pixmap_file);
2324   
2325   fd = open (buf, O_RDONLY);
2326   if (fd >= 0)
2327     {
2328       close (fd);
2329       return buf;
2330     }
2331    
2332   g_free (buf);
2333  
2334    return NULL;
2335  }
2336  
2337 gchar*
2338 gtk_rc_find_pixmap_in_path (GScanner *scanner,
2339                             const gchar *pixmap_file)
2340 {
2341   gint i;
2342   gchar *filename;
2343   GSList *tmp_list;
2344     
2345   for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
2346     {
2347       filename = gtk_rc_check_pixmap_dir (pixmap_path[i], pixmap_file);
2348       if (filename)
2349         return filename;
2350     }
2351  
2352   tmp_list = rc_dir_stack;
2353   while (tmp_list)
2354     {
2355       filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
2356       if (filename)
2357         return filename;
2358        
2359       tmp_list = tmp_list->next;
2360     }
2361   
2362   if (scanner)
2363     g_warning (_("Unable to locate image file in pixmap_path: \"%s\" line %d"),
2364                pixmap_file, scanner->line);
2365   else
2366     g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
2367                pixmap_file);
2368     
2369   return NULL;
2370 }
2371
2372 gchar*
2373 gtk_rc_find_module_in_path (const gchar *module_file)
2374 {
2375   gint i;
2376   gint fd;
2377   gchar *buf;
2378   
2379   for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
2380     {
2381       buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
2382                              module_path[i], module_file);
2383       
2384       fd = open (buf, O_RDONLY);
2385       if (fd >= 0)
2386         {
2387           close (fd);
2388           return buf;
2389         }
2390       
2391       g_free (buf);
2392     }
2393     
2394   return NULL;
2395 }
2396
2397 static guint
2398 gtk_rc_parse_font (GScanner   *scanner,
2399                    GtkRcStyle *rc_style)
2400 {
2401   guint token;
2402   
2403   token = g_scanner_get_next_token (scanner);
2404   if (token != GTK_RC_TOKEN_FONT)
2405     return GTK_RC_TOKEN_FONT;
2406   
2407   token = g_scanner_get_next_token (scanner);
2408   if (token != G_TOKEN_EQUAL_SIGN)
2409     return G_TOKEN_EQUAL_SIGN;
2410   
2411   token = g_scanner_get_next_token (scanner);
2412   if (token != G_TOKEN_STRING)
2413     return G_TOKEN_STRING;
2414
2415   /* Ignore, do nothing */
2416   
2417   return G_TOKEN_NONE;
2418 }
2419
2420 static guint
2421 gtk_rc_parse_fontset (GScanner   *scanner,
2422                       GtkRcStyle *rc_style)
2423 {
2424   guint token;
2425   
2426   token = g_scanner_get_next_token (scanner);
2427   if (token != GTK_RC_TOKEN_FONTSET)
2428     return GTK_RC_TOKEN_FONTSET;
2429   
2430   token = g_scanner_get_next_token (scanner);
2431   if (token != G_TOKEN_EQUAL_SIGN)
2432     return G_TOKEN_EQUAL_SIGN;
2433   
2434   token = g_scanner_get_next_token (scanner);
2435   if (token != G_TOKEN_STRING)
2436     return G_TOKEN_STRING;
2437
2438   /* Do nothing - silently ignore */
2439   
2440   return G_TOKEN_NONE;
2441 }
2442
2443 static guint
2444 gtk_rc_parse_font_name (GScanner   *scanner,
2445                         GtkRcStyle *rc_style)
2446 {
2447   guint token;
2448   
2449   token = g_scanner_get_next_token (scanner);
2450   if (token != GTK_RC_TOKEN_FONT_NAME)
2451     return GTK_RC_TOKEN_FONT;
2452   
2453   token = g_scanner_get_next_token (scanner);
2454   if (token != G_TOKEN_EQUAL_SIGN)
2455     return G_TOKEN_EQUAL_SIGN;
2456   
2457   token = g_scanner_get_next_token (scanner);
2458   if (token != G_TOKEN_STRING)
2459     return G_TOKEN_STRING;
2460
2461   rc_style->font_desc = pango_font_description_from_string (scanner->value.v_string);
2462   
2463   return G_TOKEN_NONE;
2464 }
2465
2466 static guint       
2467 gtk_rc_parse_engine (GScanner    *scanner,
2468                      GtkRcStyle **rc_style)
2469 {
2470   guint token;
2471   GtkThemeEngine *engine;
2472   guint result = G_TOKEN_NONE;
2473   GtkRcStyle *new_style = NULL;
2474   gboolean parsed_curlies = FALSE;
2475   
2476   token = g_scanner_get_next_token (scanner);
2477   if (token != GTK_RC_TOKEN_ENGINE)
2478     return GTK_RC_TOKEN_ENGINE;
2479
2480   token = g_scanner_get_next_token (scanner);
2481   if (token != G_TOKEN_STRING)
2482     return G_TOKEN_STRING;
2483
2484   engine = gtk_theme_engine_get (scanner->value.v_string);
2485   
2486   token = g_scanner_get_next_token (scanner);
2487   if (token != G_TOKEN_LEFT_CURLY)
2488     return G_TOKEN_LEFT_CURLY;
2489
2490   if (engine)
2491     {
2492       GtkRcStyleClass *new_class;
2493       
2494       new_style = gtk_theme_engine_create_rc_style (engine);
2495       g_type_module_unuse (G_TYPE_MODULE (engine));
2496
2497       new_class = GTK_RC_STYLE_GET_CLASS (new_style);
2498
2499       new_class->merge (new_style, *rc_style);
2500       if ((*rc_style)->name)
2501         new_style->name = g_strdup ((*rc_style)->name);
2502       
2503       if (new_class->parse)
2504         {
2505           parsed_curlies = TRUE;
2506           result = new_class->parse (new_style, scanner);
2507
2508           if (result != G_TOKEN_NONE)
2509             {
2510               g_object_unref (G_OBJECT (new_style));
2511               new_style = NULL;
2512             }
2513         }
2514     }
2515
2516   if (!parsed_curlies)
2517     {
2518       /* Skip over remainder, looking for nested {}'s
2519        */
2520       guint count = 1;
2521       
2522       result = G_TOKEN_RIGHT_CURLY;
2523       while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
2524         {
2525           if (token == G_TOKEN_LEFT_CURLY)
2526             count++;
2527           else if (token == G_TOKEN_RIGHT_CURLY)
2528             count--;
2529           
2530           if (count == 0)
2531             {
2532               result = G_TOKEN_NONE;
2533               break;
2534             }
2535         }
2536     }
2537
2538   if (new_style)
2539     {
2540       g_object_unref (G_OBJECT (*rc_style));
2541       *rc_style = new_style;
2542     }
2543
2544   return result;
2545 }
2546
2547 guint
2548 gtk_rc_parse_state (GScanner     *scanner,
2549                     GtkStateType *state)
2550 {
2551   guint old_scope;
2552   guint token;
2553
2554   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2555   g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
2556   
2557   /* we don't know where we got called from, so we reset the scope here.
2558    * if we bail out due to errors, we *don't* reset the scope, so the
2559    * error messaging code can make sense of our tokens.
2560    */
2561   old_scope = g_scanner_set_scope (scanner, 0);
2562   
2563   token = g_scanner_get_next_token (scanner);
2564   if (token != G_TOKEN_LEFT_BRACE)
2565     return G_TOKEN_LEFT_BRACE;
2566   
2567   token = g_scanner_get_next_token (scanner);
2568   switch (token)
2569     {
2570     case GTK_RC_TOKEN_ACTIVE:
2571       *state = GTK_STATE_ACTIVE;
2572       break;
2573     case GTK_RC_TOKEN_INSENSITIVE:
2574       *state = GTK_STATE_INSENSITIVE;
2575       break;
2576     case GTK_RC_TOKEN_NORMAL:
2577       *state = GTK_STATE_NORMAL;
2578       break;
2579     case GTK_RC_TOKEN_PRELIGHT:
2580       *state = GTK_STATE_PRELIGHT;
2581       break;
2582     case GTK_RC_TOKEN_SELECTED:
2583       *state = GTK_STATE_SELECTED;
2584       break;
2585     default:
2586       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
2587     }
2588   
2589   token = g_scanner_get_next_token (scanner);
2590   if (token != G_TOKEN_RIGHT_BRACE)
2591     return G_TOKEN_RIGHT_BRACE;
2592   
2593   g_scanner_set_scope (scanner, old_scope);
2594
2595   return G_TOKEN_NONE;
2596 }
2597
2598 guint
2599 gtk_rc_parse_priority (GScanner            *scanner,
2600                        GtkPathPriorityType *priority)
2601 {
2602   guint old_scope;
2603   guint token;
2604
2605   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2606   g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
2607
2608   /* we don't know where we got called from, so we reset the scope here.
2609    * if we bail out due to errors, we *don't* reset the scope, so the
2610    * error messaging code can make sense of our tokens.
2611    */
2612   old_scope = g_scanner_set_scope (scanner, 0);
2613   
2614   token = g_scanner_get_next_token (scanner);
2615   if (token != ':')
2616     return ':';
2617   
2618   token = g_scanner_get_next_token (scanner);
2619   switch (token)
2620     {
2621     case GTK_RC_TOKEN_LOWEST:
2622       *priority = GTK_PATH_PRIO_LOWEST;
2623       break;
2624     case GTK_RC_TOKEN_GTK:
2625       *priority = GTK_PATH_PRIO_GTK;
2626       break;
2627     case GTK_RC_TOKEN_APPLICATION:
2628       *priority = GTK_PATH_PRIO_APPLICATION;
2629       break;
2630     case GTK_RC_TOKEN_RC:
2631       *priority = GTK_PATH_PRIO_RC;
2632       break;
2633     case GTK_RC_TOKEN_HIGHEST:
2634       *priority = GTK_PATH_PRIO_HIGHEST;
2635       break;
2636     default:
2637       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
2638     }
2639   
2640   g_scanner_set_scope (scanner, old_scope);
2641
2642   return G_TOKEN_NONE;
2643 }
2644
2645 guint
2646 gtk_rc_parse_color (GScanner *scanner,
2647                     GdkColor *color)
2648 {
2649   guint token;
2650
2651   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2652
2653   /* we don't need to set our own scope here, because
2654    * we don't need own symbols
2655    */
2656   
2657   token = g_scanner_get_next_token (scanner);
2658   switch (token)
2659     {
2660       gint token_int;
2661       gint length;
2662       gint temp;
2663       gchar buf[9];
2664       gint i, j;
2665       
2666     case G_TOKEN_LEFT_CURLY:
2667       token = g_scanner_get_next_token (scanner);
2668       if (token == G_TOKEN_INT)
2669         token_int = scanner->value.v_int;
2670       else if (token == G_TOKEN_FLOAT)
2671         token_int = scanner->value.v_float * 65535.0;
2672       else
2673         return G_TOKEN_FLOAT;
2674       color->red = CLAMP (token_int, 0, 65535);
2675       
2676       token = g_scanner_get_next_token (scanner);
2677       if (token != G_TOKEN_COMMA)
2678         return G_TOKEN_COMMA;
2679       
2680       token = g_scanner_get_next_token (scanner);
2681       if (token == G_TOKEN_INT)
2682         token_int = scanner->value.v_int;
2683       else if (token == G_TOKEN_FLOAT)
2684         token_int = scanner->value.v_float * 65535.0;
2685       else
2686         return G_TOKEN_FLOAT;
2687       color->green = CLAMP (token_int, 0, 65535);
2688       
2689       token = g_scanner_get_next_token (scanner);
2690       if (token != G_TOKEN_COMMA)
2691         return G_TOKEN_COMMA;
2692       
2693       token = g_scanner_get_next_token (scanner);
2694       if (token == G_TOKEN_INT)
2695         token_int = scanner->value.v_int;
2696       else if (token == G_TOKEN_FLOAT)
2697         token_int = scanner->value.v_float * 65535.0;
2698       else
2699         return G_TOKEN_FLOAT;
2700       color->blue = CLAMP (token_int, 0, 65535);
2701       
2702       token = g_scanner_get_next_token (scanner);
2703       if (token != G_TOKEN_RIGHT_CURLY)
2704         return G_TOKEN_RIGHT_CURLY;
2705       return G_TOKEN_NONE;
2706       
2707     case G_TOKEN_STRING:
2708       if (scanner->value.v_string[0] != '#')
2709         return G_TOKEN_STRING;
2710       
2711       length = strlen (scanner->value.v_string) - 1;
2712       if (((length % 3) != 0) || (length > 12))
2713         return G_TOKEN_STRING;
2714       length /= 3;
2715       
2716       for (i = 0, j = 1; i < length; i++, j++)
2717         buf[i] = scanner->value.v_string[j];
2718       buf[i] = '\0';
2719       
2720       sscanf (buf, "%x", &temp);
2721       color->red = temp;
2722       
2723       for (i = 0; i < length; i++, j++)
2724         buf[i] = scanner->value.v_string[j];
2725       buf[i] = '\0';
2726       
2727       sscanf (buf, "%x", &temp);
2728       color->green = temp;
2729       
2730       for (i = 0; i < length; i++, j++)
2731         buf[i] = scanner->value.v_string[j];
2732       buf[i] = '\0';
2733       
2734       sscanf (buf, "%x", &temp);
2735       color->blue = temp;
2736       
2737       if (length == 1)
2738         {
2739           color->red *= 4369;
2740           color->green *= 4369;
2741           color->blue *= 4369;
2742         }
2743       else if (length == 2)
2744         {
2745           color->red *= 257;
2746           color->green *= 257;
2747           color->blue *= 257;
2748         }
2749       else if (length == 3)
2750         {
2751           color->red *= 16;
2752           color->green *= 16;
2753           color->blue *= 16;
2754         }
2755       return G_TOKEN_NONE;
2756       
2757     default:
2758       return G_TOKEN_STRING;
2759     }
2760 }
2761
2762 static guint
2763 gtk_rc_parse_pixmap_path (GScanner *scanner)
2764 {
2765   guint token;
2766   
2767   token = g_scanner_get_next_token (scanner);
2768   if (token != GTK_RC_TOKEN_PIXMAP_PATH)
2769     return GTK_RC_TOKEN_PIXMAP_PATH;
2770   
2771   token = g_scanner_get_next_token (scanner);
2772   if (token != G_TOKEN_STRING)
2773     return G_TOKEN_STRING;
2774   
2775   gtk_rc_parse_pixmap_path_string (scanner->value.v_string);
2776   
2777   return G_TOKEN_NONE;
2778 }
2779
2780 static void
2781 gtk_rc_parse_pixmap_path_string (gchar *pix_path)
2782 {
2783   gchar *buf;
2784   gint end_offset;
2785   gint start_offset = 0;
2786   gint path_len;
2787   gint path_num;
2788   
2789   /* free the old one, or just add to the old one ? */
2790   for (path_num=0; pixmap_path[path_num]; path_num++)
2791     {
2792       g_free (pixmap_path[path_num]);
2793       pixmap_path[path_num] = NULL;
2794     }
2795   
2796   path_num = 0;
2797   
2798   path_len = strlen (pix_path);
2799   
2800   buf = g_strdup (pix_path);
2801   
2802   for (end_offset = 0; end_offset <= path_len; end_offset++)
2803     {
2804       if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2805           (end_offset == path_len))
2806         {
2807           buf[end_offset] = '\0';
2808           pixmap_path[path_num] = g_strdup (buf + start_offset);
2809           path_num++;
2810           pixmap_path[path_num] = NULL;
2811           start_offset = end_offset + 1;
2812         }
2813     }
2814   g_free (buf);
2815 }
2816
2817 static guint
2818 gtk_rc_parse_module_path (GScanner *scanner)
2819 {
2820   guint token;
2821   
2822   token = g_scanner_get_next_token (scanner);
2823   if (token != GTK_RC_TOKEN_MODULE_PATH)
2824     return GTK_RC_TOKEN_MODULE_PATH;
2825   
2826   token = g_scanner_get_next_token (scanner);
2827   if (token != G_TOKEN_STRING)
2828     return G_TOKEN_STRING;
2829   
2830   gtk_rc_parse_module_path_string (scanner->value.v_string);
2831   
2832   return G_TOKEN_NONE;
2833 }
2834
2835 static guint
2836 gtk_rc_parse_im_module_path (GScanner *scanner)
2837 {
2838   guint token;
2839   
2840   token = g_scanner_get_next_token (scanner);
2841   if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
2842     return GTK_RC_TOKEN_IM_MODULE_FILE;
2843   
2844   token = g_scanner_get_next_token (scanner);
2845   if (token != G_TOKEN_STRING)
2846     return G_TOKEN_STRING;
2847
2848   if (im_module_path)
2849     g_free (im_module_path);
2850     
2851   im_module_path = g_strdup (scanner->value.v_string);
2852
2853   return G_TOKEN_NONE;
2854 }
2855
2856 static guint
2857 gtk_rc_parse_im_module_file (GScanner *scanner)
2858 {
2859   guint token;
2860   
2861   token = g_scanner_get_next_token (scanner);
2862   if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
2863     return GTK_RC_TOKEN_IM_MODULE_FILE;
2864   
2865   token = g_scanner_get_next_token (scanner);
2866   if (token != G_TOKEN_STRING)
2867     return G_TOKEN_STRING;
2868
2869   if (im_module_file)
2870     g_free (im_module_file);
2871     
2872   im_module_file = g_strdup (scanner->value.v_string);
2873
2874   return G_TOKEN_NONE;
2875 }
2876
2877 static void
2878 gtk_rc_parse_module_path_string (gchar *mod_path)
2879 {
2880   gchar *buf;
2881   gint end_offset;
2882   gint start_offset = 0;
2883   gint path_len;
2884   gint path_num;
2885   
2886   /* free the old one, or just add to the old one ? */
2887   for (path_num=0; module_path[path_num]; path_num++)
2888     {
2889       g_free (module_path[path_num]);
2890       module_path[path_num] = NULL;
2891     }
2892   
2893   path_num = 0;
2894   
2895   path_len = strlen (mod_path);
2896   
2897   buf = g_strdup (mod_path);
2898   
2899   for (end_offset = 0; end_offset <= path_len; end_offset++)
2900     {
2901       if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2902           (end_offset == path_len))
2903         {
2904           buf[end_offset] = '\0';
2905           module_path[path_num] = g_strdup (buf + start_offset);
2906           path_num++;
2907           module_path[path_num] = NULL;
2908           start_offset = end_offset + 1;
2909         }
2910     }
2911   g_free (buf);
2912   gtk_rc_append_default_module_path();
2913 }
2914
2915 static guint
2916 gtk_rc_parse_path_pattern (GScanner   *scanner)
2917 {
2918   guint token;
2919   GtkPathType path_type;
2920   gchar *pattern;
2921   gboolean is_binding;
2922   GtkPathPriorityType priority = GTK_PATH_PRIO_RC;
2923   
2924   token = g_scanner_get_next_token (scanner);
2925   switch (token)
2926     {
2927     case GTK_RC_TOKEN_WIDGET:
2928       path_type = GTK_PATH_WIDGET;
2929       break;
2930     case GTK_RC_TOKEN_WIDGET_CLASS:
2931       path_type = GTK_PATH_WIDGET_CLASS;
2932       break;
2933     case GTK_RC_TOKEN_CLASS:
2934       path_type = GTK_PATH_CLASS;
2935       break;
2936     default:
2937       return GTK_RC_TOKEN_WIDGET_CLASS;
2938     }
2939   
2940   token = g_scanner_get_next_token (scanner);
2941   if (token != G_TOKEN_STRING)
2942     return G_TOKEN_STRING;
2943
2944   pattern = g_strdup (scanner->value.v_string);
2945
2946   token = g_scanner_get_next_token (scanner);
2947   if (token == GTK_RC_TOKEN_STYLE)
2948     is_binding = FALSE;
2949   else if (token == GTK_RC_TOKEN_BINDING)
2950     {
2951       is_binding = TRUE;
2952       if (g_scanner_peek_next_token (scanner) == ':')
2953         {
2954           token = gtk_rc_parse_priority (scanner, &priority);
2955           if (token != G_TOKEN_NONE)
2956             {
2957               g_free (pattern);
2958               return token;
2959             }
2960         }
2961     }
2962   else
2963     {
2964       g_free (pattern);
2965       return GTK_RC_TOKEN_STYLE;
2966     }
2967   
2968   token = g_scanner_get_next_token (scanner);
2969   if (token != G_TOKEN_STRING)
2970     {
2971       g_free (pattern);
2972       return G_TOKEN_STRING;
2973     }
2974
2975   if (is_binding)
2976     {
2977       GtkBindingSet *binding;
2978
2979       binding = gtk_binding_set_find (scanner->value.v_string);
2980       if (!binding)
2981         {
2982           g_free (pattern);
2983           return G_TOKEN_STRING;
2984         }
2985       gtk_binding_set_add_path (binding, path_type, pattern, priority);
2986     }
2987   else
2988     {
2989       GtkRcStyle *rc_style;
2990       GtkRcSet *rc_set;
2991
2992       rc_style = gtk_rc_style_find (scanner->value.v_string);
2993       
2994       if (!rc_style)
2995         {
2996           g_free (pattern);
2997           return G_TOKEN_STRING;
2998         }
2999
3000       rc_set = g_new (GtkRcSet, 1);
3001       rc_set->pspec = g_pattern_spec_new (pattern);
3002       rc_set->rc_style = rc_style;
3003
3004       if (path_type == GTK_PATH_WIDGET)
3005         gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set);
3006       else if (path_type == GTK_PATH_WIDGET_CLASS)
3007         gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set);
3008       else
3009         gtk_rc_sets_class = g_slist_prepend (gtk_rc_sets_class, rc_set);
3010     }
3011
3012   g_free (pattern);
3013   return G_TOKEN_NONE;
3014 }
3015
3016 static guint
3017 gtk_rc_parse_stock_id (GScanner  *scanner,
3018                        gchar    **stock_id)
3019 {
3020   guint token;
3021   
3022   token = g_scanner_get_next_token (scanner);
3023   if (token != G_TOKEN_LEFT_BRACE)
3024     return G_TOKEN_LEFT_BRACE;
3025
3026   token = g_scanner_get_next_token (scanner);
3027   
3028   if (token != G_TOKEN_STRING)
3029     return G_TOKEN_STRING;
3030   
3031   *stock_id = g_strdup (scanner->value.v_string);
3032   
3033   token = g_scanner_get_next_token (scanner);
3034   if (token != G_TOKEN_RIGHT_BRACE)
3035     {
3036       g_free (*stock_id);
3037       return G_TOKEN_RIGHT_BRACE;
3038     }
3039   
3040   return G_TOKEN_NONE;
3041 }
3042
3043 static guint
3044 gtk_rc_parse_icon_source (GScanner       *scanner,
3045                           GtkIconSet     *icon_set)
3046 {
3047   guint token;
3048   GtkIconSource *source;
3049   
3050   token = g_scanner_get_next_token (scanner);
3051   if (token != G_TOKEN_LEFT_CURLY)
3052     return G_TOKEN_LEFT_CURLY;
3053
3054   token = g_scanner_get_next_token (scanner);
3055   
3056   if (token != G_TOKEN_STRING)
3057     return G_TOKEN_STRING;
3058
3059   source = gtk_icon_source_new ();
3060
3061   gtk_icon_source_set_filename (source, scanner->value.v_string);
3062   
3063   token = g_scanner_get_next_token (scanner);
3064
3065   if (token == G_TOKEN_RIGHT_CURLY)
3066     {
3067       gtk_icon_set_add_source (icon_set, source);
3068       gtk_icon_source_free (source);
3069       return G_TOKEN_NONE;
3070     }  
3071   else if (token != G_TOKEN_COMMA)
3072     {
3073       gtk_icon_source_free (source);
3074       return G_TOKEN_COMMA;
3075     }
3076
3077   /* Get the direction */
3078   
3079   token = g_scanner_get_next_token (scanner);
3080
3081   switch (token)
3082     {
3083     case GTK_RC_TOKEN_RTL:
3084       gtk_icon_source_set_direction_wildcarded (source, FALSE);
3085       gtk_icon_source_set_direction (source, GTK_TEXT_DIR_RTL);
3086       break;
3087
3088     case GTK_RC_TOKEN_LTR:
3089       gtk_icon_source_set_direction_wildcarded (source, FALSE);
3090       gtk_icon_source_set_direction (source, GTK_TEXT_DIR_LTR);
3091       break;
3092       
3093     case '*':
3094       break;
3095       
3096     default:
3097       gtk_icon_source_free (source);
3098       return GTK_RC_TOKEN_RTL;
3099       break;
3100     }
3101
3102   token = g_scanner_get_next_token (scanner);
3103
3104   if (token == G_TOKEN_RIGHT_CURLY)
3105     {
3106       gtk_icon_set_add_source (icon_set, source);
3107       gtk_icon_source_free (source);
3108       return G_TOKEN_NONE;
3109     }  
3110   else if (token != G_TOKEN_COMMA)
3111     {
3112       gtk_icon_source_free (source);
3113       return G_TOKEN_COMMA;
3114     }
3115
3116   /* Get the state */
3117   
3118   token = g_scanner_get_next_token (scanner);
3119   
3120   switch (token)
3121     {
3122     case GTK_RC_TOKEN_NORMAL:
3123       gtk_icon_source_set_state_wildcarded (source, FALSE);
3124       gtk_icon_source_set_state (source, GTK_STATE_NORMAL);
3125       break;
3126
3127     case GTK_RC_TOKEN_PRELIGHT:
3128       gtk_icon_source_set_state_wildcarded (source, FALSE);
3129       gtk_icon_source_set_state (source, GTK_STATE_PRELIGHT);
3130       break;
3131       
3132
3133     case GTK_RC_TOKEN_INSENSITIVE:
3134       gtk_icon_source_set_state_wildcarded (source, FALSE);
3135       gtk_icon_source_set_state (source, GTK_STATE_INSENSITIVE);
3136       break;
3137
3138     case GTK_RC_TOKEN_ACTIVE:
3139       gtk_icon_source_set_state_wildcarded (source, FALSE);
3140       gtk_icon_source_set_state (source, GTK_STATE_ACTIVE);
3141       break;
3142
3143     case GTK_RC_TOKEN_SELECTED:
3144       gtk_icon_source_set_state_wildcarded (source, FALSE);
3145       gtk_icon_source_set_state (source, GTK_STATE_SELECTED);
3146       break;
3147
3148     case '*':
3149       break;
3150       
3151     default:
3152       gtk_icon_source_free (source);
3153       return GTK_RC_TOKEN_PRELIGHT;
3154       break;
3155     }  
3156
3157   token = g_scanner_get_next_token (scanner);
3158
3159   if (token == G_TOKEN_RIGHT_CURLY)
3160     {
3161       gtk_icon_set_add_source (icon_set, source);
3162       gtk_icon_source_free (source);
3163       return G_TOKEN_NONE;
3164     }
3165   else if (token != G_TOKEN_COMMA)
3166     {
3167       gtk_icon_source_free (source);
3168       return G_TOKEN_COMMA;
3169     }
3170   
3171   /* Get the size */
3172   
3173   token = g_scanner_get_next_token (scanner);
3174
3175   if (token != '*')
3176     {
3177       GtkIconSize size;
3178       
3179       if (token != G_TOKEN_STRING)
3180         {
3181           gtk_icon_source_free (source);
3182           return G_TOKEN_STRING;
3183         }
3184
3185       size = gtk_icon_size_from_name (scanner->value.v_string);
3186
3187       if (size != GTK_ICON_SIZE_INVALID)
3188         {
3189           gtk_icon_source_set_size_wildcarded (source, FALSE);
3190           gtk_icon_source_set_size (source, size);
3191         }
3192     }
3193
3194   /* Check the close brace */
3195   
3196   token = g_scanner_get_next_token (scanner);
3197   if (token != G_TOKEN_RIGHT_CURLY)
3198     {
3199       gtk_icon_source_free (source);
3200       return G_TOKEN_RIGHT_CURLY;
3201     }
3202
3203   gtk_icon_set_add_source (icon_set, source);
3204
3205   gtk_icon_source_free (source);
3206   
3207   return G_TOKEN_NONE;
3208 }
3209
3210 static guint
3211 gtk_rc_parse_stock (GScanner       *scanner,
3212                     GtkRcStyle     *rc_style,
3213                     GtkIconFactory *factory)
3214 {
3215   GtkIconSet *icon_set = NULL;
3216   gchar *stock_id = NULL;
3217   guint token;
3218   
3219   token = g_scanner_get_next_token (scanner);
3220   if (token != GTK_RC_TOKEN_STOCK)
3221     return GTK_RC_TOKEN_STOCK;
3222   
3223   token = gtk_rc_parse_stock_id (scanner, &stock_id);
3224   if (token != G_TOKEN_NONE)
3225     return token;
3226   
3227   token = g_scanner_get_next_token (scanner);
3228   if (token != G_TOKEN_EQUAL_SIGN)
3229     {
3230       g_free (stock_id);
3231       return G_TOKEN_EQUAL_SIGN;
3232     }
3233
3234   token = g_scanner_get_next_token (scanner);
3235   if (token != G_TOKEN_LEFT_CURLY)
3236     {
3237       g_free (stock_id);
3238       return G_TOKEN_LEFT_CURLY;
3239     }
3240
3241   token = g_scanner_peek_next_token (scanner);
3242   while (token != G_TOKEN_RIGHT_CURLY)
3243     {
3244       if (icon_set == NULL)
3245         icon_set = gtk_icon_set_new ();
3246       
3247       token = gtk_rc_parse_icon_source (scanner, icon_set);
3248       if (token != G_TOKEN_NONE)
3249         {
3250           g_free (stock_id);
3251           gtk_icon_set_unref (icon_set);
3252           return token;
3253         }
3254
3255       token = g_scanner_get_next_token (scanner);
3256       
3257       if (token != G_TOKEN_COMMA &&
3258           token != G_TOKEN_RIGHT_CURLY)
3259         {
3260           g_free (stock_id);
3261           gtk_icon_set_unref (icon_set);
3262           return G_TOKEN_RIGHT_CURLY;
3263         }
3264     }
3265
3266   if (icon_set)
3267     {
3268       gtk_icon_factory_add (factory,
3269                             stock_id,
3270                             icon_set);
3271       
3272       gtk_icon_set_unref (icon_set);
3273     }
3274   
3275   g_free (stock_id);
3276
3277   return G_TOKEN_NONE;
3278 }
3279
3280 /*
3281 typedef  GdkPixmap * (*GtkImageLoader) (GdkWindow   *window,
3282                                         GdkColormap *colormap,
3283                                         GdkBitmap  **mask,
3284                                         GdkColor    *transparent_color,
3285                                         const gchar *filename);
3286 */
3287
3288 void
3289 gtk_rc_set_image_loader(GtkImageLoader loader)
3290 {
3291   image_loader = loader;
3292 }
3293
3294 GdkPixmap *
3295 gtk_rc_load_image (GdkColormap *colormap,
3296                    GdkColor    *transparent_color,
3297                    const gchar *filename)
3298 {
3299   if (strcmp (filename, "<parent>") == 0)
3300     return (GdkPixmap*) GDK_PARENT_RELATIVE;
3301   else
3302     {
3303       if(image_loader)
3304         return image_loader(NULL, colormap, NULL,
3305                             transparent_color,
3306                             filename);
3307       else
3308         return gdk_pixmap_colormap_create_from_xpm (NULL, colormap, NULL,
3309                                                     transparent_color,
3310                                                     filename);
3311     }
3312 }