]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkrc.c
Support added for building using a GNU toolchain on Win32,
[~andy/gtk] / gtk / gtkrc.c
index 86bc20121b89863c256546738ff003e0e636ffcf..09d22a49b8a2f316e5f7d26bc0f74daf3b1d6e46 100644 (file)
  *
  * 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
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
  */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdkx.h"
+
+#if GDK_WINDOWING == GDK_WINDOWING_X11
+#include <X11/Xlocale.h>       /* so we get the right setlocale */
+#else
+#include <locale.h>
+#endif
 #include <ctype.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#include <fcntl.h>
+#include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
-#include "gtkrc.h"
-
-
-enum {
-  TOKEN_EOF,
-  TOKEN_LEFT_CURLY,
-  TOKEN_RIGHT_CURLY,
-  TOKEN_LEFT_BRACE,
-  TOKEN_RIGHT_BRACE,
-  TOKEN_EQUAL_SIGN,
-  TOKEN_COMMA,
-  TOKEN_INTEGER,
-  TOKEN_FLOAT,
-  TOKEN_STRING,
-  TOKEN_SYMBOL,
-  TOKEN_ACTIVE,
-  TOKEN_BASE,
-  TOKEN_BG,
-  TOKEN_BG_PIXMAP,
-  TOKEN_FG,
-  TOKEN_FONT,
-  TOKEN_FONTSET,
-  TOKEN_INSENSITIVE,
-  TOKEN_NORMAL,
-  TOKEN_PIXMAP_PATH,
-  TOKEN_PRELIGHT,
-  TOKEN_SELECTED,
-  TOKEN_STYLE,
-  TOKEN_TEXT,
-  TOKEN_WIDGET,
-  TOKEN_WIDGET_CLASS
-};
 
-enum {
-  PARSE_OK,
-  PARSE_ERROR,
-  PARSE_SYNTAX
-};
+#ifndef HAVE_LSTAT
+#define lstat stat
+#endif
 
-enum {
-  PARSE_START,
-  PARSE_COMMENT,
-  PARSE_STRING,
-  PARSE_SYMBOL,
-  PARSE_NUMBER
-};
+#ifdef NATIVE_WIN32
+#include <io.h>
+#endif
 
+#include "gtkrc.h"
+#include "gtkbindings.h"
+#include "gtkthemes.h"
+#include "gtkintl.h"
 
-typedef struct _GtkRcStyle  GtkRcStyle;
 typedef struct _GtkRcSet    GtkRcSet;
+typedef struct _GtkRcNode   GtkRcNode;
+typedef struct _GtkRcFile   GtkRcFile;
 
-struct _GtkRcStyle
+struct _GtkRcSet
 {
-  int initialize;
-  char *name;
-  char *font_name;
-  char *fontset_name;
-  char *bg_pixmap_name[5];
-  GtkStyle *style;
+  GtkPatternSpec pspec;
+  GtkRcStyle   *rc_style;
 };
 
-struct _GtkRcSet
+struct _GtkRcFile
 {
-  char *set;
-  GtkRcStyle *rc_style;
+  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,
-                                                   const char   *path);
-static gint        gtk_rc_style_match              (const char *set,
-                                                   const char *path);
-static void        gtk_rc_style_init               (GtkRcStyle *rc_style);
-static gint        gtk_rc_get_token                (void);
-static gint        gtk_rc_simple_token             (char ch);
-static gint        gtk_rc_symbol_token             (const char *sym);
-static gint        gtk_rc_get_next_token           (void);
-static gint        gtk_rc_peek_next_token          (void);
-static gint        gtk_rc_parse_statement          (void);
-static gint        gtk_rc_parse_style              (void);
-static gint        gtk_rc_parse_style_option       (GtkRcStyle   *rc_style);
-static gint        gtk_rc_parse_base               (GtkStyle     *style);
-static gint        gtk_rc_parse_bg                 (GtkStyle     *style);
-static gint        gtk_rc_parse_fg                 (GtkStyle     *style);
-static gint        gtk_rc_parse_bg_pixmap          (GtkRcStyle   *rc_style);
-static gint        gtk_rc_parse_font               (GtkRcStyle   *rc_style);
-static gint       gtk_rc_parse_fontset            (GtkRcStyle   *rc_style);
-static gint        gtk_rc_parse_state              (GtkStateType *state);
-static gint        gtk_rc_parse_color              (GdkColor     *color);
-static gint        gtk_rc_parse_pixmap_path        (void);
-static void        gtk_rc_parse_pixmap_path_string (gchar *pix_path);
-static char*       gtk_rc_find_pixmap_in_path      (gchar *pixmap_file);
-static gint        gtk_rc_parse_widget_style       (void);
-static gint        gtk_rc_parse_widget_class_style (void);
-static char*       gtk_rc_widget_path              (GtkWidget *widget);
-static char*       gtk_rc_widget_class_path        (GtkWidget *widget);
-
-
-static struct
+static guint      gtk_rc_style_hash               (const char   *name);
+static gint       gtk_rc_style_compare            (const char   *a,
+                                                   const char   *b);
+static guint      gtk_rc_styles_hash              (const GSList *rc_styles);
+static gint       gtk_rc_styles_compare           (const GSList *a,
+                                                   const GSList *b);
+static GtkRcStyle* gtk_rc_style_find              (const char   *name);
+static GSList *    gtk_rc_styles_match             (GSList       *rc_styles,
+                                                   GSList       *sets,
+                                                   guint         path_length,
+                                                   gchar        *path,
+                                                   gchar        *path_reversed);
+static GtkStyle *  gtk_rc_style_to_style           (GtkRcStyle   *rc_style);
+static GtkStyle*   gtk_rc_style_init              (GSList       *rc_styles);
+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,
+                                                   GtkRcStyle   *style);
+static guint      gtk_rc_parse_bg                 (GScanner     *scanner,
+                                                   GtkRcStyle   *style);
+static guint      gtk_rc_parse_fg                 (GScanner     *scanner,
+                                                   GtkRcStyle   *style);
+static guint      gtk_rc_parse_text               (GScanner     *scanner,
+                                                   GtkRcStyle   *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_engine             (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 guint      gtk_rc_parse_module_path        (GScanner     *scanner);
+static void       gtk_rc_parse_module_path_string (gchar *mod_path);
+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 void        gtk_rc_append_default_pixmap_path (void);
+static void        gtk_rc_append_default_module_path (void);
+static void        gtk_rc_append_pixmap_path         (gchar *dir);
+static void        gtk_rc_add_initial_default_files  (void);
+
+
+static const GScannerConfig    gtk_rc_scanner_config =
 {
-  char *name;
-  int token;
-} symbols[] =
-  {
-    { "ACTIVE", TOKEN_ACTIVE },
-    { "base", TOKEN_BASE },
-    { "bg", TOKEN_BG },
-    { "bg_pixmap", TOKEN_BG_PIXMAP },
-    { "fg", TOKEN_FG },
-    { "font", TOKEN_FONT },
-    { "fontset", TOKEN_FONTSET },
-    { "INSENSITIVE", TOKEN_INSENSITIVE },
-    { "NORMAL", TOKEN_NORMAL },
-    { "pixmap_path", TOKEN_PIXMAP_PATH },
-    { "PRELIGHT", TOKEN_PRELIGHT },
-    { "SELECTED", TOKEN_SELECTED },
-    { "style", TOKEN_STYLE },
-    { "text", TOKEN_TEXT },
-    { "widget", TOKEN_WIDGET },
-    { "widget_class", TOKEN_WIDGET_CLASS },
-  };
-
-static int nsymbols = sizeof (symbols) / sizeof (symbols[0]);
-
-static struct
+  (
+   " \t\r\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 const struct
 {
-  char ch;
-  int token;
-} simple_tokens[] =
-  {
-    { '{', TOKEN_LEFT_CURLY },
-    { '}', TOKEN_RIGHT_CURLY },
-    { '[', TOKEN_LEFT_BRACE },
-    { ']', TOKEN_RIGHT_BRACE },
-    { '=', TOKEN_EQUAL_SIGN },
-    { ',', TOKEN_COMMA },
-  };
-
-static int nsimple_tokens = sizeof (simple_tokens) / sizeof (simple_tokens[0]);
-
-static FILE *input_fp = NULL;
-static char *buffer = NULL;
-static char *tokenbuf = NULL;
-static int position = 0;
-static int linenum = 1;
-static int buffer_size = 1024;
-static int tokenbuf_size = 1024;
-
-static int done;
-static int cur_token;
-static int next_token;
-
-static char *token_str;
-static double token_float;
-static int token_int;
+  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 },
+  { "engine", GTK_RC_TOKEN_ENGINE },
+  { "module_path", GTK_RC_TOKEN_MODULE_PATH },
+};
+
+static const guint n_symbols = sizeof (symbols) / sizeof (symbols[0]);
 
 static GHashTable *rc_style_ht = NULL;
-static GSList *widget_sets = NULL;
-static GSList *widget_class_sets = NULL;
+static GHashTable *realized_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_DEFAULT_FILES 128
+static gchar *gtk_rc_default_files[GTK_RC_MAX_DEFAULT_FILES];
+static gboolean gtk_rc_auto_parse = TRUE;
 
 #define GTK_RC_MAX_PIXMAP_PATHS 128
 static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
+#define GTK_RC_MAX_MODULE_PATHS 128
+static gchar *module_path[GTK_RC_MAX_MODULE_PATHS];
 
+/* The files we have parsed, to reread later if necessary */
+GSList *rc_files = NULL;
 
-void
-gtk_rc_init ()
+static GtkImageLoader image_loader = NULL;
+
+/* RC file handling */
+
+
+#ifdef NATIVE_WIN32
+
+static gchar *
+get_gtk_sysconf_directory ()
 {
-  rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
-                                 (GCompareFunc) gtk_rc_style_compare);
+  static gchar gtk_sysconf_dir[200];
+  gchar win_dir[100];
+
+  GetWindowsDirectory (win_dir, sizeof (win_dir));
+  sprintf (gtk_sysconf_dir, "%s\\gtk", win_dir);
+  return gtk_sysconf_dir;
 }
 
