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/.
30 #include "gdkconfig.h"
32 #ifdef GDK_WINDOWING_X11
33 #include <X11/Xlocale.h> /* so we get the right setlocale */
42 #ifdef HAVE_SYS_PARAM_H
43 #include <sys/param.h>
55 #include <windows.h> /* For GetWindowsDirectory */
60 #include "gtkbindings.h"
61 #include "gtkthemes.h"
64 typedef struct _GtkRcSet GtkRcSet;
65 typedef struct _GtkRcNode GtkRcNode;
66 typedef struct _GtkRcFile GtkRcFile;
78 gchar *canonical_name;
82 static guint gtk_rc_style_hash (const char *name);
83 static gint gtk_rc_style_compare (const char *a,
85 static guint gtk_rc_styles_hash (const GSList *rc_styles);
86 static gint gtk_rc_styles_compare (const GSList *a,
88 static GtkRcStyle* gtk_rc_style_find (const char *name);
89 static GSList * gtk_rc_styles_match (GSList *rc_styles,
93 gchar *path_reversed);
94 static GtkStyle * gtk_rc_style_to_style (GtkRcStyle *rc_style);
95 static GtkStyle* gtk_rc_init_style (GSList *rc_styles);
96 static void gtk_rc_parse_file (const gchar *filename,
98 static void gtk_rc_parse_any (const gchar *input_name,
100 const gchar *input_string);
101 static guint gtk_rc_parse_statement (GScanner *scanner);
102 static guint gtk_rc_parse_style (GScanner *scanner);
103 static guint gtk_rc_parse_bg (GScanner *scanner,
105 static guint gtk_rc_parse_fg (GScanner *scanner,
107 static guint gtk_rc_parse_text (GScanner *scanner,
109 static guint gtk_rc_parse_base (GScanner *scanner,
111 static guint gtk_rc_parse_xthickness (GScanner *scanner,
113 static guint gtk_rc_parse_ythickness (GScanner *scanner,
115 static guint gtk_rc_parse_bg_pixmap (GScanner *scanner,
116 GtkRcStyle *rc_style);
117 static guint gtk_rc_parse_font (GScanner *scanner,
118 GtkRcStyle *rc_style);
119 static guint gtk_rc_parse_fontset (GScanner *scanner,
120 GtkRcStyle *rc_style);
121 static guint gtk_rc_parse_font_name (GScanner *scanner,
122 GtkRcStyle *rc_style);
123 static guint gtk_rc_parse_engine (GScanner *scanner,
124 GtkRcStyle **rc_style);
125 static guint gtk_rc_parse_pixmap_path (GScanner *scanner);
126 static void gtk_rc_parse_pixmap_path_string (gchar *pix_path);
127 static guint gtk_rc_parse_module_path (GScanner *scanner);
128 static void gtk_rc_parse_module_path_string (gchar *mod_path);
129 static guint gtk_rc_parse_path_pattern (GScanner *scanner);
130 static void gtk_rc_clear_hash_node (gpointer key,
133 static void gtk_rc_clear_styles (void);
134 static void gtk_rc_append_default_module_path (void);
135 static void gtk_rc_add_initial_default_files (void);
137 static void gtk_rc_style_init (GtkRcStyle *style);
138 static void gtk_rc_style_class_init (GtkRcStyleClass *klass);
139 static void gtk_rc_style_finalize (GObject *object);
140 static void gtk_rc_style_real_merge (GtkRcStyle *dest,
142 static GtkRcStyle *gtk_rc_style_real_clone (GtkRcStyle *rc_style);
143 static GtkStyle * gtk_rc_style_real_create_style (GtkRcStyle *rc_style);
145 static gpointer parent_class = NULL;
147 static const GScannerConfig gtk_rc_scanner_config =
151 ) /* cset_skip_characters */,
156 ) /* cset_identifier_first */,
161 ) /* cset_identifier_nth */,
162 ( "#\n" ) /* cpair_comment_single */,
164 TRUE /* case_sensitive */,
166 TRUE /* skip_comment_multi */,
167 TRUE /* skip_comment_single */,
168 TRUE /* scan_comment_multi */,
169 TRUE /* scan_identifier */,
170 FALSE /* scan_identifier_1char */,
171 FALSE /* scan_identifier_NULL */,
172 TRUE /* scan_symbols */,
173 TRUE /* scan_binary */,
174 TRUE /* scan_octal */,
175 TRUE /* scan_float */,
177 TRUE /* scan_hex_dollar */,
178 TRUE /* scan_string_sq */,
179 TRUE /* scan_string_dq */,
180 TRUE /* numbers_2_int */,
181 FALSE /* int_2_float */,
182 FALSE /* identifier_2_string */,
183 TRUE /* char_2_token */,
184 TRUE /* symbol_2_token */,
185 FALSE /* scope_0_fallback */,
193 { "include", GTK_RC_TOKEN_INCLUDE },
194 { "NORMAL", GTK_RC_TOKEN_NORMAL },
195 { "ACTIVE", GTK_RC_TOKEN_ACTIVE },
196 { "PRELIGHT", GTK_RC_TOKEN_PRELIGHT },
197 { "SELECTED", GTK_RC_TOKEN_SELECTED },
198 { "INSENSITIVE", GTK_RC_TOKEN_INSENSITIVE },
199 { "fg", GTK_RC_TOKEN_FG },
200 { "bg", GTK_RC_TOKEN_BG },
201 { "text", GTK_RC_TOKEN_TEXT },
202 { "base", GTK_RC_TOKEN_BASE },
203 { "xthickness", GTK_RC_TOKEN_XTHICKNESS },
204 { "ythickness", GTK_RC_TOKEN_YTHICKNESS },
205 { "font", GTK_RC_TOKEN_FONT },
206 { "fontset", GTK_RC_TOKEN_FONTSET },
207 { "font_name", GTK_RC_TOKEN_FONT_NAME },
208 { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP },
209 { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH },
210 { "style", GTK_RC_TOKEN_STYLE },
211 { "binding", GTK_RC_TOKEN_BINDING },
212 { "bind", GTK_RC_TOKEN_BIND },
213 { "widget", GTK_RC_TOKEN_WIDGET },
214 { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS },
215 { "class", GTK_RC_TOKEN_CLASS },
216 { "lowest", GTK_RC_TOKEN_LOWEST },
217 { "gtk", GTK_RC_TOKEN_GTK },
218 { "application", GTK_RC_TOKEN_APPLICATION },
219 { "rc", GTK_RC_TOKEN_RC },
220 { "highest", GTK_RC_TOKEN_HIGHEST },
221 { "engine", GTK_RC_TOKEN_ENGINE },
222 { "module_path", GTK_RC_TOKEN_MODULE_PATH },
225 static const guint n_symbols = sizeof (symbols) / sizeof (symbols[0]);
227 static GHashTable *rc_style_ht = NULL;
228 static GHashTable *realized_style_ht = NULL;
229 static GSList *gtk_rc_sets_widget = NULL;
230 static GSList *gtk_rc_sets_widget_class = NULL;
231 static GSList *gtk_rc_sets_class = NULL;
233 #define GTK_RC_MAX_DEFAULT_FILES 128
234 static gchar *gtk_rc_default_files[GTK_RC_MAX_DEFAULT_FILES];
235 static gboolean gtk_rc_auto_parse = TRUE;
237 #define GTK_RC_MAX_PIXMAP_PATHS 128
238 static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
239 #define GTK_RC_MAX_MODULE_PATHS 128
240 static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
242 /* A stack of directories for RC files we are parsing currently.
243 * these are implicitely added to the end of PIXMAP_PATHS
245 GSList *rc_dir_stack = NULL;
247 /* The files we have parsed, to reread later if necessary */
248 GSList *rc_files = NULL;
250 static GtkImageLoader image_loader = NULL;
252 /* RC file handling */
258 gtk_win32_get_installation_directory (void)
260 static gboolean been_here = FALSE;
261 static gchar gtk_installation_dir[200];
265 DWORD nbytes = sizeof (gtk_installation_dir);
268 return gtk_installation_dir;
272 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\GNU\\GTk+", 0,
273 KEY_QUERY_VALUE, ®_key) != ERROR_SUCCESS
274 || RegQueryValueEx (reg_key, "InstallationDirectory", 0,
275 &type, gtk_installation_dir, &nbytes) != ERROR_SUCCESS
278 /* Uh oh. Use the old hard-coded %WinDir%\GTk+ value */
279 GetWindowsDirectory (win_dir, sizeof (win_dir));
280 sprintf (gtk_installation_dir, "%s\\gtk+", win_dir);
284 RegCloseKey (reg_key);
286 return gtk_installation_dir;
290 get_themes_directory (void)
292 static gchar themes_dir[200];
294 sprintf (themes_dir, "%s\\themes", gtk_win32_get_installation_directory ());
301 gtk_rc_get_theme_dir(void)
306 var = getenv("GTK_DATA_PREFIX");
308 path = g_strdup_printf("%s%s", var, "/share/themes");
310 path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/themes");
312 path = g_strdup (get_themes_directory ());
319 gtk_rc_get_module_dir(void)
324 var = getenv("GTK_EXE_PREFIX");
326 path = g_strdup_printf("%s%s", var, "/lib/gtk-2.0/" GTK_VERSION "/engines");
328 path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk-2.0/" GTK_VERSION "/engines");
330 path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
337 gtk_rc_append_default_module_path(void)
342 for (n = 0; module_path[n]; n++) ;
343 if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
347 var = getenv("GTK_EXE_PREFIX");
349 path = g_strdup_printf("%s%s", var, "/lib/gtk-2.0/" GTK_VERSION "/engines");
351 path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk-2.0/" GTK_VERSION "/engines");
353 path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
355 module_path[n++] = path;
357 var = g_get_home_dir ();
361 path = g_strdup_printf ("%s%s", var, "/.gtk-2.0/" GTK_VERSION "/engines");
363 path = g_strdup_printf ("%s%s", var, "\\_gtk\\themes\\engines");
365 module_path[n++] = path;
367 module_path[n] = NULL;
371 gtk_rc_add_initial_default_files (void)
373 static gint init = FALSE;
381 gtk_rc_default_files[0] = NULL;
384 var = g_getenv("GTK_RC_FILES");
387 files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
391 gtk_rc_add_default_file (files[i]);
399 str = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk-2.0" G_DIR_SEPARATOR_S "gtkrc");
401 str = g_strdup_printf ("%s\\gtkrc", gtk_win32_get_installation_directory ());
404 gtk_rc_add_default_file (str);
407 var = g_get_home_dir ();
410 str = g_strdup_printf ("%s" G_DIR_SEPARATOR_S ".gtkrc-2.0", var);
411 gtk_rc_add_default_file (str);
418 gtk_rc_add_default_file (const gchar *file)
422 gtk_rc_add_initial_default_files ();
424 for (n = 0; gtk_rc_default_files[n]; n++) ;
425 if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
428 gtk_rc_default_files[n++] = g_strdup (file);
429 gtk_rc_default_files[n] = NULL;
433 gtk_rc_set_default_files (gchar **files)
437 gtk_rc_add_initial_default_files ();
440 while (gtk_rc_default_files[i])
442 g_free (gtk_rc_default_files[i]);
446 gtk_rc_default_files[0] = NULL;
447 gtk_rc_auto_parse = FALSE;
450 while (files[i] != NULL)
452 gtk_rc_add_default_file (files[i]);
458 gtk_rc_get_default_files (void)
460 gtk_rc_add_initial_default_files ();
462 return gtk_rc_default_files;
465 /* The following routine is based on _nl_normalize_codeset from
466 * the GNU C library. Contributed by
468 * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
469 * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
471 * Normalize codeset name. There is no standard for the codeset
472 * names. Normalization allows the user to use any of the common
476 _gtk_normalize_codeset (const char *codeset, int name_len)
484 for (cnt = 0; cnt < name_len; ++cnt)
485 if (isalnum (codeset[cnt]))
489 if (isalpha (codeset[cnt]))
493 retval = g_malloc ((only_digit ? 3 : 0) + len + 1);
497 strcpy (retval, "iso");
503 for (cnt = 0; cnt < name_len; ++cnt)
504 if (isalpha (codeset[cnt]))
505 *wp++ = isupper(codeset[cnt]) ? tolower (codeset[cnt]) : codeset[cnt];
506 else if (isdigit (codeset[cnt]))
507 *wp++ = codeset[cnt];
517 static gchar *locale_suffixes[3];
518 static gint n_locale_suffixes = 0;
522 static gboolean initted = FALSE;
531 locale = g_win32_getlocale ();
533 locale = setlocale (LC_CTYPE, NULL);
538 pixmap_path[0] = NULL;
539 module_path[0] = NULL;
540 gtk_rc_append_default_module_path();
542 gtk_rc_add_initial_default_files ();
544 if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
546 /* Determine locale-specific suffixes for RC files
548 * We normalize the charset into a standard form,
549 * which has all '-' and '_' characters removed,
552 gchar *normalized_locale;
554 p = strchr (locale, '@');
555 length = p ? (p -locale) : strlen (locale);
557 p = strchr (locale, '.');
560 gchar *tmp1 = g_strndup (locale, p - locale + 1);
561 gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
563 normalized_locale = g_strconcat (tmp1, tmp2, NULL);
567 locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
571 normalized_locale = g_strndup (locale, length);
573 p = strchr (normalized_locale, '_');
576 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
577 length = p - normalized_locale;
580 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
582 g_free (normalized_locale);
587 while (gtk_rc_default_files[i] != NULL)
589 /* Try to find a locale specific RC file corresponding to
590 * to parse before the default file.
592 for (j=n_locale_suffixes-1; j>=0; j--)
594 gchar *name = g_strconcat (gtk_rc_default_files[i],
602 gtk_rc_parse (gtk_rc_default_files[i]);
608 gtk_rc_parse_string (const gchar *rc_string)
610 g_return_if_fail (rc_string != NULL);
612 gtk_rc_parse_any ("-", -1, rc_string);
616 gtk_rc_parse_file (const gchar *filename, gboolean reload)
618 GtkRcFile *rc_file = NULL;
622 g_return_if_fail (filename != NULL);
627 rc_file = tmp_list->data;
628 if (!strcmp (rc_file->name, filename))
631 tmp_list = tmp_list->next;
636 rc_file = g_new (GtkRcFile, 1);
637 rc_file->name = g_strdup (filename);
638 rc_file->canonical_name = NULL;
640 rc_file->reload = reload;
642 rc_files = g_slist_append (rc_files, rc_file);
645 if (!rc_file->canonical_name)
647 /* Get the absolute pathname */
649 if (g_path_is_absolute (rc_file->name))
650 rc_file->canonical_name = rc_file->name;
656 cwd = g_get_current_dir ();
658 str = g_string_new (cwd);
660 g_string_append_c (str, G_DIR_SEPARATOR);
661 g_string_append (str, rc_file->name);
663 rc_file->canonical_name = str->str;
664 g_string_free (str, FALSE);
668 if (!lstat (rc_file->canonical_name, &statbuf))
673 rc_file->mtime = statbuf.st_mtime;
675 fd = open (rc_file->canonical_name, O_RDONLY);
679 /* Temporarily push directory name for this file on
680 * a stack of directory names while parsing it
682 rc_dir_stack = g_slist_prepend (rc_dir_stack,
683 g_dirname (rc_file->canonical_name));
684 gtk_rc_parse_any (filename, fd, NULL);
686 tmp_list = rc_dir_stack;
687 rc_dir_stack = rc_dir_stack->next;
689 g_free (tmp_list->data);
690 g_slist_free_1 (tmp_list);
697 gtk_rc_parse (const gchar *filename)
699 g_return_if_fail (filename != NULL);
701 gtk_rc_parse_file (filename, TRUE);
704 /* Handling of RC styles */
707 gtk_rc_style_get_type (void)
709 static GType object_type = 0;
713 static const GTypeInfo object_info =
715 sizeof (GtkRcStyleClass),
716 (GBaseInitFunc) NULL,
717 (GBaseFinalizeFunc) NULL,
718 (GClassInitFunc) gtk_rc_style_class_init,
719 NULL, /* class_finalize */
720 NULL, /* class_data */
723 (GInstanceInitFunc) gtk_rc_style_init,
726 object_type = g_type_register_static (G_TYPE_OBJECT,
735 gtk_rc_style_init (GtkRcStyle *style)
740 for (i = 0; i < 5; i++)
742 static const GdkColor init_color = { 0, 0, 0, 0, };
744 style->bg_pixmap_name[i] = NULL;
745 style->color_flags[i] = 0;
746 style->fg[i] = init_color;
747 style->bg[i] = init_color;
748 style->text[i] = init_color;
749 style->base[i] = init_color;
751 style->xthickness = -1;
752 style->ythickness = -1;
753 style->rc_style_lists = NULL;
757 gtk_rc_style_class_init (GtkRcStyleClass *klass)
759 GObjectClass *object_class = G_OBJECT_CLASS (klass);
761 parent_class = g_type_class_peek_parent (klass);
763 object_class->finalize = gtk_rc_style_finalize;
766 klass->clone = gtk_rc_style_real_clone;
767 klass->merge = gtk_rc_style_real_merge;
768 klass->create_style = gtk_rc_style_real_create_style;
771 /* Like g_slist_remove, but remove all copies of data */
773 gtk_rc_slist_remove_all (GSList *list,
784 if (tmp->data == data)
790 prev->next = tmp->next;
792 g_slist_free_1 (tmp);
810 gtk_rc_style_finalize (GObject *object)
813 GSList *tmp_list1, *tmp_list2;
814 GtkRcStyle *rc_style;
816 rc_style = GTK_RC_STYLE (object);
819 g_free (rc_style->name);
820 if (rc_style->font_desc)
821 pango_font_description_free (rc_style->font_desc);
823 for (i=0 ; i < 5 ; i++)
824 if (rc_style->bg_pixmap_name[i])
825 g_free (rc_style->bg_pixmap_name[i]);
827 /* Now remove all references to this rc_style from
830 tmp_list1 = rc_style->rc_style_lists;
833 GSList *rc_styles = tmp_list1->data;
834 GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
835 gtk_style_unref (style);
837 /* Remove the list of styles from the other rc_styles
840 tmp_list2 = rc_styles;
843 GtkRcStyle *other_style = tmp_list2->data;
845 if (other_style != rc_style)
846 other_style->rc_style_lists =
847 gtk_rc_slist_remove_all (other_style->rc_style_lists, rc_styles);
849 tmp_list2 = tmp_list2->next;
852 /* And from the hash table itself
854 g_hash_table_remove (realized_style_ht, rc_styles);
855 g_slist_free (rc_styles);
857 tmp_list1 = tmp_list1->next;
859 g_slist_free (rc_style->rc_style_lists);
861 G_OBJECT_CLASS (parent_class)->finalize (object);
865 gtk_rc_style_new (void)
869 style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
876 * @orig: the style to copy
878 * Make a copy of the specified #GtkRcStyle. This function
879 * will correctly copy an rc style that is a member of a class
880 * derived from #GtkRcStyle.
882 * Return value: the resulting #GtkRcStyle
885 gtk_rc_style_copy (GtkRcStyle *orig)
889 g_return_if_fail (GTK_IS_RC_STYLE (orig));
891 style = GTK_RC_STYLE_GET_CLASS (orig)->clone (orig);
892 GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
898 gtk_rc_style_ref (GtkRcStyle *rc_style)
900 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
902 g_object_ref (G_OBJECT (rc_style));
906 gtk_rc_style_unref (GtkRcStyle *rc_style)
908 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
910 g_object_unref (G_OBJECT (rc_style));
914 gtk_rc_style_real_clone (GtkRcStyle *style)
916 return GTK_RC_STYLE (g_object_new (G_OBJECT_TYPE (style), NULL));
920 gtk_rc_style_real_merge (GtkRcStyle *dest,
925 for (i = 0; i < 5; i++)
927 if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
928 dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
930 if (!(dest->color_flags[i] & GTK_RC_FG) &&
931 src->color_flags[i] & GTK_RC_FG)
933 dest->fg[i] = src->fg[i];
934 dest->color_flags[i] |= GTK_RC_FG;
936 if (!(dest->color_flags[i] & GTK_RC_BG) &&
937 src->color_flags[i] & GTK_RC_BG)
939 dest->bg[i] = src->bg[i];
940 dest->color_flags[i] |= GTK_RC_BG;
942 if (!(dest->color_flags[i] & GTK_RC_TEXT) &&
943 src->color_flags[i] & GTK_RC_TEXT)
945 dest->text[i] = src->text[i];
946 dest->color_flags[i] |= GTK_RC_TEXT;
948 if (!(dest->color_flags[i] & GTK_RC_BASE) &&
949 src->color_flags[i] & GTK_RC_BASE)
951 dest->base[i] = src->base[i];
952 dest->color_flags[i] |= GTK_RC_BASE;
956 if (dest->xthickness < 0 && src->xthickness >= 0)
957 dest->xthickness = src->xthickness;
958 if (dest->ythickness < 0 && src->ythickness >= 0)
959 dest->ythickness = src->ythickness;
961 if (!dest->font_desc && src->font_desc)
962 dest->font_desc = pango_font_description_copy (src->font_desc);
966 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
968 return gtk_style_new ();
972 gtk_rc_clear_hash_node (gpointer key,
976 gtk_rc_style_unref (data);
980 gtk_rc_free_rc_sets (GSList *slist)
986 rc_set = slist->data;
987 gtk_pattern_spec_free_segs (&rc_set->pspec);
995 gtk_rc_clear_styles (void)
997 /* Clear out all old rc_styles */
1001 g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
1002 g_hash_table_destroy (rc_style_ht);
1006 gtk_rc_free_rc_sets (gtk_rc_sets_widget);
1007 g_slist_free (gtk_rc_sets_widget);
1008 gtk_rc_sets_widget = NULL;
1010 gtk_rc_free_rc_sets (gtk_rc_sets_widget_class);
1011 g_slist_free (gtk_rc_sets_widget_class);
1012 gtk_rc_sets_widget_class = NULL;
1014 gtk_rc_free_rc_sets (gtk_rc_sets_class);
1015 g_slist_free (gtk_rc_sets_class);
1016 gtk_rc_sets_class = NULL;
1020 gtk_rc_reparse_all (void)
1023 gboolean mtime_modified = FALSE;
1026 struct stat statbuf;
1028 /* Check through and see if any of the RC's have had their
1029 * mtime modified. If so, reparse everything.
1031 tmp_list = rc_files;
1034 rc_file = tmp_list->data;
1036 if (!lstat (rc_file->name, &statbuf) &&
1037 (statbuf.st_mtime > rc_file->mtime))
1039 mtime_modified = TRUE;
1043 tmp_list = tmp_list->next;
1048 gtk_rc_clear_styles();
1050 tmp_list = rc_files;
1053 rc_file = tmp_list->data;
1054 if (rc_file->reload)
1055 gtk_rc_parse_file (rc_file->name, FALSE);
1057 tmp_list = tmp_list->next;
1061 return mtime_modified;
1065 gtk_rc_styles_match (GSList *rc_styles,
1069 gchar *path_reversed)
1076 rc_set = sets->data;
1079 if (gtk_pattern_match (&rc_set->pspec, path_length, path, path_reversed))
1080 rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
1087 gtk_rc_get_style (GtkWidget *widget)
1089 GtkRcStyle *widget_rc_style;
1090 GSList *rc_styles = NULL;
1092 static guint rc_style_key_id = 0;
1094 /* We allow the specification of a single rc style to be bound
1095 * tightly to a widget, for application modifications
1097 if (!rc_style_key_id)
1098 rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1100 widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
1103 if (widget_rc_style)
1104 rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
1106 if (gtk_rc_sets_widget)
1108 gchar *path, *path_reversed;
1111 gtk_widget_path (widget, &path_length, &path, &path_reversed);
1112 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget, path_length, path, path_reversed);
1114 g_free (path_reversed);
1118 if (gtk_rc_sets_widget_class)
1120 gchar *path, *path_reversed;
1123 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1124 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget_class, path_length, path, path_reversed);
1126 g_free (path_reversed);
1129 if (gtk_rc_sets_class)
1133 type = GTK_OBJECT_TYPE (widget);
1136 gchar *path, *path_reversed;
1139 path = gtk_type_name (type);
1140 path_length = strlen (path);
1141 path_reversed = g_strdup (path);
1142 g_strreverse (path_reversed);
1144 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_class, path_length, path, path_reversed);
1145 g_free (path_reversed);
1147 type = gtk_type_parent (type);
1152 return gtk_rc_init_style (rc_styles);
1158 gtk_rc_add_rc_sets (GSList *slist,
1159 GtkRcStyle *rc_style,
1160 const char *pattern)
1162 GtkRcStyle *new_style;
1166 new_style = gtk_rc_style_new ();
1167 *new_style = *rc_style;
1168 new_style->name = g_strdup (rc_style->name);
1169 if (rc_style->font_desc)
1170 new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
1172 for (i = 0; i < 5; i++)
1173 new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1175 rc_set = g_new (GtkRcSet, 1);
1176 gtk_pattern_spec_init (&rc_set->pspec, pattern);
1177 rc_set->rc_style = rc_style;
1179 return g_slist_prepend (slist, rc_set);
1183 gtk_rc_add_widget_name_style (GtkRcStyle *rc_style,
1184 const gchar *pattern)
1186 g_return_if_fail (rc_style != NULL);
1187 g_return_if_fail (pattern != NULL);
1189 gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, rc_style, pattern);
1193 gtk_rc_add_widget_class_style (GtkRcStyle *rc_style,
1194 const gchar *pattern)
1196 g_return_if_fail (rc_style != NULL);
1197 g_return_if_fail (pattern != NULL);
1199 gtk_rc_sets_widget_class = gtk_rc_add_rc_sets (gtk_rc_sets_widget_class, rc_style, pattern);
1203 gtk_rc_add_class_style (GtkRcStyle *rc_style,
1204 const gchar *pattern)
1206 g_return_if_fail (rc_style != NULL);
1207 g_return_if_fail (pattern != NULL);
1209 gtk_rc_sets_class = gtk_rc_add_rc_sets (gtk_rc_sets_class, rc_style, pattern);
1213 gtk_rc_parse_any (const gchar *input_name,
1215 const gchar *input_string)
1221 scanner = g_scanner_new ((GScannerConfig *) >k_rc_scanner_config);
1225 g_assert (input_string == NULL);
1227 g_scanner_input_file (scanner, input_fd);
1231 g_assert (input_string != NULL);
1233 g_scanner_input_text (scanner, input_string, strlen (input_string));
1235 scanner->input_name = input_name;
1237 g_scanner_freeze_symbol_table (scanner);
1238 for (i = 0; i < n_symbols; i++)
1239 g_scanner_add_symbol (scanner, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1240 g_scanner_thaw_symbol_table (scanner);
1245 if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1249 guint expected_token;
1251 expected_token = gtk_rc_parse_statement (scanner);
1253 if (expected_token != G_TOKEN_NONE)
1260 if (scanner->scope_id == 0)
1262 /* if we are in scope 0, we know the symbol names
1263 * that are associated with certaintoken values.
1264 * so we look them up to make the error messages
1267 if (expected_token > GTK_RC_TOKEN_INVALID &&
1268 expected_token < GTK_RC_TOKEN_LAST)
1270 for (i = 0; i < n_symbols; i++)
1271 if (symbols[i].token == expected_token)
1272 msg = symbols[i].name;
1274 msg = g_strconcat ("e.g. `", msg, "'", NULL);
1276 if (scanner->token > GTK_RC_TOKEN_INVALID &&
1277 scanner->token < GTK_RC_TOKEN_LAST)
1279 symbol_name = "???";
1280 for (i = 0; i < n_symbols; i++)
1281 if (symbols[i].token == scanner->token)
1282 symbol_name = symbols[i].name;
1285 g_scanner_unexp_token (scanner,
1298 g_scanner_destroy (scanner);
1302 gtk_rc_styles_hash (const GSList *rc_styles)
1309 result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1310 rc_styles = rc_styles->next;
1317 gtk_rc_styles_compare (const GSList *a,
1322 if (a->data != b->data)
1332 gtk_rc_style_hash (const char *name)
1338 result += (result << 3) + *name++;
1344 gtk_rc_style_compare (const char *a,
1347 return (strcmp (a, b) == 0);
1351 gtk_rc_style_find (const char *name)
1354 return g_hash_table_lookup (rc_style_ht, (gpointer) name);
1360 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1364 style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
1366 style->rc_style = rc_style;
1367 gtk_rc_style_ref (rc_style);
1369 GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);
1374 /* Reuses or frees rc_styles */
1376 gtk_rc_init_style (GSList *rc_styles)
1378 GtkStyle *style = NULL;
1381 g_return_val_if_fail (rc_styles != NULL, NULL);
1383 if (!realized_style_ht)
1384 realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
1385 (GCompareFunc) gtk_rc_styles_compare);
1387 style = g_hash_table_lookup (realized_style_ht, rc_styles);
1391 GtkRcStyle *base_style = NULL;
1392 GtkRcStyle *proto_style;
1393 GtkRcStyleClass *proto_style_class;
1395 GType rc_style_type = GTK_TYPE_RC_STYLE;
1397 /* Find the first derived style in the list, and use that to
1398 * create the merged style. If we only have raw GtkRcStyles, use
1399 * the first style to create the merged style.
1401 base_style = rc_styles->data;
1402 tmp_styles = rc_styles;
1405 GtkRcStyle *rc_style = tmp_styles->data;
1407 if (G_OBJECT_TYPE (rc_style) != rc_style_type)
1409 base_style = rc_style;
1413 tmp_styles = tmp_styles->next;
1416 proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
1417 proto_style = proto_style_class->clone (base_style);
1419 tmp_styles = rc_styles;
1422 GtkRcStyle *rc_style = tmp_styles->data;
1424 proto_style_class->merge (proto_style, rc_style);
1426 /* Point from each rc_style to the list of styles */
1427 if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
1428 rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
1430 tmp_styles = tmp_styles->next;
1433 for (i = 0; i < 5; i++)
1434 if (proto_style->bg_pixmap_name[i] &&
1435 (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1437 g_free (proto_style->bg_pixmap_name[i]);
1438 proto_style->bg_pixmap_name[i] = NULL;
1441 style = gtk_rc_style_to_style (proto_style);
1442 gtk_rc_style_unref (proto_style);
1444 g_hash_table_insert (realized_style_ht, rc_styles, style);
1447 g_slist_free (rc_styles);
1452 /*********************
1453 * Parsing functions *
1454 *********************/
1457 gtk_rc_parse_statement (GScanner *scanner)
1461 token = g_scanner_peek_next_token (scanner);
1465 case GTK_RC_TOKEN_INCLUDE:
1466 token = g_scanner_get_next_token (scanner);
1467 if (token != GTK_RC_TOKEN_INCLUDE)
1468 return GTK_RC_TOKEN_INCLUDE;
1470 token = g_scanner_get_next_token (scanner);
1471 if (token != G_TOKEN_STRING)
1472 return G_TOKEN_STRING;
1474 gtk_rc_parse_file (scanner->value.v_string, FALSE);
1475 return G_TOKEN_NONE;
1477 case GTK_RC_TOKEN_STYLE:
1478 return gtk_rc_parse_style (scanner);
1480 case GTK_RC_TOKEN_BINDING:
1481 return gtk_binding_parse_binding (scanner);
1483 case GTK_RC_TOKEN_PIXMAP_PATH:
1484 return gtk_rc_parse_pixmap_path (scanner);
1486 case GTK_RC_TOKEN_WIDGET:
1487 return gtk_rc_parse_path_pattern (scanner);
1489 case GTK_RC_TOKEN_WIDGET_CLASS:
1490 return gtk_rc_parse_path_pattern (scanner);
1492 case GTK_RC_TOKEN_CLASS:
1493 return gtk_rc_parse_path_pattern (scanner);
1495 case GTK_RC_TOKEN_MODULE_PATH:
1496 return gtk_rc_parse_module_path (scanner);
1499 g_scanner_get_next_token (scanner);
1500 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
1505 gtk_rc_parse_style (GScanner *scanner)
1507 GtkRcStyle *rc_style;
1508 GtkRcStyle *parent_style;
1513 token = g_scanner_get_next_token (scanner);
1514 if (token != GTK_RC_TOKEN_STYLE)
1515 return GTK_RC_TOKEN_STYLE;
1517 token = g_scanner_get_next_token (scanner);
1518 if (token != G_TOKEN_STRING)
1519 return G_TOKEN_STRING;
1522 rc_style = gtk_rc_style_find (scanner->value.v_string);
1527 rc_style = gtk_rc_style_new ();
1528 rc_style->name = g_strdup (scanner->value.v_string);
1530 for (i = 0; i < 5; i++)
1531 rc_style->bg_pixmap_name[i] = NULL;
1533 for (i = 0; i < 5; i++)
1534 rc_style->color_flags[i] = 0;
1537 token = g_scanner_peek_next_token (scanner);
1538 if (token == G_TOKEN_EQUAL_SIGN)
1540 token = g_scanner_get_next_token (scanner);
1542 token = g_scanner_get_next_token (scanner);
1543 if (token != G_TOKEN_STRING)
1548 return G_TOKEN_STRING;
1551 parent_style = gtk_rc_style_find (scanner->value.v_string);
1554 for (i = 0; i < 5; i++)
1556 rc_style->color_flags[i] = parent_style->color_flags[i];
1557 rc_style->fg[i] = parent_style->fg[i];
1558 rc_style->bg[i] = parent_style->bg[i];
1559 rc_style->text[i] = parent_style->text[i];
1560 rc_style->base[i] = parent_style->base[i];
1563 rc_style->xthickness = parent_style->xthickness;
1564 rc_style->ythickness = parent_style->ythickness;
1566 if (parent_style->font_desc)
1568 if (rc_style->font_desc)
1569 pango_font_description_free (rc_style->font_desc);
1570 rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
1573 for (i = 0; i < 5; i++)
1575 if (rc_style->bg_pixmap_name[i])
1576 g_free (rc_style->bg_pixmap_name[i]);
1577 rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
1582 token = g_scanner_get_next_token (scanner);
1583 if (token != G_TOKEN_LEFT_CURLY)
1588 return G_TOKEN_LEFT_CURLY;
1591 token = g_scanner_peek_next_token (scanner);
1592 while (token != G_TOKEN_RIGHT_CURLY)
1596 case GTK_RC_TOKEN_BG:
1597 token = gtk_rc_parse_bg (scanner, rc_style);
1599 case GTK_RC_TOKEN_FG:
1600 token = gtk_rc_parse_fg (scanner, rc_style);
1602 case GTK_RC_TOKEN_TEXT:
1603 token = gtk_rc_parse_text (scanner, rc_style);
1605 case GTK_RC_TOKEN_BASE:
1606 token = gtk_rc_parse_base (scanner, rc_style);
1608 case GTK_RC_TOKEN_XTHICKNESS:
1609 token = gtk_rc_parse_xthickness (scanner, rc_style);
1611 case GTK_RC_TOKEN_YTHICKNESS:
1612 token = gtk_rc_parse_ythickness (scanner, rc_style);
1614 case GTK_RC_TOKEN_BG_PIXMAP:
1615 token = gtk_rc_parse_bg_pixmap (scanner, rc_style);
1617 case GTK_RC_TOKEN_FONT:
1618 token = gtk_rc_parse_font (scanner, rc_style);
1620 case GTK_RC_TOKEN_FONTSET:
1621 token = gtk_rc_parse_fontset (scanner, rc_style);
1623 case GTK_RC_TOKEN_FONT_NAME:
1624 token = gtk_rc_parse_font_name (scanner, rc_style);
1626 case GTK_RC_TOKEN_ENGINE:
1627 token = gtk_rc_parse_engine (scanner, &rc_style);
1630 g_scanner_get_next_token (scanner);
1631 token = G_TOKEN_RIGHT_CURLY;
1635 if (token != G_TOKEN_NONE)
1639 if (rc_style->font_desc)
1640 pango_font_description_free (rc_style->font_desc);
1642 for (i = 0; i < 5; i++)
1643 if (rc_style->bg_pixmap_name[i])
1644 g_free (rc_style->bg_pixmap_name[i]);
1649 token = g_scanner_peek_next_token (scanner);
1652 token = g_scanner_get_next_token (scanner);
1653 if (token != G_TOKEN_RIGHT_CURLY)
1657 if (rc_style->font_desc)
1658 pango_font_description_free (rc_style->font_desc);
1660 for (i = 0; i < 5; i++)
1661 if (rc_style->bg_pixmap_name[i])
1662 g_free (rc_style->bg_pixmap_name[i]);
1666 return G_TOKEN_RIGHT_CURLY;
1672 rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
1673 (GCompareFunc) gtk_rc_style_compare);
1675 g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
1678 return G_TOKEN_NONE;
1682 gtk_rc_parse_bg (GScanner *scanner,
1688 token = g_scanner_get_next_token (scanner);
1689 if (token != GTK_RC_TOKEN_BG)
1690 return GTK_RC_TOKEN_BG;
1692 token = gtk_rc_parse_state (scanner, &state);
1693 if (token != G_TOKEN_NONE)
1696 token = g_scanner_get_next_token (scanner);
1697 if (token != G_TOKEN_EQUAL_SIGN)
1698 return G_TOKEN_EQUAL_SIGN;
1700 style->color_flags[state] |= GTK_RC_BG;
1701 return gtk_rc_parse_color (scanner, &style->bg[state]);
1705 gtk_rc_parse_fg (GScanner *scanner,
1711 token = g_scanner_get_next_token (scanner);
1712 if (token != GTK_RC_TOKEN_FG)
1713 return GTK_RC_TOKEN_FG;
1715 token = gtk_rc_parse_state (scanner, &state);
1716 if (token != G_TOKEN_NONE)
1719 token = g_scanner_get_next_token (scanner);
1720 if (token != G_TOKEN_EQUAL_SIGN)
1721 return G_TOKEN_EQUAL_SIGN;
1723 style->color_flags[state] |= GTK_RC_FG;
1724 return gtk_rc_parse_color (scanner, &style->fg[state]);
1728 gtk_rc_parse_text (GScanner *scanner,
1734 token = g_scanner_get_next_token (scanner);
1735 if (token != GTK_RC_TOKEN_TEXT)
1736 return GTK_RC_TOKEN_TEXT;
1738 token = gtk_rc_parse_state (scanner, &state);
1739 if (token != G_TOKEN_NONE)
1742 token = g_scanner_get_next_token (scanner);
1743 if (token != G_TOKEN_EQUAL_SIGN)
1744 return G_TOKEN_EQUAL_SIGN;
1746 style->color_flags[state] |= GTK_RC_TEXT;
1747 return gtk_rc_parse_color (scanner, &style->text[state]);
1751 gtk_rc_parse_base (GScanner *scanner,
1757 token = g_scanner_get_next_token (scanner);
1758 if (token != GTK_RC_TOKEN_BASE)
1759 return GTK_RC_TOKEN_BASE;
1761 token = gtk_rc_parse_state (scanner, &state);
1762 if (token != G_TOKEN_NONE)
1765 token = g_scanner_get_next_token (scanner);
1766 if (token != G_TOKEN_EQUAL_SIGN)
1767 return G_TOKEN_EQUAL_SIGN;
1769 style->color_flags[state] |= GTK_RC_BASE;
1770 return gtk_rc_parse_color (scanner, &style->base[state]);
1774 gtk_rc_parse_xthickness (GScanner *scanner,
1777 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
1778 return GTK_RC_TOKEN_XTHICKNESS;
1780 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
1781 return G_TOKEN_EQUAL_SIGN;
1783 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
1786 style->xthickness = scanner->value.v_int;
1788 return G_TOKEN_NONE;
1792 gtk_rc_parse_ythickness (GScanner *scanner,
1795 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
1796 return GTK_RC_TOKEN_YTHICKNESS;
1798 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
1799 return G_TOKEN_EQUAL_SIGN;
1801 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
1804 style->ythickness = scanner->value.v_int;
1806 return G_TOKEN_NONE;
1810 gtk_rc_parse_bg_pixmap (GScanner *scanner,
1811 GtkRcStyle *rc_style)
1817 token = g_scanner_get_next_token (scanner);
1818 if (token != GTK_RC_TOKEN_BG_PIXMAP)
1819 return GTK_RC_TOKEN_BG_PIXMAP;
1821 token = gtk_rc_parse_state (scanner, &state);
1822 if (token != G_TOKEN_NONE)
1825 token = g_scanner_get_next_token (scanner);
1826 if (token != G_TOKEN_EQUAL_SIGN)
1827 return G_TOKEN_EQUAL_SIGN;
1829 token = g_scanner_get_next_token (scanner);
1830 if (token != G_TOKEN_STRING)
1831 return G_TOKEN_STRING;
1833 if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
1834 (strcmp (scanner->value.v_string, "<none>") == 0))
1835 pixmap_file = g_strdup (scanner->value.v_string);
1837 pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
1841 if (rc_style->bg_pixmap_name[state])
1842 g_free (rc_style->bg_pixmap_name[state]);
1843 rc_style->bg_pixmap_name[state] = pixmap_file;
1846 return G_TOKEN_NONE;
1850 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
1855 buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", dir, pixmap_file);
1857 fd = open (buf, O_RDONLY);
1870 gtk_rc_find_pixmap_in_path (GScanner *scanner,
1871 const gchar *pixmap_file)
1877 for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
1879 filename = gtk_rc_check_pixmap_dir (pixmap_path[i], pixmap_file);
1884 tmp_list = rc_dir_stack;
1887 filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
1891 tmp_list = tmp_list->next;
1895 g_warning (_("Unable to locate image file in pixmap_path: \"%s\" line %d"),
1896 pixmap_file, scanner->line);
1898 g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
1905 gtk_rc_find_module_in_path (const gchar *module_file)
1911 for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
1913 buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
1914 module_path[i], module_file);
1916 fd = open (buf, O_RDONLY);
1930 gtk_rc_parse_font (GScanner *scanner,
1931 GtkRcStyle *rc_style)
1935 token = g_scanner_get_next_token (scanner);
1936 if (token != GTK_RC_TOKEN_FONT)
1937 return GTK_RC_TOKEN_FONT;
1939 token = g_scanner_get_next_token (scanner);
1940 if (token != G_TOKEN_EQUAL_SIGN)
1941 return G_TOKEN_EQUAL_SIGN;
1943 token = g_scanner_get_next_token (scanner);
1944 if (token != G_TOKEN_STRING)
1945 return G_TOKEN_STRING;
1947 /* Ignore, do nothing */
1949 return G_TOKEN_NONE;
1953 gtk_rc_parse_fontset (GScanner *scanner,
1954 GtkRcStyle *rc_style)
1958 token = g_scanner_get_next_token (scanner);
1959 if (token != GTK_RC_TOKEN_FONTSET)
1960 return GTK_RC_TOKEN_FONTSET;
1962 token = g_scanner_get_next_token (scanner);
1963 if (token != G_TOKEN_EQUAL_SIGN)
1964 return G_TOKEN_EQUAL_SIGN;
1966 token = g_scanner_get_next_token (scanner);
1967 if (token != G_TOKEN_STRING)
1968 return G_TOKEN_STRING;
1970 /* Do nothing - silently ignore */
1972 return G_TOKEN_NONE;
1976 gtk_rc_parse_font_name (GScanner *scanner,
1977 GtkRcStyle *rc_style)
1981 token = g_scanner_get_next_token (scanner);
1982 if (token != GTK_RC_TOKEN_FONT_NAME)
1983 return GTK_RC_TOKEN_FONT;
1985 token = g_scanner_get_next_token (scanner);
1986 if (token != G_TOKEN_EQUAL_SIGN)
1987 return G_TOKEN_EQUAL_SIGN;
1989 token = g_scanner_get_next_token (scanner);
1990 if (token != G_TOKEN_STRING)
1991 return G_TOKEN_STRING;
1993 rc_style->font_desc = pango_font_description_from_string (scanner->value.v_string);
1995 return G_TOKEN_NONE;
1999 gtk_rc_parse_engine (GScanner *scanner,
2000 GtkRcStyle **rc_style)
2003 GtkThemeEngine *engine;
2004 guint result = G_TOKEN_NONE;
2005 GtkRcStyle *new_style = NULL;
2006 gboolean parsed_curlies = FALSE;
2008 token = g_scanner_get_next_token (scanner);
2009 if (token != GTK_RC_TOKEN_ENGINE)
2010 return GTK_RC_TOKEN_ENGINE;
2012 token = g_scanner_get_next_token (scanner);
2013 if (token != G_TOKEN_STRING)
2014 return G_TOKEN_STRING;
2016 engine = gtk_theme_engine_get (scanner->value.v_string);
2018 token = g_scanner_get_next_token (scanner);
2019 if (token != G_TOKEN_LEFT_CURLY)
2020 return G_TOKEN_LEFT_CURLY;
2024 GtkRcStyleClass *new_class;
2026 new_style = gtk_theme_engine_create_rc_style (engine);
2027 gtk_theme_engine_unref (engine);
2029 new_class = GTK_RC_STYLE_GET_CLASS (new_style);
2031 new_class->merge (new_style, *rc_style);
2032 if ((*rc_style)->name)
2033 new_style->name = g_strdup ((*rc_style)->name);
2035 if (new_class->parse)
2037 parsed_curlies = TRUE;
2038 result = new_class->parse (new_style, scanner);
2040 if (result != G_TOKEN_NONE)
2042 g_object_unref (G_OBJECT (new_style));
2048 if (!parsed_curlies)
2050 /* Skip over remainder, looking for nested {}'s
2054 result = G_TOKEN_RIGHT_CURLY;
2055 while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
2057 if (token == G_TOKEN_LEFT_CURLY)
2059 else if (token == G_TOKEN_RIGHT_CURLY)
2064 result = G_TOKEN_NONE;
2072 g_object_unref (G_OBJECT (*rc_style));
2073 *rc_style = new_style;
2080 gtk_rc_parse_state (GScanner *scanner,
2081 GtkStateType *state)
2086 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2087 g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
2089 /* we don't know where we got called from, so we reset the scope here.
2090 * if we bail out due to errors, we *don't* reset the scope, so the
2091 * error messaging code can make sense of our tokens.
2093 old_scope = g_scanner_set_scope (scanner, 0);
2095 token = g_scanner_get_next_token (scanner);
2096 if (token != G_TOKEN_LEFT_BRACE)
2097 return G_TOKEN_LEFT_BRACE;
2099 token = g_scanner_get_next_token (scanner);
2102 case GTK_RC_TOKEN_ACTIVE:
2103 *state = GTK_STATE_ACTIVE;
2105 case GTK_RC_TOKEN_INSENSITIVE:
2106 *state = GTK_STATE_INSENSITIVE;
2108 case GTK_RC_TOKEN_NORMAL:
2109 *state = GTK_STATE_NORMAL;
2111 case GTK_RC_TOKEN_PRELIGHT:
2112 *state = GTK_STATE_PRELIGHT;
2114 case GTK_RC_TOKEN_SELECTED:
2115 *state = GTK_STATE_SELECTED;
2118 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
2121 token = g_scanner_get_next_token (scanner);
2122 if (token != G_TOKEN_RIGHT_BRACE)
2123 return G_TOKEN_RIGHT_BRACE;
2125 g_scanner_set_scope (scanner, old_scope);
2127 return G_TOKEN_NONE;
2131 gtk_rc_parse_priority (GScanner *scanner,
2132 GtkPathPriorityType *priority)
2137 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2138 g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
2140 /* we don't know where we got called from, so we reset the scope here.
2141 * if we bail out due to errors, we *don't* reset the scope, so the
2142 * error messaging code can make sense of our tokens.
2144 old_scope = g_scanner_set_scope (scanner, 0);
2146 token = g_scanner_get_next_token (scanner);
2150 token = g_scanner_get_next_token (scanner);
2153 case GTK_RC_TOKEN_LOWEST:
2154 *priority = GTK_PATH_PRIO_LOWEST;
2156 case GTK_RC_TOKEN_GTK:
2157 *priority = GTK_PATH_PRIO_GTK;
2159 case GTK_RC_TOKEN_APPLICATION:
2160 *priority = GTK_PATH_PRIO_APPLICATION;
2162 case GTK_RC_TOKEN_RC:
2163 *priority = GTK_PATH_PRIO_RC;
2165 case GTK_RC_TOKEN_HIGHEST:
2166 *priority = GTK_PATH_PRIO_HIGHEST;
2169 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
2172 g_scanner_set_scope (scanner, old_scope);
2174 return G_TOKEN_NONE;
2178 gtk_rc_parse_color (GScanner *scanner,
2183 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2185 /* we don't need to set our own scop here, because
2186 * we don't need own symbols
2189 token = g_scanner_get_next_token (scanner);
2198 case G_TOKEN_LEFT_CURLY:
2199 token = g_scanner_get_next_token (scanner);
2200 if (token == G_TOKEN_INT)
2201 token_int = scanner->value.v_int;
2202 else if (token == G_TOKEN_FLOAT)
2203 token_int = scanner->value.v_float * 65535.0;
2205 return G_TOKEN_FLOAT;
2206 color->red = CLAMP (token_int, 0, 65535);
2208 token = g_scanner_get_next_token (scanner);
2209 if (token != G_TOKEN_COMMA)
2210 return G_TOKEN_COMMA;
2212 token = g_scanner_get_next_token (scanner);
2213 if (token == G_TOKEN_INT)
2214 token_int = scanner->value.v_int;
2215 else if (token == G_TOKEN_FLOAT)
2216 token_int = scanner->value.v_float * 65535.0;
2218 return G_TOKEN_FLOAT;
2219 color->green = CLAMP (token_int, 0, 65535);
2221 token = g_scanner_get_next_token (scanner);
2222 if (token != G_TOKEN_COMMA)
2223 return G_TOKEN_COMMA;
2225 token = g_scanner_get_next_token (scanner);
2226 if (token == G_TOKEN_INT)
2227 token_int = scanner->value.v_int;
2228 else if (token == G_TOKEN_FLOAT)
2229 token_int = scanner->value.v_float * 65535.0;
2231 return G_TOKEN_FLOAT;
2232 color->blue = CLAMP (token_int, 0, 65535);
2234 token = g_scanner_get_next_token (scanner);
2235 if (token != G_TOKEN_RIGHT_CURLY)
2236 return G_TOKEN_RIGHT_CURLY;
2237 return G_TOKEN_NONE;
2239 case G_TOKEN_STRING:
2240 if (scanner->value.v_string[0] != '#')
2241 return G_TOKEN_STRING;
2243 length = strlen (scanner->value.v_string) - 1;
2244 if (((length % 3) != 0) || (length > 12))
2245 return G_TOKEN_STRING;
2248 for (i = 0, j = 1; i < length; i++, j++)
2249 buf[i] = scanner->value.v_string[j];
2252 sscanf (buf, "%x", &temp);
2255 for (i = 0; i < length; i++, j++)
2256 buf[i] = scanner->value.v_string[j];
2259 sscanf (buf, "%x", &temp);
2260 color->green = temp;
2262 for (i = 0; i < length; i++, j++)
2263 buf[i] = scanner->value.v_string[j];
2266 sscanf (buf, "%x", &temp);
2272 color->green *= 4369;
2273 color->blue *= 4369;
2275 else if (length == 2)
2278 color->green *= 257;
2281 else if (length == 3)
2287 return G_TOKEN_NONE;
2290 return G_TOKEN_STRING;
2295 gtk_rc_parse_pixmap_path (GScanner *scanner)
2299 token = g_scanner_get_next_token (scanner);
2300 if (token != GTK_RC_TOKEN_PIXMAP_PATH)
2301 return GTK_RC_TOKEN_PIXMAP_PATH;
2303 token = g_scanner_get_next_token (scanner);
2304 if (token != G_TOKEN_STRING)
2305 return G_TOKEN_STRING;
2307 gtk_rc_parse_pixmap_path_string (scanner->value.v_string);
2309 return G_TOKEN_NONE;
2313 gtk_rc_parse_pixmap_path_string (gchar *pix_path)
2317 gint start_offset = 0;
2321 /* free the old one, or just add to the old one ? */
2322 for (path_num=0; pixmap_path[path_num]; path_num++)
2324 g_free (pixmap_path[path_num]);
2325 pixmap_path[path_num] = NULL;
2330 path_len = strlen (pix_path);
2332 buf = g_strdup (pix_path);
2334 for (end_offset = 0; end_offset <= path_len; end_offset++)
2336 if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2337 (end_offset == path_len))
2339 buf[end_offset] = '\0';
2340 pixmap_path[path_num] = g_strdup (buf + start_offset);
2342 pixmap_path[path_num] = NULL;
2343 start_offset = end_offset + 1;
2350 gtk_rc_parse_module_path (GScanner *scanner)
2354 token = g_scanner_get_next_token (scanner);
2355 if (token != GTK_RC_TOKEN_MODULE_PATH)
2356 return GTK_RC_TOKEN_MODULE_PATH;
2358 token = g_scanner_get_next_token (scanner);
2359 if (token != G_TOKEN_STRING)
2360 return G_TOKEN_STRING;
2362 gtk_rc_parse_module_path_string (scanner->value.v_string);
2364 return G_TOKEN_NONE;
2368 gtk_rc_parse_module_path_string (gchar *mod_path)
2372 gint start_offset = 0;
2376 /* free the old one, or just add to the old one ? */
2377 for (path_num=0; module_path[path_num]; path_num++)
2379 g_free (module_path[path_num]);
2380 module_path[path_num] = NULL;
2385 path_len = strlen (mod_path);
2387 buf = g_strdup (mod_path);
2389 for (end_offset = 0; end_offset <= path_len; end_offset++)
2391 if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2392 (end_offset == path_len))
2394 buf[end_offset] = '\0';
2395 module_path[path_num] = g_strdup (buf + start_offset);
2397 module_path[path_num] = NULL;
2398 start_offset = end_offset + 1;
2402 gtk_rc_append_default_module_path();
2406 gtk_rc_parse_path_pattern (GScanner *scanner)
2409 GtkPathType path_type;
2411 gboolean is_binding;
2412 GtkPathPriorityType priority = GTK_PATH_PRIO_RC;
2414 token = g_scanner_get_next_token (scanner);
2417 case GTK_RC_TOKEN_WIDGET:
2418 path_type = GTK_PATH_WIDGET;
2420 case GTK_RC_TOKEN_WIDGET_CLASS:
2421 path_type = GTK_PATH_WIDGET_CLASS;
2423 case GTK_RC_TOKEN_CLASS:
2424 path_type = GTK_PATH_CLASS;
2427 return GTK_RC_TOKEN_WIDGET_CLASS;
2430 token = g_scanner_get_next_token (scanner);
2431 if (token != G_TOKEN_STRING)
2432 return G_TOKEN_STRING;
2434 pattern = g_strdup (scanner->value.v_string);
2436 token = g_scanner_get_next_token (scanner);
2437 if (token == GTK_RC_TOKEN_STYLE)
2439 else if (token == GTK_RC_TOKEN_BINDING)
2442 if (g_scanner_peek_next_token (scanner) == ':')
2444 token = gtk_rc_parse_priority (scanner, &priority);
2445 if (token != G_TOKEN_NONE)
2455 return GTK_RC_TOKEN_STYLE;
2458 token = g_scanner_get_next_token (scanner);
2459 if (token != G_TOKEN_STRING)
2462 return G_TOKEN_STRING;
2467 GtkBindingSet *binding;
2469 binding = gtk_binding_set_find (scanner->value.v_string);
2473 return G_TOKEN_STRING;
2475 gtk_binding_set_add_path (binding, path_type, pattern, priority);
2479 GtkRcStyle *rc_style;
2482 rc_style = gtk_rc_style_find (scanner->value.v_string);
2487 return G_TOKEN_STRING;
2490 rc_set = g_new (GtkRcSet, 1);
2491 gtk_pattern_spec_init (&rc_set->pspec, pattern);
2492 rc_set->rc_style = rc_style;
2494 if (path_type == GTK_PATH_WIDGET)
2495 gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set);
2496 else if (path_type == GTK_PATH_WIDGET_CLASS)
2497 gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set);
2499 gtk_rc_sets_class = g_slist_prepend (gtk_rc_sets_class, rc_set);
2503 return G_TOKEN_NONE;
2507 typedef GdkPixmap * (*GtkImageLoader) (GdkWindow *window,
2508 GdkColormap *colormap,
2510 GdkColor *transparent_color,
2511 const gchar *filename);
2515 gtk_rc_set_image_loader(GtkImageLoader loader)
2517 image_loader = loader;
2521 gtk_rc_load_image (GdkColormap *colormap,
2522 GdkColor *transparent_color,
2523 const gchar *filename)
2525 if (strcmp (filename, "<parent>") == 0)
2526 return (GdkPixmap*) GDK_PARENT_RELATIVE;
2530 return image_loader(NULL, colormap, NULL,
2534 return gdk_pixmap_colormap_create_from_xpm (NULL, colormap, NULL,