]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkrc.c
Include the build directory.
[~andy/gtk] / gtk / gtkrc.c
index 1d9d59eb36004c7673504fcecd860c9b45f4fdc7..b6b3c820343e80b1040977cc40dd025851095918 100644 (file)
  * 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 "glib.h"
+#include "gdkconfig.h"
+
+#ifdef 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 "gtkrc.h"
-#include "gtkbindings.h"
+#include <stdlib.h>
 
+#ifndef HAVE_LSTAT
+#define lstat stat
+#endif
 
-enum {
-  TOKEN_INVALID = G_TOKEN_LAST,
-  TOKEN_INCLUDE,
-  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,
-  TOKEN_LAST
-};
+#ifdef G_OS_WIN32
+#include <windows.h>           /* For GetWindowsDirectory */
+#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 _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;
@@ -84,59 +79,75 @@ struct _GtkRcFile
   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_state              (GScanner     *scanner,
-                                                   GtkStateType *state);
-static guint      gtk_rc_parse_color              (GScanner     *scanner,
-                                                   GdkColor     *color);
-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_widget_style       (GScanner     *scanner);
-static guint      gtk_rc_parse_widget_class_style (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 =
+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_init_style                 (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_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_base                 (GScanner        *scanner,
+                                                      GtkRcStyle      *style);
+static guint       gtk_rc_parse_xthickness           (GScanner        *scanner,
+                                                      GtkRcStyle      *style);
+static guint       gtk_rc_parse_ythickness           (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_font_name            (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_module_path (void);
+static void        gtk_rc_add_initial_default_files  (void);
+
+static void        gtk_rc_style_init              (GtkRcStyle      *style);
+static void        gtk_rc_style_class_init        (GtkRcStyleClass *klass);
+static void        gtk_rc_style_finalize          (GObject         *object);
+static void        gtk_rc_style_real_merge        (GtkRcStyle      *dest,
+                                                  GtkRcStyle      *src);
+static GtkRcStyle *gtk_rc_style_real_clone        (GtkRcStyle      *rc_style);
+static GtkStyle *  gtk_rc_style_real_create_style (GtkRcStyle      *rc_style);
+
+static gpointer parent_class = NULL;
+
+static const GScannerConfig    gtk_rc_scanner_config =
 {
   (
-   " \t\n"
+   " \t\r\n"
    )                   /* cset_skip_characters */,
   (
    G_CSET_a_2_z
@@ -145,10 +156,8 @@ static     GScannerConfig  gtk_rc_scanner_config =
    )                   /* cset_identifier_first */,
   (
    G_CSET_a_2_z
-   "_0123456789"
+   "_-0123456789"
    G_CSET_A_2_Z
-   G_CSET_LATINS
-   G_CSET_LATINC
    )                   /* cset_identifier_nth */,
   ( "#\n" )            /* cpair_comment_single */,
   
@@ -170,53 +179,429 @@ static   GScannerConfig  gtk_rc_scanner_config =
   TRUE                 /* scan_string_dq */,
   TRUE                 /* numbers_2_int */,
   FALSE                        /* int_2_float */,
-  TRUE                 /* identifier_2_string */,
+  FALSE                        /* identifier_2_string */,
   TRUE                 /* char_2_token */,
   TRUE                 /* symbol_2_token */,
+  FALSE                        /* scope_0_fallback */,
 };
 
-static struct
+static const struct
 {
   gchar *name;
   guint token;
 } symbols[] = {
-  { "include", TOKEN_INCLUDE },
-  { "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 },
+  { "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 },
+  { "text", GTK_RC_TOKEN_TEXT },
+  { "base", GTK_RC_TOKEN_BASE },
+  { "xthickness", GTK_RC_TOKEN_XTHICKNESS },
+  { "ythickness", GTK_RC_TOKEN_YTHICKNESS },
+  { "font", GTK_RC_TOKEN_FONT },
+  { "fontset", GTK_RC_TOKEN_FONTSET },
+  { "font_name", GTK_RC_TOKEN_FONT_NAME },
+  { "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 guint nsymbols = sizeof (symbols) / sizeof (symbols[0]);
+
+static const guint n_symbols = sizeof (symbols) / sizeof (symbols[0]);
 
 static GHashTable *rc_style_ht = 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];
+
+/* A stack of directories for RC files we are parsing currently.
+ * these are implicitely added to the end of PIXMAP_PATHS
+ */
+GSList *rc_dir_stack = NULL;
 
 /* The files we have parsed, to reread later if necessary */
 GSList *rc_files = NULL;
 
 static GtkImageLoader image_loader = NULL;
 
+/* RC file handling */
+
+
+#ifdef G_OS_WIN32
+
+gchar *
+gtk_win32_get_installation_directory (void)
+{
+  static gboolean been_here = FALSE;
+  static gchar gtk_installation_dir[200];
+  gchar win_dir[100];
+  HKEY reg_key = NULL;
+  DWORD type;
+  DWORD nbytes = sizeof (gtk_installation_dir);
+
+  if (been_here)
+    return gtk_installation_dir;
+
+  been_here = TRUE;
+
+  if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\GNU\\GTk+", 0,
+                   KEY_QUERY_VALUE, &reg_key) != ERROR_SUCCESS
+      || RegQueryValueEx (reg_key, "InstallationDirectory", 0,
+                         &type, gtk_installation_dir, &nbytes) != ERROR_SUCCESS
+      || type != REG_SZ)
+    {
+      /* Uh oh. Use the old hard-coded %WinDir%\GTk+ value */
+      GetWindowsDirectory (win_dir, sizeof (win_dir));
+      sprintf (gtk_installation_dir, "%s\\gtk+", win_dir);
+    }
+
+  if (reg_key != NULL)
+    RegCloseKey (reg_key);
+
+  return gtk_installation_dir;
+}
+
+static gchar *
+get_themes_directory (void)
+{
+  static gchar themes_dir[200];
+
+  sprintf (themes_dir, "%s\\themes", gtk_win32_get_installation_directory ());
+  return themes_dir;
+}
+
+#endif
+gchar *
+gtk_rc_get_theme_dir(void)
+{
+  gchar *var, *path;
+
+#ifndef G_OS_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
+
+  return path;
+}
+
+gchar *
+gtk_rc_get_module_dir(void)
+{
+  gchar *var, *path;
+
+#ifndef G_OS_WIN32
+  var = getenv("GTK_EXE_PREFIX");
+  if (var)
+    path = g_strdup_printf("%s%s", var, "/lib/gtk-2.0/" GTK_VERSION "/engines");
+  else
+    path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk-2.0/" GTK_VERSION "/engines");
+#else
+  path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
+#endif
+
+  return path;
+}
+
+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 G_OS_WIN32
+  var = getenv("GTK_EXE_PREFIX");
+  if (var)
+    path = g_strdup_printf("%s%s", var, "/lib/gtk-2.0/" GTK_VERSION "/engines");
+  else
+    path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk-2.0/" GTK_VERSION "/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 G_OS_WIN32
+      path = g_strdup_printf ("%s%s", var, "/.gtk-2.0/" GTK_VERSION "/engines");
+#else
+      path = g_strdup_printf ("%s%s", var, "\\_gtk\\themes\\engines");
+#endif
+      module_path[n++] = path;
+    }
+  module_path[n] = NULL;
+}
+
+static void
+gtk_rc_add_initial_default_files (void)
+{
+  static gint init = FALSE;
+  gchar *var, *str;
+  gchar **files;
+  gint i;
+
+  if (init)
+    return;
+  
+  gtk_rc_default_files[0] = NULL;
+  init = TRUE;
+
+  var = g_getenv("GTK_RC_FILES");
+  if (var)
+    {
+      files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, 128);
+      i=0;
+      while (files[i])
+       {
+         gtk_rc_add_default_file (files[i]);
+         i++;
+       }
+      g_strfreev (files);
+    }
+  else
+    {
+#ifndef G_OS_WIN32
+      str = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk-2.0" G_DIR_SEPARATOR_S "gtkrc");
+#else
+      str = g_strdup_printf ("%s\\gtkrc", gtk_win32_get_installation_directory ());
+#endif
+
+      gtk_rc_add_default_file (str);
+      g_free (str);
+
+      var = g_get_home_dir ();
+      if (var)
+       {
+         str = g_strdup_printf ("%s" G_DIR_SEPARATOR_S ".gtkrc-2.0", var);
+         gtk_rc_add_default_file (str);
+         g_free (str);
+       }
+    }
+}
+
+void
+gtk_rc_add_default_file (const gchar *file)
+{
+  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;
+}
+
+void
+gtk_rc_set_default_files (gchar **files)
+{
+  gint i;
+
+  gtk_rc_add_initial_default_files ();
+
+  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;
+
+  i = 0;
+  while (files[i] != NULL)
+    {
+      gtk_rc_add_default_file (files[i]);
+      i++;
+    }
+}
+
+gchar **
+gtk_rc_get_default_files (void)
+{
+  gtk_rc_add_initial_default_files ();
+
+  return gtk_rc_default_files;
+}
+
+ /* The following routine is based on _nl_normalize_codeset from
+  * the GNU C library. Contributed by
+  *
+  * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+  * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+  * 
+  * Normalize codeset name.  There is no standard for the codeset
+  * names.  Normalization allows the user to use any of the common
+  * names.
+  */
+ static char *
+ _gtk_normalize_codeset (const char *codeset, int name_len)
+ {
+   int len = 0;
+   int only_digit = 1;
+   char *retval;
+   char *wp;
+   int cnt;
+   for (cnt = 0; cnt < name_len; ++cnt)
+     if (isalnum (codeset[cnt]))
+       {
+       ++len;
+       if (isalpha (codeset[cnt]))
+         only_digit = 0;
+       }
+   retval = g_malloc ((only_digit ? 3 : 0) + len + 1);
+   if (only_digit)
+     {
+       strcpy (retval, "iso");
+       wp = retval + 3;
+     }
+   else
+     wp = retval;
+   
+   for (cnt = 0; cnt < name_len; ++cnt)
+     if (isalpha (codeset[cnt]))
+       *wp++ = isupper(codeset[cnt]) ? tolower (codeset[cnt]) : codeset[cnt];
+     else if (isdigit (codeset[cnt]))
+       *wp++ = codeset[cnt];
+   
+   *wp = '\0';
+   return retval;
+ }
 void
 gtk_rc_init (void)
 {
-  rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
-                                 (GCompareFunc) gtk_rc_style_compare);
+  static gchar *locale_suffixes[3];
+  static gint n_locale_suffixes = 0;
+
+  gint i, j;
+
+  static gboolean initted = FALSE;
+
+  if (!initted)
+    {
+      gint length;
+      gchar *locale;
+      gchar *p;
+
+#ifdef G_OS_WIN32      
+      locale = g_win32_getlocale ();
+#else      
+      locale = setlocale (LC_CTYPE, NULL);
+#endif      
+      
+      initted = TRUE;
+
+      pixmap_path[0] = NULL;
+      module_path[0] = NULL;
+      gtk_rc_append_default_module_path();
+      
+      gtk_rc_add_initial_default_files ();
+
+      if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
+       {
+         /* Determine locale-specific suffixes for RC files
+          *
+          * We normalize the charset into a standard form,
+          * which has all '-' and '_' characters removed,
+          * and is lowercase.
+          */
+         gchar *normalized_locale;
+
+         p = strchr (locale, '@');
+         length = p ? (p -locale) : strlen (locale);
+
+         p = strchr (locale, '.');
+         if (p)
+           {
+             gchar *tmp1 = g_strndup (locale, p - locale + 1);
+             gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
+             
+             normalized_locale = g_strconcat (tmp1, tmp2, NULL);
+             g_free (tmp1);
+             g_free (tmp2);
+                                                
+             locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
+             length = p - locale;
+           }
+         else
+           normalized_locale = g_strndup (locale, length);
+         
+         p = strchr (normalized_locale, '_');
+         if (p)
+           {
+             locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
+             length = p - normalized_locale;
+           }
+         
+         locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
+
+         g_free (normalized_locale);
+       }
+    }
+  
+  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);
+       }
+
+      gtk_rc_parse (gtk_rc_default_files[i]);
+      i++;
+    }
 }
 
 void