-void
-gtk_rc_parse (const char *filename)
+static gchar *
+get_themes_directory ()
 {
-  input_fp = fopen (filename, "r");
-  if (!input_fp)
-         return;
+  /* We really should fetch this from the Registry. The GIMP
+   * installation program stores the Themes installation
+   * directory in HKLM\Software\GNU\GTk+\Themes\InstallDirectory.
+   * Later.
+   */
+  static gchar themes_dir[200];
+
+  sprintf (themes_dir, "%s\\themes", get_gtk_sysconf_directory ());
+  return themes_dir;
+}
 
-  buffer = g_new (char, buffer_size + tokenbuf_size);
-  tokenbuf = buffer + buffer_size;
-  position = 0;
-  linenum = 1;
+#endif
+gchar *
+gtk_rc_get_theme_dir(void)
+{
+  gchar *var, *path;
 
-  cur_token = -1;
-  next_token = -1;
-  done = FALSE;
+#ifndef NATIVE_WIN32
+  var = getenv("GTK_DATA_PREFIX");
+  if (var)
+    path = g_strdup_printf("%s%s", var, "/share/themes");
+  else
+    path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/themes");
+#else
+  path = g_strdup (get_themes_directory ());
+#endif
 
-  while (!done)
+  return path;
+}
+
+gchar *
+gtk_rc_get_module_dir(void)
+{
+  gchar *var, *path;
+
+#ifndef NATIVE_WIN32
+  var = getenv("GTK_EXE_PREFIX");
+  if (var)
+    path = g_strdup_printf("%s%s", var, "/lib/gtk/themes/engines");
+  else
+    path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk/themes/engines");
+#else
+  path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
+#endif
+
+  return path;
+}
+
+static void
+gtk_rc_append_default_pixmap_path(void)
+{
+  gchar *var, *path;
+  gint n;
+
+#ifndef NATIVE_WIN32
+  var = getenv("GTK_DATA_PREFIX");
+  if (var)
+    path = g_strdup_printf("%s%s", var, "/share/gtk/themes");
+  else
+    path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/gtk/themes");
+#else
+  path = g_strdup (get_themes_directory ());
+#endif      
+  
+  for (n = 0; pixmap_path[n]; n++) ;
+  if (n >= GTK_RC_MAX_PIXMAP_PATHS - 1)
     {
-      if (gtk_rc_parse_statement () != PARSE_OK)
-       {
-         g_warning ("rc file parse error: \"%s\" line %d",
-                    filename, linenum);
-         done = TRUE;
-       }
+      g_free (path);
+      return;
     }
+  pixmap_path[n++] = path;
+  pixmap_path[n] = NULL;
+}
 
-  fclose (input_fp);
+static void
+gtk_rc_append_pixmap_path(gchar *dir)
+{
+  gint n;
 
-  g_free (buffer);
+  for (n = 0; pixmap_path[n]; n++) ;
+  if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
+    return;
+  pixmap_path[n++] = g_strdup(dir);
+  pixmap_path[n] = NULL;
+}
 
-  buffer = NULL;
-  tokenbuf = NULL;
-  position = 0;
-  linenum = 1;
+static void
+gtk_rc_append_default_module_path(void)
+{
+  gchar *var, *path;
+  gint n;
+
+  for (n = 0; module_path[n]; n++) ;
+  if (n >= GTK_RC_MAX_MODULE_PATHS - 1)
+    return;
+  
+#ifndef NATIVE_WIN32
+  var = getenv("GTK_EXE_PREFIX");
+  if (var)
+    path = g_strdup_printf("%s%s", var, "/lib/gtk/themes/engines");
+  else
+    path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk/themes/engines");
+#else
+  path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
+#endif
+  module_path[n++] = path;
+
+  var = g_get_home_dir ();
+  if (var)
+    {
+#ifndef NATIVE_WIN32
+      path = g_strdup_printf ("%s%s", var, "/.gtk/lib/themes/engines");
+#else
+      path = g_strdup_printf ("%s%s", var, "\\_gtk\\themes\\engines");
+#endif
+      module_path[n++] = path;
+    }
+  module_path[n] = NULL;
 }
 
-GtkStyle*
-gtk_rc_get_style (GtkWidget *widget)
+static void
+gtk_rc_add_initial_default_files (void)
 {
-  GtkRcStyle *rc_style;
-  char *path;
+  static gint init = FALSE;
+  gchar *var, *str;
+  gchar **files;
+  gint i;
+
+  if (init)
+    return;
+  
+  gtk_rc_default_files[0] = NULL;
+  init = TRUE;
 
-  if (widget_sets)
+  var = g_getenv("GTK_RC_FILES");
+  if (var)
     {
-      path = gtk_rc_widget_path (widget);
-      if (path)
+      files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
+      i=0;
+      while (files[i])
        {
-         rc_style = gtk_rc_styles_match (widget_sets, path);
-         g_free (path);
-
-         if (rc_style)
-           {
-             gtk_rc_style_init (rc_style);
-             return rc_style->style;
-           }
+         gtk_rc_add_default_file (files[i]);
+         i++;
        }
+      g_strfreev (files);
     }
-
-  if (widget_class_sets)
+  else
     {
-      path = gtk_rc_widget_class_path (widget);
-      if (path)
+#ifndef NATIVE_WIN32
+      str = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk" G_DIR_SEPARATOR_S "gtkrc");
+#else
+      str = g_strdup_printf ("%s\\gtkrc", get_gtk_sysconf_directory ());
+#endif
+      gtk_rc_add_default_file (str);
+      g_free (str);
+
+      var = g_get_home_dir ();
+      if (var)
        {
-         rc_style = gtk_rc_styles_match (widget_class_sets, path);
-         g_free (path);
-
-         if (rc_style)
-           {
-             gtk_rc_style_init (rc_style);
-             return rc_style->style;
-           }
+         str = g_strdup_printf ("%s" G_DIR_SEPARATOR_S ".gtkrc", var);
+         gtk_rc_add_default_file (str);
+         g_free (str);
        }
     }
-
-  return widget->style;
 }
 
 void
-gtk_rc_add_widget_name_style (GtkStyle *style,
-                             const char     *pattern)
+gtk_rc_add_default_file (const gchar *file)
 {
-  GtkRcStyle *rc_style;
-  GtkRcSet *rc_set;
-  int i;
+  guint n;
+  
+  gtk_rc_add_initial_default_files ();
+
+  for (n = 0; gtk_rc_default_files[n]; n++) ;
+  if (n >= GTK_RC_MAX_DEFAULT_FILES - 1)
+    return;
+  
+  gtk_rc_default_files[n++] = g_strdup (file);
+  gtk_rc_default_files[n] = NULL;
+}
 
-  gtk_style_ref (style);
+void
+gtk_rc_set_default_files (gchar **files)
+{
+  gint i;
 
-  rc_style = g_new (GtkRcStyle, 1);
-  rc_style->initialize = FALSE;
-  rc_style->name = NULL;
-  rc_style->font_name = NULL;
-  rc_style->fontset_name = NULL;
+  gtk_rc_add_initial_default_files ();
 
-  for (i = 0; i < 5; i++)
-    rc_style->bg_pixmap_name[i] = NULL;
+  i = 0;
+  while (gtk_rc_default_files[i])
+    {
+      g_free (gtk_rc_default_files[i]);
+      i++;
+    }
+    
+  gtk_rc_default_files[0] = NULL;
+  gtk_rc_auto_parse = FALSE;
 
-  rc_style->style = style;
+  i = 0;
+  while (files[i] != NULL)
+    {
+      gtk_rc_add_default_file (files[i]);
+      i++;
+    }
+}
 
