[glib/g-property: 7/16] gproperty: Clean up default value implementation



commit 8a50a9941335fcc0e0c4f9142841d39f9464f68c
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Mon May 23 17:04:55 2011 +0100

    gproperty: Clean up default value implementation
    
    An overhaul of the default value implementation for GProperty.
    
    Instead of using a separate GValue pointer we can use a slot inside the
    GParamSpec qdata member, using a generalized lock quark as the unique
    property id. The id is created on demand, so properties with no default
    and no locking do not pay any penalty.
    
    The API for setting and overriding the default required some changes:
    now it is not necessary to call g_property_set_default() and pass the
    class type â though overriding requires calling the newly added
    g_property_override_default() and passing the GType used as the key
    to retrieve the default.
    
    These changes allow us to drop the GValue* member in the GProperty
    structure; we can also reuse the GParamSpec value_type field to drop
    both the gtype and prerequisite members of GProperty, thus making
    GProperty smaller that 60 bytes on 32bit archs â well within the first
    cacheline. This should improve memory usage and caching:
    
    struct _GProperty {
            GParamSpec                 parent_instance;      /*     0    40 */
            guint                      flags:15;             /*    40:17  4 */
            guint                      is_installed:1;       /*    40:16  4 */
    
            /* Bitfield combined with next fields */
    
            guint16                    type_size;            /*    42     2 */
            guint16                    priv_offset;          /*    44     2 */
            guint16                    field_offset;         /*    46     2 */
            GQuark                     prop_id;              /*    48     4 */
            GPropertyLockFunc          lock_func;            /*    52     4 */
            GPropertyUnlockFunc        unlock_func;          /*    56     4 */
    
            /* size: 60, cachelines: 1, members: 9 */
            /* last cacheline: 60 bytes */
    };
    
    As a bonus, this commit adds support for generic pointer properties.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=648526

 gobject/gobject.c              |    6 +-
 gobject/gobject.symbols        |    1 +
 gobject/gproperty.c            |  765 ++++++++++++++++++++++++++++------------
 gobject/gproperty.h            |   16 +-
 gobject/tests/autoproperties.c |   67 ++++-
 5 files changed, 612 insertions(+), 243 deletions(-)
---
diff --git a/gobject/gobject.c b/gobject/gobject.c
index 212f7a6..686101f 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -798,7 +798,7 @@ override_property_default_value (GObjectClass *oclass,
                                  GProperty    *property,
                                  const GValue *value)
 {
-  g_property_set_default_value (property, oclass, value);
+  g_property_override_default_value (property, G_OBJECT_CLASS_TYPE (oclass), value);
 }
 
 /**
@@ -1331,9 +1331,7 @@ object_set_property (GObject             *object,
     {
       if (G_IS_PROPERTY (pspec))
         {
-          GProperty *prop = G_PROPERTY (pspec);
-
-          g_property_set_value (prop, object, &tmp_value);
+          g_property_set_value ((GProperty *) pspec, object, &tmp_value);
         }
       else
         {
diff --git a/gobject/gobject.symbols b/gobject/gobject.symbols
index 2d849b3..6098c8a 100644
--- a/gobject/gobject.symbols
+++ b/gobject/gobject.symbols
@@ -217,6 +217,7 @@ g_int8_property_new
 g_int_property_new
 g_long_property_new
 g_object_property_new
+g_pointer_property_new
 g_property_canonicalize_name
 g_property_collect
 g_property_get
diff --git a/gobject/gproperty.c b/gobject/gproperty.c
index 5693771..d0fa053 100644
--- a/gobject/gproperty.c
+++ b/gobject/gproperty.c
@@ -443,13 +443,8 @@ struct _GProperty
   guint16 priv_offset;
   guint16 field_offset;
 
-  GType gtype;
-  GType prerequisite;
-
-  /* used by the default locking */
-  GValue *default_value;
+  GQuark prop_id;
 
-  GQuark lock_quark;
   GPropertyLockFunc lock_func;
   GPropertyUnlockFunc unlock_func;
 };
@@ -570,8 +565,8 @@ g_##g_t##_property_new (const gchar         *name,      \
                                 property_flags_to_param_flags (flags)); \
 \
   prop->flags = flags; \
-  prop->gtype = G_T; \
-  prop->prerequisite = G_TYPE_INVALID; \
+\
+  G_PARAM_SPEC (prop)->value_type = G_T; \
 \
   prop->field_offset = offset; \
 \
