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