-  rc_set = g_new (GtkRcSet, 1);
-  rc_set->set = g_strdup (pattern);
-  rc_set->rc_style = rc_style;
+gchar **
+gtk_rc_get_default_files (void)
+{
+  gtk_rc_add_initial_default_files ();
 
-  widget_sets = g_slist_append (widget_sets, rc_set);
+  return gtk_rc_default_files;
 }
 
 void
-gtk_rc_add_widget_class_style (GtkStyle *style,
-                              const char     *pattern)
+gtk_rc_init (void)
 {
-  GtkRcStyle *rc_style;
-  GtkRcSet *rc_set;
-  int i;
+  gchar *locale_suffixes[3];
+  gint n_locale_suffixes = 0;
+  gint i, j;
+#ifdef HAVE_LC_MESSAGES
+  char *locale = setlocale (LC_MESSAGES, NULL);
+#else
+  char *locale = setlocale (LC_CTYPE, NULL);
+#endif
+  guint length;
+  char *p;
 
-  gtk_style_ref (style);
+  rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
+                                 (GCompareFunc) gtk_rc_style_compare);
+  pixmap_path[0] = NULL;
+  module_path[0] = NULL;
+  gtk_rc_append_default_pixmap_path();
+  gtk_rc_append_default_module_path();
 
-  rc_style = g_new (GtkRcStyle, 1);
-  rc_style->initialize = FALSE;
-  rc_style->name = NULL;
-  rc_style->font_name = NULL;
-  rc_style->fontset_name = NULL;
+  gtk_rc_add_initial_default_files ();
 
-  for (i = 0; i < 5; i++)
-    rc_style->bg_pixmap_name[i] = NULL;
+  if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
+    {
+      /* Determine locale-specific suffixes for RC files
+       */
+      p = strchr (locale, '@');
+      length = p ? (p -locale) : strlen (locale);
+      
+      p = strchr (locale, '.');
+      if (p)
+       {
+         locale_suffixes[n_locale_suffixes++] = g_strndup (locale, length);
+         length = p - locale;
+       }
+      
+      p = strchr (locale, '_');
+      if (p)
+       {
+         locale_suffixes[n_locale_suffixes++] = g_strndup (locale, length);
+         length = p - locale;
+       }
 
-  rc_style->style = style;
+      locale_suffixes[n_locale_suffixes++] = g_strndup (locale, length);
+    }
+  
+  i = 0;
+  while (gtk_rc_default_files[i] != NULL)
+    {
+      /* Try to find a locale specific RC file corresponding to
+       * to parse before the default file.
+       */
+      for (j=n_locale_suffixes-1; j>=0; j--)
+       {
+         gchar *name = g_strconcat (gtk_rc_default_files[i],
+                                    ".",
+                                    locale_suffixes[j],
+                                    NULL);
+         gtk_rc_parse (name);
+         g_free (name);
+       }
 
-  rc_set = g_new (GtkRcSet, 1);
-  rc_set->set = g_strdup (pattern);
-  rc_set->rc_style = rc_style;
+      gtk_rc_parse (gtk_rc_default_files[i]);
+      i++;
+    }
+ }
 
-  widget_class_sets = g_slist_append (widget_class_sets, rc_set);
-}
+void
+gtk_rc_parse_string (const gchar *rc_string)
+{
+  g_return_if_fail (rc_string != NULL);
 
+  gtk_rc_parse_any ("-", -1, rc_string);
+}
 
-static guint
-gtk_rc_style_hash (const char *name)
+static void
+gtk_rc_parse_file (const gchar *filename, gboolean reload)
 {
-  guint result;
+  GtkRcFile *rc_file = NULL;
+  struct stat statbuf;
+  GSList *tmp_list;
 
-  result = 0;
-  while (*name)
-    result += (result << 3) + *name++;
+  g_return_if_fail (filename != NULL);
 
-  return result;
+  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 (g_path_is_absolute (rc_file->name))
+       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_DIR_SEPARATOR);
+         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;
+
+       {
+         gint i;
+         gchar *dir;
+         
+         dir = g_strdup(rc_file->canonical_name);
+         for (i = strlen(dir) - 1; (i >= 0) && (dir[i] != G_DIR_SEPARATOR); i--)
+           dir[i] = 0;
+         gtk_rc_append_pixmap_path(dir);
+         g_free(dir);
+       }
+      gtk_rc_parse_any (filename, fd, NULL);
+
+      close (fd);
+    }
 }
 
-static gint
-gtk_rc_style_compare (const char *a,
-                     const char *b)
+void
+gtk_rc_parse (const gchar *filename)
 {
-  return (strcmp (a, b) == 0);
+  g_return_if_fail (filename != NULL);
+
+  gtk_rc_parse_file (filename, TRUE);
 }
 
-static GtkRcStyle*
-gtk_rc_style_find (const char *name)
+/* Handling of RC styles */
+
+GtkRcStyle *
+gtk_rc_style_new              (void)
 {
-  GtkRcStyle *rc_style;
+  GtkRcStyle *new_style;
 
-  rc_style = g_hash_table_lookup (rc_style_ht, (gpointer) name);
+  new_style = g_new0 (GtkRcStyle, 1);
+  new_style->ref_count = 1;
 
-  return rc_style;
+  return new_style;
 }
 
-static GtkRcStyle*
-gtk_rc_styles_match (GSList       *sets,
-                    const char   *path)
+void      
+gtk_rc_style_ref (GtkRcStyle  *rc_style)
 {
-  GtkRcSet *rc_set;
+  g_return_if_fail (rc_style != NULL);
 
-  while (sets)
+  rc_style->ref_count++;
+}
+
+void      
+gtk_rc_style_unref (GtkRcStyle  *rc_style)
+{
+  gint i;
+
+  g_return_if_fail (rc_style != NULL);
+  g_return_if_fail (rc_style->ref_count > 0);
+
+  rc_style->ref_count--;
+
+  if (rc_style->ref_count == 0)
     {
-      rc_set = sets->data;
-      sets = sets->next;
+      if (rc_style->engine)
+       {
+         rc_style->engine->destroy_rc_style (rc_style);
+         gtk_theme_engine_unref (rc_style->engine);
+       }
 
-      if (gtk_rc_style_match (rc_set->set, path))
-       return rc_set->rc_style;
+      if (rc_style->name)
+       g_free (rc_style->name);
+      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]);
+      
+      g_free (rc_style);
     }
+}
 
-  return NULL;
+static void
+gtk_rc_clear_realized_node (gpointer key,
+                           gpointer data,
+                           gpointer user_data)
+{
+  gtk_style_unref (data);
 }
 
-static gint
-gtk_rc_style_match (const char *set,
-                   const char *path)
+static void
+gtk_rc_clear_hash_node (gpointer key, 
+                       gpointer data, 
+                       gpointer user_data)
 {
-  char ch;
+  gtk_rc_style_unref (data);
+}
 
-  while (1)
+static void
+gtk_rc_free_rc_sets (GSList *slist)
+{
+  while (slist)
     {
-      ch = *set++;
-      if (ch == '\0')
-       return (*path == '\0');
+      GtkRcSet *rc_set;
 
-      switch (ch)
-       {
-       case '*':
-         while (*set == '*')
-           set++;
+      rc_set = slist->data;
+      gtk_pattern_spec_free_segs (&rc_set->pspec);
+      g_free (rc_set);
 
-         ch = *set++;
-         if (ch == '\0')
-           return TRUE;
+      slist = slist->next;
+    }
+}
 
-         while (*path)
-           {
-             while (*path && (ch != *path))
-               path++;
+static void
+gtk_rc_clear_styles (void)
+{
+  /* Clear out all old rc_styles */
 
-             if (!(*path))
-               return FALSE;
+  if (rc_style_ht)
+    {
+      g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
+      g_hash_table_destroy (rc_style_ht);
+      rc_style_ht = NULL;
+    }
 
-             path++;
-             if (gtk_rc_style_match (set, path))
-               return TRUE;
-           }
-         break;
+  if (realized_style_ht)
+    {
+      g_hash_table_foreach (realized_style_ht, gtk_rc_clear_realized_node, NULL);
+      g_hash_table_destroy (realized_style_ht);
+      realized_style_ht = NULL;
+    }
 
-       case '?':
-         break;
+  gtk_rc_free_rc_sets (gtk_rc_sets_widget);
+  g_slist_free (gtk_rc_sets_widget);
+  gtk_rc_sets_widget = NULL;
 
-       default:
-         if (ch == *path)
-           path++;
-         else
-           return FALSE;
-         break;
-       }
-    }
+  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;
 
-  return TRUE;
+  gtk_rc_init ();
 }
 