@@ -728,11 +723,11 @@ g_property_default_lock (GProperty *property,
 {
   gpointer bit_lock_p;
 
-  bit_lock_p = g_object_get_qdata (gobject, property->lock_quark);
+  bit_lock_p = g_object_get_qdata (gobject, property->prop_id);
   if (bit_lock_p == NULL)
     {
       bit_lock_p = g_new0 (gint, 1);
-      g_object_set_qdata (gobject, property->lock_quark, bit_lock_p);
+      g_object_set_qdata (gobject, property->prop_id, bit_lock_p);
     }
 
   g_bit_lock (bit_lock_p, 0);
@@ -744,11 +739,11 @@ g_property_default_unlock (GProperty *property,
 {
   gpointer bit_lock_p;
 
-  bit_lock_p = g_object_get_qdata (gobject, property->lock_quark);
+  bit_lock_p = g_object_get_qdata (gobject, property->prop_id);
   if (G_UNLIKELY (bit_lock_p == NULL))
     return;
 
-  g_object_set_qdata (gobject, property->lock_quark, NULL);
+  g_object_set_qdata (gobject, property->prop_id, NULL);
   g_bit_unlock (bit_lock_p, 0);
   g_free (bit_lock_p);
 }
@@ -818,13 +813,22 @@ static const GValue *
 property_get_default_for_type (GProperty *property,
                                GType      gtype)
 {
+  GParamSpec *pspec = (GParamSpec *) property;
+
   if (gtype == G_TYPE_INVALID)
     {
-      return property->default_value;
+      if (property->prop_id == 0)
+        {
+          gchar *lock_name = g_strconcat ("__g_property_id_", pspec->name, NULL);
+
+          property->prop_id = g_quark_from_string (lock_name);
+          g_free (lock_name);
+        }
+
+      return g_param_spec_get_qdata (pspec, property->prop_id);
     }
   else
     {
-      GParamSpec *pspec = (GParamSpec *) property;
 
       return g_param_spec_get_qdata (pspec, g_type_qname (gtype));
     }
@@ -839,16 +843,42 @@ value_unset_and_free (gpointer data)
   g_free (value);
 }
 
-static void
+static inline void
 property_set_default_for_type (GProperty *property,
                                GType      gtype,
                                GValue    *value)
 {
   GParamSpec *pspec = (GParamSpec *) property;
 
-  g_param_spec_set_qdata_full (pspec, g_type_qname (gtype),
-                               value,
-                               value_unset_and_free);
+  if (gtype == G_TYPE_INVALID)
+    {
+      if (property->prop_id == 0)
+        {
+          gchar *lock_name = g_strconcat ("__g_property_id_", pspec->name, NULL);
+
+          property->prop_id = g_quark_from_string (lock_name);
+          g_free (lock_name);
+        }
+
+      if (g_param_spec_get_qdata (pspec, property->prop_id) != NULL)
+        {
+          g_critical (G_STRLOC ": The property '%s' already has a default "
+                      "value. Use g_property_override_default() instead.",
+                      pspec->name);
+          return;
+        }
+
+      g_param_spec_set_qdata_full (pspec, property->prop_id,
+                                   value,
+                                   value_unset_and_free);
+    }
+  else
+    {
+
+      g_param_spec_set_qdata_full (pspec, g_type_qname (gtype),
+                                   value,
+                                   value_unset_and_free);
+    }
 }
 
 /**
@@ -888,7 +918,7 @@ DEFINE_PROPERTY_INTEGER (Boolean, boolean, gboolean, G_TYPE_BOOLEAN, FALSE, FALS
  *
  * Since: 2.32
  */
-DEFINE_PROPERTY_INTEGER (Int, int, gint, G_TYPE_INT, 0, G_MININT, G_MAXINT)
+DEFINE_PROPERTY_INTEGER (Int, int, int, G_TYPE_INT, 0, G_MININT, G_MAXINT)
 
 /**
  * g_int8_property_new:
@@ -983,7 +1013,7 @@ DEFINE_PROPERTY_INTEGER (Int64, int64, gint64, G_TYPE_INT64, 0, G_MININT64, G_MA
  *
  * Since: 2.32
  */
-DEFINE_PROPERTY_INTEGER (Long, long, glong, G_TYPE_LONG, 0, G_MINLONG, G_MAXLONG)
+DEFINE_PROPERTY_INTEGER (Long, long, long, G_TYPE_LONG, 0, G_MINLONG, G_MAXLONG)
 
 /**
  * g_uint_property_new:
@@ -1226,8 +1256,8 @@ g_enum_property_new (const gchar      *name,
                                 property_flags_to_param_flags (flags));
 
   prop->flags = flags;
-  prop->gtype = G_TYPE_ENUM;
-  prop->prerequisite = G_TYPE_INVALID;
+
+  G_PARAM_SPEC (prop)->value_type = G_TYPE_ENUM;
 
   prop->field_offset = offset;
 
@@ -1476,8 +1506,8 @@ g_flags_property_new (const gchar       *name,
                                 property_flags_to_param_flags (flags));
 
   prop->flags = flags;
-  prop->gtype = G_TYPE_FLAGS;
-  prop->prerequisite = G_TYPE_INVALID;
+
+  G_PARAM_SPEC (prop)->value_type = G_TYPE_FLAGS;
 
   prop->field_offset = offset;
 
@@ -1729,8 +1759,8 @@ g_float_property_new (const gchar       *name,
                                 property_flags_to_param_flags (flags));
 
   prop->flags = flags;
-  prop->gtype = G_TYPE_FLOAT;
-  prop->prerequisite = G_TYPE_INVALID;
+
+  G_PARAM_SPEC (prop)->value_type = G_TYPE_FLOAT;
 
   prop->field_offset = offset;
 
@@ -2002,8 +2032,8 @@ g_double_property_new (const gchar        *name,
                                 property_flags_to_param_flags (flags));
 
   prop->flags = flags;
-  prop->gtype = G_TYPE_DOUBLE;
-  prop->prerequisite = G_TYPE_INVALID;
+
+  G_PARAM_SPEC (prop)->value_type = G_TYPE_DOUBLE;
 
   prop->field_offset = offset;
 
@@ -2233,8 +2263,8 @@ g_string_property_new (const gchar        *name,
                                 property_flags_to_param_flags (flags));
 
   prop->flags = flags;
-  prop->gtype = G_TYPE_STRING;
-  prop->prerequisite = G_TYPE_INVALID;
+
+  G_PARAM_SPEC (prop)->value_type = G_TYPE_STRING;
 
   prop->field_offset = offset;
 
@@ -2443,8 +2473,8 @@ g_boxed_property_new (const gchar       *name,
                                 property_flags_to_param_flags (flags));
 
   prop->flags = flags;
-  prop->gtype = G_TYPE_BOXED;
-  prop->prerequisite = G_TYPE_INVALID;
+
+  G_PARAM_SPEC (prop)->value_type = G_TYPE_BOXED;
 
   prop->field_offset = offset;
 
@@ -2511,10 +2541,10 @@ g_boxed_property_set_value (GProperty     *property,
         }
 
       if ((* (gpointer *) field_p) != NULL)
-        g_boxed_free (property->prerequisite, (* (gpointer *) field_p));
+        g_boxed_free (((GParamSpec *) property)->value_type, (* (gpointer *) field_p));
 
       if (value != NULL)
-        (* (gpointer *) field_p) = g_boxed_copy (property->prerequisite, value);
+        (* (gpointer *) field_p) = g_boxed_copy (((GParamSpec *) property)->value_type, value);
       else
         (* (gpointer *) field_p) = NULL;
 
@@ -2652,8 +2682,8 @@ g_object_property_new (const gchar        *name,
                                 property_flags_to_param_flags (flags));
 
   prop->flags = flags;
-  prop->gtype = G_TYPE_OBJECT;
-  prop->prerequisite = G_TYPE_INVALID;
+
+  G_PARAM_SPEC (prop)->value_type = G_TYPE_OBJECT;
 
   prop->field_offset = offset;
 
@@ -2672,14 +2702,10 @@ static inline gboolean
 g_object_property_validate (GProperty     *property,
                             gconstpointer  value)
 {
-  GType gtype;
-
-  if (property->prerequisite != G_TYPE_INVALID)
-    gtype = property->prerequisite;
-  else
-    gtype = property->gtype;
+  if (value == NULL)
+    return FALSE;
 
-  return g_type_is_a (G_OBJECT_TYPE (value), gtype);
+  return g_type_is_a (G_OBJECT_TYPE (value), G_PARAM_SPEC (property)->value_type);
 }
 
 static inline gboolean
@@ -2792,6 +2818,208 @@ g_object_property_get_value (GProperty *property,
 }
 
 /*
+ * gpointer
+ */
+
+/* forward declaration */
+GType _g_pointer_property_get_type (void);
+
+typedef struct {
+  GProperty parent;
+
+  GPropertyPointerSet setter;
+  GPropertyPointerGet getter;
+} GPointerProperty;
+
+static void
+property_pointer_class_init (GParamSpecClass *klass)
+{
+  klass->value_type = G_TYPE_POINTER;
+}
+
+static void
+property_pointer_init (GParamSpec *pspec)
+{
+}
+
+GType
+_g_pointer_property_get_type (void)
+{
+  static volatile gsize pspec_type_id__volatile = 0;
+
+  if (g_once_init_enter (&pspec_type_id__volatile))
+    {
+      const GTypeInfo info = {
+        sizeof (GParamSpecClass),
+        NULL, NULL,
+        (GClassInitFunc) property_pointer_class_init,
+        NULL, NULL,
+        sizeof (GPointerProperty),
+        0,
+        (GInstanceInitFunc) property_pointer_init,
+      };
+
+      GType pspec_type_id =
+        g_type_register_static (G_TYPE_PROPERTY,
+                                g_intern_static_string ("GPointerProperty"),
+                                &info, 0);
+
+      g_once_init_leave (&pspec_type_id__volatile, pspec_type_id);
+    }
+
+  return pspec_type_id__volatile;
+}
+
+/**
+ * g_pointer_property_new:
+ * @name: canonical name of the property
+ * @flags: flags for the property
+ * @offset: the offset in the private structure of the field
+ *   that stores the property, or -1
+ * @setter: (allow-none): the setter function for the property
+ * @getter: (allow-none): the getter function for the property
+ *
+ * Creates a new #GProperty mapping to an untyped pointer.
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+GParamSpec *
+g_pointer_property_new (const gchar        *name,
+                        GPropertyFlags      flags,
+                        gssize              offset,
+                        GPropertyObjectSet  setter,
+                        GPropertyObjectGet  getter)
+{
+  GProperty *prop;
+  GPointerProperty *internal;
+
+  prop = g_param_spec_internal (_g_pointer_property_get_type (),
+                                name, NULL, NULL,
+                                property_flags_to_param_flags (flags));
+
+  prop->flags = flags;
+
+  G_PARAM_SPEC (prop)->value_type = G_TYPE_POINTER;
+
+  prop->field_offset = offset;
+
+  prop->is_installed = FALSE;
+
+  prop->type_size = sizeof (gpointer);
+
+  internal = (GPointerProperty *) prop;
+  internal->setter = setter;
+  internal->getter = getter;
+
+  return G_PARAM_SPEC (prop);
+}
+
+static inline gboolean
+g_pointer_property_validate (GProperty     *property,
+                             gconstpointer  value)
+{
+  return TRUE;
+}
+
+static inline gboolean
+g_pointer_property_set_value (GProperty *property,
+                              gpointer   gobject,
+                              gpointer   value)
+{
+  gboolean retval = FALSE;
+
+  if ((property->flags & G_PROPERTY_WRITABLE) == 0)
+    {
+      g_critical ("The property '%s' of object '%s' is not writable",
+                  G_PARAM_SPEC (property)->name,
+                  G_OBJECT_TYPE_NAME (gobject));
+      return FALSE;
+    }
+
+  if (!g_pointer_property_validate (property, value))
+    {
+      g_warning ("The value for the property '%s' of object '%s' is out of the valid range",
+                 G_PARAM_SPEC (property)->name,
+                 G_OBJECT_TYPE_NAME (gobject));
+      return FALSE;
+    }
+
+  property_lock_internal (property, gobject);
+
+  if (((GPointerProperty *) property)->setter != NULL)
+    {
+      ((GPointerProperty *) property)->setter (gobject, value);
+
+      retval = TRUE;
+    }
+  else if (property->field_offset >= 0)
+    {
+      gpointer priv_p, field_p;
+
+      g_return_val_if_fail (value == NULL || G_IS_OBJECT (value), FALSE);
+
+      priv_p = get_private_pointer (gobject, property->priv_offset);
+      field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
+
+      if ((* (gpointer *) field_p) == value)
+        {
+          property_unlock_internal (property, gobject);
+          return FALSE;
+        }
+
+      (* (gpointer *) field_p) = value;
+
+      g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+
+      retval = TRUE;
+    }
+  else
+    g_critical (G_STRLOC ": No setter function or field offset specified "
+                "for property '%s'",
+                G_PARAM_SPEC (property)->name);
+
+  property_unlock_internal (property, gobject);
+
+  return retval;
+}
+
+static inline gpointer
+g_pointer_property_get_value (GProperty *property,
+                              gpointer   gobject)
+{
+  if ((property->flags & G_PROPERTY_READABLE) == 0)
+    {
+      g_critical ("The property '%s' of object '%s' is not readable",
+                  G_PARAM_SPEC (property)->name,
+                  G_OBJECT_TYPE_NAME (gobject));
+      return FALSE;
+    }
+
+  if (((GPointerProperty *) property)->getter != NULL)
+    {
+      return ((GPointerProperty *) property)->getter (gobject);
+    }
+  else if (property->field_offset >= 0)
+    {
+      gpointer priv_p, field_p;
+
+      priv_p = g_type_instance_get_private (gobject, G_OBJECT_TYPE (gobject));
+      field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
+
+      return (* (gpointer *) field_p);
+    }
+  else
+    {
+      g_critical (G_STRLOC ": No getter function or field offset specified "
+                  "for property '%s'",
+                  G_PARAM_SPEC (property)->name);
+      return NULL;
+    }
+}
+
+/*
  * GProperty common API
  */
 
@@ -2847,12 +3075,13 @@ _g_property_set_installed (GProperty *property,
    * quark for the lock
    */
   if ((property->flags & G_PROPERTY_ATOMIC) != 0 &&
+      property->prop_id == 0 &&
       property->lock_func == NULL)
     {
-      gchar *lock_n = g_strconcat ("__g_property_lock_",
+      gchar *lock_n = g_strconcat ("__g_property_id_",
                                    G_PARAM_SPEC (property)->name,
                                    NULL);
-      property->lock_quark = g_quark_from_string (lock_n);
+      property->prop_id = g_quark_from_string (lock_n);
       g_free (lock_n);
     }
 
@@ -3009,23 +3238,23 @@ g_property_set_prerequisite (GProperty *property,
 {
   g_return_if_fail (G_IS_PROPERTY (property));
   g_return_if_fail (gtype != G_TYPE_INVALID);
-  g_return_if_fail (property->gtype != G_TYPE_INVALID);
-  g_return_if_fail (g_type_is_a (gtype, property->gtype));
+  g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
+  g_return_if_fail (g_type_is_a (gtype, G_PARAM_SPEC (property)->value_type));
 
-  switch (property->gtype)
+  switch (G_PARAM_SPEC (property)->value_type)
     {
     case G_TYPE_BOXED:
     case G_TYPE_OBJECT:
-      property->prerequisite = gtype;
+      G_PARAM_SPEC (property)->value_type = gtype;
       break;
 
     case G_TYPE_ENUM:
-      property->prerequisite = gtype;
+      G_PARAM_SPEC (property)->value_type = gtype;
       ((GEnumProperty *) property)->e_class = g_type_class_ref (gtype);
       break;
 
     case G_TYPE_FLAGS:
-      property->prerequisite = gtype;
+      G_PARAM_SPEC (property)->value_type = gtype;
       ((GFlagsProperty *) property)->f_class = g_type_class_ref (gtype);
       break;
 
@@ -3051,14 +3280,18 @@ g_property_set_range_values (GProperty    *property,
                              const GValue *min_value,
                              const GValue *max_value)
 {
+  GType gtype;
+
   g_return_if_fail (G_IS_PROPERTY (property));
-  g_return_if_fail (property->gtype != G_TYPE_INVALID);
+  g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
   g_return_if_fail (!property->is_installed);
   g_return_if_fail (min_value != NULL && max_value != NULL);
-  g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (min_value), property->gtype));
-  g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (max_value), property->gtype));
 
-  switch (property->gtype)
+  gtype = G_PARAM_SPEC (property)->value_type;
+  g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (min_value), gtype));
+  g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (max_value), gtype));
+
+  switch (gtype)
     {
     case G_TYPE_BOOLEAN:
       g_boolean_property_set_range (property,
@@ -3178,14 +3411,17 @@ g_property_get_range_values (GProperty *property,
                              GValue    *max_value)
 {
   gboolean retval;
+  GType gtype;
 
   g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
   g_return_val_if_fail (min_value != NULL, FALSE);
   g_return_val_if_fail (max_value != NULL, FALSE);
-  g_return_val_if_fail (g_value_type_compatible (property->gtype, G_VALUE_TYPE (min_value)), FALSE);
-  g_return_val_if_fail (g_value_type_compatible (property->gtype, G_VALUE_TYPE (max_value)), FALSE);
 
-  switch (property->gtype)
+  gtype = G_PARAM_SPEC (property)->value_type;
+  g_return_val_if_fail (g_value_type_compatible (gtype, G_VALUE_TYPE (min_value)), FALSE);
+  g_return_val_if_fail (g_value_type_compatible (gtype, G_VALUE_TYPE (max_value)), FALSE);
+
+  switch (gtype)
     {
     case G_TYPE_BOOLEAN:
       {
@@ -3323,7 +3559,7 @@ g_property_get_range_values (GProperty *property,
       break;
 
     default:
-      g_critical (G_STRLOC ": Invalid type '%s'", g_type_name (property->gtype));
+      g_critical (G_STRLOC ": Invalid type '%s'", g_type_name (gtype));
       retval = FALSE;
       break;
     }
@@ -3346,16 +3582,19 @@ g_property_set_range (GProperty *property,
 {
   GValue min_value = { 0, };
   GValue max_value = { 0, };
+  GType gtype;
   gchar *error;
   va_list var_args;
 
   g_return_if_fail (G_IS_PROPERTY (property));
-  g_return_if_fail (property->gtype != G_TYPE_INVALID);
   g_return_if_fail (!property->is_installed);
 
+  gtype = G_PARAM_SPEC (property)->value_type;
+  g_return_if_fail (gtype != G_TYPE_INVALID);
+
   va_start (var_args, property);
 
-  G_VALUE_COLLECT_INIT (&min_value, property->gtype, var_args, 0, &error);
+  G_VALUE_COLLECT_INIT (&min_value, gtype, var_args, 0, &error);
   if (error != NULL)
     {
       g_warning (G_STRLOC ": %s", error);
@@ -3364,7 +3603,7 @@ g_property_set_range (GProperty *property,
       return;
     }
 
-  G_VALUE_COLLECT_INIT (&max_value, property->gtype, var_args, 0, &error);
+  G_VALUE_COLLECT_INIT (&max_value, gtype, var_args, 0, &error);
   if (error != NULL)
     {
       g_warning (G_STRLOC ": %s", error);
@@ -3403,12 +3642,9 @@ g_property_get_range (GProperty *property,
   gpointer min_p, max_p;
 
   g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
-  g_return_val_if_fail (property->gtype != G_TYPE_INVALID, FALSE);
+  g_return_val_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID, FALSE);
 
-  if (property->prerequisite != G_TYPE_INVALID)
-    gtype = property->prerequisite;
-  else
-    gtype = property->gtype;
+  gtype = G_PARAM_SPEC (property)->value_type;
 
   va_start (var_args, property);
 
@@ -3528,58 +3764,68 @@ g_property_get_range (GProperty *property,
  */
 void
 g_property_set_default_value (GProperty    *property,
-                              gpointer      gobject_class,
                               const GValue *default_value)
 {
   GValue *value;
-  GType gtype, class_gtype;
+  GType gtype;
 
   g_return_if_fail (G_IS_PROPERTY (property));
-  g_return_if_fail (G_IS_OBJECT_CLASS (gobject_class));
-  g_return_if_fail (property->gtype != G_TYPE_INVALID);
+  g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
   g_return_if_fail (default_value != NULL);
 
-  if (property->prerequisite != G_TYPE_INVALID)
-    gtype = property->prerequisite;
-  else
-    gtype = property->gtype;
+  gtype = G_PARAM_SPEC (property)->value_type;
 
   g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (default_value), gtype));
 
-  /* if this is the first time g_property_set_default() has been called
-   * on this property, then we special-case it, and we use a single
-   * GValue, to avoid creating an hash table for the common case of a
-   * property with a single default.
-   */
-  if (property->default_value == NULL)
+  value = g_new0 (GValue, 1);
+  g_value_init (value, gtype);
+  if (!g_value_transform (default_value, value))
     {
-      property->default_value = g_new0 (GValue, 1);
-      g_value_init (property->default_value, gtype);
-      if (!g_value_transform (default_value, property->default_value))
-        {
-          g_critical (G_STRLOC ": unable to set the default value for "
-                      "property '%s': the type %s of the value is not "
-                      "compatible with the type of the %s property",
-                      G_PARAM_SPEC (property)->name,
-                      g_type_name (G_VALUE_TYPE (default_value)),
-                      g_type_name (gtype));
-
-          g_value_unset (property->default_value);
-          g_free (property->default_value);
-        }
+      g_critical (G_STRLOC ": unable to set the default value for "
+                  "property '%s': the type %s of the value is not "
+                  "compatible with the type of the %s property",
+                  G_PARAM_SPEC (property)->name,
+                  g_type_name (G_VALUE_TYPE (default_value)),
+                  g_type_name (gtype));
 
+      g_value_unset (value);
+      g_free (value);
       return;
     }
 
-  class_gtype = G_TYPE_FROM_CLASS (gobject_class);
-  if (property_get_default_for_type (property, class_gtype) == NULL)
-    {
-      g_critical (G_STRLOC ": a default value of property '%s' for "
-                  "type '%s' has already been defined.",
-                  G_PARAM_SPEC (property)->name,
-                  g_type_name (class_gtype));
-      return;
-    }
+  property_set_default_for_type (property, G_TYPE_INVALID, value);
+}
+
+/**
+ * g_property_override_default_value:
+ * @property: a #GProperty
+ * @class_gtype: the type of the class overriding the value
+ * @default_value: a #GValue containing a value with the type of the
+ *   property or a transformable type
+ *
+ * Overrides the default value of a @property for the given class
+ * type.
+ *
+ * This function should only be called by language bindings.
+ *
+ * Since: 2.32
+ */
+void
+g_property_override_default_value (GProperty    *property,
+                                   GType         class_gtype,
+                                   const GValue *default_value)
+{
+  GValue *value;
+  GType gtype;
+
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
+  g_return_if_fail (g_type_name (class_gtype) != 0);
+  g_return_if_fail (default_value != NULL);
+
+  gtype = G_PARAM_SPEC (property)->value_type;
+
+  g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (default_value), gtype));
 
   value = g_new0 (GValue, 1);
   g_value_init (value, gtype);
@@ -3597,6 +3843,7 @@ g_property_set_default_value (GProperty    *property,
       return;
     }
 
+  /* takes ownership of value */
   property_set_default_for_type (property, class_gtype, value);
 }
 
@@ -3612,45 +3859,77 @@ g_property_set_default_value (GProperty    *property,
  * introspection tools; #GObject implementations should use
  * g_property_get_default() instead.
  *
+ * Return value: %TRUE if there is a default got the given type,
+ *   and %FALSE otherwise.
+ *
  * Since: 2.32
  */
-void
+gboolean
 g_property_get_default_value_for_type (GProperty *property,
                                        GType      gtype,
                                        GValue    *value)
 {
-  const GValue *default_value;
+  const GValue *default_value = NULL;
+  GType iter;
 
-  g_return_if_fail (G_IS_PROPERTY (property));
-  g_return_if_fail (property->gtype != G_TYPE_INVALID);
-  g_return_if_fail (g_type_name (gtype) != 0);
+  g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+  g_return_val_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID, FALSE);
+  g_return_val_if_fail (g_type_name (gtype) != 0, FALSE);
+
+  /* we need to recurse through the inheritance chain... */
+  iter = gtype;
+  while (iter != G_TYPE_INVALID && default_value == NULL)
+    {
+      default_value = property_get_default_for_type (property, iter);
+      gtype = g_type_parent (iter);
+    }
+
+  if (default_value != NULL)
+    goto out;
 
-  if (property->default_value != NULL)
+  /* ... and eventually check the implemented interfaces */
+  if (default_value == NULL)
     {
-      if (!g_value_transform (property->default_value, value))
+      GType *ifaces;
+      guint n_ifaces;
+
+      ifaces = g_type_interfaces (gtype, &n_ifaces);
+      while (n_ifaces-- && default_value == NULL)
         {
-          g_critical (G_STRLOC ": Unable to copy the default value "
-                      "of property '%s' from type '%s' to type '%s'",
-                      G_PARAM_SPEC (property)->name,
-                      g_type_name (property->gtype),
-                      g_type_name (G_VALUE_TYPE (value)));
+          iter = ifaces[n_ifaces];
+          default_value = property_get_default_for_type (property, iter);
         }
 
-      return;
+      g_free (ifaces);
     }
 
-  default_value = property_get_default_for_type (property, gtype);
   if (default_value != NULL)
+    goto out;
+
+  /* if the property hasn't been overridden then we look for the default */
+  default_value = property_get_default_for_type (property, G_TYPE_INVALID);
+
+  if (default_value == NULL)
     {
-      if (!g_value_transform (default_value, value))
-        {
-          g_critical (G_STRLOC ": Unable to copy the default value "
-                      "of property '%s' from type '%s' to type '%s'",
-                      G_PARAM_SPEC (property)->name,
-                      g_type_name (property->gtype),
-                      g_type_name (G_VALUE_TYPE (value)));
-        }
+      g_critical (G_STRLOC ": No default value of property '%s' "
+                  "was found for type '%s'",
+                  G_PARAM_SPEC (property)->name,
+                  g_type_name (gtype));
+
+      return FALSE;
     }
+
+out:
+  if (!g_value_transform (default_value, value))
+    {
+      g_critical (G_STRLOC ": Unable to transform a value of type '%s' "
+                  "into a value of type '%s'",
+                  g_type_name (G_VALUE_TYPE (default_value)),
+                  g_type_name (G_VALUE_TYPE (value)));
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
 /**
@@ -3665,37 +3944,40 @@ g_property_get_default_value_for_type (GProperty *property,
  * This function should only be used by language bindings and other
  * introspection tools.
  *
+ * Return value: %TRUE if a default value was found, and %FALSE
+ *   otherwise
+ *
  * Since: 2.32
  */
-void
+gboolean
 g_property_get_default_value (GProperty *property,
                               gpointer   gobject,
                               GValue    *value)
 {
-  g_return_if_fail (G_IS_OBJECT (gobject));
+  g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
 
-  g_property_get_default_value_for_type (property,
-                                         G_OBJECT_TYPE (gobject),
-                                         value);
+  return g_property_get_default_value_for_type (property,
+                                                G_OBJECT_TYPE (gobject),
+                                                value);
 }
 
 /**
  * g_property_set_default:
  * @property: a #GProperty
- * @gobject_class: a pointer to a #GObject class
  * @...: the default value for the property
  *
- * Sets the default value of @property for the given @gobject_class.
+ * Sets the default value of @property.
  *
- * This function can only be called once for each @gobject_class.
+ * This function can only be called once for each property; derived
+ * types should call g_property_override_default() instead.
  *
- * See also g_object_class_override_property_default().
+ * See also g_property_override_default() and
+ * g_object_class_override_property_default().
  *
  * Since: 2.32
  */
 void
 g_property_set_default (GProperty *property,
-                        gpointer   gobject_class,
                         ...)
 {
   GValue value = { 0, };
@@ -3704,15 +3986,11 @@ g_property_set_default (GProperty *property,
   va_list var_args;
 
   g_return_if_fail (G_IS_PROPERTY (property));
-  g_return_if_fail (G_IS_OBJECT_CLASS (gobject_class));
-  g_return_if_fail (property->gtype != G_TYPE_INVALID);
+  g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
 
-  if (property->prerequisite != G_TYPE_INVALID)
-    p_type = property->prerequisite;
-  else
-    p_type = property->gtype;
+  p_type = G_PARAM_SPEC (property)->value_type;
 
-  va_start (var_args, gobject_class);
+  va_start (var_args, property);
 
   G_VALUE_COLLECT_INIT (&value, p_type, var_args, 0, &error);
   if (error != NULL)
@@ -3721,10 +3999,11 @@ g_property_set_default (GProperty *property,
       g_free (error);
     }
   else
-    g_property_set_default_value (property, gobject_class, &value);
+    g_property_set_default_value (property, &value);
 
-  va_end (var_args);
   g_value_unset (&value);
+
+  va_end (var_args);
 }
 
 /**
@@ -3751,22 +4030,13 @@ g_property_get_default (GProperty *property,
 
   g_return_if_fail (G_IS_PROPERTY (property));
   g_return_if_fail (G_IS_OBJECT (gobject));
-  g_return_if_fail (property->gtype != G_TYPE_INVALID);
-
-  gtype = G_OBJECT_TYPE (gobject);
+  g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
 
-  if (property->prerequisite != G_TYPE_INVALID)
-    p_type = property->prerequisite;
-  else
-    p_type = property->gtype;
+  p_type = G_PARAM_SPEC (property)->value_type;
 
   g_value_init (&value, p_type);
 
-  if (property->default_value != NULL)
-    {
-      g_value_copy (property->default_value, &value);
-      goto lcopy;
-    }
+  gtype = G_OBJECT_TYPE (gobject);
 
   /* we need to recurse through the inheritance chain... */
   while (gtype != G_TYPE_INVALID && default_value == NULL)
@@ -3775,6 +4045,9 @@ g_property_get_default (GProperty *property,
       gtype = g_type_parent (gtype);
     }
 
+  if (default_value != NULL)
+    goto lcopy;
+
   /* ... and eventually check the implemented interfaces */
   if (default_value == NULL)
     {
@@ -3785,11 +4058,21 @@ g_property_get_default (GProperty *property,
 
       ifaces = g_type_interfaces (gtype, &n_ifaces);
       while (n_ifaces-- && default_value == NULL)
-        default_value = property_get_default_for_type (property, ifaces[n_ifaces]);
+        {
+          gtype = ifaces[n_ifaces];
+          default_value = property_get_default_for_type (property, gtype);
+        }
 
       g_free (ifaces);
     }
 
+  if (default_value != NULL)
+    goto lcopy;
+
+  /* if the property hasn't been overridden then we look for the default */
+  default_value = property_get_default_for_type (property, G_TYPE_INVALID);
+
+lcopy:
   if (default_value == NULL)
     {
       g_critical (G_STRLOC ": No default value of property '%s' "
@@ -3800,7 +4083,6 @@ g_property_get_default (GProperty *property,
   else
     g_value_copy (default_value, &value);
 
-lcopy:
   va_start (var_args, gobject);
 
   G_VALUE_LCOPY (&value, var_args, 0, &error);
@@ -3815,6 +4097,47 @@ lcopy:
 }
 
 /**
+ * g_property_override_default:
+ * @property: a #GProperty
+ * @class_gtype: the type of the class overriding the default
+ * @...: the new default value for the property
+ *
+ * Overrides the default value of @property for the given class type.
+ *
+ * Since: 2.32
+ */
+void
+g_property_override_default (GProperty *property,
+                             GType      class_gtype,
+                             ...)
+{
+  GValue value = { 0, };
+  GType p_type;
+  gchar *error;
+  va_list var_args;
+
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
+  g_return_if_fail (g_type_name (class_gtype) != 0);
+
+  p_type = G_PARAM_SPEC (property)->value_type;
+
+  va_start (var_args, class_gtype);
+
+  G_VALUE_COLLECT_INIT (&value, p_type, var_args, 0, &error);
+  if (error != NULL)
+    {
+      g_critical (G_STRLOC ": %s", error);
+      g_free (error);
+    }
+  else
+    g_property_override_default_value (property, class_gtype, &value);
+
+  va_end (var_args);
+  g_value_unset (&value);
+}
+
+/**
  * g_property_set_valist:
  * @property: a #GProperty
  * @gobject: a #GObject instance
@@ -3840,10 +4163,7 @@ g_property_set_valist (GProperty *property,
   g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
   g_return_val_if_fail (property->is_installed, FALSE);
 
-  if (property->prerequisite != G_TYPE_INVALID)
-    gtype = property->prerequisite;
-  else
-    gtype = property->gtype;
+  gtype = G_PARAM_SPEC (property)->value_type;
 
   switch (G_TYPE_FUNDAMENTAL (gtype))
     {
@@ -3937,6 +4257,10 @@ g_property_set_valist (GProperty *property,
       retval = g_object_property_set_value (property, gobject, va_arg (args, gpointer));
       break;
 
+    case G_TYPE_POINTER:
+      retval = g_pointer_property_set_value (property, gobject, va_arg (args, gpointer));
+      break;
+
     default:
       g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype));
       retval = FALSE;
@@ -3973,10 +4297,7 @@ g_property_get_valist (GProperty *property,
   g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
   g_return_val_if_fail (property->is_installed, FALSE);
 
-  if (property->prerequisite != G_TYPE_INVALID)
-    gtype = property->prerequisite;
-  else
-    gtype = property->gtype;
+  gtype = G_PARAM_SPEC (property)->value_type;
 
   ret_p = va_arg (args, gpointer);
 
@@ -4072,8 +4393,12 @@ g_property_get_valist (GProperty *property,
       (* (gpointer *) ret_p) = g_object_property_get_value (property, gobject);
       break;
 
+    case G_TYPE_POINTER:
+      (* (gpointer *) ret_p) = g_pointer_property_get_value (property, gobject);
+      break;
+
     default:
-      g_critical (G_STRLOC ": Invalid type %s", g_type_name (property->gtype));
+      g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype));
       break;
     }
 
@@ -4146,10 +4471,7 @@ g_property_collect (GProperty *property,
   g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
   g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
 
-  if (property->prerequisite != G_TYPE_INVALID)
-    gtype = property->prerequisite;
-  else
-    gtype = property->gtype;
+  gtype = G_PARAM_SPEC (property)->value_type;
 
   for (i = 0; i < n_cvalues; i++)
     {
@@ -4239,6 +4561,10 @@ g_property_collect (GProperty *property,
           retval = g_object_property_set_value (property, gobject, _cvalue->v_pointer);
           break;
 
+        case G_TYPE_POINTER:
+          retval = g_pointer_property_set_value (property, gobject, _cvalue->v_pointer);
+          break;
+
         default:
           g_critical (G_STRLOC ": Invalid value for type '%s'", g_type_name (gtype));
           retval = FALSE;
@@ -4282,10 +4608,7 @@ g_property_lcopy (GProperty *property,
   g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
   g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
 
-  if (property->prerequisite != G_TYPE_INVALID)
-    gtype = property->prerequisite;
-  else
-    gtype = property->gtype;
+  gtype = G_PARAM_SPEC (property)->value_type;
 
   for (i = 0; i < n_cvalues; i++)
     {
@@ -4518,6 +4841,17 @@ g_property_lcopy (GProperty *property,
             }
           break;
 
+        case G_TYPE_POINTER:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for gpointer passed as NULL");
+              return FALSE;
+            }
+
+          (* (gpointer *) _cvalue->v_pointer) =
+            g_pointer_property_get_value (property, gobject);
+          break;
+
         default:
           g_critical (G_STRLOC ": Invalid value location for type '%s'",
                       g_type_name (gtype));
@@ -4584,10 +4918,7 @@ g_property_set_value (GProperty    *property,
   g_return_if_fail (value != NULL);
   g_return_if_fail (property->is_installed);
 
-  if (property->prerequisite != G_TYPE_INVALID)
-    gtype = property->prerequisite;
-  else
-    gtype = property->gtype;
+  gtype = G_PARAM_SPEC (property)->value_type;
 
   g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (value), gtype));
 
@@ -4701,6 +5032,10 @@ g_property_set_value (GProperty    *property,
       g_object_property_set_value (property, gobject, g_value_get_object (&copy));
       break;
 
+    case G_TYPE_POINTER:
+      g_pointer_property_set_value (property, gobject, g_value_get_pointer (&copy));
+      break;
+
     default:
       g_critical (G_STRLOC ": Invalid type %s", g_type_name (G_VALUE_TYPE (&copy)));
       break;
@@ -4735,10 +5070,7 @@ g_property_get_value (GProperty *property,
   g_return_if_fail (value != NULL);
   g_return_if_fail (property->is_installed);
 
-  if (property->prerequisite != G_TYPE_INVALID)
-    gtype = property->prerequisite;
-  else
-    gtype = property->gtype;
+  gtype = G_PARAM_SPEC (property)->value_type;
 
   g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (value), gtype));
 
@@ -4856,6 +5188,10 @@ g_property_get_value (GProperty *property,
       g_value_set_object (&copy, g_object_property_get_value (property, gobject));
       break;
 
+    case G_TYPE_POINTER:
+      g_value_set_pointer (&copy, g_pointer_property_get_value (property, gobject));
+      break;
+
     default:
       g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype));
       break;
@@ -4889,10 +5225,7 @@ g_property_get_value_type (GProperty *property)
 {
   g_return_val_if_fail (G_IS_PROPERTY (property), G_TYPE_INVALID);
 
-  if (property->prerequisite != G_TYPE_INVALID)
-    return property->prerequisite;
-
-  return property->gtype;
+  return G_PARAM_SPEC (property)->value_type;
 }
 
 /**
@@ -4919,10 +5252,7 @@ g_property_validate (GProperty *property,
 
   va_start (args, property);
 
-  if (property->prerequisite != G_TYPE_INVALID)
-    gtype = property->prerequisite;
-  else
-    gtype = property->gtype;
+  gtype = G_PARAM_SPEC (property)->value_type;
 
   switch (G_TYPE_FUNDAMENTAL (gtype))
     {
@@ -4933,15 +5263,15 @@ g_property_validate (GProperty *property,
     case G_TYPE_INT:
       switch (property->type_size)
         {
-        case 8:
+        case 1:
           retval = g_int8_property_validate (property, va_arg (args, gint));
           break;
 
-        case 16:
+        case 2:
           retval = g_int16_property_validate (property, va_arg (args, gint));
           break;
 
-        case 32:
+        case 4:
           retval = g_int32_property_validate (property, va_arg (args, gint));
           break;
 
@@ -4962,15 +5292,15 @@ g_property_validate (GProperty *property,
     case G_TYPE_UINT:
       switch (property->type_size)
         {
-        case 8:
+        case 1:
           retval = g_uint8_property_validate (property, va_arg (args, guint));
           break;
 
-        case 16:
+        case 2:
           retval = g_uint16_property_validate (property, va_arg (args, guint));
           break;
 
-        case 32:
+        case 4:
           retval = g_uint32_property_validate (property, va_arg (args, guint));
           break;
 
@@ -5050,10 +5380,7 @@ g_property_validate_value (GProperty *property,
   g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
   g_return_val_if_fail (value != NULL, FALSE);
 
-  if (property->prerequisite != G_TYPE_INVALID)
-    gtype = property->prerequisite;
-  else
-    gtype = property->gtype;
+  gtype = G_PARAM_SPEC (property)->value_type;
 
   g_return_val_if_fail (g_value_type_transformable (gtype, G_VALUE_TYPE (value)), FALSE);
 
@@ -5081,15 +5408,15 @@ g_property_validate_value (GProperty *property,
 
         switch (property->type_size)
           {
-          case 8:
+          case 1:
             retval = g_int8_property_validate (property, val);
             break;
 
-          case 16:
+          case 2:
             retval = g_int16_property_validate (property, val);
             break;
 
-          case 32:
+          case 4:
             retval = g_int32_property_validate (property, val);
             break;
 
@@ -5114,15 +5441,15 @@ g_property_validate_value (GProperty *property,
 
         switch (property->type_size)
           {
-          case 8:
+          case 1:
             retval = g_uint8_property_validate (property, val);
             break;
 
-          case 16:
+          case 2:
             retval = g_uint16_property_validate (property, val);
             break;
 
-          case 32:
+          case 4:
             retval = g_uint32_property_validate (property, val);
             break;
 
@@ -5324,15 +5651,8 @@ g_property_set_lock_functions (GProperty           *property,
 static void
 property_finalize (GParamSpec *pspec)
 {
-  GProperty *property = G_PROPERTY (pspec);
   GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (G_TYPE_PROPERTY));
 
-  if (property->default_value != NULL)
-    {
-      g_value_unset (property->default_value);
-      g_free (property->default_value);
-    }
-
   parent_class->finalize (pspec);
 }
 
@@ -5353,17 +5673,11 @@ property_validate (GParamSpec *pspec,
                    GValue     *value)
 {
   GProperty *property = G_PROPERTY (pspec);
-  GType gtype;
-
-  if (property->prerequisite != G_TYPE_INVALID)
-    gtype = property->prerequisite;
-  else
-    gtype = property->gtype;
 
-  if (!g_value_type_transformable (G_VALUE_TYPE (value), gtype))
-    return FALSE;
+  if (!g_value_type_transformable (G_VALUE_TYPE (value), pspec->value_type))
+    return TRUE;
 
-  return g_property_validate_value (G_PROPERTY (pspec), value);
+  return !g_property_validate_value (property, value);
 }
 
 static gint
@@ -5391,8 +5705,7 @@ property_init (GParamSpec *pspec)
 {
   GProperty *property = G_PROPERTY (pspec);
 
-  property->gtype = G_TYPE_INVALID;
-  property->prerequisite = G_TYPE_INVALID;
+  pspec->value_type = G_TYPE_INVALID;
 
   property->field_offset = -1;
   property->priv_offset = -1;
diff --git a/gobject/gproperty.h b/gobject/gproperty.h
index 2e95322..41427f7 100644
--- a/gobject/gproperty.h
+++ b/gobject/gproperty.h
@@ -102,17 +102,21 @@ gboolean        g_property_get_range                    (GProperty    *property,
                                                          ...);
 
 void            g_property_set_default_value            (GProperty    *property,
-                                                         gpointer      gobject_class,
                                                          const GValue *value);
-void            g_property_get_default_value_for_type   (GProperty    *property,
+void            g_property_set_default                  (GProperty    *property,
+                                                         ...);
+void            g_property_override_default_value       (GProperty    *property,
+                                                         GType         class_gtype,
+                                                         const GValue *value);
+void            g_property_override_default             (GProperty    *property,
+                                                         GType         class_gtype,
+                                                         ...);
+gboolean        g_property_get_default_value_for_type   (GProperty    *property,
                                                          GType         gtype,
                                                          GValue       *value);
-void            g_property_get_default_value            (GProperty    *property,
+gboolean        g_property_get_default_value            (GProperty    *property,
                                                          gpointer      gobject,
                                                          GValue       *value);
-void            g_property_set_default                  (GProperty    *property,
-                                                         gpointer      gobject_class,
-                                                         ...);
 void            g_property_get_default                  (GProperty    *property,
                                                          gpointer      gobject,
                                                          ...);
diff --git a/gobject/tests/autoproperties.c b/gobject/tests/autoproperties.c
index 2106c52..62f7a8a 100644
--- a/gobject/tests/autoproperties.c
+++ b/gobject/tests/autoproperties.c
@@ -37,6 +37,8 @@ struct _TestObjectClass
 
 struct _TestObjectPrivate
 {
+  gint dummy;
+
   gint foo;
 
   gboolean bar;
@@ -168,7 +170,7 @@ static GParamSpec *test_object_properties[LAST_PROP] = { NULL, };
 
 G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
 
-G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, gint, foo)
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, int, foo)
 G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, gboolean, bar)
 G_DEFINE_PROPERTY_GET (TestObject, test_object, gboolean, str_set)
 G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, gint8, single_byte)
@@ -217,7 +219,7 @@ test_object_class_init (TestObjectClass *klass)
                         G_STRUCT_OFFSET (TestObjectPrivate, foo),
                         NULL, NULL);
   g_property_set_range (G_PROPERTY (test_object_properties[PROP_FOO]), -1, 100);
-  g_property_set_default (G_PROPERTY (test_object_properties[PROP_FOO]), klass, 50);
+  g_property_set_default (G_PROPERTY (test_object_properties[PROP_FOO]), 50);
 
   test_object_properties[PROP_BAR] =
     g_boolean_property_new ("bar", G_PROPERTY_READWRITE | G_PROPERTY_ATOMIC,
@@ -266,7 +268,7 @@ test_object_class_init (TestObjectClass *klass)
                            G_STRUCT_OFFSET (TestObjectPrivate, x_align),
                            NULL, NULL);
   g_property_set_range (G_PROPERTY (test_object_properties[PROP_X_ALIGN]), 0.0, 1.0);
-  g_property_set_default (G_PROPERTY (test_object_properties[PROP_X_ALIGN]), klass, 0.5);
+  g_property_set_default (G_PROPERTY (test_object_properties[PROP_X_ALIGN]), 0.5);
 
   test_object_properties[PROP_ENUM_VALUE] =
     g_enum_property_new ("enum-value", G_PROPERTY_READWRITE,
@@ -275,7 +277,6 @@ test_object_class_init (TestObjectClass *klass)
   g_property_set_prerequisite (G_PROPERTY (test_object_properties[PROP_ENUM_VALUE]),
                                test_enum_value_get_type ());
   g_property_set_default (G_PROPERTY (test_object_properties[PROP_ENUM_VALUE]),
-                          klass,
                           TEST_ENUM_VALUE_BAR);
 
   test_object_properties[PROP_FLAGS_VALUE] =
@@ -285,7 +286,6 @@ test_object_class_init (TestObjectClass *klass)
   g_property_set_prerequisite (G_PROPERTY (test_object_properties[PROP_FLAGS_VALUE]),
                                test_flags_value_get_type ());
   g_property_set_default (G_PROPERTY (test_object_properties[PROP_FLAGS_VALUE]),
-                          klass,
                           TEST_FLAGS_VALUE_FOO);
 
   test_object_properties[PROP_BOXED] =
@@ -330,6 +330,53 @@ autoproperties_base (void)
 }
 
 static void
+autoproperties_constructor (void)
+{
+  TestObject *t = g_object_new (test_object_get_type (),
+                                "str", "Hello, World!",
+                                "x-align", 1.0,
+                                NULL);
+
+  g_assert (G_TYPE_CHECK_INSTANCE_TYPE (t, test_object_get_type ()));
+  g_assert_cmpstr (test_object_get_str (t), ==, "Hello, World!");
+  g_assert_cmpfloat (test_object_get_x_align (t), ==, 1.0);
+
+  g_object_unref (t);
+}
+
+typedef TestObject      TestDerived;
+typedef TestObjectClass TestDerivedClass;
+
+G_DEFINE_TYPE (TestDerived, test_derived, test_object_get_type ())
+
+static void
+test_derived_class_init (TestDerivedClass *klass)
+{
+  g_object_class_override_property_default (G_OBJECT_CLASS (klass), "foo", -1);
+  g_object_class_override_property_default (G_OBJECT_CLASS (klass), "enum-value", TEST_ENUM_VALUE_BAZ);
+}
+
+static void
+test_derived_init (TestDerived *self)
+{
+  GValue value = { 0, };
+
+  g_value_init (&value, g_property_get_value_type (G_PROPERTY (test_object_properties[PROP_FOO])));
+  g_property_get_default_value_for_type (G_PROPERTY (test_object_properties[PROP_FOO]),
+                                         test_derived_get_type (),
+                                         &value);
+
+  g_assert_cmpint (g_value_get_int (&value), !=, 50);
+  g_assert_cmpint (g_value_get_int (&value), ==, -1);
+
+  test_object_set_foo ((TestObject *) self, g_value_get_int (&value));
+
+  g_value_unset (&value);
+
+  test_object_set_enum_value ((TestObject *) self, TEST_ENUM_VALUE_BAZ);
+}
+
+static void
 autoproperties_default (void)
 {
   TestObject *t = g_object_new (test_object_get_type (), NULL);
@@ -340,6 +387,13 @@ autoproperties_default (void)
   g_assert (test_object_get_flags_value (t) == TEST_FLAGS_VALUE_FOO);
 
   g_object_unref (t);
+
+  t = g_object_new (test_derived_get_type (), NULL);
+
+  g_assert_cmpint (test_object_get_foo (t), ==, -1);
+  g_assert (test_object_get_enum_value (t) == TEST_ENUM_VALUE_BAZ);
+
+  g_object_unref (t);
 }
 
 static void
@@ -410,7 +464,6 @@ autoproperties_validate (void)
       exit (0);
     }
   g_test_trap_assert_failed ();
-//  g_test_trap_assert_stderr ("**");
 
   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT|G_TEST_TRAP_SILENCE_STDERR))
     {
@@ -420,7 +473,6 @@ autoproperties_validate (void)
       exit (0);
     }
   g_test_trap_assert_failed ();
-//  g_test_trap_assert_stderr ("**");
 }
 
 static void
@@ -518,6 +570,7 @@ main (int argc, char *argv[])
   g_test_bug_base ("http://bugzilla.gnome.org/";);
 
   g_test_add_func ("/auto-properties/base", autoproperties_base);
+  g_test_add_func ("/auto-properties/constructor", autoproperties_constructor);
   g_test_add_func ("/auto-properties/default", autoproperties_default);
   g_test_add_func ("/auto-properties/range", autoproperties_range);
   g_test_add_func ("/auto-properties/accessors", autoproperties_accessors);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]