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;
78 gchar *canonical_name;
82 static guint gtk_rc_style_hash (const char *name);
83 static gint gtk_rc_style_compare (const char *a,
85 static guint gtk_rc_styles_hash (const GSList *rc_styles);
86 static gint gtk_rc_styles_compare (const GSList *a,
88 static GtkRcStyle* gtk_rc_style_find (const char *name);
89 static GSList * gtk_rc_styles_match (GSList *rc_styles,
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,
98 static void gtk_rc_parse_any (const gchar *input_name,
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,
105 static guint gtk_rc_parse_fg (GScanner *scanner,
107 static guint gtk_rc_parse_text (GScanner *scanner,
109 static guint gtk_rc_parse_base (GScanner *scanner,
111 static guint gtk_rc_parse_xthickness (GScanner *scanner,
113 static guint gtk_rc_parse_ythickness (GScanner *scanner,
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,
133 static void gtk_rc_clear_styles (void);
134 static void gtk_rc_append_default_pixmap_path (void);
135 static void gtk_rc_append_default_module_path (void);
136 static void gtk_rc_add_initial_default_files (void);
138 static void gtk_rc_style_init (GtkRcStyle *style);
139 static void gtk_rc_style_class_init (GtkRcStyleClass *klass);
140 static void gtk_rc_style_finalize (GObject *object);
142 static gpointer parent_class = NULL;
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 { "text", GTK_RC_TOKEN_TEXT },
199 { "base", GTK_RC_TOKEN_BASE },
200 { "xthickness", GTK_RC_TOKEN_XTHICKNESS },
201 { "ythickness", GTK_RC_TOKEN_YTHICKNESS },
202 { "font", GTK_RC_TOKEN_FONT },
203 { "fontset", GTK_RC_TOKEN_FONTSET },
204 { "font_name", GTK_RC_TOKEN_FONT_NAME },
205 { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP },
206 { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH },
207 { "style", GTK_RC_TOKEN_STYLE },
208 { "binding", GTK_RC_TOKEN_BINDING },
209 { "bind", GTK_RC_TOKEN_BIND },
210 { "widget", GTK_RC_TOKEN_WIDGET },
211 { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS },
212 { "class", GTK_RC_TOKEN_CLASS },
213 { "lowest", GTK_RC_TOKEN_LOWEST },
214 { "gtk", GTK_RC_TOKEN_GTK },
215 { "application", GTK_RC_TOKEN_APPLICATION },
216 { "rc", GTK_RC_TOKEN_RC },
217 { "highest", GTK_RC_TOKEN_HIGHEST },
218 { "engine", GTK_RC_TOKEN_ENGINE },
219 { "module_path", GTK_RC_TOKEN_MODULE_PATH },
222 static const guint n_symbols = sizeof (symbols) / sizeof (symbols[0]);
224 static GHashTable *rc_style_ht = NULL;
225 static GHashTable *realized_style_ht = NULL;
226 static GSList *gtk_rc_sets_widget = NULL;
227 static GSList *gtk_rc_sets_widget_class = NULL;
228 static GSList *gtk_rc_sets_class = NULL;
230 #define GTK_RC_MAX_DEFAULT_FILES 128
231 static gchar *gtk_rc_default_files[GTK_RC_MAX_DEFAULT_FILES];
232 static gboolean gtk_rc_auto_parse = TRUE;
234 #define GTK_RC_MAX_PIXMAP_PATHS 128
235 static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
236 #define GTK_RC_MAX_MODULE_PATHS 128
237 static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
239 /* A stack of directories for RC files we are parsing currently.
240 * these are implicitely added to the end of PIXMAP_PATHS
242 GSList *rc_dir_stack = NULL;
244 /* The files we have parsed, to reread later if necessary */
245 GSList *rc_files = NULL;
247 static GtkImageLoader image_loader = NULL;
249 /* RC file handling */
255 get_gtk_sysconf_directory (void)
257 static gboolean been_here = FALSE;
258 static gchar gtk_sysconf_dir[200];
262 DWORD nbytes = sizeof (gtk_sysconf_dir);
265 return gtk_sysconf_dir;
269 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\GNU\\GTk+", 0,
270 KEY_QUERY_VALUE, ®_key) != ERROR_SUCCESS
271 || RegQueryValueEx (reg_key, "InstallationDirectory", 0,
272 &type, gtk_sysconf_dir, &nbytes) != ERROR_SUCCESS
275 /* Uh oh. Use the old hard-coded %WinDir%\GTk+ value */
276 GetWindowsDirectory (win_dir, sizeof (win_dir));
277 sprintf (gtk_sysconf_dir, "%s\\gtk+", win_dir);
281 RegCloseKey (reg_key);
283 return gtk_sysconf_dir;
287 get_themes_directory (void)
289 static gchar themes_dir[200];
291 sprintf (themes_dir, "%s\\themes", get_gtk_sysconf_directory ());
298 gtk_rc_get_theme_dir(void)
303 var = getenv("GTK_DATA_PREFIX");
305 path = g_strdup_printf("%s%s", var, "/share/themes");
307 path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/themes");
309 path = g_strdup (get_themes_directory ());
316 gtk_rc_get_module_dir(void)
321 var = getenv("GTK_EXE_PREFIX");
323 path = g_strdup_printf("%s%s", var, "/lib/gtk-2.0/" GTK_VERSION "/engines");
325 path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk-2.0/" GTK_VERSION "/engines");
327 path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
334 gtk_rc_append_default_pixmap_path(void)
340 var = getenv("GTK_DATA_PREFIX");
342 path = g_strdup_printf("%s%s", var, "/share/gtk/themes");
344 path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/gtk/themes");
346 path = g_strdup (get_themes_directory ());
349 for (n = 0; pixmap_path[n]; n++) ;
350 if (n >= GTK_RC_MAX_PIXMAP_PATHS - 1)
355 pixmap_path[n++] = path;
356 pixmap_path[n] = NULL;
360 gtk_rc_append_default_module_path(void)
365 for (n = 0; module_path[n]; n++) ;
366 if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
370 var = getenv("GTK_EXE_PREFIX");
372 path = g_strdup_printf("%s%s", var, "/lib/gtk-2.0/" GTK_VERSION "/engines");
374 path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk-2.0/" GTK_VERSION "/engines");
376 path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
378 module_path[n++] = path;
380 var = g_get_home_dir ();
384 path = g_strdup_printf ("%s%s", var, "/.gtk-2.0/" GTK_VERSION "/engines");
386 path = g_strdup_printf ("%s%s", var, "\\_gtk\\themes\\engines");
388 module_path[n++] = path;
390 module_path[n] = NULL;
394 gtk_rc_add_initial_default_files (void)
396 static gint init = FALSE;
404 gtk_rc_default_files[0] = NULL;
407 var = g_getenv("GTK_RC_FILES");
410 files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
414 gtk_rc_add_default_file (files[i]);
422 str = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk-2.0" G_DIR_SEPARATOR_S "gtkrc");
424 str = g_strdup_printf ("%s\\gtkrc", get_gtk_sysconf_directory ());
427 gtk_rc_add_default_file (str);
430 var = g_get_home_dir ();
433 str = g_strdup_printf ("%s" G_DIR_SEPARATOR_S ".gtkrc-2.0", var);
434 gtk_rc_add_default_file (str);
441 gtk_rc_add_default_file (const gchar *file)
445 gtk_rc_add_initial_default_files ();
447 for (n = 0; gtk_rc_default_files[n]; n++) ;
448 if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
451 gtk_rc_default_files[n++] = g_strdup (file);
452 gtk_rc_default_files[n] = NULL;
456 gtk_rc_set_default_files (gchar **files)
460 gtk_rc_add_initial_default_files ();
463 while (gtk_rc_default_files[i])
465 g_free (gtk_rc_default_files[i]);
469 gtk_rc_default_files[0] = NULL;
470 gtk_rc_auto_parse = FALSE;
473 while (files[i] != NULL)
475 gtk_rc_add_default_file (files[i]);
481 gtk_rc_get_default_files (void)
483 gtk_rc_add_initial_default_files ();
485 return gtk_rc_default_files;
488 /* The following routine is based on _nl_normalize_codeset from
489 * the GNU C library. Contributed by
491 * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
492 * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
494 * Normalize codeset name. There is no standard for the codeset
495 * names. Normalization allows the user to use any of the common
499 _gtk_normalize_codeset (const char *codeset, int name_len)
507 for (cnt = 0; cnt < name_len; ++cnt)
508 if (isalnum (codeset[cnt]))
512 if (isalpha (codeset[cnt]))
516 retval = g_malloc ((only_digit ? 3 : 0) + len + 1);
520 strcpy (retval, "iso");
526 for (cnt = 0; cnt < name_len; ++cnt)
527 if (isalpha (codeset[cnt]))
528 *wp++ = isupper(codeset[cnt]) ? tolower (codeset[cnt]) : codeset[cnt];
529 else if (isdigit (codeset[cnt]))
530 *wp++ = codeset[cnt];
540 static gchar *locale_suffixes[3];
541 static gint n_locale_suffixes = 0;
545 static gboolean initted = FALSE;
554 locale = g_win32_getlocale ();
556 locale = setlocale (LC_CTYPE, NULL);
561 pixmap_path[0] = NULL;
562 module_path[0] = NULL;
563 gtk_rc_append_default_pixmap_path();
564 gtk_rc_append_default_module_path();
566 gtk_rc_add_initial_default_files ();
568 if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
570 /* Determine locale-specific suffixes for RC files
572 * We normalize the charset into a standard form,
573 * which has all '-' and '_' characters removed,
576 gchar *normalized_locale;
578 p = strchr (locale, '@');
579 length = p ? (p -locale) : strlen (locale);
581 p = strchr (locale, '.');
584 gchar *tmp1 = g_strndup (locale, p - locale + 1);
585 gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
587 normalized_locale = g_strconcat (tmp1, tmp2, NULL);
591 locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
595 normalized_locale = g_strndup (locale, length);
597 p = strchr (normalized_locale, '_');
600 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
601 length = p - normalized_locale;
604 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
606 g_free (normalized_locale);
611 while (gtk_rc_default_files[i] != NULL)
613 /* Try to find a locale specific RC file corresponding to
614 * to parse before the default file.
616 for (j=n_locale_suffixes-1; j>=0; j--)
618 gchar *name = g_strconcat (gtk_rc_default_files[i],
626 gtk_rc_parse (gtk_rc_default_files[i]);
632 gtk_rc_parse_string (const gchar *rc_string)
634 g_return_if_fail (rc_string != NULL);
636 gtk_rc_parse_any ("-", -1, rc_string);
640 gtk_rc_parse_file (const gchar *filename, gboolean reload)
642 GtkRcFile *rc_file = NULL;
646 g_return_if_fail (filename != NULL);
651 rc_file = tmp_list->data;
652 if (!strcmp (rc_file->name, filename))
655 tmp_list = tmp_list->next;
660 rc_file = g_new (GtkRcFile, 1);
661 rc_file->name = g_strdup (filename);
662 rc_file->canonical_name = NULL;
664 rc_file->reload = reload;
666 rc_files = g_slist_append (rc_files, rc_file);
669 if (!rc_file->canonical_name)
671 /* Get the absolute pathname */
673 if (g_path_is_absolute (rc_file->name))
674 rc_file->canonical_name = rc_file->name;
680 cwd = g_get_current_dir ();
682 str = g_string_new (cwd);
684 g_string_append_c (str, G_DIR_SEPARATOR);
685 g_string_append (str, rc_file->name);
687 rc_file->canonical_name = str->str;
688 g_string_free (str, FALSE);
692 if (!lstat (rc_file->canonical_name, &statbuf))
697 rc_file->mtime = statbuf.st_mtime;
699 fd = open (rc_file->canonical_name, O_RDONLY);
703 /* Temporarily push directory name for this file on
704 * a stack of directory names while parsing it
706 rc_dir_stack = g_slist_prepend (rc_dir_stack,
707 g_dirname (rc_file->canonical_name));
708 gtk_rc_parse_any (filename, fd, NULL);
710 tmp_list = rc_dir_stack;
711 rc_dir_stack = rc_dir_stack->next;
713 g_free (tmp_list->data);
714 g_slist_free_1 (tmp_list);
721 gtk_rc_parse (const gchar *filename)
723 g_return_if_fail (filename != NULL);
725 gtk_rc_parse_file (filename, TRUE);
728 /* Handling of RC styles */
731 gtk_rc_style_get_type (void)
733 static GType object_type = 0;
737 static const GTypeInfo object_info =
739 sizeof (GtkRcStyleClass),
740 (GBaseInitFunc) NULL,
741 (GBaseFinalizeFunc) NULL,
742 (GClassInitFunc) gtk_rc_style_class_init,
743 NULL, /* class_finalize */
744 NULL, /* class_data */
747 (GInstanceInitFunc) gtk_rc_style_init,
750 object_type = g_type_register_static (G_TYPE_OBJECT,
759 gtk_rc_style_init (GtkRcStyle *style)
764 for (i = 0; i < 5; i++)
766 static const GdkColor init_color = { 0, 0, 0, 0, };
768 style->bg_pixmap_name[i] = NULL;
769 style->color_flags[i] = 0;
770 style->fg[i] = init_color;
771 style->bg[i] = init_color;
772 style->text[i] = init_color;
773 style->base[i] = init_color;
775 style->xthickness = -1;
776 style->ythickness = -1;
777 style->engine = NULL;
778 style->engine_data = NULL;
779 style->rc_style_lists = NULL;
783 gtk_rc_style_class_init (GtkRcStyleClass *klass)
785 GObjectClass *object_class = G_OBJECT_CLASS (klass);
787 parent_class = g_type_class_peek_parent (klass);
789 object_class->finalize = gtk_rc_style_finalize;
792 /* Like g_slist_remove, but remove all copies of data */
794 gtk_rc_slist_remove_all (GSList *list,
805 if (tmp->data == data)
811 prev->next = tmp->next;
813 g_slist_free_1 (tmp);
831 gtk_rc_style_finalize (GObject *object)
834 GSList *tmp_list1, *tmp_list2;
835 GtkRcStyle *rc_style;
837 rc_style = GTK_RC_STYLE (object);
839 if (rc_style->engine)
841 rc_style->engine->destroy_rc_style (rc_style);
842 gtk_theme_engine_unref (rc_style->engine);
846 g_free (rc_style->name);
847 if (rc_style->font_desc)
848 pango_font_description_free (rc_style->font_desc);
850 for (i=0 ; i<5 ; i++)
851 if (rc_style->bg_pixmap_name[i])
852 g_free (rc_style->bg_pixmap_name[i]);
854 /* Now remove all references to this rc_style from
857 tmp_list1 = rc_style->rc_style_lists;
860 GSList *rc_styles = tmp_list1->data;
861 GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
862 gtk_style_unref (style);
864 /* Remove the list of styles from the other rc_styles
867 tmp_list2 = rc_styles;
870 GtkRcStyle *other_style = tmp_list2->data;
872 if (other_style != rc_style)
873 other_style->rc_style_lists =
874 gtk_rc_slist_remove_all (other_style->rc_style_lists, rc_styles);
876 tmp_list2 = tmp_list2->next;
879 /* And from the hash table itself
881 g_hash_table_remove (realized_style_ht, rc_styles);
882 g_slist_free (rc_styles);
884 tmp_list1 = tmp_list1->next;
886 g_slist_free (rc_style->rc_style_lists);
888 G_OBJECT_CLASS (parent_class)->finalize (object);
892 gtk_rc_style_new (void)
896 style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
902 gtk_rc_style_ref (GtkRcStyle *rc_style)
904 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
906 g_object_ref (G_OBJECT (rc_style));
910 gtk_rc_style_unref (GtkRcStyle *rc_style)
912 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
914 g_object_unref (G_OBJECT (rc_style));
918 gtk_rc_clear_hash_node (gpointer key,
922 gtk_rc_style_unref (data);
926 gtk_rc_free_rc_sets (GSList *slist)
932 rc_set = slist->data;
933 gtk_pattern_spec_free_segs (&rc_set->pspec);
941 gtk_rc_clear_styles (void)
943 /* Clear out all old rc_styles */
947 g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
948 g_hash_table_destroy (rc_style_ht);
952 gtk_rc_free_rc_sets (gtk_rc_sets_widget);
953 g_slist_free (gtk_rc_sets_widget);
954 gtk_rc_sets_widget = NULL;
956 gtk_rc_free_rc_sets (gtk_rc_sets_widget_class);
957 g_slist_free (gtk_rc_sets_widget_class);
958 gtk_rc_sets_widget_class = NULL;
960 gtk_rc_free_rc_sets (gtk_rc_sets_class);
961 g_slist_free (gtk_rc_sets_class);
962 gtk_rc_sets_class = NULL;
966 gtk_rc_reparse_all (void)
969 gboolean mtime_modified = FALSE;
974 /* Check through and see if any of the RC's have had their
975 * mtime modified. If so, reparse everything.
980 rc_file = tmp_list->data;
982 if (!lstat (rc_file->name, &statbuf) &&
983 (statbuf.st_mtime > rc_file->mtime))
985 mtime_modified = TRUE;
989 tmp_list = tmp_list->next;
994 gtk_rc_clear_styles();
999 rc_file = tmp_list->data;
1000 if (rc_file->reload)
1001 gtk_rc_parse_file (rc_file->name, FALSE);
1003 tmp_list = tmp_list->next;
1007 return mtime_modified;
1011 gtk_rc_styles_match (GSList *rc_styles,
1015 gchar *path_reversed)
1022 rc_set = sets->data;
1025 if (gtk_pattern_match (&rc_set->pspec, path_length, path, path_reversed))
1026 rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
1033 gtk_rc_get_style (GtkWidget *widget)
1035 GtkRcStyle *widget_rc_style;
1036 GSList *rc_styles = NULL;
1038 static guint rc_style_key_id = 0;
1040 /* We allow the specification of a single rc style to be bound
1041 * tightly to a widget, for application modifications
1043 if (!rc_style_key_id)
1044 rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1046 widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
1049 if (widget_rc_style)
1050 rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
1052 if (gtk_rc_sets_widget)
1054 gchar *path, *path_reversed;
1057 gtk_widget_path (widget, &path_length, &path, &path_reversed);
1058 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget, path_length, path, path_reversed);
1060 g_free (path_reversed);
1064 if (gtk_rc_sets_widget_class)
1066 gchar *path, *path_reversed;
1069 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1070 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget_class, path_length, path, path_reversed);
1072 g_free (path_reversed);
1075 if (gtk_rc_sets_class)
1079 type = GTK_OBJECT_TYPE (widget);
1082 gchar *path, *path_reversed;
1085 path = gtk_type_name (type);
1086 path_length = strlen (path);
1087 path_reversed = g_strdup (path);
1088 g_strreverse (path_reversed);
1090 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_class, path_length, path, path_reversed);
1091 g_free (path_reversed);
1093 type = gtk_type_parent (type);
1098 return gtk_rc_init_style (rc_styles);
1104 gtk_rc_add_rc_sets (GSList *slist,
1105 GtkRcStyle *rc_style,
1106 const char *pattern)
1108 GtkRcStyle *new_style;
1112 new_style = gtk_rc_style_new ();
1113 *new_style = *rc_style;
1114 new_style->name = g_strdup (rc_style->name);
1115 if (rc_style->font_desc)
1116 new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
1118 for (i = 0; i < 5; i++)
1119 new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1121 rc_set = g_new (GtkRcSet, 1);
1122 gtk_pattern_spec_init (&rc_set->pspec, pattern);
1123 rc_set->rc_style = rc_style;
1125 return g_slist_prepend (slist, rc_set);
1129 gtk_rc_add_widget_name_style (GtkRcStyle *rc_style,
1130 const gchar *pattern)
1132 g_return_if_fail (rc_style != NULL);
1133 g_return_if_fail (pattern != NULL);
1135 gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, rc_style, pattern);
1139 gtk_rc_add_widget_class_style (GtkRcStyle *rc_style,
1140 const gchar *pattern)
1142 g_return_if_fail (rc_style != NULL);
1143 g_return_if_fail (pattern != NULL);
1145 gtk_rc_sets_widget_class = gtk_rc_add_rc_sets (gtk_rc_sets_widget_class, rc_style, pattern);
1149 gtk_rc_add_class_style (GtkRcStyle *rc_style,
1150 const gchar *pattern)
1152 g_return_if_fail (rc_style != NULL);
1153 g_return_if_fail (pattern != NULL);
1155 gtk_rc_sets_class = gtk_rc_add_rc_sets (gtk_rc_sets_class, rc_style, pattern);
1159 gtk_rc_parse_any (const gchar *input_name,
1161 const gchar *input_string)
1167 scanner = g_scanner_new ((GScannerConfig *) >k_rc_scanner_config);
1171 g_assert (input_string == NULL);
1173 g_scanner_input_file (scanner, input_fd);
1177 g_assert (input_string != NULL);
1179 g_scanner_input_text (scanner, input_string, strlen (input_string));
1181 scanner->input_name = input_name;
1183 g_scanner_freeze_symbol_table (scanner);
1184 for (i = 0; i < n_symbols; i++)
1185 g_scanner_add_symbol (scanner, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1186 g_scanner_thaw_symbol_table (scanner);
1191 if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1195 guint expected_token;
1197 expected_token = gtk_rc_parse_statement (scanner);
1199 if (expected_token != G_TOKEN_NONE)
1206 if (scanner->scope_id == 0)
1208 /* if we are in scope 0, we know the symbol names
1209 * that are associated with certaintoken values.
1210 * so we look them up to make the error messages
1213 if (expected_token > GTK_RC_TOKEN_INVALID &&
1214 expected_token < GTK_RC_TOKEN_LAST)
1216 for (i = 0; i < n_symbols; i++)
1217 if (symbols[i].token == expected_token)
1218 msg = symbols[i].name;
1220 msg = g_strconcat ("e.g. `", msg, "'", NULL);
1222 if (scanner->token > GTK_RC_TOKEN_INVALID &&
1223 scanner->token < GTK_RC_TOKEN_LAST)
1225 symbol_name = "???";
1226 for (i = 0; i < n_symbols; i++)
1227 if (symbols[i].token == scanner->token)
1228 symbol_name = symbols[i].name;
1231 g_scanner_unexp_token (scanner,
1244 g_scanner_destroy (scanner);
1248 gtk_rc_styles_hash (const GSList *rc_styles)
1255 result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1256 rc_styles = rc_styles->next;
1263 gtk_rc_styles_compare (const GSList *a,
1268 if (a->data != b->data)
1278 gtk_rc_style_hash (const char *name)
1284 result += (result << 3) + *name++;
1290 gtk_rc_style_compare (const char *a,
1293 return (strcmp (a, b) == 0);
1297 gtk_rc_style_find (const char *name)
1300 return g_hash_table_lookup (rc_style_ht, (gpointer) name);
1305 /* Assumes ownership of rc_style */
1307 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1313 style = gtk_style_new ();
1315 style->rc_style = rc_style;
1317 if (rc_style->font_desc)
1319 pango_font_description_free (style->font_desc);
1320 style->font_desc = pango_font_description_copy (rc_style->font_desc);
1322 old_font = style->font;
1323 style->font = gdk_font_from_description (style->font_desc);
1325 gdk_font_unref (old_font);
1327 style->font = old_font;
1330 for (i = 0; i < 5; i++)
1332 if (rc_style->color_flags[i] & GTK_RC_FG)
1333 style->fg[i] = rc_style->fg[i];
1334 if (rc_style->color_flags[i] & GTK_RC_BG)
1335 style->bg[i] = rc_style->bg[i];
1336 if (rc_style->color_flags[i] & GTK_RC_TEXT)
1337 style->text[i] = rc_style->text[i];
1338 if (rc_style->color_flags[i] & GTK_RC_BASE)
1339 style->base[i] = rc_style->base[i];
1342 if (rc_style->xthickness >= 0)
1343 style->xthickness = rc_style->xthickness;
1344 if (rc_style->ythickness >= 0)
1345 style->ythickness = rc_style->ythickness;
1347 if (rc_style->engine)
1349 style->engine = rc_style->engine;
1350 gtk_theme_engine_ref (style->engine);
1351 rc_style->engine->rc_style_to_style (style, rc_style);
1357 /* Reuses or frees rc_styles */
1359 gtk_rc_init_style (GSList *rc_styles)
1361 GtkStyle *style = NULL;
1364 if (!realized_style_ht)
1365 realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
1366 (GCompareFunc) gtk_rc_styles_compare);
1368 style = g_hash_table_lookup (realized_style_ht, rc_styles);
1372 GtkRcStyle *proto_style;
1375 proto_style = gtk_rc_style_new ();
1377 tmp_style = rc_styles;
1380 GtkRcStyle *rc_style = tmp_style->data;
1382 for (i = 0; i < 5; i++)
1384 if (!proto_style->bg_pixmap_name[i] && rc_style->bg_pixmap_name[i])
1385 proto_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1387 if (!(proto_style->color_flags[i] & GTK_RC_FG) &&
1388 rc_style->color_flags[i] & GTK_RC_FG)
1390 proto_style->fg[i] = rc_style->fg[i];
1391 proto_style->color_flags[i] |= GTK_RC_FG;
1393 if (!(proto_style->color_flags[i] & GTK_RC_BG) &&
1394 rc_style->color_flags[i] & GTK_RC_BG)
1396 proto_style->bg[i] = rc_style->bg[i];
1397 proto_style->color_flags[i] |= GTK_RC_BG;
1399 if (!(proto_style->color_flags[i] & GTK_RC_TEXT) &&
1400 rc_style->color_flags[i] & GTK_RC_TEXT)
1402 proto_style->text[i] = rc_style->text[i];
1403 proto_style->color_flags[i] |= GTK_RC_TEXT;
1405 if (!(proto_style->color_flags[i] & GTK_RC_BASE) &&
1406 rc_style->color_flags[i] & GTK_RC_BASE)
1408 proto_style->base[i] = rc_style->base[i];
1409 proto_style->color_flags[i] |= GTK_RC_BASE;
1413 if (proto_style->xthickness < 0 && rc_style->xthickness >= 0)
1414 proto_style->xthickness = rc_style->xthickness;
1415 if (proto_style->ythickness < 0 && rc_style->ythickness >= 0)
1416 proto_style->ythickness = rc_style->ythickness;
1418 if (!proto_style->font_desc && rc_style->font_desc)
1419 proto_style->font_desc = pango_font_description_copy (rc_style->font_desc);
1421 if (!proto_style->engine && rc_style->engine)
1423 proto_style->engine = rc_style->engine;
1424 gtk_theme_engine_ref (proto_style->engine);
1427 if (proto_style->engine &&
1428 (proto_style->engine == rc_style->engine))
1429 proto_style->engine->merge_rc_style (proto_style, rc_style);
1431 /* Point from each rc_style to the list of styles */
1433 if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
1434 rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
1436 tmp_style = tmp_style->next;
1439 for (i = 0; i < 5; i++)
1440 if (proto_style->bg_pixmap_name[i] &&
1441 (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1443 g_free (proto_style->bg_pixmap_name[i]);
1444 proto_style->bg_pixmap_name[i] = NULL;
1447 style = gtk_rc_style_to_style (proto_style);
1449 g_hash_table_insert (realized_style_ht, rc_styles, style);
1452 g_slist_free (rc_styles);
1457 /*********************
1458 * Parsing functions *
1459 *********************/
1462 gtk_rc_parse_statement (GScanner *scanner)
1466 token = g_scanner_peek_next_token (scanner);
1470 case GTK_RC_TOKEN_INCLUDE:
1471 token = g_scanner_get_next_token (scanner);
1472 if (token != GTK_RC_TOKEN_INCLUDE)
1473 return GTK_RC_TOKEN_INCLUDE;
1475 token = g_scanner_get_next_token (scanner);
1476 if (token != G_TOKEN_STRING)
1477 return G_TOKEN_STRING;
1479 gtk_rc_parse_file (scanner->value.v_string, FALSE);
1480 return G_TOKEN_NONE;
1482 case GTK_RC_TOKEN_STYLE:
1483 return gtk_rc_parse_style (scanner);
1485 case GTK_RC_TOKEN_BINDING:
1486 return gtk_binding_parse_binding (scanner);
1488 case GTK_RC_TOKEN_PIXMAP_PATH:
1489 return gtk_rc_parse_pixmap_path (scanner);
1491 case GTK_RC_TOKEN_WIDGET:
1492 return gtk_rc_parse_path_pattern (scanner);
1494 case GTK_RC_TOKEN_WIDGET_CLASS:
1495 return gtk_rc_parse_path_pattern (scanner);
1497 case GTK_RC_TOKEN_CLASS:
1498 return gtk_rc_parse_path_pattern (scanner);
1500 case GTK_RC_TOKEN_MODULE_PATH:
1501 return gtk_rc_parse_module_path (scanner);
1504 g_scanner_get_next_token (scanner);
1505 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
1510 gtk_rc_parse_style (GScanner *scanner)
1512 GtkRcStyle *rc_style;
1513 GtkRcStyle *parent_style;
1518 token = g_scanner_get_next_token (scanner);
1519 if (token != GTK_RC_TOKEN_STYLE)
1520 return GTK_RC_TOKEN_STYLE;
1522 token = g_scanner_get_next_token (scanner);
1523 if (token != G_TOKEN_STRING)
1524 return G_TOKEN_STRING;
1527 rc_style = gtk_rc_style_find (scanner->value.v_string);
1532 rc_style = gtk_rc_style_new ();
1533 rc_style->name = g_strdup (scanner->value.v_string);
1535 for (i = 0; i < 5; i++)
1536 rc_style->bg_pixmap_name[i] = NULL;
1538 for (i = 0; i < 5; i++)
1539 rc_style->color_flags[i] = 0;
1541 rc_style->engine = NULL;
1542 rc_style->engine_data = NULL;
1545 token = g_scanner_peek_next_token (scanner);
1546 if (token == G_TOKEN_EQUAL_SIGN)
1548 token = g_scanner_get_next_token (scanner);
1550 token = g_scanner_get_next_token (scanner);
1551 if (token != G_TOKEN_STRING)
1556 return G_TOKEN_STRING;
1559 parent_style = gtk_rc_style_find (scanner->value.v_string);
1562 for (i = 0; i < 5; i++)
1564 rc_style->color_flags[i] = parent_style->color_flags[i];
1565 rc_style->fg[i] = parent_style->fg[i];
1566 rc_style->bg[i] = parent_style->bg[i];
1567 rc_style->text[i] = parent_style->text[i];
1568 rc_style->base[i] = parent_style->base[i];
1571 rc_style->xthickness = parent_style->xthickness;
1572 rc_style->ythickness = parent_style->ythickness;
1574 if (parent_style->font_desc)
1576 if (rc_style->font_desc)
1577 pango_font_description_free (rc_style->font_desc);
1578 rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
1581 for (i = 0; i < 5; i++)
1583 if (rc_style->bg_pixmap_name[i])
1584 g_free (rc_style->bg_pixmap_name[i]);
1585 rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
1590 token = g_scanner_get_next_token (scanner);
1591 if (token != G_TOKEN_LEFT_CURLY)
1596 return G_TOKEN_LEFT_CURLY;
1599 token = g_scanner_peek_next_token (scanner);
1600 while (token != G_TOKEN_RIGHT_CURLY)
1604 case GTK_RC_TOKEN_BG:
1605 token = gtk_rc_parse_bg (scanner, rc_style);
1607 case GTK_RC_TOKEN_FG:
1608 token = gtk_rc_parse_fg (scanner, rc_style);
1610 case GTK_RC_TOKEN_TEXT:
1611 token = gtk_rc_parse_text (scanner, rc_style);
1613 case GTK_RC_TOKEN_BASE:
1614 token = gtk_rc_parse_base (scanner, rc_style);
1616 case GTK_RC_TOKEN_XTHICKNESS:
1617 token = gtk_rc_parse_xthickness (scanner, rc_style);
1619 case GTK_RC_TOKEN_YTHICKNESS:
1620 token = gtk_rc_parse_ythickness (scanner, rc_style);
1622 case GTK_RC_TOKEN_BG_PIXMAP:
1623 token = gtk_rc_parse_bg_pixmap (scanner, rc_style);
1625 case GTK_RC_TOKEN_FONT:
1626 token = gtk_rc_parse_font (scanner, rc_style);
1628 case GTK_RC_TOKEN_FONTSET:
1629 token = gtk_rc_parse_fontset (scanner, rc_style);
1631 case GTK_RC_TOKEN_FONT_NAME:
1632 token = gtk_rc_parse_font_name (scanner, rc_style);
1634 case GTK_RC_TOKEN_ENGINE:
1635 token = gtk_rc_parse_engine (scanner, rc_style);
1638 g_scanner_get_next_token (scanner);
1639 token = G_TOKEN_RIGHT_CURLY;
1643 if (token != G_TOKEN_NONE)
1647 if (rc_style->font_desc)
1648 pango_font_description_free (rc_style->font_desc);
1650 for (i = 0; i < 5; i++)
1651 if (rc_style->bg_pixmap_name[i])
1652 g_free (rc_style->bg_pixmap_name[i]);
1657 token = g_scanner_peek_next_token (scanner);
1660 token = g_scanner_get_next_token (scanner);
1661 if (token != G_TOKEN_RIGHT_CURLY)
1665 if (rc_style->font_desc)
1666 pango_font_description_free (rc_style->font_desc);
1668 for (i = 0; i < 5; i++)
1669 if (rc_style->bg_pixmap_name[i])
1670 g_free (rc_style->bg_pixmap_name[i]);
1674 return G_TOKEN_RIGHT_CURLY;
1680 rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
1681 (GCompareFunc) gtk_rc_style_compare);
1683 g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
1686 return G_TOKEN_NONE;
1690 gtk_rc_parse_bg (GScanner *scanner,
1696 token = g_scanner_get_next_token (scanner);
1697 if (token != GTK_RC_TOKEN_BG)
1698 return GTK_RC_TOKEN_BG;
1700 token = gtk_rc_parse_state (scanner, &state);
1701 if (token != G_TOKEN_NONE)
1704 token = g_scanner_get_next_token (scanner);
1705 if (token != G_TOKEN_EQUAL_SIGN)
1706 return G_TOKEN_EQUAL_SIGN;
1708 style->color_flags[state] |= GTK_RC_BG;
1709 return gtk_rc_parse_color (scanner, &style->bg[state]);
1713 gtk_rc_parse_fg (GScanner *scanner,
1719 token = g_scanner_get_next_token (scanner);
1720 if (token != GTK_RC_TOKEN_FG)
1721 return GTK_RC_TOKEN_FG;
1723 token = gtk_rc_parse_state (scanner, &state);
1724 if (token != G_TOKEN_NONE)
1727 token = g_scanner_get_next_token (scanner);
1728 if (token != G_TOKEN_EQUAL_SIGN)
1729 return G_TOKEN_EQUAL_SIGN;
1731 style->color_flags[state] |= GTK_RC_FG;
1732 return gtk_rc_parse_color (scanner, &style->fg[state]);
1736 gtk_rc_parse_text (GScanner *scanner,
1742 token = g_scanner_get_next_token (scanner);
1743 if (token != GTK_RC_TOKEN_TEXT)
1744 return GTK_RC_TOKEN_TEXT;
1746 token = gtk_rc_parse_state (scanner, &state);
1747 if (token != G_TOKEN_NONE)
1750 token = g_scanner_get_next_token (scanner);
1751 if (token != G_TOKEN_EQUAL_SIGN)
1752 return G_TOKEN_EQUAL_SIGN;
1754 style->color_flags[state] |= GTK_RC_TEXT;
1755 return gtk_rc_parse_color (scanner, &style->text[state]);
1759 gtk_rc_parse_base (GScanner *scanner,
1765 token = g_scanner_get_next_token (scanner);
1766 if (token != GTK_RC_TOKEN_BASE)
1767 return GTK_RC_TOKEN_BASE;
1769 token = gtk_rc_parse_state (scanner, &state);
1770 if (token != G_TOKEN_NONE)
1773 token = g_scanner_get_next_token (scanner);
1774 if (token != G_TOKEN_EQUAL_SIGN)
1775 return G_TOKEN_EQUAL_SIGN;
1777 style->color_flags[state] |= GTK_RC_BASE;
1778 return gtk_rc_parse_color (scanner, &style->base[state]);
1782 gtk_rc_parse_xthickness (GScanner *scanner,
1785 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
1786 return GTK_RC_TOKEN_XTHICKNESS;
1788 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
1789 return G_TOKEN_EQUAL_SIGN;
1791 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
1794 style->xthickness = scanner->value.v_int;
1796 return G_TOKEN_NONE;
1800 gtk_rc_parse_ythickness (GScanner *scanner,
1803 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
1804 return GTK_RC_TOKEN_YTHICKNESS;
1806 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
1807 return G_TOKEN_EQUAL_SIGN;
1809 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
1812 style->ythickness = scanner->value.v_int;
1814 return G_TOKEN_NONE;
1818 gtk_rc_parse_bg_pixmap (GScanner *scanner,
1819 GtkRcStyle *rc_style)
1825 token = g_scanner_get_next_token (scanner);
1826 if (token != GTK_RC_TOKEN_BG_PIXMAP)
1827 return GTK_RC_TOKEN_BG_PIXMAP;
1829 token = gtk_rc_parse_state (scanner, &state);
1830 if (token != G_TOKEN_NONE)
1833 token = g_scanner_get_next_token (scanner);
1834 if (token != G_TOKEN_EQUAL_SIGN)
1835 return G_TOKEN_EQUAL_SIGN;
1837 token = g_scanner_get_next_token (scanner);
1838 if (token != G_TOKEN_STRING)
1839 return G_TOKEN_STRING;
1841 if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
1842 (strcmp (scanner->value.v_string, "<none>") == 0))
1843 pixmap_file = g_strdup (scanner->value.v_string);
1845 pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
1849 if (rc_style->bg_pixmap_name[state])
1850 g_free (rc_style->bg_pixmap_name[state]);
1851 rc_style->bg_pixmap_name[state] = pixmap_file;
1854 return G_TOKEN_NONE;
1858 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
1863 buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", dir, pixmap_file);
1865 fd = open (buf, O_RDONLY);
1878 gtk_rc_find_pixmap_in_path (GScanner *scanner,
1879 const gchar *pixmap_file)
1885 for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
1887 filename = gtk_rc_check_pixmap_dir (pixmap_path[i], pixmap_file);
1892 tmp_list = rc_dir_stack;
1895 filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
1899 tmp_list = tmp_list->next;
1903 g_warning (_("Unable to locate image file in pixmap_path: \"%s\" line %d"),
1904 pixmap_file, scanner->line);
1906 g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
1913 gtk_rc_find_module_in_path (const gchar *module_file)
1919 for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
1921 buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
1922 module_path[i], module_file);
1924 fd = open (buf, O_RDONLY);
1938 gtk_rc_parse_font (GScanner *scanner,
1939 GtkRcStyle *rc_style)
1943 token = g_scanner_get_next_token (scanner);
1944 if (token != GTK_RC_TOKEN_FONT)
1945 return GTK_RC_TOKEN_FONT;
1947 token = g_scanner_get_next_token (scanner);
1948 if (token != G_TOKEN_EQUAL_SIGN)
1949 return G_TOKEN_EQUAL_SIGN;
1951 token = g_scanner_get_next_token (scanner);
1952 if (token != G_TOKEN_STRING)
1953 return G_TOKEN_STRING;
1955 /* Ignore, do nothing */
1957 return G_TOKEN_NONE;
1961 gtk_rc_parse_fontset (GScanner *scanner,
1962 GtkRcStyle *rc_style)
1966 token = g_scanner_get_next_token (scanner);
1967 if (token != GTK_RC_TOKEN_FONTSET)
1968 return GTK_RC_TOKEN_FONTSET;
1970 token = g_scanner_get_next_token (scanner);
1971 if (token != G_TOKEN_EQUAL_SIGN)
1972 return G_TOKEN_EQUAL_SIGN;
1974 token = g_scanner_get_next_token (scanner);
1975 if (token != G_TOKEN_STRING)
1976 return G_TOKEN_STRING;
1978 /* Do nothing - silently ignore */
1980 return G_TOKEN_NONE;
1984 gtk_rc_parse_font_name (GScanner *scanner,
1985 GtkRcStyle *rc_style)
1989 token = g_scanner_get_next_token (scanner);
1990 if (token != GTK_RC_TOKEN_FONT_NAME)
1991 return GTK_RC_TOKEN_FONT;
1993 token = g_scanner_get_next_token (scanner);
1994 if (token != G_TOKEN_EQUAL_SIGN)
1995 return G_TOKEN_EQUAL_SIGN;
1997 token = g_scanner_get_next_token (scanner);
1998 if (token != G_TOKEN_STRING)
1999 return G_TOKEN_STRING;
2001 rc_style->font_desc = pango_font_description_from_string (scanner->value.v_string);
2003 return G_TOKEN_NONE;
2007 gtk_rc_parse_engine (GScanner *scanner,
2008 GtkRcStyle *rc_style)
2012 token = g_scanner_get_next_token (scanner);
2013 if (token != GTK_RC_TOKEN_ENGINE)
2014 return GTK_RC_TOKEN_ENGINE;
2016 token = g_scanner_get_next_token (scanner);
2017 if (token != G_TOKEN_STRING)
2018 return G_TOKEN_STRING;
2020 rc_style->engine = gtk_theme_engine_get (scanner->value.v_string);
2022 token = g_scanner_get_next_token (scanner);
2023 if (token != G_TOKEN_LEFT_CURLY)
2024 return G_TOKEN_LEFT_CURLY;
2026 if (rc_style->engine)
2027 return rc_style->engine->parse_rc_style (scanner, rc_style);
2030 /* Skip over remainder, looking for nested {}'s */
2033 while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
2035 if (token == G_TOKEN_LEFT_CURLY)
2037 else if (token == G_TOKEN_RIGHT_CURLY)
2041 return G_TOKEN_NONE;
2044 return G_TOKEN_RIGHT_CURLY;
2049 gtk_rc_parse_state (GScanner *scanner,
2050 GtkStateType *state)
2055 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2056 g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
2058 /* we don't know where we got called from, so we reset the scope here.
2059 * if we bail out due to errors, we *don't* reset the scope, so the
2060 * error messaging code can make sense of our tokens.
2062 old_scope = g_scanner_set_scope (scanner, 0);
2064 token = g_scanner_get_next_token (scanner);
2065 if (token != G_TOKEN_LEFT_BRACE)
2066 return G_TOKEN_LEFT_BRACE;
2068 token = g_scanner_get_next_token (scanner);
2071 case GTK_RC_TOKEN_ACTIVE:
2072 *state = GTK_STATE_ACTIVE;
2074 case GTK_RC_TOKEN_INSENSITIVE:
2075 *state = GTK_STATE_INSENSITIVE;
2077 case GTK_RC_TOKEN_NORMAL:
2078 *state = GTK_STATE_NORMAL;
2080 case GTK_RC_TOKEN_PRELIGHT:
2081 *state = GTK_STATE_PRELIGHT;
2083 case GTK_RC_TOKEN_SELECTED:
2084 *state = GTK_STATE_SELECTED;
2087 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
2090 token = g_scanner_get_next_token (scanner);
2091 if (token != G_TOKEN_RIGHT_BRACE)
2092 return G_TOKEN_RIGHT_BRACE;
2094 g_scanner_set_scope (scanner, old_scope);
2096 return G_TOKEN_NONE;
2100 gtk_rc_parse_priority (GScanner *scanner,
2101 GtkPathPriorityType *priority)
2106 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2107 g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
2109 /* we don't know where we got called from, so we reset the scope here.
2110 * if we bail out due to errors, we *don't* reset the scope, so the
2111 * error messaging code can make sense of our tokens.
2113 old_scope = g_scanner_set_scope (scanner, 0);
2115 token = g_scanner_get_next_token (scanner);
2119 token = g_scanner_get_next_token (scanner);
2122 case GTK_RC_TOKEN_LOWEST:
2123 *priority = GTK_PATH_PRIO_LOWEST;
2125 case GTK_RC_TOKEN_GTK:
2126 *priority = GTK_PATH_PRIO_GTK;
2128 case GTK_RC_TOKEN_APPLICATION:
2129 *priority = GTK_PATH_PRIO_APPLICATION;
2131 case GTK_RC_TOKEN_RC:
2132 *priority = GTK_PATH_PRIO_RC;
2134 case GTK_RC_TOKEN_HIGHEST:
2135 *priority = GTK_PATH_PRIO_HIGHEST;
2138 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
2141 g_scanner_set_scope (scanner, old_scope);
2143 return G_TOKEN_NONE;
2147 gtk_rc_parse_color (GScanner *scanner,
2152 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2154 /* we don't need to set our own scop here, because
2155 * we don't need own symbols
2158 token = g_scanner_get_next_token (scanner);
2167 case G_TOKEN_LEFT_CURLY:
2168 token = g_scanner_get_next_token (scanner);
2169 if (token == G_TOKEN_INT)
2170 token_int = scanner->value.v_int;
2171 else if (token == G_TOKEN_FLOAT)
2172 token_int = scanner->value.v_float * 65535.0;
2174 return G_TOKEN_FLOAT;
2175 color->red = CLAMP (token_int, 0, 65535);
2177 token = g_scanner_get_next_token (scanner);
2178 if (token != G_TOKEN_COMMA)
2179 return G_TOKEN_COMMA;
2181 token = g_scanner_get_next_token (scanner);
2182 if (token == G_TOKEN_INT)
2183 token_int = scanner->value.v_int;
2184 else if (token == G_TOKEN_FLOAT)
2185 token_int = scanner->value.v_float * 65535.0;
2187 return G_TOKEN_FLOAT;
2188 color->green = CLAMP (token_int, 0, 65535);
2190 token = g_scanner_get_next_token (scanner);
2191 if (token != G_TOKEN_COMMA)
2192 return G_TOKEN_COMMA;
2194 token = g_scanner_get_next_token (scanner);
2195 if (token == G_TOKEN_INT)
2196 token_int = scanner->value.v_int;
2197 else if (token == G_TOKEN_FLOAT)
2198 token_int = scanner->value.v_float * 65535.0;
2200 return G_TOKEN_FLOAT;
2201 color->blue = CLAMP (token_int, 0, 65535);
2203 token = g_scanner_get_next_token (scanner);
2204 if (token != G_TOKEN_RIGHT_CURLY)
2205 return G_TOKEN_RIGHT_CURLY;
2206 return G_TOKEN_NONE;
2208 case G_TOKEN_STRING:
2209 if (scanner->value.v_string[0] != '#')
2210 return G_TOKEN_STRING;
2212 length = strlen (scanner->value.v_string) - 1;
2213 if (((length % 3) != 0) || (length > 12))
2214 return G_TOKEN_STRING;
2217 for (i = 0, j = 1; i < length; i++, j++)
2218 buf[i] = scanner->value.v_string[j];
2221 sscanf (buf, "%x", &temp);
2224 for (i = 0; i < length; i++, j++)
2225 buf[i] = scanner->value.v_string[j];
2228 sscanf (buf, "%x", &temp);
2229 color->green = temp;
2231 for (i = 0; i < length; i++, j++)
2232 buf[i] = scanner->value.v_string[j];
2235 sscanf (buf, "%x", &temp);
2241 color->green *= 4369;
2242 color->blue *= 4369;
2244 else if (length == 2)
2247 color->green *= 257;
2250 else if (length == 3)
2256 return G_TOKEN_NONE;
2259 return G_TOKEN_STRING;
2264 gtk_rc_parse_pixmap_path (GScanner *scanner)
2268 token = g_scanner_get_next_token (scanner);
2269 if (token != GTK_RC_TOKEN_PIXMAP_PATH)
2270 return GTK_RC_TOKEN_PIXMAP_PATH;
2272 token = g_scanner_get_next_token (scanner);
2273 if (token != G_TOKEN_STRING)
2274 return G_TOKEN_STRING;
2276 gtk_rc_parse_pixmap_path_string (scanner->value.v_string);
2278 return G_TOKEN_NONE;
2282 gtk_rc_parse_pixmap_path_string (gchar *pix_path)
2286 gint start_offset = 0;
2290 /* free the old one, or just add to the old one ? */
2291 for (path_num=0; pixmap_path[path_num]; path_num++)
2293 g_free (pixmap_path[path_num]);
2294 pixmap_path[path_num] = NULL;
2299 path_len = strlen (pix_path);
2301 buf = g_strdup (pix_path);
2303 for (end_offset = 0; end_offset <= path_len; end_offset++)
2305 if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2306 (end_offset == path_len))
2308 buf[end_offset] = '\0';
2309 pixmap_path[path_num] = g_strdup (buf + start_offset);
2311 pixmap_path[path_num] = NULL;
2312 start_offset = end_offset + 1;
2316 gtk_rc_append_default_pixmap_path();
2320 gtk_rc_parse_module_path (GScanner *scanner)
2324 token = g_scanner_get_next_token (scanner);
2325 if (token != GTK_RC_TOKEN_MODULE_PATH)
2326 return GTK_RC_TOKEN_MODULE_PATH;
2328 token = g_scanner_get_next_token (scanner);
2329 if (token != G_TOKEN_STRING)
2330 return G_TOKEN_STRING;
2332 gtk_rc_parse_module_path_string (scanner->value.v_string);
2334 return G_TOKEN_NONE;
2338 gtk_rc_parse_module_path_string (gchar *mod_path)
2342 gint start_offset = 0;
2346 /* free the old one, or just add to the old one ? */
2347 for (path_num=0; module_path[path_num]; path_num++)
2349 g_free (module_path[path_num]);
2350 module_path[path_num] = NULL;
2355 path_len = strlen (mod_path);
2357 buf = g_strdup (mod_path);
2359 for (end_offset = 0; end_offset <= path_len; end_offset++)
2361 if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2362 (end_offset == path_len))
2364 buf[end_offset] = '\0';
2365 module_path[path_num] = g_strdup (buf + start_offset);
2367 module_path[path_num] = NULL;
2368 start_offset = end_offset + 1;
2372 gtk_rc_append_default_module_path();
2376 gtk_rc_parse_path_pattern (GScanner *scanner)
2379 GtkPathType path_type;
2381 gboolean is_binding;
2382 GtkPathPriorityType priority = GTK_PATH_PRIO_RC;
2384 token = g_scanner_get_next_token (scanner);
2387 case GTK_RC_TOKEN_WIDGET:
2388 path_type = GTK_PATH_WIDGET;
2390 case GTK_RC_TOKEN_WIDGET_CLASS:
2391 path_type = GTK_PATH_WIDGET_CLASS;
2393 case GTK_RC_TOKEN_CLASS:
2394 path_type = GTK_PATH_CLASS;
2397 return GTK_RC_TOKEN_WIDGET_CLASS;
2400 token = g_scanner_get_next_token (scanner);
2401 if (token != G_TOKEN_STRING)
2402 return G_TOKEN_STRING;
2404 pattern = g_strdup (scanner->value.v_string);
2406 token = g_scanner_get_next_token (scanner);
2407 if (token == GTK_RC_TOKEN_STYLE)
2409 else if (token == GTK_RC_TOKEN_BINDING)
2412 if (g_scanner_peek_next_token (scanner) == ':')
2414 token = gtk_rc_parse_priority (scanner, &priority);
2415 if (token != G_TOKEN_NONE)
2425 return GTK_RC_TOKEN_STYLE;
2428 token = g_scanner_get_next_token (scanner);
2429 if (token != G_TOKEN_STRING)
2432 return G_TOKEN_STRING;
2437 GtkBindingSet *binding;
2439 binding = gtk_binding_set_find (scanner->value.v_string);
2443 return G_TOKEN_STRING;
2445 gtk_binding_set_add_path (binding, path_type, pattern, priority);
2449 GtkRcStyle *rc_style;
2452 rc_style = gtk_rc_style_find (scanner->value.v_string);
2457 return G_TOKEN_STRING;
2460 rc_set = g_new (GtkRcSet, 1);
2461 gtk_pattern_spec_init (&rc_set->pspec, pattern);
2462 rc_set->rc_style = rc_style;
2464 if (path_type == GTK_PATH_WIDGET)
2465 gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set);
2466 else if (path_type == GTK_PATH_WIDGET_CLASS)
2467 gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set);
2469 gtk_rc_sets_class = g_slist_prepend (gtk_rc_sets_class, rc_set);
2473 return G_TOKEN_NONE;
2477 typedef GdkPixmap * (*GtkImageLoader) (GdkWindow *window,
2478 GdkColormap *colormap,
2480 GdkColor *transparent_color,
2481 const gchar *filename);
2485 gtk_rc_set_image_loader(GtkImageLoader loader)
2487 image_loader = loader;
2491 gtk_rc_load_image (GdkColormap *colormap,
2492 GdkColor *transparent_color,
2493 const gchar *filename)
2495 if (strcmp (filename, "<parent>") == 0)
2496 return (GdkPixmap*) GDK_PARENT_RELATIVE;
2500 return image_loader(NULL, colormap, NULL,
2504 return gdk_pixmap_colormap_create_from_xpm (NULL, colormap, NULL,