[glib/g-property] gobject: Add GProperty



commit 5294e1d9240bb7e5fea21e753fa9976d4b23841a
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Fri Apr 22 14:08:11 2011 +0100

    gobject: Add GProperty
    
    Dealing with GParamSpec is tedious and less efficient than necessary;
    property definitions should be able to either directly access a struct
    field or specify the accessors pair that control a property. On top of
    that, most of the property and accessor definition can be autogenerated
    from simple pre-processor directives.
    
    So, here's to you GProperty.
    
    GProperty is a GParamSpec sub-class that encapsulates all the types
    inside a single, opaque structure (to avoid leaking out implementation
    details); a GProperty can access the structure member holding the value
    of the property, or invoke the accessor functions passed to its
    constructor. Type safety is maintained through the GType system and
    without having to use GValue.
    
    Along with GProperty, this patch introduces a series of macros for
    automating the declaration and definition of property accessor functions,
    and for automating the collection and lcopy of values without going
    through GValue.
    
    GObject will recognize whether a GParamSpec used to set or get
    a property is really a GProperty, and thus will shortcircuit most of
    the GValue-based marshalled code, preferring the direct C function
    and direct argument collection instead of boxing/unboxing of GValues.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=648526

 glib/glib-object.h             |    1 +
 gobject/Makefile.am            |    2 +
 gobject/gobject.c              |  119 +-
 gobject/gproperty.c            | 3150 ++++++++++++++++++++++++++++++++++++++++
 gobject/gproperty.h            |  630 ++++++++
 gobject/gvaluecollector.h      |   97 ++
 gobject/tests/.gitignore       |    1 +
 gobject/tests/Makefile.am      |    6 +-
 gobject/tests/autoproperties.c |  353 +++++
 9 files changed, 4320 insertions(+), 39 deletions(-)
---
diff --git a/glib/glib-object.h b/glib/glib-object.h
index 10cff1b..318ace9 100644
--- a/glib/glib-object.h
+++ b/glib/glib-object.h
@@ -28,6 +28,7 @@
 #include	<gobject/gobject.h>
 #include	<gobject/gparam.h>
 #include	<gobject/gparamspecs.h>
+#include        <gobject/gproperty.h>
 #include	<gobject/gsignal.h>
 #include	<gobject/gsourceclosure.h>
 #include	<gobject/gtype.h>
diff --git a/gobject/Makefile.am b/gobject/Makefile.am
index c013a2f..ce587ea 100644
--- a/gobject/Makefile.am
+++ b/gobject/Makefile.am
@@ -98,6 +98,7 @@ gobject_public_h_sources = \
 	gobject.h		\
 	gparam.h		\
 	gparamspecs.h		\
+	gproperty.h		\
 	gsignal.h		\
 	gsourceclosure.h	\
 	gtype.h			\
@@ -127,6 +128,7 @@ gobject_c_sources = \
 	gobject_trace.h		\
 	gparam.c		\
 	gparamspecs.c		\
+	gproperty.c		\
 	gsignal.c		\
 	gsourceclosure.c	\
 	gtype.c			\
diff --git a/gobject/gobject.c b/gobject/gobject.c
index ead9071..6e6ef46 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -407,6 +407,9 @@ install_property_internal (GType       g_type,
   g_param_spec_sink (pspec);
   PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
   g_param_spec_pool_insert (pspec_pool, pspec, g_type);
+
+  if (G_IS_PROPERTY (pspec))
+    _g_property_set_installed (G_PROPERTY (pspec), g_type);
 }
 
 /**
@@ -435,9 +438,9 @@ g_object_class_install_property (GObjectClass *class,
 
   class->flags |= CLASS_HAS_PROPS_FLAG;
 
-  if (pspec->flags & G_PARAM_WRITABLE)
+  if (pspec->flags & G_PARAM_WRITABLE && !G_IS_PROPERTY (pspec))
     g_return_if_fail (class->set_property != NULL);
-  if (pspec->flags & G_PARAM_READABLE)
+  if (pspec->flags & G_PARAM_READABLE && !G_IS_PROPERTY (pspec))
     g_return_if_fail (class->get_property != NULL);
   g_return_if_fail (property_id > 0);
   g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);	/* paranoid */
@@ -552,9 +555,9 @@ g_object_class_install_properties (GObjectClass  *oclass,
 
       g_return_if_fail (pspec != NULL);
 
-      if (pspec->flags & G_PARAM_WRITABLE)
+      if (!G_IS_PROPERTY (pspec) && pspec->flags & G_PARAM_WRITABLE)
         g_return_if_fail (oclass->set_property != NULL);
-      if (pspec->flags & G_PARAM_READABLE)
+      if (!G_IS_PROPERTY (pspec) && pspec->flags & G_PARAM_READABLE)
         g_return_if_fail (oclass->get_property != NULL);
       g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);	/* paranoid */
       if (pspec->flags & G_PARAM_CONSTRUCT)
@@ -1134,8 +1137,15 @@ object_get_property (GObject     *object,
   redirect = g_param_spec_get_redirect_target (pspec);
   if (redirect)
     pspec = redirect;    
-  
-  class->get_property (object, param_id, value, pspec);
+
+  if (G_IS_PROPERTY (pspec))
+    {
+      GProperty *prop = G_PROPERTY (pspec);
+
+      g_property_get_value (prop, object, value);
+    }
+  else
+    class->get_property (object, param_id, value, pspec);
 }
 
 static inline void
@@ -1196,7 +1206,15 @@ object_set_property (GObject             *object,
     }
   else
     {
-      class->set_property (object, param_id, &tmp_value, pspec);
+      if (G_IS_PROPERTY (pspec))
+        {
+          GProperty *prop = G_PROPERTY (pspec);
+
+          g_property_set_value (prop, object, value);
+        }
+      else
+        class->set_property (object, param_id, &tmp_value, pspec);
+
       g_object_notify_queue_add (object, nqueue, pspec);
     }
   g_value_unset (&tmp_value);
@@ -1683,9 +1701,7 @@ g_object_set_valist (GObject	 *object,
   name = first_property_name;
   while (name)
     {
-      GValue value = { 0, };
       GParamSpec *pspec;
-      gchar *error = NULL;
       
       pspec = g_param_spec_pool_lookup (pspec_pool,
 					name,
@@ -1714,19 +1730,33 @@ g_object_set_valist (GObject	 *object,
           break;
         }
 
-      G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args,
-			    0, &error);
-      if (error)
-	{
-	  g_warning ("%s: %s", G_STRFUNC, error);
-	  g_free (error);
+      if (G_IS_PROPERTY (pspec))
+        {
+          GProperty *property = (GProperty *) pspec;
+          gboolean res = FALSE;
+
+          G_PROPERTY_COLLECT (property, object, var_args, &res);
+          if (!res)
+            break;
+        }
+      else
+        {
+          GValue value = { 0, };
+          gchar *error = NULL;
+
+          G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args, 0, &error);
+          if (error != NULL)
+            {
+	      g_warning ("%s: %s", G_STRFUNC, error);
+	      g_free (error);
+              g_value_unset (&value);
+	      break;
+	    }
+
+          object_set_property (object, pspec, &value, nqueue);
           g_value_unset (&value);
-	  break;
-	}
-      
-      object_set_property (object, pspec, &value, nqueue);
-      g_value_unset (&value);
-      
+        }
+
       name = va_arg (var_args, gchar*);
     }
 
