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