]> Pileus Git - ~andy/gtk/blob - gtk/gtkrc.c
Merge from themes-2. See the ChangeLog for a somewhat detailed
[~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 #include <ctype.h>
20 #include <unistd.h>
21 #include <sys/stat.h>
22 #include <sys/param.h>
23 #include <fcntl.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include "gtkrc.h"
27 #include "gtkbindings.h"
28 #include "gtkthemes.h"
29
30 typedef struct _GtkRcSet    GtkRcSet;
31 typedef struct _GtkRcNode   GtkRcNode;
32 typedef struct _GtkRcFile   GtkRcFile;
33
34 struct _GtkRcSet
35 {
36   GtkPatternSpec pspec;
37   GtkRcStyle    *rc_style;
38 };
39
40 struct _GtkRcFile
41 {
42   time_t mtime;
43   gchar *name;
44   gchar *canonical_name;
45   gboolean reload;
46 };
47
48 static guint       gtk_rc_style_hash               (const char   *name);
49 static gint        gtk_rc_style_compare            (const char   *a,
50                                                     const char   *b);
51 static guint       gtk_rc_styles_hash              (const GSList *rc_styles);
52 static gint        gtk_rc_styles_compare           (const GSList *a,
53                                                     const GSList *b);
54 static GtkRcStyle* gtk_rc_style_find               (const char   *name);
55 static GSList *    gtk_rc_styles_match             (GSList       *rc_styles,
56                                                     GSList       *sets,
57                                                     guint         path_length,
58                                                     gchar        *path,
59                                                     gchar        *path_reversed);
60 static GtkStyle *  gtk_rc_style_to_style           (GtkRcStyle   *rc_style);
61 static GtkStyle*   gtk_rc_style_init               (GSList       *rc_styles);
62 static void        gtk_rc_parse_file               (const gchar  *filename,
63                                                     gboolean      reload);
64
65 static void        gtk_rc_parse_any                (const gchar  *input_name,
66                                                     gint          input_fd,
67                                                     const gchar  *input_string);
68 static guint       gtk_rc_parse_statement          (GScanner     *scanner);
69 static guint       gtk_rc_parse_style              (GScanner     *scanner);
70 static guint       gtk_rc_parse_base               (GScanner     *scanner,
71                                                     GtkRcStyle   *style);
72 static guint       gtk_rc_parse_bg                 (GScanner     *scanner,
73                                                     GtkRcStyle   *style);
74 static guint       gtk_rc_parse_fg                 (GScanner     *scanner,
75                                                     GtkRcStyle   *style);
76 static guint       gtk_rc_parse_text               (GScanner     *scanner,
77                                                     GtkRcStyle   *style);
78 static guint       gtk_rc_parse_bg_pixmap          (GScanner     *scanner,
79                                                     GtkRcStyle   *rc_style);
80 static guint       gtk_rc_parse_font               (GScanner     *scanner,
81                                                     GtkRcStyle   *rc_style);
82 static guint       gtk_rc_parse_fontset            (GScanner     *scanner,
83                                                     GtkRcStyle   *rc_style);
84 static guint       gtk_rc_parse_engine             (GScanner     *scanner,
85                                                     GtkRcStyle   *rc_style);
86 static guint       gtk_rc_parse_pixmap_path        (GScanner     *scanner);
87 static void        gtk_rc_parse_pixmap_path_string (gchar *pix_path);
88 static guint       gtk_rc_parse_module_path        (GScanner     *scanner);
89 static void        gtk_rc_parse_module_path_string (gchar *mod_path);
90 static guint       gtk_rc_parse_path_pattern       (GScanner     *scanner);
91 static void        gtk_rc_clear_hash_node          (gpointer   key, 
92                                                     gpointer   data, 
93                                                     gpointer   user_data);
94 static void        gtk_rc_clear_styles               (void);
95 static void        gtk_rc_append_default_pixmap_path (void);
96 static void        gtk_rc_append_default_module_path (void);
97 static void        gtk_rc_append_pixmap_path         (gchar *dir);
98
99
100 static  GScannerConfig  gtk_rc_scanner_config =
101 {
102   (
103    " \t\n"
104    )                    /* cset_skip_characters */,
105   (
106    G_CSET_a_2_z
107    "_"
108    G_CSET_A_2_Z
109    )                    /* cset_identifier_first */,
110   (
111    G_CSET_a_2_z
112    "_-0123456789"
113    G_CSET_A_2_Z
114    )                    /* cset_identifier_nth */,
115   ( "#\n" )             /* cpair_comment_single */,
116   
117   TRUE                  /* case_sensitive */,
118   
119   TRUE                  /* skip_comment_multi */,
120   TRUE                  /* skip_comment_single */,
121   TRUE                  /* scan_comment_multi */,
122   TRUE                  /* scan_identifier */,
123   FALSE                 /* scan_identifier_1char */,
124   FALSE                 /* scan_identifier_NULL */,
125   TRUE                  /* scan_symbols */,
126   TRUE                  /* scan_binary */,
127   TRUE                  /* scan_octal */,
128   TRUE                  /* scan_float */,
129   TRUE                  /* scan_hex */,
130   TRUE                  /* scan_hex_dollar */,
131   TRUE                  /* scan_string_sq */,
132   TRUE                  /* scan_string_dq */,
133   TRUE                  /* numbers_2_int */,
134   FALSE                 /* int_2_float */,
135   FALSE                 /* identifier_2_string */,
136   TRUE                  /* char_2_token */,
137   TRUE                  /* symbol_2_token */,
138   FALSE                 /* scope_0_fallback */,
139 };
140
141 static struct
142 {
143   gchar *name;
144   guint token;
145 } symbols[] = {
146   { "include", GTK_RC_TOKEN_INCLUDE },
147   { "NORMAL", GTK_RC_TOKEN_NORMAL },
148   { "ACTIVE", GTK_RC_TOKEN_ACTIVE },
149   { "PRELIGHT", GTK_RC_TOKEN_PRELIGHT },
150   { "SELECTED", GTK_RC_TOKEN_SELECTED },
151   { "INSENSITIVE", GTK_RC_TOKEN_INSENSITIVE },
152   { "fg", GTK_RC_TOKEN_FG },
153   { "bg", GTK_RC_TOKEN_BG },
154   { "base", GTK_RC_TOKEN_BASE },
155   { "text", GTK_RC_TOKEN_TEXT },
156   { "font", GTK_RC_TOKEN_FONT },
157   { "fontset", GTK_RC_TOKEN_FONTSET },
158   { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP },
159   { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH },
160   { "style", GTK_RC_TOKEN_STYLE },
161   { "binding", GTK_RC_TOKEN_BINDING },
162   { "bind", GTK_RC_TOKEN_BIND },
163   { "widget", GTK_RC_TOKEN_WIDGET },
164   { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS },
165   { "class", GTK_RC_TOKEN_CLASS },
166   { "lowest", GTK_RC_TOKEN_LOWEST },
167   { "gtk", GTK_RC_TOKEN_GTK },
168   { "application", GTK_RC_TOKEN_APPLICATION },
169   { "rc", GTK_RC_TOKEN_RC },
170   { "highest", GTK_RC_TOKEN_HIGHEST },
171   { "engine", GTK_RC_TOKEN_ENGINE },
172   { "module_path", GTK_RC_TOKEN_MODULE_PATH },
173 };
174
175 static guint n_symbols = sizeof (symbols) / sizeof (symbols[0]);
176
177 static GHashTable *rc_style_ht = NULL;
178 static GHashTable *realized_style_ht = NULL;
179 static GSList *gtk_rc_sets_widget = NULL;
180 static GSList *gtk_rc_sets_widget_class = NULL;
181 static GSList *gtk_rc_sets_class = NULL;
182
183 #define GTK_RC_MAX_PIXMAP_PATHS 128
184 static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
185 #define GTK_RC_MAX_MODULE_PATHS 128
186 static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
187
188 /* The files we have parsed, to reread later if necessary */
189 GSList *rc_files = NULL;
190
191 static GtkImageLoader image_loader = NULL;
192
193 /* RC file handling */
194
195
196 gchar *
197 gtk_rc_get_theme_dir(void)
198 {
199   gchar *var, *path;
200
201   var = getenv("GTK_DATA_PREFIX");
202   if (var)
203     {
204       path = g_malloc(strlen(var) + strlen("/share/themes") +1);
205       sprintf(path, "%s%s", var, "/share/themes");
206     }
207   else
208     {
209       path = g_malloc(strlen(GTK_DATA_PREFIX) + strlen("/share/themes") +1);
210       sprintf(path, "%s%s", GTK_DATA_PREFIX, "/share/themes");
211     }
212   return path;
213 }
214
215 gchar *
216 gtk_rc_get_module_dir(void)
217 {
218   gchar *var, *path;
219
220   var = getenv("GTK_EXE_PREFIX");
221   if (var)
222     {
223       path = g_malloc(strlen(var) + strlen("/lib/gtk/themes/engines") +1);
224       sprintf(path, "%s%s", var, "/lib/gtk/themes/engines");
225     }
226   else
227     {
228       path = g_malloc(strlen(GTK_EXE_PREFIX) + strlen("/lib/gtk/themes/engines") +1);
229       sprintf(path, "%s%s", GTK_EXE_PREFIX, "/lib/gtk/themes/engines");
230     }
231   return path;
232 }
233
234 static void
235 gtk_rc_append_default_pixmap_path(void)
236 {
237   gchar *var, *path;
238   gint n;
239
240   var = getenv("GTK_DATA_PREFIX");
241   if (var)
242     {
243       path = g_malloc(strlen(var) + strlen("/share/gtk/themes") +1);
244       sprintf(path, "%s%s", var, "/share/gtk/themes");
245     }
246   else
247     {
248       path = g_malloc(strlen(GTK_DATA_PREFIX) + strlen("/share/gtk/themes") +1);
249       sprintf(path, "%s%s", GTK_DATA_PREFIX, "/share/gtk/themes");
250     }
251   
252   for (n = 0; pixmap_path[n]; n++) ;
253   if (n >= GTK_RC_MAX_PIXMAP_PATHS - 1)
254     return;
255   pixmap_path[n++] = g_strdup(path);
256   pixmap_path[n] = NULL;
257   g_free(path);
258 }
259
260 static void
261 gtk_rc_append_pixmap_path(gchar *dir)
262 {
263   gint n;
264
265   for (n = 0; pixmap_path[n]; n++) ;
266   if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
267     return;
268   pixmap_path[n++] = g_strdup(dir);
269   pixmap_path[n] = NULL;
270 }
271
272 static void
273 gtk_rc_append_default_module_path(void)
274 {
275   gchar *var, *path;
276   gint n;
277
278   for (n = 0; module_path[n]; n++) ;
279   if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
280     return;
281   
282   var = getenv("GTK_EXE_PREFIX");
283   if (var)
284     {
285       path = g_malloc(strlen(var) + strlen("/lib/gtk/themes/engines") +1);
286       sprintf(path, "%s%s", var, "/lib/gtk/themes/engines");
287     }
288   else
289     {
290       path = g_malloc(strlen(GTK_EXE_PREFIX) + strlen("/lib/gtk/themes/engines") +1);
291       sprintf(path, "%s%s", GTK_EXE_PREFIX, "/lib/gtk/themes/engines");
292     }
293   module_path[n++] = g_strdup(path);
294   g_free(path);
295   var = getenv("HOME");
296   if (var)
297     {
298       path = g_malloc(strlen(var) + strlen(".gtk/lib/themes/engines") +1);
299       sprintf(path, "%s%s", var, ".gtk/lib/themes/engines");
300     }
301   module_path[n++] = g_strdup(path);
302   module_path[n] = NULL;
303   g_free(path);
304 }
305
306 void
307 gtk_rc_init (void)
308 {
309   rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
310                                   (GCompareFunc) gtk_rc_style_compare);
311   pixmap_path[0] = NULL;
312   module_path[0] = NULL;
313   gtk_rc_append_default_pixmap_path();
314   gtk_rc_append_default_module_path();
315 }
316
317 void
318 gtk_rc_parse_string (const gchar *rc_string)
319 {
320   g_return_if_fail (rc_string != NULL);
321
322   gtk_rc_parse_any ("-", -1, rc_string);
323 }
324
325 static void
326 gtk_rc_parse_file (const gchar *filename, gboolean reload)
327 {
328   GtkRcFile *rc_file = NULL;
329   struct stat statbuf;
330   GSList *tmp_list;
331
332   g_return_if_fail (filename != NULL);
333
334   tmp_list = rc_files;
335   while (tmp_list)
336     {
337       rc_file = tmp_list->data;
338       if (!strcmp (rc_file->name, filename))
339         break;
340       
341       tmp_list = tmp_list->next;
342     }
343
344   if (!tmp_list)
345     {
346       rc_file = g_new (GtkRcFile, 1);
347       rc_file->name = g_strdup (filename);
348       rc_file->canonical_name = NULL;
349       rc_file->mtime = 0;
350       rc_file->reload = reload;
351
352       rc_files = g_slist_append (rc_files, rc_file);
353     }
354
355   if (!rc_file->canonical_name)
356     {
357       /* Get the absolute pathname */
358
359       if (rc_file->name[0] == '/')
360         rc_file->canonical_name = rc_file->name;
361       else
362         {
363           GString *str;
364           gchar *cwd;
365
366           cwd = g_get_current_dir ();
367
368           str = g_string_new (cwd);
369           g_free (cwd);
370           g_string_append_c (str, '/');
371           g_string_append (str, rc_file->name);
372           
373           rc_file->canonical_name = str->str;
374           g_string_free (str, FALSE);
375         }
376     }
377
378   if (!lstat (rc_file->canonical_name, &statbuf))
379     {
380       gint fd;
381
382       rc_file->mtime = statbuf.st_mtime;
383
384       fd = open (rc_file->canonical_name, O_RDONLY);
385       if (fd < 0)
386         return;
387
388         {
389           gint i;
390           gchar *dir;
391           
392           dir = g_strdup(rc_file->canonical_name);
393           for (i = strlen(dir) - 1; (i >= 0) && (dir[i] != '/'); i--)
394             dir[i] = 0;
395           gtk_rc_append_pixmap_path(dir);
396           g_free(dir);
397         }
398       gtk_rc_parse_any (filename, fd, NULL);
399
400       close (fd);
401     }
402 }
403
404 void
405 gtk_rc_parse (const gchar *filename)
406 {
407   g_return_if_fail (filename != NULL);
408
409   gtk_rc_parse_file (filename, TRUE);
410 }
411
412 /* Handling of RC styles */
413
414 GtkRcStyle *
415 gtk_rc_style_new              (void)
416 {
417   GtkRcStyle *new_style;
418
419   new_style = g_new0 (GtkRcStyle, 1);
420   new_style->ref_count = 1;
421
422   return new_style;
423 }
424
425 void      
426 gtk_rc_style_ref (GtkRcStyle  *rc_style)
427 {
428   g_return_if_fail (rc_style != NULL);
429
430   rc_style->ref_count++;
431 }
432
433 void      
434 gtk_rc_style_unref (GtkRcStyle  *rc_style)
435 {
436   gint i;
437
438   g_return_if_fail (rc_style != NULL);
439
440   rc_style->ref_count--;
441
442   if (rc_style->ref_count == 0)
443     {
444       if (rc_style->engine)
445         {
446           rc_style->engine->destroy_rc_style (rc_style);
447           gtk_theme_engine_unref (rc_style->engine);
448         }
449
450       if (rc_style->name)
451         g_free (rc_style->name);
452       if (rc_style->fontset_name)
453         g_free (rc_style->fontset_name);
454       if (rc_style->font_name)
455         g_free (rc_style->font_name);
456       
457       for (i=0 ; i<5 ; i++)
458         if (rc_style->bg_pixmap_name[i])
459           g_free (rc_style->bg_pixmap_name[i]);
460       
461       g_free (rc_style);
462     }
463 }
464
465 static void
466 gtk_rc_clear_realized_node (gpointer key,
467                             gpointer data,
468                             gpointer user_data)
469 {
470   gtk_style_unref (data);
471 }
472
473 static void
474 gtk_rc_clear_hash_node (gpointer key, 
475                         gpointer data, 
476                         gpointer user_data)
477 {
478   gtk_rc_style_unref (data);
479 }
480
481 static void
482 gtk_rc_free_rc_sets (GSList *slist)
483 {
484   while (slist)
485     {
486       GtkRcSet *rc_set;
487
488       rc_set = slist->data;
489       gtk_pattern_spec_free_segs (&rc_set->pspec);
490       g_free (rc_set);
491
492       slist = slist->next;
493     }
494 }
495
496 static void
497 gtk_rc_clear_styles (void)
498 {
499   /* Clear out all old rc_styles */
500
501   if (rc_style_ht)
502     {
503       g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
504       g_hash_table_destroy (rc_style_ht);
505       rc_style_ht = NULL;
506     }
507
508   if (realized_style_ht)
509     {
510       g_hash_table_foreach (realized_style_ht, gtk_rc_clear_realized_node, NULL);
511       g_hash_table_destroy (realized_style_ht);
512       realized_style_ht = NULL;
513     }
514
515   gtk_rc_free_rc_sets (gtk_rc_sets_widget);
516   g_slist_free (gtk_rc_sets_widget);
517   gtk_rc_sets_widget = NULL;
518
519   gtk_rc_free_rc_sets (gtk_rc_sets_widget_class);
520   g_slist_free (gtk_rc_sets_widget_class);
521   gtk_rc_sets_widget_class = NULL;
522
523   gtk_rc_free_rc_sets (gtk_rc_sets_class);
524   g_slist_free (gtk_rc_sets_class);
525   gtk_rc_sets_class = NULL;
526
527   gtk_rc_init ();
528 }
529
530 gboolean
531 gtk_rc_reparse_all (void)
532 {
533   GSList *tmp_list;
534   gboolean mtime_modified = FALSE;
535   GtkRcFile *rc_file;
536
537   struct stat statbuf;
538
539   /* Check through and see if any of the RC's have had their
540    * mtime modified. If so, reparse everything.
541    */
542   tmp_list = rc_files;
543   while (tmp_list)
544     {
545       rc_file = tmp_list->data;
546       
547       if (!lstat (rc_file->name, &statbuf) && 
548           (statbuf.st_mtime > rc_file->mtime))
549         {
550           mtime_modified = TRUE;
551           break;
552         }
553       
554       tmp_list = tmp_list->next;
555     }
556
557   if (mtime_modified)
558     {
559       gtk_rc_clear_styles();
560
561       tmp_list = rc_files;
562       while (tmp_list)
563         {
564           rc_file = tmp_list->data;
565           if (rc_file->reload)
566             gtk_rc_parse_file (rc_file->name, FALSE);
567           
568           tmp_list = tmp_list->next;
569         }
570     }
571
572   return mtime_modified;
573 }
574
575 static GSList *
576 gtk_rc_styles_match (GSList       *rc_styles,
577                      GSList       *sets,
578                      guint         path_length,
579                      gchar        *path,
580                      gchar        *path_reversed)
581                      
582 {
583   GtkRcSet *rc_set;
584
585   while (sets)
586     {
587       rc_set = sets->data;
588       sets = sets->next;
589
590       if (gtk_pattern_match (&rc_set->pspec, path_length, path, path_reversed))
591         rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
592     }
593   
594   return rc_styles;
595 }
596
597 GtkStyle*
598 gtk_rc_get_style (GtkWidget *widget)
599 {
600   GtkRcStyle *widget_rc_style;
601   GSList *rc_styles = NULL;
602
603   static guint rc_style_key_id = 0;
604
605   /* We allow the specification of a single rc style to be bound
606    * tightly to a widget, for application modifications
607    */
608   if (!rc_style_key_id)
609     rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
610
611   widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
612                                                rc_style_key_id);
613
614   if (widget_rc_style)
615     rc_styles = g_list_prepend (rc_styles, widget_rc_style);
616   
617   if (gtk_rc_sets_widget)
618     {
619       gchar *path, *path_reversed;
620       guint path_length;
621
622       gtk_widget_path (widget, &path_length, &path, &path_reversed);
623       rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget, path_length, path, path_reversed);
624       g_free (path);
625       g_free (path_reversed);
626       
627     }
628   
629   if (gtk_rc_sets_widget_class)
630     {
631       gchar *path, *path_reversed;
632       guint path_length;
633
634       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
635       rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget_class, path_length, path, path_reversed);
636       g_free (path);
637       g_free (path_reversed);
638     }
639
640   if (gtk_rc_sets_class)
641     {
642       GtkType type;
643
644       type = GTK_OBJECT_TYPE (widget);
645       while (type)
646         {
647           gchar *path, *path_reversed;
648           guint path_length;
649
650           path = gtk_type_name (type);
651           path_length = strlen (path);
652           path_reversed = g_strdup (path);
653           g_strreverse (path_reversed);
654           
655           rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_class, path_length, path, path_reversed);
656           g_free (path_reversed);
657       
658           type = gtk_type_parent (type);
659         }
660     }
661   
662   if (rc_styles)
663     return gtk_rc_style_init (rc_styles);
664
665   return NULL;
666 }
667
668 static GSList*
669 gtk_rc_add_rc_sets (GSList     *slist,
670                     GtkRcStyle *rc_style,
671                     const char *pattern)
672 {
673   GtkRcStyle *new_style;
674   GtkRcSet *rc_set;
675   guint i;
676   
677   new_style = gtk_rc_style_new ();
678   *new_style = *rc_style;
679   new_style->name = g_strdup (rc_style->name);
680   new_style->font_name = g_strdup (rc_style->font_name);
681   new_style->fontset_name = g_strdup (rc_style->fontset_name);
682   
683   for (i = 0; i < 5; i++)
684     new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
685   
686   rc_set = g_new (GtkRcSet, 1);
687   gtk_pattern_spec_init (&rc_set->pspec, pattern);
688   rc_set->rc_style = rc_style;
689   
690   return g_slist_prepend (slist, rc_set);
691 }
692
693 void
694 gtk_rc_add_widget_name_style (GtkRcStyle  *rc_style,
695                               const gchar *pattern)
696 {
697   g_return_if_fail (rc_style != NULL);
698   g_return_if_fail (pattern != NULL);
699
700   gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, rc_style, pattern);
701 }
702
703 void
704 gtk_rc_add_widget_class_style (GtkRcStyle  *rc_style,
705                                const gchar *pattern)
706 {
707   g_return_if_fail (rc_style != NULL);
708   g_return_if_fail (pattern != NULL);
709
710   gtk_rc_sets_widget_class = gtk_rc_add_rc_sets (gtk_rc_sets_widget_class, rc_style, pattern);
711 }
712
713 void
714 gtk_rc_add_class_style (GtkRcStyle  *rc_style,
715                         const gchar *pattern)
716 {
717   g_return_if_fail (rc_style != NULL);
718   g_return_if_fail (pattern != NULL);
719
720   gtk_rc_sets_class = gtk_rc_add_rc_sets (gtk_rc_sets_class, rc_style, pattern);
721 }
722
723 static void
724 gtk_rc_parse_any (const gchar  *input_name,
725                   gint          input_fd,
726                   const gchar  *input_string)
727 {
728   GScanner *scanner;
729   guint    i;
730   gboolean done;
731   
732   scanner = g_scanner_new (&gtk_rc_scanner_config);
733   
734   if (input_fd >= 0)
735     {
736       g_assert (input_string == NULL);
737       
738       g_scanner_input_file (scanner, input_fd);
739     }
740   else
741     {
742       g_assert (input_string != NULL);
743       
744       g_scanner_input_text (scanner, input_string, strlen (input_string));
745     }
746   scanner->input_name = input_name;
747
748   g_scanner_freeze_symbol_table (scanner);
749   for (i = 0; i < n_symbols; i++)
750     g_scanner_add_symbol (scanner, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
751   g_scanner_thaw_symbol_table (scanner);
752   
753   done = FALSE;
754   while (!done)
755     {
756       if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
757         done = TRUE;
758       else
759         {
760           guint expected_token;
761           
762           expected_token = gtk_rc_parse_statement (scanner);
763
764           if (expected_token != G_TOKEN_NONE)
765             {
766               gchar *symbol_name;
767               gchar *msg;
768               
769               msg = NULL;
770               symbol_name = NULL;
771               if (scanner->scope_id == 0)
772                 {
773                   /* if we are in scope 0, we know the symbol names
774                    * that are associated with certaintoken values.
775                    * so we look them up to make the error messages
776                    * more readable.
777                    */
778                   if (expected_token > GTK_RC_TOKEN_INVALID &&
779                       expected_token < GTK_RC_TOKEN_LAST)
780                     {
781                       for (i = 0; i < n_symbols; i++)
782                         if (symbols[i].token == expected_token)
783                           msg = symbols[i].name;
784                       if (msg)
785                         msg = g_strconcat ("e.g. `", msg, "'", NULL);
786                     }
787                   if (scanner->token > GTK_RC_TOKEN_INVALID &&
788                       scanner->token < GTK_RC_TOKEN_LAST)
789                     {
790                       symbol_name = "???";
791                       for (i = 0; i < n_symbols; i++)
792                         if (symbols[i].token == scanner->token)
793                           symbol_name = symbols[i].name;
794                     }
795                 }
796               g_scanner_unexp_token (scanner,
797                                      expected_token,
798                                      NULL,
799                                      "keyword",
800                                      symbol_name,
801                                      msg,
802                                      TRUE);
803               g_free (msg);
804               done = TRUE;
805             }
806         }
807     }
808   
809   g_scanner_destroy (scanner);
810 }
811
812 static guint       
813 gtk_rc_styles_hash (const GSList *rc_styles)
814 {
815   guint result;
816   
817   result = 0;
818   while (rc_styles)
819     {
820       result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
821       rc_styles = rc_styles->next;
822     }
823   
824   return result;
825 }
826
827 static gint        
828 gtk_rc_styles_compare (const GSList *a,
829                        const GSList *b)
830 {
831   while (a && b)
832     {
833       if (a->data != b->data)
834         return FALSE;
835       a = a->next;
836       b = b->next;
837     }
838   
839   return (a == b);
840 }
841
842 static guint
843 gtk_rc_style_hash (const char *name)
844 {
845   guint result;
846   
847   result = 0;
848   while (*name)
849     result += (result << 3) + *name++;
850   
851   return result;
852 }
853
854 static gint
855 gtk_rc_style_compare (const char *a,
856                       const char *b)
857 {
858   return (strcmp (a, b) == 0);
859 }
860
861 static GtkRcStyle*
862 gtk_rc_style_find (const char *name)
863 {
864   GtkRcStyle *rc_style;
865   
866   rc_style = g_hash_table_lookup (rc_style_ht, (gpointer) name);
867   
868   return rc_style;
869 }
870
871 /* Assumes ownership of rc_style */
872 static GtkStyle *
873 gtk_rc_style_to_style (GtkRcStyle *rc_style)
874 {
875   GtkStyle *style;
876   GdkFont *old_font;
877   gint i;
878
879   style = gtk_style_new ();
880
881   style->rc_style = rc_style;
882   
883   if (rc_style->fontset_name)
884     {
885       old_font = style->font;
886       style->font = gdk_fontset_load (rc_style->fontset_name);
887       if (style->font)
888         gdk_font_unref (old_font);
889       else
890         style->font = old_font;
891     }
892   else if (rc_style->font_name)
893     {
894       old_font = style->font;
895       style->font = gdk_font_load (rc_style->font_name);
896       if (style->font)
897         gdk_font_unref (old_font);
898       else
899         style->font = old_font;
900     }
901   
902   for (i = 0; i < 5; i++)
903     {
904       if (rc_style->color_flags[i] & GTK_RC_FG)
905         style->fg[i] = rc_style->fg[i];
906       if (rc_style->color_flags[i] & GTK_RC_BG)
907         style->bg[i] = rc_style->bg[i];
908       if (rc_style->color_flags[i] & GTK_RC_TEXT)
909         style->text[i] = rc_style->text[i];
910       if (rc_style->color_flags[i] & GTK_RC_BASE)
911         style->base[i] = rc_style->base[i];
912     }
913
914   if (rc_style->engine)
915     {
916       style->engine = rc_style->engine;
917       gtk_theme_engine_ref (style->engine);
918       rc_style->engine->rc_style_to_style (style, rc_style);
919     }
920
921   return style;
922 }
923
924 /* Reuses or frees rc_styles */
925 static GtkStyle *
926 gtk_rc_style_init (GSList *rc_styles)
927 {
928   gint i;
929
930   GtkStyle *style = NULL;
931   GtkRcStyle *proto_style;
932
933   if (!realized_style_ht)
934     realized_style_ht = g_hash_table_new ((GHashFunc)gtk_rc_styles_hash,
935                                            (GCompareFunc)gtk_rc_styles_compare);
936
937   style = g_hash_table_lookup (realized_style_ht, rc_styles);
938
939   if (!style)
940     {
941       GSList *tmp_styles = rc_styles;
942       
943       proto_style = gtk_rc_style_new ();
944
945       while (tmp_styles)
946         {
947           GtkRcStyle *rc_style = tmp_styles->data;
948
949           for (i=0; i<5; i++)
950             {
951               if (!proto_style->bg_pixmap_name[i] && rc_style->bg_pixmap_name[i])
952                 proto_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
953
954               if (!(proto_style->color_flags[i] & GTK_RC_FG) && 
955                     rc_style->color_flags[i] & GTK_RC_FG)
956                 {
957                   proto_style->fg[i] = rc_style->fg[i];
958                   proto_style->color_flags[i] |= GTK_RC_FG;
959                 }
960               if (!(proto_style->color_flags[i] & GTK_RC_BG) && 
961                     rc_style->color_flags[i] & GTK_RC_BG)
962                 {
963                   proto_style->bg[i] = rc_style->bg[i];
964                   proto_style->color_flags[i] |= GTK_RC_BG;
965                 }
966               if (!(proto_style->color_flags[i] & GTK_RC_TEXT) && 
967                     rc_style->color_flags[i] & GTK_RC_TEXT)
968                 {
969                   proto_style->text[i] = rc_style->text[i];
970                   proto_style->color_flags[i] |= GTK_RC_TEXT;
971                 }
972               if (!(proto_style->color_flags[i] & GTK_RC_BASE) && 
973                     rc_style->color_flags[i] & GTK_RC_BASE)
974                 {
975                   proto_style->base[i] = rc_style->base[i];
976                   proto_style->color_flags[i] |= GTK_RC_BASE;
977                 }
978             }
979
980           if (!proto_style->font_name && rc_style->font_name)
981             proto_style->font_name = g_strdup (rc_style->font_name);
982           if (!proto_style->fontset_name && rc_style->fontset_name)
983             proto_style->fontset_name = g_strdup (rc_style->fontset_name);
984
985           if (!proto_style->engine && rc_style->engine)
986             {
987               proto_style->engine = rc_style->engine;
988               gtk_theme_engine_ref (proto_style->engine);
989             }
990           
991           if (proto_style->engine &&
992               (proto_style->engine == rc_style->engine))
993             proto_style->engine->merge_rc_style (proto_style, rc_style);
994
995           tmp_styles = tmp_styles->next;
996         }
997
998       style = gtk_rc_style_to_style (proto_style);
999
1000       g_hash_table_insert (realized_style_ht, rc_styles, style);
1001     }
1002
1003   return style;
1004 }
1005
1006 /*********************
1007  * Parsing functions *
1008  *********************/
1009
1010 static guint
1011 gtk_rc_parse_statement (GScanner *scanner)
1012 {
1013   guint token;
1014   
1015   token = g_scanner_peek_next_token (scanner);
1016
1017   switch (token)
1018     {
1019     case GTK_RC_TOKEN_INCLUDE:
1020       token = g_scanner_get_next_token (scanner);
1021       if (token != GTK_RC_TOKEN_INCLUDE)
1022         return GTK_RC_TOKEN_INCLUDE;
1023
1024       token = g_scanner_get_next_token (scanner);
1025       if (token != G_TOKEN_STRING)
1026         return G_TOKEN_STRING;
1027
1028       gtk_rc_parse_file (scanner->value.v_string, FALSE);
1029       return G_TOKEN_NONE;
1030
1031     case GTK_RC_TOKEN_STYLE:
1032       return gtk_rc_parse_style (scanner);
1033
1034     case GTK_RC_TOKEN_BINDING:
1035       return gtk_binding_parse_binding (scanner);
1036
1037     case GTK_RC_TOKEN_PIXMAP_PATH:
1038       return gtk_rc_parse_pixmap_path (scanner);
1039
1040     case GTK_RC_TOKEN_WIDGET:
1041       return gtk_rc_parse_path_pattern (scanner);
1042
1043     case GTK_RC_TOKEN_WIDGET_CLASS:
1044       return gtk_rc_parse_path_pattern (scanner);
1045
1046     case GTK_RC_TOKEN_CLASS:
1047       return gtk_rc_parse_path_pattern (scanner);
1048
1049     case GTK_RC_TOKEN_MODULE_PATH:
1050       return gtk_rc_parse_module_path (scanner);
1051        
1052     default:
1053       g_scanner_get_next_token (scanner);
1054       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
1055     }
1056 }
1057
1058 static guint
1059 gtk_rc_parse_style (GScanner *scanner)
1060 {
1061   GtkRcStyle *rc_style;
1062   GtkRcStyle *parent_style;
1063   guint token;
1064   gint insert;
1065   gint i;
1066   
1067   token = g_scanner_get_next_token (scanner);
1068   if (token != GTK_RC_TOKEN_STYLE)
1069     return GTK_RC_TOKEN_STYLE;
1070   
1071   token = g_scanner_get_next_token (scanner);
1072   if (token != G_TOKEN_STRING)
1073     return G_TOKEN_STRING;
1074   
1075   insert = FALSE;
1076   rc_style = g_hash_table_lookup (rc_style_ht, scanner->value.v_string);
1077   
1078   if (!rc_style)
1079     {
1080       insert = TRUE;
1081       rc_style = gtk_rc_style_new ();
1082       rc_style->name = g_strdup (scanner->value.v_string);
1083       
1084       for (i = 0; i < 5; i++)
1085         rc_style->bg_pixmap_name[i] = NULL;
1086
1087       for (i = 0; i < 5; i++)
1088         rc_style->color_flags[i] = 0;
1089
1090       rc_style->engine = NULL;
1091       rc_style->engine_data = NULL;
1092     }
1093   
1094   token = g_scanner_peek_next_token (scanner);
1095   if (token == G_TOKEN_EQUAL_SIGN)
1096     {
1097       token = g_scanner_get_next_token (scanner);
1098       
1099       token = g_scanner_get_next_token (scanner);
1100       if (token != G_TOKEN_STRING)
1101         {
1102           if (insert)
1103             g_free (rc_style);
1104
1105           return G_TOKEN_STRING;
1106         }
1107       
1108       parent_style = g_hash_table_lookup (rc_style_ht, scanner->value.v_string);
1109       if (parent_style)
1110         {
1111           for (i = 0; i < 5; i++)
1112             {
1113               rc_style->color_flags[i] = parent_style->color_flags[i];
1114               rc_style->fg[i] = parent_style->fg[i];
1115               rc_style->bg[i] = parent_style->bg[i];
1116               rc_style->text[i] = parent_style->text[i];
1117               rc_style->base[i] = parent_style->base[i];
1118             }
1119           
1120           if (rc_style->fontset_name)
1121             {
1122               g_free (rc_style->fontset_name);
1123               rc_style->fontset_name = g_strdup (parent_style->fontset_name);
1124             }
1125           else if (rc_style->font_name)
1126             {
1127               g_free (rc_style->font_name);
1128               rc_style->font_name = g_strdup (parent_style->font_name);
1129             }
1130           
1131           for (i = 0; i < 5; i++)
1132             {
1133               if (rc_style->bg_pixmap_name[i])
1134                 g_free (rc_style->bg_pixmap_name[i]);
1135               rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
1136             }
1137         }
1138     }
1139   
1140   token = g_scanner_get_next_token (scanner);
1141   if (token != G_TOKEN_LEFT_CURLY)
1142     {
1143       if (insert)
1144         g_free (rc_style);
1145
1146       return G_TOKEN_LEFT_CURLY;
1147     }
1148   
1149   token = g_scanner_peek_next_token (scanner);
1150   while (token != G_TOKEN_RIGHT_CURLY)
1151     {
1152       switch (token)
1153         {
1154         case GTK_RC_TOKEN_BASE:
1155           token = gtk_rc_parse_base (scanner, rc_style);
1156           break;
1157         case GTK_RC_TOKEN_BG:
1158           token = gtk_rc_parse_bg (scanner, rc_style);
1159           break;
1160         case GTK_RC_TOKEN_FG:
1161           token = gtk_rc_parse_fg (scanner, rc_style);
1162           break;
1163         case GTK_RC_TOKEN_TEXT:
1164           token = gtk_rc_parse_text (scanner, rc_style);
1165           break;
1166         case GTK_RC_TOKEN_BG_PIXMAP:
1167           token = gtk_rc_parse_bg_pixmap (scanner, rc_style);
1168           break;
1169         case GTK_RC_TOKEN_FONT:
1170           token = gtk_rc_parse_font (scanner, rc_style);
1171           break;
1172         case GTK_RC_TOKEN_FONTSET:
1173           token = gtk_rc_parse_fontset (scanner, rc_style);
1174           break;
1175         case GTK_RC_TOKEN_ENGINE:
1176           token = gtk_rc_parse_engine (scanner, rc_style);
1177           break;
1178         default:
1179           g_scanner_get_next_token (scanner);
1180           token = G_TOKEN_RIGHT_CURLY;
1181           break;
1182         }
1183
1184       if (token != G_TOKEN_NONE)
1185         {
1186           if (insert)
1187             {
1188               if (rc_style->fontset_name)
1189                 g_free (rc_style->fontset_name);
1190               if (rc_style->font_name)
1191                 g_free (rc_style->font_name);
1192               for (i = 0; i < 5; i++)
1193                 if (rc_style->bg_pixmap_name[i])
1194                   g_free (rc_style->bg_pixmap_name[i]);
1195               g_free (rc_style);
1196             }
1197           return token;
1198         }
1199       token = g_scanner_peek_next_token (scanner);
1200     }
1201   
1202   token = g_scanner_get_next_token (scanner);
1203   if (token != G_TOKEN_RIGHT_CURLY)
1204     {
1205       if (insert)
1206         {
1207           if (rc_style->fontset_name)
1208             g_free (rc_style->fontset_name);
1209           if (rc_style->font_name)
1210             g_free (rc_style->font_name);
1211           
1212           for (i = 0; i < 5; i++)
1213             if (rc_style->bg_pixmap_name[i])
1214               g_free (rc_style->bg_pixmap_name[i]);
1215           
1216           g_free (rc_style);
1217         }
1218       return G_TOKEN_RIGHT_CURLY;
1219     }
1220   
1221   if (insert)
1222     g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
1223   
1224   return G_TOKEN_NONE;
1225 }
1226
1227 static guint
1228 gtk_rc_parse_base (GScanner   *scanner,
1229                    GtkRcStyle *style)
1230 {
1231   GtkStateType state;
1232   guint token;
1233   
1234   token = g_scanner_get_next_token (scanner);
1235   if (token != GTK_RC_TOKEN_BASE)
1236     return GTK_RC_TOKEN_BASE;
1237   
1238   token = gtk_rc_parse_state (scanner, &state);
1239   if (token != G_TOKEN_NONE)
1240     return token;
1241   
1242   token = g_scanner_get_next_token (scanner);
1243   if (token != G_TOKEN_EQUAL_SIGN)
1244     return G_TOKEN_EQUAL_SIGN;
1245
1246   style->color_flags[state] |= GTK_RC_BASE;
1247   return gtk_rc_parse_color (scanner, &style->base[state]);
1248 }
1249
1250 static guint
1251 gtk_rc_parse_bg (GScanner   *scanner,
1252                  GtkRcStyle *style)
1253 {
1254   GtkStateType state;
1255   guint token;
1256   
1257   token = g_scanner_get_next_token (scanner);
1258   if (token != GTK_RC_TOKEN_BG)
1259     return GTK_RC_TOKEN_BG;
1260   
1261   token = gtk_rc_parse_state (scanner, &state);
1262   if (token != G_TOKEN_NONE)
1263     return token;
1264   
1265   token = g_scanner_get_next_token (scanner);
1266   if (token != G_TOKEN_EQUAL_SIGN)
1267     return G_TOKEN_EQUAL_SIGN;
1268
1269   style->color_flags[state] |= GTK_RC_BG;
1270   return gtk_rc_parse_color (scanner, &style->bg[state]);
1271 }
1272
1273 static guint
1274 gtk_rc_parse_fg (GScanner   *scanner,
1275                  GtkRcStyle *style)
1276 {
1277   GtkStateType state;
1278   guint token;
1279   
1280   token = g_scanner_get_next_token (scanner);
1281   if (token != GTK_RC_TOKEN_FG)
1282     return GTK_RC_TOKEN_FG;
1283   
1284   token = gtk_rc_parse_state (scanner, &state);
1285   if (token != G_TOKEN_NONE)
1286     return token;
1287   
1288   token = g_scanner_get_next_token (scanner);
1289   if (token != G_TOKEN_EQUAL_SIGN)
1290     return G_TOKEN_EQUAL_SIGN;
1291   
1292   style->color_flags[state] |= GTK_RC_FG;
1293   return gtk_rc_parse_color (scanner, &style->fg[state]);
1294 }
1295
1296 static guint
1297 gtk_rc_parse_text (GScanner   *scanner,
1298                    GtkRcStyle *style)
1299 {
1300   GtkStateType state;
1301   guint token;
1302   
1303   token = g_scanner_get_next_token (scanner);
1304   if (token != GTK_RC_TOKEN_TEXT)
1305     return GTK_RC_TOKEN_TEXT;
1306   
1307   token = gtk_rc_parse_state (scanner, &state);
1308   if (token != G_TOKEN_NONE)
1309     return token;
1310   
1311   token = g_scanner_get_next_token (scanner);
1312   if (token != G_TOKEN_EQUAL_SIGN)
1313     return G_TOKEN_EQUAL_SIGN;
1314   
1315   style->color_flags[state] |= GTK_RC_TEXT;
1316   return gtk_rc_parse_color (scanner, &style->text[state]);
1317 }
1318
1319 static guint
1320 gtk_rc_parse_bg_pixmap (GScanner   *scanner,
1321                         GtkRcStyle *rc_style)
1322 {
1323   GtkStateType state;
1324   guint token;
1325   gchar *pixmap_file;
1326   
1327   token = g_scanner_get_next_token (scanner);
1328   if (token != GTK_RC_TOKEN_BG_PIXMAP)
1329     return GTK_RC_TOKEN_BG_PIXMAP;
1330   
1331   token = gtk_rc_parse_state (scanner, &state);
1332   if (token != G_TOKEN_NONE)
1333     return token;
1334   
1335   token = g_scanner_get_next_token (scanner);
1336   if (token != G_TOKEN_EQUAL_SIGN)
1337     return G_TOKEN_EQUAL_SIGN;
1338   
1339   token = g_scanner_get_next_token (scanner);
1340   if (token != G_TOKEN_STRING)
1341     return G_TOKEN_STRING;
1342   
1343   if (strcmp (scanner->value.v_string, "<parent>"))
1344     pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
1345   else
1346     pixmap_file = g_strdup (scanner->value.v_string);
1347   
1348   if (pixmap_file)
1349     {
1350       if (rc_style->bg_pixmap_name[state])
1351         g_free (rc_style->bg_pixmap_name[state]);
1352       rc_style->bg_pixmap_name[state] = pixmap_file;
1353     }
1354   
1355   return G_TOKEN_NONE;
1356 }
1357
1358 gchar*
1359 gtk_rc_find_pixmap_in_path (GScanner *scanner,
1360                             gchar    *pixmap_file)
1361 {
1362   gint i;
1363   gint fd;
1364   gchar *buf;
1365   
1366   for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
1367     {
1368       buf = g_malloc (strlen (pixmap_path[i]) + strlen (pixmap_file) + 2);
1369       sprintf (buf, "%s%c%s", pixmap_path[i], '/', pixmap_file);
1370       
1371       fd = open (buf, O_RDONLY);
1372       if (fd >= 0)
1373         {
1374           close (fd);
1375           return buf;
1376         }
1377       
1378       g_free (buf);
1379     }
1380
1381   if (scanner)
1382     g_warning ("Unable to locate image file in pixmap_path: \"%s\" line %d",
1383                pixmap_file, scanner->line);
1384   else
1385     g_warning ("Unable to locate image file in pixmap_path: \"%s\"",
1386                pixmap_file);
1387     
1388   return NULL;
1389 }
1390
1391 gchar*
1392 gtk_rc_find_module_in_path (GScanner *scanner,
1393                             gchar    *module_file)
1394 {
1395   gint i;
1396   gint fd;
1397   gchar *buf;
1398   
1399   for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
1400     {
1401       buf = g_malloc (strlen (module_path[i]) + strlen (module_file) + 2);
1402       sprintf (buf, "%s%c%s", module_path[i], '/', module_file);
1403       
1404       fd = open (buf, O_RDONLY);
1405       if (fd >= 0)
1406         {
1407           close (fd);
1408           return buf;
1409         }
1410       
1411       g_free (buf);
1412     }
1413   
1414   if (scanner)
1415     g_warning ("Unable to locate loadable module in module_path: \"%s\" line %d",
1416                module_file, scanner->line);
1417   else
1418     g_warning ("Unable to locate loadable module in module_path: \"%s\",",
1419                module_file);
1420     
1421   return NULL;
1422 }
1423
1424 static guint
1425 gtk_rc_parse_font (GScanner   *scanner,
1426                    GtkRcStyle *rc_style)
1427 {
1428   guint token;
1429   
1430   token = g_scanner_get_next_token (scanner);
1431   if (token != GTK_RC_TOKEN_FONT)
1432     return GTK_RC_TOKEN_FONT;
1433   
1434   token = g_scanner_get_next_token (scanner);
1435   if (token != G_TOKEN_EQUAL_SIGN)
1436     return G_TOKEN_EQUAL_SIGN;
1437   
1438   token = g_scanner_get_next_token (scanner);
1439   if (token != G_TOKEN_STRING)
1440     return G_TOKEN_STRING;
1441   
1442   if (rc_style->font_name)
1443     g_free (rc_style->font_name);
1444   rc_style->font_name = g_strdup (scanner->value.v_string);
1445   
1446   return G_TOKEN_NONE;
1447 }
1448
1449 static guint
1450 gtk_rc_parse_fontset (GScanner   *scanner,
1451                       GtkRcStyle *rc_style)
1452 {
1453   guint token;
1454   
1455   token = g_scanner_get_next_token (scanner);
1456   if (token != GTK_RC_TOKEN_FONTSET)
1457     return GTK_RC_TOKEN_FONTSET;
1458   
1459   token = g_scanner_get_next_token (scanner);
1460   if (token != G_TOKEN_EQUAL_SIGN)
1461     return G_TOKEN_EQUAL_SIGN;
1462   
1463   token = g_scanner_get_next_token (scanner);
1464   if (token != G_TOKEN_STRING)
1465     return G_TOKEN_STRING;
1466   
1467   if (rc_style->fontset_name)
1468     g_free (rc_style->fontset_name);
1469   rc_style->fontset_name = g_strdup (scanner->value.v_string);
1470   
1471   return G_TOKEN_NONE;
1472 }
1473
1474 static guint       
1475 gtk_rc_parse_engine (GScanner    *scanner,
1476                      GtkRcStyle  *rc_style)
1477 {
1478   guint token;
1479
1480   token = g_scanner_get_next_token (scanner);
1481   if (token != GTK_RC_TOKEN_ENGINE)
1482     return GTK_RC_TOKEN_ENGINE;
1483
1484   token = g_scanner_get_next_token (scanner);
1485   if (token != G_TOKEN_STRING)
1486     return G_TOKEN_STRING;
1487
1488   rc_style->engine = gtk_theme_engine_get (scanner->value.v_string);
1489
1490   token = g_scanner_get_next_token (scanner);
1491   if (token != G_TOKEN_LEFT_CURLY)
1492     return G_TOKEN_LEFT_CURLY;
1493
1494   if (rc_style->engine)
1495     return rc_style->engine->parse_rc_style (scanner, rc_style);
1496   else
1497     {
1498       /* Skip over remainder, looking for nested {}'s */
1499       guint count = 1;
1500       
1501       while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
1502         {
1503           if (token == G_TOKEN_LEFT_CURLY)
1504             count++;
1505           else if (token == G_TOKEN_RIGHT_CURLY)
1506             count--;
1507
1508           if (count == 0)
1509             return G_TOKEN_NONE;
1510         }
1511
1512       return G_TOKEN_RIGHT_CURLY;
1513     }
1514 }
1515
1516 guint
1517 gtk_rc_parse_state (GScanner     *scanner,
1518                     GtkStateType *state)
1519 {
1520   guint old_scope;
1521   guint token;
1522
1523   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1524   g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
1525   
1526   /* we don't know where we got called from, so we reset the scope here.
1527    * if we bail out due to errors, we *don't* reset the scope, so the
1528    * error messaging code can make sense of our tokens.
1529    */
1530   old_scope = g_scanner_set_scope (scanner, 0);
1531   
1532   token = g_scanner_get_next_token (scanner);
1533   if (token != G_TOKEN_LEFT_BRACE)
1534     return G_TOKEN_LEFT_BRACE;
1535   
1536   token = g_scanner_get_next_token (scanner);
1537   switch (token)
1538     {
1539     case GTK_RC_TOKEN_ACTIVE:
1540       *state = GTK_STATE_ACTIVE;
1541       break;
1542     case GTK_RC_TOKEN_INSENSITIVE:
1543       *state = GTK_STATE_INSENSITIVE;
1544       break;
1545     case GTK_RC_TOKEN_NORMAL:
1546       *state = GTK_STATE_NORMAL;
1547       break;
1548     case GTK_RC_TOKEN_PRELIGHT:
1549       *state = GTK_STATE_PRELIGHT;
1550       break;
1551     case GTK_RC_TOKEN_SELECTED:
1552       *state = GTK_STATE_SELECTED;
1553       break;
1554     default:
1555       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
1556     }
1557   
1558   token = g_scanner_get_next_token (scanner);
1559   if (token != G_TOKEN_RIGHT_BRACE)
1560     return G_TOKEN_RIGHT_BRACE;
1561   
1562   g_scanner_set_scope (scanner, old_scope);
1563
1564   return G_TOKEN_NONE;
1565 }
1566
1567 guint
1568 gtk_rc_parse_priority (GScanner            *scanner,
1569                        GtkPathPriorityType *priority)
1570 {
1571   guint old_scope;
1572   guint token;
1573
1574   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1575   g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
1576
1577   /* we don't know where we got called from, so we reset the scope here.
1578    * if we bail out due to errors, we *don't* reset the scope, so the
1579    * error messaging code can make sense of our tokens.
1580    */
1581   old_scope = g_scanner_set_scope (scanner, 0);
1582   
1583   token = g_scanner_get_next_token (scanner);
1584   if (token != ':')
1585     return ':';
1586   
1587   token = g_scanner_get_next_token (scanner);
1588   switch (token)
1589     {
1590     case GTK_RC_TOKEN_LOWEST:
1591       *priority = GTK_PATH_PRIO_LOWEST;
1592       break;
1593     case GTK_RC_TOKEN_GTK:
1594       *priority = GTK_PATH_PRIO_GTK;
1595       break;
1596     case GTK_RC_TOKEN_APPLICATION:
1597       *priority = GTK_PATH_PRIO_APPLICATION;
1598       break;
1599     case GTK_RC_TOKEN_RC:
1600       *priority = GTK_PATH_PRIO_RC;
1601       break;
1602     case GTK_RC_TOKEN_HIGHEST:
1603       *priority = GTK_PATH_PRIO_HIGHEST;
1604       break;
1605     default:
1606       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
1607     }
1608   
1609   g_scanner_set_scope (scanner, old_scope);
1610
1611   return G_TOKEN_NONE;
1612 }
1613
1614 guint
1615 gtk_rc_parse_color (GScanner *scanner,
1616                     GdkColor *color)
1617 {
1618   guint token;
1619
1620   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1621
1622   /* we don't need to set our own scop here, because
1623    * we don't need own symbols
1624    */
1625   
1626   token = g_scanner_get_next_token (scanner);
1627   switch (token)
1628     {
1629       gint token_int;
1630       gint length;
1631       gint temp;
1632       gchar buf[9];
1633       gint i, j;
1634       
1635     case G_TOKEN_LEFT_CURLY:
1636       token = g_scanner_get_next_token (scanner);
1637       if (token == G_TOKEN_INT)
1638         token_int = scanner->value.v_int;
1639       else if (token == G_TOKEN_FLOAT)
1640         token_int = scanner->value.v_float * 65535.0;
1641       else
1642         return G_TOKEN_FLOAT;
1643       color->red = CLAMP (token_int, 0, 65535);
1644       
1645       token = g_scanner_get_next_token (scanner);
1646       if (token != G_TOKEN_COMMA)
1647         return G_TOKEN_COMMA;
1648       
1649       token = g_scanner_get_next_token (scanner);
1650       if (token == G_TOKEN_INT)
1651         token_int = scanner->value.v_int;
1652       else if (token == G_TOKEN_FLOAT)
1653         token_int = scanner->value.v_float * 65535.0;
1654       else
1655         return G_TOKEN_FLOAT;
1656       color->green = CLAMP (token_int, 0, 65535);
1657       
1658       token = g_scanner_get_next_token (scanner);
1659       if (token != G_TOKEN_COMMA)
1660         return G_TOKEN_COMMA;
1661       
1662       token = g_scanner_get_next_token (scanner);
1663       if (token == G_TOKEN_INT)
1664         token_int = scanner->value.v_int;
1665       else if (token == G_TOKEN_FLOAT)
1666         token_int = scanner->value.v_float * 65535.0;
1667       else
1668         return G_TOKEN_FLOAT;
1669       color->blue = CLAMP (token_int, 0, 65535);
1670       
1671       token = g_scanner_get_next_token (scanner);
1672       if (token != G_TOKEN_RIGHT_CURLY)
1673         return G_TOKEN_RIGHT_CURLY;
1674       return G_TOKEN_NONE;
1675       
1676     case G_TOKEN_STRING:
1677       if (scanner->value.v_string[0] != '#')
1678         return G_TOKEN_STRING;
1679       
1680       length = strlen (scanner->value.v_string) - 1;
1681       if (((length % 3) != 0) || (length > 12))
1682         return G_TOKEN_STRING;
1683       length /= 3;
1684       
1685       for (i = 0, j = 1; i < length; i++, j++)
1686         buf[i] = scanner->value.v_string[j];
1687       buf[i] = '\0';
1688       
1689       sscanf (buf, "%x", &temp);
1690       color->red = temp;
1691       
1692       for (i = 0; i < length; i++, j++)
1693         buf[i] = scanner->value.v_string[j];
1694       buf[i] = '\0';
1695       
1696       sscanf (buf, "%x", &temp);
1697       color->green = temp;
1698       
1699       for (i = 0; i < length; i++, j++)
1700         buf[i] = scanner->value.v_string[j];
1701       buf[i] = '\0';
1702       
1703       sscanf (buf, "%x", &temp);
1704       color->blue = temp;
1705       
1706       if (length == 1)
1707         {
1708           color->red *= 4369;
1709           color->green *= 4369;
1710           color->blue *= 4369;
1711         }
1712       else if (length == 2)
1713         {
1714           color->red *= 257;
1715           color->green *= 257;
1716           color->blue *= 257;
1717         }
1718       else if (length == 3)
1719         {
1720           color->red *= 16;
1721           color->green *= 16;
1722           color->blue *= 16;
1723         }
1724       return G_TOKEN_NONE;
1725       
1726     default:
1727       return G_TOKEN_STRING;
1728     }
1729 }
1730
1731 static guint
1732 gtk_rc_parse_pixmap_path (GScanner *scanner)
1733 {
1734   guint token;
1735   
1736   token = g_scanner_get_next_token (scanner);
1737   if (token != GTK_RC_TOKEN_PIXMAP_PATH)
1738     return GTK_RC_TOKEN_PIXMAP_PATH;
1739   
1740   token = g_scanner_get_next_token (scanner);
1741   if (token != G_TOKEN_STRING)
1742     return G_TOKEN_STRING;
1743   
1744   gtk_rc_parse_pixmap_path_string (scanner->value.v_string);
1745   
1746   return G_TOKEN_NONE;
1747 }
1748
1749 static void
1750 gtk_rc_parse_pixmap_path_string (gchar *pix_path)
1751 {
1752   gchar *buf;
1753   gint end_offset;
1754   gint start_offset = 0;
1755   gint path_len;
1756   gint path_num;
1757   
1758   /* free the old one, or just add to the old one ? */
1759   for (path_num=0; pixmap_path[path_num]; path_num++)
1760     {
1761       g_free (pixmap_path[path_num]);
1762       pixmap_path[path_num] = NULL;
1763     }
1764   
1765   path_num = 0;
1766   
1767   path_len = strlen (pix_path);
1768   
1769   buf = g_strdup (pix_path);
1770   
1771   for (end_offset = 0; end_offset <= path_len; end_offset++)
1772     {
1773       if ((buf[end_offset] == ':') ||
1774           (end_offset == path_len))
1775         {
1776           buf[end_offset] = '\0';
1777           pixmap_path[path_num] = g_strdup (buf + start_offset);
1778           path_num++;
1779           pixmap_path[path_num] = NULL;
1780           start_offset = end_offset + 1;
1781         }
1782     }
1783   g_free (buf);
1784   gtk_rc_append_default_pixmap_path();
1785 }
1786
1787 static guint
1788 gtk_rc_parse_module_path (GScanner *scanner)
1789 {
1790   guint token;
1791   
1792   token = g_scanner_get_next_token (scanner);
1793   if (token != GTK_RC_TOKEN_MODULE_PATH)
1794     return GTK_RC_TOKEN_MODULE_PATH;
1795   
1796   token = g_scanner_get_next_token (scanner);
1797   if (token != G_TOKEN_STRING)
1798     return G_TOKEN_STRING;
1799   
1800   gtk_rc_parse_module_path_string (scanner->value.v_string);
1801   
1802   return G_TOKEN_NONE;
1803 }
1804
1805 static void
1806 gtk_rc_parse_module_path_string (gchar *mod_path)
1807 {
1808   gchar *buf;
1809   gint end_offset;
1810   gint start_offset = 0;
1811   gint path_len;
1812   gint path_num;
1813   
1814   /* free the old one, or just add to the old one ? */
1815   for (path_num=0; module_path[path_num]; path_num++)
1816     {
1817       g_free (module_path[path_num]);
1818       module_path[path_num] = NULL;
1819     }
1820   
1821   path_num = 0;
1822   
1823   path_len = strlen (mod_path);
1824   
1825   buf = g_strdup (mod_path);
1826   
1827   for (end_offset = 0; end_offset <= path_len; end_offset++)
1828     {
1829       if ((buf[end_offset] == ':') ||
1830           (end_offset == path_len))
1831         {
1832           buf[end_offset] = '\0';
1833           module_path[path_num] = g_strdup (buf + start_offset);
1834           path_num++;
1835           module_path[path_num] = NULL;
1836           start_offset = end_offset + 1;
1837         }
1838     }
1839   g_free (buf);
1840   gtk_rc_append_default_module_path();
1841 }
1842
1843 static guint
1844 gtk_rc_parse_path_pattern (GScanner   *scanner)
1845 {
1846   guint token;
1847   GtkPathType path_type;
1848   gchar *pattern;
1849   gboolean is_binding;
1850   GtkPathPriorityType priority = GTK_PATH_PRIO_RC;
1851   
1852   token = g_scanner_get_next_token (scanner);
1853   switch (token)
1854     {
1855     case GTK_RC_TOKEN_WIDGET:
1856       path_type = GTK_PATH_WIDGET;
1857       break;
1858     case GTK_RC_TOKEN_WIDGET_CLASS:
1859       path_type = GTK_PATH_WIDGET_CLASS;
1860       break;
1861     case GTK_RC_TOKEN_CLASS:
1862       path_type = GTK_PATH_CLASS;
1863       break;
1864     default:
1865       return GTK_RC_TOKEN_WIDGET_CLASS;
1866     }
1867   
1868   token = g_scanner_get_next_token (scanner);
1869   if (token != G_TOKEN_STRING)
1870     return G_TOKEN_STRING;
1871
1872   pattern = g_strdup (scanner->value.v_string);
1873
1874   token = g_scanner_get_next_token (scanner);
1875   if (token == GTK_RC_TOKEN_STYLE)
1876     is_binding = FALSE;
1877   else if (token == GTK_RC_TOKEN_BINDING)
1878     {
1879       is_binding = TRUE;
1880       if (g_scanner_peek_next_token (scanner) == ':')
1881         {
1882           token = gtk_rc_parse_priority (scanner, &priority);
1883           if (token != G_TOKEN_NONE)
1884             {
1885               g_free (pattern);
1886               return token;
1887             }
1888         }
1889     }
1890   else
1891     {
1892       g_free (pattern);
1893       return GTK_RC_TOKEN_STYLE;
1894     }
1895   
1896   token = g_scanner_get_next_token (scanner);
1897   if (token != G_TOKEN_STRING)
1898     {
1899       g_free (pattern);
1900       return G_TOKEN_STRING;
1901     }
1902
1903   if (is_binding)
1904     {
1905       GtkBindingSet *binding;
1906
1907       binding = gtk_binding_set_find (scanner->value.v_string);
1908       if (!binding)
1909         {
1910           g_free (pattern);
1911           return G_TOKEN_STRING;
1912         }
1913       gtk_binding_set_add_path (binding, path_type, pattern, priority);
1914     }
1915   else
1916     {
1917       GtkRcStyle *rc_style;
1918       GtkRcSet *rc_set;
1919
1920       rc_style = gtk_rc_style_find (scanner->value.v_string);
1921       
1922       if (!rc_style)
1923         {
1924           g_free (pattern);
1925           return G_TOKEN_STRING;
1926         }
1927
1928       rc_set = g_new (GtkRcSet, 1);
1929       gtk_pattern_spec_init (&rc_set->pspec, pattern);
1930       rc_set->rc_style = rc_style;
1931
1932       if (path_type == GTK_PATH_WIDGET)
1933         gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set);
1934       else if (path_type == GTK_PATH_WIDGET_CLASS)
1935         gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set);
1936       else
1937         gtk_rc_sets_class = g_slist_prepend (gtk_rc_sets_class, rc_set);
1938     }
1939
1940   g_free (pattern);
1941   return G_TOKEN_NONE;
1942 }
1943
1944 /*
1945 typedef  GdkPixmap * (*GtkImageLoader) (GdkWindow   *window,
1946                                         GdkColormap *colormap,
1947                                         GdkBitmap  **mask,
1948                                         GdkColor    *transparent_color,
1949                                         const gchar *filename);
1950 */
1951
1952 void
1953 gtk_rc_set_image_loader(GtkImageLoader loader)
1954 {
1955   image_loader = loader;
1956 }
1957
1958 GdkPixmap *
1959 gtk_rc_load_image (GdkColormap *colormap,
1960                    GdkColor    *transparent_color,
1961                    const gchar *filename)
1962 {
1963   if (strcmp (filename, "<parent>") == 0)
1964     return (GdkPixmap*) GDK_PARENT_RELATIVE;
1965   else
1966     {
1967       if(image_loader)
1968         return image_loader(NULL, colormap, NULL,
1969                             transparent_color,
1970                             filename);
1971       else
1972         return gdk_pixmap_colormap_create_from_xpm (NULL, colormap, NULL,
1973                                                     transparent_color,
1974                                                     filename);
1975     }
1976 }