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 */
299 gtk_rc_make_default_dir (const gchar *type)
303 var = getenv("GTK_EXE_PREFIX");
305 path = g_build_filename (var, "lib", "gtk-2.0", type, GTK_BINARY_VERSION, NULL);
307 path = g_build_filename (GTK_LIBDIR, "gtk-2.0,", type, GTK_BINARY_VERSION, NULL);
313 gtk_rc_get_im_module_path (void)
315 const gchar *result = g_getenv ("GTK_IM_MODULE_PATH");
320 result = im_module_path;
322 return gtk_rc_make_default_dir ("immodules");
325 return g_strdup (result);
329 gtk_rc_get_im_module_file (void)
331 gchar *result = g_strdup (g_getenv ("GTK_IM_MODULE_FILE"));
336 result = g_strdup (im_module_file);
338 result = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gtk.immodules", NULL);
345 gtk_rc_get_theme_dir(void)
349 var = getenv("GTK_DATA_PREFIX");
351 path = g_build_filename (var, "share", "themes", NULL);
353 path = g_build_filename (GTK_DATA_PREFIX, "share", "themes", NULL);
359 gtk_rc_get_module_dir(void)
361 return gtk_rc_make_default_dir ("engines");
365 gtk_rc_append_default_module_path(void)
371 for (n = 0; module_path[n]; n++) ;
372 if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
375 var = getenv("GTK_EXE_PREFIX");
377 path = g_build_filename (var, "lib", "gtk-2.0", GTK_VERSION, "engines", NULL);
379 path = g_build_filename (GTK_LIBDIR, "gtk-2.0", GTK_VERSION, "engines", NULL);
380 module_path[n++] = path;
382 var = g_get_home_dir ();
385 path = g_build_filename (var, ".gtk-2.0", GTK_VERSION, "engines", NULL);
386 module_path[n++] = path;
388 module_path[n] = NULL;
392 gtk_rc_add_initial_default_files (void)
394 static gint init = FALSE;
403 gtk_rc_default_files[0] = NULL;
406 var = g_getenv("GTK_RC_FILES");
409 files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
413 gtk_rc_add_default_file (files[i]);
420 str = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gtkrc", NULL);
422 gtk_rc_add_default_file (str);
425 var = g_get_home_dir ();
428 str = g_build_filename (var, ".gtkrc-2.0", NULL);
429 gtk_rc_add_default_file (str);
436 * gtk_rc_add_default_file:
437 * @filename: the pathname to the file.
439 * Adds a file to the list of files to be parsed at the
443 gtk_rc_add_default_file (const gchar *filename)
447 gtk_rc_add_initial_default_files ();
449 for (n = 0; gtk_rc_default_files[n]; n++) ;
450 if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
453 gtk_rc_default_files[n++] = g_strdup (filename);
454 gtk_rc_default_files[n] = NULL;
458 * gtk_rc_set_default_files:
459 * @filenames: A %NULL terminated list of filenames.
461 * Sets the list of files that GTK+ will read at the
465 gtk_rc_set_default_files (gchar **filenames)
469 gtk_rc_add_initial_default_files ();
472 while (gtk_rc_default_files[i])
474 g_free (gtk_rc_default_files[i]);
478 gtk_rc_default_files[0] = NULL;
481 while (filenames[i] != NULL)
483 gtk_rc_add_default_file (filenames[i]);
489 * gtk_rc_get_default_files:
491 * Retrieves the current list of RC files that will be parsed
492 * at the end of gtk_init()
494 * Return value: A NULL terminated array of filenames. This memory
495 * is owned by GTK+ and must not be freed by the application.
496 * If you want to store this information, you should make a
500 gtk_rc_get_default_files (void)
502 gtk_rc_add_initial_default_files ();
504 return gtk_rc_default_files;
507 /* The following routine is based on _nl_normalize_codeset from
508 * the GNU C library. Contributed by
510 * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
511 * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
513 * Normalize codeset name. There is no standard for the codeset
514 * names. Normalization allows the user to use any of the common
518 _gtk_normalize_codeset (const gchar *codeset, gint name_len)
526 for (cnt = 0; cnt < name_len; ++cnt)
527 if (isalnum (codeset[cnt]))
531 if (isalpha (codeset[cnt]))
535 retval = g_malloc ((only_digit ? 3 : 0) + len + 1);
539 memcpy (retval, "iso", 4);
545 for (cnt = 0; cnt < name_len; ++cnt)
546 if (isalpha (codeset[cnt]))
547 *wp++ = isupper(codeset[cnt]) ? tolower (codeset[cnt]) : codeset[cnt];
548 else if (isdigit (codeset[cnt]))
549 *wp++ = codeset[cnt];
557 gtk_rc_settings_changed (GtkSettings *settings,
559 GtkRcContext *context)
561 gchar *new_theme_name;
562 gchar *new_key_theme_name;
564 g_object_get (settings,
565 "gtk-theme-name", &new_theme_name,
566 "gtk-key-theme-name", &new_key_theme_name,
569 if ((new_theme_name != context->theme_name &&
570 !(new_theme_name && context->theme_name && strcmp (new_theme_name, context->theme_name) == 0)) ||
571 (new_key_theme_name != context->key_theme_name &&
572 !(new_key_theme_name && context->key_theme_name && strcmp (new_key_theme_name, context->key_theme_name) == 0)))
574 gtk_rc_reparse_all_for_settings (settings, TRUE);
577 g_free (new_theme_name);
578 g_free (new_key_theme_name);
581 static GtkRcContext *
582 gtk_rc_context_get (GtkSettings *settings)
584 if (!settings->rc_context)
586 GtkRcContext *context = settings->rc_context = g_new (GtkRcContext, 1);
588 context->settings = settings;
589 context->rc_style_ht = NULL;
590 context->rc_sets_widget = NULL;
591 context->rc_sets_widget_class = NULL;
592 context->rc_sets_class = NULL;
593 context->rc_files = NULL;
595 g_object_get (settings,
596 "gtk-theme-name", &context->theme_name,
597 "gtk-key-theme-name", &context->key_theme_name,
600 g_signal_connect (settings,
601 "notify::gtk-theme-name",
602 G_CALLBACK (gtk_rc_settings_changed),
604 g_signal_connect (settings,
605 "notify::gtk-key-theme-name",
606 G_CALLBACK (gtk_rc_settings_changed),
609 context->pixmap_path[0] = NULL;
611 context->default_priority = GTK_PATH_PRIO_RC;
614 return settings->rc_context;
618 gtk_rc_parse_named (GtkRcContext *context,
623 const gchar *home_dir;
627 subpath = g_strconcat ("gtk-2.0-", type,
628 G_DIR_SEPARATOR_S "gtkrc",
631 subpath = g_strdup ("gtk-2.0" G_DIR_SEPARATOR_S "gtkrc");
633 /* First look in the users home directory
635 home_dir = g_get_home_dir ();
638 path = g_build_filename (home_dir, ".themes", name, subpath, NULL);
639 if (!g_file_test (path, G_FILE_TEST_EXISTS))
648 gchar *theme_dir = gtk_rc_get_theme_dir ();
649 path = g_build_filename (theme_dir, name, subpath, NULL);
652 if (!g_file_test (path, G_FILE_TEST_EXISTS))
661 gtk_rc_parse_file (context, path, GTK_PATH_PRIO_THEME, FALSE);
669 gtk_rc_parse_default_files (GtkRcContext *context)
671 gchar *locale_suffixes[3];
672 gint n_locale_suffixes = 0;
679 locale = g_win32_getlocale ();
681 locale = setlocale (LC_CTYPE, NULL);
684 if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
686 /* Determine locale-specific suffixes for RC files
688 * We normalize the charset into a standard form,
689 * which has all '-' and '_' characters removed,
692 gchar *normalized_locale;
694 p = strchr (locale, '@');
695 length = p ? (p -locale) : strlen (locale);
697 p = strchr (locale, '.');
700 gchar *tmp1 = g_strndup (locale, p - locale + 1);
701 gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
703 normalized_locale = g_strconcat (tmp1, tmp2, NULL);
707 locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
711 normalized_locale = g_strndup (locale, length);
713 p = strchr (normalized_locale, '_');
716 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
717 length = p - normalized_locale;
720 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
722 g_free (normalized_locale);
725 for (i = 0; gtk_rc_default_files[i] != NULL; i++)
727 /* Try to find a locale specific RC file corresponding to the
728 * current locale to parse before the default file.
730 for (j = n_locale_suffixes - 1; j >= 0; j--)
732 gchar *name = g_strconcat (gtk_rc_default_files[i],
736 gtk_rc_parse_file (context, name, GTK_PATH_PRIO_RC, FALSE);
739 gtk_rc_parse_file (context, gtk_rc_default_files[i], GTK_PATH_PRIO_RC, FALSE);
742 for (j = 0; j < n_locale_suffixes; j++)
743 g_free (locale_suffixes[j]);
749 static gboolean initialized = FALSE;
755 module_path[0] = NULL;
756 gtk_rc_append_default_module_path();
758 gtk_rc_add_initial_default_files ();
761 gtk_rc_reparse_all_for_settings (gtk_settings_get_default (), TRUE);
765 gtk_rc_parse_string (const gchar *rc_string)
767 g_return_if_fail (rc_string != NULL);
769 gtk_rc_parse_any (gtk_rc_context_get (gtk_settings_get_default ()),
770 "-", -1, rc_string); /* FIXME */
774 gtk_rc_parse_file (GtkRcContext *context,
775 const gchar *filename,
779 GtkRcFile *rc_file = NULL;
784 g_return_if_fail (filename != NULL);
786 saved_priority = context->default_priority;
787 context->default_priority = priority;
789 tmp_list = context->rc_files;
792 rc_file = tmp_list->data;
793 if (!strcmp (rc_file->name, filename))
796 tmp_list = tmp_list->next;
801 rc_file = g_new (GtkRcFile, 1);
802 rc_file->name = g_strdup (filename);
803 rc_file->canonical_name = NULL;
805 rc_file->reload = reload;
807 context->rc_files = g_slist_append (context->rc_files, rc_file);
810 if (!rc_file->canonical_name)
812 /* Get the absolute pathname */
814 if (g_path_is_absolute (rc_file->name))
815 rc_file->canonical_name = rc_file->name;
820 cwd = g_get_current_dir ();
821 rc_file->canonical_name = g_build_filename (cwd, rc_file->name, NULL);
826 if (!lstat (rc_file->canonical_name, &statbuf))
831 rc_file->mtime = statbuf.st_mtime;
833 fd = open (rc_file->canonical_name, O_RDONLY);
837 /* Temporarily push directory name for this file on
838 * a stack of directory names while parsing it
841 g_slist_prepend (rc_dir_stack,
842 g_path_get_dirname (rc_file->canonical_name));
843 gtk_rc_parse_any (context, filename, fd, NULL);
845 tmp_list = rc_dir_stack;
846 rc_dir_stack = rc_dir_stack->next;
848 g_free (tmp_list->data);
849 g_slist_free_1 (tmp_list);
855 context->default_priority = saved_priority;
859 gtk_rc_parse (const gchar *filename)
861 g_return_if_fail (filename != NULL);
863 gtk_rc_parse_file (gtk_rc_context_get (gtk_settings_get_default ()),
864 filename, GTK_PATH_PRIO_RC, TRUE); /* FIXME */
867 /* Handling of RC styles */
870 gtk_rc_style_get_type (void)
872 static GType object_type = 0;
876 static const GTypeInfo object_info =
878 sizeof (GtkRcStyleClass),
879 (GBaseInitFunc) NULL,
880 (GBaseFinalizeFunc) NULL,
881 (GClassInitFunc) gtk_rc_style_class_init,
882 NULL, /* class_finalize */
883 NULL, /* class_data */
886 (GInstanceInitFunc) gtk_rc_style_init,
889 object_type = g_type_register_static (G_TYPE_OBJECT,
898 gtk_rc_style_init (GtkRcStyle *style)
903 style->font_desc = NULL;
905 for (i = 0; i < 5; i++)
907 static const GdkColor init_color = { 0, 0, 0, 0, };
909 style->bg_pixmap_name[i] = NULL;
910 style->color_flags[i] = 0;
911 style->fg[i] = init_color;
912 style->bg[i] = init_color;
913 style->text[i] = init_color;
914 style->base[i] = init_color;
916 style->xthickness = -1;
917 style->ythickness = -1;
918 style->rc_properties = NULL;
920 style->rc_style_lists = NULL;
921 style->icon_factories = NULL;
925 gtk_rc_style_class_init (GtkRcStyleClass *klass)
927 GObjectClass *object_class = G_OBJECT_CLASS (klass);
929 parent_class = g_type_class_peek_parent (klass);
931 object_class->finalize = gtk_rc_style_finalize;
934 klass->create_rc_style = gtk_rc_style_real_create_rc_style;
935 klass->merge = gtk_rc_style_real_merge;
936 klass->create_style = gtk_rc_style_real_create_style;
940 gtk_rc_style_finalize (GObject *object)
942 GSList *tmp_list1, *tmp_list2;
943 GtkRcStyle *rc_style;
946 rc_style = GTK_RC_STYLE (object);
949 g_free (rc_style->name);
950 if (rc_style->font_desc)
951 pango_font_description_free (rc_style->font_desc);
953 for (i = 0; i < 5; i++)
954 if (rc_style->bg_pixmap_name[i])
955 g_free (rc_style->bg_pixmap_name[i]);
957 /* Now remove all references to this rc_style from
960 tmp_list1 = rc_style->rc_style_lists;
963 GSList *rc_styles = tmp_list1->data;
964 GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
965 gtk_style_unref (style);
967 /* Remove the list of styles from the other rc_styles
970 tmp_list2 = rc_styles;
973 GtkRcStyle *other_style = tmp_list2->data;
975 if (other_style != rc_style)
976 other_style->rc_style_lists = g_slist_remove_all (other_style->rc_style_lists,
978 tmp_list2 = tmp_list2->next;
981 /* And from the hash table itself
983 g_hash_table_remove (realized_style_ht, rc_styles);
984 g_slist_free (rc_styles);
986 tmp_list1 = tmp_list1->next;
988 g_slist_free (rc_style->rc_style_lists);
990 if (rc_style->rc_properties)
994 for (i = 0; i < rc_style->rc_properties->len; i++)
996 GtkRcProperty *node = &g_array_index (rc_style->rc_properties, GtkRcProperty, i);
998 g_free (node->origin);
999 g_value_unset (&node->value);
1001 g_array_free (rc_style->rc_properties, TRUE);
1002 rc_style->rc_properties = NULL;
1005 tmp_list1 = rc_style->icon_factories;
1008 g_object_unref (G_OBJECT (tmp_list1->data));
1010 tmp_list1 = tmp_list1->next;
1012 g_slist_free (rc_style->icon_factories);
1014 G_OBJECT_CLASS (parent_class)->finalize (object);
1018 gtk_rc_style_new (void)
1022 style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
1028 * gtk_rc_style_copy:
1029 * @orig: the style to copy
1031 * Make a copy of the specified #GtkRcStyle. This function
1032 * will correctly copy an rc style that is a member of a class
1033 * derived from #GtkRcStyle.
1035 * Return value: the resulting #GtkRcStyle
1038 gtk_rc_style_copy (GtkRcStyle *orig)
1042 g_return_val_if_fail (GTK_IS_RC_STYLE (orig), NULL);
1044 style = GTK_RC_STYLE_GET_CLASS (orig)->create_rc_style (orig);
1045 GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
1051 gtk_rc_style_ref (GtkRcStyle *rc_style)
1053 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1055 g_object_ref (G_OBJECT (rc_style));
1059 gtk_rc_style_unref (GtkRcStyle *rc_style)
1061 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1063 g_object_unref (G_OBJECT (rc_style));
1067 gtk_rc_style_real_create_rc_style (GtkRcStyle *style)
1069 return GTK_RC_STYLE (g_object_new (G_OBJECT_TYPE (style), NULL));
1073 gtk_rc_properties_cmp (gconstpointer bsearch_node1,
1074 gconstpointer bsearch_node2)
1076 const GtkRcProperty *prop1 = bsearch_node1;
1077 const GtkRcProperty *prop2 = bsearch_node2;
1079 if (prop1->type_name == prop2->type_name)
1080 return prop1->property_name < prop2->property_name ? -1 : prop1->property_name == prop2->property_name ? 0 : 1;
1082 return prop1->type_name < prop2->type_name ? -1 : 1;
1086 insert_rc_property (GtkRcStyle *style,
1087 GtkRcProperty *property,
1091 GtkRcProperty *new_property = NULL;
1092 GtkRcProperty key = { 0, 0, NULL, { 0, }, };
1094 key.type_name = property->type_name;
1095 key.property_name = property->property_name;
1097 if (!style->rc_properties)
1098 style->rc_properties = g_array_new (FALSE, FALSE, sizeof (GtkRcProperty));
1101 while (i < style->rc_properties->len)
1103 gint cmp = gtk_rc_properties_cmp (&key, &g_array_index (style->rc_properties, GtkRcProperty, i));
1109 new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
1111 g_free (new_property->origin);
1112 g_value_unset (&new_property->value);
1114 *new_property = key;
1128 g_array_insert_val (style->rc_properties, i, key);
1129 new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
1132 new_property->origin = g_strdup (property->origin);
1133 g_value_init (&new_property->value, G_VALUE_TYPE (&property->value));
1134 g_value_copy (&property->value, &new_property->value);
1138 gtk_rc_style_real_merge (GtkRcStyle *dest,
1143 for (i = 0; i < 5; i++)
1145 if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
1146 dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
1148 if (!(dest->color_flags[i] & GTK_RC_FG) &&
1149 src->color_flags[i] & GTK_RC_FG)
1151 dest->fg[i] = src->fg[i];
1152 dest->color_flags[i] |= GTK_RC_FG;
1154 if (!(dest->color_flags[i] & GTK_RC_BG) &&
1155 src->color_flags[i] & GTK_RC_BG)
1157 dest->bg[i] = src->bg[i];
1158 dest->color_flags[i] |= GTK_RC_BG;
1160 if (!(dest->color_flags[i] & GTK_RC_TEXT) &&
1161 src->color_flags[i] & GTK_RC_TEXT)
1163 dest->text[i] = src->text[i];
1164 dest->color_flags[i] |= GTK_RC_TEXT;
1166 if (!(dest->color_flags[i] & GTK_RC_BASE) &&
1167 src->color_flags[i] & GTK_RC_BASE)
1169 dest->base[i] = src->base[i];
1170 dest->color_flags[i] |= GTK_RC_BASE;
1174 if (dest->xthickness < 0 && src->xthickness >= 0)
1175 dest->xthickness = src->xthickness;
1176 if (dest->ythickness < 0 && src->ythickness >= 0)
1177 dest->ythickness = src->ythickness;
1179 if (!dest->font_desc && src->font_desc)
1180 dest->font_desc = pango_font_description_copy (src->font_desc);
1182 if (src->rc_properties)
1186 for (i = 0; i < src->rc_properties->len; i++)
1187 insert_rc_property (dest,
1188 &g_array_index (src->rc_properties, GtkRcProperty, i),
1194 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
1196 return gtk_style_new ();
1200 gtk_rc_clear_hash_node (gpointer key,
1204 gtk_rc_style_unref (data);
1208 gtk_rc_free_rc_sets (GSList *slist)
1214 rc_set = slist->data;
1215 g_pattern_spec_free (rc_set->pspec);
1218 slist = slist->next;
1223 gtk_rc_clear_styles (GtkRcContext *context)
1225 /* Clear out all old rc_styles */
1227 if (context->rc_style_ht)
1229 g_hash_table_foreach (context->rc_style_ht, gtk_rc_clear_hash_node, NULL);
1230 g_hash_table_destroy (context->rc_style_ht);
1231 context->rc_style_ht = NULL;
1234 gtk_rc_free_rc_sets (context->rc_sets_widget);
1235 g_slist_free (context->rc_sets_widget);
1236 context->rc_sets_widget = NULL;
1238 gtk_rc_free_rc_sets (context->rc_sets_widget_class);
1239 g_slist_free (context->rc_sets_widget_class);
1240 context->rc_sets_widget_class = NULL;
1242 gtk_rc_free_rc_sets (context->rc_sets_class);
1243 g_slist_free (context->rc_sets_class);
1244 context->rc_sets_class = NULL;
1247 /* Reset all our widgets. Also, we have to invalidate cached icons in
1248 * icon sets so they get re-rendered.
1251 gtk_rc_reset_widgets (GtkRcContext *context)
1253 GList *list, *toplevels;
1255 _gtk_icon_set_invalidate_caches ();
1257 toplevels = gtk_window_list_toplevels ();
1258 g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1260 for (list = toplevels; list; list = list->next)
1262 gtk_widget_reset_rc_styles (list->data);
1263 gtk_widget_unref (list->data);
1265 g_list_free (toplevels);
1269 * gtk_rc_reparse_all_for_settings:
1270 * @settings: a #GtkSettings
1271 * @force_load: load whether or not anything changed
1273 * If the modification time on any previously read file
1274 * for the given GtkSettings has changed, discard all style information
1275 * and then reread all previously read RC files.
1277 * Return value: %TRUE if the files were reread.
1280 gtk_rc_reparse_all_for_settings (GtkSettings *settings,
1281 gboolean force_load)
1283 gboolean mtime_modified = FALSE;
1286 GtkRcContext *context;
1288 struct stat statbuf;
1290 g_return_val_if_fail (GTK_IS_SETTINGS (settings), FALSE);
1292 context = gtk_rc_context_get (settings);
1296 /* Check through and see if any of the RC's have had their
1297 * mtime modified. If so, reparse everything.
1299 tmp_list = context->rc_files;
1302 rc_file = tmp_list->data;
1304 if (!lstat (rc_file->name, &statbuf) &&
1305 (statbuf.st_mtime > rc_file->mtime))
1307 mtime_modified = TRUE;
1311 tmp_list = tmp_list->next;
1315 if (force_load || mtime_modified)
1319 gtk_rc_clear_styles (context);
1320 g_object_freeze_notify (G_OBJECT (context->settings));
1322 old_files = context->rc_files;
1323 context->rc_files = NULL;
1325 gtk_rc_parse_default_files (context);
1327 tmp_list = old_files;
1330 rc_file = tmp_list->data;
1331 if (rc_file->reload)
1332 gtk_rc_parse_file (context, rc_file->name, GTK_PATH_PRIO_RC, TRUE);
1334 if (rc_file->canonical_name != rc_file->name)
1335 g_free (rc_file->canonical_name);
1336 g_free (rc_file->name);
1339 tmp_list = tmp_list->next;
1342 g_slist_free (old_files);;
1344 g_free (context->theme_name);
1345 g_free (context->key_theme_name);
1346 g_object_get (context->settings,
1347 "gtk-theme-name", &context->theme_name,
1348 "gtk-key-theme-name", &context->key_theme_name,
1351 if (context->theme_name && context->theme_name[0])
1352 gtk_rc_parse_named (context, context->theme_name, NULL);
1353 if (context->key_theme_name && context->key_theme_name[0])
1354 gtk_rc_parse_named (context, context->key_theme_name, "key");
1356 g_object_thaw_notify (G_OBJECT (context->settings));
1358 gtk_rc_reset_widgets (context);
1361 return mtime_modified;
1365 * gtk_rc_reparse_all:
1367 * If the modification time on any previously read file for the
1368 * default #GtkSettings has changed, discard all style information
1369 * and then reread all previously read RC files.
1371 * Return value: %TRUE if the files were reread.
1374 gtk_rc_reparse_all (void)
1376 return gtk_rc_reparse_all_for_settings (gtk_settings_get_default (), FALSE);
1380 gtk_rc_styles_match (GSList *rc_styles,
1384 const gchar *path_reversed)
1391 rc_set = sets->data;
1394 if (g_pattern_match (rc_set->pspec, path_length, path, path_reversed))
1395 rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
1403 * @widget: a #GtkWidget
1405 * Finds all matching RC styles for a given widget,
1406 * composites them together, and then creates a
1407 * #GtkStyle representing the composite appearance.
1408 * (GTK+ actually keeps a cache of previously
1409 * created styles, so a new style may not be
1412 * Returns: the resulting style. No refcount is added
1413 * to the returned style, so if you want to save this
1414 * style around, you should add a reference yourself.
1417 gtk_rc_get_style (GtkWidget *widget)
1419 GtkRcStyle *widget_rc_style;
1420 GSList *rc_styles = NULL;
1421 GtkRcContext *context;
1423 static guint rc_style_key_id = 0;
1425 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1427 context = gtk_rc_context_get (gtk_widget_get_settings (widget));
1429 /* We allow the specification of a single rc style to be bound
1430 * tightly to a widget, for application modifications
1432 if (!rc_style_key_id)
1433 rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1435 widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
1438 if (widget_rc_style)
1439 rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
1441 if (context->rc_sets_widget)
1443 gchar *path, *path_reversed;
1446 gtk_widget_path (widget, &path_length, &path, &path_reversed);
1447 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, path, path_reversed);
1449 g_free (path_reversed);
1452 if (context->rc_sets_widget_class)
1454 gchar *path, *path_reversed;
1457 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1458 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, path, path_reversed);
1460 g_free (path_reversed);
1463 if (context->rc_sets_class)
1467 type = GTK_OBJECT_TYPE (widget);
1471 gchar *path_reversed;
1474 path = gtk_type_name (type);
1475 path_length = strlen (path);
1476 path_reversed = g_strdup (path);
1477 g_strreverse (path_reversed);
1479 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
1480 g_free (path_reversed);
1482 type = gtk_type_parent (type);
1487 return gtk_rc_init_style (rc_styles);
1493 * gtk_rc_get_style_by_paths:
1494 * @settings: a #GtkSettings object
1495 * @widget_path: the widget path to use when looking up the style, or %NULL
1496 * @class_path: the class path to use when looking up the style, or %NULL
1497 * @type: a type that will be used along with parent types of this type
1498 * when matching against class styles, or G_TYPE_NONE
1500 * Creates up a #GtkStyle from styles defined in a RC file by providing
1501 * the raw components used in matching. This function may be useful
1502 * when creating pseudo-widgets that should be themed like widgets but
1503 * don't actually have corresponding GTK+ widgets. An example of this
1504 * would be items inside a GNOME canvas widget.
1506 * The action of gtk_rc_get_style() is similar to:
1508 * gtk_widget_path (widget, NULL, &path, NULL);
1509 * gtk_widget_class_path (widget, NULL, &class_path, NULL);
1510 * gtk_rc_get_style_by_paths (gtk_widget_get_settings (widget), path, class_path,
1511 * G_OBJECT_TYPE (widget));
1513 * Return value: A style created by matching with the supplied paths,
1514 * or %NULL if nothign matching was specified and the default style should
1515 * be used. The returned value is owned by GTK+ as part of an internal cache,
1516 * so you must call g_object_ref() on the returned value if you want to
1517 * keep a reference to it.
1520 gtk_rc_get_style_by_paths (GtkSettings *settings,
1521 const char *widget_path,
1522 const char *class_path,
1525 /* We duplicate the code from above to avoid slowing down the above
1526 * by generating paths when we don't need them. I don't know if
1527 * this is really worth it.
1529 GSList *rc_styles = NULL;
1530 GtkRcContext *context;
1532 g_return_val_if_fail (GTK_IS_SETTINGS (settings), NULL);
1534 context = gtk_rc_context_get (settings);
1536 if (context->rc_sets_widget)
1538 gchar *path_reversed;
1541 path_length = strlen (widget_path);
1542 path_reversed = g_strdup (widget_path);
1543 g_strreverse (path_reversed);
1545 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, widget_path, path_reversed);
1546 g_free (path_reversed);
1549 if (context->rc_sets_widget_class)
1551 gchar *path_reversed;
1554 path_length = strlen (class_path);
1555 path_reversed = g_strdup (class_path);
1556 g_strreverse (path_reversed);
1558 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, class_path, path_reversed);
1559 g_free (path_reversed);
1562 if (type != G_TYPE_NONE && context->rc_sets_class)
1567 gchar *path_reversed;
1570 path = g_type_name (type);
1571 path_length = strlen (path);
1572 path_reversed = g_strdup (path);
1573 g_strreverse (path_reversed);
1575 rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
1576 g_free (path_reversed);
1578 type = g_type_parent (type);
1583 return gtk_rc_init_style (rc_styles);
1589 gtk_rc_add_rc_sets (GSList *slist,
1590 GtkRcStyle *rc_style,
1591 const gchar *pattern)
1593 GtkRcStyle *new_style;
1597 new_style = gtk_rc_style_new ();
1598 *new_style = *rc_style;
1599 new_style->name = g_strdup (rc_style->name);
1600 if (rc_style->font_desc)
1601 new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
1603 for (i = 0; i < 5; i++)
1604 new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1606 rc_set = g_new (GtkRcSet, 1);
1607 rc_set->pspec = g_pattern_spec_new (pattern);
1608 rc_set->rc_style = rc_style;
1610 return g_slist_prepend (slist, rc_set);
1614 gtk_rc_add_widget_name_style (GtkRcStyle *rc_style,
1615 const gchar *pattern)
1617 GtkRcContext *context;
1619 g_return_if_fail (rc_style != NULL);
1620 g_return_if_fail (pattern != NULL);
1622 context = gtk_rc_context_get (gtk_settings_get_default ());
1624 context->rc_sets_widget = gtk_rc_add_rc_sets (context->rc_sets_widget, rc_style, pattern);
1628 gtk_rc_add_widget_class_style (GtkRcStyle *rc_style,
1629 const gchar *pattern)
1631 GtkRcContext *context;
1633 g_return_if_fail (rc_style != NULL);
1634 g_return_if_fail (pattern != NULL);
1636 context = gtk_rc_context_get (gtk_settings_get_default ());
1638 context->rc_sets_widget_class = gtk_rc_add_rc_sets (context->rc_sets_widget_class, rc_style, pattern);
1642 gtk_rc_add_class_style (GtkRcStyle *rc_style,
1643 const gchar *pattern)
1645 GtkRcContext *context;
1647 g_return_if_fail (rc_style != NULL);
1648 g_return_if_fail (pattern != NULL);
1650 context = gtk_rc_context_get (gtk_settings_get_default ());
1652 context->rc_sets_class = gtk_rc_add_rc_sets (context->rc_sets_class, rc_style, pattern);
1656 gtk_rc_scanner_new (void)
1658 return g_scanner_new (>k_rc_scanner_config);
1662 gtk_rc_parse_any (GtkRcContext *context,
1663 const gchar *input_name,
1665 const gchar *input_string)
1671 scanner = gtk_rc_scanner_new ();
1675 g_assert (input_string == NULL);
1677 g_scanner_input_file (scanner, input_fd);
1681 g_assert (input_string != NULL);
1683 g_scanner_input_text (scanner, input_string, strlen (input_string));
1685 scanner->input_name = input_name;
1687 for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1688 g_scanner_scope_add_symbol (scanner, 0, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1693 if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1697 guint expected_token;
1699 expected_token = gtk_rc_parse_statement (context, scanner);
1701 if (expected_token != G_TOKEN_NONE)
1708 if (scanner->scope_id == 0)
1710 /* if we are in scope 0, we know the symbol names
1711 * that are associated with certaintoken values.
1712 * so we look them up to make the error messages
1715 if (expected_token > GTK_RC_TOKEN_INVALID &&
1716 expected_token < GTK_RC_TOKEN_LAST)
1718 for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1719 if (symbols[i].token == expected_token)
1720 msg = symbols[i].name;
1722 msg = g_strconcat ("e.g. `", msg, "'", NULL);
1724 if (scanner->token > GTK_RC_TOKEN_INVALID &&
1725 scanner->token < GTK_RC_TOKEN_LAST)
1727 symbol_name = "???";
1728 for (i = 0; i < G_N_ELEMENTS (symbols); i++)
1729 if (symbols[i].token == scanner->token)
1730 symbol_name = symbols[i].name;
1733 g_scanner_unexp_token (scanner,
1746 g_scanner_destroy (scanner);
1750 gtk_rc_styles_hash (const GSList *rc_styles)
1757 result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1758 rc_styles = rc_styles->next;
1765 gtk_rc_styles_equal (const GSList *a,
1770 if (a->data != b->data)
1780 gtk_rc_style_hash (const gchar *name)
1786 result += (result << 3) + *name++;
1792 gtk_rc_style_equal (const gchar *a,
1795 return (strcmp (a, b) == 0);
1799 gtk_rc_style_find (GtkRcContext *context,
1802 if (context->rc_style_ht)
1803 return g_hash_table_lookup (context->rc_style_ht, (gpointer) name);
1809 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1813 style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
1815 style->rc_style = rc_style;
1817 gtk_rc_style_ref (rc_style);
1819 GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);
1824 /* Reuses or frees rc_styles */
1826 gtk_rc_init_style (GSList *rc_styles)
1828 GtkStyle *style = NULL;
1831 g_return_val_if_fail (rc_styles != NULL, NULL);
1833 if (!realized_style_ht)
1834 realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
1835 (GEqualFunc) gtk_rc_styles_equal);
1837 style = g_hash_table_lookup (realized_style_ht, rc_styles);
1841 GtkRcStyle *base_style = NULL;
1842 GtkRcStyle *proto_style;
1843 GtkRcStyleClass *proto_style_class;
1845 GType rc_style_type = GTK_TYPE_RC_STYLE;
1847 /* Find the first derived style in the list, and use that to
1848 * create the merged style. If we only have raw GtkRcStyles, use
1849 * the first style to create the merged style.
1851 base_style = rc_styles->data;
1852 tmp_styles = rc_styles;
1855 GtkRcStyle *rc_style = tmp_styles->data;
1857 if (G_OBJECT_TYPE (rc_style) != rc_style_type)
1859 base_style = rc_style;
1863 tmp_styles = tmp_styles->next;
1866 proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
1867 proto_style = proto_style_class->create_rc_style (base_style);
1869 tmp_styles = rc_styles;
1872 GtkRcStyle *rc_style = tmp_styles->data;
1875 proto_style_class->merge (proto_style, rc_style);
1877 /* Point from each rc_style to the list of styles */
1878 if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
1879 rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
1881 factories = g_slist_copy (rc_style->icon_factories);
1887 while (iter != NULL)
1889 g_object_ref (G_OBJECT (iter->data));
1890 iter = g_slist_next (iter);
1893 proto_style->icon_factories = g_slist_concat (proto_style->icon_factories,
1898 tmp_styles = tmp_styles->next;
1901 for (i = 0; i < 5; i++)
1902 if (proto_style->bg_pixmap_name[i] &&
1903 (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1905 g_free (proto_style->bg_pixmap_name[i]);
1906 proto_style->bg_pixmap_name[i] = NULL;
1909 style = gtk_rc_style_to_style (proto_style);
1910 gtk_rc_style_unref (proto_style);
1912 g_hash_table_insert (realized_style_ht, rc_styles, style);
1915 g_slist_free (rc_styles);
1920 /*********************
1921 * Parsing functions *
1922 *********************/
1925 rc_parse_token_or_compound (GScanner *scanner,
1927 GTokenType delimiter)
1929 guint token = g_scanner_get_next_token (scanner);
1931 /* we either scan a single token (skipping comments)
1932 * or a compund statement.
1933 * compunds are enclosed in (), [] or {} braces, we read
1934 * them in via deep recursion.
1941 g_string_append_printf (gstring, " 0x%lx", scanner->value.v_int);
1944 g_string_append_printf (gstring, " %f", scanner->value.v_float);
1946 case G_TOKEN_STRING:
1947 string = g_strescape (scanner->value.v_string, NULL);
1948 g_string_append (gstring, " \"");
1949 g_string_append (gstring, string);
1950 g_string_append_c (gstring, '"');
1953 case G_TOKEN_IDENTIFIER:
1954 g_string_append_c (gstring, ' ');
1955 g_string_append (gstring, scanner->value.v_identifier);
1957 case G_TOKEN_COMMENT_SINGLE:
1958 case G_TOKEN_COMMENT_MULTI:
1959 return rc_parse_token_or_compound (scanner, gstring, delimiter);
1960 case G_TOKEN_LEFT_PAREN:
1961 g_string_append_c (gstring, ' ');
1962 g_string_append_c (gstring, token);
1963 token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_PAREN);
1964 if (token != G_TOKEN_NONE)
1967 case G_TOKEN_LEFT_CURLY:
1968 g_string_append_c (gstring, ' ');
1969 g_string_append_c (gstring, token);
1970 token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_CURLY);
1971 if (token != G_TOKEN_NONE)
1974 case G_TOKEN_LEFT_BRACE:
1975 g_string_append_c (gstring, ' ');
1976 g_string_append_c (gstring, token);
1977 token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_BRACE);
1978 if (token != G_TOKEN_NONE)
1982 if (token >= 256 || token < 1)
1983 return delimiter ? delimiter : G_TOKEN_STRING;
1984 g_string_append_c (gstring, ' ');
1985 g_string_append_c (gstring, token);
1986 if (token == delimiter)
1987 return G_TOKEN_NONE;
1991 return G_TOKEN_NONE;
1993 return rc_parse_token_or_compound (scanner, gstring, delimiter);
1997 gtk_rc_parse_assignment (GScanner *scanner,
1998 GtkRcProperty *prop)
2000 gboolean scan_identifier = scanner->config->scan_identifier;
2001 gboolean scan_symbols = scanner->config->scan_symbols;
2002 gboolean identifier_2_string = scanner->config->identifier_2_string;
2003 gboolean char_2_token = scanner->config->char_2_token;
2004 gboolean scan_identifier_NULL = scanner->config->scan_identifier_NULL;
2005 gboolean numbers_2_int = scanner->config->numbers_2_int;
2006 gboolean negate = FALSE;
2009 /* check that this is an assignment */
2010 if (g_scanner_get_next_token (scanner) != '=')
2013 /* adjust scanner mode */
2014 scanner->config->scan_identifier = TRUE;
2015 scanner->config->scan_symbols = FALSE;
2016 scanner->config->identifier_2_string = FALSE;
2017 scanner->config->char_2_token = TRUE;
2018 scanner->config->scan_identifier_NULL = FALSE;
2019 scanner->config->numbers_2_int = TRUE;
2021 /* record location */
2022 prop->origin = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
2024 /* parse optional sign */
2025 if (g_scanner_peek_next_token (scanner) == '-')
2027 g_scanner_get_next_token (scanner); /* eat sign */
2031 /* parse one of LONG, DOUBLE and STRING or, if that fails, create an unparsed compund */
2032 token = g_scanner_peek_next_token (scanner);
2036 g_scanner_get_next_token (scanner);
2037 g_value_init (&prop->value, G_TYPE_LONG);
2038 g_value_set_long (&prop->value, negate ? -scanner->value.v_int : scanner->value.v_int);
2039 token = G_TOKEN_NONE;
2042 g_scanner_get_next_token (scanner);
2043 g_value_init (&prop->value, G_TYPE_DOUBLE);
2044 g_value_set_double (&prop->value, negate ? -scanner->value.v_float : scanner->value.v_float);
2045 token = G_TOKEN_NONE;
2047 case G_TOKEN_STRING:
2048 g_scanner_get_next_token (scanner);
2050 token = G_TOKEN_INT;
2053 g_value_init (&prop->value, G_TYPE_STRING);
2054 g_value_set_string (&prop->value, scanner->value.v_string);
2055 token = G_TOKEN_NONE;
2058 case G_TOKEN_IDENTIFIER:
2059 case G_TOKEN_LEFT_PAREN:
2060 case G_TOKEN_LEFT_CURLY:
2061 case G_TOKEN_LEFT_BRACE:
2064 GString *gstring = g_string_new ("");
2066 token = rc_parse_token_or_compound (scanner, gstring, 0);
2067 if (token == G_TOKEN_NONE)
2069 g_string_append_c (gstring, ' ');
2070 g_value_init (&prop->value, G_TYPE_GSTRING);
2071 g_value_set_static_boxed (&prop->value, gstring);
2074 g_string_free (gstring, TRUE);
2079 g_scanner_get_next_token (scanner);
2080 token = G_TOKEN_INT;
2084 /* restore scanner mode */
2085 scanner->config->scan_identifier = scan_identifier;
2086 scanner->config->scan_symbols = scan_symbols;
2087 scanner->config->identifier_2_string = identifier_2_string;
2088 scanner->config->char_2_token = char_2_token;
2089 scanner->config->scan_identifier_NULL = scan_identifier_NULL;
2090 scanner->config->numbers_2_int = numbers_2_int;
2096 is_c_identifier (const gchar *string)
2099 gboolean is_varname;
2101 is_varname = strchr (G_CSET_a_2_z G_CSET_A_2_Z "_", string[0]) != NULL;
2102 for (p = string + 1; *p && is_varname; p++)
2103 is_varname &= strchr (G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "_-", *p) != NULL;
2109 gtk_rc_parse_statement (GtkRcContext *context,
2114 token = g_scanner_peek_next_token (scanner);
2117 case GTK_RC_TOKEN_INCLUDE:
2118 token = g_scanner_get_next_token (scanner);
2119 if (token != GTK_RC_TOKEN_INCLUDE)
2120 return GTK_RC_TOKEN_INCLUDE;
2121 token = g_scanner_get_next_token (scanner);
2122 if (token != G_TOKEN_STRING)
2123 return G_TOKEN_STRING;
2124 gtk_rc_parse_file (context, scanner->value.v_string, context->default_priority, FALSE);
2125 return G_TOKEN_NONE;
2127 case GTK_RC_TOKEN_STYLE:
2128 return gtk_rc_parse_style (context, scanner);
2130 case GTK_RC_TOKEN_BINDING:
2131 return gtk_binding_parse_binding (scanner);
2133 case GTK_RC_TOKEN_PIXMAP_PATH:
2134 return gtk_rc_parse_pixmap_path (context, scanner);
2136 case GTK_RC_TOKEN_WIDGET:
2137 return gtk_rc_parse_path_pattern (context, scanner);
2139 case GTK_RC_TOKEN_WIDGET_CLASS:
2140 return gtk_rc_parse_path_pattern (context, scanner);
2142 case GTK_RC_TOKEN_CLASS:
2143 return gtk_rc_parse_path_pattern (context, scanner);
2145 case GTK_RC_TOKEN_MODULE_PATH:
2146 return gtk_rc_parse_module_path (scanner);
2148 case GTK_RC_TOKEN_IM_MODULE_PATH:
2149 return gtk_rc_parse_im_module_path (scanner);
2151 case GTK_RC_TOKEN_IM_MODULE_FILE:
2152 return gtk_rc_parse_im_module_file (scanner);
2154 case G_TOKEN_IDENTIFIER:
2155 if (is_c_identifier (scanner->next_value.v_identifier))
2157 GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2160 g_scanner_get_next_token (scanner); /* eat identifier */
2161 name = g_strdup (scanner->value.v_identifier);
2163 token = gtk_rc_parse_assignment (scanner, &prop);
2164 if (token == G_TOKEN_NONE)
2166 GtkSettingsValue svalue;
2168 svalue.origin = prop.origin;
2169 memcpy (&svalue.value, &prop.value, sizeof (prop.value));
2170 g_strcanon (name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
2171 gtk_settings_set_property_value (context->settings,
2175 g_free (prop.origin);
2176 if (G_VALUE_TYPE (&prop.value))
2177 g_value_unset (&prop.value);
2184 g_scanner_get_next_token (scanner);
2185 return G_TOKEN_IDENTIFIER;
2188 g_scanner_get_next_token (scanner);
2189 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
2194 gtk_rc_parse_style (GtkRcContext *context,
2197 GtkRcStyle *rc_style;
2198 GtkRcStyle *parent_style;
2202 GtkIconFactory *our_factory = NULL;
2204 token = g_scanner_get_next_token (scanner);
2205 if (token != GTK_RC_TOKEN_STYLE)
2206 return GTK_RC_TOKEN_STYLE;
2208 token = g_scanner_get_next_token (scanner);
2209 if (token != G_TOKEN_STRING)
2210 return G_TOKEN_STRING;
2213 rc_style = gtk_rc_style_find (context, scanner->value.v_string);
2215 /* If there's a list, its first member is always the factory belonging
2218 if (rc_style && rc_style->icon_factories)
2219 our_factory = rc_style->icon_factories->data;
2224 rc_style = gtk_rc_style_new ();
2225 rc_style->name = g_strdup (scanner->value.v_string);
2227 for (i = 0; i < 5; i++)
2228 rc_style->bg_pixmap_name[i] = NULL;
2230 for (i = 0; i < 5; i++)
2231 rc_style->color_flags[i] = 0;
2234 token = g_scanner_peek_next_token (scanner);
2235 if (token == G_TOKEN_EQUAL_SIGN)
2237 token = g_scanner_get_next_token (scanner);
2239 token = g_scanner_get_next_token (scanner);
2240 if (token != G_TOKEN_STRING)
2245 return G_TOKEN_STRING;
2248 parent_style = gtk_rc_style_find (context, scanner->value.v_string);
2253 for (i = 0; i < 5; i++)
2255 rc_style->color_flags[i] = parent_style->color_flags[i];
2256 rc_style->fg[i] = parent_style->fg[i];
2257 rc_style->bg[i] = parent_style->bg[i];
2258 rc_style->text[i] = parent_style->text[i];
2259 rc_style->base[i] = parent_style->base[i];
2262 rc_style->xthickness = parent_style->xthickness;
2263 rc_style->ythickness = parent_style->ythickness;
2265 if (parent_style->font_desc)
2267 if (rc_style->font_desc)
2268 pango_font_description_free (rc_style->font_desc);
2269 rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
2272 if (parent_style->rc_properties)
2276 for (i = 0; i < parent_style->rc_properties->len; i++)
2277 insert_rc_property (rc_style,
2278 &g_array_index (parent_style->rc_properties, GtkRcProperty, i),
2282 for (i = 0; i < 5; i++)
2284 if (rc_style->bg_pixmap_name[i])
2285 g_free (rc_style->bg_pixmap_name[i]);
2286 rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
2289 /* Append parent's factories, adding a ref to them */
2290 if (parent_style->icon_factories != NULL)
2292 /* Add a factory for ourselves if we have none,
2293 * in case we end up defining more stock icons.
2294 * I see no real way around this; we need to maintain
2295 * the invariant that the first factory in the list
2296 * is always our_factory, the one belonging to us,
2297 * and if we put parent factories in the list we can't
2298 * do that if the style is reopened.
2300 if (our_factory == NULL)
2302 our_factory = gtk_icon_factory_new ();
2303 rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
2307 rc_style->icon_factories = g_slist_concat (rc_style->icon_factories,
2308 g_slist_copy (parent_style->icon_factories));
2310 factories = parent_style->icon_factories;
2311 while (factories != NULL)
2313 g_object_ref (G_OBJECT (factories->data));
2314 factories = factories->next;
2320 token = g_scanner_get_next_token (scanner);
2321 if (token != G_TOKEN_LEFT_CURLY)
2326 return G_TOKEN_LEFT_CURLY;
2329 token = g_scanner_peek_next_token (scanner);
2330 while (token != G_TOKEN_RIGHT_CURLY)
2334 case GTK_RC_TOKEN_BG:
2335 token = gtk_rc_parse_bg (scanner, rc_style);
2337 case GTK_RC_TOKEN_FG:
2338 token = gtk_rc_parse_fg (scanner, rc_style);
2340 case GTK_RC_TOKEN_TEXT:
2341 token = gtk_rc_parse_text (scanner, rc_style);
2343 case GTK_RC_TOKEN_BASE:
2344 token = gtk_rc_parse_base (scanner, rc_style);
2346 case GTK_RC_TOKEN_XTHICKNESS:
2347 token = gtk_rc_parse_xthickness (scanner, rc_style);
2349 case GTK_RC_TOKEN_YTHICKNESS:
2350 token = gtk_rc_parse_ythickness (scanner, rc_style);
2352 case GTK_RC_TOKEN_BG_PIXMAP:
2353 token = gtk_rc_parse_bg_pixmap (context, scanner, rc_style);
2355 case GTK_RC_TOKEN_FONT:
2356 token = gtk_rc_parse_font (scanner, rc_style);
2358 case GTK_RC_TOKEN_FONTSET:
2359 token = gtk_rc_parse_fontset (scanner, rc_style);
2361 case GTK_RC_TOKEN_FONT_NAME:
2362 token = gtk_rc_parse_font_name (scanner, rc_style);
2364 case GTK_RC_TOKEN_ENGINE:
2365 token = gtk_rc_parse_engine (context, scanner, &rc_style);
2367 case GTK_RC_TOKEN_STOCK:
2368 if (our_factory == NULL)
2370 our_factory = gtk_icon_factory_new ();
2371 rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
2374 token = gtk_rc_parse_stock (context, scanner, rc_style, our_factory);
2376 case G_TOKEN_IDENTIFIER:
2377 if (is_c_identifier (scanner->next_value.v_identifier) &&
2378 scanner->next_value.v_identifier[0] >= 'A' &&
2379 scanner->next_value.v_identifier[0] <= 'Z') /* match namespaced type names */
2381 GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2383 g_scanner_get_next_token (scanner); /* eat type name */
2384 prop.type_name = g_quark_from_string (scanner->value.v_identifier);
2385 if (g_scanner_get_next_token (scanner) != ':' ||
2386 g_scanner_get_next_token (scanner) != ':')
2391 if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER ||
2392 !is_c_identifier (scanner->value.v_identifier))
2394 token = G_TOKEN_IDENTIFIER;
2398 /* it's important that we do the same canonification as GParamSpecPool here */
2399 g_strcanon (scanner->value.v_identifier, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
2400 prop.property_name = g_quark_from_string (scanner->value.v_identifier);
2402 token = gtk_rc_parse_assignment (scanner, &prop);
2403 if (token == G_TOKEN_NONE)
2405 g_return_val_if_fail (prop.origin != NULL && G_VALUE_TYPE (&prop.value) != 0, G_TOKEN_ERROR);
2406 insert_rc_property (rc_style, &prop, TRUE);
2409 g_free (prop.origin);
2410 if (G_VALUE_TYPE (&prop.value))
2411 g_value_unset (&prop.value);
2415 g_scanner_get_next_token (scanner);
2416 token = G_TOKEN_IDENTIFIER;
2420 g_scanner_get_next_token (scanner);
2421 token = G_TOKEN_RIGHT_CURLY;
2425 if (token != G_TOKEN_NONE)
2428 gtk_rc_style_unref (rc_style);
2432 token = g_scanner_peek_next_token (scanner);
2433 } /* while (token != G_TOKEN_RIGHT_CURLY) */
2435 token = g_scanner_get_next_token (scanner);
2436 if (token != G_TOKEN_RIGHT_CURLY)
2440 if (rc_style->font_desc)
2441 pango_font_description_free (rc_style->font_desc);
2443 for (i = 0; i < 5; i++)
2444 if (rc_style->bg_pixmap_name[i])
2445 g_free (rc_style->bg_pixmap_name[i]);
2449 return G_TOKEN_RIGHT_CURLY;
2454 if (!context->rc_style_ht)
2455 context->rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
2456 (GEqualFunc) gtk_rc_style_equal);
2458 g_hash_table_insert (context->rc_style_ht, rc_style->name, rc_style);
2461 return G_TOKEN_NONE;
2464 const GtkRcProperty*
2465 _gtk_rc_style_lookup_rc_property (GtkRcStyle *rc_style,
2467 GQuark property_name)
2469 GtkRcProperty *node = NULL;
2471 g_return_val_if_fail (GTK_IS_RC_STYLE (rc_style), NULL);
2473 if (rc_style->rc_properties)
2477 key.type_name = type_name;
2478 key.property_name = property_name;
2480 node = bsearch (&key,
2481 rc_style->rc_properties->data, rc_style->rc_properties->len,
2482 sizeof (GtkRcProperty), gtk_rc_properties_cmp);
2489 gtk_rc_parse_bg (GScanner *scanner,
2495 token = g_scanner_get_next_token (scanner);
2496 if (token != GTK_RC_TOKEN_BG)
2497 return GTK_RC_TOKEN_BG;
2499 token = gtk_rc_parse_state (scanner, &state);
2500 if (token != G_TOKEN_NONE)
2503 token = g_scanner_get_next_token (scanner);
2504 if (token != G_TOKEN_EQUAL_SIGN)
2505 return G_TOKEN_EQUAL_SIGN;
2507 style->color_flags[state] |= GTK_RC_BG;
2508 return gtk_rc_parse_color (scanner, &style->bg[state]);
2512 gtk_rc_parse_fg (GScanner *scanner,
2518 token = g_scanner_get_next_token (scanner);
2519 if (token != GTK_RC_TOKEN_FG)
2520 return GTK_RC_TOKEN_FG;
2522 token = gtk_rc_parse_state (scanner, &state);
2523 if (token != G_TOKEN_NONE)
2526 token = g_scanner_get_next_token (scanner);
2527 if (token != G_TOKEN_EQUAL_SIGN)
2528 return G_TOKEN_EQUAL_SIGN;
2530 style->color_flags[state] |= GTK_RC_FG;
2531 return gtk_rc_parse_color (scanner, &style->fg[state]);
2535 gtk_rc_parse_text (GScanner *scanner,
2541 token = g_scanner_get_next_token (scanner);
2542 if (token != GTK_RC_TOKEN_TEXT)
2543 return GTK_RC_TOKEN_TEXT;
2545 token = gtk_rc_parse_state (scanner, &state);
2546 if (token != G_TOKEN_NONE)
2549 token = g_scanner_get_next_token (scanner);
2550 if (token != G_TOKEN_EQUAL_SIGN)
2551 return G_TOKEN_EQUAL_SIGN;
2553 style->color_flags[state] |= GTK_RC_TEXT;
2554 return gtk_rc_parse_color (scanner, &style->text[state]);
2558 gtk_rc_parse_base (GScanner *scanner,
2564 token = g_scanner_get_next_token (scanner);
2565 if (token != GTK_RC_TOKEN_BASE)
2566 return GTK_RC_TOKEN_BASE;
2568 token = gtk_rc_parse_state (scanner, &state);
2569 if (token != G_TOKEN_NONE)
2572 token = g_scanner_get_next_token (scanner);
2573 if (token != G_TOKEN_EQUAL_SIGN)
2574 return G_TOKEN_EQUAL_SIGN;
2576 style->color_flags[state] |= GTK_RC_BASE;
2577 return gtk_rc_parse_color (scanner, &style->base[state]);
2581 gtk_rc_parse_xthickness (GScanner *scanner,
2584 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
2585 return GTK_RC_TOKEN_XTHICKNESS;
2587 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2588 return G_TOKEN_EQUAL_SIGN;
2590 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2593 style->xthickness = scanner->value.v_int;
2595 return G_TOKEN_NONE;
2599 gtk_rc_parse_ythickness (GScanner *scanner,
2602 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
2603 return GTK_RC_TOKEN_YTHICKNESS;
2605 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2606 return G_TOKEN_EQUAL_SIGN;
2608 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2611 style->ythickness = scanner->value.v_int;
2613 return G_TOKEN_NONE;
2617 gtk_rc_parse_bg_pixmap (GtkRcContext *context,
2619 GtkRcStyle *rc_style)
2625 token = g_scanner_get_next_token (scanner);
2626 if (token != GTK_RC_TOKEN_BG_PIXMAP)
2627 return GTK_RC_TOKEN_BG_PIXMAP;
2629 token = gtk_rc_parse_state (scanner, &state);
2630 if (token != G_TOKEN_NONE)
2633 token = g_scanner_get_next_token (scanner);
2634 if (token != G_TOKEN_EQUAL_SIGN)
2635 return G_TOKEN_EQUAL_SIGN;
2637 token = g_scanner_get_next_token (scanner);
2638 if (token != G_TOKEN_STRING)
2639 return G_TOKEN_STRING;
2641 if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
2642 (strcmp (scanner->value.v_string, "<none>") == 0))
2643 pixmap_file = g_strdup (scanner->value.v_string);
2645 pixmap_file = gtk_rc_find_pixmap_in_path (context->settings,
2646 scanner, scanner->value.v_string);
2650 if (rc_style->bg_pixmap_name[state])
2651 g_free (rc_style->bg_pixmap_name[state]);
2652 rc_style->bg_pixmap_name[state] = pixmap_file;
2655 return G_TOKEN_NONE;
2659 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
2664 buf = g_build_filename (dir, pixmap_file, NULL);
2666 fd = open (buf, O_RDONLY);
2679 * gtk_rc_context_find_pixmap_in_path:
2680 * @settings: a #GtkSettinsg
2681 * @scanner: Scanner used to get line number information for the
2682 * warning message, or %NULL
2683 * @pixmap_file: name of the pixmap file to locate.
2685 * Looks up a file in pixmap path for the specified #GtkSettings.
2686 * If the file is not found, it outputs a warning message using
2687 * g_warning() and returns %NULL.
2692 gtk_rc_find_pixmap_in_path (GtkSettings *settings,
2694 const gchar *pixmap_file)
2700 GtkRcContext *context = gtk_rc_context_get (settings);
2702 for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (context->pixmap_path[i] != NULL); i++)
2704 filename = gtk_rc_check_pixmap_dir (context->pixmap_path[i], pixmap_file);
2709 tmp_list = rc_dir_stack;
2712 filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
2716 tmp_list = tmp_list->next;
2720 g_warning (_("Unable to locate image file in pixmap_path: \"%s\" line %d"),
2721 pixmap_file, scanner->line);
2723 g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
2730 gtk_rc_find_module_in_path (const gchar *module_file)
2736 for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
2738 buf = g_build_filename (module_path[i], module_file, NULL);
2740 fd = open (buf, O_RDONLY);
2754 gtk_rc_parse_font (GScanner *scanner,
2755 GtkRcStyle *rc_style)
2759 token = g_scanner_get_next_token (scanner);
2760 if (token != GTK_RC_TOKEN_FONT)
2761 return GTK_RC_TOKEN_FONT;
2763 token = g_scanner_get_next_token (scanner);
2764 if (token != G_TOKEN_EQUAL_SIGN)
2765 return G_TOKEN_EQUAL_SIGN;
2767 token = g_scanner_get_next_token (scanner);
2768 if (token != G_TOKEN_STRING)
2769 return G_TOKEN_STRING;
2771 /* Ignore, do nothing */
2773 return G_TOKEN_NONE;
2777 gtk_rc_parse_fontset (GScanner *scanner,
2778 GtkRcStyle *rc_style)
2782 token = g_scanner_get_next_token (scanner);
2783 if (token != GTK_RC_TOKEN_FONTSET)
2784 return GTK_RC_TOKEN_FONTSET;
2786 token = g_scanner_get_next_token (scanner);
2787 if (token != G_TOKEN_EQUAL_SIGN)
2788 return G_TOKEN_EQUAL_SIGN;
2790 token = g_scanner_get_next_token (scanner);
2791 if (token != G_TOKEN_STRING)
2792 return G_TOKEN_STRING;
2794 /* Do nothing - silently ignore */
2796 return G_TOKEN_NONE;
2800 gtk_rc_parse_font_name (GScanner *scanner,
2801 GtkRcStyle *rc_style)
2805 token = g_scanner_get_next_token (scanner);
2806 if (token != GTK_RC_TOKEN_FONT_NAME)
2807 return GTK_RC_TOKEN_FONT;
2809 token = g_scanner_get_next_token (scanner);
2810 if (token != G_TOKEN_EQUAL_SIGN)
2811 return G_TOKEN_EQUAL_SIGN;
2813 token = g_scanner_get_next_token (scanner);
2814 if (token != G_TOKEN_STRING)
2815 return G_TOKEN_STRING;
2817 rc_style->font_desc = pango_font_description_from_string (scanner->value.v_string);
2819 return G_TOKEN_NONE;
2823 gtk_rc_parse_engine (GtkRcContext *context,
2825 GtkRcStyle **rc_style)
2828 GtkThemeEngine *engine;
2829 guint result = G_TOKEN_NONE;
2830 GtkRcStyle *new_style = NULL;
2831 gboolean parsed_curlies = FALSE;
2833 token = g_scanner_get_next_token (scanner);
2834 if (token != GTK_RC_TOKEN_ENGINE)
2835 return GTK_RC_TOKEN_ENGINE;
2837 token = g_scanner_get_next_token (scanner);
2838 if (token != G_TOKEN_STRING)
2839 return G_TOKEN_STRING;
2841 engine = gtk_theme_engine_get (scanner->value.v_string);
2843 token = g_scanner_get_next_token (scanner);
2844 if (token != G_TOKEN_LEFT_CURLY)
2845 return G_TOKEN_LEFT_CURLY;
2849 GtkRcStyleClass *new_class;
2851 new_style = gtk_theme_engine_create_rc_style (engine);
2852 g_type_module_unuse (G_TYPE_MODULE (engine));
2854 new_class = GTK_RC_STYLE_GET_CLASS (new_style);
2856 new_class->merge (new_style, *rc_style);
2857 if ((*rc_style)->name)
2858 new_style->name = g_strdup ((*rc_style)->name);
2860 if (new_class->parse)
2862 parsed_curlies = TRUE;
2863 result = new_class->parse (new_style, context->settings, scanner);
2865 if (result != G_TOKEN_NONE)
2867 g_object_unref (G_OBJECT (new_style));
2873 if (!parsed_curlies)
2875 /* Skip over remainder, looking for nested {}'s
2879 result = G_TOKEN_RIGHT_CURLY;
2880 while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
2882 if (token == G_TOKEN_LEFT_CURLY)
2884 else if (token == G_TOKEN_RIGHT_CURLY)
2889 result = G_TOKEN_NONE;
2897 g_object_unref (G_OBJECT (*rc_style));
2898 *rc_style = new_style;
2905 gtk_rc_parse_state (GScanner *scanner,
2906 GtkStateType *state)
2911 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2912 g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
2914 /* we don't know where we got called from, so we reset the scope here.
2915 * if we bail out due to errors, we *don't* reset the scope, so the
2916 * error messaging code can make sense of our tokens.
2918 old_scope = g_scanner_set_scope (scanner, 0);
2920 token = g_scanner_get_next_token (scanner);
2921 if (token != G_TOKEN_LEFT_BRACE)
2922 return G_TOKEN_LEFT_BRACE;
2924 token = g_scanner_get_next_token (scanner);
2927 case GTK_RC_TOKEN_ACTIVE:
2928 *state = GTK_STATE_ACTIVE;
2930 case GTK_RC_TOKEN_INSENSITIVE:
2931 *state = GTK_STATE_INSENSITIVE;
2933 case GTK_RC_TOKEN_NORMAL:
2934 *state = GTK_STATE_NORMAL;
2936 case GTK_RC_TOKEN_PRELIGHT:
2937 *state = GTK_STATE_PRELIGHT;
2939 case GTK_RC_TOKEN_SELECTED:
2940 *state = GTK_STATE_SELECTED;
2943 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
2946 token = g_scanner_get_next_token (scanner);
2947 if (token != G_TOKEN_RIGHT_BRACE)
2948 return G_TOKEN_RIGHT_BRACE;
2950 g_scanner_set_scope (scanner, old_scope);
2952 return G_TOKEN_NONE;
2956 gtk_rc_parse_priority (GScanner *scanner,
2957 GtkPathPriorityType *priority)
2962 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2963 g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
2965 /* we don't know where we got called from, so we reset the scope here.
2966 * if we bail out due to errors, we *don't* reset the scope, so the
2967 * error messaging code can make sense of our tokens.
2969 old_scope = g_scanner_set_scope (scanner, 0);
2971 token = g_scanner_get_next_token (scanner);
2975 token = g_scanner_get_next_token (scanner);
2978 case GTK_RC_TOKEN_LOWEST:
2979 *priority = GTK_PATH_PRIO_LOWEST;
2981 case GTK_RC_TOKEN_GTK:
2982 *priority = GTK_PATH_PRIO_GTK;
2984 case GTK_RC_TOKEN_APPLICATION:
2985 *priority = GTK_PATH_PRIO_APPLICATION;
2987 case GTK_RC_TOKEN_THEME:
2988 *priority = GTK_PATH_PRIO_THEME;
2990 case GTK_RC_TOKEN_RC:
2991 *priority = GTK_PATH_PRIO_RC;
2993 case GTK_RC_TOKEN_HIGHEST:
2994 *priority = GTK_PATH_PRIO_HIGHEST;
2997 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
3000 g_scanner_set_scope (scanner, old_scope);
3002 return G_TOKEN_NONE;
3006 gtk_rc_parse_color (GScanner *scanner,
3011 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3013 /* we don't need to set our own scope here, because
3014 * we don't need own symbols
3017 token = g_scanner_get_next_token (scanner);
3022 case G_TOKEN_LEFT_CURLY:
3023 token = g_scanner_get_next_token (scanner);
3024 if (token == G_TOKEN_INT)
3025 token_int = scanner->value.v_int;
3026 else if (token == G_TOKEN_FLOAT)
3027 token_int = scanner->value.v_float * 65535.0;
3029 return G_TOKEN_FLOAT;
3030 color->red = CLAMP (token_int, 0, 65535);
3032 token = g_scanner_get_next_token (scanner);
3033 if (token != G_TOKEN_COMMA)
3034 return G_TOKEN_COMMA;
3036 token = g_scanner_get_next_token (scanner);
3037 if (token == G_TOKEN_INT)
3038 token_int = scanner->value.v_int;
3039 else if (token == G_TOKEN_FLOAT)
3040 token_int = scanner->value.v_float * 65535.0;
3042 return G_TOKEN_FLOAT;
3043 color->green = CLAMP (token_int, 0, 65535);
3045 token = g_scanner_get_next_token (scanner);
3046 if (token != G_TOKEN_COMMA)
3047 return G_TOKEN_COMMA;
3049 token = g_scanner_get_next_token (scanner);
3050 if (token == G_TOKEN_INT)
3051 token_int = scanner->value.v_int;
3052 else if (token == G_TOKEN_FLOAT)
3053 token_int = scanner->value.v_float * 65535.0;
3055 return G_TOKEN_FLOAT;
3056 color->blue = CLAMP (token_int, 0, 65535);
3058 token = g_scanner_get_next_token (scanner);
3059 if (token != G_TOKEN_RIGHT_CURLY)
3060 return G_TOKEN_RIGHT_CURLY;
3061 return G_TOKEN_NONE;
3063 case G_TOKEN_STRING:
3064 if (!gdk_color_parse (scanner->value.v_string, color))
3066 g_scanner_warn (scanner, "Invalid color constant '%s'",
3067 scanner->value.v_string);
3068 return G_TOKEN_STRING;
3071 return G_TOKEN_NONE;
3074 return G_TOKEN_STRING;
3079 gtk_rc_parse_pixmap_path (GtkRcContext *context,
3084 token = g_scanner_get_next_token (scanner);
3085 if (token != GTK_RC_TOKEN_PIXMAP_PATH)
3086 return GTK_RC_TOKEN_PIXMAP_PATH;
3088 token = g_scanner_get_next_token (scanner);
3089 if (token != G_TOKEN_STRING)
3090 return G_TOKEN_STRING;
3092 gtk_rc_parse_pixmap_path_string (context, scanner, scanner->value.v_string);
3094 return G_TOKEN_NONE;
3098 gtk_rc_parse_pixmap_path_string (GtkRcContext *context,
3100 const gchar *pix_path)
3103 gint start_offset = 0;
3107 /* free the old one, or just add to the old one ? */
3108 for (path_num = 0; context->pixmap_path[path_num]; path_num++)
3110 g_free (context->pixmap_path[path_num]);
3111 context->pixmap_path[path_num] = NULL;
3116 path_len = strlen (pix_path);
3118 for (end_offset = 0; end_offset <= path_len; end_offset++)
3120 if ((pix_path[end_offset] == G_SEARCHPATH_SEPARATOR) ||
3121 (end_offset == path_len))
3123 gchar *path_element = g_strndup (pix_path + start_offset, end_offset - start_offset);
3124 if (g_path_is_absolute (path_element))
3126 context->pixmap_path[path_num] = path_element;
3128 context->pixmap_path[path_num] = NULL;
3132 g_warning (_("Pixmap path element: \"%s\" must be absolute, %s, line %d"),
3133 path_element, scanner->input_name, scanner->line);
3134 g_free (path_element);
3137 start_offset = end_offset + 1;
3143 gtk_rc_parse_module_path (GScanner *scanner)
3147 token = g_scanner_get_next_token (scanner);
3148 if (token != GTK_RC_TOKEN_MODULE_PATH)
3149 return GTK_RC_TOKEN_MODULE_PATH;
3151 token = g_scanner_get_next_token (scanner);
3152 if (token != G_TOKEN_STRING)
3153 return G_TOKEN_STRING;
3155 gtk_rc_parse_module_path_string (scanner->value.v_string);
3157 return G_TOKEN_NONE;
3161 gtk_rc_parse_im_module_path (GScanner *scanner)
3165 token = g_scanner_get_next_token (scanner);
3166 if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
3167 return GTK_RC_TOKEN_IM_MODULE_FILE;
3169 token = g_scanner_get_next_token (scanner);
3170 if (token != G_TOKEN_STRING)
3171 return G_TOKEN_STRING;
3174 g_free (im_module_path);
3176 im_module_path = g_strdup (scanner->value.v_string);
3178 return G_TOKEN_NONE;
3182 gtk_rc_parse_im_module_file (GScanner *scanner)
3186 token = g_scanner_get_next_token (scanner);
3187 if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
3188 return GTK_RC_TOKEN_IM_MODULE_FILE;
3190 token = g_scanner_get_next_token (scanner);
3191 if (token != G_TOKEN_STRING)
3192 return G_TOKEN_STRING;
3195 g_free (im_module_file);
3197 im_module_file = g_strdup (scanner->value.v_string);
3199 return G_TOKEN_NONE;
3203 gtk_rc_parse_module_path_string (const gchar *mod_path)
3206 gint start_offset = 0;
3210 /* free the old one, or just add to the old one ? */
3211 for (path_num=0; module_path[path_num]; path_num++)
3213 g_free (module_path[path_num]);
3214 module_path[path_num] = NULL;
3219 path_len = strlen (mod_path);
3221 for (end_offset = 0; end_offset <= path_len; end_offset++)
3223 if ((mod_path[end_offset] == G_SEARCHPATH_SEPARATOR) ||
3224 (end_offset == path_len))
3226 module_path[path_num] = g_strndup (mod_path + start_offset, end_offset - start_offset);
3228 module_path[path_num] = NULL;
3229 start_offset = end_offset + 1;
3232 gtk_rc_append_default_module_path();
3236 rc_set_compare (gconstpointer a, gconstpointer b)
3238 const GtkRcSet *set_a = a;
3239 const GtkRcSet *set_b = b;
3241 return (set_a->priority < set_b->priority) ? 1 : (set_a->priority == set_b->priority ? 0 : -1);
3245 insert_rc_set (GSList *list, GtkRcSet *set)
3247 return g_slist_insert_sorted (list, set, rc_set_compare);
3251 gtk_rc_parse_path_pattern (GtkRcContext *context,
3255 GtkPathType path_type;
3257 gboolean is_binding;
3258 GtkPathPriorityType priority = context->default_priority;
3260 token = g_scanner_get_next_token (scanner);
3263 case GTK_RC_TOKEN_WIDGET:
3264 path_type = GTK_PATH_WIDGET;
3266 case GTK_RC_TOKEN_WIDGET_CLASS:
3267 path_type = GTK_PATH_WIDGET_CLASS;
3269 case GTK_RC_TOKEN_CLASS:
3270 path_type = GTK_PATH_CLASS;
3273 return GTK_RC_TOKEN_WIDGET_CLASS;
3276 token = g_scanner_get_next_token (scanner);
3277 if (token != G_TOKEN_STRING)
3278 return G_TOKEN_STRING;
3280 pattern = g_strdup (scanner->value.v_string);
3282 token = g_scanner_get_next_token (scanner);
3283 if (token == GTK_RC_TOKEN_STYLE)
3285 else if (token == GTK_RC_TOKEN_BINDING)
3290 return GTK_RC_TOKEN_STYLE;
3293 if (g_scanner_peek_next_token (scanner) == ':')
3295 token = gtk_rc_parse_priority (scanner, &priority);
3296 if (token != G_TOKEN_NONE)
3303 token = g_scanner_get_next_token (scanner);
3304 if (token != G_TOKEN_STRING)
3307 return G_TOKEN_STRING;
3312 GtkBindingSet *binding;
3314 binding = gtk_binding_set_find (scanner->value.v_string);
3318 return G_TOKEN_STRING;
3320 gtk_binding_set_add_path (binding, path_type, pattern, priority);
3324 GtkRcStyle *rc_style;
3327 rc_style = gtk_rc_style_find (context, scanner->value.v_string);
3332 return G_TOKEN_STRING;
3335 rc_set = g_new (GtkRcSet, 1);
3336 rc_set->pspec = g_pattern_spec_new (pattern);
3337 rc_set->rc_style = rc_style;
3338 rc_set->priority = priority;
3340 if (path_type == GTK_PATH_WIDGET)
3341 context->rc_sets_widget = insert_rc_set (context->rc_sets_widget, rc_set);
3342 else if (path_type == GTK_PATH_WIDGET_CLASS)
3343 context->rc_sets_widget_class = insert_rc_set (context->rc_sets_widget_class, rc_set);
3345 context->rc_sets_class = insert_rc_set (context->rc_sets_class, rc_set);
3349 return G_TOKEN_NONE;
3353 gtk_rc_parse_stock_id (GScanner *scanner,
3358 token = g_scanner_get_next_token (scanner);
3359 if (token != G_TOKEN_LEFT_BRACE)
3360 return G_TOKEN_LEFT_BRACE;
3362 token = g_scanner_get_next_token (scanner);
3364 if (token != G_TOKEN_STRING)
3365 return G_TOKEN_STRING;
3367 *stock_id = g_strdup (scanner->value.v_string);
3369 token = g_scanner_get_next_token (scanner);
3370 if (token != G_TOKEN_RIGHT_BRACE)
3373 return G_TOKEN_RIGHT_BRACE;
3376 return G_TOKEN_NONE;
3380 gtk_rc_parse_icon_source (GtkRcContext *context,
3382 GtkIconSet *icon_set)
3385 GtkIconSource *source;
3386 gchar *full_filename;
3388 token = g_scanner_get_next_token (scanner);
3389 if (token != G_TOKEN_LEFT_CURLY)
3390 return G_TOKEN_LEFT_CURLY;
3392 token = g_scanner_get_next_token (scanner);
3394 if (token != G_TOKEN_STRING)
3395 return G_TOKEN_STRING;
3398 source = gtk_icon_source_new ();
3400 full_filename = gtk_rc_find_pixmap_in_path (context->settings, scanner, scanner->value.v_string);
3403 gtk_icon_source_set_filename (source, full_filename);
3404 g_free (full_filename);
3407 /* We continue parsing even if we didn't find the pixmap so that rest of the
3408 * file is read, even if the syntax is bad
3410 token = g_scanner_get_next_token (scanner);
3412 if (token == G_TOKEN_RIGHT_CURLY)
3414 else if (token != G_TOKEN_COMMA)
3416 gtk_icon_source_free (source);
3417 return G_TOKEN_COMMA;
3420 /* Get the direction */
3422 token = g_scanner_get_next_token (scanner);
3426 case GTK_RC_TOKEN_RTL:
3427 gtk_icon_source_set_direction_wildcarded (source, FALSE);
3428 gtk_icon_source_set_direction (source, GTK_TEXT_DIR_RTL);
3431 case GTK_RC_TOKEN_LTR:
3432 gtk_icon_source_set_direction_wildcarded (source, FALSE);
3433 gtk_icon_source_set_direction (source, GTK_TEXT_DIR_LTR);
3440 gtk_icon_source_free (source);
3441 return GTK_RC_TOKEN_RTL;
3445 token = g_scanner_get_next_token (scanner);
3447 if (token == G_TOKEN_RIGHT_CURLY)
3449 else if (token != G_TOKEN_COMMA)
3451 gtk_icon_source_free (source);
3452 return G_TOKEN_COMMA;
3457 token = g_scanner_get_next_token (scanner);
3461 case GTK_RC_TOKEN_NORMAL:
3462 gtk_icon_source_set_state_wildcarded (source, FALSE);
3463 gtk_icon_source_set_state (source, GTK_STATE_NORMAL);
3466 case GTK_RC_TOKEN_PRELIGHT:
3467 gtk_icon_source_set_state_wildcarded (source, FALSE);
3468 gtk_icon_source_set_state (source, GTK_STATE_PRELIGHT);
3472 case GTK_RC_TOKEN_INSENSITIVE:
3473 gtk_icon_source_set_state_wildcarded (source, FALSE);
3474 gtk_icon_source_set_state (source, GTK_STATE_INSENSITIVE);
3477 case GTK_RC_TOKEN_ACTIVE:
3478 gtk_icon_source_set_state_wildcarded (source, FALSE);
3479 gtk_icon_source_set_state (source, GTK_STATE_ACTIVE);
3482 case GTK_RC_TOKEN_SELECTED:
3483 gtk_icon_source_set_state_wildcarded (source, FALSE);
3484 gtk_icon_source_set_state (source, GTK_STATE_SELECTED);
3491 gtk_icon_source_free (source);
3492 return GTK_RC_TOKEN_PRELIGHT;
3496 token = g_scanner_get_next_token (scanner);
3498 if (token == G_TOKEN_RIGHT_CURLY)
3500 else if (token != G_TOKEN_COMMA)
3502 gtk_icon_source_free (source);
3503 return G_TOKEN_COMMA;
3508 token = g_scanner_get_next_token (scanner);
3514 if (token != G_TOKEN_STRING)
3516 gtk_icon_source_free (source);
3517 return G_TOKEN_STRING;
3520 size = gtk_icon_size_from_name (scanner->value.v_string);
3522 if (size != GTK_ICON_SIZE_INVALID)
3524 gtk_icon_source_set_size_wildcarded (source, FALSE);
3525 gtk_icon_source_set_size (source, size);
3529 /* Check the close brace */
3531 token = g_scanner_get_next_token (scanner);
3532 if (token != G_TOKEN_RIGHT_CURLY)
3534 gtk_icon_source_free (source);
3535 return G_TOKEN_RIGHT_CURLY;
3539 if (gtk_icon_source_get_filename (source))
3540 gtk_icon_set_add_source (icon_set, source);
3541 gtk_icon_source_free (source);
3543 return G_TOKEN_NONE;
3547 gtk_rc_parse_stock (GtkRcContext *context,
3549 GtkRcStyle *rc_style,
3550 GtkIconFactory *factory)
3552 GtkIconSet *icon_set = NULL;
3553 gchar *stock_id = NULL;
3556 token = g_scanner_get_next_token (scanner);
3557 if (token != GTK_RC_TOKEN_STOCK)
3558 return GTK_RC_TOKEN_STOCK;
3560 token = gtk_rc_parse_stock_id (scanner, &stock_id);
3561 if (token != G_TOKEN_NONE)
3564 token = g_scanner_get_next_token (scanner);
3565 if (token != G_TOKEN_EQUAL_SIGN)
3568 return G_TOKEN_EQUAL_SIGN;
3571 token = g_scanner_get_next_token (scanner);
3572 if (token != G_TOKEN_LEFT_CURLY)
3575 return G_TOKEN_LEFT_CURLY;
3578 token = g_scanner_peek_next_token (scanner);
3579 while (token != G_TOKEN_RIGHT_CURLY)
3581 if (icon_set == NULL)
3582 icon_set = gtk_icon_set_new ();
3584 token = gtk_rc_parse_icon_source (context, scanner, icon_set);
3585 if (token != G_TOKEN_NONE)
3588 gtk_icon_set_unref (icon_set);
3592 token = g_scanner_get_next_token (scanner);
3594 if (token != G_TOKEN_COMMA &&
3595 token != G_TOKEN_RIGHT_CURLY)
3598 gtk_icon_set_unref (icon_set);
3599 return G_TOKEN_RIGHT_CURLY;
3605 gtk_icon_factory_add (factory,
3609 gtk_icon_set_unref (icon_set);
3614 return G_TOKEN_NONE;