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"
63 #include "gtkiconfactory.h"
65 typedef struct _GtkRcSet GtkRcSet;
66 typedef struct _GtkRcNode GtkRcNode;
67 typedef struct _GtkRcFile GtkRcFile;
79 gchar *canonical_name;
83 static guint gtk_rc_style_hash (const char *name);
84 static gint gtk_rc_style_compare (const char *a,
86 static guint gtk_rc_styles_hash (const GSList *rc_styles);
87 static gint gtk_rc_styles_compare (const GSList *a,
89 static GtkRcStyle* gtk_rc_style_find (const char *name);
90 static GSList * gtk_rc_styles_match (GSList *rc_styles,
94 gchar *path_reversed);
95 static GtkStyle * gtk_rc_style_to_style (GtkRcStyle *rc_style);
96 static GtkStyle* gtk_rc_init_style (GSList *rc_styles);
97 static void gtk_rc_parse_file (const gchar *filename,
99 static void gtk_rc_parse_any (const gchar *input_name,
101 const gchar *input_string);
102 static guint gtk_rc_parse_statement (GScanner *scanner);
103 static guint gtk_rc_parse_style (GScanner *scanner);
104 static guint gtk_rc_parse_bg (GScanner *scanner,
106 static guint gtk_rc_parse_fg (GScanner *scanner,
108 static guint gtk_rc_parse_text (GScanner *scanner,
110 static guint gtk_rc_parse_base (GScanner *scanner,
112 static guint gtk_rc_parse_xthickness (GScanner *scanner,
114 static guint gtk_rc_parse_ythickness (GScanner *scanner,
116 static guint gtk_rc_parse_bg_pixmap (GScanner *scanner,
117 GtkRcStyle *rc_style);
118 static guint gtk_rc_parse_font (GScanner *scanner,
119 GtkRcStyle *rc_style);
120 static guint gtk_rc_parse_fontset (GScanner *scanner,
121 GtkRcStyle *rc_style);
122 static guint gtk_rc_parse_font_name (GScanner *scanner,
123 GtkRcStyle *rc_style);
124 static guint gtk_rc_parse_engine (GScanner *scanner,
125 GtkRcStyle **rc_style);
126 static guint gtk_rc_parse_pixmap_path (GScanner *scanner);
127 static void gtk_rc_parse_pixmap_path_string (gchar *pix_path);
128 static guint gtk_rc_parse_module_path (GScanner *scanner);
129 static void gtk_rc_parse_module_path_string (gchar *mod_path);
130 static guint gtk_rc_parse_path_pattern (GScanner *scanner);
131 static guint gtk_rc_parse_stock (GScanner *scanner,
132 GtkRcStyle *rc_style,
133 GtkIconFactory *factory);
134 static void gtk_rc_clear_hash_node (gpointer key,
137 static void gtk_rc_clear_styles (void);
138 static void gtk_rc_append_default_module_path (void);
139 static void gtk_rc_add_initial_default_files (void);
141 static void gtk_rc_style_init (GtkRcStyle *style);
142 static void gtk_rc_style_class_init (GtkRcStyleClass *klass);
143 static void gtk_rc_style_finalize (GObject *object);
144 static void gtk_rc_style_real_merge (GtkRcStyle *dest,
146 static GtkRcStyle *gtk_rc_style_real_clone (GtkRcStyle *rc_style);
147 static GtkStyle * gtk_rc_style_real_create_style (GtkRcStyle *rc_style);
149 static gpointer parent_class = NULL;
151 static const GScannerConfig gtk_rc_scanner_config =
155 ) /* cset_skip_characters */,
160 ) /* cset_identifier_first */,
165 ) /* cset_identifier_nth */,
166 ( "#\n" ) /* cpair_comment_single */,
168 TRUE /* case_sensitive */,
170 TRUE /* skip_comment_multi */,
171 TRUE /* skip_comment_single */,
172 TRUE /* scan_comment_multi */,
173 TRUE /* scan_identifier */,
174 FALSE /* scan_identifier_1char */,
175 FALSE /* scan_identifier_NULL */,
176 TRUE /* scan_symbols */,
177 TRUE /* scan_binary */,
178 TRUE /* scan_octal */,
179 TRUE /* scan_float */,
181 TRUE /* scan_hex_dollar */,
182 TRUE /* scan_string_sq */,
183 TRUE /* scan_string_dq */,
184 TRUE /* numbers_2_int */,
185 FALSE /* int_2_float */,
186 FALSE /* identifier_2_string */,
187 TRUE /* char_2_token */,
188 TRUE /* symbol_2_token */,
189 FALSE /* scope_0_fallback */,
197 { "include", GTK_RC_TOKEN_INCLUDE },
198 { "NORMAL", GTK_RC_TOKEN_NORMAL },
199 { "ACTIVE", GTK_RC_TOKEN_ACTIVE },
200 { "PRELIGHT", GTK_RC_TOKEN_PRELIGHT },
201 { "SELECTED", GTK_RC_TOKEN_SELECTED },
202 { "INSENSITIVE", GTK_RC_TOKEN_INSENSITIVE },
203 { "fg", GTK_RC_TOKEN_FG },
204 { "bg", GTK_RC_TOKEN_BG },
205 { "text", GTK_RC_TOKEN_TEXT },
206 { "base", GTK_RC_TOKEN_BASE },
207 { "xthickness", GTK_RC_TOKEN_XTHICKNESS },
208 { "ythickness", GTK_RC_TOKEN_YTHICKNESS },
209 { "font", GTK_RC_TOKEN_FONT },
210 { "fontset", GTK_RC_TOKEN_FONTSET },
211 { "font_name", GTK_RC_TOKEN_FONT_NAME },
212 { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP },
213 { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH },
214 { "style", GTK_RC_TOKEN_STYLE },
215 { "binding", GTK_RC_TOKEN_BINDING },
216 { "bind", GTK_RC_TOKEN_BIND },
217 { "widget", GTK_RC_TOKEN_WIDGET },
218 { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS },
219 { "class", GTK_RC_TOKEN_CLASS },
220 { "lowest", GTK_RC_TOKEN_LOWEST },
221 { "gtk", GTK_RC_TOKEN_GTK },
222 { "application", GTK_RC_TOKEN_APPLICATION },
223 { "rc", GTK_RC_TOKEN_RC },
224 { "highest", GTK_RC_TOKEN_HIGHEST },
225 { "engine", GTK_RC_TOKEN_ENGINE },
226 { "module_path", GTK_RC_TOKEN_MODULE_PATH },
227 { "stock", GTK_RC_TOKEN_STOCK },
228 { "LTR", GTK_RC_TOKEN_LTR },
229 { "RTL", GTK_RC_TOKEN_RTL }
232 static const guint n_symbols = sizeof (symbols) / sizeof (symbols[0]);
234 static GHashTable *rc_style_ht = NULL;
235 static GHashTable *realized_style_ht = NULL;
236 static GSList *gtk_rc_sets_widget = NULL;
237 static GSList *gtk_rc_sets_widget_class = NULL;
238 static GSList *gtk_rc_sets_class = NULL;
240 #define GTK_RC_MAX_DEFAULT_FILES 128
241 static gchar *gtk_rc_default_files[GTK_RC_MAX_DEFAULT_FILES];
242 static gboolean gtk_rc_auto_parse = TRUE;
244 #define GTK_RC_MAX_PIXMAP_PATHS 128
245 static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
246 #define GTK_RC_MAX_MODULE_PATHS 128
247 static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
249 /* A stack of directories for RC files we are parsing currently.
250 * these are implicitely added to the end of PIXMAP_PATHS
252 GSList *rc_dir_stack = NULL;
254 /* The files we have parsed, to reread later if necessary */
255 GSList *rc_files = NULL;
257 static GtkImageLoader image_loader = NULL;
259 /* RC file handling */
265 gtk_win32_get_installation_directory (void)
267 static gboolean been_here = FALSE;
268 static gchar gtk_installation_dir[200];
272 DWORD nbytes = sizeof (gtk_installation_dir);
275 return gtk_installation_dir;
279 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\GNU\\GTk+", 0,
280 KEY_QUERY_VALUE, ®_key) != ERROR_SUCCESS
281 || RegQueryValueEx (reg_key, "InstallationDirectory", 0,
282 &type, gtk_installation_dir, &nbytes) != ERROR_SUCCESS
285 /* Uh oh. Use the old hard-coded %WinDir%\GTk+ value */
286 GetWindowsDirectory (win_dir, sizeof (win_dir));
287 sprintf (gtk_installation_dir, "%s\\gtk+", win_dir);
291 RegCloseKey (reg_key);
293 return gtk_installation_dir;
297 get_themes_directory (void)
299 static gchar themes_dir[200];
301 sprintf (themes_dir, "%s\\themes", gtk_win32_get_installation_directory ());
308 gtk_rc_get_theme_dir(void)
313 var = getenv("GTK_DATA_PREFIX");
315 path = g_strdup_printf("%s%s", var, "/share/themes");
317 path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/themes");
319 path = g_strdup (get_themes_directory ());
326 gtk_rc_get_module_dir(void)
331 var = getenv("GTK_EXE_PREFIX");
333 path = g_strdup_printf("%s%s", var, "/lib/gtk-2.0/" GTK_VERSION "/engines");
335 path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk-2.0/" GTK_VERSION "/engines");
337 path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
344 gtk_rc_append_default_module_path(void)
349 for (n = 0; module_path[n]; n++) ;
350 if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
354 var = getenv("GTK_EXE_PREFIX");
356 path = g_strdup_printf("%s%s", var, "/lib/gtk-2.0/" GTK_VERSION "/engines");
358 path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk-2.0/" GTK_VERSION "/engines");
360 path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
362 module_path[n++] = path;
364 var = g_get_home_dir ();
368 /* Don't duplicate the directory separator, causes trouble at
371 if (var[strlen (var) -1] != G_DIR_SEPARATOR)
372 sep = G_DIR_SEPARATOR_S;
375 /* This produces something like ~/.gtk-2.0/2.0/engines */
376 path = g_strdup_printf ("%s%s%s", var, sep,
377 ".gtk-2.0" G_DIR_SEPARATOR_S
378 GTK_VERSION G_DIR_SEPARATOR_S
380 module_path[n++] = path;
382 module_path[n] = NULL;
386 gtk_rc_add_initial_default_files (void)
388 static gint init = FALSE;
396 gtk_rc_default_files[0] = NULL;
399 var = g_getenv("GTK_RC_FILES");
402 files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
406 gtk_rc_add_default_file (files[i]);
414 str = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk-2.0" G_DIR_SEPARATOR_S "gtkrc");
416 str = g_strdup_printf ("%s\\gtkrc", gtk_win32_get_installation_directory ());
419 gtk_rc_add_default_file (str);
422 var = g_get_home_dir ();
426 if (var[strlen (var) -1] != G_DIR_SEPARATOR)
427 sep = G_DIR_SEPARATOR_S;
430 str = g_strdup_printf ("%s%s.gtkrc-2.0", var, sep);
431 gtk_rc_add_default_file (str);
438 gtk_rc_add_default_file (const gchar *file)
442 gtk_rc_add_initial_default_files ();
444 for (n = 0; gtk_rc_default_files[n]; n++) ;
445 if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
448 gtk_rc_default_files[n++] = g_strdup (file);
449 gtk_rc_default_files[n] = NULL;
453 gtk_rc_set_default_files (gchar **files)
457 gtk_rc_add_initial_default_files ();
460 while (gtk_rc_default_files[i])
462 g_free (gtk_rc_default_files[i]);
466 gtk_rc_default_files[0] = NULL;
467 gtk_rc_auto_parse = FALSE;
470 while (files[i] != NULL)
472 gtk_rc_add_default_file (files[i]);
478 gtk_rc_get_default_files (void)
480 gtk_rc_add_initial_default_files ();
482 return gtk_rc_default_files;
485 /* The following routine is based on _nl_normalize_codeset from
486 * the GNU C library. Contributed by
488 * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
489 * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
491 * Normalize codeset name. There is no standard for the codeset
492 * names. Normalization allows the user to use any of the common
496 _gtk_normalize_codeset (const char *codeset, int name_len)
504 for (cnt = 0; cnt < name_len; ++cnt)
505 if (isalnum (codeset[cnt]))
509 if (isalpha (codeset[cnt]))
513 retval = g_malloc ((only_digit ? 3 : 0) + len + 1);
517 strcpy (retval, "iso");
523 for (cnt = 0; cnt < name_len; ++cnt)
524 if (isalpha (codeset[cnt]))
525 *wp++ = isupper(codeset[cnt]) ? tolower (codeset[cnt]) : codeset[cnt];
526 else if (isdigit (codeset[cnt]))
527 *wp++ = codeset[cnt];
537 static gchar *locale_suffixes[3];
538 static gint n_locale_suffixes = 0;
542 static gboolean initted = FALSE;
551 locale = g_win32_getlocale ();
553 locale = setlocale (LC_CTYPE, NULL);
558 pixmap_path[0] = NULL;
559 module_path[0] = NULL;
560 gtk_rc_append_default_module_path();
562 gtk_rc_add_initial_default_files ();
564 if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
566 /* Determine locale-specific suffixes for RC files
568 * We normalize the charset into a standard form,
569 * which has all '-' and '_' characters removed,
572 gchar *normalized_locale;
574 p = strchr (locale, '@');
575 length = p ? (p -locale) : strlen (locale);
577 p = strchr (locale, '.');
580 gchar *tmp1 = g_strndup (locale, p - locale + 1);
581 gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
583 normalized_locale = g_strconcat (tmp1, tmp2, NULL);
587 locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
591 normalized_locale = g_strndup (locale, length);
593 p = strchr (normalized_locale, '_');
596 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
597 length = p - normalized_locale;
600 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
602 g_free (normalized_locale);
607 while (gtk_rc_default_files[i] != NULL)
609 /* Try to find a locale specific RC file corresponding to
610 * to parse before the default file.
612 for (j=n_locale_suffixes-1; j>=0; j--)
614 gchar *name = g_strconcat (gtk_rc_default_files[i],
622 gtk_rc_parse (gtk_rc_default_files[i]);
628 gtk_rc_parse_string (const gchar *rc_string)
630 g_return_if_fail (rc_string != NULL);
632 gtk_rc_parse_any ("-", -1, rc_string);
636 gtk_rc_parse_file (const gchar *filename, gboolean reload)
638 GtkRcFile *rc_file = NULL;
642 g_return_if_fail (filename != NULL);
647 rc_file = tmp_list->data;
648 if (!strcmp (rc_file->name, filename))
651 tmp_list = tmp_list->next;
656 rc_file = g_new (GtkRcFile, 1);
657 rc_file->name = g_strdup (filename);
658 rc_file->canonical_name = NULL;
660 rc_file->reload = reload;
662 rc_files = g_slist_append (rc_files, rc_file);
665 if (!rc_file->canonical_name)
667 /* Get the absolute pathname */
669 if (g_path_is_absolute (rc_file->name))
670 rc_file->canonical_name = rc_file->name;
676 cwd = g_get_current_dir ();
678 str = g_string_new (cwd);
680 g_string_append_c (str, G_DIR_SEPARATOR);
681 g_string_append (str, rc_file->name);
683 rc_file->canonical_name = str->str;
684 g_string_free (str, FALSE);
688 if (!lstat (rc_file->canonical_name, &statbuf))
693 rc_file->mtime = statbuf.st_mtime;
695 fd = open (rc_file->canonical_name, O_RDONLY);
699 /* Temporarily push directory name for this file on
700 * a stack of directory names while parsing it
703 g_slist_prepend (rc_dir_stack,
704 g_path_get_dirname (rc_file->canonical_name));
705 gtk_rc_parse_any (filename, fd, NULL);
707 tmp_list = rc_dir_stack;
708 rc_dir_stack = rc_dir_stack->next;
710 g_free (tmp_list->data);
711 g_slist_free_1 (tmp_list);
718 gtk_rc_parse (const gchar *filename)
720 g_return_if_fail (filename != NULL);
722 gtk_rc_parse_file (filename, TRUE);
725 /* Handling of RC styles */
728 gtk_rc_style_get_type (void)
730 static GType object_type = 0;
734 static const GTypeInfo object_info =
736 sizeof (GtkRcStyleClass),
737 (GBaseInitFunc) NULL,
738 (GBaseFinalizeFunc) NULL,
739 (GClassInitFunc) gtk_rc_style_class_init,
740 NULL, /* class_finalize */
741 NULL, /* class_data */
744 (GInstanceInitFunc) gtk_rc_style_init,
747 object_type = g_type_register_static (G_TYPE_OBJECT,
756 gtk_rc_style_init (GtkRcStyle *style)
761 for (i = 0; i < 5; i++)
763 static const GdkColor init_color = { 0, 0, 0, 0, };
765 style->bg_pixmap_name[i] = NULL;
766 style->color_flags[i] = 0;
767 style->fg[i] = init_color;
768 style->bg[i] = init_color;
769 style->text[i] = init_color;
770 style->base[i] = init_color;
772 style->xthickness = -1;
773 style->ythickness = -1;
774 style->rc_style_lists = NULL;
778 gtk_rc_style_class_init (GtkRcStyleClass *klass)
780 GObjectClass *object_class = G_OBJECT_CLASS (klass);
782 parent_class = g_type_class_peek_parent (klass);
784 object_class->finalize = gtk_rc_style_finalize;
787 klass->clone = gtk_rc_style_real_clone;
788 klass->merge = gtk_rc_style_real_merge;
789 klass->create_style = gtk_rc_style_real_create_style;
792 /* Like g_slist_remove, but remove all copies of data */
794 gtk_rc_slist_remove_all (GSList *list,
805 if (tmp->data == data)
811 prev->next = tmp->next;
813 g_slist_free_1 (tmp);
831 gtk_rc_style_finalize (GObject *object)
834 GSList *tmp_list1, *tmp_list2;
835 GtkRcStyle *rc_style;
837 rc_style = GTK_RC_STYLE (object);
840 g_free (rc_style->name);
841 if (rc_style->font_desc)
842 pango_font_description_free (rc_style->font_desc);
844 for (i=0 ; i < 5 ; i++)
845 if (rc_style->bg_pixmap_name[i])
846 g_free (rc_style->bg_pixmap_name[i]);
848 /* Now remove all references to this rc_style from
851 tmp_list1 = rc_style->rc_style_lists;
854 GSList *rc_styles = tmp_list1->data;
855 GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
856 gtk_style_unref (style);
858 /* Remove the list of styles from the other rc_styles
861 tmp_list2 = rc_styles;
864 GtkRcStyle *other_style = tmp_list2->data;
866 if (other_style != rc_style)
867 other_style->rc_style_lists =
868 gtk_rc_slist_remove_all (other_style->rc_style_lists, rc_styles);
870 tmp_list2 = tmp_list2->next;
873 /* And from the hash table itself
875 g_hash_table_remove (realized_style_ht, rc_styles);
876 g_slist_free (rc_styles);
878 tmp_list1 = tmp_list1->next;
881 g_slist_free (rc_style->rc_style_lists);
883 tmp_list1 = rc_style->icon_factories;
886 g_object_unref (G_OBJECT (tmp_list1->data));
888 tmp_list1 = tmp_list1->next;
891 g_slist_free (rc_style->icon_factories);
893 G_OBJECT_CLASS (parent_class)->finalize (object);
897 gtk_rc_style_new (void)
901 style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
908 * @orig: the style to copy
910 * Make a copy of the specified #GtkRcStyle. This function
911 * will correctly copy an rc style that is a member of a class
912 * derived from #GtkRcStyle.
914 * Return value: the resulting #GtkRcStyle
917 gtk_rc_style_copy (GtkRcStyle *orig)
921 g_return_val_if_fail (GTK_IS_RC_STYLE (orig), NULL);
923 style = GTK_RC_STYLE_GET_CLASS (orig)->clone (orig);
924 GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
930 gtk_rc_style_ref (GtkRcStyle *rc_style)
932 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
934 g_object_ref (G_OBJECT (rc_style));
938 gtk_rc_style_unref (GtkRcStyle *rc_style)
940 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
942 g_object_unref (G_OBJECT (rc_style));
946 gtk_rc_style_real_clone (GtkRcStyle *style)
948 return GTK_RC_STYLE (g_object_new (G_OBJECT_TYPE (style), NULL));
952 gtk_rc_style_real_merge (GtkRcStyle *dest,
957 for (i = 0; i < 5; i++)
959 if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
960 dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
962 if (!(dest->color_flags[i] & GTK_RC_FG) &&
963 src->color_flags[i] & GTK_RC_FG)
965 dest->fg[i] = src->fg[i];
966 dest->color_flags[i] |= GTK_RC_FG;
968 if (!(dest->color_flags[i] & GTK_RC_BG) &&
969 src->color_flags[i] & GTK_RC_BG)
971 dest->bg[i] = src->bg[i];
972 dest->color_flags[i] |= GTK_RC_BG;
974 if (!(dest->color_flags[i] & GTK_RC_TEXT) &&
975 src->color_flags[i] & GTK_RC_TEXT)
977 dest->text[i] = src->text[i];
978 dest->color_flags[i] |= GTK_RC_TEXT;
980 if (!(dest->color_flags[i] & GTK_RC_BASE) &&
981 src->color_flags[i] & GTK_RC_BASE)
983 dest->base[i] = src->base[i];
984 dest->color_flags[i] |= GTK_RC_BASE;
988 if (dest->xthickness < 0 && src->xthickness >= 0)
989 dest->xthickness = src->xthickness;
990 if (dest->ythickness < 0 && src->ythickness >= 0)
991 dest->ythickness = src->ythickness;
993 if (!dest->font_desc && src->font_desc)
994 dest->font_desc = pango_font_description_copy (src->font_desc);
998 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
1000 return gtk_style_new ();
1004 gtk_rc_clear_hash_node (gpointer key,
1008 gtk_rc_style_unref (data);
1012 gtk_rc_free_rc_sets (GSList *slist)
1018 rc_set = slist->data;
1019 gtk_pattern_spec_free_segs (&rc_set->pspec);
1022 slist = slist->next;
1027 gtk_rc_clear_styles (void)
1029 /* Clear out all old rc_styles */
1033 g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
1034 g_hash_table_destroy (rc_style_ht);
1038 gtk_rc_free_rc_sets (gtk_rc_sets_widget);
1039 g_slist_free (gtk_rc_sets_widget);
1040 gtk_rc_sets_widget = NULL;
1042 gtk_rc_free_rc_sets (gtk_rc_sets_widget_class);
1043 g_slist_free (gtk_rc_sets_widget_class);
1044 gtk_rc_sets_widget_class = NULL;
1046 gtk_rc_free_rc_sets (gtk_rc_sets_class);
1047 g_slist_free (gtk_rc_sets_class);
1048 gtk_rc_sets_class = NULL;
1052 gtk_rc_reparse_all (void)
1055 gboolean mtime_modified = FALSE;
1058 struct stat statbuf;
1060 /* Check through and see if any of the RC's have had their
1061 * mtime modified. If so, reparse everything.
1063 tmp_list = rc_files;
1066 rc_file = tmp_list->data;
1068 if (!lstat (rc_file->name, &statbuf) &&
1069 (statbuf.st_mtime > rc_file->mtime))
1071 mtime_modified = TRUE;
1075 tmp_list = tmp_list->next;
1080 gtk_rc_clear_styles();
1082 tmp_list = rc_files;
1085 rc_file = tmp_list->data;
1086 if (rc_file->reload)
1087 gtk_rc_parse_file (rc_file->name, FALSE);
1089 tmp_list = tmp_list->next;
1093 return mtime_modified;
1097 gtk_rc_styles_match (GSList *rc_styles,
1101 gchar *path_reversed)
1108 rc_set = sets->data;
1111 if (gtk_pattern_match (&rc_set->pspec, path_length, path, path_reversed))
1112 rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
1119 gtk_rc_get_style (GtkWidget *widget)
1121 GtkRcStyle *widget_rc_style;
1122 GSList *rc_styles = NULL;
1124 static guint rc_style_key_id = 0;
1126 /* We allow the specification of a single rc style to be bound
1127 * tightly to a widget, for application modifications
1129 if (!rc_style_key_id)
1130 rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1132 widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
1135 if (widget_rc_style)
1136 rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
1138 if (gtk_rc_sets_widget)
1140 gchar *path, *path_reversed;
1143 gtk_widget_path (widget, &path_length, &path, &path_reversed);
1144 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget, path_length, path, path_reversed);
1146 g_free (path_reversed);
1150 if (gtk_rc_sets_widget_class)
1152 gchar *path, *path_reversed;
1155 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1156 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget_class, path_length, path, path_reversed);
1158 g_free (path_reversed);
1161 if (gtk_rc_sets_class)
1165 type = GTK_OBJECT_TYPE (widget);
1168 gchar *path, *path_reversed;
1171 path = gtk_type_name (type);
1172 path_length = strlen (path);
1173 path_reversed = g_strdup (path);
1174 g_strreverse (path_reversed);
1176 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_class, path_length, path, path_reversed);
1177 g_free (path_reversed);
1179 type = gtk_type_parent (type);
1184 return gtk_rc_init_style (rc_styles);
1190 gtk_rc_add_rc_sets (GSList *slist,
1191 GtkRcStyle *rc_style,
1192 const char *pattern)
1194 GtkRcStyle *new_style;
1198 new_style = gtk_rc_style_new ();
1199 *new_style = *rc_style;
1200 new_style->name = g_strdup (rc_style->name);
1201 if (rc_style->font_desc)
1202 new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
1204 for (i = 0; i < 5; i++)
1205 new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1207 rc_set = g_new (GtkRcSet, 1);
1208 gtk_pattern_spec_init (&rc_set->pspec, pattern);
1209 rc_set->rc_style = rc_style;
1211 return g_slist_prepend (slist, rc_set);
1215 gtk_rc_add_widget_name_style (GtkRcStyle *rc_style,
1216 const gchar *pattern)
1218 g_return_if_fail (rc_style != NULL);
1219 g_return_if_fail (pattern != NULL);
1221 gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, rc_style, pattern);
1225 gtk_rc_add_widget_class_style (GtkRcStyle *rc_style,
1226 const gchar *pattern)
1228 g_return_if_fail (rc_style != NULL);
1229 g_return_if_fail (pattern != NULL);
1231 gtk_rc_sets_widget_class = gtk_rc_add_rc_sets (gtk_rc_sets_widget_class, rc_style, pattern);
1235 gtk_rc_add_class_style (GtkRcStyle *rc_style,
1236 const gchar *pattern)
1238 g_return_if_fail (rc_style != NULL);
1239 g_return_if_fail (pattern != NULL);
1241 gtk_rc_sets_class = gtk_rc_add_rc_sets (gtk_rc_sets_class, rc_style, pattern);
1245 gtk_rc_parse_any (const gchar *input_name,
1247 const gchar *input_string)
1253 scanner = g_scanner_new ((GScannerConfig *) >k_rc_scanner_config);
1257 g_assert (input_string == NULL);
1259 g_scanner_input_file (scanner, input_fd);
1263 g_assert (input_string != NULL);
1265 g_scanner_input_text (scanner, input_string, strlen (input_string));
1267 scanner->input_name = input_name;
1269 for (i = 0; i < n_symbols; i++)
1270 g_scanner_add_symbol (scanner, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1275 if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1279 guint expected_token;
1281 expected_token = gtk_rc_parse_statement (scanner);
1283 if (expected_token != G_TOKEN_NONE)
1290 if (scanner->scope_id == 0)
1292 /* if we are in scope 0, we know the symbol names
1293 * that are associated with certaintoken values.
1294 * so we look them up to make the error messages
1297 if (expected_token > GTK_RC_TOKEN_INVALID &&
1298 expected_token < GTK_RC_TOKEN_LAST)
1300 for (i = 0; i < n_symbols; i++)
1301 if (symbols[i].token == expected_token)
1302 msg = symbols[i].name;
1304 msg = g_strconcat ("e.g. `", msg, "'", NULL);
1306 if (scanner->token > GTK_RC_TOKEN_INVALID &&
1307 scanner->token < GTK_RC_TOKEN_LAST)
1309 symbol_name = "???";
1310 for (i = 0; i < n_symbols; i++)
1311 if (symbols[i].token == scanner->token)
1312 symbol_name = symbols[i].name;
1315 g_scanner_unexp_token (scanner,
1328 g_scanner_destroy (scanner);
1332 gtk_rc_styles_hash (const GSList *rc_styles)
1339 result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1340 rc_styles = rc_styles->next;
1347 gtk_rc_styles_compare (const GSList *a,
1352 if (a->data != b->data)
1362 gtk_rc_style_hash (const char *name)
1368 result += (result << 3) + *name++;
1374 gtk_rc_style_compare (const char *a,
1377 return (strcmp (a, b) == 0);
1381 gtk_rc_style_find (const char *name)
1384 return g_hash_table_lookup (rc_style_ht, (gpointer) name);
1390 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1394 style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
1396 style->rc_style = rc_style;
1398 gtk_rc_style_ref (rc_style);
1400 GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);
1405 /* Reuses or frees rc_styles */
1407 gtk_rc_init_style (GSList *rc_styles)
1409 GtkStyle *style = NULL;
1412 g_return_val_if_fail (rc_styles != NULL, NULL);
1414 if (!realized_style_ht)
1415 realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
1416 (GCompareFunc) gtk_rc_styles_compare);
1418 style = g_hash_table_lookup (realized_style_ht, rc_styles);
1422 GtkRcStyle *base_style = NULL;
1423 GtkRcStyle *proto_style;
1424 GtkRcStyleClass *proto_style_class;
1426 GType rc_style_type = GTK_TYPE_RC_STYLE;
1428 /* Find the first derived style in the list, and use that to
1429 * create the merged style. If we only have raw GtkRcStyles, use
1430 * the first style to create the merged style.
1432 base_style = rc_styles->data;
1433 tmp_styles = rc_styles;
1436 GtkRcStyle *rc_style = tmp_styles->data;
1438 if (G_OBJECT_TYPE (rc_style) != rc_style_type)
1440 base_style = rc_style;
1444 tmp_styles = tmp_styles->next;
1447 proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
1448 proto_style = proto_style_class->clone (base_style);
1450 tmp_styles = rc_styles;
1453 GtkRcStyle *rc_style = tmp_styles->data;
1456 proto_style_class->merge (proto_style, rc_style);
1458 /* Point from each rc_style to the list of styles */
1459 if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
1460 rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
1462 factories = g_slist_copy (rc_style->icon_factories);
1468 while (iter != NULL)
1470 g_object_ref (G_OBJECT (iter->data));
1471 iter = g_slist_next (iter);
1474 proto_style->icon_factories = g_slist_concat (proto_style->icon_factories,
1479 tmp_styles = tmp_styles->next;
1482 for (i = 0; i < 5; i++)
1483 if (proto_style->bg_pixmap_name[i] &&
1484 (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1486 g_free (proto_style->bg_pixmap_name[i]);
1487 proto_style->bg_pixmap_name[i] = NULL;
1490 style = gtk_rc_style_to_style (proto_style);
1491 gtk_rc_style_unref (proto_style);
1493 g_hash_table_insert (realized_style_ht, rc_styles, style);
1496 g_slist_free (rc_styles);
1501 /*********************
1502 * Parsing functions *
1503 *********************/
1506 gtk_rc_parse_statement (GScanner *scanner)
1510 token = g_scanner_peek_next_token (scanner);
1514 case GTK_RC_TOKEN_INCLUDE:
1515 token = g_scanner_get_next_token (scanner);
1516 if (token != GTK_RC_TOKEN_INCLUDE)
1517 return GTK_RC_TOKEN_INCLUDE;
1519 token = g_scanner_get_next_token (scanner);
1520 if (token != G_TOKEN_STRING)
1521 return G_TOKEN_STRING;
1523 gtk_rc_parse_file (scanner->value.v_string, FALSE);
1524 return G_TOKEN_NONE;
1526 case GTK_RC_TOKEN_STYLE:
1527 return gtk_rc_parse_style (scanner);
1529 case GTK_RC_TOKEN_BINDING:
1530 return gtk_binding_parse_binding (scanner);
1532 case GTK_RC_TOKEN_PIXMAP_PATH:
1533 return gtk_rc_parse_pixmap_path (scanner);
1535 case GTK_RC_TOKEN_WIDGET:
1536 return gtk_rc_parse_path_pattern (scanner);
1538 case GTK_RC_TOKEN_WIDGET_CLASS:
1539 return gtk_rc_parse_path_pattern (scanner);
1541 case GTK_RC_TOKEN_CLASS:
1542 return gtk_rc_parse_path_pattern (scanner);
1544 case GTK_RC_TOKEN_MODULE_PATH:
1545 return gtk_rc_parse_module_path (scanner);
1548 g_scanner_get_next_token (scanner);
1549 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
1554 gtk_rc_parse_style (GScanner *scanner)
1556 GtkRcStyle *rc_style;
1557 GtkRcStyle *parent_style;
1561 GtkIconFactory *our_factory = NULL;
1563 token = g_scanner_get_next_token (scanner);
1564 if (token != GTK_RC_TOKEN_STYLE)
1565 return GTK_RC_TOKEN_STYLE;
1567 token = g_scanner_get_next_token (scanner);
1568 if (token != G_TOKEN_STRING)
1569 return G_TOKEN_STRING;
1572 rc_style = gtk_rc_style_find (scanner->value.v_string);
1574 /* If there's a list, its first member is always the factory belonging
1577 if (rc_style && rc_style->icon_factories)
1578 our_factory = rc_style->icon_factories->data;
1583 rc_style = gtk_rc_style_new ();
1584 rc_style->name = g_strdup (scanner->value.v_string);
1586 for (i = 0; i < 5; i++)
1587 rc_style->bg_pixmap_name[i] = NULL;
1589 for (i = 0; i < 5; i++)
1590 rc_style->color_flags[i] = 0;
1593 token = g_scanner_peek_next_token (scanner);
1594 if (token == G_TOKEN_EQUAL_SIGN)
1596 token = g_scanner_get_next_token (scanner);
1598 token = g_scanner_get_next_token (scanner);
1599 if (token != G_TOKEN_STRING)
1604 return G_TOKEN_STRING;
1607 parent_style = gtk_rc_style_find (scanner->value.v_string);
1612 for (i = 0; i < 5; i++)
1614 rc_style->color_flags[i] = parent_style->color_flags[i];
1615 rc_style->fg[i] = parent_style->fg[i];
1616 rc_style->bg[i] = parent_style->bg[i];
1617 rc_style->text[i] = parent_style->text[i];
1618 rc_style->base[i] = parent_style->base[i];
1621 rc_style->xthickness = parent_style->xthickness;
1622 rc_style->ythickness = parent_style->ythickness;
1624 if (parent_style->font_desc)
1626 if (rc_style->font_desc)
1627 pango_font_description_free (rc_style->font_desc);
1628 rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
1631 for (i = 0; i < 5; i++)
1633 if (rc_style->bg_pixmap_name[i])
1634 g_free (rc_style->bg_pixmap_name[i]);
1635 rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
1638 /* Append parent's factories, adding a ref to them */
1639 if (parent_style->icon_factories != NULL)
1641 /* Add a factory for ourselves if we have none,
1642 * in case we end up defining more stock icons.
1643 * I see no real way around this; we need to maintain
1644 * the invariant that the first factory in the list
1645 * is always our_factory, the one belonging to us,
1646 * and if we put parent factories in the list we can't
1647 * do that if the style is reopened.
1649 if (our_factory == NULL)
1651 our_factory = gtk_icon_factory_new ();
1652 rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
1656 rc_style->icon_factories = g_slist_concat (rc_style->icon_factories,
1657 g_slist_copy (parent_style->icon_factories));
1659 factories = parent_style->icon_factories;
1660 while (factories != NULL)
1662 g_object_ref (G_OBJECT (factories->data));
1663 factories = factories->next;
1669 token = g_scanner_get_next_token (scanner);
1670 if (token != G_TOKEN_LEFT_CURLY)
1675 return G_TOKEN_LEFT_CURLY;
1678 token = g_scanner_peek_next_token (scanner);
1679 while (token != G_TOKEN_RIGHT_CURLY)
1683 case GTK_RC_TOKEN_BG:
1684 token = gtk_rc_parse_bg (scanner, rc_style);
1686 case GTK_RC_TOKEN_FG:
1687 token = gtk_rc_parse_fg (scanner, rc_style);
1689 case GTK_RC_TOKEN_TEXT:
1690 token = gtk_rc_parse_text (scanner, rc_style);
1692 case GTK_RC_TOKEN_BASE:
1693 token = gtk_rc_parse_base (scanner, rc_style);
1695 case GTK_RC_TOKEN_XTHICKNESS:
1696 token = gtk_rc_parse_xthickness (scanner, rc_style);
1698 case GTK_RC_TOKEN_YTHICKNESS:
1699 token = gtk_rc_parse_ythickness (scanner, rc_style);
1701 case GTK_RC_TOKEN_BG_PIXMAP:
1702 token = gtk_rc_parse_bg_pixmap (scanner, rc_style);
1704 case GTK_RC_TOKEN_FONT:
1705 token = gtk_rc_parse_font (scanner, rc_style);
1707 case GTK_RC_TOKEN_FONTSET:
1708 token = gtk_rc_parse_fontset (scanner, rc_style);
1710 case GTK_RC_TOKEN_FONT_NAME:
1711 token = gtk_rc_parse_font_name (scanner, rc_style);
1713 case GTK_RC_TOKEN_ENGINE:
1714 token = gtk_rc_parse_engine (scanner, &rc_style);
1716 case GTK_RC_TOKEN_STOCK:
1717 if (our_factory == NULL)
1719 our_factory = gtk_icon_factory_new ();
1720 rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
1723 token = gtk_rc_parse_stock (scanner, rc_style, our_factory);
1726 g_scanner_get_next_token (scanner);
1727 token = G_TOKEN_RIGHT_CURLY;
1731 if (token != G_TOKEN_NONE)
1735 if (rc_style->font_desc)
1736 pango_font_description_free (rc_style->font_desc);
1738 for (i = 0; i < 5; i++)
1739 if (rc_style->bg_pixmap_name[i])
1740 g_free (rc_style->bg_pixmap_name[i]);
1745 token = g_scanner_peek_next_token (scanner);
1748 token = g_scanner_get_next_token (scanner);
1749 if (token != G_TOKEN_RIGHT_CURLY)
1753 if (rc_style->font_desc)
1754 pango_font_description_free (rc_style->font_desc);
1756 for (i = 0; i < 5; i++)
1757 if (rc_style->bg_pixmap_name[i])
1758 g_free (rc_style->bg_pixmap_name[i]);
1762 return G_TOKEN_RIGHT_CURLY;
1768 rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
1769 (GCompareFunc) gtk_rc_style_compare);
1771 g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
1774 return G_TOKEN_NONE;
1778 gtk_rc_parse_bg (GScanner *scanner,
1784 token = g_scanner_get_next_token (scanner);
1785 if (token != GTK_RC_TOKEN_BG)
1786 return GTK_RC_TOKEN_BG;
1788 token = gtk_rc_parse_state (scanner, &state);
1789 if (token != G_TOKEN_NONE)
1792 token = g_scanner_get_next_token (scanner);
1793 if (token != G_TOKEN_EQUAL_SIGN)
1794 return G_TOKEN_EQUAL_SIGN;
1796 style->color_flags[state] |= GTK_RC_BG;
1797 return gtk_rc_parse_color (scanner, &style->bg[state]);
1801 gtk_rc_parse_fg (GScanner *scanner,
1807 token = g_scanner_get_next_token (scanner);
1808 if (token != GTK_RC_TOKEN_FG)
1809 return GTK_RC_TOKEN_FG;
1811 token = gtk_rc_parse_state (scanner, &state);
1812 if (token != G_TOKEN_NONE)
1815 token = g_scanner_get_next_token (scanner);
1816 if (token != G_TOKEN_EQUAL_SIGN)
1817 return G_TOKEN_EQUAL_SIGN;
1819 style->color_flags[state] |= GTK_RC_FG;
1820 return gtk_rc_parse_color (scanner, &style->fg[state]);
1824 gtk_rc_parse_text (GScanner *scanner,
1830 token = g_scanner_get_next_token (scanner);
1831 if (token != GTK_RC_TOKEN_TEXT)
1832 return GTK_RC_TOKEN_TEXT;
1834 token = gtk_rc_parse_state (scanner, &state);
1835 if (token != G_TOKEN_NONE)
1838 token = g_scanner_get_next_token (scanner);
1839 if (token != G_TOKEN_EQUAL_SIGN)
1840 return G_TOKEN_EQUAL_SIGN;
1842 style->color_flags[state] |= GTK_RC_TEXT;
1843 return gtk_rc_parse_color (scanner, &style->text[state]);
1847 gtk_rc_parse_base (GScanner *scanner,
1853 token = g_scanner_get_next_token (scanner);
1854 if (token != GTK_RC_TOKEN_BASE)
1855 return GTK_RC_TOKEN_BASE;
1857 token = gtk_rc_parse_state (scanner, &state);
1858 if (token != G_TOKEN_NONE)
1861 token = g_scanner_get_next_token (scanner);
1862 if (token != G_TOKEN_EQUAL_SIGN)
1863 return G_TOKEN_EQUAL_SIGN;
1865 style->color_flags[state] |= GTK_RC_BASE;
1866 return gtk_rc_parse_color (scanner, &style->base[state]);
1870 gtk_rc_parse_xthickness (GScanner *scanner,
1873 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
1874 return GTK_RC_TOKEN_XTHICKNESS;
1876 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
1877 return G_TOKEN_EQUAL_SIGN;
1879 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
1882 style->xthickness = scanner->value.v_int;
1884 return G_TOKEN_NONE;
1888 gtk_rc_parse_ythickness (GScanner *scanner,
1891 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
1892 return GTK_RC_TOKEN_YTHICKNESS;
1894 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
1895 return G_TOKEN_EQUAL_SIGN;
1897 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
1900 style->ythickness = scanner->value.v_int;
1902 return G_TOKEN_NONE;
1906 gtk_rc_parse_bg_pixmap (GScanner *scanner,
1907 GtkRcStyle *rc_style)
1913 token = g_scanner_get_next_token (scanner);
1914 if (token != GTK_RC_TOKEN_BG_PIXMAP)
1915 return GTK_RC_TOKEN_BG_PIXMAP;
1917 token = gtk_rc_parse_state (scanner, &state);
1918 if (token != G_TOKEN_NONE)
1921 token = g_scanner_get_next_token (scanner);
1922 if (token != G_TOKEN_EQUAL_SIGN)
1923 return G_TOKEN_EQUAL_SIGN;
1925 token = g_scanner_get_next_token (scanner);
1926 if (token != G_TOKEN_STRING)
1927 return G_TOKEN_STRING;
1929 if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
1930 (strcmp (scanner->value.v_string, "<none>") == 0))
1931 pixmap_file = g_strdup (scanner->value.v_string);
1933 pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
1937 if (rc_style->bg_pixmap_name[state])
1938 g_free (rc_style->bg_pixmap_name[state]);
1939 rc_style->bg_pixmap_name[state] = pixmap_file;
1942 return G_TOKEN_NONE;
1946 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
1951 buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", dir, pixmap_file);
1953 fd = open (buf, O_RDONLY);
1966 gtk_rc_find_pixmap_in_path (GScanner *scanner,
1967 const gchar *pixmap_file)
1973 for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
1975 filename = gtk_rc_check_pixmap_dir (pixmap_path[i], pixmap_file);
1980 tmp_list = rc_dir_stack;
1983 filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
1987 tmp_list = tmp_list->next;
1991 g_warning (_("Unable to locate image file in pixmap_path: \"%s\" line %d"),
1992 pixmap_file, scanner->line);
1994 g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
2001 gtk_rc_find_module_in_path (const gchar *module_file)
2007 for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
2009 buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
2010 module_path[i], module_file);
2012 fd = open (buf, O_RDONLY);
2026 gtk_rc_parse_font (GScanner *scanner,
2027 GtkRcStyle *rc_style)
2031 token = g_scanner_get_next_token (scanner);
2032 if (token != GTK_RC_TOKEN_FONT)
2033 return GTK_RC_TOKEN_FONT;
2035 token = g_scanner_get_next_token (scanner);
2036 if (token != G_TOKEN_EQUAL_SIGN)
2037 return G_TOKEN_EQUAL_SIGN;
2039 token = g_scanner_get_next_token (scanner);
2040 if (token != G_TOKEN_STRING)
2041 return G_TOKEN_STRING;
2043 /* Ignore, do nothing */
2045 return G_TOKEN_NONE;
2049 gtk_rc_parse_fontset (GScanner *scanner,
2050 GtkRcStyle *rc_style)
2054 token = g_scanner_get_next_token (scanner);
2055 if (token != GTK_RC_TOKEN_FONTSET)
2056 return GTK_RC_TOKEN_FONTSET;
2058 token = g_scanner_get_next_token (scanner);
2059 if (token != G_TOKEN_EQUAL_SIGN)
2060 return G_TOKEN_EQUAL_SIGN;
2062 token = g_scanner_get_next_token (scanner);
2063 if (token != G_TOKEN_STRING)
2064 return G_TOKEN_STRING;
2066 /* Do nothing - silently ignore */
2068 return G_TOKEN_NONE;
2072 gtk_rc_parse_font_name (GScanner *scanner,
2073 GtkRcStyle *rc_style)
2077 token = g_scanner_get_next_token (scanner);
2078 if (token != GTK_RC_TOKEN_FONT_NAME)
2079 return GTK_RC_TOKEN_FONT;
2081 token = g_scanner_get_next_token (scanner);
2082 if (token != G_TOKEN_EQUAL_SIGN)
2083 return G_TOKEN_EQUAL_SIGN;
2085 token = g_scanner_get_next_token (scanner);
2086 if (token != G_TOKEN_STRING)
2087 return G_TOKEN_STRING;
2089 rc_style->font_desc = pango_font_description_from_string (scanner->value.v_string);
2091 return G_TOKEN_NONE;
2095 gtk_rc_parse_engine (GScanner *scanner,
2096 GtkRcStyle **rc_style)
2099 GtkThemeEngine *engine;
2100 guint result = G_TOKEN_NONE;
2101 GtkRcStyle *new_style = NULL;
2102 gboolean parsed_curlies = FALSE;
2104 token = g_scanner_get_next_token (scanner);
2105 if (token != GTK_RC_TOKEN_ENGINE)
2106 return GTK_RC_TOKEN_ENGINE;
2108 token = g_scanner_get_next_token (scanner);
2109 if (token != G_TOKEN_STRING)
2110 return G_TOKEN_STRING;
2112 engine = gtk_theme_engine_get (scanner->value.v_string);
2114 token = g_scanner_get_next_token (scanner);
2115 if (token != G_TOKEN_LEFT_CURLY)
2116 return G_TOKEN_LEFT_CURLY;
2120 GtkRcStyleClass *new_class;
2122 new_style = gtk_theme_engine_create_rc_style (engine);
2123 gtk_theme_engine_unref (engine);
2125 new_class = GTK_RC_STYLE_GET_CLASS (new_style);
2127 new_class->merge (new_style, *rc_style);
2128 if ((*rc_style)->name)
2129 new_style->name = g_strdup ((*rc_style)->name);
2131 if (new_class->parse)
2133 parsed_curlies = TRUE;
2134 result = new_class->parse (new_style, scanner);
2136 if (result != G_TOKEN_NONE)
2138 g_object_unref (G_OBJECT (new_style));
2144 if (!parsed_curlies)
2146 /* Skip over remainder, looking for nested {}'s
2150 result = G_TOKEN_RIGHT_CURLY;
2151 while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
2153 if (token == G_TOKEN_LEFT_CURLY)
2155 else if (token == G_TOKEN_RIGHT_CURLY)
2160 result = G_TOKEN_NONE;
2168 g_object_unref (G_OBJECT (*rc_style));
2169 *rc_style = new_style;
2176 gtk_rc_parse_state (GScanner *scanner,
2177 GtkStateType *state)
2182 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2183 g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
2185 /* we don't know where we got called from, so we reset the scope here.
2186 * if we bail out due to errors, we *don't* reset the scope, so the
2187 * error messaging code can make sense of our tokens.
2189 old_scope = g_scanner_set_scope (scanner, 0);
2191 token = g_scanner_get_next_token (scanner);
2192 if (token != G_TOKEN_LEFT_BRACE)
2193 return G_TOKEN_LEFT_BRACE;
2195 token = g_scanner_get_next_token (scanner);
2198 case GTK_RC_TOKEN_ACTIVE:
2199 *state = GTK_STATE_ACTIVE;
2201 case GTK_RC_TOKEN_INSENSITIVE:
2202 *state = GTK_STATE_INSENSITIVE;
2204 case GTK_RC_TOKEN_NORMAL:
2205 *state = GTK_STATE_NORMAL;
2207 case GTK_RC_TOKEN_PRELIGHT:
2208 *state = GTK_STATE_PRELIGHT;
2210 case GTK_RC_TOKEN_SELECTED:
2211 *state = GTK_STATE_SELECTED;
2214 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
2217 token = g_scanner_get_next_token (scanner);
2218 if (token != G_TOKEN_RIGHT_BRACE)
2219 return G_TOKEN_RIGHT_BRACE;
2221 g_scanner_set_scope (scanner, old_scope);
2223 return G_TOKEN_NONE;
2227 gtk_rc_parse_priority (GScanner *scanner,
2228 GtkPathPriorityType *priority)
2233 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2234 g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
2236 /* we don't know where we got called from, so we reset the scope here.
2237 * if we bail out due to errors, we *don't* reset the scope, so the
2238 * error messaging code can make sense of our tokens.
2240 old_scope = g_scanner_set_scope (scanner, 0);
2242 token = g_scanner_get_next_token (scanner);
2246 token = g_scanner_get_next_token (scanner);
2249 case GTK_RC_TOKEN_LOWEST:
2250 *priority = GTK_PATH_PRIO_LOWEST;
2252 case GTK_RC_TOKEN_GTK:
2253 *priority = GTK_PATH_PRIO_GTK;
2255 case GTK_RC_TOKEN_APPLICATION:
2256 *priority = GTK_PATH_PRIO_APPLICATION;
2258 case GTK_RC_TOKEN_RC:
2259 *priority = GTK_PATH_PRIO_RC;
2261 case GTK_RC_TOKEN_HIGHEST:
2262 *priority = GTK_PATH_PRIO_HIGHEST;
2265 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
2268 g_scanner_set_scope (scanner, old_scope);
2270 return G_TOKEN_NONE;
2274 gtk_rc_parse_color (GScanner *scanner,
2279 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2281 /* we don't need to set our own scop here, because
2282 * we don't need own symbols
2285 token = g_scanner_get_next_token (scanner);
2294 case G_TOKEN_LEFT_CURLY:
2295 token = g_scanner_get_next_token (scanner);
2296 if (token == G_TOKEN_INT)
2297 token_int = scanner->value.v_int;
2298 else if (token == G_TOKEN_FLOAT)
2299 token_int = scanner->value.v_float * 65535.0;
2301 return G_TOKEN_FLOAT;
2302 color->red = CLAMP (token_int, 0, 65535);
2304 token = g_scanner_get_next_token (scanner);
2305 if (token != G_TOKEN_COMMA)
2306 return G_TOKEN_COMMA;
2308 token = g_scanner_get_next_token (scanner);
2309 if (token == G_TOKEN_INT)
2310 token_int = scanner->value.v_int;
2311 else if (token == G_TOKEN_FLOAT)
2312 token_int = scanner->value.v_float * 65535.0;
2314 return G_TOKEN_FLOAT;
2315 color->green = CLAMP (token_int, 0, 65535);
2317 token = g_scanner_get_next_token (scanner);
2318 if (token != G_TOKEN_COMMA)
2319 return G_TOKEN_COMMA;
2321 token = g_scanner_get_next_token (scanner);
2322 if (token == G_TOKEN_INT)
2323 token_int = scanner->value.v_int;
2324 else if (token == G_TOKEN_FLOAT)
2325 token_int = scanner->value.v_float * 65535.0;
2327 return G_TOKEN_FLOAT;
2328 color->blue = CLAMP (token_int, 0, 65535);
2330 token = g_scanner_get_next_token (scanner);
2331 if (token != G_TOKEN_RIGHT_CURLY)
2332 return G_TOKEN_RIGHT_CURLY;
2333 return G_TOKEN_NONE;
2335 case G_TOKEN_STRING:
2336 if (scanner->value.v_string[0] != '#')
2337 return G_TOKEN_STRING;
2339 length = strlen (scanner->value.v_string) - 1;
2340 if (((length % 3) != 0) || (length > 12))
2341 return G_TOKEN_STRING;
2344 for (i = 0, j = 1; i < length; i++, j++)
2345 buf[i] = scanner->value.v_string[j];
2348 sscanf (buf, "%x", &temp);
2351 for (i = 0; i < length; i++, j++)
2352 buf[i] = scanner->value.v_string[j];
2355 sscanf (buf, "%x", &temp);
2356 color->green = temp;
2358 for (i = 0; i < length; i++, j++)
2359 buf[i] = scanner->value.v_string[j];
2362 sscanf (buf, "%x", &temp);
2368 color->green *= 4369;
2369 color->blue *= 4369;
2371 else if (length == 2)
2374 color->green *= 257;
2377 else if (length == 3)
2383 return G_TOKEN_NONE;
2386 return G_TOKEN_STRING;
2391 gtk_rc_parse_pixmap_path (GScanner *scanner)
2395 token = g_scanner_get_next_token (scanner);
2396 if (token != GTK_RC_TOKEN_PIXMAP_PATH)
2397 return GTK_RC_TOKEN_PIXMAP_PATH;
2399 token = g_scanner_get_next_token (scanner);
2400 if (token != G_TOKEN_STRING)
2401 return G_TOKEN_STRING;
2403 gtk_rc_parse_pixmap_path_string (scanner->value.v_string);
2405 return G_TOKEN_NONE;
2409 gtk_rc_parse_pixmap_path_string (gchar *pix_path)
2413 gint start_offset = 0;
2417 /* free the old one, or just add to the old one ? */
2418 for (path_num=0; pixmap_path[path_num]; path_num++)
2420 g_free (pixmap_path[path_num]);
2421 pixmap_path[path_num] = NULL;
2426 path_len = strlen (pix_path);
2428 buf = g_strdup (pix_path);
2430 for (end_offset = 0; end_offset <= path_len; end_offset++)
2432 if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2433 (end_offset == path_len))
2435 buf[end_offset] = '\0';
2436 pixmap_path[path_num] = g_strdup (buf + start_offset);
2438 pixmap_path[path_num] = NULL;
2439 start_offset = end_offset + 1;
2446 gtk_rc_parse_module_path (GScanner *scanner)
2450 token = g_scanner_get_next_token (scanner);
2451 if (token != GTK_RC_TOKEN_MODULE_PATH)
2452 return GTK_RC_TOKEN_MODULE_PATH;
2454 token = g_scanner_get_next_token (scanner);
2455 if (token != G_TOKEN_STRING)
2456 return G_TOKEN_STRING;
2458 gtk_rc_parse_module_path_string (scanner->value.v_string);
2460 return G_TOKEN_NONE;
2464 gtk_rc_parse_module_path_string (gchar *mod_path)
2468 gint start_offset = 0;
2472 /* free the old one, or just add to the old one ? */
2473 for (path_num=0; module_path[path_num]; path_num++)
2475 g_free (module_path[path_num]);
2476 module_path[path_num] = NULL;
2481 path_len = strlen (mod_path);
2483 buf = g_strdup (mod_path);
2485 for (end_offset = 0; end_offset <= path_len; end_offset++)
2487 if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2488 (end_offset == path_len))
2490 buf[end_offset] = '\0';
2491 module_path[path_num] = g_strdup (buf + start_offset);
2493 module_path[path_num] = NULL;
2494 start_offset = end_offset + 1;
2498 gtk_rc_append_default_module_path();
2502 gtk_rc_parse_path_pattern (GScanner *scanner)
2505 GtkPathType path_type;
2507 gboolean is_binding;
2508 GtkPathPriorityType priority = GTK_PATH_PRIO_RC;
2510 token = g_scanner_get_next_token (scanner);
2513 case GTK_RC_TOKEN_WIDGET:
2514 path_type = GTK_PATH_WIDGET;
2516 case GTK_RC_TOKEN_WIDGET_CLASS:
2517 path_type = GTK_PATH_WIDGET_CLASS;
2519 case GTK_RC_TOKEN_CLASS:
2520 path_type = GTK_PATH_CLASS;
2523 return GTK_RC_TOKEN_WIDGET_CLASS;
2526 token = g_scanner_get_next_token (scanner);
2527 if (token != G_TOKEN_STRING)
2528 return G_TOKEN_STRING;
2530 pattern = g_strdup (scanner->value.v_string);
2532 token = g_scanner_get_next_token (scanner);
2533 if (token == GTK_RC_TOKEN_STYLE)
2535 else if (token == GTK_RC_TOKEN_BINDING)
2538 if (g_scanner_peek_next_token (scanner) == ':')
2540 token = gtk_rc_parse_priority (scanner, &priority);
2541 if (token != G_TOKEN_NONE)
2551 return GTK_RC_TOKEN_STYLE;
2554 token = g_scanner_get_next_token (scanner);
2555 if (token != G_TOKEN_STRING)
2558 return G_TOKEN_STRING;
2563 GtkBindingSet *binding;
2565 binding = gtk_binding_set_find (scanner->value.v_string);
2569 return G_TOKEN_STRING;
2571 gtk_binding_set_add_path (binding, path_type, pattern, priority);
2575 GtkRcStyle *rc_style;
2578 rc_style = gtk_rc_style_find (scanner->value.v_string);
2583 return G_TOKEN_STRING;
2586 rc_set = g_new (GtkRcSet, 1);
2587 gtk_pattern_spec_init (&rc_set->pspec, pattern);
2588 rc_set->rc_style = rc_style;
2590 if (path_type == GTK_PATH_WIDGET)
2591 gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set);
2592 else if (path_type == GTK_PATH_WIDGET_CLASS)
2593 gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set);
2595 gtk_rc_sets_class = g_slist_prepend (gtk_rc_sets_class, rc_set);
2599 return G_TOKEN_NONE;
2603 gtk_rc_parse_stock_id (GScanner *scanner,
2608 token = g_scanner_get_next_token (scanner);
2609 if (token != G_TOKEN_LEFT_BRACE)
2610 return G_TOKEN_LEFT_BRACE;
2612 token = g_scanner_get_next_token (scanner);
2614 if (token != G_TOKEN_STRING)
2615 return G_TOKEN_STRING;
2617 *stock_id = g_strdup (scanner->value.v_string);
2619 token = g_scanner_get_next_token (scanner);
2620 if (token != G_TOKEN_RIGHT_BRACE)
2623 return G_TOKEN_RIGHT_BRACE;
2626 return G_TOKEN_NONE;
2630 cleanup_source (GtkIconSource *source)
2632 g_free (source->filename);
2633 g_free (source->size);
2637 gtk_rc_parse_icon_source (GScanner *scanner,
2638 GtkIconSet *icon_set)
2641 GtkIconSource source = { NULL, NULL,
2645 token = g_scanner_get_next_token (scanner);
2646 if (token != G_TOKEN_LEFT_CURLY)
2647 return G_TOKEN_LEFT_CURLY;
2649 token = g_scanner_get_next_token (scanner);
2651 if (token != G_TOKEN_STRING)
2652 return G_TOKEN_STRING;
2654 source.filename = g_strdup (scanner->value.v_string);
2656 token = g_scanner_get_next_token (scanner);
2658 if (token == G_TOKEN_RIGHT_CURLY)
2660 gtk_icon_set_add_source (icon_set, &source);
2661 cleanup_source (&source);
2662 return G_TOKEN_NONE;
2664 else if (token != G_TOKEN_COMMA)
2666 cleanup_source (&source);
2667 return G_TOKEN_COMMA;
2670 /* Get the direction */
2672 token = g_scanner_get_next_token (scanner);
2676 case GTK_RC_TOKEN_RTL:
2677 source.any_direction = FALSE;
2678 source.direction = GTK_TEXT_DIR_RTL;
2681 case GTK_RC_TOKEN_LTR:
2682 source.any_direction = FALSE;
2683 source.direction = GTK_TEXT_DIR_LTR;
2690 cleanup_source (&source);
2691 return GTK_RC_TOKEN_RTL;
2695 token = g_scanner_get_next_token (scanner);
2697 if (token == G_TOKEN_RIGHT_CURLY)
2699 gtk_icon_set_add_source (icon_set, &source);
2700 cleanup_source (&source);
2701 return G_TOKEN_NONE;
2703 else if (token != G_TOKEN_COMMA)
2705 cleanup_source (&source);
2706 return G_TOKEN_COMMA;
2711 token = g_scanner_get_next_token (scanner);
2715 case GTK_RC_TOKEN_NORMAL:
2716 source.any_state = FALSE;
2717 source.state = GTK_STATE_NORMAL;
2720 case GTK_RC_TOKEN_PRELIGHT:
2721 source.any_state = FALSE;
2722 source.state = GTK_STATE_PRELIGHT;
2726 case GTK_RC_TOKEN_INSENSITIVE:
2727 source.any_state = FALSE;
2728 source.state = GTK_STATE_INSENSITIVE;
2731 case GTK_RC_TOKEN_ACTIVE:
2732 source.any_state = FALSE;
2733 source.state = GTK_STATE_ACTIVE;
2736 case GTK_RC_TOKEN_SELECTED:
2737 source.any_state = FALSE;
2738 source.state = GTK_STATE_SELECTED;
2745 cleanup_source (&source);
2746 return GTK_RC_TOKEN_PRELIGHT;
2750 token = g_scanner_get_next_token (scanner);
2752 if (token == G_TOKEN_RIGHT_CURLY)
2754 gtk_icon_set_add_source (icon_set, &source);
2755 cleanup_source (&source);
2756 return G_TOKEN_NONE;
2758 else if (token != G_TOKEN_COMMA)
2760 cleanup_source (&source);
2761 return G_TOKEN_COMMA;
2766 token = g_scanner_get_next_token (scanner);
2770 if (token != G_TOKEN_STRING)
2772 cleanup_source (&source);
2773 return G_TOKEN_STRING;
2776 source.size = g_strdup (scanner->value.v_string);
2777 source.any_size = FALSE;
2780 /* Check the close brace */
2782 token = g_scanner_get_next_token (scanner);
2783 if (token != G_TOKEN_RIGHT_CURLY)
2785 cleanup_source (&source);
2786 return G_TOKEN_RIGHT_CURLY;
2789 gtk_icon_set_add_source (icon_set, &source);
2791 cleanup_source (&source);
2793 return G_TOKEN_NONE;
2797 gtk_rc_parse_stock (GScanner *scanner,
2798 GtkRcStyle *rc_style,
2799 GtkIconFactory *factory)
2801 GtkIconSet *icon_set = NULL;
2802 gchar *stock_id = NULL;
2805 token = g_scanner_get_next_token (scanner);
2806 if (token != GTK_RC_TOKEN_STOCK)
2807 return GTK_RC_TOKEN_STOCK;
2809 token = gtk_rc_parse_stock_id (scanner, &stock_id);
2810 if (token != G_TOKEN_NONE)
2813 token = g_scanner_get_next_token (scanner);
2814 if (token != G_TOKEN_EQUAL_SIGN)
2817 return G_TOKEN_EQUAL_SIGN;
2820 token = g_scanner_get_next_token (scanner);
2821 if (token != G_TOKEN_LEFT_CURLY)
2824 return G_TOKEN_LEFT_CURLY;
2827 token = g_scanner_peek_next_token (scanner);
2828 while (token != G_TOKEN_RIGHT_CURLY)
2830 if (icon_set == NULL)
2831 icon_set = gtk_icon_set_new ();
2833 token = gtk_rc_parse_icon_source (scanner, icon_set);
2834 if (token != G_TOKEN_NONE)
2837 gtk_icon_set_unref (icon_set);
2841 token = g_scanner_get_next_token (scanner);
2843 if (token != G_TOKEN_COMMA &&
2844 token != G_TOKEN_RIGHT_CURLY)
2847 gtk_icon_set_unref (icon_set);
2848 return G_TOKEN_RIGHT_CURLY;
2854 gtk_icon_factory_add (factory,
2858 gtk_icon_set_unref (icon_set);
2863 return G_TOKEN_NONE;
2867 typedef GdkPixmap * (*GtkImageLoader) (GdkWindow *window,
2868 GdkColormap *colormap,
2870 GdkColor *transparent_color,
2871 const gchar *filename);
2875 gtk_rc_set_image_loader(GtkImageLoader loader)
2877 image_loader = loader;
2881 gtk_rc_load_image (GdkColormap *colormap,
2882 GdkColor *transparent_color,
2883 const gchar *filename)
2885 if (strcmp (filename, "<parent>") == 0)
2886 return (GdkPixmap*) GDK_PARENT_RELATIVE;
2890 return image_loader(NULL, colormap, NULL,
2894 return gdk_pixmap_colormap_create_from_xpm (NULL, colormap, NULL,