]> Pileus Git - ~andy/gtk/blob - gtk/gtkrc.c
495fbbd411f4cb3469f036fe54736cf1a0a098f8
[~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 = 
683         g_slist_prepend (rc_dir_stack,
684                          g_path_get_dirname (rc_file->canonical_name));
685       gtk_rc_parse_any (filename, fd, NULL);
686  
687       tmp_list = rc_dir_stack;
688       rc_dir_stack = rc_dir_stack->next;
689  
690       g_free (tmp_list->data);
691       g_slist_free_1 (tmp_list);
692
693       close (fd);
694     }
695 }
696
697 void
698 gtk_rc_parse (const gchar *filename)
699 {
700   g_return_if_fail (filename != NULL);
701
702   gtk_rc_parse_file (filename, TRUE);
703 }
704
705 /* Handling of RC styles */
706
707 GType
708 gtk_rc_style_get_type (void)
709 {
710   static GType object_type = 0;
711
712   if (!object_type)
713     {
714       static const GTypeInfo object_info =
715       {
716         sizeof (GtkRcStyleClass),
717         (GBaseInitFunc) NULL,
718         (GBaseFinalizeFunc) NULL,
719         (GClassInitFunc) gtk_rc_style_class_init,
720         NULL,           /* class_finalize */
721         NULL,           /* class_data */
722         sizeof (GtkRcStyle),
723         0,              /* n_preallocs */
724         (GInstanceInitFunc) gtk_rc_style_init,
725       };
726       
727       object_type = g_type_register_static (G_TYPE_OBJECT,
728                                             "GtkRcStyle",
729                                             &object_info);
730     }
731   
732   return object_type;
733 }
734
735 static void
736 gtk_rc_style_init (GtkRcStyle *style)
737 {
738   guint i;
739
740   style->name = NULL;
741   for (i = 0; i < 5; i++)
742     {
743       static const GdkColor init_color = { 0, 0, 0, 0, };
744
745       style->bg_pixmap_name[i] = NULL;
746       style->color_flags[i] = 0;
747       style->fg[i] = init_color;
748       style->bg[i] = init_color;
749       style->text[i] = init_color;
750       style->base[i] = init_color;
751     }
752   style->xthickness = -1;
753   style->ythickness = -1;
754   style->rc_style_lists = NULL;
755 }
756
757 static void
758 gtk_rc_style_class_init (GtkRcStyleClass *klass)
759 {
760   GObjectClass *object_class = G_OBJECT_CLASS (klass);
761   
762   parent_class = g_type_class_peek_parent (klass);
763
764   object_class->finalize = gtk_rc_style_finalize;
765
766   klass->parse = NULL;
767   klass->clone = gtk_rc_style_real_clone;
768   klass->merge = gtk_rc_style_real_merge;
769   klass->create_style = gtk_rc_style_real_create_style;
770 }
771
772 /* Like g_slist_remove, but remove all copies of data */
773 static GSList*
774 gtk_rc_slist_remove_all (GSList   *list,
775                          gpointer  data)
776 {
777   GSList *tmp;
778   GSList *prev;
779
780   prev = NULL;
781   tmp = list;
782
783   while (tmp)
784     {
785       if (tmp->data == data)
786         {
787           if (list == tmp)
788             list = list->next;
789
790           if (prev) 
791             prev->next = tmp->next;
792
793           g_slist_free_1 (tmp);
794
795           if (prev)
796             tmp = prev->next;
797           else
798             tmp = list;
799         }
800       else
801         {
802           prev = tmp;
803           tmp = tmp->next;
804         }
805     }
806
807   return list;
808 }
809
810 static void
811 gtk_rc_style_finalize (GObject *object)
812 {
813   gint i;
814   GSList *tmp_list1, *tmp_list2;
815   GtkRcStyle *rc_style;
816
817   rc_style = GTK_RC_STYLE (object);
818   
819   if (rc_style->name)
820     g_free (rc_style->name);
821   if (rc_style->font_desc)
822     pango_font_description_free (rc_style->font_desc);
823       
824   for (i=0 ; i < 5 ; i++)
825     if (rc_style->bg_pixmap_name[i])
826       g_free (rc_style->bg_pixmap_name[i]);
827   
828   /* Now remove all references to this rc_style from
829    * realized_style_ht
830    */
831   tmp_list1 = rc_style->rc_style_lists;
832   while (tmp_list1)
833     {
834       GSList *rc_styles = tmp_list1->data;
835       GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
836       gtk_style_unref (style);
837
838       /* Remove the list of styles from the other rc_styles
839        * in the list
840        */
841       tmp_list2 = rc_styles;
842       while (tmp_list2)
843         {
844           GtkRcStyle *other_style = tmp_list2->data;
845
846           if (other_style != rc_style)
847             other_style->rc_style_lists =
848               gtk_rc_slist_remove_all (other_style->rc_style_lists, rc_styles);
849                   
850           tmp_list2 = tmp_list2->next;
851         }
852
853       /* And from the hash table itself
854        */
855       g_hash_table_remove (realized_style_ht, rc_styles);
856       g_slist_free (rc_styles);
857
858       tmp_list1 = tmp_list1->next;
859     }
860   g_slist_free (rc_style->rc_style_lists);
861
862   G_OBJECT_CLASS (parent_class)->finalize (object);
863 }
864
865 GtkRcStyle *
866 gtk_rc_style_new (void)
867 {
868   GtkRcStyle *style;
869   
870   style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
871   
872   return style;
873 }
874
875 /**
876  * gtk_rc_style_copy:
877  * @orig: the style to copy
878  * 
879  * Make a copy of the specified #GtkRcStyle. This function
880  * will correctly copy an rc style that is a member of a class
881  * derived from #GtkRcStyle.
882  * 
883  * Return value: the resulting #GtkRcStyle
884  **/
885 GtkRcStyle *
886 gtk_rc_style_copy (GtkRcStyle *orig)
887 {
888   GtkRcStyle *style;
889
890   g_return_if_fail (GTK_IS_RC_STYLE (orig));
891   
892   style = GTK_RC_STYLE_GET_CLASS (orig)->clone (orig);
893   GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
894
895   return style;
896 }
897
898 void      
899 gtk_rc_style_ref (GtkRcStyle  *rc_style)
900 {
901   g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
902
903   g_object_ref (G_OBJECT (rc_style));
904 }
905
906 void      
907 gtk_rc_style_unref (GtkRcStyle  *rc_style)
908 {
909   g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
910
911   g_object_unref (G_OBJECT (rc_style));
912 }
913
914 static GtkRcStyle *
915 gtk_rc_style_real_clone (GtkRcStyle *style)
916 {
917   return GTK_RC_STYLE (g_object_new (G_OBJECT_TYPE (style), NULL));
918 }
919
920 static void
921 gtk_rc_style_real_merge (GtkRcStyle *dest,
922                          GtkRcStyle *src)
923 {
924   gint i;
925   
926   for (i = 0; i < 5; i++)
927     {
928       if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
929         dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
930       
931       if (!(dest->color_flags[i] & GTK_RC_FG) && 
932           src->color_flags[i] & GTK_RC_FG)
933         {
934           dest->fg[i] = src->fg[i];
935           dest->color_flags[i] |= GTK_RC_FG;
936         }
937       if (!(dest->color_flags[i] & GTK_RC_BG) && 
938           src->color_flags[i] & GTK_RC_BG)
939         {
940           dest->bg[i] = src->bg[i];
941           dest->color_flags[i] |= GTK_RC_BG;
942         }
943       if (!(dest->color_flags[i] & GTK_RC_TEXT) && 
944           src->color_flags[i] & GTK_RC_TEXT)
945         {
946           dest->text[i] = src->text[i];
947           dest->color_flags[i] |= GTK_RC_TEXT;
948         }
949       if (!(dest->color_flags[i] & GTK_RC_BASE) && 
950           src->color_flags[i] & GTK_RC_BASE)
951         {
952           dest->base[i] = src->base[i];
953           dest->color_flags[i] |= GTK_RC_BASE;
954         }
955     }
956
957   if (dest->xthickness < 0 && src->xthickness >= 0)
958     dest->xthickness = src->xthickness;
959   if (dest->ythickness < 0 && src->ythickness >= 0)
960     dest->ythickness = src->ythickness;
961
962   if (!dest->font_desc && src->font_desc)
963     dest->font_desc = pango_font_description_copy (src->font_desc);
964 }
965
966 static GtkStyle *
967 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
968 {
969   return gtk_style_new ();
970 }
971
972 static void
973 gtk_rc_clear_hash_node (gpointer key, 
974                         gpointer data, 
975                         gpointer user_data)
976 {
977   gtk_rc_style_unref (data);
978 }
979
980 static void
981 gtk_rc_free_rc_sets (GSList *slist)
982 {
983   while (slist)
984     {
985       GtkRcSet *rc_set;
986
987       rc_set = slist->data;
988       gtk_pattern_spec_free_segs (&rc_set->pspec);
989       g_free (rc_set);
990
991       slist = slist->next;
992     }
993 }
994
995 static void
996 gtk_rc_clear_styles (void)
997 {
998   /* Clear out all old rc_styles */
999
1000   if (rc_style_ht)
1001     {
1002       g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
1003       g_hash_table_destroy (rc_style_ht);
1004       rc_style_ht = NULL;
1005     }
1006
1007   gtk_rc_free_rc_sets (gtk_rc_sets_widget);
1008   g_slist_free (gtk_rc_sets_widget);
1009   gtk_rc_sets_widget = NULL;
1010
1011   gtk_rc_free_rc_sets (gtk_rc_sets_widget_class);
1012   g_slist_free (gtk_rc_sets_widget_class);
1013   gtk_rc_sets_widget_class = NULL;
1014
1015   gtk_rc_free_rc_sets (gtk_rc_sets_class);
1016   g_slist_free (gtk_rc_sets_class);
1017   gtk_rc_sets_class = NULL;
1018 }
1019
1020 gboolean
1021 gtk_rc_reparse_all (void)
1022 {
1023   GSList *tmp_list;
1024   gboolean mtime_modified = FALSE;
1025   GtkRcFile *rc_file;
1026
1027   struct stat statbuf;
1028
1029   /* Check through and see if any of the RC's have had their
1030    * mtime modified. If so, reparse everything.
1031    */
1032   tmp_list = rc_files;
1033   while (tmp_list)
1034     {
1035       rc_file = tmp_list->data;
1036       
1037       if (!lstat (rc_file->name, &statbuf) && 
1038           (statbuf.st_mtime > rc_file->mtime))
1039         {
1040           mtime_modified = TRUE;
1041           break;
1042         }
1043       
1044       tmp_list = tmp_list->next;
1045     }
1046
1047   if (mtime_modified)
1048     {
1049       gtk_rc_clear_styles();
1050
1051       tmp_list = rc_files;
1052       while (tmp_list)
1053         {
1054           rc_file = tmp_list->data;
1055           if (rc_file->reload)
1056             gtk_rc_parse_file (rc_file->name, FALSE);
1057           
1058           tmp_list = tmp_list->next;
1059         }
1060     }
1061
1062   return mtime_modified;
1063 }
1064
1065 static GSList *
1066 gtk_rc_styles_match (GSList       *rc_styles,
1067                      GSList       *sets,
1068                      guint         path_length,
1069                      gchar        *path,
1070                      gchar        *path_reversed)
1071                      
1072 {
1073   GtkRcSet *rc_set;
1074
1075   while (sets)
1076     {
1077       rc_set = sets->data;
1078       sets = sets->next;
1079
1080       if (gtk_pattern_match (&rc_set->pspec, path_length, path, path_reversed))
1081         rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
1082     }
1083   
1084   return rc_styles;
1085 }
1086
1087 GtkStyle*
1088 gtk_rc_get_style (GtkWidget *widget)
1089 {
1090   GtkRcStyle *widget_rc_style;
1091   GSList *rc_styles = NULL;
1092
1093   static guint rc_style_key_id = 0;
1094
1095   /* We allow the specification of a single rc style to be bound
1096    * tightly to a widget, for application modifications
1097    */
1098   if (!rc_style_key_id)
1099     rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1100
1101   widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
1102                                                rc_style_key_id);
1103
1104   if (widget_rc_style)
1105     rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
1106   
1107   if (gtk_rc_sets_widget)
1108     {
1109       gchar *path, *path_reversed;
1110       guint path_length;
1111
1112       gtk_widget_path (widget, &path_length, &path, &path_reversed);
1113       rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget, path_length, path, path_reversed);
1114       g_free (path);
1115       g_free (path_reversed);
1116       
1117     }
1118   
1119   if (gtk_rc_sets_widget_class)
1120     {
1121       gchar *path, *path_reversed;
1122       guint path_length;
1123
1124       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1125       rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget_class, path_length, path, path_reversed);
1126       g_free (path);
1127       g_free (path_reversed);
1128     }
1129
1130   if (gtk_rc_sets_class)
1131     {
1132       GtkType type;
1133
1134       type = GTK_OBJECT_TYPE (widget);
1135       while (type)
1136         {
1137           gchar *path, *path_reversed;
1138           guint path_length;
1139
1140           path = gtk_type_name (type);
1141           path_length = strlen (path);
1142           path_reversed = g_strdup (path);
1143           g_strreverse (path_reversed);
1144           
1145           rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_class, path_length, path, path_reversed);
1146           g_free (path_reversed);
1147       
1148           type = gtk_type_parent (type);
1149         }
1150     }
1151   
1152   if (rc_styles)
1153     return gtk_rc_init_style (rc_styles);
1154
1155   return NULL;
1156 }
1157
1158 static GSList*
1159 gtk_rc_add_rc_sets (GSList     *slist,
1160                     GtkRcStyle *rc_style,
1161                     const char *pattern)
1162 {
1163   GtkRcStyle *new_style;
1164   GtkRcSet *rc_set;
1165   guint i;
1166   
1167   new_style = gtk_rc_style_new ();
1168   *new_style = *rc_style;
1169   new_style->name = g_strdup (rc_style->name);
1170   if (rc_style->font_desc)
1171     new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
1172   
1173   for (i = 0; i < 5; i++)
1174     new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1175   
1176   rc_set = g_new (GtkRcSet, 1);
1177   gtk_pattern_spec_init (&rc_set->pspec, pattern);
1178   rc_set->rc_style = rc_style;
1179   
1180   return g_slist_prepend (slist, rc_set);
1181 }
1182
1183 void
1184 gtk_rc_add_widget_name_style (GtkRcStyle  *rc_style,
1185                               const gchar *pattern)
1186 {
1187   g_return_if_fail (rc_style != NULL);
1188   g_return_if_fail (pattern != NULL);
1189
1190   gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, rc_style, pattern);
1191 }
1192
1193 void
1194 gtk_rc_add_widget_class_style (GtkRcStyle  *rc_style,
1195                                const gchar *pattern)
1196 {
1197   g_return_if_fail (rc_style != NULL);
1198   g_return_if_fail (pattern != NULL);
1199
1200   gtk_rc_sets_widget_class = gtk_rc_add_rc_sets (gtk_rc_sets_widget_class, rc_style, pattern);
1201 }
1202
1203 void
1204 gtk_rc_add_class_style (GtkRcStyle  *rc_style,
1205                         const gchar *pattern)
1206 {
1207   g_return_if_fail (rc_style != NULL);
1208   g_return_if_fail (pattern != NULL);
1209
1210   gtk_rc_sets_class = gtk_rc_add_rc_sets (gtk_rc_sets_class, rc_style, pattern);
1211 }
1212
1213 static void
1214 gtk_rc_parse_any (const gchar  *input_name,
1215                   gint          input_fd,
1216                   const gchar  *input_string)
1217 {
1218   GScanner *scanner;
1219   guint    i;
1220   gboolean done;
1221   
1222   scanner = g_scanner_new ((GScannerConfig *) &gtk_rc_scanner_config);
1223   
1224   if (input_fd >= 0)
1225     {
1226       g_assert (input_string == NULL);
1227       
1228       g_scanner_input_file (scanner, input_fd);
1229     }
1230   else
1231     {
1232       g_assert (input_string != NULL);
1233       
1234       g_scanner_input_text (scanner, input_string, strlen (input_string));
1235     }
1236   scanner->input_name = input_name;
1237
1238   for (i = 0; i < n_symbols; i++)
1239     g_scanner_add_symbol (scanner, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1240   
1241   done = FALSE;
1242   while (!done)
1243     {
1244       if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1245         done = TRUE;
1246       else
1247         {
1248           guint expected_token;
1249           
1250           expected_token = gtk_rc_parse_statement (scanner);
1251
1252           if (expected_token != G_TOKEN_NONE)
1253             {
1254               gchar *symbol_name;
1255               gchar *msg;
1256               
1257               msg = NULL;
1258               symbol_name = NULL;
1259               if (scanner->scope_id == 0)
1260                 {
1261                   /* if we are in scope 0, we know the symbol names
1262                    * that are associated with certaintoken values.
1263                    * so we look them up to make the error messages
1264                    * more readable.
1265                    */
1266                   if (expected_token > GTK_RC_TOKEN_INVALID &&
1267                       expected_token < GTK_RC_TOKEN_LAST)
1268                     {
1269                       for (i = 0; i < n_symbols; i++)
1270                         if (symbols[i].token == expected_token)
1271                           msg = symbols[i].name;
1272                       if (msg)
1273                         msg = g_strconcat ("e.g. `", msg, "'", NULL);
1274                     }
1275                   if (scanner->token > GTK_RC_TOKEN_INVALID &&
1276                       scanner->token < GTK_RC_TOKEN_LAST)
1277                     {
1278                       symbol_name = "???";
1279                       for (i = 0; i < n_symbols; i++)
1280                         if (symbols[i].token == scanner->token)
1281                           symbol_name = symbols[i].name;
1282                     }
1283                 }
1284               g_scanner_unexp_token (scanner,
1285                                      expected_token,
1286                                      NULL,
1287                                      "keyword",
1288                                      symbol_name,
1289                                      msg,
1290                                      TRUE);
1291               g_free (msg);
1292               done = TRUE;
1293             }
1294         }
1295     }
1296   
1297   g_scanner_destroy (scanner);
1298 }
1299
1300 static guint       
1301 gtk_rc_styles_hash (const GSList *rc_styles)
1302 {
1303   guint result;
1304   
1305   result = 0;
1306   while (rc_styles)
1307     {
1308       result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1309       rc_styles = rc_styles->next;
1310     }
1311   
1312   return result;
1313 }
1314
1315 static gint        
1316 gtk_rc_styles_compare (const GSList *a,
1317                        const GSList *b)
1318 {
1319   while (a && b)
1320     {
1321       if (a->data != b->data)
1322         return FALSE;
1323       a = a->next;
1324       b = b->next;
1325     }
1326   
1327   return (a == b);
1328 }
1329
1330 static guint
1331 gtk_rc_style_hash (const char *name)
1332 {
1333   guint result;
1334   
1335   result = 0;
1336   while (*name)
1337     result += (result << 3) + *name++;
1338   
1339   return result;
1340 }
1341
1342 static gint
1343 gtk_rc_style_compare (const char *a,
1344                       const char *b)
1345 {
1346   return (strcmp (a, b) == 0);
1347 }
1348
1349 static GtkRcStyle*
1350 gtk_rc_style_find (const char *name)
1351 {
1352   if (rc_style_ht)
1353     return g_hash_table_lookup (rc_style_ht, (gpointer) name);
1354   else
1355     return NULL;
1356 }
1357
1358 static GtkStyle *
1359 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1360 {
1361   GtkStyle *style;
1362
1363   style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
1364
1365   style->rc_style = rc_style;
1366   gtk_rc_style_ref (rc_style);
1367   
1368   GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);
1369   
1370   return style;
1371 }
1372
1373 /* Reuses or frees rc_styles */
1374 static GtkStyle *
1375 gtk_rc_init_style (GSList *rc_styles)
1376 {
1377   GtkStyle *style = NULL;
1378   gint i;
1379
1380   g_return_val_if_fail (rc_styles != NULL, NULL);
1381   
1382   if (!realized_style_ht)
1383     realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
1384                                           (GCompareFunc) gtk_rc_styles_compare);
1385
1386   style = g_hash_table_lookup (realized_style_ht, rc_styles);
1387
1388   if (!style)
1389     {
1390       GtkRcStyle *base_style = NULL;
1391       GtkRcStyle *proto_style;
1392       GtkRcStyleClass *proto_style_class;
1393       GSList *tmp_styles;
1394       GType rc_style_type = GTK_TYPE_RC_STYLE;
1395
1396       /* Find the first derived style in the list, and use that to
1397        * create the merged style. If we only have raw GtkRcStyles, use
1398        * the first style to create the merged style.
1399        */
1400       base_style = rc_styles->data;
1401       tmp_styles = rc_styles;
1402       while (tmp_styles)
1403         {
1404           GtkRcStyle *rc_style = tmp_styles->data;
1405
1406           if (G_OBJECT_TYPE (rc_style) != rc_style_type)
1407             {
1408               base_style = rc_style;
1409               break;
1410             }
1411
1412           tmp_styles = tmp_styles->next;
1413         }
1414       
1415       proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
1416       proto_style = proto_style_class->clone (base_style);
1417       
1418       tmp_styles = rc_styles;
1419       while (tmp_styles)
1420         {
1421           GtkRcStyle *rc_style = tmp_styles->data;
1422           
1423           proto_style_class->merge (proto_style, rc_style);
1424           
1425           /* Point from each rc_style to the list of styles */
1426           if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
1427             rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
1428           
1429           tmp_styles = tmp_styles->next;
1430         }
1431
1432       for (i = 0; i < 5; i++)
1433         if (proto_style->bg_pixmap_name[i] &&
1434             (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1435           {
1436             g_free (proto_style->bg_pixmap_name[i]);
1437             proto_style->bg_pixmap_name[i] = NULL;
1438           }
1439
1440       style = gtk_rc_style_to_style (proto_style);
1441       gtk_rc_style_unref (proto_style);
1442
1443       g_hash_table_insert (realized_style_ht, rc_styles, style);
1444     }
1445   else
1446     g_slist_free (rc_styles);
1447
1448   return style;
1449 }
1450
1451 /*********************
1452  * Parsing functions *
1453  *********************/
1454
1455 static guint
1456 gtk_rc_parse_statement (GScanner *scanner)
1457 {
1458   guint token;
1459   
1460   token = g_scanner_peek_next_token (scanner);
1461
1462   switch (token)
1463     {
1464     case GTK_RC_TOKEN_INCLUDE:
1465       token = g_scanner_get_next_token (scanner);
1466       if (token != GTK_RC_TOKEN_INCLUDE)
1467         return GTK_RC_TOKEN_INCLUDE;
1468
1469       token = g_scanner_get_next_token (scanner);
1470       if (token != G_TOKEN_STRING)
1471         return G_TOKEN_STRING;
1472
1473       gtk_rc_parse_file (scanner->value.v_string, FALSE);
1474       return G_TOKEN_NONE;
1475
1476     case GTK_RC_TOKEN_STYLE:
1477       return gtk_rc_parse_style (scanner);
1478
1479     case GTK_RC_TOKEN_BINDING:
1480       return gtk_binding_parse_binding (scanner);
1481
1482     case GTK_RC_TOKEN_PIXMAP_PATH:
1483       return gtk_rc_parse_pixmap_path (scanner);
1484
1485     case GTK_RC_TOKEN_WIDGET:
1486       return gtk_rc_parse_path_pattern (scanner);
1487
1488     case GTK_RC_TOKEN_WIDGET_CLASS:
1489       return gtk_rc_parse_path_pattern (scanner);
1490
1491     case GTK_RC_TOKEN_CLASS:
1492       return gtk_rc_parse_path_pattern (scanner);
1493
1494     case GTK_RC_TOKEN_MODULE_PATH:
1495       return gtk_rc_parse_module_path (scanner);
1496        
1497     default:
1498       g_scanner_get_next_token (scanner);
1499       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
1500     }
1501 }
1502
1503 static guint
1504 gtk_rc_parse_style (GScanner *scanner)
1505 {
1506   GtkRcStyle *rc_style;
1507   GtkRcStyle *parent_style;
1508   guint token;
1509   gint insert;
1510   gint i;
1511   
1512   token = g_scanner_get_next_token (scanner);
1513   if (token != GTK_RC_TOKEN_STYLE)
1514     return GTK_RC_TOKEN_STYLE;
1515   
1516   token = g_scanner_get_next_token (scanner);
1517   if (token != G_TOKEN_STRING)
1518     return G_TOKEN_STRING;
1519   
1520   insert = FALSE;
1521   rc_style = gtk_rc_style_find (scanner->value.v_string);
1522   
1523   if (!rc_style)
1524     {
1525       insert = TRUE;
1526       rc_style = gtk_rc_style_new ();
1527       rc_style->name = g_strdup (scanner->value.v_string);
1528       
1529       for (i = 0; i < 5; i++)
1530         rc_style->bg_pixmap_name[i] = NULL;
1531
1532       for (i = 0; i < 5; i++)
1533         rc_style->color_flags[i] = 0;
1534     }
1535   
1536   token = g_scanner_peek_next_token (scanner);
1537   if (token == G_TOKEN_EQUAL_SIGN)
1538     {
1539       token = g_scanner_get_next_token (scanner);
1540       
1541       token = g_scanner_get_next_token (scanner);
1542       if (token != G_TOKEN_STRING)
1543         {
1544           if (insert)
1545             g_free (rc_style);
1546
1547           return G_TOKEN_STRING;
1548         }
1549       
1550       parent_style = gtk_rc_style_find (scanner->value.v_string);
1551       if (parent_style)
1552         {
1553           for (i = 0; i < 5; i++)
1554             {
1555               rc_style->color_flags[i] = parent_style->color_flags[i];
1556               rc_style->fg[i] = parent_style->fg[i];
1557               rc_style->bg[i] = parent_style->bg[i];
1558               rc_style->text[i] = parent_style->text[i];
1559               rc_style->base[i] = parent_style->base[i];
1560             }
1561
1562           rc_style->xthickness = parent_style->xthickness;
1563           rc_style->ythickness = parent_style->ythickness;
1564           
1565           if (parent_style->font_desc)
1566             {
1567               if (rc_style->font_desc)
1568                 pango_font_description_free (rc_style->font_desc);
1569               rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
1570             }
1571           
1572           for (i = 0; i < 5; i++)
1573             {
1574               if (rc_style->bg_pixmap_name[i])
1575                 g_free (rc_style->bg_pixmap_name[i]);
1576               rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
1577             }
1578         }
1579     }
1580   
1581   token = g_scanner_get_next_token (scanner);
1582   if (token != G_TOKEN_LEFT_CURLY)
1583     {
1584       if (insert)
1585         g_free (rc_style);
1586
1587       return G_TOKEN_LEFT_CURLY;
1588     }
1589   
1590   token = g_scanner_peek_next_token (scanner);
1591   while (token != G_TOKEN_RIGHT_CURLY)
1592     {
1593       switch (token)
1594         {
1595         case GTK_RC_TOKEN_BG:
1596           token = gtk_rc_parse_bg (scanner, rc_style);
1597           break;
1598         case GTK_RC_TOKEN_FG:
1599           token = gtk_rc_parse_fg (scanner, rc_style);
1600           break;
1601         case GTK_RC_TOKEN_TEXT:
1602           token = gtk_rc_parse_text (scanner, rc_style);
1603           break;
1604         case GTK_RC_TOKEN_BASE:
1605           token = gtk_rc_parse_base (scanner, rc_style);
1606           break;
1607         case GTK_RC_TOKEN_XTHICKNESS:
1608           token = gtk_rc_parse_xthickness (scanner, rc_style);
1609           break;
1610         case GTK_RC_TOKEN_YTHICKNESS:
1611           token = gtk_rc_parse_ythickness (scanner, rc_style);
1612           break;
1613         case GTK_RC_TOKEN_BG_PIXMAP:
1614           token = gtk_rc_parse_bg_pixmap (scanner, rc_style);
1615           break;
1616         case GTK_RC_TOKEN_FONT:
1617           token = gtk_rc_parse_font (scanner, rc_style);
1618           break;
1619         case GTK_RC_TOKEN_FONTSET:
1620           token = gtk_rc_parse_fontset (scanner, rc_style);
1621           break;
1622         case GTK_RC_TOKEN_FONT_NAME:
1623           token = gtk_rc_parse_font_name (scanner, rc_style);
1624           break;
1625         case GTK_RC_TOKEN_ENGINE:
1626           token = gtk_rc_parse_engine (scanner, &rc_style);
1627           break;
1628         default:
1629           g_scanner_get_next_token (scanner);
1630           token = G_TOKEN_RIGHT_CURLY;
1631           break;
1632         }
1633
1634       if (token != G_TOKEN_NONE)
1635         {
1636           if (insert)
1637             {
1638               if (rc_style->font_desc)
1639                 pango_font_description_free (rc_style->font_desc);
1640               
1641               for (i = 0; i < 5; i++)
1642                 if (rc_style->bg_pixmap_name[i])
1643                   g_free (rc_style->bg_pixmap_name[i]);
1644               g_free (rc_style);
1645             }
1646           return token;
1647         }
1648       token = g_scanner_peek_next_token (scanner);
1649     }
1650   
1651   token = g_scanner_get_next_token (scanner);
1652   if (token != G_TOKEN_RIGHT_CURLY)
1653     {
1654       if (insert)
1655         {
1656           if (rc_style->font_desc)
1657             pango_font_description_free (rc_style->font_desc);
1658           
1659           for (i = 0; i < 5; i++)
1660             if (rc_style->bg_pixmap_name[i])
1661               g_free (rc_style->bg_pixmap_name[i]);
1662           
1663           g_free (rc_style);
1664         }
1665       return G_TOKEN_RIGHT_CURLY;
1666     }
1667   
1668   if (insert)
1669     {
1670       if (!rc_style_ht)
1671         rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
1672                                         (GCompareFunc) gtk_rc_style_compare);
1673       
1674       g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
1675     }
1676   
1677   return G_TOKEN_NONE;
1678 }
1679
1680 static guint
1681 gtk_rc_parse_bg (GScanner   *scanner,
1682                  GtkRcStyle *style)
1683 {
1684   GtkStateType state;
1685   guint token;
1686   
1687   token = g_scanner_get_next_token (scanner);
1688   if (token != GTK_RC_TOKEN_BG)
1689     return GTK_RC_TOKEN_BG;
1690   
1691   token = gtk_rc_parse_state (scanner, &state);
1692   if (token != G_TOKEN_NONE)
1693     return token;
1694   
1695   token = g_scanner_get_next_token (scanner);
1696   if (token != G_TOKEN_EQUAL_SIGN)
1697     return G_TOKEN_EQUAL_SIGN;
1698
1699   style->color_flags[state] |= GTK_RC_BG;
1700   return gtk_rc_parse_color (scanner, &style->bg[state]);
1701 }
1702
1703 static guint
1704 gtk_rc_parse_fg (GScanner   *scanner,
1705                  GtkRcStyle *style)
1706 {
1707   GtkStateType state;
1708   guint token;
1709   
1710   token = g_scanner_get_next_token (scanner);
1711   if (token != GTK_RC_TOKEN_FG)
1712     return GTK_RC_TOKEN_FG;
1713   
1714   token = gtk_rc_parse_state (scanner, &state);
1715   if (token != G_TOKEN_NONE)
1716     return token;
1717   
1718   token = g_scanner_get_next_token (scanner);
1719   if (token != G_TOKEN_EQUAL_SIGN)
1720     return G_TOKEN_EQUAL_SIGN;
1721   
1722   style->color_flags[state] |= GTK_RC_FG;
1723   return gtk_rc_parse_color (scanner, &style->fg[state]);
1724 }
1725
1726 static guint
1727 gtk_rc_parse_text (GScanner   *scanner,
1728                    GtkRcStyle *style)
1729 {
1730   GtkStateType state;
1731   guint token;
1732   
1733   token = g_scanner_get_next_token (scanner);
1734   if (token != GTK_RC_TOKEN_TEXT)
1735     return GTK_RC_TOKEN_TEXT;
1736   
1737   token = gtk_rc_parse_state (scanner, &state);
1738   if (token != G_TOKEN_NONE)
1739     return token;
1740   
1741   token = g_scanner_get_next_token (scanner);
1742   if (token != G_TOKEN_EQUAL_SIGN)
1743     return G_TOKEN_EQUAL_SIGN;
1744   
1745   style->color_flags[state] |= GTK_RC_TEXT;
1746   return gtk_rc_parse_color (scanner, &style->text[state]);
1747 }
1748
1749 static guint
1750 gtk_rc_parse_base (GScanner   *scanner,
1751                    GtkRcStyle *style)
1752 {
1753   GtkStateType state;
1754   guint token;
1755   
1756   token = g_scanner_get_next_token (scanner);
1757   if (token != GTK_RC_TOKEN_BASE)
1758     return GTK_RC_TOKEN_BASE;
1759   
1760   token = gtk_rc_parse_state (scanner, &state);
1761   if (token != G_TOKEN_NONE)
1762     return token;
1763   
1764   token = g_scanner_get_next_token (scanner);
1765   if (token != G_TOKEN_EQUAL_SIGN)
1766     return G_TOKEN_EQUAL_SIGN;
1767
1768   style->color_flags[state] |= GTK_RC_BASE;
1769   return gtk_rc_parse_color (scanner, &style->base[state]);
1770 }
1771
1772 static guint
1773 gtk_rc_parse_xthickness (GScanner   *scanner,
1774                          GtkRcStyle *style)
1775 {
1776   if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
1777     return GTK_RC_TOKEN_XTHICKNESS;
1778
1779   if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
1780     return G_TOKEN_EQUAL_SIGN;
1781
1782   if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
1783     return G_TOKEN_INT;
1784
1785   style->xthickness = scanner->value.v_int;
1786
1787   return G_TOKEN_NONE;
1788 }
1789
1790 static guint
1791 gtk_rc_parse_ythickness (GScanner   *scanner,
1792                          GtkRcStyle *style)
1793 {
1794   if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
1795     return GTK_RC_TOKEN_YTHICKNESS;
1796
1797   if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
1798     return G_TOKEN_EQUAL_SIGN;
1799
1800   if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
1801     return G_TOKEN_INT;
1802
1803   style->ythickness = scanner->value.v_int;
1804
1805   return G_TOKEN_NONE;
1806 }
1807
1808 static guint
1809 gtk_rc_parse_bg_pixmap (GScanner   *scanner,
1810                         GtkRcStyle *rc_style)
1811 {
1812   GtkStateType state;
1813   guint token;
1814   gchar *pixmap_file;
1815   
1816   token = g_scanner_get_next_token (scanner);
1817   if (token != GTK_RC_TOKEN_BG_PIXMAP)
1818     return GTK_RC_TOKEN_BG_PIXMAP;
1819   
1820   token = gtk_rc_parse_state (scanner, &state);
1821   if (token != G_TOKEN_NONE)
1822     return token;
1823   
1824   token = g_scanner_get_next_token (scanner);
1825   if (token != G_TOKEN_EQUAL_SIGN)
1826     return G_TOKEN_EQUAL_SIGN;
1827   
1828   token = g_scanner_get_next_token (scanner);
1829   if (token != G_TOKEN_STRING)
1830     return G_TOKEN_STRING;
1831   
1832   if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
1833       (strcmp (scanner->value.v_string, "<none>") == 0))
1834     pixmap_file = g_strdup (scanner->value.v_string);
1835   else
1836     pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
1837   
1838   if (pixmap_file)
1839     {
1840       if (rc_style->bg_pixmap_name[state])
1841         g_free (rc_style->bg_pixmap_name[state]);
1842       rc_style->bg_pixmap_name[state] = pixmap_file;
1843     }
1844   
1845   return G_TOKEN_NONE;
1846 }
1847
1848 static gchar*
1849 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
1850 {
1851   gchar *buf;
1852   gint fd;
1853
1854   buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", dir, pixmap_file);
1855   
1856   fd = open (buf, O_RDONLY);
1857   if (fd >= 0)
1858     {
1859       close (fd);
1860       return buf;
1861     }
1862    
1863   g_free (buf);
1864  
1865    return NULL;
1866  }
1867  
1868 gchar*
1869 gtk_rc_find_pixmap_in_path (GScanner *scanner,
1870                             const gchar *pixmap_file)
1871 {
1872   gint i;
1873   gchar *filename;
1874   GSList *tmp_list;
1875     
1876   for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
1877     {
1878       filename = gtk_rc_check_pixmap_dir (pixmap_path[i], pixmap_file);
1879       if (filename)
1880         return filename;
1881     }
1882  
1883   tmp_list = rc_dir_stack;
1884   while (tmp_list)
1885     {
1886       filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
1887       if (filename)
1888         return filename;
1889        
1890       tmp_list = tmp_list->next;
1891     }
1892   
1893   if (scanner)
1894     g_warning (_("Unable to locate image file in pixmap_path: \"%s\" line %d"),
1895                pixmap_file, scanner->line);
1896   else
1897     g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
1898                pixmap_file);
1899     
1900   return NULL;
1901 }
1902
1903 gchar*
1904 gtk_rc_find_module_in_path (const gchar *module_file)
1905 {
1906   gint i;
1907   gint fd;
1908   gchar *buf;
1909   
1910   for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
1911     {
1912       buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
1913                              module_path[i], module_file);
1914       
1915       fd = open (buf, O_RDONLY);
1916       if (fd >= 0)
1917         {
1918           close (fd);
1919           return buf;
1920         }
1921       
1922       g_free (buf);
1923     }
1924     
1925   return NULL;
1926 }
1927
1928 static guint
1929 gtk_rc_parse_font (GScanner   *scanner,
1930                    GtkRcStyle *rc_style)
1931 {
1932   guint token;
1933   
1934   token = g_scanner_get_next_token (scanner);
1935   if (token != GTK_RC_TOKEN_FONT)
1936     return GTK_RC_TOKEN_FONT;
1937   
1938   token = g_scanner_get_next_token (scanner);
1939   if (token != G_TOKEN_EQUAL_SIGN)
1940     return G_TOKEN_EQUAL_SIGN;
1941   
1942   token = g_scanner_get_next_token (scanner);
1943   if (token != G_TOKEN_STRING)
1944     return G_TOKEN_STRING;
1945
1946   /* Ignore, do nothing */
1947   
1948   return G_TOKEN_NONE;
1949 }
1950
1951 static guint
1952 gtk_rc_parse_fontset (GScanner   *scanner,
1953                       GtkRcStyle *rc_style)
1954 {
1955   guint token;
1956   
1957   token = g_scanner_get_next_token (scanner);
1958   if (token != GTK_RC_TOKEN_FONTSET)
1959     return GTK_RC_TOKEN_FONTSET;
1960   
1961   token = g_scanner_get_next_token (scanner);
1962   if (token != G_TOKEN_EQUAL_SIGN)
1963     return G_TOKEN_EQUAL_SIGN;
1964   
1965   token = g_scanner_get_next_token (scanner);
1966   if (token != G_TOKEN_STRING)
1967     return G_TOKEN_STRING;
1968
1969   /* Do nothing - silently ignore */
1970   
1971   return G_TOKEN_NONE;
1972 }
1973
1974 static guint
1975 gtk_rc_parse_font_name (GScanner   *scanner,
1976                         GtkRcStyle *rc_style)
1977 {
1978   guint token;
1979   
1980   token = g_scanner_get_next_token (scanner);
1981   if (token != GTK_RC_TOKEN_FONT_NAME)
1982     return GTK_RC_TOKEN_FONT;
1983   
1984   token = g_scanner_get_next_token (scanner);
1985   if (token != G_TOKEN_EQUAL_SIGN)
1986     return G_TOKEN_EQUAL_SIGN;
1987   
1988   token = g_scanner_get_next_token (scanner);
1989   if (token != G_TOKEN_STRING)
1990     return G_TOKEN_STRING;
1991
1992   rc_style->font_desc = pango_font_description_from_string (scanner->value.v_string);
1993   
1994   return G_TOKEN_NONE;
1995 }
1996
1997 static guint       
1998 gtk_rc_parse_engine (GScanner    *scanner,
1999                      GtkRcStyle **rc_style)
2000 {
2001   guint token;
2002   GtkThemeEngine *engine;
2003   guint result = G_TOKEN_NONE;
2004   GtkRcStyle *new_style = NULL;
2005   gboolean parsed_curlies = FALSE;
2006   
2007   token = g_scanner_get_next_token (scanner);
2008   if (token != GTK_RC_TOKEN_ENGINE)
2009     return GTK_RC_TOKEN_ENGINE;
2010
2011   token = g_scanner_get_next_token (scanner);
2012   if (token != G_TOKEN_STRING)
2013     return G_TOKEN_STRING;
2014
2015   engine = gtk_theme_engine_get (scanner->value.v_string);
2016   
2017   token = g_scanner_get_next_token (scanner);
2018   if (token != G_TOKEN_LEFT_CURLY)
2019     return G_TOKEN_LEFT_CURLY;
2020
2021   if (engine)
2022     {
2023       GtkRcStyleClass *new_class;
2024       
2025       new_style = gtk_theme_engine_create_rc_style (engine);
2026       gtk_theme_engine_unref (engine);
2027
2028       new_class = GTK_RC_STYLE_GET_CLASS (new_style);
2029
2030       new_class->merge (new_style, *rc_style);
2031       if ((*rc_style)->name)
2032         new_style->name = g_strdup ((*rc_style)->name);
2033       
2034       if (new_class->parse)
2035         {
2036           parsed_curlies = TRUE;
2037           result = new_class->parse (new_style, scanner);
2038
2039           if (result != G_TOKEN_NONE)
2040             {
2041               g_object_unref (G_OBJECT (new_style));
2042               new_style = NULL;
2043             }
2044         }
2045     }
2046
2047   if (!parsed_curlies)
2048     {
2049       /* Skip over remainder, looking for nested {}'s
2050        */
2051       guint count = 1;
2052       
2053       result = G_TOKEN_RIGHT_CURLY;
2054       while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
2055         {
2056           if (token == G_TOKEN_LEFT_CURLY)
2057             count++;
2058           else if (token == G_TOKEN_RIGHT_CURLY)
2059             count--;
2060           
2061           if (count == 0)
2062             {
2063               result = G_TOKEN_NONE;
2064               break;
2065             }
2066         }
2067     }
2068
2069   if (new_style)
2070     {
2071       g_object_unref (G_OBJECT (*rc_style));
2072       *rc_style = new_style;
2073     }
2074
2075   return result;
2076 }
2077
2078 guint
2079 gtk_rc_parse_state (GScanner     *scanner,
2080                     GtkStateType *state)
2081 {
2082   guint old_scope;
2083   guint token;
2084
2085   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2086   g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
2087   
2088   /* we don't know where we got called from, so we reset the scope here.
2089    * if we bail out due to errors, we *don't* reset the scope, so the
2090    * error messaging code can make sense of our tokens.
2091    */
2092   old_scope = g_scanner_set_scope (scanner, 0);
2093   
2094   token = g_scanner_get_next_token (scanner);
2095   if (token != G_TOKEN_LEFT_BRACE)
2096     return G_TOKEN_LEFT_BRACE;
2097   
2098   token = g_scanner_get_next_token (scanner);
2099   switch (token)
2100     {
2101     case GTK_RC_TOKEN_ACTIVE:
2102       *state = GTK_STATE_ACTIVE;
2103       break;
2104     case GTK_RC_TOKEN_INSENSITIVE:
2105       *state = GTK_STATE_INSENSITIVE;
2106       break;
2107     case GTK_RC_TOKEN_NORMAL:
2108       *state = GTK_STATE_NORMAL;
2109       break;
2110     case GTK_RC_TOKEN_PRELIGHT:
2111       *state = GTK_STATE_PRELIGHT;
2112       break;
2113     case GTK_RC_TOKEN_SELECTED:
2114       *state = GTK_STATE_SELECTED;
2115       break;
2116     default:
2117       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
2118     }
2119   
2120   token = g_scanner_get_next_token (scanner);
2121   if (token != G_TOKEN_RIGHT_BRACE)
2122     return G_TOKEN_RIGHT_BRACE;
2123   
2124   g_scanner_set_scope (scanner, old_scope);
2125
2126   return G_TOKEN_NONE;
2127 }
2128
2129 guint
2130 gtk_rc_parse_priority (GScanner            *scanner,
2131                        GtkPathPriorityType *priority)
2132 {
2133   guint old_scope;
2134   guint token;
2135
2136   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2137   g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
2138
2139   /* we don't know where we got called from, so we reset the scope here.
2140    * if we bail out due to errors, we *don't* reset the scope, so the
2141    * error messaging code can make sense of our tokens.
2142    */
2143   old_scope = g_scanner_set_scope (scanner, 0);
2144   
2145   token = g_scanner_get_next_token (scanner);
2146   if (token != ':')
2147     return ':';
2148   
2149   token = g_scanner_get_next_token (scanner);
2150   switch (token)
2151     {
2152     case GTK_RC_TOKEN_LOWEST:
2153       *priority = GTK_PATH_PRIO_LOWEST;
2154       break;
2155     case GTK_RC_TOKEN_GTK:
2156       *priority = GTK_PATH_PRIO_GTK;
2157       break;
2158     case GTK_RC_TOKEN_APPLICATION:
2159       *priority = GTK_PATH_PRIO_APPLICATION;
2160       break;
2161     case GTK_RC_TOKEN_RC:
2162       *priority = GTK_PATH_PRIO_RC;
2163       break;
2164     case GTK_RC_TOKEN_HIGHEST:
2165       *priority = GTK_PATH_PRIO_HIGHEST;
2166       break;
2167     default:
2168       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
2169     }
2170   
2171   g_scanner_set_scope (scanner, old_scope);
2172
2173   return G_TOKEN_NONE;
2174 }
2175
2176 guint
2177 gtk_rc_parse_color (GScanner *scanner,
2178                     GdkColor *color)
2179 {
2180   guint token;
2181
2182   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2183
2184   /* we don't need to set our own scop here, because
2185    * we don't need own symbols
2186    */
2187   
2188   token = g_scanner_get_next_token (scanner);
2189   switch (token)
2190     {
2191       gint token_int;
2192       gint length;
2193       gint temp;
2194       gchar buf[9];
2195       gint i, j;
2196       
2197     case G_TOKEN_LEFT_CURLY:
2198       token = g_scanner_get_next_token (scanner);
2199       if (token == G_TOKEN_INT)
2200         token_int = scanner->value.v_int;
2201       else if (token == G_TOKEN_FLOAT)
2202         token_int = scanner->value.v_float * 65535.0;
2203       else
2204         return G_TOKEN_FLOAT;
2205       color->red = CLAMP (token_int, 0, 65535);
2206       
2207       token = g_scanner_get_next_token (scanner);
2208       if (token != G_TOKEN_COMMA)
2209         return G_TOKEN_COMMA;
2210       
2211       token = g_scanner_get_next_token (scanner);
2212       if (token == G_TOKEN_INT)
2213         token_int = scanner->value.v_int;
2214       else if (token == G_TOKEN_FLOAT)
2215         token_int = scanner->value.v_float * 65535.0;
2216       else
2217         return G_TOKEN_FLOAT;
2218       color->green = CLAMP (token_int, 0, 65535);
2219       
2220       token = g_scanner_get_next_token (scanner);
2221       if (token != G_TOKEN_COMMA)
2222         return G_TOKEN_COMMA;
2223       
2224       token = g_scanner_get_next_token (scanner);
2225       if (token == G_TOKEN_INT)
2226         token_int = scanner->value.v_int;
2227       else if (token == G_TOKEN_FLOAT)
2228         token_int = scanner->value.v_float * 65535.0;
2229       else
2230         return G_TOKEN_FLOAT;
2231       color->blue = CLAMP (token_int, 0, 65535);
2232       
2233       token = g_scanner_get_next_token (scanner);
2234       if (token != G_TOKEN_RIGHT_CURLY)
2235         return G_TOKEN_RIGHT_CURLY;
2236       return G_TOKEN_NONE;
2237       
2238     case G_TOKEN_STRING:
2239       if (scanner->value.v_string[0] != '#')
2240         return G_TOKEN_STRING;
2241       
2242       length = strlen (scanner->value.v_string) - 1;
2243       if (((length % 3) != 0) || (length > 12))
2244         return G_TOKEN_STRING;
2245       length /= 3;
2246       
2247       for (i = 0, j = 1; i < length; i++, j++)
2248         buf[i] = scanner->value.v_string[j];
2249       buf[i] = '\0';
2250       
2251       sscanf (buf, "%x", &temp);
2252       color->red = temp;
2253       
2254       for (i = 0; i < length; i++, j++)
2255         buf[i] = scanner->value.v_string[j];
2256       buf[i] = '\0';
2257       
2258       sscanf (buf, "%x", &temp);
2259       color->green = temp;
2260       
2261       for (i = 0; i < length; i++, j++)
2262         buf[i] = scanner->value.v_string[j];
2263       buf[i] = '\0';
2264       
2265       sscanf (buf, "%x", &temp);
2266       color->blue = temp;
2267       
2268       if (length == 1)
2269         {
2270           color->red *= 4369;
2271           color->green *= 4369;
2272           color->blue *= 4369;
2273         }
2274       else if (length == 2)
2275         {
2276           color->red *= 257;
2277           color->green *= 257;
2278           color->blue *= 257;
2279         }
2280       else if (length == 3)
2281         {
2282           color->red *= 16;
2283           color->green *= 16;
2284           color->blue *= 16;
2285         }
2286       return G_TOKEN_NONE;
2287       
2288     default:
2289       return G_TOKEN_STRING;
2290     }
2291 }
2292
2293 static guint
2294 gtk_rc_parse_pixmap_path (GScanner *scanner)
2295 {
2296   guint token;
2297   
2298   token = g_scanner_get_next_token (scanner);
2299   if (token != GTK_RC_TOKEN_PIXMAP_PATH)
2300     return GTK_RC_TOKEN_PIXMAP_PATH;
2301   
2302   token = g_scanner_get_next_token (scanner);
2303   if (token != G_TOKEN_STRING)
2304     return G_TOKEN_STRING;
2305   
2306   gtk_rc_parse_pixmap_path_string (scanner->value.v_string);
2307   
2308   return G_TOKEN_NONE;
2309 }
2310
2311 static void
2312 gtk_rc_parse_pixmap_path_string (gchar *pix_path)
2313 {
2314   gchar *buf;
2315   gint end_offset;
2316   gint start_offset = 0;
2317   gint path_len;
2318   gint path_num;
2319   
2320   /* free the old one, or just add to the old one ? */
2321   for (path_num=0; pixmap_path[path_num]; path_num++)
2322     {
2323       g_free (pixmap_path[path_num]);
2324       pixmap_path[path_num] = NULL;
2325     }
2326   
2327   path_num = 0;
2328   
2329   path_len = strlen (pix_path);
2330   
2331   buf = g_strdup (pix_path);
2332   
2333   for (end_offset = 0; end_offset <= path_len; end_offset++)
2334     {
2335       if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2336           (end_offset == path_len))
2337         {
2338           buf[end_offset] = '\0';
2339           pixmap_path[path_num] = g_strdup (buf + start_offset);
2340           path_num++;
2341           pixmap_path[path_num] = NULL;
2342           start_offset = end_offset + 1;
2343         }
2344     }
2345   g_free (buf);
2346 }
2347
2348 static guint
2349 gtk_rc_parse_module_path (GScanner *scanner)
2350 {
2351   guint token;
2352   
2353   token = g_scanner_get_next_token (scanner);
2354   if (token != GTK_RC_TOKEN_MODULE_PATH)
2355     return GTK_RC_TOKEN_MODULE_PATH;
2356   
2357   token = g_scanner_get_next_token (scanner);
2358   if (token != G_TOKEN_STRING)
2359     return G_TOKEN_STRING;
2360   
2361   gtk_rc_parse_module_path_string (scanner->value.v_string);
2362   
2363   return G_TOKEN_NONE;
2364 }
2365
2366 static void
2367 gtk_rc_parse_module_path_string (gchar *mod_path)
2368 {
2369   gchar *buf;
2370   gint end_offset;
2371   gint start_offset = 0;
2372   gint path_len;
2373   gint path_num;
2374   
2375   /* free the old one, or just add to the old one ? */
2376   for (path_num=0; module_path[path_num]; path_num++)
2377     {
2378       g_free (module_path[path_num]);
2379       module_path[path_num] = NULL;
2380     }
2381   
2382   path_num = 0;
2383   
2384   path_len = strlen (mod_path);
2385   
2386   buf = g_strdup (mod_path);
2387   
2388   for (end_offset = 0; end_offset <= path_len; end_offset++)
2389     {
2390       if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2391           (end_offset == path_len))
2392         {
2393           buf[end_offset] = '\0';
2394           module_path[path_num] = g_strdup (buf + start_offset);
2395           path_num++;
2396           module_path[path_num] = NULL;
2397           start_offset = end_offset + 1;
2398         }
2399     }
2400   g_free (buf);
2401   gtk_rc_append_default_module_path();
2402 }
2403
2404 static guint
2405 gtk_rc_parse_path_pattern (GScanner   *scanner)
2406 {
2407   guint token;
2408   GtkPathType path_type;
2409   gchar *pattern;
2410   gboolean is_binding;
2411   GtkPathPriorityType priority = GTK_PATH_PRIO_RC;
2412   
2413   token = g_scanner_get_next_token (scanner);
2414   switch (token)
2415     {
2416     case GTK_RC_TOKEN_WIDGET:
2417       path_type = GTK_PATH_WIDGET;
2418       break;
2419     case GTK_RC_TOKEN_WIDGET_CLASS:
2420       path_type = GTK_PATH_WIDGET_CLASS;
2421       break;
2422     case GTK_RC_TOKEN_CLASS:
2423       path_type = GTK_PATH_CLASS;
2424       break;
2425     default:
2426       return GTK_RC_TOKEN_WIDGET_CLASS;
2427     }
2428   
2429   token = g_scanner_get_next_token (scanner);
2430   if (token != G_TOKEN_STRING)
2431     return G_TOKEN_STRING;
2432
2433   pattern = g_strdup (scanner->value.v_string);
2434
2435   token = g_scanner_get_next_token (scanner);
2436   if (token == GTK_RC_TOKEN_STYLE)
2437     is_binding = FALSE;
2438   else if (token == GTK_RC_TOKEN_BINDING)
2439     {
2440       is_binding = TRUE;
2441       if (g_scanner_peek_next_token (scanner) == ':')
2442         {
2443           token = gtk_rc_parse_priority (scanner, &priority);
2444           if (token != G_TOKEN_NONE)
2445             {
2446               g_free (pattern);
2447               return token;
2448             }
2449         }
2450     }
2451   else
2452     {
2453       g_free (pattern);
2454       return GTK_RC_TOKEN_STYLE;
2455     }
2456   
2457   token = g_scanner_get_next_token (scanner);
2458   if (token != G_TOKEN_STRING)
2459     {
2460       g_free (pattern);
2461       return G_TOKEN_STRING;
2462     }
2463
2464   if (is_binding)
2465     {
2466       GtkBindingSet *binding;
2467
2468       binding = gtk_binding_set_find (scanner->value.v_string);
2469       if (!binding)
2470         {
2471           g_free (pattern);
2472           return G_TOKEN_STRING;
2473         }
2474       gtk_binding_set_add_path (binding, path_type, pattern, priority);
2475     }
2476   else
2477     {
2478       GtkRcStyle *rc_style;
2479       GtkRcSet *rc_set;
2480
2481       rc_style = gtk_rc_style_find (scanner->value.v_string);
2482       
2483       if (!rc_style)
2484         {
2485           g_free (pattern);
2486           return G_TOKEN_STRING;
2487         }
2488
2489       rc_set = g_new (GtkRcSet, 1);
2490       gtk_pattern_spec_init (&rc_set->pspec, pattern);
2491       rc_set->rc_style = rc_style;
2492
2493       if (path_type == GTK_PATH_WIDGET)
2494         gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set);
2495       else if (path_type == GTK_PATH_WIDGET_CLASS)
2496         gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set);
2497       else
2498         gtk_rc_sets_class = g_slist_prepend (gtk_rc_sets_class, rc_set);
2499     }
2500
2501   g_free (pattern);
2502   return G_TOKEN_NONE;
2503 }
2504
2505 /*
2506 typedef  GdkPixmap * (*GtkImageLoader) (GdkWindow   *window,
2507                                         GdkColormap *colormap,
2508                                         GdkBitmap  **mask,
2509                                         GdkColor    *transparent_color,
2510                                         const gchar *filename);
2511 */
2512
2513 void
2514 gtk_rc_set_image_loader(GtkImageLoader loader)
2515 {
2516   image_loader = loader;
2517 }
2518
2519 GdkPixmap *
2520 gtk_rc_load_image (GdkColormap *colormap,
2521                    GdkColor    *transparent_color,
2522                    const gchar *filename)
2523 {
2524   if (strcmp (filename, "<parent>") == 0)
2525     return (GdkPixmap*) GDK_PARENT_RELATIVE;
2526   else
2527     {
2528       if(image_loader)
2529         return image_loader(NULL, colormap, NULL,
2530                             transparent_color,
2531                             filename);
2532       else
2533         return gdk_pixmap_colormap_create_from_xpm (NULL, colormap, NULL,
2534                                                     transparent_color,
2535                                                     filename);
2536     }
2537 }