@@ -261,22 +646,18 @@ gtk_rc_parse_file (const gchar *filename, gboolean reload)
     {
       /* Get the absolute pathname */
 
-      if (rc_file->name[0] == '/')
+      if (g_path_is_absolute (rc_file->name))
        rc_file->canonical_name = rc_file->name;
       else
        {
          GString *str;
-         gchar buffer[MAXPATHLEN];
-         
-#if defined(sun) && !defined(__SVR4)
-         if(!getwd(buffer))
-#else
-         if(!getcwd(buffer, MAXPATHLEN))
-#endif    
-             return;
+         gchar *cwd;
 
-         str = g_string_new (buffer);
-         g_string_append_c (str, '/');
+         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;
@@ -287,6 +668,7 @@ gtk_rc_parse_file (const gchar *filename, gboolean reload)
   if (!lstat (rc_file->canonical_name, &statbuf))
     {
       gint fd;
+      GSList *tmp_list;
 
       rc_file->mtime = statbuf.st_mtime;
 
@@ -294,7 +676,18 @@ gtk_rc_parse_file (const gchar *filename, gboolean reload)
       if (fd < 0)
        return;
 
+      /* Temporarily push directory name for this file on
+       * a stack of directory names while parsing it
+       */
+      rc_dir_stack = g_slist_prepend (rc_dir_stack,
+                                     g_dirname (rc_file->canonical_name));
       gtk_rc_parse_any (filename, fd, NULL);
+      tmp_list = rc_dir_stack;
+      rc_dir_stack = rc_dir_stack->next;
+      g_free (tmp_list->data);
+      g_slist_free_1 (tmp_list);
 
       close (fd);
     }
@@ -308,79 +701,296 @@ gtk_rc_parse (const gchar *filename)
   gtk_rc_parse_file (filename, TRUE);
 }
 
+/* Handling of RC styles */
+
+GType
+gtk_rc_style_get_type (void)
+{
+  static GType object_type = 0;
+
+  if (!object_type)
+    {
+      static const GTypeInfo object_info =
+      {
+        sizeof (GtkRcStyleClass),
+        (GBaseInitFunc) NULL,
+        (GBaseFinalizeFunc) NULL,
+        (GClassInitFunc) gtk_rc_style_class_init,
+        NULL,           /* class_finalize */
+        NULL,           /* class_data */
+        sizeof (GtkRcStyle),
+        0,              /* n_preallocs */
+        (GInstanceInitFunc) gtk_rc_style_init,
+      };
+      
+      object_type = g_type_register_static (G_TYPE_OBJECT,
+                                            "GtkRcStyle",
+                                            &object_info);
+    }
+  
+  return object_type;
+}
+
 static void
-gtk_rc_clear_hash_node (gpointer key, 
-                       gpointer data, 
-                       gpointer user_data)
+gtk_rc_style_init (GtkRcStyle *style)
 {
-  int i;
-  GtkRcStyle *rc_style = data;
-  GList *tmp_list;
+  guint i;
 
-  g_free (rc_style->name);
-  g_free (rc_style->font_name);
-  g_free (rc_style->fontset_name);
+  style->name = NULL;
+  for (i = 0; i < 5; i++)
+    {
+      static const GdkColor init_color = { 0, 0, 0, 0, };
+
+      style->bg_pixmap_name[i] = NULL;
+      style->color_flags[i] = 0;
+      style->fg[i] = init_color;
+      style->bg[i] = init_color;
+      style->text[i] = init_color;
+      style->base[i] = init_color;
+    }
+  style->xthickness = -1;
+  style->ythickness = -1;
+  style->rc_style_lists = NULL;
+}
+
+static void
+gtk_rc_style_class_init (GtkRcStyleClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  
+  parent_class = g_type_class_peek_parent (klass);
 
-  for (i=0 ; i<5 ; i++)
-    g_free (rc_style->bg_pixmap_name[i]);
+  object_class->finalize = gtk_rc_style_finalize;
 
-  gtk_style_unref (rc_style->proto_style);
+  klass->parse = NULL;
+  klass->clone = gtk_rc_style_real_clone;
+  klass->merge = gtk_rc_style_real_merge;
+  klass->create_style = gtk_rc_style_real_create_style;
+}
 
-  tmp_list = rc_style->styles;
-  while (tmp_list)
+/* Like g_slist_remove, but remove all copies of data */
+static GSList*
+gtk_rc_slist_remove_all (GSList   *list,
+                        gpointer  data)
+{
+  GSList *tmp;
+  GSList *prev;
+
+  prev = NULL;
+  tmp = list;
+
+  while (tmp)
     {
-      GtkRcNode *node = tmp_list->data;
+      if (tmp->data == data)
+       {
+         if (list == tmp)
+           list = list->next;
 
-      gdk_colormap_unref (node->cmap);
-      gtk_style_unref (node->style);
+         if (prev) 
+           prev->next = tmp->next;
 
-      g_free (node);
-      tmp_list = tmp_list->next;
+         g_slist_free_1 (tmp);
+
+         if (prev)
+           tmp = prev->next;
+         else
+           tmp = list;
+       }
+      else
+       {
+         prev = tmp;
+         tmp = tmp->next;
+       }
     }
 
-  g_free (rc_style);
+  return list;
 }
 
 static void
-gtk_rc_clear_styles (void)
+gtk_rc_style_finalize (GObject *object)
 {
-  GSList *tmp_list;
+  gint i;
+  GSList *tmp_list1, *tmp_list2;
+  GtkRcStyle *rc_style;
 
-  /* Clear out all old rc_styles */
+  rc_style = GTK_RC_STYLE (object);
+  
+  if (rc_style->name)
+    g_free (rc_style->name);
+  if (rc_style->font_desc)
+    pango_font_description_free (rc_style->font_desc);
+      
+  for (i=0 ; i < 5 ; i++)
+    if (rc_style->bg_pixmap_name[i])
+      g_free (rc_style->bg_pixmap_name[i]);
+  
+  /* Now remove all references to this rc_style from
+   * realized_style_ht
+   */
+  tmp_list1 = rc_style->rc_style_lists;
+  while (tmp_list1)
+    {
+      GSList *rc_styles = tmp_list1->data;
+      GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
+      gtk_style_unref (style);
 
-  g_hash_table_foreach (rc_style_ht, gtk_rc_clear_hash_node, NULL);
-  g_hash_table_destroy (rc_style_ht);
-  rc_style_ht = NULL;
+      /* Remove the list of styles from the other rc_styles
+       * in the list
+       */
+      tmp_list2 = rc_styles;
+      while (tmp_list2)
+        {
+          GtkRcStyle *other_style = tmp_list2->data;
+
+          if (other_style != rc_style)
+            other_style->rc_style_lists =
+              gtk_rc_slist_remove_all (other_style->rc_style_lists, rc_styles);
+                 
+          tmp_list2 = tmp_list2->next;
+        }
+
+      /* And from the hash table itself
+       */
+      g_hash_table_remove (realized_style_ht, rc_styles);
+      g_slist_free (rc_styles);
 
-  tmp_list = gtk_rc_sets_widget;
-  while (tmp_list)
-    {
-      GtkRcSet *rc_set;
+      tmp_list1 = tmp_list1->next;
+    }
+  g_slist_free (rc_style->rc_style_lists);
 
-      rc_set = tmp_list->data;
-      gtk_pattern_spec_free_segs (&rc_set->pspec);
-      g_free (rc_set);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+GtkRcStyle *
+gtk_rc_style_new (void)
+{
+  GtkRcStyle *style;
+  
+  style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
+  
+  return style;
+}
+
+void      
+gtk_rc_style_ref (GtkRcStyle  *rc_style)
+{
+  g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
+
+  g_object_ref (G_OBJECT (rc_style));
+}
+
+void      
+gtk_rc_style_unref (GtkRcStyle  *rc_style)
+{
+  g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
+
+  g_object_unref (G_OBJECT (rc_style));
+}
+
+static GtkRcStyle *
+gtk_rc_style_real_clone (GtkRcStyle *style)
+{
+  return GTK_RC_STYLE (g_object_new (G_OBJECT_TYPE (style), NULL));
+}
+
+static void
+gtk_rc_style_real_merge (GtkRcStyle *dest,
+                        GtkRcStyle *src)
+{
+  gint i;
+  
+  for (i = 0; i < 5; i++)
+    {
+      if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
+       dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
       
-      tmp_list = tmp_list->next;
+      if (!(dest->color_flags[i] & GTK_RC_FG) && 
+         src->color_flags[i] & GTK_RC_FG)
+       {
+         dest->fg[i] = src->fg[i];
+         dest->color_flags[i] |= GTK_RC_FG;
+       }
+      if (!(dest->color_flags[i] & GTK_RC_BG) && 
+         src->color_flags[i] & GTK_RC_BG)
+       {
+         dest->bg[i] = src->bg[i];
+         dest->color_flags[i] |= GTK_RC_BG;
+       }
+      if (!(dest->color_flags[i] & GTK_RC_TEXT) && 
+         src->color_flags[i] & GTK_RC_TEXT)
+       {
+         dest->text[i] = src->text[i];
+         dest->color_flags[i] |= GTK_RC_TEXT;
+       }
+      if (!(dest->color_flags[i] & GTK_RC_BASE) && 
+         src->color_flags[i] & GTK_RC_BASE)
+       {
+         dest->base[i] = src->base[i];
+         dest->color_flags[i] |= GTK_RC_BASE;
+       }
     }
-  g_slist_free (gtk_rc_sets_widget);
-  gtk_rc_sets_widget = NULL;
 
-  tmp_list = gtk_rc_sets_widget_class;
-  while (tmp_list)
+  if (dest->xthickness < 0 && src->xthickness >= 0)
+    dest->xthickness = src->xthickness;
+  if (dest->ythickness < 0 && src->ythickness >= 0)
+    dest->ythickness = src->ythickness;
+
+  if (!dest->font_desc && src->font_desc)
+    dest->font_desc = pango_font_description_copy (src->font_desc);
+}
+
+static GtkStyle *
+gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
+{
+  return gtk_style_new ();
+}
+
+static void
+gtk_rc_clear_hash_node (gpointer key, 
+                       gpointer data, 
+                       gpointer user_data)
+{
+  gtk_rc_style_unref (data);
+}
+
+static void
+gtk_rc_free_rc_sets (GSList *slist)
+{
+  while (slist)
     {
       GtkRcSet *rc_set;
 
-      rc_set = tmp_list->data;
+      rc_set = slist->data;
       gtk_pattern_spec_free_segs (&rc_set->pspec);
       g_free (rc_set);
-      
-      tmp_list = tmp_list->next;
+
+      slist = slist->next;
     }
+}
+
+static void
+gtk_rc_clear_styles (void)
+{
+  /* Clear out all old rc_styles */
+
+  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;
+    }
+
+  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_init ();
+  gtk_rc_free_rc_sets (gtk_rc_sets_class);
+  g_slist_free (gtk_rc_sets_class);
+  gtk_rc_sets_class = NULL;
 }
 
 gboolean
@@ -428,10 +1038,47 @@ gtk_rc_reparse_all (void)
   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;
+}
+
 GtkStyle*
 gtk_rc_get_style (GtkWidget *widget)
 {
-  GtkRcStyle *rc_style;
+  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)
     {
@@ -439,12 +1086,10 @@ gtk_rc_get_style (GtkWidget *widget)
       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);
+      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 (rc_style)
-       return gtk_rc_style_init (rc_style, gtk_widget_get_colormap (widget));
     }
   
   if (gtk_rc_sets_widget_class)