-static void
-gtk_rc_style_init (GtkRcStyle *rc_style)
+gboolean
+gtk_rc_reparse_all (void)
 {
-  GdkFont *old_font;
-  gint i;
+  GSList *tmp_list;
+  gboolean mtime_modified = FALSE;
+  GtkRcFile *rc_file;
 
-  if (rc_style->initialize)
-    {
-      rc_style->initialize = FALSE;
+  struct stat statbuf;
 
-      if (rc_style->fontset_name)
+  /* 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))
        {
-         old_font = rc_style->style->font;
-         rc_style->style->font = gdk_fontset_load (rc_style->fontset_name);
-         if (rc_style->style->font)
-           gdk_fontset_free (old_font);
-         else
-           rc_style->style->font = old_font;
+         mtime_modified = TRUE;
+         break;
        }
-      else if (rc_style->font_name)
+      
+      tmp_list = tmp_list->next;
+    }
+
+  if (mtime_modified)
+    {
+      gtk_rc_clear_styles();
+
+      tmp_list = rc_files;
+      while (tmp_list)
        {
-         old_font = rc_style->style->font;
-         rc_style->style->font = gdk_font_load (rc_style->font_name);
-         if (rc_style->style->font)
-           gdk_font_free (old_font);
-         else
-           rc_style->style->font = old_font;
+         rc_file = tmp_list->data;
+         if (rc_file->reload)
+           gtk_rc_parse_file (rc_file->name, FALSE);
+         
+         tmp_list = tmp_list->next;
        }
+    }
 
-      for (i = 0; i < 5; i++)
-       if (rc_style->bg_pixmap_name[i])
-         {
-           if (strcmp (rc_style->bg_pixmap_name[i], "<parent>") == 0)
-             rc_style->style->bg_pixmap[i] = (GdkPixmap*) GDK_PARENT_RELATIVE;
-           else
-             rc_style->style->bg_pixmap[i] = gdk_pixmap_create_from_xpm (NULL, NULL,
-                                                                         &rc_style->style->bg[i],
-                                                                         rc_style->bg_pixmap_name[i]);
-         }
+  return mtime_modified;
+}
+
+static GSList *
+gtk_rc_styles_match (GSList       *rc_styles,
+                    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))
+       rc_styles = g_slist_append (rc_styles, rc_set->rc_style);
     }
+  
+  return rc_styles;
 }
 
-static gint
-gtk_rc_get_token ()
+GtkStyle*
+gtk_rc_get_style (GtkWidget *widget)
 {
-  int tokenpos;
-  int state;
-  int count;
-  int token;
-  int hex_number = FALSE;
-  int float_number = FALSE;
-  char ch;
-
-  tokenpos = 0;
-  state = PARSE_START;
-
-  while (1)
+  GtkRcStyle *widget_rc_style;
+  GSList *rc_styles = NULL;
+
+  static guint rc_style_key_id = 0;
+
+  /* We allow the specification of a single rc style to be bound
+   * tightly to a widget, for application modifications
+   */
+  if (!rc_style_key_id)
+    rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
+
+  widget_rc_style = gtk_object_get_data_by_id (GTK_OBJECT (widget),
+                                              rc_style_key_id);
+
+  if (widget_rc_style)
+    rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
+  
+  if (gtk_rc_sets_widget)
+    {
+      gchar *path, *path_reversed;
+      guint path_length;
+
+      gtk_widget_path (widget, &path_length, &path, &path_reversed);
+      rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget, path_length, path, path_reversed);
+      g_free (path);
+      g_free (path_reversed);
+      
+    }
+  
+  if (gtk_rc_sets_widget_class)
+    {
+      gchar *path, *path_reversed;
+      guint path_length;
+
+      gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
+      rc_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_widget_class, path_length, path, path_reversed);
+      g_free (path);
+      g_free (path_reversed);
+    }
+
+  if (gtk_rc_sets_class)
     {
-      if (position >= (buffer_size - 1))
-       position = 0;
-      if (!position || (buffer[position] == '\0'))
+      GtkType type;
+
+      type = GTK_OBJECT_TYPE (widget);
+      while (type)
        {
-         count = fread (buffer, sizeof (char), buffer_size - 1, input_fp);
-         if ((count == 0) && feof (input_fp))
-           return TOKEN_EOF;
-         buffer[count] = '\0';
+         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_styles = gtk_rc_styles_match (rc_styles, gtk_rc_sets_class, path_length, path, path_reversed);
+         g_free (path_reversed);
+      
+         type = gtk_type_parent (type);
        }
+    }
+  
+  if (rc_styles)
+    return gtk_rc_style_init (rc_styles);
 
-      ch = buffer[position++];
-      if (ch == '\n')
-       linenum += 1;
+  return NULL;
+}
 
-      switch (state)
-       {
-       case PARSE_START:
-         token = gtk_rc_simple_token (ch);
-
-         if (token)
-           return token;
-         else if (ch == '#')
-           state = PARSE_COMMENT;
-         else if (ch == '"')
-           state = PARSE_STRING;
-         else if ((ch == ' ') || (ch == '\t') || (ch == '\n'))
-           break;
-         else if (ch == '.')
-           {
-             hex_number = FALSE;
-             float_number = TRUE;
-             tokenbuf[tokenpos++] = ch;
-             state = PARSE_NUMBER;
-           }
-         else if ((ch == '$') || (ch == '#'))
-           {
-             hex_number = TRUE;
-             float_number = FALSE;
-             state = PARSE_NUMBER;
-           }
-         else if (isdigit (ch))
-           {
-             hex_number = FALSE;
-             float_number = FALSE;
-             tokenbuf[tokenpos++] = ch;
-             state = PARSE_NUMBER;
-           }
-         else
-           {
-             tokenbuf[tokenpos++] = ch;
-             state = PARSE_SYMBOL;
-           }
-         break;
+static GSList*
+gtk_rc_add_rc_sets (GSList     *slist,
+                   GtkRcStyle *rc_style,
+                   const char *pattern)
+{
+  GtkRcStyle *new_style;
+  GtkRcSet *rc_set;
+  guint i;
+  
+  new_style = gtk_rc_style_new ();
+  *new_style = *rc_style;
+  new_style->name = g_strdup (rc_style->name);
+  new_style->font_name = g_strdup (rc_style->font_name);
+  new_style->fontset_name = g_strdup (rc_style->fontset_name);
+  
+  for (i = 0; i < 5; i++)
+    new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
+  
+  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);
+}
 
-       case PARSE_COMMENT:
-         if (ch == '\n')
-           state = PARSE_START;
-         break;
+void
+gtk_rc_add_widget_name_style (GtkRcStyle  *rc_style,
+                             const gchar *pattern)
+{
+  g_return_if_fail (rc_style != NULL);
+  g_return_if_fail (pattern != NULL);
 
-       case PARSE_STRING:
-         if (ch != '"')
-           {
-             tokenbuf[tokenpos++] = ch;
-           }
-         else
-           {
-             tokenbuf[tokenpos] = '\0';
-             token_str = tokenbuf;
-             return TOKEN_STRING;
-           }
-         break;
+  gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, rc_style, pattern);
+}
 
