]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkrc.c
Include the build directory.
[~andy/gtk] / gtk / gtkrc.c
index aed1588f01bd3c04b9b5fc1da37752bc8fdc04ee..b6b3c820343e80b1040977cc40dd025851095918 100644 (file)
@@ -64,7 +64,6 @@
 typedef struct _GtkRcSet    GtkRcSet;
 typedef struct _GtkRcNode   GtkRcNode;
 typedef struct _GtkRcFile   GtkRcFile;
-typedef struct _GtkRcStylePrivate  GtkRcStylePrivate;
 
 struct _GtkRcSet
 {
@@ -80,66 +79,70 @@ struct _GtkRcFile
   gboolean reload;
 };
 
-struct _GtkRcStylePrivate
-{
-  GtkRcStyle style;
-
-  guint ref_count;
-  /* list of RC style lists including this RC style */
-  GSList *rc_style_lists;
-};
-
-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 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_pixmap_path (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 =
 {
@@ -195,10 +198,13 @@ static const struct
   { "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 },
+  { "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 },
@@ -249,35 +255,35 @@ static GtkImageLoader image_loader = NULL;
 #ifdef G_OS_WIN32
 
 gchar *
-get_gtk_sysconf_directory (void)
+gtk_win32_get_installation_directory (void)
 {
   static gboolean been_here = FALSE;
-  static gchar gtk_sysconf_dir[200];
+  static gchar gtk_installation_dir[200];
   gchar win_dir[100];
   HKEY reg_key = NULL;
   DWORD type;
-  DWORD nbytes = sizeof (gtk_sysconf_dir);
+  DWORD nbytes = sizeof (gtk_installation_dir);
 
   if (been_here)
-    return gtk_sysconf_dir;
+    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_sysconf_dir, &nbytes) != ERROR_SUCCESS
+                         &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_sysconf_dir, "%s\\gtk+", win_dir);
+      sprintf (gtk_installation_dir, "%s\\gtk+", win_dir);
     }
 
   if (reg_key != NULL)
     RegCloseKey (reg_key);
 
-  return gtk_sysconf_dir;
+  return gtk_installation_dir;
 }
 
 static gchar *
@@ -285,7 +291,7 @@ get_themes_directory (void)
 {
   static gchar themes_dir[200];
 
-  sprintf (themes_dir, "%s\\themes", get_gtk_sysconf_directory ());
+  sprintf (themes_dir, "%s\\themes", gtk_win32_get_installation_directory ());
   return themes_dir;
 }
 
@@ -317,9 +323,9 @@ gtk_rc_get_module_dir(void)
 #ifndef G_OS_WIN32
   var = getenv("GTK_EXE_PREFIX");
   if (var)
-    path = g_strdup_printf("%s%s", var, "/lib/gtk/themes/engines");
+    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/themes/engines");
+    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
@@ -327,32 +333,6 @@ gtk_rc_get_module_dir(void)
   return path;
 }
 
