1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
30 #include "gdkconfig.h"
32 #ifdef GDK_WINDOWING_X11
33 #include <X11/Xlocale.h> /* so we get the right setlocale */
42 #ifdef HAVE_SYS_PARAM_H
43 #include <sys/param.h>
55 #include <windows.h> /* For GetWindowsDirectory */
60 #include "gtkbindings.h"
61 #include "gtkthemes.h"
64 typedef struct _GtkRcSet GtkRcSet;
65 typedef struct _GtkRcNode GtkRcNode;
66 typedef struct _GtkRcFile GtkRcFile;
67 typedef struct _GtkRcStylePrivate GtkRcStylePrivate;
79 gchar *canonical_name;
83 struct _GtkRcStylePrivate
88 /* list of RC style lists including this RC style */
89 GSList *rc_style_lists;
92 static guint gtk_rc_style_hash (const char *name);
93 static gint gtk_rc_style_compare (const char *a,
95 static guint gtk_rc_styles_hash (const GSList *rc_styles);
96 static gint gtk_rc_styles_compare (const GSList *a,
98 static GtkRcStyle* gtk_rc_style_find (const char *name);
99 static GSList * gtk_rc_styles_match (GSList *rc_styles,
103 gchar *path_reversed);
104 static GtkStyle * gtk_rc_style_to_style (GtkRcStyle *rc_style);
105 static GtkStyle* gtk_rc_style_init (GSList *rc_styles);
106 static void gtk_rc_parse_file (const gchar *filename,
109 static void gtk_rc_parse_any (const gchar *input_name,
111 const gchar *input_string);
112 static guint gtk_rc_parse_statement (GScanner *scanner);
113 static guint gtk_rc_parse_style (GScanner *scanner);
114 static guint gtk_rc_parse_base (GScanner *scanner,
116 static guint gtk_rc_parse_bg (GScanner *scanner,
118 static guint gtk_rc_parse_fg (GScanner *scanner,
120 static guint gtk_rc_parse_text (GScanner *scanner,
122 static guint gtk_rc_parse_bg_pixmap (GScanner *scanner,
123 GtkRcStyle *rc_style);
124 static guint gtk_rc_parse_font (GScanner *scanner,
125 GtkRcStyle *rc_style);
126 static guint gtk_rc_parse_fontset (GScanner *scanner,
127 GtkRcStyle *rc_style);
128 static guint gtk_rc_parse_engine (GScanner *scanner,
129 GtkRcStyle *rc_style);
130 static guint gtk_rc_parse_pixmap_path (GScanner *scanner);
131 static void gtk_rc_parse_pixmap_path_string (gchar *pix_path);
132 static guint gtk_rc_parse_module_path (GScanner *scanner);
133 static void gtk_rc_parse_module_path_string (gchar *mod_path);
134 static guint gtk_rc_parse_path_pattern (GScanner *scanner);
135 static void gtk_rc_clear_hash_node (gpointer key,
138 static void gtk_rc_clear_styles (void);
139 static void gtk_rc_append_default_pixmap_path (void);
140 static void gtk_rc_append_default_module_path (void);
141 static void gtk_rc_add_initial_default_files (void);
144 static const GScannerConfig gtk_rc_scanner_config =
148 ) /* cset_skip_characters */,
153 ) /* cset_identifier_first */,
158 ) /* cset_identifier_nth */,
159 ( "#\n" ) /* cpair_comment_single */,
161 TRUE /* case_sensitive */,
163 TRUE /* skip_comment_multi */,
164 TRUE /* skip_comment_single */,
165 TRUE /* scan_comment_multi */,
166 TRUE /* scan_identifier */,
167 FALSE /* scan_identifier_1char */,
168 FALSE /* scan_identifier_NULL */,
169 TRUE /* scan_symbols */,
170 TRUE /* scan_binary */,
171 TRUE /* scan_octal */,
172 TRUE /* scan_float */,
174 TRUE /* scan_hex_dollar */,
175 TRUE /* scan_string_sq */,
176 TRUE /* scan_string_dq */,
177 TRUE /* numbers_2_int */,
178 FALSE /* int_2_float */,
179 FALSE /* identifier_2_string */,
180 TRUE /* char_2_token */,
181 TRUE /* symbol_2_token */,
182 FALSE /* scope_0_fallback */,
190 { "include", GTK_RC_TOKEN_INCLUDE },
191 { "NORMAL", GTK_RC_TOKEN_NORMAL },
192 { "ACTIVE", GTK_RC_TOKEN_ACTIVE },
193 { "PRELIGHT", GTK_RC_TOKEN_PRELIGHT },
194 { "SELECTED", GTK_RC_TOKEN_SELECTED },
195 { "INSENSITIVE", GTK_RC_TOKEN_INSENSITIVE },
196 { "fg", GTK_RC_TOKEN_FG },
197 { "bg", GTK_RC_TOKEN_BG },
198 { "base", GTK_RC_TOKEN_BASE },
199 { "text", GTK_RC_TOKEN_TEXT },
200 { "font", GTK_RC_TOKEN_FONT },
201 { "fontset", GTK_RC_TOKEN_FONTSET },
202 { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP },
203 { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH },
204 { "style", GTK_RC_TOKEN_STYLE },
205 { "binding", GTK_RC_TOKEN_BINDING },
206 { "bind", GTK_RC_TOKEN_BIND },
207 { "widget", GTK_RC_TOKEN_WIDGET },
208 { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS },
209 { "class", GTK_RC_TOKEN_CLASS },
210 { "lowest", GTK_RC_TOKEN_LOWEST },
211 { "gtk", GTK_RC_TOKEN_GTK },
212 { "application", GTK_RC_TOKEN_APPLICATION },
213 { "rc", GTK_RC_TOKEN_RC },
214 { "highest", GTK_RC_TOKEN_HIGHEST },
215 { "engine", GTK_RC_TOKEN_ENGINE },
216 { "module_path", GTK_RC_TOKEN_MODULE_PATH },
219 static const guint n_symbols = sizeof (symbols) / sizeof (symbols[0]);
221 static GHashTable *rc_style_ht = NULL;
222 static GHashTable *realized_style_ht = NULL;
223 static GSList *gtk_rc_sets_widget = NULL;
224 static GSList *gtk_rc_sets_widget_class = NULL;
225 static GSList *gtk_rc_sets_class = NULL;
227 #define GTK_RC_MAX_DEFAULT_FILES 128
228 static gchar *gtk_rc_default_files[GTK_RC_MAX_DEFAULT_FILES];
229 static gboolean gtk_rc_auto_parse = TRUE;
231 #define GTK_RC_MAX_PIXMAP_PATHS 128
232 static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
233 #define GTK_RC_MAX_MODULE_PATHS 128
234 static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
236 /* A stack of directories for RC files we are parsing currently.
237 * these are implicitely added to the end of PIXMAP_PATHS
239 GSList *rc_dir_stack = NULL;
241 /* The files we have parsed, to reread later if necessary */
242 GSList *rc_files = NULL;
244 static GtkImageLoader image_loader = NULL;
246 /* RC file handling */
252 get_gtk_sysconf_directory (void)
254 static gchar gtk_sysconf_dir[200];
257 GetWindowsDirectory (win_dir, sizeof (win_dir));
258 sprintf (gtk_sysconf_dir, "%s\\gtk+", win_dir);
259 return gtk_sysconf_dir;
263 get_themes_directory (void)
265 /* We really should fetch this from the Registry. The GIMP
266 * installation program stores the Themes installation
267 * directory in HKLM\Software\GNU\GTk+\Themes\InstallDirectory.
270 static gchar themes_dir[200];
272 sprintf (themes_dir, "%s\\themes", get_gtk_sysconf_directory ());
279 gtk_rc_get_theme_dir(void)
284 var = getenv("GTK_DATA_PREFIX");
286 path = g_strdup_printf("%s%s", var, "/share/themes");
288 path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/themes");
290 path = g_strdup (get_themes_directory ());
297 gtk_rc_get_module_dir(void)
302 var = getenv("GTK_EXE_PREFIX");
304 path = g_strdup_printf("%s%s", var, "/lib/gtk/themes/engines");
306 path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk/themes/engines");
308 path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
315 gtk_rc_append_default_pixmap_path(void)
321 var = getenv("GTK_DATA_PREFIX");
323 path = g_strdup_printf("%s%s", var, "/share/gtk/themes");
325 path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/gtk/themes");
327 path = g_strdup (get_themes_directory ());
330 for (n = 0; pixmap_path[n]; n++) ;
331 if (n >= GTK_RC_MAX_PIXMAP_PATHS - 1)
336 pixmap_path[n++] = path;
337 pixmap_path[n] = NULL;
341 gtk_rc_append_default_module_path(void)
346 for (n = 0; module_path[n]; n++) ;
347 if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
351 var = getenv("GTK_EXE_PREFIX");
353 path = g_strdup_printf("%s%s", var, "/lib/gtk/themes/engines");
355 path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk/themes/engines");
357 path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
359 module_path[n++] = path;
361 var = g_get_home_dir ();
365 path = g_strdup_printf ("%s%s", var, "/.gtk/lib/themes/engines");
367 path = g_strdup_printf ("%s%s", var, "\\_gtk\\themes\\engines");
369 module_path[n++] = path;
371 module_path[n] = NULL;
375 gtk_rc_add_initial_default_files (void)
377 static gint init = FALSE;
385 gtk_rc_default_files[0] = NULL;
388 var = g_getenv("GTK_RC_FILES");
391 files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
395 gtk_rc_add_default_file (files[i]);
403 str = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk" G_DIR_SEPARATOR_S "gtkrc");
405 str = g_strdup_printf ("%s\\gtkrc", get_gtk_sysconf_directory ());
407 gtk_rc_add_default_file (str);
410 var = g_get_home_dir ();
413 str = g_strdup_printf ("%s" G_DIR_SEPARATOR_S ".gtkrc", var);
414 gtk_rc_add_default_file (str);
421 gtk_rc_add_default_file (const gchar *file)
425 gtk_rc_add_initial_default_files ();
427 for (n = 0; gtk_rc_default_files[n]; n++) ;
428 if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
431 gtk_rc_default_files[n++] = g_strdup (file);
432 gtk_rc_default_files[n] = NULL;
436 gtk_rc_set_default_files (gchar **files)
440 gtk_rc_add_initial_default_files ();
443 while (gtk_rc_default_files[i])
445 g_free (gtk_rc_default_files[i]);
449 gtk_rc_default_files[0] = NULL;
450 gtk_rc_auto_parse = FALSE;
453 while (files[i] != NULL)
455 gtk_rc_add_default_file (files[i]);
461 gtk_rc_get_default_files (void)
463 gtk_rc_add_initial_default_files ();
465 return gtk_rc_default_files;
468 /* The following routine is based on _nl_normalize_codeset from
469 * the GNU C library. Contributed by
471 * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
472 * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
474 * Normalize codeset name. There is no standard for the codeset
475 * names. Normalization allows the user to use any of the common
479 _gtk_normalize_codeset (const char *codeset, int name_len)
487 for (cnt = 0; cnt < name_len; ++cnt)
488 if (isalnum (codeset[cnt]))
492 if (isalpha (codeset[cnt]))
496 retval = g_malloc ((only_digit ? 3 : 0) + len + 1);
500 strcpy (retval, "iso");
506 for (cnt = 0; cnt < name_len; ++cnt)
507 if (isalpha (codeset[cnt]))
508 *wp++ = isupper(codeset[cnt]) ? tolower (codeset[cnt]) : codeset[cnt];
509 else if (isdigit (codeset[cnt]))
510 *wp++ = codeset[cnt];
520 static gchar *locale_suffixes[3];
521 static gint n_locale_suffixes = 0;
525 static gboolean initted = FALSE;
534 locale = g_win32_getlocale ();
536 locale = setlocale (LC_CTYPE, NULL);
541 pixmap_path[0] = NULL;
542 module_path[0] = NULL;
543 gtk_rc_append_default_pixmap_path();
544 gtk_rc_append_default_module_path();
546 gtk_rc_add_initial_default_files ();
548 if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
550 /* Determine locale-specific suffixes for RC files
552 * We normalize the charset into a standard form,
553 * which has all '-' and '_' characters removed,
556 gchar *normalized_locale;
558 p = strchr (locale, '@');
559 length = p ? (p -locale) : strlen (locale);
561 p = strchr (locale, '.');
564 gchar *tmp1 = g_strndup (locale, p - locale + 1);
565 gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
567 normalized_locale = g_strconcat (tmp1, tmp2, NULL);
571 locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
575 normalized_locale = g_strndup (locale, length);
577 p = strchr (normalized_locale, '_');
580 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
581 length = p - normalized_locale;
584 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
586 g_free (normalized_locale);
591 while (gtk_rc_default_files[i] != NULL)
593 /* Try to find a locale specific RC file corresponding to
594 * to parse before the default file.
596 for (j=n_locale_suffixes-1; j>=0; j--)
598 gchar *name = g_strconcat (gtk_rc_default_files[i],
606 gtk_rc_parse (gtk_rc_default_files[i]);
612 gtk_rc_parse_string (const gchar *rc_string)
614 g_return_if_fail (rc_string != NULL);
616 gtk_rc_parse_any ("-", -1, rc_string);
620 gtk_rc_parse_file (const gchar *filename, gboolean reload)
622 GtkRcFile *rc_file = NULL;
626 g_return_if_fail (filename != NULL);
631 rc_file = tmp_list->data;
632 if (!strcmp (rc_file->name, filename))
635 tmp_list = tmp_list->next;
640 rc_file = g_new (GtkRcFile, 1);
641 rc_file->name = g_strdup (filename);
642 rc_file->canonical_name = NULL;
644 rc_file->reload = reload;
646 rc_files = g_slist_append (rc_files, rc_file);
649 if (!rc_file->canonical_name)
651 /* Get the absolute pathname */
653 if (g_path_is_absolute (rc_file->name))
654 rc_file->canonical_name = rc_file->name;
660 cwd = g_get_current_dir ();
662 str = g_string_new (cwd);
664 g_string_append_c (str, G_DIR_SEPARATOR);
665 g_string_append (str, rc_file->name);
667 rc_file->canonical_name = str->str;
668 g_string_free (str, FALSE);
672 if (!lstat (rc_file->canonical_name, &statbuf))
677 rc_file->mtime = statbuf.st_mtime;
679 fd = open (rc_file->canonical_name, O_RDONLY);
683 /* Temporarily push directory name for this file on
684 * a stack of directory names while parsing it
686 rc_dir_stack = g_slist_prepend (rc_dir_stack,
687 g_dirname (rc_file->canonical_name));
688 gtk_rc_parse_any (filename, fd, NULL);
690 tmp_list = rc_dir_stack;
691 rc_dir_stack = rc_dir_stack->next;
693 g_free (tmp_list->data);
694 g_slist_free_1 (tmp_list);
701 gtk_rc_parse (const gchar *filename)
703 g_return_if_fail (filename != NULL);
705 gtk_rc_parse_file (filename, TRUE);
708 /* Handling of RC styles */
711 gtk_rc_style_new (void)
713 GtkRcStylePrivate *new_style;
715 new_style = g_new0 (GtkRcStylePrivate, 1);
716 new_style->ref_count = 1;
718 return (GtkRcStyle *)new_style;
722 gtk_rc_style_ref (GtkRcStyle *rc_style)
724 g_return_if_fail (rc_style != NULL);
726 ((GtkRcStylePrivate *)rc_style)->ref_count++;
729 /* Like g_slist_remove, but remove all copies of data */
731 gtk_rc_slist_remove_all (GSList *list,
742 if (tmp->data == data)
748 prev->next = tmp->next;
750 g_slist_free_1 (tmp);
768 gtk_rc_style_unref (GtkRcStyle *rc_style)
770 GtkRcStylePrivate *private = (GtkRcStylePrivate *)rc_style;
773 g_return_if_fail (rc_style != NULL);
774 g_return_if_fail (private->ref_count > 0);
776 private->ref_count--;
778 if (private->ref_count == 0)
780 GSList *tmp_list1, *tmp_list2;
782 if (rc_style->engine)
784 rc_style->engine->destroy_rc_style (rc_style);
785 gtk_theme_engine_unref (rc_style->engine);
789 g_free (rc_style->name);
790 if (rc_style->fontset_name)
791 g_free (rc_style->fontset_name);
792 if (rc_style->font_name)
793 g_free (rc_style->font_name);
795 for (i=0 ; i<5 ; i++)
796 if (rc_style->bg_pixmap_name[i])
797 g_free (rc_style->bg_pixmap_name[i]);
799 /* Now remove all references to this rc_style from
802 tmp_list1 = private->rc_style_lists;
805 GSList *rc_styles = tmp_list1->data;
806 GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
807 gtk_style_unref (style);
809 /* Remove the list of styles from the other rc_styles
812 tmp_list2 = rc_styles;
815 GtkRcStylePrivate *other_style = tmp_list2->data;
817 if (other_style != private)
818 other_style->rc_style_lists =
819 gtk_rc_slist_remove_all (other_style->rc_style_lists, rc_styles);
821 tmp_list2 = tmp_list2->next;
824 /* And from the hash table itself
826 g_hash_table_remove (realized_style_ht, rc_styles);
827 g_slist_free (rc_styles);
829 tmp_list1 = tmp_list1->next;
831 g_slist_free (private->rc_style_lists);
838 gtk_rc_clear_hash_node (gpointer key,
842 gtk_rc_style_unref (data);
846 gtk_rc_free_rc_sets (GSList *slist)
852 rc_set = slist->data;
853 gtk_pattern_spec_free_segs (&rc_set->pspec);
861 gtk_rc_clear_styles (void)
863 /* Clear out all old rc_styles */
867 g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
868 g_hash_table_destroy (rc_style_ht);
872 gtk_rc_free_rc_sets (gtk_rc_sets_widget);
873 g_slist_free (gtk_rc_sets_widget);
874 gtk_rc_sets_widget = NULL;
876 gtk_rc_free_rc_sets (gtk_rc_sets_widget_class);
877 g_slist_free (gtk_rc_sets_widget_class);
878 gtk_rc_sets_widget_class = NULL;
880 gtk_rc_free_rc_sets (gtk_rc_sets_class);
881 g_slist_free (gtk_rc_sets_class);
882 gtk_rc_sets_class = NULL;
886 gtk_rc_reparse_all (void)
889 gboolean mtime_modified = FALSE;
894 /* Check through and see if any of the RC's have had their
895 * mtime modified. If so, reparse everything.
900 rc_file = tmp_list->data;
902 if (!lstat (rc_file->name, &statbuf) &&
903 (statbuf.st_mtime > rc_file->mtime))
905 mtime_modified = TRUE;
909 tmp_list = tmp_list->next;
914 gtk_rc_clear_styles();
919 rc_file = tmp_list->data;
921 gtk_rc_parse_file (rc_file->name, FALSE);
923 tmp_list = tmp_list->next;
927 return mtime_modified;
931 gtk_rc_styles_match (GSList *rc_styles,
935 gchar *path_reversed)
945 if (gtk_pattern_match (&rc_set->pspec, path_length, path, path_reversed))
946 rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
953 gtk_rc_get_style (GtkWidget *widget)
955 GtkRcStyle *widget_rc_style;
956 GSList *rc_styles = NULL;
958 static guint rc_style_key_id = 0;
960 /* We allow the specification of a single rc style to be bound
961 * tightly to a widget, for application modifications
963 if (!rc_style_key_id)
964 rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
966 widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
970 rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
972 if (gtk_rc_sets_widget)
974 gchar *path, *path_reversed;
977 gtk_widget_path (widget, &path_length, &path, &path_reversed);
978 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget, path_length, path, path_reversed);
980 g_free (path_reversed);
984 if (gtk_rc_sets_widget_class)
986 gchar *path, *path_reversed;
989 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
990 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget_class, path_length, path, path_reversed);
992 g_free (path_reversed);
995 if (gtk_rc_sets_class)
999 type = GTK_OBJECT_TYPE (widget);
1002 gchar *path, *path_reversed;
1005 path = gtk_type_name (type);
1006 path_length = strlen (path);
1007 path_reversed = g_strdup (path);
1008 g_strreverse (path_reversed);
1010 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_class, path_length, path, path_reversed);
1011 g_free (path_reversed);
1013 type = gtk_type_parent (type);
1018 return gtk_rc_style_init (rc_styles);
1024 gtk_rc_add_rc_sets (GSList *slist,
1025 GtkRcStyle *rc_style,
1026 const char *pattern)
1028 GtkRcStyle *new_style;
1032 new_style = gtk_rc_style_new ();
1033 *new_style = *rc_style;
1034 new_style->name = g_strdup (rc_style->name);
1035 new_style->font_name = g_strdup (rc_style->font_name);
1036 new_style->fontset_name = g_strdup (rc_style->fontset_name);
1038 for (i = 0; i < 5; i++)
1039 new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1041 rc_set = g_new (GtkRcSet, 1);
1042 gtk_pattern_spec_init (&rc_set->pspec, pattern);
1043 rc_set->rc_style = rc_style;
1045 return g_slist_prepend (slist, rc_set);
1049 gtk_rc_add_widget_name_style (GtkRcStyle *rc_style,
1050 const gchar *pattern)
1052 g_return_if_fail (rc_style != NULL);
1053 g_return_if_fail (pattern != NULL);
1055 gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, rc_style, pattern);
1059 gtk_rc_add_widget_class_style (GtkRcStyle *rc_style,
1060 const gchar *pattern)
1062 g_return_if_fail (rc_style != NULL);
1063 g_return_if_fail (pattern != NULL);
1065 gtk_rc_sets_widget_class = gtk_rc_add_rc_sets (gtk_rc_sets_widget_class, rc_style, pattern);
1069 gtk_rc_add_class_style (GtkRcStyle *rc_style,
1070 const gchar *pattern)
1072 g_return_if_fail (rc_style != NULL);
1073 g_return_if_fail (pattern != NULL);
1075 gtk_rc_sets_class = gtk_rc_add_rc_sets (gtk_rc_sets_class, rc_style, pattern);
1079 gtk_rc_parse_any (const gchar *input_name,
1081 const gchar *input_string)
1087 scanner = g_scanner_new ((GScannerConfig *) >k_rc_scanner_config);
1091 g_assert (input_string == NULL);
1093 g_scanner_input_file (scanner, input_fd);
1097 g_assert (input_string != NULL);
1099 g_scanner_input_text (scanner, input_string, strlen (input_string));
1101 scanner->input_name = input_name;
1103 g_scanner_freeze_symbol_table (scanner);
1104 for (i = 0; i < n_symbols; i++)
1105 g_scanner_add_symbol (scanner, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1106 g_scanner_thaw_symbol_table (scanner);
1111 if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1115 guint expected_token;
1117 expected_token = gtk_rc_parse_statement (scanner);
1119 if (expected_token != G_TOKEN_NONE)
1126 if (scanner->scope_id == 0)
1128 /* if we are in scope 0, we know the symbol names
1129 * that are associated with certaintoken values.
1130 * so we look them up to make the error messages
1133 if (expected_token > GTK_RC_TOKEN_INVALID &&
1134 expected_token < GTK_RC_TOKEN_LAST)
1136 for (i = 0; i < n_symbols; i++)
1137 if (symbols[i].token == expected_token)
1138 msg = symbols[i].name;
1140 msg = g_strconcat ("e.g. `", msg, "'", NULL);
1142 if (scanner->token > GTK_RC_TOKEN_INVALID &&
1143 scanner->token < GTK_RC_TOKEN_LAST)
1145 symbol_name = "???";
1146 for (i = 0; i < n_symbols; i++)
1147 if (symbols[i].token == scanner->token)
1148 symbol_name = symbols[i].name;
1151 g_scanner_unexp_token (scanner,
1164 g_scanner_destroy (scanner);
1168 gtk_rc_styles_hash (const GSList *rc_styles)
1175 result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1176 rc_styles = rc_styles->next;
1183 gtk_rc_styles_compare (const GSList *a,
1188 if (a->data != b->data)
1198 gtk_rc_style_hash (const char *name)
1204 result += (result << 3) + *name++;
1210 gtk_rc_style_compare (const char *a,
1213 return (strcmp (a, b) == 0);
1217 gtk_rc_style_find (const char *name)
1220 return g_hash_table_lookup (rc_style_ht, (gpointer) name);
1225 /* Assumes ownership of rc_style */
1227 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1233 style = gtk_style_new ();
1235 style->rc_style = rc_style;
1237 if (rc_style->fontset_name)
1239 old_font = style->font;
1240 style->font = gdk_fontset_load (rc_style->fontset_name);
1242 gdk_font_unref (old_font);
1244 style->font = old_font;
1246 else if (rc_style->font_name)
1248 old_font = style->font;
1249 style->font = gdk_font_load (rc_style->font_name);
1251 gdk_font_unref (old_font);
1253 style->font = old_font;
1256 for (i = 0; i < 5; i++)
1258 if (rc_style->color_flags[i] & GTK_RC_FG)
1259 style->fg[i] = rc_style->fg[i];
1260 if (rc_style->color_flags[i] & GTK_RC_BG)
1261 style->bg[i] = rc_style->bg[i];
1262 if (rc_style->color_flags[i] & GTK_RC_TEXT)
1263 style->text[i] = rc_style->text[i];
1264 if (rc_style->color_flags[i] & GTK_RC_BASE)
1265 style->base[i] = rc_style->base[i];
1268 if (rc_style->engine)
1270 style->engine = rc_style->engine;
1271 gtk_theme_engine_ref (style->engine);
1272 rc_style->engine->rc_style_to_style (style, rc_style);
1278 /* Reuses or frees rc_styles */
1280 gtk_rc_style_init (GSList *rc_styles)
1284 GtkStyle *style = NULL;
1286 if (!realized_style_ht)
1287 realized_style_ht = g_hash_table_new ((GHashFunc)gtk_rc_styles_hash,
1288 (GCompareFunc)gtk_rc_styles_compare);
1290 style = g_hash_table_lookup (realized_style_ht, rc_styles);
1294 GtkRcStyle *proto_style;
1297 proto_style = gtk_rc_style_new ();
1299 tmp_styles = rc_styles;
1302 GtkRcStyle *rc_style = tmp_styles->data;
1303 GtkRcStylePrivate *rc_style_private;
1307 if (!proto_style->bg_pixmap_name[i] && rc_style->bg_pixmap_name[i])
1308 proto_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1310 if (!(proto_style->color_flags[i] & GTK_RC_FG) &&
1311 rc_style->color_flags[i] & GTK_RC_FG)
1313 proto_style->fg[i] = rc_style->fg[i];
1314 proto_style->color_flags[i] |= GTK_RC_FG;
1316 if (!(proto_style->color_flags[i] & GTK_RC_BG) &&
1317 rc_style->color_flags[i] & GTK_RC_BG)
1319 proto_style->bg[i] = rc_style->bg[i];
1320 proto_style->color_flags[i] |= GTK_RC_BG;
1322 if (!(proto_style->color_flags[i] & GTK_RC_TEXT) &&
1323 rc_style->color_flags[i] & GTK_RC_TEXT)
1325 proto_style->text[i] = rc_style->text[i];
1326 proto_style->color_flags[i] |= GTK_RC_TEXT;
1328 if (!(proto_style->color_flags[i] & GTK_RC_BASE) &&
1329 rc_style->color_flags[i] & GTK_RC_BASE)
1331 proto_style->base[i] = rc_style->base[i];
1332 proto_style->color_flags[i] |= GTK_RC_BASE;
1336 if (!proto_style->font_name && rc_style->font_name)
1337 proto_style->font_name = g_strdup (rc_style->font_name);
1338 if (!proto_style->fontset_name && rc_style->fontset_name)
1339 proto_style->fontset_name = g_strdup (rc_style->fontset_name);
1341 if (!proto_style->engine && rc_style->engine)
1343 proto_style->engine = rc_style->engine;
1344 gtk_theme_engine_ref (proto_style->engine);
1347 if (proto_style->engine &&
1348 (proto_style->engine == rc_style->engine))
1349 proto_style->engine->merge_rc_style (proto_style, rc_style);
1351 /* Point from each rc_style to the list of styles */
1353 rc_style_private = (GtkRcStylePrivate *)rc_style;
1354 if (!g_slist_find (rc_style_private->rc_style_lists, rc_styles))
1355 rc_style_private->rc_style_lists = g_slist_prepend (rc_style_private->rc_style_lists, rc_styles);
1357 tmp_styles = tmp_styles->next;
1361 if (proto_style->bg_pixmap_name[i] &&
1362 (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1364 g_free (proto_style->bg_pixmap_name[i]);
1365 proto_style->bg_pixmap_name[i] = NULL;
1368 style = gtk_rc_style_to_style (proto_style);
1370 g_hash_table_insert (realized_style_ht, rc_styles, style);
1373 g_slist_free (rc_styles);
1378 /*********************
1379 * Parsing functions *
1380 *********************/
1383 gtk_rc_parse_statement (GScanner *scanner)
1387 token = g_scanner_peek_next_token (scanner);
1391 case GTK_RC_TOKEN_INCLUDE:
1392 token = g_scanner_get_next_token (scanner);
1393 if (token != GTK_RC_TOKEN_INCLUDE)
1394 return GTK_RC_TOKEN_INCLUDE;
1396 token = g_scanner_get_next_token (scanner);
1397 if (token != G_TOKEN_STRING)
1398 return G_TOKEN_STRING;
1400 gtk_rc_parse_file (scanner->value.v_string, FALSE);
1401 return G_TOKEN_NONE;
1403 case GTK_RC_TOKEN_STYLE:
1404 return gtk_rc_parse_style (scanner);
1406 case GTK_RC_TOKEN_BINDING:
1407 return gtk_binding_parse_binding (scanner);
1409 case GTK_RC_TOKEN_PIXMAP_PATH:
1410 return gtk_rc_parse_pixmap_path (scanner);
1412 case GTK_RC_TOKEN_WIDGET:
1413 return gtk_rc_parse_path_pattern (scanner);
1415 case GTK_RC_TOKEN_WIDGET_CLASS:
1416 return gtk_rc_parse_path_pattern (scanner);
1418 case GTK_RC_TOKEN_CLASS:
1419 return gtk_rc_parse_path_pattern (scanner);
1421 case GTK_RC_TOKEN_MODULE_PATH:
1422 return gtk_rc_parse_module_path (scanner);
1425 g_scanner_get_next_token (scanner);
1426 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
1431 gtk_rc_parse_style (GScanner *scanner)
1433 GtkRcStyle *rc_style;
1434 GtkRcStyle *parent_style;
1439 token = g_scanner_get_next_token (scanner);
1440 if (token != GTK_RC_TOKEN_STYLE)
1441 return GTK_RC_TOKEN_STYLE;
1443 token = g_scanner_get_next_token (scanner);
1444 if (token != G_TOKEN_STRING)
1445 return G_TOKEN_STRING;
1448 rc_style = gtk_rc_style_find (scanner->value.v_string);
1453 rc_style = gtk_rc_style_new ();
1454 rc_style->name = g_strdup (scanner->value.v_string);
1456 for (i = 0; i < 5; i++)
1457 rc_style->bg_pixmap_name[i] = NULL;
1459 for (i = 0; i < 5; i++)
1460 rc_style->color_flags[i] = 0;
1462 rc_style->engine = NULL;
1463 rc_style->engine_data = NULL;
1466 token = g_scanner_peek_next_token (scanner);
1467 if (token == G_TOKEN_EQUAL_SIGN)
1469 token = g_scanner_get_next_token (scanner);
1471 token = g_scanner_get_next_token (scanner);
1472 if (token != G_TOKEN_STRING)
1477 return G_TOKEN_STRING;
1480 parent_style = gtk_rc_style_find (scanner->value.v_string);
1483 for (i = 0; i < 5; i++)
1485 rc_style->color_flags[i] = parent_style->color_flags[i];
1486 rc_style->fg[i] = parent_style->fg[i];
1487 rc_style->bg[i] = parent_style->bg[i];
1488 rc_style->text[i] = parent_style->text[i];
1489 rc_style->base[i] = parent_style->base[i];
1492 if (parent_style->fontset_name)
1494 if (rc_style->fontset_name)
1495 g_free (rc_style->fontset_name);
1496 rc_style->fontset_name = g_strdup (parent_style->fontset_name);
1498 else if (parent_style->font_name)
1500 if (rc_style->font_name)
1501 g_free (rc_style->font_name);
1502 rc_style->font_name = g_strdup (parent_style->font_name);
1505 for (i = 0; i < 5; i++)
1507 if (rc_style->bg_pixmap_name[i])
1508 g_free (rc_style->bg_pixmap_name[i]);
1509 rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
1514 token = g_scanner_get_next_token (scanner);
1515 if (token != G_TOKEN_LEFT_CURLY)
1520 return G_TOKEN_LEFT_CURLY;
1523 token = g_scanner_peek_next_token (scanner);
1524 while (token != G_TOKEN_RIGHT_CURLY)
1528 case GTK_RC_TOKEN_BASE:
1529 token = gtk_rc_parse_base (scanner, rc_style);
1531 case GTK_RC_TOKEN_BG:
1532 token = gtk_rc_parse_bg (scanner, rc_style);
1534 case GTK_RC_TOKEN_FG:
1535 token = gtk_rc_parse_fg (scanner, rc_style);
1537 case GTK_RC_TOKEN_TEXT:
1538 token = gtk_rc_parse_text (scanner, rc_style);
1540 case GTK_RC_TOKEN_BG_PIXMAP:
1541 token = gtk_rc_parse_bg_pixmap (scanner, rc_style);
1543 case GTK_RC_TOKEN_FONT:
1544 token = gtk_rc_parse_font (scanner, rc_style);
1546 case GTK_RC_TOKEN_FONTSET:
1547 token = gtk_rc_parse_fontset (scanner, rc_style);
1549 case GTK_RC_TOKEN_ENGINE:
1550 token = gtk_rc_parse_engine (scanner, rc_style);
1553 g_scanner_get_next_token (scanner);
1554 token = G_TOKEN_RIGHT_CURLY;
1558 if (token != G_TOKEN_NONE)
1562 if (rc_style->fontset_name)
1563 g_free (rc_style->fontset_name);
1564 if (rc_style->font_name)
1565 g_free (rc_style->font_name);
1566 for (i = 0; i < 5; i++)
1567 if (rc_style->bg_pixmap_name[i])
1568 g_free (rc_style->bg_pixmap_name[i]);
1573 token = g_scanner_peek_next_token (scanner);
1576 token = g_scanner_get_next_token (scanner);
1577 if (token != G_TOKEN_RIGHT_CURLY)
1581 if (rc_style->fontset_name)
1582 g_free (rc_style->fontset_name);
1583 if (rc_style->font_name)
1584 g_free (rc_style->font_name);
1586 for (i = 0; i < 5; i++)
1587 if (rc_style->bg_pixmap_name[i])
1588 g_free (rc_style->bg_pixmap_name[i]);
1592 return G_TOKEN_RIGHT_CURLY;
1598 rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
1599 (GCompareFunc) gtk_rc_style_compare);
1601 g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
1604 return G_TOKEN_NONE;
1608 gtk_rc_parse_base (GScanner *scanner,
1614 token = g_scanner_get_next_token (scanner);
1615 if (token != GTK_RC_TOKEN_BASE)
1616 return GTK_RC_TOKEN_BASE;
1618 token = gtk_rc_parse_state (scanner, &state);
1619 if (token != G_TOKEN_NONE)
1622 token = g_scanner_get_next_token (scanner);
1623 if (token != G_TOKEN_EQUAL_SIGN)
1624 return G_TOKEN_EQUAL_SIGN;
1626 style->color_flags[state] |= GTK_RC_BASE;
1627 return gtk_rc_parse_color (scanner, &style->base[state]);
1631 gtk_rc_parse_bg (GScanner *scanner,
1637 token = g_scanner_get_next_token (scanner);
1638 if (token != GTK_RC_TOKEN_BG)
1639 return GTK_RC_TOKEN_BG;
1641 token = gtk_rc_parse_state (scanner, &state);
1642 if (token != G_TOKEN_NONE)
1645 token = g_scanner_get_next_token (scanner);
1646 if (token != G_TOKEN_EQUAL_SIGN)
1647 return G_TOKEN_EQUAL_SIGN;
1649 style->color_flags[state] |= GTK_RC_BG;
1650 return gtk_rc_parse_color (scanner, &style->bg[state]);
1654 gtk_rc_parse_fg (GScanner *scanner,
1660 token = g_scanner_get_next_token (scanner);
1661 if (token != GTK_RC_TOKEN_FG)
1662 return GTK_RC_TOKEN_FG;
1664 token = gtk_rc_parse_state (scanner, &state);
1665 if (token != G_TOKEN_NONE)
1668 token = g_scanner_get_next_token (scanner);
1669 if (token != G_TOKEN_EQUAL_SIGN)
1670 return G_TOKEN_EQUAL_SIGN;
1672 style->color_flags[state] |= GTK_RC_FG;
1673 return gtk_rc_parse_color (scanner, &style->fg[state]);
1677 gtk_rc_parse_text (GScanner *scanner,
1683 token = g_scanner_get_next_token (scanner);
1684 if (token != GTK_RC_TOKEN_TEXT)
1685 return GTK_RC_TOKEN_TEXT;
1687 token = gtk_rc_parse_state (scanner, &state);
1688 if (token != G_TOKEN_NONE)
1691 token = g_scanner_get_next_token (scanner);
1692 if (token != G_TOKEN_EQUAL_SIGN)
1693 return G_TOKEN_EQUAL_SIGN;
1695 style->color_flags[state] |= GTK_RC_TEXT;
1696 return gtk_rc_parse_color (scanner, &style->text[state]);
1700 gtk_rc_parse_bg_pixmap (GScanner *scanner,
1701 GtkRcStyle *rc_style)
1707 token = g_scanner_get_next_token (scanner);
1708 if (token != GTK_RC_TOKEN_BG_PIXMAP)
1709 return GTK_RC_TOKEN_BG_PIXMAP;
1711 token = gtk_rc_parse_state (scanner, &state);
1712 if (token != G_TOKEN_NONE)
1715 token = g_scanner_get_next_token (scanner);
1716 if (token != G_TOKEN_EQUAL_SIGN)
1717 return G_TOKEN_EQUAL_SIGN;
1719 token = g_scanner_get_next_token (scanner);
1720 if (token != G_TOKEN_STRING)
1721 return G_TOKEN_STRING;
1723 if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
1724 (strcmp (scanner->value.v_string, "<none>") == 0))
1725 pixmap_file = g_strdup (scanner->value.v_string);
1727 pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
1731 if (rc_style->bg_pixmap_name[state])
1732 g_free (rc_style->bg_pixmap_name[state]);
1733 rc_style->bg_pixmap_name[state] = pixmap_file;
1736 return G_TOKEN_NONE;
1740 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
1745 buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", dir, pixmap_file);
1747 fd = open (buf, O_RDONLY);
1760 gtk_rc_find_pixmap_in_path (GScanner *scanner,
1761 const gchar *pixmap_file)
1767 for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
1769 filename = gtk_rc_check_pixmap_dir (pixmap_path[i], pixmap_file);
1774 tmp_list = rc_dir_stack;
1777 filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
1781 tmp_list = tmp_list->next;
1785 g_warning (_("Unable to locate image file in pixmap_path: \"%s\" line %d"),
1786 pixmap_file, scanner->line);
1788 g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
1795 gtk_rc_find_module_in_path (const gchar *module_file)
1801 for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
1803 buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
1804 module_path[i], module_file);
1806 fd = open (buf, O_RDONLY);
1820 gtk_rc_parse_font (GScanner *scanner,
1821 GtkRcStyle *rc_style)
1825 token = g_scanner_get_next_token (scanner);
1826 if (token != GTK_RC_TOKEN_FONT)
1827 return GTK_RC_TOKEN_FONT;
1829 token = g_scanner_get_next_token (scanner);
1830 if (token != G_TOKEN_EQUAL_SIGN)
1831 return G_TOKEN_EQUAL_SIGN;
1833 token = g_scanner_get_next_token (scanner);
1834 if (token != G_TOKEN_STRING)
1835 return G_TOKEN_STRING;
1837 if (rc_style->font_name)
1838 g_free (rc_style->font_name);
1839 rc_style->font_name = g_strdup (scanner->value.v_string);
1841 return G_TOKEN_NONE;
1845 gtk_rc_parse_fontset (GScanner *scanner,
1846 GtkRcStyle *rc_style)
1850 token = g_scanner_get_next_token (scanner);
1851 if (token != GTK_RC_TOKEN_FONTSET)
1852 return GTK_RC_TOKEN_FONTSET;
1854 token = g_scanner_get_next_token (scanner);
1855 if (token != G_TOKEN_EQUAL_SIGN)
1856 return G_TOKEN_EQUAL_SIGN;
1858 token = g_scanner_get_next_token (scanner);
1859 if (token != G_TOKEN_STRING)
1860 return G_TOKEN_STRING;
1862 if (rc_style->fontset_name)
1863 g_free (rc_style->fontset_name);
1864 rc_style->fontset_name = g_strdup (scanner->value.v_string);
1866 return G_TOKEN_NONE;
1870 gtk_rc_parse_engine (GScanner *scanner,
1871 GtkRcStyle *rc_style)
1875 token = g_scanner_get_next_token (scanner);
1876 if (token != GTK_RC_TOKEN_ENGINE)
1877 return GTK_RC_TOKEN_ENGINE;
1879 token = g_scanner_get_next_token (scanner);
1880 if (token != G_TOKEN_STRING)
1881 return G_TOKEN_STRING;
1883 rc_style->engine = gtk_theme_engine_get (scanner->value.v_string);
1885 token = g_scanner_get_next_token (scanner);
1886 if (token != G_TOKEN_LEFT_CURLY)
1887 return G_TOKEN_LEFT_CURLY;
1889 if (rc_style->engine)
1890 return rc_style->engine->parse_rc_style (scanner, rc_style);
1893 /* Skip over remainder, looking for nested {}'s */
1896 while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
1898 if (token == G_TOKEN_LEFT_CURLY)
1900 else if (token == G_TOKEN_RIGHT_CURLY)
1904 return G_TOKEN_NONE;
1907 return G_TOKEN_RIGHT_CURLY;
1912 gtk_rc_parse_state (GScanner *scanner,
1913 GtkStateType *state)
1918 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1919 g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
1921 /* we don't know where we got called from, so we reset the scope here.
1922 * if we bail out due to errors, we *don't* reset the scope, so the
1923 * error messaging code can make sense of our tokens.
1925 old_scope = g_scanner_set_scope (scanner, 0);
1927 token = g_scanner_get_next_token (scanner);
1928 if (token != G_TOKEN_LEFT_BRACE)
1929 return G_TOKEN_LEFT_BRACE;
1931 token = g_scanner_get_next_token (scanner);
1934 case GTK_RC_TOKEN_ACTIVE:
1935 *state = GTK_STATE_ACTIVE;
1937 case GTK_RC_TOKEN_INSENSITIVE:
1938 *state = GTK_STATE_INSENSITIVE;
1940 case GTK_RC_TOKEN_NORMAL:
1941 *state = GTK_STATE_NORMAL;
1943 case GTK_RC_TOKEN_PRELIGHT:
1944 *state = GTK_STATE_PRELIGHT;
1946 case GTK_RC_TOKEN_SELECTED:
1947 *state = GTK_STATE_SELECTED;
1950 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
1953 token = g_scanner_get_next_token (scanner);
1954 if (token != G_TOKEN_RIGHT_BRACE)
1955 return G_TOKEN_RIGHT_BRACE;
1957 g_scanner_set_scope (scanner, old_scope);
1959 return G_TOKEN_NONE;
1963 gtk_rc_parse_priority (GScanner *scanner,
1964 GtkPathPriorityType *priority)
1969 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1970 g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
1972 /* we don't know where we got called from, so we reset the scope here.
1973 * if we bail out due to errors, we *don't* reset the scope, so the
1974 * error messaging code can make sense of our tokens.
1976 old_scope = g_scanner_set_scope (scanner, 0);
1978 token = g_scanner_get_next_token (scanner);
1982 token = g_scanner_get_next_token (scanner);
1985 case GTK_RC_TOKEN_LOWEST:
1986 *priority = GTK_PATH_PRIO_LOWEST;
1988 case GTK_RC_TOKEN_GTK:
1989 *priority = GTK_PATH_PRIO_GTK;
1991 case GTK_RC_TOKEN_APPLICATION:
1992 *priority = GTK_PATH_PRIO_APPLICATION;
1994 case GTK_RC_TOKEN_RC:
1995 *priority = GTK_PATH_PRIO_RC;
1997 case GTK_RC_TOKEN_HIGHEST:
1998 *priority = GTK_PATH_PRIO_HIGHEST;
2001 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
2004 g_scanner_set_scope (scanner, old_scope);
2006 return G_TOKEN_NONE;
2010 gtk_rc_parse_color (GScanner *scanner,
2015 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2017 /* we don't need to set our own scop here, because
2018 * we don't need own symbols
2021 token = g_scanner_get_next_token (scanner);
2030 case G_TOKEN_LEFT_CURLY:
2031 token = g_scanner_get_next_token (scanner);
2032 if (token == G_TOKEN_INT)
2033 token_int = scanner->value.v_int;
2034 else if (token == G_TOKEN_FLOAT)
2035 token_int = scanner->value.v_float * 65535.0;
2037 return G_TOKEN_FLOAT;
2038 color->red = CLAMP (token_int, 0, 65535);
2040 token = g_scanner_get_next_token (scanner);
2041 if (token != G_TOKEN_COMMA)
2042 return G_TOKEN_COMMA;
2044 token = g_scanner_get_next_token (scanner);
2045 if (token == G_TOKEN_INT)
2046 token_int = scanner->value.v_int;
2047 else if (token == G_TOKEN_FLOAT)
2048 token_int = scanner->value.v_float * 65535.0;
2050 return G_TOKEN_FLOAT;
2051 color->green = CLAMP (token_int, 0, 65535);
2053 token = g_scanner_get_next_token (scanner);
2054 if (token != G_TOKEN_COMMA)
2055 return G_TOKEN_COMMA;
2057 token = g_scanner_get_next_token (scanner);
2058 if (token == G_TOKEN_INT)
2059 token_int = scanner->value.v_int;
2060 else if (token == G_TOKEN_FLOAT)
2061 token_int = scanner->value.v_float * 65535.0;
2063 return G_TOKEN_FLOAT;
2064 color->blue = CLAMP (token_int, 0, 65535);
2066 token = g_scanner_get_next_token (scanner);
2067 if (token != G_TOKEN_RIGHT_CURLY)
2068 return G_TOKEN_RIGHT_CURLY;
2069 return G_TOKEN_NONE;
2071 case G_TOKEN_STRING:
2072 if (scanner->value.v_string[0] != '#')
2073 return G_TOKEN_STRING;
2075 length = strlen (scanner->value.v_string) - 1;
2076 if (((length % 3) != 0) || (length > 12))
2077 return G_TOKEN_STRING;
2080 for (i = 0, j = 1; i < length; i++, j++)
2081 buf[i] = scanner->value.v_string[j];
2084 sscanf (buf, "%x", &temp);
2087 for (i = 0; i < length; i++, j++)
2088 buf[i] = scanner->value.v_string[j];
2091 sscanf (buf, "%x", &temp);
2092 color->green = temp;
2094 for (i = 0; i < length; i++, j++)
2095 buf[i] = scanner->value.v_string[j];
2098 sscanf (buf, "%x", &temp);
2104 color->green *= 4369;
2105 color->blue *= 4369;
2107 else if (length == 2)
2110 color->green *= 257;
2113 else if (length == 3)
2119 return G_TOKEN_NONE;
2122 return G_TOKEN_STRING;
2127 gtk_rc_parse_pixmap_path (GScanner *scanner)
2131 token = g_scanner_get_next_token (scanner);
2132 if (token != GTK_RC_TOKEN_PIXMAP_PATH)
2133 return GTK_RC_TOKEN_PIXMAP_PATH;
2135 token = g_scanner_get_next_token (scanner);
2136 if (token != G_TOKEN_STRING)
2137 return G_TOKEN_STRING;
2139 gtk_rc_parse_pixmap_path_string (scanner->value.v_string);
2141 return G_TOKEN_NONE;
2145 gtk_rc_parse_pixmap_path_string (gchar *pix_path)
2149 gint start_offset = 0;
2153 /* free the old one, or just add to the old one ? */
2154 for (path_num=0; pixmap_path[path_num]; path_num++)
2156 g_free (pixmap_path[path_num]);
2157 pixmap_path[path_num] = NULL;
2162 path_len = strlen (pix_path);
2164 buf = g_strdup (pix_path);
2166 for (end_offset = 0; end_offset <= path_len; end_offset++)
2168 if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2169 (end_offset == path_len))
2171 buf[end_offset] = '\0';
2172 pixmap_path[path_num] = g_strdup (buf + start_offset);
2174 pixmap_path[path_num] = NULL;
2175 start_offset = end_offset + 1;
2179 gtk_rc_append_default_pixmap_path();
2183 gtk_rc_parse_module_path (GScanner *scanner)
2187 token = g_scanner_get_next_token (scanner);
2188 if (token != GTK_RC_TOKEN_MODULE_PATH)
2189 return GTK_RC_TOKEN_MODULE_PATH;
2191 token = g_scanner_get_next_token (scanner);
2192 if (token != G_TOKEN_STRING)
2193 return G_TOKEN_STRING;
2195 gtk_rc_parse_module_path_string (scanner->value.v_string);
2197 return G_TOKEN_NONE;
2201 gtk_rc_parse_module_path_string (gchar *mod_path)
2205 gint start_offset = 0;
2209 /* free the old one, or just add to the old one ? */
2210 for (path_num=0; module_path[path_num]; path_num++)
2212 g_free (module_path[path_num]);
2213 module_path[path_num] = NULL;
2218 path_len = strlen (mod_path);
2220 buf = g_strdup (mod_path);
2222 for (end_offset = 0; end_offset <= path_len; end_offset++)
2224 if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2225 (end_offset == path_len))
2227 buf[end_offset] = '\0';
2228 module_path[path_num] = g_strdup (buf + start_offset);
2230 module_path[path_num] = NULL;
2231 start_offset = end_offset + 1;
2235 gtk_rc_append_default_module_path();
2239 gtk_rc_parse_path_pattern (GScanner *scanner)
2242 GtkPathType path_type;
2244 gboolean is_binding;
2245 GtkPathPriorityType priority = GTK_PATH_PRIO_RC;
2247 token = g_scanner_get_next_token (scanner);
2250 case GTK_RC_TOKEN_WIDGET:
2251 path_type = GTK_PATH_WIDGET;
2253 case GTK_RC_TOKEN_WIDGET_CLASS:
2254 path_type = GTK_PATH_WIDGET_CLASS;
2256 case GTK_RC_TOKEN_CLASS:
2257 path_type = GTK_PATH_CLASS;
2260 return GTK_RC_TOKEN_WIDGET_CLASS;
2263 token = g_scanner_get_next_token (scanner);
2264 if (token != G_TOKEN_STRING)
2265 return G_TOKEN_STRING;
2267 pattern = g_strdup (scanner->value.v_string);
2269 token = g_scanner_get_next_token (scanner);
2270 if (token == GTK_RC_TOKEN_STYLE)
2272 else if (token == GTK_RC_TOKEN_BINDING)
2275 if (g_scanner_peek_next_token (scanner) == ':')
2277 token = gtk_rc_parse_priority (scanner, &priority);
2278 if (token != G_TOKEN_NONE)
2288 return GTK_RC_TOKEN_STYLE;
2291 token = g_scanner_get_next_token (scanner);
2292 if (token != G_TOKEN_STRING)
2295 return G_TOKEN_STRING;
2300 GtkBindingSet *binding;
2302 binding = gtk_binding_set_find (scanner->value.v_string);
2306 return G_TOKEN_STRING;
2308 gtk_binding_set_add_path (binding, path_type, pattern, priority);
2312 GtkRcStyle *rc_style;
2315 rc_style = gtk_rc_style_find (scanner->value.v_string);
2320 return G_TOKEN_STRING;
2323 rc_set = g_new (GtkRcSet, 1);
2324 gtk_pattern_spec_init (&rc_set->pspec, pattern);
2325 rc_set->rc_style = rc_style;
2327 if (path_type == GTK_PATH_WIDGET)
2328 gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set);
2329 else if (path_type == GTK_PATH_WIDGET_CLASS)
2330 gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set);
2332 gtk_rc_sets_class = g_slist_prepend (gtk_rc_sets_class, rc_set);
2336 return G_TOKEN_NONE;
2340 typedef GdkPixmap * (*GtkImageLoader) (GdkWindow *window,
2341 GdkColormap *colormap,
2343 GdkColor *transparent_color,
2344 const gchar *filename);
2348 gtk_rc_set_image_loader(GtkImageLoader loader)
2350 image_loader = loader;
2354 gtk_rc_load_image (GdkColormap *colormap,
2355 GdkColor *transparent_color,
2356 const gchar *filename)
2358 if (strcmp (filename, "<parent>") == 0)
2359 return (GdkPixmap*) GDK_PARENT_RELATIVE;
2363 return image_loader(NULL, colormap, NULL,
2367 return gdk_pixmap_colormap_create_from_xpm (NULL, colormap, NULL,