@@ -1764,9 +1794,7 @@ g_object_get_valist (GObject	 *object,
   
   while (name)
     {
-      GValue value = { 0, };
       GParamSpec *pspec;
-      gchar *error;
       
       pspec = g_param_spec_pool_lookup (pspec_pool,
 					name,
@@ -1788,21 +1816,36 @@ g_object_get_valist (GObject	 *object,
 		     G_OBJECT_TYPE_NAME (object));
 	  break;
 	}
-      
-      g_value_init (&value, pspec->value_type);
-      
-      object_get_property (object, pspec, &value);
-      
-      G_VALUE_LCOPY (&value, var_args, 0, &error);
-      if (error)
-	{
-	  g_warning ("%s: %s", G_STRFUNC, error);
-	  g_free (error);
-	  g_value_unset (&value);
-	  break;
-	}
-      
-      g_value_unset (&value);
+
+      if (G_IS_PROPERTY (pspec))
+        {
+          GProperty *property = (GProperty *) pspec;
+          gboolean res = FALSE;
+
+          G_PROPERTY_LCOPY (property, object, var_args, &res);
+          if (!res)
+            break;
+        }
+      else
+        {
+          GValue value = { 0, };
+          gchar *error;
+
+          g_value_init (&value, pspec->value_type);
+
+          object_get_property (object, pspec, &value);
+
+          G_VALUE_LCOPY (&value, var_args, 0, &error);
+          if (error != NULL)
+            {
+              g_warning ("%s: %s", G_STRFUNC, error);
+              g_free (error);
+              g_value_unset (&value);
+              break;
+            }
+
+          g_value_unset (&value);
+        }
       
       name = va_arg (var_args, gchar*);
     }
diff --git a/gobject/gproperty.c b/gobject/gproperty.c
new file mode 100644
index 0000000..b91c05b
--- /dev/null
+++ b/gobject/gproperty.c
@@ -0,0 +1,3150 @@
+/* gproperty.c: Property definitions for GObject
+ *
+ * Copyright © 2011  Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Emmanuele Bassi <ebassi linux intel com>
+ */
+
+/**
+ * SECTION:gproperty
+ * @Title: GProperty
+ * @Short_Desc: Property definitions for GObject
+ *
+ * FIXME
+ */
+
+#if !defined (__GLIB_GOBJECT_H_INSIDE__) && !defined (GOBJECT_COMPILATION)
+#error "Only <glib-object.h> can be included directly."
+#endif
+#include "config.h"
+
+#include <string.h>
+
+#include "gproperty.h"
+
+#include <glib.h>
+
+#include "gvaluecollector.h"
+#include "gparam.h"
+#include "gtype.h"
+#include "gvalue.h"
+#include "gvaluetypes.h"
+
+struct _GProperty
+{
+  GParamSpec parent_instance;
+
+  GPropertyFlags flags;
+
+  GType gtype;
+  GType class_gtype;
+
+  gssize type_size;
+  gssize priv_offset;
+  gssize field_offset;
+
+  GHashTable *default_values;
+
+  GType prerequisite;
+
+  GPropertyLockFunc lock_func;
+  GPropertyUnlockFunc unlock_func;
+
+  guint is_installed : 1;
+};
+
+/* needed defines for types we don't have */
+#define g_value_get_int8        g_value_get_int
+#define g_value_get_int16       g_value_get_int
+#define g_value_get_int32       g_value_get_int
+
+#define g_value_get_uint8       g_value_get_uint
+#define g_value_get_uint16      g_value_get_uint
+#define g_value_get_uint32      g_value_get_uint
+
+#define DEFINE_PROPERTY_SIMPLE(G_t, g_t, c_t, G_T, defVal, minVal, maxVal) \
+typedef struct { \
+  GProperty parent; \
+\
+  c_t min_value; \
+  c_t max_value; \
+\
+  GProperty##G_t##Set setter; \
+  GProperty##G_t##Get getter; \
+} G##G_t##Property; \
+\
+static void \
+property_##g_t##_set_default (GParamSpec *pspec, \
+                              GValue     *value) \
+{ \
+  GProperty *property = G_PROPERTY (pspec); \
+\
+  if (property->is_installed) \
+    g_property_get_default_value (property, property->class_gtype, value); \
+} \
+\
+static gint \
+property_##g_t##_values_cmp (GParamSpec   *pspec, \
+                             const GValue *value_a, \
+                             const GValue *value_b) \
+{ \
+  c_t val_a = g_value_get_##g_t (value_a); \
+  c_t val_b = g_value_get_##g_t (value_b); \
+\
+  if (val_a < val_b) \
+    return -1; \
+\
+  if (val_a > val_b) \
+    return 1; \
+\
+  return 0; \
+} \
+\
+static gboolean \
+property_##g_t##_validate (GParamSpec *pspec, \
+                           GValue     *value) \
+{ \
+  G##G_t##Property *internal = (G##G_t##Property *) pspec; \
+  c_t oval = g_value_get_##g_t (value); \
+  c_t nval = oval; \
+\
+  nval = CLAMP (nval, internal->min_value, internal->max_value); \
+\
+  return nval != oval; \
+} \
+\
+static void \
+property_##g_t##_class_init (GParamSpecClass *klass) \
+{ \
+  klass->value_type = G_T; \
+\
+  klass->value_set_default = property_##g_t##_set_default; \
+  klass->value_validate = property_##g_t##_validate; \
+  klass->values_cmp = property_##g_t##_values_cmp; \
+} \
+\
+static void \
+property_##g_t##_init (GParamSpec *pspec) \
+{ \
+  G##G_t##Property *property = (G##G_t##Property *) pspec; \
+\
+  property->min_value = minVal; \
+  property->max_value = maxVal; \
+} \
+\
+GType \
+_g_##g_t##_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_##g_t##_class_init, \
+        NULL, NULL, \
+        sizeof (G##G_t##Property), \
+        0, \
+        (GInstanceInitFunc) property_##g_t##_init, \
+      }; \
+\
+      GType pspec_type_id = \
+        g_type_register_static (G_TYPE_PROPERTY, \
+                                g_intern_static_string ("G" #G_t "Property"), \
+                                &info, 0); \
+\
+      g_once_init_leave (&pspec_type_id__volatile, pspec_type_id); \
+    } \
+\
+  return pspec_type_id__volatile; \
+} \
+\
+GParamSpec * \
+g_##g_t##_property_new (const gchar         *name,      \
+                        GPropertyFlags       flags,     \
+                        gssize               offset,    \
+                        GProperty##G_t##Set  setter,    \
+                        GProperty##G_t##Get  getter)    \
+{ \
+  GProperty *prop; \
+  G##G_t##Property *internal; \
+\
+  g_return_val_if_fail (name != NULL, NULL); \
+\
+  if (setter == NULL && getter == NULL) \
+    g_return_val_if_fail (offset >= 0, NULL); \
+\
+  prop = g_param_spec_internal (_g_##g_t##_property_get_type (), \
+                                name, NULL, NULL, \
+                                property_flags_to_param_flags (flags)); \
+\
+  prop->flags = flags; \
+  prop->gtype = G_T; \
+  prop->prerequisite = G_TYPE_INVALID; \
+  prop->class_gtype = G_TYPE_INVALID; \
+\
+  prop->field_offset = offset; \
+\
+  prop->is_installed = FALSE; \
+\
+  prop->type_size = sizeof (c_t); \
+\
+  internal = (G##G_t##Property *) prop; \
+  internal->setter = setter; \
+  internal->getter = getter; \
+\
+  return G_PARAM_SPEC (prop); \
+} \
+\
+static void \
+g_##g_t##_property_set_range (GProperty *property, \
+                              c_t        min_value, \
+                              c_t        max_value) \
+{ \
+  ((G##G_t##Property *) property)->min_value = min_value; \
+  ((G##G_t##Property *) property)->max_value = max_value; \
+} \
+\
+static void \
+g_##g_t##_property_get_range (GProperty *property, \
+                              c_t       *min_value, \
+                              c_t       *max_value) \
+{ \
+  *min_value = ((G##G_t##Property *) property)->min_value; \
+  *max_value = ((G##G_t##Property *) property)->max_value; \
+} \
+\
+static gboolean \
+g_##g_t##_property_validate (GProperty *property, \
+                             c_t        value) \
+{ \
+  G##G_t##Property *internal = (G##G_t##Property *) property; \
+\
+  if (value >= internal->min_value && \
+      value <= internal->max_value) \
+    return TRUE; \
+\
+  return FALSE; \
+} \
+\
+static void \
+g_##g_t##_property_set_value (GProperty *property, \
+                              gpointer   gobject, \
+                              c_t        value) \
+{ \
+  g_return_if_fail (G_IS_PROPERTY (property)); \
+  g_return_if_fail (G_IS_OBJECT (gobject)); \
+  g_return_if_fail (g_##g_t##_property_validate (property, value)); \
+  g_return_if_fail (g_property_is_writable (property)); \
+\
+  g_property_lock (property, gobject); \
+\
+  if (((G##G_t##Property *) property)->setter != NULL) \
+    { \
+      ((G##G_t##Property *) property)->setter (gobject, value); \
+    } \
+  else if (property->field_offset >= 0) \
+    { \
+      gpointer priv_p, field_p; \
+\
+      priv_p = get_private_pointer (gobject, property->priv_offset); \
+      field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); \
+\
+      if ((* (c_t *) field_p) == value) \
+        { \
+          g_property_unlock (property, gobject); \
+          return; \
+        } \
+\
+      (* (c_t *) field_p) = value; \
+\
+      g_object_notify_by_pspec (gobject, (GParamSpec *) property); \
+    } \
+  else \
+    g_critical (G_STRLOC ": No setter function or field offset specified " \
+                "for property '%s'", \
+                G_PARAM_SPEC (property)->name); \
+\
+  g_property_unlock (property, gobject); \
+} \
+\
+static c_t \
+g_##g_t##_property_get_value (GProperty *property, \
+                              gpointer   gobject) \
+{ \
+  g_return_val_if_fail (G_IS_PROPERTY (property), defVal); \
+  g_return_val_if_fail (G_IS_OBJECT (gobject), defVal); \
+  g_return_val_if_fail (g_property_is_readable (property), defVal); \
+\
+  if (((G##G_t##Property *) property)->getter != NULL) \
+    { \
+      return ((G##G_t##Property *) property)->getter (gobject); \
+    } \
+  else if (property->field_offset >= 0) \
+    { \
+      gpointer priv_p, field_p; \
+\
+      priv_p = get_private_pointer (gobject, property->priv_offset); \
+      field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); \
+\
+      return (* (c_t *) field_p); \
+    } \
+  else \
+    { \
+      g_critical (G_STRLOC ": No setter function or field offset specified " \
+                  "for property '%s'", \
+                  G_PARAM_SPEC (property)->name); \
+      return defVal; \
+    } \
+}
+
+static gpointer
+get_private_pointer (gpointer instance,
+                     gssize   offset)
+{
+  gpointer priv_p;
+
+  if (offset < 0)
+    priv_p = g_type_instance_get_private (instance, G_OBJECT_TYPE (instance));
+  else
+    priv_p = (* (gpointer *) G_STRUCT_MEMBER_P (instance, offset));
+
+  return priv_p;
+}
+
+static GParamFlags
+property_flags_to_param_flags (GPropertyFlags flags)
+{
+  GParamFlags retval = 0;
+
+  if (flags & G_PROPERTY_READABLE)
+    retval |= G_PARAM_READABLE;
+
+  if (flags & G_PROPERTY_WRITABLE)
+    retval |= G_PARAM_WRITABLE;
+
+  if (flags & G_PROPERTY_DEPRECATED)
+    retval |= G_PARAM_DEPRECATED;
+
+  return retval;
+}
+
+/**
+ * g_boolean_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 a boolean value.
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+DEFINE_PROPERTY_SIMPLE (Boolean, boolean, gboolean, G_TYPE_BOOLEAN, FALSE, FALSE, TRUE)
+
+/**
+ * g_int_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to an integer value.
+ *
+ * The default range of valid values is [ %G_MININT, %G_MAXINT ].
+ *
+ * If you require a specific integer size, use g_int8_property_new(),
+ * g_int16_property_new(), g_int32_property_new() or g_int64_property_new().
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+DEFINE_PROPERTY_SIMPLE (Int, int, gint, G_TYPE_INT, 0, G_MININT, G_MAXINT)
+
+/**
+ * g_int8_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to an 8 bits integer value.
+ *
+ * The default range of valid values is [ %G_MININT8, %G_MAXINT8 ].
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+DEFINE_PROPERTY_SIMPLE (Int8, int8, gint8, G_TYPE_INT, 0, G_MININT8, G_MAXINT8)
+
+/**
+ * g_int16_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to a 16 bits integer value.
+ *
+ * The default range of valid values is [ %G_MININT16, %G_MAXINT16 ].
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+DEFINE_PROPERTY_SIMPLE (Int16, int16, gint16, G_TYPE_INT, 0, G_MININT16, G_MAXINT16)
+
+/**
+ * g_int32_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to a 32 bits integer value.
+ *
+ * The default range of valid values is [ %G_MININT32, %G_MAXINT32 ].
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+DEFINE_PROPERTY_SIMPLE (Int32, int32, gint32, G_TYPE_INT, 0, G_MININT32, G_MAXINT32)
+
+/**
+ * g_int64_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to a 64 bits integer value.
+ *
+ * The default range of valid values is [ %G_MININT64, %G_MAXINT64 ].
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+DEFINE_PROPERTY_SIMPLE (Int64, int64, gint64, G_TYPE_INT64, 0, G_MININT64, G_MAXINT64)
+
+/**
+ * g_long_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to a long integer value.
+ *
+ * The default range of valid values is [ %G_MINLONG, %G_MAXLONG ].
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+DEFINE_PROPERTY_SIMPLE (Long, long, glong, G_TYPE_LONG, 0, G_MINLONG, G_MAXLONG)
+
+/**
+ * g_uint_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to an unsigned integer value.
+ *
+ * The default range of valid values is [ 0, %G_MAXUINT ].
+ *
+ * If you require a specific integer size, use g_uint8_property_new(),
+ * g_uint16_property_new(), g_uint32_property_new() or g_uint64_property_new().
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+DEFINE_PROPERTY_SIMPLE (UInt, uint, guint, G_TYPE_UINT, 0, 0, G_MAXUINT)
+
+/**
+ * g_uint8_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to an unsigned 8 bits integer value.
+ *
+ * The default range of valid values is [ 0, %G_MAXUINT8 ].
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+DEFINE_PROPERTY_SIMPLE (UInt8, uint8, guint8, G_TYPE_UINT, 0, 0, G_MAXUINT8)
+
+/**
+ * g_uint16_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to an unsigned 16 bits integer value.
+ *
+ * The default range of valid values is [ 0, %G_MAXUINT16 ].
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+DEFINE_PROPERTY_SIMPLE (UInt16, uint16, guint16, G_TYPE_UINT, 0, 0, G_MAXUINT16)
+
+/**
+ * g_uint32_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to an unsigned 32 bits integer value.
+ *
+ * The default range of valid values is [ 0, %G_MAXUINT32 ].
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+DEFINE_PROPERTY_SIMPLE (UInt32, uint32, guint32, G_TYPE_UINT, 0, 0, G_MAXUINT32)
+
+/**
+ * g_uint64_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to an unsigned 64 bits integer value.
+ *
+ * The default range of valid values is [ 0, %G_MAXUINT64 ].
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+DEFINE_PROPERTY_SIMPLE (UInt64, uint64, guint64, G_TYPE_UINT64, 0, 0, G_MAXUINT64)
+
+/**
+ * g_ulong_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to an unsigned long integer value.
+ *
+ * The default range of valid values is [ 0, %G_MAXULONG ].
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+DEFINE_PROPERTY_SIMPLE (ULong, ulong, gulong, G_TYPE_ULONG, 0, 0, G_MAXULONG)
+
+/**
+ * g_enum_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to an enumeration value.
+ *
+ * The enumeration type can be specified using g_property_set_prerequisite().
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+/* FIXME: move to explicit code because of validation and lack of range */
+DEFINE_PROPERTY_SIMPLE (Enum, enum, glong, G_TYPE_ENUM, 0, G_MINLONG, G_MAXLONG)
+
+/**
+ * g_flags_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, or %NULL
+ * @getter: (allow-none): the getter function for the property, or %NULL
+ *
+ * Creates a new #GProperty mapping to a bitwise flag value.
+ *
+ * The flag type can be specified using g_property_set_prerequisite().
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+/* FIXME: move to explicit code because of validation and lack of range */
+DEFINE_PROPERTY_SIMPLE (Flags, flags, gulong, G_TYPE_ENUM, 0, 0, G_MAXULONG)
+
+/* FIXME: move to explicit code because of the epsilon in validate() */
+DEFINE_PROPERTY_SIMPLE (Float, float, gfloat, G_TYPE_FLOAT, 0.0, G_MINFLOAT, G_MAXFLOAT)
+
+/* FIXME: move to explicit code because of the epsilon in validate() */
+DEFINE_PROPERTY_SIMPLE (Double, double, gdouble, G_TYPE_DOUBLE, 0.0, G_MINDOUBLE, G_MAXDOUBLE)
+
+typedef struct {
+  GProperty parent;
+
+  GPropertyStringSet setter;
+  GPropertyStringGet getter;
+} GStringProperty;
+
+static void
+property_string_class_init (GParamSpecClass *klass)
+{
+  klass->value_type = G_TYPE_STRING;
+}
+
+static void
+property_string_init (GParamSpec *pspec)
+{
+}
+
+GType
+_g_string_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_string_class_init,
+        NULL, NULL,
+        sizeof (GStringProperty),
+        0,
+        (GInstanceInitFunc) property_string_init,
+      };
+
+      GType pspec_type_id =
+        g_type_register_static (G_TYPE_PROPERTY,
+                                g_intern_static_string ("GStringProperty"),
+                                &info, 0);
+
+      g_once_init_leave (&pspec_type_id__volatile, pspec_type_id);
+    }
+
+  return pspec_type_id__volatile;
+}
+
+/**
+ * g_string_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 a string value.
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+GParamSpec *
+g_string_property_new (const gchar        *name,
+                       GPropertyFlags      flags,
+                       gssize              offset,
+                       GPropertyStringSet  setter,
+                       GPropertyStringGet  getter)
+{
+  GProperty *prop;
+  GStringProperty *internal;
+
+  prop = g_param_spec_internal (_g_string_property_get_type (),
+                                name, NULL, NULL,
+                                property_flags_to_param_flags (flags));
+
+  prop->flags = flags;
+  prop->gtype = G_TYPE_STRING;
+  prop->prerequisite = G_TYPE_INVALID;
+  prop->class_gtype = G_TYPE_INVALID;
+
+  prop->field_offset = offset;
+
+  prop->is_installed = FALSE;
+
+  prop->type_size = sizeof (gchar*);
+
+  internal = (GStringProperty *) prop;
+  internal->setter = setter;
+  internal->getter = getter; 
+
+  return G_PARAM_SPEC (prop);
+}
+
+static gboolean
+g_string_property_validate (GProperty   *property,
+                            const gchar *value)
+{
+  return TRUE;
+}
+
+static void
+g_string_property_set_value (GProperty   *property,
+                             gpointer     gobject,
+                             const gchar *value)
+{
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (G_IS_OBJECT (gobject));
+  g_return_if_fail (g_string_property_validate (property, value));
+  g_return_if_fail (g_property_is_writable (property));
+
+  g_property_lock (property, gobject);
+
+  if (((GStringProperty *) property)->setter != NULL)
+    {
+      ((GStringProperty *) property)->setter (gobject, value);
+    }
+  else if (property->field_offset >= 0)
+    {
+      gpointer priv_p, field_p;
+      gchar *str;
+
+      priv_p = get_private_pointer (gobject, property->priv_offset);
+      field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
+
+      str = (* (gpointer *) field_p);
+
+      if (g_strcmp0 (str, value) == 0)
+        {
+          g_property_unlock (property, gobject);
+          return;
+        }
+
+      g_free (str);
+      (* (gpointer *) field_p) = g_strdup (value);
+
+      g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+    }
+  else
+    g_critical (G_STRLOC ": No setter function or field offset specified "
+                "for property '%s'",
+                G_PARAM_SPEC (property)->name);
+
+  g_property_unlock (property, gobject);
+}
+
+static const gchar *
+g_string_property_get_value (GProperty *property,
+                             gpointer   gobject)
+{
+  g_return_val_if_fail (G_IS_PROPERTY (property), NULL);
+  g_return_val_if_fail (G_IS_OBJECT (gobject), NULL);
+  g_return_val_if_fail (g_property_is_readable (property), NULL);
+
+  if (((GStringProperty *) property)->getter != NULL)
+    {
+      return ((GStringProperty *) property)->getter (gobject);
+    }
+  else if (property->field_offset >= 0)
+    {
+      gpointer priv_p, field_p;
+      gchar *retval;
+
+      priv_p = get_private_pointer (gobject, property->priv_offset);
+      field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
+
+      retval = (* (gpointer *) field_p);
+
+      return retval;
+    }
+  else
+    {
+      g_critical (G_STRLOC ": No getter function or field offset specified "
+                  "for property '%s'",
+                  G_PARAM_SPEC (property)->name);
+      return NULL;
+    }
+}
+
+typedef struct {
+  GProperty parent;
+
+  GPropertyBoxedSet setter;
+  GPropertyBoxedGet getter;
+} GBoxedProperty;
+
+static void
+property_boxed_class_init (GParamSpecClass *klass)
+{
+  klass->value_type = G_TYPE_BOXED;
+}
+
+static void
+property_boxed_init (GParamSpec *pspec)
+{
+}
+
+GType
+_g_boxed_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_boxed_class_init,
+        NULL, NULL,
+        sizeof (GBoxedProperty),
+        0,
+        (GInstanceInitFunc) property_boxed_init,
+      };
+
+      GType pspec_type_id =
+        g_type_register_static (G_TYPE_PROPERTY,
+                                g_intern_static_string ("GBoxedProperty"),
+                                &info, 0);
+
+      g_once_init_leave (&pspec_type_id__volatile, pspec_type_id);
+    }
+
+  return pspec_type_id__volatile;
+}
+
+/**
+ * g_boxed_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 a boxed value.
+ *
+ * You can use g_property_set_prerequisite() to specify the #GType
+ * of the boxed value.
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+GParamSpec *
+g_boxed_property_new (const gchar       *name,
+                      GPropertyFlags     flags,
+                      gssize             offset,
+                      GPropertyBoxedSet  setter,
+                      GPropertyBoxedGet  getter)
+{
+  GProperty *prop;
+  GBoxedProperty *internal;
+
+  prop = g_param_spec_internal (_g_boxed_property_get_type (),
+                                name, NULL, NULL,
+                                property_flags_to_param_flags (flags));
+
+  prop->flags = flags;
+  prop->gtype = G_TYPE_BOXED;
+  prop->prerequisite = G_TYPE_INVALID;
+  prop->class_gtype = G_TYPE_INVALID;
+
+  prop->field_offset = offset;
+
+  prop->is_installed = FALSE;
+
+  prop->type_size = sizeof (gpointer);
+
+  internal = (GBoxedProperty *) prop;
+  internal->setter = setter;
+  internal->getter = getter;
+
+  return G_PARAM_SPEC (prop);
+}
+
+static gboolean
+g_boxed_property_validate (GProperty     *property,
+                           gconstpointer  value)
+{
+  return TRUE;
+}
+
+static void
+g_boxed_property_set_value (GProperty     *property,
+                            gpointer       gobject,
+                            gconstpointer  value)
+{
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (G_IS_OBJECT (gobject));
+  g_return_if_fail (g_property_is_writable (property));
+
+  g_property_lock (property, gobject);
+
+  if (((GBoxedProperty *) property)->setter != NULL)
+    {
+      ((GBoxedProperty *) property)->setter (gobject, value);
+    }
+  if (property->field_offset >= 0)
+    {
+      gpointer priv_p, field_p;
+
+      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)
+        {
+          g_property_unlock (property, gobject);
+          return;
+        }
+
+      g_boxed_free (property->prerequisite, (* (gpointer *) field_p));
+      (* (gpointer *) field_p) = g_boxed_copy (property->prerequisite, value);
+
+      g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+    }
+  else
+    g_critical (G_STRLOC ": No setter function or field offset specified "
+                "for property '%s'",
+                G_PARAM_SPEC (property)->name);
+
+  g_property_unlock (property, gobject);
+}
+
+static gconstpointer
+g_boxed_property_get_value (GProperty *property,
+                            gpointer   gobject)
+{
+  g_return_val_if_fail (G_IS_PROPERTY (property), NULL);
+  g_return_val_if_fail (G_IS_OBJECT (gobject), NULL);
+  g_return_val_if_fail (g_property_is_readable (property), NULL);
+
+  if (((GBoxedProperty *) property)->getter != NULL)
+    {
+      return ((GBoxedProperty *) property)->getter (gobject);
+    }
+  if (property->field_offset >= 0)
+    {
+      gpointer priv_p, field_p;
+
+      priv_p = get_private_pointer (gobject, property->priv_offset);
+      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;
+    }
+}
+
+typedef struct {
+  GProperty parent;
+
+  GPropertyObjectSet setter;
+  GPropertyObjectGet getter;
+} GObjectProperty;
+
+static void
+property_object_class_init (GParamSpecClass *klass)
+{
+  klass->value_type = G_TYPE_OBJECT;
+}
+
+static void
+property_object_init (GParamSpec *pspec)
+{
+}
+
+GType
+_g_object_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_object_class_init,
+        NULL, NULL,
+        sizeof (GObjectProperty),
+        0,
+        (GInstanceInitFunc) property_object_init,
+      };
+
+      GType pspec_type_id =
+        g_type_register_static (G_TYPE_PROPERTY,
+                                g_intern_static_string ("GObjectProperty"),
+                                &info, 0);
+
+      g_once_init_leave (&pspec_type_id__volatile, pspec_type_id);
+    }
+
+  return pspec_type_id__volatile;
+}
+
+/**
+ * g_object_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 object value.
+ *
+ * You can use g_property_set_prerequisite() to specify the #GType
+ * of the object value.
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+GParamSpec *
+g_object_property_new (const gchar        *name,
+                       GPropertyFlags      flags,
+                       gssize              offset,
+                       GPropertyObjectSet  setter,
+                       GPropertyObjectGet  getter)
+{
+  GProperty *prop;
+  GObjectProperty *internal;
+
+  prop = g_param_spec_internal (_g_object_property_get_type (),
+                                name, NULL, NULL,
+                                property_flags_to_param_flags (flags));
+
+  prop->flags = flags;
+  prop->gtype = G_TYPE_OBJECT;
+  prop->prerequisite = G_TYPE_INVALID;
+  prop->class_gtype = G_TYPE_INVALID;
+
+  prop->field_offset = offset;
+
+  prop->is_installed = FALSE;
+
+  prop->type_size = sizeof (gpointer);
+
+  internal = (GObjectProperty *) prop;
+  internal->setter = setter;
+  internal->getter = getter;
+
+  return G_PARAM_SPEC (prop);
+}
+
+static gboolean
+g_object_property_validate (GProperty     *property,
+                            gconstpointer  value)
+{
+  return TRUE;
+}
+
+static void
+g_object_property_set_value (GProperty *property,
+                             gpointer   gobject,
+                             gpointer   value)
+{
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (G_IS_OBJECT (gobject));
+  g_return_if_fail (g_property_is_writable (property));
+  g_return_if_fail (value == NULL || G_IS_OBJECT (value));
+
+  g_property_lock (property, gobject);
+
+  if (((GObjectProperty *) property)->setter != NULL)
+    {
+      ((GObjectProperty *) property)->setter (gobject, value);
+    }
+  else if (property->field_offset >= 0)
+    {
+      gpointer priv_p, field_p;
+      gpointer obj;
+
+      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)
+        {
+          g_property_unlock (property, gobject);
+          return;
+        }
+
+      obj = (* (gpointer *) field_p);
+      if (obj != NULL)
+        g_object_unref (obj);
+
+      (* (gpointer *) field_p) = obj = value;
+
+      if (obj != NULL)
+        g_object_ref (obj);
+
+      g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+    }
+  else
+    g_critical (G_STRLOC ": No setter function or field offset specified "
+                "for property '%s'",
+                G_PARAM_SPEC (property)->name);
+
+  g_property_unlock (property, gobject);
+}
+
+static gpointer
+g_object_property_get_value (GProperty *property,
+                             gpointer   gobject)
+{
+  g_return_val_if_fail (G_IS_PROPERTY (property), NULL);
+  g_return_val_if_fail (G_IS_OBJECT (gobject), NULL);
+  g_return_val_if_fail (g_property_is_readable (property), NULL);
+
+  if (((GObjectProperty *) property)->getter != NULL)
+    {
+      return ((GObjectProperty *) 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;
+    }
+}
+
+/*< private >
+ * g_property_set_installed:
+ * @property: a #GProperty
+ * @class_gtype: the #GType of the class that installed @property
+ *
+ * Performs additional work once a type class has been associated to
+ * the property.
+ */
+void
+_g_property_set_installed (GProperty *property,
+                           GType      class_gtype)
+{
+  if (property->field_offset >= 0)
+    {
+      GTypeQuery query = { 0, };
+
+      g_type_query (class_gtype, &query);
+
+      /* XXX - this is pretty evil; it assumes that the instance structure
+       * contains a pointer to the private data structure as its last member
+       */
+
+      if (query.instance_size > sizeof (gpointer))
+        property->priv_offset = (gssize) query.instance_size - sizeof (gpointer);
+      else
+        property->priv_offset = -1;
+    }
+  else
+    property->priv_offset = -1;
+
+  property->class_gtype = class_gtype;
+  property->is_installed = TRUE;
+}
+
+static gboolean
+is_canonical (const gchar *key)
+{
+  const gchar *p;
+
+  for (p = key; *p != 0; p++)
+    {
+      gchar c = *p;
+
+      if (c != '-' &&
+          (c < '0' || c > '9') &&
+          (c < 'A' || c > 'Z') &&
+          (c < 'a' || c > 'z'))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+canonicalize_name (gchar *key)
+{
+  gchar *p;
+
+  for (p = key; *p != 0; p++)
+    {
+      gchar c = *p;
+
+      if (c != '-' &&
+          (c < '0' || c > '9') &&
+          (c < 'A' || c > 'Z') &&
+          (c < 'a' || c > 'z'))
+        *p = '-';
+    }
+}
+
+/**
+ * g_property_canonicalize:
+ * @name: a string
+ *
+ * Canonicalizes a string into a property name.
+ *
+ * Return value: (transfer full): a newly allocated string with
+ *   the canonical version of @name
+ *
+ * Since: 2.32
+ */
+gchar *
+g_property_canonicalize (const gchar *name)
+{
+  gchar *retval;
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  if (is_canonical (name))
+    return g_intern_string (name);
+
+  retval = g_strdup (name);
+  canonicalize_name (retval);
+  g_intern_string (retval);
+
+  return retval;
+}
+
+/**
+ * g_property_set_static_nick:
+ * @property: a #GProperty
+ * @nick: a static string with the user-readable name
+ *   of the property
+ *
+ * Sets the user-readable, and optionally translatable, name
+ * of the property.
+ *
+ * This function cannot be called more than once.
+ *
+ * Since: 2.32
+ */
+void
+g_property_set_static_nick (GProperty   *property,
+                            const gchar *nick)
+{
+  GParamSpec *pspec;
+
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (nick != NULL);
+
+  pspec = G_PARAM_SPEC (property);
+
+  if (pspec->_nick != NULL)
+    {
+      g_critical (G_STRLOC ": Redefining the nick of a property is not allowed");
+      return;
+    }
+
+  pspec->_nick = (gchar *) nick;
+  pspec->flags |= G_PARAM_STATIC_NICK;
+}
+
+/**
+ * g_property_set_static_blurb:
+ * @property: a #GProperty
+ * @blurb: a static string with the user-readable description
+ *   of the property
+ *
+ * Sets the user-readable, and optionally translatable, description
+ * of the property.
+ *
+ * This function cannot be called more than once.
+ *
+ * Since: 2.32
+ */
+void
+g_property_set_static_blurb (GProperty   *property,
+                             const gchar *blurb)
+{
+  GParamSpec *pspec;
+
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (blurb != NULL);
+
+  pspec = G_PARAM_SPEC (property);
+
+  if (pspec->_blurb != NULL)
+    {
+      g_critical (G_STRLOC ": Redefining the blurb of a property is not allowed");
+      return;
+    }
+
+  pspec->_blurb = (gchar *) blurb;
+  pspec->flags |= G_PARAM_STATIC_BLURB;
+}
+
+/**
+ * g_property_set_prerequisite:
+ * @property: a #GProperty
+ * @gtype: the prerequisite type
+ *
+ * Sets the prerequisite type for the @property.
+ *
+ * The prerequisite type must have the @property GType as a super-type,
+ * and will be used to make the type checking stricter.
+ *
+ * Since: 2.32
+ */
+void
+g_property_set_prerequisite (GProperty *property,
+                             GType      gtype)
+{
+  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));
+
+  switch (property->gtype)
+    {
+    case G_TYPE_BOXED:
+    case G_TYPE_OBJECT:
+    case G_TYPE_ENUM:
+    case G_TYPE_FLAGS:
+      property->prerequisite = gtype;
+      break;
+
+    default:
+      break;
+    }
+}
+
+void
+g_property_set_range_values (GProperty    *property,
+                             const GValue *min_value,
+                             const GValue *max_value)
+{
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (property->gtype != 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)
+    {
+    case G_TYPE_BOOLEAN:
+      g_boolean_property_set_range (property,
+                                    g_value_get_boolean (min_value),
+                                    g_value_get_boolean (max_value));
+      break;
+
+    case G_TYPE_INT:
+      {
+        gint min_v = g_value_get_int (min_value);
+        gint max_v = g_value_get_int (max_value);
+
+        switch (property->type_size)
+          {
+          case 1:
+            g_int8_property_set_range (property, min_v, max_v);
+            break;
+
+          case 2:
+            g_int16_property_set_range (property, min_v, max_v);
+            break;
+
+          case 4:
+            g_int32_property_set_range (property, min_v, max_v);
+            break;
+
+          default:
+            g_int_property_set_range (property, min_v, max_v);
+            break;
+          }
+      }
+      break;
+
+    case G_TYPE_INT64:
+      g_int64_property_set_range (property,
+                                  g_value_get_int64 (min_value),
+                                  g_value_get_int64 (max_value));
+      break;
+
+    case G_TYPE_LONG:
+      g_long_property_set_range (property,
+                                 g_value_get_long (min_value),
+                                 g_value_get_long (max_value));
+      break;
+
+    case G_TYPE_UINT:
+      {
+        guint min_v = g_value_get_uint (min_value);
+        guint max_v = g_value_get_uint (max_value);
+
+        switch (property->type_size)
+          {
+          case 1:
+            g_uint8_property_set_range (property, min_v, max_v);
+            break;
+
+          case 2:
+            g_uint16_property_set_range (property, min_v, max_v);
+            break;
+
+          case 4:
+            g_uint32_property_set_range (property, min_v, max_v);
+            break;
+
+          default:
+            g_uint_property_set_range (property, min_v, max_v);
+            break;
+          }
+      }
+      break;
+
+    case G_TYPE_UINT64:
+      g_uint64_property_set_range (property,
+                                   g_value_get_uint64 (min_value),
+                                   g_value_get_uint64 (max_value));
+      break;
+
+    case G_TYPE_ULONG:
+      g_ulong_property_set_range (property,
+                                  g_value_get_ulong (min_value),
+                                  g_value_get_ulong (max_value));
+      break;
+
+    case G_TYPE_FLOAT:
+      g_float_property_set_range (property,
+                                  g_value_get_float (min_value),
+                                  g_value_get_float (max_value));
+      break;
+
+    case G_TYPE_DOUBLE:
+      g_double_property_set_range (property,
+                                   g_value_get_double (min_value),
+                                   g_value_get_double (max_value));
+      break;
+
+    default:
+      break;
+    }
+}
+
+gboolean
+g_property_get_range_values (GProperty *property,
+                             GValue    *min_value,
+                             GValue    *max_value)
+{
+  gboolean retval;
+
+  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)
+    {
+    case G_TYPE_BOOLEAN:
+      {
+        gboolean min_v, max_v;
+
+        g_boolean_property_get_range (property, &min_v, &max_v);
+        g_value_set_boolean (min_value, min_v);
+        g_value_set_boolean (max_value, max_v);
+      }
+      retval = TRUE;
+      break;
+
+    case G_TYPE_INT:
+      {
+        gint min_v, max_v;
+
+        switch (property->type_size)
+          {
+          case 1:
+            g_int8_property_get_range (property, (gint8 *) &min_v, (gint8 *) &max_v);
+            break;
+
+          case 2:
+            g_int16_property_get_range (property, (gint16 *) &min_v, (gint16 *) &max_v);
+            break;
+
+          case 4:
+            g_int32_property_get_range (property, (gint32 *) &min_v, (gint32 *) &max_v);
+            break;
+
+          default:
+            g_int_property_get_range (property, &min_v, &max_v);
+            break;
+          }
+
+        g_value_set_int (min_value, min_v);
+        g_value_set_int (min_value, max_v);
+      }
+      retval = TRUE;
+      break;
+
+    case G_TYPE_INT64:
+      {
+        gint64 min_v, max_v;
+
+        g_int64_property_get_range (property, &min_v, &max_v);
+        g_value_set_int64 (min_value, min_v);
+        g_value_set_int64 (max_value, max_v);
+      }
+      retval = TRUE;
+      break;
+
+    case G_TYPE_LONG:
+      {
+        glong min_v, max_v;
+
+        g_long_property_get_range (property, &min_v, &max_v);
+        g_value_set_long (min_value, min_v);
+        g_value_set_long (max_value, max_v);
+      }
+      retval = TRUE;
+      break;
+
+    case G_TYPE_UINT:
+      {
+        guint min_v, max_v;
+
+        switch (property->type_size)
+          {
+          case 1:
+            g_uint8_property_get_range (property, (guint8 *) &min_v, (guint8 *) &max_v);
+            break;
+
+          case 2:
+            g_uint16_property_get_range (property, (guint16 *) &min_v, (guint16 *) &max_v);
+            break;
+
+          case 4:
+            g_uint32_property_get_range (property, (guint32 *) &min_v, (guint32 *) &max_v);
+            break;
+
+          default:
+            g_uint_property_get_range (property, &min_v, &max_v);
+            break;
+          }
+
+        g_value_set_uint (min_value, min_v);
+        g_value_set_uint (min_value, max_v);
+      }
+      retval = TRUE;
+      break;
+
+    case G_TYPE_UINT64:
+      {
+        guint64 min_v, max_v;
+
+        g_uint64_property_get_range (property, &min_v, &max_v);
+        g_value_set_uint64 (min_value, min_v);
+        g_value_set_uint64 (max_value, max_v);
+      }
+      retval = TRUE;
+      break;
+
+    case G_TYPE_ULONG:
+      {
+        gulong min_v, max_v;
+
+        g_ulong_property_get_range (property, &min_v, &max_v);
+        g_value_set_ulong (min_value, min_v);
+        g_value_set_ulong (max_value, max_v);
+      }
+      retval = TRUE;
+      break;
+
+    case G_TYPE_FLOAT:
+      {
+        gfloat min_v, max_v;
+
+        g_float_property_get_range (property, &min_v, &max_v);
+        g_value_set_float (min_value, min_v);
+        g_value_set_float (max_value, max_v);
+      }
+      retval = TRUE;
+      break;
+
+    case G_TYPE_DOUBLE:
+      {
+        gdouble min_v, max_v;
+
+        g_double_property_get_range (property, &min_v, &max_v);
+        g_value_set_double (min_value, min_v);
+        g_value_set_double (max_value, max_v);
+      }
+      retval = TRUE;
+      break;
+
+    default:
+      g_critical (G_STRLOC ": Invalid type '%s'", g_type_name (property->gtype));
+      retval = FALSE;
+      break;
+    }
+
+  return retval;
+}
+
+void
+g_property_set_default_value (GProperty    *property,
+                              GType         class_gtype,
+                              const GValue *default_value)
+{
+  const gchar *gtype_name;
+  GValue *value;
+  GType gtype;
+
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (property->gtype != G_TYPE_INVALID);
+  g_return_if_fail (default_value != NULL);
+
+  if (property->prerequisite != G_TYPE_INVALID)
+    gtype = property->prerequisite;
+  else
+    gtype = property->gtype;
+
+  if (G_VALUE_TYPE (default_value) != gtype)
+    g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (default_value), gtype));
+
+  if (property->default_values == NULL)
+    property->default_values = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                      g_free,
+                                                      g_free);
+
+  gtype_name = g_type_name (class_gtype);
+  if (g_hash_table_lookup (property->default_values, gtype_name) != NULL)
+    {
+      g_critical (G_STRLOC ": a default value of property '%s' for "
+                  "type '%s' has already been defined.",
+                  G_PARAM_SPEC (property)->name,
+                  gtype_name);
+      return;
+    }
+
+  value = g_new0 (GValue, 1);
+  g_value_init (value, gtype);
+  if (!g_value_transform (default_value, 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;
+    }
+
+  g_hash_table_insert (property->default_values,
+                       g_strdup (gtype_name),
+                       value);
+}
+
+void
+g_property_set_range (GProperty *property,
+                      ...)
+{
+  GValue min_value = { 0, };
+  GValue max_value = { 0, };
+  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);
+
+  va_start (var_args, property);
+
+  G_VALUE_COLLECT_INIT (&min_value, property->gtype, var_args, 0, &error);
+  if (error != NULL)
+    {
+      g_warning (G_STRLOC ": %s", error);
+      g_free (error);
+      va_end (var_args);
+      return;
+    }
+
+  G_VALUE_COLLECT_INIT (&max_value, property->gtype, var_args, 0, &error);
+  if (error != NULL)
+    {
+      g_warning (G_STRLOC ": %s", error);
+      g_free (error);
+      va_end (var_args);
+      return;
+    }
+
+  va_end (var_args);
+
+  g_property_set_range_values (property, &min_value, &max_value);
+
+  g_value_unset (&min_value);
+  g_value_unset (&max_value);
+}
+
+gboolean
+g_property_get_range (GProperty *property,
+                      ...)
+{
+  GValue min_value = { 0, };
+  GValue max_value = { 0, };
+  gchar *error;
+  va_list var_args;
+
+  g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+  g_return_val_if_fail (property->gtype != G_TYPE_INVALID, FALSE);
+
+  g_value_init (&min_value, property->gtype);
+  g_value_init (&max_value, property->gtype);
+
+  g_property_get_range_values (property, &min_value, &max_value);
+
+  va_start (var_args, property);
+
+  G_VALUE_LCOPY (&min_value, var_args, 0, &error);
+  if (error != NULL)
+    {
+      g_warning (G_STRLOC ": %s", error);
+      g_free (error);
+      goto out;
+    }
+
+  G_VALUE_LCOPY (&max_value, var_args, 0, &error);
+  if (error != NULL)
+    {
+      g_warning (G_STRLOC ": %s", error);
+      g_free (error);
+      goto out;
+    }
+
+out:
+  va_end (var_args);
+
+  g_value_unset (&min_value);
+  g_value_unset (&max_value);
+
+  return FALSE;
+}
+
+void
+g_property_get_default_value (GProperty *property,
+                              GType      class_gtype,
+                              GValue    *value)
+{
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (property->gtype != G_TYPE_INVALID);
+  g_return_if_fail (g_type_name (class_gtype) != 0);
+
+  if (property->default_values != NULL)
+    {
+      GValue *default_value;
+
+      default_value = g_hash_table_lookup (property->default_values,
+                                           g_type_name (class_gtype));
+
+      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)));
+            }
+        }
+    }
+}
+
+void
+g_property_set_default (GProperty *property,
+                        GType      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 (property->gtype != G_TYPE_INVALID);
+
+  if (property->prerequisite != G_TYPE_INVALID)
+    p_type = property->prerequisite;
+  else
+    p_type = property->gtype;
+
+  va_start (var_args, 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_set_default_value (property, gtype, &value);
+
+  va_end (var_args);
+  g_value_unset (&value);
+}
+
+void
+g_property_get_default (GProperty *property,
+                        GType      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 (property->gtype != G_TYPE_INVALID);
+  g_return_if_fail (g_type_name (gtype) != 0);
+
+  if (property->prerequisite != G_TYPE_INVALID)
+    p_type = property->prerequisite;
+  else
+    p_type = property->gtype;
+
+  g_value_init (&value, p_type);
+
+  if (property->default_values != NULL)
+    {
+      GValue *default_value;
+
+      default_value = g_hash_table_lookup (property->default_values,
+                                           g_type_name (gtype));
+
+      if (default_value != NULL)
+        g_value_copy (default_value, &value);
+      else
+        g_critical (G_STRLOC ": No default value of property '%s' "
+                    "was found for type '%s'",
+                    G_PARAM_SPEC (property)->name,
+                    g_type_name (gtype));
+    }
+
+
+  va_start (var_args, gtype);
+
+  G_VALUE_LCOPY (&value, var_args, 0, &error);
+  if (error != NULL)
+    {
+      g_warning (G_STRLOC ": %s", error);
+      g_free (error);
+    }
+
+  va_end (var_args);
+  g_value_unset (&value);
+}
+
+void
+g_property_set_valist (GProperty *property,
+                       gpointer   gobject,
+                       va_list    args)
+{
+  GType gtype;
+
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (G_IS_OBJECT (gobject));
+  g_return_if_fail (property->is_installed);
+
+  if (property->prerequisite != G_TYPE_INVALID)
+    gtype = property->prerequisite;
+  else
+    gtype = property->gtype;
+
+  switch (G_TYPE_FUNDAMENTAL (gtype))
+    {
+    case G_TYPE_BOOLEAN:
+      g_boolean_property_set_value (property, gobject, va_arg (args, gboolean));
+      break;
+
+    case G_TYPE_INT:
+      switch (property->type_size)
+        {
+        case 1:
+          g_int8_property_set_value (property, gobject, va_arg (args, gint));
+          break;
+
+        case 2:
+          g_int16_property_set_value (property, gobject, va_arg (args, gint));
+          break;
+
+        case 4:
+          g_int32_property_set_value (property, gobject, va_arg (args, gint));
+          break;
+
+        default:
+          g_int_property_set_value (property, gobject, va_arg (args, gint));
+          break;
+        }
+      break;
+
+    case G_TYPE_INT64:
+      g_int64_property_set_value (property, gobject, va_arg (args, gint64));
+      break;
+
+    case G_TYPE_LONG:
+      g_long_property_set_value (property, gobject, va_arg (args, glong));
+      break;
+
+    case G_TYPE_UINT:
+      switch (property->type_size)
+        {
+        case 1:
+          g_uint8_property_set_value (property, gobject, va_arg (args, guint));
+          break;
+
+        case 2:
+          g_uint16_property_set_value (property, gobject, va_arg (args, guint));
+          break;
+
+        case 4:
+          g_uint32_property_set_value (property, gobject, va_arg (args, guint));
+          break;
+
+        default:
+          g_uint_property_set_value (property, gobject, va_arg (args, guint));
+          break;
+        }
+      break;
+
+    case G_TYPE_UINT64:
+      g_uint64_property_set_value (property, gobject, va_arg (args, guint64));
+      break;
+
+    case G_TYPE_ULONG:
+      g_ulong_property_set_value (property, gobject, va_arg (args, gulong));
+      break;
+
+    case G_TYPE_ENUM:
+      g_enum_property_set_value (property, gobject, va_arg (args, glong));
+      break;
+
+    case G_TYPE_FLAGS:
+      g_flags_property_set_value (property, gobject, va_arg (args, gulong));
+      break;
+
+    case G_TYPE_FLOAT:
+      g_float_property_set_value (property, gobject, va_arg (args, gdouble));
+      break;
+
+    case G_TYPE_DOUBLE:
+      g_double_property_set_value (property, gobject, va_arg (args, gdouble));
+      break;
+
+    case G_TYPE_STRING:
+      g_string_property_set_value (property, gobject, va_arg (args, gchar *));
+      break;
+
+    case G_TYPE_BOXED:
+      g_boxed_property_set_value (property, gobject, va_arg (args, gpointer));
+      break;
+
+    case G_TYPE_OBJECT:
+      g_object_property_set_value (property, gobject, va_arg (args, gpointer));
+      break;
+
+    default:
+      g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype));
+      break;
+    }
+}
+
+void
+g_property_get_valist (GProperty *property,
+                       gpointer   gobject,
+                       va_list    args)
+{
+  GType gtype;
+  gpointer ret_p;
+
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (G_IS_OBJECT (gobject));
+  g_return_if_fail (property->is_installed);
+
+  if (property->prerequisite != G_TYPE_INVALID)
+    gtype = property->prerequisite;
+  else
+    gtype = property->gtype;
+
+  ret_p = va_arg (args, gpointer);
+
+  switch (G_TYPE_FUNDAMENTAL (gtype))
+    {
+    case G_TYPE_BOOLEAN:
+      (* (gboolean *) ret_p) = g_boolean_property_get_value (property, gobject);
+      break;
+
+    case G_TYPE_INT:
+      switch (property->type_size)
+        {
+        case 1:
+          (* (gint8 *) ret_p) = g_int8_property_get_value (property, gobject);
+          break;
+
+        case 2:
+          (* (gint16 *) ret_p) = g_int16_property_get_value (property, gobject);
+          break;
+
+        case 4:
+          (* (gint32 *) ret_p) = g_int32_property_get_value (property, gobject);
+          break;
+
+        default:
+          (* (gint *) ret_p) = g_int_property_get_value (property, gobject);
+          break;
+        }
+      break;
+
+    case G_TYPE_INT64:
+      (* (gint64 *) ret_p) = g_int64_property_get_value (property, gobject);
+      break;
+
+    case G_TYPE_LONG:
+      (* (glong *) ret_p) = g_long_property_get_value (property, gobject);
+      break;
+
+    case G_TYPE_UINT:
+      switch (property->type_size)
+        {
+        case 1:
+          (* (guint8 *) ret_p) = g_uint8_property_get_value (property, gobject);
+          break;
+
+        case 2:
+          (* (guint16 *) ret_p) = g_uint16_property_get_value (property, gobject);
+          break;
+
+        case 4:
+          (* (guint32 *) ret_p) = g_uint32_property_get_value (property, gobject);
+          break;
+
+        default:
+          (* (guint *) ret_p) = g_uint_property_get_value (property, gobject);
+          break;
+        }
+      break;
+
+    case G_TYPE_UINT64:
+      (* (guint64 *) ret_p) = g_uint64_property_get_value (property, gobject);
+      break;
+
+    case G_TYPE_ULONG:
+      (* (gulong *) ret_p) = g_ulong_property_get_value (property, gobject);
+      break;
+
+    case G_TYPE_ENUM:
+      (* (glong *) ret_p) = g_enum_property_get_value (property, gobject);
+      break;
+
+    case G_TYPE_FLAGS:
+      (* (gulong *) ret_p) = g_flags_property_get_value (property, gobject);
+      break;
+
+    case G_TYPE_FLOAT:
+      (* (gfloat *) ret_p) = g_float_property_get_value (property, gobject);
+      break;
+
+    case G_TYPE_DOUBLE:
+      (* (gdouble *) ret_p) = g_double_property_get_value (property, gobject);
+      break;
+
+    case G_TYPE_STRING:
+      (* (gconstpointer *) ret_p) = g_string_property_get_value (property, gobject);
+      break;
+
+    case G_TYPE_BOXED:
+      (* (gconstpointer *) ret_p) = g_boxed_property_get_value (property, gobject);
+      break;
+
+    case G_TYPE_OBJECT:
+      (* (gpointer *) ret_p) = g_object_property_get_value (property, gobject);
+      break;
+
+    default:
+      g_critical (G_STRLOC ": Invalid type %s", g_type_name (property->gtype));
+      break;
+    }
+}
+
+/**
+ * g_property_set:
+ * @property: a #GProperty
+ * @gobject: a #GObject instance
+ * @...: the value to be set
+ *
+ * Sets the value of the @property for the given #GObject instance.
+ *
+ * The value will either be copied or have its reference count increased.
+ *
+ * Since: 2.32
+ */
+void
+g_property_set (GProperty *property,
+                gpointer   gobject,
+                ...)
+{
+  va_list args;
+
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (G_IS_OBJECT (gobject));
+  g_return_if_fail (property->is_installed);
+
+  va_start (args, gobject);
+  g_property_set_valist (property, gobject, args);
+  va_end (args);
+}
+
+gboolean
+g_property_collect (GProperty *property,
+                    gpointer   gobject,
+                    guint      n_cvalues,
+                    gpointer   cvalues)
+{
+  GTypeCValue *_cvalues = cvalues;
+  GType gtype;
+  gint i;
+
+  if (property->prerequisite != G_TYPE_INVALID)
+    gtype = property->prerequisite;
+  else
+    gtype = property->gtype;
+
+  for (i = 0; i < n_cvalues; i++)
+    {
+      GTypeCValue *_cvalue = _cvalues + i;
+
+      switch (G_TYPE_FUNDAMENTAL (gtype))
+        {
+        case G_TYPE_BOOLEAN:
+          g_boolean_property_set_value (property, gobject, _cvalue->v_int != 0 ? TRUE : FALSE);
+          break;
+
+        case G_TYPE_INT:
+        case G_TYPE_UINT:
+          switch (property->type_size)
+            {
+            case 1:
+              if (G_TYPE_FUNDAMENTAL (gtype) == G_TYPE_INT)
+                g_int8_property_set_value (property, gobject, _cvalue->v_int);
+              else
+                g_uint8_property_set_value (property, gobject, _cvalue->v_int);
+              break;
+
+            case 2:
+              if (G_TYPE_FUNDAMENTAL (gtype) == G_TYPE_INT)
+                g_int16_property_set_value (property, gobject, _cvalue->v_int);
+              else
+                g_uint16_property_set_value (property, gobject, _cvalue->v_int);
+              break;
+
+            case 4:
+              if (G_TYPE_FUNDAMENTAL (gtype) == G_TYPE_INT)
+                g_int32_property_set_value (property, gobject, _cvalue->v_int);
+              else
+                g_uint32_property_set_value (property, gobject, _cvalue->v_int);
+              break;
+
+            default:
+              if (G_TYPE_FUNDAMENTAL (gtype) == G_TYPE_INT)
+                g_int_property_set_value (property, gobject, _cvalue->v_int);
+              else
+                g_uint_property_set_value (property, gobject, _cvalue->v_int);
+              break;
+            }
+          break;
+
+        case G_TYPE_INT64:
+          g_int64_property_set_value (property, gobject, _cvalue->v_int64);
+          break;
+
+        case G_TYPE_UINT64:
+          g_uint64_property_set_value (property, gobject, _cvalue->v_int64);
+          break;
+
+        case G_TYPE_LONG:
+          g_long_property_set_value (property, gobject, _cvalue->v_long);
+          break;
+
+        case G_TYPE_ULONG:
+          g_ulong_property_set_value (property, gobject, _cvalue->v_long);
+          break;
+
+        case G_TYPE_ENUM:
+          g_enum_property_set_value (property, gobject, _cvalue->v_long);
+          break;
+
+        case G_TYPE_FLAGS:
+          g_flags_property_set_value (property, gobject, _cvalue->v_long);
+          break;
+
+        case G_TYPE_FLOAT:
+          g_float_property_set_value (property, gobject, _cvalue->v_double);
+          break;
+
+        case G_TYPE_DOUBLE:
+          g_double_property_set_value (property, gobject, _cvalue->v_double);
+          break;
+
+        case G_TYPE_STRING:
+          g_string_property_set_value (property, gobject, _cvalue->v_pointer);
+          break;
+
+        case G_TYPE_BOXED:
+          g_boxed_property_set_value (property, gobject, _cvalue->v_pointer);
+          break;
+
+        case G_TYPE_OBJECT:
+          g_object_property_set_value (property, gobject, _cvalue->v_pointer);
+          break;
+
+        default:
+          g_critical (G_STRLOC ": Invalid value for type '%s'", g_type_name (gtype));
+          return FALSE;
+        }
+    }
+
+  return TRUE;
+}
+
+gboolean
+g_property_lcopy (GProperty *property,
+                  gpointer   gobject,
+                  guint      n_cvalues,
+                  gpointer   cvalues)
+{
+  GTypeCValue *_cvalues = cvalues;
+  GType gtype;
+  gint i;
+
+  if (property->prerequisite != G_TYPE_INVALID)
+    gtype = property->prerequisite;
+  else
+    gtype = property->gtype;
+
+  for (i = 0; i < n_cvalues; i++)
+    {
+      GTypeCValue *_cvalue = _cvalues + i;
+
+      switch (G_TYPE_FUNDAMENTAL (gtype))
+        {
+        case G_TYPE_BOOLEAN:
+          {
+            gboolean *val = _cvalue->v_pointer;
+            if (val != NULL)
+              *val = g_boolean_property_get_value (property, gobject);
+            else
+              {
+                g_critical (G_STRLOC ": value location for gboolean passed as NULL");
+                return FALSE;
+              }
+          }
+          break;
+
+        case G_TYPE_INT:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for gint passed as NULL");
+              return FALSE;
+            }
+
+          switch (property->type_size)
+            {
+            case 1:
+              (* (gint8 *) _cvalue->v_pointer) =
+                g_int8_property_get_value (property, gobject);
+              break;
+
+            case 2:
+              (* (gint16 *) _cvalue->v_pointer) =
+                g_int16_property_get_value (property, gobject);
+              break;
+
+            case 4:
+              (* (gint32 *) _cvalue->v_pointer) =
+                g_int32_property_get_value (property, gobject);
+              break;
+
+            default:
+              (* (gint *) _cvalue->v_pointer) =
+                g_int_property_get_value (property, gobject);
+              break;
+            }
+          break;
+
+        case G_TYPE_UINT:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for guint passed as NULL");
+              return FALSE;
+            }
+
+          switch (property->type_size)
+            {
+            case 1:
+              (* (guint8 *) _cvalue->v_pointer) =
+                g_uint8_property_get_value (property, gobject);
+              break;
+
+            case 2:
+              (* (guint16 *) _cvalue->v_pointer) =
+                g_uint16_property_get_value (property, gobject);
+              break;
+
+            case 4:
+              (* (guint32 *) _cvalue->v_pointer) =
+                g_uint32_property_get_value (property, gobject);
+              break;
+
+            default:
+              (* (guint *) _cvalue->v_pointer) =
+                g_uint_property_get_value (property, gobject);
+              break;
+            }
+          break;
+
+        case G_TYPE_INT64:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for gint64 passed as NULL");
+              return FALSE;
+            }
+
+          (* (gint64 *) _cvalue->v_pointer) =
+            g_int64_property_get_value (property, gobject);
+          break;
+
+        case G_TYPE_UINT64:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for guint64 passed as NULL");
+              return FALSE;
+            }
+
+          (* (guint64 *) _cvalue->v_pointer) =
+            g_uint64_property_get_value (property, gobject);
+          break;
+
+        case G_TYPE_LONG:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for glong passed as NULL");
+              return FALSE;
+            }
+
+          (* (glong *) _cvalue->v_pointer) =
+            g_long_property_get_value (property, gobject);
+          break;
+
+        case G_TYPE_ULONG:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for gulong passed as NULL");
+              return FALSE;
+            }
+
+          (* (gulong *) _cvalue->v_pointer) =
+            g_ulong_property_get_value (property, gobject);
+          break;
+
+        case G_TYPE_ENUM:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for GEnum passed as NULL");
+              return FALSE;
+            }
+
+          (* (glong *) _cvalue->v_pointer) =
+            g_enum_property_get_value (property, gobject);
+          break;
+
+        case G_TYPE_FLAGS:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for GFlags passed as NULL");
+              return FALSE;
+            }
+
+          (* (gulong *) _cvalue->v_pointer) =
+            g_flags_property_get_value (property, gobject);
+          break;
+
+        case G_TYPE_FLOAT:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for gfloat passed as NULL");
+              return FALSE;
+            }
+
+          (* (gfloat *) _cvalue->v_pointer) =
+            g_float_property_get_value (property, gobject);
+          break;
+
+        case G_TYPE_DOUBLE:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for gdouble passed as NULL");
+              return FALSE;
+            }
+
+          (* (gdouble *) _cvalue->v_pointer) =
+            g_double_property_get_value (property, gobject);
+          break;
+
+        case G_TYPE_STRING:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for string passed as NULL");
+              return FALSE;
+            }
+
+          (* (gchar **) _cvalue->v_pointer) =
+            (gchar *) g_string_property_get_value (property, gobject);
+          break;
+
+        case G_TYPE_BOXED:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for %s passed as NULL",
+                          g_type_name (gtype));
+              return FALSE;
+            }
+          else
+            {
+              gconstpointer boxed;
+
+              boxed = g_boxed_property_get_value (property, gobject);
+
+              if (boxed == NULL)
+                (* (gpointer *) _cvalue->v_pointer) = NULL;
+              else
+                (* (gpointer *) _cvalue->v_pointer) = g_boxed_copy (gtype, boxed);
+            }
+          break;
+
+        case G_TYPE_OBJECT:
+          if (_cvalue->v_pointer == NULL)
+            {
+              g_critical (G_STRLOC ": value location for %s passed as NULL",
+                          g_type_name (gtype));
+              return FALSE;
+            }
+          else
+            {
+              gpointer obj = g_object_property_get_value (property, gobject);
+
+              if (obj != NULL)
+                (* (gpointer *) _cvalue->v_pointer) = g_object_ref (obj);
+            }
+          break;
+
+        default:
+          g_critical (G_STRLOC ": Invalid value location for type '%s'",
+                      g_type_name (gtype));
+          return FALSE;
+        }
+    }
+
+  return TRUE;
+}
+
+/**
+ * g_property_get:
+ * @property: a #GProperty
+ * @gobject: a #GObject instance
+ * @...: a pointer to the value to be retrieved
+ *
+ * Retrieves the value of the @property for the given #GObject instance.
+ *
+ * The value will either be copied or have its reference count increased.
+ *
+ * Since: 2.32
+ */
+void
+g_property_get (GProperty *property,
+                gpointer   gobject,
+                ...)
+{
+  va_list args;
+
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (G_IS_OBJECT (gobject));
+  g_return_if_fail (property->is_installed);
+
+  va_start (args, gobject);
+  g_property_get_valist (property, gobject, args);
+  va_end (args);
+}
+
+/**
+ * g_property_set_value:
+ * @property: a #GProperty
+ * @gobject: a #GObject instance
+ * @value: a #GValue
+ *
+ * Sets the value of the @property for the given #GObject instance
+ * by unboxing it from the #GValue, honouring eventual transformation
+ * functions between the #GValue type and the property type.
+ *
+ * Since: 2.32
+ */
+void
+g_property_set_value (GProperty    *property,
+                      gpointer      gobject,
+                      const GValue *value)
+{
+  GType gtype;
+
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (G_IS_OBJECT (gobject));
+  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;
+
+  g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (value), gtype));
+
+  switch (G_TYPE_FUNDAMENTAL (gtype))
+    {
+    case G_TYPE_BOOLEAN:
+      g_boolean_property_set_value (property, gobject, g_value_get_boolean (value));
+      break;
+
+    case G_TYPE_INT:
+      {
+        gint val = g_value_get_int (value);
+
+        switch (property->type_size)
+          {
+          case 1:
+            g_int8_property_set_value (property, gobject, val);
+            break;
+
+          case 2:
+            g_int16_property_set_value (property, gobject, val);
+            break;
+
+          case 4:
+            g_int32_property_set_value (property, gobject, val);
+            break;
+
+          default:
+            g_int_property_set_value (property, gobject, g_value_get_int (value));
+            break;
+          }
+      }
+      break;
+
+    case G_TYPE_INT64:
+      g_int64_property_set_value (property, gobject, g_value_get_int64 (value));
+      break;
+
+    case G_TYPE_LONG:
+      g_long_property_set_value (property, gobject, g_value_get_long (value));
+      break;
+
+    case G_TYPE_UINT:
+      g_uint_property_set_value (property, gobject, g_value_get_uint (value));
+      break;
+
+    case G_TYPE_UINT64:
+      g_uint64_property_set_value (property, gobject, g_value_get_uint64 (value));
+      break;
+
+    case G_TYPE_ULONG:
+      g_ulong_property_set_value (property, gobject, g_value_get_ulong (value));
+      break;
+
+    case G_TYPE_FLOAT:
+      g_float_property_set_value (property, gobject, g_value_get_float (value));
+      break;
+
+    case G_TYPE_DOUBLE:
+      g_double_property_set_value (property, gobject, g_value_get_double (value));
+      break;
+
+    case G_TYPE_STRING:
+      g_string_property_set_value (property, gobject, g_value_get_string (value));
+      break;
+
+    case G_TYPE_BOXED:
+      g_boxed_property_set_value (property, gobject, g_value_get_boxed (value));
+      break;
+
+    case G_TYPE_OBJECT:
+      g_object_property_set_value (property, gobject, g_value_get_object (value));
+      break;
+
+    default:
+      g_critical (G_STRLOC ": Invalid type %s", g_type_name (G_VALUE_TYPE (value)));
+      break;
+    }
+}
+
+/**
+ * g_property_get_value:
+ * @property: a #GProperty
+ * @gobject: a #GObject instance
+ * @value: a #GValue, initialized to the type of the property or to a
+ *   type that satisfies the transformable relation
+ *
+ * Retrieves the value of @property for the object instance, and
+ * boxes it inside a #GValue, honouring eventual transformation
+ * functions between the #GValue type and the property type.
+ *
+ * Since: 2.32
+ */
+void
+g_property_get_value (GProperty *property,
+                      gpointer   gobject,
+                      GValue    *value)
+{
+  GType gtype;
+
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (G_IS_OBJECT (gobject));
+  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;
+
+  g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (value), gtype));
+
+  switch (G_TYPE_FUNDAMENTAL (gtype))
+    {
+    case G_TYPE_BOOLEAN:
+      g_value_set_boolean (value, g_boolean_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_INT:
+      g_value_set_int (value, g_int_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_INT64:
+      g_value_set_int64 (value, g_int64_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_LONG:
+      g_value_set_long (value, g_long_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_UINT:
+      g_value_set_uint (value, g_uint_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_UINT64:
+      g_value_set_uint64 (value, g_uint64_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_ULONG:
+      g_value_set_ulong (value, g_ulong_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_STRING:
+      g_value_set_string (value, g_string_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_CHAR:
+      g_value_set_char (value, g_int8_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_UCHAR:
+      g_value_set_uchar (value, g_uint8_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_ENUM:
+      g_value_set_enum (value, g_enum_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_FLOAT:
+      g_value_set_float (value, g_float_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_DOUBLE:
+      g_value_set_double (value, g_double_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_FLAGS:
+      g_value_set_flags (value, g_flags_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_BOXED:
+      g_value_set_boxed (value, g_boxed_property_get_value (property, gobject));
+      break;
+
+    case G_TYPE_OBJECT:
+      g_value_set_object (value, g_object_property_get_value (property, gobject));
+      break;
+
+    default:
+      g_critical (G_STRLOC ": Invalid type %s", g_type_name (G_VALUE_TYPE (value)));
+      break;
+    }
+}
+
+/**
+ * g_property_get_value_type:
+ * @property: a #GProperty
+ *
+ * Retrieves the #GType of the value stored by the property.
+ *
+ * If a prerequisite type has been set, it will be the one returned.
+ *
+ * Return value: a #GType
+ *
+ * Since: 2.32
+ */
+GType
+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;
+}
+
+gboolean
+g_property_validate (GProperty *property,
+                     ...)
+{
+  gboolean retval = FALSE;
+  GType gtype;
+  va_list args;
+
+  g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+
+  va_start (args, property);
+
+  if (property->prerequisite != G_TYPE_INVALID)
+    gtype = property->prerequisite;
+  else
+    gtype = property->gtype;
+
+  switch (G_TYPE_FUNDAMENTAL (gtype))
+    {
+    case G_TYPE_BOOLEAN:
+      retval = g_boolean_property_validate (property, va_arg (args, gboolean));
+      break;
+
+    case G_TYPE_INT:
+      switch (property->type_size)
+        {
+        case 8:
+          retval = g_int8_property_validate (property, va_arg (args, gint));
+          break;
+
+        case 16:
+          retval = g_int16_property_validate (property, va_arg (args, gint));
+          break;
+
+        case 32:
+          retval = g_int32_property_validate (property, va_arg (args, gint));
+          break;
+
+        default:
+          retval = g_int_property_validate (property, va_arg (args, gint));
+          break;
+        }
+      break;
+
+    case G_TYPE_INT64:
+      retval = g_int64_property_validate (property, va_arg (args, gint64));
+      break;
+
+    case G_TYPE_LONG:
+      retval = g_long_property_validate (property, va_arg (args, glong));
+      break;
+
+    case G_TYPE_UINT:
+      retval = g_uint_property_validate (property, va_arg (args, guint));
+      break;
+
+    case G_TYPE_UINT64:
+      retval = g_uint64_property_validate (property, va_arg (args, guint64));
+      break;
+
+    case G_TYPE_ULONG:
+      retval = g_ulong_property_validate (property, va_arg (args, gulong));
+      break;
+
+    case G_TYPE_FLOAT:
+      retval = g_float_property_validate (property, va_arg (args, gdouble));
+      break;
+
+    case G_TYPE_DOUBLE:
+      retval = g_double_property_validate (property, va_arg (args, gdouble));
+      break;
+
+    case G_TYPE_STRING:
+      retval = g_string_property_validate (property, va_arg (args, gchar *));
+      break;
+
+    case G_TYPE_BOXED:
+      retval = g_boxed_property_validate (property, va_arg (args, gpointer));
+      break;
+
+    case G_TYPE_OBJECT:
+      retval = g_object_property_validate (property, va_arg (args, gpointer));
+      break;
+
+    default:
+      g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype));
+      break;
+    }
+
+  va_end (args);
+
+  return retval;
+}
+
+gboolean
+g_property_validate_value (GProperty *property,
+                           GValue    *value)
+{
+  gboolean retval = FALSE;
+
+  g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+
+  return retval;
+}
+
+/**
+ * g_property_is_writable:
+ * @property: a #GProperty
+ *
+ * Checks whether the @property has the %G_PROPERTY_WRITABLE flag set.
+ *
+ * Return value: %TRUE if the flag is set, and %FALSE otherwise
+ *
+ * Since: 2.32
+ */
+gboolean
+g_property_is_writable (GProperty *property)
+{
+  g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+
+  return (property->flags & G_PROPERTY_WRITABLE) != 0;
+}
+
+/**
+ * g_property_is_readable:
+ * @property: a #GProperty
+ *
+ * Checks whether the @property has the %G_PROPERTY_READABLE flag set.
+ *
+ * Return value: %TRUE if the flag is set, and %FALSE otherwise
+ *
+ * Since: 2.32
+ */
+gboolean
+g_property_is_readable (GProperty *property)
+{
+  g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+
+  return (property->flags & G_PROPERTY_READABLE) != 0;
+}
+
+/**
+ * g_property_is_deprecated:
+ * @property: a #GProperty
+ *
+ * Checks whether the @property has the %G_PROPERTY_DEPRECATED flag set.
+ *
+ * Return value: %TRUE if the flag is set, and %FALSE otherwise
+ *
+ * Since: 2.32
+ */
+gboolean
+g_property_is_deprecated (GProperty *property)
+{
+  g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+
+  return (property->flags & G_PROPERTY_DEPRECATED) != 0;
+}
+
+/**
+ * g_property_is_atomic:
+ * @property: a #GProperty
+ *
+ * Checks whether the @property has the %G_PROPERTY_ATOMIC flag set.
+ *
+ * Return value: %TRUE if the flag is set, and %FALSE otherwise
+ *
+ * Since: 2.32
+ */
+gboolean
+g_property_is_atomic (GProperty *property)
+{
+  g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+
+  return (property->flags & G_PROPERTY_ATOMIC) != 0;
+}
+
+/**
+ * g_property_lock:
+ * @property: a #GProperty
+ * @gobject: a #GObject
+ *
+ * Locks a property on the given object.
+ *
+ * Use g_property_unlock() to unlock the property when done.
+ *
+ * Since: 2.32
+ */
+void
+g_property_lock (GProperty *property,
+                 gpointer   gobject)
+{
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (G_IS_OBJECT (gobject));
+
+  if (property->lock_func != NULL)
+    property->lock_func (property, gobject);
+}
+
+/**
+ * g_property_unlock:
+ * @property: a #GProperty
+ * @gobject: a #GObject
+ *
+ * Unlocks a property on the given object previously locked
+ * using g_property_lock().
+ *
+ * Since: 2.32
+ */
+void
+g_property_unlock (GProperty *property,
+                   gpointer   gobject)
+{
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (G_IS_OBJECT (gobject));
+
+  if (property->unlock_func != NULL)
+    property->unlock_func (property, gobject);
+}
+
+static void
+g_property_default_lock (GProperty *property,
+                         gpointer   gobject)
+{
+}
+
+static void
+g_property_default_unlock (GProperty *property,
+                           gpointer   gobject)
+{
+}
+
+/**
+ * g_property_set_lock_functions:
+ * @property: a #GProperty
+ * @lock_func: (allow-none): the function to be called when locking
+ *   the @property, or %NULL for the default locking function
+ * @unlock_func: (allow-none): the function to be called when unlocking
+ *   the @property, or %NULL for the default unlocking function
+ *
+ * Replaces the locking and unlocking functions for @property with
+ * custom functions.
+ *
+ * Since: 2.32
+ */
+void
+g_property_set_lock_functions (GProperty           *property,
+                               GPropertyLockFunc    lock_func,
+                               GPropertyUnlockFunc  unlock_func)
+{
+  g_return_if_fail (G_IS_PROPERTY (property));
+  g_return_if_fail (!property->is_installed);
+
+  if (lock_func == NULL)
+    {
+      g_return_if_fail (unlock_func == NULL);
+      lock_func = g_property_default_lock;
+    }
+
+  if (unlock_func == NULL)
+    unlock_func = g_property_default_unlock;
+
+  property->lock_func = lock_func;
+  property->unlock_func = unlock_func;
+}
+
+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_values != NULL)
+    g_hash_table_destroy (property->default_values);
+
+  parent_class->finalize (pspec);
+}
+
+static void
+property_set_default (GParamSpec *pspec,
+                      GValue     *value)
+{
+  GProperty *property = G_PROPERTY (pspec);
+
+  if (property->is_installed)
+    g_property_get_default_value (property, property->class_gtype, value);
+}
+
+static gboolean
+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;
+
+  return g_property_validate_value (G_PROPERTY (pspec), value);
+}
+
+static gint
+property_values_cmp (GParamSpec   *pspec,
+                     const GValue *value1,
+                     const GValue *value2)
+{
+  return 0;
+}
+
+static void
+property_class_init (GParamSpecClass *klass)
+{
+  klass->value_type = G_TYPE_INVALID;
+
+  klass->value_set_default = property_set_default;
+  klass->value_validate = property_validate;
+  klass->values_cmp = property_values_cmp;
+
+  klass->finalize = property_finalize;
+}
+
+static void
+property_init (GParamSpec *pspec)
+{
+  GProperty *property = G_PROPERTY (pspec);
+
+  property->gtype = G_TYPE_INVALID;
+  property->prerequisite = G_TYPE_INVALID;
+
+  property->field_offset = -1;
+  property->priv_offset = -1;
+
+  property->lock_func = g_property_default_lock;
+  property->unlock_func = g_property_default_unlock;
+}
+
+GType
+g_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_class_init,
+        NULL, NULL,
+        sizeof (GProperty),
+        0,
+        (GInstanceInitFunc) property_init,
+      };
+
+      GType pspec_type_id =
+        g_type_register_static (G_TYPE_PARAM,
+                                g_intern_static_string ("GProperty"),
+                                &info, 0);
+
+      g_once_init_leave (&pspec_type_id__volatile, pspec_type_id);
+    }
+
+  return pspec_type_id__volatile;
+}
diff --git a/gobject/gproperty.h b/gobject/gproperty.h
new file mode 100644
index 0000000..fd70561
--- /dev/null
+++ b/gobject/gproperty.h
@@ -0,0 +1,630 @@
+/* gproperty.h: Property definitions for GObject
+ *
+ * Copyright © 2011  Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#if !defined (__GLIB_GOBJECT_H_INSIDE__) && !defined (GOBJECT_COMPILATION)
+#error "Only <glib-object.h> can be included directly."
+#endif
+
+#ifndef __G_PROPERTY_H__
+#define __G_PROPERTY_H__
+
+#include <glib.h>
+#include <gobject/gparam.h>
+#include <gobject/gobject.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_PROPERTY         (g_property_get_type ())
+#define G_PROPERTY(obj)         (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_PROPERTY, GProperty))
+#define G_IS_PROPERTY(obj)      (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_PROPERTY))
+
+/**
+ * GProperty:
+ *
+ * The <structname>GProperty</structname> structure is an opaque structure
+ * whose members cannot be directly accessed.
+ *
+ * Since: 2.32
+ */
+typedef struct _GProperty       GProperty;
+
+/**
+ * GPropertyFlags:
+ * @G_PROPERTY_READABLE: Whether the property is readable
+ * @G_PROPERTY_WRITABLE: Whether the property is writable
+ * @G_PROPERTY_READWRITE: Whether the property is readable and writable
+ * @G_PROPERTY_DEPRECATED: Whether the property is deprecated and should
+ *   not be accessed in newly written code.
+ * @G_PROPERTY_ATOMIC: Whether the autogenerated setter function should
+ *   be thread-safe, and acquire a lock when changing the value of the
+ *   property.
+ *
+ * Flags for properties declared using #GProperty and relative macros.
+ *
+ * This enumeration might be extended at later date.
+ *
+ * Since: 2.32
+ */
+typedef enum {
+  G_PROPERTY_READABLE       = 1 << 0,
+  G_PROPERTY_WRITABLE       = 1 << 1,
+  G_PROPERTY_READWRITE      = (G_PROPERTY_READABLE | G_PROPERTY_WRITABLE),
+
+  G_PROPERTY_DEPRECATED     = 1 << 2,
+  G_PROPERTY_ATOMIC         = 1 << 3
+} GPropertyFlags;
+
+GType           g_property_get_type             (void) G_GNUC_CONST;
+
+/* general purpose API */
+gchar *         g_property_canonicalize         (const gchar         *name);
+
+void            g_property_set_static_nick      (GProperty           *property,
+                                                 const gchar         *nick);
+void            g_property_set_static_blurb     (GProperty           *property,
+                                                 const gchar         *blurb);
+
+GType           g_property_get_value_type       (GProperty           *property);
+
+gboolean        g_property_is_writable          (GProperty           *property);
+gboolean        g_property_is_readable          (GProperty           *property);
+gboolean        g_property_is_deprecated        (GProperty           *property);
+gboolean        g_property_is_atomic            (GProperty           *property);
+
+void            g_property_set_range_values     (GProperty           *property,
+                                                 const GValue        *min_value,
+                                                 const GValue        *max_value);
+void            g_property_set_range            (GProperty           *property,
+                                                 ...);
+
+void            g_property_set_default_value    (GProperty           *property,
+                                                 GType                class_type,
+                                                 const GValue        *value);
+void            g_property_get_default_value    (GProperty           *property,
+                                                 GType                class_type,
+                                                 GValue              *value);
+void            g_property_set_default          (GProperty           *property,
+                                                 GType                gtype,
+                                                 ...);
+void            g_property_get_default          (GProperty           *property,
+                                                 GType                gtype,
+                                                 ...);
+
+void            g_property_set_prerequisite     (GProperty           *property,
+                                                 GType                gtype);
+
+gboolean        g_property_validate             (GProperty           *property,
+                                                 ...);
+gboolean        g_property_validate_value       (GProperty           *property,
+                                                 GValue              *value);
+
+void            g_property_set_value            (GProperty           *property,
+                                                 gpointer             gobject,
+                                                 const GValue        *value);
+void            g_property_get_value            (GProperty           *property,
+                                                 gpointer             gobject,
+                                                 GValue              *value);
+void            g_property_set_valist           (GProperty           *property,
+                                                 gpointer             gobject,
+                                                 va_list              args);
+void            g_property_get_valist           (GProperty           *property,
+                                                 gpointer             gobject,
+                                                 va_list              args);
+void            g_property_set                  (GProperty           *property,
+                                                 gpointer             gobject,
+                                                 ...);
+void            g_property_get                  (GProperty           *property,
+                                                 gpointer             gobject,
+                                                 ...);
+
+typedef void (* GPropertyLockFunc)   (GProperty *property,
+                                      gpointer   gobject);
+
+typedef void (* GPropertyUnlockFunc) (GProperty *property,
+                                      gpointer   gobject);
+
+void            g_property_set_lock_functions   (GProperty           *property,
+                                                 GPropertyLockFunc    lock_func,
+                                                 GPropertyUnlockFunc  unlock_func);
+
+void            g_property_lock                 (GProperty           *property,
+                                                 gpointer             gobject);
+void            g_property_unlock               (GProperty           *property,
+                                                 gpointer             gobject);
+
+void            _g_property_set_installed       (GProperty           *property,
+                                                 GType                class_gtype);
+gboolean        g_property_collect              (GProperty           *property,
+                                                 gpointer             gobject,
+                                                 guint                n_cvalues,
+                                                 gpointer             cvalues);
+gboolean        g_property_lcopy                (GProperty           *property,
+                                                 gpointer             gobject,
+                                                 guint                n_cvalues,
+                                                 gpointer             cvalues);
+
+/* per-type specific accessors */
+typedef void          (* GPropertyBooleanSet) (gpointer       gobject,
+                                               gboolean       value);
+typedef gboolean      (* GPropertyBooleanGet) (gpointer       gobject);
+
+typedef void          (* GPropertyIntSet)     (gpointer       gobject,
+                                               gint           value);
+typedef gint          (* GPropertyIntGet)     (gpointer       gobject);
+
+typedef void          (* GPropertyInt8Set)    (gpointer       gobject,
+                                               gint8          value);
+typedef gint8         (* GPropertyInt8Get)    (gpointer       gobject);
+
+typedef void          (* GPropertyInt16Set)   (gpointer       gobject,
+                                               gint16         value);
+typedef gint16        (* GPropertyInt16Get)   (gpointer       gobject);
+
+typedef void          (* GPropertyInt32Set)   (gpointer       gobject,
+                                               gint32         value);
+typedef gint32        (* GPropertyInt32Get)   (gpointer       gobject);
+
+typedef void          (* GPropertyInt64Set)   (gpointer       gobject,
+                                               gint64         value);
+typedef gint64        (* GPropertyInt64Get)   (gpointer       gobject);
+
+typedef void          (* GPropertyLongSet)    (gpointer       gobject,
+                                               glong          value);
+typedef glong         (* GPropertyLongGet)    (gpointer       gobject);
+
+typedef void          (* GPropertyUIntSet)    (gpointer       gobject,
+                                               guint          value);
+typedef guint         (* GPropertyUIntGet)    (gpointer       gobject);
+
+typedef void          (* GPropertyUInt8Set)   (gpointer       gobject,
+                                               guint8         value);
+typedef guint8        (* GPropertyUInt8Get)   (gpointer       gobject);
+
+typedef void          (* GPropertyUInt16Set)  (gpointer       gobject,
+                                               guint16        value);
+typedef guint16       (* GPropertyUInt16Get)  (gpointer       gobject);
+
+typedef void          (* GPropertyUInt32Set)  (gpointer       gobject,
+                                               guint32        value);
+typedef guint32       (* GPropertyUInt32Get)  (gpointer       gobject);
+
+typedef void          (* GPropertyUInt64Set)  (gpointer       gobject,
+                                               guint64        value);
+typedef guint64       (* GPropertyUInt64Get)  (gpointer       gobject);
+
+typedef void          (* GPropertyULongSet)   (gpointer       gobject,
+                                               gulong         value);
+typedef gulong        (* GPropertyULongGet)   (gpointer       gobject);
+
+typedef void          (* GPropertyEnumSet)    (gpointer       gobject,
+                                               glong          value);
+typedef glong         (* GPropertyEnumGet)    (gpointer       gobject);
+
+typedef void          (* GPropertyFlagsSet)   (gpointer       gobject,
+                                               glong          value);
+typedef glong         (* GPropertyFlagsGet)   (gpointer       gobject);
+
+typedef void          (* GPropertyFloatSet)   (gpointer       gobject,
+                                               gfloat         value);
+typedef gfloat        (* GPropertyFloatGet)   (gpointer       gobject);
+
+typedef void          (* GPropertyDoubleSet)  (gpointer       gobject,
+                                               gdouble        value);
+typedef gdouble       (* GPropertyDoubleGet)  (gpointer       gobject);
+
+typedef void          (* GPropertyStringSet)  (gpointer       gobject,
+                                               const gchar   *value);
+typedef const gchar * (* GPropertyStringGet)  (gpointer       gobject);
+
+typedef void          (* GPropertyBoxedSet)   (gpointer       gobject,
+                                               gconstpointer  value);
+typedef gconstpointer (* GPropertyBoxedGet)   (gpointer       gobject);
+
+typedef void          (* GPropertyObjectSet)  (gpointer       gobject,
+                                               gpointer       value);
+typedef gpointer      (* GPropertyObjectGet)  (gpointer       gobject);
+
+typedef void          (* GPropertyPointerSet) (gpointer       gobject,
+                                               gpointer       value);
+typedef gpointer      (* GPropertyPointerGet) (gpointer       gobject);
+
+/* per-type specific constructors */
+GParamSpec *    g_boolean_property_new  (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyBooleanSet  setter,
+                                         GPropertyBooleanGet  getter);
+
+GParamSpec *    g_int_property_new      (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyIntSet      setter,
+                                         GPropertyIntGet      getter);
+GParamSpec *    g_int8_property_new     (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyInt8Set     setter,
+                                         GPropertyInt8Get     getter);
+GParamSpec *    g_int16_property_new    (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyInt16Set    setter,
+                                         GPropertyInt16Get    getter);
+GParamSpec *    g_int32_property_new    (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyInt32Set    setter,
+                                         GPropertyInt32Get    getter);
+GParamSpec *    g_int64_property_new    (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyInt64Set    setter,
+                                         GPropertyInt64Get    getter);
+GParamSpec *    g_long_property_new     (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyLongSet     setter,
+                                         GPropertyLongGet     getter);
+
+GParamSpec *    g_uint_property_new     (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyUIntSet     setter,
+                                         GPropertyUIntGet     getter);
+GParamSpec *    g_uint8_property_new    (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyUInt8Set    setter,
+                                         GPropertyUInt8Get    getter);
+GParamSpec *    g_uint16_property_new   (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyUInt16Set   setter,
+                                         GPropertyUInt16Get   getter);
+GParamSpec *    g_uint32_property_new   (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyUInt32Set   setter,
+                                         GPropertyUInt32Get   getter);
+GParamSpec *    g_uint64_property_new   (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyUInt64Set   setter,
+                                         GPropertyUInt64Get   getter);
+GParamSpec *    g_ulong_property_new    (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyULongSet    setter,
+                                         GPropertyULongGet    getter);
+
+#define g_char_property_new     g_int8_property_new
+#define g_uchar_property_new    g_uint8_property_new
+#define g_unichar_property_new  g_uint32_property_new
+
+GParamSpec *    g_enum_property_new     (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyEnumSet     setter,
+                                         GPropertyEnumGet     getter);
+GParamSpec *    g_flags_property_new    (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyFlagsSet    setter,
+                                         GPropertyFlagsGet    getter);
+
+GParamSpec *    g_float_property_new    (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyFloatSet    setter,
+                                         GPropertyFloatGet    getter);
+GParamSpec *    g_double_property_new   (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyDoubleSet   setter,
+                                         GPropertyDoubleGet   getter);
+
+GParamSpec *    g_string_property_new   (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyStringSet   setter,
+                                         GPropertyStringGet   getter);
+
+GParamSpec *    g_boxed_property_new    (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyBoxedSet    setter,
+                                         GPropertyBoxedGet    getter);
+
+GParamSpec *    g_object_property_new   (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyObjectSet   setter,
+                                         GPropertyObjectGet   getter);
+
+GParamSpec *    g_pointer_property_new  (const gchar         *name,
+                                         GPropertyFlags       flags,
+                                         gssize               field_offset,
+                                         GPropertyPointerSet  setter,
+                                         GPropertyPointerGet  getter);
+
+/* accessors generation */
+#define _G_DECLARE_PROPERTY_GETTER(T_n, t_n, f_t, f_n)  f_t t_n##_get_##f_n (T_n *self)
+
+#define _G_DEFINE_PROPERTY_GETTER_BEGIN(T_n, t_n, f_t, f_n) \
+{ \
+  GProperty *g_property = NULL; \
+  f_t retval; \
+\
+  g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, t_n##_get_type ()), (f_t) 0); \
+\
+  { \
+    GObjectClass *_self_class; \
+    _self_class = G_OBJECT_GET_CLASS (self); \
+    g_property = (GProperty *) g_object_class_find_property (_self_class, #f_n); \
+    if (G_UNLIKELY (g_property == NULL)) \
+      { \
+        g_critical (G_STRLOC ": No property " #f_n " found for class %s", \
+                    G_OBJECT_TYPE_NAME (self)); \
+        return (f_t) 0; \
+      } \
+  } \
+\
+  if (!g_property_is_readable (g_property)) \
+    { \
+       g_critical (G_STRLOC ": The property " #f_n " is not readable"); \
+       g_property_get_default (g_property, t_n##_get_type (), &retval); \
+       return retval; \
+    } \
+\
+  { /* custom code follows */
+#define _G_DEFINE_PROPERTY_GETTER_END           \
+  } /* following custom code */                 \
+  g_property_get (g_property, self, &retval);   \
+  return retval;                                \
+}
+
+#define _G_DECLARE_PROPERTY_SETTER(T_n, t_n, f_t, f_n)  void t_n##_set_##f_n (T_n *self, f_t value)
+
+#define _G_DEFINE_PROPERTY_SETTER_BEGIN(T_n, t_n, f_t, f_n) \
+{ \
+  GProperty *g_property = NULL; \
+\
+  g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, t_n##_get_type ())); \
+\
+  { \
+    GObjectClass *_self_class; \
+    _self_class = G_OBJECT_GET_CLASS (self); \
+    g_property = (GProperty *) g_object_class_find_property (_self_class, #f_n); \
+    if (G_UNLIKELY (g_property == NULL)) \
+      { \
+        g_critical (G_STRLOC ": No property " #f_n " found for class %s", G_OBJECT_TYPE_NAME (self)); \
+        return; \
+      } \
+  } \
+\
+  if (!g_property_is_writable (g_property)) \
+    { \
+       g_critical (G_STRLOC ": The property " #f_n " is not writable"); \
+       return; \
+    } \
+\
+  g_property_set (g_property, self, value); \
+\
+  { /* custom code follows */
+#define _G_DEFINE_PROPERTY_SETTER_END           \
+  }/* following custom code */                  \
+}
+
+/**
+ * G_DECLARE_PROPERTY_GET_SET:
+ * @TypeName: the name of the type, in Camel case
+ * @type_name: the name of the type, in lowercase, with words separated by '_'
+ * @field_type: the type of the property, which must match the type of the
+ *   field in the @TypeName<!-- -->Private structure
+ * @field_name: the name of the property, which must match the name of the
+ *   field in the @TypeName<!-- -->Private structure
+ *
+ * Declares the accessor functions for a @field_name property in the
+ * class @TypeName. This macro should only be used in header files.
+ */
+#define G_DECLARE_PROPERTY_GET_SET(T_n, t_n, f_t, f_n)  \
+_G_DECLARE_PROPERTY_SETTER (T_n, t_n, f_t, f_n);        \
+_G_DECLARE_PROPERTY_GETTER (T_n, t_n, f_t, f_n);
+
+/**
+ * G_DECLARE_PROPERTY_GET:
+ * @T_n: the name of the type, in Camel case
+ * @t_n: the name of the type, in lowercase, with words separated by '_'
+ * @f_t: the type of the property, which must match the type of the field
+ * @f_n: the name of the property, which must match the name of the field
+ *
+ * Declares the getter function for a @f_n property in the @T_n class.
+ *
+ * This macro should only be used in header files.
+ *
+ * Since: 2.32
+ */
+#define G_DECLARE_PROPERTY_GET(T_n, t_n, f_t, f_n)      _G_DECLARE_PROPERTY_GETTER (T_n, t_n, f_t, f_n);
+
+/**
+ * G_DECLARE_PROPERTY_SET:
+ * @T_n: the name of the type, in Camel case
+ * @t_n: the name of the type, in lowercase, with words separated by '_'
+ * @f_t: the type of the property, which must match the type of the field
+ * @f_n: the name of the property, which must match the name of the field
+ *
+ * Declares the setter function for a @f_n property in the @T_n class.
+ *
+ * This macro should only be used in header files.
+ *
+ * Since: 2.32
+ */
+#define G_DECLARE_PROPERTY_SET(T_n, t_n, f_t, f_n)      _G_DECLARE_PROPERTY_SETTER (T_n, t_n, f_t, f_n);
+
+/**
+ * G_DEFINE_PROPERTY_SET_WITH_CODE:
+ * @TypeName: the name of the type, in Camel case
+ * @type_name: the name of the type, in lowercase, with words separated by '_'
+ * @field_type: the type of the property, which must match the type of the
+ *   field in the @TypeName<!-- -->Private structure
+ * @field_name: the name of the property, which must match the name of the
+ *   field in the @TypeName<!-- -->Private structure
+ *
+ * Defines the setter function for a @field_name property in the
+ * class @TypeName, with the possibility of calling custom code.
+ *
+ * This macro should only be used in C source files.
+ *
+ * |[
+ * G_DEFINE_PROPERTY_SET_WITH_CODE (ClutterActor, clutter_actor,
+ *                                  int, margin_top,
+ *                                  clutter_actor_queue_redraw (self))
+ * ]|
+ *
+ * Since: 2.32
+ */
+
+#define G_DEFINE_PROPERTY_SET_WITH_CODE(T_n, t_n, f_t, f_n, _C_)   \
+_G_DECLARE_PROPERTY_SETTER (T_n, t_n, f_t, f_n)                         \
+_G_DEFINE_PROPERTY_SETTER_BEGIN (T_n, t_n, f_t, f_n)               \
+{ _C_; } \
+_G_DEFINE_PROPERTY_SETTER_END
+
+/**
+ * G_DEFINE_PROPERTY_GET_WITH_CODE:
+ * @TypeName: the name of the type, in Camel case
+ * @type_name: the name of the type, in lowercase, with words separated by '_'
+ * @field_type: the type of the property, which must match the type of the
+ *   field in the @TypeName<!-- -->Private structure
+ * @field_name: the name of the property, which must match the name of the
+ *   field in the @TypeName<!-- -->Private structure
+ *
+ * Defines the getter function for a @field_name property in the
+ * class @TypeName, with the possibility of calling custom code.
+ *
+ * This macro should only be used in C source files.
+ */
+
+#define G_DEFINE_PROPERTY_GET_WITH_CODE(T_n, t_n, f_t, f_n, _C_)   \
+_G_DECLARE_PROPERTY_GETTER (T_n, t_n, f_t, f_n)                         \
+_G_DEFINE_PROPERTY_GETTER_BEGIN (T_n, t_n, f_t, f_n)               \
+{ _C_; } \
+_G_DEFINE_PROPERTY_GETTER_END
+
+/**
+ * G_DEFINE_PROPERTY_SET:
+ * @TypeName: the name of the type, in Camel case
+ * @type_name: the name of the type, in lowercase, with words separated by '_'
+ * @field_type: the type of the property, which must match the type of the
+ *   field in the @TypeName<!-- -->Private structure
+ * @field_name: the name of the property, which must match the name of the
+ *   field in the @TypeName<!-- -->Private structure
+ *
+ * Defines the setter function for a @field_name property in the
+ * class @TypeName. This macro should only be used in C source files.
+ *
+ * See also %G_DEFINE_PROPERTY_SET_WITH_CODE.
+ */
+#define G_DEFINE_PROPERTY_SET(T_n, t_n, f_t, f_n)  G_DEFINE_PROPERTY_SET_WITH_CODE (T_n, t_n, f_t, f_n, ;)
+
+/**
+ * G_DEFINE_PROPERTY_GET:
+ * @TypeName: the name of the type, in Camel case
+ * @type_name: the name of the type, in lowercase, with words separated by '_'
+ * @field_type: the type of the property, which must match the type of the
+ *   field in the @TypeName<!-- -->Private structure
+ * @field_name: the name of the property, which must match the name of the
+ *   field in the @TypeName<!-- -->Private structure
+ *
+ * Defines the getter function for a @field_name property in the
+ * class @TypeName. This macro should only be used in C source files.
+ *
+ * See also %G_DEFINE_PROPERTY_GET_WITH_CODE.
+ */
+
+#define G_DEFINE_PROPERTY_GET(T_n, t_n, f_t, f_n)  G_DEFINE_PROPERTY_GET_WITH_CODE (T_n, t_n, f_t, f_n, ;)
+
+/**
+ * G_DEFINE_PROPERTY_GET_SET:
+ * @T_n: the name of the type, in Camel case
+ * @t_n: the name of the type, in lowercase, with words separated by '_'
+ * @f_t: the type of the property, which must match the type of the
+ *   field in the @TypeName<!-- -->Private structure
+ * @f_n: the name of the property, which must match the name of the
+ *   field in the @TypeName<!-- -->Private structure
+ *
+ * Defines the accessor functions for a @f_n property in the class @T_n.
+ *
+ * This macro should only be used in C source files, for instance:
+ *
+ * |[
+ *   G_DEFINE_PROPERTY_GET_SET (ClutterActor, clutter_actor, int, margin_top)
+ * ]|
+ *
+ * will synthesize the equivalent of the following code:
+ *
+ * |[
+ * void
+ * clutter_actor_set_margin_top (ClutterActor *self,
+ *                               int           value)
+ * {
+ *   ClutterActorPrivate *priv;
+ *
+ *   g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, clutter_actor_get_type ()));
+ *
+ *   priv = self->priv;
+ *
+ *   if (priv->margin_top == value)
+ *     return;
+ *
+ *   priv->value = value;
+ *
+ *   g_object_notify (G_OBJECT (self), "margin-top");
+ * }
+ *
+ * int
+ * clutter_actor_get_margin_top (ClutterActor *self)
+ * {
+ *   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, clutter_actor_get_type ()), 0);
+ *
+ *   return self->priv->margin_top;
+ * }
+ * ]|
+ *
+ * This macro will generate both the setter and getter functions, but the @flags will
+ * be used to determine whether the setter or the getter functions will be implemented.
+ *
+ * For greater control on the setter and getter implementation, see also the
+ * %G_DEFINE_PROPERTY_GET and %G_DEFINE_PROPERTY_SET macros, along with their
+ * %G_DEFINE_PROPERTY_GET_WITH_CODE and %G_DEFINE_PROPERTY_SET_WITH_CODE
+ * variants.
+ *
+ * Since: 2.32
+ */
+
+#define G_DEFINE_PROPERTY_GET_SET(T_n, t_n, f_t, f_n)      \
+G_DEFINE_PROPERTY_GET (T_n, t_n, f_t, f_n)                 \
+G_DEFINE_PROPERTY_SET (T_n, t_n, f_t, f_n)
+
+G_END_DECLS
+
+#endif /* __G_PROPERTY_H__ */
diff --git a/gobject/gvaluecollector.h b/gobject/gvaluecollector.h
index b39b40d..47e4fa8 100644
--- a/gobject/gvaluecollector.h
+++ b/gobject/gvaluecollector.h
@@ -222,6 +222,103 @@ G_STMT_START {										\
  */
 #define	G_VALUE_COLLECT_FORMAT_MAX_LENGTH	(8)
 
+/**
+ * G_PROPERTY_LCOPY:
+ * @property: a #GProperty
+ * @gobject: a #GObject
+ * @var_args: the va_list variable; it may be evaluated multiple times
+ * @__retval: the address of a #gboolean variable, which will be set
+ *   to %FALSE if the copy was not successful
+ *
+ * Collects a variable argument value from a va_list and sets it for
+ * the given #GProperty.
+ *
+ * We have to implement the varargs collection as a macro, because on some
+ * systems va_list variables cannot be passed by reference.
+ */
+#define G_PROPERTY_COLLECT(property, gobject, var_args, __retval)       G_STMT_START {  \
+  GType _p_type = g_property_get_value_type ((property)); \
+  GTypeValueTable *_vtab = g_type_value_table_peek (_p_type); \
+  gchar *_collect_format = _vtab->collect_format; \
+  GTypeCValue _cvalues[G_VALUE_COLLECT_FORMAT_MAX_LENGTH] = { { 0, }, }; \
+  guint _n_values = 0; \
+\
+  while (*_collect_format) \
+    { \
+      GTypeCValue *_cvalue = _cvalues + _n_values++; \
+\
+      switch (*_collect_format++) \
+        { \
+        case G_VALUE_COLLECT_INT: \
+          _cvalue->v_int = va_arg ((var_args), gint); \
+          break; \
+        case G_VALUE_COLLECT_LONG: \
+          _cvalue->v_long = va_arg ((var_args), glong); \
+          break; \
+        case G_VALUE_COLLECT_INT64: \
+          _cvalue->v_int64 = va_arg ((var_args), gint64); \
+          break; \
+        case G_VALUE_COLLECT_DOUBLE: \
+          _cvalue->v_double = va_arg ((var_args), gdouble); \
+          break; \
+        case G_VALUE_COLLECT_POINTER: \
+          _cvalue->v_pointer = va_arg ((var_args), gpointer); \
+          break; \
+        default: \
+          g_assert_not_reached (); \
+        } \
+    } \
+\
+  *(__retval) = \
+    g_property_collect ((property), (gobject), _n_values, _cvalues);    } G_STMT_END
+
+/**
+ * G_PROPERTY_LCOPY:
+ * @property: a #GProperty
+ * @gobject: a #GObject
+ * @var_args: the va_list variable; it may be evaluated multiple times
+ * @__retval: the address of a #gboolean variable, which will be set
+ *   to %FALSE if the copy was not successful
+ *
+ * Collects a property value and places it into the variable argument location
+ * from a va_list. Usage is analogous to G_PROPERTY_COLLECT().
+ */
+#define G_PROPERTY_LCOPY(property, gobject, var_args, __retval)         G_STMT_START {  \
+  GType _p_type = g_property_get_value_type ((property)); \
+  GTypeValueTable *_vtab = g_type_value_table_peek (_p_type); \
+  gchar *_lcopy_format = _vtab->lcopy_format; \
+  GTypeCValue _cvalues[G_VALUE_COLLECT_FORMAT_MAX_LENGTH] = { { 0, }, }; \
+  guint _n_values = 0; \
+\
+  while (*_lcopy_format) \
+    { \
+      GTypeCValue *_cvalue = _cvalues + _n_values++; \
+\
+      switch (*_lcopy_format++) \
+        { \
+        case G_VALUE_COLLECT_INT: \
+          _cvalue->v_int = va_arg ((var_args), gint); \
+          break; \
+        case G_VALUE_COLLECT_LONG: \
+          _cvalue->v_long = va_arg ((var_args), glong); \
+          break; \
+        case G_VALUE_COLLECT_INT64: \
+          _cvalue->v_int64 = va_arg ((var_args), gint64); \
+          break; \
+        case G_VALUE_COLLECT_DOUBLE: \
+          _cvalue->v_double = va_arg ((var_args), gdouble); \
+          break; \
+        case G_VALUE_COLLECT_POINTER: \
+          _cvalue->v_pointer = va_arg ((var_args), gpointer); \
+          break; \
+        default: \
+          g_assert_not_reached (); \
+        } \
+    } \
+\
+  *(__retval) = \
+    g_property_lcopy (property, object, _n_values, _cvalues);           } G_STMT_END
+
 G_END_DECLS
 
 #endif /* __G_VALUE_COLLECTOR_H__ */
diff --git a/gobject/tests/.gitignore b/gobject/tests/.gitignore
index afafc4a..861d114 100644
--- a/gobject/tests/.gitignore
+++ b/gobject/tests/.gitignore
@@ -1,3 +1,4 @@
+autoproperties
 binding
 boxed
 dynamictests
diff --git a/gobject/tests/Makefile.am b/gobject/tests/Makefile.am
index 010f04b..b27df9a 100644
--- a/gobject/tests/Makefile.am
+++ b/gobject/tests/Makefile.am
@@ -1,5 +1,7 @@
 include $(top_srcdir)/Makefile.decl
 
+NULL =
+
 INCLUDES = -g $(gobject_INCLUDES) $(GLIB_DEBUG_FLAGS)
 
 noinst_PROGRAMS  = $(TEST_PROGS)
@@ -15,6 +17,8 @@ TEST_PROGS += 		\
 	binding		\
 	properties	\
 	reference	\
-	ifaceproperties
+	ifaceproperties	\
+	autoproperties	\
+	$(NULL)
 
 ifaceproperties_SOURCES = ifaceproperties.c testcommon.h
diff --git a/gobject/tests/autoproperties.c b/gobject/tests/autoproperties.c
new file mode 100644
index 0000000..691de36
--- /dev/null
+++ b/gobject/tests/autoproperties.c
@@ -0,0 +1,353 @@
+#include <stdlib.h>
+#include <glib-object.h>
+
+typedef struct _TestObject              TestObject;
+typedef struct _TestObjectPrivate       TestObjectPrivate;
+typedef struct _TestObjectClass         TestObjectClass;
+
+typedef enum {
+  TEST_ENUM_VALUE_FOO = -1,
+  TEST_ENUM_VALUE_BAR =  0,
+  TEST_ENUM_VALUE_BAZ =  1
+} TestEnumValue;
+
+struct _TestObject
+{
+  GObject parent_instance;
+
+  TestObjectPrivate *priv;
+};
+
+struct _TestObjectClass
+{
+  GObjectClass parent_class;
+};
+
+G_DECLARE_PROPERTY_GET_SET (TestObject, test_object, gint, foo);
+G_DECLARE_PROPERTY_GET_SET (TestObject, test_object, gboolean, bar);
+G_DECLARE_PROPERTY_GET_SET (TestObject, test_object, const gchar *, str);
+G_DECLARE_PROPERTY_GET (TestObject, test_object, gboolean, str_set);
+G_DECLARE_PROPERTY_GET_SET (TestObject, test_object, gint8, single_byte);
+G_DECLARE_PROPERTY_GET_SET (TestObject, test_object, gint16, double_byte);
+G_DECLARE_PROPERTY_GET_SET (TestObject, test_object, gint32, four_bytes);
+G_DECLARE_PROPERTY_GET_SET (TestObject, test_object, float, width);
+G_DECLARE_PROPERTY_GET_SET (TestObject, test_object, double, x_align);
+
+struct _TestObjectPrivate
+{
+  gint foo;
+
+  gboolean bar;
+
+  gchar *str;
+  gboolean str_set;
+
+  gint8 single_byte;
+  gint16 double_byte;
+  gint32 four_bytes;
+
+  float width;
+  double x_align;
+
+  TestEnumValue value;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_FOO,
+  PROP_BAR,
+  PROP_STR,
+  PROP_STR_SET,
+  PROP_BAZ,
+  PROP_SINGLE_BYTE,
+  PROP_DOUBLE_BYTE,
+  PROP_FOUR_BYTES,
+  PROP_WIDTH,
+  PROP_X_ALIGN,
+  PROP_VALUE,
+
+  LAST_PROP
+};
+
+GType
+test_enum_value_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { TEST_ENUM_VALUE_FOO, "TEST_ENUM_VALUE_FOO", "foo" },
+        { TEST_ENUM_VALUE_BAR, "TEST_ENUM_VALUE_BAR", "bar" },
+        { TEST_ENUM_VALUE_BAZ, "TEST_ENUM_VALUE_BAZ", "baz" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("TestEnumValue"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+
+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, gboolean, bar);
+G_DEFINE_PROPERTY_GET (TestObject, test_object, gboolean, str_set);
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, gint8, single_byte);
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, gint16, double_byte);
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, gint32, four_bytes);
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, float, width);
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, double, x_align);
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, TestEnumValue, value);
+
+void
+test_object_set_str (TestObject  *self,
+                     const gchar *value)
+{
+  TestObjectPrivate *priv;
+
+  g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, test_object_get_type ()));
+
+  priv = self->priv;
+
+  if (g_strcmp0 (priv->str, value) == 0)
+    return;
+
+  g_free (priv->str);
+  priv->str = g_strdup (value);
+
+  if (priv->str != NULL)
+    priv->str_set = TRUE;
+  else
+    priv->str_set = FALSE;
+
+  g_object_notify_by_pspec (G_OBJECT (self), test_object_properties[PROP_STR]);
+  g_object_notify_by_pspec (G_OBJECT (self), test_object_properties[PROP_STR_SET]);
+}
+
+G_DEFINE_PROPERTY_GET (TestObject, test_object, const gchar *, str);
+
+static void
+test_object_class_init (TestObjectClass *klass)
+{
+  g_type_class_add_private (klass, sizeof (TestObjectPrivate));
+
+  test_object_properties[PROP_FOO] =
+    g_int_property_new ("foo", G_PROPERTY_READWRITE,
+                        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]),
+                          G_TYPE_FROM_CLASS (klass),
+                          50);
+
+  test_object_properties[PROP_BAR] =
+    g_boolean_property_new ("bar", G_PROPERTY_READWRITE | G_PROPERTY_ATOMIC,
+                            G_STRUCT_OFFSET (TestObjectPrivate, bar),
+                            NULL, NULL);
+
+  test_object_properties[PROP_STR] =
+    g_string_property_new ("str", G_PROPERTY_READWRITE,
+                           G_STRUCT_OFFSET (TestObjectPrivate, str),
+                           (GPropertyStringSet) test_object_set_str,
+                           NULL);
+
+  test_object_properties[PROP_STR_SET] =
+    g_boolean_property_new ("str-set", G_PROPERTY_READABLE,
+                            G_STRUCT_OFFSET (TestObjectPrivate, str_set),
+                            NULL, NULL);
+
+  test_object_properties[PROP_BAZ] =
+    g_int_property_new ("baz", G_PROPERTY_READWRITE,
+                        G_STRUCT_OFFSET (TestObjectPrivate, foo),
+                        NULL, NULL);
+
+  test_object_properties[PROP_SINGLE_BYTE] =
+    g_int8_property_new ("single-byte", G_PROPERTY_READWRITE,
+                         G_STRUCT_OFFSET (TestObjectPrivate, single_byte),
+                         NULL, NULL);
+
+  test_object_properties[PROP_DOUBLE_BYTE] =
+    g_int16_property_new ("double-byte", G_PROPERTY_READWRITE,
+                          G_STRUCT_OFFSET (TestObjectPrivate, double_byte),
+                          NULL, NULL);
+
+  test_object_properties[PROP_FOUR_BYTES] =
+    g_int32_property_new ("four-bytes", G_PROPERTY_READWRITE,
+                          G_STRUCT_OFFSET (TestObjectPrivate, four_bytes),
+                          NULL, NULL);
+
+  test_object_properties[PROP_WIDTH] =
+    g_float_property_new ("width", G_PROPERTY_READWRITE,
+                          G_STRUCT_OFFSET (TestObjectPrivate, width),
+                          NULL, NULL);
+  g_property_set_range (G_PROPERTY (test_object_properties[PROP_WIDTH]), 0.0, G_MAXFLOAT);
+
+  test_object_properties[PROP_X_ALIGN] =
+    g_double_property_new ("x-align", G_PROPERTY_READWRITE,
+                           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]),
+                          G_TYPE_FROM_CLASS (klass),
+                          0.5);
+
+  test_object_properties[PROP_VALUE] =
+    g_enum_property_new ("value", G_PROPERTY_READWRITE,
+                         G_STRUCT_OFFSET (TestObjectPrivate, value),
+                         NULL, NULL);
+  g_property_set_prerequisite (G_PROPERTY (test_object_properties[PROP_VALUE]),
+                               test_enum_value_get_type ());
+  g_property_set_default (G_PROPERTY (test_object_properties[PROP_VALUE]),
+                          G_TYPE_FROM_CLASS (klass),
+                          TEST_ENUM_VALUE_BAR);
+
+  g_object_class_install_properties (G_OBJECT_CLASS (klass),
+                                     G_N_ELEMENTS (test_object_properties),
+                                     test_object_properties);
+}
+
+static void
+test_object_init (TestObject *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, test_object_get_type (), TestObjectPrivate);
+
+  g_property_get_default (G_PROPERTY (test_object_properties[PROP_FOO]),
+                          test_object_get_type (),
+                          &(self->priv->foo));
+  g_property_get_default (G_PROPERTY (test_object_properties[PROP_X_ALIGN]),
+                          test_object_get_type (),
+                          &(self->priv->x_align));
+  g_property_get_default (G_PROPERTY (test_object_properties[PROP_VALUE]),
+                          test_object_get_type (),
+                          &(self->priv->value));
+}
+
+static void
+autoproperties_base (void)
+{
+  TestObject *t = g_object_new (test_object_get_type (), NULL);
+
+  g_assert (G_TYPE_CHECK_INSTANCE_TYPE (t, test_object_get_type ()));
+
+  g_object_unref (t);
+}
+
+static void
+autoproperties_default (void)
+{
+  TestObject *t = g_object_new (test_object_get_type (), NULL);
+
+  g_assert_cmpint (test_object_get_foo (t), ==, 50);
+  g_assert_cmpfloat (test_object_get_x_align (t), ==, 0.5f);
+  g_assert (test_object_get_value (t) == TEST_ENUM_VALUE_BAR);
+
+  g_object_unref (t);
+}
+
+static void
+autoproperties_accessors (void)
+{
+  TestObject *t = g_object_new (test_object_get_type (), NULL);
+
+  test_object_set_foo (t, 42);
+  g_assert_cmpint (test_object_get_foo (t), ==, 42);
+
+  test_object_set_str (t, "hello");
+  g_assert_cmpstr (test_object_get_str (t), ==, "hello");
+  g_assert (test_object_get_str_set (t));
+
+  g_assert (!test_object_get_bar (t));
+
+  test_object_set_single_byte (t, 64);
+  g_assert_cmpint (test_object_get_single_byte (t), ==, 64);
+
+  test_object_set_double_byte (t, G_MAXINT16 / 2);
+  g_assert_cmpint (test_object_get_double_byte (t), ==, G_MAXINT16 / 2);
+
+  test_object_set_four_bytes (t, 47);
+  g_assert_cmpint (test_object_get_four_bytes (t), ==, 47);
+
+  test_object_set_width (t, 640);
+  g_assert_cmpfloat (test_object_get_width (t), ==, 640.0f);
+
+  test_object_set_x_align (t, 1.0);
+  g_assert_cmpfloat (test_object_get_x_align (t), ==, 1.0);
+
+  g_object_unref (t);
+}
+
+static void
+autoproperties_validate (void)
+{
+  if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT|G_TEST_TRAP_SILENCE_STDERR))
+    {
+      TestObject *t = g_object_new (test_object_get_type (), NULL);
+      test_object_set_foo (t, 101);
+      g_object_unref (t);
+      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))
+    {
+      TestObject *t = g_object_new (test_object_get_type (), NULL);
+      test_object_set_foo (t, -10);
+      g_object_unref (t);
+      exit (0);
+    }
+  g_test_trap_assert_failed ();
+//  g_test_trap_assert_stderr ("**");
+}
+
+static void
+autoproperties_object_set (void)
+{
+  TestObject *t = g_object_new (test_object_get_type (), NULL);
+
+  g_object_set (t, "foo", 42, "bar", TRUE, NULL);
+
+  g_assert_cmpint (test_object_get_foo (t), ==, 42);
+  g_assert (test_object_get_bar (t));
+
+  g_object_unref (t);
+}
+
+static void
+autoproperties_object_get (void)
+{
+  TestObject *t = g_object_new (test_object_get_type (), NULL);
+  gdouble x_align;
+  gfloat width;
+
+  g_object_get (t, "x-align", &x_align, "width", &width, NULL);
+  g_assert_cmpfloat (x_align, ==, 0.5);
+  g_assert_cmpfloat (width, ==, 0);
+
+  g_object_unref (t);
+}
+
+int
+main (int argc, char *argv[])
+{
+  g_type_init ();
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_bug_base ("http://bugzilla.gnome.org/";);
+
+  g_test_add_func ("/auto-properties/base", autoproperties_base);
+  g_test_add_func ("/auto-properties/default", autoproperties_default);
+  g_test_add_func ("/auto-properties/accessors", autoproperties_accessors);
+  g_test_add_func ("/auto-properties/validate", autoproperties_validate);
+  g_test_add_func ("/auto-properties/object-set", autoproperties_object_set);
+  g_test_add_func ("/auto-properties/object-get", autoproperties_object_get);
+
+  return g_test_run ();
+}



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