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 "gtkprivate.h"
57 #include "gtksettings.h"
58 #include "gtkwindow.h"
64 typedef struct _GtkRcSet GtkRcSet;
65 typedef struct _GtkRcNode GtkRcNode;
66 typedef struct _GtkRcFile GtkRcFile;
79 gchar *canonical_name;
83 #define GTK_RC_MAX_PIXMAP_PATHS 128
87 GHashTable *rc_style_ht;
88 GtkSettings *settings;
89 GSList *rc_sets_widget;
90 GSList *rc_sets_widget_class;
91 GSList *rc_sets_class;
93 /* The files we have parsed, to reread later if necessary */
97 gchar *key_theme_name;
99 gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
101 gint default_priority;
104 static GtkRcContext *gtk_rc_context_get (GtkSettings *settings);
106 static guint gtk_rc_style_hash (const gchar *name);
107 static gboolean gtk_rc_style_equal (const gchar *a,
109 static guint gtk_rc_styles_hash (const GSList *rc_styles);
110 static gboolean gtk_rc_styles_equal (const GSList *a,
112 static GtkRcStyle* gtk_rc_style_find (GtkRcContext *context,
114 static GSList * gtk_rc_styles_match (GSList *rc_styles,
118 const gchar *path_reversed);
119 static GtkStyle * gtk_rc_style_to_style (GtkRcStyle *rc_style);
120 static GtkStyle* gtk_rc_init_style (GSList *rc_styles);
121 static void gtk_rc_parse_default_files (GtkRcContext *context);
122 static void gtk_rc_parse_named (GtkRcContext *context,
125 static void gtk_rc_parse_file (GtkRcContext *context,
126 const gchar *filename,
129 static void gtk_rc_parse_any (GtkRcContext *context,
130 const gchar *input_name,
132 const gchar *input_string);
133 static guint gtk_rc_parse_statement (GtkRcContext *context,
135 static guint gtk_rc_parse_style (GtkRcContext *context,
137 static guint gtk_rc_parse_assignment (GScanner *scanner,
138 GtkRcProperty *prop);
139 static guint gtk_rc_parse_bg (GScanner *scanner,
141 static guint gtk_rc_parse_fg (GScanner *scanner,
143 static guint gtk_rc_parse_text (GScanner *scanner,
145 static guint gtk_rc_parse_base (GScanner *scanner,
147 static guint gtk_rc_parse_xthickness (GScanner *scanner,
149 static guint gtk_rc_parse_ythickness (GScanner *scanner,
151 static guint gtk_rc_parse_bg_pixmap (GtkRcContext *context,
153 GtkRcStyle *rc_style);
154 static guint gtk_rc_parse_font (GScanner *scanner,
155 GtkRcStyle *rc_style);
156 static guint gtk_rc_parse_fontset (GScanner *scanner,
157 GtkRcStyle *rc_style);
158 static guint gtk_rc_parse_font_name (GScanner *scanner,
159 GtkRcStyle *rc_style);
160 static guint gtk_rc_parse_engine (GtkRcContext *context,
162 GtkRcStyle **rc_style);
163 static guint gtk_rc_parse_pixmap_path (GtkRcContext *context,
165 static void gtk_rc_parse_pixmap_path_string (GtkRcContext *context,
167 const gchar *pix_path);
168 static guint gtk_rc_parse_module_path (GScanner *scanner);
169 static void gtk_rc_parse_module_path_string (const gchar *mod_path);
170 static guint gtk_rc_parse_im_module_path (GScanner *scanner);
171 static guint gtk_rc_parse_im_module_file (GScanner *scanner);
172 static guint gtk_rc_parse_path_pattern (GtkRcContext *context,
174 static guint gtk_rc_parse_stock (GtkRcContext *context,
176 GtkRcStyle *rc_style,
177 GtkIconFactory *factory);
178 static void gtk_rc_clear_hash_node (gpointer key,
181 static void gtk_rc_clear_styles (GtkRcContext *context);
182 static void gtk_rc_append_default_module_path (void);
183 static void gtk_rc_add_initial_default_files (void);
185 static void gtk_rc_style_init (GtkRcStyle *style);
186 static void gtk_rc_style_class_init (GtkRcStyleClass *klass);
187 static void gtk_rc_style_finalize (GObject *object);
188 static void gtk_rc_style_real_merge (GtkRcStyle *dest,
190 static GtkRcStyle* gtk_rc_style_real_create_rc_style (GtkRcStyle *rc_style);
191 static GtkStyle* gtk_rc_style_real_create_style (GtkRcStyle *rc_style);
192 static gint gtk_rc_properties_cmp (gconstpointer bsearch_node1,
193 gconstpointer bsearch_node2);
195 static gpointer parent_class = NULL;
197 static const GScannerConfig gtk_rc_scanner_config =
201 ) /* cset_skip_characters */,
206 ) /* cset_identifier_first */,
211 ) /* cset_identifier_nth */,
212 ( "#\n" ) /* cpair_comment_single */,
214 TRUE /* case_sensitive */,
216 TRUE /* skip_comment_multi */,
217 TRUE /* skip_comment_single */,
218 TRUE /* scan_comment_multi */,
219 TRUE /* scan_identifier */,
220 FALSE /* scan_identifier_1char */,
221 FALSE /* scan_identifier_NULL */,
222 TRUE /* scan_symbols */,
223 TRUE /* scan_binary */,
224 TRUE /* scan_octal */,
225 TRUE /* scan_float */,
227 TRUE /* scan_hex_dollar */,
228 TRUE /* scan_string_sq */,
229 TRUE /* scan_string_dq */,
230 TRUE /* numbers_2_int */,
231 FALSE /* int_2_float */,
232 FALSE /* identifier_2_string */,
233 TRUE /* char_2_token */,
234 TRUE /* symbol_2_token */,
235 FALSE /* scope_0_fallback */,
243 { "include", GTK_RC_TOKEN_INCLUDE },
244 { "NORMAL", GTK_RC_TOKEN_NORMAL },
245 { "ACTIVE", GTK_RC_TOKEN_ACTIVE },
246 { "PRELIGHT", GTK_RC_TOKEN_PRELIGHT },
247 { "SELECTED", GTK_RC_TOKEN_SELECTED },
248 { "INSENSITIVE", GTK_RC_TOKEN_INSENSITIVE },
249 { "fg", GTK_RC_TOKEN_FG },
250 { "bg", GTK_RC_TOKEN_BG },
251 { "text", GTK_RC_TOKEN_TEXT },
252 { "base", GTK_RC_TOKEN_BASE },
253 { "xthickness", GTK_RC_TOKEN_XTHICKNESS },
254 { "ythickness", GTK_RC_TOKEN_YTHICKNESS },
255 { "font", GTK_RC_TOKEN_FONT },
256 { "fontset", GTK_RC_TOKEN_FONTSET },
257 { "font_name", GTK_RC_TOKEN_FONT_NAME },
258 { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP },
259 { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH },
260 { "style", GTK_RC_TOKEN_STYLE },
261 { "binding", GTK_RC_TOKEN_BINDING },
262 { "bind", GTK_RC_TOKEN_BIND },
263 { "widget", GTK_RC_TOKEN_WIDGET },
264 { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS },
265 { "class", GTK_RC_TOKEN_CLASS },
266 { "lowest", GTK_RC_TOKEN_LOWEST },
267 { "gtk", GTK_RC_TOKEN_GTK },
268 { "application", GTK_RC_TOKEN_APPLICATION },
269 { "theme", GTK_RC_TOKEN_THEME },
270 { "rc", GTK_RC_TOKEN_RC },
271 { "highest", GTK_RC_TOKEN_HIGHEST },
272 { "engine", GTK_RC_TOKEN_ENGINE },
273 { "module_path", GTK_RC_TOKEN_MODULE_PATH },
274 { "stock", GTK_RC_TOKEN_STOCK },
275 { "im_module_path", GTK_RC_TOKEN_IM_MODULE_PATH },
276 { "im_module_file", GTK_RC_TOKEN_IM_MODULE_FILE },
277 { "LTR", GTK_RC_TOKEN_LTR },
278 { "RTL", GTK_RC_TOKEN_RTL }
281 static GHashTable *realized_style_ht = NULL;
283 static gchar *im_module_path = NULL;
284 static gchar *im_module_file = NULL;
286 #define GTK_RC_MAX_DEFAULT_FILES 128
287 static gchar *gtk_rc_default_files[GTK_RC_MAX_DEFAULT_FILES];
289 #define GTK_RC_MAX_MODULE_PATHS 128
290 static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
292 /* A stack of directories for RC files we are parsing currently.
293 * these are implicitely added to the end of PIXMAP_PATHS
295 static GSList *rc_dir_stack = NULL;
297 /* RC file handling */
300 gtk_rc_make_default_dir (const gchar *type)
305 var = g_getenv ("GTK_EXE_PREFIX");
307 path = g_build_filename (var, "lib", "gtk-2.0", type, GTK_BINARY_VERSION, NULL);
309 path = g_build_filename (GTK_LIBDIR, "gtk-2.0", type, GTK_BINARY_VERSION, NULL);
315 * gtk_rc_get_im_module_path:
316 * @returns: a newly-allocated string containing the path in which to
317 * look for IM modules.
319 * Obtains the path in which to look for IM modules. See the documentation
320 * of the <link linkend="im-module-path"><envar>GTK_IM_MODULE_PATH</envar></link>
321 * environment variable for more details.
324 gtk_rc_get_im_module_path (void)
326 const gchar *result = g_getenv ("GTK_IM_MODULE_PATH");
331 result = im_module_path;
333 return gtk_rc_make_default_dir ("immodules");
336 return g_strdup (result);
340 * gtk_rc_get_im_module_file:
341 * @returns: a newly-allocated string containing the name of the file
342 * listing the IM modules to load
344 * Obtains the path to the IM modules file. See the documentation
345 * of the <link linkend="im-module-file"><envar>GTK_IM_MODULE_FILE</envar></link>
346 * environment variable for more details.
349 gtk_rc_get_im_module_file (void)
351 gchar *result = g_strdup (g_getenv ("GTK_IM_MODULE_FILE"));
356 result = g_strdup (im_module_file);
358 result = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gtk.immodules", NULL);
365 gtk_rc_get_theme_dir (void)
370 var = g_getenv ("GTK_DATA_PREFIX");
372 path = g_build_filename (var, "share", "themes", NULL);
374 path = g_build_filename (GTK_DATA_PREFIX, "share", "themes", NULL);
380 gtk_rc_get_module_dir (void)
382 return gtk_rc_make_default_dir ("engines");
386 gtk_rc_append_default_module_path (void)
392 for (n = 0; module_path[n]; n++) ;
393 if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
396 var = g_getenv ("GTK_EXE_PREFIX");
398 path = g_build_filename (var, "lib", "gtk-2.0", GTK_VERSION, "engines", NULL);
400 path = g_build_filename (GTK_LIBDIR, "gtk-2.0", GTK_VERSION, "engines", NULL);
401 module_path[n++] = path;
403 var = g_get_home_dir ();
406 path = g_build_filename (var, ".gtk-2.0", GTK_VERSION, "engines", NULL);
407 module_path[n++] = path;
409 module_path[n] = NULL;
413 gtk_rc_add_initial_default_files (void)
415 static gint init = FALSE;
424 gtk_rc_default_files[0] = NULL;
427 var = g_getenv ("GTK_RC_FILES");
430 files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
434 gtk_rc_add_default_file (files[i]);
441 str = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gtkrc", NULL);
443 gtk_rc_add_default_file (str);
446 var = g_get_home_dir ();
449 str = g_build_filename (var, ".gtkrc-2.0", NULL);
450 gtk_rc_add_default_file (str);
457 * gtk_rc_add_default_file:
458 * @filename: the pathname to the file.
460 * Adds a file to the list of files to be parsed at the
464 gtk_rc_add_default_file (const gchar *filename)
468 gtk_rc_add_initial_default_files ();
470 for (n = 0; gtk_rc_default_files[n]; n++) ;
471 if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
474 gtk_rc_default_files[n++] = g_strdup (filename);
475 gtk_rc_default_files[n] = NULL;
479 * gtk_rc_set_default_files:
480 * @filenames: A %NULL-terminated list of filenames.
482 * Sets the list of files that GTK+ will read at the
486 gtk_rc_set_default_files (gchar **filenames)
490 gtk_rc_add_initial_default_files ();
493 while (gtk_rc_default_files[i])
495 g_free (gtk_rc_default_files[i]);
499 gtk_rc_default_files[0] = NULL;
502 while (filenames[i] != NULL)
504 gtk_rc_add_default_file (filenames[i]);
510 * gtk_rc_get_default_files:
512 * Retrieves the current list of RC files that will be parsed
513 * at the end of gtk_init().
515 * Return value: A %NULL-terminated array of filenames. This memory
516 * is owned by GTK+ and must not be freed by the application.
517 * If you want to store this information, you should make a copy.
520 gtk_rc_get_default_files (void)
522 gtk_rc_add_initial_default_files ();
524 return gtk_rc_default_files;
527 /* The following routine is based on _nl_normalize_codeset from
528 * the GNU C library. Contributed by
530 * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
531 * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
533 * Normalize codeset name. There is no standard for the codeset
534 * names. Normalization allows the user to use any of the common
538 _gtk_normalize_codeset (const gchar *codeset, gint name_len)
546 for (cnt = 0; cnt < name_len; ++cnt)
547 if (isalnum (codeset[cnt]))
551 if (isalpha (codeset[cnt]))
555 retval = g_malloc ((only_digit ? 3 : 0) + len + 1);
559 memcpy (retval, "iso", 4);
565 for (cnt = 0; cnt < name_len; ++cnt)
566 if (isalpha (codeset[cnt]))
567 *wp++ = isupper(codeset[cnt]) ? tolower (codeset[cnt]) : codeset[cnt];
568 else if (isdigit (codeset[cnt]))
569 *wp++ = codeset[cnt];
577 gtk_rc_settings_changed (GtkSettings *settings,
579 GtkRcContext *context)
581 gchar *new_theme_name;
582 gchar *new_key_theme_name;
584 g_object_get (settings,
585 "gtk-theme-name", &new_theme_name,
586 "gtk-key-theme-name", &new_key_theme_name,
589 if ((new_theme_name != context->theme_name &&
590 !(new_theme_name && context->theme_name && strcmp (new_theme_name, context->theme_name) == 0)) ||
591 (new_key_theme_name != context->key_theme_name &&
592 !(new_key_theme_name && context->key_theme_name && strcmp (new_key_theme_name, context->key_theme_name) == 0)))
594 gtk_rc_reparse_all_for_settings (settings, TRUE);
597 g_free (new_theme_name);
598 g_free (new_key_theme_name);
601 static GtkRcContext *
602 gtk_rc_context_get (GtkSettings *settings)
604 if (!settings->rc_context)
606 GtkRcContext *context = settings->rc_context = g_new (GtkRcContext, 1);
608 context->settings = settings;
609 context->rc_style_ht = NULL;
610 context->rc_sets_widget = NULL;
611 context->rc_sets_widget_class = NULL;
612 context->rc_sets_class = NULL;
613 context->rc_files = NULL;
615 g_object_get (settings,
616 "gtk-theme-name", &context->theme_name,
617 "gtk-key-theme-name", &context->key_theme_name,
620 g_signal_connect (settings,
621 "notify::gtk-theme-name",
622 G_CALLBACK (gtk_rc_settings_changed),
624 g_signal_connect (settings,
625 "notify::gtk-key-theme-name",
626 G_CALLBACK (gtk_rc_settings_changed),
629 context->pixmap_path[0] = NULL;
631 context->default_priority = GTK_PATH_PRIO_RC;
634 return settings->rc_context;
638 gtk_rc_parse_named (GtkRcContext *context,
643 const gchar *home_dir;
647 subpath = g_strconcat ("gtk-2.0-", type,
648 G_DIR_SEPARATOR_S "gtkrc",
651 subpath = g_strdup ("gtk-2.0" G_DIR_SEPARATOR_S "gtkrc");
653 /* First look in the users home directory
655 home_dir = g_get_home_dir ();
658 path = g_build_filename (home_dir, ".themes", name, subpath, NULL);
659 if (!g_file_test (path, G_FILE_TEST_EXISTS))
668 gchar *theme_dir = gtk_rc_get_theme_dir ();
669 path = g_build_filename (theme_dir, name, subpath, NULL);
672 if (!g_file_test (path, G_FILE_TEST_EXISTS))
681 gtk_rc_parse_file (context, path, GTK_PATH_PRIO_THEME, FALSE);
689 gtk_rc_parse_default_files (GtkRcContext *context)
691 gchar *locale_suffixes[3];
692 gint n_locale_suffixes = 0;
699 locale = g_win32_getlocale ();
701 locale = setlocale (LC_CTYPE, NULL);
704 if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
706 /* Determine locale-specific suffixes for RC files
708 * We normalize the charset into a standard form,
709 * which has all '-' and '_' characters removed,
712 gchar *normalized_locale;
714 p = strchr (locale, '@');
715 length = p ? (p - locale) : strlen (locale);
717 p = strchr (locale, '.');
720 gchar *tmp1 = g_strndup (locale, p - locale + 1);
721 gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
723 normalized_locale = g_strconcat (tmp1, tmp2, NULL);
727 locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
731 normalized_locale = g_strndup (locale, length);
733 p = strchr (normalized_locale, '_');
736 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
737 length = p - normalized_locale;
740 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
742 g_free (normalized_locale);
745 for (i = 0; gtk_rc_default_files[i] != NULL; i++)
747 /* Try to find a locale specific RC file corresponding to the
748 * current locale to parse before the default file.
750 for (j = n_locale_suffixes - 1; j >= 0; j--)
752 gchar *name = g_strconcat (gtk_rc_default_files[i],
756 gtk_rc_parse_file (context, name, GTK_PATH_PRIO_RC, FALSE);
759 gtk_rc_parse_file (context, gtk_rc_default_files[i], GTK_PATH_PRIO_RC, FALSE);
762 for (j = 0; j < n_locale_suffixes; j++)
763 g_free (locale_suffixes[j]);
769 static gboolean initialized = FALSE;
775 module_path[0] = NULL;
776 gtk_rc_append_default_module_path();
778 gtk_rc_add_initial_default_files ();
781 gtk_rc_reparse_all_for_settings (gtk_settings_get_default (), TRUE);
785 gtk_rc_parse_string (const gchar *rc_string)
787 g_return_if_fail (rc_string != NULL);
789 gtk_rc_parse_any (gtk_rc_context_get (gtk_settings_get_default ()),
790 "-", -1, rc_string); /* FIXME */
794 gtk_rc_parse_file (GtkRcContext *context,
795 const gchar *filename,
799 GtkRcFile *rc_file = NULL;
804 g_return_if_fail (filename != NULL);
806 saved_priority = context->default_priority;
807 context->default_priority = priority;
809 tmp_list = context->rc_files;
812 rc_file = tmp_list->data;
813 if (!strcmp (rc_file->name, filename))
816 tmp_list = tmp_list->next;
821 rc_file = g_new (GtkRcFile, 1);
822 rc_file->name = g_strdup (filename);
823 rc_file->canonical_name = NULL;
825 rc_file->reload = reload;
827 context->rc_files = g_slist_append (context->rc_files, rc_file);
830 if (!rc_file->canonical_name)
832 /* Get the absolute pathname */
834 if (g_path_is_absolute (rc_file->name))
835 rc_file->canonical_name = rc_file->name;
840 cwd = g_get_current_dir ();
841 rc_file->canonical_name = g_build_filename (cwd, rc_file->name, NULL);
846 if (!lstat (rc_file->canonical_name, &statbuf))
851 rc_file->mtime = statbuf.st_mtime;
853 fd = open (rc_file->canonical_name, O_RDONLY);
857 /* Temporarily push directory name for this file on
858 * a stack of directory names while parsing it
861 g_slist_prepend (rc_dir_stack,
862 g_path_get_dirname (rc_file->canonical_name));
863 gtk_rc_parse_any (context, filename, fd, NULL);
865 tmp_list = rc_dir_stack;
866 rc_dir_stack = rc_dir_stack->next;
868 g_free (tmp_list->data);
869 g_slist_free_1 (tmp_list);
875 context->default_priority = saved_priority;
879 gtk_rc_parse (const gchar *filename)
881 g_return_if_fail (filename != NULL);
883 gtk_rc_parse_file (gtk_rc_context_get (gtk_settings_get_default ()),
884 filename, GTK_PATH_PRIO_RC, TRUE); /* FIXME */
887 /* Handling of RC styles */
890 gtk_rc_style_get_type (void)
892 static GType object_type = 0;
896 static const GTypeInfo object_info =
898 sizeof (GtkRcStyleClass),
899 (GBaseInitFunc) NULL,
900 (GBaseFinalizeFunc) NULL,
901 (GClassInitFunc) gtk_rc_style_class_init,
902 NULL, /* class_finalize */
903 NULL, /* class_data */
906 (GInstanceInitFunc) gtk_rc_style_init,
909 object_type = g_type_register_static (G_TYPE_OBJECT,
918 gtk_rc_style_init (GtkRcStyle *style)
923 style->font_desc = NULL;
925 for (i = 0; i < 5; i++)
927 static const GdkColor init_color = { 0, 0, 0, 0, };
929 style->bg_pixmap_name[i] = NULL;
930 style->color_flags[i] = 0;
931 style->fg[i] = init_color;
932 style->bg[i] = init_color;
933 style->text[i] = init_color;
934 style->base[i] = init_color;
936 style->xthickness = -1;
937 style->ythickness = -1;
938 style->rc_properties = NULL;
940 style->rc_style_lists = NULL;
941 style->icon_factories = NULL;
945 gtk_rc_style_class_init (GtkRcStyleClass *klass)
947 GObjectClass *object_class = G_OBJECT_CLASS (klass);
949 parent_class = g_type_class_peek_parent (klass);
951 object_class->finalize = gtk_rc_style_finalize;
954 klass->create_rc_style = gtk_rc_style_real_create_rc_style;
955 klass->merge = gtk_rc_style_real_merge;
956 klass->create_style = gtk_rc_style_real_create_style;
960 gtk_rc_style_finalize (GObject *object)
962 GSList *tmp_list1, *tmp_list2;
963 GtkRcStyle *rc_style;
966 rc_style = GTK_RC_STYLE (object);
969 g_free (rc_style->name);
970 if (rc_style->font_desc)
971 pango_font_description_free (rc_style->font_desc);
973 for (i = 0; i < 5; i++)
974 if (rc_style->bg_pixmap_name[i])
975 g_free (rc_style->bg_pixmap_name[i]);
977 /* Now remove all references to this rc_style from
980 tmp_list1 = rc_style->rc_style_lists;
983 GSList *rc_styles = tmp_list1->data;
984 GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
985 gtk_style_unref (style);
987 /* Remove the list of styles from the other rc_styles
990 tmp_list2 = rc_styles;
993 GtkRcStyle *other_style = tmp_list2->data;
995 if (other_style != rc_style)
996 other_style->rc_style_lists = g_slist_remove_all (other_style->rc_style_lists,
998 tmp_list2 = tmp_list2->next;
1001 /* And from the hash table itself
1003 g_hash_table_remove (realized_style_ht, rc_styles);
1004 g_slist_free (rc_styles);
1006 tmp_list1 = tmp_list1->next;
1008 g_slist_free (rc_style->rc_style_lists);
1010 if (rc_style->rc_properties)
1014 for (i = 0; i < rc_style->rc_properties->len; i++)
1016 GtkRcProperty *node = &g_array_index (rc_style->rc_properties, GtkRcProperty, i);
1018 g_free (node->origin);
1019 g_value_unset (&node->value);
1021 g_array_free (rc_style->rc_properties, TRUE);
1022 rc_style->rc_properties = NULL;
1025 tmp_list1 = rc_style->icon_factories;
1028 g_object_unref (G_OBJECT (tmp_list1->data));
1030 tmp_list1 = tmp_list1->next;
1032 g_slist_free (rc_style->icon_factories);
1034 G_OBJECT_CLASS (parent_class)->finalize (object);
1038 gtk_rc_style_new (void)
1042 style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
1048 * gtk_rc_style_copy:
1049 * @orig: the style to copy
1051 * Makes a copy of the specified #GtkRcStyle. This function
1052 * will correctly copy an RC style that is a member of a class
1053 * derived from #GtkRcStyle.
1055 * Return value: the resulting #GtkRcStyle
1058 gtk_rc_style_copy (GtkRcStyle *orig)
1062 g_return_val_if_fail (GTK_IS_RC_STYLE (orig), NULL);
1064 style = GTK_RC_STYLE_GET_CLASS (orig)->create_rc_style (orig);
1065 GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
1071 gtk_rc_style_ref (GtkRcStyle *rc_style)
1073 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1075 g_object_ref (G_OBJECT (rc_style));
1079 gtk_rc_style_unref (GtkRcStyle *rc_style)
1081 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1083 g_object_unref (G_OBJECT (rc_style));
1087 gtk_rc_style_real_create_rc_style (GtkRcStyle *style)
1089 return GTK_RC_STYLE (g_object_new (G_OBJECT_TYPE (style), NULL));
1093 gtk_rc_properties_cmp (gconstpointer bsearch_node1,
1094 gconstpointer bsearch_node2)
1096 const GtkRcProperty *prop1 = bsearch_node1;
1097 const GtkRcProperty *prop2 = bsearch_node2;
1099 if (prop1->type_name == prop2->type_name)
1100 return prop1->property_name < prop2->property_name ? -1 : prop1->property_name == prop2->property_name ? 0 : 1;
1102 return prop1->type_name < prop2->type_name ? -1 : 1;
1106 insert_rc_property (GtkRcStyle *style,
1107 GtkRcProperty *property,
1111 GtkRcProperty *new_property = NULL;
1112 GtkRcProperty key = { 0, 0, NULL, { 0, }, };
1114 key.type_name = property->type_name;
1115 key.property_name = property->property_name;
1117 if (!style->rc_properties)
1118 style->rc_properties = g_array_new (FALSE, FALSE, sizeof (GtkRcProperty));
1121 while (i < style->rc_properties->len)
1123 gint cmp = gtk_rc_properties_cmp (&key, &g_array_index (style->rc_properties, GtkRcProperty, i));
1129 new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
1131 g_free (new_property->origin);
1132 g_value_unset (&new_property->value);
1134 *new_property = key;
1148 g_array_insert_val (style->rc_properties, i, key);
1149 new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
1152 new_property->origin = g_strdup (property->origin);
1153 g_value_init (&new_property->value, G_VALUE_TYPE (&property->value));
1154 g_value_copy (&property->value, &new_property->value);
1158 gtk_rc_style_real_merge (GtkRcStyle *dest,
1163 for (i = 0; i < 5; i++)
1165 if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
1166 dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
1168 if (!(dest->color_flags[i] & GTK_RC_FG) &&
1169 src->color_flags[i] & GTK_RC_FG)
1171 dest->fg[i] = src->fg[i];
1172 dest->color_flags[i] |= GTK_RC_FG;
1174 if (!(dest->color_flags[i] & GTK_RC_BG) &&
1175 src->color_flags[i] & GTK_RC_BG)
1177 dest->bg[i] = src->bg[i];
1178 dest->color_flags[i] |= GTK_RC_BG;
1180 if (!(dest->color_flags[i] & GTK_RC_TEXT) &&
1181 src->color_flags[i] & GTK_RC_TEXT)
1183 dest->text[i] = src->text[i];
1184 dest->color_flags[i] |= GTK_RC_TEXT;
1186 if (!(dest->color_flags[i] & GTK_RC_BASE) &&
1187 src->color_flags[i] & GTK_RC_BASE)
1189 dest->base[i] = src->base[i];
1190 dest->color_flags[i] |= GTK_RC_BASE;
1194 if (dest->xthickness < 0 && src->xthickness >= 0)
1195 dest->xthickness = src->xthickness;
1196 if (dest->ythickness < 0 && src->ythickness >= 0)
1197 dest->ythickness = src->ythickness;
1201 if (!dest->font_desc)
1202 dest->font_desc = pango_font_description_copy (src->font_desc);
1204 pango_font_description_merge (dest->font_desc, src->font_desc, FALSE);
1207 if (src->rc_properties)
1211 for (i = 0; i < src->rc_properties->len; i++)
1212 insert_rc_property (dest,
1213 &g_array_index (src->rc_properties, GtkRcProperty, i),
1219 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
1221 return gtk_style_new ();
1225 gtk_rc_clear_hash_node (gpointer key,
1229 gtk_rc_style_unref (data);
1233 gtk_rc_free_rc_sets (GSList *slist)
1239 rc_set = slist->data;
1240 g_pattern_spec_free (rc_set->pspec);
1243 slist = slist->next;
1248 gtk_rc_clear_styles (GtkRcContext *context)
1250 /* Clear out all old rc_styles */
1252 if (context->rc_style_ht)
1254 g_hash_table_foreach (context->rc_style_ht, gtk_rc_clear_hash_node, NULL);
1255 g_hash_table_destroy (context->rc_style_ht);
1256 context->rc_style_ht = NULL;
1259 gtk_rc_free_rc_sets (context->rc_sets_widget);
1260 g_slist_free (context->rc_sets_widget);
1261 context->rc_sets_widget = NULL;
1263 gtk_rc_free_rc_sets (context->rc_sets_widget_class);
1264 g_slist_free (context->rc_sets_widget_class);
1265 context->rc_sets_widget_class = NULL;
1267 gtk_rc_free_rc_sets (context->rc_sets_class);
1268 g_slist_free (context->rc_sets_class);
1269 context->rc_sets_class = NULL;
1272 /* Reset all our widgets. Also, we have to invalidate cached icons in
1273 * icon sets so they get re-rendered.
1276 gtk_rc_reset_widgets (GtkRcContext *context)
1278 GList *list, *toplevels;
1280 _gtk_icon_set_invalidate_caches ();
1282 toplevels = gtk_window_list_toplevels ();
1283 g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1285 for (list = toplevels; list; list = list->next)
1287 gtk_widget_reset_rc_styles (list->data);
1288 gtk_widget_unref (list->data);
1290 g_list_free (toplevels);
1294 * gtk_rc_reparse_all_for_settings:
1295 * @settings: a #GtkSettings
1296 * @force_load: load whether or not anything changed
1298 * If the modification time on any previously read file
1299 * for the given #GtkSettings has changed, discard all style information
1300 * and then reread all previously read RC files.
1302 * Return value: %TRUE if the files were reread.
1305 gtk_rc_reparse_all_for_settings (GtkSettings *settings,
1306 gboolean force_load)
1308 gboolean mtime_modified = FALSE;
1311 GtkRcContext *context;
1313 struct stat statbuf;
1315 g_return_val_if_fail (GTK_IS_SETTINGS (settings), FALSE);
1317 context = gtk_rc_context_get (settings);
1321 /* Check through and see if any of the RC's have had their
1322 * mtime modified. If so, reparse everything.
1324 tmp_list = context->rc_files;
1327 rc_file = tmp_list->data;
1329 if (!lstat (rc_file->name, &statbuf) &&
1330 (statbuf.st_mtime > rc_file->mtime))
1332 mtime_modified = TRUE;
1336 tmp_list = tmp_list->next;
1340 if (force_load || mtime_modified)
1344 gtk_rc_clear_styles (context);
1345 g_object_freeze_notify (G_OBJECT (context->settings));
1347 old_files = context->rc_files;
1348 context->rc_files = NULL;
1350 gtk_rc_parse_default_files (context);
1352 tmp_list = old_files;
1355 rc_file = tmp_list->data;
1356 if (rc_file->reload)
1357 gtk_rc_parse_file (context, rc_file->name, GTK_PATH_PRIO_RC, TRUE);
1359 if (rc_file->canonical_name != rc_file->name)
1360 g_free (rc_file->canonical_name);
1361 g_free (rc_file->name);
1364 tmp_list = tmp_list->next;
1367 g_slist_free (old_files);;
1369 g_free (context->theme_name);
1370 g_free (context->key_theme_name);
1371 g_object_get (context->settings,
1372 "gtk-theme-name", &context->theme_name,
1373 "gtk-key-theme-name", &context->key_theme_name,
1376 if (context->theme_name && context->theme_name[0])
1377 gtk_rc_parse_named (context, context->theme_name, NULL);
1378 if (context->key_theme_name && context->key_theme_name[0])
1379 gtk_rc_parse_named (context, context->key_theme_name, "key");
1381 g_object_thaw_notify (G_OBJECT (context->settings));
1383 gtk_rc_reset_widgets (context);
1386 return mtime_modified;
1390 * gtk_rc_reparse_all:
1392 * If the modification time on any previously read file for the
1393 * default #GtkSettings has changed, discard all style information
1394 * and then reread all previously read RC files.
1396 * Return value: %TRUE if the files were reread.
1399 gtk_rc_reparse_all (void)
1401 return gtk_rc_reparse_all_for_settings (gtk_settings_get_default (), FALSE);
1405 gtk_rc_styles_match (GSList *rc_styles,
1409 const gchar *path_reversed)
1416 rc_set = sets->data;
1419 if (g_pattern_match (rc_set->pspec, path_length, path, path_reversed))
1420 rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
1428 * @widget: a #GtkWidget
1430 * Finds all matching RC styles for a given widget,
1431 * composites them together, and then creates a
1432 * #GtkStyle representing the composite appearance.
1433 * (GTK+ actually keeps a cache of previously
1434 * created styles, so a new style may not be
1437 * Returns: the resulting style. No refcount is added
1438 * to the returned style, so if you want to save this
1439 * style around, you should add a reference yourself.
1442 gtk_rc_get_style (GtkWidget *widget)
1444 GtkRcStyle *widget_rc_style;
1445 GSList *rc_styles = NULL;
1446 GtkRcContext *context;
1448 static guint rc_style_key_id = 0;
1450 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1452 context = gtk_rc_context_get (gtk_widget_get_settings (widget));
1454 /* We allow the specification of a single rc style to be bound
1455 * tightly to a widget, for application modifications
1457 if (!rc_style_key_id)
1458 rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1460 widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
1463 if (widget_rc_style)
1464 rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
1466 if (context->rc_sets_widget)
1468 gchar *path, *path_reversed;
1471 gtk_widget_path (widget, &path_length, &path, &path_reversed);
1472 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, path, path_reversed);
1474 g_free (path_reversed);
1477 if (context->rc_sets_widget_class)
1479 gchar *path, *path_reversed;
1482 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1483 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, path, path_reversed);
1485 g_free (path_reversed);
1488 if (context->rc_sets_class)
1492 type = GTK_OBJECT_TYPE (widget);
1496 gchar *path_reversed;
1499 path = gtk_type_name (type);
1500 path_length = strlen (path);
1501 path_reversed = g_strdup (path);
1502 g_strreverse (path_reversed);
1504 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
1505 g_free (path_reversed);
1507 type = gtk_type_parent (type);
1512 return gtk_rc_init_style (rc_styles);
1518 * gtk_rc_get_style_by_paths:
1519 * @settings: a #GtkSettings object
1520 * @widget_path: the widget path to use when looking up the style, or %NULL
1521 * @class_path: the class path to use when looking up the style, or %NULL
1522 * @type: a type that will be used along with parent types of this type
1523 * when matching against class styles, or #G_TYPE_NONE
1525 * Creates up a #GtkStyle from styles defined in a RC file by providing
1526 * the raw components used in matching. This function may be useful
1527 * when creating pseudo-widgets that should be themed like widgets but
1528 * don't actually have corresponding GTK+ widgets. An example of this
1529 * would be items inside a GNOME canvas widget.
1531 * The action of gtk_rc_get_style() is similar to:
1532 * <informalexample><programlisting>
1533 * <!> gtk_widget_path (widget, NULL, &path, NULL);
1534 * <!> gtk_widget_class_path (widget, NULL, &class_path, NULL);
1535 * <!> gtk_rc_get_style_by_paths (gtk_widget_get_settings (widget), path, class_path,
1536 * <!> G_OBJECT_TYPE (widget));
1537 * </programlisting></informalexample>
1539 * Return value: A style created by matching with the supplied paths,
1540 * or %NULL if nothing matching was specified and the default style should
1541 * be used. The returned value is owned by GTK+ as part of an internal cache,
1542 * so you must call g_object_ref() on the returned value if you want to
1543 * keep a reference to it.
1546 gtk_rc_get_style_by_paths (GtkSettings *settings,
1547 const char *widget_path,
1548 const char *class_path,
1551 /* We duplicate the code from above to avoid slowing down the above
1552 * by generating paths when we don't need them. I don't know if
1553 * this is really worth it.
1555 GSList *rc_styles = NULL;
1556 GtkRcContext *context;
1558 g_return_val_if_fail (GTK_IS_SETTINGS (settings), NULL);
1560 context = gtk_rc_context_get (settings);
1562 if (context->rc_sets_widget)
1564 gchar *path_reversed;
1567 path_length = strlen (widget_path);
1568 path_reversed = g_strdup (widget_path);
1569 g_strreverse (path_reversed);
1571 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, widget_path, path_reversed);
1572 g_free (path_reversed);
1575 if (context->rc_sets_widget_class)
1577 gchar *path_reversed;
1580 path_length = strlen (class_path);
1581 path_reversed = g_strdup (class_path);
1582 g_strreverse (path_reversed);
1584 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, class_path, path_reversed);
1585 g_free (path_reversed);
1588 if (type != G_TYPE_NONE && context->rc_sets_class)
1593 gchar *path_reversed;
1596 path = g_type_name (type);
1597 path_length = strlen (path);
1598 path_reversed = g_strdup (path);
1599 g_strreverse (path_reversed);
1601 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
1602 g_free (path_reversed);
1604 type = g_type_parent (type);
1609 return gtk_rc_init_style (rc_styles);
1615 gtk_rc_add_rc_sets (GSList *slist,
1616 GtkRcStyle *rc_style,
1617 const gchar *pattern)
1619 GtkRcStyle *new_style;
1623 new_style = gtk_rc_style_new ();
1624 *new_style = *rc_style;
1625 new_style->name = g_strdup (rc_style->name);
1626 if (rc_style->font_desc)
1627 new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
1629 for (i = 0; i < 5; i++)
1630 new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1632 rc_set = g_new (GtkRcSet, 1);
1633 rc_set->pspec = g_pattern_spec_new (pattern);
1634 rc_set->rc_style = rc_style;
1636 return g_slist_prepend (slist, rc_set);
1640 gtk_rc_add_widget_name_style (GtkRcStyle *rc_style,
1641 const gchar *pattern)
1643 GtkRcContext *context;
1645 g_return_if_fail (rc_style != NULL);
1646 g_return_if_fail (pattern != NULL);
1648 context = gtk_rc_context_get (gtk_settings_get_default ());
1650 context->rc_sets_widget = gtk_rc_add_rc_sets (context->rc_sets_widget, rc_style, pattern);
1654 gtk_rc_add_widget_class_style (GtkRcStyle *rc_style,
1655 const gchar *pattern)
1657 GtkRcContext *context;
1659 g_return_if_fail (rc_style != NULL);
1660 g_return_if_fail (pattern != NULL);
1662 context = gtk_rc_context_get (gtk_settings_get_default ());
1664 context->rc_sets_widget_class = gtk_rc_add_rc_sets (context->rc_sets_widget_class, rc_style, pattern);
1668 gtk_rc_add_class_style (GtkRcStyle *rc_style,
1669 const gchar *pattern)
1671 GtkRcContext *context;
1673 g_return_if_fail (rc_style != NULL);
1674 g_return_if_fail (pattern != NULL);
1676 context = gtk_rc_context_get (gtk_settings_get_default ());
1678 context->rc_sets_class = gtk_rc_add_rc_sets (context->rc_sets_class, rc_style, pattern);
1682 gtk_rc_scanner_new (void)
1684 return g_scanner_new (>k_rc_scanner_config);
1688 gtk_rc_parse_any (GtkRcContext *context,
1689 const gchar *input_name,
1691 const gchar *input_string)
1697 scanner = gtk_rc_scanner_new ();
1701 g_assert (input_string == NULL);
1703 g_scanner_input_file (scanner, input_fd);
1707 g_assert (input_string != NULL);
1709 g_scanner_input_text (scanner, input_string, strlen (input_string));
1711 scanner->input_name = input_name;
1713 for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1714 g_scanner_scope_add_symbol (scanner, 0, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1719 if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1723 guint expected_token;
1725 expected_token = gtk_rc_parse_statement (context, scanner);
1727 if (expected_token != G_TOKEN_NONE)
1734 if (scanner->scope_id == 0)
1736 /* if we are in scope 0, we know the symbol names
1737 * that are associated with certain token values.
1738 * so we look them up to make the error messages
1741 if (expected_token > GTK_RC_TOKEN_INVALID &&
1742 expected_token < GTK_RC_TOKEN_LAST)
1744 for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1745 if (symbols[i].token == expected_token)
1746 msg = symbols[i].name;
1748 msg = g_strconcat ("e.g. `", msg, "'", NULL);
1750 if (scanner->token > GTK_RC_TOKEN_INVALID &&
1751 scanner->token < GTK_RC_TOKEN_LAST)
1753 symbol_name = "???";
1754 for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1755 if (symbols[i].token == scanner->token)
1756 symbol_name = symbols[i].name;
1759 g_scanner_unexp_token (scanner,
1772 g_scanner_destroy (scanner);
1776 gtk_rc_styles_hash (const GSList *rc_styles)
1783 result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1784 rc_styles = rc_styles->next;
1791 gtk_rc_styles_equal (const GSList *a,
1796 if (a->data != b->data)
1806 gtk_rc_style_hash (const gchar *name)
1812 result += (result << 3) + *name++;
1818 gtk_rc_style_equal (const gchar *a,
1821 return (strcmp (a, b) == 0);
1825 gtk_rc_style_find (GtkRcContext *context,
1828 if (context->rc_style_ht)
1829 return g_hash_table_lookup (context->rc_style_ht, (gpointer) name);
1835 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1839 style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
1841 style->rc_style = rc_style;
1843 gtk_rc_style_ref (rc_style);
1845 GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);
1850 /* Reuses or frees rc_styles */
1852 gtk_rc_init_style (GSList *rc_styles)
1854 GtkStyle *style = NULL;
1857 g_return_val_if_fail (rc_styles != NULL, NULL);
1859 if (!realized_style_ht)
1860 realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
1861 (GEqualFunc) gtk_rc_styles_equal);
1863 style = g_hash_table_lookup (realized_style_ht, rc_styles);
1867 GtkRcStyle *base_style = NULL;
1868 GtkRcStyle *proto_style;
1869 GtkRcStyleClass *proto_style_class;
1871 GType rc_style_type = GTK_TYPE_RC_STYLE;
1873 /* Find the first derived style in the list, and use that to
1874 * create the merged style. If we only have raw GtkRcStyles, use
1875 * the first style to create the merged style.
1877 base_style = rc_styles->data;
1878 tmp_styles = rc_styles;
1881 GtkRcStyle *rc_style = tmp_styles->data;
1883 if (G_OBJECT_TYPE (rc_style) != rc_style_type)
1885 base_style = rc_style;
1889 tmp_styles = tmp_styles->next;
1892 proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
1893 proto_style = proto_style_class->create_rc_style (base_style);
1895 tmp_styles = rc_styles;
1898 GtkRcStyle *rc_style = tmp_styles->data;
1901 proto_style_class->merge (proto_style, rc_style);
1903 /* Point from each rc_style to the list of styles */
1904 if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
1905 rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
1907 factories = g_slist_copy (rc_style->icon_factories);
1913 while (iter != NULL)
1915 g_object_ref (G_OBJECT (iter->data));
1916 iter = g_slist_next (iter);
1919 proto_style->icon_factories = g_slist_concat (proto_style->icon_factories,
1924 tmp_styles = tmp_styles->next;
1927 for (i = 0; i < 5; i++)
1928 if (proto_style->bg_pixmap_name[i] &&
1929 (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1931 g_free (proto_style->bg_pixmap_name[i]);
1932 proto_style->bg_pixmap_name[i] = NULL;
1935 style = gtk_rc_style_to_style (proto_style);
1936 gtk_rc_style_unref (proto_style);
1938 g_hash_table_insert (realized_style_ht, rc_styles, style);
1941 g_slist_free (rc_styles);
1946 /*********************
1947 * Parsing functions *
1948 *********************/
1951 rc_parse_token_or_compound (GScanner *scanner,
1953 GTokenType delimiter)
1955 guint token = g_scanner_get_next_token (scanner);
1957 /* we either scan a single token (skipping comments)
1958 * or a compund statement.
1959 * compunds are enclosed in (), [] or {} braces, we read
1960 * them in via deep recursion.
1967 g_string_append_printf (gstring, " 0x%lx", scanner->value.v_int);
1970 g_string_append_printf (gstring, " %f", scanner->value.v_float);
1972 case G_TOKEN_STRING:
1973 string = g_strescape (scanner->value.v_string, NULL);
1974 g_string_append (gstring, " \"");
1975 g_string_append (gstring, string);
1976 g_string_append_c (gstring, '"');
1979 case G_TOKEN_IDENTIFIER:
1980 g_string_append_c (gstring, ' ');
1981 g_string_append (gstring, scanner->value.v_identifier);
1983 case G_TOKEN_COMMENT_SINGLE:
1984 case G_TOKEN_COMMENT_MULTI:
1985 return rc_parse_token_or_compound (scanner, gstring, delimiter);
1986 case G_TOKEN_LEFT_PAREN:
1987 g_string_append_c (gstring, ' ');
1988 g_string_append_c (gstring, token);
1989 token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_PAREN);
1990 if (token != G_TOKEN_NONE)
1993 case G_TOKEN_LEFT_CURLY:
1994 g_string_append_c (gstring, ' ');
1995 g_string_append_c (gstring, token);
1996 token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_CURLY);
1997 if (token != G_TOKEN_NONE)
2000 case G_TOKEN_LEFT_BRACE:
2001 g_string_append_c (gstring, ' ');
2002 g_string_append_c (gstring, token);
2003 token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_BRACE);
2004 if (token != G_TOKEN_NONE)
2008 if (token >= 256 || token < 1)
2009 return delimiter ? delimiter : G_TOKEN_STRING;
2010 g_string_append_c (gstring, ' ');
2011 g_string_append_c (gstring, token);
2012 if (token == delimiter)
2013 return G_TOKEN_NONE;
2017 return G_TOKEN_NONE;
2019 return rc_parse_token_or_compound (scanner, gstring, delimiter);
2023 gtk_rc_parse_assignment (GScanner *scanner,
2024 GtkRcProperty *prop)
2026 gboolean scan_identifier = scanner->config->scan_identifier;
2027 gboolean scan_symbols = scanner->config->scan_symbols;
2028 gboolean identifier_2_string = scanner->config->identifier_2_string;
2029 gboolean char_2_token = scanner->config->char_2_token;
2030 gboolean scan_identifier_NULL = scanner->config->scan_identifier_NULL;
2031 gboolean numbers_2_int = scanner->config->numbers_2_int;
2032 gboolean negate = FALSE;
2035 /* check that this is an assignment */
2036 if (g_scanner_get_next_token (scanner) != '=')
2039 /* adjust scanner mode */
2040 scanner->config->scan_identifier = TRUE;
2041 scanner->config->scan_symbols = FALSE;
2042 scanner->config->identifier_2_string = FALSE;
2043 scanner->config->char_2_token = TRUE;
2044 scanner->config->scan_identifier_NULL = FALSE;
2045 scanner->config->numbers_2_int = TRUE;
2047 /* record location */
2048 prop->origin = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
2050 /* parse optional sign */
2051 if (g_scanner_peek_next_token (scanner) == '-')
2053 g_scanner_get_next_token (scanner); /* eat sign */
2057 /* parse one of LONG, DOUBLE and STRING or, if that fails, create an unparsed compund */
2058 token = g_scanner_peek_next_token (scanner);
2062 g_scanner_get_next_token (scanner);
2063 g_value_init (&prop->value, G_TYPE_LONG);
2064 g_value_set_long (&prop->value, negate ? -scanner->value.v_int : scanner->value.v_int);
2065 token = G_TOKEN_NONE;
2068 g_scanner_get_next_token (scanner);
2069 g_value_init (&prop->value, G_TYPE_DOUBLE);
2070 g_value_set_double (&prop->value, negate ? -scanner->value.v_float : scanner->value.v_float);
2071 token = G_TOKEN_NONE;
2073 case G_TOKEN_STRING:
2074 g_scanner_get_next_token (scanner);
2076 token = G_TOKEN_INT;
2079 g_value_init (&prop->value, G_TYPE_STRING);
2080 g_value_set_string (&prop->value, scanner->value.v_string);
2081 token = G_TOKEN_NONE;
2084 case G_TOKEN_IDENTIFIER:
2085 case G_TOKEN_LEFT_PAREN:
2086 case G_TOKEN_LEFT_CURLY:
2087 case G_TOKEN_LEFT_BRACE:
2090 GString *gstring = g_string_new ("");
2092 token = rc_parse_token_or_compound (scanner, gstring, 0);
2093 if (token == G_TOKEN_NONE)
2095 g_string_append_c (gstring, ' ');
2096 g_value_init (&prop->value, G_TYPE_GSTRING);
2097 g_value_set_static_boxed (&prop->value, gstring);
2100 g_string_free (gstring, TRUE);
2105 g_scanner_get_next_token (scanner);
2106 token = G_TOKEN_INT;
2110 /* restore scanner mode */
2111 scanner->config->scan_identifier = scan_identifier;
2112 scanner->config->scan_symbols = scan_symbols;
2113 scanner->config->identifier_2_string = identifier_2_string;
2114 scanner->config->char_2_token = char_2_token;
2115 scanner->config->scan_identifier_NULL = scan_identifier_NULL;
2116 scanner->config->numbers_2_int = numbers_2_int;
2122 is_c_identifier (const gchar *string)
2125 gboolean is_varname;
2127 is_varname = strchr (G_CSET_a_2_z G_CSET_A_2_Z "_", string[0]) != NULL;
2128 for (p = string + 1; *p && is_varname; p++)
2129 is_varname &= strchr (G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "_-", *p) != NULL;
2135 gtk_rc_parse_statement (GtkRcContext *context,
2140 token = g_scanner_peek_next_token (scanner);
2143 case GTK_RC_TOKEN_INCLUDE:
2144 token = g_scanner_get_next_token (scanner);
2145 if (token != GTK_RC_TOKEN_INCLUDE)
2146 return GTK_RC_TOKEN_INCLUDE;
2147 token = g_scanner_get_next_token (scanner);
2148 if (token != G_TOKEN_STRING)
2149 return G_TOKEN_STRING;
2150 gtk_rc_parse_file (context, scanner->value.v_string, context->default_priority, FALSE);
2151 return G_TOKEN_NONE;
2153 case GTK_RC_TOKEN_STYLE:
2154 return gtk_rc_parse_style (context, scanner);
2156 case GTK_RC_TOKEN_BINDING:
2157 return gtk_binding_parse_binding (scanner);
2159 case GTK_RC_TOKEN_PIXMAP_PATH:
2160 return gtk_rc_parse_pixmap_path (context, scanner);
2162 case GTK_RC_TOKEN_WIDGET:
2163 return gtk_rc_parse_path_pattern (context, scanner);
2165 case GTK_RC_TOKEN_WIDGET_CLASS:
2166 return gtk_rc_parse_path_pattern (context, scanner);
2168 case GTK_RC_TOKEN_CLASS:
2169 return gtk_rc_parse_path_pattern (context, scanner);
2171 case GTK_RC_TOKEN_MODULE_PATH:
2172 return gtk_rc_parse_module_path (scanner);
2174 case GTK_RC_TOKEN_IM_MODULE_PATH:
2175 return gtk_rc_parse_im_module_path (scanner);
2177 case GTK_RC_TOKEN_IM_MODULE_FILE:
2178 return gtk_rc_parse_im_module_file (scanner);
2180 case G_TOKEN_IDENTIFIER:
2181 if (is_c_identifier (scanner->next_value.v_identifier))
2183 GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2186 g_scanner_get_next_token (scanner); /* eat identifier */
2187 name = g_strdup (scanner->value.v_identifier);
2189 token = gtk_rc_parse_assignment (scanner, &prop);
2190 if (token == G_TOKEN_NONE)
2192 GtkSettingsValue svalue;
2194 svalue.origin = prop.origin;
2195 memcpy (&svalue.value, &prop.value, sizeof (prop.value));
2196 g_strcanon (name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
2197 gtk_settings_set_property_value (context->settings,
2201 g_free (prop.origin);
2202 if (G_VALUE_TYPE (&prop.value))
2203 g_value_unset (&prop.value);
2210 g_scanner_get_next_token (scanner);
2211 return G_TOKEN_IDENTIFIER;
2214 g_scanner_get_next_token (scanner);
2215 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
2220 fixup_rc_set (GSList *list,
2226 GtkRcSet *set = list->data;
2227 if (set->rc_style == orig)
2228 set->rc_style = new;
2234 fixup_rc_sets (GtkRcContext *context,
2238 fixup_rc_set (context->rc_sets_widget, orig, new);
2239 fixup_rc_set (context->rc_sets_widget_class, orig, new);
2240 fixup_rc_set (context->rc_sets_class, orig, new);
2244 gtk_rc_parse_style (GtkRcContext *context,
2247 GtkRcStyle *rc_style;
2248 GtkRcStyle *orig_style;
2249 GtkRcStyle *parent_style;
2252 GtkIconFactory *our_factory = NULL;
2254 token = g_scanner_get_next_token (scanner);
2255 if (token != GTK_RC_TOKEN_STYLE)
2256 return GTK_RC_TOKEN_STYLE;
2258 token = g_scanner_get_next_token (scanner);
2259 if (token != G_TOKEN_STRING)
2260 return G_TOKEN_STRING;
2262 rc_style = gtk_rc_style_find (context, scanner->value.v_string);
2264 orig_style = g_object_ref (rc_style);
2268 /* If there's a list, its first member is always the factory belonging
2271 if (rc_style && rc_style->icon_factories)
2272 our_factory = rc_style->icon_factories->data;
2276 rc_style = gtk_rc_style_new ();
2277 rc_style->name = g_strdup (scanner->value.v_string);
2279 for (i = 0; i < 5; i++)
2280 rc_style->bg_pixmap_name[i] = NULL;
2282 for (i = 0; i < 5; i++)
2283 rc_style->color_flags[i] = 0;
2286 token = g_scanner_peek_next_token (scanner);
2287 if (token == G_TOKEN_EQUAL_SIGN)
2289 token = g_scanner_get_next_token (scanner);
2291 token = g_scanner_get_next_token (scanner);
2292 if (token != G_TOKEN_STRING)
2294 token = G_TOKEN_STRING;
2298 parent_style = gtk_rc_style_find (context, scanner->value.v_string);
2303 for (i = 0; i < 5; i++)
2305 rc_style->color_flags[i] = parent_style->color_flags[i];
2306 rc_style->fg[i] = parent_style->fg[i];
2307 rc_style->bg[i] = parent_style->bg[i];
2308 rc_style->text[i] = parent_style->text[i];
2309 rc_style->base[i] = parent_style->base[i];
2312 rc_style->xthickness = parent_style->xthickness;
2313 rc_style->ythickness = parent_style->ythickness;
2315 if (parent_style->font_desc)
2317 if (rc_style->font_desc)
2318 pango_font_description_free (rc_style->font_desc);
2319 rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
2322 if (parent_style->rc_properties)
2326 for (i = 0; i < parent_style->rc_properties->len; i++)
2327 insert_rc_property (rc_style,
2328 &g_array_index (parent_style->rc_properties, GtkRcProperty, i),
2332 for (i = 0; i < 5; i++)
2334 if (rc_style->bg_pixmap_name[i])
2335 g_free (rc_style->bg_pixmap_name[i]);
2336 rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
2339 /* Append parent's factories, adding a ref to them */
2340 if (parent_style->icon_factories != NULL)
2342 /* Add a factory for ourselves if we have none,
2343 * in case we end up defining more stock icons.
2344 * I see no real way around this; we need to maintain
2345 * the invariant that the first factory in the list
2346 * is always our_factory, the one belonging to us,
2347 * and if we put parent factories in the list we can't
2348 * do that if the style is reopened.
2350 if (our_factory == NULL)
2352 our_factory = gtk_icon_factory_new ();
2353 rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
2357 rc_style->icon_factories = g_slist_concat (rc_style->icon_factories,
2358 g_slist_copy (parent_style->icon_factories));
2360 factories = parent_style->icon_factories;
2361 while (factories != NULL)
2363 g_object_ref (G_OBJECT (factories->data));
2364 factories = factories->next;
2370 token = g_scanner_get_next_token (scanner);
2371 if (token != G_TOKEN_LEFT_CURLY)
2373 token = G_TOKEN_LEFT_CURLY;
2377 token = g_scanner_peek_next_token (scanner);
2378 while (token != G_TOKEN_RIGHT_CURLY)
2382 case GTK_RC_TOKEN_BG:
2383 token = gtk_rc_parse_bg (scanner, rc_style);
2385 case GTK_RC_TOKEN_FG:
2386 token = gtk_rc_parse_fg (scanner, rc_style);
2388 case GTK_RC_TOKEN_TEXT:
2389 token = gtk_rc_parse_text (scanner, rc_style);
2391 case GTK_RC_TOKEN_BASE:
2392 token = gtk_rc_parse_base (scanner, rc_style);
2394 case GTK_RC_TOKEN_XTHICKNESS:
2395 token = gtk_rc_parse_xthickness (scanner, rc_style);
2397 case GTK_RC_TOKEN_YTHICKNESS:
2398 token = gtk_rc_parse_ythickness (scanner, rc_style);
2400 case GTK_RC_TOKEN_BG_PIXMAP:
2401 token = gtk_rc_parse_bg_pixmap (context, scanner, rc_style);
2403 case GTK_RC_TOKEN_FONT:
2404 token = gtk_rc_parse_font (scanner, rc_style);
2406 case GTK_RC_TOKEN_FONTSET:
2407 token = gtk_rc_parse_fontset (scanner, rc_style);
2409 case GTK_RC_TOKEN_FONT_NAME:
2410 token = gtk_rc_parse_font_name (scanner, rc_style);
2412 case GTK_RC_TOKEN_ENGINE:
2413 token = gtk_rc_parse_engine (context, scanner, &rc_style);
2415 case GTK_RC_TOKEN_STOCK:
2416 if (our_factory == NULL)
2418 our_factory = gtk_icon_factory_new ();
2419 rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
2422 token = gtk_rc_parse_stock (context, scanner, rc_style, our_factory);
2424 case G_TOKEN_IDENTIFIER:
2425 if (is_c_identifier (scanner->next_value.v_identifier) &&
2426 scanner->next_value.v_identifier[0] >= 'A' &&
2427 scanner->next_value.v_identifier[0] <= 'Z') /* match namespaced type names */
2429 GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2431 g_scanner_get_next_token (scanner); /* eat type name */
2432 prop.type_name = g_quark_from_string (scanner->value.v_identifier);
2433 if (g_scanner_get_next_token (scanner) != ':' ||
2434 g_scanner_get_next_token (scanner) != ':')
2439 if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER ||
2440 !is_c_identifier (scanner->value.v_identifier))
2442 token = G_TOKEN_IDENTIFIER;
2446 /* it's important that we do the same canonification as GParamSpecPool here */
2447 g_strcanon (scanner->value.v_identifier, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
2448 prop.property_name = g_quark_from_string (scanner->value.v_identifier);
2450 token = gtk_rc_parse_assignment (scanner, &prop);
2451 if (token == G_TOKEN_NONE)
2453 g_return_val_if_fail (prop.origin != NULL && G_VALUE_TYPE (&prop.value) != 0, G_TOKEN_ERROR);
2454 insert_rc_property (rc_style, &prop, TRUE);
2457 g_free (prop.origin);
2458 if (G_VALUE_TYPE (&prop.value))
2459 g_value_unset (&prop.value);
2463 g_scanner_get_next_token (scanner);
2464 token = G_TOKEN_IDENTIFIER;
2468 g_scanner_get_next_token (scanner);
2469 token = G_TOKEN_RIGHT_CURLY;
2473 if (token != G_TOKEN_NONE)
2476 token = g_scanner_peek_next_token (scanner);
2477 } /* while (token != G_TOKEN_RIGHT_CURLY) */
2479 token = g_scanner_get_next_token (scanner);
2480 if (token != G_TOKEN_RIGHT_CURLY)
2482 token = G_TOKEN_RIGHT_CURLY;
2486 if (rc_style != orig_style)
2488 if (!context->rc_style_ht)
2489 context->rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
2490 (GEqualFunc) gtk_rc_style_equal);
2492 g_hash_table_replace (context->rc_style_ht, rc_style->name, rc_style);
2494 /* If we copied the data into a new rc style, fix up references to the old rc style
2495 * in bindings that we have.
2498 fixup_rc_sets (context, orig_style, rc_style);
2502 g_object_unref (orig_style);
2504 return G_TOKEN_NONE;
2507 if (rc_style != orig_style)
2508 gtk_rc_style_unref (rc_style);
2511 g_object_unref (orig_style);
2516 const GtkRcProperty*
2517 _gtk_rc_style_lookup_rc_property (GtkRcStyle *rc_style,
2519 GQuark property_name)
2521 GtkRcProperty *node = NULL;
2523 g_return_val_if_fail (GTK_IS_RC_STYLE (rc_style), NULL);
2525 if (rc_style->rc_properties)
2529 key.type_name = type_name;
2530 key.property_name = property_name;
2532 node = bsearch (&key,
2533 rc_style->rc_properties->data, rc_style->rc_properties->len,
2534 sizeof (GtkRcProperty), gtk_rc_properties_cmp);
2541 gtk_rc_parse_bg (GScanner *scanner,
2547 token = g_scanner_get_next_token (scanner);
2548 if (token != GTK_RC_TOKEN_BG)
2549 return GTK_RC_TOKEN_BG;
2551 token = gtk_rc_parse_state (scanner, &state);
2552 if (token != G_TOKEN_NONE)
2555 token = g_scanner_get_next_token (scanner);
2556 if (token != G_TOKEN_EQUAL_SIGN)
2557 return G_TOKEN_EQUAL_SIGN;
2559 style->color_flags[state] |= GTK_RC_BG;
2560 return gtk_rc_parse_color (scanner, &style->bg[state]);
2564 gtk_rc_parse_fg (GScanner *scanner,
2570 token = g_scanner_get_next_token (scanner);
2571 if (token != GTK_RC_TOKEN_FG)
2572 return GTK_RC_TOKEN_FG;
2574 token = gtk_rc_parse_state (scanner, &state);
2575 if (token != G_TOKEN_NONE)
2578 token = g_scanner_get_next_token (scanner);
2579 if (token != G_TOKEN_EQUAL_SIGN)
2580 return G_TOKEN_EQUAL_SIGN;
2582 style->color_flags[state] |= GTK_RC_FG;
2583 return gtk_rc_parse_color (scanner, &style->fg[state]);
2587 gtk_rc_parse_text (GScanner *scanner,
2593 token = g_scanner_get_next_token (scanner);
2594 if (token != GTK_RC_TOKEN_TEXT)
2595 return GTK_RC_TOKEN_TEXT;
2597 token = gtk_rc_parse_state (scanner, &state);
2598 if (token != G_TOKEN_NONE)
2601 token = g_scanner_get_next_token (scanner);
2602 if (token != G_TOKEN_EQUAL_SIGN)
2603 return G_TOKEN_EQUAL_SIGN;
2605 style->color_flags[state] |= GTK_RC_TEXT;
2606 return gtk_rc_parse_color (scanner, &style->text[state]);
2610 gtk_rc_parse_base (GScanner *scanner,
2616 token = g_scanner_get_next_token (scanner);
2617 if (token != GTK_RC_TOKEN_BASE)
2618 return GTK_RC_TOKEN_BASE;
2620 token = gtk_rc_parse_state (scanner, &state);
2621 if (token != G_TOKEN_NONE)
2624 token = g_scanner_get_next_token (scanner);
2625 if (token != G_TOKEN_EQUAL_SIGN)
2626 return G_TOKEN_EQUAL_SIGN;
2628 style->color_flags[state] |= GTK_RC_BASE;
2629 return gtk_rc_parse_color (scanner, &style->base[state]);
2633 gtk_rc_parse_xthickness (GScanner *scanner,
2636 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
2637 return GTK_RC_TOKEN_XTHICKNESS;
2639 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2640 return G_TOKEN_EQUAL_SIGN;
2642 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2645 style->xthickness = scanner->value.v_int;
2647 return G_TOKEN_NONE;
2651 gtk_rc_parse_ythickness (GScanner *scanner,
2654 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
2655 return GTK_RC_TOKEN_YTHICKNESS;
2657 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2658 return G_TOKEN_EQUAL_SIGN;
2660 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2663 style->ythickness = scanner->value.v_int;
2665 return G_TOKEN_NONE;
2669 gtk_rc_parse_bg_pixmap (GtkRcContext *context,
2671 GtkRcStyle *rc_style)
2677 token = g_scanner_get_next_token (scanner);
2678 if (token != GTK_RC_TOKEN_BG_PIXMAP)
2679 return GTK_RC_TOKEN_BG_PIXMAP;
2681 token = gtk_rc_parse_state (scanner, &state);
2682 if (token != G_TOKEN_NONE)
2685 token = g_scanner_get_next_token (scanner);
2686 if (token != G_TOKEN_EQUAL_SIGN)
2687 return G_TOKEN_EQUAL_SIGN;
2689 token = g_scanner_get_next_token (scanner);
2690 if (token != G_TOKEN_STRING)
2691 return G_TOKEN_STRING;
2693 if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
2694 (strcmp (scanner->value.v_string, "<none>") == 0))
2695 pixmap_file = g_strdup (scanner->value.v_string);
2697 pixmap_file = gtk_rc_find_pixmap_in_path (context->settings,
2698 scanner, scanner->value.v_string);
2702 if (rc_style->bg_pixmap_name[state])
2703 g_free (rc_style->bg_pixmap_name[state]);
2704 rc_style->bg_pixmap_name[state] = pixmap_file;
2707 return G_TOKEN_NONE;
2711 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
2716 buf = g_build_filename (dir, pixmap_file, NULL);
2718 fd = open (buf, O_RDONLY);
2731 * gtk_rc_find_pixmap_in_path:
2732 * @settings: a #GtkSettings
2733 * @scanner: Scanner used to get line number information for the
2734 * warning message, or %NULL
2735 * @pixmap_file: name of the pixmap file to locate.
2737 * Looks up a file in pixmap path for the specified #GtkSettings.
2738 * If the file is not found, it outputs a warning message using
2739 * g_warning() and returns %NULL.
2741 * Return value: the filename.
2744 gtk_rc_find_pixmap_in_path (GtkSettings *settings,
2746 const gchar *pixmap_file)
2752 GtkRcContext *context = gtk_rc_context_get (settings);
2754 for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (context->pixmap_path[i] != NULL); i++)
2756 filename = gtk_rc_check_pixmap_dir (context->pixmap_path[i], pixmap_file);
2761 tmp_list = rc_dir_stack;
2764 filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
2768 tmp_list = tmp_list->next;
2772 g_scanner_warn (scanner,
2773 _("Unable to locate image file in pixmap_path: \"%s\""),
2776 g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
2783 gtk_rc_find_module_in_path (const gchar *module_file)
2789 for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
2791 buf = g_build_filename (module_path[i], module_file, NULL);
2793 fd = open (buf, O_RDONLY);
2807 gtk_rc_parse_font (GScanner *scanner,
2808 GtkRcStyle *rc_style)
2812 token = g_scanner_get_next_token (scanner);
2813 if (token != GTK_RC_TOKEN_FONT)
2814 return GTK_RC_TOKEN_FONT;
2816 token = g_scanner_get_next_token (scanner);
2817 if (token != G_TOKEN_EQUAL_SIGN)
2818 return G_TOKEN_EQUAL_SIGN;
2820 token = g_scanner_get_next_token (scanner);
2821 if (token != G_TOKEN_STRING)
2822 return G_TOKEN_STRING;
2824 /* Ignore, do nothing */
2826 return G_TOKEN_NONE;
2830 gtk_rc_parse_fontset (GScanner *scanner,
2831 GtkRcStyle *rc_style)
2835 token = g_scanner_get_next_token (scanner);
2836 if (token != GTK_RC_TOKEN_FONTSET)
2837 return GTK_RC_TOKEN_FONTSET;
2839 token = g_scanner_get_next_token (scanner);
2840 if (token != G_TOKEN_EQUAL_SIGN)
2841 return G_TOKEN_EQUAL_SIGN;
2843 token = g_scanner_get_next_token (scanner);
2844 if (token != G_TOKEN_STRING)
2845 return G_TOKEN_STRING;
2847 /* Do nothing - silently ignore */
2849 return G_TOKEN_NONE;
2853 gtk_rc_parse_font_name (GScanner *scanner,
2854 GtkRcStyle *rc_style)
2858 token = g_scanner_get_next_token (scanner);
2859 if (token != GTK_RC_TOKEN_FONT_NAME)
2860 return GTK_RC_TOKEN_FONT;
2862 token = g_scanner_get_next_token (scanner);
2863 if (token != G_TOKEN_EQUAL_SIGN)
2864 return G_TOKEN_EQUAL_SIGN;
2866 token = g_scanner_get_next_token (scanner);
2867 if (token != G_TOKEN_STRING)
2868 return G_TOKEN_STRING;
2870 rc_style->font_desc = pango_font_description_from_string (scanner->value.v_string);
2872 return G_TOKEN_NONE;
2876 gtk_rc_parse_engine (GtkRcContext *context,
2878 GtkRcStyle **rc_style)
2881 GtkThemeEngine *engine;
2882 guint result = G_TOKEN_NONE;
2883 GtkRcStyle *new_style = NULL;
2884 gboolean parsed_curlies = FALSE;
2886 token = g_scanner_get_next_token (scanner);
2887 if (token != GTK_RC_TOKEN_ENGINE)
2888 return GTK_RC_TOKEN_ENGINE;
2890 token = g_scanner_get_next_token (scanner);
2891 if (token != G_TOKEN_STRING)
2892 return G_TOKEN_STRING;
2894 engine = gtk_theme_engine_get (scanner->value.v_string);
2896 token = g_scanner_get_next_token (scanner);
2897 if (token != G_TOKEN_LEFT_CURLY)
2898 return G_TOKEN_LEFT_CURLY;
2902 GtkRcStyleClass *new_class;
2904 new_style = gtk_theme_engine_create_rc_style (engine);
2905 g_type_module_unuse (G_TYPE_MODULE (engine));
2907 new_class = GTK_RC_STYLE_GET_CLASS (new_style);
2909 new_class->merge (new_style, *rc_style);
2910 if ((*rc_style)->name)
2911 new_style->name = g_strdup ((*rc_style)->name);
2913 if (new_class->parse)
2915 parsed_curlies = TRUE;
2916 result = new_class->parse (new_style, context->settings, scanner);
2918 if (result != G_TOKEN_NONE)
2920 g_object_unref (G_OBJECT (new_style));
2926 if (!parsed_curlies)
2928 /* Skip over remainder, looking for nested {}'s
2932 result = G_TOKEN_RIGHT_CURLY;
2933 while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
2935 if (token == G_TOKEN_LEFT_CURLY)
2937 else if (token == G_TOKEN_RIGHT_CURLY)
2942 result = G_TOKEN_NONE;
2950 g_object_unref (G_OBJECT (*rc_style));
2951 *rc_style = new_style;
2958 gtk_rc_parse_state (GScanner *scanner,
2959 GtkStateType *state)
2964 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2965 g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
2967 /* we don't know where we got called from, so we reset the scope here.
2968 * if we bail out due to errors, we *don't* reset the scope, so the
2969 * error messaging code can make sense of our tokens.
2971 old_scope = g_scanner_set_scope (scanner, 0);
2973 token = g_scanner_get_next_token (scanner);
2974 if (token != G_TOKEN_LEFT_BRACE)
2975 return G_TOKEN_LEFT_BRACE;
2977 token = g_scanner_get_next_token (scanner);
2980 case GTK_RC_TOKEN_ACTIVE:
2981 *state = GTK_STATE_ACTIVE;
2983 case GTK_RC_TOKEN_INSENSITIVE:
2984 *state = GTK_STATE_INSENSITIVE;
2986 case GTK_RC_TOKEN_NORMAL:
2987 *state = GTK_STATE_NORMAL;
2989 case GTK_RC_TOKEN_PRELIGHT:
2990 *state = GTK_STATE_PRELIGHT;
2992 case GTK_RC_TOKEN_SELECTED:
2993 *state = GTK_STATE_SELECTED;
2996 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
2999 token = g_scanner_get_next_token (scanner);
3000 if (token != G_TOKEN_RIGHT_BRACE)
3001 return G_TOKEN_RIGHT_BRACE;
3003 g_scanner_set_scope (scanner, old_scope);
3005 return G_TOKEN_NONE;
3009 gtk_rc_parse_priority (GScanner *scanner,
3010 GtkPathPriorityType *priority)
3015 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3016 g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
3018 /* we don't know where we got called from, so we reset the scope here.
3019 * if we bail out due to errors, we *don't* reset the scope, so the
3020 * error messaging code can make sense of our tokens.
3022 old_scope = g_scanner_set_scope (scanner, 0);
3024 token = g_scanner_get_next_token (scanner);
3028 token = g_scanner_get_next_token (scanner);
3031 case GTK_RC_TOKEN_LOWEST:
3032 *priority = GTK_PATH_PRIO_LOWEST;
3034 case GTK_RC_TOKEN_GTK:
3035 *priority = GTK_PATH_PRIO_GTK;
3037 case GTK_RC_TOKEN_APPLICATION:
3038 *priority = GTK_PATH_PRIO_APPLICATION;
3040 case GTK_RC_TOKEN_THEME:
3041 *priority = GTK_PATH_PRIO_THEME;
3043 case GTK_RC_TOKEN_RC:
3044 *priority = GTK_PATH_PRIO_RC;
3046 case GTK_RC_TOKEN_HIGHEST:
3047 *priority = GTK_PATH_PRIO_HIGHEST;
3050 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
3053 g_scanner_set_scope (scanner, old_scope);
3055 return G_TOKEN_NONE;
3059 gtk_rc_parse_color (GScanner *scanner,
3064 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3066 /* we don't need to set our own scope here, because
3067 * we don't need own symbols
3070 token = g_scanner_get_next_token (scanner);
3075 case G_TOKEN_LEFT_CURLY:
3076 token = g_scanner_get_next_token (scanner);
3077 if (token == G_TOKEN_INT)
3078 token_int = scanner->value.v_int;
3079 else if (token == G_TOKEN_FLOAT)
3080 token_int = scanner->value.v_float * 65535.0;
3082 return G_TOKEN_FLOAT;
3083 color->red = CLAMP (token_int, 0, 65535);
3085 token = g_scanner_get_next_token (scanner);
3086 if (token != G_TOKEN_COMMA)
3087 return G_TOKEN_COMMA;
3089 token = g_scanner_get_next_token (scanner);
3090 if (token == G_TOKEN_INT)
3091 token_int = scanner->value.v_int;
3092 else if (token == G_TOKEN_FLOAT)
3093 token_int = scanner->value.v_float * 65535.0;
3095 return G_TOKEN_FLOAT;
3096 color->green = CLAMP (token_int, 0, 65535);
3098 token = g_scanner_get_next_token (scanner);
3099 if (token != G_TOKEN_COMMA)
3100 return G_TOKEN_COMMA;
3102 token = g_scanner_get_next_token (scanner);
3103 if (token == G_TOKEN_INT)
3104 token_int = scanner->value.v_int;
3105 else if (token == G_TOKEN_FLOAT)
3106 token_int = scanner->value.v_float * 65535.0;
3108 return G_TOKEN_FLOAT;
3109 color->blue = CLAMP (token_int, 0, 65535);
3111 token = g_scanner_get_next_token (scanner);
3112 if (token != G_TOKEN_RIGHT_CURLY)
3113 return G_TOKEN_RIGHT_CURLY;
3114 return G_TOKEN_NONE;
3116 case G_TOKEN_STRING:
3117 if (!gdk_color_parse (scanner->value.v_string, color))
3119 g_scanner_warn (scanner, "Invalid color constant '%s'",
3120 scanner->value.v_string);
3121 return G_TOKEN_STRING;
3124 return G_TOKEN_NONE;
3127 return G_TOKEN_STRING;
3132 gtk_rc_parse_pixmap_path (GtkRcContext *context,
3137 token = g_scanner_get_next_token (scanner);
3138 if (token != GTK_RC_TOKEN_PIXMAP_PATH)
3139 return GTK_RC_TOKEN_PIXMAP_PATH;
3141 token = g_scanner_get_next_token (scanner);
3142 if (token != G_TOKEN_STRING)
3143 return G_TOKEN_STRING;
3145 gtk_rc_parse_pixmap_path_string (context, scanner, scanner->value.v_string);
3147 return G_TOKEN_NONE;
3151 gtk_rc_parse_pixmap_path_string (GtkRcContext *context,
3153 const gchar *pix_path)
3156 gint start_offset = 0;
3160 /* free the old one, or just add to the old one ? */
3161 for (path_num = 0; context->pixmap_path[path_num]; path_num++)
3163 g_free (context->pixmap_path[path_num]);
3164 context->pixmap_path[path_num] = NULL;
3169 path_len = strlen (pix_path);
3171 for (end_offset = 0; end_offset <= path_len; end_offset++)
3173 if ((pix_path[end_offset] == G_SEARCHPATH_SEPARATOR) ||
3174 (end_offset == path_len))
3176 gchar *path_element = g_strndup (pix_path + start_offset, end_offset - start_offset);
3177 if (g_path_is_absolute (path_element))
3179 context->pixmap_path[path_num] = path_element;
3181 context->pixmap_path[path_num] = NULL;
3185 g_warning (_("Pixmap path element: \"%s\" must be absolute, %s, line %d"),
3186 path_element, scanner->input_name, scanner->line);
3187 g_free (path_element);
3190 start_offset = end_offset + 1;
3196 gtk_rc_parse_module_path (GScanner *scanner)
3200 token = g_scanner_get_next_token (scanner);
3201 if (token != GTK_RC_TOKEN_MODULE_PATH)
3202 return GTK_RC_TOKEN_MODULE_PATH;
3204 token = g_scanner_get_next_token (scanner);
3205 if (token != G_TOKEN_STRING)
3206 return G_TOKEN_STRING;
3208 gtk_rc_parse_module_path_string (scanner->value.v_string);
3210 return G_TOKEN_NONE;
3214 gtk_rc_parse_im_module_path (GScanner *scanner)
3218 token = g_scanner_get_next_token (scanner);
3219 if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
3220 return GTK_RC_TOKEN_IM_MODULE_FILE;
3222 token = g_scanner_get_next_token (scanner);
3223 if (token != G_TOKEN_STRING)
3224 return G_TOKEN_STRING;
3227 g_free (im_module_path);
3229 im_module_path = g_strdup (scanner->value.v_string);
3231 return G_TOKEN_NONE;
3235 gtk_rc_parse_im_module_file (GScanner *scanner)
3239 token = g_scanner_get_next_token (scanner);
3240 if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
3241 return GTK_RC_TOKEN_IM_MODULE_FILE;
3243 token = g_scanner_get_next_token (scanner);
3244 if (token != G_TOKEN_STRING)
3245 return G_TOKEN_STRING;
3248 g_free (im_module_file);
3250 im_module_file = g_strdup (scanner->value.v_string);
3252 return G_TOKEN_NONE;
3256 gtk_rc_parse_module_path_string (const gchar *mod_path)
3259 gint start_offset = 0;
3263 /* free the old one, or just add to the old one ? */
3264 for (path_num=0; module_path[path_num]; path_num++)
3266 g_free (module_path[path_num]);
3267 module_path[path_num] = NULL;
3272 path_len = strlen (mod_path);
3274 for (end_offset = 0; end_offset <= path_len; end_offset++)
3276 if ((mod_path[end_offset] == G_SEARCHPATH_SEPARATOR) ||
3277 (end_offset == path_len))
3279 module_path[path_num] = g_strndup (mod_path + start_offset, end_offset - start_offset);
3281 module_path[path_num] = NULL;
3282 start_offset = end_offset + 1;
3285 gtk_rc_append_default_module_path();
3289 rc_set_compare (gconstpointer a, gconstpointer b)
3291 const GtkRcSet *set_a = a;
3292 const GtkRcSet *set_b = b;
3294 return (set_a->priority < set_b->priority) ? 1 : (set_a->priority == set_b->priority ? 0 : -1);
3298 insert_rc_set (GSList *list, GtkRcSet *set)
3300 return g_slist_insert_sorted (list, set, rc_set_compare);
3304 gtk_rc_parse_path_pattern (GtkRcContext *context,
3308 GtkPathType path_type;
3310 gboolean is_binding;
3311 GtkPathPriorityType priority = context->default_priority;
3313 token = g_scanner_get_next_token (scanner);
3316 case GTK_RC_TOKEN_WIDGET:
3317 path_type = GTK_PATH_WIDGET;
3319 case GTK_RC_TOKEN_WIDGET_CLASS:
3320 path_type = GTK_PATH_WIDGET_CLASS;
3322 case GTK_RC_TOKEN_CLASS:
3323 path_type = GTK_PATH_CLASS;
3326 return GTK_RC_TOKEN_WIDGET_CLASS;
3329 token = g_scanner_get_next_token (scanner);
3330 if (token != G_TOKEN_STRING)
3331 return G_TOKEN_STRING;
3333 pattern = g_strdup (scanner->value.v_string);
3335 token = g_scanner_get_next_token (scanner);
3336 if (token == GTK_RC_TOKEN_STYLE)
3338 else if (token == GTK_RC_TOKEN_BINDING)
3343 return GTK_RC_TOKEN_STYLE;
3346 if (g_scanner_peek_next_token (scanner) == ':')
3348 token = gtk_rc_parse_priority (scanner, &priority);
3349 if (token != G_TOKEN_NONE)
3356 token = g_scanner_get_next_token (scanner);
3357 if (token != G_TOKEN_STRING)
3360 return G_TOKEN_STRING;
3365 GtkBindingSet *binding;
3367 binding = gtk_binding_set_find (scanner->value.v_string);
3371 return G_TOKEN_STRING;
3373 gtk_binding_set_add_path (binding, path_type, pattern, priority);
3377 GtkRcStyle *rc_style;
3380 rc_style = gtk_rc_style_find (context, scanner->value.v_string);
3385 return G_TOKEN_STRING;
3388 rc_set = g_new (GtkRcSet, 1);
3389 rc_set->pspec = g_pattern_spec_new (pattern);
3390 rc_set->rc_style = rc_style;
3391 rc_set->priority = priority;
3393 if (path_type == GTK_PATH_WIDGET)
3394 context->rc_sets_widget = insert_rc_set (context->rc_sets_widget, rc_set);
3395 else if (path_type == GTK_PATH_WIDGET_CLASS)
3396 context->rc_sets_widget_class = insert_rc_set (context->rc_sets_widget_class, rc_set);
3398 context->rc_sets_class = insert_rc_set (context->rc_sets_class, rc_set);
3402 return G_TOKEN_NONE;
3406 gtk_rc_parse_stock_id (GScanner *scanner,
3411 token = g_scanner_get_next_token (scanner);
3412 if (token != G_TOKEN_LEFT_BRACE)
3413 return G_TOKEN_LEFT_BRACE;
3415 token = g_scanner_get_next_token (scanner);
3417 if (token != G_TOKEN_STRING)
3418 return G_TOKEN_STRING;
3420 *stock_id = g_strdup (scanner->value.v_string);
3422 token = g_scanner_get_next_token (scanner);
3423 if (token != G_TOKEN_RIGHT_BRACE)
3426 return G_TOKEN_RIGHT_BRACE;
3429 return G_TOKEN_NONE;
3433 gtk_rc_parse_icon_source (GtkRcContext *context,
3435 GtkIconSet *icon_set,
3436 gboolean *icon_set_valid)
3439 GtkIconSource *source;
3440 gchar *full_filename;
3442 token = g_scanner_get_next_token (scanner);
3443 if (token != G_TOKEN_LEFT_CURLY)
3444 return G_TOKEN_LEFT_CURLY;
3446 token = g_scanner_get_next_token (scanner);
3448 if (token != G_TOKEN_STRING)
3449 return G_TOKEN_STRING;
3452 source = gtk_icon_source_new ();
3454 full_filename = gtk_rc_find_pixmap_in_path (context->settings, scanner, scanner->value.v_string);
3457 gtk_icon_source_set_filename (source, full_filename);
3458 g_free (full_filename);
3461 /* We continue parsing even if we didn't find the pixmap so that rest of the
3462 * file is read, even if the syntax is bad. However we don't validate the
3463 * icon_set so the caller can choose not to install it.
3465 token = g_scanner_get_next_token (scanner);
3467 if (token == G_TOKEN_RIGHT_CURLY)
3469 else if (token != G_TOKEN_COMMA)
3471 gtk_icon_source_free (source);
3472 return G_TOKEN_COMMA;
3475 /* Get the direction */
3477 token = g_scanner_get_next_token (scanner);
3481 case GTK_RC_TOKEN_RTL:
3482 gtk_icon_source_set_direction_wildcarded (source, FALSE);
3483 gtk_icon_source_set_direction (source, GTK_TEXT_DIR_RTL);
3486 case GTK_RC_TOKEN_LTR:
3487 gtk_icon_source_set_direction_wildcarded (source, FALSE);
3488 gtk_icon_source_set_direction (source, GTK_TEXT_DIR_LTR);
3495 gtk_icon_source_free (source);
3496 return GTK_RC_TOKEN_RTL;
3500 token = g_scanner_get_next_token (scanner);
3502 if (token == G_TOKEN_RIGHT_CURLY)
3504 else if (token != G_TOKEN_COMMA)
3506 gtk_icon_source_free (source);
3507 return G_TOKEN_COMMA;
3512 token = g_scanner_get_next_token (scanner);
3516 case GTK_RC_TOKEN_NORMAL:
3517 gtk_icon_source_set_state_wildcarded (source, FALSE);
3518 gtk_icon_source_set_state (source, GTK_STATE_NORMAL);
3521 case GTK_RC_TOKEN_PRELIGHT:
3522 gtk_icon_source_set_state_wildcarded (source, FALSE);
3523 gtk_icon_source_set_state (source, GTK_STATE_PRELIGHT);
3527 case GTK_RC_TOKEN_INSENSITIVE:
3528 gtk_icon_source_set_state_wildcarded (source, FALSE);
3529 gtk_icon_source_set_state (source, GTK_STATE_INSENSITIVE);
3532 case GTK_RC_TOKEN_ACTIVE:
3533 gtk_icon_source_set_state_wildcarded (source, FALSE);
3534 gtk_icon_source_set_state (source, GTK_STATE_ACTIVE);
3537 case GTK_RC_TOKEN_SELECTED:
3538 gtk_icon_source_set_state_wildcarded (source, FALSE);
3539 gtk_icon_source_set_state (source, GTK_STATE_SELECTED);
3546 gtk_icon_source_free (source);
3547 return GTK_RC_TOKEN_PRELIGHT;
3551 token = g_scanner_get_next_token (scanner);
3553 if (token == G_TOKEN_RIGHT_CURLY)
3555 else if (token != G_TOKEN_COMMA)
3557 gtk_icon_source_free (source);
3558 return G_TOKEN_COMMA;
3563 token = g_scanner_get_next_token (scanner);
3569 if (token != G_TOKEN_STRING)
3571 gtk_icon_source_free (source);
3572 return G_TOKEN_STRING;
3575 size = gtk_icon_size_from_name (scanner->value.v_string);
3577 if (size != GTK_ICON_SIZE_INVALID)
3579 gtk_icon_source_set_size_wildcarded (source, FALSE);
3580 gtk_icon_source_set_size (source, size);
3584 /* Check the close brace */
3586 token = g_scanner_get_next_token (scanner);
3587 if (token != G_TOKEN_RIGHT_CURLY)
3589 gtk_icon_source_free (source);
3590 return G_TOKEN_RIGHT_CURLY;
3594 if (gtk_icon_source_get_filename (source))
3596 gtk_icon_set_add_source (icon_set, source);
3597 *icon_set_valid = TRUE;
3599 gtk_icon_source_free (source);
3601 return G_TOKEN_NONE;
3605 gtk_rc_parse_stock (GtkRcContext *context,
3607 GtkRcStyle *rc_style,
3608 GtkIconFactory *factory)
3610 GtkIconSet *icon_set = NULL;
3611 gboolean icon_set_valid = FALSE;
3612 gchar *stock_id = NULL;
3615 token = g_scanner_get_next_token (scanner);
3616 if (token != GTK_RC_TOKEN_STOCK)
3617 return GTK_RC_TOKEN_STOCK;
3619 token = gtk_rc_parse_stock_id (scanner, &stock_id);
3620 if (token != G_TOKEN_NONE)
3623 token = g_scanner_get_next_token (scanner);
3624 if (token != G_TOKEN_EQUAL_SIGN)
3627 return G_TOKEN_EQUAL_SIGN;
3630 token = g_scanner_get_next_token (scanner);
3631 if (token != G_TOKEN_LEFT_CURLY)
3634 return G_TOKEN_LEFT_CURLY;
3637 token = g_scanner_peek_next_token (scanner);
3638 while (token != G_TOKEN_RIGHT_CURLY)
3640 if (icon_set == NULL)
3641 icon_set = gtk_icon_set_new ();
3643 token = gtk_rc_parse_icon_source (context,
3644 scanner, icon_set, &icon_set_valid);
3645 if (token != G_TOKEN_NONE)
3648 gtk_icon_set_unref (icon_set);
3652 token = g_scanner_get_next_token (scanner);
3654 if (token != G_TOKEN_COMMA &&
3655 token != G_TOKEN_RIGHT_CURLY)
3658 gtk_icon_set_unref (icon_set);
3659 return G_TOKEN_RIGHT_CURLY;
3663 if (icon_set && icon_set_valid)
3665 gtk_icon_factory_add (factory,
3669 gtk_icon_set_unref (icon_set);
3674 return G_TOKEN_NONE;