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 path = g_strdup_printf ("%s%s", var, "/.gtk-2.0/" GTK_VERSION "/engines");
370 path = g_strdup_printf ("%s%s", var, "\\_gtk\\themes\\engines");
372 module_path[n++] = path;
374 module_path[n] = NULL;
378 gtk_rc_add_initial_default_files (void)
380 static gint init = FALSE;
388 gtk_rc_default_files[0] = NULL;
391 var = g_getenv("GTK_RC_FILES");
394 files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
398 gtk_rc_add_default_file (files[i]);
406 str = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk-2.0" G_DIR_SEPARATOR_S "gtkrc");
408 str = g_strdup_printf ("%s\\gtkrc", gtk_win32_get_installation_directory ());
411 gtk_rc_add_default_file (str);
414 var = g_get_home_dir ();
417 str = g_strdup_printf ("%s" G_DIR_SEPARATOR_S ".gtkrc-2.0", var);
418 gtk_rc_add_default_file (str);
425 gtk_rc_add_default_file (const gchar *file)
429 gtk_rc_add_initial_default_files ();
431 for (n = 0; gtk_rc_default_files[n]; n++) ;
432 if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
435 gtk_rc_default_files[n++] = g_strdup (file);
436 gtk_rc_default_files[n] = NULL;
440 gtk_rc_set_default_files (gchar **files)
444 gtk_rc_add_initial_default_files ();
447 while (gtk_rc_default_files[i])
449 g_free (gtk_rc_default_files[i]);
453 gtk_rc_default_files[0] = NULL;
454 gtk_rc_auto_parse = FALSE;
457 while (files[i] != NULL)
459 gtk_rc_add_default_file (files[i]);
465 gtk_rc_get_default_files (void)
467 gtk_rc_add_initial_default_files ();
469 return gtk_rc_default_files;
472 /* The following routine is based on _nl_normalize_codeset from
473 * the GNU C library. Contributed by
475 * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
476 * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
478 * Normalize codeset name. There is no standard for the codeset
479 * names. Normalization allows the user to use any of the common
483 _gtk_normalize_codeset (const char *codeset, int name_len)
491 for (cnt = 0; cnt < name_len; ++cnt)
492 if (isalnum (codeset[cnt]))
496 if (isalpha (codeset[cnt]))
500 retval = g_malloc ((only_digit ? 3 : 0) + len + 1);
504 strcpy (retval, "iso");
510 for (cnt = 0; cnt < name_len; ++cnt)
511 if (isalpha (codeset[cnt]))
512 *wp++ = isupper(codeset[cnt]) ? tolower (codeset[cnt]) : codeset[cnt];
513 else if (isdigit (codeset[cnt]))
514 *wp++ = codeset[cnt];
524 static gchar *locale_suffixes[3];
525 static gint n_locale_suffixes = 0;
529 static gboolean initted = FALSE;
538 locale = g_win32_getlocale ();
540 locale = setlocale (LC_CTYPE, NULL);
545 pixmap_path[0] = NULL;
546 module_path[0] = NULL;
547 gtk_rc_append_default_module_path();
549 gtk_rc_add_initial_default_files ();
551 if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
553 /* Determine locale-specific suffixes for RC files
555 * We normalize the charset into a standard form,
556 * which has all '-' and '_' characters removed,
559 gchar *normalized_locale;
561 p = strchr (locale, '@');
562 length = p ? (p -locale) : strlen (locale);
564 p = strchr (locale, '.');
567 gchar *tmp1 = g_strndup (locale, p - locale + 1);
568 gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
570 normalized_locale = g_strconcat (tmp1, tmp2, NULL);
574 locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
578 normalized_locale = g_strndup (locale, length);
580 p = strchr (normalized_locale, '_');
583 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
584 length = p - normalized_locale;
587 locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
589 g_free (normalized_locale);
594 while (gtk_rc_default_files[i] != NULL)
596 /* Try to find a locale specific RC file corresponding to
597 * to parse before the default file.
599 for (j=n_locale_suffixes-1; j>=0; j--)
601 gchar *name = g_strconcat (gtk_rc_default_files[i],
609 gtk_rc_parse (gtk_rc_default_files[i]);
615 gtk_rc_parse_string (const gchar *rc_string)
617 g_return_if_fail (rc_string != NULL);
619 gtk_rc_parse_any ("-", -1, rc_string);
623 gtk_rc_parse_file (const gchar *filename, gboolean reload)
625 GtkRcFile *rc_file = NULL;
629 g_return_if_fail (filename != NULL);
634 rc_file = tmp_list->data;
635 if (!strcmp (rc_file->name, filename))
638 tmp_list = tmp_list->next;
643 rc_file = g_new (GtkRcFile, 1);
644 rc_file->name = g_strdup (filename);
645 rc_file->canonical_name = NULL;
647 rc_file->reload = reload;
649 rc_files = g_slist_append (rc_files, rc_file);
652 if (!rc_file->canonical_name)
654 /* Get the absolute pathname */
656 if (g_path_is_absolute (rc_file->name))
657 rc_file->canonical_name = rc_file->name;
663 cwd = g_get_current_dir ();
665 str = g_string_new (cwd);
667 g_string_append_c (str, G_DIR_SEPARATOR);
668 g_string_append (str, rc_file->name);
670 rc_file->canonical_name = str->str;
671 g_string_free (str, FALSE);
675 if (!lstat (rc_file->canonical_name, &statbuf))
680 rc_file->mtime = statbuf.st_mtime;
682 fd = open (rc_file->canonical_name, O_RDONLY);
686 /* Temporarily push directory name for this file on
687 * a stack of directory names while parsing it
690 g_slist_prepend (rc_dir_stack,
691 g_path_get_dirname (rc_file->canonical_name));
692 gtk_rc_parse_any (filename, fd, NULL);
694 tmp_list = rc_dir_stack;
695 rc_dir_stack = rc_dir_stack->next;
697 g_free (tmp_list->data);
698 g_slist_free_1 (tmp_list);
705 gtk_rc_parse (const gchar *filename)
707 g_return_if_fail (filename != NULL);
709 gtk_rc_parse_file (filename, TRUE);
712 /* Handling of RC styles */
715 gtk_rc_style_get_type (void)
717 static GType object_type = 0;
721 static const GTypeInfo object_info =
723 sizeof (GtkRcStyleClass),
724 (GBaseInitFunc) NULL,
725 (GBaseFinalizeFunc) NULL,
726 (GClassInitFunc) gtk_rc_style_class_init,
727 NULL, /* class_finalize */
728 NULL, /* class_data */
731 (GInstanceInitFunc) gtk_rc_style_init,
734 object_type = g_type_register_static (G_TYPE_OBJECT,
743 gtk_rc_style_init (GtkRcStyle *style)
748 for (i = 0; i < 5; i++)
750 static const GdkColor init_color = { 0, 0, 0, 0, };
752 style->bg_pixmap_name[i] = NULL;
753 style->color_flags[i] = 0;
754 style->fg[i] = init_color;
755 style->bg[i] = init_color;
756 style->text[i] = init_color;
757 style->base[i] = init_color;
759 style->xthickness = -1;
760 style->ythickness = -1;
761 style->rc_style_lists = NULL;
765 gtk_rc_style_class_init (GtkRcStyleClass *klass)
767 GObjectClass *object_class = G_OBJECT_CLASS (klass);
769 parent_class = g_type_class_peek_parent (klass);
771 object_class->finalize = gtk_rc_style_finalize;
774 klass->clone = gtk_rc_style_real_clone;
775 klass->merge = gtk_rc_style_real_merge;
776 klass->create_style = gtk_rc_style_real_create_style;
779 /* Like g_slist_remove, but remove all copies of data */
781 gtk_rc_slist_remove_all (GSList *list,
792 if (tmp->data == data)
798 prev->next = tmp->next;
800 g_slist_free_1 (tmp);
818 gtk_rc_style_finalize (GObject *object)
821 GSList *tmp_list1, *tmp_list2;
822 GtkRcStyle *rc_style;
824 rc_style = GTK_RC_STYLE (object);
827 g_free (rc_style->name);
828 if (rc_style->font_desc)
829 pango_font_description_free (rc_style->font_desc);
831 for (i=0 ; i < 5 ; i++)
832 if (rc_style->bg_pixmap_name[i])
833 g_free (rc_style->bg_pixmap_name[i]);
835 /* Now remove all references to this rc_style from
838 tmp_list1 = rc_style->rc_style_lists;
841 GSList *rc_styles = tmp_list1->data;
842 GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
843 gtk_style_unref (style);
845 /* Remove the list of styles from the other rc_styles
848 tmp_list2 = rc_styles;
851 GtkRcStyle *other_style = tmp_list2->data;
853 if (other_style != rc_style)
854 other_style->rc_style_lists =
855 gtk_rc_slist_remove_all (other_style->rc_style_lists, rc_styles);
857 tmp_list2 = tmp_list2->next;
860 /* And from the hash table itself
862 g_hash_table_remove (realized_style_ht, rc_styles);
863 g_slist_free (rc_styles);
865 tmp_list1 = tmp_list1->next;
868 g_slist_free (rc_style->rc_style_lists);
870 tmp_list1 = rc_style->icon_factories;
873 g_object_unref (G_OBJECT (tmp_list1->data));
875 tmp_list1 = tmp_list1->next;
878 g_slist_free (rc_style->icon_factories);
880 G_OBJECT_CLASS (parent_class)->finalize (object);
884 gtk_rc_style_new (void)
888 style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
895 * @orig: the style to copy
897 * Make a copy of the specified #GtkRcStyle. This function
898 * will correctly copy an rc style that is a member of a class
899 * derived from #GtkRcStyle.
901 * Return value: the resulting #GtkRcStyle
904 gtk_rc_style_copy (GtkRcStyle *orig)
908 g_return_val_if_fail (GTK_IS_RC_STYLE (orig), NULL);
910 style = GTK_RC_STYLE_GET_CLASS (orig)->clone (orig);
911 GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
917 gtk_rc_style_ref (GtkRcStyle *rc_style)
919 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
921 g_object_ref (G_OBJECT (rc_style));
925 gtk_rc_style_unref (GtkRcStyle *rc_style)
927 g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
929 g_object_unref (G_OBJECT (rc_style));
933 gtk_rc_style_real_clone (GtkRcStyle *style)
935 return GTK_RC_STYLE (g_object_new (G_OBJECT_TYPE (style), NULL));
939 gtk_rc_style_real_merge (GtkRcStyle *dest,
944 for (i = 0; i < 5; i++)
946 if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
947 dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
949 if (!(dest->color_flags[i] & GTK_RC_FG) &&
950 src->color_flags[i] & GTK_RC_FG)
952 dest->fg[i] = src->fg[i];
953 dest->color_flags[i] |= GTK_RC_FG;
955 if (!(dest->color_flags[i] & GTK_RC_BG) &&
956 src->color_flags[i] & GTK_RC_BG)
958 dest->bg[i] = src->bg[i];
959 dest->color_flags[i] |= GTK_RC_BG;
961 if (!(dest->color_flags[i] & GTK_RC_TEXT) &&
962 src->color_flags[i] & GTK_RC_TEXT)
964 dest->text[i] = src->text[i];
965 dest->color_flags[i] |= GTK_RC_TEXT;
967 if (!(dest->color_flags[i] & GTK_RC_BASE) &&
968 src->color_flags[i] & GTK_RC_BASE)
970 dest->base[i] = src->base[i];
971 dest->color_flags[i] |= GTK_RC_BASE;
975 if (dest->xthickness < 0 && src->xthickness >= 0)
976 dest->xthickness = src->xthickness;
977 if (dest->ythickness < 0 && src->ythickness >= 0)
978 dest->ythickness = src->ythickness;
980 if (!dest->font_desc && src->font_desc)
981 dest->font_desc = pango_font_description_copy (src->font_desc);
985 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
987 return gtk_style_new ();
991 gtk_rc_clear_hash_node (gpointer key,
995 gtk_rc_style_unref (data);
999 gtk_rc_free_rc_sets (GSList *slist)
1005 rc_set = slist->data;
1006 gtk_pattern_spec_free_segs (&rc_set->pspec);
1009 slist = slist->next;
1014 gtk_rc_clear_styles (void)
1016 /* Clear out all old rc_styles */
1020 g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
1021 g_hash_table_destroy (rc_style_ht);
1025 gtk_rc_free_rc_sets (gtk_rc_sets_widget);
1026 g_slist_free (gtk_rc_sets_widget);
1027 gtk_rc_sets_widget = NULL;
1029 gtk_rc_free_rc_sets (gtk_rc_sets_widget_class);
1030 g_slist_free (gtk_rc_sets_widget_class);
1031 gtk_rc_sets_widget_class = NULL;
1033 gtk_rc_free_rc_sets (gtk_rc_sets_class);
1034 g_slist_free (gtk_rc_sets_class);
1035 gtk_rc_sets_class = NULL;
1039 gtk_rc_reparse_all (void)
1042 gboolean mtime_modified = FALSE;
1045 struct stat statbuf;
1047 /* Check through and see if any of the RC's have had their
1048 * mtime modified. If so, reparse everything.
1050 tmp_list = rc_files;
1053 rc_file = tmp_list->data;
1055 if (!lstat (rc_file->name, &statbuf) &&
1056 (statbuf.st_mtime > rc_file->mtime))
1058 mtime_modified = TRUE;
1062 tmp_list = tmp_list->next;
1067 gtk_rc_clear_styles();
1069 tmp_list = rc_files;
1072 rc_file = tmp_list->data;
1073 if (rc_file->reload)
1074 gtk_rc_parse_file (rc_file->name, FALSE);
1076 tmp_list = tmp_list->next;
1080 return mtime_modified;
1084 gtk_rc_styles_match (GSList *rc_styles,
1088 gchar *path_reversed)
1095 rc_set = sets->data;
1098 if (gtk_pattern_match (&rc_set->pspec, path_length, path, path_reversed))
1099 rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
1106 gtk_rc_get_style (GtkWidget *widget)
1108 GtkRcStyle *widget_rc_style;
1109 GSList *rc_styles = NULL;
1111 static guint rc_style_key_id = 0;
1113 /* We allow the specification of a single rc style to be bound
1114 * tightly to a widget, for application modifications
1116 if (!rc_style_key_id)
1117 rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1119 widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
1122 if (widget_rc_style)
1123 rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
1125 if (gtk_rc_sets_widget)
1127 gchar *path, *path_reversed;
1130 gtk_widget_path (widget, &path_length, &path, &path_reversed);
1131 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget, path_length, path, path_reversed);
1133 g_free (path_reversed);
1137 if (gtk_rc_sets_widget_class)
1139 gchar *path, *path_reversed;
1142 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1143 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget_class, path_length, path, path_reversed);
1145 g_free (path_reversed);
1148 if (gtk_rc_sets_class)
1152 type = GTK_OBJECT_TYPE (widget);
1155 gchar *path, *path_reversed;
1158 path = gtk_type_name (type);
1159 path_length = strlen (path);
1160 path_reversed = g_strdup (path);
1161 g_strreverse (path_reversed);
1163 rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_class, path_length, path, path_reversed);
1164 g_free (path_reversed);
1166 type = gtk_type_parent (type);
1171 return gtk_rc_init_style (rc_styles);
1177 gtk_rc_add_rc_sets (GSList *slist,
1178 GtkRcStyle *rc_style,
1179 const char *pattern)
1181 GtkRcStyle *new_style;
1185 new_style = gtk_rc_style_new ();
1186 *new_style = *rc_style;
1187 new_style->name = g_strdup (rc_style->name);
1188 if (rc_style->font_desc)
1189 new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
1191 for (i = 0; i < 5; i++)
1192 new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
1194 rc_set = g_new (GtkRcSet, 1);
1195 gtk_pattern_spec_init (&rc_set->pspec, pattern);
1196 rc_set->rc_style = rc_style;
1198 return g_slist_prepend (slist, rc_set);
1202 gtk_rc_add_widget_name_style (GtkRcStyle *rc_style,
1203 const gchar *pattern)
1205 g_return_if_fail (rc_style != NULL);
1206 g_return_if_fail (pattern != NULL);
1208 gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, rc_style, pattern);
1212 gtk_rc_add_widget_class_style (GtkRcStyle *rc_style,
1213 const gchar *pattern)
1215 g_return_if_fail (rc_style != NULL);
1216 g_return_if_fail (pattern != NULL);
1218 gtk_rc_sets_widget_class = gtk_rc_add_rc_sets (gtk_rc_sets_widget_class, rc_style, pattern);
1222 gtk_rc_add_class_style (GtkRcStyle *rc_style,
1223 const gchar *pattern)
1225 g_return_if_fail (rc_style != NULL);
1226 g_return_if_fail (pattern != NULL);
1228 gtk_rc_sets_class = gtk_rc_add_rc_sets (gtk_rc_sets_class, rc_style, pattern);
1232 gtk_rc_parse_any (const gchar *input_name,
1234 const gchar *input_string)
1240 scanner = g_scanner_new ((GScannerConfig *) >k_rc_scanner_config);
1244 g_assert (input_string == NULL);
1246 g_scanner_input_file (scanner, input_fd);
1250 g_assert (input_string != NULL);
1252 g_scanner_input_text (scanner, input_string, strlen (input_string));
1254 scanner->input_name = input_name;
1256 for (i = 0; i < n_symbols; i++)
1257 g_scanner_add_symbol (scanner, symbols[i].name, GINT_TO_POINTER (symbols[i].token));
1262 if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1266 guint expected_token;
1268 expected_token = gtk_rc_parse_statement (scanner);
1270 if (expected_token != G_TOKEN_NONE)
1277 if (scanner->scope_id == 0)
1279 /* if we are in scope 0, we know the symbol names
1280 * that are associated with certaintoken values.
1281 * so we look them up to make the error messages
1284 if (expected_token > GTK_RC_TOKEN_INVALID &&
1285 expected_token < GTK_RC_TOKEN_LAST)
1287 for (i = 0; i < n_symbols; i++)
1288 if (symbols[i].token == expected_token)
1289 msg = symbols[i].name;
1291 msg = g_strconcat ("e.g. `", msg, "'", NULL);
1293 if (scanner->token > GTK_RC_TOKEN_INVALID &&
1294 scanner->token < GTK_RC_TOKEN_LAST)
1296 symbol_name = "???";
1297 for (i = 0; i < n_symbols; i++)
1298 if (symbols[i].token == scanner->token)
1299 symbol_name = symbols[i].name;
1302 g_scanner_unexp_token (scanner,
1315 g_scanner_destroy (scanner);
1319 gtk_rc_styles_hash (const GSList *rc_styles)
1326 result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
1327 rc_styles = rc_styles->next;
1334 gtk_rc_styles_compare (const GSList *a,
1339 if (a->data != b->data)
1349 gtk_rc_style_hash (const char *name)
1355 result += (result << 3) + *name++;
1361 gtk_rc_style_compare (const char *a,
1364 return (strcmp (a, b) == 0);
1368 gtk_rc_style_find (const char *name)
1371 return g_hash_table_lookup (rc_style_ht, (gpointer) name);
1377 gtk_rc_style_to_style (GtkRcStyle *rc_style)
1381 style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
1383 style->rc_style = rc_style;
1385 gtk_rc_style_ref (rc_style);
1387 GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);
1392 /* Reuses or frees rc_styles */
1394 gtk_rc_init_style (GSList *rc_styles)
1396 GtkStyle *style = NULL;
1399 g_return_val_if_fail (rc_styles != NULL, NULL);
1401 if (!realized_style_ht)
1402 realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
1403 (GCompareFunc) gtk_rc_styles_compare);
1405 style = g_hash_table_lookup (realized_style_ht, rc_styles);
1409 GtkRcStyle *base_style = NULL;
1410 GtkRcStyle *proto_style;
1411 GtkRcStyleClass *proto_style_class;
1413 GType rc_style_type = GTK_TYPE_RC_STYLE;
1415 /* Find the first derived style in the list, and use that to
1416 * create the merged style. If we only have raw GtkRcStyles, use
1417 * the first style to create the merged style.
1419 base_style = rc_styles->data;
1420 tmp_styles = rc_styles;
1423 GtkRcStyle *rc_style = tmp_styles->data;
1425 if (G_OBJECT_TYPE (rc_style) != rc_style_type)
1427 base_style = rc_style;
1431 tmp_styles = tmp_styles->next;
1434 proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
1435 proto_style = proto_style_class->clone (base_style);
1437 tmp_styles = rc_styles;
1440 GtkRcStyle *rc_style = tmp_styles->data;
1443 proto_style_class->merge (proto_style, rc_style);
1445 /* Point from each rc_style to the list of styles */
1446 if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
1447 rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
1449 factories = g_slist_copy (rc_style->icon_factories);
1455 while (iter != NULL)
1457 g_object_ref (G_OBJECT (iter->data));
1458 iter = g_slist_next (iter);
1461 proto_style->icon_factories = g_slist_concat (proto_style->icon_factories,
1466 tmp_styles = tmp_styles->next;
1469 for (i = 0; i < 5; i++)
1470 if (proto_style->bg_pixmap_name[i] &&
1471 (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
1473 g_free (proto_style->bg_pixmap_name[i]);
1474 proto_style->bg_pixmap_name[i] = NULL;
1477 style = gtk_rc_style_to_style (proto_style);
1478 gtk_rc_style_unref (proto_style);
1480 g_hash_table_insert (realized_style_ht, rc_styles, style);
1483 g_slist_free (rc_styles);
1488 /*********************
1489 * Parsing functions *
1490 *********************/
1493 gtk_rc_parse_statement (GScanner *scanner)
1497 token = g_scanner_peek_next_token (scanner);
1501 case GTK_RC_TOKEN_INCLUDE:
1502 token = g_scanner_get_next_token (scanner);
1503 if (token != GTK_RC_TOKEN_INCLUDE)
1504 return GTK_RC_TOKEN_INCLUDE;
1506 token = g_scanner_get_next_token (scanner);
1507 if (token != G_TOKEN_STRING)
1508 return G_TOKEN_STRING;
1510 gtk_rc_parse_file (scanner->value.v_string, FALSE);
1511 return G_TOKEN_NONE;
1513 case GTK_RC_TOKEN_STYLE:
1514 return gtk_rc_parse_style (scanner);
1516 case GTK_RC_TOKEN_BINDING:
1517 return gtk_binding_parse_binding (scanner);
1519 case GTK_RC_TOKEN_PIXMAP_PATH:
1520 return gtk_rc_parse_pixmap_path (scanner);
1522 case GTK_RC_TOKEN_WIDGET:
1523 return gtk_rc_parse_path_pattern (scanner);
1525 case GTK_RC_TOKEN_WIDGET_CLASS:
1526 return gtk_rc_parse_path_pattern (scanner);
1528 case GTK_RC_TOKEN_CLASS:
1529 return gtk_rc_parse_path_pattern (scanner);
1531 case GTK_RC_TOKEN_MODULE_PATH:
1532 return gtk_rc_parse_module_path (scanner);
1535 g_scanner_get_next_token (scanner);
1536 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
1541 gtk_rc_parse_style (GScanner *scanner)
1543 GtkRcStyle *rc_style;
1544 GtkRcStyle *parent_style;
1548 GtkIconFactory *our_factory = NULL;
1550 token = g_scanner_get_next_token (scanner);
1551 if (token != GTK_RC_TOKEN_STYLE)
1552 return GTK_RC_TOKEN_STYLE;
1554 token = g_scanner_get_next_token (scanner);
1555 if (token != G_TOKEN_STRING)
1556 return G_TOKEN_STRING;
1559 rc_style = gtk_rc_style_find (scanner->value.v_string);
1561 /* If there's a list, its first member is always the factory belonging
1564 if (rc_style && rc_style->icon_factories)
1565 our_factory = rc_style->icon_factories->data;
1570 rc_style = gtk_rc_style_new ();
1571 rc_style->name = g_strdup (scanner->value.v_string);
1573 for (i = 0; i < 5; i++)
1574 rc_style->bg_pixmap_name[i] = NULL;
1576 for (i = 0; i < 5; i++)
1577 rc_style->color_flags[i] = 0;
1580 token = g_scanner_peek_next_token (scanner);
1581 if (token == G_TOKEN_EQUAL_SIGN)
1583 token = g_scanner_get_next_token (scanner);
1585 token = g_scanner_get_next_token (scanner);
1586 if (token != G_TOKEN_STRING)
1591 return G_TOKEN_STRING;
1594 parent_style = gtk_rc_style_find (scanner->value.v_string);
1599 for (i = 0; i < 5; i++)
1601 rc_style->color_flags[i] = parent_style->color_flags[i];
1602 rc_style->fg[i] = parent_style->fg[i];
1603 rc_style->bg[i] = parent_style->bg[i];
1604 rc_style->text[i] = parent_style->text[i];
1605 rc_style->base[i] = parent_style->base[i];
1608 rc_style->xthickness = parent_style->xthickness;
1609 rc_style->ythickness = parent_style->ythickness;
1611 if (parent_style->font_desc)
1613 if (rc_style->font_desc)
1614 pango_font_description_free (rc_style->font_desc);
1615 rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
1618 for (i = 0; i < 5; i++)
1620 if (rc_style->bg_pixmap_name[i])
1621 g_free (rc_style->bg_pixmap_name[i]);
1622 rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
1625 /* Append parent's factories, adding a ref to them */
1626 if (parent_style->icon_factories != NULL)
1628 /* Add a factory for ourselves if we have none,
1629 * in case we end up defining more stock icons.
1630 * I see no real way around this; we need to maintain
1631 * the invariant that the first factory in the list
1632 * is always our_factory, the one belonging to us,
1633 * and if we put parent factories in the list we can't
1634 * do that if the style is reopened.
1636 if (our_factory == NULL)
1638 our_factory = gtk_icon_factory_new ();
1639 rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
1643 rc_style->icon_factories = g_slist_concat (rc_style->icon_factories,
1644 g_slist_copy (parent_style->icon_factories));
1646 factories = parent_style->icon_factories;
1647 while (factories != NULL)
1649 g_object_ref (G_OBJECT (factories->data));
1650 factories = factories->next;
1656 token = g_scanner_get_next_token (scanner);
1657 if (token != G_TOKEN_LEFT_CURLY)
1662 return G_TOKEN_LEFT_CURLY;
1665 token = g_scanner_peek_next_token (scanner);
1666 while (token != G_TOKEN_RIGHT_CURLY)
1670 case GTK_RC_TOKEN_BG:
1671 token = gtk_rc_parse_bg (scanner, rc_style);
1673 case GTK_RC_TOKEN_FG:
1674 token = gtk_rc_parse_fg (scanner, rc_style);
1676 case GTK_RC_TOKEN_TEXT:
1677 token = gtk_rc_parse_text (scanner, rc_style);
1679 case GTK_RC_TOKEN_BASE:
1680 token = gtk_rc_parse_base (scanner, rc_style);
1682 case GTK_RC_TOKEN_XTHICKNESS:
1683 token = gtk_rc_parse_xthickness (scanner, rc_style);
1685 case GTK_RC_TOKEN_YTHICKNESS:
1686 token = gtk_rc_parse_ythickness (scanner, rc_style);
1688 case GTK_RC_TOKEN_BG_PIXMAP:
1689 token = gtk_rc_parse_bg_pixmap (scanner, rc_style);
1691 case GTK_RC_TOKEN_FONT:
1692 token = gtk_rc_parse_font (scanner, rc_style);
1694 case GTK_RC_TOKEN_FONTSET:
1695 token = gtk_rc_parse_fontset (scanner, rc_style);
1697 case GTK_RC_TOKEN_FONT_NAME:
1698 token = gtk_rc_parse_font_name (scanner, rc_style);
1700 case GTK_RC_TOKEN_ENGINE:
1701 token = gtk_rc_parse_engine (scanner, &rc_style);
1703 case GTK_RC_TOKEN_STOCK:
1704 if (our_factory == NULL)
1706 our_factory = gtk_icon_factory_new ();
1707 rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
1710 token = gtk_rc_parse_stock (scanner, rc_style, our_factory);
1713 g_scanner_get_next_token (scanner);
1714 token = G_TOKEN_RIGHT_CURLY;
1718 if (token != G_TOKEN_NONE)
1722 if (rc_style->font_desc)
1723 pango_font_description_free (rc_style->font_desc);
1725 for (i = 0; i < 5; i++)
1726 if (rc_style->bg_pixmap_name[i])
1727 g_free (rc_style->bg_pixmap_name[i]);
1732 token = g_scanner_peek_next_token (scanner);
1735 token = g_scanner_get_next_token (scanner);
1736 if (token != G_TOKEN_RIGHT_CURLY)
1740 if (rc_style->font_desc)
1741 pango_font_description_free (rc_style->font_desc);
1743 for (i = 0; i < 5; i++)
1744 if (rc_style->bg_pixmap_name[i])
1745 g_free (rc_style->bg_pixmap_name[i]);
1749 return G_TOKEN_RIGHT_CURLY;
1755 rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
1756 (GCompareFunc) gtk_rc_style_compare);
1758 g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
1761 return G_TOKEN_NONE;
1765 gtk_rc_parse_bg (GScanner *scanner,
1771 token = g_scanner_get_next_token (scanner);
1772 if (token != GTK_RC_TOKEN_BG)
1773 return GTK_RC_TOKEN_BG;
1775 token = gtk_rc_parse_state (scanner, &state);
1776 if (token != G_TOKEN_NONE)
1779 token = g_scanner_get_next_token (scanner);
1780 if (token != G_TOKEN_EQUAL_SIGN)
1781 return G_TOKEN_EQUAL_SIGN;
1783 style->color_flags[state] |= GTK_RC_BG;
1784 return gtk_rc_parse_color (scanner, &style->bg[state]);
1788 gtk_rc_parse_fg (GScanner *scanner,
1794 token = g_scanner_get_next_token (scanner);
1795 if (token != GTK_RC_TOKEN_FG)
1796 return GTK_RC_TOKEN_FG;
1798 token = gtk_rc_parse_state (scanner, &state);
1799 if (token != G_TOKEN_NONE)
1802 token = g_scanner_get_next_token (scanner);
1803 if (token != G_TOKEN_EQUAL_SIGN)
1804 return G_TOKEN_EQUAL_SIGN;
1806 style->color_flags[state] |= GTK_RC_FG;
1807 return gtk_rc_parse_color (scanner, &style->fg[state]);
1811 gtk_rc_parse_text (GScanner *scanner,
1817 token = g_scanner_get_next_token (scanner);
1818 if (token != GTK_RC_TOKEN_TEXT)
1819 return GTK_RC_TOKEN_TEXT;
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 style->color_flags[state] |= GTK_RC_TEXT;
1830 return gtk_rc_parse_color (scanner, &style->text[state]);
1834 gtk_rc_parse_base (GScanner *scanner,
1840 token = g_scanner_get_next_token (scanner);
1841 if (token != GTK_RC_TOKEN_BASE)
1842 return GTK_RC_TOKEN_BASE;
1844 token = gtk_rc_parse_state (scanner, &state);
1845 if (token != G_TOKEN_NONE)
1848 token = g_scanner_get_next_token (scanner);
1849 if (token != G_TOKEN_EQUAL_SIGN)
1850 return G_TOKEN_EQUAL_SIGN;
1852 style->color_flags[state] |= GTK_RC_BASE;
1853 return gtk_rc_parse_color (scanner, &style->base[state]);
1857 gtk_rc_parse_xthickness (GScanner *scanner,
1860 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
1861 return GTK_RC_TOKEN_XTHICKNESS;
1863 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
1864 return G_TOKEN_EQUAL_SIGN;
1866 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
1869 style->xthickness = scanner->value.v_int;
1871 return G_TOKEN_NONE;
1875 gtk_rc_parse_ythickness (GScanner *scanner,
1878 if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
1879 return GTK_RC_TOKEN_YTHICKNESS;
1881 if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
1882 return G_TOKEN_EQUAL_SIGN;
1884 if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
1887 style->ythickness = scanner->value.v_int;
1889 return G_TOKEN_NONE;
1893 gtk_rc_parse_bg_pixmap (GScanner *scanner,
1894 GtkRcStyle *rc_style)
1900 token = g_scanner_get_next_token (scanner);
1901 if (token != GTK_RC_TOKEN_BG_PIXMAP)
1902 return GTK_RC_TOKEN_BG_PIXMAP;
1904 token = gtk_rc_parse_state (scanner, &state);
1905 if (token != G_TOKEN_NONE)
1908 token = g_scanner_get_next_token (scanner);
1909 if (token != G_TOKEN_EQUAL_SIGN)
1910 return G_TOKEN_EQUAL_SIGN;
1912 token = g_scanner_get_next_token (scanner);
1913 if (token != G_TOKEN_STRING)
1914 return G_TOKEN_STRING;
1916 if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
1917 (strcmp (scanner->value.v_string, "<none>") == 0))
1918 pixmap_file = g_strdup (scanner->value.v_string);
1920 pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
1924 if (rc_style->bg_pixmap_name[state])
1925 g_free (rc_style->bg_pixmap_name[state]);
1926 rc_style->bg_pixmap_name[state] = pixmap_file;
1929 return G_TOKEN_NONE;
1933 gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
1938 buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", dir, pixmap_file);
1940 fd = open (buf, O_RDONLY);
1953 gtk_rc_find_pixmap_in_path (GScanner *scanner,
1954 const gchar *pixmap_file)
1960 for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
1962 filename = gtk_rc_check_pixmap_dir (pixmap_path[i], pixmap_file);
1967 tmp_list = rc_dir_stack;
1970 filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
1974 tmp_list = tmp_list->next;
1978 g_warning (_("Unable to locate image file in pixmap_path: \"%s\" line %d"),
1979 pixmap_file, scanner->line);
1981 g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
1988 gtk_rc_find_module_in_path (const gchar *module_file)
1994 for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
1996 buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
1997 module_path[i], module_file);
1999 fd = open (buf, O_RDONLY);
2013 gtk_rc_parse_font (GScanner *scanner,
2014 GtkRcStyle *rc_style)
2018 token = g_scanner_get_next_token (scanner);
2019 if (token != GTK_RC_TOKEN_FONT)
2020 return GTK_RC_TOKEN_FONT;
2022 token = g_scanner_get_next_token (scanner);
2023 if (token != G_TOKEN_EQUAL_SIGN)
2024 return G_TOKEN_EQUAL_SIGN;
2026 token = g_scanner_get_next_token (scanner);
2027 if (token != G_TOKEN_STRING)
2028 return G_TOKEN_STRING;
2030 /* Ignore, do nothing */
2032 return G_TOKEN_NONE;
2036 gtk_rc_parse_fontset (GScanner *scanner,
2037 GtkRcStyle *rc_style)
2041 token = g_scanner_get_next_token (scanner);
2042 if (token != GTK_RC_TOKEN_FONTSET)
2043 return GTK_RC_TOKEN_FONTSET;
2045 token = g_scanner_get_next_token (scanner);
2046 if (token != G_TOKEN_EQUAL_SIGN)
2047 return G_TOKEN_EQUAL_SIGN;
2049 token = g_scanner_get_next_token (scanner);
2050 if (token != G_TOKEN_STRING)
2051 return G_TOKEN_STRING;
2053 /* Do nothing - silently ignore */
2055 return G_TOKEN_NONE;
2059 gtk_rc_parse_font_name (GScanner *scanner,
2060 GtkRcStyle *rc_style)
2064 token = g_scanner_get_next_token (scanner);
2065 if (token != GTK_RC_TOKEN_FONT_NAME)
2066 return GTK_RC_TOKEN_FONT;
2068 token = g_scanner_get_next_token (scanner);
2069 if (token != G_TOKEN_EQUAL_SIGN)
2070 return G_TOKEN_EQUAL_SIGN;
2072 token = g_scanner_get_next_token (scanner);
2073 if (token != G_TOKEN_STRING)
2074 return G_TOKEN_STRING;
2076 rc_style->font_desc = pango_font_description_from_string (scanner->value.v_string);
2078 return G_TOKEN_NONE;
2082 gtk_rc_parse_engine (GScanner *scanner,
2083 GtkRcStyle **rc_style)
2086 GtkThemeEngine *engine;
2087 guint result = G_TOKEN_NONE;
2088 GtkRcStyle *new_style = NULL;
2089 gboolean parsed_curlies = FALSE;
2091 token = g_scanner_get_next_token (scanner);
2092 if (token != GTK_RC_TOKEN_ENGINE)
2093 return GTK_RC_TOKEN_ENGINE;
2095 token = g_scanner_get_next_token (scanner);
2096 if (token != G_TOKEN_STRING)
2097 return G_TOKEN_STRING;
2099 engine = gtk_theme_engine_get (scanner->value.v_string);
2101 token = g_scanner_get_next_token (scanner);
2102 if (token != G_TOKEN_LEFT_CURLY)
2103 return G_TOKEN_LEFT_CURLY;
2107 GtkRcStyleClass *new_class;
2109 new_style = gtk_theme_engine_create_rc_style (engine);
2110 gtk_theme_engine_unref (engine);
2112 new_class = GTK_RC_STYLE_GET_CLASS (new_style);
2114 new_class->merge (new_style, *rc_style);
2115 if ((*rc_style)->name)
2116 new_style->name = g_strdup ((*rc_style)->name);
2118 if (new_class->parse)
2120 parsed_curlies = TRUE;
2121 result = new_class->parse (new_style, scanner);
2123 if (result != G_TOKEN_NONE)
2125 g_object_unref (G_OBJECT (new_style));
2131 if (!parsed_curlies)
2133 /* Skip over remainder, looking for nested {}'s
2137 result = G_TOKEN_RIGHT_CURLY;
2138 while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
2140 if (token == G_TOKEN_LEFT_CURLY)
2142 else if (token == G_TOKEN_RIGHT_CURLY)
2147 result = G_TOKEN_NONE;
2155 g_object_unref (G_OBJECT (*rc_style));
2156 *rc_style = new_style;
2163 gtk_rc_parse_state (GScanner *scanner,
2164 GtkStateType *state)
2169 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2170 g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
2172 /* we don't know where we got called from, so we reset the scope here.
2173 * if we bail out due to errors, we *don't* reset the scope, so the
2174 * error messaging code can make sense of our tokens.
2176 old_scope = g_scanner_set_scope (scanner, 0);
2178 token = g_scanner_get_next_token (scanner);
2179 if (token != G_TOKEN_LEFT_BRACE)
2180 return G_TOKEN_LEFT_BRACE;
2182 token = g_scanner_get_next_token (scanner);
2185 case GTK_RC_TOKEN_ACTIVE:
2186 *state = GTK_STATE_ACTIVE;
2188 case GTK_RC_TOKEN_INSENSITIVE:
2189 *state = GTK_STATE_INSENSITIVE;
2191 case GTK_RC_TOKEN_NORMAL:
2192 *state = GTK_STATE_NORMAL;
2194 case GTK_RC_TOKEN_PRELIGHT:
2195 *state = GTK_STATE_PRELIGHT;
2197 case GTK_RC_TOKEN_SELECTED:
2198 *state = GTK_STATE_SELECTED;
2201 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
2204 token = g_scanner_get_next_token (scanner);
2205 if (token != G_TOKEN_RIGHT_BRACE)
2206 return G_TOKEN_RIGHT_BRACE;
2208 g_scanner_set_scope (scanner, old_scope);
2210 return G_TOKEN_NONE;
2214 gtk_rc_parse_priority (GScanner *scanner,
2215 GtkPathPriorityType *priority)
2220 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2221 g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
2223 /* we don't know where we got called from, so we reset the scope here.
2224 * if we bail out due to errors, we *don't* reset the scope, so the
2225 * error messaging code can make sense of our tokens.
2227 old_scope = g_scanner_set_scope (scanner, 0);
2229 token = g_scanner_get_next_token (scanner);
2233 token = g_scanner_get_next_token (scanner);
2236 case GTK_RC_TOKEN_LOWEST:
2237 *priority = GTK_PATH_PRIO_LOWEST;
2239 case GTK_RC_TOKEN_GTK:
2240 *priority = GTK_PATH_PRIO_GTK;
2242 case GTK_RC_TOKEN_APPLICATION:
2243 *priority = GTK_PATH_PRIO_APPLICATION;
2245 case GTK_RC_TOKEN_RC:
2246 *priority = GTK_PATH_PRIO_RC;
2248 case GTK_RC_TOKEN_HIGHEST:
2249 *priority = GTK_PATH_PRIO_HIGHEST;
2252 return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
2255 g_scanner_set_scope (scanner, old_scope);
2257 return G_TOKEN_NONE;
2261 gtk_rc_parse_color (GScanner *scanner,
2266 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
2268 /* we don't need to set our own scop here, because
2269 * we don't need own symbols
2272 token = g_scanner_get_next_token (scanner);
2281 case G_TOKEN_LEFT_CURLY:
2282 token = g_scanner_get_next_token (scanner);
2283 if (token == G_TOKEN_INT)
2284 token_int = scanner->value.v_int;
2285 else if (token == G_TOKEN_FLOAT)
2286 token_int = scanner->value.v_float * 65535.0;
2288 return G_TOKEN_FLOAT;
2289 color->red = CLAMP (token_int, 0, 65535);
2291 token = g_scanner_get_next_token (scanner);
2292 if (token != G_TOKEN_COMMA)
2293 return G_TOKEN_COMMA;
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->green = 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->blue = CLAMP (token_int, 0, 65535);
2317 token = g_scanner_get_next_token (scanner);
2318 if (token != G_TOKEN_RIGHT_CURLY)
2319 return G_TOKEN_RIGHT_CURLY;
2320 return G_TOKEN_NONE;
2322 case G_TOKEN_STRING:
2323 if (scanner->value.v_string[0] != '#')
2324 return G_TOKEN_STRING;
2326 length = strlen (scanner->value.v_string) - 1;
2327 if (((length % 3) != 0) || (length > 12))
2328 return G_TOKEN_STRING;
2331 for (i = 0, j = 1; i < length; i++, j++)
2332 buf[i] = scanner->value.v_string[j];
2335 sscanf (buf, "%x", &temp);
2338 for (i = 0; i < length; i++, j++)
2339 buf[i] = scanner->value.v_string[j];
2342 sscanf (buf, "%x", &temp);
2343 color->green = temp;
2345 for (i = 0; i < length; i++, j++)
2346 buf[i] = scanner->value.v_string[j];
2349 sscanf (buf, "%x", &temp);
2355 color->green *= 4369;
2356 color->blue *= 4369;
2358 else if (length == 2)
2361 color->green *= 257;
2364 else if (length == 3)
2370 return G_TOKEN_NONE;
2373 return G_TOKEN_STRING;
2378 gtk_rc_parse_pixmap_path (GScanner *scanner)
2382 token = g_scanner_get_next_token (scanner);
2383 if (token != GTK_RC_TOKEN_PIXMAP_PATH)
2384 return GTK_RC_TOKEN_PIXMAP_PATH;
2386 token = g_scanner_get_next_token (scanner);
2387 if (token != G_TOKEN_STRING)
2388 return G_TOKEN_STRING;
2390 gtk_rc_parse_pixmap_path_string (scanner->value.v_string);
2392 return G_TOKEN_NONE;
2396 gtk_rc_parse_pixmap_path_string (gchar *pix_path)
2400 gint start_offset = 0;
2404 /* free the old one, or just add to the old one ? */
2405 for (path_num=0; pixmap_path[path_num]; path_num++)
2407 g_free (pixmap_path[path_num]);
2408 pixmap_path[path_num] = NULL;
2413 path_len = strlen (pix_path);
2415 buf = g_strdup (pix_path);
2417 for (end_offset = 0; end_offset <= path_len; end_offset++)
2419 if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2420 (end_offset == path_len))
2422 buf[end_offset] = '\0';
2423 pixmap_path[path_num] = g_strdup (buf + start_offset);
2425 pixmap_path[path_num] = NULL;
2426 start_offset = end_offset + 1;
2433 gtk_rc_parse_module_path (GScanner *scanner)
2437 token = g_scanner_get_next_token (scanner);
2438 if (token != GTK_RC_TOKEN_MODULE_PATH)
2439 return GTK_RC_TOKEN_MODULE_PATH;
2441 token = g_scanner_get_next_token (scanner);
2442 if (token != G_TOKEN_STRING)
2443 return G_TOKEN_STRING;
2445 gtk_rc_parse_module_path_string (scanner->value.v_string);
2447 return G_TOKEN_NONE;
2451 gtk_rc_parse_module_path_string (gchar *mod_path)
2455 gint start_offset = 0;
2459 /* free the old one, or just add to the old one ? */
2460 for (path_num=0; module_path[path_num]; path_num++)
2462 g_free (module_path[path_num]);
2463 module_path[path_num] = NULL;
2468 path_len = strlen (mod_path);
2470 buf = g_strdup (mod_path);
2472 for (end_offset = 0; end_offset <= path_len; end_offset++)
2474 if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
2475 (end_offset == path_len))
2477 buf[end_offset] = '\0';
2478 module_path[path_num] = g_strdup (buf + start_offset);
2480 module_path[path_num] = NULL;
2481 start_offset = end_offset + 1;
2485 gtk_rc_append_default_module_path();
2489 gtk_rc_parse_path_pattern (GScanner *scanner)
2492 GtkPathType path_type;
2494 gboolean is_binding;
2495 GtkPathPriorityType priority = GTK_PATH_PRIO_RC;
2497 token = g_scanner_get_next_token (scanner);
2500 case GTK_RC_TOKEN_WIDGET:
2501 path_type = GTK_PATH_WIDGET;
2503 case GTK_RC_TOKEN_WIDGET_CLASS:
2504 path_type = GTK_PATH_WIDGET_CLASS;
2506 case GTK_RC_TOKEN_CLASS:
2507 path_type = GTK_PATH_CLASS;
2510 return GTK_RC_TOKEN_WIDGET_CLASS;
2513 token = g_scanner_get_next_token (scanner);
2514 if (token != G_TOKEN_STRING)
2515 return G_TOKEN_STRING;
2517 pattern = g_strdup (scanner->value.v_string);
2519 token = g_scanner_get_next_token (scanner);
2520 if (token == GTK_RC_TOKEN_STYLE)
2522 else if (token == GTK_RC_TOKEN_BINDING)
2525 if (g_scanner_peek_next_token (scanner) == ':')
2527 token = gtk_rc_parse_priority (scanner, &priority);
2528 if (token != G_TOKEN_NONE)
2538 return GTK_RC_TOKEN_STYLE;
2541 token = g_scanner_get_next_token (scanner);
2542 if (token != G_TOKEN_STRING)
2545 return G_TOKEN_STRING;
2550 GtkBindingSet *binding;
2552 binding = gtk_binding_set_find (scanner->value.v_string);
2556 return G_TOKEN_STRING;
2558 gtk_binding_set_add_path (binding, path_type, pattern, priority);
2562 GtkRcStyle *rc_style;
2565 rc_style = gtk_rc_style_find (scanner->value.v_string);
2570 return G_TOKEN_STRING;
2573 rc_set = g_new (GtkRcSet, 1);
2574 gtk_pattern_spec_init (&rc_set->pspec, pattern);
2575 rc_set->rc_style = rc_style;
2577 if (path_type == GTK_PATH_WIDGET)
2578 gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set);
2579 else if (path_type == GTK_PATH_WIDGET_CLASS)
2580 gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set);
2582 gtk_rc_sets_class = g_slist_prepend (gtk_rc_sets_class, rc_set);
2586 return G_TOKEN_NONE;
2590 gtk_rc_parse_stock_id (GScanner *scanner,
2595 token = g_scanner_get_next_token (scanner);
2596 if (token != G_TOKEN_LEFT_BRACE)
2597 return G_TOKEN_LEFT_BRACE;
2599 token = g_scanner_get_next_token (scanner);
2601 if (token != G_TOKEN_STRING)
2602 return G_TOKEN_STRING;
2604 *stock_id = g_strdup (scanner->value.v_string);
2606 token = g_scanner_get_next_token (scanner);
2607 if (token != G_TOKEN_RIGHT_BRACE)
2610 return G_TOKEN_RIGHT_BRACE;
2613 return G_TOKEN_NONE;
2617 cleanup_source (GtkIconSource *source)
2619 g_free (source->filename);
2620 g_free (source->size);
2624 gtk_rc_parse_icon_source (GScanner *scanner,
2625 GtkIconSet *icon_set)
2628 GtkIconSource source = { NULL, NULL,
2632 token = g_scanner_get_next_token (scanner);
2633 if (token != G_TOKEN_LEFT_CURLY)
2634 return G_TOKEN_LEFT_CURLY;
2636 token = g_scanner_get_next_token (scanner);
2638 if (token != G_TOKEN_STRING)
2639 return G_TOKEN_STRING;
2641 source.filename = g_strdup (scanner->value.v_string);
2643 token = g_scanner_get_next_token (scanner);
2645 if (token == G_TOKEN_RIGHT_CURLY)
2647 gtk_icon_set_add_source (icon_set, &source);
2648 cleanup_source (&source);
2649 return G_TOKEN_NONE;
2651 else if (token != G_TOKEN_COMMA)
2653 cleanup_source (&source);
2654 return G_TOKEN_COMMA;
2657 /* Get the direction */
2659 token = g_scanner_get_next_token (scanner);
2663 case GTK_RC_TOKEN_RTL:
2664 source.any_direction = FALSE;
2665 source.direction = GTK_TEXT_DIR_RTL;
2668 case GTK_RC_TOKEN_LTR:
2669 source.any_direction = FALSE;
2670 source.direction = GTK_TEXT_DIR_LTR;
2677 cleanup_source (&source);
2678 return GTK_RC_TOKEN_RTL;
2682 token = g_scanner_get_next_token (scanner);
2684 if (token == G_TOKEN_RIGHT_CURLY)
2686 gtk_icon_set_add_source (icon_set, &source);
2687 cleanup_source (&source);
2688 return G_TOKEN_NONE;
2690 else if (token != G_TOKEN_COMMA)
2692 cleanup_source (&source);
2693 return G_TOKEN_COMMA;
2698 token = g_scanner_get_next_token (scanner);
2702 case GTK_RC_TOKEN_NORMAL:
2703 source.any_state = FALSE;
2704 source.state = GTK_STATE_NORMAL;
2707 case GTK_RC_TOKEN_PRELIGHT:
2708 source.any_state = FALSE;
2709 source.state = GTK_STATE_PRELIGHT;
2713 case GTK_RC_TOKEN_INSENSITIVE:
2714 source.any_state = FALSE;
2715 source.state = GTK_STATE_INSENSITIVE;
2718 case GTK_RC_TOKEN_ACTIVE:
2719 source.any_state = FALSE;
2720 source.state = GTK_STATE_ACTIVE;
2723 case GTK_RC_TOKEN_SELECTED:
2724 source.any_state = FALSE;
2725 source.state = GTK_STATE_SELECTED;
2732 cleanup_source (&source);
2733 return GTK_RC_TOKEN_PRELIGHT;
2737 token = g_scanner_get_next_token (scanner);
2739 if (token == G_TOKEN_RIGHT_CURLY)
2741 gtk_icon_set_add_source (icon_set, &source);
2742 cleanup_source (&source);
2743 return G_TOKEN_NONE;
2745 else if (token != G_TOKEN_COMMA)
2747 cleanup_source (&source);
2748 return G_TOKEN_COMMA;
2753 token = g_scanner_get_next_token (scanner);
2757 if (token != G_TOKEN_STRING)
2759 cleanup_source (&source);
2760 return G_TOKEN_STRING;
2763 source.size = g_strdup (scanner->value.v_string);
2764 source.any_size = FALSE;
2767 /* Check the close brace */
2769 token = g_scanner_get_next_token (scanner);
2770 if (token != G_TOKEN_RIGHT_CURLY)
2772 cleanup_source (&source);
2773 return G_TOKEN_RIGHT_CURLY;
2776 gtk_icon_set_add_source (icon_set, &source);
2778 cleanup_source (&source);
2780 return G_TOKEN_NONE;
2784 gtk_rc_parse_stock (GScanner *scanner,
2785 GtkRcStyle *rc_style,
2786 GtkIconFactory *factory)
2788 GtkIconSet *icon_set = NULL;
2789 gchar *stock_id = NULL;
2792 token = g_scanner_get_next_token (scanner);
2793 if (token != GTK_RC_TOKEN_STOCK)
2794 return GTK_RC_TOKEN_STOCK;
2796 token = gtk_rc_parse_stock_id (scanner, &stock_id);
2797 if (token != G_TOKEN_NONE)
2800 token = g_scanner_get_next_token (scanner);
2801 if (token != G_TOKEN_EQUAL_SIGN)
2804 return G_TOKEN_EQUAL_SIGN;
2807 token = g_scanner_get_next_token (scanner);
2808 if (token != G_TOKEN_LEFT_CURLY)
2811 return G_TOKEN_LEFT_CURLY;
2814 token = g_scanner_peek_next_token (scanner);
2815 while (token != G_TOKEN_RIGHT_CURLY)
2817 if (icon_set == NULL)
2818 icon_set = gtk_icon_set_new ();
2820 token = gtk_rc_parse_icon_source (scanner, icon_set);
2821 if (token != G_TOKEN_NONE)
2824 gtk_icon_set_unref (icon_set);
2828 token = g_scanner_get_next_token (scanner);
2830 if (token != G_TOKEN_COMMA &&
2831 token != G_TOKEN_RIGHT_CURLY)
2834 gtk_icon_set_unref (icon_set);
2835 return G_TOKEN_RIGHT_CURLY;
2841 gtk_icon_factory_add (factory,
2845 gtk_icon_set_unref (icon_set);
2850 return G_TOKEN_NONE;
2854 typedef GdkPixmap * (*GtkImageLoader) (GdkWindow *window,
2855 GdkColormap *colormap,
2857 GdkColor *transparent_color,
2858 const gchar *filename);
2862 gtk_rc_set_image_loader(GtkImageLoader loader)
2864 image_loader = loader;
2868 gtk_rc_load_image (GdkColormap *colormap,
2869 GdkColor *transparent_color,
2870 const gchar *filename)
2872 if (strcmp (filename, "<parent>") == 0)
2873 return (GdkPixmap*) GDK_PARENT_RELATIVE;
2877 return image_loader(NULL, colormap, NULL,
2881 return gdk_pixmap_colormap_create_from_xpm (NULL, colormap, NULL,