-       case PARSE_SYMBOL:
-         if ((ch != ' ') && (ch != '\t') && (ch != '\n') &&
-             (gtk_rc_simple_token (ch) == 0))
-           {
-             tokenbuf[tokenpos++] = ch;
-           }
-         else
-           {
-             position -= 1;
-             tokenbuf[tokenpos] = '\0';
-             token_str = tokenbuf;
-             return gtk_rc_symbol_token (tokenbuf);
-           }
-         break;
+void
+gtk_rc_add_widget_class_style (GtkRcStyle  *rc_style,
+                              const gchar *pattern)
+{
+  g_return_if_fail (rc_style != NULL);
+  g_return_if_fail (pattern != NULL);
 
-       case PARSE_NUMBER:
-         if (isdigit (ch) || (hex_number && isxdigit (ch)))
-           {
-             tokenbuf[tokenpos++] = ch;
-           }
-         else if (!hex_number && !float_number && (ch == '.'))
-           {
-             float_number = TRUE;
-             tokenbuf[tokenpos++] = ch;
-           }
-         else if (!float_number &&
-                  (ch == 'x') && (tokenpos == 1) &&
-                  (tokenbuf[0] == '0'))
-           {
-             hex_number = TRUE;
-             tokenpos = 0;
-           }
-         else
+  gtk_rc_sets_widget_class = gtk_rc_add_rc_sets (gtk_rc_sets_widget_class, rc_style, pattern);
+}
+
+void
+gtk_rc_add_class_style (GtkRcStyle  *rc_style,
+                       const gchar *pattern)
+{
+  g_return_if_fail (rc_style != NULL);
+  g_return_if_fail (pattern != NULL);
+
+  gtk_rc_sets_class = gtk_rc_add_rc_sets (gtk_rc_sets_class, rc_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 ((GScannerConfig *) &gtk_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)
            {
-             position -= 1;
-             tokenbuf[tokenpos] = '\0';
-             if (float_number)
+             gchar *symbol_name;
+             gchar *msg;
+             
+             msg = NULL;
+             symbol_name = NULL;
+             if (scanner->scope_id == 0)
                {
-                 sscanf (tokenbuf, "%lf", &token_float);
-                 return TOKEN_FLOAT;
-               }
-             else
-               {
-                 sscanf (tokenbuf, (hex_number ? "%x" : "%d"), &token_int);
-                 return TOKEN_INTEGER;
+                 /* 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;
            }
-         break;
        }
     }
+  
+  g_scanner_destroy (scanner);
 }
 
-static gint
-gtk_rc_simple_token (char ch)
+static guint      
+gtk_rc_styles_hash (const GSList *rc_styles)
 {
-  gint i;
+  guint result;
+  
+  result = 0;
+  while (rc_styles)
+    {
+      result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
+      rc_styles = rc_styles->next;
+    }
+  
+  return result;
+}
 
-  for (i = 0; i < nsimple_tokens; i++)
-    if (simple_tokens[i].ch == ch)
-      return simple_tokens[i].token;
+static gint       
+gtk_rc_styles_compare (const GSList *a,
+                      const GSList *b)
+{
+  while (a && b)
+    {
+      if (a->data != b->data)
+       return FALSE;
+      a = a->next;
+      b = b->next;
+    }
+  
+  return (a == b);
+}
 
-  return 0;
+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_symbol_token (const char *sym)
+gtk_rc_style_compare (const char *a,
+                     const char *b)
 {
-  gint i;
-
-  for (i = 0; i < nsymbols; i++)
-    if (strcmp (symbols[i].name, sym) == 0)
-      return symbols[i].token;
+  return (strcmp (a, b) == 0);
+}
 
-  return TOKEN_STRING;
+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 gint
-gtk_rc_get_next_token ()
+/* Assumes ownership of rc_style */
+static GtkStyle *
+gtk_rc_style_to_style (GtkRcStyle *rc_style)
 {
-  if (next_token != -1)
+  GtkStyle *style;
+  GdkFont *old_font;
+  gint i;
+
+  style = gtk_style_new ();
+
+  style->rc_style = rc_style;
+  
+  if (rc_style->fontset_name)
     {
-      cur_token = next_token;
-      next_token = -1;
+      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
+  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->color_flags[i] & GTK_RC_FG)
+       style->fg[i] = rc_style->fg[i];
+      if (rc_style->color_flags[i] & GTK_RC_BG)
+       style->bg[i] = rc_style->bg[i];
+      if (rc_style->color_flags[i] & GTK_RC_TEXT)
+       style->text[i] = rc_style->text[i];
+      if (rc_style->color_flags[i] & GTK_RC_BASE)
+       style->base[i] = rc_style->base[i];
+    }
+
+  if (rc_style->engine)
     {
-      cur_token = gtk_rc_get_token ();
+      style->engine = rc_style->engine;
+      gtk_theme_engine_ref (style->engine);
+      rc_style->engine->rc_style_to_style (style, rc_style);
     }
 
-  return cur_token;
+  return style;
 }
 
-static gint
-gtk_rc_peek_next_token ()
+/* Reuses or frees rc_styles */
+static GtkStyle *
+gtk_rc_style_init (GSList *rc_styles)
 {
-  if (next_token == -1)
-    next_token = gtk_rc_get_token ();
+  gint i;
+
+  GtkStyle *style = NULL;
+  GtkRcStyle *proto_style;
+
+  if (!realized_style_ht)
+    realized_style_ht = g_hash_table_new ((GHashFunc)gtk_rc_styles_hash,
+                                          (GCompareFunc)gtk_rc_styles_compare);
+
+  style = g_hash_table_lookup (realized_style_ht, rc_styles);
+
+  if (!style)
+    {
+      GSList *tmp_styles = rc_styles;
+      
+      proto_style = gtk_rc_style_new ();
+
+      while (tmp_styles)
+       {
+         GtkRcStyle *rc_style = tmp_styles->data;
+
+         for (i=0; i<5; i++)
+           {
+             if (!proto_style->bg_pixmap_name[i] && rc_style->bg_pixmap_name[i])
+               proto_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
+
+             if (!(proto_style->color_flags[i] & GTK_RC_FG) && 
+                   rc_style->color_flags[i] & GTK_RC_FG)
+               {
+                 proto_style->fg[i] = rc_style->fg[i];
+                 proto_style->color_flags[i] |= GTK_RC_FG;
+               }
+             if (!(proto_style->color_flags[i] & GTK_RC_BG) && 
+                   rc_style->color_flags[i] & GTK_RC_BG)
+               {
+                 proto_style->bg[i] = rc_style->bg[i];
+                 proto_style->color_flags[i] |= GTK_RC_BG;
+               }
+             if (!(proto_style->color_flags[i] & GTK_RC_TEXT) && 
+                   rc_style->color_flags[i] & GTK_RC_TEXT)
+               {
+                 proto_style->text[i] = rc_style->text[i];
+                 proto_style->color_flags[i] |= GTK_RC_TEXT;
+               }
+             if (!(proto_style->color_flags[i] & GTK_RC_BASE) && 
+                   rc_style->color_flags[i] & GTK_RC_BASE)
+               {
+                 proto_style->base[i] = rc_style->base[i];
+                 proto_style->color_flags[i] |= GTK_RC_BASE;
+               }
+           }
+
+         if (!proto_style->font_name && rc_style->font_name)
+           proto_style->font_name = g_strdup (rc_style->font_name);
+         if (!proto_style->fontset_name && rc_style->fontset_name)
+           proto_style->fontset_name = g_strdup (rc_style->fontset_name);
+
+         if (!proto_style->engine && rc_style->engine)
+           {
+             proto_style->engine = rc_style->engine;
+             gtk_theme_engine_ref (proto_style->engine);
+           }
+         
+         if (proto_style->engine &&
+             (proto_style->engine == rc_style->engine))
+           proto_style->engine->merge_rc_style (proto_style, rc_style);
+
+         tmp_styles = tmp_styles->next;
+       }
+
+      for (i=0; i<5; i++)
+       if (proto_style->bg_pixmap_name[i] &&
+           (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
+         {
+           g_free (proto_style->bg_pixmap_name[i]);
+           proto_style->bg_pixmap_name[i] = NULL;
+         }
+
+      style = gtk_rc_style_to_style (proto_style);
+
+      g_hash_table_insert (realized_style_ht, rc_styles, style);
+    }
 
-  return next_token;
+  return style;
 }
 
-static gint
-gtk_rc_parse_statement ()
+/*********************
+ * Parsing functions *
+ *********************/
+
+static guint
+gtk_rc_parse_statement (GScanner *scanner)
 {
-  gint token;
-  gint error;
+  guint token;
+  
+  token = g_scanner_peek_next_token (scanner);
 
-  token = gtk_rc_peek_next_token ();
-  if (!token)
+  switch (token)
     {
-      done = TRUE;
-      return PARSE_OK;
-    }
+    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;
 
-  error = gtk_rc_parse_style ();
-  if (error != PARSE_SYNTAX)
-    return error;
+      gtk_rc_parse_file (scanner->value.v_string, FALSE);
+      return G_TOKEN_NONE;
 
-  error = gtk_rc_parse_pixmap_path ();
-  if (error != PARSE_SYNTAX)
-    return error;
+    case GTK_RC_TOKEN_STYLE:
+      return gtk_rc_parse_style (scanner);
 
-  error = gtk_rc_parse_widget_style ();
-  if (error != PARSE_SYNTAX)
-    return error;
+    case GTK_RC_TOKEN_BINDING:
+      return gtk_binding_parse_binding (scanner);
 
-  error = gtk_rc_parse_widget_class_style ();
+    case GTK_RC_TOKEN_PIXMAP_PATH:
+      return gtk_rc_parse_pixmap_path (scanner);
 
-  return error;
+    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);
+
+    case GTK_RC_TOKEN_MODULE_PATH:
+      return gtk_rc_parse_module_path (scanner);
+       
+    default:
+      g_scanner_get_next_token (scanner);
+      return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
+    }
 }
 
-static gint
-gtk_rc_parse_style ()
+static guint
+gtk_rc_parse_style (GScanner *scanner)
 {
   GtkRcStyle *rc_style;
   GtkRcStyle *parent_style;
-  gint token;
-  gint error;
-  gint insert;
-  gint i;
-
-  token = gtk_rc_peek_next_token ();
-  if (!token)
-    return PARSE_ERROR;
-  if (token != TOKEN_STYLE)
-    return PARSE_SYNTAX;
-  token = gtk_rc_get_next_token ();
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_STRING))
-    return PARSE_ERROR;
-
+  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, token_str);
-
+  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->initialize = TRUE;
-      rc_style->name = g_strdup (token_str);
-      rc_style->font_name = NULL;
-      rc_style->fontset_name = NULL;
-
+      rc_style = gtk_rc_style_new ();
+      rc_style->name = g_strdup (scanner->value.v_string);
+      
       for (i = 0; i < 5; i++)
        rc_style->bg_pixmap_name[i] = NULL;
 
-      rc_style->style = gtk_style_new ();
-      gtk_style_ref (rc_style->style);
-    }
+      for (i = 0; i < 5; i++)
+       rc_style->color_flags[i] = 0;
 