@@ -453,69 +1098,92 @@ gtk_rc_get_style (GtkWidget *widget)
       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);
+      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)
+    {
+      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_styles = gtk_rc_styles_match (rc_styles, 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);
+       }
     }
   
+  if (rc_styles)
+    return gtk_rc_init_style (rc_styles);
+
   return NULL;
 }
 
-void
-gtk_rc_add_widget_name_style (GtkStyle  *style,
-                             const char *pattern)
+static GSList*
+gtk_rc_add_rc_sets (GSList     *slist,
+                   GtkRcStyle *rc_style,
+                   const char *pattern)
 {
-  GtkRcStyle *rc_style;
+  GtkRcStyle *new_style;
   GtkRcSet *rc_set;
-  int i;
-  
-  gtk_style_ref (style);
+  guint i;
   
-  rc_style = g_new (GtkRcStyle, 1);
-  rc_style->name = NULL;
-  rc_style->font_name = NULL;
-  rc_style->fontset_name = NULL;
+  new_style = gtk_rc_style_new ();
+  *new_style = *rc_style;
+  new_style->name = g_strdup (rc_style->name);
+  if (rc_style->font_desc)
+    new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
   
   for (i = 0; i < 5; i++)
-    rc_style->bg_pixmap_name[i] = NULL;
+    new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
   
-  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;
   
-  gtk_rc_sets_widget = g_slist_append (gtk_rc_sets_widget, rc_set);
+  return g_slist_prepend (slist, rc_set);
 }
 
 void