-static void
-gtk_rc_append_default_pixmap_path(void)
-{
-  gchar *var, *path;
-  gint n;
-
-#ifndef G_OS_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)
-    {
-      g_free (path);
-      return;
-    }
-  pixmap_path[n++] = path;
-  pixmap_path[n] = NULL;
-}
-
 static void
 gtk_rc_append_default_module_path(void)
 {
@@ -366,9 +346,9 @@ gtk_rc_append_default_module_path(void)
 #ifndef G_OS_WIN32
   var = getenv("GTK_EXE_PREFIX");
   if (var)
-    path = g_strdup_printf("%s%s", var, "/lib/gtk/themes/engines");
+    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/themes/engines");
+    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
@@ -378,7 +358,7 @@ gtk_rc_append_default_module_path(void)
   if (var)
     {
 #ifndef G_OS_WIN32
-      path = g_strdup_printf ("%s%s", var, "/.gtk/lib/themes/engines");
+      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
@@ -416,17 +396,18 @@ gtk_rc_add_initial_default_files (void)
   else
     {
 #ifndef G_OS_WIN32
-      str = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk" G_DIR_SEPARATOR_S "gtkrc");
+      str = g_strdup (GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk-2.0" G_DIR_SEPARATOR_S "gtkrc");
 #else
-      str = g_strdup_printf ("%s\\gtkrc", get_gtk_sysconf_directory ());
+      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", var);
+         str = g_strdup_printf ("%s" G_DIR_SEPARATOR_S ".gtkrc-2.0", var);
          gtk_rc_add_default_file (str);
          g_free (str);
        }
@@ -556,7 +537,6 @@ gtk_rc_init (void)
 
       pixmap_path[0] = NULL;
       module_path[0] = NULL;
-      gtk_rc_append_default_pixmap_path();
       gtk_rc_append_default_module_path();
       
       gtk_rc_add_initial_default_files ();
@@ -723,23 +703,69 @@ gtk_rc_parse (const gchar *filename)
 
 /* Handling of RC styles */
 
-GtkRcStyle *
-gtk_rc_style_new              (void)
+GType
+gtk_rc_style_get_type (void)
 {
-  GtkRcStylePrivate *new_style;
+  static GType object_type = 0;
 
-  new_style = g_new0 (GtkRcStylePrivate, 1);
-  new_style->ref_count = 1;
+  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_style_init (GtkRcStyle *style)
+{
+  guint i;
 
-  return (GtkRcStyle *)new_style;
+  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;
 }
 
-void      
-gtk_rc_style_ref (GtkRcStyle  *rc_style)
+static void
+gtk_rc_style_class_init (GtkRcStyleClass *klass)
 {
-  g_return_if_fail (rc_style != NULL);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  
+  parent_class = g_type_class_peek_parent (klass);
+
+  object_class->finalize = gtk_rc_style_finalize;
 
-  ((GtkRcStylePrivate *)rc_style)->ref_count++;
+  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;
 }
 
 /* Like g_slist_remove, but remove all copies of data */
@@ -780,74 +806,143 @@ gtk_rc_slist_remove_all (GSList   *list,
   return list;
 }
 
+static void
+gtk_rc_style_finalize (GObject *object)
+{
+  gint i;
+  GSList *tmp_list1, *tmp_list2;
+  GtkRcStyle *rc_style;
+
+  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);
+
+      /* 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_list1 = tmp_list1->next;
+    }
+  g_slist_free (rc_style->rc_style_lists);
+
+  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)
 {
-  GtkRcStylePrivate *private = (GtkRcStylePrivate *)rc_style;
-  gint i;
+  g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
 
-  g_return_if_fail (rc_style != NULL);
-  g_return_if_fail (private->ref_count > 0);
+  g_object_unref (G_OBJECT (rc_style));
+}
 
-  private->ref_count--;
+static GtkRcStyle *
+gtk_rc_style_real_clone (GtkRcStyle *style)
+{
+  return GTK_RC_STYLE (g_object_new (G_OBJECT_TYPE (style), NULL));
+}
 
-  if (private->ref_count == 0)
+static void
+gtk_rc_style_real_merge (GtkRcStyle *dest,
+                        GtkRcStyle *src)
+{
+  gint i;
+  
+  for (i = 0; i < 5; i++)
     {
-      GSList *tmp_list1, *tmp_list2;
-       
-      if (rc_style->engine)
+      if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
+       dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
+      
+      if (!(dest->color_flags[i] & GTK_RC_FG) && 
+         src->color_flags[i] & GTK_RC_FG)
        {
-         rc_style->engine->destroy_rc_style (rc_style);
-         gtk_theme_engine_unref (rc_style->engine);
+         dest->fg[i] = src->fg[i];
+         dest->color_flags[i] |= GTK_RC_FG;
        }
-
-      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]);
-      
-      /* Now remove all references to this rc_style from
-       * realized_style_ht
-       */
-      tmp_list1 = private->rc_style_lists;
-      while (tmp_list1)
+      if (!(dest->color_flags[i] & GTK_RC_BG) && 
+         src->color_flags[i] & GTK_RC_BG)
        {
-         GSList *rc_styles = tmp_list1->data;
-         GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
-         gtk_style_unref (style);
-
-         /* Remove the list of styles from the other rc_styles
-          * in the list
-          */
-         tmp_list2 = rc_styles;
-         while (tmp_list2)
-           {
-             GtkRcStylePrivate *other_style = tmp_list2->data;
-
-             if (other_style != private)
-               other_style->rc_style_lists =
-                 gtk_rc_slist_remove_all (other_style->rc_style_lists, rc_styles);
-                 
-             tmp_list2 = tmp_list2->next;
-           }
+         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;
+       }
+    }
 
-         /* And from the hash table itself
-          */
-         g_hash_table_remove (realized_style_ht, rc_styles);
-         g_slist_free (rc_styles);
+  if (dest->xthickness < 0 && src->xthickness >= 0)
+    dest->xthickness = src->xthickness;
+  if (dest->ythickness < 0 && src->ythickness >= 0)
+    dest->ythickness = src->ythickness;
 
-         tmp_list1 = tmp_list1->next;
-       }
-      g_slist_free (private->rc_style_lists);
+  if (!dest->font_desc && src->font_desc)
+    dest->font_desc = pango_font_description_copy (src->font_desc);
+}
 
-      g_free (private);
-    }
+static GtkStyle *
+gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
+{
+  return gtk_style_new ();
 }
 
 static void