-  token = gtk_rc_peek_next_token ();
-  if (token == TOKEN_EQUAL_SIGN)
+      rc_style->engine = NULL;
+      rc_style->engine_data = NULL;
+    }
+  
+  token = g_scanner_peek_next_token (scanner);
+  if (token == G_TOKEN_EQUAL_SIGN)
     {
-      token = gtk_rc_get_next_token ();
-
-      token = gtk_rc_get_next_token ();
-      if (!token || (token != TOKEN_STRING))
+      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->style);
-             g_free (rc_style);
-           }
-         return PARSE_ERROR;
-       }
+           g_free (rc_style);
 
-      parent_style = g_hash_table_lookup (rc_style_ht, token_str);
+         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->style->fg[i] = parent_style->style->fg[i];
-             rc_style->style->bg[i] = parent_style->style->bg[i];
-             rc_style->style->light[i] = parent_style->style->light[i];
-             rc_style->style->dark[i] = parent_style->style->dark[i];
-             rc_style->style->mid[i] = parent_style->style->mid[i];
-             rc_style->style->text[i] = parent_style->style->text[i];
-             rc_style->style->base[i] = parent_style->style->base[i];
+             rc_style->color_flags[i] = parent_style->color_flags[i];
+             rc_style->fg[i] = parent_style->fg[i];
+             rc_style->bg[i] = parent_style->bg[i];
+             rc_style->text[i] = parent_style->text[i];
+             rc_style->base[i] = parent_style->base[i];
            }
-
-         rc_style->style->black = parent_style->style->black;
-         rc_style->style->white = parent_style->style->white;
-
-         if (rc_style->fontset_name)
+         
+         if (parent_style->fontset_name)
            {
-             g_free (rc_style->fontset_name);
+             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)
+         else if (parent_style->font_name)
            {
-             g_free (rc_style->font_name);
+             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])
@@ -779,435 +1362,566 @@ gtk_rc_parse_style ()
            }
        }
     }
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_LEFT_CURLY))
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_LEFT_CURLY)
     {
       if (insert)
+       g_free (rc_style);
+
+      return G_TOKEN_LEFT_CURLY;
+    }
+  
+  token = g_scanner_peek_next_token (scanner);
+  while (token != G_TOKEN_RIGHT_CURLY)
+    {
+      switch (token)
        {
-         gtk_style_unref (rc_style->style);
-         g_free (rc_style);
+       case GTK_RC_TOKEN_BASE:
+         token = gtk_rc_parse_base (scanner, rc_style);
+         break;
+       case GTK_RC_TOKEN_BG:
+         token = gtk_rc_parse_bg (scanner, rc_style);
+         break;
+       case GTK_RC_TOKEN_FG:
+         token = gtk_rc_parse_fg (scanner, rc_style);
+         break;
+       case GTK_RC_TOKEN_TEXT:
+         token = gtk_rc_parse_text (scanner, rc_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;
+       case GTK_RC_TOKEN_ENGINE:
+         token = gtk_rc_parse_engine (scanner, rc_style);
+         break;
+       default:
+         g_scanner_get_next_token (scanner);
+         token = G_TOKEN_RIGHT_CURLY;
+         break;
        }
-      return PARSE_ERROR;
-    }
 
-  while (1)
-    {
-      error = gtk_rc_parse_style_option (rc_style);
-      if (error == PARSE_SYNTAX)
-       break;
-      if (error == PARSE_ERROR)
+      if (token != G_TOKEN_NONE)
        {
          if (insert)
            {
-             gtk_style_unref (rc_style->style);
+             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]);
              g_free (rc_style);
            }
-         return error;
+         return token;
        }
+      token = g_scanner_peek_next_token (scanner);
     }
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_RIGHT_CURLY))
+  
+  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);
-         else if (rc_style->font_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->style);
+         
          g_free (rc_style);
        }
-      return PARSE_ERROR;
+      return G_TOKEN_RIGHT_CURLY;
     }
-
+  
   if (insert)
     g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
-
-  return PARSE_OK;
+  
+  return G_TOKEN_NONE;
 }
 
-static gint
-gtk_rc_parse_style_option (GtkRcStyle *rc_style)
+static guint
+gtk_rc_parse_base (GScanner   *scanner,
+                  GtkRcStyle *style)
 {
-  gint token;
-  gint error;
-
-  token = gtk_rc_peek_next_token ();
-  if (!token)
-    return PARSE_ERROR;
-
-  error = gtk_rc_parse_base (rc_style->style);
-  if (error != PARSE_SYNTAX)
-    return error;
-
-  error = gtk_rc_parse_bg (rc_style->style);
-  if (error != PARSE_SYNTAX)
-    return error;
-
-  error = gtk_rc_parse_fg (rc_style->style);
-  if (error != PARSE_SYNTAX)
-    return error;
-
-  error = gtk_rc_parse_bg_pixmap (rc_style);
-  if (error != PARSE_SYNTAX)
-    return error;
-
-  error = gtk_rc_parse_font (rc_style);
-  if (error != PARSE_SYNTAX)
-    return error;
-
-  error = gtk_rc_parse_fontset (rc_style);
-
-  return error;
+  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;
+
+  style->color_flags[state] |= GTK_RC_BASE;
+  return gtk_rc_parse_color (scanner, &style->base[state]);
 }
 
-static gint
-gtk_rc_parse_base (GtkStyle *style)
+static guint
+gtk_rc_parse_bg (GScanner   *scanner,
+                GtkRcStyle *style)
 {
   GtkStateType state;
-  gint token;
-  gint error;
-
-  token = gtk_rc_peek_next_token ();
-  if (!token)
-    return PARSE_ERROR;
-  if (token != TOKEN_BASE)
-    return PARSE_SYNTAX;
-  token = gtk_rc_get_next_token ();
-
-  error = gtk_rc_parse_state (&state);
-  if (error != PARSE_OK)
-    return error;
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_EQUAL_SIGN))
-    return PARSE_ERROR;
-
-  error = gtk_rc_parse_color (&style->base[state]);
-
-  return error;
+  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;
+
+  style->color_flags[state] |= GTK_RC_BG;
+  return gtk_rc_parse_color (scanner, &style->bg[state]);
 }
 
-static gint
-gtk_rc_parse_bg (GtkStyle *style)
+static guint
+gtk_rc_parse_fg (GScanner   *scanner,
+                GtkRcStyle *style)
 {
   GtkStateType state;
-  gint token;
-  gint error;
-
-  token = gtk_rc_peek_next_token ();
-  if (!token)
-    return PARSE_ERROR;
-  if (token != TOKEN_BG)
-    return PARSE_SYNTAX;
-  token = gtk_rc_get_next_token ();
-
-  error = gtk_rc_parse_state (&state);
-  if (error != PARSE_OK)
-    return error;
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_EQUAL_SIGN))
-    return PARSE_ERROR;
-
-  error = gtk_rc_parse_color (&style->bg[state]);
-
-  return error;
+  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;
+  
+  style->color_flags[state] |= GTK_RC_FG;
+  return gtk_rc_parse_color (scanner, &style->fg[state]);
 }
 
-static gint
-gtk_rc_parse_fg (GtkStyle *style)
+static guint
+gtk_rc_parse_text (GScanner   *scanner,
+                  GtkRcStyle *style)
 {
   GtkStateType state;
-  gint token;
-  gint error;
-
-  token = gtk_rc_peek_next_token ();
-  if (!token)
-    return PARSE_ERROR;
-  if (token != TOKEN_FG)
-    return PARSE_SYNTAX;
-  token = gtk_rc_get_next_token ();
-
-  error = gtk_rc_parse_state (&state);
-  if (error != PARSE_OK)
-    return error;
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_EQUAL_SIGN))
-    return PARSE_ERROR;
-
-  error = gtk_rc_parse_color (&style->fg[state]);
-
-  return error;
+  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;
+  
+  style->color_flags[state] |= GTK_RC_TEXT;
+  return gtk_rc_parse_color (scanner, &style->text[state]);
 }
 
-static gint
-gtk_rc_parse_bg_pixmap (GtkRcStyle *rc_style)
+static guint
+gtk_rc_parse_bg_pixmap (GScanner   *scanner,
+                       GtkRcStyle *rc_style)
 {
   GtkStateType state;
-  gint token;
-  gint error;
+  guint token;
   gchar *pixmap_file;
-
-  token = gtk_rc_peek_next_token ();
-  if (!token)
-    return PARSE_ERROR;
-  if (token != TOKEN_BG_PIXMAP)
-    return PARSE_SYNTAX;
-  token = gtk_rc_get_next_token ();
-
-  error = gtk_rc_parse_state (&state);
-  if (error != PARSE_OK)
-    return error;
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_EQUAL_SIGN))
-    return PARSE_ERROR;
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_STRING))
-    return PARSE_ERROR;
-
-  if (strcmp (token_str, "<parent>"))
-    pixmap_file = gtk_rc_find_pixmap_in_path (token_str);
+  
+  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, "<parent>") == 0) ||
+      (strcmp (scanner->value.v_string, "<none>") == 0))
+    pixmap_file = g_strdup (scanner->value.v_string);
   else
