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 "gtkcompat.h"
52 #include "gtkbindings.h"
53 #include "gtkthemes.h"
55 #include "gtkiconfactory.h"
56 #include "gtksettings.h"
62 typedef struct _GtkRcSet GtkRcSet;
63 typedef struct _GtkRcNode GtkRcNode;
64 typedef struct _GtkRcFile GtkRcFile;
76 gchar *canonical_name;
80 static guint gtk_rc_style_hash (const gchar *name);
81 static gboolean gtk_rc_style_equal (const gchar *a,
83 static guint gtk_rc_styles_hash (const GSList *rc_styles);
84 static gboolean gtk_rc_styles_equal (const GSList *a,
86 static GtkRcStyle* gtk_rc_style_find (const gchar *name);
87 static GSList * gtk_rc_styles_match (GSList *rc_styles,
91 const gchar *path_reversed);
92 static GtkStyle * gtk_rc_style_to_style (GtkRcStyle *rc_style);
93 static GtkStyle* gtk_rc_init_style (GSList *rc_styles);
94 static void gtk_rc_parse_file (const gchar *filename,
96 static void gtk_rc_parse_any (const gchar *input_name,
98 const gchar *input_string);
99 static guint gtk_rc_parse_statement (GScanner *scanner);
100 static guint gtk_rc_parse_style (GScanner *scanner);
101 static guint gtk_rc_parse_assignment (GScanner *scanner,
102 GtkRcProperty *prop);
103 static guint gtk_rc_parse_bg (GScanner *scanner,
105 static guint gtk_rc_parse_fg (GScanner *scanner,
107 static guint gtk_rc_parse_text (GScanner *scanner,
109 static guint gtk_rc_parse_base (GScanner *scanner,
111 static guint gtk_rc_parse_xthickness (GScanner *scanner,
113 static guint gtk_rc_parse_ythickness (GScanner *scanner,
115 static guint gtk_rc_parse_bg_pixmap (GScanner *scanner,
116 GtkRcStyle *rc_style);
117 static guint gtk_rc_parse_font (GScanner *scanner,
118 GtkRcStyle *rc_style);
119 static guint gtk_rc_parse_fontset (GScanner *scanner,
120 GtkRcStyle *rc_style);
121 static guint gtk_rc_parse_font_name (GScanner *scanner,
122 GtkRcStyle *rc_style);
123 static guint gtk_rc_parse_engine (GScanner *scanner,
124 GtkRcStyle **rc_style);
125 static guint gtk_rc_parse_pixmap_path (GScanner *scanner);
126 static void gtk_rc_parse_pixmap_path_string (gchar *pix_path);
127 static guint gtk_rc_parse_module_path (GScanner *scanner);
128 static void gtk_rc_parse_module_path_string (gchar *mod_path);
129 static guint gtk_rc_parse_im_module_path (GScanner *scanner);
130 static guint gtk_rc_parse_im_module_file (GScanner *scanner);
131 static guint gtk_rc_parse_path_pattern (GScanner *scanner);
132 static guint gtk_rc_parse_stock (GScanner *scanner,
133 GtkRcStyle *rc_style,
134 GtkIconFactory *factory);
135 static void gtk_rc_clear_hash_node (gpointer key,
138 static void gtk_rc_clear_styles (void);
139 static void gtk_rc_append_default_module_path (void);
140 static void gtk_rc_add_initial_default_files (void);
142 static void gtk_rc_style_init (GtkRcStyle *style);
143 static void gtk_rc_style_class_init (GtkRcStyleClass *klass);
144 static void gtk_rc_style_finalize (GObject *object);
145 static void gtk_rc_style_real_merge (GtkRcStyle *dest,
147 static GtkRcStyle* gtk_rc_style_real_create_rc_style (GtkRcStyle *rc_style);
148 static GtkStyle* gtk_rc_style_real_create_style (GtkRcStyle *rc_style);
149 static gint gtk_rc_properties_cmp (gconstpointer bsearch_node1,
150 gconstpointer bsearch_node2);
152 static gpointer parent_class = NULL;
154 static const GScannerConfig gtk_rc_scanner_config =
158 ) /* cset_skip_characters */,
163 ) /* cset_identifier_first */,
168 ) /* cset_identifier_nth */,
169 ( "#\n" ) /* cpair_comment_single */,
171 TRUE /* case_sensitive */,
173 TRUE /* skip_comment_multi */,
174 TRUE /* skip_comment_single */,
175 TRUE /* scan_comment_multi */,
176 TRUE /* scan_identifier */,
177 FALSE /* scan_identifier_1char */,
178 FALSE /* scan_identifier_NULL */,
179 TRUE /* scan_symbols */,
180 TRUE /* scan_binary */,
181 TRUE /* scan_octal */,
182 TRUE /* scan_float */,
184 TRUE /* scan_hex_dollar */,
185 TRUE /* scan_string_sq */,
186 TRUE /* scan_string_dq */,
187 TRUE /* numbers_2_int */,
188 FALSE /* int_2_float */,
189 FALSE /* identifier_2_string */,
190 TRUE /* char_2_token */,
191 TRUE /* symbol_2_token */,
192 FALSE /* scope_0_fallback */,
200 { "include", GTK_RC_TOKEN_INCLUDE },
201 { "NORMAL", GTK_RC_TOKEN_NORMAL },
202 { "ACTIVE", GTK_RC_TOKEN_ACTIVE },
203 { "PRELIGHT", GTK_RC_TOKEN_PRELIGHT },
204 { "SELECTED", GTK_RC_TOKEN_SELECTED },
205 { "INSENSITIVE", GTK_RC_TOKEN_INSENSITIVE },
206 { "fg", GTK_RC_TOKEN_FG },
207 { "bg", GTK_RC_TOKEN_BG },
208 { "text", GTK_RC_TOKEN_TEXT },
209 { "base", GTK_RC_TOKEN_BASE },
210 { "xthickness", GTK_RC_TOKEN_XTHICKNESS },
211 { "ythickness", GTK_RC_TOKEN_YTHICKNESS },
212 { "font", GTK_RC_TOKEN_FONT },
213 { "fontset", GTK_RC_TOKEN_FONTSET },
214 { "font_name", GTK_RC_TOKEN_FONT_NAME },
215 { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP },
216 { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH },
217 { "style", GTK_RC_TOKEN_STYLE },
218 { "binding", GTK_RC_TOKEN_BINDING },
219 { "bind", GTK_RC_TOKEN_BIND },
220 { "widget", GTK_RC_TOKEN_WIDGET },
221 { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS },
222 { "class", GTK_RC_TOKEN_CLASS },
223 { "lowest", GTK_RC_TOKEN_LOWEST },
224 { "gtk", GTK_RC_TOKEN_GTK },
225 { "application", GTK_RC_TOKEN_APPLICATION },
226 { "rc", GTK_RC_TOKEN_RC },
227 { "highest", GTK_RC_TOKEN_HIGHEST },
228 { "engine", GTK_RC_TOKEN_ENGINE },
229 { "module_path", GTK_RC_TOKEN_MODULE_PATH },
230 { "stock", GTK_RC_TOKEN_STOCK },
231 { "im_module_path", GTK_RC_TOKEN_IM_MODULE_PATH },
232 { "im_module_file", GTK_RC_TOKEN_IM_MODULE_FILE },
233 { "LTR", GTK_RC_TOKEN_LTR },
234 { "RTL", GTK_RC_TOKEN_RTL }
237 static const guint n_symbols = sizeof (symbols) / sizeof (symbols[0]);
239 static gchar *im_module_path = NULL;
240 static gchar *im_module_file = NULL;
242 static GHashTable *rc_style_ht = NULL;
243 static GHashTable *realized_style_ht = NULL;
244 static GSList *gtk_rc_sets_widget = NULL;
245 static GSList *gtk_rc_sets_widget_class = NULL;
246 static GSList *gtk_rc_sets_class = NULL;
248 #define GTK_RC_MAX_DEFAULT_FILES 128
249 static gchar *gtk_rc_default_files[GTK_RC_MAX_DEFAULT_FILES];
250 static gboolean gtk_rc_auto_parse = TRUE;
252 #define GTK_RC_MAX_PIXMAP_PATHS 128
253 static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
254 #define GTK_RC_MAX_MODULE_PATHS 128
255 static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
257 /* A stack of directories for RC files we are parsing currently.
258 * these are implicitely added to the end of PIXMAP_PATHS
260 GSList *rc_dir_stack = NULL;
262 /* The files we have parsed, to reread later if necessary */
263 GSList *rc_files = NULL;
265 static GtkImageLoader image_loader = NULL;
267 /* RC file handling */
272 get_gtk_dll_name (void)
274 static gchar *gtk_dll = NULL;
277 gtk_dll = g_strdup_printf ("gtk-%d.%d.dll", GTK_MAJOR_VERSION, GTK_MINOR_VERSION);
283 get_themes_directory (void)
285 return g_win32_get_package_installation_subdirectory (GETTEXT_PACKAGE,
289 #endif /* G_OS_WIN32 */
292 gtk_rc_make_default_dir (const gchar *type)
297 var = getenv("GTK_EXE_PREFIX");
299 path = g_strconcat (var, "/lib/gtk-2.0/" GTK_VERSION "/", type, NULL);
301 path = g_strconcat (GTK_LIBDIR "/gtk-2.0/" GTK_VERSION "/", type, NULL);
303 path = g_strconcat ("%s\\%s", get_themes_directory (), type);
310 gtk_rc_get_im_module_path (void)
312 const gchar *result = g_getenv ("GTK_IM_MODULE_PATH");
317 result = im_module_path;
319 return gtk_rc_make_default_dir ("immodules");
322 return g_strdup (result);
326 gtk_rc_get_im_module_file (void)
328 gchar *result = g_strdup (g_getenv ("GTK_IM_MODULE_FILE"));
333 result = g_strdup (im_module_file);
336 result = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk-2.0" G_DIR_SEPARATOR_S "gtk.immodules");
338 result = g_strdup_printf ("%s\\gtk.immodules", g_win32_get_package_installation_directory (GETTEXT_PACKAGE, get_gtk_dll_name ()));
346 gtk_rc_get_theme_dir(void)
351 var = getenv("GTK_DATA_PREFIX");
353 path = g_strconcat (var, "/share/themes", NULL);
355 path = g_strconcat (GTK_DATA_PREFIX, "/share/themes", NULL);
357 path = g_strdup (get_themes_directory ());
364 gtk_rc_get_module_dir(void)
366 return gtk_rc_make_default_dir ("engines");
370 gtk_rc_append_default_module_path(void)
376 for (n = 0; module_path[n]; n++) ;
377 if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
381 var = getenv("GTK_EXE_PREFIX");
383 path = g_strconcat(var, "/lib/gtk-2.0/" GTK_VERSION "/engines", NULL);
385 path = g_strdup (GTK_LIBDIR "/gtk-2.0/" GTK_VERSION "/engines");
387 path = g_strconcat (get_themes_directory (), "\\engines", NULL);
389 module_path[n++] = path;
391 var = g_get_home_dir ();
395 /* Don't duplicate the directory separator, causes trouble at
398 if (var[strlen (var) -1] != G_DIR_SEPARATOR)
399 sep = G_DIR_SEPARATOR_S;
402 /* This produces something like ~/.gtk-2.0/2.0/engines */
403 path = g_strconcat (var, sep,
404 ".gtk-2.0" G_DIR_SEPARATOR_S
405 GTK_VERSION G_DIR_SEPARATOR_S
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]);
442 str = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk-2.0" G_DIR_SEPARATOR_S "gtkrc");
444 str = g_strdup_printf ("%s\\gtkrc", g_win32_get_package_installation_directory (GETTEXT_PACKAGE, get_gtk_dll_name ()));
447 gtk_rc_add_default_file (str);
450 var = g_get_home_dir ();
454 if (var[strlen (var) -1] != G_DIR_SEPARATOR)
455 sep = G_DIR_SEPARATOR_S;
458 str = g_strdup_printf ("%s%s.gtkrc-2.0", var, sep);
459 gtk_rc_add_default_file (str);
466 gtk_rc_add_default_file (const gchar *file)
470 gtk_rc_add_initial_default_files ();
472 for (n = 0; gtk_rc_default_files[n]; n++) ;
473 if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
476 gtk_rc_default_files[n++] = g_strdup (file);
477 gtk_rc_default_files[n] = NULL;
481 gtk_rc_set_default_files (gchar **files)
485 gtk_rc_add_initial_default_files ();
488 while (gtk_rc_default_files[i])
490 g_free (gtk_rc_default_files[i]);
494 gtk_rc_default_files[0] = NULL;
495 gtk_rc_auto_parse = FALSE;
498 while (files[i] != NULL)
500 gtk_rc_add_default_file (files[i]);
506 gtk_rc_get_default_files (void)
508 gtk_rc_add_initial_default_files ();
510 return gtk_rc_default_files;
513 /* The following routine is based on _nl_normalize_codeset from
514 * the GNU C library. Contributed by
516 * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
517 * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
519 * Normalize codeset name. There is no standard for the codeset
520 * names. Normalization allows the user to use any of the common
524 _gtk_normalize_codeset (const gchar *codeset, gint name_len)
532 for (cnt = 0; cnt < name_len; ++cnt)
533 if (isalnum (codeset[cnt]))
537 if (isalpha (codeset[cnt]))
541 retval = g_malloc ((only_digit ? 3 : 0) + len + 1);
545 memcpy (retval, "iso", 4);
551 for (cnt = 0; cnt < name_len; ++cnt)
552 if (isalpha (codeset[cnt]))
553 *wp++ = isupper(codeset[cnt]) ? tolower (codeset[cnt]) : codeset[cnt];
554 else if (isdigit (codeset[cnt]))
555 *wp++ = codeset[cnt];
565 static gboolean initialized = FALSE;
566 static gchar *locale_suffixes[3];
567 static gint n_locale_suffixes = 0;
578 locale = g_win32_getlocale ();
580 locale = setlocale (LC_CTYPE, NULL);
584 pixmap_path[0] = NULL;
585 module_path[0] = NULL;
586 gtk_rc_append_default_module_path();
588 gtk_rc_add_initial_default_files ();
590 if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
592 /* Determine locale-specific suffixes for RC files
594 * We normalize the charset into a standard form,
595 * which has all '-' and '_' characters removed,
598 gchar *normalized_locale;
600 p = strchr (locale, '@');
601 length = p ? (p -locale) : strlen (locale);
603 p = strchr (locale, '.');
606 gchar *tmp1 = g_strndup (locale, p - locale + 1);
607 gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
609 normalized_locale = g_strconcat (tmp1, tmp2, NULL);
613 locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
617 normalized_locale = g_strndup (locale, length);
619 p = strchr (normalized_locale, '_');
622 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
623 length = p - normalized_locale;
626 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
628 g_free (normalized_locale);
632 g_object_freeze_notify (G_OBJECT (gtk_settings_get_global ()));
633 for (i = 0; gtk_rc_default_files[i] != NULL; i++)
635 /* Try to find a locale specific RC file corresponding to the
636 * current locale to parse before the default file.
638 for (j = n_locale_suffixes - 1; j >= 0; j--)
640 gchar *name = g_strconcat (gtk_rc_default_files[i],
647 gtk_rc_parse (gtk_rc_default_files[i]);
649 g_object_thaw_notify (G_OBJECT (gtk_settings_get_global ()));
653 gtk_rc_parse_string (const gchar *rc_string)
655 g_return_if_fail (rc_string != NULL);
657 gtk_rc_parse_any ("-", -1, rc_string);
661 gtk_rc_parse_file (const gchar *filename, gboolean reload)
663 GtkRcFile *rc_file = NULL;
667 g_return_if_fail (filename != NULL);
672 rc_file = tmp_list->data;
673 if (!strcmp (rc_file->name, filename))
676 tmp_list = tmp_list->next;
681 rc_file = g_new (GtkRcFile, 1);
682 rc_file->name = g_strdup (filename);
683 rc_file->canonical_name = NULL;
685 rc_file->reload = reload;
687 rc_files = g_slist_append (rc_files, rc_file);
690 if (!rc_file->canonical_name)
692 /* Get the absolute pathname */
694 if (g_path_is_absolute (rc_file->name))
695 rc_file->canonical_name = rc_file->name;
701 cwd = g_get_current_dir ();
703 str = g_string_new (cwd);
705 g_string_append_c (str, G_DIR_SEPARATOR);
706 g_string_append (str, rc_file->name);
708 rc_file->canonical_name = str->str;
709 g_string_free (str, FALSE);
713 if (!lstat (rc_file->canonical_name, &statbuf))
718 rc_file->mtime = statbuf.st_mtime;
720 fd = open (rc_file->canonical_name, O_RDONLY);
724 /* Temporarily push directory name for this file on
725 * a stack of directory names while parsing it
728 g_slist_prepend (rc_dir_stack,
729 g_path_get_dirname (rc_file->canonical_name));
730 gtk_rc_parse_any (filename, fd, NULL);
732 tmp_list = rc_dir_stack;
733 rc_dir_stack = rc_dir_stack->next;
735 g_free (tmp_list->data);
736 g_slist_free_1 (tmp_list);
743 gtk_rc_parse (const gchar *filename)
745 g_return_if_fail (filename != NULL);
747 gtk_rc_parse_file (filename, TRUE);
750 /* Handling of RC styles */
753 gtk_rc_style_get_type (void)
755 static GType object_type = 0;
759 static const GTypeInfo object_info =
761 sizeof (GtkRcStyleClass),
762 (GBaseInitFunc) NULL,
763 (GBaseFinalizeFunc) NULL,
764 (GClassInitFunc) gtk_rc_style_class_init,
765 NULL, /* class_finalize */
766 NULL, /* class_data */
769 (GInstanceInitFunc) gtk_rc_style_init,
772 object_type = g_type_register_static (G_TYPE_OBJECT,
781 gtk_rc_style_init (GtkRcStyle *style)
786 style->font_desc = NULL;
788 for (i = 0; i < 5; i++)
790 static const GdkColor init_color = { 0, 0, 0, 0, };
792 style->bg_pixmap_name[i] = NULL;
793 style->color_flags[i] = 0;
794 style->fg[i] = init_color;
795 style->bg[i] = init_color;
796 style->text[i] = init_color;
797 style->base[i] = init_color;
799 style->xthickness = -1;
800 style->ythickness = -1;
801 style->rc_properties = NULL;
803 style->rc_style_lists = NULL;
804 style->icon_factories = NULL;
808 gtk_rc_style_class_init (GtkRcStyleClass *klass)
810 GObjectClass *object_class = G_OBJECT_CLASS (klass);
812 parent_class = g_type_class_peek_parent (klass);
814 object_class->finalize = gtk_rc_style_finalize;
817 klass->create_rc_style = gtk_rc_style_real_create_rc_style;
818 klass->merge = gtk_rc_style_real_merge;
819 klass->create_style = gtk_rc_style_real_create_style;
823 gtk_rc_style_finalize (GObject *object)
825 GSList *tmp_list1, *tmp_list2;
826 GtkRcStyle *rc_style;
829 rc_style = GTK_RC_STYLE (object);
832 g_free (rc_style->name);
833 if (rc_style->font_desc)
834 pango_font_description_free (rc_style->font_desc);
836 for (i = 0; i < 5; i++)
837 if (rc_style->bg_pixmap_name[i])
838 g_free (rc_style->bg_pixmap_name[i]);
840 /* Now remove all references to this rc_style from
843 tmp_list1 = rc_style->rc_style_lists;
846 GSList *rc_styles = tmp_list1->data;
847 GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
848 gtk_style_unref (style);
850 /* Remove the list of styles from the other rc_styles
853 tmp_list2 = rc_styles;
856 GtkRcStyle *other_style = tmp_list2->data;
858 if (other_style != rc_style)
859 other_style->rc_style_lists = g_slist_remove_all (other_style->rc_style_lists,
861 tmp_list2 = tmp_list2->next;
864 /* And from the hash table itself
866 g_hash_table_remove (realized_style_ht, rc_styles);
867 g_slist_free (rc_styles);
869 tmp_list1 = tmp_list1->next;
871 g_slist_free (rc_style->rc_style_lists);
873 if (rc_style->rc_properties)
877 for (i = 0; i < rc_style->rc_properties->n_nodes; i++)
879 GtkRcProperty *node = g_bsearch_array_get_nth (rc_style->rc_properties, i);
881 g_free (node->origin);
882 g_value_unset (&node->value);
884 g_bsearch_array_destroy (rc_style->rc_properties);
885 rc_style->rc_properties = NULL;
888 tmp_list1 = rc_style->icon_factories;
891 g_object_unref (G_OBJECT (tmp_list1->data));
893 tmp_list1 = tmp_list1->next;
895 g_slist_free (rc_style->icon_factories);
897 G_OBJECT_CLASS (parent_class)->finalize (object);
901 gtk_rc_style_new (void)
905 style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
912 * @orig: the style to copy
914 * Make a copy of the specified #GtkRcStyle. This function
915 * will correctly copy an rc style that is a member of a class
916 * derived from #GtkRcStyle.
918 * Return value: the resulting #GtkRcStyle
921 gtk_rc_style_copy (GtkRcStyle *orig)
925 g_return_val_if_fail (GTK_IS_RC_STYLE (orig), NULL);
927 style = GTK_RC_STYLE_GET_CLASS (orig)->create_rc_style (orig);
928 GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
934 gtk_rc_style_ref (GtkRcStyle *rc_style)
936 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
938 g_object_ref (G_OBJECT (rc_style));
942 gtk_rc_style_unref (GtkRcStyle *rc_style)
944 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
946 g_object_unref (G_OBJECT (rc_style));
950 gtk_rc_style_real_create_rc_style (GtkRcStyle *style)
952 return GTK_RC_STYLE (g_object_new (G_OBJECT_TYPE (style), NULL));
956 gtk_rc_properties_cmp (gconstpointer bsearch_node1,
957 gconstpointer bsearch_node2)
959 const GtkRcProperty *prop1 = bsearch_node1;
960 const GtkRcProperty *prop2 = bsearch_node2;
963 cmp = G_BSEARCH_ARRAY_CMP (prop1->type_name, prop2->type_name);
965 cmp = G_BSEARCH_ARRAY_CMP (prop1->property_name, prop2->property_name);
971 gtk_rc_style_real_merge (GtkRcStyle *dest,
976 for (i = 0; i < 5; i++)
978 if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
979 dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
981 if (!(dest->color_flags[i] & GTK_RC_FG) &&
982 src->color_flags[i] & GTK_RC_FG)
984 dest->fg[i] = src->fg[i];
985 dest->color_flags[i] |= GTK_RC_FG;
987 if (!(dest->color_flags[i] & GTK_RC_BG) &&
988 src->color_flags[i] & GTK_RC_BG)
990 dest->bg[i] = src->bg[i];
991 dest->color_flags[i] |= GTK_RC_BG;
993 if (!(dest->color_flags[i] & GTK_RC_TEXT) &&
994 src->color_flags[i] & GTK_RC_TEXT)
996 dest->text[i] = src->text[i];
997 dest->color_flags[i] |= GTK_RC_TEXT;
999 if (!(dest->color_flags[i] & GTK_RC_BASE) &&
1000 src->color_flags[i] & GTK_RC_BASE)
1002 dest->base[i] = src->base[i];
1003 dest->color_flags[i] |= GTK_RC_BASE;
1007 if (dest->xthickness < 0 && src->xthickness >= 0)
1008 dest->xthickness = src->xthickness;
1009 if (dest->ythickness < 0 && src->ythickness >= 0)
1010 dest->ythickness = src->ythickness;
1012 if (!dest->font_desc && src->font_desc)
1013 dest->font_desc = pango_font_description_copy (src->font_desc);
1015 if (src->rc_properties)
1019 if (!dest->rc_properties)
1020 dest->rc_properties = g_bsearch_array_new (sizeof (GtkRcProperty),
1021 gtk_rc_properties_cmp,
1023 for (i = 0; i < src->rc_properties->n_nodes; i++)
1025 GtkRcProperty *node = g_bsearch_array_get_nth (src->rc_properties, i);
1026 GtkRcProperty *prop, key = { 0, 0, NULL, { 0, }, };
1028 key.type_name = node->type_name;
1029 key.property_name = node->property_name;
1030 prop = g_bsearch_array_insert (dest->rc_properties, &key, FALSE);
1033 prop->origin = g_strdup (node->origin);
1034 g_value_init (&prop->value, G_VALUE_TYPE (&node->value));
1035 g_value_copy (&node->value, &prop->value);
1042 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
1044 return gtk_style_new ();
1048 gtk_rc_clear_hash_node (gpointer key,
1052 gtk_rc_style_unref (data);
1056 gtk_rc_free_rc_sets (GSList *slist)
1062 rc_set = slist->data;
1063 g_pattern_spec_free (rc_set->pspec);
1066 slist = slist->next;
1071 gtk_rc_clear_styles (void)
1073 /* Clear out all old rc_styles */
1077 g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
1078 g_hash_table_destroy (rc_style_ht);
1082 gtk_rc_free_rc_sets (gtk_rc_sets_widget);
1083 g_slist_free (gtk_rc_sets_widget);
1084 gtk_rc_sets_widget = NULL;
1086 gtk_rc_free_rc_sets (gtk_rc_sets_widget_class);
1087 g_slist_free (gtk_rc_sets_widget_class);
1088 gtk_rc_sets_widget_class = NULL;
1090 gtk_rc_free_rc_sets (gtk_rc_sets_class);
1091 g_slist_free (gtk_rc_sets_class);
1092 gtk_rc_sets_class = NULL;
1096 gtk_rc_reparse_all (void)
1099 gboolean mtime_modified = FALSE;
1102 struct stat statbuf;
1104 /* Check through and see if any of the RC's have had their
1105 * mtime modified. If so, reparse everything.
1107 tmp_list = rc_files;
1110 rc_file = tmp_list->data;
1112 if (!lstat (rc_file->name, &statbuf) &&
1113 (statbuf.st_mtime > rc_file->mtime))
1115 mtime_modified = TRUE;
1119 tmp_list = tmp_list->next;
1124 gtk_rc_clear_styles();
1126 tmp_list = rc_files;
1129 rc_file = tmp_list->data;
1130 if (rc_file->reload)
1131 gtk_rc_parse_file (rc_file->name, FALSE);
1133 tmp_list = tmp_list->next;
1137 return mtime_modified;
1141 gtk_rc_styles_match (GSList *rc_styles,
1145 const gchar *path_reversed)
1152 rc_set = sets->data;
1155 if (g_pattern_match (rc_set->pspec, path_length, path, path_reversed))
1156 rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
1163 gtk_rc_get_style (GtkWidget *widget)
1165 GtkRcStyle *widget_rc_style;
1166 GSList *rc_styles = NULL;
1168 static guint rc_style_key_id = 0;
1170 /* We allow the specification of a single rc style to be bound
1171 * tightly to a widget, for application modifications
1173 if (!rc_style_key_id)
1174 rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1176 widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
1179 if (widget_rc_style)
1180 rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
1182 if (gtk_rc_sets_widget)
1184 gchar *path, *path_reversed;
1187 gtk_widget_path (widget, &path_length, &path, &path_reversed);
1188 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget, path_length, path, path_reversed);
1190 g_free (path_reversed);
1194 if (gtk_rc_sets_widget_class)
1196 gchar *path, *path_reversed;
1199 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1200 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget_class, path_length, path, path_reversed);
1202 g_free (path_reversed);
1205 if (gtk_rc_sets_class)
1209 type = GTK_OBJECT_TYPE (widget);
1213 gchar *path_reversed;
1216 path = gtk_type_name (type);
1217 path_length = strlen (path);
1218 path_reversed = g_strdup (path);
1219 g_strreverse (path_reversed);
1221 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_class, path_length, path, path_reversed);
1222 g_free (path_reversed);
1224 type = gtk_type_parent (type);
1229 return gtk_rc_init_style (rc_styles);
1235 gtk_rc_add_rc_sets (GSList *slist,
1236 GtkRcStyle *rc_style,
1237 const gchar *pattern)
1239 GtkRcStyle *new_style;
1243 new_style = gtk_rc_style_new ();
1244 *new_style = *rc_style;
1245 new_style->name = g_strdup (rc_style->name);
1246 if (rc_style->font_desc)
1247 new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
1249 for (i = 0; i < 5; i++)
1250 new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1252 rc_set = g_new (GtkRcSet, 1);
1253 rc_set->pspec = g_pattern_spec_new (pattern);
1254 rc_set->rc_style = rc_style;
1256 return g_slist_prepend (slist, rc_set);
1260 gtk_rc_add_widget_name_style (GtkRcStyle *rc_style,
1261 const gchar *pattern)
1263 g_return_if_fail (rc_style != NULL);
1264 g_return_if_fail (pattern != NULL);
1266 gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, rc_style, pattern);
1270 gtk_rc_add_widget_class_style (GtkRcStyle *rc_style,
1271 const gchar *pattern)
1273 g_return_if_fail (rc_style != NULL);
1274 g_return_if_fail (pattern != NULL);
1276 gtk_rc_sets_widget_class = gtk_rc_add_rc_sets (gtk_rc_sets_widget_class, rc_style, pattern);
1280 gtk_rc_add_class_style (GtkRcStyle *rc_style,
1281 const gchar *pattern)
1283 g_return_if_fail (rc_style != NULL);
1284 g_return_if_fail (pattern != NULL);
1286 gtk_rc_sets_class = gtk_rc_add_rc_sets (gtk_rc_sets_class, rc_style, pattern);
1290 gtk_rc_scanner_new (void)
1292 return g_scanner_new (>k_rc_scanner_config);
1296 gtk_rc_parse_any (const gchar *input_name,
1298 const gchar *input_string)
1304 scanner = gtk_rc_scanner_new ();
1308 g_assert (input_string == NULL);
1310 g_scanner_input_file (scanner, input_fd);
1314 g_assert (input_string != NULL);
1316 g_scanner_input_text (scanner, input_string, strlen (input_string));
1318 scanner->input_name = input_name;
1320 for (i = 0; i < n_symbols; i++)
1321 g_scanner_add_symbol (scanner, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1326 if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1330 guint expected_token;
1332 expected_token = gtk_rc_parse_statement (scanner);
1334 if (expected_token != G_TOKEN_NONE)
1341 if (scanner->scope_id == 0)
1343 /* if we are in scope 0, we know the symbol names
1344 * that are associated with certaintoken values.
1345 * so we look them up to make the error messages
1348 if (expected_token > GTK_RC_TOKEN_INVALID &&
1349 expected_token < GTK_RC_TOKEN_LAST)
1351 for (i = 0; i < n_symbols; i++)
1352 if (symbols[i].token == expected_token)
1353 msg = symbols[i].name;
1355 msg = g_strconcat ("e.g. `", msg, "'", NULL);
1357 if (scanner->token > GTK_RC_TOKEN_INVALID &&
1358 scanner->token < GTK_RC_TOKEN_LAST)
1360 symbol_name = "???";
1361 for (i = 0; i < n_symbols; i++)
1362 if (symbols[i].token == scanner->token)
1363 symbol_name = symbols[i].name;
1366 g_scanner_unexp_token (scanner,
1379 g_scanner_destroy (scanner);
1383 gtk_rc_styles_hash (const GSList *rc_styles)
1390 result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1391 rc_styles = rc_styles->next;
1398 gtk_rc_styles_equal (const GSList *a,
1403 if (a->data != b->data)
1413 gtk_rc_style_hash (const gchar *name)
1419 result += (result << 3) + *name++;
1425 gtk_rc_style_equal (const gchar *a,
1428 return (strcmp (a, b) == 0);
1432 gtk_rc_style_find (const gchar *name)
1435 return g_hash_table_lookup (rc_style_ht, (gpointer) name);
1441 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1445 style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
1447 style->rc_style = rc_style;
1449 gtk_rc_style_ref (rc_style);
1451 GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);
1456 /* Reuses or frees rc_styles */
1458 gtk_rc_init_style (GSList *rc_styles)
1460 GtkStyle *style = NULL;
1463 g_return_val_if_fail (rc_styles != NULL, NULL);
1465 if (!realized_style_ht)
1466 realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
1467 (GEqualFunc) gtk_rc_styles_equal);
1469 style = g_hash_table_lookup (realized_style_ht, rc_styles);
1473 GtkRcStyle *base_style = NULL;
1474 GtkRcStyle *proto_style;
1475 GtkRcStyleClass *proto_style_class;
1477 GType rc_style_type = GTK_TYPE_RC_STYLE;
1479 /* Find the first derived style in the list, and use that to
1480 * create the merged style. If we only have raw GtkRcStyles, use
1481 * the first style to create the merged style.
1483 base_style = rc_styles->data;
1484 tmp_styles = rc_styles;
1487 GtkRcStyle *rc_style = tmp_styles->data;
1489 if (G_OBJECT_TYPE (rc_style) != rc_style_type)
1491 base_style = rc_style;
1495 tmp_styles = tmp_styles->next;
1498 proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
1499 proto_style = proto_style_class->create_rc_style (base_style);
1501 tmp_styles = rc_styles;
1504 GtkRcStyle *rc_style = tmp_styles->data;
1507 proto_style_class->merge (proto_style, rc_style);
1509 /* Point from each rc_style to the list of styles */
1510 if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
1511 rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
1513 factories = g_slist_copy (rc_style->icon_factories);
1519 while (iter != NULL)
1521 g_object_ref (G_OBJECT (iter->data));
1522 iter = g_slist_next (iter);
1525 proto_style->icon_factories = g_slist_concat (proto_style->icon_factories,
1530 tmp_styles = tmp_styles->next;
1533 for (i = 0; i < 5; i++)
1534 if (proto_style->bg_pixmap_name[i] &&
1535 (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1537 g_free (proto_style->bg_pixmap_name[i]);
1538 proto_style->bg_pixmap_name[i] = NULL;
1541 style = gtk_rc_style_to_style (proto_style);
1542 gtk_rc_style_unref (proto_style);
1544 g_hash_table_insert (realized_style_ht, rc_styles, style);
1547 g_slist_free (rc_styles);
1552 /*********************
1553 * Parsing functions *
1554 *********************/
1557 rc_parse_token_or_compound (GScanner *scanner,
1559 GTokenType delimiter)
1561 guint token = g_scanner_get_next_token (scanner);
1563 /* we either scan a single token (skipping comments)
1564 * or a compund statement.
1565 * compunds are enclosed in (), [] or {} braces, we read
1566 * them in via deep recursion.
1573 g_string_printfa (gstring, " 0x%lx", scanner->value.v_int);
1576 g_string_printfa (gstring, " %f", scanner->value.v_float);
1578 case G_TOKEN_STRING:
1579 string = g_strescape (scanner->value.v_string, NULL);
1580 g_string_append (gstring, " \"");
1581 g_string_append (gstring, string);
1582 g_string_append_c (gstring, '"');
1585 case G_TOKEN_IDENTIFIER:
1586 g_string_append_c (gstring, ' ');
1587 g_string_append (gstring, scanner->value.v_identifier);
1589 case G_TOKEN_COMMENT_SINGLE:
1590 case G_TOKEN_COMMENT_MULTI:
1591 return rc_parse_token_or_compound (scanner, gstring, delimiter);
1592 case G_TOKEN_LEFT_PAREN:
1593 g_string_append_c (gstring, ' ');
1594 g_string_append_c (gstring, token);
1595 token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_PAREN);
1596 if (token != G_TOKEN_NONE)
1599 case G_TOKEN_LEFT_CURLY:
1600 g_string_append_c (gstring, ' ');
1601 g_string_append_c (gstring, token);
1602 token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_CURLY);
1603 if (token != G_TOKEN_NONE)
1606 case G_TOKEN_LEFT_BRACE:
1607 g_string_append_c (gstring, ' ');
1608 g_string_append_c (gstring, token);
1609 token = rc_parse_token_or_compound (scanner, gstring, G_TOKEN_RIGHT_BRACE);
1610 if (token != G_TOKEN_NONE)
1614 if (token >= 256 || token < 1)
1615 return delimiter ? delimiter : G_TOKEN_STRING;
1616 g_string_append_c (gstring, ' ');
1617 g_string_append_c (gstring, token);
1618 if (token == delimiter)
1619 return G_TOKEN_NONE;
1623 return G_TOKEN_NONE;
1625 return rc_parse_token_or_compound (scanner, gstring, delimiter);
1629 gtk_rc_parse_assignment (GScanner *scanner,
1630 GtkRcProperty *prop)
1632 gboolean scan_identifier = scanner->config->scan_identifier;
1633 gboolean scan_symbols = scanner->config->scan_symbols;
1634 gboolean identifier_2_string = scanner->config->identifier_2_string;
1635 gboolean char_2_token = scanner->config->char_2_token;
1636 gboolean scan_identifier_NULL = scanner->config->scan_identifier_NULL;
1637 gboolean numbers_2_int = scanner->config->numbers_2_int;
1638 gboolean negate = FALSE;
1641 /* check that this is an assignment */
1642 if (g_scanner_get_next_token (scanner) != '=')
1645 /* adjust scanner mode */
1646 scanner->config->scan_identifier = TRUE;
1647 scanner->config->scan_symbols = FALSE;
1648 scanner->config->identifier_2_string = FALSE;
1649 scanner->config->char_2_token = TRUE;
1650 scanner->config->scan_identifier_NULL = FALSE;
1651 scanner->config->numbers_2_int = TRUE;
1653 /* record location */
1654 prop->origin = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
1656 /* parse optional sign */
1657 if (g_scanner_peek_next_token (scanner) == '-')
1659 g_scanner_get_next_token (scanner); /* eat sign */
1663 /* parse one of LONG, DOUBLE and STRING or, if that fails, create an unparsed compund */
1664 token = g_scanner_peek_next_token (scanner);
1668 g_scanner_get_next_token (scanner);
1669 g_value_init (&prop->value, G_TYPE_LONG);
1670 g_value_set_long (&prop->value, negate ? -scanner->value.v_int : scanner->value.v_int);
1671 token = G_TOKEN_NONE;
1674 g_scanner_get_next_token (scanner);
1675 g_value_init (&prop->value, G_TYPE_DOUBLE);
1676 g_value_set_double (&prop->value, negate ? -scanner->value.v_float : scanner->value.v_float);
1677 token = G_TOKEN_NONE;
1679 case G_TOKEN_STRING:
1680 g_scanner_get_next_token (scanner);
1682 token = G_TOKEN_INT;
1685 g_value_init (&prop->value, G_TYPE_STRING);
1686 g_value_set_string (&prop->value, scanner->value.v_string);
1687 token = G_TOKEN_NONE;
1690 case G_TOKEN_IDENTIFIER:
1691 case G_TOKEN_LEFT_PAREN:
1692 case G_TOKEN_LEFT_CURLY:
1693 case G_TOKEN_LEFT_BRACE:
1696 GString *gstring = g_string_new ("");
1698 token = rc_parse_token_or_compound (scanner, gstring, 0);
1699 if (token == G_TOKEN_NONE)
1701 g_string_append_c (gstring, ' ');
1702 g_value_init (&prop->value, G_TYPE_GSTRING);
1703 g_value_set_static_boxed (&prop->value, gstring);
1706 g_string_free (gstring, TRUE);
1711 g_scanner_get_next_token (scanner);
1712 token = G_TOKEN_INT;
1716 /* restore scanner mode */
1717 scanner->config->scan_identifier = scan_identifier;
1718 scanner->config->scan_symbols = scan_symbols;
1719 scanner->config->identifier_2_string = identifier_2_string;
1720 scanner->config->char_2_token = char_2_token;
1721 scanner->config->scan_identifier_NULL = scan_identifier_NULL;
1722 scanner->config->numbers_2_int = numbers_2_int;
1728 is_c_identifier (const gchar *string)
1731 gboolean is_varname;
1733 is_varname = strchr (G_CSET_a_2_z G_CSET_A_2_Z "_", string[0]) != NULL;
1734 for (p = string + 1; *p && is_varname; p++)
1735 is_varname &= strchr (G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "_-", *p) != NULL;
1741 gtk_rc_parse_statement (GScanner *scanner)
1745 token = g_scanner_peek_next_token (scanner);
1748 case GTK_RC_TOKEN_INCLUDE:
1749 token = g_scanner_get_next_token (scanner);
1750 if (token != GTK_RC_TOKEN_INCLUDE)
1751 return GTK_RC_TOKEN_INCLUDE;
1752 token = g_scanner_get_next_token (scanner);
1753 if (token != G_TOKEN_STRING)
1754 return G_TOKEN_STRING;
1755 gtk_rc_parse_file (scanner->value.v_string, FALSE);
1756 return G_TOKEN_NONE;
1758 case GTK_RC_TOKEN_STYLE:
1759 return gtk_rc_parse_style (scanner);
1761 case GTK_RC_TOKEN_BINDING:
1762 return gtk_binding_parse_binding (scanner);
1764 case GTK_RC_TOKEN_PIXMAP_PATH:
1765 return gtk_rc_parse_pixmap_path (scanner);
1767 case GTK_RC_TOKEN_WIDGET:
1768 return gtk_rc_parse_path_pattern (scanner);
1770 case GTK_RC_TOKEN_WIDGET_CLASS:
1771 return gtk_rc_parse_path_pattern (scanner);
1773 case GTK_RC_TOKEN_CLASS:
1774 return gtk_rc_parse_path_pattern (scanner);
1776 case GTK_RC_TOKEN_MODULE_PATH:
1777 return gtk_rc_parse_module_path (scanner);
1779 case GTK_RC_TOKEN_IM_MODULE_PATH:
1780 return gtk_rc_parse_im_module_path (scanner);
1782 case GTK_RC_TOKEN_IM_MODULE_FILE:
1783 return gtk_rc_parse_im_module_file (scanner);
1785 case G_TOKEN_IDENTIFIER:
1786 if (is_c_identifier (scanner->next_value.v_identifier))
1788 GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
1791 g_scanner_get_next_token (scanner); /* eat identifier */
1792 name = g_strdup (scanner->value.v_identifier);
1794 token = gtk_rc_parse_assignment (scanner, &prop);
1795 if (token == G_TOKEN_NONE)
1797 GtkSettingsValue svalue;
1799 svalue.origin = prop.origin;
1800 memcpy (&svalue.value, &prop.value, sizeof (prop.value));
1801 g_strcanon (name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
1802 gtk_settings_set_property_value (gtk_settings_get_global (),
1806 g_free (prop.origin);
1807 if (G_VALUE_TYPE (&prop.value))
1808 g_value_unset (&prop.value);
1815 g_scanner_get_next_token (scanner);
1816 return G_TOKEN_IDENTIFIER;
1819 g_scanner_get_next_token (scanner);
1820 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
1825 gtk_rc_parse_style (GScanner *scanner)
1827 GtkRcStyle *rc_style;
1828 GtkRcStyle *parent_style;
1832 GtkIconFactory *our_factory = NULL;
1834 token = g_scanner_get_next_token (scanner);
1835 if (token != GTK_RC_TOKEN_STYLE)
1836 return GTK_RC_TOKEN_STYLE;
1838 token = g_scanner_get_next_token (scanner);
1839 if (token != G_TOKEN_STRING)
1840 return G_TOKEN_STRING;
1843 rc_style = gtk_rc_style_find (scanner->value.v_string);
1845 /* If there's a list, its first member is always the factory belonging
1848 if (rc_style && rc_style->icon_factories)
1849 our_factory = rc_style->icon_factories->data;
1854 rc_style = gtk_rc_style_new ();
1855 rc_style->name = g_strdup (scanner->value.v_string);
1857 for (i = 0; i < 5; i++)
1858 rc_style->bg_pixmap_name[i] = NULL;
1860 for (i = 0; i < 5; i++)
1861 rc_style->color_flags[i] = 0;
1864 token = g_scanner_peek_next_token (scanner);
1865 if (token == G_TOKEN_EQUAL_SIGN)
1867 token = g_scanner_get_next_token (scanner);
1869 token = g_scanner_get_next_token (scanner);
1870 if (token != G_TOKEN_STRING)
1875 return G_TOKEN_STRING;
1878 parent_style = gtk_rc_style_find (scanner->value.v_string);
1883 for (i = 0; i < 5; i++)
1885 rc_style->color_flags[i] = parent_style->color_flags[i];
1886 rc_style->fg[i] = parent_style->fg[i];
1887 rc_style->bg[i] = parent_style->bg[i];
1888 rc_style->text[i] = parent_style->text[i];
1889 rc_style->base[i] = parent_style->base[i];
1892 rc_style->xthickness = parent_style->xthickness;
1893 rc_style->ythickness = parent_style->ythickness;
1895 if (parent_style->font_desc)
1897 if (rc_style->font_desc)
1898 pango_font_description_free (rc_style->font_desc);
1899 rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
1902 if (parent_style->rc_properties)
1906 if (!rc_style->rc_properties)
1907 rc_style->rc_properties = g_bsearch_array_new (sizeof (GtkRcProperty),
1908 gtk_rc_properties_cmp,
1910 for (i = 0; i < parent_style->rc_properties->n_nodes; i++)
1912 GtkRcProperty *node = g_bsearch_array_get_nth (parent_style->rc_properties, i);
1913 GtkRcProperty *prop, key = { 0, 0, NULL, { 0, }, };
1915 key.type_name = node->type_name;
1916 key.property_name = node->property_name;
1917 prop = g_bsearch_array_insert (rc_style->rc_properties, &key, FALSE);
1920 g_free (prop->origin);
1921 g_value_unset (&prop->value);
1923 prop->origin = g_strdup (node->origin);
1924 g_value_init (&prop->value, G_VALUE_TYPE (&node->value));
1925 g_value_copy (&node->value, &prop->value);
1929 for (i = 0; i < 5; i++)
1931 if (rc_style->bg_pixmap_name[i])
1932 g_free (rc_style->bg_pixmap_name[i]);
1933 rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
1936 /* Append parent's factories, adding a ref to them */
1937 if (parent_style->icon_factories != NULL)
1939 /* Add a factory for ourselves if we have none,
1940 * in case we end up defining more stock icons.
1941 * I see no real way around this; we need to maintain
1942 * the invariant that the first factory in the list
1943 * is always our_factory, the one belonging to us,
1944 * and if we put parent factories in the list we can't
1945 * do that if the style is reopened.
1947 if (our_factory == NULL)
1949 our_factory = gtk_icon_factory_new ();
1950 rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
1954 rc_style->icon_factories = g_slist_concat (rc_style->icon_factories,
1955 g_slist_copy (parent_style->icon_factories));
1957 factories = parent_style->icon_factories;
1958 while (factories != NULL)
1960 g_object_ref (G_OBJECT (factories->data));
1961 factories = factories->next;
1967 token = g_scanner_get_next_token (scanner);
1968 if (token != G_TOKEN_LEFT_CURLY)
1973 return G_TOKEN_LEFT_CURLY;
1976 token = g_scanner_peek_next_token (scanner);
1977 while (token != G_TOKEN_RIGHT_CURLY)
1981 case GTK_RC_TOKEN_BG:
1982 token = gtk_rc_parse_bg (scanner, rc_style);
1984 case GTK_RC_TOKEN_FG:
1985 token = gtk_rc_parse_fg (scanner, rc_style);
1987 case GTK_RC_TOKEN_TEXT:
1988 token = gtk_rc_parse_text (scanner, rc_style);
1990 case GTK_RC_TOKEN_BASE:
1991 token = gtk_rc_parse_base (scanner, rc_style);
1993 case GTK_RC_TOKEN_XTHICKNESS:
1994 token = gtk_rc_parse_xthickness (scanner, rc_style);
1996 case GTK_RC_TOKEN_YTHICKNESS:
1997 token = gtk_rc_parse_ythickness (scanner, rc_style);
1999 case GTK_RC_TOKEN_BG_PIXMAP:
2000 token = gtk_rc_parse_bg_pixmap (scanner, rc_style);
2002 case GTK_RC_TOKEN_FONT:
2003 token = gtk_rc_parse_font (scanner, rc_style);
2005 case GTK_RC_TOKEN_FONTSET:
2006 token = gtk_rc_parse_fontset (scanner, rc_style);
2008 case GTK_RC_TOKEN_FONT_NAME:
2009 token = gtk_rc_parse_font_name (scanner, rc_style);
2011 case GTK_RC_TOKEN_ENGINE:
2012 token = gtk_rc_parse_engine (scanner, &rc_style);
2014 case GTK_RC_TOKEN_STOCK:
2015 if (our_factory == NULL)
2017 our_factory = gtk_icon_factory_new ();
2018 rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
2021 token = gtk_rc_parse_stock (scanner, rc_style, our_factory);
2023 case G_TOKEN_IDENTIFIER:
2024 if (is_c_identifier (scanner->next_value.v_identifier) &&
2025 scanner->next_value.v_identifier[0] >= 'A' &&
2026 scanner->next_value.v_identifier[0] <= 'Z') /* match namespaced type names */
2028 GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2030 g_scanner_get_next_token (scanner); /* eat type name */
2031 prop.type_name = g_quark_from_string (scanner->value.v_identifier);
2032 if (g_scanner_get_next_token (scanner) != ':' ||
2033 g_scanner_get_next_token (scanner) != ':')
2038 if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER ||
2039 !is_c_identifier (scanner->value.v_identifier))
2041 token = G_TOKEN_IDENTIFIER;
2045 /* it's important that we do the same canonification as GParamSpecPool here */
2046 g_strcanon (scanner->value.v_identifier, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
2047 prop.property_name = g_quark_from_string (scanner->value.v_identifier);
2049 token = gtk_rc_parse_assignment (scanner, &prop);
2050 if (token == G_TOKEN_NONE)
2054 g_return_val_if_fail (prop.origin != NULL && G_VALUE_TYPE (&prop.value) != 0, G_TOKEN_ERROR);
2056 if (!rc_style->rc_properties)
2057 rc_style->rc_properties = g_bsearch_array_new (sizeof (GtkRcProperty),
2058 gtk_rc_properties_cmp,
2060 tmp = g_bsearch_array_insert (rc_style->rc_properties, &prop, FALSE);
2061 if (prop.origin != tmp->origin)
2063 g_free (tmp->origin);
2064 g_value_unset (&tmp->value);
2065 tmp->origin = prop.origin;
2066 memcpy (&tmp->value, &prop.value, sizeof (prop.value));
2071 g_free (prop.origin);
2072 if (G_VALUE_TYPE (&prop.value))
2073 g_value_unset (&prop.value);
2078 g_scanner_get_next_token (scanner);
2079 token = G_TOKEN_IDENTIFIER;
2083 g_scanner_get_next_token (scanner);
2084 token = G_TOKEN_RIGHT_CURLY;
2088 if (token != G_TOKEN_NONE)
2091 gtk_rc_style_unref (rc_style);
2095 token = g_scanner_peek_next_token (scanner);
2096 } /* while (token != G_TOKEN_RIGHT_CURLY) */
2098 token = g_scanner_get_next_token (scanner);
2099 if (token != G_TOKEN_RIGHT_CURLY)
2103 if (rc_style->font_desc)
2104 pango_font_description_free (rc_style->font_desc);
2106 for (i = 0; i < 5; i++)
2107 if (rc_style->bg_pixmap_name[i])
2108 g_free (rc_style->bg_pixmap_name[i]);
2112 return G_TOKEN_RIGHT_CURLY;
2118 rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
2119 (GEqualFunc) gtk_rc_style_equal);
2121 g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
2124 return G_TOKEN_NONE;
2127 const GtkRcProperty*
2128 _gtk_rc_style_lookup_rc_property (GtkRcStyle *rc_style,
2130 GQuark property_name)
2132 GtkRcProperty *node = NULL;
2134 g_return_val_if_fail (GTK_IS_RC_STYLE (rc_style), NULL);
2136 if (rc_style->rc_properties)
2140 key.type_name = type_name;
2141 key.property_name = property_name;
2143 node = g_bsearch_array_lookup (rc_style->rc_properties, &key);
2150 gtk_rc_parse_bg (GScanner *scanner,
2156 token = g_scanner_get_next_token (scanner);
2157 if (token != GTK_RC_TOKEN_BG)
2158 return GTK_RC_TOKEN_BG;
2160 token = gtk_rc_parse_state (scanner, &state);
2161 if (token != G_TOKEN_NONE)
2164 token = g_scanner_get_next_token (scanner);
2165 if (token != G_TOKEN_EQUAL_SIGN)
2166 return G_TOKEN_EQUAL_SIGN;
2168 style->color_flags[state] |= GTK_RC_BG;
2169 return gtk_rc_parse_color (scanner, &style->bg[state]);
2173 gtk_rc_parse_fg (GScanner *scanner,
2179 token = g_scanner_get_next_token (scanner);
2180 if (token != GTK_RC_TOKEN_FG)
2181 return GTK_RC_TOKEN_FG;
2183 token = gtk_rc_parse_state (scanner, &state);
2184 if (token != G_TOKEN_NONE)
2187 token = g_scanner_get_next_token (scanner);
2188 if (token != G_TOKEN_EQUAL_SIGN)
2189 return G_TOKEN_EQUAL_SIGN;
2191 style->color_flags[state] |= GTK_RC_FG;
2192 return gtk_rc_parse_color (scanner, &style->fg[state]);
2196 gtk_rc_parse_text (GScanner *scanner,
2202 token = g_scanner_get_next_token (scanner);
2203 if (token != GTK_RC_TOKEN_TEXT)
2204 return GTK_RC_TOKEN_TEXT;
2206 token = gtk_rc_parse_state (scanner, &state);
2207 if (token != G_TOKEN_NONE)
2210 token = g_scanner_get_next_token (scanner);
2211 if (token != G_TOKEN_EQUAL_SIGN)
2212 return G_TOKEN_EQUAL_SIGN;
2214 style->color_flags[state] |= GTK_RC_TEXT;
2215 return gtk_rc_parse_color (scanner, &style->text[state]);
2219 gtk_rc_parse_base (GScanner *scanner,
2225 token = g_scanner_get_next_token (scanner);
2226 if (token != GTK_RC_TOKEN_BASE)
2227 return GTK_RC_TOKEN_BASE;
2229 token = gtk_rc_parse_state (scanner, &state);
2230 if (token != G_TOKEN_NONE)
2233 token = g_scanner_get_next_token (scanner);
2234 if (token != G_TOKEN_EQUAL_SIGN)
2235 return G_TOKEN_EQUAL_SIGN;
2237 style->color_flags[state] |= GTK_RC_BASE;
2238 return gtk_rc_parse_color (scanner, &style->base[state]);
2242 gtk_rc_parse_xthickness (GScanner *scanner,
2245 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
2246 return GTK_RC_TOKEN_XTHICKNESS;
2248 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2249 return G_TOKEN_EQUAL_SIGN;
2251 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2254 style->xthickness = scanner->value.v_int;
2256 return G_TOKEN_NONE;
2260 gtk_rc_parse_ythickness (GScanner *scanner,
2263 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
2264 return GTK_RC_TOKEN_YTHICKNESS;
2266 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
2267 return G_TOKEN_EQUAL_SIGN;
2269 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
2272 style->ythickness = scanner->value.v_int;
2274 return G_TOKEN_NONE;
2278 gtk_rc_parse_bg_pixmap (GScanner *scanner,
2279 GtkRcStyle *rc_style)
2285 token = g_scanner_get_next_token (scanner);
2286 if (token != GTK_RC_TOKEN_BG_PIXMAP)
2287 return GTK_RC_TOKEN_BG_PIXMAP;
2289 token = gtk_rc_parse_state (scanner, &state);
2290 if (token != G_TOKEN_NONE)
2293 token = g_scanner_get_next_token (scanner);
2294 if (token != G_TOKEN_EQUAL_SIGN)
2295 return G_TOKEN_EQUAL_SIGN;
2297 token = g_scanner_get_next_token (scanner);
2298 if (token != G_TOKEN_STRING)
2299 return G_TOKEN_STRING;
2301 if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
2302 (strcmp (scanner->value.v_string, "<none>") == 0))
2303 pixmap_file = g_strdup (scanner->value.v_string);
2305 pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
2309 if (rc_style->bg_pixmap_name[state])
2310 g_free (rc_style->bg_pixmap_name[state]);
2311 rc_style->bg_pixmap_name[state] = pixmap_file;
2314 return G_TOKEN_NONE;
2318 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
2323 buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", dir, pixmap_file);
2325 fd = open (buf, O_RDONLY);
2338 gtk_rc_find_pixmap_in_path (GScanner *scanner,
2339 const gchar *pixmap_file)
2345 for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
2347 filename = gtk_rc_check_pixmap_dir (pixmap_path[i], pixmap_file);
2352 tmp_list = rc_dir_stack;
2355 filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
2359 tmp_list = tmp_list->next;
2363 g_warning (_("Unable to locate image file in pixmap_path: \"%s\" line %d"),
2364 pixmap_file, scanner->line);
2366 g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
2373 gtk_rc_find_module_in_path (const gchar *module_file)
2379 for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
2381 buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
2382 module_path[i], module_file);
2384 fd = open (buf, O_RDONLY);
2398 gtk_rc_parse_font (GScanner *scanner,
2399 GtkRcStyle *rc_style)
2403 token = g_scanner_get_next_token (scanner);
2404 if (token != GTK_RC_TOKEN_FONT)
2405 return GTK_RC_TOKEN_FONT;
2407 token = g_scanner_get_next_token (scanner);
2408 if (token != G_TOKEN_EQUAL_SIGN)
2409 return G_TOKEN_EQUAL_SIGN;
2411 token = g_scanner_get_next_token (scanner);
2412 if (token != G_TOKEN_STRING)
2413 return G_TOKEN_STRING;
2415 /* Ignore, do nothing */
2417 return G_TOKEN_NONE;
2421 gtk_rc_parse_fontset (GScanner *scanner,
2422 GtkRcStyle *rc_style)
2426 token = g_scanner_get_next_token (scanner);
2427 if (token != GTK_RC_TOKEN_FONTSET)
2428 return GTK_RC_TOKEN_FONTSET;
2430 token = g_scanner_get_next_token (scanner);
2431 if (token != G_TOKEN_EQUAL_SIGN)
2432 return G_TOKEN_EQUAL_SIGN;
2434 token = g_scanner_get_next_token (scanner);
2435 if (token != G_TOKEN_STRING)
2436 return G_TOKEN_STRING;
2438 /* Do nothing - silently ignore */
2440 return G_TOKEN_NONE;
2444 gtk_rc_parse_font_name (GScanner *scanner,
2445 GtkRcStyle *rc_style)
2449 token = g_scanner_get_next_token (scanner);
2450 if (token != GTK_RC_TOKEN_FONT_NAME)
2451 return GTK_RC_TOKEN_FONT;
2453 token = g_scanner_get_next_token (scanner);
2454 if (token != G_TOKEN_EQUAL_SIGN)
2455 return G_TOKEN_EQUAL_SIGN;
2457 token = g_scanner_get_next_token (scanner);
2458 if (token != G_TOKEN_STRING)
2459 return G_TOKEN_STRING;
2461 rc_style->font_desc = pango_font_description_from_string (scanner->value.v_string);
2463 return G_TOKEN_NONE;
2467 gtk_rc_parse_engine (GScanner *scanner,
2468 GtkRcStyle **rc_style)
2471 GtkThemeEngine *engine;
2472 guint result = G_TOKEN_NONE;
2473 GtkRcStyle *new_style = NULL;
2474 gboolean parsed_curlies = FALSE;
2476 token = g_scanner_get_next_token (scanner);
2477 if (token != GTK_RC_TOKEN_ENGINE)
2478 return GTK_RC_TOKEN_ENGINE;
2480 token = g_scanner_get_next_token (scanner);
2481 if (token != G_TOKEN_STRING)
2482 return G_TOKEN_STRING;
2484 engine = gtk_theme_engine_get (scanner->value.v_string);
2486 token = g_scanner_get_next_token (scanner);
2487 if (token != G_TOKEN_LEFT_CURLY)
2488 return G_TOKEN_LEFT_CURLY;
2492 GtkRcStyleClass *new_class;
2494 new_style = gtk_theme_engine_create_rc_style (engine);
2495 g_type_module_unuse (G_TYPE_MODULE (engine));
2497 new_class = GTK_RC_STYLE_GET_CLASS (new_style);
2499 new_class->merge (new_style, *rc_style);
2500 if ((*rc_style)->name)
2501 new_style->name = g_strdup ((*rc_style)->name);
2503 if (new_class->parse)
2505 parsed_curlies = TRUE;
2506 result = new_class->parse (new_style, scanner);
2508 if (result != G_TOKEN_NONE)
2510 g_object_unref (G_OBJECT (new_style));
2516 if (!parsed_curlies)
2518 /* Skip over remainder, looking for nested {}'s
2522 result = G_TOKEN_RIGHT_CURLY;
2523 while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
2525 if (token == G_TOKEN_LEFT_CURLY)
2527 else if (token == G_TOKEN_RIGHT_CURLY)
2532 result = G_TOKEN_NONE;
2540 g_object_unref (G_OBJECT (*rc_style));
2541 *rc_style = new_style;
2548 gtk_rc_parse_state (GScanner *scanner,
2549 GtkStateType *state)
2554 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2555 g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
2557 /* we don't know where we got called from, so we reset the scope here.
2558 * if we bail out due to errors, we *don't* reset the scope, so the
2559 * error messaging code can make sense of our tokens.
2561 old_scope = g_scanner_set_scope (scanner, 0);
2563 token = g_scanner_get_next_token (scanner);
2564 if (token != G_TOKEN_LEFT_BRACE)
2565 return G_TOKEN_LEFT_BRACE;
2567 token = g_scanner_get_next_token (scanner);
2570 case GTK_RC_TOKEN_ACTIVE:
2571 *state = GTK_STATE_ACTIVE;
2573 case GTK_RC_TOKEN_INSENSITIVE:
2574 *state = GTK_STATE_INSENSITIVE;
2576 case GTK_RC_TOKEN_NORMAL:
2577 *state = GTK_STATE_NORMAL;
2579 case GTK_RC_TOKEN_PRELIGHT:
2580 *state = GTK_STATE_PRELIGHT;
2582 case GTK_RC_TOKEN_SELECTED:
2583 *state = GTK_STATE_SELECTED;
2586 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
2589 token = g_scanner_get_next_token (scanner);
2590 if (token != G_TOKEN_RIGHT_BRACE)
2591 return G_TOKEN_RIGHT_BRACE;
2593 g_scanner_set_scope (scanner, old_scope);
2595 return G_TOKEN_NONE;
2599 gtk_rc_parse_priority (GScanner *scanner,
2600 GtkPathPriorityType *priority)
2605 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2606 g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
2608 /* we don't know where we got called from, so we reset the scope here.
2609 * if we bail out due to errors, we *don't* reset the scope, so the
2610 * error messaging code can make sense of our tokens.
2612 old_scope = g_scanner_set_scope (scanner, 0);
2614 token = g_scanner_get_next_token (scanner);
2618 token = g_scanner_get_next_token (scanner);
2621 case GTK_RC_TOKEN_LOWEST:
2622 *priority = GTK_PATH_PRIO_LOWEST;
2624 case GTK_RC_TOKEN_GTK:
2625 *priority = GTK_PATH_PRIO_GTK;
2627 case GTK_RC_TOKEN_APPLICATION:
2628 *priority = GTK_PATH_PRIO_APPLICATION;
2630 case GTK_RC_TOKEN_RC:
2631 *priority = GTK_PATH_PRIO_RC;
2633 case GTK_RC_TOKEN_HIGHEST:
2634 *priority = GTK_PATH_PRIO_HIGHEST;
2637 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
2640 g_scanner_set_scope (scanner, old_scope);
2642 return G_TOKEN_NONE;
2646 gtk_rc_parse_color (GScanner *scanner,
2651 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2653 /* we don't need to set our own scope here, because
2654 * we don't need own symbols
2657 token = g_scanner_get_next_token (scanner);
2666 case G_TOKEN_LEFT_CURLY:
2667 token = g_scanner_get_next_token (scanner);
2668 if (token == G_TOKEN_INT)
2669 token_int = scanner->value.v_int;
2670 else if (token == G_TOKEN_FLOAT)
2671 token_int = scanner->value.v_float * 65535.0;
2673 return G_TOKEN_FLOAT;
2674 color->red = CLAMP (token_int, 0, 65535);
2676 token = g_scanner_get_next_token (scanner);
2677 if (token != G_TOKEN_COMMA)
2678 return G_TOKEN_COMMA;
2680 token = g_scanner_get_next_token (scanner);
2681 if (token == G_TOKEN_INT)
2682 token_int = scanner->value.v_int;
2683 else if (token == G_TOKEN_FLOAT)
2684 token_int = scanner->value.v_float * 65535.0;
2686 return G_TOKEN_FLOAT;
2687 color->green = CLAMP (token_int, 0, 65535);
2689 token = g_scanner_get_next_token (scanner);
2690 if (token != G_TOKEN_COMMA)
2691 return G_TOKEN_COMMA;
2693 token = g_scanner_get_next_token (scanner);
2694 if (token == G_TOKEN_INT)
2695 token_int = scanner->value.v_int;
2696 else if (token == G_TOKEN_FLOAT)
2697 token_int = scanner->value.v_float * 65535.0;
2699 return G_TOKEN_FLOAT;
2700 color->blue = CLAMP (token_int, 0, 65535);
2702 token = g_scanner_get_next_token (scanner);
2703 if (token != G_TOKEN_RIGHT_CURLY)
2704 return G_TOKEN_RIGHT_CURLY;
2705 return G_TOKEN_NONE;
2707 case G_TOKEN_STRING:
2708 if (scanner->value.v_string[0] != '#')
2709 return G_TOKEN_STRING;
2711 length = strlen (scanner->value.v_string) - 1;
2712 if (((length % 3) != 0) || (length > 12))
2713 return G_TOKEN_STRING;
2716 for (i = 0, j = 1; i < length; i++, j++)
2717 buf[i] = scanner->value.v_string[j];
2720 sscanf (buf, "%x", &temp);
2723 for (i = 0; i < length; i++, j++)
2724 buf[i] = scanner->value.v_string[j];
2727 sscanf (buf, "%x", &temp);
2728 color->green = temp;
2730 for (i = 0; i < length; i++, j++)
2731 buf[i] = scanner->value.v_string[j];
2734 sscanf (buf, "%x", &temp);
2740 color->green *= 4369;
2741 color->blue *= 4369;
2743 else if (length == 2)
2746 color->green *= 257;
2749 else if (length == 3)
2755 return G_TOKEN_NONE;
2758 return G_TOKEN_STRING;
2763 gtk_rc_parse_pixmap_path (GScanner *scanner)
2767 token = g_scanner_get_next_token (scanner);
2768 if (token != GTK_RC_TOKEN_PIXMAP_PATH)
2769 return GTK_RC_TOKEN_PIXMAP_PATH;
2771 token = g_scanner_get_next_token (scanner);
2772 if (token != G_TOKEN_STRING)
2773 return G_TOKEN_STRING;
2775 gtk_rc_parse_pixmap_path_string (scanner->value.v_string);
2777 return G_TOKEN_NONE;
2781 gtk_rc_parse_pixmap_path_string (gchar *pix_path)
2785 gint start_offset = 0;
2789 /* free the old one, or just add to the old one ? */
2790 for (path_num=0; pixmap_path[path_num]; path_num++)
2792 g_free (pixmap_path[path_num]);
2793 pixmap_path[path_num] = NULL;
2798 path_len = strlen (pix_path);
2800 buf = g_strdup (pix_path);
2802 for (end_offset = 0; end_offset <= path_len; end_offset++)
2804 if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2805 (end_offset == path_len))
2807 buf[end_offset] = '\0';
2808 pixmap_path[path_num] = g_strdup (buf + start_offset);
2810 pixmap_path[path_num] = NULL;
2811 start_offset = end_offset + 1;
2818 gtk_rc_parse_module_path (GScanner *scanner)
2822 token = g_scanner_get_next_token (scanner);
2823 if (token != GTK_RC_TOKEN_MODULE_PATH)
2824 return GTK_RC_TOKEN_MODULE_PATH;
2826 token = g_scanner_get_next_token (scanner);
2827 if (token != G_TOKEN_STRING)
2828 return G_TOKEN_STRING;
2830 gtk_rc_parse_module_path_string (scanner->value.v_string);
2832 return G_TOKEN_NONE;
2836 gtk_rc_parse_im_module_path (GScanner *scanner)
2840 token = g_scanner_get_next_token (scanner);
2841 if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
2842 return GTK_RC_TOKEN_IM_MODULE_FILE;
2844 token = g_scanner_get_next_token (scanner);
2845 if (token != G_TOKEN_STRING)
2846 return G_TOKEN_STRING;
2849 g_free (im_module_path);
2851 im_module_path = g_strdup (scanner->value.v_string);
2853 return G_TOKEN_NONE;
2857 gtk_rc_parse_im_module_file (GScanner *scanner)
2861 token = g_scanner_get_next_token (scanner);
2862 if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
2863 return GTK_RC_TOKEN_IM_MODULE_FILE;
2865 token = g_scanner_get_next_token (scanner);
2866 if (token != G_TOKEN_STRING)
2867 return G_TOKEN_STRING;
2870 g_free (im_module_file);
2872 im_module_file = g_strdup (scanner->value.v_string);
2874 return G_TOKEN_NONE;
2878 gtk_rc_parse_module_path_string (gchar *mod_path)
2882 gint start_offset = 0;
2886 /* free the old one, or just add to the old one ? */
2887 for (path_num=0; module_path[path_num]; path_num++)
2889 g_free (module_path[path_num]);
2890 module_path[path_num] = NULL;
2895 path_len = strlen (mod_path);
2897 buf = g_strdup (mod_path);
2899 for (end_offset = 0; end_offset <= path_len; end_offset++)
2901 if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2902 (end_offset == path_len))
2904 buf[end_offset] = '\0';
2905 module_path[path_num] = g_strdup (buf + start_offset);
2907 module_path[path_num] = NULL;
2908 start_offset = end_offset + 1;
2912 gtk_rc_append_default_module_path();
2916 gtk_rc_parse_path_pattern (GScanner *scanner)
2919 GtkPathType path_type;
2921 gboolean is_binding;
2922 GtkPathPriorityType priority = GTK_PATH_PRIO_RC;
2924 token = g_scanner_get_next_token (scanner);
2927 case GTK_RC_TOKEN_WIDGET:
2928 path_type = GTK_PATH_WIDGET;
2930 case GTK_RC_TOKEN_WIDGET_CLASS:
2931 path_type = GTK_PATH_WIDGET_CLASS;
2933 case GTK_RC_TOKEN_CLASS:
2934 path_type = GTK_PATH_CLASS;
2937 return GTK_RC_TOKEN_WIDGET_CLASS;
2940 token = g_scanner_get_next_token (scanner);
2941 if (token != G_TOKEN_STRING)
2942 return G_TOKEN_STRING;
2944 pattern = g_strdup (scanner->value.v_string);
2946 token = g_scanner_get_next_token (scanner);
2947 if (token == GTK_RC_TOKEN_STYLE)
2949 else if (token == GTK_RC_TOKEN_BINDING)
2952 if (g_scanner_peek_next_token (scanner) == ':')
2954 token = gtk_rc_parse_priority (scanner, &priority);
2955 if (token != G_TOKEN_NONE)
2965 return GTK_RC_TOKEN_STYLE;
2968 token = g_scanner_get_next_token (scanner);
2969 if (token != G_TOKEN_STRING)
2972 return G_TOKEN_STRING;
2977 GtkBindingSet *binding;
2979 binding = gtk_binding_set_find (scanner->value.v_string);
2983 return G_TOKEN_STRING;
2985 gtk_binding_set_add_path (binding, path_type, pattern, priority);
2989 GtkRcStyle *rc_style;
2992 rc_style = gtk_rc_style_find (scanner->value.v_string);
2997 return G_TOKEN_STRING;
3000 rc_set = g_new (GtkRcSet, 1);
3001 rc_set->pspec = g_pattern_spec_new (pattern);
3002 rc_set->rc_style = rc_style;
3004 if (path_type == GTK_PATH_WIDGET)
3005 gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set);
3006 else if (path_type == GTK_PATH_WIDGET_CLASS)
3007 gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set);
3009 gtk_rc_sets_class = g_slist_prepend (gtk_rc_sets_class, rc_set);
3013 return G_TOKEN_NONE;
3017 gtk_rc_parse_stock_id (GScanner *scanner,
3022 token = g_scanner_get_next_token (scanner);
3023 if (token != G_TOKEN_LEFT_BRACE)
3024 return G_TOKEN_LEFT_BRACE;
3026 token = g_scanner_get_next_token (scanner);
3028 if (token != G_TOKEN_STRING)
3029 return G_TOKEN_STRING;
3031 *stock_id = g_strdup (scanner->value.v_string);
3033 token = g_scanner_get_next_token (scanner);
3034 if (token != G_TOKEN_RIGHT_BRACE)
3037 return G_TOKEN_RIGHT_BRACE;
3040 return G_TOKEN_NONE;
3044 gtk_rc_parse_icon_source (GScanner *scanner,
3045 GtkIconSet *icon_set)
3048 GtkIconSource *source;
3050 token = g_scanner_get_next_token (scanner);
3051 if (token != G_TOKEN_LEFT_CURLY)
3052 return G_TOKEN_LEFT_CURLY;
3054 token = g_scanner_get_next_token (scanner);
3056 if (token != G_TOKEN_STRING)
3057 return G_TOKEN_STRING;
3059 source = gtk_icon_source_new ();
3061 gtk_icon_source_set_filename (source, scanner->value.v_string);
3063 token = g_scanner_get_next_token (scanner);
3065 if (token == G_TOKEN_RIGHT_CURLY)
3067 gtk_icon_set_add_source (icon_set, source);
3068 gtk_icon_source_free (source);
3069 return G_TOKEN_NONE;
3071 else if (token != G_TOKEN_COMMA)
3073 gtk_icon_source_free (source);
3074 return G_TOKEN_COMMA;
3077 /* Get the direction */
3079 token = g_scanner_get_next_token (scanner);
3083 case GTK_RC_TOKEN_RTL:
3084 gtk_icon_source_set_direction_wildcarded (source, FALSE);
3085 gtk_icon_source_set_direction (source, GTK_TEXT_DIR_RTL);
3088 case GTK_RC_TOKEN_LTR:
3089 gtk_icon_source_set_direction_wildcarded (source, FALSE);
3090 gtk_icon_source_set_direction (source, GTK_TEXT_DIR_LTR);
3097 gtk_icon_source_free (source);
3098 return GTK_RC_TOKEN_RTL;
3102 token = g_scanner_get_next_token (scanner);
3104 if (token == G_TOKEN_RIGHT_CURLY)
3106 gtk_icon_set_add_source (icon_set, source);
3107 gtk_icon_source_free (source);
3108 return G_TOKEN_NONE;
3110 else if (token != G_TOKEN_COMMA)
3112 gtk_icon_source_free (source);
3113 return G_TOKEN_COMMA;
3118 token = g_scanner_get_next_token (scanner);
3122 case GTK_RC_TOKEN_NORMAL:
3123 gtk_icon_source_set_state_wildcarded (source, FALSE);
3124 gtk_icon_source_set_state (source, GTK_STATE_NORMAL);
3127 case GTK_RC_TOKEN_PRELIGHT:
3128 gtk_icon_source_set_state_wildcarded (source, FALSE);
3129 gtk_icon_source_set_state (source, GTK_STATE_PRELIGHT);
3133 case GTK_RC_TOKEN_INSENSITIVE:
3134 gtk_icon_source_set_state_wildcarded (source, FALSE);
3135 gtk_icon_source_set_state (source, GTK_STATE_INSENSITIVE);
3138 case GTK_RC_TOKEN_ACTIVE:
3139 gtk_icon_source_set_state_wildcarded (source, FALSE);
3140 gtk_icon_source_set_state (source, GTK_STATE_ACTIVE);
3143 case GTK_RC_TOKEN_SELECTED:
3144 gtk_icon_source_set_state_wildcarded (source, FALSE);
3145 gtk_icon_source_set_state (source, GTK_STATE_SELECTED);
3152 gtk_icon_source_free (source);
3153 return GTK_RC_TOKEN_PRELIGHT;
3157 token = g_scanner_get_next_token (scanner);
3159 if (token == G_TOKEN_RIGHT_CURLY)
3161 gtk_icon_set_add_source (icon_set, source);
3162 gtk_icon_source_free (source);
3163 return G_TOKEN_NONE;
3165 else if (token != G_TOKEN_COMMA)
3167 gtk_icon_source_free (source);
3168 return G_TOKEN_COMMA;
3173 token = g_scanner_get_next_token (scanner);
3179 if (token != G_TOKEN_STRING)
3181 gtk_icon_source_free (source);
3182 return G_TOKEN_STRING;
3185 size = gtk_icon_size_from_name (scanner->value.v_string);
3187 if (size != GTK_ICON_SIZE_INVALID)
3189 gtk_icon_source_set_size_wildcarded (source, FALSE);
3190 gtk_icon_source_set_size (source, size);
3194 /* Check the close brace */
3196 token = g_scanner_get_next_token (scanner);
3197 if (token != G_TOKEN_RIGHT_CURLY)
3199 gtk_icon_source_free (source);
3200 return G_TOKEN_RIGHT_CURLY;
3203 gtk_icon_set_add_source (icon_set, source);
3205 gtk_icon_source_free (source);
3207 return G_TOKEN_NONE;
3211 gtk_rc_parse_stock (GScanner *scanner,
3212 GtkRcStyle *rc_style,
3213 GtkIconFactory *factory)
3215 GtkIconSet *icon_set = NULL;
3216 gchar *stock_id = NULL;
3219 token = g_scanner_get_next_token (scanner);
3220 if (token != GTK_RC_TOKEN_STOCK)
3221 return GTK_RC_TOKEN_STOCK;
3223 token = gtk_rc_parse_stock_id (scanner, &stock_id);
3224 if (token != G_TOKEN_NONE)
3227 token = g_scanner_get_next_token (scanner);
3228 if (token != G_TOKEN_EQUAL_SIGN)
3231 return G_TOKEN_EQUAL_SIGN;
3234 token = g_scanner_get_next_token (scanner);
3235 if (token != G_TOKEN_LEFT_CURLY)
3238 return G_TOKEN_LEFT_CURLY;
3241 token = g_scanner_peek_next_token (scanner);
3242 while (token != G_TOKEN_RIGHT_CURLY)
3244 if (icon_set == NULL)
3245 icon_set = gtk_icon_set_new ();
3247 token = gtk_rc_parse_icon_source (scanner, icon_set);
3248 if (token != G_TOKEN_NONE)
3251 gtk_icon_set_unref (icon_set);
3255 token = g_scanner_get_next_token (scanner);
3257 if (token != G_TOKEN_COMMA &&
3258 token != G_TOKEN_RIGHT_CURLY)
3261 gtk_icon_set_unref (icon_set);
3262 return G_TOKEN_RIGHT_CURLY;
3268 gtk_icon_factory_add (factory,
3272 gtk_icon_set_unref (icon_set);
3277 return G_TOKEN_NONE;
3281 typedef GdkPixmap * (*GtkImageLoader) (GdkWindow *window,
3282 GdkColormap *colormap,
3284 GdkColor *transparent_color,
3285 const gchar *filename);
3289 gtk_rc_set_image_loader(GtkImageLoader loader)
3291 image_loader = loader;
3295 gtk_rc_load_image (GdkColormap *colormap,
3296 GdkColor *transparent_color,
3297 const gchar *filename)
3299 if (strcmp (filename, "<parent>") == 0)
3300 return (GdkPixmap*) GDK_PARENT_RELATIVE;
3304 return image_loader(NULL, colormap, NULL,
3308 return gdk_pixmap_colormap_create_from_xpm (NULL, colormap, NULL,