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