-gtk_rc_add_widget_class_style (GtkStyle *style,
-                              const char     *pattern)
+gtk_rc_add_widget_name_style (GtkRcStyle  *rc_style,
+                             const gchar *pattern)
 {
-  GtkRcStyle *rc_style;
-  GtkRcSet *rc_set;
-  int 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;
-  
-  gtk_rc_sets_widget_class = g_slist_append (gtk_rc_sets_widget_class, rc_set);
+  g_return_if_fail (rc_style != NULL);
+  g_return_if_fail (pattern != NULL);
+
+  gtk_rc_sets_widget = gtk_rc_add_rc_sets (gtk_rc_sets_widget, rc_style, pattern);
+}
+
+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);
+
+  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
@@ -527,7 +1195,7 @@ gtk_rc_parse_any (const gchar  *input_name,
   guint           i;
   gboolean done;
   
-  scanner = g_scanner_new (&gtk_rc_scanner_config);
+  scanner = g_scanner_new ((GScannerConfig *) &gtk_rc_scanner_config);
   
   if (input_fd >= 0)
     {
@@ -542,9 +1210,9 @@ gtk_rc_parse_any (const gchar  *input_name,
       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 < nsymbols; i++)
+  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);
   
@@ -565,25 +1233,32 @@ gtk_rc_parse_any (const gchar  *input_name,
              gchar *msg;
              
              msg = NULL;
-             if (expected_token > TOKEN_INVALID &&
-                 expected_token < TOKEN_LAST)
-               {
-                 for (i = 0; i < nsymbols; i++)
-                   if (symbols[i].token == expected_token)
-                     msg = symbols[i].name;
-                 if (msg)
-                   msg = g_strconcat ("e.g. `", msg, "'", NULL);
-               }
-             if (scanner->token > TOKEN_INVALID &&
-                 scanner->token < TOKEN_LAST)
+             symbol_name = NULL;
+             if (scanner->scope_id == 0)
                {
-                 symbol_name = "???";
-                 for (i = 0; i < nsymbols; i++)
-                   if (symbols[i].token == scanner->token)
-                     symbol_name = symbols[i].name;
+                 /* 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;
+                   }
                }
-             else
-               symbol_name = NULL;
              g_scanner_unexp_token (scanner,
                                     expected_token,
                                     NULL,
@@ -600,6 +1275,36 @@ gtk_rc_parse_any (const gchar  *input_name,
   g_scanner_destroy (scanner);
 }
 
+static guint      
+gtk_rc_styles_hash (const GSList *rc_styles)
+{
+  guint result;
+  
+  result = 0;
+  while (rc_styles)
+    {
+      result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
+      rc_styles = rc_styles->next;
+    }
+  
+  return result;
+}
+
+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);
+}
+
 static guint
 gtk_rc_style_hash (const char *name)
 {
@@ -622,121 +1327,109 @@ gtk_rc_style_compare (const char *a,
 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;
+  if (rc_style_ht)
+    return g_hash_table_lookup (rc_style_ht, (gpointer) name);
+  else
+    return NULL;
 }
 
-static GtkRcStyle*
-gtk_rc_styles_match (GSList      *sets,
-                    guint         path_length,
-                    gchar        *path,
-                    gchar        *path_reversed)
+static GtkStyle *
+gtk_rc_style_to_style (GtkRcStyle *rc_style)
 {
-  GtkRcSet *rc_set;
+  GtkStyle *style;
 
-  while (sets)
-    {
-      rc_set = sets->data;
-      sets = sets->next;
+  style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
 
-      if (gtk_pattern_match (&rc_set->pspec, path_length, path, path_reversed))
-       return rc_set->rc_style;
-    }
+  style->rc_style = rc_style;
+  gtk_rc_style_ref (rc_style);
   
-  return NULL;
+  GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);
+  
+  return style;
 }
 
+/* Reuses or frees rc_styles */
 static GtkStyle *
-gtk_rc_style_init (GtkRcStyle *rc_style, GdkColormap *cmap)
+gtk_rc_init_style (GSList *rc_styles)
 {
-  GdkFont *old_font;
-  gboolean match_cmap = FALSE;
-  gint i;
-
-  GList *tmp_list;
   GtkStyle *style = NULL;
-  GtkRcNode *node;
-
-  tmp_list = rc_style->styles;
+  gint i;
 
-  for (i=0; i<5; i++)
-    if (rc_style->bg_pixmap_name[i])
-      match_cmap = TRUE;
-      
-  while (tmp_list)
-    {
-      node = (GtkRcNode *)tmp_list->data;
+  g_return_val_if_fail (rc_styles != NULL, NULL);
+  
+  if (!realized_style_ht)
+    realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
+                                         (GCompareFunc) gtk_rc_styles_compare);
 
-      if (!match_cmap || (node->cmap == cmap))
-       {
-         style = node->style;
-         break;
-       }
+  style = g_hash_table_lookup (realized_style_ht, rc_styles);
 
-      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
+      GtkRcStyle *base_style = NULL;
+      GtkRcStyle *proto_style;
+      GtkRcStyleClass *proto_style_class;
+      GSList *tmp_styles;
+      GType rc_style_type = GTK_TYPE_RC_STYLE;
+
+      /* Find the first derived style in the list, and use that to
+       * create the merged style. If we only have raw GtkRcStyles, use
+       * the first style to create the merged style.
        */
-      gdk_colormap_ref (cmap);
-      node->style = style;
-      node->cmap = cmap;
-      
-      if (rc_style->fontset_name)
+      base_style = rc_styles->data;
+      tmp_styles = rc_styles;
+      while (tmp_styles)
        {
-         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;
+         GtkRcStyle *rc_style = tmp_styles->data;
+
+         if (G_OBJECT_TYPE (rc_style) != rc_style_type)
+           {
+             base_style = rc_style;
+             break;
+           }
+
+         tmp_styles = tmp_styles->next;
        }
-      else if (rc_style->font_name)
+      
+      proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
+      proto_style = proto_style_class->clone (base_style);
+      
+      tmp_styles = rc_styles;
+      while (tmp_styles)
        {
-         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;
+         GtkRcStyle *rc_style = tmp_styles->data;
+         
+         proto_style_class->merge (proto_style, rc_style);
+         
+         /* Point from each rc_style to the list of styles */
+         if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
+           rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
+         
+         tmp_styles = tmp_styles->next;
        }
-      
+
       for (i = 0; i < 5; i++)
-       if (rc_style->bg_pixmap_name[i])
+       if (proto_style->bg_pixmap_name[i] &&
+           (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
          {
-           if (strcmp (rc_style->bg_pixmap_name[i], "<parent>") == 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]);
-             }
+           g_free (proto_style->bg_pixmap_name[i]);
+           proto_style->bg_pixmap_name[i] = NULL;
          }
 
-      rc_style->styles = g_list_append (rc_style->styles, node);
+      style = gtk_rc_style_to_style (proto_style);
+      gtk_rc_style_unref (proto_style);
+
+      g_hash_table_insert (realized_style_ht, rc_styles, style);
     }
+  else
+    g_slist_free (rc_styles);
 
   return style;
 }
 
+/*********************
+ * Parsing functions *
+ *********************/
+
 static guint
 gtk_rc_parse_statement (GScanner *scanner)
 {
@@ -746,10 +1439,10 @@ gtk_rc_parse_statement (GScanner *scanner)
 
   switch (token)
     {
-    case TOKEN_INCLUDE:
+    case GTK_RC_TOKEN_INCLUDE:
       token = g_scanner_get_next_token (scanner);
-      if (token != TOKEN_INCLUDE)
-       return TOKEN_INCLUDE;
+      if (token != GTK_RC_TOKEN_INCLUDE)
+       return GTK_RC_TOKEN_INCLUDE;
 
       token = g_scanner_get_next_token (scanner);
       if (token != G_TOKEN_STRING)
@@ -758,21 +1451,30 @@ gtk_rc_parse_statement (GScanner *scanner)
       gtk_rc_parse_file (scanner->value.v_string, FALSE);
       return G_TOKEN_NONE;
 
-    case TOKEN_STYLE:
+    case GTK_RC_TOKEN_STYLE:
       return gtk_rc_parse_style (scanner);
 
-    case TOKEN_PIXMAP_PATH:
+    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 TOKEN_WIDGET:
-      return gtk_rc_parse_widget_style (scanner);
+    case GTK_RC_TOKEN_WIDGET:
+      return gtk_rc_parse_path_pattern (scanner);
 
-    case TOKEN_WIDGET_CLASS:
-      return gtk_rc_parse_widget_class_style (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 */ TOKEN_STYLE;
+      return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
     }
 }
 
@@ -786,29 +1488,27 @@ gtk_rc_parse_style (GScanner *scanner)
   gint i;
   
   token = g_scanner_get_next_token (scanner);
-  if (token != TOKEN_STYLE)
-    return TOKEN_STYLE;
+  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);
+  rc_style = gtk_rc_style_find (scanner->value.v_string);
   
   if (!rc_style)
     {
       insert = TRUE;
-      rc_style = g_new (GtkRcStyle, 1);
+      rc_style = gtk_rc_style_new ();
       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;
+      for (i = 0; i < 5; i++)
+       rc_style->color_flags[i] = 0;
     }
   
   token = g_scanner_peek_next_token (scanner);
@@ -820,39 +1520,31 @@ gtk_rc_parse_style (GScanner *scanner)
       if (token != G_TOKEN_STRING)
        {
          if (insert)
-           {
-             gtk_style_unref (rc_style->proto_style);
-             g_free (rc_style);
-           }
+           g_free (rc_style);
+
          return G_TOKEN_STRING;
        }
       
-      parent_style = g_hash_table_lookup (rc_style_ht, scanner->value.v_string);
+      parent_style = gtk_rc_style_find (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->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->xthickness = parent_style->xthickness;
+         rc_style->ythickness = parent_style->ythickness;
          
-         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)
+         if (parent_style->font_desc)
            {
-             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);
+             if (rc_style->font_desc)
+               pango_font_description_free (rc_style->font_desc);
+             rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
            }
          
          for (i = 0; i < 5; i++)
@@ -868,10 +1560,8 @@ gtk_rc_parse_style (GScanner *scanner)
   if (token != G_TOKEN_LEFT_CURLY)
     {
       if (insert)
-       {
-         gtk_style_unref (rc_style->proto_style);
-         g_free (rc_style);
-       }
+       g_free (rc_style);
+
       return G_TOKEN_LEFT_CURLY;
     }
   
@@ -880,27 +1570,39 @@ gtk_rc_parse_style (GScanner *scanner)
     {
       switch (token)
        {
-       case TOKEN_BASE:
-         token = gtk_rc_parse_base (scanner, rc_style->proto_style);
+       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 TOKEN_BG:
-         token = gtk_rc_parse_bg (scanner, rc_style->proto_style);
+       case GTK_RC_TOKEN_TEXT:
+         token = gtk_rc_parse_text (scanner, rc_style);
          break;
-       case TOKEN_FG:
-         token = gtk_rc_parse_fg (scanner, rc_style->proto_style);
+       case GTK_RC_TOKEN_BASE:
+         token = gtk_rc_parse_base (scanner, rc_style);
          break;
-       case TOKEN_TEXT:
-         token = gtk_rc_parse_text (scanner, rc_style->proto_style);
+       case GTK_RC_TOKEN_XTHICKNESS:
+         token = gtk_rc_parse_xthickness (scanner, rc_style);
          break;
-       case TOKEN_BG_PIXMAP:
+       case GTK_RC_TOKEN_YTHICKNESS:
+         token = gtk_rc_parse_ythickness (scanner, rc_style);
+         break;
+       case GTK_RC_TOKEN_BG_PIXMAP:
          token = gtk_rc_parse_bg_pixmap (scanner, rc_style);
          break;
-       case TOKEN_FONT:
+       case GTK_RC_TOKEN_FONT:
          token = gtk_rc_parse_font (scanner, rc_style);
          break;
-       case TOKEN_FONTSET:
+       case GTK_RC_TOKEN_FONTSET:
          token = gtk_rc_parse_fontset (scanner, rc_style);
          break;
+       case GTK_RC_TOKEN_FONT_NAME:
+         token = gtk_rc_parse_font_name (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;
@@ -911,14 +1613,12 @@ gtk_rc_parse_style (GScanner *scanner)
        {
          if (insert)
            {
-             if (rc_style->fontset_name)
-               g_free (rc_style->fontset_name);
-             if (rc_style->font_name)
-               g_free (rc_style->font_name);
+             if (rc_style->font_desc)
+               pango_font_description_free (rc_style->font_desc);
+             
              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;
@@ -931,37 +1631,40 @@ gtk_rc_parse_style (GScanner *scanner)
     {
       if (insert)
        {
-         if (rc_style->fontset_name)
-           g_free (rc_style->fontset_name);
-         if (rc_style->font_name)
-           g_free (rc_style->font_name);
+         if (rc_style->font_desc)
+           pango_font_description_free (rc_style->font_desc);
          
          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);
-  
+  if (insert)
+    {
+      if (!rc_style_ht)
+       rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
+                                       (GCompareFunc) gtk_rc_style_compare);
+      
+      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)
+gtk_rc_parse_bg (GScanner   *scanner,
+                GtkRcStyle *style)
 {
   GtkStateType state;
   guint token;
   
   token = g_scanner_get_next_token (scanner);
-  if (token != TOKEN_BASE)
-    return TOKEN_BASE;
+  if (token != GTK_RC_TOKEN_BG)
+    return GTK_RC_TOKEN_BG;
   
   token = gtk_rc_parse_state (scanner, &state);
   if (token != G_TOKEN_NONE)
@@ -970,20 +1673,21 @@ gtk_rc_parse_base (GScanner *scanner,
   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]);
+
+  style->color_flags[state] |= GTK_RC_BG;
+  return gtk_rc_parse_color (scanner, &style->bg[state]);
 }
 
 static guint
-gtk_rc_parse_bg (GScanner *scanner,
-                GtkStyle *style)
+gtk_rc_parse_fg (GScanner   *scanner,
+                GtkRcStyle *style)
 {
   GtkStateType state;
   guint token;
   
   token = g_scanner_get_next_token (scanner);
-  if (token != TOKEN_BG)
-    return TOKEN_BG;
+  if (token != GTK_RC_TOKEN_FG)
+    return GTK_RC_TOKEN_FG;
   
   token = gtk_rc_parse_state (scanner, &state);
   if (token != G_TOKEN_NONE)
@@ -993,19 +1697,20 @@ gtk_rc_parse_bg (GScanner *scanner,
   if (token != G_TOKEN_EQUAL_SIGN)
     return G_TOKEN_EQUAL_SIGN;
   
-  return gtk_rc_parse_color (scanner, &style->bg[state]);
+  style->color_flags[state] |= GTK_RC_FG;
+  return gtk_rc_parse_color (scanner, &style->fg[state]);
 }
 
 static guint
-gtk_rc_parse_fg (GScanner *scanner,
-                GtkStyle *style)
+gtk_rc_parse_text (GScanner   *scanner,
+                  GtkRcStyle *style)
 {
   GtkStateType state;
   guint token;
   
   token = g_scanner_get_next_token (scanner);
-  if (token != TOKEN_FG)
-    return TOKEN_FG;
+  if (token != GTK_RC_TOKEN_TEXT)
+    return GTK_RC_TOKEN_TEXT;
   
   token = gtk_rc_parse_state (scanner, &state);
   if (token != G_TOKEN_NONE)
@@ -1015,19 +1720,20 @@ gtk_rc_parse_fg (GScanner *scanner,
   if (token != G_TOKEN_EQUAL_SIGN)
     return G_TOKEN_EQUAL_SIGN;
   
-  return gtk_rc_parse_color (scanner, &style->fg[state]);
+  style->color_flags[state] |= GTK_RC_TEXT;
+  return gtk_rc_parse_color (scanner, &style->text[state]);
 }
 
 static guint
-gtk_rc_parse_text (GScanner *scanner,
-                  GtkStyle *style)
+gtk_rc_parse_base (GScanner   *scanner,
+                  GtkRcStyle *style)
 {
   GtkStateType state;
   guint token;
   
   token = g_scanner_get_next_token (scanner);
-  if (token != TOKEN_TEXT)
-    return TOKEN_TEXT;
+  if (token != GTK_RC_TOKEN_BASE)
+    return GTK_RC_TOKEN_BASE;
   
   token = gtk_rc_parse_state (scanner, &state);
   if (token != G_TOKEN_NONE)
@@ -1036,8 +1742,45 @@ gtk_rc_parse_text (GScanner *scanner,
   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]);
+
+  style->color_flags[state] |= GTK_RC_BASE;
+  return gtk_rc_parse_color (scanner, &style->base[state]);
+}
+
+static guint
+gtk_rc_parse_xthickness (GScanner   *scanner,
+                        GtkRcStyle *style)
+{
+  if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_XTHICKNESS)
+    return GTK_RC_TOKEN_XTHICKNESS;
+
+  if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
+    return G_TOKEN_EQUAL_SIGN;
+
+  if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
+    return G_TOKEN_INT;
+
+  style->xthickness = scanner->value.v_int;
+
+  return G_TOKEN_NONE;
+}
+
+static guint
+gtk_rc_parse_ythickness (GScanner   *scanner,
+                        GtkRcStyle *style)
+{
+  if (g_scanner_get_next_token (scanner) != GTK_RC_TOKEN_YTHICKNESS)
+    return GTK_RC_TOKEN_YTHICKNESS;
+
+  if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
+    return G_TOKEN_EQUAL_SIGN;
+
+  if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
+    return G_TOKEN_INT;
+
+  style->ythickness = scanner->value.v_int;
+
+  return G_TOKEN_NONE;
 }
 
 static guint
@@ -1049,8 +1792,8 @@ gtk_rc_parse_bg_pixmap (GScanner   *scanner,
   gchar *pixmap_file;
   
   token = g_scanner_get_next_token (scanner);
-  if (token != TOKEN_BG_PIXMAP)
-    return TOKEN_BG_PIXMAP;
+  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)
@@ -1064,10 +1807,11 @@ gtk_rc_parse_bg_pixmap (GScanner   *scanner,
   if (token != G_TOKEN_STRING)
     return G_TOKEN_STRING;
   
-  if (strcmp (scanner->value.v_string, "<parent>"))
-    pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
-  else
+  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 = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
   
   if (pixmap_file)
     {
@@ -1080,17 +1824,71 @@ gtk_rc_parse_bg_pixmap (GScanner   *scanner,
 }
 
 static gchar*
+gtk_rc_check_pixmap_dir (const gchar *dir, const gchar *pixmap_file)
+{
+  gchar *buf;
+  gint fd;
+
+  buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", dir, pixmap_file);
+  
+  fd = open (buf, O_RDONLY);
+  if (fd >= 0)
+    {
+      close (fd);
+      return buf;
+    }
+   
+  g_free (buf);
+   return NULL;
+ }
+gchar*
 gtk_rc_find_pixmap_in_path (GScanner *scanner,
-                           gchar    *pixmap_file)
+                           const gchar *pixmap_file)
+{
+  gint i;
+  gchar *filename;
+  GSList *tmp_list;
+    
+  for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
+    {
+      filename = gtk_rc_check_pixmap_dir (pixmap_path[i], pixmap_file);
+      if (filename)
+       return filename;
+    }
+  tmp_list = rc_dir_stack;
+  while (tmp_list)
+    {
+      filename = gtk_rc_check_pixmap_dir (tmp_list->data, pixmap_file);
+      if (filename)
+       return filename;
+       
+      tmp_list = tmp_list->next;
+    }
+  
+  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;
+}
+
+gchar*
+gtk_rc_find_module_in_path (const gchar *module_file)
 {
   gint i;
   gint fd;
   gchar *buf;
   
-  for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
+  for (i = 0; (i < GTK_RC_MAX_MODULE_PATHS) && (module_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);
+      buf = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
+                            module_path[i], module_file);
       
       fd = open (buf, O_RDONLY);
       if (fd >= 0)
@@ -1101,10 +1899,7 @@ gtk_rc_find_pixmap_in_path (GScanner *scanner,
       
       g_free (buf);
     }
-  
-  g_warning ("Unable to locate image file in pixmap_path: \"%s\" line %d",
-            pixmap_file, scanner->line);
-  
+    
   return NULL;
 }
 
@@ -1115,8 +1910,8 @@ gtk_rc_parse_font (GScanner   *scanner,
   guint token;
   
   token = g_scanner_get_next_token (scanner);
-  if (token != TOKEN_FONT)
-    return TOKEN_FONT;
+  if (token != GTK_RC_TOKEN_FONT)
+    return GTK_RC_TOKEN_FONT;
   
   token = g_scanner_get_next_token (scanner);
   if (token != G_TOKEN_EQUAL_SIGN)
@@ -1125,10 +1920,8 @@ gtk_rc_parse_font (GScanner   *scanner,
   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);
+
+  /* Ignore, do nothing */
   
   return G_TOKEN_NONE;
 }
@@ -1140,8 +1933,8 @@ gtk_rc_parse_fontset (GScanner     *scanner,
   guint token;
   
   token = g_scanner_get_next_token (scanner);
-  if (token != TOKEN_FONTSET)
-    return TOKEN_FONTSET;
+  if (token != GTK_RC_TOKEN_FONTSET)
+    return GTK_RC_TOKEN_FONTSET;
   
   token = g_scanner_get_next_token (scanner);
   if (token != G_TOKEN_EQUAL_SIGN)
@@ -1150,19 +1943,131 @@ gtk_rc_parse_fontset (GScanner  *scanner,
   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);
+
+  /* Do nothing - silently ignore */
   
   return G_TOKEN_NONE;
 }
 
 static guint
+gtk_rc_parse_font_name (GScanner   *scanner,
+                       GtkRcStyle *rc_style)
+{
+  guint token;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != GTK_RC_TOKEN_FONT_NAME)
+    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;
+
+  rc_style->font_desc = pango_font_description_from_string (scanner->value.v_string);
+  
+  return G_TOKEN_NONE;
+}
+
+static guint      
+gtk_rc_parse_engine (GScanner   *scanner,
+                    GtkRcStyle **rc_style)
+{
+  guint token;
+  GtkThemeEngine *engine;
+  guint result = G_TOKEN_NONE;
+  GtkRcStyle *new_style = NULL;
+  gboolean parsed_curlies = FALSE;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != GTK_RC_TOKEN_ENGINE)
+    return GTK_RC_TOKEN_ENGINE;
+
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_STRING)
+    return G_TOKEN_STRING;
+
+  engine = gtk_theme_engine_get (scanner->value.v_string);
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_LEFT_CURLY)
+    return G_TOKEN_LEFT_CURLY;
+
+  if (engine)
+    {
+      GtkRcStyleClass *new_class;
+      
+      new_style = gtk_theme_engine_create_rc_style (engine);
+      gtk_theme_engine_unref (engine);
+
+      new_class = GTK_RC_STYLE_GET_CLASS (new_style);
+
+      new_class->merge (new_style, *rc_style);
+      if ((*rc_style)->name)
+       new_style->name = g_strdup ((*rc_style)->name);
+      
+      if (new_class->parse)
+       {
+         parsed_curlies = TRUE;
+         result = new_class->parse (new_style, scanner);
+
+         if (result != G_TOKEN_NONE)
+           {
+             g_object_unref (G_OBJECT (new_style));
+             new_style = NULL;
+           }
+       }
+    }
+
+  if (!parsed_curlies)
+    {
+      /* Skip over remainder, looking for nested {}'s
+       */
+      guint count = 1;
+      
+      result = G_TOKEN_RIGHT_CURLY;
+      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--;
+         
+         if (count == 0)
+           {
+             result = G_TOKEN_NONE;
+             break;
+           }
+       }
+    }
+
+  if (new_style)
+    {
+      g_object_unref (G_OBJECT (*rc_style));
+      *rc_style = new_style;
+    }
+
+  return result;
+}
+
+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)
@@ -1171,37 +2076,92 @@ gtk_rc_parse_state (GScanner     *scanner,
   token = g_scanner_get_next_token (scanner);
   switch (token)
     {
-    case TOKEN_ACTIVE:
+    case GTK_RC_TOKEN_ACTIVE:
       *state = GTK_STATE_ACTIVE;
       break;
-    case TOKEN_INSENSITIVE:
+    case GTK_RC_TOKEN_INSENSITIVE:
       *state = GTK_STATE_INSENSITIVE;
       break;
-    case TOKEN_NORMAL:
+    case GTK_RC_TOKEN_NORMAL:
       *state = GTK_STATE_NORMAL;
       break;
-    case TOKEN_PRELIGHT:
+    case GTK_RC_TOKEN_PRELIGHT:
       *state = GTK_STATE_PRELIGHT;
       break;
-    case TOKEN_SELECTED:
+    case GTK_RC_TOKEN_SELECTED:
       *state = GTK_STATE_SELECTED;
       break;
     default:
-      return /* G_TOKEN_SYMBOL */ TOKEN_NORMAL;
+      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;
 }
 
-static guint
+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)
@@ -1314,8 +2274,8 @@ gtk_rc_parse_pixmap_path (GScanner *scanner)
   guint token;
   
   token = g_scanner_get_next_token (scanner);