-    pixmap_file = g_strdup(token_str);
-
+    pixmap_file = gtk_rc_find_pixmap_in_path (scanner, 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 PARSE_OK;
+  
+  return G_TOKEN_NONE;
 }
 
-static char*
-gtk_rc_find_pixmap_in_path (gchar *pixmap_file)
+gchar*
+gtk_rc_find_pixmap_in_path (GScanner *scanner,
+                           const gchar *pixmap_file)
 {
   gint i;
-  FILE *fp;
+  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);
-
-      fp = fopen (buf, "r");
-      if (fp)
+      buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
+                            pixmap_path[i], pixmap_file);
+      
+      fd = open (buf, O_RDONLY);
+      if (fd >= 0)
        {
-         fclose (fp);
+         close (fd);
          return buf;
        }
-
+      
       g_free (buf);
     }
 
-  g_warning ("Unable to locate image file in pixmap_path: \"%s\" line %d",
-            pixmap_file, linenum);
-
+  if (scanner)
+    g_warning (_("Unable to locate image file in pixmap_path: \"%s\" line %d"),
+              pixmap_file, scanner->line);
+  else
+    g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
+              pixmap_file);
+    
   return NULL;
 }
 
-static gint
-gtk_rc_parse_font (GtkRcStyle *rc_style)
+gchar*
+gtk_rc_find_module_in_path (const gchar *module_file)
 {
-  gint token;
-
-  token = gtk_rc_peek_next_token ();
-  if (!token)
-    return PARSE_ERROR;
-  if (token != TOKEN_FONT)
-    return PARSE_SYNTAX;
-  token = gtk_rc_get_next_token ();
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_EQUAL_SIGN))
-    return PARSE_ERROR;
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_STRING))
-    return PARSE_ERROR;
+  gint i;
+  gint fd;
+  gchar *buf;
+  
+  for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_path[i] != NULL); i++)
+    {
+      buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
+                            module_path[i], module_file);
+      
+      fd = open (buf, O_RDONLY);
+      if (fd >= 0)
+       {
+         close (fd);
+         return buf;
+       }
+      
+      g_free (buf);
+    }
+    
+  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 (token_str);
-
-  return PARSE_OK;
+  rc_style->font_name = g_strdup (scanner->value.v_string);
+  
+  return G_TOKEN_NONE;
 }
 
-static gint
-gtk_rc_parse_fontset (GtkRcStyle *rc_style)
+static guint
+gtk_rc_parse_fontset (GScanner  *scanner,
+                     GtkRcStyle *rc_style)
 {
-  gint token;
+  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;
+}
 
-  token = gtk_rc_peek_next_token ();
-  if (!token)
-    return PARSE_ERROR;
-  if (token != TOKEN_FONTSET)
-    return PARSE_SYNTAX;
-  token = gtk_rc_get_next_token ();
+static guint      
+gtk_rc_parse_engine (GScanner   *scanner,
+                    GtkRcStyle  *rc_style)
+{
+  guint token;
 
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_EQUAL_SIGN))
-    return PARSE_ERROR;
+  token = g_scanner_get_next_token (scanner);
+  if (token != GTK_RC_TOKEN_ENGINE)
+    return GTK_RC_TOKEN_ENGINE;
 
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_STRING))
-    return PARSE_ERROR;
+  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 (token_str);
+  rc_style->engine = gtk_theme_engine_get (scanner->value.v_string);
 
-  return PARSE_OK;
-}
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_LEFT_CURLY)
+    return G_TOKEN_LEFT_CURLY;
 
-static gint
-gtk_rc_parse_state (GtkStateType *state)
-{
-  gint token;
-
-  token = gtk_rc_peek_next_token ();
-  if (!token)
-    return PARSE_ERROR;
-  if (token != TOKEN_LEFT_BRACE)
-    return PARSE_SYNTAX;
-  token = gtk_rc_get_next_token ();
-
-  token = gtk_rc_get_next_token ();
-  if (token == TOKEN_ACTIVE)
-    *state = GTK_STATE_ACTIVE;
-  else if (token == TOKEN_INSENSITIVE)
-    *state = GTK_STATE_INSENSITIVE;
-  else if (token == TOKEN_NORMAL)
-    *state = GTK_STATE_NORMAL;
-  else if (token == TOKEN_PRELIGHT)
-    *state = GTK_STATE_PRELIGHT;
-  else if (token == TOKEN_SELECTED)
-    *state = GTK_STATE_SELECTED;
+  if (rc_style->engine)
+    return rc_style->engine->parse_rc_style (scanner, rc_style);
   else
-    return PARSE_ERROR;
+    {
+      /* Skip over remainder, looking for nested {}'s */
+      guint count = 1;
+      
+      while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
+       {
+         if (token == G_TOKEN_LEFT_CURLY)
+           count++;
+         else if (token == G_TOKEN_RIGHT_CURLY)
+           count--;
 
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_RIGHT_BRACE))
-    return PARSE_ERROR;
+         if (count == 0)
+           return G_TOKEN_NONE;
+       }
 
-  return PARSE_OK;
+      return G_TOKEN_RIGHT_CURLY;
+    }
 }
 
-static gint
-gtk_rc_parse_color (GdkColor *color)
+guint
+gtk_rc_parse_state (GScanner    *scanner,
+                   GtkStateType *state)
 {
-  gint token;
-  gint length;
-  gint temp;
-  gchar buf[9];
-  gint i, j;
-
-  token = gtk_rc_peek_next_token ();
-  if (!token)
-    return PARSE_ERROR;
+  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 TOKEN_LEFT_CURLY:
-      token = gtk_rc_get_next_token ();
-
-      token = gtk_rc_get_next_token ();
-      if (!token || ((token != TOKEN_INTEGER) && (token != TOKEN_FLOAT)))
-       return PARSE_ERROR;
-
-      if (token == TOKEN_FLOAT)
-       token_int = token_float * 65535.0;
-      if (token_int < 0)
-       token_int = 0;
-      if (token_int > 65535)
-       token_int = 65535;
-
-      color->red = token_int;
-
-      token = gtk_rc_get_next_token ();
-      if (!token || (token != TOKEN_COMMA))
-       return PARSE_ERROR;
-
-      token = gtk_rc_get_next_token ();
-      if (!token || ((token != TOKEN_INTEGER) && (token != TOKEN_FLOAT)))
-       return PARSE_ERROR;
-
-      if (token == TOKEN_FLOAT)
-       token_int = token_float * 65535.0;
-      if (token_int < 0)
-       token_int = 0;
-      if (token_int > 65535)
-       token_int = 65535;
-
-      color->green = token_int;
-
-      token = gtk_rc_get_next_token ();
-      if (!token || (token != TOKEN_COMMA))
-       return PARSE_ERROR;
-
-      token = gtk_rc_get_next_token ();
-      if (!token || ((token != TOKEN_INTEGER) && (token != TOKEN_FLOAT)))
-       return PARSE_ERROR;
-
-      if (token == TOKEN_FLOAT)
-       token_int = token_float * 65535.0;
-      if (token_int < 0)
-       token_int = 0;
-      if (token_int > 65535)
-       token_int = 65535;
-
-      color->blue = token_int;
-
-      token = gtk_rc_get_next_token ();
-      if (!token || (token != TOKEN_RIGHT_CURLY))
-       return PARSE_ERROR;
+    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;
+}
 