@@ -1031,7 +1126,7 @@ gtk_rc_get_style (GtkWidget *widget)
     }
   
   if (rc_styles)
-    return gtk_rc_style_init (rc_styles);
+    return gtk_rc_init_style (rc_styles);
 
   return NULL;
 }
@@ -1048,8 +1143,8 @@ gtk_rc_add_rc_sets (GSList     *slist,
   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);
+  if (rc_style->font_desc)
+    new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
   
   for (i = 0; i < 5; i++)
     new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
@@ -1238,142 +1333,81 @@ gtk_rc_style_find (const char *name)
     return NULL;
 }
 
-/* Assumes ownership of rc_style */
 static GtkStyle *
 gtk_rc_style_to_style (GtkRcStyle *rc_style)
 {
   GtkStyle *style;
-  GdkFont *old_font;
-  gint i;
 
-  style = gtk_style_new ();
+  style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
 
   style->rc_style = rc_style;
+  gtk_rc_style_ref (rc_style);
   
-  if (rc_style->fontset_name)
-    {
-      old_font = style->font;
-      style->font = gdk_fontset_load (rc_style->fontset_name);
-      if (style->font)
-       gdk_font_unref (old_font);
-      else
-       style->font = old_font;
-    }
-  else if (rc_style->font_name)
-    {
-      old_font = style->font;
-      style->font = gdk_font_load (rc_style->font_name);
-      if (style->font)
-       gdk_font_unref (old_font);
-      else
-       style->font = old_font;
-    }
+  GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);
   
-  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)
-    {
-      style->engine = rc_style->engine;
-      gtk_theme_engine_ref (style->engine);
-      rc_style->engine->rc_style_to_style (style, rc_style);
-    }
-
   return style;
 }
 
 /* Reuses or frees rc_styles */
 static GtkStyle *
-gtk_rc_style_init (GSList *rc_styles)
+gtk_rc_init_style (GSList *rc_styles)
 {
-  gint i;
-
   GtkStyle *style = NULL;
+  gint i;
 
+  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);
+    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)
     {
+      GtkRcStyle *base_style = NULL;
       GtkRcStyle *proto_style;
+      GtkRcStyleClass *proto_style_class;
       GSList *tmp_styles;
-      
-      proto_style = gtk_rc_style_new ();
+      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.
+       */
+      base_style = rc_styles->data;
       tmp_styles = rc_styles;
       while (tmp_styles)
        {
          GtkRcStyle *rc_style = tmp_styles->data;
-         GtkRcStylePrivate *rc_style_private;
 
-         for (i=0; i<5; i++)
+         if (G_OBJECT_TYPE (rc_style) != rc_style_type)
            {
-             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;
-               }
+             base_style = rc_style;
+             break;
            }
 
-         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);
-           }
+         tmp_styles = tmp_styles->next;
+       }
+      
+      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)
+       {
+         GtkRcStyle *rc_style = tmp_styles->data;
+         
+         proto_style_class->merge (proto_style, rc_style);
          
-         if (proto_style->engine &&
-             (proto_style->engine == rc_style->engine))
-           proto_style->engine->merge_rc_style (proto_style, rc_style);
-
          /* Point from each rc_style to the list of styles */
-
-         rc_style_private = (GtkRcStylePrivate *)rc_style;
-         if (!g_slist_find (rc_style_private->rc_style_lists, rc_styles))
-           rc_style_private->rc_style_lists = g_slist_prepend (rc_style_private->rc_style_lists, rc_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++)
+      for (i = 0; i < 5; i++)
        if (proto_style->bg_pixmap_name[i] &&
            (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
          {
@@ -1382,6 +1416,7 @@ gtk_rc_style_init (GSList *rc_styles)
          }
 
       style = gtk_rc_style_to_style (proto_style);
+      gtk_rc_style_unref (proto_style);
 
       g_hash_table_insert (realized_style_ht, rc_styles, style);
     }
@@ -1474,9 +1509,6 @@ gtk_rc_parse_style (GScanner *scanner)
 
       for (i = 0; i < 5; i++)
        rc_style->color_flags[i] = 0;
-
-      rc_style->engine = NULL;
-      rc_style->engine_data = NULL;
     }
   
   token = g_scanner_peek_next_token (scanner);
@@ -1504,18 +1536,15 @@ gtk_rc_parse_style (GScanner *scanner)
              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;
          
-         if (parent_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 (parent_style->font_name)
+         if (parent_style->font_desc)
            {
-             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++)
@@ -1541,9 +1570,6 @@ gtk_rc_parse_style (GScanner *scanner)
     {
       switch (token)
        {
-       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;
@@ -1553,6 +1579,15 @@ gtk_rc_parse_style (GScanner *scanner)
        case GTK_RC_TOKEN_TEXT:
          token = gtk_rc_parse_text (scanner, rc_style);
          break;
+       case GTK_RC_TOKEN_BASE:
+         token = gtk_rc_parse_base (scanner, rc_style);
+         break;
+       case GTK_RC_TOKEN_XTHICKNESS:
+         token = gtk_rc_parse_xthickness (scanner, rc_style);
+         break;
+       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;
@@ -1562,8 +1597,11 @@ gtk_rc_parse_style (GScanner *scanner)
        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);
+         token = gtk_rc_parse_engine (scanner, &rc_style);
          break;
        default:
          g_scanner_get_next_token (scanner);
@@ -1575,10 +1613,9 @@ 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]);
@@ -1594,10 +1631,8 @@ 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])
@@ -1620,29 +1655,6 @@ gtk_rc_parse_style (GScanner *scanner)
   return G_TOKEN_NONE;
 }
 
