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