-    case TOKEN_STRING:
-      token = gtk_rc_get_next_token ();
+guint
+gtk_rc_parse_color (GScanner *scanner,
+                   GdkColor *color)
+{
+  guint token;
 
-      if (token_str[0] != '#')
-       return PARSE_ERROR;
+  g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
 
-      length = strlen (token_str) - 1;
+  /* 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 PARSE_ERROR;
+       return G_TOKEN_STRING;
       length /= 3;
-
+      
       for (i = 0, j = 1; i < length; i++, j++)
-       buf[i] = token_str[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] = token_str[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] = token_str[j];
+       buf[i] = scanner->value.v_string[j];
       buf[i] = '\0';
-
+      
       sscanf (buf, "%x", &temp);
       color->blue = temp;
-
+      
       if (length == 1)
        {
          color->red *= 4369;
@@ -1226,264 +1940,256 @@ gtk_rc_parse_color (GdkColor *color)
          color->green *= 16;
          color->blue *= 16;
        }
-      break;
-
+      return G_TOKEN_NONE;
+      
     default:
-      return PARSE_SYNTAX;
+      return G_TOKEN_STRING;
     }
-
-  return PARSE_OK;
 }
 
-static gint
-gtk_rc_parse_pixmap_path ()
+static guint
+gtk_rc_parse_pixmap_path (GScanner *scanner)
 {
-  gint token;
-
-  token = gtk_rc_peek_next_token ();
-  if (!token)
-    return PARSE_ERROR;
-  if (token != TOKEN_PIXMAP_PATH)
-    return PARSE_SYNTAX;
-  token = gtk_rc_get_next_token ();
-
-  token = gtk_rc_get_next_token ();
-
-  if (!token || (token != TOKEN_STRING))
-    return PARSE_ERROR;
-
-  gtk_rc_parse_pixmap_path_string(token_str);
-
-  return PARSE_OK;
+  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)
+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]);
+      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++)
+  
+  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) )
+      if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
+         (end_offset == path_len))
        {
          buf[end_offset] = '\0';
-         pixmap_path[path_num] = g_strdup(buf + start_offset);
+         pixmap_path[path_num] = g_strdup (buf + start_offset);
          path_num++;
          pixmap_path[path_num] = NULL;
          start_offset = end_offset + 1;
-         g_free(buf);
-         buf = g_strdup(pix_path);
        }
     }
-  g_free(buf);
+  g_free (buf);
+  gtk_rc_append_default_pixmap_path();
 }
 
-static gint
-gtk_rc_parse_widget_style ()
+static guint
+gtk_rc_parse_module_path (GScanner *scanner)
 {
-  GtkRcSet *rc_set;
-  gint token;
-
-  token = gtk_rc_peek_next_token ();
-  if (!token)
-    return PARSE_ERROR;
-  if (token != TOKEN_WIDGET)
-    return PARSE_SYNTAX;
-  token = gtk_rc_get_next_token ();
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_STRING))
-    return PARSE_ERROR;
-
-  rc_set = g_new (GtkRcSet, 1);
-  rc_set->set = g_strdup (token_str);
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_STYLE))
-    {
-      g_free (rc_set->set);
-      g_free (rc_set);
-      return PARSE_ERROR;
-    }
+  guint token;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != GTK_RC_TOKEN_MODULE_PATH)
+    return GTK_RC_TOKEN_MODULE_PATH;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_STRING)
+    return G_TOKEN_STRING;
+  
+  gtk_rc_parse_module_path_string (scanner->value.v_string);
+  
+  return G_TOKEN_NONE;
+}
 
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_STRING))
+static void
+gtk_rc_parse_module_path_string (gchar *mod_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; module_path[path_num]; path_num++)
     {
-      g_free (rc_set->set);
-      g_free (rc_set);
-      return PARSE_ERROR;
+      g_free (module_path[path_num]);
+      module_path[path_num] = NULL;
     }
-
-  rc_set->rc_style = gtk_rc_style_find (token_str);
-  if (!rc_set->rc_style)
+  
+  path_num = 0;
+  
+  path_len = strlen (mod_path);
+  
+  buf = g_strdup (mod_path);
+  
+  for (end_offset = 0; end_offset <= path_len; end_offset++)
     {
-      g_free (rc_set->set);
-      g_free (rc_set);
-      return PARSE_ERROR;
+      if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
+         (end_offset == path_len))
+       {
+         buf[end_offset] = '\0';
+         module_path[path_num] = g_strdup (buf + start_offset);
+         path_num++;
+         module_path[path_num] = NULL;
+         start_offset = end_offset + 1;
+       }
     }
-
-  widget_sets = g_slist_append (widget_sets, rc_set);
-
-  return PARSE_OK;
+  g_free (buf);
+  gtk_rc_append_default_module_path();
 }
 
-static gint
-gtk_rc_parse_widget_class_style ()
+static guint
+gtk_rc_parse_path_pattern (GScanner   *scanner)
 {
-  GtkRcSet *rc_set;
-  gint token;
-
-  token = gtk_rc_peek_next_token ();
-  if (!token)
-    return PARSE_ERROR;
-  if (token != TOKEN_WIDGET_CLASS)
-    return PARSE_SYNTAX;
-  token = gtk_rc_get_next_token ();
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_STRING))
-    return PARSE_ERROR;
-
-  rc_set = g_new (GtkRcSet, 1);
-  rc_set->set = g_strdup (token_str);
-
-  token = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_STYLE))
+  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)
     {
-      g_free (rc_set->set);
-      g_free (rc_set);
-      return PARSE_ERROR;
+    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 = gtk_rc_get_next_token ();
-  if (!token || (token != TOKEN_STRING))
+  token = g_scanner_get_next_token (scanner);
+  if (token == GTK_RC_TOKEN_STYLE)
+    is_binding = FALSE;
+  else if (token == GTK_RC_TOKEN_BINDING)
     {
-      g_free (rc_set->set);
-      g_free (rc_set);
-      return PARSE_ERROR;
+      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;
+           }
+       }
     }
-
-  rc_set->rc_style = gtk_rc_style_find (token_str);
-  if (!rc_set->rc_style)
+  else
     {
-      g_free (rc_set->set);
-      g_free (rc_set);
-      return PARSE_ERROR;
+      g_free (pattern);
+      return GTK_RC_TOKEN_STYLE;
     }
-
-  widget_class_sets = g_slist_append (widget_class_sets, rc_set);
-
-  return PARSE_OK;
-}
-
-static char*
-gtk_rc_widget_path (GtkWidget *widget)
-{
-  GtkWidget *tmp_widget;
-  char *path;
-  char *name;
-  int pathlength;
-  int namelength;
-
-  path = NULL;
-  pathlength = 0;
-
-  tmp_widget = widget;
-  while (tmp_widget)
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_STRING)
     {
-      name = gtk_widget_get_name (tmp_widget);
-      pathlength += strlen (name);
-
-      tmp_widget = tmp_widget->parent;
-
-      if (tmp_widget)
-       pathlength += 1;
+      g_free (pattern);
+      return G_TOKEN_STRING;
     }
 
-  path = g_new (char, pathlength + 1);
-  path[pathlength] = '\0';
-
-  tmp_widget = widget;
-  while (tmp_widget)
+  if (is_binding)
     {
-      name = gtk_widget_get_name (tmp_widget);
-      namelength = strlen (name);
-
-      strncpy (&path[pathlength - namelength], name, namelength);
-      pathlength -= namelength;
-
-      tmp_widget = tmp_widget->parent;
+      GtkBindingSet *binding;
 
-      if (tmp_widget)
+      binding = gtk_binding_set_find (scanner->value.v_string);
+      if (!binding)
        {
-         pathlength -= 1;
-         path[pathlength] = '.';
+         g_free (pattern);
+         return G_TOKEN_STRING;
        }
+      gtk_binding_set_add_path (binding, path_type, pattern, priority);
     }
-
-  return path;
-}
-
-static char*
-gtk_rc_widget_class_path (GtkWidget *widget)
-{
-  GtkWidget *tmp_widget;
-  char *path;
-  char *name;
-  int pathlength;
-  int namelength;
-
-  path = NULL;
-  pathlength = 0;
-
-  tmp_widget = widget;
-  while (tmp_widget)
+  else
     {
-      name = gtk_type_name (GTK_WIDGET_TYPE (tmp_widget));
-      pathlength += strlen (name);
+      GtkRcStyle *rc_style;
+      GtkRcSet *rc_set;
 
-      tmp_widget = tmp_widget->parent;
+      rc_style = gtk_rc_style_find (scanner->value.v_string);
+      
+      if (!rc_style)
+       {
+         g_free (pattern);
+         return G_TOKEN_STRING;
+       }
 
-      if (tmp_widget)
-       pathlength += 1;
-    }
+      rc_set = g_new (GtkRcSet, 1);
+      gtk_pattern_spec_init (&rc_set->pspec, pattern);
+      rc_set->rc_style = rc_style;
 
-  path = g_new (char, pathlength + 1);
-  path[pathlength] = '\0';
+      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);
+    }
 
-  tmp_widget = widget;
-  while (tmp_widget)
-    {
-      name = gtk_type_name (GTK_WIDGET_TYPE (tmp_widget));
-      namelength = strlen (name);
+  g_free (pattern);
+  return G_TOKEN_NONE;
+}
 
-      strncpy (&path[pathlength - namelength], name, namelength);
-      pathlength -= namelength;
+/*
+typedef  GdkPixmap * (*GtkImageLoader) (GdkWindow   *window,
+                                        GdkColormap *colormap,
+                                        GdkBitmap  **mask,
+                                        GdkColor    *transparent_color,
+                                        const gchar *filename);
+*/
 
-      tmp_widget = tmp_widget->parent;
+void
+gtk_rc_set_image_loader(GtkImageLoader loader)
+{
+  image_loader = loader;
+}
 
-      if (tmp_widget)
-       {
-         pathlength -= 1;
-         path[pathlength] = '.';
-       }
+GdkPixmap *
+gtk_rc_load_image (GdkColormap *colormap,
+                  GdkColor    *transparent_color,
+                  const gchar *filename)
+{
+  if (strcmp (filename, "<parent>") == 0)
+    return (GdkPixmap*) GDK_PARENT_RELATIVE;
+  else
+    {
+      if(image_loader)
+       return image_loader(NULL, colormap, NULL,
+                           transparent_color,
+                           filename);
+      else
+       return gdk_pixmap_colormap_create_from_xpm (NULL, colormap, NULL,
+                                                   transparent_color,
+                                                   filename);
     }
-
-  return path;
 }