]> Pileus Git - ~andy/gtk/blob - gtk/gtkrc.c
1e4f6195aec8df8c76db6c1fcfc60cb505cd9151
[~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
29
30 enum {
31   TOKEN_INVALID = G_TOKEN_LAST,
32   TOKEN_INCLUDE,
33   TOKEN_ACTIVE,
34   TOKEN_BASE,
35   TOKEN_BG,
36   TOKEN_BG_PIXMAP,
37   TOKEN_FG,
38   TOKEN_FONT,
39   TOKEN_FONTSET,
40   TOKEN_INSENSITIVE,
41   TOKEN_NORMAL,
42   TOKEN_PIXMAP_PATH,
43   TOKEN_PRELIGHT,
44   TOKEN_SELECTED,
45   TOKEN_STYLE,
46   TOKEN_TEXT,
47   TOKEN_WIDGET,
48   TOKEN_WIDGET_CLASS,
49   TOKEN_LAST
50 };
51
52 typedef struct _GtkRcStyle  GtkRcStyle;
53 typedef struct _GtkRcSet    GtkRcSet;
54 typedef struct _GtkRcNode   GtkRcNode;
55 typedef struct _GtkRcFile   GtkRcFile;
56
57 struct _GtkRcNode
58 {
59   GdkColormap *cmap;
60   GtkStyle *style;
61 };
62
63 struct _GtkRcStyle
64 {
65   char *name;
66   char *font_name;
67   char *fontset_name;
68   char *bg_pixmap_name[5];
69   GtkStyle *proto_style;
70   GList *styles;
71 };
72
73 struct _GtkRcSet
74 {
75   GtkPatternSpec pspec;
76   GtkRcStyle    *rc_style;
77 };
78
79 struct _GtkRcFile
80 {
81   time_t mtime;
82   gchar *name;
83   gchar *canonical_name;
84   gboolean reload;
85 };
86
87 static guint       gtk_rc_style_hash               (const char   *name);
88 static gint        gtk_rc_style_compare            (const char   *a,
89                                                     const char   *b);
90 static GtkRcStyle* gtk_rc_style_find               (const char   *name);
91 static GtkRcStyle* gtk_rc_styles_match             (GSList       *sets,
92                                                     guint         path_length,
93                                                     gchar        *path,
94                                                     gchar        *path_reversed);
95 static GtkStyle*   gtk_rc_style_init               (GtkRcStyle   *rc_style,
96                                                     GdkColormap  *cmap);
97 static void        gtk_rc_parse_file               (const gchar  *filename,
98                                                     gboolean      reload);
99
100 static void        gtk_rc_parse_any                (const gchar  *input_name,
101                                                     gint          input_fd,
102                                                     const gchar  *input_string);
103 static guint       gtk_rc_parse_statement          (GScanner     *scanner);
104 static guint       gtk_rc_parse_style              (GScanner     *scanner);
105 static guint       gtk_rc_parse_base               (GScanner     *scanner,
106                                                     GtkStyle     *style);
107 static guint       gtk_rc_parse_bg                 (GScanner     *scanner,
108                                                     GtkStyle     *style);
109 static guint       gtk_rc_parse_fg                 (GScanner     *scanner,
110                                                     GtkStyle     *style);
111 static guint       gtk_rc_parse_text               (GScanner     *scanner,
112                                                     GtkStyle     *style);
113 static guint       gtk_rc_parse_bg_pixmap          (GScanner     *scanner,
114                                                     GtkRcStyle   *rc_style);
115 static guint       gtk_rc_parse_font               (GScanner     *scanner,
116                                                     GtkRcStyle   *rc_style);
117 static guint       gtk_rc_parse_fontset            (GScanner     *scanner,
118                                                     GtkRcStyle   *rc_style);
119 static guint       gtk_rc_parse_state              (GScanner     *scanner,
120                                                     GtkStateType *state);
121 static guint       gtk_rc_parse_color              (GScanner     *scanner,
122                                                     GdkColor     *color);
123 static guint       gtk_rc_parse_pixmap_path        (GScanner     *scanner);
124 static void        gtk_rc_parse_pixmap_path_string (gchar *pix_path);
125 static char*       gtk_rc_find_pixmap_in_path      (GScanner     *scanner,
126                                                     gchar *pixmap_file);
127 static guint       gtk_rc_parse_widget_style       (GScanner     *scanner);
128 static guint       gtk_rc_parse_widget_class_style (GScanner     *scanner);
129 static void        gtk_rc_clear_hash_node          (gpointer   key, 
130                                                     gpointer   data, 
131                                                     gpointer   user_data);
132 static void        gtk_rc_clear_styles             (void);
133
134
135
136 static  GScannerConfig  gtk_rc_scanner_config =
137 {
138   (
139    " \t\n"
140    )                    /* cset_skip_characters */,
141   (
142    G_CSET_a_2_z
143    "_"
144    G_CSET_A_2_Z
145    )                    /* cset_identifier_first */,
146   (
147    G_CSET_a_2_z
148    "_0123456789"
149    G_CSET_A_2_Z
150    G_CSET_LATINS
151    G_CSET_LATINC
152    )                    /* cset_identifier_nth */,
153   ( "#\n" )             /* cpair_comment_single */,
154   
155   TRUE                  /* case_sensitive */,
156   
157   TRUE                  /* skip_comment_multi */,
158   TRUE                  /* skip_comment_single */,
159   TRUE                  /* scan_comment_multi */,
160   TRUE                  /* scan_identifier */,
161   FALSE                 /* scan_identifier_1char */,
162   FALSE                 /* scan_identifier_NULL */,
163   TRUE                  /* scan_symbols */,
164   TRUE                  /* scan_binary */,
165   TRUE                  /* scan_octal */,
166   TRUE                  /* scan_float */,
167   TRUE                  /* scan_hex */,
168   TRUE                  /* scan_hex_dollar */,
169   TRUE                  /* scan_string_sq */,
170   TRUE                  /* scan_string_dq */,
171   TRUE                  /* numbers_2_int */,
172   FALSE                 /* int_2_float */,
173   TRUE                  /* identifier_2_string */,
174   TRUE                  /* char_2_token */,
175   TRUE                  /* symbol_2_token */,
176 };
177
178 static struct
179 {
180   gchar *name;
181   guint token;
182 } symbols[] = {
183   { "include", TOKEN_INCLUDE },
184   { "ACTIVE", TOKEN_ACTIVE },
185   { "base", TOKEN_BASE },
186   { "bg", TOKEN_BG },
187   { "bg_pixmap", TOKEN_BG_PIXMAP },
188   { "fg", TOKEN_FG },
189   { "font", TOKEN_FONT },
190   { "fontset", TOKEN_FONTSET },
191   { "INSENSITIVE", TOKEN_INSENSITIVE },
192   { "NORMAL", TOKEN_NORMAL },
193   { "pixmap_path", TOKEN_PIXMAP_PATH },
194   { "PRELIGHT", TOKEN_PRELIGHT },
195   { "SELECTED", TOKEN_SELECTED },
196   { "style", TOKEN_STYLE },
197   { "text", TOKEN_TEXT },
198   { "widget", TOKEN_WIDGET },
199   { "widget_class", TOKEN_WIDGET_CLASS },
200 };
201 static guint nsymbols = sizeof (symbols) / sizeof (symbols[0]);
202
203 static GHashTable *rc_style_ht = NULL;
204 static GSList *gtk_rc_sets_widget = NULL;
205 static GSList *gtk_rc_sets_widget_class = NULL;
206
207 #define GTK_RC_MAX_PIXMAP_PATHS 128
208 static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
209
210 /* The files we have parsed, to reread later if necessary */
211 GSList *rc_files = NULL;
212
213 static GtkImageLoader image_loader = NULL;
214
215 void
216 gtk_rc_init (void)
217 {
218   rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
219                                   (GCompareFunc) gtk_rc_style_compare);
220 }
221
222 void
223 gtk_rc_parse_string (const gchar *rc_string)
224 {
225   g_return_if_fail (rc_string != NULL);
226
227   gtk_rc_parse_any ("-", -1, rc_string);
228 }
229
230 static void
231 gtk_rc_parse_file (const gchar *filename, gboolean reload)
232 {
233   GtkRcFile *rc_file = NULL;
234   struct stat statbuf;
235   GSList *tmp_list;
236
237   g_return_if_fail (filename != NULL);
238
239   tmp_list = rc_files;
240   while (tmp_list)
241     {
242       rc_file = tmp_list->data;
243       if (!strcmp (rc_file->name, filename))
244         break;
245       
246       tmp_list = tmp_list->next;
247     }
248
249   if (!tmp_list)
250     {
251       rc_file = g_new (GtkRcFile, 1);
252       rc_file->name = g_strdup (filename);
253       rc_file->canonical_name = NULL;
254       rc_file->mtime = 0;
255       rc_file->reload = reload;
256
257       rc_files = g_slist_append (rc_files, rc_file);
258     }
259
260   if (!rc_file->canonical_name)
261     {
262       /* Get the absolute pathname */
263
264       if (rc_file->name[0] == '/')
265         rc_file->canonical_name = rc_file->name;
266       else
267         {
268           GString *str;
269           gchar buffer[MAXPATHLEN];
270           
271 #if defined(sun) && !defined(__SVR4)
272           if(!getwd(buffer))
273 #else
274           if(!getcwd(buffer, MAXPATHLEN))
275 #endif    
276               return;
277
278           str = g_string_new (buffer);
279           g_string_append_c (str, '/');
280           g_string_append (str, rc_file->name);
281           
282           rc_file->canonical_name = str->str;
283           g_string_free (str, FALSE);
284         }
285     }
286
287   if (!lstat (rc_file->canonical_name, &statbuf))
288     {
289       gint fd;
290
291       rc_file->mtime = statbuf.st_mtime;
292
293       fd = open (rc_file->canonical_name, O_RDONLY);
294       if (fd < 0)
295         return;
296
297       gtk_rc_parse_any (filename, fd, NULL);
298
299       close (fd);
300     }
301 }
302
303 void
304 gtk_rc_parse (const gchar *filename)
305 {
306   g_return_if_fail (filename != NULL);
307
308   gtk_rc_parse_file (filename, TRUE);
309 }
310
311 static void
312 gtk_rc_clear_hash_node (gpointer key, 
313                         gpointer data, 
314                         gpointer user_data)
315 {
316   int i;
317   GtkRcStyle *rc_style = data;
318   GList *tmp_list;
319
320   g_free (rc_style->name);
321   g_free (rc_style->font_name);
322   g_free (rc_style->fontset_name);
323
324   for (i=0 ; i<5 ; i++)
325     g_free (rc_style->bg_pixmap_name[i]);
326
327   gtk_style_unref (rc_style->proto_style);
328
329   tmp_list = rc_style->styles;
330   while (tmp_list)
331     {
332       GtkRcNode *node = tmp_list->data;
333
334       gdk_colormap_unref (node->cmap);
335       gtk_style_unref (node->style);
336
337       g_free (node);
338       tmp_list = tmp_list->next;
339     }
340
341   g_free (rc_style);
342 }
343
344 static void
345 gtk_rc_clear_styles (void)
346 {
347   GSList *tmp_list;
348
349   /* Clear out all old rc_styles */
350
351   g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
352   g_hash_table_destroy (rc_style_ht);
353   rc_style_ht = NULL;
354
355   tmp_list = gtk_rc_sets_widget;
356   while (tmp_list)
357     {
358       GtkRcSet *rc_set;
359
360       rc_set = tmp_list->data;
361       gtk_pattern_spec_free_segs (&rc_set->pspec);
362       g_free (rc_set);
363       
364       tmp_list = tmp_list->next;
365     }
366   g_slist_free (gtk_rc_sets_widget);
367   gtk_rc_sets_widget = NULL;
368
369   tmp_list = gtk_rc_sets_widget_class;
370   while (tmp_list)
371     {
372       GtkRcSet *rc_set;
373
374       rc_set = tmp_list->data;
375       gtk_pattern_spec_free_segs (&rc_set->pspec);
376       g_free (rc_set);
377       
378       tmp_list = tmp_list->next;
379     }
380   g_slist_free (gtk_rc_sets_widget_class);
381   gtk_rc_sets_widget_class = NULL;
382
383   gtk_rc_init ();
384 }
385
386 gboolean
387 gtk_rc_reparse_all (void)
388 {
389   GSList *tmp_list;
390   gboolean mtime_modified = FALSE;
391   GtkRcFile *rc_file;
392
393   struct stat statbuf;
394
395   /* Check through and see if any of the RC's have had their
396    * mtime modified. If so, reparse everything.
397    */
398   tmp_list = rc_files;
399   while (tmp_list)
400     {
401       rc_file = tmp_list->data;
402       
403       if (!lstat (rc_file->name, &statbuf) && 
404           (statbuf.st_mtime > rc_file->mtime))
405         {
406           mtime_modified = TRUE;
407           break;
408         }
409       
410       tmp_list = tmp_list->next;
411     }
412
413   if (mtime_modified)
414     {
415       gtk_rc_clear_styles();
416
417       tmp_list = rc_files;
418       while (tmp_list)
419         {
420           rc_file = tmp_list->data;
421           if (rc_file->reload)
422             gtk_rc_parse_file (rc_file->name, FALSE);
423           
424           tmp_list = tmp_list->next;
425         }
426     }
427
428   return mtime_modified;
429 }
430
431 GtkStyle*
432 gtk_rc_get_style (GtkWidget *widget)
433 {
434   GtkRcStyle *rc_style;
435   
436   if (gtk_rc_sets_widget)
437     {
438       gchar *path, *path_reversed;
439       guint path_length;
440
441       gtk_widget_path (widget, &path_length, &path, &path_reversed);
442       rc_style = gtk_rc_styles_match (gtk_rc_sets_widget, path_length, path, path_reversed);
443       g_free (path);
444       g_free (path_reversed);
445       
446       if (rc_style)
447         return gtk_rc_style_init (rc_style, gtk_widget_get_colormap (widget));
448     }
449   
450   if (gtk_rc_sets_widget_class)
451     {
452       gchar *path, *path_reversed;
453       guint path_length;
454
455       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
456       rc_style = gtk_rc_styles_match (gtk_rc_sets_widget_class, path_length, path, path_reversed);
457       g_free (path);
458       g_free (path_reversed);
459       
460       if (rc_style)
461         return gtk_rc_style_init (rc_style, gtk_widget_get_colormap (widget));
462     }
463   
464   return NULL;
465 }
466
467 void
468 gtk_rc_add_widget_name_style (GtkStyle   *style,
469                               const char *pattern)
470 {
471   GtkRcStyle *rc_style;
472   GtkRcSet *rc_set;
473   int i;
474   
475   gtk_style_ref (style);
476   
477   rc_style = g_new (GtkRcStyle, 1);
478   rc_style->name = NULL;
479   rc_style->font_name = NULL;
480   rc_style->fontset_name = NULL;
481   
482   for (i = 0; i < 5; i++)
483     rc_style->bg_pixmap_name[i] = NULL;
484   
485   rc_style->styles = g_list_append (NULL, style);
486
487   rc_set = g_new (GtkRcSet, 1);
488   gtk_pattern_spec_init (&rc_set->pspec, pattern);
489   rc_set->rc_style = rc_style;
490   
491   gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set);
492 }
493
494 void
495 gtk_rc_add_widget_class_style (GtkStyle *style,
496                                const char     *pattern)
497 {
498   GtkRcStyle *rc_style;
499   GtkRcSet *rc_set;
500   int i;
501   
502   gtk_style_ref (style);
503   
504   rc_style = g_new (GtkRcStyle, 1);
505   rc_style->name = NULL;
506   rc_style->font_name = NULL;
507   rc_style->fontset_name = NULL;
508   
509   for (i = 0; i < 5; i++)
510     rc_style->bg_pixmap_name[i] = NULL;
511   
512   rc_style->styles = g_list_append (NULL, style);
513   
514   rc_set = g_new (GtkRcSet, 1);
515   gtk_pattern_spec_init (&rc_set->pspec, pattern);
516   rc_set->rc_style = rc_style;
517   
518   gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set);
519 }
520
521 static void
522 gtk_rc_parse_any (const gchar  *input_name,
523                   gint          input_fd,
524                   const gchar  *input_string)
525 {
526   GScanner *scanner;
527   guint    i;
528   gboolean done;
529   
530   scanner = g_scanner_new (&gtk_rc_scanner_config);
531   
532   if (input_fd >= 0)
533     {
534       g_assert (input_string == NULL);
535       
536       g_scanner_input_file (scanner, input_fd);
537     }
538   else
539     {
540       g_assert (input_string != NULL);
541       
542       g_scanner_input_text (scanner, input_string, strlen (input_string));
543     }
544   scanner->input_name = input_name;
545   
546   g_scanner_freeze_symbol_table (scanner);
547   for (i = 0; i < nsymbols; i++)
548     g_scanner_add_symbol (scanner, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
549   g_scanner_thaw_symbol_table (scanner);
550   
551   done = FALSE;
552   while (!done)
553     {
554       if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
555         done = TRUE;
556       else
557         {
558           guint expected_token;
559           
560           expected_token = gtk_rc_parse_statement (scanner);
561
562           if (expected_token != G_TOKEN_NONE)
563             {
564               gchar *symbol_name;
565               gchar *msg;
566               
567               msg = NULL;
568               if (expected_token > TOKEN_INVALID &&
569                   expected_token < TOKEN_LAST)
570                 {
571                   for (i = 0; i < nsymbols; i++)
572                     if (symbols[i].token == expected_token)
573                       msg = symbols[i].name;
574                   if (msg)
575                     msg = g_strconcat ("e.g. `", msg, "'", NULL);
576                 }
577               if (scanner->token > TOKEN_INVALID &&
578                   scanner->token < TOKEN_LAST)
579                 {
580                   symbol_name = "???";
581                   for (i = 0; i < nsymbols; i++)
582                     if (symbols[i].token == scanner->token)
583                       symbol_name = symbols[i].name;
584                 }
585               else
586                 symbol_name = NULL;
587               g_scanner_unexp_token (scanner,
588                                      expected_token,
589                                      NULL,
590                                      "keyword",
591                                      symbol_name,
592                                      msg,
593                                      TRUE);
594               g_free (msg);
595               done = TRUE;
596             }
597         }
598     }
599   
600   g_scanner_destroy (scanner);
601 }
602
603 static guint
604 gtk_rc_style_hash (const char *name)
605 {
606   guint result;
607   
608   result = 0;
609   while (*name)
610     result += (result << 3) + *name++;
611   
612   return result;
613 }
614
615 static gint
616 gtk_rc_style_compare (const char *a,
617                       const char *b)
618 {
619   return (strcmp (a, b) == 0);
620 }
621
622 static GtkRcStyle*
623 gtk_rc_style_find (const char *name)
624 {
625   GtkRcStyle *rc_style;
626   
627   rc_style = g_hash_table_lookup (rc_style_ht, (gpointer) name);
628   
629   return rc_style;
630 }
631
632 static GtkRcStyle*
633 gtk_rc_styles_match (GSList       *sets,
634                      guint         path_length,
635                      gchar        *path,
636                      gchar        *path_reversed)
637 {
638   GtkRcSet *rc_set;
639
640   while (sets)
641     {
642       rc_set = sets->data;
643       sets = sets->next;
644
645       if (gtk_pattern_match (&rc_set->pspec, path_length, path, path_reversed))
646         return rc_set->rc_style;
647     }
648   
649   return NULL;
650 }
651
652 static GtkStyle *
653 gtk_rc_style_init (GtkRcStyle *rc_style, GdkColormap *cmap)
654 {
655   GdkFont *old_font;
656   gboolean match_cmap = FALSE;
657   gint i;
658
659   GList *tmp_list;
660   GtkStyle *style = NULL;
661   GtkRcNode *node;
662
663   tmp_list = rc_style->styles;
664
665   for (i=0; i<5; i++)
666     if (rc_style->bg_pixmap_name[i])
667       match_cmap = TRUE;
668       
669   while (tmp_list)
670     {
671       node = (GtkRcNode *)tmp_list->data;
672
673       if (!match_cmap || (node->cmap == cmap))
674         {
675           style = node->style;
676           break;
677         }
678
679       tmp_list = tmp_list->next;
680     }
681   
682   if (!style)
683     {
684       node = g_new (GtkRcNode, 1);
685       style = gtk_style_copy (rc_style->proto_style);
686
687      /* FIXME, this leaks colormaps, but if we don't do this, then we'll
688        * be screwed, because we identify colormaps by address equality
689        */
690       gdk_colormap_ref (cmap);
691  
692       node->style = style;
693       node->cmap = cmap;
694       
695       if (rc_style->fontset_name)
696         {
697           old_font = style->font;
698           style->font = gdk_fontset_load (rc_style->fontset_name);
699           if (style->font)
700             gdk_font_unref (old_font);
701           else
702             style->font = old_font;
703         }
704       else if (rc_style->font_name)
705         {
706           old_font = style->font;
707           style->font = gdk_font_load (rc_style->font_name);
708           if (style->font)
709             gdk_font_unref (old_font);
710           else
711             style->font = old_font;
712         }
713       
714       for (i = 0; i < 5; i++)
715         if (rc_style->bg_pixmap_name[i])
716           {
717             if (strcmp (rc_style->bg_pixmap_name[i], "<parent>") == 0)
718               style->bg_pixmap[i] = (GdkPixmap*) GDK_PARENT_RELATIVE;
719             else
720               {
721                 if(image_loader)
722                   style->bg_pixmap[i] = image_loader(NULL, cmap, NULL,
723                                                      &style->bg[i],
724                                                      rc_style->bg_pixmap_name[i]);
725                 else
726                   style->bg_pixmap[i] = 
727                     gdk_pixmap_colormap_create_from_xpm (NULL, cmap,
728                                                          NULL,
729                                                          &style->bg[i],
730                                                          rc_style->bg_pixmap_name[i]);
731               }
732           }
733
734       rc_style->styles = g_list_append (rc_style->styles, node);
735     }
736
737   return style;
738 }
739
740 static guint
741 gtk_rc_parse_statement (GScanner *scanner)
742 {
743   guint token;
744   
745   token = g_scanner_peek_next_token (scanner);
746
747   switch (token)
748     {
749     case TOKEN_INCLUDE:
750       token = g_scanner_get_next_token (scanner);
751       if (token != TOKEN_INCLUDE)
752         return TOKEN_INCLUDE;
753
754       token = g_scanner_get_next_token (scanner);
755       if (token != G_TOKEN_STRING)
756         return G_TOKEN_STRING;
757
758       gtk_rc_parse_file (scanner->value.v_string, FALSE);
759       return G_TOKEN_NONE;
760
761     case TOKEN_STYLE:
762       return gtk_rc_parse_style (scanner);
763
764     case TOKEN_PIXMAP_PATH:
765       return gtk_rc_parse_pixmap_path (scanner);
766
767     case TOKEN_WIDGET:
768       return gtk_rc_parse_widget_style (scanner);
769
770     case TOKEN_WIDGET_CLASS:
771       return gtk_rc_parse_widget_class_style (scanner);
772
773     default:
774       g_scanner_get_next_token (scanner);
775       return /* G_TOKEN_SYMBOL */ TOKEN_STYLE;
776     }
777 }
778
779 static guint
780 gtk_rc_parse_style (GScanner *scanner)
781 {
782   GtkRcStyle *rc_style;
783   GtkRcStyle *parent_style;
784   guint token;
785   gint insert;
786   gint i;
787   
788   token = g_scanner_get_next_token (scanner);
789   if (token != TOKEN_STYLE)
790     return TOKEN_STYLE;
791   
792   token = g_scanner_get_next_token (scanner);
793   if (token != G_TOKEN_STRING)
794     return G_TOKEN_STRING;
795   
796   insert = FALSE;
797   rc_style = g_hash_table_lookup (rc_style_ht, scanner->value.v_string);
798   
799   if (!rc_style)
800     {
801       insert = TRUE;
802       rc_style = g_new (GtkRcStyle, 1);
803       rc_style->name = g_strdup (scanner->value.v_string);
804       rc_style->font_name = NULL;
805       rc_style->fontset_name = NULL;
806       
807       for (i = 0; i < 5; i++)
808         rc_style->bg_pixmap_name[i] = NULL;
809
810       rc_style->proto_style = gtk_style_new();
811       rc_style->styles = NULL;
812     }
813   
814   token = g_scanner_peek_next_token (scanner);
815   if (token == G_TOKEN_EQUAL_SIGN)
816     {
817       token = g_scanner_get_next_token (scanner);
818       
819       token = g_scanner_get_next_token (scanner);
820       if (token != G_TOKEN_STRING)
821         {
822           if (insert)
823             {
824               gtk_style_unref (rc_style->proto_style);
825               g_free (rc_style);
826             }
827           return G_TOKEN_STRING;
828         }
829       
830       parent_style = g_hash_table_lookup (rc_style_ht, scanner->value.v_string);
831       if (parent_style)
832         {
833           for (i = 0; i < 5; i++)
834             {
835               rc_style->proto_style->fg[i] = parent_style->proto_style->fg[i];
836               rc_style->proto_style->bg[i] = parent_style->proto_style->bg[i];
837               rc_style->proto_style->light[i] = parent_style->proto_style->light[i];
838               rc_style->proto_style->dark[i] = parent_style->proto_style->dark[i];
839               rc_style->proto_style->mid[i] = parent_style->proto_style->mid[i];
840               rc_style->proto_style->text[i] = parent_style->proto_style->text[i];
841               rc_style->proto_style->base[i] = parent_style->proto_style->base[i];
842             }
843           
844           rc_style->proto_style->black = parent_style->proto_style->black;
845           rc_style->proto_style->white = parent_style->proto_style->white;
846           
847           if (rc_style->fontset_name)
848             {
849               g_free (rc_style->fontset_name);
850               rc_style->fontset_name = g_strdup (parent_style->fontset_name);
851             }
852           else if (rc_style->font_name)
853             {
854               g_free (rc_style->font_name);
855               rc_style->font_name = g_strdup (parent_style->font_name);
856             }
857           
858           for (i = 0; i < 5; i++)
859             {
860               if (rc_style->bg_pixmap_name[i])
861                 g_free (rc_style->bg_pixmap_name[i]);
862               rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
863             }
864         }
865     }
866   
867   token = g_scanner_get_next_token (scanner);
868   if (token != G_TOKEN_LEFT_CURLY)
869     {
870       if (insert)
871         {
872           gtk_style_unref (rc_style->proto_style);
873           g_free (rc_style);
874         }
875       return G_TOKEN_LEFT_CURLY;
876     }
877   
878   token = g_scanner_peek_next_token (scanner);
879   while (token != G_TOKEN_RIGHT_CURLY)
880     {
881       switch (token)
882         {
883         case TOKEN_BASE:
884           token = gtk_rc_parse_base (scanner, rc_style->proto_style);
885           break;
886         case TOKEN_BG:
887           token = gtk_rc_parse_bg (scanner, rc_style->proto_style);
888           break;
889         case TOKEN_FG:
890           token = gtk_rc_parse_fg (scanner, rc_style->proto_style);
891           break;
892         case TOKEN_TEXT:
893           token = gtk_rc_parse_text (scanner, rc_style->proto_style);
894           break;
895         case TOKEN_BG_PIXMAP:
896           token = gtk_rc_parse_bg_pixmap (scanner, rc_style);
897           break;
898         case TOKEN_FONT:
899           token = gtk_rc_parse_font (scanner, rc_style);
900           break;
901         case TOKEN_FONTSET:
902           token = gtk_rc_parse_fontset (scanner, rc_style);
903           break;
904         default:
905           g_scanner_get_next_token (scanner);
906           token = G_TOKEN_RIGHT_CURLY;
907           break;
908         }
909
910       if (token != G_TOKEN_NONE)
911         {
912           if (insert)
913             {
914               if (rc_style->fontset_name)
915                 g_free (rc_style->fontset_name);
916               if (rc_style->font_name)
917                 g_free (rc_style->font_name);
918               for (i = 0; i < 5; i++)
919                 if (rc_style->bg_pixmap_name[i])
920                   g_free (rc_style->bg_pixmap_name[i]);
921               gtk_style_unref (rc_style->proto_style);
922               g_free (rc_style);
923             }
924           return token;
925         }
926       token = g_scanner_peek_next_token (scanner);
927     }
928   
929   token = g_scanner_get_next_token (scanner);
930   if (token != G_TOKEN_RIGHT_CURLY)
931     {
932       if (insert)
933         {
934           if (rc_style->fontset_name)
935             g_free (rc_style->fontset_name);
936           if (rc_style->font_name)
937             g_free (rc_style->font_name);
938           
939           for (i = 0; i < 5; i++)
940             if (rc_style->bg_pixmap_name[i])
941               g_free (rc_style->bg_pixmap_name[i]);
942           
943           gtk_style_unref (rc_style->proto_style);
944           g_free (rc_style);
945         }
946       return G_TOKEN_RIGHT_CURLY;
947     }
948   
949   if (insert)
950     g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
951   
952   return G_TOKEN_NONE;
953 }
954
955 static guint
956 gtk_rc_parse_base (GScanner *scanner,
957                    GtkStyle *style)
958 {
959   GtkStateType state;
960   guint token;
961   
962   token = g_scanner_get_next_token (scanner);
963   if (token != TOKEN_BASE)
964     return TOKEN_BASE;
965   
966   token = gtk_rc_parse_state (scanner, &state);
967   if (token != G_TOKEN_NONE)
968     return token;
969   
970   token = g_scanner_get_next_token (scanner);
971   if (token != G_TOKEN_EQUAL_SIGN)
972     return G_TOKEN_EQUAL_SIGN;
973   
974   return gtk_rc_parse_color (scanner, &style->base[state]);
975 }
976
977 static guint
978 gtk_rc_parse_bg (GScanner *scanner,
979                  GtkStyle *style)
980 {
981   GtkStateType state;
982   guint token;
983   
984   token = g_scanner_get_next_token (scanner);
985   if (token != TOKEN_BG)
986     return TOKEN_BG;
987   
988   token = gtk_rc_parse_state (scanner, &state);
989   if (token != G_TOKEN_NONE)
990     return token;
991   
992   token = g_scanner_get_next_token (scanner);
993   if (token != G_TOKEN_EQUAL_SIGN)
994     return G_TOKEN_EQUAL_SIGN;
995   
996   return gtk_rc_parse_color (scanner, &style->bg[state]);
997 }
998
999 static guint
1000 gtk_rc_parse_fg (GScanner *scanner,
1001                  GtkStyle *style)
1002 {
1003   GtkStateType state;
1004   guint token;
1005   
1006   token = g_scanner_get_next_token (scanner);
1007   if (token != TOKEN_FG)
1008     return TOKEN_FG;
1009   
1010   token = gtk_rc_parse_state (scanner, &state);
1011   if (token != G_TOKEN_NONE)
1012     return token;
1013   
1014   token = g_scanner_get_next_token (scanner);
1015   if (token != G_TOKEN_EQUAL_SIGN)
1016     return G_TOKEN_EQUAL_SIGN;
1017   
1018   return gtk_rc_parse_color (scanner, &style->fg[state]);
1019 }
1020
1021 static guint
1022 gtk_rc_parse_text (GScanner *scanner,
1023                    GtkStyle *style)
1024 {
1025   GtkStateType state;
1026   guint token;
1027   
1028   token = g_scanner_get_next_token (scanner);
1029   if (token != TOKEN_TEXT)
1030     return TOKEN_TEXT;
1031   
1032   token = gtk_rc_parse_state (scanner, &state);
1033   if (token != G_TOKEN_NONE)
1034     return token;
1035   
1036   token = g_scanner_get_next_token (scanner);
1037   if (token != G_TOKEN_EQUAL_SIGN)
1038     return G_TOKEN_EQUAL_SIGN;
1039   
1040   return gtk_rc_parse_color (scanner, &style->text[state]);
1041 }
1042
1043 static guint
1044 gtk_rc_parse_bg_pixmap (GScanner   *scanner,
1045                         GtkRcStyle *rc_style)
1046 {
1047   GtkStateType state;
1048   guint token;
1049   gchar *pixmap_file;
1050   
1051   token = g_scanner_get_next_token (scanner);
1052   if (token != TOKEN_BG_PIXMAP)
1053     return TOKEN_BG_PIXMAP;
1054   
1055   token = gtk_rc_parse_state (scanner, &state);
1056   if (token != G_TOKEN_NONE)
1057     return token;
1058   
1059   token = g_scanner_get_next_token (scanner);
1060   if (token != G_TOKEN_EQUAL_SIGN)
1061     return G_TOKEN_EQUAL_SIGN;
1062   
1063   token = g_scanner_get_next_token (scanner);
1064   if (token != G_TOKEN_STRING)
1065     return G_TOKEN_STRING;
1066   
1067   if (strcmp (scanner->value.v_string, "<parent>"))
1068     pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
1069   else
1070     pixmap_file = g_strdup (scanner->value.v_string);
1071   
1072   if (pixmap_file)
1073     {
1074       if (rc_style->bg_pixmap_name[state])
1075         g_free (rc_style->bg_pixmap_name[state]);
1076       rc_style->bg_pixmap_name[state] = pixmap_file;
1077     }
1078   
1079   return G_TOKEN_NONE;
1080 }
1081
1082 static gchar*
1083 gtk_rc_find_pixmap_in_path (GScanner *scanner,
1084                             gchar    *pixmap_file)
1085 {
1086   gint i;
1087   gint fd;
1088   gchar *buf;
1089   
1090   for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
1091     {
1092       buf = g_malloc (strlen (pixmap_path[i]) + strlen (pixmap_file) + 2);
1093       sprintf (buf, "%s%c%s", pixmap_path[i], '/', pixmap_file);
1094       
1095       fd = open (buf, O_RDONLY);
1096       if (fd >= 0)
1097         {
1098           close (fd);
1099           return buf;
1100         }
1101       
1102       g_free (buf);
1103     }
1104   
1105   g_warning ("Unable to locate image file in pixmap_path: \"%s\" line %d",
1106              pixmap_file, scanner->line);
1107   
1108   return NULL;
1109 }
1110
1111 static guint
1112 gtk_rc_parse_font (GScanner   *scanner,
1113                    GtkRcStyle *rc_style)
1114 {
1115   guint token;
1116   
1117   token = g_scanner_get_next_token (scanner);
1118   if (token != TOKEN_FONT)
1119     return TOKEN_FONT;
1120   
1121   token = g_scanner_get_next_token (scanner);
1122   if (token != G_TOKEN_EQUAL_SIGN)
1123     return G_TOKEN_EQUAL_SIGN;
1124   
1125   token = g_scanner_get_next_token (scanner);
1126   if (token != G_TOKEN_STRING)
1127     return G_TOKEN_STRING;
1128   
1129   if (rc_style->font_name)
1130     g_free (rc_style->font_name);
1131   rc_style->font_name = g_strdup (scanner->value.v_string);
1132   
1133   return G_TOKEN_NONE;
1134 }
1135
1136 static guint
1137 gtk_rc_parse_fontset (GScanner   *scanner,
1138                       GtkRcStyle *rc_style)
1139 {
1140   guint token;
1141   
1142   token = g_scanner_get_next_token (scanner);
1143   if (token != TOKEN_FONTSET)
1144     return TOKEN_FONTSET;
1145   
1146   token = g_scanner_get_next_token (scanner);
1147   if (token != G_TOKEN_EQUAL_SIGN)
1148     return G_TOKEN_EQUAL_SIGN;
1149   
1150   token = g_scanner_get_next_token (scanner);
1151   if (token != G_TOKEN_STRING)
1152     return G_TOKEN_STRING;
1153   
1154   if (rc_style->fontset_name)
1155     g_free (rc_style->fontset_name);
1156   rc_style->fontset_name = g_strdup (scanner->value.v_string);
1157   
1158   return G_TOKEN_NONE;
1159 }
1160
1161 static guint
1162 gtk_rc_parse_state (GScanner     *scanner,
1163                     GtkStateType *state)
1164 {
1165   guint token;
1166   
1167   token = g_scanner_get_next_token (scanner);
1168   if (token != G_TOKEN_LEFT_BRACE)
1169     return G_TOKEN_LEFT_BRACE;
1170   
1171   token = g_scanner_get_next_token (scanner);
1172   switch (token)
1173     {
1174     case TOKEN_ACTIVE:
1175       *state = GTK_STATE_ACTIVE;
1176       break;
1177     case TOKEN_INSENSITIVE:
1178       *state = GTK_STATE_INSENSITIVE;
1179       break;
1180     case TOKEN_NORMAL:
1181       *state = GTK_STATE_NORMAL;
1182       break;
1183     case TOKEN_PRELIGHT:
1184       *state = GTK_STATE_PRELIGHT;
1185       break;
1186     case TOKEN_SELECTED:
1187       *state = GTK_STATE_SELECTED;
1188       break;
1189     default:
1190       return /* G_TOKEN_SYMBOL */ TOKEN_NORMAL;
1191     }
1192   
1193   token = g_scanner_get_next_token (scanner);
1194   if (token != G_TOKEN_RIGHT_BRACE)
1195     return G_TOKEN_RIGHT_BRACE;
1196   
1197   return G_TOKEN_NONE;
1198 }
1199
1200 static guint
1201 gtk_rc_parse_color (GScanner *scanner,
1202                     GdkColor *color)
1203 {
1204   guint token;
1205   
1206   token = g_scanner_get_next_token (scanner);
1207   switch (token)
1208     {
1209       gint token_int;
1210       gint length;
1211       gint temp;
1212       gchar buf[9];
1213       gint i, j;
1214       
1215     case G_TOKEN_LEFT_CURLY:
1216       token = g_scanner_get_next_token (scanner);
1217       if (token == G_TOKEN_INT)
1218         token_int = scanner->value.v_int;
1219       else if (token == G_TOKEN_FLOAT)
1220         token_int = scanner->value.v_float * 65535.0;
1221       else
1222         return G_TOKEN_FLOAT;
1223       color->red = CLAMP (token_int, 0, 65535);
1224       
1225       token = g_scanner_get_next_token (scanner);
1226       if (token != G_TOKEN_COMMA)
1227         return G_TOKEN_COMMA;
1228       
1229       token = g_scanner_get_next_token (scanner);
1230       if (token == G_TOKEN_INT)
1231         token_int = scanner->value.v_int;
1232       else if (token == G_TOKEN_FLOAT)
1233         token_int = scanner->value.v_float * 65535.0;
1234       else
1235         return G_TOKEN_FLOAT;
1236       color->green = CLAMP (token_int, 0, 65535);
1237       
1238       token = g_scanner_get_next_token (scanner);
1239       if (token != G_TOKEN_COMMA)
1240         return G_TOKEN_COMMA;
1241       
1242       token = g_scanner_get_next_token (scanner);
1243       if (token == G_TOKEN_INT)
1244         token_int = scanner->value.v_int;
1245       else if (token == G_TOKEN_FLOAT)
1246         token_int = scanner->value.v_float * 65535.0;
1247       else
1248         return G_TOKEN_FLOAT;
1249       color->blue = CLAMP (token_int, 0, 65535);
1250       
1251       token = g_scanner_get_next_token (scanner);
1252       if (token != G_TOKEN_RIGHT_CURLY)
1253         return G_TOKEN_RIGHT_CURLY;
1254       return G_TOKEN_NONE;
1255       
1256     case G_TOKEN_STRING:
1257       if (scanner->value.v_string[0] != '#')
1258         return G_TOKEN_STRING;
1259       
1260       length = strlen (scanner->value.v_string) - 1;
1261       if (((length % 3) != 0) || (length > 12))
1262         return G_TOKEN_STRING;
1263       length /= 3;
1264       
1265       for (i = 0, j = 1; i < length; i++, j++)
1266         buf[i] = scanner->value.v_string[j];
1267       buf[i] = '\0';
1268       
1269       sscanf (buf, "%x", &temp);
1270       color->red = temp;
1271       
1272       for (i = 0; i < length; i++, j++)
1273         buf[i] = scanner->value.v_string[j];
1274       buf[i] = '\0';
1275       
1276       sscanf (buf, "%x", &temp);
1277       color->green = temp;
1278       
1279       for (i = 0; i < length; i++, j++)
1280         buf[i] = scanner->value.v_string[j];
1281       buf[i] = '\0';
1282       
1283       sscanf (buf, "%x", &temp);
1284       color->blue = temp;
1285       
1286       if (length == 1)
1287         {
1288           color->red *= 4369;
1289           color->green *= 4369;
1290           color->blue *= 4369;
1291         }
1292       else if (length == 2)
1293         {
1294           color->red *= 257;
1295           color->green *= 257;
1296           color->blue *= 257;
1297         }
1298       else if (length == 3)
1299         {
1300           color->red *= 16;
1301           color->green *= 16;
1302           color->blue *= 16;
1303         }
1304       return G_TOKEN_NONE;
1305       
1306     default:
1307       return G_TOKEN_STRING;
1308     }
1309 }
1310
1311 static guint
1312 gtk_rc_parse_pixmap_path (GScanner *scanner)
1313 {
1314   guint token;
1315   
1316   token = g_scanner_get_next_token (scanner);
1317   if (token != TOKEN_PIXMAP_PATH)
1318     return TOKEN_PIXMAP_PATH;
1319   
1320   token = g_scanner_get_next_token (scanner);
1321   if (token != G_TOKEN_STRING)
1322     return G_TOKEN_STRING;
1323   
1324   gtk_rc_parse_pixmap_path_string (scanner->value.v_string);
1325   
1326   return G_TOKEN_NONE;
1327 }
1328
1329 static void
1330 gtk_rc_parse_pixmap_path_string (gchar *pix_path)
1331 {
1332   gchar *buf;
1333   gint end_offset;
1334   gint start_offset = 0;
1335   gint path_len;
1336   gint path_num;
1337   
1338   /* free the old one, or just add to the old one ? */
1339   for (path_num=0; pixmap_path[path_num]; path_num++)
1340     {
1341       g_free (pixmap_path[path_num]);
1342       pixmap_path[path_num] = NULL;
1343     }
1344   
1345   path_num = 0;
1346   
1347   path_len = strlen (pix_path);
1348   
1349   buf = g_strdup (pix_path);
1350   
1351   for (end_offset = 0; end_offset <= path_len; end_offset++)
1352     {
1353       if ((buf[end_offset] == ':') ||
1354           (end_offset == path_len))
1355         {
1356           buf[end_offset] = '\0';
1357           pixmap_path[path_num] = g_strdup (buf + start_offset);
1358           path_num++;
1359           pixmap_path[path_num] = NULL;
1360           start_offset = end_offset + 1;
1361         }
1362     }
1363   g_free (buf);
1364 }
1365
1366 static guint
1367 gtk_rc_parse_widget_style (GScanner *scanner)
1368 {
1369   GtkRcSet *rc_set;
1370   guint token;
1371   
1372   token = g_scanner_get_next_token (scanner);
1373   if (token != TOKEN_WIDGET)
1374     return TOKEN_WIDGET;
1375   
1376   token = g_scanner_get_next_token (scanner);
1377   if (token != G_TOKEN_STRING)
1378     return G_TOKEN_STRING;
1379
1380   rc_set = g_new (GtkRcSet, 1);
1381   gtk_pattern_spec_init (&rc_set->pspec, scanner->value.v_string);
1382   
1383   token = g_scanner_get_next_token (scanner);
1384   if (token != TOKEN_STYLE)
1385     {
1386       gtk_pattern_spec_free_segs (&rc_set->pspec);
1387       g_free (rc_set);
1388       return TOKEN_STYLE;
1389     }
1390   
1391   token = g_scanner_get_next_token (scanner);
1392   if (token != G_TOKEN_STRING)
1393     {
1394       gtk_pattern_spec_free_segs (&rc_set->pspec);
1395       g_free (rc_set);
1396       return G_TOKEN_STRING;
1397     }
1398   
1399   rc_set->rc_style = gtk_rc_style_find (scanner->value.v_string);
1400   if (!rc_set->rc_style)
1401     {
1402       gtk_pattern_spec_free_segs (&rc_set->pspec);
1403       g_free (rc_set);
1404       return G_TOKEN_STRING;
1405     }
1406   
1407   gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set);
1408   
1409   return G_TOKEN_NONE;
1410 }
1411
1412 static guint
1413 gtk_rc_parse_widget_class_style (GScanner *scanner)
1414 {
1415   GtkRcSet *rc_set;
1416   guint token;
1417   
1418   token = g_scanner_get_next_token (scanner);
1419   if (token != TOKEN_WIDGET_CLASS)
1420     return TOKEN_WIDGET_CLASS;
1421   
1422   token = g_scanner_get_next_token (scanner);
1423   if (token != G_TOKEN_STRING)
1424     return G_TOKEN_STRING;
1425   
1426   rc_set = g_new (GtkRcSet, 1);
1427   gtk_pattern_spec_init (&rc_set->pspec, scanner->value.v_string);
1428
1429   token = g_scanner_get_next_token (scanner);
1430   if (token != TOKEN_STYLE)
1431     {
1432       gtk_pattern_spec_free_segs (&rc_set->pspec);
1433       g_free (rc_set);
1434       return G_TOKEN_STRING;
1435     }
1436   
1437   token = g_scanner_get_next_token (scanner);
1438   if (token != G_TOKEN_STRING)
1439     {
1440       gtk_pattern_spec_free_segs (&rc_set->pspec);
1441       g_free (rc_set);
1442       return G_TOKEN_STRING;
1443     }
1444   
1445   rc_set->rc_style = gtk_rc_style_find (scanner->value.v_string);
1446   if (!rc_set->rc_style)
1447     {
1448       gtk_pattern_spec_free_segs (&rc_set->pspec);
1449       g_free (rc_set);
1450       return G_TOKEN_STRING;
1451     }
1452   
1453   gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set);
1454   
1455   return G_TOKEN_NONE;
1456 }
1457
1458 /*
1459 typedef  GdkPixmap * (*GtkImageLoader) (GdkWindow   *window,
1460                                         GdkColormap *colormap,
1461                                         GdkBitmap  **mask,
1462                                         GdkColor    *transparent_color,
1463                                         const gchar *filename);
1464 */
1465
1466 void
1467 gtk_rc_set_image_loader(GtkImageLoader loader)
1468 {
1469         image_loader = loader;
1470 }
1471