-  if (token != TOKEN_PIXMAP_PATH)
-    return TOKEN_PIXMAP_PATH;
+  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)
@@ -1350,7 +2310,7 @@ gtk_rc_parse_pixmap_path_string (gchar *pix_path)
   
   for (end_offset = 0; end_offset <= path_len; end_offset++)
     {
-      if ((buf[end_offset] == ':') ||
+      if ((buf[end_offset] == G_SEARCHPATH_SEPARATOR) ||
          (end_offset == path_len))
        {
          buf[end_offset] = '\0';
@@ -1364,94 +2324,159 @@ gtk_rc_parse_pixmap_path_string (gchar *pix_path)
 }
 
 static guint
-gtk_rc_parse_widget_style (GScanner *scanner)
+gtk_rc_parse_module_path (GScanner *scanner)
 {
-  GtkRcSet *rc_set;
   guint token;
   
   token = g_scanner_get_next_token (scanner);
-  if (token != TOKEN_WIDGET)
-    return TOKEN_WIDGET;
+  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;
+}
 
-  rc_set = g_new (GtkRcSet, 1);
-  gtk_pattern_spec_init (&rc_set->pspec, scanner->value.v_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;
   
-  token = g_scanner_get_next_token (scanner);
-  if (token != TOKEN_STYLE)
+  /* free the old one, or just add to the old one ? */
+  for (path_num=0; module_path[path_num]; path_num++)
     {
-      gtk_pattern_spec_free_segs (&rc_set->pspec);
-      g_free (rc_set);
-      return TOKEN_STYLE;
+      g_free (module_path[path_num]);
+      module_path[path_num] = NULL;
     }
   
-  token = g_scanner_get_next_token (scanner);
-  if (token != G_TOKEN_STRING)
-    {
-      gtk_pattern_spec_free_segs (&rc_set->pspec);
-      g_free (rc_set);
-      return G_TOKEN_STRING;
-    }
+  path_num = 0;
   
-  rc_set->rc_style = gtk_rc_style_find (scanner->value.v_string);
-  if (!rc_set->rc_style)
-    {
-      gtk_pattern_spec_free_segs (&rc_set->pspec);
-      g_free (rc_set);
-      return G_TOKEN_STRING;
-    }
+  path_len = strlen (mod_path);
   
-  gtk_rc_sets_widget = g_slist_append (gtk_rc_sets_widget, rc_set);
+  buf = g_strdup (mod_path);
   
-  return G_TOKEN_NONE;
+  for (end_offset = 0; end_offset <= path_len; end_offset++)
+    {
+      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;
+       }
+    }
+  g_free (buf);
+  gtk_rc_append_default_module_path();
 }
 
 static guint
-gtk_rc_parse_widget_class_style (GScanner *scanner)
+gtk_rc_parse_path_pattern (GScanner   *scanner)
 {
-  GtkRcSet *rc_set;
   guint token;
+  GtkPathType path_type;
+  gchar *pattern;
+  gboolean is_binding;
+  GtkPathPriorityType priority = GTK_PATH_PRIO_RC;
   
   token = g_scanner_get_next_token (scanner);
-  if (token != TOKEN_WIDGET_CLASS)
-    return TOKEN_WIDGET_CLASS;
+  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;
-  
-  rc_set = g_new (GtkRcSet, 1);
-  gtk_pattern_spec_init (&rc_set->pspec, scanner->value.v_string);
+
+  pattern = g_strdup (scanner->value.v_string);
 
   token = g_scanner_get_next_token (scanner);
-  if (token != TOKEN_STYLE)
+  if (token == GTK_RC_TOKEN_STYLE)
+    is_binding = FALSE;
+  else if (token == GTK_RC_TOKEN_BINDING)
     {
-      gtk_pattern_spec_free_segs (&rc_set->pspec);
-      g_free (rc_set);
-      return G_TOKEN_STRING;
+      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)
     {
-      gtk_pattern_spec_free_segs (&rc_set->pspec);
-      g_free (rc_set);
+      g_free (pattern);
       return G_TOKEN_STRING;
     }
-  
-  rc_set->rc_style = gtk_rc_style_find (scanner->value.v_string);
-  if (!rc_set->rc_style)
+
+  if (is_binding)
     {
-      gtk_pattern_spec_free_segs (&rc_set->pspec);
-      g_free (rc_set);
-      return G_TOKEN_STRING;
+      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);
     }
-  
-  gtk_rc_sets_widget_class = g_slist_append (gtk_rc_sets_widget_class, rc_set);
-  
+  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;
 }
 
@@ -1466,6 +2491,25 @@ typedef  GdkPixmap * (*GtkImageLoader) (GdkWindow   *window,
 void
 gtk_rc_set_image_loader(GtkImageLoader loader)
 {
-       image_loader = loader;
+  image_loader = loader;
 }
 
+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);
+    }
+}