/* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include "gtkrc.h" #include "gtkbindings.h" typedef struct _GtkRcStyle GtkRcStyle; typedef struct _GtkRcSet GtkRcSet; typedef struct _GtkRcNode GtkRcNode; typedef struct _GtkRcFile GtkRcFile; struct _GtkRcNode { GdkColormap *cmap; GtkStyle *style; }; struct _GtkRcStyle { char *name; char *font_name; char *fontset_name; char *bg_pixmap_name[5]; GtkStyle *proto_style; GList *styles; }; struct _GtkRcSet { GtkPatternSpec pspec; GtkRcStyle *rc_style; }; struct _GtkRcFile { time_t mtime; gchar *name; gchar *canonical_name; gboolean reload; }; static guint gtk_rc_style_hash (const char *name); static gint gtk_rc_style_compare (const char *a, const char *b); static GtkRcStyle* gtk_rc_style_find (const char *name); static GtkRcStyle* gtk_rc_styles_match (GSList *sets, guint path_length, gchar *path, gchar *path_reversed); static GtkStyle* gtk_rc_style_init (GtkRcStyle *rc_style, GdkColormap *cmap); static void gtk_rc_parse_file (const gchar *filename, gboolean reload); static void gtk_rc_parse_any (const gchar *input_name, gint input_fd, const gchar *input_string); static guint gtk_rc_parse_statement (GScanner *scanner); static guint gtk_rc_parse_style (GScanner *scanner); static guint gtk_rc_parse_base (GScanner *scanner, GtkStyle *style); static guint gtk_rc_parse_bg (GScanner *scanner, GtkStyle *style); static guint gtk_rc_parse_fg (GScanner *scanner, GtkStyle *style); static guint gtk_rc_parse_text (GScanner *scanner, GtkStyle *style); static guint gtk_rc_parse_bg_pixmap (GScanner *scanner, GtkRcStyle *rc_style); static guint gtk_rc_parse_font (GScanner *scanner, GtkRcStyle *rc_style); static guint gtk_rc_parse_fontset (GScanner *scanner, GtkRcStyle *rc_style); static guint gtk_rc_parse_pixmap_path (GScanner *scanner); static void gtk_rc_parse_pixmap_path_string (gchar *pix_path); static char* gtk_rc_find_pixmap_in_path (GScanner *scanner, gchar *pixmap_file); static guint gtk_rc_parse_path_pattern (GScanner *scanner); static void gtk_rc_clear_hash_node (gpointer key, gpointer data, gpointer user_data); static void gtk_rc_clear_styles (void); static GScannerConfig gtk_rc_scanner_config = { ( " \t\n" ) /* cset_skip_characters */, ( G_CSET_a_2_z "_" G_CSET_A_2_Z ) /* cset_identifier_first */, ( G_CSET_a_2_z "_-0123456789" G_CSET_A_2_Z ) /* cset_identifier_nth */, ( "#\n" ) /* cpair_comment_single */, TRUE /* case_sensitive */, TRUE /* skip_comment_multi */, TRUE /* skip_comment_single */, TRUE /* scan_comment_multi */, TRUE /* scan_identifier */, FALSE /* scan_identifier_1char */, FALSE /* scan_identifier_NULL */, TRUE /* scan_symbols */, TRUE /* scan_binary */, TRUE /* scan_octal */, TRUE /* scan_float */, TRUE /* scan_hex */, TRUE /* scan_hex_dollar */, TRUE /* scan_string_sq */, TRUE /* scan_string_dq */, TRUE /* numbers_2_int */, FALSE /* int_2_float */, FALSE /* identifier_2_string */, TRUE /* char_2_token */, TRUE /* symbol_2_token */, FALSE /* scope_0_fallback */, }; static struct { gchar *name; guint token; } symbols[] = { { "include", GTK_RC_TOKEN_INCLUDE }, { "NORMAL", GTK_RC_TOKEN_NORMAL }, { "ACTIVE", GTK_RC_TOKEN_ACTIVE }, { "PRELIGHT", GTK_RC_TOKEN_PRELIGHT }, { "SELECTED", GTK_RC_TOKEN_SELECTED }, { "INSENSITIVE", GTK_RC_TOKEN_INSENSITIVE }, { "fg", GTK_RC_TOKEN_FG }, { "bg", GTK_RC_TOKEN_BG }, { "base", GTK_RC_TOKEN_BASE }, { "text", GTK_RC_TOKEN_TEXT }, { "font", GTK_RC_TOKEN_FONT }, { "fontset", GTK_RC_TOKEN_FONTSET }, { "bg_pixmap", GTK_RC_TOKEN_BG_PIXMAP }, { "pixmap_path", GTK_RC_TOKEN_PIXMAP_PATH }, { "style", GTK_RC_TOKEN_STYLE }, { "binding", GTK_RC_TOKEN_BINDING }, { "bind", GTK_RC_TOKEN_BIND }, { "widget", GTK_RC_TOKEN_WIDGET }, { "widget_class", GTK_RC_TOKEN_WIDGET_CLASS }, { "class", GTK_RC_TOKEN_CLASS }, { "lowest", GTK_RC_TOKEN_LOWEST }, { "gtk", GTK_RC_TOKEN_GTK }, { "application", GTK_RC_TOKEN_APPLICATION }, { "rc", GTK_RC_TOKEN_RC }, { "highest", GTK_RC_TOKEN_HIGHEST }, }; static guint n_symbols = sizeof (symbols) / sizeof (symbols[0]); static GHashTable *rc_style_ht = NULL; static GSList *gtk_rc_sets_widget = NULL; static GSList *gtk_rc_sets_widget_class = NULL; static GSList *gtk_rc_sets_class = NULL; #define GTK_RC_MAX_PIXMAP_PATHS 128 static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS]; /* The files we have parsed, to reread later if necessary */ GSList *rc_files = NULL; static GtkImageLoader image_loader = NULL; void gtk_rc_init (void) { rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash, (GCompareFunc) gtk_rc_style_compare); } void gtk_rc_parse_string (const gchar *rc_string) { g_return_if_fail (rc_string != NULL); gtk_rc_parse_any ("-", -1, rc_string); } static void gtk_rc_parse_file (const gchar *filename, gboolean reload) { GtkRcFile *rc_file = NULL; struct stat statbuf; GSList *tmp_list; g_return_if_fail (filename != NULL); tmp_list = rc_files; while (tmp_list) { rc_file = tmp_list->data; if (!strcmp (rc_file->name, filename)) break; tmp_list = tmp_list->next; } if (!tmp_list) { rc_file = g_new (GtkRcFile, 1); rc_file->name = g_strdup (filename); rc_file->canonical_name = NULL; rc_file->mtime = 0; rc_file->reload = reload; rc_files = g_slist_append (rc_files, rc_file); } if (!rc_file->canonical_name) { /* Get the absolute pathname */ if (rc_file->name[0] == '/') rc_file->canonical_name = rc_file->name; else { GString *str; gchar *cwd; cwd = g_get_current_dir (); str = g_string_new (cwd); g_free (cwd); g_string_append_c (str, '/'); g_string_append (str, rc_file->name); rc_file->canonical_name = str->str; g_string_free (str, FALSE); } } if (!lstat (rc_file->canonical_name, &statbuf)) { gint fd; rc_file->mtime = statbuf.st_mtime; fd = open (rc_file->canonical_name, O_RDONLY); if (fd < 0) return; gtk_rc_parse_any (filename, fd, NULL); close (fd); } } void gtk_rc_parse (const gchar *filename) { g_return_if_fail (filename != NULL); gtk_rc_parse_file (filename, TRUE); } static void gtk_rc_clear_hash_node (gpointer key, gpointer data, gpointer user_data) { int i; GtkRcStyle *rc_style = data; GList *tmp_list; g_free (rc_style->name); g_free (rc_style->font_name); g_free (rc_style->fontset_name); for (i=0 ; i<5 ; i++) g_free (rc_style->bg_pixmap_name[i]); gtk_style_unref (rc_style->proto_style); tmp_list = rc_style->styles; while (tmp_list) { GtkRcNode *node = tmp_list->data; gdk_colormap_unref (node->cmap); gtk_style_unref (node->style); g_free (node); tmp_list = tmp_list->next; } g_free (rc_style); } static void gtk_rc_free_rc_sets (GSList *slist) { while (slist) { GtkRcSet *rc_set; rc_set = slist->data; gtk_pattern_spec_free_segs (&rc_set->pspec); g_free (rc_set); slist = slist->next; } } static void gtk_rc_clear_styles (void) { /* Clear out all old rc_styles */ g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL); g_hash_table_destroy (rc_style_ht); rc_style_ht = NULL; gtk_rc_free_rc_sets (gtk_rc_sets_widget); g_slist_free (gtk_rc_sets_widget); gtk_rc_sets_widget = NULL; gtk_rc_free_rc_sets (gtk_rc_sets_widget_class); g_slist_free (gtk_rc_sets_widget_class); gtk_rc_sets_widget_class = NULL; gtk_rc_free_rc_sets (gtk_rc_sets_class); g_slist_free (gtk_rc_sets_class); gtk_rc_sets_class = NULL; gtk_rc_init (); } gboolean gtk_rc_reparse_all (void) { GSList *tmp_list; gboolean mtime_modified = FALSE; GtkRcFile *rc_file; struct stat statbuf; /* Check through and see if any of the RC's have had their * mtime modified. If so, reparse everything. */ tmp_list = rc_files; while (tmp_list) { rc_file = tmp_list->data; if (!lstat (rc_file->name, &statbuf) && (statbuf.st_mtime > rc_file->mtime)) { mtime_modified = TRUE; break; } tmp_list = tmp_list->next; } if (mtime_modified) { gtk_rc_clear_styles(); tmp_list = rc_files; while (tmp_list) { rc_file = tmp_list->data; if (rc_file->reload) gtk_rc_parse_file (rc_file->name, FALSE); tmp_list = tmp_list->next; } } return mtime_modified; } static GtkRcStyle* gtk_rc_styles_match (GSList *sets, guint path_length, gchar *path, gchar *path_reversed) { GtkRcSet *rc_set; while (sets) { rc_set = sets->data; sets = sets->next; if (gtk_pattern_match (&rc_set->pspec, path_length, path, path_reversed)) return rc_set->rc_style; } return NULL; } GtkStyle* gtk_rc_get_style (GtkWidget *widget) { GtkRcStyle *rc_style; if (gtk_rc_sets_widget) { gchar *path, *path_reversed; guint path_length; gtk_widget_path (widget, &path_length, &path, &path_reversed); rc_style = gtk_rc_styles_match (gtk_rc_sets_widget, path_length, path, path_reversed); g_free (path); g_free (path_reversed); if (rc_style) return gtk_rc_style_init (rc_style, gtk_widget_get_colormap (widget)); } if (gtk_rc_sets_widget_class) { gchar *path, *path_reversed; guint path_length; gtk_widget_class_path (widget, &path_length, &path, &path_reversed); rc_style = gtk_rc_styles_match (gtk_rc_sets_widget_class, path_length, path, path_reversed); g_free (path); g_free (path_reversed); if (rc_style) return gtk_rc_style_init (rc_style, gtk_widget_get_colormap (widget)); } if (gtk_rc_sets_class) { GtkType type; type = GTK_OBJECT_TYPE (widget); while (type) { gchar *path, *path_reversed; guint path_length; path = gtk_type_name (type); path_length = strlen (path); path_reversed = g_strdup (path); g_strreverse (path_reversed); rc_style = gtk_rc_styles_match (gtk_rc_sets_class, path_length, path, path_reversed); g_free (path_reversed); if (rc_style) return gtk_rc_style_init (rc_style, gtk_widget_get_colormap (widget)); type = gtk_type_parent (type); } } return NULL; } static GSList* gtk_rc_add_rc_sets (GSList *slist, GtkStyle *style, const char *pattern) { GtkRcStyle *rc_style; GtkRcSet *rc_set; guint i; gtk_style_ref (style); rc_style = g_new (GtkRcStyle, 1); rc_style->name = NULL; rc_style->font_name = NULL; rc_style->fontset_name = NULL; for (i = 0; i < 5; i++) rc_style->bg_pixmap_name[i] = NULL; rc_style->styles = g_list_append (NULL, style); rc_set = g_new (GtkRcSet, 1); gtk_pattern_spec_init (&rc_set->pspec, pattern); rc_set->rc_style = rc_style; return g_slist_prepend (slist, rc_set); } void gtk_rc_add_widget_name_style (GtkStyle *style, const gchar *pattern) { g_return_if_fail (style != NULL); g_return_if_fail (pattern != NULL); gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, style, pattern); } void gtk_rc_add_widget_class_style (GtkStyle *style, const gchar *pattern) { g_return_if_fail (style != NULL); g_return_if_fail (pattern != NULL); gtk_rc_sets_widget_class = gtk_rc_add_rc_sets (gtk_rc_sets_widget_class, style, pattern); } void gtk_rc_add_class_style (GtkStyle *style, const gchar *pattern) { g_return_if_fail (style != NULL); g_return_if_fail (pattern != NULL); gtk_rc_sets_class = gtk_rc_add_rc_sets (gtk_rc_sets_class, style, pattern); } static void gtk_rc_parse_any (const gchar *input_name, gint input_fd, const gchar *input_string) { GScanner *scanner; guint i; gboolean done; scanner = g_scanner_new (>k_rc_scanner_config); if (input_fd >= 0) { g_assert (input_string == NULL); g_scanner_input_file (scanner, input_fd); } else { g_assert (input_string != NULL); g_scanner_input_text (scanner, input_string, strlen (input_string)); } scanner->input_name = input_name; g_scanner_freeze_symbol_table (scanner); for (i = 0; i < n_symbols; i++) g_scanner_add_symbol (scanner, symbols[i].name, GINT_TO_POINTER (symbols[i].token)); g_scanner_thaw_symbol_table (scanner); done = FALSE; while (!done) { if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF) done = TRUE; else { guint expected_token; expected_token = gtk_rc_parse_statement (scanner); if (expected_token != G_TOKEN_NONE) { gchar *symbol_name; gchar *msg; msg = NULL; symbol_name = NULL; if (scanner->scope_id == 0) { /* if we are in scope 0, we know the symbol names * that are associated with certaintoken values. * so we look them up to make the error messages * more readable. */ if (expected_token > GTK_RC_TOKEN_INVALID && expected_token < GTK_RC_TOKEN_LAST) { for (i = 0; i < n_symbols; i++) if (symbols[i].token == expected_token) msg = symbols[i].name; if (msg) msg = g_strconcat ("e.g. `", msg, "'", NULL); } if (scanner->token > GTK_RC_TOKEN_INVALID && scanner->token < GTK_RC_TOKEN_LAST) { symbol_name = "???"; for (i = 0; i < n_symbols; i++) if (symbols[i].token == scanner->token) symbol_name = symbols[i].name; } } g_scanner_unexp_token (scanner, expected_token, NULL, "keyword", symbol_name, msg, TRUE); g_free (msg); done = TRUE; } } } g_scanner_destroy (scanner); } static guint gtk_rc_style_hash (const char *name) { guint result; result = 0; while (*name) result += (result << 3) + *name++; return result; } static gint gtk_rc_style_compare (const char *a, const char *b) { return (strcmp (a, b) == 0); } static GtkRcStyle* gtk_rc_style_find (const char *name) { GtkRcStyle *rc_style; rc_style = g_hash_table_lookup (rc_style_ht, (gpointer) name); return rc_style; } static GtkStyle * gtk_rc_style_init (GtkRcStyle *rc_style, GdkColormap *cmap) { GdkFont *old_font; gboolean match_cmap = FALSE; gint i; GList *tmp_list; GtkStyle *style = NULL; GtkRcNode *node; tmp_list = rc_style->styles; for (i=0; i<5; i++) if (rc_style->bg_pixmap_name[i]) match_cmap = TRUE; while (tmp_list) { node = (GtkRcNode *)tmp_list->data; if (!match_cmap || (node->cmap == cmap)) { style = node->style; break; } tmp_list = tmp_list->next; } if (!style) { node = g_new (GtkRcNode, 1); style = gtk_style_copy (rc_style->proto_style); /* FIXME, this leaks colormaps, but if we don't do this, then we'll * be screwed, because we identify colormaps by address equality */ gdk_colormap_ref (cmap); node->style = style; node->cmap = cmap; if (rc_style->fontset_name) { old_font = style->font; style->font = gdk_fontset_load (rc_style->fontset_name); if (style->font) gdk_font_unref (old_font); else style->font = old_font; } else if (rc_style->font_name) { old_font = style->font; style->font = gdk_font_load (rc_style->font_name); if (style->font) gdk_font_unref (old_font); else style->font = old_font; } for (i = 0; i < 5; i++) if (rc_style->bg_pixmap_name[i]) { if (strcmp (rc_style->bg_pixmap_name[i], "") == 0) style->bg_pixmap[i] = (GdkPixmap*) GDK_PARENT_RELATIVE; else { if(image_loader) style->bg_pixmap[i] = image_loader(NULL, cmap, NULL, &style->bg[i], rc_style->bg_pixmap_name[i]); else style->bg_pixmap[i] = gdk_pixmap_colormap_create_from_xpm (NULL, cmap, NULL, &style->bg[i], rc_style->bg_pixmap_name[i]); } } rc_style->styles = g_list_append (rc_style->styles, node); } return style; } static guint gtk_rc_parse_statement (GScanner *scanner) { guint token; token = g_scanner_peek_next_token (scanner); switch (token) { case GTK_RC_TOKEN_INCLUDE: token = g_scanner_get_next_token (scanner); if (token != GTK_RC_TOKEN_INCLUDE) return GTK_RC_TOKEN_INCLUDE; token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_STRING) return G_TOKEN_STRING; gtk_rc_parse_file (scanner->value.v_string, FALSE); return G_TOKEN_NONE; case GTK_RC_TOKEN_STYLE: return gtk_rc_parse_style (scanner); case GTK_RC_TOKEN_BINDING: return gtk_binding_parse_binding (scanner); case GTK_RC_TOKEN_PIXMAP_PATH: return gtk_rc_parse_pixmap_path (scanner); case GTK_RC_TOKEN_WIDGET: return gtk_rc_parse_path_pattern (scanner); case GTK_RC_TOKEN_WIDGET_CLASS: return gtk_rc_parse_path_pattern (scanner); case GTK_RC_TOKEN_CLASS: return gtk_rc_parse_path_pattern (scanner); default: g_scanner_get_next_token (scanner); return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE; } } static guint gtk_rc_parse_style (GScanner *scanner) { GtkRcStyle *rc_style; GtkRcStyle *parent_style; guint token; gint insert; gint i; token = g_scanner_get_next_token (scanner); if (token != GTK_RC_TOKEN_STYLE) return GTK_RC_TOKEN_STYLE; token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_STRING) return G_TOKEN_STRING; insert = FALSE; rc_style = g_hash_table_lookup (rc_style_ht, scanner->value.v_string); if (!rc_style) { insert = TRUE; rc_style = g_new (GtkRcStyle, 1); rc_style->name = g_strdup (scanner->value.v_string); rc_style->font_name = NULL; rc_style->fontset_name = NULL; for (i = 0; i < 5; i++) rc_style->bg_pixmap_name[i] = NULL; rc_style->proto_style = gtk_style_new(); rc_style->styles = NULL; } token = g_scanner_peek_next_token (scanner); if (token == G_TOKEN_EQUAL_SIGN) { token = g_scanner_get_next_token (scanner); token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_STRING) { if (insert) { gtk_style_unref (rc_style->proto_style); g_free (rc_style); } return G_TOKEN_STRING; } parent_style = g_hash_table_lookup (rc_style_ht, scanner->value.v_string); if (parent_style) { for (i = 0; i < 5; i++) { rc_style->proto_style->fg[i] = parent_style->proto_style->fg[i]; rc_style->proto_style->bg[i] = parent_style->proto_style->bg[i]; rc_style->proto_style->light[i] = parent_style->proto_style->light[i]; rc_style->proto_style->dark[i] = parent_style->proto_style->dark[i]; rc_style->proto_style->mid[i] = parent_style->proto_style->mid[i]; rc_style->proto_style->text[i] = parent_style->proto_style->text[i]; rc_style->proto_style->base[i] = parent_style->proto_style->base[i]; } rc_style->proto_style->black = parent_style->proto_style->black; rc_style->proto_style->white = parent_style->proto_style->white; if (rc_style->fontset_name) { g_free (rc_style->fontset_name); rc_style->fontset_name = g_strdup (parent_style->fontset_name); } else if (rc_style->font_name) { g_free (rc_style->font_name); rc_style->font_name = g_strdup (parent_style->font_name); } for (i = 0; i < 5; i++) { if (rc_style->bg_pixmap_name[i]) g_free (rc_style->bg_pixmap_name[i]); rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]); } } } token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_LEFT_CURLY) { if (insert) { gtk_style_unref (rc_style->proto_style); g_free (rc_style); } return G_TOKEN_LEFT_CURLY; } token = g_scanner_peek_next_token (scanner); while (token != G_TOKEN_RIGHT_CURLY) { switch (token) { case GTK_RC_TOKEN_BASE: token = gtk_rc_parse_base (scanner, rc_style->proto_style); break; case GTK_RC_TOKEN_BG: token = gtk_rc_parse_bg (scanner, rc_style->proto_style); break; case GTK_RC_TOKEN_FG: token = gtk_rc_parse_fg (scanner, rc_style->proto_style); break; case GTK_RC_TOKEN_TEXT: token = gtk_rc_parse_text (scanner, rc_style->proto_style); break; case GTK_RC_TOKEN_BG_PIXMAP: token = gtk_rc_parse_bg_pixmap (scanner, rc_style); break; case GTK_RC_TOKEN_FONT: token = gtk_rc_parse_font (scanner, rc_style); break; case GTK_RC_TOKEN_FONTSET: token = gtk_rc_parse_fontset (scanner, rc_style); break; default: g_scanner_get_next_token (scanner); token = G_TOKEN_RIGHT_CURLY; break; } if (token != G_TOKEN_NONE) { if (insert) { if (rc_style->fontset_name) g_free (rc_style->fontset_name); if (rc_style->font_name) g_free (rc_style->font_name); for (i = 0; i < 5; i++) if (rc_style->bg_pixmap_name[i]) g_free (rc_style->bg_pixmap_name[i]); gtk_style_unref (rc_style->proto_style); g_free (rc_style); } return token; } token = g_scanner_peek_next_token (scanner); } token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_RIGHT_CURLY) { if (insert) { if (rc_style->fontset_name) g_free (rc_style->fontset_name); if (rc_style->font_name) g_free (rc_style->font_name); for (i = 0; i < 5; i++) if (rc_style->bg_pixmap_name[i]) g_free (rc_style->bg_pixmap_name[i]); gtk_style_unref (rc_style->proto_style); g_free (rc_style); } return G_TOKEN_RIGHT_CURLY; } if (insert) g_hash_table_insert (rc_style_ht, rc_style->name, rc_style); return G_TOKEN_NONE; } static guint gtk_rc_parse_base (GScanner *scanner, GtkStyle *style) { GtkStateType state; guint token; token = g_scanner_get_next_token (scanner); if (token != GTK_RC_TOKEN_BASE) return GTK_RC_TOKEN_BASE; token = gtk_rc_parse_state (scanner, &state); if (token != G_TOKEN_NONE) return token; token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_EQUAL_SIGN) return G_TOKEN_EQUAL_SIGN; return gtk_rc_parse_color (scanner, &style->base[state]); } static guint gtk_rc_parse_bg (GScanner *scanner, GtkStyle *style) { GtkStateType state; guint token; token = g_scanner_get_next_token (scanner); if (token != GTK_RC_TOKEN_BG) return GTK_RC_TOKEN_BG; token = gtk_rc_parse_state (scanner, &state); if (token != G_TOKEN_NONE) return token; token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_EQUAL_SIGN) return G_TOKEN_EQUAL_SIGN; return gtk_rc_parse_color (scanner, &style->bg[state]); } static guint gtk_rc_parse_fg (GScanner *scanner, GtkStyle *style) { GtkStateType state; guint token; token = g_scanner_get_next_token (scanner); if (token != GTK_RC_TOKEN_FG) return GTK_RC_TOKEN_FG; token = gtk_rc_parse_state (scanner, &state); if (token != G_TOKEN_NONE) return token; token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_EQUAL_SIGN) return G_TOKEN_EQUAL_SIGN; return gtk_rc_parse_color (scanner, &style->fg[state]); } static guint gtk_rc_parse_text (GScanner *scanner, GtkStyle *style) { GtkStateType state; guint token; token = g_scanner_get_next_token (scanner); if (token != GTK_RC_TOKEN_TEXT) return GTK_RC_TOKEN_TEXT; token = gtk_rc_parse_state (scanner, &state); if (token != G_TOKEN_NONE) return token; token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_EQUAL_SIGN) return G_TOKEN_EQUAL_SIGN; return gtk_rc_parse_color (scanner, &style->text[state]); } static guint gtk_rc_parse_bg_pixmap (GScanner *scanner, GtkRcStyle *rc_style) { GtkStateType state; guint token; gchar *pixmap_file; token = g_scanner_get_next_token (scanner); if (token != GTK_RC_TOKEN_BG_PIXMAP) return GTK_RC_TOKEN_BG_PIXMAP; token = gtk_rc_parse_state (scanner, &state); if (token != G_TOKEN_NONE) return token; token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_EQUAL_SIGN) return G_TOKEN_EQUAL_SIGN; token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_STRING) return G_TOKEN_STRING; if (strcmp (scanner->value.v_string, "")) pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string); else pixmap_file = g_strdup (scanner->value.v_string); if (pixmap_file) { if (rc_style->bg_pixmap_name[state]) g_free (rc_style->bg_pixmap_name[state]); rc_style->bg_pixmap_name[state] = pixmap_file; } return G_TOKEN_NONE; } static gchar* gtk_rc_find_pixmap_in_path (GScanner *scanner, gchar *pixmap_file) { gint i; gint fd; gchar *buf; for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++) { buf = g_malloc (strlen (pixmap_path[i]) + strlen (pixmap_file) + 2); sprintf (buf, "%s%c%s", pixmap_path[i], '/', pixmap_file); fd = open (buf, O_RDONLY); if (fd >= 0) { close (fd); return buf; } g_free (buf); } g_warning ("Unable to locate image file in pixmap_path: \"%s\" line %d", pixmap_file, scanner->line); return NULL; } static guint gtk_rc_parse_font (GScanner *scanner, GtkRcStyle *rc_style) { guint token; token = g_scanner_get_next_token (scanner); if (token != GTK_RC_TOKEN_FONT) return GTK_RC_TOKEN_FONT; token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_EQUAL_SIGN) return G_TOKEN_EQUAL_SIGN; token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_STRING) return G_TOKEN_STRING; if (rc_style->font_name) g_free (rc_style->font_name); rc_style->font_name = g_strdup (scanner->value.v_string); return G_TOKEN_NONE; } static guint gtk_rc_parse_fontset (GScanner *scanner, GtkRcStyle *rc_style) { guint token; token = g_scanner_get_next_token (scanner); if (token != GTK_RC_TOKEN_FONTSET) return GTK_RC_TOKEN_FONTSET; token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_EQUAL_SIGN) return G_TOKEN_EQUAL_SIGN; token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_STRING) return G_TOKEN_STRING; if (rc_style->fontset_name) g_free (rc_style->fontset_name); rc_style->fontset_name = g_strdup (scanner->value.v_string); return G_TOKEN_NONE; } guint gtk_rc_parse_state (GScanner *scanner, GtkStateType *state) { guint old_scope; guint token; g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR); g_return_val_if_fail (state != NULL, G_TOKEN_ERROR); /* we don't know where we got called from, so we reset the scope here. * if we bail out due to errors, we *don't* reset the scope, so the * error messaging code can make sense of our tokens. */ old_scope = g_scanner_set_scope (scanner, 0); token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_LEFT_BRACE) return G_TOKEN_LEFT_BRACE; token = g_scanner_get_next_token (scanner); switch (token) { case GTK_RC_TOKEN_ACTIVE: *state = GTK_STATE_ACTIVE; break; case GTK_RC_TOKEN_INSENSITIVE: *state = GTK_STATE_INSENSITIVE; break; case GTK_RC_TOKEN_NORMAL: *state = GTK_STATE_NORMAL; break; case GTK_RC_TOKEN_PRELIGHT: *state = GTK_STATE_PRELIGHT; break; case GTK_RC_TOKEN_SELECTED: *state = GTK_STATE_SELECTED; break; default: return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL; } token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_RIGHT_BRACE) return G_TOKEN_RIGHT_BRACE; g_scanner_set_scope (scanner, old_scope); return G_TOKEN_NONE; } guint gtk_rc_parse_priority (GScanner *scanner, GtkPathPriorityType *priority) { guint old_scope; guint token; g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR); g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR); /* we don't know where we got called from, so we reset the scope here. * if we bail out due to errors, we *don't* reset the scope, so the * error messaging code can make sense of our tokens. */ old_scope = g_scanner_set_scope (scanner, 0); token = g_scanner_get_next_token (scanner); if (token != ':') return ':'; token = g_scanner_get_next_token (scanner); switch (token) { case GTK_RC_TOKEN_LOWEST: *priority = GTK_PATH_PRIO_LOWEST; break; case GTK_RC_TOKEN_GTK: *priority = GTK_PATH_PRIO_GTK; break; case GTK_RC_TOKEN_APPLICATION: *priority = GTK_PATH_PRIO_APPLICATION; break; case GTK_RC_TOKEN_RC: *priority = GTK_PATH_PRIO_RC; break; case GTK_RC_TOKEN_HIGHEST: *priority = GTK_PATH_PRIO_HIGHEST; break; default: return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION; } g_scanner_set_scope (scanner, old_scope); return G_TOKEN_NONE; } guint gtk_rc_parse_color (GScanner *scanner, GdkColor *color) { guint token; g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR); /* we don't need to set our own scop here, because * we don't need own symbols */ token = g_scanner_get_next_token (scanner); switch (token) { gint token_int; gint length; gint temp; gchar buf[9]; gint i, j; case G_TOKEN_LEFT_CURLY: token = g_scanner_get_next_token (scanner); if (token == G_TOKEN_INT) token_int = scanner->value.v_int; else if (token == G_TOKEN_FLOAT) token_int = scanner->value.v_float * 65535.0; else return G_TOKEN_FLOAT; color->red = CLAMP (token_int, 0, 65535); token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_COMMA) return G_TOKEN_COMMA; token = g_scanner_get_next_token (scanner); if (token == G_TOKEN_INT) token_int = scanner->value.v_int; else if (token == G_TOKEN_FLOAT) token_int = scanner->value.v_float * 65535.0; else return G_TOKEN_FLOAT; color->green = CLAMP (token_int, 0, 65535); token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_COMMA) return G_TOKEN_COMMA; token = g_scanner_get_next_token (scanner); if (token == G_TOKEN_INT) token_int = scanner->value.v_int; else if (token == G_TOKEN_FLOAT) token_int = scanner->value.v_float * 65535.0; else return G_TOKEN_FLOAT; color->blue = CLAMP (token_int, 0, 65535); token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_RIGHT_CURLY) return G_TOKEN_RIGHT_CURLY; return G_TOKEN_NONE; case G_TOKEN_STRING: if (scanner->value.v_string[0] != '#') return G_TOKEN_STRING; length = strlen (scanner->value.v_string) - 1; if (((length % 3) != 0) || (length > 12)) return G_TOKEN_STRING; length /= 3; for (i = 0, j = 1; i < length; i++, j++) buf[i] = scanner->value.v_string[j]; buf[i] = '\0'; sscanf (buf, "%x", &temp); color->red = temp; for (i = 0; i < length; i++, j++) buf[i] = scanner->value.v_string[j]; buf[i] = '\0'; sscanf (buf, "%x", &temp); color->green = temp; for (i = 0; i < length; i++, j++) buf[i] = scanner->value.v_string[j]; buf[i] = '\0'; sscanf (buf, "%x", &temp); color->blue = temp; if (length == 1) { color->red *= 4369; color->green *= 4369; color->blue *= 4369; } else if (length == 2) { color->red *= 257; color->green *= 257; color->blue *= 257; } else if (length == 3) { color->red *= 16; color->green *= 16; color->blue *= 16; } return G_TOKEN_NONE; default: return G_TOKEN_STRING; } } static guint gtk_rc_parse_pixmap_path (GScanner *scanner) { guint token; token = g_scanner_get_next_token (scanner); if (token != GTK_RC_TOKEN_PIXMAP_PATH) return GTK_RC_TOKEN_PIXMAP_PATH; token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_STRING) return G_TOKEN_STRING; gtk_rc_parse_pixmap_path_string (scanner->value.v_string); return G_TOKEN_NONE; } static void gtk_rc_parse_pixmap_path_string (gchar *pix_path) { gchar *buf; gint end_offset; gint start_offset = 0; gint path_len; gint path_num; /* free the old one, or just add to the old one ? */ for (path_num=0; pixmap_path[path_num]; path_num++) { g_free (pixmap_path[path_num]); pixmap_path[path_num] = NULL; } path_num = 0; path_len = strlen (pix_path); buf = g_strdup (pix_path); for (end_offset = 0; end_offset <= path_len; end_offset++) { if ((buf[end_offset] == ':') || (end_offset == path_len)) { buf[end_offset] = '\0'; pixmap_path[path_num] = g_strdup (buf + start_offset); path_num++; pixmap_path[path_num] = NULL; start_offset = end_offset + 1; } } g_free (buf); } static guint gtk_rc_parse_path_pattern (GScanner *scanner) { guint token; GtkPathType path_type; gchar *pattern; gboolean is_binding; GtkPathPriorityType priority = GTK_PATH_PRIO_RC; token = g_scanner_get_next_token (scanner); switch (token) { case GTK_RC_TOKEN_WIDGET: path_type = GTK_PATH_WIDGET; break; case GTK_RC_TOKEN_WIDGET_CLASS: path_type = GTK_PATH_WIDGET_CLASS; break; case GTK_RC_TOKEN_CLASS: path_type = GTK_PATH_CLASS; break; default: return GTK_RC_TOKEN_WIDGET_CLASS; } token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_STRING) return G_TOKEN_STRING; pattern = g_strdup (scanner->value.v_string); token = g_scanner_get_next_token (scanner); if (token == GTK_RC_TOKEN_STYLE) is_binding = FALSE; else if (token == GTK_RC_TOKEN_BINDING) { is_binding = TRUE; if (g_scanner_peek_next_token (scanner) == ':') { token = gtk_rc_parse_priority (scanner, &priority); if (token != G_TOKEN_NONE) { g_free (pattern); return token; } } } else { g_free (pattern); return GTK_RC_TOKEN_STYLE; } token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_STRING) { g_free (pattern); return G_TOKEN_STRING; } if (is_binding) { GtkBindingSet *binding; binding = gtk_binding_set_find (scanner->value.v_string); if (!binding) { g_free (pattern); return G_TOKEN_STRING; } gtk_binding_set_add_path (binding, path_type, pattern, priority); } else { GtkRcStyle *rc_style; GtkRcSet *rc_set; rc_style = gtk_rc_style_find (scanner->value.v_string); if (!rc_style) { g_free (pattern); return G_TOKEN_STRING; } rc_set = g_new (GtkRcSet, 1); gtk_pattern_spec_init (&rc_set->pspec, pattern); rc_set->rc_style = rc_style; if (path_type == GTK_PATH_WIDGET) gtk_rc_sets_widget = g_slist_prepend (gtk_rc_sets_widget, rc_set); else if (path_type == GTK_PATH_WIDGET_CLASS) gtk_rc_sets_widget_class = g_slist_prepend (gtk_rc_sets_widget_class, rc_set); else gtk_rc_sets_class = g_slist_prepend (gtk_rc_sets_class, rc_set); } g_free (pattern); return G_TOKEN_NONE; } /* typedef GdkPixmap * (*GtkImageLoader) (GdkWindow *window, GdkColormap *colormap, GdkBitmap **mask, GdkColor *transparent_color, const gchar *filename); */ void gtk_rc_set_image_loader(GtkImageLoader loader) { image_loader = loader; }