-static guint
-gtk_rc_parse_base (GScanner   *scanner,
-                  GtkRcStyle *style)
-{
-  GtkStateType state;
-  guint token;
-  
-  token = g_scanner_get_next_token (scanner);
-  if (token != GTK_RC_TOKEN_BASE)
-    return GTK_RC_TOKEN_BASE;
-  
-  token = gtk_rc_parse_state (scanner, &state);
-  if (token != G_TOKEN_NONE)
-    return token;
-  
-  token = g_scanner_get_next_token (scanner);
-  if (token != G_TOKEN_EQUAL_SIGN)
-    return G_TOKEN_EQUAL_SIGN;
-
-  style->color_flags[state] |= GTK_RC_BASE;
-  return gtk_rc_parse_color (scanner, &style->base[state]);
-}
-
 static guint
 gtk_rc_parse_bg (GScanner   *scanner,
                 GtkRcStyle *style)
@@ -1712,6 +1724,65 @@ gtk_rc_parse_text (GScanner   *scanner,
   return gtk_rc_parse_color (scanner, &style->text[state]);
 }
 
+static guint
+gtk_rc_parse_base (GScanner   *scanner,
+                  GtkRcStyle *style)
+{
+  GtkStateType state;
+  guint token;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != GTK_RC_TOKEN_BASE)
+    return GTK_RC_TOKEN_BASE;
+  
+  token = gtk_rc_parse_state (scanner, &state);
+  if (token != G_TOKEN_NONE)
+    return token;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_EQUAL_SIGN)
+    return G_TOKEN_EQUAL_SIGN;
+
+  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
 gtk_rc_parse_bg_pixmap (GScanner   *scanner,
                        GtkRcStyle *rc_style)
@@ -1849,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;
 }
@@ -1874,20 +1943,45 @@ gtk_rc_parse_fontset (GScanner   *scanner,
   token = g_scanner_get_next_token (scanner);
   if (token != G_TOKEN_STRING)
     return G_TOKEN_STRING;
+
+  /* Do nothing - silently ignore */
+  
+  return G_TOKEN_NONE;
+}
+
+static guint
+gtk_rc_parse_font_name (GScanner   *scanner,
+                       GtkRcStyle *rc_style)
+{
+  guint token;
   
-  if (rc_style->fontset_name)
-    g_free (rc_style->fontset_name);
-  rc_style->fontset_name = g_strdup (scanner->value.v_string);
+  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)
+                    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;
@@ -1896,32 +1990,67 @@ gtk_rc_parse_engine (GScanner    *scanner,
   if (token != G_TOKEN_STRING)
     return G_TOKEN_STRING;
 
-  rc_style->engine = gtk_theme_engine_get (scanner->value.v_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 (rc_style->engine)
-    return rc_style->engine->parse_rc_style (scanner, rc_style);
-  else
+  if (engine)
     {
-      /* Skip over remainder, looking for nested {}'s */
+      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)
-           return G_TOKEN_NONE;
+           {
+             result = G_TOKEN_NONE;
+             break;
+           }
        }
+    }
 
-      return G_TOKEN_RIGHT_CURLY;
+  if (new_style)
+    {
+      g_object_unref (G_OBJECT (*rc_style));
+      *rc_style = new_style;
     }
+
+  return result;
 }
 
 guint
@@ -2192,7 +2321,6 @@ gtk_rc_parse_pixmap_path_string (gchar *pix_path)
        }
     }
   g_free (buf);
-  gtk_rc_append_default_pixmap_path();
 }
 
 static guint