]> Pileus Git - ~andy/gtk/blob - gtk/gtkrc.c
cf97c48ae848f64bec42e0797f0af8be16eade8b
[~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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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-1999.  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
64 typedef struct _GtkRcSet    GtkRcSet;
65 typedef struct _GtkRcNode   GtkRcNode;
66 typedef struct _GtkRcFile   GtkRcFile;
67 typedef struct _GtkRcStylePrivate  GtkRcStylePrivate;
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 struct _GtkRcStylePrivate
84 {
85   GtkRcStyle style;
86
87   guint ref_count;
88   /* list of RC style lists including this RC style */
89   GSList *rc_style_lists;
90 };
91
92 static guint       gtk_rc_style_hash               (const char   *name);
93 static gint        gtk_rc_style_compare            (const char   *a,
94                                                     const char   *b);
95 static guint       gtk_rc_styles_hash              (const GSList *rc_styles);
96 static gint        gtk_rc_styles_compare           (const GSList *a,
97                                                     const GSList *b);
98 static GtkRcStyle* gtk_rc_style_find               (const char   *name);
99 static GSList *    gtk_rc_styles_match             (GSList       *rc_styles,
100                                                     GSList       *sets,
101                                                     guint         path_length,
102                                                     gchar        *path,
103                                                     gchar        *path_reversed);
104 static GtkStyle *  gtk_rc_style_to_style           (GtkRcStyle   *rc_style);
105 static GtkStyle*   gtk_rc_style_init               (GSList       *rc_styles);
106 static void        gtk_rc_parse_file               (const gchar  *filename,
107                                                     gboolean      reload);
108
109 static void        gtk_rc_parse_any                (const gchar  *input_name,
110                                                     gint          input_fd,
111                                                     const gchar  *input_string);
112 static guint       gtk_rc_parse_statement          (GScanner     *scanner);
113 static guint       gtk_rc_parse_style              (GScanner     *scanner);
114 static guint       gtk_rc_parse_base               (GScanner     *scanner,
115                                                     GtkRcStyle   *style);
116 static guint       gtk_rc_parse_bg                 (GScanner     *scanner,
117                                                     GtkRcStyle   *style);
118 static guint       gtk_rc_parse_fg                 (GScanner     *scanner,
119                                                     GtkRcStyle   *style);
120 static guint       gtk_rc_parse_text               (GScanner     *scanner,
121                                                     GtkRcStyle   *style);
122 static guint       gtk_rc_parse_bg_pixmap          (GScanner     *scanner,
123                                                     GtkRcStyle   *rc_style);
124 static guint       gtk_rc_parse_font               (GScanner     *scanner,
125                                                     GtkRcStyle   *rc_style);
126 static guint       gtk_rc_parse_fontset            (GScanner     *scanner,
127                                                     GtkRcStyle   *rc_style);
128 static guint       gtk_rc_parse_engine             (GScanner     *scanner,
129                                                     GtkRcStyle   *rc_style);
130 static guint       gtk_rc_parse_pixmap_path        (GScanner     *scanner);
131 static void        gtk_rc_parse_pixmap_path_string (gchar *pix_path);
132 static guint       gtk_rc_parse_module_path        (GScanner     *scanner);
133 static void        gtk_rc_parse_module_path_string (gchar *mod_path);
134 static guint       gtk_rc_parse_path_pattern       (GScanner     *scanner);
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_pixmap_path (void);
140 static void        gtk_rc_append_default_module_path (void);
141 static void        gtk_rc_add_initial_default_files  (void);
142
143
144 static const GScannerConfig     gtk_rc_scanner_config =
145 {
146   (
147    " \t\r\n"
148    )                    /* cset_skip_characters */,
149   (
150    G_CSET_a_2_z
151    "_"
152    G_CSET_A_2_Z
153    )                    /* cset_identifier_first */,
154   (
155    G_CSET_a_2_z
156    "_-0123456789"
157    G_CSET_A_2_Z
158    )                    /* cset_identifier_nth */,
159   ( "#\n" )             /* cpair_comment_single */,
160   
161   TRUE                  /* case_sensitive */,
162   
163   TRUE                  /* skip_comment_multi */,
164   TRUE                  /* skip_comment_single */,
165   TRUE                  /* scan_comment_multi */,
166   TRUE                  /* scan_identifier */,
167   FALSE                 /* scan_identifier_1char */,
168   FALSE                 /* scan_identifier_NULL */,
169   TRUE                  /* scan_symbols */,
170   TRUE                  /* scan_binary */,
171   TRUE                  /* scan_octal */,
172   TRUE                  /* scan_float */,
173   TRUE                  /* scan_hex */,
174   TRUE                  /* scan_hex_dollar */,
175   TRUE                  /* scan_string_sq */,
176   TRUE                  /* scan_string_dq */,
177   TRUE                  /* numbers_2_int */,
178   FALSE                 /* int_2_float */,
179   FALSE                 /* identifier_2_string */,
180   TRUE                  /* char_2_token */,
181   TRUE                  /* symbol_2_token */,
182   FALSE                 /* scope_0_fallback */,
183 };
184
185 static const struct
186 {
187   gchar *name;
188   guint token;
189 } symbols[] = {
190   { "include", GTK_RC_TOKEN_INCLUDE },
191   { "NORMAL", GTK_RC_TOKEN_NORMAL },
192   { "ACTIVE", GTK_RC_TOKEN_ACTIVE },
193   { "PRELIGHT", GTK_RC_TOKEN_PRELIGHT },
194   { "SELECTED", GTK_RC_TOKEN_SELECTED },
195   { "INSENSITIVE", GTK_RC_TOKEN_INSENSITIVE },
196   { "fg", GTK_RC_TOKEN_FG },
197   { "bg", GTK_RC_TOKEN_BG },
198   { "base", GTK_RC_TOKEN_BASE },
199   { "text", GTK_RC_TOKEN_TEXT },
200   { "font", GTK_RC_TOKEN_FONT },
201   { "fontset", GTK_RC_TOKEN_FONTSET },
202   { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP },
203   { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH },
204   { "style", GTK_RC_TOKEN_STYLE },
205   { "binding", GTK_RC_TOKEN_BINDING },
206   { "bind", GTK_RC_TOKEN_BIND },
207   { "widget", GTK_RC_TOKEN_WIDGET },
208   { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS },
209   { "class", GTK_RC_TOKEN_CLASS },
210   { "lowest", GTK_RC_TOKEN_LOWEST },
211   { "gtk", GTK_RC_TOKEN_GTK },
212   { "application", GTK_RC_TOKEN_APPLICATION },
213   { "rc", GTK_RC_TOKEN_RC },
214   { "highest", GTK_RC_TOKEN_HIGHEST },
215   { "engine", GTK_RC_TOKEN_ENGINE },
216   { "module_path", GTK_RC_TOKEN_MODULE_PATH },
217 };
218
219 static const guint n_symbols = sizeof (symbols) / sizeof (symbols[0]);
220
221 static GHashTable *rc_style_ht = NULL;
222 static GHashTable *realized_style_ht = NULL;
223 static GSList *gtk_rc_sets_widget = NULL;
224 static GSList *gtk_rc_sets_widget_class = NULL;
225 static GSList *gtk_rc_sets_class = NULL;
226
227 #define GTK_RC_MAX_DEFAULT_FILES 128
228 static gchar *gtk_rc_default_files[GTK_RC_MAX_DEFAULT_FILES];
229 static gboolean gtk_rc_auto_parse = TRUE;
230
231 #define GTK_RC_MAX_PIXMAP_PATHS 128
232 static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
233 #define GTK_RC_MAX_MODULE_PATHS 128
234 static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
235
236 /* A stack of directories for RC files we are parsing currently.
237  * these are implicitely added to the end of PIXMAP_PATHS
238  */
239 GSList *rc_dir_stack = NULL;
240
241 /* The files we have parsed, to reread later if necessary */
242 GSList *rc_files = NULL;
243
244 static GtkImageLoader image_loader = NULL;
245
246 /* RC file handling */
247
248
249 #ifdef G_OS_WIN32
250
251 gchar *
252 get_gtk_sysconf_directory (void)
253 {
254   static gchar gtk_sysconf_dir[200];
255   gchar win_dir[100];
256
257   GetWindowsDirectory (win_dir, sizeof (win_dir));
258   sprintf (gtk_sysconf_dir, "%s\\gtk+", win_dir);
259   return gtk_sysconf_dir;
260 }
261
262 static gchar *
263 get_themes_directory (void)
264 {
265   /* We really should fetch this from the Registry. The GIMP
266    * installation program stores the Themes installation
267    * directory in HKLM\Software\GNU\GTk+\Themes\InstallDirectory.
268    * Later.
269    */
270   static gchar themes_dir[200];
271
272   sprintf (themes_dir, "%s\\themes", get_gtk_sysconf_directory ());
273   return themes_dir;
274 }
275
276 #endif
277  
278 gchar *
279 gtk_rc_get_theme_dir(void)
280 {
281   gchar *var, *path;
282
283 #ifndef G_OS_WIN32
284   var = getenv("GTK_DATA_PREFIX");
285   if (var)
286     path = g_strdup_printf("%s%s", var, "/share/themes");
287   else
288     path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/themes");
289 #else
290   path = g_strdup (get_themes_directory ());
291 #endif
292
293   return path;
294 }
295
296 gchar *
297 gtk_rc_get_module_dir(void)
298 {
299   gchar *var, *path;
300
301 #ifndef G_OS_WIN32
302   var = getenv("GTK_EXE_PREFIX");
303   if (var)
304     path = g_strdup_printf("%s%s", var, "/lib/gtk/themes/engines");
305   else
306     path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk/themes/engines");
307 #else
308   path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
309 #endif
310
311   return path;
312 }
313
314 static void
315 gtk_rc_append_default_pixmap_path(void)
316 {
317   gchar *var, *path;
318   gint n;
319
320 #ifndef G_OS_WIN32
321   var = getenv("GTK_DATA_PREFIX");
322   if (var)
323     path = g_strdup_printf("%s%s", var, "/share/gtk/themes");
324   else
325     path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/gtk/themes");
326 #else
327   path = g_strdup (get_themes_directory ());
328 #endif      
329   
330   for (n = 0; pixmap_path[n]; n++) ;
331   if (n >= GTK_RC_MAX_PIXMAP_PATHS - 1)
332     {
333       g_free (path);
334       return;
335     }
336   pixmap_path[n++] = path;
337   pixmap_path[n] = NULL;
338 }
339
340 static void
341 gtk_rc_append_default_module_path(void)
342 {
343   gchar *var, *path;
344   gint n;
345
346   for (n = 0; module_path[n]; n++) ;
347   if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
348     return;
349   
350 #ifndef G_OS_WIN32
351   var = getenv("GTK_EXE_PREFIX");
352   if (var)
353     path = g_strdup_printf("%s%s", var, "/lib/gtk/themes/engines");
354   else
355     path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk/themes/engines");
356 #else
357   path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
358 #endif
359   module_path[n++] = path;
360
361   var = g_get_home_dir ();
362   if (var)
363     {
364 #ifndef G_OS_WIN32
365       path = g_strdup_printf ("%s%s", var, "/.gtk/lib/themes/engines");
366 #else
367       path = g_strdup_printf ("%s%s", var, "\\_gtk\\themes\\engines");
368 #endif
369       module_path[n++] = path;
370     }
371   module_path[n] = NULL;
372 }
373
374 static void
375 gtk_rc_add_initial_default_files (void)
376 {
377   static gint init = FALSE;
378   gchar *var, *str;
379   gchar **files;
380   gint i;
381
382   if (init)
383     return;
384   
385   gtk_rc_default_files[0] = NULL;
386   init = TRUE;
387
388   var = g_getenv("GTK_RC_FILES");
389   if (var)
390     {
391       files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
392       i=0;
393       while (files[i])
394         {
395           gtk_rc_add_default_file (files[i]);
396           i++;
397         }
398       g_strfreev (files);
399     }
400   else
401     {
402 #ifndef G_OS_WIN32
403       str = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk" G_DIR_SEPARATOR_S "gtkrc");
404 #else
405       str = g_strdup_printf ("%s\\gtkrc", get_gtk_sysconf_directory ());
406 #endif
407       gtk_rc_add_default_file (str);
408       g_free (str);
409
410       var = g_get_home_dir ();
411       if (var)
412         {
413           str = g_strdup_printf ("%s" G_DIR_SEPARATOR_S ".gtkrc", var);
414           gtk_rc_add_default_file (str);
415           g_free (str);
416         }
417     }
418 }
419
420 void
421 gtk_rc_add_default_file (const gchar *file)
422 {
423   guint n;
424   
425   gtk_rc_add_initial_default_files ();
426
427   for (n = 0; gtk_rc_default_files[n]; n++) ;
428   if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
429     return;
430   
431   gtk_rc_default_files[n++] = g_strdup (file);
432   gtk_rc_default_files[n] = NULL;
433 }
434
435 void
436 gtk_rc_set_default_files (gchar **files)
437 {
438   gint i;
439
440   gtk_rc_add_initial_default_files ();
441
442   i = 0;
443   while (gtk_rc_default_files[i])
444     {
445       g_free (gtk_rc_default_files[i]);
446       i++;
447     }
448     
449   gtk_rc_default_files[0] = NULL;
450   gtk_rc_auto_parse = FALSE;
451
452   i = 0;
453   while (files[i] != NULL)
454     {
455       gtk_rc_add_default_file (files[i]);
456       i++;
457     }
458 }
459
460 gchar **
461 gtk_rc_get_default_files (void)
462 {
463   gtk_rc_add_initial_default_files ();
464
465   return gtk_rc_default_files;
466 }
467
468  /* The following routine is based on _nl_normalize_codeset from
469   * the GNU C library. Contributed by
470   *
471   * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
472   * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
473   * 
474   * Normalize codeset name.  There is no standard for the codeset
475   * names.  Normalization allows the user to use any of the common
476   * names.
477   */
478  static char *
479  _gtk_normalize_codeset (const char *codeset, int name_len)
480  {
481    int len = 0;
482    int only_digit = 1;
483    char *retval;
484    char *wp;
485    int cnt;
486  
487    for (cnt = 0; cnt < name_len; ++cnt)
488      if (isalnum (codeset[cnt]))
489        {
490         ++len;
491  
492         if (isalpha (codeset[cnt]))
493           only_digit = 0;
494        }
495  
496    retval = g_malloc ((only_digit ? 3 : 0) + len + 1);
497  
498    if (only_digit)
499      {
500        strcpy (retval, "iso");
501        wp = retval + 3;
502      }
503    else
504      wp = retval;
505    
506    for (cnt = 0; cnt < name_len; ++cnt)
507      if (isalpha (codeset[cnt]))
508        *wp++ = isupper(codeset[cnt]) ? tolower (codeset[cnt]) : codeset[cnt];
509      else if (isdigit (codeset[cnt]))
510        *wp++ = codeset[cnt];
511    
512    *wp = '\0';
513  
514    return retval;
515  }
516  
517 void
518 gtk_rc_init (void)
519 {
520   static gchar *locale_suffixes[3];
521   static gint n_locale_suffixes = 0;
522
523   gint i, j;
524
525   static gboolean initted = FALSE;
526
527   if (!initted)
528     {
529       gint length;
530       gchar *locale;
531       gchar *p;
532
533 #ifdef G_OS_WIN32      
534       locale = g_win32_getlocale ();
535 #else      
536       locale = setlocale (LC_CTYPE, NULL);
537 #endif      
538       
539       initted = TRUE;
540
541       pixmap_path[0] = NULL;
542       module_path[0] = NULL;
543       gtk_rc_append_default_pixmap_path();
544       gtk_rc_append_default_module_path();
545       
546       gtk_rc_add_initial_default_files ();
547
548       if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
549         {
550           /* Determine locale-specific suffixes for RC files
551            *
552            * We normalize the charset into a standard form,
553            * which has all '-' and '_' characters removed,
554            * and is lowercase.
555            */
556           gchar *normalized_locale;
557
558           p = strchr (locale, '@');
559           length = p ? (p -locale) : strlen (locale);
560
561           p = strchr (locale, '.');
562           if (p)
563             {
564               gchar *tmp1 = g_strndup (locale, p - locale + 1);
565               gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
566               
567               normalized_locale = g_strconcat (tmp1, tmp2, NULL);
568               g_free (tmp1);
569               g_free (tmp2);
570                                                  
571               locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
572               length = p - locale;
573             }
574           else
575             normalized_locale = g_strndup (locale, length);
576           
577           p = strchr (normalized_locale, '_');
578           if (p)
579             {
580               locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
581               length = p - normalized_locale;
582             }
583           
584           locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
585
586           g_free (normalized_locale);
587         }
588     }
589   
590   i = 0;
591   while (gtk_rc_default_files[i] != NULL)
592     {
593       /* Try to find a locale specific RC file corresponding to
594        * to parse before the default file.
595        */
596       for (j=n_locale_suffixes-1; j>=0; j--)
597         {
598           gchar *name = g_strconcat (gtk_rc_default_files[i],
599                                      ".",
600                                      locale_suffixes[j],
601                                      NULL);
602           gtk_rc_parse (name);
603           g_free (name);
604         }
605
606       gtk_rc_parse (gtk_rc_default_files[i]);
607       i++;
608     }
609 }
610
611 void
612 gtk_rc_parse_string (const gchar *rc_string)
613 {
614   g_return_if_fail (rc_string != NULL);
615
616   gtk_rc_parse_any ("-", -1, rc_string);
617 }
618
619 static void
620 gtk_rc_parse_file (const gchar *filename, gboolean reload)
621 {
622   GtkRcFile *rc_file = NULL;
623   struct stat statbuf;
624   GSList *tmp_list;
625
626   g_return_if_fail (filename != NULL);
627
628   tmp_list = rc_files;
629   while (tmp_list)
630     {
631       rc_file = tmp_list->data;
632       if (!strcmp (rc_file->name, filename))
633         break;
634       
635       tmp_list = tmp_list->next;
636     }
637
638   if (!tmp_list)
639     {
640       rc_file = g_new (GtkRcFile, 1);
641       rc_file->name = g_strdup (filename);
642       rc_file->canonical_name = NULL;
643       rc_file->mtime = 0;
644       rc_file->reload = reload;
645
646       rc_files = g_slist_append (rc_files, rc_file);
647     }
648
649   if (!rc_file->canonical_name)
650     {
651       /* Get the absolute pathname */
652
653       if (g_path_is_absolute (rc_file->name))
654         rc_file->canonical_name = rc_file->name;
655       else
656         {
657           GString *str;
658           gchar *cwd;
659
660           cwd = g_get_current_dir ();
661
662           str = g_string_new (cwd);
663           g_free (cwd);
664           g_string_append_c (str, G_DIR_SEPARATOR);
665           g_string_append (str, rc_file->name);
666           
667           rc_file->canonical_name = str->str;
668           g_string_free (str, FALSE);
669         }
670     }
671
672   if (!lstat (rc_file->canonical_name, &statbuf))
673     {
674       gint fd;
675       GSList *tmp_list;
676
677       rc_file->mtime = statbuf.st_mtime;
678
679       fd = open (rc_file->canonical_name, O_RDONLY);
680       if (fd < 0)
681         return;
682
683       /* Temporarily push directory name for this file on
684        * a stack of directory names while parsing it
685        */
686       rc_dir_stack = g_slist_prepend (rc_dir_stack,
687                                       g_dirname (rc_file->canonical_name));
688       gtk_rc_parse_any (filename, fd, NULL);
689  
690       tmp_list = rc_dir_stack;
691       rc_dir_stack = rc_dir_stack->next;
692  
693       g_free (tmp_list->data);
694       g_slist_free_1 (tmp_list);
695
696       close (fd);
697     }
698 }
699
700 void
701 gtk_rc_parse (const gchar *filename)
702 {
703   g_return_if_fail (filename != NULL);
704
705   gtk_rc_parse_file (filename, TRUE);
706 }
707
708 /* Handling of RC styles */
709
710 GtkRcStyle *
711 gtk_rc_style_new              (void)
712 {
713   GtkRcStylePrivate *new_style;
714
715   new_style = g_new0 (GtkRcStylePrivate, 1);
716   new_style->ref_count = 1;
717
718   return (GtkRcStyle *)new_style;
719 }
720
721 void      
722 gtk_rc_style_ref (GtkRcStyle  *rc_style)
723 {
724   g_return_if_fail (rc_style != NULL);
725
726   ((GtkRcStylePrivate *)rc_style)->ref_count++;
727 }
728
729 /* Like g_slist_remove, but remove all copies of data */
730 static GSList*
731 gtk_rc_slist_remove_all (GSList   *list,
732                          gpointer  data)
733 {
734   GSList *tmp;
735   GSList *prev;
736
737   prev = NULL;
738   tmp = list;
739
740   while (tmp)
741     {
742       if (tmp->data == data)
743         {
744           if (list == tmp)
745             list = list->next;
746
747           if (prev) 
748             prev->next = tmp->next;
749
750           g_slist_free_1 (tmp);
751
752           if (prev)
753             tmp = prev->next;
754           else
755             tmp = list;
756         }
757       else
758         {
759           prev = tmp;
760           tmp = tmp->next;
761         }
762     }
763
764   return list;
765 }
766
767 void      
768 gtk_rc_style_unref (GtkRcStyle  *rc_style)
769 {
770   GtkRcStylePrivate *private = (GtkRcStylePrivate *)rc_style;
771   gint i;
772
773   g_return_if_fail (rc_style != NULL);
774   g_return_if_fail (private->ref_count > 0);
775
776   private->ref_count--;
777
778   if (private->ref_count == 0)
779     {
780       GSList *tmp_list1, *tmp_list2;
781         
782       if (rc_style->engine)
783         {
784           rc_style->engine->destroy_rc_style (rc_style);
785           gtk_theme_engine_unref (rc_style->engine);
786         }
787
788       if (rc_style->name)
789         g_free (rc_style->name);
790       if (rc_style->fontset_name)
791         g_free (rc_style->fontset_name);
792       if (rc_style->font_name)
793         g_free (rc_style->font_name);
794       
795       for (i=0 ; i<5 ; i++)
796         if (rc_style->bg_pixmap_name[i])
797           g_free (rc_style->bg_pixmap_name[i]);
798       
799       /* Now remove all references to this rc_style from
800        * realized_style_ht
801        */
802       tmp_list1 = private->rc_style_lists;
803       while (tmp_list1)
804         {
805           GSList *rc_styles = tmp_list1->data;
806           GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
807           gtk_style_unref (style);
808
809           /* Remove the list of styles from the other rc_styles
810            * in the list
811            */
812           tmp_list2 = rc_styles;
813           while (tmp_list2)
814             {
815               GtkRcStylePrivate *other_style = tmp_list2->data;
816
817               if (other_style != private)
818                 other_style->rc_style_lists =
819                   gtk_rc_slist_remove_all (other_style->rc_style_lists, rc_styles);
820                   
821               tmp_list2 = tmp_list2->next;
822             }
823
824           /* And from the hash table itself
825            */
826           g_hash_table_remove (realized_style_ht, rc_styles);
827           g_slist_free (rc_styles);
828
829           tmp_list1 = tmp_list1->next;
830         }
831       g_slist_free (private->rc_style_lists);
832
833       g_free (private);
834     }
835 }
836
837 static void
838 gtk_rc_clear_hash_node (gpointer key, 
839                         gpointer data, 
840                         gpointer user_data)
841 {
842   gtk_rc_style_unref (data);
843 }
844
845 static void
846 gtk_rc_free_rc_sets (GSList *slist)
847 {
848   while (slist)
849     {
850       GtkRcSet *rc_set;
851
852       rc_set = slist->data;
853       gtk_pattern_spec_free_segs (&rc_set->pspec);
854       g_free (rc_set);
855
856       slist = slist->next;
857     }
858 }
859
860 static void
861 gtk_rc_clear_styles (void)
862 {
863   /* Clear out all old rc_styles */
864
865   if (rc_style_ht)
866     {
867       g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
868       g_hash_table_destroy (rc_style_ht);
869       rc_style_ht = NULL;
870     }
871
872   gtk_rc_free_rc_sets (gtk_rc_sets_widget);
873   g_slist_free (gtk_rc_sets_widget);
874   gtk_rc_sets_widget = NULL;
875
876   gtk_rc_free_rc_sets (gtk_rc_sets_widget_class);
877   g_slist_free (gtk_rc_sets_widget_class);
878   gtk_rc_sets_widget_class = NULL;
879
880   gtk_rc_free_rc_sets (gtk_rc_sets_class);
881   g_slist_free (gtk_rc_sets_class);
882   gtk_rc_sets_class = NULL;
883 }
884
885 gboolean
886 gtk_rc_reparse_all (void)
887 {
888   GSList *tmp_list;
889   gboolean mtime_modified = FALSE;
890   GtkRcFile *rc_file;
891
892   struct stat statbuf;
893
894   /* Check through and see if any of the RC's have had their
895    * mtime modified. If so, reparse everything.
896    */
897   tmp_list = rc_files;
898   while (tmp_list)
899     {
900       rc_file = tmp_list->data;
901       
902       if (!lstat (rc_file->name, &statbuf) && 
903           (statbuf.st_mtime > rc_file->mtime))
904         {
905           mtime_modified = TRUE;
906           break;
907         }
908       
909       tmp_list = tmp_list->next;
910     }
911
912   if (mtime_modified)
913     {
914       gtk_rc_clear_styles();
915
916       tmp_list = rc_files;
917       while (tmp_list)
918         {
919           rc_file = tmp_list->data;
920           if (rc_file->reload)
921             gtk_rc_parse_file (rc_file->name, FALSE);
922           
923           tmp_list = tmp_list->next;
924         }
925     }
926
927   return mtime_modified;
928 }
929
930 static GSList *
931 gtk_rc_styles_match (GSList       *rc_styles,
932                      GSList       *sets,
933                      guint         path_length,
934                      gchar        *path,
935                      gchar        *path_reversed)
936                      
937 {
938   GtkRcSet *rc_set;
939
940   while (sets)
941     {
942       rc_set = sets->data;
943       sets = sets->next;
944
945       if (gtk_pattern_match (&rc_set->pspec, path_length, path, path_reversed))
946         rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
947     }
948   
949   return rc_styles;
950 }
951
952 GtkStyle*
953 gtk_rc_get_style (GtkWidget *widget)
954 {
955   GtkRcStyle *widget_rc_style;
956   GSList *rc_styles = NULL;
957
958   static guint rc_style_key_id = 0;
959
960   /* We allow the specification of a single rc style to be bound
961    * tightly to a widget, for application modifications
962    */
963   if (!rc_style_key_id)
964     rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
965
966   widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
967                                                rc_style_key_id);
968
969   if (widget_rc_style)
970     rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
971   
972   if (gtk_rc_sets_widget)
973     {
974       gchar *path, *path_reversed;
975       guint path_length;
976
977       gtk_widget_path (widget, &path_length, &path, &path_reversed);
978       rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget, path_length, path, path_reversed);
979       g_free (path);
980       g_free (path_reversed);
981       
982     }
983   
984   if (gtk_rc_sets_widget_class)
985     {
986       gchar *path, *path_reversed;
987       guint path_length;
988
989       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
990       rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget_class, path_length, path, path_reversed);
991       g_free (path);
992       g_free (path_reversed);
993     }
994
995   if (gtk_rc_sets_class)
996     {
997       GtkType type;
998
999       type = GTK_OBJECT_TYPE (widget);
1000       while (type)
1001         {
1002           gchar *path, *path_reversed;
1003           guint path_length;
1004
1005           path = gtk_type_name (type);
1006           path_length = strlen (path);
1007           path_reversed = g_strdup (path);
1008           g_strreverse (path_reversed);
1009           
1010           rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_class, path_length, path, path_reversed);
1011           g_free (path_reversed);
1012       
1013           type = gtk_type_parent (type);
1014         }
1015     }
1016   
1017   if (rc_styles)
1018     return gtk_rc_style_init (rc_styles);
1019
1020   return NULL;
1021 }
1022
1023 static GSList*
1024 gtk_rc_add_rc_sets (GSList     *slist,
1025                     GtkRcStyle *rc_style,
1026                     const char *pattern)
1027 {
1028   GtkRcStyle *new_style;
1029   GtkRcSet *rc_set;
1030   guint i;
1031   
1032   new_style = gtk_rc_style_new ();
1033   *new_style = *rc_style;
1034   new_style->name = g_strdup (rc_style->name);
1035   new_style->font_name = g_strdup (rc_style->font_name);
1036   new_style->fontset_name = g_strdup (rc_style->fontset_name);
1037   
1038   for (i = 0; i < 5; i++)
1039     new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1040   
1041   rc_set = g_new (GtkRcSet, 1);
1042   gtk_pattern_spec_init (&rc_set->pspec, pattern);
1043   rc_set->rc_style = rc_style;
1044   
1045   return g_slist_prepend (slist, rc_set);
1046 }
1047
1048 void
1049 gtk_rc_add_widget_name_style (GtkRcStyle  *rc_style,
1050                               const gchar *pattern)
1051 {
1052   g_return_if_fail (rc_style != NULL);
1053   g_return_if_fail (pattern != NULL);
1054
1055   gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, rc_style, pattern);
1056 }
1057
1058 void
1059 gtk_rc_add_widget_class_style (GtkRcStyle  *rc_style,
1060                                const gchar *pattern)
1061 {
1062   g_return_if_fail (rc_style != NULL);
1063   g_return_if_fail (pattern != NULL);
1064
1065   gtk_rc_sets_widget_class = gtk_rc_add_rc_sets (gtk_rc_sets_widget_class, rc_style, pattern);
1066 }
1067
1068 void
1069 gtk_rc_add_class_style (GtkRcStyle  *rc_style,
1070                         const gchar *pattern)
1071 {
1072   g_return_if_fail (rc_style != NULL);
1073   g_return_if_fail (pattern != NULL);
1074
1075   gtk_rc_sets_class = gtk_rc_add_rc_sets (gtk_rc_sets_class, rc_style, pattern);
1076 }
1077
1078 static void
1079 gtk_rc_parse_any (const gchar  *input_name,
1080                   gint          input_fd,
1081                   const gchar  *input_string)
1082 {
1083   GScanner *scanner;
1084   guint    i;
1085   gboolean done;
1086   
1087   scanner = g_scanner_new ((GScannerConfig *) &gtk_rc_scanner_config);
1088   
1089   if (input_fd >= 0)
1090     {
1091       g_assert (input_string == NULL);
1092       
1093       g_scanner_input_file (scanner, input_fd);
1094     }
1095   else
1096     {
1097       g_assert (input_string != NULL);
1098       
1099       g_scanner_input_text (scanner, input_string, strlen (input_string));
1100     }
1101   scanner->input_name = input_name;
1102
1103   g_scanner_freeze_symbol_table (scanner);
1104   for (i = 0; i < n_symbols; i++)
1105     g_scanner_add_symbol (scanner, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1106   g_scanner_thaw_symbol_table (scanner);
1107   
1108   done = FALSE;
1109   while (!done)
1110     {
1111       if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1112         done = TRUE;
1113       else
1114         {
1115           guint expected_token;
1116           
1117           expected_token = gtk_rc_parse_statement (scanner);
1118
1119           if (expected_token != G_TOKEN_NONE)
1120             {
1121               gchar *symbol_name;
1122               gchar *msg;
1123               
1124               msg = NULL;
1125               symbol_name = NULL;
1126               if (scanner->scope_id == 0)
1127                 {
1128                   /* if we are in scope 0, we know the symbol names
1129                    * that are associated with certaintoken values.
1130                    * so we look them up to make the error messages
1131                    * more readable.
1132                    */
1133                   if (expected_token > GTK_RC_TOKEN_INVALID &&
1134                       expected_token < GTK_RC_TOKEN_LAST)
1135                     {
1136                       for (i = 0; i < n_symbols; i++)
1137                         if (symbols[i].token == expected_token)
1138                           msg = symbols[i].name;
1139                       if (msg)
1140                         msg = g_strconcat ("e.g. `", msg, "'", NULL);
1141                     }
1142                   if (scanner->token > GTK_RC_TOKEN_INVALID &&
1143                       scanner->token < GTK_RC_TOKEN_LAST)
1144                     {
1145                       symbol_name = "???";
1146                       for (i = 0; i < n_symbols; i++)
1147                         if (symbols[i].token == scanner->token)
1148                           symbol_name = symbols[i].name;
1149                     }
1150                 }
1151               g_scanner_unexp_token (scanner,
1152                                      expected_token,
1153                                      NULL,
1154                                      "keyword",
1155                                      symbol_name,
1156                                      msg,
1157                                      TRUE);
1158               g_free (msg);
1159               done = TRUE;
1160             }
1161         }
1162     }
1163   
1164   g_scanner_destroy (scanner);
1165 }
1166
1167 static guint       
1168 gtk_rc_styles_hash (const GSList *rc_styles)
1169 {
1170   guint result;
1171   
1172   result = 0;
1173   while (rc_styles)
1174     {
1175       result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1176       rc_styles = rc_styles->next;
1177     }
1178   
1179   return result;
1180 }
1181
1182 static gint        
1183 gtk_rc_styles_compare (const GSList *a,
1184                        const GSList *b)
1185 {
1186   while (a && b)
1187     {
1188       if (a->data != b->data)
1189         return FALSE;
1190       a = a->next;
1191       b = b->next;
1192     }
1193   
1194   return (a == b);
1195 }
1196
1197 static guint
1198 gtk_rc_style_hash (const char *name)
1199 {
1200   guint result;
1201   
1202   result = 0;
1203   while (*name)
1204     result += (result << 3) + *name++;
1205   
1206   return result;
1207 }
1208
1209 static gint
1210 gtk_rc_style_compare (const char *a,
1211                       const char *b)
1212 {
1213   return (strcmp (a, b) == 0);
1214 }
1215
1216 static GtkRcStyle*
1217 gtk_rc_style_find (const char *name)
1218 {
1219   if (rc_style_ht)
1220     return g_hash_table_lookup (rc_style_ht, (gpointer) name);
1221   else
1222     return NULL;
1223 }
1224
1225 /* Assumes ownership of rc_style */
1226 static GtkStyle *
1227 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1228 {
1229   GtkStyle *style;
1230   GdkFont *old_font;
1231   gint i;
1232
1233   style = gtk_style_new ();
1234
1235   style->rc_style = rc_style;
1236   
1237   if (rc_style->fontset_name)
1238     {
1239       old_font = style->font;
1240       style->font = gdk_fontset_load (rc_style->fontset_name);
1241       if (style->font)
1242         gdk_font_unref (old_font);
1243       else
1244         style->font = old_font;
1245     }
1246   else if (rc_style->font_name)
1247     {
1248       old_font = style->font;
1249       style->font = gdk_font_load (rc_style->font_name);
1250       if (style->font)
1251         gdk_font_unref (old_font);
1252       else
1253         style->font = old_font;
1254     }
1255   
1256   for (i = 0; i < 5; i++)
1257     {
1258       if (rc_style->color_flags[i] & GTK_RC_FG)
1259         style->fg[i] = rc_style->fg[i];
1260       if (rc_style->color_flags[i] & GTK_RC_BG)
1261         style->bg[i] = rc_style->bg[i];
1262       if (rc_style->color_flags[i] & GTK_RC_TEXT)
1263         style->text[i] = rc_style->text[i];
1264       if (rc_style->color_flags[i] & GTK_RC_BASE)
1265         style->base[i] = rc_style->base[i];
1266     }
1267
1268   if (rc_style->engine)
1269     {
1270       style->engine = rc_style->engine;
1271       gtk_theme_engine_ref (style->engine);
1272       rc_style->engine->rc_style_to_style (style, rc_style);
1273     }
1274
1275   return style;
1276 }
1277
1278 /* Reuses or frees rc_styles */
1279 static GtkStyle *
1280 gtk_rc_style_init (GSList *rc_styles)
1281 {
1282   gint i;
1283
1284   GtkStyle *style = NULL;
1285
1286   if (!realized_style_ht)
1287     realized_style_ht = g_hash_table_new ((GHashFunc)gtk_rc_styles_hash,
1288                                            (GCompareFunc)gtk_rc_styles_compare);
1289
1290   style = g_hash_table_lookup (realized_style_ht, rc_styles);
1291
1292   if (!style)
1293     {
1294       GtkRcStyle *proto_style;
1295       GSList *tmp_styles;
1296       
1297       proto_style = gtk_rc_style_new ();
1298
1299       tmp_styles = rc_styles;
1300       while (tmp_styles)
1301         {
1302           GtkRcStyle *rc_style = tmp_styles->data;
1303           GtkRcStylePrivate *rc_style_private;
1304
1305           for (i=0; i<5; i++)
1306             {
1307               if (!proto_style->bg_pixmap_name[i] && rc_style->bg_pixmap_name[i])
1308                 proto_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1309
1310               if (!(proto_style->color_flags[i] & GTK_RC_FG) && 
1311                     rc_style->color_flags[i] & GTK_RC_FG)
1312                 {
1313                   proto_style->fg[i] = rc_style->fg[i];
1314                   proto_style->color_flags[i] |= GTK_RC_FG;
1315                 }
1316               if (!(proto_style->color_flags[i] & GTK_RC_BG) && 
1317                     rc_style->color_flags[i] & GTK_RC_BG)
1318                 {
1319                   proto_style->bg[i] = rc_style->bg[i];
1320                   proto_style->color_flags[i] |= GTK_RC_BG;
1321                 }
1322               if (!(proto_style->color_flags[i] & GTK_RC_TEXT) && 
1323                     rc_style->color_flags[i] & GTK_RC_TEXT)
1324                 {
1325                   proto_style->text[i] = rc_style->text[i];
1326                   proto_style->color_flags[i] |= GTK_RC_TEXT;
1327                 }
1328               if (!(proto_style->color_flags[i] & GTK_RC_BASE) && 
1329                     rc_style->color_flags[i] & GTK_RC_BASE)
1330                 {
1331                   proto_style->base[i] = rc_style->base[i];
1332                   proto_style->color_flags[i] |= GTK_RC_BASE;
1333                 }
1334             }
1335
1336           if (!proto_style->font_name && rc_style->font_name)
1337             proto_style->font_name = g_strdup (rc_style->font_name);
1338           if (!proto_style->fontset_name && rc_style->fontset_name)
1339             proto_style->fontset_name = g_strdup (rc_style->fontset_name);
1340
1341           if (!proto_style->engine && rc_style->engine)
1342             {
1343               proto_style->engine = rc_style->engine;
1344               gtk_theme_engine_ref (proto_style->engine);
1345             }
1346           
1347           if (proto_style->engine &&
1348               (proto_style->engine == rc_style->engine))
1349             proto_style->engine->merge_rc_style (proto_style, rc_style);
1350
1351           /* Point from each rc_style to the list of styles */
1352
1353           rc_style_private = (GtkRcStylePrivate *)rc_style;
1354           if (!g_slist_find (rc_style_private->rc_style_lists, rc_styles))
1355             rc_style_private->rc_style_lists = g_slist_prepend (rc_style_private->rc_style_lists, rc_styles);
1356
1357           tmp_styles = tmp_styles->next;
1358         }
1359
1360       for (i=0; i<5; i++)
1361         if (proto_style->bg_pixmap_name[i] &&
1362             (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1363           {
1364             g_free (proto_style->bg_pixmap_name[i]);
1365             proto_style->bg_pixmap_name[i] = NULL;
1366           }
1367
1368       style = gtk_rc_style_to_style (proto_style);
1369
1370       g_hash_table_insert (realized_style_ht, rc_styles, style);
1371     }
1372   else
1373     g_slist_free (rc_styles);
1374
1375   return style;
1376 }
1377
1378 /*********************
1379  * Parsing functions *
1380  *********************/
1381
1382 static guint
1383 gtk_rc_parse_statement (GScanner *scanner)
1384 {
1385   guint token;
1386   
1387   token = g_scanner_peek_next_token (scanner);
1388
1389   switch (token)
1390     {
1391     case GTK_RC_TOKEN_INCLUDE:
1392       token = g_scanner_get_next_token (scanner);
1393       if (token != GTK_RC_TOKEN_INCLUDE)
1394         return GTK_RC_TOKEN_INCLUDE;
1395
1396       token = g_scanner_get_next_token (scanner);
1397       if (token != G_TOKEN_STRING)
1398         return G_TOKEN_STRING;
1399
1400       gtk_rc_parse_file (scanner->value.v_string, FALSE);
1401       return G_TOKEN_NONE;
1402
1403     case GTK_RC_TOKEN_STYLE:
1404       return gtk_rc_parse_style (scanner);
1405
1406     case GTK_RC_TOKEN_BINDING:
1407       return gtk_binding_parse_binding (scanner);
1408
1409     case GTK_RC_TOKEN_PIXMAP_PATH:
1410       return gtk_rc_parse_pixmap_path (scanner);
1411
1412     case GTK_RC_TOKEN_WIDGET:
1413       return gtk_rc_parse_path_pattern (scanner);
1414
1415     case GTK_RC_TOKEN_WIDGET_CLASS:
1416       return gtk_rc_parse_path_pattern (scanner);
1417
1418     case GTK_RC_TOKEN_CLASS:
1419       return gtk_rc_parse_path_pattern (scanner);
1420
1421     case GTK_RC_TOKEN_MODULE_PATH:
1422       return gtk_rc_parse_module_path (scanner);
1423        
1424     default:
1425       g_scanner_get_next_token (scanner);
1426       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
1427     }
1428 }
1429
1430 static guint
1431 gtk_rc_parse_style (GScanner *scanner)
1432 {
1433   GtkRcStyle *rc_style;
1434   GtkRcStyle *parent_style;
1435   guint token;
1436   gint insert;
1437   gint i;
1438   
1439   token = g_scanner_get_next_token (scanner);
1440   if (token != GTK_RC_TOKEN_STYLE)
1441     return GTK_RC_TOKEN_STYLE;
1442   
1443   token = g_scanner_get_next_token (scanner);
1444   if (token != G_TOKEN_STRING)
1445     return G_TOKEN_STRING;
1446   
1447   insert = FALSE;
1448   rc_style = gtk_rc_style_find (scanner->value.v_string);
1449   
1450   if (!rc_style)
1451     {
1452       insert = TRUE;
1453       rc_style = gtk_rc_style_new ();
1454       rc_style->name = g_strdup (scanner->value.v_string);
1455       
1456       for (i = 0; i < 5; i++)
1457         rc_style->bg_pixmap_name[i] = NULL;
1458
1459       for (i = 0; i < 5; i++)
1460         rc_style->color_flags[i] = 0;
1461
1462       rc_style->engine = NULL;
1463       rc_style->engine_data = NULL;
1464     }
1465   
1466   token = g_scanner_peek_next_token (scanner);
1467   if (token == G_TOKEN_EQUAL_SIGN)
1468     {
1469       token = g_scanner_get_next_token (scanner);
1470       
1471       token = g_scanner_get_next_token (scanner);
1472       if (token != G_TOKEN_STRING)
1473         {
1474           if (insert)
1475             g_free (rc_style);
1476
1477           return G_TOKEN_STRING;
1478         }
1479       
1480       parent_style = gtk_rc_style_find (scanner->value.v_string);
1481       if (parent_style)
1482         {
1483           for (i = 0; i < 5; i++)
1484             {
1485               rc_style->color_flags[i] = parent_style->color_flags[i];
1486               rc_style->fg[i] = parent_style->fg[i];
1487               rc_style->bg[i] = parent_style->bg[i];
1488               rc_style->text[i] = parent_style->text[i];
1489               rc_style->base[i] = parent_style->base[i];
1490             }
1491           
1492           if (parent_style->fontset_name)
1493             {
1494               if (rc_style->fontset_name)
1495                 g_free (rc_style->fontset_name);
1496               rc_style->fontset_name = g_strdup (parent_style->fontset_name);
1497             }
1498           else if (parent_style->font_name)
1499             {
1500               if (rc_style->font_name)
1501                 g_free (rc_style->font_name);
1502               rc_style->font_name = g_strdup (parent_style->font_name);
1503             }
1504           
1505           for (i = 0; i < 5; i++)
1506             {
1507               if (rc_style->bg_pixmap_name[i])
1508                 g_free (rc_style->bg_pixmap_name[i]);
1509               rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
1510             }
1511         }
1512     }
1513   
1514   token = g_scanner_get_next_token (scanner);
1515   if (token != G_TOKEN_LEFT_CURLY)
1516     {
1517       if (insert)
1518         g_free (rc_style);
1519
1520       return G_TOKEN_LEFT_CURLY;
1521     }
1522   
1523   token = g_scanner_peek_next_token (scanner);
1524   while (token != G_TOKEN_RIGHT_CURLY)
1525     {
1526       switch (token)
1527         {
1528         case GTK_RC_TOKEN_BASE:
1529           token = gtk_rc_parse_base (scanner, rc_style);
1530           break;
1531         case GTK_RC_TOKEN_BG:
1532           token = gtk_rc_parse_bg (scanner, rc_style);
1533           break;
1534         case GTK_RC_TOKEN_FG:
1535           token = gtk_rc_parse_fg (scanner, rc_style);
1536           break;
1537         case GTK_RC_TOKEN_TEXT:
1538           token = gtk_rc_parse_text (scanner, rc_style);
1539           break;
1540         case GTK_RC_TOKEN_BG_PIXMAP:
1541           token = gtk_rc_parse_bg_pixmap (scanner, rc_style);
1542           break;
1543         case GTK_RC_TOKEN_FONT:
1544           token = gtk_rc_parse_font (scanner, rc_style);
1545           break;
1546         case GTK_RC_TOKEN_FONTSET:
1547           token = gtk_rc_parse_fontset (scanner, rc_style);
1548           break;
1549         case GTK_RC_TOKEN_ENGINE:
1550           token = gtk_rc_parse_engine (scanner, rc_style);
1551           break;
1552         default:
1553           g_scanner_get_next_token (scanner);
1554           token = G_TOKEN_RIGHT_CURLY;
1555           break;
1556         }
1557
1558       if (token != G_TOKEN_NONE)
1559         {
1560           if (insert)
1561             {
1562               if (rc_style->fontset_name)
1563                 g_free (rc_style->fontset_name);
1564               if (rc_style->font_name)
1565                 g_free (rc_style->font_name);
1566               for (i = 0; i < 5; i++)
1567                 if (rc_style->bg_pixmap_name[i])
1568                   g_free (rc_style->bg_pixmap_name[i]);
1569               g_free (rc_style);
1570             }
1571           return token;
1572         }
1573       token = g_scanner_peek_next_token (scanner);
1574     }
1575   
1576   token = g_scanner_get_next_token (scanner);
1577   if (token != G_TOKEN_RIGHT_CURLY)
1578     {
1579       if (insert)
1580         {
1581           if (rc_style->fontset_name)
1582             g_free (rc_style->fontset_name);
1583           if (rc_style->font_name)
1584             g_free (rc_style->font_name);
1585           
1586           for (i = 0; i < 5; i++)
1587             if (rc_style->bg_pixmap_name[i])
1588               g_free (rc_style->bg_pixmap_name[i]);
1589           
1590           g_free (rc_style);
1591         }
1592       return G_TOKEN_RIGHT_CURLY;
1593     }
1594   
1595   if (insert)
1596     {
1597       if (!rc_style_ht)
1598         rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
1599                                         (GCompareFunc) gtk_rc_style_compare);
1600       
1601       g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
1602     }
1603   
1604   return G_TOKEN_NONE;
1605 }
1606
1607 static guint
1608 gtk_rc_parse_base (GScanner   *scanner,
1609                    GtkRcStyle *style)
1610 {
1611   GtkStateType state;
1612   guint token;
1613   
1614   token = g_scanner_get_next_token (scanner);
1615   if (token != GTK_RC_TOKEN_BASE)
1616     return GTK_RC_TOKEN_BASE;
1617   
1618   token = gtk_rc_parse_state (scanner, &state);
1619   if (token != G_TOKEN_NONE)
1620     return token;
1621   
1622   token = g_scanner_get_next_token (scanner);
1623   if (token != G_TOKEN_EQUAL_SIGN)
1624     return G_TOKEN_EQUAL_SIGN;
1625
1626   style->color_flags[state] |= GTK_RC_BASE;
1627   return gtk_rc_parse_color (scanner, &style->base[state]);
1628 }
1629
1630 static guint
1631 gtk_rc_parse_bg (GScanner   *scanner,
1632                  GtkRcStyle *style)
1633 {
1634   GtkStateType state;
1635   guint token;
1636   
1637   token = g_scanner_get_next_token (scanner);
1638   if (token != GTK_RC_TOKEN_BG)
1639     return GTK_RC_TOKEN_BG;
1640   
1641   token = gtk_rc_parse_state (scanner, &state);
1642   if (token != G_TOKEN_NONE)
1643     return token;
1644   
1645   token = g_scanner_get_next_token (scanner);
1646   if (token != G_TOKEN_EQUAL_SIGN)
1647     return G_TOKEN_EQUAL_SIGN;
1648
1649   style->color_flags[state] |= GTK_RC_BG;
1650   return gtk_rc_parse_color (scanner, &style->bg[state]);
1651 }
1652
1653 static guint
1654 gtk_rc_parse_fg (GScanner   *scanner,
1655                  GtkRcStyle *style)
1656 {
1657   GtkStateType state;
1658   guint token;
1659   
1660   token = g_scanner_get_next_token (scanner);
1661   if (token != GTK_RC_TOKEN_FG)
1662     return GTK_RC_TOKEN_FG;
1663   
1664   token = gtk_rc_parse_state (scanner, &state);
1665   if (token != G_TOKEN_NONE)
1666     return token;
1667   
1668   token = g_scanner_get_next_token (scanner);
1669   if (token != G_TOKEN_EQUAL_SIGN)
1670     return G_TOKEN_EQUAL_SIGN;
1671   
1672   style->color_flags[state] |= GTK_RC_FG;
1673   return gtk_rc_parse_color (scanner, &style->fg[state]);
1674 }
1675
1676 static guint
1677 gtk_rc_parse_text (GScanner   *scanner,
1678                    GtkRcStyle *style)
1679 {
1680   GtkStateType state;
1681   guint token;
1682   
1683   token = g_scanner_get_next_token (scanner);
1684   if (token != GTK_RC_TOKEN_TEXT)
1685     return GTK_RC_TOKEN_TEXT;
1686   
1687   token = gtk_rc_parse_state (scanner, &state);
1688   if (token != G_TOKEN_NONE)
1689     return token;
1690   
1691   token = g_scanner_get_next_token (scanner);
1692   if (token != G_TOKEN_EQUAL_SIGN)
1693     return G_TOKEN_EQUAL_SIGN;
1694   
1695   style->color_flags[state] |= GTK_RC_TEXT;
1696   return gtk_rc_parse_color (scanner, &style->text[state]);
1697 }
1698
1699 static guint
1700 gtk_rc_parse_bg_pixmap (GScanner   *scanner,
1701                         GtkRcStyle *rc_style)
1702 {
1703   GtkStateType state;
1704   guint token;
1705   gchar *pixmap_file;
1706   
1707   token = g_scanner_get_next_token (scanner);
1708   if (token != GTK_RC_TOKEN_BG_PIXMAP)
1709     return GTK_RC_TOKEN_BG_PIXMAP;
1710   
1711   token = gtk_rc_parse_state (scanner, &state);
1712   if (token != G_TOKEN_NONE)
1713     return token;
1714   
1715   token = g_scanner_get_next_token (scanner);
1716   if (token != G_TOKEN_EQUAL_SIGN)
1717     return G_TOKEN_EQUAL_SIGN;
1718   
1719   token = g_scanner_get_next_token (scanner);
1720   if (token != G_TOKEN_STRING)
1721     return G_TOKEN_STRING;
1722   
1723   if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
1724       (strcmp (scanner->value.v_string, "<none>") == 0))
1725     pixmap_file = g_strdup (scanner->value.v_string);
1726   else
1727     pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
1728   
1729   if (pixmap_file)
1730     {
1731       if (rc_style->bg_pixmap_name[state])
1732         g_free (rc_style->bg_pixmap_name[state]);
1733       rc_style->bg_pixmap_name[state] = pixmap_file;
1734     }
1735   
1736   return G_TOKEN_NONE;
1737 }
1738
1739 static gchar*
1740 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
1741 {
1742   gchar *buf;
1743   gint fd;
1744
1745   buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", dir, pixmap_file);
1746   
1747   fd = open (buf, O_RDONLY);
1748   if (fd >= 0)
1749     {
1750       close (fd);
1751       return buf;
1752     }
1753    
1754   g_free (buf);
1755  
1756    return NULL;
1757  }
1758  
1759 gchar*
1760 gtk_rc_find_pixmap_in_path (GScanner *scanner,
1761                             const gchar *pixmap_file)
1762 {
1763   gint i;
1764   gchar *filename;
1765   GSList *tmp_list;
1766     
1767   for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
1768     {
1769       filename = gtk_rc_check_pixmap_dir (pixmap_path[i], pixmap_file);
1770       if (filename)
1771         return filename;
1772     }
1773  
1774   tmp_list = rc_dir_stack;
1775   while (tmp_list)
1776     {
1777       filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
1778       if (filename)
1779         return filename;
1780        
1781       tmp_list = tmp_list->next;
1782     }
1783   
1784   if (scanner)
1785     g_warning (_("Unable to locate image file in pixmap_path: \"%s\" line %d"),
1786                pixmap_file, scanner->line);
1787   else
1788     g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
1789                pixmap_file);
1790     
1791   return NULL;
1792 }
1793
1794 gchar*
1795 gtk_rc_find_module_in_path (const gchar *module_file)
1796 {
1797   gint i;
1798   gint fd;
1799   gchar *buf;
1800   
1801   for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
1802     {
1803       buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
1804                              module_path[i], module_file);
1805       
1806       fd = open (buf, O_RDONLY);
1807       if (fd >= 0)
1808         {
1809           close (fd);
1810           return buf;
1811         }
1812       
1813       g_free (buf);
1814     }
1815     
1816   return NULL;
1817 }
1818
1819 static guint
1820 gtk_rc_parse_font (GScanner   *scanner,
1821                    GtkRcStyle *rc_style)
1822 {
1823   guint token;
1824   
1825   token = g_scanner_get_next_token (scanner);
1826   if (token != GTK_RC_TOKEN_FONT)
1827     return GTK_RC_TOKEN_FONT;
1828   
1829   token = g_scanner_get_next_token (scanner);
1830   if (token != G_TOKEN_EQUAL_SIGN)
1831     return G_TOKEN_EQUAL_SIGN;
1832   
1833   token = g_scanner_get_next_token (scanner);
1834   if (token != G_TOKEN_STRING)
1835     return G_TOKEN_STRING;
1836   
1837   if (rc_style->font_name)
1838     g_free (rc_style->font_name);
1839   rc_style->font_name = g_strdup (scanner->value.v_string);
1840   
1841   return G_TOKEN_NONE;
1842 }
1843
1844 static guint
1845 gtk_rc_parse_fontset (GScanner   *scanner,
1846                       GtkRcStyle *rc_style)
1847 {
1848   guint token;
1849   
1850   token = g_scanner_get_next_token (scanner);
1851   if (token != GTK_RC_TOKEN_FONTSET)
1852     return GTK_RC_TOKEN_FONTSET;
1853   
1854   token = g_scanner_get_next_token (scanner);
1855   if (token != G_TOKEN_EQUAL_SIGN)
1856     return G_TOKEN_EQUAL_SIGN;
1857   
1858   token = g_scanner_get_next_token (scanner);
1859   if (token != G_TOKEN_STRING)
1860     return G_TOKEN_STRING;
1861   
1862   if (rc_style->fontset_name)
1863     g_free (rc_style->fontset_name);
1864   rc_style->fontset_name = g_strdup (scanner->value.v_string);
1865   
1866   return G_TOKEN_NONE;
1867 }
1868
1869 static guint       
1870 gtk_rc_parse_engine (GScanner    *scanner,
1871                      GtkRcStyle  *rc_style)
1872 {
1873   guint token;
1874
1875   token = g_scanner_get_next_token (scanner);
1876   if (token != GTK_RC_TOKEN_ENGINE)
1877     return GTK_RC_TOKEN_ENGINE;
1878
1879   token = g_scanner_get_next_token (scanner);
1880   if (token != G_TOKEN_STRING)
1881     return G_TOKEN_STRING;
1882
1883   rc_style->engine = gtk_theme_engine_get (scanner->value.v_string);
1884
1885   token = g_scanner_get_next_token (scanner);
1886   if (token != G_TOKEN_LEFT_CURLY)
1887     return G_TOKEN_LEFT_CURLY;
1888
1889   if (rc_style->engine)
1890     return rc_style->engine->parse_rc_style (scanner, rc_style);
1891   else
1892     {
1893       /* Skip over remainder, looking for nested {}'s */
1894       guint count = 1;
1895       
1896       while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
1897         {
1898           if (token == G_TOKEN_LEFT_CURLY)
1899             count++;
1900           else if (token == G_TOKEN_RIGHT_CURLY)
1901             count--;
1902
1903           if (count == 0)
1904             return G_TOKEN_NONE;
1905         }
1906
1907       return G_TOKEN_RIGHT_CURLY;
1908     }
1909 }
1910
1911 guint
1912 gtk_rc_parse_state (GScanner     *scanner,
1913                     GtkStateType *state)
1914 {
1915   guint old_scope;
1916   guint token;
1917
1918   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1919   g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
1920   
1921   /* we don't know where we got called from, so we reset the scope here.
1922    * if we bail out due to errors, we *don't* reset the scope, so the
1923    * error messaging code can make sense of our tokens.
1924    */
1925   old_scope = g_scanner_set_scope (scanner, 0);
1926   
1927   token = g_scanner_get_next_token (scanner);
1928   if (token != G_TOKEN_LEFT_BRACE)
1929     return G_TOKEN_LEFT_BRACE;
1930   
1931   token = g_scanner_get_next_token (scanner);
1932   switch (token)
1933     {
1934     case GTK_RC_TOKEN_ACTIVE:
1935       *state = GTK_STATE_ACTIVE;
1936       break;
1937     case GTK_RC_TOKEN_INSENSITIVE:
1938       *state = GTK_STATE_INSENSITIVE;
1939       break;
1940     case GTK_RC_TOKEN_NORMAL:
1941       *state = GTK_STATE_NORMAL;
1942       break;
1943     case GTK_RC_TOKEN_PRELIGHT:
1944       *state = GTK_STATE_PRELIGHT;
1945       break;
1946     case GTK_RC_TOKEN_SELECTED:
1947       *state = GTK_STATE_SELECTED;
1948       break;
1949     default:
1950       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
1951     }
1952   
1953   token = g_scanner_get_next_token (scanner);
1954   if (token != G_TOKEN_RIGHT_BRACE)
1955     return G_TOKEN_RIGHT_BRACE;
1956   
1957   g_scanner_set_scope (scanner, old_scope);
1958
1959   return G_TOKEN_NONE;
1960 }
1961
1962 guint
1963 gtk_rc_parse_priority (GScanner            *scanner,
1964                        GtkPathPriorityType *priority)
1965 {
1966   guint old_scope;
1967   guint token;
1968
1969   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1970   g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
1971
1972   /* we don't know where we got called from, so we reset the scope here.
1973    * if we bail out due to errors, we *don't* reset the scope, so the
1974    * error messaging code can make sense of our tokens.
1975    */
1976   old_scope = g_scanner_set_scope (scanner, 0);
1977   
1978   token = g_scanner_get_next_token (scanner);
1979   if (token != ':')
1980     return ':';
1981   
1982   token = g_scanner_get_next_token (scanner);
1983   switch (token)
1984     {
1985     case GTK_RC_TOKEN_LOWEST:
1986       *priority = GTK_PATH_PRIO_LOWEST;
1987       break;
1988     case GTK_RC_TOKEN_GTK:
1989       *priority = GTK_PATH_PRIO_GTK;
1990       break;
1991     case GTK_RC_TOKEN_APPLICATION:
1992       *priority = GTK_PATH_PRIO_APPLICATION;
1993       break;
1994     case GTK_RC_TOKEN_RC:
1995       *priority = GTK_PATH_PRIO_RC;
1996       break;
1997     case GTK_RC_TOKEN_HIGHEST:
1998       *priority = GTK_PATH_PRIO_HIGHEST;
1999       break;
2000     default:
2001       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
2002     }
2003   
2004   g_scanner_set_scope (scanner, old_scope);
2005
2006   return G_TOKEN_NONE;
2007 }
2008
2009 guint
2010 gtk_rc_parse_color (GScanner *scanner,
2011                     GdkColor *color)
2012 {
2013   guint token;
2014
2015   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2016
2017   /* we don't need to set our own scop here, because
2018    * we don't need own symbols
2019    */
2020   
2021   token = g_scanner_get_next_token (scanner);
2022   switch (token)
2023     {
2024       gint token_int;
2025       gint length;
2026       gint temp;
2027       gchar buf[9];
2028       gint i, j;
2029       
2030     case G_TOKEN_LEFT_CURLY:
2031       token = g_scanner_get_next_token (scanner);
2032       if (token == G_TOKEN_INT)
2033         token_int = scanner->value.v_int;
2034       else if (token == G_TOKEN_FLOAT)
2035         token_int = scanner->value.v_float * 65535.0;
2036       else
2037         return G_TOKEN_FLOAT;
2038       color->red = CLAMP (token_int, 0, 65535);
2039       
2040       token = g_scanner_get_next_token (scanner);
2041       if (token != G_TOKEN_COMMA)
2042         return G_TOKEN_COMMA;
2043       
2044       token = g_scanner_get_next_token (scanner);
2045       if (token == G_TOKEN_INT)
2046         token_int = scanner->value.v_int;
2047       else if (token == G_TOKEN_FLOAT)
2048         token_int = scanner->value.v_float * 65535.0;
2049       else
2050         return G_TOKEN_FLOAT;
2051       color->green = CLAMP (token_int, 0, 65535);
2052       
2053       token = g_scanner_get_next_token (scanner);
2054       if (token != G_TOKEN_COMMA)
2055         return G_TOKEN_COMMA;
2056       
2057       token = g_scanner_get_next_token (scanner);
2058       if (token == G_TOKEN_INT)
2059         token_int = scanner->value.v_int;
2060       else if (token == G_TOKEN_FLOAT)
2061         token_int = scanner->value.v_float * 65535.0;
2062       else
2063         return G_TOKEN_FLOAT;
2064       color->blue = CLAMP (token_int, 0, 65535);
2065       
2066       token = g_scanner_get_next_token (scanner);
2067       if (token != G_TOKEN_RIGHT_CURLY)
2068         return G_TOKEN_RIGHT_CURLY;
2069       return G_TOKEN_NONE;
2070       
2071     case G_TOKEN_STRING:
2072       if (scanner->value.v_string[0] != '#')
2073         return G_TOKEN_STRING;
2074       
2075       length = strlen (scanner->value.v_string) - 1;
2076       if (((length % 3) != 0) || (length > 12))
2077         return G_TOKEN_STRING;
2078       length /= 3;
2079       
2080       for (i = 0, j = 1; i < length; i++, j++)
2081         buf[i] = scanner->value.v_string[j];
2082       buf[i] = '\0';
2083       
2084       sscanf (buf, "%x", &temp);
2085       color->red = temp;
2086       
2087       for (i = 0; i < length; i++, j++)
2088         buf[i] = scanner->value.v_string[j];
2089       buf[i] = '\0';
2090       
2091       sscanf (buf, "%x", &temp);
2092       color->green = temp;
2093       
2094       for (i = 0; i < length; i++, j++)
2095         buf[i] = scanner->value.v_string[j];
2096       buf[i] = '\0';
2097       
2098       sscanf (buf, "%x", &temp);
2099       color->blue = temp;
2100       
2101       if (length == 1)
2102         {
2103           color->red *= 4369;
2104           color->green *= 4369;
2105           color->blue *= 4369;
2106         }
2107       else if (length == 2)
2108         {
2109           color->red *= 257;
2110           color->green *= 257;
2111           color->blue *= 257;
2112         }
2113       else if (length == 3)
2114         {
2115           color->red *= 16;
2116           color->green *= 16;
2117           color->blue *= 16;
2118         }
2119       return G_TOKEN_NONE;
2120       
2121     default:
2122       return G_TOKEN_STRING;
2123     }
2124 }
2125
2126 static guint
2127 gtk_rc_parse_pixmap_path (GScanner *scanner)
2128 {
2129   guint token;
2130   
2131   token = g_scanner_get_next_token (scanner);
2132   if (token != GTK_RC_TOKEN_PIXMAP_PATH)
2133     return GTK_RC_TOKEN_PIXMAP_PATH;
2134   
2135   token = g_scanner_get_next_token (scanner);
2136   if (token != G_TOKEN_STRING)
2137     return G_TOKEN_STRING;
2138   
2139   gtk_rc_parse_pixmap_path_string (scanner->value.v_string);
2140   
2141   return G_TOKEN_NONE;
2142 }
2143
2144 static void
2145 gtk_rc_parse_pixmap_path_string (gchar *pix_path)
2146 {
2147   gchar *buf;
2148   gint end_offset;
2149   gint start_offset = 0;
2150   gint path_len;
2151   gint path_num;
2152   
2153   /* free the old one, or just add to the old one ? */
2154   for (path_num=0; pixmap_path[path_num]; path_num++)
2155     {
2156       g_free (pixmap_path[path_num]);
2157       pixmap_path[path_num] = NULL;
2158     }
2159   
2160   path_num = 0;
2161   
2162   path_len = strlen (pix_path);
2163   
2164   buf = g_strdup (pix_path);
2165   
2166   for (end_offset = 0; end_offset <= path_len; end_offset++)
2167     {
2168       if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2169           (end_offset == path_len))
2170         {
2171           buf[end_offset] = '\0';
2172           pixmap_path[path_num] = g_strdup (buf + start_offset);
2173           path_num++;
2174           pixmap_path[path_num] = NULL;
2175           start_offset = end_offset + 1;
2176         }
2177     }
2178   g_free (buf);
2179   gtk_rc_append_default_pixmap_path();
2180 }
2181
2182 static guint
2183 gtk_rc_parse_module_path (GScanner *scanner)
2184 {
2185   guint token;
2186   
2187   token = g_scanner_get_next_token (scanner);
2188   if (token != GTK_RC_TOKEN_MODULE_PATH)
2189     return GTK_RC_TOKEN_MODULE_PATH;
2190   
2191   token = g_scanner_get_next_token (scanner);
2192   if (token != G_TOKEN_STRING)
2193     return G_TOKEN_STRING;
2194   
2195   gtk_rc_parse_module_path_string (scanner->value.v_string);
2196   
2197   return G_TOKEN_NONE;
2198 }
2199
2200 static void
2201 gtk_rc_parse_module_path_string (gchar *mod_path)
2202 {
2203   gchar *buf;
2204   gint end_offset;
2205   gint start_offset = 0;
2206   gint path_len;
2207   gint path_num;
2208   
2209   /* free the old one, or just add to the old one ? */
2210   for (path_num=0; module_path[path_num]; path_num++)
2211     {
2212       g_free (module_path[path_num]);
2213       module_path[path_num] = NULL;
2214     }
2215   
2216   path_num = 0;
2217   
2218   path_len = strlen (mod_path);
2219   
2220   buf = g_strdup (mod_path);
2221   
2222   for (end_offset = 0; end_offset <= path_len; end_offset++)
2223     {
2224       if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2225           (end_offset == path_len))
2226         {
2227           buf[end_offset] = '\0';
2228           module_path[path_num] = g_strdup (buf + start_offset);
2229           path_num++;
2230           module_path[path_num] = NULL;
2231           start_offset = end_offset + 1;
2232         }
2233     }
2234   g_free (buf);
2235   gtk_rc_append_default_module_path();
2236 }
2237
2238 static guint
2239 gtk_rc_parse_path_pattern (GScanner   *scanner)
2240 {
2241   guint token;
2242   GtkPathType path_type;
2243   gchar *pattern;
2244   gboolean is_binding;
2245   GtkPathPriorityType priority = GTK_PATH_PRIO_RC;
2246   
2247   token = g_scanner_get_next_token (scanner);
2248   switch (token)
2249     {
2250     case GTK_RC_TOKEN_WIDGET:
2251       path_type = GTK_PATH_WIDGET;
2252       break;
2253     case GTK_RC_TOKEN_WIDGET_CLASS:
2254       path_type = GTK_PATH_WIDGET_CLASS;
2255       break;
2256     case GTK_RC_TOKEN_CLASS:
2257       path_type = GTK_PATH_CLASS;
2258       break;
2259     default:
2260       return GTK_RC_TOKEN_WIDGET_CLASS;
2261     }
2262   
2263   token = g_scanner_get_next_token (scanner);
2264   if (token != G_TOKEN_STRING)
2265     return G_TOKEN_STRING;
2266
2267   pattern = g_strdup (scanner->value.v_string);
2268
2269   token = g_scanner_get_next_token (scanner);
2270   if (token == GTK_RC_TOKEN_STYLE)
2271     is_binding = FALSE;
2272   else if (token == GTK_RC_TOKEN_BINDING)
2273     {
2274       is_binding = TRUE;
2275       if (g_scanner_peek_next_token (scanner) == ':')
2276         {
2277           token = gtk_rc_parse_priority (scanner, &priority);
2278           if (token != G_TOKEN_NONE)
2279             {
2280               g_free (pattern);
2281               return token;
2282             }
2283         }
2284     }
2285   else
2286     {
2287       g_free (pattern);
2288       return GTK_RC_TOKEN_STYLE;
2289     }
2290   
2291   token = g_scanner_get_next_token (scanner);
2292   if (token != G_TOKEN_STRING)
2293     {
2294       g_free (pattern);
2295       return G_TOKEN_STRING;
2296     }
2297
2298   if (is_binding)
2299     {
2300       GtkBindingSet *binding;
2301
2302       binding = gtk_binding_set_find (scanner->value.v_string);
2303       if (!binding)
2304         {
2305           g_free (pattern);
2306           return G_TOKEN_STRING;
2307         }
2308       gtk_binding_set_add_path (binding, path_type, pattern, priority);
2309     }
2310   else
2311     {
2312       GtkRcStyle *rc_style;
2313       GtkRcSet *rc_set;
2314
2315       rc_style = gtk_rc_style_find (scanner->value.v_string);
2316       
2317       if (!rc_style)
2318         {
2319           g_free (pattern);
2320           return G_TOKEN_STRING;
2321         }
2322
2323       rc_set = g_new (GtkRcSet, 1);
2324       gtk_pattern_spec_init (&rc_set->pspec, pattern);
2325       rc_set->rc_style = rc_style;
2326
2327       if (path_type == GTK_PATH_WIDGET)
2328         gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set);
2329       else if (path_type == GTK_PATH_WIDGET_CLASS)
2330         gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set);
2331       else
2332         gtk_rc_sets_class = g_slist_prepend (gtk_rc_sets_class, rc_set);
2333     }
2334
2335   g_free (pattern);
2336   return G_TOKEN_NONE;
2337 }
2338
2339 /*
2340 typedef  GdkPixmap * (*GtkImageLoader) (GdkWindow   *window,
2341                                         GdkColormap *colormap,
2342                                         GdkBitmap  **mask,
2343                                         GdkColor    *transparent_color,
2344                                         const gchar *filename);
2345 */
2346
2347 void
2348 gtk_rc_set_image_loader(GtkImageLoader loader)
2349 {
2350   image_loader = loader;
2351 }
2352
2353 GdkPixmap *
2354 gtk_rc_load_image (GdkColormap *colormap,
2355                    GdkColor    *transparent_color,
2356                    const gchar *filename)
2357 {
2358   if (strcmp (filename, "<parent>") == 0)
2359     return (GdkPixmap*) GDK_PARENT_RELATIVE;
2360   else
2361     {
2362       if(image_loader)
2363         return image_loader(NULL, colormap, NULL,
2364                             transparent_color,
2365                             filename);
2366       else
2367         return gdk_pixmap_colormap_create_from_xpm (NULL, colormap, NULL,
2368                                                     transparent_color,
2369                                                     filename);
2370     }
2371 }