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 Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
35 #ifdef HAVE_SYS_PARAM_H
36 #include <sys/param.h>
48 #include "gdkconfig.h"
50 #include "gtkversion.h"
52 #include "gtkbindings.h"
53 #include "gtkthemes.h"
55 #include "gtkiconfactory.h"
56 #include "gtksettings.h"
57 #include "gtkwindow.h"
63 typedef struct _GtkRcSet GtkRcSet;
64 typedef struct _GtkRcNode GtkRcNode;
65 typedef struct _GtkRcFile GtkRcFile;
78 gchar *canonical_name;
82 #define GTK_RC_MAX_PIXMAP_PATHS 128
86 GHashTable *rc_style_ht;
87 GtkSettings *settings;
88 GSList *rc_sets_widget;
89 GSList *rc_sets_widget_class;
90 GSList *rc_sets_class;
92 /* The files we have parsed, to reread later if necessary */
96 gchar *key_theme_name;
98 gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
100 gint default_priority;
103 static GtkRcContext *gtk_rc_context_get (GtkSettings *settings);
105 static guint gtk_rc_style_hash (const gchar *name);
106 static gboolean gtk_rc_style_equal (const gchar *a,
108 static guint gtk_rc_styles_hash (const GSList *rc_styles);
109 static gboolean gtk_rc_styles_equal (const GSList *a,
111 static GtkRcStyle* gtk_rc_style_find (GtkRcContext *context,
113 static GSList * gtk_rc_styles_match (GSList *rc_styles,
117 const gchar *path_reversed);
118 static GtkStyle * gtk_rc_style_to_style (GtkRcStyle *rc_style);
119 static GtkStyle* gtk_rc_init_style (GSList *rc_styles);
120 static void gtk_rc_parse_default_files (GtkRcContext *context);
121 static void gtk_rc_parse_named (GtkRcContext *context,
124 static void gtk_rc_parse_file (GtkRcContext *context,
125 const gchar *filename,
128 static void gtk_rc_parse_any (GtkRcContext *context,
129 const gchar *input_name,
131 const gchar *input_string);
132 static guint gtk_rc_parse_statement (GtkRcContext *context,
134 static guint gtk_rc_parse_style (GtkRcContext *context,
136 static guint gtk_rc_parse_assignment (GScanner *scanner,
137 GtkRcProperty *prop);
138 static guint gtk_rc_parse_bg (GScanner *scanner,
140 static guint gtk_rc_parse_fg (GScanner *scanner,
142 static guint gtk_rc_parse_text (GScanner *scanner,
144 static guint gtk_rc_parse_base (GScanner *scanner,
146 static guint gtk_rc_parse_xthickness (GScanner *scanner,
148 static guint gtk_rc_parse_ythickness (GScanner *scanner,
150 static guint gtk_rc_parse_bg_pixmap (GtkRcContext *context,
152 GtkRcStyle *rc_style);
153 static guint gtk_rc_parse_font (GScanner *scanner,
154 GtkRcStyle *rc_style);
155 static guint gtk_rc_parse_fontset (GScanner *scanner,
156 GtkRcStyle *rc_style);
157 static guint gtk_rc_parse_font_name (GScanner *scanner,
158 GtkRcStyle *rc_style);
159 static guint gtk_rc_parse_engine (GtkRcContext *context,
161 GtkRcStyle **rc_style);
162 static guint gtk_rc_parse_pixmap_path (GtkRcContext *context,
164 static void gtk_rc_parse_pixmap_path_string (GtkRcContext *context,
166 const gchar *pix_path);
167 static guint gtk_rc_parse_module_path (GScanner *scanner);
168 static void gtk_rc_parse_module_path_string (const gchar *mod_path);
169 static guint gtk_rc_parse_im_module_path (GScanner *scanner);
170 static guint gtk_rc_parse_im_module_file (GScanner *scanner);
171 static guint gtk_rc_parse_path_pattern (GtkRcContext *context,
173 static guint gtk_rc_parse_stock (GtkRcContext *context,
175 GtkRcStyle *rc_style,
176 GtkIconFactory *factory);
177 static void gtk_rc_clear_hash_node (gpointer key,
180 static void gtk_rc_clear_styles (GtkRcContext *context);
181 static void gtk_rc_append_default_module_path (void);
182 static void gtk_rc_add_initial_default_files (void);
184 static void gtk_rc_style_init (GtkRcStyle *style);
185 static void gtk_rc_style_class_init (GtkRcStyleClass *klass);
186 static void gtk_rc_style_finalize (GObject *object);
187 static void gtk_rc_style_real_merge (GtkRcStyle *dest,
189 static GtkRcStyle* gtk_rc_style_real_create_rc_style (GtkRcStyle *rc_style);
190 static GtkStyle* gtk_rc_style_real_create_style (GtkRcStyle *rc_style);
191 static gint gtk_rc_properties_cmp (gconstpointer bsearch_node1,
192 gconstpointer bsearch_node2);
194 static gpointer parent_class = NULL;
196 static const GScannerConfig gtk_rc_scanner_config =
200 ) /* cset_skip_characters */,
205 ) /* cset_identifier_first */,
210 ) /* cset_identifier_nth */,
211 ( "#\n" ) /* cpair_comment_single */,
213 TRUE /* case_sensitive */,
215 TRUE /* skip_comment_multi */,
216 TRUE /* skip_comment_single */,
217 TRUE /* scan_comment_multi */,
218 TRUE /* scan_identifier */,
219 FALSE /* scan_identifier_1char */,
220 FALSE /* scan_identifier_NULL */,
221 TRUE /* scan_symbols */,
222 TRUE /* scan_binary */,
223 TRUE /* scan_octal */,
224 TRUE /* scan_float */,
226 TRUE /* scan_hex_dollar */,
227 TRUE /* scan_string_sq */,
228 TRUE /* scan_string_dq */,
229 TRUE /* numbers_2_int */,
230 FALSE /* int_2_float */,
231 FALSE /* identifier_2_string */,
232 TRUE /* char_2_token */,
233 TRUE /* symbol_2_token */,
234 FALSE /* scope_0_fallback */,
242 { "include", GTK_RC_TOKEN_INCLUDE },
243 { "NORMAL", GTK_RC_TOKEN_NORMAL },
244 { "ACTIVE", GTK_RC_TOKEN_ACTIVE },
245 { "PRELIGHT", GTK_RC_TOKEN_PRELIGHT },
246 { "SELECTED", GTK_RC_TOKEN_SELECTED },
247 { "INSENSITIVE", GTK_RC_TOKEN_INSENSITIVE },
248 { "fg", GTK_RC_TOKEN_FG },
249 { "bg", GTK_RC_TOKEN_BG },
250 { "text", GTK_RC_TOKEN_TEXT },
251 { "base", GTK_RC_TOKEN_BASE },
252 { "xthickness", GTK_RC_TOKEN_XTHICKNESS },
253 { "ythickness", GTK_RC_TOKEN_YTHICKNESS },
254 { "font", GTK_RC_TOKEN_FONT },
255 { "fontset", GTK_RC_TOKEN_FONTSET },
256 { "font_name", GTK_RC_TOKEN_FONT_NAME },
257 { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP },
258 { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH },
259 { "style", GTK_RC_TOKEN_STYLE },
260 { "binding", GTK_RC_TOKEN_BINDING },
261 { "bind", GTK_RC_TOKEN_BIND },
262 { "widget", GTK_RC_TOKEN_WIDGET },
263 { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS },
264 { "class", GTK_RC_TOKEN_CLASS },
265 { "lowest", GTK_RC_TOKEN_LOWEST },
266 { "gtk", GTK_RC_TOKEN_GTK },
267 { "application", GTK_RC_TOKEN_APPLICATION },
268 { "theme", GTK_RC_TOKEN_THEME },
269 { "rc", GTK_RC_TOKEN_RC },
270 { "highest", GTK_RC_TOKEN_HIGHEST },
271 { "engine", GTK_RC_TOKEN_ENGINE },
272 { "module_path", GTK_RC_TOKEN_MODULE_PATH },
273 { "stock", GTK_RC_TOKEN_STOCK },
274 { "im_module_path", GTK_RC_TOKEN_IM_MODULE_PATH },
275 { "im_module_file", GTK_RC_TOKEN_IM_MODULE_FILE },
276 { "LTR", GTK_RC_TOKEN_LTR },
277 { "RTL", GTK_RC_TOKEN_RTL }
280 static GHashTable *realized_style_ht = NULL;
282 static gchar *im_module_path = NULL;
283 static gchar *im_module_file = NULL;
285 #define GTK_RC_MAX_DEFAULT_FILES 128
286 static gchar *gtk_rc_default_files[GTK_RC_MAX_DEFAULT_FILES];
288 #define GTK_RC_MAX_MODULE_PATHS 128
289 static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
291 /* A stack of directories for RC files we are parsing currently.
292 * these are implicitely added to the end of PIXMAP_PATHS
294 static GSList *rc_dir_stack = NULL;
296 /* RC file handling */
300 get_gtk_win32_directory (gchar *subdir)
302 static gchar *gtk_dll = NULL;
305 gtk_dll = g_strdup_printf ("gtk-win32-%d.%d.dll", GTK_MAJOR_VERSION, GTK_MINOR_VERSION);
307 if (subdir && strlen(subdir) > 0)
308 return g_win32_get_package_installation_subdirectory (GETTEXT_PACKAGE,
312 return g_win32_get_package_installation_directory (GETTEXT_PACKAGE,
315 #endif /* G_OS_WIN32 */
318 gtk_rc_make_default_dir (const gchar *type)
323 var = getenv("GTK_EXE_PREFIX");
325 path = g_build_filename (var, "lib", "gtk-2.0", type, GTK_BINARY_VERSION, NULL);
327 path = g_build_filename (GTK_LIBDIR, "gtk-2.0,", type, GTK_BINARY_VERSION, NULL);
329 path = g_build_filename (get_gtk_win32_directory (""), type, NULL);
336 gtk_rc_get_im_module_path (void)
338 const gchar *result = g_getenv ("GTK_IM_MODULE_PATH");
343 result = im_module_path;
345 return gtk_rc_make_default_dir ("immodules");
348 return g_strdup (result);
352 gtk_rc_get_im_module_file (void)
354 gchar *result = g_strdup (g_getenv ("GTK_IM_MODULE_FILE"));
359 result = g_strdup (im_module_file);
362 result = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gtk.immodules", NULL);
364 result = g_build_filename (get_gtk_win32_directory ("gtk-2.0"), "gtk.immodules", NULL);
372 gtk_rc_get_theme_dir(void)
377 var = getenv("GTK_DATA_PREFIX");
379 path = g_build_filename (var, "share", "themes", NULL);
381 path = g_build_filename (GTK_DATA_PREFIX, "share", "themes", NULL);
383 path = g_build_filename (get_gtk_win32_directory (""), "themes", NULL);
390 gtk_rc_get_module_dir(void)
392 return gtk_rc_make_default_dir ("engines");
396 gtk_rc_append_default_module_path(void)
402 for (n = 0; module_path[n]; n++) ;
403 if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
407 var = getenv("GTK_EXE_PREFIX");
409 path = g_build_filename (var, "lib", "gtk-2.0", GTK_VERSION, "engines", NULL);
411 path = g_build_filename (GTK_LIBDIR, "gtk-2.0", GTK_VERSION, "engines", NULL);
413 path = g_build_filename (get_gtk_win32_directory ("gtk-2.0"), GTK_VERSION, "engines", NULL);
415 module_path[n++] = path;
417 var = g_get_home_dir ();
420 path = g_build_filename (var, ".gtk-2.0", GTK_VERSION, "engines", NULL);
421 module_path[n++] = path;
423 module_path[n] = NULL;
427 gtk_rc_add_initial_default_files (void)
429 static gint init = FALSE;
438 gtk_rc_default_files[0] = NULL;
441 var = g_getenv("GTK_RC_FILES");
444 files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
448 gtk_rc_add_default_file (files[i]);
456 str = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gtkrc", NULL);
458 str = g_build_filename (get_gtk_win32_directory (""), "gtkrc", NULL);
461 gtk_rc_add_default_file (str);
464 var = g_get_home_dir ();
467 str = g_build_filename (var, ".gtkrc-2.0", NULL);
468 gtk_rc_add_default_file (str);
475 * gtk_rc_add_default_file:
476 * @filename: the pathname to the file.
478 * Adds a file to the list of files to be parsed at the
482 gtk_rc_add_default_file (const gchar *filename)
486 gtk_rc_add_initial_default_files ();
488 for (n = 0; gtk_rc_default_files[n]; n++) ;
489 if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
492 gtk_rc_default_files[n++] = g_strdup (filename);
493 gtk_rc_default_files[n] = NULL;
497 * gtk_rc_set_default_files:
498 * @filenames: A %NULL terminated list of filenames.
500 * Sets the list of files that GTK+ will read at the
504 gtk_rc_set_default_files (gchar **filenames)
508 gtk_rc_add_initial_default_files ();
511 while (gtk_rc_default_files[i])
513 g_free (gtk_rc_default_files[i]);
517 gtk_rc_default_files[0] = NULL;
520 while (filenames[i] != NULL)
522 gtk_rc_add_default_file (filenames[i]);
528 * gtk_rc_get_default_files:
530 * Retrieves the current list of RC files that will be parsed
531 * at the end of gtk_init()
533 * Return value: A NULL terminated array of filenames. This memory
534 * is owned by GTK+ and must not be freed by the application.
535 * If you want to store this information, you should make a
539 gtk_rc_get_default_files (void)
541 gtk_rc_add_initial_default_files ();
543 return gtk_rc_default_files;
546 /* The following routine is based on _nl_normalize_codeset from
547 * the GNU C library. Contributed by
549 * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
550 * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
552 * Normalize codeset name. There is no standard for the codeset
553 * names. Normalization allows the user to use any of the common
557 _gtk_normalize_codeset (const gchar *codeset, gint name_len)
565 for (cnt = 0; cnt < name_len; ++cnt)
566 if (isalnum (codeset[cnt]))
570 if (isalpha (codeset[cnt]))
574 retval = g_malloc ((only_digit ? 3 : 0) + len + 1);
578 memcpy (retval, "iso", 4);
584 for (cnt = 0; cnt < name_len; ++cnt)
585 if (isalpha (codeset[cnt]))
586 *wp++ = isupper(codeset[cnt]) ? tolower (codeset[cnt]) : codeset[cnt];
587 else if (isdigit (codeset[cnt]))
588 *wp++ = codeset[cnt];
596 gtk_rc_settings_changed (GtkSettings *settings,
598 GtkRcContext *context)
600 gchar *new_theme_name;
601 gchar *new_key_theme_name;
603 g_object_get (settings,
604 "gtk-theme-name", &new_theme_name,
605 "gtk-key-theme-name", &new_key_theme_name,
608 if ((new_theme_name != context->theme_name &&
609 !(new_theme_name && context->theme_name && strcmp (new_theme_name, context->theme_name) == 0)) ||
610 (new_key_theme_name != context->key_theme_name &&
611 !(new_key_theme_name && context->key_theme_name && strcmp (new_key_theme_name, context->key_theme_name) == 0)))
613 gtk_rc_reparse_all_for_settings (settings, TRUE);
616 g_free (new_theme_name);
617 g_free (new_key_theme_name);
620 static GtkRcContext *
621 gtk_rc_context_get (GtkSettings *settings)
623 if (!settings->rc_context)
625 GtkRcContext *context = settings->rc_context = g_new (GtkRcContext, 1);
627 context->settings = settings;
628 context->rc_style_ht = NULL;
629 context->rc_sets_widget = NULL;
630 context->rc_sets_widget_class = NULL;
631 context->rc_sets_class = NULL;
632 context->rc_files = NULL;
634 g_object_get (settings,
635 "gtk-theme-name", &context->theme_name,
636 "gtk-key-theme-name", &context->key_theme_name,
639 g_signal_connect (settings,
640 "notify::gtk-theme-name",
641 G_CALLBACK (gtk_rc_settings_changed),
643 g_signal_connect (settings,
644 "notify::gtk-key-theme-name",
645 G_CALLBACK (gtk_rc_settings_changed),
648 context->pixmap_path[0] = NULL;
650 context->default_priority = GTK_PATH_PRIO_RC;
653 return settings->rc_context;
657 gtk_rc_parse_named (GtkRcContext *context,
662 const gchar *home_dir;
666 subpath = g_strconcat ("gtk-2.0-", type,
667 G_DIR_SEPARATOR_S "gtkrc",
670 subpath = g_strdup ("gtk-2.0" G_DIR_SEPARATOR_S "gtkrc");
672 /* First look in the users home directory
674 home_dir = g_get_home_dir ();
677 path = g_build_filename (home_dir, ".themes", name, subpath, NULL);
678 if (!g_file_test (path, G_FILE_TEST_EXISTS))
687 gchar *theme_dir = gtk_rc_get_theme_dir ();
688 path = g_build_filename (theme_dir, name, subpath, NULL);
691 if (!g_file_test (path, G_FILE_TEST_EXISTS))
700 gtk_rc_parse_file (context, path, GTK_PATH_PRIO_THEME, FALSE);
708 gtk_rc_parse_default_files (GtkRcContext *context)
710 gchar *locale_suffixes[3];
711 gint n_locale_suffixes = 0;
718 locale = g_win32_getlocale ();
720 locale = setlocale (LC_CTYPE, NULL);
723 if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
725 /* Determine locale-specific suffixes for RC files
727 * We normalize the charset into a standard form,
728 * which has all '-' and '_' characters removed,
731 gchar *normalized_locale;
733 p = strchr (locale, '@');
734 length = p ? (p -locale) : strlen (locale);
736 p = strchr (locale, '.');
739 gchar *tmp1 = g_strndup (locale, p - locale + 1);
740 gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
742 normalized_locale = g_strconcat (tmp1, tmp2, NULL);
746 locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
750 normalized_locale = g_strndup (locale, length);
752 p = strchr (normalized_locale, '_');
755 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
756 length = p - normalized_locale;
759 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
761 g_free (normalized_locale);
764 for (i = 0; gtk_rc_default_files[i] != NULL; i++)
766 /* Try to find a locale specific RC file corresponding to the
767 * current locale to parse before the default file.
769 for (j = n_locale_suffixes - 1; j >= 0; j--)
771 gchar *name = g_strconcat (gtk_rc_default_files[i],
775 gtk_rc_parse_file (context, name, GTK_PATH_PRIO_RC, FALSE);
778 gtk_rc_parse_file (context, gtk_rc_default_files[i], GTK_PATH_PRIO_RC, FALSE);
781 for (j = 0; j < n_locale_suffixes; j++)
782 g_free (locale_suffixes[j]);
788 static gboolean initialized = FALSE;
794 module_path[0] = NULL;
795 gtk_rc_append_default_module_path();
797 gtk_rc_add_initial_default_files ();
800 gtk_rc_reparse_all_for_settings (gtk_settings_get_default (), TRUE);
804 gtk_rc_parse_string (const gchar *rc_string)
806 g_return_if_fail (rc_string != NULL);
808 gtk_rc_parse_any (gtk_rc_context_get (gtk_settings_get_default ()),
809 "-", -1, rc_string); /* FIXME */
813 gtk_rc_parse_file (GtkRcContext *context,
814 const gchar *filename,
818 GtkRcFile *rc_file = NULL;
823 g_return_if_fail (filename != NULL);
825 saved_priority = context->default_priority;
826 context->default_priority = priority;
828 tmp_list = context->rc_files;
831 rc_file = tmp_list->data;
832 if (!strcmp (rc_file->name, filename))
835 tmp_list = tmp_list->next;
840 rc_file = g_new (GtkRcFile, 1);
841 rc_file->name = g_strdup (filename);
842 rc_file->canonical_name = NULL;
844 rc_file->reload = reload;
846 context->rc_files = g_slist_append (context->rc_files, rc_file);
849 if (!rc_file->canonical_name)
851 /* Get the absolute pathname */
853 if (g_path_is_absolute (rc_file->name))
854 rc_file->canonical_name = rc_file->name;
859 cwd = g_get_current_dir ();
860 rc_file->canonical_name = g_build_filename (cwd, rc_file->name, NULL);
865 if (!lstat (rc_file->canonical_name, &statbuf))
870 rc_file->mtime = statbuf.st_mtime;
872 fd = open (rc_file->canonical_name, O_RDONLY);
876 /* Temporarily push directory name for this file on
877 * a stack of directory names while parsing it
880 g_slist_prepend (rc_dir_stack,
881 g_path_get_dirname (rc_file->canonical_name));
882 gtk_rc_parse_any (context, filename, fd, NULL);
884 tmp_list = rc_dir_stack;
885 rc_dir_stack = rc_dir_stack->next;
887 g_free (tmp_list->data);
888 g_slist_free_1 (tmp_list);
894 context->default_priority = saved_priority;
898 gtk_rc_parse (const gchar *filename)
900 g_return_if_fail (filename != NULL);
902 gtk_rc_parse_file (gtk_rc_context_get (gtk_settings_get_default ()),
903 filename, GTK_PATH_PRIO_RC, TRUE); /* FIXME */
906 /* Handling of RC styles */
909 gtk_rc_style_get_type (void)
911 static GType object_type = 0;
915 static const GTypeInfo object_info =
917 sizeof (GtkRcStyleClass),
918 (GBaseInitFunc) NULL,
919 (GBaseFinalizeFunc) NULL,
920 (GClassInitFunc) gtk_rc_style_class_init,
921 NULL, /* class_finalize */
922 NULL, /* class_data */
925 (GInstanceInitFunc) gtk_rc_style_init,
928 object_type = g_type_register_static (G_TYPE_OBJECT,
937 gtk_rc_style_init (GtkRcStyle *style)
942 style->font_desc = NULL;
944 for (i = 0; i < 5; i++)
946 static const GdkColor init_color = { 0, 0, 0, 0, };
948 style->bg_pixmap_name[i] = NULL;
949 style->color_flags[i] = 0;
950 style->fg[i] = init_color;
951 style->bg[i] = init_color;
952 style->text[i] = init_color;
953 style->base[i] = init_color;
955 style->xthickness = -1;
956 style->ythickness = -1;
957 style->rc_properties = NULL;
959 style->rc_style_lists = NULL;
960 style->icon_factories = NULL;
964 gtk_rc_style_class_init (GtkRcStyleClass *klass)
966 GObjectClass *object_class = G_OBJECT_CLASS (klass);
968 parent_class = g_type_class_peek_parent (klass);
970 object_class->finalize = gtk_rc_style_finalize;
973 klass->create_rc_style = gtk_rc_style_real_create_rc_style;
974 klass->merge = gtk_rc_style_real_merge;
975 klass->create_style = gtk_rc_style_real_create_style;
979 gtk_rc_style_finalize (GObject *object)
981 GSList *tmp_list1, *tmp_list2;
982 GtkRcStyle *rc_style;
985 rc_style = GTK_RC_STYLE (object);
988 g_free (rc_style->name);
989 if (rc_style->font_desc)
990 pango_font_description_free (rc_style->font_desc);
992 for (i = 0; i < 5; i++)
993 if (rc_style->bg_pixmap_name[i])
994 g_free (rc_style->bg_pixmap_name[i]);
996 /* Now remove all references to this rc_style from
999 tmp_list1 = rc_style->rc_style_lists;
1002 GSList *rc_styles = tmp_list1->data;
1003 GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
1004 gtk_style_unref (style);
1006 /* Remove the list of styles from the other rc_styles
1009 tmp_list2 = rc_styles;
1012 GtkRcStyle *other_style = tmp_list2->data;
1014 if (other_style != rc_style)
1015 other_style->rc_style_lists = g_slist_remove_all (other_style->rc_style_lists,
1017 tmp_list2 = tmp_list2->next;
1020 /* And from the hash table itself
1022 g_hash_table_remove (realized_style_ht, rc_styles);
1023 g_slist_free (rc_styles);
1025 tmp_list1 = tmp_list1->next;
1027 g_slist_free (rc_style->rc_style_lists);
1029 if (rc_style->rc_properties)
1033 for (i = 0; i < rc_style->rc_properties->len; i++)
1035 GtkRcProperty *node = &g_array_index (rc_style->rc_properties, GtkRcProperty, i);
1037 g_free (node->origin);
1038 g_value_unset (&node->value);
1040 g_array_free (rc_style->rc_properties, TRUE);
1041 rc_style->rc_properties = NULL;
1044 tmp_list1 = rc_style->icon_factories;
1047 g_object_unref (G_OBJECT (tmp_list1->data));
1049 tmp_list1 = tmp_list1->next;
1051 g_slist_free (rc_style->icon_factories);
1053 G_OBJECT_CLASS (parent_class)->finalize (object);
1057 gtk_rc_style_new (void)
1061 style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
1067 * gtk_rc_style_copy:
1068 * @orig: the style to copy
1070 * Make a copy of the specified #GtkRcStyle. This function
1071 * will correctly copy an rc style that is a member of a class
1072 * derived from #GtkRcStyle.
1074 * Return value: the resulting #GtkRcStyle
1077 gtk_rc_style_copy (GtkRcStyle *orig)
1081 g_return_val_if_fail (GTK_IS_RC_STYLE (orig), NULL);
1083 style = GTK_RC_STYLE_GET_CLASS (orig)->create_rc_style (orig);
1084 GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
1090 gtk_rc_style_ref (GtkRcStyle *rc_style)
1092 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1094 g_object_ref (G_OBJECT (rc_style));
1098 gtk_rc_style_unref (GtkRcStyle *rc_style)
1100 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1102 g_object_unref (G_OBJECT (rc_style));
1106 gtk_rc_style_real_create_rc_style (GtkRcStyle *style)
1108 return GTK_RC_STYLE (g_object_new (G_OBJECT_TYPE (style), NULL));
1112 gtk_rc_properties_cmp (gconstpointer bsearch_node1,
1113 gconstpointer bsearch_node2)
1115 const GtkRcProperty *prop1 = bsearch_node1;
1116 const GtkRcProperty *prop2 = bsearch_node2;
1118 if (prop1->type_name == prop2->type_name)
1119 return prop1->property_name < prop2->property_name ? -1 : prop1->property_name == prop2->property_name ? 0 : 1;
1121 return prop1->type_name < prop2->type_name ? -1 : 1;
1125 insert_rc_property (GtkRcStyle *style,
1126 GtkRcProperty *property,
1130 GtkRcProperty *new_property = NULL;
1131 GtkRcProperty key = { 0, 0, NULL, { 0, }, };
1133 key.type_name = property->type_name;
1134 key.property_name = property->property_name;
1136 if (!style->rc_properties)
1137 style->rc_properties = g_array_new (FALSE, FALSE, sizeof (GtkRcProperty));
1140 while (i < style->rc_properties->len)
1142 gint cmp = gtk_rc_properties_cmp (&key, &g_array_index (style->rc_properties, GtkRcProperty, i));
1148 new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
1150 g_free (new_property->origin);
1151 g_value_unset (&new_property->value);
1153 *new_property = key;
1167 g_array_insert_val (style->rc_properties, i, key);
1168 new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
1171 new_property->origin = g_strdup (property->origin);
1172 g_value_init (&new_property->value, G_VALUE_TYPE (&property->value));
1173 g_value_copy (&property->value, &new_property->value);
1177 gtk_rc_style_real_merge (GtkRcStyle *dest,
1182 for (i = 0; i < 5; i++)
1184 if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
1185 dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
1187 if (!(dest->color_flags[i] & GTK_RC_FG) &&
1188 src->color_flags[i] & GTK_RC_FG)
1190 dest->fg[i] = src->fg[i];
1191 dest->color_flags[i] |= GTK_RC_FG;
1193 if (!(dest->color_flags[i] & GTK_RC_BG) &&
1194 src->color_flags[i] & GTK_RC_BG)
1196 dest->bg[i] = src->bg[i];
1197 dest->color_flags[i] |= GTK_RC_BG;
1199 if (!(dest->color_flags[i] & GTK_RC_TEXT) &&
1200 src->color_flags[i] & GTK_RC_TEXT)
1202 dest->text[i] = src->text[i];
1203 dest->color_flags[i] |= GTK_RC_TEXT;
1205 if (!(dest->color_flags[i] & GTK_RC_BASE) &&
1206 src->color_flags[i] & GTK_RC_BASE)
1208 dest->base[i] = src->base[i];
1209 dest->color_flags[i] |= GTK_RC_BASE;
1213 if (dest->xthickness < 0 && src->xthickness >= 0)
1214 dest->xthickness = src->xthickness;
1215 if (dest->ythickness < 0 && src->ythickness >= 0)
1216 dest->ythickness = src->ythickness;
1218 if (!dest->font_desc && src->font_desc)
1219 dest->font_desc = pango_font_description_copy (src->font_desc);
1221 if (src->rc_properties)
1225 for (i = 0; i < src->rc_properties->len; i++)
1226 insert_rc_property (dest,
1227 &g_array_index (src->rc_properties, GtkRcProperty, i),
1233 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
1235 return gtk_style_new ();
1239 gtk_rc_clear_hash_node (gpointer key,
1243 gtk_rc_style_unref (data);
1247 gtk_rc_free_rc_sets (GSList *slist)
1253 rc_set = slist->data;
1254 g_pattern_spec_free (rc_set->pspec);
1257 slist = slist->next;
1262 gtk_rc_clear_styles (GtkRcContext *context)
1264 /* Clear out all old rc_styles */
1266 if (context->rc_style_ht)
1268 g_hash_table_foreach (context->rc_style_ht, gtk_rc_clear_hash_node, NULL);
1269 g_hash_table_destroy (context->rc_style_ht);
1270 context->rc_style_ht = NULL;
1273 gtk_rc_free_rc_sets (context->rc_sets_widget);
1274 g_slist_free (context->rc_sets_widget);
1275 context->rc_sets_widget = NULL;
1277 gtk_rc_free_rc_sets (context->rc_sets_widget_class);
1278 g_slist_free (context->rc_sets_widget_class);
1279 context->rc_sets_widget_class = NULL;
1281 gtk_rc_free_rc_sets (context->rc_sets_class);
1282 g_slist_free (context->rc_sets_class);
1283 context->rc_sets_class = NULL;
1286 /* Reset all our widgets. Also, we have to invalidate cached icons in
1287 * icon sets so they get re-rendered.
1290 gtk_rc_reset_widgets (GtkRcContext *context)
1292 GList *list, *toplevels;
1294 _gtk_icon_set_invalidate_caches ();
1296 toplevels = gtk_window_list_toplevels ();
1297 g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1299 for (list = toplevels; list; list = list->next)
1301 gtk_widget_reset_rc_styles (list->data);
1302 gtk_widget_unref (list->data);
1304 g_list_free (toplevels);
1308 * gtk_rc_reparse_all_for_settings:
1309 * @settings: a #GtkSettings
1310 * @force_load: load whether or not anything changed
1312 * If the modification time on any previously read file
1313 * for the given GtkSettings has changed, discard all style information
1314 * and then reread all previously read RC files.
1316 * Return value: %TRUE if the files were reread.
1319 gtk_rc_reparse_all_for_settings (GtkSettings *settings,
1320 gboolean force_load)
1322 gboolean mtime_modified = FALSE;
1325 GtkRcContext *context;
1327 struct stat statbuf;
1329 g_return_val_if_fail (GTK_IS_SETTINGS (settings), FALSE);
1331 context = gtk_rc_context_get (settings);
1335 /* Check through and see if any of the RC's have had their
1336 * mtime modified. If so, reparse everything.
1338 tmp_list = context->rc_files;
1341 rc_file = tmp_list->data;
1343 if (!lstat (rc_file->name, &statbuf) &&
1344 (statbuf.st_mtime > rc_file->mtime))
1346 mtime_modified = TRUE;
1350 tmp_list = tmp_list->next;
1354 if (force_load || mtime_modified)
1358 gtk_rc_clear_styles (context);
1359 g_object_freeze_notify (G_OBJECT (context->settings));
1361 old_files = context->rc_files;
1362 context->rc_files = NULL;
1364 gtk_rc_parse_default_files (context);
1366 tmp_list = old_files;
1369 rc_file = tmp_list->data;
1370 if (rc_file->reload)
1371 gtk_rc_parse_file (context, rc_file->name, GTK_PATH_PRIO_RC, TRUE);
1373 if (rc_file->canonical_name != rc_file->name)
1374 g_free (rc_file->canonical_name);
1375 g_free (rc_file->name);
1378 tmp_list = tmp_list->next;
1381 g_slist_free (old_files);;
1383 g_free (context->theme_name);
1384 g_free (context->key_theme_name);
1385 g_object_get (context->settings,
1386 "gtk-theme-name", &context->theme_name,
1387 "gtk-key-theme-name", &context->key_theme_name,
1390 if (context->theme_name && context->theme_name[0])
1391 gtk_rc_parse_named (context, context->theme_name, NULL);
1392 if (context->key_theme_name && context->key_theme_name[0])
1393 gtk_rc_parse_named (context, context->key_theme_name, "key");
1395 g_object_thaw_notify (G_OBJECT (context->settings));
1397 gtk_rc_reset_widgets (context);
1400 return mtime_modified;
1404 * gtk_rc_reparse_all:
1406 * If the modification time on any previously read file for the
1407 * default #GtkSettings has changed, discard all style information
1408 * and then reread all previously read RC files.
1410 * Return value: %TRUE if the files were reread.
1413 gtk_rc_reparse_all (void)
1415 return gtk_rc_reparse_all_for_settings (gtk_settings_get_default (), FALSE);
1419 gtk_rc_styles_match (GSList *rc_styles,
1423 const gchar *path_reversed)
1430 rc_set = sets->data;
1433 if (g_pattern_match (rc_set->pspec, path_length, path, path_reversed))
1434 rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
1442 * @widget: a #GtkWidget
1444 * Finds all matching RC styles for a given widget,
1445 * composites them together, and then creates a
1446 * #GtkStyle representing the composite appearance.
1447 * (GTK+ actually keeps a cache of previously
1448 * created styles, so a new style may not be
1451 * Returns: the resulting style. No refcount is added
1452 * to the returned style, so if you want to save this
1453 * style around, you should add a reference yourself.
1456 gtk_rc_get_style (GtkWidget *widget)
1458 GtkRcStyle *widget_rc_style;
1459 GSList *rc_styles = NULL;
1460 GtkRcContext *context;
1462 static guint rc_style_key_id = 0;
1464 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1466 context = gtk_rc_context_get (gtk_widget_get_settings (widget));
1468 /* We allow the specification of a single rc style to be bound
1469 * tightly to a widget, for application modifications
1471 if (!rc_style_key_id)
1472 rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1474 widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
1477 if (widget_rc_style)
1478 rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
1480 if (context->rc_sets_widget)
1482 gchar *path, *path_reversed;
1485 gtk_widget_path (widget, &path_length, &path, &path_reversed);
1486 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, path, path_reversed);
1488 g_free (path_reversed);
1491 if (context->rc_sets_widget_class)
1493 gchar *path, *path_reversed;
1496 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1497 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, path, path_reversed);
1499 g_free (path_reversed);
1502 if (context->rc_sets_class)
1506 type = GTK_OBJECT_TYPE (widget);
1510 gchar *path_reversed;
1513 path = gtk_type_name (type);
1514 path_length = strlen (path);
1515 path_reversed = g_strdup (path);
1516 g_strreverse (path_reversed);
1518 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
1519 g_free (path_reversed);
1521 type = gtk_type_parent (type);
1526 return gtk_rc_init_style (rc_styles);
1532 * gtk_rc_get_style_by_paths:
1533 * @settings: a #GtkSettings object
1534 * @widget_path: the widget path to use when looking up the style, or %NULL
1535 * @class_path: the class path to use when looking up the style, or %NULL
1536 * @type: a type that will be used along with parent types of this type
1537 * when matching against class styles, or G_TYPE_NONE
1539 * Creates up a #GtkStyle from styles defined in a RC file by providing
1540 * the raw components used in matching. This function may be useful
1541 * when creating pseudo-widgets that should be themed like widgets but
1542 * don't actually have corresponding GTK+ widgets. An example of this
1543 * would be items inside a GNOME canvas widget.
1545 * The action of gtk_rc_get_style() is similar to:
1547 * gtk_widget_path (widget, NULL, &path, NULL);
1548 * gtk_widget_class_path (widget, NULL, &class_path, NULL);
1549 * gtk_rc_get_style_by_paths (gtk_widget_get_settings (widget), path, class_path,
1550 * G_OBJECT_TYPE (widget));
1552 * Return value: A style created by matching with the supplied paths,
1553 * or %NULL if nothign matching was specified and the default style should
1554 * be used. The returned value is owned by GTK+ as part of an internal cache,
1555 * so you must call g_object_ref() on the returned value if you want to
1556 * keep a reference to it.
1559 gtk_rc_get_style_by_paths (GtkSettings *settings,
1560 const char *widget_path,
1561 const char *class_path,
1564 /* We duplicate the code from above to avoid slowing down the above
1565 * by generating paths when we don't need them. I don't know if
1566 * this is really worth it.
1568 GSList *rc_styles = NULL;
1569 GtkRcContext *context;
1571 g_return_val_if_fail (GTK_IS_SETTINGS (settings), NULL);
1573 context = gtk_rc_context_get (settings);
1575 if (context->rc_sets_widget)
1577 gchar *path_reversed;
1580 path_length = strlen (widget_path);
1581 path_reversed = g_strdup (widget_path);
1582 g_strreverse (path_reversed);
1584 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, widget_path, path_reversed);
1585 g_free (path_reversed);
1588 if (context->rc_sets_widget_class)
1590 gchar *path_reversed;
1593 path_length = strlen (class_path);
1594 path_reversed = g_strdup (class_path);
1595 g_strreverse (path_reversed);
1597 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, class_path, path_reversed);
1598 g_free (path_reversed);
1601 if (type != G_TYPE_NONE && context->rc_sets_class)
1606 gchar *path_reversed;
1609 path = g_type_name (type);
1610 path_length = strlen (path);
1611 path_reversed = g_strdup (path);
1612 g_strreverse (path_reversed);
1614 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
1615 g_free (path_reversed);
1617 type = g_type_parent (type);
1622 return gtk_rc_init_style (rc_styles);
1628 gtk_rc_add_rc_sets (GSList *slist,
1629 GtkRcStyle *rc_style,
1630 const gchar *pattern)
1632 GtkRcStyle *new_style;
1636 new_style = gtk_rc_style_new ();
1637 *new_style = *rc_style;
1638 new_style->name = g_strdup (rc_style->name);
1639 if (rc_style->font_desc)
1640 new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
1642 for (i = 0; i < 5; i++)
1643 new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1645 rc_set = g_new (GtkRcSet, 1);
1646 rc_set->pspec = g_pattern_spec_new (pattern);
1647 rc_set->rc_style = rc_style;
1649 return g_slist_prepend (slist, rc_set);
1653 gtk_rc_add_widget_name_style (GtkRcStyle *rc_style,
1654 const gchar *pattern)
1656 GtkRcContext *context;
1658 g_return_if_fail (rc_style != NULL);
1659 g_return_if_fail (pattern != NULL);
1661 context = gtk_rc_context_get (gtk_settings_get_default ());
1663 context->rc_sets_widget = gtk_rc_add_rc_sets (context->rc_sets_widget, rc_style, pattern);
1667 gtk_rc_add_widget_class_style (GtkRcStyle *rc_style,
1668 const gchar *pattern)
1670 GtkRcContext *context;
1672 g_return_if_fail (rc_style != NULL);
1673 g_return_if_fail (pattern != NULL);
1675 context = gtk_rc_context_get (gtk_settings_get_default ());
1677 context->rc_sets_widget_class = gtk_rc_add_rc_sets (context->rc_sets_widget_class, rc_style, pattern);
1681 gtk_rc_add_class_style (GtkRcStyle *rc_style,
1682 const gchar *pattern)
1684 GtkRcContext *context;
1686 g_return_if_fail (rc_style != NULL);
1687 g_return_if_fail (pattern != NULL);
1689 context = gtk_rc_context_get (gtk_settings_get_default ());
1691 context->rc_sets_class = gtk_rc_add_rc_sets (context->rc_sets_class, rc_style, pattern);
1695 gtk_rc_scanner_new (void)
1697 return g_scanner_new (>k_rc_scanner_config);
1701 gtk_rc_parse_any (GtkRcContext *context,
1702 const gchar *input_name,
1704 const gchar *input_string)
1710 scanner = gtk_rc_scanner_new ();
1714 g_assert (input_string == NULL);
1716 g_scanner_input_file (scanner, input_fd);
1720 g_assert (input_string != NULL);
1722 g_scanner_input_text (scanner, input_string, strlen (input_string));
1724 scanner->input_name = input_name;
1726 for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1727 g_scanner_scope_add_symbol (scanner, 0, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1732 if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1736 guint expected_token;
1738 expected_token = gtk_rc_parse_statement (context, scanner);
1740 if (expected_token != G_TOKEN_NONE)
1747 if (scanner->scope_id == 0)
1749 /* if we are in scope 0, we know the symbol names
1750 * that are associated with certaintoken values.
1751 * so we look them up to make the error messages
1754 if (expected_token > GTK_RC_TOKEN_INVALID &&
1755 expected_token < GTK_RC_TOKEN_LAST)
1757 for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1758 if (symbols[i].token == expected_token)
1759 msg = symbols[i].name;
1761 msg = g_strconcat ("e.g. `", msg, "'", NULL);
1763 if (scanner->token > GTK_RC_TOKEN_INVALID &&
1764 scanner->token < GTK_RC_TOKEN_LAST)
1766 symbol_name = "???";
1767 for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1768 if (symbols[i].token == scanner->token)
1769 symbol_name = symbols[i].name;
1772 g_scanner_unexp_token (scanner,
1785 g_scanner_destroy (scanner);
1789 gtk_rc_styles_hash (const GSList *rc_styles)
1796 result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1797 rc_styles = rc_styles->next;
1804 gtk_rc_styles_equal (const GSList *a,
1809 if (a->data != b->data)
1819 gtk_rc_style_hash (const gchar *name)
1825 result += (result << 3) + *name++;
1831 gtk_rc_style_equal (const gchar *a,
1834 return (strcmp (a, b) == 0);
1838 gtk_rc_style_find (GtkRcContext *context,
1841 if (context->rc_style_ht)
1842 return g_hash_table_lookup (context->rc_style_ht, (gpointer) name);
1848 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1852 style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
1854 style->rc_style = rc_style;
1856 gtk_rc_style_ref (rc_style);
1858 GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);
1863 /* Reuses or frees rc_styles */
1865 gtk_rc_init_style (GSList *rc_styles)
1867 GtkStyle *style = NULL;
1870 g_return_val_if_fail (rc_styles != NULL, NULL);
1872 if (!realized_style_ht)
1873 realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
1874 (GEqualFunc) gtk_rc_styles_equal);
1876 style = g_hash_table_lookup (realized_style_ht, rc_styles);
1880 GtkRcStyle *base_style = NULL;
1881 GtkRcStyle *proto_style;
1882 GtkRcStyleClass *proto_style_class;
1884 GType rc_style_type = GTK_TYPE_RC_STYLE;
1886 /* Find the first derived style in the list, and use that to
1887 * create the merged style. If we only have raw GtkRcStyles, use
1888 * the first style to create the merged style.
1890 base_style = rc_styles->data;
1891 tmp_styles = rc_styles;
1894 GtkRcStyle *rc_style = tmp_styles->data;
1896 if (G_OBJECT_TYPE (rc_style) != rc_style_type)
1898 base_style = rc_style;
1902 tmp_styles = tmp_styles->next;
1905 proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
1906 proto_style = proto_style_class->create_rc_style (base_style);
1908 tmp_styles = rc_styles;
1911 GtkRcStyle *rc_style = tmp_styles->data;
1914 proto_style_class->merge (proto_style, rc_style);
1916 /* Point from each rc_style to the list of styles */
1917 if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
1918 rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
1920 factories = g_slist_copy (rc_style->icon_factories);
1926 while (iter != NULL)
1928 g_object_ref (G_OBJECT (iter->data));
1929 iter = g_slist_next (iter);
1932 proto_style->icon_factories = g_slist_concat (proto_style->icon_factories,
1937 tmp_styles = tmp_styles->next;
1940 for (i = 0; i < 5; i++)
1941 if (proto_style->bg_pixmap_name[i] &&
1942 (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1944 g_free (proto_style->bg_pixmap_name[i]);
1945 proto_style->bg_pixmap_name[i] = NULL;
1948 style = gtk_rc_style_to_style (proto_style);
1949 gtk_rc_style_unref (proto_style);
1951 g_hash_table_insert (realized_style_ht, rc_styles, style);
1954 g_slist_free (rc_styles);
1959 /*********************
1960 * Parsing functions *
1961 *********************/
1964 rc_parse_token_or_compound (GScanner *scanner,
1966 GTokenType delimiter)
1968 guint token = g_scanner_get_next_token (scanner);
1970 /* we either scan a single token (skipping comments)
1971 * or a compund statement.
1972 * compunds are enclosed in (), [] or {} braces, we read
1973 * them in via deep recursion.
1980 g_string_append_printf (gstring, " 0x%lx", scanner->value.v_int);
1983 g_string_append_printf (gstring, " %f", scanner->value.v_float);
1985 case G_TOKEN_STRING:
1986 string = g_strescape (scanner->value.v_string, NULL);
1987 g_string_append (gstring, " \"");
1988 g_string_append (gstring, string);
1989 g_string_append_c (gstring, '"');
1992 case G_TOKEN_IDENTIFIER:
1993 g_string_append_c (gstring, ' ');
1994 g_string_append (gstring, scanner->value.v_identifier);
1996 case G_TOKEN_COMMENT_SINGLE:
1997 case G_TOKEN_COMMENT_MULTI:
1998 return rc_parse_token_or_compound (scanner, gstring, delimiter);
1999 case G_TOKEN_LEFT_PAREN:
2000 g_string_append_c (gstring, ' ');
2001 g_string_append_c (gstring, token);
2002 token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_PAREN);
2003 if (token != G_TOKEN_NONE)
2006 case G_TOKEN_LEFT_CURLY:
2007 g_string_append_c (gstring, ' ');
2008 g_string_append_c (gstring, token);
2009 token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_CURLY);
2010 if (token != G_TOKEN_NONE)
2013 case G_TOKEN_LEFT_BRACE:
2014 g_string_append_c (gstring, ' ');
2015 g_string_append_c (gstring, token);
2016 token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_BRACE);
2017 if (token != G_TOKEN_NONE)
2021 if (token >= 256 || token < 1)
2022 return delimiter ? delimiter : G_TOKEN_STRING;
2023 g_string_append_c (gstring, ' ');
2024 g_string_append_c (gstring, token);
2025 if (token == delimiter)
2026 return G_TOKEN_NONE;
2030 return G_TOKEN_NONE;
2032 return rc_parse_token_or_compound (scanner, gstring, delimiter);
2036 gtk_rc_parse_assignment (GScanner *scanner,
2037 GtkRcProperty *prop)
2039 gboolean scan_identifier = scanner->config->scan_identifier;
2040 gboolean scan_symbols = scanner->config->scan_symbols;
2041 gboolean identifier_2_string = scanner->config->identifier_2_string;
2042 gboolean char_2_token = scanner->config->char_2_token;
2043 gboolean scan_identifier_NULL = scanner->config->scan_identifier_NULL;
2044 gboolean numbers_2_int = scanner->config->numbers_2_int;
2045 gboolean negate = FALSE;
2048 /* check that this is an assignment */
2049 if (g_scanner_get_next_token (scanner) != '=')
2052 /* adjust scanner mode */
2053 scanner->config->scan_identifier = TRUE;
2054 scanner->config->scan_symbols = FALSE;
2055 scanner->config->identifier_2_string = FALSE;
2056 scanner->config->char_2_token = TRUE;
2057 scanner->config->scan_identifier_NULL = FALSE;
2058 scanner->config->numbers_2_int = TRUE;
2060 /* record location */
2061 prop->origin = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
2063 /* parse optional sign */
2064 if (g_scanner_peek_next_token (scanner) == '-')
2066 g_scanner_get_next_token (scanner); /* eat sign */
2070 /* parse one of LONG, DOUBLE and STRING or, if that fails, create an unparsed compund */
2071 token = g_scanner_peek_next_token (scanner);
2075 g_scanner_get_next_token (scanner);
2076 g_value_init (&prop->value, G_TYPE_LONG);
2077 g_value_set_long (&prop->value, negate ? -scanner->value.v_int : scanner->value.v_int);
2078 token = G_TOKEN_NONE;
2081 g_scanner_get_next_token (scanner);
2082 g_value_init (&prop->value, G_TYPE_DOUBLE);
2083 g_value_set_double (&prop->value, negate ? -scanner->value.v_float : scanner->value.v_float);
2084 token = G_TOKEN_NONE;
2086 case G_TOKEN_STRING:
2087 g_scanner_get_next_token (scanner);
2089 token = G_TOKEN_INT;
2092 g_value_init (&prop->value, G_TYPE_STRING);
2093 g_value_set_string (&prop->value, scanner->value.v_string);
2094 token = G_TOKEN_NONE;
2097 case G_TOKEN_IDENTIFIER:
2098 case G_TOKEN_LEFT_PAREN:
2099 case G_TOKEN_LEFT_CURLY:
2100 case G_TOKEN_LEFT_BRACE:
2103 GString *gstring = g_string_new ("");
2105 token = rc_parse_token_or_compound (scanner, gstring, 0);
2106 if (token == G_TOKEN_NONE)
2108 g_string_append_c (gstring, ' ');
2109 g_value_init (&prop->value, G_TYPE_GSTRING);
2110 g_value_set_static_boxed (&prop->value, gstring);
2113 g_string_free (gstring, TRUE);
2118 g_scanner_get_next_token (scanner);
2119 token = G_TOKEN_INT;
2123 /* restore scanner mode */
2124 scanner->config->scan_identifier = scan_identifier;
2125 scanner->config->scan_symbols = scan_symbols;
2126 scanner->config->identifier_2_string = identifier_2_string;
2127 scanner->config->char_2_token = char_2_token;
2128 scanner->config->scan_identifier_NULL = scan_identifier_NULL;
2129 scanner->config->numbers_2_int = numbers_2_int;
2135 is_c_identifier (const gchar *string)
2138 gboolean is_varname;
2140 is_varname = strchr (G_CSET_a_2_z G_CSET_A_2_Z "_", string[0]) != NULL;
2141 for (p = string + 1; *p && is_varname; p++)
2142 is_varname &= strchr (G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "_-", *p) != NULL;
2148 gtk_rc_parse_statement (GtkRcContext *context,
2153 token = g_scanner_peek_next_token (scanner);
2156 case GTK_RC_TOKEN_INCLUDE:
2157 token = g_scanner_get_next_token (scanner);
2158 if (token != GTK_RC_TOKEN_INCLUDE)
2159 return GTK_RC_TOKEN_INCLUDE;
2160 token = g_scanner_get_next_token (scanner);
2161 if (token != G_TOKEN_STRING)
2162 return G_TOKEN_STRING;
2163 gtk_rc_parse_file (context, scanner->value.v_string, context->default_priority, FALSE);
2164 return G_TOKEN_NONE;
2166 case GTK_RC_TOKEN_STYLE:
2167 return gtk_rc_parse_style (context, scanner);
2169 case GTK_RC_TOKEN_BINDING:
2170 return gtk_binding_parse_binding (scanner);
2172 case GTK_RC_TOKEN_PIXMAP_PATH:
2173 return gtk_rc_parse_pixmap_path (context, scanner);
2175 case GTK_RC_TOKEN_WIDGET:
2176 return gtk_rc_parse_path_pattern (context, scanner);
2178 case GTK_RC_TOKEN_WIDGET_CLASS:
2179 return gtk_rc_parse_path_pattern (context, scanner);
2181 case GTK_RC_TOKEN_CLASS:
2182 return gtk_rc_parse_path_pattern (context, scanner);
2184 case GTK_RC_TOKEN_MODULE_PATH:
2185 return gtk_rc_parse_module_path (scanner);
2187 case GTK_RC_TOKEN_IM_MODULE_PATH:
2188 return gtk_rc_parse_im_module_path (scanner);
2190 case GTK_RC_TOKEN_IM_MODULE_FILE:
2191 return gtk_rc_parse_im_module_file (scanner);
2193 case G_TOKEN_IDENTIFIER:
2194 if (is_c_identifier (scanner->next_value.v_identifier))
2196 GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2199 g_scanner_get_next_token (scanner); /* eat identifier */
2200 name = g_strdup (scanner->value.v_identifier);
2202 token = gtk_rc_parse_assignment (scanner, &prop);
2203 if (token == G_TOKEN_NONE)
2205 GtkSettingsValue svalue;
2207 svalue.origin = prop.origin;
2208 memcpy (&svalue.value, &prop.value, sizeof (prop.value));
2209 g_strcanon (name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
2210 gtk_settings_set_property_value (context->settings,
2214 g_free (prop.origin);
2215 if (G_VALUE_TYPE (&prop.value))
2216 g_value_unset (&prop.value);
2223 g_scanner_get_next_token (scanner);
2224 return G_TOKEN_IDENTIFIER;
2227 g_scanner_get_next_token (scanner);
2228 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
2233 gtk_rc_parse_style (GtkRcContext *context,
2236 GtkRcStyle *rc_style;
2237 GtkRcStyle *parent_style;
2241 GtkIconFactory *our_factory = NULL;
2243 token = g_scanner_get_next_token (scanner);
2244 if (token != GTK_RC_TOKEN_STYLE)
2245 return GTK_RC_TOKEN_STYLE;
2247 token = g_scanner_get_next_token (scanner);
2248 if (token != G_TOKEN_STRING)
2249 return G_TOKEN_STRING;
2252 rc_style = gtk_rc_style_find (context, scanner->value.v_string);
2254 /* If there's a list, its first member is always the factory belonging
2257 if (rc_style && rc_style->icon_factories)
2258 our_factory = rc_style->icon_factories->data;
2263 rc_style = gtk_rc_style_new ();
2264 rc_style->name = g_strdup (scanner->value.v_string);
2266 for (i = 0; i < 5; i++)
2267 rc_style->bg_pixmap_name[i] = NULL;
2269 for (i = 0; i < 5; i++)
2270 rc_style->color_flags[i] = 0;
2273 token = g_scanner_peek_next_token (scanner);
2274 if (token == G_TOKEN_EQUAL_SIGN)
2276 token = g_scanner_get_next_token (scanner);
2278 token = g_scanner_get_next_token (scanner);
2279 if (token != G_TOKEN_STRING)
2284 return G_TOKEN_STRING;
2287 parent_style = gtk_rc_style_find (context, scanner->value.v_string);
2292 for (i = 0; i < 5; i++)
2294 rc_style->color_flags[i] = parent_style->color_flags[i];
2295 rc_style->fg[i] = parent_style->fg[i];
2296 rc_style->bg[i] = parent_style->bg[i];
2297 rc_style->text[i] = parent_style->text[i];
2298 rc_style->base[i] = parent_style->base[i];
2301 rc_style->xthickness = parent_style->xthickness;
2302 rc_style->ythickness = parent_style->ythickness;
2304 if (parent_style->font_desc)
2306 if (rc_style->font_desc)
2307 pango_font_description_free (rc_style->font_desc);
2308 rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
2311 if (parent_style->rc_properties)
2315 for (i = 0; i < parent_style->rc_properties->len; i++)
2316 insert_rc_property (rc_style,
2317 &g_array_index (parent_style->rc_properties, GtkRcProperty, i),
2321 for (i = 0; i < 5; i++)
2323 if (rc_style->bg_pixmap_name[i])
2324 g_free (rc_style->bg_pixmap_name[i]);
2325 rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
2328 /* Append parent's factories, adding a ref to them */
2329 if (parent_style->icon_factories != NULL)
2331 /* Add a factory for ourselves if we have none,
2332 * in case we end up defining more stock icons.
2333 * I see no real way around this; we need to maintain
2334 * the invariant that the first factory in the list
2335 * is always our_factory, the one belonging to us,
2336 * and if we put parent factories in the list we can't
2337 * do that if the style is reopened.
2339 if (our_factory == NULL)
2341 our_factory = gtk_icon_factory_new ();
2342 rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
2346 rc_style->icon_factories = g_slist_concat (rc_style->icon_factories,
2347 g_slist_copy (parent_style->icon_factories));
2349 factories = parent_style->icon_factories;
2350 while (factories != NULL)
2352 g_object_ref (G_OBJECT (factories->data));
2353 factories = factories->next;
2359 token = g_scanner_get_next_token (scanner);
2360 if (token != G_TOKEN_LEFT_CURLY)
2365 return G_TOKEN_LEFT_CURLY;
2368 token = g_scanner_peek_next_token (scanner);
2369 while (token != G_TOKEN_RIGHT_CURLY)
2373 case GTK_RC_TOKEN_BG:
2374 token = gtk_rc_parse_bg (scanner, rc_style);
2376 case GTK_RC_TOKEN_FG:
2377 token = gtk_rc_parse_fg (scanner, rc_style);
2379 case GTK_RC_TOKEN_TEXT:
2380 token = gtk_rc_parse_text (scanner, rc_style);
2382 case GTK_RC_TOKEN_BASE:
2383 token = gtk_rc_parse_base (scanner, rc_style);
2385 case GTK_RC_TOKEN_XTHICKNESS:
2386 token = gtk_rc_parse_xthickness (scanner, rc_style);
2388 case GTK_RC_TOKEN_YTHICKNESS:
2389 token = gtk_rc_parse_ythickness (scanner, rc_style);
2391 case GTK_RC_TOKEN_BG_PIXMAP:
2392 token = gtk_rc_parse_bg_pixmap (context, scanner, rc_style);
2394 case GTK_RC_TOKEN_FONT:
2395 token = gtk_rc_parse_font (scanner, rc_style);
2397 case GTK_RC_TOKEN_FONTSET:
2398 token = gtk_rc_parse_fontset (scanner, rc_style);
2400 case GTK_RC_TOKEN_FONT_NAME:
2401 token = gtk_rc_parse_font_name (scanner, rc_style);
2403 case GTK_RC_TOKEN_ENGINE:
2404 token = gtk_rc_parse_engine (context, scanner, &rc_style);
2406 case GTK_RC_TOKEN_STOCK:
2407 if (our_factory == NULL)
2409 our_factory = gtk_icon_factory_new ();
2410 rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
2413 token = gtk_rc_parse_stock (context, scanner, rc_style, our_factory);
2415 case G_TOKEN_IDENTIFIER:
2416 if (is_c_identifier (scanner->next_value.v_identifier) &&
2417 scanner->next_value.v_identifier[0] >= 'A' &&
2418 scanner->next_value.v_identifier[0] <= 'Z') /* match namespaced type names */
2420 GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2422 g_scanner_get_next_token (scanner); /* eat type name */
2423 prop.type_name = g_quark_from_string (scanner->value.v_identifier);
2424 if (g_scanner_get_next_token (scanner) != ':' ||
2425 g_scanner_get_next_token (scanner) != ':')
2430 if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER ||
2431 !is_c_identifier (scanner->value.v_identifier))
2433 token = G_TOKEN_IDENTIFIER;
2437 /* it's important that we do the same canonification as GParamSpecPool here */
2438 g_strcanon (scanner->value.v_identifier, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
2439 prop.property_name = g_quark_from_string (scanner->value.v_identifier);
2441 token = gtk_rc_parse_assignment (scanner, &prop);
2442 if (token == G_TOKEN_NONE)
2444 g_return_val_if_fail (prop.origin != NULL && G_VALUE_TYPE (&prop.value) != 0, G_TOKEN_ERROR);
2445 insert_rc_property (rc_style, &prop, TRUE);
2448 g_free (prop.origin);
2449 if (G_VALUE_TYPE (&prop.value))
2450 g_value_unset (&prop.value);
2454 g_scanner_get_next_token (scanner);
2455 token = G_TOKEN_IDENTIFIER;
2459 g_scanner_get_next_token (scanner);
2460 token = G_TOKEN_RIGHT_CURLY;
2464 if (token != G_TOKEN_NONE)
2467 gtk_rc_style_unref (rc_style);
2471 token = g_scanner_peek_next_token (scanner);
2472 } /* while (token != G_TOKEN_RIGHT_CURLY) */
2474 token = g_scanner_get_next_token (scanner);
2475 if (token != G_TOKEN_RIGHT_CURLY)
2479 if (rc_style->font_desc)
2480 pango_font_description_free (rc_style->font_desc);
2482 for (i = 0; i < 5; i++)
2483 if (rc_style->bg_pixmap_name[i])
2484 g_free (rc_style->bg_pixmap_name[i]);
2488 return G_TOKEN_RIGHT_CURLY;
2493 if (!context->rc_style_ht)
2494 context->rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
2495 (GEqualFunc) gtk_rc_style_equal);
2497 g_hash_table_insert (context->rc_style_ht, rc_style->name, rc_style);
2500 return G_TOKEN_NONE;
2503 const GtkRcProperty*
2504 _gtk_rc_style_lookup_rc_property (GtkRcStyle *rc_style,
2506 GQuark property_name)
2508 GtkRcProperty *node = NULL;
2510 g_return_val_if_fail (GTK_IS_RC_STYLE (rc_style), NULL);
2512 if (rc_style->rc_properties)
2516 key.type_name = type_name;
2517 key.property_name = property_name;
2519 node = bsearch (&key,
2520 rc_style->rc_properties->data, rc_style->rc_properties->len,
2521 sizeof (GtkRcProperty), gtk_rc_properties_cmp);
2528 gtk_rc_parse_bg (GScanner *scanner,
2534 token = g_scanner_get_next_token (scanner);
2535 if (token != GTK_RC_TOKEN_BG)
2536 return GTK_RC_TOKEN_BG;
2538 token = gtk_rc_parse_state (scanner, &state);
2539 if (token != G_TOKEN_NONE)
2542 token = g_scanner_get_next_token (scanner);
2543 if (token != G_TOKEN_EQUAL_SIGN)
2544 return G_TOKEN_EQUAL_SIGN;
2546 style->color_flags[state] |= GTK_RC_BG;
2547 return gtk_rc_parse_color (scanner, &style->bg[state]);
2551 gtk_rc_parse_fg (GScanner *scanner,
2557 token = g_scanner_get_next_token (scanner);
2558 if (token != GTK_RC_TOKEN_FG)
2559 return GTK_RC_TOKEN_FG;
2561 token = gtk_rc_parse_state (scanner, &state);
2562 if (token != G_TOKEN_NONE)
2565 token = g_scanner_get_next_token (scanner);
2566 if (token != G_TOKEN_EQUAL_SIGN)
2567 return G_TOKEN_EQUAL_SIGN;
2569 style->color_flags[state] |= GTK_RC_FG;
2570 return gtk_rc_parse_color (scanner, &style->fg[state]);
2574 gtk_rc_parse_text (GScanner *scanner,
2580 token = g_scanner_get_next_token (scanner);
2581 if (token != GTK_RC_TOKEN_TEXT)
2582 return GTK_RC_TOKEN_TEXT;
2584 token = gtk_rc_parse_state (scanner, &state);
2585 if (token != G_TOKEN_NONE)
2588 token = g_scanner_get_next_token (scanner);
2589 if (token != G_TOKEN_EQUAL_SIGN)
2590 return G_TOKEN_EQUAL_SIGN;
2592 style->color_flags[state] |= GTK_RC_TEXT;
2593 return gtk_rc_parse_color (scanner, &style->text[state]);
2597 gtk_rc_parse_base (GScanner *scanner,
2603 token = g_scanner_get_next_token (scanner);
2604 if (token != GTK_RC_TOKEN_BASE)
2605 return GTK_RC_TOKEN_BASE;
2607 token = gtk_rc_parse_state (scanner, &state);
2608 if (token != G_TOKEN_NONE)
2611 token = g_scanner_get_next_token (scanner);
2612 if (token != G_TOKEN_EQUAL_SIGN)
2613 return G_TOKEN_EQUAL_SIGN;
2615 style->color_flags[state] |= GTK_RC_BASE;
2616 return gtk_rc_parse_color (scanner, &style->base[state]);
2620 gtk_rc_parse_xthickness (GScanner *scanner,
2623 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
2624 return GTK_RC_TOKEN_XTHICKNESS;
2626 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2627 return G_TOKEN_EQUAL_SIGN;
2629 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2632 style->xthickness = scanner->value.v_int;
2634 return G_TOKEN_NONE;
2638 gtk_rc_parse_ythickness (GScanner *scanner,
2641 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
2642 return GTK_RC_TOKEN_YTHICKNESS;
2644 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2645 return G_TOKEN_EQUAL_SIGN;
2647 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2650 style->ythickness = scanner->value.v_int;
2652 return G_TOKEN_NONE;
2656 gtk_rc_parse_bg_pixmap (GtkRcContext *context,
2658 GtkRcStyle *rc_style)
2664 token = g_scanner_get_next_token (scanner);
2665 if (token != GTK_RC_TOKEN_BG_PIXMAP)
2666 return GTK_RC_TOKEN_BG_PIXMAP;
2668 token = gtk_rc_parse_state (scanner, &state);
2669 if (token != G_TOKEN_NONE)
2672 token = g_scanner_get_next_token (scanner);
2673 if (token != G_TOKEN_EQUAL_SIGN)
2674 return G_TOKEN_EQUAL_SIGN;
2676 token = g_scanner_get_next_token (scanner);
2677 if (token != G_TOKEN_STRING)
2678 return G_TOKEN_STRING;
2680 if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
2681 (strcmp (scanner->value.v_string, "<none>") == 0))
2682 pixmap_file = g_strdup (scanner->value.v_string);
2684 pixmap_file = gtk_rc_find_pixmap_in_path (context->settings,
2685 scanner, scanner->value.v_string);
2689 if (rc_style->bg_pixmap_name[state])
2690 g_free (rc_style->bg_pixmap_name[state]);
2691 rc_style->bg_pixmap_name[state] = pixmap_file;
2694 return G_TOKEN_NONE;
2698 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
2703 buf = g_build_filename (dir, pixmap_file, NULL);
2705 fd = open (buf, O_RDONLY);
2718 * gtk_rc_context_find_pixmap_in_path:
2719 * @settings: a #GtkSettinsg
2720 * @scanner: Scanner used to get line number information for the
2721 * warning message, or %NULL
2722 * @pixmap_file: name of the pixmap file to locate.
2724 * Looks up a file in pixmap path for the specified #GtkSettings.
2725 * If the file is not found, it outputs a warning message using
2726 * g_warning() and returns %NULL.
2731 gtk_rc_find_pixmap_in_path (GtkSettings *settings,
2733 const gchar *pixmap_file)
2739 GtkRcContext *context = gtk_rc_context_get (settings);
2741 for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (context->pixmap_path[i] != NULL); i++)
2743 filename = gtk_rc_check_pixmap_dir (context->pixmap_path[i], pixmap_file);
2748 tmp_list = rc_dir_stack;
2751 filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
2755 tmp_list = tmp_list->next;
2759 g_warning (_("Unable to locate image file in pixmap_path: \"%s\" line %d"),
2760 pixmap_file, scanner->line);
2762 g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
2769 gtk_rc_find_module_in_path (const gchar *module_file)
2775 for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
2777 buf = g_build_filename (module_path[i], module_file, NULL);
2779 fd = open (buf, O_RDONLY);
2793 gtk_rc_parse_font (GScanner *scanner,
2794 GtkRcStyle *rc_style)
2798 token = g_scanner_get_next_token (scanner);
2799 if (token != GTK_RC_TOKEN_FONT)
2800 return GTK_RC_TOKEN_FONT;
2802 token = g_scanner_get_next_token (scanner);
2803 if (token != G_TOKEN_EQUAL_SIGN)
2804 return G_TOKEN_EQUAL_SIGN;
2806 token = g_scanner_get_next_token (scanner);
2807 if (token != G_TOKEN_STRING)
2808 return G_TOKEN_STRING;
2810 /* Ignore, do nothing */
2812 return G_TOKEN_NONE;
2816 gtk_rc_parse_fontset (GScanner *scanner,
2817 GtkRcStyle *rc_style)
2821 token = g_scanner_get_next_token (scanner);
2822 if (token != GTK_RC_TOKEN_FONTSET)
2823 return GTK_RC_TOKEN_FONTSET;
2825 token = g_scanner_get_next_token (scanner);
2826 if (token != G_TOKEN_EQUAL_SIGN)
2827 return G_TOKEN_EQUAL_SIGN;
2829 token = g_scanner_get_next_token (scanner);
2830 if (token != G_TOKEN_STRING)
2831 return G_TOKEN_STRING;
2833 /* Do nothing - silently ignore */
2835 return G_TOKEN_NONE;
2839 gtk_rc_parse_font_name (GScanner *scanner,
2840 GtkRcStyle *rc_style)
2844 token = g_scanner_get_next_token (scanner);
2845 if (token != GTK_RC_TOKEN_FONT_NAME)
2846 return GTK_RC_TOKEN_FONT;
2848 token = g_scanner_get_next_token (scanner);
2849 if (token != G_TOKEN_EQUAL_SIGN)
2850 return G_TOKEN_EQUAL_SIGN;
2852 token = g_scanner_get_next_token (scanner);
2853 if (token != G_TOKEN_STRING)
2854 return G_TOKEN_STRING;
2856 rc_style->font_desc = pango_font_description_from_string (scanner->value.v_string);
2858 return G_TOKEN_NONE;
2862 gtk_rc_parse_engine (GtkRcContext *context,
2864 GtkRcStyle **rc_style)
2867 GtkThemeEngine *engine;
2868 guint result = G_TOKEN_NONE;
2869 GtkRcStyle *new_style = NULL;
2870 gboolean parsed_curlies = FALSE;
2872 token = g_scanner_get_next_token (scanner);
2873 if (token != GTK_RC_TOKEN_ENGINE)
2874 return GTK_RC_TOKEN_ENGINE;
2876 token = g_scanner_get_next_token (scanner);
2877 if (token != G_TOKEN_STRING)
2878 return G_TOKEN_STRING;
2880 engine = gtk_theme_engine_get (scanner->value.v_string);
2882 token = g_scanner_get_next_token (scanner);
2883 if (token != G_TOKEN_LEFT_CURLY)
2884 return G_TOKEN_LEFT_CURLY;
2888 GtkRcStyleClass *new_class;
2890 new_style = gtk_theme_engine_create_rc_style (engine);
2891 g_type_module_unuse (G_TYPE_MODULE (engine));
2893 new_class = GTK_RC_STYLE_GET_CLASS (new_style);
2895 new_class->merge (new_style, *rc_style);
2896 if ((*rc_style)->name)
2897 new_style->name = g_strdup ((*rc_style)->name);
2899 if (new_class->parse)
2901 parsed_curlies = TRUE;
2902 result = new_class->parse (new_style, context->settings, scanner);
2904 if (result != G_TOKEN_NONE)
2906 g_object_unref (G_OBJECT (new_style));
2912 if (!parsed_curlies)
2914 /* Skip over remainder, looking for nested {}'s
2918 result = G_TOKEN_RIGHT_CURLY;
2919 while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
2921 if (token == G_TOKEN_LEFT_CURLY)
2923 else if (token == G_TOKEN_RIGHT_CURLY)
2928 result = G_TOKEN_NONE;
2936 g_object_unref (G_OBJECT (*rc_style));
2937 *rc_style = new_style;
2944 gtk_rc_parse_state (GScanner *scanner,
2945 GtkStateType *state)
2950 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2951 g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
2953 /* we don't know where we got called from, so we reset the scope here.
2954 * if we bail out due to errors, we *don't* reset the scope, so the
2955 * error messaging code can make sense of our tokens.
2957 old_scope = g_scanner_set_scope (scanner, 0);
2959 token = g_scanner_get_next_token (scanner);
2960 if (token != G_TOKEN_LEFT_BRACE)
2961 return G_TOKEN_LEFT_BRACE;
2963 token = g_scanner_get_next_token (scanner);
2966 case GTK_RC_TOKEN_ACTIVE:
2967 *state = GTK_STATE_ACTIVE;
2969 case GTK_RC_TOKEN_INSENSITIVE:
2970 *state = GTK_STATE_INSENSITIVE;
2972 case GTK_RC_TOKEN_NORMAL:
2973 *state = GTK_STATE_NORMAL;
2975 case GTK_RC_TOKEN_PRELIGHT:
2976 *state = GTK_STATE_PRELIGHT;
2978 case GTK_RC_TOKEN_SELECTED:
2979 *state = GTK_STATE_SELECTED;
2982 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
2985 token = g_scanner_get_next_token (scanner);
2986 if (token != G_TOKEN_RIGHT_BRACE)
2987 return G_TOKEN_RIGHT_BRACE;
2989 g_scanner_set_scope (scanner, old_scope);
2991 return G_TOKEN_NONE;
2995 gtk_rc_parse_priority (GScanner *scanner,
2996 GtkPathPriorityType *priority)
3001 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3002 g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
3004 /* we don't know where we got called from, so we reset the scope here.
3005 * if we bail out due to errors, we *don't* reset the scope, so the
3006 * error messaging code can make sense of our tokens.
3008 old_scope = g_scanner_set_scope (scanner, 0);
3010 token = g_scanner_get_next_token (scanner);
3014 token = g_scanner_get_next_token (scanner);
3017 case GTK_RC_TOKEN_LOWEST:
3018 *priority = GTK_PATH_PRIO_LOWEST;
3020 case GTK_RC_TOKEN_GTK:
3021 *priority = GTK_PATH_PRIO_GTK;
3023 case GTK_RC_TOKEN_APPLICATION:
3024 *priority = GTK_PATH_PRIO_APPLICATION;
3026 case GTK_RC_TOKEN_THEME:
3027 *priority = GTK_PATH_PRIO_THEME;
3029 case GTK_RC_TOKEN_RC:
3030 *priority = GTK_PATH_PRIO_RC;
3032 case GTK_RC_TOKEN_HIGHEST:
3033 *priority = GTK_PATH_PRIO_HIGHEST;
3036 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
3039 g_scanner_set_scope (scanner, old_scope);
3041 return G_TOKEN_NONE;
3045 gtk_rc_parse_color (GScanner *scanner,
3050 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3052 /* we don't need to set our own scope here, because
3053 * we don't need own symbols
3056 token = g_scanner_get_next_token (scanner);
3061 case G_TOKEN_LEFT_CURLY:
3062 token = g_scanner_get_next_token (scanner);
3063 if (token == G_TOKEN_INT)
3064 token_int = scanner->value.v_int;
3065 else if (token == G_TOKEN_FLOAT)
3066 token_int = scanner->value.v_float * 65535.0;
3068 return G_TOKEN_FLOAT;
3069 color->red = CLAMP (token_int, 0, 65535);
3071 token = g_scanner_get_next_token (scanner);
3072 if (token != G_TOKEN_COMMA)
3073 return G_TOKEN_COMMA;
3075 token = g_scanner_get_next_token (scanner);
3076 if (token == G_TOKEN_INT)
3077 token_int = scanner->value.v_int;
3078 else if (token == G_TOKEN_FLOAT)
3079 token_int = scanner->value.v_float * 65535.0;
3081 return G_TOKEN_FLOAT;
3082 color->green = CLAMP (token_int, 0, 65535);
3084 token = g_scanner_get_next_token (scanner);
3085 if (token != G_TOKEN_COMMA)
3086 return G_TOKEN_COMMA;
3088 token = g_scanner_get_next_token (scanner);
3089 if (token == G_TOKEN_INT)
3090 token_int = scanner->value.v_int;
3091 else if (token == G_TOKEN_FLOAT)
3092 token_int = scanner->value.v_float * 65535.0;
3094 return G_TOKEN_FLOAT;
3095 color->blue = CLAMP (token_int, 0, 65535);
3097 token = g_scanner_get_next_token (scanner);
3098 if (token != G_TOKEN_RIGHT_CURLY)
3099 return G_TOKEN_RIGHT_CURLY;
3100 return G_TOKEN_NONE;
3102 case G_TOKEN_STRING:
3103 if (!gdk_color_parse (scanner->value.v_string, color))
3105 g_scanner_warn (scanner, "Invalid color constant '%s'",
3106 scanner->value.v_string);
3107 return G_TOKEN_STRING;
3110 return G_TOKEN_NONE;
3113 return G_TOKEN_STRING;
3118 gtk_rc_parse_pixmap_path (GtkRcContext *context,
3123 token = g_scanner_get_next_token (scanner);
3124 if (token != GTK_RC_TOKEN_PIXMAP_PATH)
3125 return GTK_RC_TOKEN_PIXMAP_PATH;
3127 token = g_scanner_get_next_token (scanner);
3128 if (token != G_TOKEN_STRING)
3129 return G_TOKEN_STRING;
3131 gtk_rc_parse_pixmap_path_string (context, scanner, scanner->value.v_string);
3133 return G_TOKEN_NONE;
3137 gtk_rc_parse_pixmap_path_string (GtkRcContext *context,
3139 const gchar *pix_path)
3142 gint start_offset = 0;
3146 /* free the old one, or just add to the old one ? */
3147 for (path_num = 0; context->pixmap_path[path_num]; path_num++)
3149 g_free (context->pixmap_path[path_num]);
3150 context->pixmap_path[path_num] = NULL;
3155 path_len = strlen (pix_path);
3157 for (end_offset = 0; end_offset <= path_len; end_offset++)
3159 if ((pix_path[end_offset] == G_SEARCHPATH_SEPARATOR) ||
3160 (end_offset == path_len))
3162 gchar *path_element = g_strndup (pix_path + start_offset, end_offset - start_offset);
3163 if (g_path_is_absolute (path_element))
3165 context->pixmap_path[path_num] = path_element;
3167 context->pixmap_path[path_num] = NULL;
3171 g_warning (_("Pixmap path element: \"%s\" must be absolute, %s, line %d"),
3172 path_element, scanner->input_name, scanner->line);
3173 g_free (path_element);
3176 start_offset = end_offset + 1;
3182 gtk_rc_parse_module_path (GScanner *scanner)
3186 token = g_scanner_get_next_token (scanner);
3187 if (token != GTK_RC_TOKEN_MODULE_PATH)
3188 return GTK_RC_TOKEN_MODULE_PATH;
3190 token = g_scanner_get_next_token (scanner);
3191 if (token != G_TOKEN_STRING)
3192 return G_TOKEN_STRING;
3194 gtk_rc_parse_module_path_string (scanner->value.v_string);
3196 return G_TOKEN_NONE;
3200 gtk_rc_parse_im_module_path (GScanner *scanner)
3204 token = g_scanner_get_next_token (scanner);
3205 if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
3206 return GTK_RC_TOKEN_IM_MODULE_FILE;
3208 token = g_scanner_get_next_token (scanner);
3209 if (token != G_TOKEN_STRING)
3210 return G_TOKEN_STRING;
3213 g_free (im_module_path);
3215 im_module_path = g_strdup (scanner->value.v_string);
3217 return G_TOKEN_NONE;
3221 gtk_rc_parse_im_module_file (GScanner *scanner)
3225 token = g_scanner_get_next_token (scanner);
3226 if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
3227 return GTK_RC_TOKEN_IM_MODULE_FILE;
3229 token = g_scanner_get_next_token (scanner);
3230 if (token != G_TOKEN_STRING)
3231 return G_TOKEN_STRING;
3234 g_free (im_module_file);
3236 im_module_file = g_strdup (scanner->value.v_string);
3238 return G_TOKEN_NONE;
3242 gtk_rc_parse_module_path_string (const gchar *mod_path)
3245 gint start_offset = 0;
3249 /* free the old one, or just add to the old one ? */
3250 for (path_num=0; module_path[path_num]; path_num++)
3252 g_free (module_path[path_num]);
3253 module_path[path_num] = NULL;
3258 path_len = strlen (mod_path);
3260 for (end_offset = 0; end_offset <= path_len; end_offset++)
3262 if ((mod_path[end_offset] == G_SEARCHPATH_SEPARATOR) ||
3263 (end_offset == path_len))
3265 module_path[path_num] = g_strndup (mod_path + start_offset, end_offset - start_offset);
3267 module_path[path_num] = NULL;
3268 start_offset = end_offset + 1;
3271 gtk_rc_append_default_module_path();
3275 rc_set_compare (gconstpointer a, gconstpointer b)
3277 const GtkRcSet *set_a = a;
3278 const GtkRcSet *set_b = b;
3280 return (set_a->priority < set_b->priority) ? 1 : (set_a->priority == set_b->priority ? 0 : -1);
3284 insert_rc_set (GSList *list, GtkRcSet *set)
3286 return g_slist_insert_sorted (list, set, rc_set_compare);
3290 gtk_rc_parse_path_pattern (GtkRcContext *context,
3294 GtkPathType path_type;
3296 gboolean is_binding;
3297 GtkPathPriorityType priority = context->default_priority;
3299 token = g_scanner_get_next_token (scanner);
3302 case GTK_RC_TOKEN_WIDGET:
3303 path_type = GTK_PATH_WIDGET;
3305 case GTK_RC_TOKEN_WIDGET_CLASS:
3306 path_type = GTK_PATH_WIDGET_CLASS;
3308 case GTK_RC_TOKEN_CLASS:
3309 path_type = GTK_PATH_CLASS;
3312 return GTK_RC_TOKEN_WIDGET_CLASS;
3315 token = g_scanner_get_next_token (scanner);
3316 if (token != G_TOKEN_STRING)
3317 return G_TOKEN_STRING;
3319 pattern = g_strdup (scanner->value.v_string);
3321 token = g_scanner_get_next_token (scanner);
3322 if (token == GTK_RC_TOKEN_STYLE)
3324 else if (token == GTK_RC_TOKEN_BINDING)
3329 return GTK_RC_TOKEN_STYLE;
3332 if (g_scanner_peek_next_token (scanner) == ':')
3334 token = gtk_rc_parse_priority (scanner, &priority);
3335 if (token != G_TOKEN_NONE)
3342 token = g_scanner_get_next_token (scanner);
3343 if (token != G_TOKEN_STRING)
3346 return G_TOKEN_STRING;
3351 GtkBindingSet *binding;
3353 binding = gtk_binding_set_find (scanner->value.v_string);
3357 return G_TOKEN_STRING;
3359 gtk_binding_set_add_path (binding, path_type, pattern, priority);
3363 GtkRcStyle *rc_style;
3366 rc_style = gtk_rc_style_find (context, scanner->value.v_string);
3371 return G_TOKEN_STRING;
3374 rc_set = g_new (GtkRcSet, 1);
3375 rc_set->pspec = g_pattern_spec_new (pattern);
3376 rc_set->rc_style = rc_style;
3377 rc_set->priority = priority;
3379 if (path_type == GTK_PATH_WIDGET)
3380 context->rc_sets_widget = insert_rc_set (context->rc_sets_widget, rc_set);
3381 else if (path_type == GTK_PATH_WIDGET_CLASS)
3382 context->rc_sets_widget_class = insert_rc_set (context->rc_sets_widget_class, rc_set);
3384 context->rc_sets_class = insert_rc_set (context->rc_sets_class, rc_set);
3388 return G_TOKEN_NONE;
3392 gtk_rc_parse_stock_id (GScanner *scanner,
3397 token = g_scanner_get_next_token (scanner);
3398 if (token != G_TOKEN_LEFT_BRACE)
3399 return G_TOKEN_LEFT_BRACE;
3401 token = g_scanner_get_next_token (scanner);
3403 if (token != G_TOKEN_STRING)
3404 return G_TOKEN_STRING;
3406 *stock_id = g_strdup (scanner->value.v_string);
3408 token = g_scanner_get_next_token (scanner);
3409 if (token != G_TOKEN_RIGHT_BRACE)
3412 return G_TOKEN_RIGHT_BRACE;
3415 return G_TOKEN_NONE;
3419 gtk_rc_parse_icon_source (GtkRcContext *context,
3421 GtkIconSet *icon_set)
3424 GtkIconSource *source;
3425 gchar *full_filename;
3427 token = g_scanner_get_next_token (scanner);
3428 if (token != G_TOKEN_LEFT_CURLY)
3429 return G_TOKEN_LEFT_CURLY;
3431 token = g_scanner_get_next_token (scanner);
3433 if (token != G_TOKEN_STRING)
3434 return G_TOKEN_STRING;
3437 source = gtk_icon_source_new ();
3439 full_filename = gtk_rc_find_pixmap_in_path (context->settings, scanner, scanner->value.v_string);
3442 gtk_icon_source_set_filename (source, full_filename);
3443 g_free (full_filename);
3446 /* We continue parsing even if we didn't find the pixmap so that rest of the
3447 * file is read, even if the syntax is bad
3449 token = g_scanner_get_next_token (scanner);
3451 if (token == G_TOKEN_RIGHT_CURLY)
3453 else if (token != G_TOKEN_COMMA)
3455 gtk_icon_source_free (source);
3456 return G_TOKEN_COMMA;
3459 /* Get the direction */
3461 token = g_scanner_get_next_token (scanner);
3465 case GTK_RC_TOKEN_RTL:
3466 gtk_icon_source_set_direction_wildcarded (source, FALSE);
3467 gtk_icon_source_set_direction (source, GTK_TEXT_DIR_RTL);
3470 case GTK_RC_TOKEN_LTR:
3471 gtk_icon_source_set_direction_wildcarded (source, FALSE);
3472 gtk_icon_source_set_direction (source, GTK_TEXT_DIR_LTR);
3479 gtk_icon_source_free (source);
3480 return GTK_RC_TOKEN_RTL;
3484 token = g_scanner_get_next_token (scanner);
3486 if (token == G_TOKEN_RIGHT_CURLY)
3488 else if (token != G_TOKEN_COMMA)
3490 gtk_icon_source_free (source);
3491 return G_TOKEN_COMMA;
3496 token = g_scanner_get_next_token (scanner);
3500 case GTK_RC_TOKEN_NORMAL:
3501 gtk_icon_source_set_state_wildcarded (source, FALSE);
3502 gtk_icon_source_set_state (source, GTK_STATE_NORMAL);
3505 case GTK_RC_TOKEN_PRELIGHT:
3506 gtk_icon_source_set_state_wildcarded (source, FALSE);
3507 gtk_icon_source_set_state (source, GTK_STATE_PRELIGHT);
3511 case GTK_RC_TOKEN_INSENSITIVE:
3512 gtk_icon_source_set_state_wildcarded (source, FALSE);
3513 gtk_icon_source_set_state (source, GTK_STATE_INSENSITIVE);
3516 case GTK_RC_TOKEN_ACTIVE:
3517 gtk_icon_source_set_state_wildcarded (source, FALSE);
3518 gtk_icon_source_set_state (source, GTK_STATE_ACTIVE);
3521 case GTK_RC_TOKEN_SELECTED:
3522 gtk_icon_source_set_state_wildcarded (source, FALSE);
3523 gtk_icon_source_set_state (source, GTK_STATE_SELECTED);
3530 gtk_icon_source_free (source);
3531 return GTK_RC_TOKEN_PRELIGHT;
3535 token = g_scanner_get_next_token (scanner);
3537 if (token == G_TOKEN_RIGHT_CURLY)
3539 else if (token != G_TOKEN_COMMA)
3541 gtk_icon_source_free (source);
3542 return G_TOKEN_COMMA;
3547 token = g_scanner_get_next_token (scanner);
3553 if (token != G_TOKEN_STRING)
3555 gtk_icon_source_free (source);
3556 return G_TOKEN_STRING;
3559 size = gtk_icon_size_from_name (scanner->value.v_string);
3561 if (size != GTK_ICON_SIZE_INVALID)
3563 gtk_icon_source_set_size_wildcarded (source, FALSE);
3564 gtk_icon_source_set_size (source, size);
3568 /* Check the close brace */
3570 token = g_scanner_get_next_token (scanner);
3571 if (token != G_TOKEN_RIGHT_CURLY)
3573 gtk_icon_source_free (source);
3574 return G_TOKEN_RIGHT_CURLY;
3578 if (gtk_icon_source_get_filename (source))
3579 gtk_icon_set_add_source (icon_set, source);
3580 gtk_icon_source_free (source);
3582 return G_TOKEN_NONE;
3586 gtk_rc_parse_stock (GtkRcContext *context,
3588 GtkRcStyle *rc_style,
3589 GtkIconFactory *factory)
3591 GtkIconSet *icon_set = NULL;
3592 gchar *stock_id = NULL;
3595 token = g_scanner_get_next_token (scanner);
3596 if (token != GTK_RC_TOKEN_STOCK)
3597 return GTK_RC_TOKEN_STOCK;
3599 token = gtk_rc_parse_stock_id (scanner, &stock_id);
3600 if (token != G_TOKEN_NONE)
3603 token = g_scanner_get_next_token (scanner);
3604 if (token != G_TOKEN_EQUAL_SIGN)
3607 return G_TOKEN_EQUAL_SIGN;
3610 token = g_scanner_get_next_token (scanner);
3611 if (token != G_TOKEN_LEFT_CURLY)
3614 return G_TOKEN_LEFT_CURLY;
3617 token = g_scanner_peek_next_token (scanner);
3618 while (token != G_TOKEN_RIGHT_CURLY)
3620 if (icon_set == NULL)
3621 icon_set = gtk_icon_set_new ();
3623 token = gtk_rc_parse_icon_source (context, scanner, icon_set);
3624 if (token != G_TOKEN_NONE)
3627 gtk_icon_set_unref (icon_set);
3631 token = g_scanner_get_next_token (scanner);
3633 if (token != G_TOKEN_COMMA &&
3634 token != G_TOKEN_RIGHT_CURLY)
3637 gtk_icon_set_unref (icon_set);
3638 return G_TOKEN_RIGHT_CURLY;
3644 gtk_icon_factory_add (factory,
3648 gtk_icon_set_unref (icon_set);
3653 return G_TOKEN_NONE;