[glib/g-property] gobject: Add GProperty
- From: Emmanuele Bassi <ebassi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/g-property] gobject: Add GProperty
- Date: Mon, 16 May 2011 18:23:58 +0000 (UTC)
commit 67664b85b7f072ac0acb73f49118698fa7bfd894
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 | 130 +-
gobject/gobject.symbols | 57 +
gobject/gproperty.c | 5121 +++++++++++++++++++++++++++++
gobject/gproperty.h | 655 ++++
gobject/gvaluecollector.h | 118 +
gobject/tests/.gitignore | 3 +
gobject/tests/Makefile.am | 15 +-
gobject/tests/autoproperties.c | 522 +++
gobject/tests/gproperty-example-base.c | 139 +
gobject/tests/gproperty-example-derived.c | 296 ++
12 files changed, 7018 insertions(+), 41 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..5b3f25f 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,8 +1206,18 @@ object_set_property (GObject *object,
}
else
{
- class->set_property (object, param_id, &tmp_value, pspec);
- g_object_notify_queue_add (object, nqueue, pspec);
+ if (G_IS_PROPERTY (pspec))
+ {
+ GProperty *prop = G_PROPERTY (pspec);
+
+ g_property_set_value (prop, object, &tmp_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 +1703,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 +1732,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, 0, 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 +1796,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 +1818,43 @@ 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;
+
+ /* we use G_PROPERTY_COLLECT_COPY and G_PROPERTY_COLLECT_REF to
+ * preserve the semantics of GValues holding a typed pointer
+ * value, like GObject, GBoxed and strings
+ */
+ G_PROPERTY_LCOPY (property, object,
+ G_PROPERTY_COLLECT_REF | G_PROPERTY_COLLECT_COPY,
+ 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/gobject.symbols b/gobject/gobject.symbols
index e4722be..9d60d6e 100644
--- a/gobject/gobject.symbols
+++ b/gobject/gobject.symbols
@@ -262,6 +262,63 @@ g_value_set_param_take_ownership
#endif
#endif
+#if IN_HEADER(__G_PROPERTY_H__)
+#if IN_FILE(__G_PROPERTY_C__)
+g_boolean_property_new
+g_boxed_property_new
+g_double_property_new
+g_flags_property_new
+g_float_property_new
+g_enum_property_new
+g_int16_property_new
+g_int32_property_new
+g_int64_property_new
+g_int8_property_new
+g_int_property_new
+g_long_property_new
+g_object_property_new
+g_property_canonicalize_name
+g_property_collect
+g_property_get
+g_property_get_default
+g_property_get_default_value
+g_property_get_default_value_for_type
+g_property_get_range
+g_property_get_range_values
+g_property_get_type
+g_property_get_valist
+g_property_get_value
+g_property_get_value_type
+g_property_is_atomic
+g_property_is_deprecated
+g_property_is_readable
+g_property_is_writable
+g_property_lcopy
+g_property_lock
+g_property_set
+g_property_set_default
+g_property_set_default_value
+g_property_set_lock_functions
+g_property_set_prerequisite
+g_property_set_range
+g_property_set_range_values
+g_property_set_static_blurb
+g_property_set_static_nick
+g_property_set_valist
+g_property_set_value
+g_property_unlock
+g_property_validate
+g_property_validate_value
+g_string_property_new
+g_uint16_property_new
+g_uint32_property_new
+g_uint64_property_new
+g_uint8_property_new
+g_uint_property_new
+g_ulong_property_new
+#endif
+#endif
+
#if IN_HEADER(__G_VALUETYPES_H__)
#if IN_FILE(__G_VALUETYPES_C__)
g_pointer_type_register_static
diff --git a/gobject/gproperty.c b/gobject/gproperty.c
new file mode 100644
index 0000000..7227b22
--- /dev/null
+++ b/gobject/gproperty.c
@@ -0,0 +1,5121 @@
+/* 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
+ *
+ * #GProperty is a type of #GParamSpec for defining properties for #GObject.
+ *
+ * The main difference between #GProperty and #GParamSpec is that #GProperty
+ * enforces a specific set of best practices for accessing values exposed
+ * and #GObject properties.
+ *
+ * #GProperty uses direct access to the fields in the instance private data
+ * structure whenever possible, and allows specifying accessor functions in
+ * cases where it is necessary.
+ *
+ * #GProperty is strongly typed, both at compilation time and at run time.
+ *
+ * Unlike #GParamSpec, there is a single public #GProperty class with various
+ * constructors; all public #GProperty methods operate depending on the type
+ * handled by the #GProperty.
+ *
+ * The #GParamSpec methods can be used with #GProperty transparently, to
+ * allow backward compatibility with existing code that introspects #GObject
+ * properties through the #GParamSpec API.
+ *
+ * <refsect2>
+ * <title>Using GProperty</title>
+ * <para>A typical example of #GProperty usage is:</para>
+ *
+ * |[
+ * /* the private data structure */
+ * struct _TestObjectPrivate {
+ * int x;
+ * int y;
+ * int width;
+ * int height;
+ * };
+ *
+ * /* identifiers for each property in the array */
+ * enum { PROP_0, PROP_X, PROP_Y, PROP_WIDTH, PROP_HEIGHT, LAST_PROP };
+ *
+ * /* an array of properties */
+ * static GParamSpec *test_object_properties[LAST_PROP] = { 0, };
+ *
+ * static void
+ * test_object_class_init (TestObjectClass *klass)
+ * {
+ * g_type_class_add_private (klass, sizeof (TestObjectPrivate));
+ *
+ * test_object_properties[PROP_X] =
+ * g_int_property_new ("x", G_PROPERTY_READWRITE,
+ * G_STRUCT_OFFSET (TestObjectPrivate, x),
+ * NULL,
+ * NULL);
+ *
+ * test_object_properties[PROP_Y] =
+ * g_int_property_new ("y", G_PROPERTY_READWRITE,
+ * G_STRUCT_OFFSET (TestObjectPrivate, y),
+ * NULL,
+ * NULL);
+ *
+ * test_object_properties[PROP_WIDTH] =
+ * g_int_property_new ("width", G_PROPERTY_READWRITE,
+ * G_STRUCT_OFFSET (TestObjectPrivate, width),
+ * NULL,
+ * NULL);
+ *
+ * test_object_properties[PROP_HEIGHT] =
+ * g_int_property_new ("height", G_PROPERTY_READWRITE,
+ * G_STRUCT_OFFSET (TestObjectPrivate, height),
+ * NULL,
+ * NULL);
+ *
+ * g_object_class_install_properties (G_OBJECT_CLASS (klass),
+ * G_N_ELEMENTS (test_object_properties),
+ * test_object_properties);
+ * }
+ * ]|
+ * <para>The main differences with the #GParamSpec creation and installation
+ * code are:</para>
+ *
+ * <itemizedlist>
+ * <listitem><para>the constructors take the same parameters</para></listitem>
+ * <listitem><para>there are not #GObject set_property and get_property
+ * virtual function assignments</para></listitem>
+ * <listitem><para>all properties use direct access of the member in the
+ * instance private data structure</para></listitem>
+ * </itemizedlist>
+ *
+ * <refsect3>
+ * <title>Setting and getting values</title>
+ * <para>Writing accessors for properties defined using #GProperties is
+ * a simple case of calling g_property_set() or g_property_get(), for
+ * instance the code below is the simplest form of setter and getter
+ * pair for the "x" property as defined above:</para>
+ * |[
+ * void
+ * test_object_set_x (TestObject *self,
+ * int x)
+ * {
+ * g_return_if_fail (TEST_IS_OBJECT (self));
+ *
+ * g_property_set (G_PROPERTY (test_object_properties[PROP_X]), self, x);
+ * }
+ *
+ * int
+ * test_object_get_x (TestObject *self)
+ * {
+ * int retval;
+ *
+ * g_return_val_if_fail (TEST_IS_OBJECT (self), 0);
+ *
+ * g_property_get (G_PROPERTY (test_object_properties[PROP_X]),
+ * self,
+ * &retval);
+ *
+ * return retval;
+ * }
+ * ]|
+ * </refsect3>
+ *
+ * <refsect3>
+ * <title>Ranges and validation</title>
+ * <para>For different property types it is possible to set a range of
+ * valid values; the setter function can then use g_property_validate()
+ * to check whether the new value is valid.</para>
+ *
+ * <para>The range is set using g_property_set_range():</para>
+ *
+ * |[
+ * test_object_properties[PROP_WIDTH] =
+ * g_int_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, /* minimum value */
+ * G_MAXINT /* maximum value */)
+ *
+ * test_object_properties[PROP_HEIGHT] =
+ * g_int_property_new ("height", G_PROPERTY_READWRITE,
+ * G_STRUCT_OFFSET (TestObjectPrivate, height),
+ * NULL, NULL);
+ * g_property_set_range (G_PROPERTY (test_object_properties[PROP_HEIGHT]),
+ * 0.0, /* minimum value */
+ * G_MAXINT /* maximum value */)
+ * ]|
+ *
+ * <para>The example above keeps the "width" and "height" properties as
+ * integers, but limits the range of valid values to [ 0, %G_MAXINT ].</para>
+ *
+ * <para>Validation is automatically performed when setting a property
+ * through g_object_set(); explicit setter methods can use g_property_validate()
+ * to perform the validation, e.g.:</para>
+ *
+ * |[
+ * void
+ * test_object_set_width (TestObject *self,
+ * int width)
+ * {
+ * GProperty *property;
+ *
+ * property = G_PROPERTY (test_object_properties[PROP_WIDTH]);
+ *
+ * g_return_if_fail (!g_property_validate (property, width));
+ *
+ * /* we deliberately do not use g_property_set() here because
+ * * g_property_set() will implicitly call g_property_validate()
+ * * prior to setting the property
+ * */
+ * if (self->priv->width == width)
+ * return;
+ *
+ * self->priv->width = width;
+ *
+ * g_object_notify_by_pspec (G_OBJECT (self), G_PARAM_SPEC (property));
+ *
+ * test_object_queue_foo (self);
+ * }
+ * ]|
+ * </refsect3>
+ *
+ * <refsect3>
+ * <title>Default values</title>
+ * <para>Default values are set using g_property_set_default(), e.g.:</para>
+ * |[
+ * test_object_properties[PROP_WIDTH] =
+ * g_int_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, /* minimum value */
+ * G_MAXINT /* maximum value */)
+ * g_property_set_default (G_PROPERTY (test_object_properties[PROP_WIDTH]),
+ * G_OBJECT_CLASS (klass),
+ * 1);
+ *
+ * test_object_properties[PROP_HEIGHT] =
+ * g_int_property_new ("height", G_PROPERTY_READWRITE,
+ * G_STRUCT_OFFSET (TestObjectPrivate, height),
+ * NULL, NULL);
+ * g_property_set_range (G_PROPERTY (test_object_properties[PROP_HEIGHT]),
+ * 0, /* minimum value */
+ * G_MAXINT /* maximum value */)
+ * g_property_set_default (G_PROPERTY (test_object_properties[PROP_HEIGHT]),
+ * G_OBJECT_CLASS (klass),
+ * 1);
+ * ]|
+ *
+ * <para>Sub-classes can use g_property_override_default(), or the convenience
+ * function g_object_class_override_property_default() to specify a different
+ * default value for a given property:</para>
+ *
+ * |[
+ * property = g_object_class_find_property (G_OBJECT_CLASS (klass), "width");
+ * g_property_override_default (G_PROPERTY (property),
+ * G_OBJECT_CLASS (klass),
+ * 200);
+ *
+ * /* - or - */
+ *
+ * g_object_class_override_property_default (G_OBJECT_CLASS (klass),
+ * "height",
+ * 200);
+ * ]|
+ *
+ * <para>The default value can be retrieved using g_property_get_default(),
+ * for instance during instance initialization:</para>
+ *
+ * |[
+ * static void
+ * test_object_init (TestObject *self)
+ * {
+ * self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TEST_TYPE_OBJECT,
+ * TestObjectPrivate);
+ *
+ * g_property_get_default (G_PROPERTY (test_object_properties[PROP_WIDTH]),
+ * self,
+ * &(self->priv->width));
+ * g_property_get_default (G_PROPERTY (test_object_properties[PROP_HEIGHT]),
+ * self,
+ * &(self->priv->height));
+ * }
+ * ]|
+ *
+ * <para>Or to return the default value when writing a getter:</para>
+ *
+ * |[
+ * int
+ * test_object_get_width (TestObject *self)
+ * {
+ * GProperty *property;
+ * int retval;
+ *
+ * property = G_PROPERTY (test_object_properties[PROP_WIDTH]);
+ *
+ * /* return the default width if self has not been foobarized */
+ * if (!self->priv->is_foobarized)
+ * g_property_get_default (property, self, &retval);
+ * else
+ * g_property_get (property, self, &retval);
+ *
+ * return retval;
+ * }
+ * ]|
+ *
+ * <para>The reason why the object instance is necessary when calling
+ * g_property_get_default() is to retrieve the correct default for the
+ * given instance type, in case sub-classes overridden the default value
+ * using g_property_override_default().</para>
+ * </refsect3>
+ *
+ * <refsect3>
+ * <title>Custom accessors</title>
+ * <para>For cases where the direct access to a structure field does not
+ * match the semantics of the property it is possible to pass a setter
+ * and a getter function when creating a #GProperty:</para>
+ *
+ * |[
+ * test_object_property[PROP_COMPLEX] =
+ * g_object_property_new ("complex", G_PROPERTY_READWRITE, -1,
+ * test_object_set_complex,
+ * test_object_get_complex);
+ * ]|
+ *
+ * <para>It is also possible to still pass the offset of the structure
+ * field, and provide either the setter or the getter function:</para>
+ *
+ * |[
+ * test_object_property[PROP_WIDTH] =
+ * g_int_property_new ("width", G_PROPERTY_READWRITE,
+ * G_STRUCT_OFFSET (TestObjectPrivate, width),
+ * test_object_set_width, /* explicit setter */
+ * NULL /* implicit getter */);
+ * ]|
+ *
+ * <para>Calling g_property_set() using the "width" property in the example
+ * above will result in calling test_object_set_width(); calling, instead,
+ * g_property_get() using the "width" property will result in accessing
+ * the width structure member.</para>
+ *
+ * <warning><para>You must not call g_property_set() inside the implementation
+ * of test_object_set_width(), in order to avoid loops.</para></warning>
+ * </refsect3>
+ *
+ * <refsect3>
+ * <title>Special flags</title>
+ * <para>#GProperty has its own set of flags to be passed to its
+ * constructor functions. Alongside the usual %G_PROPERTY_READABLE
+ * and %G_PROPERTY_WRITABLE, which control the access policy for
+ * setter and getter functions, there are the following flags:</para>
+ *
+ * <itemizedlist>
+ * <listitem><para>%G_PROPERTY_DEPRECATED, a flag for marking
+ * deprecated properties. If the G_ENABLE_DIAGNOSTIC environment
+ * variable is set, calling g_property_set() and g_property_get()
+ * on the deprecated properties will result in a run time warning
+ * printed on the console.</para></listitem>
+ * <listitem><para>%G_PROPERTY_ATOMIC, a flag for marking access
+ * to properties a threadsafe operation. It is possible to change
+ * the locking mechanism by using g_property_set_lock_functions()
+ * and replacing both the lock and the unlock function, which can
+ * then be called by g_property_lock() and g_property_unlock()
+ * when needed.</para></listitem>
+ * </itemizedlist>
+ * </refsect3>
+ * </refsect2>
+ *
+ * <refsect2>
+ * <title>Auto-generating setters and getters</title>
+ * <para>Similarly to the #G_DEFINE_TYPE macro for defining a new
+ * #GObject type, GObject also provides various macros for
+ * auto-generating the accessors pair of functions.</para>
+ * <para>The most simple way to define a setter and getter pair is
+ * to use the #G_DEFINE_PROPERTY_GET_SET macro. This macro generates
+ * a getter and a setter using the type name, the type of the
+ * property and the name of the property, for instance:</para>
+ *
+ * |[
+ * G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, int, x)
+ * G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, int, y)
+ * G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, int, width)
+ * G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, int, height)
+ * ]|
+ *
+ * <para>The generated accessor pairs will use the #GProperty API
+ * to validate and access the property value. It is also possible
+ * to separate the setter and getter generation by using the
+ * #G_DEFINE_PROPERTY_GET and #G_DEFINE_PROPERTY_SET macros.</para>
+ *
+ * <para>If either the setter or the getter functions require additional
+ * custom code to be added to the auto-generated one, it is possible to
+ * use the #G_DEFINE_PROPERTY_GET_WITH_CODE macro and its sibling, the
+ * #G_DEFINE_PROPERTY_SET_WITH_CODE macro, for instance:</para>
+ *
+ * |[
+ * G_DEFINE_PROPERTY_GET (TestObject, test_object, int, width)
+ * G_DEFINE_PROPERTY_SET_WITH_CODE (Test_object, test_object, int, width,
+ * test_object_queue_resize (self))
+ * ]|
+ *
+ * <para>The WITH_CODE variant of the setter will define the "self" and
+ * "value" variables for the instance and the new value respectively; the
+ * custom code will be executed only after the value has been set.
+ * For the WITH_CODE variant of the getter, the macro will define the
+ * "self" and "retval" variables for the instance and the returned value
+ * respectively; the custom code will be executed before retrieving the
+ * value of the property to be returned.</para>
+ * </refsect2>
+ *
+ * <example id="gproperty-example-base">
+ * <title>Base object class using GProperty</title>
+ * <para>The example below shows how to use #GProperty and the code
+ * generation macros to implement a simple base class called
+ * "TestFile".</para>
+ * <programlisting>
+ * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gobject/tests/gproperty-example-base.c">
+ * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
+ * </xi:include>
+ * </programlisting>
+ * </example>
+ *
+ * <example id="gproperty-example-derived">
+ * <title>Derived object class using GProperty</title>
+ * <para>The example below shows how to use #GProperty and the code
+ * generation macros to implement a simple base class called
+ * "TestFile" and a derived class called "TestFileMp3".</para>
+ * <programlisting>
+ * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gobject/tests/gproperty-example-derived.c">
+ * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
+ * </xi:include>
+ * </programlisting>
+ * </example>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "gproperty.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;
+};
+
+/* defines for the integer sub-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_INTEGER(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_for_type (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) \
+{ \
+ if (min_value > max_value) \
+ { \
+ g_critical (G_STRLOC ": Invalid range for " #g_t " property '%s'", \
+ G_PARAM_SPEC (property)->name); \
+ return; \
+ } \
+\
+ ((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 gboolean \
+g_##g_t##_property_set_value (GProperty *property, \
+ gpointer gobject, \
+ c_t value) \
+{ \
+ gboolean retval; \
+\
+ g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); \
+ g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE); \
+ g_return_val_if_fail (g_##g_t##_property_validate (property, value), FALSE); \
+ g_return_val_if_fail (g_property_is_writable (property), FALSE); \
+\
+ g_property_lock (property, gobject); \
+\
+ if (((G##G_t##Property *) property)->setter != NULL) \
+ { \
+ ((G##G_t##Property *) property)->setter (gobject, value); \
+\
+ retval = TRUE; \
+ } \
+ 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 FALSE; \
+ } \
+\
+ (* (c_t *) field_p) = value; \
+\
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property); \
+\
+ retval = TRUE; \
+ } \
+ else \
+ { \
+ g_critical (G_STRLOC ": No setter function or field offset specified " \
+ "for property '%s'", \
+ G_PARAM_SPEC (property)->name); \
+\
+ retval = FALSE; \
+ } \
+\
+ g_property_unlock (property, gobject); \
+\
+ return retval; \
+} \
+\
+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_INTEGER (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_INTEGER (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_INTEGER (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_INTEGER (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_INTEGER (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_INTEGER (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_INTEGER (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_INTEGER (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_INTEGER (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_INTEGER (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_INTEGER (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_INTEGER (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_INTEGER (ULong, ulong, gulong, G_TYPE_ULONG, 0, 0, G_MAXULONG)
+
+/*
+ * GEnum
+ */
+
+/* forward declaration */
+GType _g_enum_property_get_type (void);
+
+typedef struct {
+ GProperty parent;
+
+ GEnumClass *e_class;
+
+ GPropertyEnumSet setter;
+ GPropertyEnumGet getter;
+} GEnumProperty;
+
+static void
+property_enum_set_default (GParamSpec *pspec,
+ GValue *value)
+{
+ GProperty *property = G_PROPERTY (pspec);
+
+ if (property->is_installed)
+ g_property_get_default_value_for_type (property, property->class_gtype, value);
+}
+
+static gboolean
+property_enum_validate (GParamSpec *pspec,
+ GValue *value)
+{
+ GEnumProperty *property = (GEnumProperty *) pspec;
+ glong oval = value->data[0].v_long;
+
+ if (property->e_class == NULL ||
+ g_enum_get_value (property->e_class, value->data[0].v_long) == NULL)
+ property_enum_set_default (pspec, value);
+
+ return value->data[0].v_long != oval;
+}
+
+static void
+property_enum_finalize (GParamSpec *pspec)
+{
+ GEnumProperty *property = (GEnumProperty *) pspec;
+ GParamSpecClass *parent_class =
+ g_type_class_peek (g_type_parent (_g_enum_property_get_type ()));
+
+ if (property->e_class)
+ {
+ g_type_class_unref (property->e_class);
+ property->e_class = NULL;
+ }
+
+ parent_class->finalize (pspec);
+}
+
+static void
+property_enum_class_init (GParamSpecClass *klass)
+{
+ klass->value_type = G_TYPE_FLAGS;
+
+ klass->value_set_default = property_enum_set_default;
+ klass->value_validate = property_enum_validate;
+
+ klass->finalize = property_enum_finalize;
+}
+
+static void
+property_enum_init (GParamSpec *pspec)
+{
+}
+
+GType
+_g_enum_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_enum_class_init,
+ NULL, NULL,
+ sizeof (GEnumProperty),
+ 0,
+ (GInstanceInitFunc) property_enum_init,
+ };
+
+ GType pspec_type_id =
+ g_type_register_static (G_TYPE_PROPERTY,
+ g_intern_static_string ("GEnumProperty"),
+ &info, 0);
+
+ g_once_init_leave (&pspec_type_id__volatile, pspec_type_id);
+ }
+
+ return pspec_type_id__volatile;
+}
+
+/**
+ * g_enum_property_new:
+ * @name: canonical name of the property
+ * @enum: enum 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 enumeration type registered
+ * as a sub-type of %G_TYPE_ENUM.
+ *
+ * You should use g_property_set_prerequisite() to set the type
+ * of the enumeration for validation; if the pre-requisite is unset,
+ * setting or getting this property will result in a warning.
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+GParamSpec *
+g_enum_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize offset,
+ GPropertyEnumSet setter,
+ GPropertyEnumGet getter)
+{
+ GProperty *prop;
+ GEnumProperty *internal;
+
+ prop = g_param_spec_internal (_g_enum_property_get_type (),
+ name, NULL, NULL,
+ property_flags_to_param_flags (flags));
+
+ prop->flags = flags;
+ prop->gtype = G_TYPE_ENUM;
+ prop->prerequisite = G_TYPE_INVALID;
+ prop->class_gtype = G_TYPE_INVALID;
+
+ prop->field_offset = offset;
+
+ prop->is_installed = FALSE;
+
+ prop->type_size = sizeof (gulong);
+
+ internal = (GEnumProperty *) prop;
+ internal->setter = setter;
+ internal->getter = getter;
+
+ return G_PARAM_SPEC (prop);
+}
+
+static gboolean
+g_enum_property_validate (GProperty *property,
+ gulong value)
+{
+ GEnumProperty *e_prop = (GEnumProperty *) property;
+
+ if (e_prop->e_class != NULL)
+ {
+ if (g_enum_get_value (e_prop->e_class, value) != NULL)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+g_enum_property_set_value (GProperty *property,
+ gpointer gobject,
+ gulong value)
+{
+ gboolean retval = FALSE;
+
+ g_property_lock (property, gobject);
+
+ if (((GEnumProperty *) property)->setter != NULL)
+ {
+ ((GEnumProperty *) property)->setter (gobject, value);
+
+ retval = TRUE;
+ }
+ 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 ((* (gulong *) field_p) == value)
+ {
+ g_property_unlock (property, gobject);
+ return FALSE;
+ }
+
+ (* (gulong *) field_p) = value;
+
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+
+ retval = TRUE;
+ }
+ else
+ g_critical (G_STRLOC ": No setter function or field offset specified "
+ "for property '%s'",
+ G_PARAM_SPEC (property)->name);
+
+ g_property_unlock (property, gobject);
+
+ return retval;
+}
+
+static gulong
+g_enum_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ if (((GEnumProperty *) property)->getter != NULL)
+ {
+ return ((GEnumProperty *) 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 (* (gulong *) field_p);
+ }
+ else
+ {
+ g_critical (G_STRLOC ": No getter function or field offset specified "
+ "for property '%s'",
+ G_PARAM_SPEC (property)->name);
+ return 0.0;
+ }
+}
+
+/*
+ * GFlags
+ */
+
+/* forward declaration */
+GType _g_flags_property_get_type (void);
+
+typedef struct {
+ GProperty parent;
+
+ GFlagsClass *f_class;
+
+ GPropertyFlagsSet setter;
+ GPropertyFlagsGet getter;
+} GFlagsProperty;
+
+static void
+property_flags_set_default (GParamSpec *pspec,
+ GValue *value)
+{
+ GProperty *property = G_PROPERTY (pspec);
+
+ if (property->is_installed)
+ g_property_get_default_value_for_type (property, property->class_gtype, value);
+}
+
+static gboolean
+property_flags_validate (GParamSpec *pspec,
+ GValue *value)
+{
+ GFlagsProperty *property = (GFlagsProperty *) pspec;
+ gulong oval = value->data[0].v_ulong;
+
+ if (property->f_class != NULL)
+ value->data[0].v_ulong &= property->f_class->mask;
+ else
+ property_flags_set_default (pspec, value);
+
+ return value->data[0].v_ulong != oval;
+}
+
+static void
+property_flags_finalize (GParamSpec *pspec)
+{
+ GFlagsProperty *property = (GFlagsProperty *) pspec;
+ GParamSpecClass *parent_class =
+ g_type_class_peek (g_type_parent (_g_flags_property_get_type ()));
+
+ if (property->f_class)
+ {
+ g_type_class_unref (property->f_class);
+ property->f_class = NULL;
+ }
+
+ parent_class->finalize (pspec);
+}
+
+static void
+property_flags_class_init (GParamSpecClass *klass)
+{
+ klass->value_type = G_TYPE_FLAGS;
+
+ klass->value_set_default = property_flags_set_default;
+ klass->value_validate = property_flags_validate;
+
+ klass->finalize = property_flags_finalize;
+}
+
+static void
+property_flags_init (GParamSpec *pspec)
+{
+}
+
+GType
+_g_flags_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_flags_class_init,
+ NULL, NULL,
+ sizeof (GFlagsProperty),
+ 0,
+ (GInstanceInitFunc) property_flags_init,
+ };
+
+ GType pspec_type_id =
+ g_type_register_static (G_TYPE_PROPERTY,
+ g_intern_static_string ("GFlagsProperty"),
+ &info, 0);
+
+ g_once_init_leave (&pspec_type_id__volatile, pspec_type_id);
+ }
+
+ return pspec_type_id__volatile;
+}
+
+/**
+ * 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
+ * @getter: (allow-none): the getter function for the property
+ *
+ * Creates a new #GProperty mapping to a flag type registered
+ * as a sub-type of %G_TYPE_FLAGS.
+ *
+ * You should use g_property_set_prerequisite() to set the type
+ * of the flags for validation; if the pre-requisite is unset,
+ * setting or getting this property will result in a warning.
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+GParamSpec *
+g_flags_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize offset,
+ GPropertyFlagsSet setter,
+ GPropertyFlagsGet getter)
+{
+ GProperty *prop;
+ GFlagsProperty *internal;
+
+ prop = g_param_spec_internal (_g_flags_property_get_type (),
+ name, NULL, NULL,
+ property_flags_to_param_flags (flags));
+
+ prop->flags = flags;
+ prop->gtype = G_TYPE_FLAGS;
+ prop->prerequisite = G_TYPE_INVALID;
+ prop->class_gtype = G_TYPE_INVALID;
+
+ prop->field_offset = offset;
+
+ prop->is_installed = FALSE;
+
+ prop->type_size = sizeof (gulong);
+
+ internal = (GFlagsProperty *) prop;
+ internal->setter = setter;
+ internal->getter = getter;
+
+ return G_PARAM_SPEC (prop);
+}
+
+static gboolean
+g_flags_property_validate (GProperty *property,
+ gulong value)
+{
+ GFlagsProperty *f_prop = (GFlagsProperty *) property;
+
+ if (f_prop->f_class != NULL)
+ {
+ gulong masked_value = value;
+
+ masked_value &= f_prop->f_class->mask;
+
+ return masked_value == value;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+g_flags_property_set_value (GProperty *property,
+ gpointer gobject,
+ gulong value)
+{
+ gboolean retval = FALSE;
+
+ g_property_lock (property, gobject);
+
+ if (((GFlagsProperty *) property)->setter != NULL)
+ {
+ ((GFlagsProperty *) property)->setter (gobject, value);
+
+ retval = TRUE;
+ }
+ 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 ((* (gulong *) field_p) == value)
+ {
+ g_property_unlock (property, gobject);
+ return FALSE;
+ }
+
+ (* (gulong *) field_p) = value;
+
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+
+ retval = TRUE;
+ }
+ else
+ g_critical (G_STRLOC ": No setter function or field offset specified "
+ "for property '%s'",
+ G_PARAM_SPEC (property)->name);
+
+ g_property_unlock (property, gobject);
+
+ return retval;
+}
+
+static gulong
+g_flags_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ if (((GFlagsProperty *) property)->getter != NULL)
+ {
+ return ((GFlagsProperty *) 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 (* (gulong *) field_p);
+ }
+ else
+ {
+ g_critical (G_STRLOC ": No getter function or field offset specified "
+ "for property '%s'",
+ G_PARAM_SPEC (property)->name);
+ return 0.0;
+ }
+}
+
+/*
+ * GFloat
+ */
+
+#define G_FLOAT_EPSILON (1e-30)
+
+/* forward declaration */
+GType _g_float_property_get_type (void);
+
+typedef struct {
+ GProperty parent;
+
+ gfloat min_value;
+ gfloat max_value;
+ gfloat epsilon;
+
+ GPropertyFloatSet setter;
+ GPropertyFloatGet getter;
+} GFloatProperty;
+
+static void
+property_float_set_default (GParamSpec *pspec,
+ GValue *value)
+{
+ GProperty *property = G_PROPERTY (pspec);
+
+ if (property->is_installed)
+ g_property_get_default_value_for_type (property, property->class_gtype, value);
+}
+
+static gboolean
+property_float_validate (GParamSpec *pspec,
+ GValue *value)
+{
+ GFloatProperty *property = (GFloatProperty *) pspec;
+ gfloat oval = value->data[0].v_float;
+
+ value->data[0].v_float = CLAMP (value->data[0].v_float,
+ property->min_value,
+ property->max_value);
+
+ return value->data[0].v_float != oval;
+}
+
+static gint
+property_float_values_cmp (GParamSpec *pspec,
+ const GValue *value1,
+ const GValue *value2)
+{
+ gfloat epsilon = ((GFloatProperty *) pspec)->epsilon;
+
+ if (value1->data[0].v_float < value2->data[0].v_float)
+ return - (value2->data[0].v_float - value1->data[0].v_float > epsilon);
+ else
+ return value1->data[0].v_float - value2->data[0].v_float > epsilon;
+}
+
+static void
+property_float_class_init (GParamSpecClass *klass)
+{
+ klass->value_type = G_TYPE_FLOAT;
+
+ klass->value_set_default = property_float_set_default;
+ klass->value_validate = property_float_validate;
+ klass->values_cmp = property_float_values_cmp;
+}
+
+static void
+property_float_init (GParamSpec *pspec)
+{
+ GFloatProperty *property = (GFloatProperty *) pspec;
+
+ property->min_value = G_MINFLOAT;
+ property->max_value = G_MAXFLOAT;
+ property->epsilon = G_FLOAT_EPSILON;
+}
+
+GType
+_g_float_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_float_class_init,
+ NULL, NULL,
+ sizeof (GFloatProperty),
+ 0,
+ (GInstanceInitFunc) property_float_init,
+ };
+
+ GType pspec_type_id =
+ g_type_register_static (G_TYPE_PROPERTY,
+ g_intern_static_string ("GFloatProperty"),
+ &info, 0);
+
+ g_once_init_leave (&pspec_type_id__volatile, pspec_type_id);
+ }
+
+ return pspec_type_id__volatile;
+}
+
+/**
+ * g_float_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 single precision floating
+ * point value.
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+GParamSpec *
+g_float_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize offset,
+ GPropertyFloatSet setter,
+ GPropertyFloatGet getter)
+{
+ GProperty *prop;
+ GFloatProperty *internal;
+
+ prop = g_param_spec_internal (_g_float_property_get_type (),
+ name, NULL, NULL,
+ property_flags_to_param_flags (flags));
+
+ prop->flags = flags;
+ prop->gtype = G_TYPE_FLOAT;
+ prop->prerequisite = G_TYPE_INVALID;
+ prop->class_gtype = G_TYPE_INVALID;
+
+ prop->field_offset = offset;
+
+ prop->is_installed = FALSE;
+
+ prop->type_size = sizeof (gfloat);
+
+ internal = (GFloatProperty *) prop;
+ internal->setter = setter;
+ internal->getter = getter;
+
+ return G_PARAM_SPEC (prop);
+}
+
+static void
+g_float_property_set_range (GProperty *property,
+ gfloat min_value,
+ gfloat max_value)
+{
+ ((GFloatProperty *) property)->min_value = min_value;
+ ((GFloatProperty *) property)->max_value = max_value;
+}
+
+static void
+g_float_property_get_range (GProperty *property,
+ gfloat *min_value,
+ gfloat *max_value)
+{
+ *min_value = ((GFloatProperty *) property)->min_value;
+ *max_value = ((GFloatProperty *) property)->max_value;
+}
+
+static gboolean
+g_float_property_validate (GProperty *property,
+ gfloat value)
+{
+ GFloatProperty *internal = (GFloatProperty *) property;
+
+ if (value >= internal->min_value &&
+ value <= internal->max_value)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_float_property_set_value (GProperty *property,
+ gpointer gobject,
+ gfloat value)
+{
+ gboolean retval = FALSE;
+
+ g_property_lock (property, gobject);
+
+ if (((GFloatProperty *) property)->setter != NULL)
+ {
+ ((GFloatProperty *) property)->setter (gobject, value);
+
+ retval = TRUE;
+ }
+ 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 ((* (gfloat *) field_p) == value)
+ {
+ g_property_unlock (property, gobject);
+ return FALSE;
+ }
+
+ (* (gfloat *) field_p) = value;
+
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+
+ retval = TRUE;
+ }
+ else
+ g_critical (G_STRLOC ": No setter function or field offset specified "
+ "for property '%s'",
+ G_PARAM_SPEC (property)->name);
+
+ g_property_unlock (property, gobject);
+
+ return retval;
+}
+
+static gfloat
+g_float_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ if (((GFloatProperty *) property)->getter != NULL)
+ {
+ return ((GFloatProperty *) 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 (* (gfloat *) field_p);
+ }
+ else
+ {
+ g_critical (G_STRLOC ": No getter function or field offset specified "
+ "for property '%s'",
+ G_PARAM_SPEC (property)->name);
+ return 0.0;
+ }
+}
+
+/*
+ * GDouble
+ */
+
+#define G_DOUBLE_EPSILON (1e-90)
+
+/* forward declaration */
+GType _g_double_property_get_type (void);
+
+typedef struct {
+ GProperty parent;
+
+ gdouble min_value;
+ gdouble max_value;
+ gdouble epsilon;
+
+ GPropertyDoubleSet setter;
+ GPropertyDoubleGet getter;
+} GDoubleProperty;
+
+static void
+property_double_set_default (GParamSpec *pspec,
+ GValue *value)
+{
+ GProperty *property = G_PROPERTY (pspec);
+
+ if (property->is_installed)
+ g_property_get_default_value_for_type (property, property->class_gtype, value);
+}
+
+static gboolean
+property_double_validate (GParamSpec *pspec,
+ GValue *value)
+{
+ GDoubleProperty *property = (GDoubleProperty *) pspec;
+ gdouble oval = value->data[0].v_double;
+
+ value->data[0].v_double = CLAMP (value->data[0].v_double,
+ property->min_value,
+ property->max_value);
+
+ return value->data[0].v_double != oval;
+}
+
+static gint
+property_double_values_cmp (GParamSpec *pspec,
+ const GValue *value1,
+ const GValue *value2)
+{
+ gdouble epsilon = ((GDoubleProperty *) pspec)->epsilon;
+
+ if (value1->data[0].v_double < value2->data[0].v_double)
+ return - (value2->data[0].v_double - value1->data[0].v_double > epsilon);
+ else
+ return value1->data[0].v_double - value2->data[0].v_double > epsilon;
+}
+
+static void
+property_double_class_init (GParamSpecClass *klass)
+{
+ klass->value_type = G_TYPE_DOUBLE;
+
+ klass->value_set_default = property_double_set_default;
+ klass->value_validate = property_double_validate;
+ klass->values_cmp = property_double_values_cmp;
+}
+
+static void
+property_double_init (GParamSpec *pspec)
+{
+ GDoubleProperty *property = (GDoubleProperty *) pspec;
+
+ property->min_value = G_MINDOUBLE;
+ property->max_value = G_MAXDOUBLE;
+ property->epsilon = G_DOUBLE_EPSILON;
+}
+
+GType
+_g_double_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_double_class_init,
+ NULL, NULL,
+ sizeof (GDoubleProperty),
+ 0,
+ (GInstanceInitFunc) property_double_init,
+ };
+
+ GType pspec_type_id =
+ g_type_register_static (G_TYPE_PROPERTY,
+ g_intern_static_string ("GDoubleProperty"),
+ &info, 0);
+
+ g_once_init_leave (&pspec_type_id__volatile, pspec_type_id);
+ }
+
+ return pspec_type_id__volatile;
+}
+
+/**
+ * g_double_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 double precision floating
+ * point value.
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.32
+ */
+GParamSpec *
+g_double_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize offset,
+ GPropertyDoubleSet setter,
+ GPropertyDoubleGet getter)
+{
+ GProperty *prop;
+ GDoubleProperty *internal;
+
+ prop = g_param_spec_internal (_g_double_property_get_type (),
+ name, NULL, NULL,
+ property_flags_to_param_flags (flags));
+
+ prop->flags = flags;
+ prop->gtype = G_TYPE_DOUBLE;
+ prop->prerequisite = G_TYPE_INVALID;
+ prop->class_gtype = G_TYPE_INVALID;
+
+ prop->field_offset = offset;
+
+ prop->is_installed = FALSE;
+
+ prop->type_size = sizeof (gdouble);
+
+ internal = (GDoubleProperty *) prop;
+ internal->setter = setter;
+ internal->getter = getter;
+
+ return G_PARAM_SPEC (prop);
+}
+
+static void
+g_double_property_set_range (GProperty *property,
+ gdouble min_value,
+ gdouble max_value)
+{
+ ((GDoubleProperty *) property)->min_value = min_value;
+ ((GDoubleProperty *) property)->max_value = max_value;
+}
+
+static void
+g_double_property_get_range (GProperty *property,
+ gdouble *min_value,
+ gdouble *max_value)
+{
+ *min_value = ((GDoubleProperty *) property)->min_value;
+ *max_value = ((GDoubleProperty *) property)->max_value;
+}
+
+static gboolean
+g_double_property_validate (GProperty *property,
+ gdouble value)
+{
+ GDoubleProperty *internal = (GDoubleProperty *) property;
+
+ if (value >= internal->min_value &&
+ value <= internal->max_value)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+g_double_property_set_value (GProperty *property,
+ gpointer gobject,
+ gdouble value)
+{
+ gboolean retval = FALSE;
+
+ g_property_lock (property, gobject);
+
+ if (((GDoubleProperty *) property)->setter != NULL)
+ {
+ ((GDoubleProperty *) property)->setter (gobject, value);
+
+ retval = TRUE;
+ }
+ 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 ((* (gdouble *) field_p) == value)
+ {
+ g_property_unlock (property, gobject);
+ return FALSE;
+ }
+
+ (* (gdouble *) field_p) = value;
+
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+
+ retval = TRUE;
+ }
+ else
+ g_critical (G_STRLOC ": No setter function or field offset specified "
+ "for property '%s'",
+ G_PARAM_SPEC (property)->name);
+
+ g_property_unlock (property, gobject);
+
+ return retval;
+}
+
+static gdouble
+g_double_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ if (((GDoubleProperty *) property)->getter != NULL)
+ {
+ return ((GDoubleProperty *) 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 (* (gdouble *) field_p);
+ }
+ else
+ {
+ g_critical (G_STRLOC ": No getter function or field offset specified "
+ "for property '%s'",
+ G_PARAM_SPEC (property)->name);
+ return 0.0;
+ }
+}
+
+/*
+ * GString
+ */
+
+/* forward declaration */
+GType _g_string_property_get_type (void);
+
+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 gboolean
+g_string_property_set_value (GProperty *property,
+ gpointer gobject,
+ const gchar *value)
+{
+ gboolean retval = FALSE;
+
+ g_property_lock (property, gobject);
+
+ if (((GStringProperty *) property)->setter != NULL)
+ {
+ ((GStringProperty *) property)->setter (gobject, value);
+
+ retval = TRUE;
+ }
+ 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 FALSE;
+ }
+
+ g_free (str);
+ (* (gpointer *) field_p) = g_strdup (value);
+
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+
+ retval = TRUE;
+ }
+ else
+ g_critical (G_STRLOC ": No setter function or field offset specified "
+ "for property '%s'",
+ G_PARAM_SPEC (property)->name);
+
+ g_property_unlock (property, gobject);
+
+ return retval;
+}
+
+static const gchar *
+g_string_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ 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;
+ }
+}
+
+/*
+ * GBoxed
+ */
+
+/* forward declaration */
+GType _g_boxed_property_get_type (void);
+
+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 gboolean
+g_boxed_property_set_value (GProperty *property,
+ gpointer gobject,
+ gconstpointer value)
+{
+ gboolean retval = FALSE;
+
+ g_property_lock (property, gobject);
+
+ if (((GBoxedProperty *) property)->setter != NULL)
+ {
+ ((GBoxedProperty *) property)->setter (gobject, value);
+
+ retval = TRUE;
+ }
+ 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 FALSE;
+ }
+
+ if ((* (gpointer *) field_p) != NULL)
+ g_boxed_free (property->prerequisite, (* (gpointer *) field_p));
+
+ if (value != NULL)
+ (* (gpointer *) field_p) = g_boxed_copy (property->prerequisite, value);
+ else
+ (* (gpointer *) field_p) = NULL;
+
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+
+ retval = TRUE;
+ }
+ else
+ g_critical (G_STRLOC ": No setter function or field offset specified "
+ "for property '%s'",
+ G_PARAM_SPEC (property)->name);
+
+ g_property_unlock (property, gobject);
+
+ return retval;
+}
+
+static gconstpointer
+g_boxed_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ 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;
+ }
+}
+
+/*
+ * GObject
+ */
+
+/* forward declaration */
+GType _g_object_property_get_type (void);
+
+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 gboolean
+g_object_property_set_value (GProperty *property,
+ gpointer gobject,
+ gpointer value)
+{
+ gboolean retval = FALSE;
+
+ g_property_lock (property, gobject);
+
+ if (((GObjectProperty *) property)->setter != NULL)
+ {
+ ((GObjectProperty *) property)->setter (gobject, value);
+
+ retval = TRUE;
+ }
+ else if (property->field_offset >= 0)
+ {
+ gpointer priv_p, field_p;
+ gpointer obj;
+
+ g_return_val_if_fail (value == NULL || G_IS_OBJECT (value), FALSE);
+
+ priv_p = get_private_pointer (gobject, property->priv_offset);
+ field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
+
+ if ((* (gpointer *) field_p) == value)
+ {
+ g_property_unlock (property, gobject);
+ return FALSE;
+ }
+
+ obj = (* (gpointer *) field_p);
+ if (obj != NULL)
+ g_object_unref (obj);
+
+ (* (gpointer *) field_p) = obj = value;
+
+ if (obj != NULL)
+ {
+ if (G_IS_INITIALLY_UNOWNED (obj))
+ g_object_ref_sink (obj);
+ else
+ g_object_ref (obj);
+ }
+
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+
+ retval = TRUE;
+ }
+ else
+ g_critical (G_STRLOC ": No setter function or field offset specified "
+ "for property '%s'",
+ G_PARAM_SPEC (property)->name);
+
+ g_property_unlock (property, gobject);
+
+ return retval;
+}
+
+static gpointer
+g_object_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ 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;
+ }
+}
+
+/*
+ * GProperty common API
+ */
+
+/*< 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)
+ {
+ gboolean is_interface = G_TYPE_IS_INTERFACE (class_gtype);
+ GTypeQuery query = { 0, };
+
+ if (is_interface)
+ {
+ g_critical (G_STRLOC ": The property '%s' has a field offset value "
+ "but it is being installed on an interface of type '%s'. "
+ "Properties installed on interfaces cannot have direct "
+ "access to a structure field.",
+ G_PARAM_SPEC (property)->name,
+ g_type_name (class_gtype));
+ return;
+ }
+
+ 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.
+ *
+ * in modern GObject/C it's usually a fair assumption to make, but it
+ * could lead to interesting segmentation faults if we try to access
+ * the private structure field later on.
+ *
+ * for non-common structure layouts we still offer the ability to define
+ * the accessors functions anyway.
+ */
+ if (query.instance_size >= (sizeof (GObject) + 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:
+ * @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_name (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:
+ property->prerequisite = gtype;
+ break;
+
+ case G_TYPE_ENUM:
+ property->prerequisite = gtype;
+ ((GEnumProperty *) property)->e_class = g_type_class_ref (gtype);
+ break;
+
+ case G_TYPE_FLAGS:
+ property->prerequisite = gtype;
+ ((GFlagsProperty *) property)->f_class = g_type_class_ref (gtype);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * g_property_set_range_values:
+ * @property: a #GProperty
+ * @min_value: a #GValue with the minimum value of the range
+ * @max_value: a #GValue with the maximum value of the range
+ *
+ * FIXME
+ *
+ * Since: 2.32
+ */
+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;
+ }
+}
+
+/**
+ * g_property_get_range_values:
+ * @property: a #GProperty
+ * @min_value: a valid #GValue, initialized to the type of @property
+ * @max_value: a valid #GValue, initialized to the type of @property
+ *
+ * Retrieves the bounds of the range of valid values for @property
+ * and stores them into @min_value and @max_value.
+ *
+ * Return value: %TRUE if successful, and %FALSE otherwise
+ *
+ * Since: 2.32
+ */
+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 (max_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 (max_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;
+}
+
+/**
+ * g_property_set_range:
+ * @property: a #GProperty
+ * @...: the minimum and maximum values of the range
+ *
+ * Sets the range of valid values for @property.
+ *
+ * Since: 2.32
+ */
+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);
+}
+
+/**
+ * g_property_get_range:
+ * @property: a #GProperty
+ * @...: the return locations for the minimum and maximum values
+ * of the range
+ *
+ * Retrieves the bounds of the range of valid values for @property.
+ *
+ * Return value: %TRUE on success, and %FALSE otherwise
+ *
+ * Since: 2.32
+ */
+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;
+}
+
+/**
+ * g_property_set_default_value:
+ * @property: a #GProperty
+ * @gobject_class: a #GObject class pointer
+ * @default_value: a #GValue, initialized to the property type
+ * containing the default value for the given class
+ *
+ * Sets the default value of @property for the given class.
+ *
+ * This function is a #GValue variant of g_property_set_default(), and
+ * it is meant to be used by language bindings.
+ *
+ * Since: 2.32
+ */
+void
+g_property_set_default_value (GProperty *property,
+ gpointer gobject_class,
+ const GValue *default_value)
+{
+ const gchar *gtype_name;
+ GValue *value;
+ GType gtype;
+
+ g_return_if_fail (G_IS_PROPERTY (property));
+ g_return_if_fail (G_IS_OBJECT_CLASS (gobject_class));
+ g_return_if_fail (property->gtype != G_TYPE_INVALID);
+ g_return_if_fail (default_value != NULL);
+
+ if (property->prerequisite != G_TYPE_INVALID)
+ gtype = property->prerequisite;
+ else
+ gtype = property->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 (G_TYPE_FROM_CLASS (gobject_class));
+ 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);
+}
+
+/**
+ * g_property_get_default_value_for_type:
+ * @property: a #GProperty
+ * @gtype: a valid #GType
+ * @value: a #GValue initialized to the property type
+ *
+ * Retrieves the default value of the property for the given type.
+ *
+ * This function is meant to be used by language bindings and other
+ * introspection tools; #GObject implementations should use
+ * g_property_get_default() instead.
+ *
+ * Since: 2.32
+ */
+void
+g_property_get_default_value_for_type (GProperty *property,
+ GType 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 (gtype) != 0);
+
+ 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)
+ {
+ if (!g_value_transform (default_value, value))
+ {
+ g_critical (G_STRLOC ": Unable to copy the default value "
+ "of property '%s' from type '%s' to type '%s'",
+ G_PARAM_SPEC (property)->name,
+ g_type_name (property->gtype),
+ g_type_name (G_VALUE_TYPE (value)));
+ }
+ }
+ }
+}
+
+/**
+ * g_property_get_default_value:
+ * @property: a #GProperty
+ * @gobject: a #GObject
+ * @value: a #GValue initialized to the type of the property
+ *
+ * Retrieves the default value of @property for the given @gobject
+ * type.
+ *
+ * This function should only be used by language bindings and other
+ * introspection tools.
+ *
+ * Since: 2.32
+ */
+void
+g_property_get_default_value (GProperty *property,
+ gpointer gobject,
+ GValue *value)
+{
+ g_return_if_fail (G_IS_OBJECT (gobject));
+
+ g_property_get_default_value_for_type (property,
+ G_OBJECT_TYPE (gobject),
+ value);
+}
+
+/**
+ * g_property_set_default:
+ * @property: a #GProperty
+ * @gobject_class: a pointer to a #GObject class
+ * @...: the default value for the property
+ *
+ * Sets the default value of @property for the given @gobject_class.
+ *
+ * This function can only be called once for each @gobject_class.
+ *
+ * See also g_object_class_override_property_default().
+ *
+ * Since: 2.32
+ */
+void
+g_property_set_default (GProperty *property,
+ gpointer gobject_class,
+ ...)
+{
+ GValue value = { 0, };
+ GType p_type;
+ gchar *error;
+ va_list var_args;
+
+ g_return_if_fail (G_IS_PROPERTY (property));
+ g_return_if_fail (G_IS_OBJECT_CLASS (gobject_class));
+ 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, gobject_class);
+
+ 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, gobject_class, &value);
+
+ va_end (var_args);
+ g_value_unset (&value);
+}
+
+/**
+ * g_property_get_default:
+ * @property: a #GProperty
+ * @gobject: a #GObject instance
+ * @...: the return location for the default value
+ *
+ * Retrieves the default value of @property for the type of the
+ * instance passed.
+ *
+ * Since: 2.32
+ */
+void
+g_property_get_default (GProperty *property,
+ gpointer gobject,
+ ...)
+{
+ GValue value = { 0, };
+ GType p_type;
+ gchar *error;
+ va_list var_args;
+
+ g_return_if_fail (G_IS_PROPERTY (property));
+ g_return_if_fail (G_IS_OBJECT (gobject));
+ g_return_if_fail (property->gtype != G_TYPE_INVALID);
+
+ 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)
+ {
+ GType gtype = G_OBJECT_TYPE (gobject);
+ GValue *default_value = NULL;
+
+ /* we need to recurse through the inheritance chain... */
+ while (gtype != G_TYPE_INVALID && default_value == NULL)
+ {
+ default_value = g_hash_table_lookup (property->default_values,
+ g_type_name (gtype));
+
+ gtype = g_type_parent (gtype);
+ }
+
+ /* ... and eventually check the implemented interfaces */
+ if (default_value == NULL)
+ {
+ GType *ifaces;
+ guint n_ifaces;
+
+ gtype = G_OBJECT_TYPE (gobject);
+
+ ifaces = g_type_interfaces (gtype, &n_ifaces);
+ while (n_ifaces-- && default_value == NULL)
+ {
+ default_value = g_hash_table_lookup (property->default_values,
+ g_type_name (ifaces[n_ifaces]));
+ }
+
+ g_free (ifaces);
+ }
+
+ if (default_value == NULL)
+ {
+ g_critical (G_STRLOC ": No default value of property '%s' "
+ "was found for type '%s'",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ }
+ else
+ g_value_copy (default_value, &value);
+ }
+
+
+ va_start (var_args, gobject);
+
+ 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);
+}
+
+/**
+ * g_property_set_valist:
+ * @property: a #GProperty
+ * @gobject: a #GObject instance
+ * @args: the value to set, inside a va_list
+ *
+ * Sets the value of @property for the given #GObject instance.
+ *
+ * This function is the va_list variant of g_property_set().
+ *
+ * Return value: %TRUE if the value was set, and %FALSE otherwise
+ *
+ * Since: 2.32
+ */
+gboolean
+g_property_set_valist (GProperty *property,
+ gpointer gobject,
+ va_list args)
+{
+ gboolean retval;
+ GType gtype;
+
+ g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+ g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
+ g_return_val_if_fail (property->is_installed, FALSE);
+
+ if (property->prerequisite != G_TYPE_INVALID)
+ gtype = property->prerequisite;
+ else
+ gtype = property->gtype;
+
+ switch (G_TYPE_FUNDAMENTAL (gtype))
+ {
+ case G_TYPE_BOOLEAN:
+ retval = g_boolean_property_set_value (property, gobject, va_arg (args, gboolean));
+ break;
+
+ case G_TYPE_INT:
+ switch (property->type_size)
+ {
+ case 1:
+ retval = g_int8_property_set_value (property, gobject, va_arg (args, gint));
+ break;
+
+ case 2:
+ retval = g_int16_property_set_value (property, gobject, va_arg (args, gint));
+ break;
+
+ case 4:
+ retval = g_int32_property_set_value (property, gobject, va_arg (args, gint));
+ break;
+
+ default:
+ retval = g_int_property_set_value (property, gobject, va_arg (args, gint));
+ break;
+ }
+ break;
+
+ case G_TYPE_INT64:
+ retval = g_int64_property_set_value (property, gobject, va_arg (args, gint64));
+ break;
+
+ case G_TYPE_LONG:
+ retval = g_long_property_set_value (property, gobject, va_arg (args, glong));
+ break;
+
+ case G_TYPE_UINT:
+ switch (property->type_size)
+ {
+ case 1:
+ retval = g_uint8_property_set_value (property, gobject, va_arg (args, guint));
+ break;
+
+ case 2:
+ retval = g_uint16_property_set_value (property, gobject, va_arg (args, guint));
+ break;
+
+ case 4:
+ retval = g_uint32_property_set_value (property, gobject, va_arg (args, guint));
+ break;
+
+ default:
+ retval = g_uint_property_set_value (property, gobject, va_arg (args, guint));
+ break;
+ }
+ break;
+
+ case G_TYPE_UINT64:
+ retval = g_uint64_property_set_value (property, gobject, va_arg (args, guint64));
+ break;
+
+ case G_TYPE_ULONG:
+ retval = g_ulong_property_set_value (property, gobject, va_arg (args, gulong));
+ break;
+
+ case G_TYPE_ENUM:
+ retval = g_enum_property_set_value (property, gobject, va_arg (args, glong));
+ break;
+
+ case G_TYPE_FLAGS:
+ retval = g_flags_property_set_value (property, gobject, va_arg (args, gulong));
+ break;
+
+ case G_TYPE_FLOAT:
+ retval = g_float_property_set_value (property, gobject, va_arg (args, gdouble));
+ break;
+
+ case G_TYPE_DOUBLE:
+ retval = g_double_property_set_value (property, gobject, va_arg (args, gdouble));
+ break;
+
+ case G_TYPE_STRING:
+ retval = g_string_property_set_value (property, gobject, va_arg (args, gchar *));
+ break;
+
+ case G_TYPE_BOXED:
+ retval = g_boxed_property_set_value (property, gobject, va_arg (args, gpointer));
+ break;
+
+ case G_TYPE_OBJECT:
+ retval = g_object_property_set_value (property, gobject, va_arg (args, gpointer));
+ break;
+
+ default:
+ g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype));
+ retval = FALSE;
+ break;
+ }
+
+ return retval;
+}
+
+/**
+ * g_property_get_valist:
+ * @property: a #GProperty
+ * @gobject: a #GObject instance
+ * @args: a va_list with the property
+ *
+ * Retrieves the value of @property for the given #GObject instance.
+ *
+ * This function is the va_list variant of g_property_get().
+ *
+ * Return value: %TRUE if the value was successfully retrieved, and
+ * %FALSE otherwise
+ *
+ * Since: 2.32
+ */
+gboolean
+g_property_get_valist (GProperty *property,
+ gpointer gobject,
+ va_list args)
+{
+ GType gtype;
+ gpointer ret_p = NULL;
+
+ g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+ g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
+ g_return_val_if_fail (property->is_installed, FALSE);
+
+ if (property->prerequisite != G_TYPE_INVALID)
+ gtype = property->prerequisite;
+ else
+ gtype = property->gtype;
+
+ 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;
+ }
+
+ return TRUE;
+}
+
+/**
+ * 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
+ */
+gboolean
+g_property_set (GProperty *property,
+ gpointer gobject,
+ ...)
+{
+ va_list args;
+ gboolean res;
+
+ g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+ g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
+ g_return_val_if_fail (property->is_installed, FALSE);
+
+ va_start (args, gobject);
+ res = g_property_set_valist (property, gobject, args);
+ va_end (args);
+
+ return res;
+}
+
+/**
+ * g_property_collect:
+ * @property: a #GProperty
+ * @gobject: a #GObject instance
+ * @flags: collection flags
+ * @n_cvalues: the number of C values in the @cvalues array
+ * @cvalues: an array of C values
+ *
+ * Collects the values in the @cvalues array and sets them on @property
+ * for the given #GObject instance.
+ *
+ * This function should only be called through the %G_PROPERTY_COLLECT
+ * macro provided by the <filename>gvaluecollector.h</filename> header
+ * and never directly.
+ *
+ * Return value: %TRUE if the collection was successful, and %FALSE
+ * otherwise
+ *
+ * Since: 2.32
+ */
+gboolean
+g_property_collect (GProperty *property,
+ gpointer gobject,
+ gulong flags,
+ guint n_cvalues,
+ gpointer cvalues)
+{
+ GTypeCValue *_cvalues = cvalues;
+ GType gtype;
+ gint i;
+ gboolean retval = FALSE;
+
+ g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+ g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
+
+ if (property->prerequisite != G_TYPE_INVALID)
+ gtype = property->prerequisite;
+ else
+ gtype = property->gtype;
+
+ for (i = 0; i < n_cvalues; i++)
+ {
+ GTypeCValue *_cvalue = _cvalues + i;
+
+ switch (G_TYPE_FUNDAMENTAL (gtype))
+ {
+ case G_TYPE_BOOLEAN:
+ retval = 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)
+ retval = g_int8_property_set_value (property, gobject, _cvalue->v_int);
+ else
+ retval = g_uint8_property_set_value (property, gobject, _cvalue->v_int);
+ break;
+
+ case 2:
+ if (G_TYPE_FUNDAMENTAL (gtype) == G_TYPE_INT)
+ retval = g_int16_property_set_value (property, gobject, _cvalue->v_int);
+ else
+ retval = g_uint16_property_set_value (property, gobject, _cvalue->v_int);
+ break;
+
+ case 4:
+ if (G_TYPE_FUNDAMENTAL (gtype) == G_TYPE_INT)
+ retval = g_int32_property_set_value (property, gobject, _cvalue->v_int);
+ else
+ retval = g_uint32_property_set_value (property, gobject, _cvalue->v_int);
+ break;
+
+ default:
+ if (G_TYPE_FUNDAMENTAL (gtype) == G_TYPE_INT)
+ retval = g_int_property_set_value (property, gobject, _cvalue->v_int);
+ else
+ retval = g_uint_property_set_value (property, gobject, _cvalue->v_int);
+ break;
+ }
+ break;
+
+ case G_TYPE_INT64:
+ retval = g_int64_property_set_value (property, gobject, _cvalue->v_int64);
+ break;
+
+ case G_TYPE_UINT64:
+ retval = g_uint64_property_set_value (property, gobject, _cvalue->v_int64);
+ break;
+
+ case G_TYPE_LONG:
+ retval = g_long_property_set_value (property, gobject, _cvalue->v_long);
+ break;
+
+ case G_TYPE_ULONG:
+ retval = g_ulong_property_set_value (property, gobject, _cvalue->v_long);
+ break;
+
+ case G_TYPE_ENUM:
+ retval = g_enum_property_set_value (property, gobject, _cvalue->v_long);
+ break;
+
+ case G_TYPE_FLAGS:
+ retval = g_flags_property_set_value (property, gobject, _cvalue->v_long);
+ break;
+
+ case G_TYPE_FLOAT:
+ retval = g_float_property_set_value (property, gobject, _cvalue->v_double);
+ break;
+
+ case G_TYPE_DOUBLE:
+ retval = g_double_property_set_value (property, gobject, _cvalue->v_double);
+ break;
+
+ case G_TYPE_STRING:
+ retval = g_string_property_set_value (property, gobject, _cvalue->v_pointer);
+ break;
+
+ case G_TYPE_BOXED:
+ retval = g_boxed_property_set_value (property, gobject, _cvalue->v_pointer);
+ break;
+
+ case G_TYPE_OBJECT:
+ retval = 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));
+ retval = FALSE;
+ }
+ }
+
+ return retval;
+}
+
+/**
+ * g_property_lcopy:
+ * @property: a #GProperty
+ * @gobject: a #GObject instance
+ * @n_cvalues: the number of C values in the @cvalues array
+ * @cvalues: an array of C values
+ *
+ * Copies the value of @property for the given #GObject instance into
+ * the passed array of C values.
+ *
+ * This function should only be called through the %G_PROPERTY_LCOPY
+ * macro provided by the <filename>gvaluecollector.h</filename> header
+ * and never directly.
+ *
+ *
+ * Return value: %TRUE if the collection was successful, and %FALSE
+ * otherwise
+ *
+ * Since: 2.32
+ */
+gboolean
+g_property_lcopy (GProperty *property,
+ gpointer gobject,
+ gulong flags,
+ guint n_cvalues,
+ gpointer cvalues)
+{
+ GTypeCValue *_cvalues = cvalues;
+ GType gtype;
+ gint i;
+
+ g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+ g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
+
+ if (property->prerequisite != G_TYPE_INVALID)
+ gtype = property->prerequisite;
+ else
+ gtype = property->gtype;
+
+ 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;
+ }
+
+ if ((flags & G_PROPERTY_COLLECT_COPY) != 0)
+ {
+ (* (gchar **) _cvalue->v_pointer) =
+ (gchar *) g_strdup (g_string_property_get_value (property, gobject));
+ }
+ else
+ {
+ (* (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 ((flags & G_PROPERTY_COLLECT_COPY) != 0)
+ {
+ if (boxed == NULL)
+ (* (gpointer *) _cvalue->v_pointer) = NULL;
+ else
+ (* (gpointer *) _cvalue->v_pointer) = g_boxed_copy (gtype, boxed);
+ }
+ else
+ (* (gpointer *) _cvalue->v_pointer) = (gpointer) 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 (((flags & G_PROPERTY_COLLECT_REF) != 0) && obj != NULL)
+ (* (gpointer *) _cvalue->v_pointer) = g_object_ref (obj);
+ else
+ (* (gpointer *) _cvalue->v_pointer) = 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
+ */
+gboolean
+g_property_get (GProperty *property,
+ gpointer gobject,
+ ...)
+{
+ va_list args;
+ gboolean retval;
+
+ g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+ g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
+ g_return_val_if_fail (property->is_installed, FALSE);
+
+ va_start (args, gobject);
+ retval = g_property_get_valist (property, gobject, args);
+ va_end (args);
+
+ return retval;
+}
+
+/**
+ * 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)
+{
+ GValue copy = { 0, };
+ 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));
+
+ g_value_init (©, gtype);
+ if (!g_value_transform (value, ©))
+ {
+ g_critical (G_STRLOC ": Unable to transform a value of type '%s' "
+ "into a value of type '%s'",
+ g_type_name (G_VALUE_TYPE (value)),
+ g_type_name (gtype));
+ return;
+ }
+
+ switch (G_TYPE_FUNDAMENTAL (gtype))
+ {
+ case G_TYPE_BOOLEAN:
+ g_boolean_property_set_value (property, gobject, g_value_get_boolean (©));
+ break;
+
+ case G_TYPE_INT:
+ {
+ gint val = g_value_get_int (©);
+
+ 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, val);
+ break;
+ }
+ }
+ break;
+
+ case G_TYPE_INT64:
+ g_int64_property_set_value (property, gobject, g_value_get_int64 (©));
+ break;
+
+ case G_TYPE_LONG:
+ g_long_property_set_value (property, gobject, g_value_get_long (©));
+ break;
+
+ case G_TYPE_UINT:
+ {
+ guint val = g_value_get_uint (©);
+
+ switch (property->type_size)
+ {
+ case 1:
+ g_uint8_property_set_value (property, gobject, val);
+ break;
+
+ case 2:
+ g_uint16_property_set_value (property, gobject, val);
+ break;
+
+ case 4:
+ g_uint32_property_set_value (property, gobject, val);
+ break;
+
+ default:
+ g_uint_property_set_value (property, gobject, val);
+ break;
+ }
+ }
+ break;
+
+ case G_TYPE_UINT64:
+ g_uint64_property_set_value (property, gobject, g_value_get_uint64 (©));
+ break;
+
+ case G_TYPE_ULONG:
+ g_ulong_property_set_value (property, gobject, g_value_get_ulong (©));
+ break;
+
+ case G_TYPE_FLOAT:
+ g_float_property_set_value (property, gobject, g_value_get_float (©));
+ break;
+
+ case G_TYPE_DOUBLE:
+ g_double_property_set_value (property, gobject, g_value_get_double (©));
+ break;
+
+ case G_TYPE_ENUM:
+ g_enum_property_set_value (property, gobject, g_value_get_enum (©));
+ break;
+
+ case G_TYPE_FLAGS:
+ g_flags_property_set_value (property, gobject, g_value_get_flags (©));
+ break;
+
+ case G_TYPE_STRING:
+ g_string_property_set_value (property, gobject, g_value_get_string (©));
+ break;
+
+ case G_TYPE_BOXED:
+ g_boxed_property_set_value (property, gobject, g_value_get_boxed (©));
+ break;
+
+ case G_TYPE_OBJECT:
+ g_object_property_set_value (property, gobject, g_value_get_object (©));
+ break;
+
+ default:
+ g_critical (G_STRLOC ": Invalid type %s", g_type_name (G_VALUE_TYPE (©)));
+ break;
+ }
+
+ g_value_unset (©);
+}
+
+/**
+ * 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;
+ GValue copy = { 0, };
+
+ 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));
+
+ g_value_init (©, gtype);
+
+ switch (G_TYPE_FUNDAMENTAL (gtype))
+ {
+ case G_TYPE_BOOLEAN:
+ g_value_set_boolean (©, g_boolean_property_get_value (property, gobject));
+ break;
+
+ case G_TYPE_INT:
+ {
+ gint val;
+
+ switch (property->type_size)
+ {
+ case 1:
+ val = g_int8_property_get_value (property, gobject);
+ break;
+
+ case 2:
+ val = g_int16_property_get_value (property, gobject);
+ break;
+
+ case 4:
+ val = g_int32_property_get_value (property, gobject);
+ break;
+
+ default:
+ val = g_int_property_get_value (property, gobject);
+ break;
+ }
+
+ g_value_set_int (©, val);
+ }
+ break;
+
+ case G_TYPE_INT64:
+ g_value_set_int64 (©, g_int64_property_get_value (property, gobject));
+ break;
+
+ case G_TYPE_LONG:
+ g_value_set_long (©, g_long_property_get_value (property, gobject));
+ break;
+
+ case G_TYPE_UINT:
+ {
+ guint val;
+
+ switch (property->type_size)
+ {
+ case 1:
+ val = g_uint8_property_get_value (property, gobject);
+ break;
+
+ case 2:
+ val = g_uint16_property_get_value (property, gobject);
+ break;
+
+ case 4:
+ val = g_uint32_property_get_value (property, gobject);
+ break;
+
+ default:
+ val = g_uint_property_get_value (property, gobject);
+ break;
+ }
+
+ g_value_set_uint (©, val);
+ }
+ break;
+
+ case G_TYPE_UINT64:
+ g_value_set_uint64 (©, g_uint64_property_get_value (property, gobject));
+ break;
+
+ case G_TYPE_ULONG:
+ g_value_set_ulong (©, g_ulong_property_get_value (property, gobject));
+ break;
+
+ case G_TYPE_STRING:
+ g_value_set_string (©, g_string_property_get_value (property, gobject));
+ break;
+
+ case G_TYPE_CHAR:
+ g_value_set_char (©, g_int8_property_get_value (property, gobject));
+ break;
+
+ case G_TYPE_UCHAR:
+ g_value_set_uchar (©, g_uint8_property_get_value (property, gobject));
+ break;
+
+ case G_TYPE_ENUM:
+ g_value_set_enum (©, g_enum_property_get_value (property, gobject));
+ break;
+
+ case G_TYPE_FLAGS:
+ g_value_set_flags (©, g_flags_property_get_value (property, gobject));
+ break;
+
+ case G_TYPE_FLOAT:
+ g_value_set_float (©, g_float_property_get_value (property, gobject));
+ break;
+
+ case G_TYPE_DOUBLE:
+ g_value_set_double (©, g_double_property_get_value (property, gobject));
+ break;
+
+ case G_TYPE_BOXED:
+ g_value_set_boxed (©, g_boxed_property_get_value (property, gobject));
+ break;
+
+ case G_TYPE_OBJECT:
+ g_value_set_object (©, g_object_property_get_value (property, gobject));
+ break;
+
+ default:
+ g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype));
+ break;
+ }
+
+ if (!g_value_transform (©, value))
+ {
+ g_critical (G_STRLOC ": Unable to transform a value of type '%s' into "
+ "a value of type '%s'",
+ g_type_name (gtype),
+ g_type_name (G_VALUE_TYPE (value)));
+ }
+
+ g_value_unset (©);
+}
+
+/**
+ * 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 returned type.
+ *
+ * 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;
+}
+
+/**
+ * g_property_validate:
+ * @property: a #GProperty
+ * @...: the value to validate
+ *
+ * Validates the passed value against the validation rules of
+ * the @property.
+ *
+ * Return value: %TRUE if the value is valid, and %FALSE otherwise
+ *
+ * Since: 2.32
+ */
+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:
+ switch (property->type_size)
+ {
+ case 8:
+ retval = g_uint8_property_validate (property, va_arg (args, guint));
+ break;
+
+ case 16:
+ retval = g_uint16_property_validate (property, va_arg (args, guint));
+ break;
+
+ case 32:
+ retval = g_uint32_property_validate (property, va_arg (args, guint));
+ break;
+
+ default:
+ retval = g_uint_property_validate (property, va_arg (args, guint));
+ break;
+ }
+ 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_ENUM:
+ retval = g_enum_property_validate (property, va_arg (args, glong));
+ break;
+
+ case G_TYPE_FLAGS:
+ retval = g_enum_property_validate (property, va_arg (args, gulong));
+ 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;
+}
+
+/**
+ * g_property_validate_value:
+ * @property: a #GProperty
+ * @value: a #GValue initialized to the property type or to a type
+ * that is transformable into the property type
+ *
+ * Validates the value stored inside the passed #GValue against the
+ * @property rules.
+ *
+ * Return value: %TRUE if the value is valid, and %FALSE otherwise
+ *
+ * Since: 2.32
+ */
+gboolean
+g_property_validate_value (GProperty *property,
+ GValue *value)
+{
+ GValue copy = { 0, };
+ gboolean retval = FALSE;
+ GType gtype;
+
+ g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ if (property->prerequisite != G_TYPE_INVALID)
+ gtype = property->prerequisite;
+ else
+ gtype = property->gtype;
+
+ g_return_val_if_fail (g_value_type_transformable (gtype, G_VALUE_TYPE (value)), FALSE);
+
+ g_value_init (©, gtype);
+
+ if (!g_value_transform (value, ©))
+ {
+ g_critical (G_STRLOC ": Unable to transform a value of type '%s' "
+ "to a value of type '%s'",
+ g_type_name (G_VALUE_TYPE (value)),
+ g_type_name (gtype));
+ g_value_unset (©);
+ return FALSE;
+ }
+
+ switch (G_TYPE_FUNDAMENTAL (gtype))
+ {
+ case G_TYPE_BOOLEAN:
+ retval = g_boolean_property_validate (property, g_value_get_boolean (©));
+ break;
+
+ case G_TYPE_INT:
+ {
+ gint val = g_value_get_int (©);
+
+ switch (property->type_size)
+ {
+ case 8:
+ retval = g_int8_property_validate (property, val);
+ break;
+
+ case 16:
+ retval = g_int16_property_validate (property, val);
+ break;
+
+ case 32:
+ retval = g_int32_property_validate (property, val);
+ break;
+
+ default:
+ retval = g_int_property_validate (property, val);
+ break;
+ }
+ }
+ break;
+
+ case G_TYPE_INT64:
+ retval = g_int64_property_validate (property, g_value_get_int64 (©));
+ break;
+
+ case G_TYPE_LONG:
+ retval = g_long_property_validate (property, g_value_get_long (©));
+ break;
+
+ case G_TYPE_UINT:
+ {
+ guint val = g_value_get_uint (©);
+
+ switch (property->type_size)
+ {
+ case 8:
+ retval = g_uint8_property_validate (property, val);
+ break;
+
+ case 16:
+ retval = g_uint16_property_validate (property, val);
+ break;
+
+ case 32:
+ retval = g_uint32_property_validate (property, val);
+ break;
+
+ default:
+ retval = g_uint_property_validate (property, val);
+ break;
+ }
+ }
+ break;
+
+ case G_TYPE_UINT64:
+ retval = g_uint64_property_validate (property, g_value_get_uint64 (©));
+ break;
+
+ case G_TYPE_ULONG:
+ retval = g_ulong_property_validate (property, g_value_get_ulong (©));
+ break;
+
+ case G_TYPE_FLOAT:
+ retval = g_float_property_validate (property, g_value_get_float (©));
+ break;
+
+ case G_TYPE_DOUBLE:
+ retval = g_double_property_validate (property, g_value_get_double (©));
+ break;
+
+ case G_TYPE_ENUM:
+ retval = g_enum_property_validate (property, g_value_get_enum (©));
+ break;
+
+ case G_TYPE_FLAGS:
+ retval = g_flags_property_validate (property, g_value_get_flags (©));
+ break;
+
+ case G_TYPE_STRING:
+ retval = g_string_property_validate (property, g_value_get_string (©));
+ break;
+
+ case G_TYPE_BOXED:
+ retval = g_boxed_property_validate (property, g_value_get_boxed (©));
+ break;
+
+ case G_TYPE_OBJECT:
+ retval = g_object_property_validate (property, g_value_get_object (©));
+ break;
+
+ default:
+ g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype));
+ retval = FALSE;
+ break;
+ }
+
+ g_value_unset (©);
+
+ 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)
+{
+ gchar *lock_name = g_strconcat ("__g_property_lock_",
+ G_PARAM_SPEC (property)->name,
+ NULL);
+ gint *bit_lock_p;
+
+ bit_lock_p = g_object_get_data (gobject, lock_name);
+ if (bit_lock_p == NULL)
+ {
+ bit_lock_p = g_new0 (gint, 1);
+
+ g_object_set_data (gobject, lock_name, bit_lock_p);
+ }
+
+ g_free (lock_name);
+
+ g_bit_lock (bit_lock_p, 0);
+}
+
+static void
+g_property_default_unlock (GProperty *property,
+ gpointer gobject)
+{
+ gchar *lock_name = g_strconcat ("__g_property_lock_",
+ G_PARAM_SPEC (property)->name,
+ NULL);
+ gpointer bit_lock_p;
+
+ bit_lock_p = g_object_get_data (gobject, lock_name);
+ if (bit_lock_p == NULL)
+ {
+ g_free (lock_name);
+ return;
+ }
+
+ g_object_set_data (gobject, lock_name, NULL);
+ g_free (lock_name);
+
+ g_bit_unlock (bit_lock_p, 0);
+ g_free (bit_lock_p);
+}
+
+/**
+ * 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_for_type (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..2e95322
--- /dev/null
+++ b/gobject/gproperty.h
@@ -0,0 +1,655 @@
+/* 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_name (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);
+gboolean g_property_get_range_values (GProperty *property,
+ GValue *min_value,
+ GValue *max_value);
+void g_property_set_range (GProperty *property,
+ ...);
+gboolean g_property_get_range (GProperty *property,
+ ...);
+
+void g_property_set_default_value (GProperty *property,
+ gpointer gobject_class,
+ const GValue *value);
+void g_property_get_default_value_for_type (GProperty *property,
+ GType gtype,
+ GValue *value);
+void g_property_get_default_value (GProperty *property,
+ gpointer gobject,
+ GValue *value);
+void g_property_set_default (GProperty *property,
+ gpointer gobject_class,
+ ...);
+void g_property_get_default (GProperty *property,
+ gpointer gobject,
+ ...);
+
+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);
+gboolean g_property_set_valist (GProperty *property,
+ gpointer gobject,
+ va_list args);
+gboolean g_property_get_valist (GProperty *property,
+ gpointer gobject,
+ va_list args);
+gboolean g_property_set (GProperty *property,
+ gpointer gobject,
+ ...);
+gboolean g_property_get (GProperty *property,
+ gpointer gobject,
+ ...);
+
+/* va_list collection/copy API; see gvaluecollector.h for
+ * the macros and types to use
+ */
+gboolean g_property_collect (GProperty *property,
+ gpointer gobject,
+ gulong flags,
+ guint n_cvalues,
+ gpointer cvalues);
+gboolean g_property_lcopy (GProperty *property,
+ gpointer gobject,
+ gulong flags,
+ guint n_cvalues,
+ gpointer cvalues);
+
+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);
+
+/* private API */
+void _g_property_set_installed (GProperty *property,
+ GType class_gtype);
+
+/* 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, self, &retval); \
+ return retval; \
+ } \
+\
+ if (!g_property_get (g_property, self, &retval)) \
+ { \
+ g_property_get_default (g_property, self, &retval); \
+ return retval; \
+ } \
+\
+ { /* custom code follows */
+#define _G_DEFINE_PROPERTY_GETTER_END \
+ } /* following custom code */ \
+\
+ 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; \
+ } \
+\
+ if (!g_property_set (g_property, self, value)) \
+ return; \
+\
+ { /* 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
+ * @_C_: C code that should be called after the property has been set
+ *
+ * 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:
+ * @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 @T_n<!-- -->Private structure
+ * @f_n: the name of the property, which must match the name of the
+ * field in the @T_n<!-- -->Private structure
+ * @_C_: C code to be called after the property has been retrieved
+ *
+ * Defines the getter function for a @f_n property in the
+ * class @T_n, with the possibility of calling custom code.
+ *
+ * This macro should only be used in C source files.
+ *
+ * Since: 2.32
+ */
+#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
+ *
+ * Since: 2.32
+ */
+#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; if the
+ * property is not readable and writable, the generated functions will
+ * warn at run-time.
+ *
+ * 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..6f1f75e 100644
--- a/gobject/gvaluecollector.h
+++ b/gobject/gvaluecollector.h
@@ -222,6 +222,124 @@ G_STMT_START { \
*/
#define G_VALUE_COLLECT_FORMAT_MAX_LENGTH (8)
+/**
+ * GPropertyCollectFlags:
+ * @G_PROPERTY_COLLECT_NONE: No flags
+ * @G_PROPERTY_COLLECT_COPY: Make a copy when collecting pointer
+ * locations for boxed and string values
+ * @G_PROPERTY_COLLECT_REF: Take a reference while collecting
+ * pointer locations for object values
+ *
+ * Flags to pass to %G_PROPERTY_LCOPY and %G_PROPERTY_COLLECT.
+ *
+ * Since: 2.32
+ */
+typedef enum { /*< prefix=G_PROPERTY_COLLECT >*/
+ G_PROPERTY_COLLECT_NONE = 0,
+
+ G_PROPERTY_COLLECT_COPY = 1 << 0,
+ G_PROPERTY_COLLECT_REF = 1 << 1
+} GPropertyCollectFlags;
+
+/**
+ * G_PROPERTY_LCOPY:
+ * @property: a #GProperty
+ * @gobject: a #GObject
+ * @flags: flags for collection
+ * @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, flags, 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), (flags), _n_values, _cvalues); } G_STMT_END
+
+/**
+ * G_PROPERTY_LCOPY:
+ * @property: a #GProperty
+ * @gobject: a #GObject
+ * @flags: flags for collection
+ * @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, flags, 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), (flags), _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..27d2dc2 100644
--- a/gobject/tests/.gitignore
+++ b/gobject/tests/.gitignore
@@ -1,7 +1,10 @@
+autoproperties
binding
boxed
dynamictests
enums
+gproperty-example-base
+gproperty-example-derived
ifaceproperties
param
properties
diff --git a/gobject/tests/Makefile.am b/gobject/tests/Makefile.am
index 010f04b..f827b12 100644
--- a/gobject/tests/Makefile.am
+++ b/gobject/tests/Makefile.am
@@ -1,8 +1,12 @@
include $(top_srcdir)/Makefile.decl
+NULL =
+
+SAMPLE_PROGS =
+
INCLUDES = -g $(gobject_INCLUDES) $(GLIB_DEBUG_FLAGS)
-noinst_PROGRAMS = $(TEST_PROGS)
+noinst_PROGRAMS = $(TEST_PROGS) $(SAMPLE_PROGS)
LDADD = ../libgobject-2.0.la $(top_builddir)/gthread/libgthread-2.0.la $(top_builddir)/glib/libglib-2.0.la
TEST_PROGS += \
@@ -15,6 +19,13 @@ TEST_PROGS += \
binding \
properties \
reference \
- ifaceproperties
+ ifaceproperties \
+ autoproperties \
+ $(NULL)
+
+SAMPLE_PROGS += \
+ gproperty-example-base \
+ gproperty-example-derived \
+ $(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..38bb40a
--- /dev/null
+++ b/gobject/tests/autoproperties.c
@@ -0,0 +1,522 @@
+#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;
+
+typedef enum {
+ TEST_FLAGS_VALUE_FOO = 0,
+ TEST_FLAGS_VALUE_BAR = 1 << 0,
+ TEST_FLAGS_VALUE_BAZ = 1 << 1
+} TestFlagsValue;
+
+typedef struct {
+ int x, y, width, height;
+
+ int ref_count;
+} TestBoxed;
+
+struct _TestObject
+{
+ GObject parent_instance;
+
+ TestObjectPrivate *priv;
+};
+
+struct _TestObjectClass
+{
+ GObjectClass parent_class;
+};
+
+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 enum_value;
+ TestFlagsValue flags_value;
+
+ TestBoxed *boxed;
+};
+
+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_ENUM_VALUE,
+ PROP_FLAGS_VALUE,
+ PROP_BOXED,
+
+ 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;
+}
+
+GType
+test_flags_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 GFlagsValue values[] = {
+ { TEST_FLAGS_VALUE_FOO, "TEST_FLAGS_VALUE_FOO", "foo" },
+ { TEST_FLAGS_VALUE_BAR, "TEST_FLAGS_VALUE_BAR", "bar" },
+ { TEST_FLAGS_VALUE_BAZ, "TEST_FLAGS_VALUE_BAZ", "baz" },
+ { 0, NULL, NULL }
+ };
+ GType g_define_type_id =
+ g_flags_register_static (g_intern_static_string ("TestFlagsValue"), values);
+ g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+ }
+
+ return g_define_type_id__volatile;
+}
+
+static gpointer
+test_boxed_copy (gpointer data)
+{
+ if (data != NULL)
+ {
+ TestBoxed *boxed = data;
+
+ boxed->ref_count += 1;
+ }
+
+ return data;
+}
+
+static void
+test_boxed_free (gpointer data)
+{
+ if (data != NULL)
+ {
+ TestBoxed *boxed = data;
+
+ boxed->ref_count -= 1;
+
+ if (boxed->ref_count == 0)
+ g_free (boxed);
+ }
+}
+
+GType
+test_boxed_get_type (void)
+{
+ static volatile gsize g_define_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_define_type_id__volatile))
+ {
+ GType g_define_type_id =
+ g_boxed_type_register_static (g_intern_static_string ("TestBoxed"),
+ test_boxed_copy,
+ test_boxed_free);
+ 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, enum_value)
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, TestFlagsValue, flags_value)
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, const TestBoxed *, boxed)
+
+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]), 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]), klass, 0.5);
+
+ test_object_properties[PROP_ENUM_VALUE] =
+ g_enum_property_new ("enum-value", G_PROPERTY_READWRITE,
+ G_STRUCT_OFFSET (TestObjectPrivate, enum_value),
+ NULL, NULL);
+ g_property_set_prerequisite (G_PROPERTY (test_object_properties[PROP_ENUM_VALUE]),
+ test_enum_value_get_type ());
+ g_property_set_default (G_PROPERTY (test_object_properties[PROP_ENUM_VALUE]),
+ klass,
+ TEST_ENUM_VALUE_BAR);
+
+ test_object_properties[PROP_FLAGS_VALUE] =
+ g_flags_property_new ("flags-value", G_PROPERTY_READWRITE,
+ G_STRUCT_OFFSET (TestObjectPrivate, flags_value),
+ NULL, NULL);
+ g_property_set_prerequisite (G_PROPERTY (test_object_properties[PROP_FLAGS_VALUE]),
+ test_flags_value_get_type ());
+ g_property_set_default (G_PROPERTY (test_object_properties[PROP_FLAGS_VALUE]),
+ klass,
+ TEST_FLAGS_VALUE_FOO);
+
+ test_object_properties[PROP_BOXED] =
+ g_boxed_property_new ("boxed", G_PROPERTY_READWRITE,
+ G_STRUCT_OFFSET (TestObjectPrivate, boxed),
+ NULL, NULL);
+ g_property_set_prerequisite (G_PROPERTY (test_object_properties[PROP_BOXED]),
+ test_boxed_get_type ());
+
+ 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]),
+ self,
+ &(self->priv->foo));
+ g_property_get_default (G_PROPERTY (test_object_properties[PROP_X_ALIGN]),
+ self,
+ &(self->priv->x_align));
+ g_property_get_default (G_PROPERTY (test_object_properties[PROP_ENUM_VALUE]),
+ self,
+ &(self->priv->enum_value));
+ g_property_get_default (G_PROPERTY (test_object_properties[PROP_FLAGS_VALUE]),
+ self,
+ &(self->priv->flags_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_enum_value (t) == TEST_ENUM_VALUE_BAR);
+ g_assert (test_object_get_flags_value (t) == TEST_FLAGS_VALUE_FOO);
+
+ g_object_unref (t);
+}
+
+static void
+autoproperties_range (void)
+{
+ TestObject *t = g_object_new (test_object_get_type (), NULL);
+ GProperty *p;
+ gint min, max;
+
+ p = (GProperty *) g_object_class_find_property (G_OBJECT_GET_CLASS (t), "foo");
+ g_assert (G_IS_PROPERTY (p));
+
+ g_property_get_range (p, &min, &max);
+ g_assert_cmpint (min, ==, -1);
+ g_assert_cmpint (max, ==, 100);
+
+ 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);
+ TestBoxed boxed = { 0, 0, 200, 200, 0 };
+
+ g_object_set (t,
+ "foo", 42,
+ "bar", TRUE,
+ "flags-value", (TEST_FLAGS_VALUE_BAR | TEST_FLAGS_VALUE_BAZ),
+ "boxed", &boxed,
+ NULL);
+
+ g_assert_cmpint (test_object_get_foo (t), ==, 42);
+ g_assert (test_object_get_bar (t));
+ g_assert ((test_object_get_flags_value (t) & TEST_FLAGS_VALUE_BAZ) != 0);
+ g_assert (test_object_get_boxed (t) != NULL);
+ boxed = *test_object_get_boxed (t);
+ g_assert_cmpint (boxed.y, ==, 0);
+ g_assert_cmpint (boxed.width, ==, 200);
+
+ g_object_unref (t);
+}
+
+static void
+autoproperties_object_get (void)
+{
+ TestObject *t = g_object_new (test_object_get_type (), NULL);
+ TestBoxed *boxed;
+ gdouble x_align;
+ gfloat width;
+
+ g_object_get (t, "x-align", &x_align, "width", &width, "boxed", &boxed, NULL);
+ g_assert_cmpfloat (x_align, ==, 0.5);
+ g_assert_cmpfloat (width, ==, 0);
+ g_assert (boxed == NULL);
+
+ g_object_unref (t);
+}
+
+G_LOCK_DEFINE_STATIC (counter);
+static gint counter = 0;
+
+static gpointer
+autoproperties_write_foo (gpointer data)
+{
+ gint i;
+
+ for (i = 0; i < 100; i++)
+ {
+ G_LOCK (counter);
+ counter = i;
+ G_UNLOCK (counter);
+
+ test_object_set_foo (data, i);
+ g_thread_yield ();
+ }
+
+ return NULL;
+}
+
+static gpointer
+autoproperties_read_foo (gpointer data)
+{
+ gint i;
+
+ for (i = 0; i < 100; i++)
+ {
+ g_assert_cmpint (test_object_get_foo (data), ==, counter);
+ g_thread_yield ();
+ }
+
+ return NULL;
+}
+
+void
+autoproperties_atomic_set (void)
+{
+ TestObject *t = g_object_new (test_object_get_type (), NULL);
+
+ g_thread_create (autoproperties_write_foo, t, FALSE, NULL);
+ g_thread_create (autoproperties_read_foo, t, FALSE, NULL);
+
+ 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/range", autoproperties_range);
+ 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);
+ g_test_add_func ("/auto-properties/atomic-set", autoproperties_atomic_set);
+
+ return g_test_run ();
+}
diff --git a/gobject/tests/gproperty-example-base.c b/gobject/tests/gproperty-example-base.c
new file mode 100644
index 0000000..d8b67f6
--- /dev/null
+++ b/gobject/tests/gproperty-example-base.c
@@ -0,0 +1,139 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+
+#define TEST_TYPE_FILE (test_file_get_type ())
+#define TEST_FILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_FILE, TestFile))
+#define TEST_IS_FILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_FILE))
+
+typedef struct _TestFile TestFile;
+typedef struct _TestFilePrivate TestFilePrivate;
+typedef struct _TestFileClass TestFileClass;
+
+struct _TestFile
+{
+ GObject parent_instance;
+
+ TestFilePrivate *priv;
+};
+
+struct _TestFileClass
+{
+ GObjectClass parent_class;
+};
+
+struct _TestFilePrivate
+{
+ gchar *path;
+
+ gint64 size;
+};
+
+G_DEFINE_TYPE (TestFile, test_file, G_TYPE_OBJECT)
+
+enum { PROP_0, PROP_PATH, PROP_SIZE, LAST_PROP };
+
+static GParamSpec *test_file_properties[LAST_PROP] = { 0, };
+
+G_DEFINE_PROPERTY_GET (TestFile, test_file, const gchar *, path)
+
+void
+test_file_set_path (TestFile *self,
+ const gchar *value)
+{
+ GStatBuf s_buf;
+
+ g_return_if_fail (TEST_IS_FILE (self));
+ g_return_if_fail (value != NULL && *value != '\0');
+
+ if (g_strcmp0 (value, self->priv->path) == 0)
+ return;
+
+ if (g_stat (value, &s_buf) == -1)
+ {
+ int saved_errno = errno;
+
+ g_warning ("Unable to access the path: %s", g_strerror (saved_errno));
+
+ return;
+ }
+
+ self->priv->size = (gint64) s_buf.st_size;
+
+ g_free (self->priv->path);
+ self->priv->path = g_strdup (value);
+
+ g_object_notify_by_pspec (G_OBJECT (self), test_file_properties[PROP_SIZE]);
+}
+
+G_DEFINE_PROPERTY_GET (TestFile, test_file, gint64, size);
+
+static void
+test_file_finalize (GObject *gobject)
+{
+ TestFilePrivate *priv = TEST_FILE (gobject)->priv;
+
+ g_free (priv->path);
+
+ G_OBJECT_CLASS (test_file_parent_class)->finalize (gobject);
+}
+
+static void
+test_file_class_init (TestFileClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = test_file_finalize;
+
+ g_type_class_add_private (klass, sizeof (TestFilePrivate));
+
+ test_file_properties[PROP_PATH] =
+ g_string_property_new ("path", G_PROPERTY_READWRITE,
+ G_STRUCT_OFFSET (TestFilePrivate, path),
+ (GPropertyStringSet) test_file_set_path,
+ NULL);
+
+ test_file_properties[PROP_SIZE] =
+ g_string_property_new ("size", G_PROPERTY_READABLE,
+ G_STRUCT_OFFSET (TestFilePrivate, size),
+ NULL, NULL);
+
+ g_object_class_install_properties (G_OBJECT_CLASS (klass),
+ G_N_ELEMENTS (test_file_properties),
+ test_file_properties);
+}
+
+static void
+test_file_init (TestFile *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ TEST_TYPE_FILE,
+ TestFilePrivate);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ TestFile *f;
+ int i;
+
+ g_type_init ();
+
+ f = g_object_new (TEST_TYPE_FILE, NULL);
+
+ for (i = 1; i < argc; i++)
+ {
+ test_file_set_path (f, argv[i]);
+
+ g_print ("File: %s, size: %" G_GINT64_FORMAT "\n",
+ test_file_get_path (f),
+ test_file_get_size (f));
+ }
+
+ g_object_unref (f);
+
+ return EXIT_SUCCESS;
+}
diff --git a/gobject/tests/gproperty-example-derived.c b/gobject/tests/gproperty-example-derived.c
new file mode 100644
index 0000000..bdde06e
--- /dev/null
+++ b/gobject/tests/gproperty-example-derived.c
@@ -0,0 +1,296 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+
+/* Test::File {{{ */
+
+#define TEST_TYPE_FILE (test_file_get_type ())
+#define TEST_FILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_FILE, TestFile))
+#define TEST_IS_FILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_FILE))
+
+typedef struct _TestFile TestFile;
+typedef struct _TestFilePrivate TestFilePrivate;
+typedef struct _TestFileClass TestFileClass;
+
+struct _TestFile
+{
+ GObject parent_instance;
+
+ TestFilePrivate *priv;
+};
+
+struct _TestFileClass
+{
+ GObjectClass parent_class;
+};
+
+struct _TestFilePrivate
+{
+ gchar *path;
+ gchar *extension;
+
+ gint64 size;
+};
+
+G_DEFINE_TYPE (TestFile, test_file, G_TYPE_OBJECT)
+
+enum { PROP_FILE_0, PROP_PATH, PROP_SIZE, PROP_EXTENSION, LAST_FILE_PROP };
+
+static GParamSpec *test_file_properties[LAST_FILE_PROP] = { NULL, };
+
+G_DEFINE_PROPERTY_GET (TestFile, test_file, gchar *, path)
+
+void
+test_file_set_path (TestFile *self,
+ const gchar *value)
+{
+ GStatBuf s_buf;
+
+ g_return_if_fail (TEST_IS_FILE (self));
+ g_return_if_fail (value != NULL && *value != '\0');
+
+ if (g_strcmp0 (value, self->priv->path) == 0)
+ return;
+
+ if (g_stat (value, &s_buf) == -1)
+ {
+ int saved_errno = errno;
+
+ g_warning ("Unable to access the path: %s", g_strerror (saved_errno));
+
+ return;
+ }
+
+ self->priv->size = (gint64) s_buf.st_size;
+
+ g_free (self->priv->path);
+ self->priv->path = g_strdup (value);
+
+ self->priv->extension = strrchr (self->priv->path, '.');
+
+ if (self->priv->extension != NULL &&
+ strlen (self->priv->extension) != 0)
+ {
+ self->priv->extension += 1;
+ }
+ else
+ self->priv->extension = NULL;
+
+ g_object_notify_by_pspec (G_OBJECT (self), test_file_properties[PROP_PATH]);
+ g_object_notify_by_pspec (G_OBJECT (self), test_file_properties[PROP_SIZE]);
+ g_object_notify_by_pspec (G_OBJECT (self), test_file_properties[PROP_EXTENSION]);
+}
+
+G_DEFINE_PROPERTY_GET (TestFile, test_file, const gchar *, extension)
+
+G_DEFINE_PROPERTY_GET (TestFile, test_file, gint64, size)
+
+static void
+test_file_finalize (GObject *gobject)
+{
+ TestFilePrivate *priv = TEST_FILE (gobject)->priv;
+
+ g_free (priv->path);
+
+ G_OBJECT_CLASS (test_file_parent_class)->finalize (gobject);
+}
+
+static void
+test_file_class_init (TestFileClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = test_file_finalize;
+
+ g_type_class_add_private (klass, sizeof (TestFilePrivate));
+
+ test_file_properties[PROP_PATH] =
+ g_string_property_new ("path", G_PROPERTY_READWRITE,
+ G_STRUCT_OFFSET (TestFilePrivate, path),
+ (GPropertyStringSet) test_file_set_path,
+ NULL);
+
+ test_file_properties[PROP_EXTENSION] =
+ g_string_property_new ("extension", G_PROPERTY_READABLE,
+ G_STRUCT_OFFSET (TestFilePrivate, extension),
+ NULL, NULL);
+
+ test_file_properties[PROP_SIZE] =
+ g_string_property_new ("size", G_PROPERTY_READABLE,
+ G_STRUCT_OFFSET (TestFilePrivate, size),
+ NULL, NULL);
+
+ g_object_class_install_properties (G_OBJECT_CLASS (klass),
+ G_N_ELEMENTS (test_file_properties),
+ test_file_properties);
+}
+
+static void
+test_file_init (TestFile *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ TEST_TYPE_FILE,
+ TestFilePrivate);
+}
+
+/* }}} */
+
+/* Test::File::Mp3 {{{ */
+
+#define TEST_TYPE_FILE_MP3 (test_file_mp3_get_type ())
+#define TEST_FILE_MP3(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_FILE_MP3, TestFileMp3))
+#define TEST_IS_FILE_MP3(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_FILE_MP3))
+
+typedef struct _TestFileMp3 TestFileMp3;
+typedef struct _TestFileMp3Private TestFileMp3Private;
+typedef struct _TestFileMp3Class TestFileMp3Class;
+
+struct _TestFileMp3
+{
+ TestFile parent_instance;
+
+ TestFileMp3Private *priv;
+};
+
+struct _TestFileMp3Class
+{
+ TestFileClass parent_class;
+};
+
+struct _TestFileMp3Private
+{
+ gchar *artist;
+ gchar *title;
+ gchar *album;
+
+ gint64 duration;
+};
+
+G_DEFINE_TYPE (TestFileMp3, test_file_mp3, TEST_TYPE_FILE)
+
+enum { PROP_MP3_0, PROP_ARTIST, PROP_TITLE, PROP_ALBUM, PROP_DURATION, LAST_MP3_PROP };
+
+static GParamSpec *test_file_mp3_properties[LAST_MP3_PROP] = { NULL, };
+
+G_DEFINE_PROPERTY_GET_SET (TestFileMp3, test_file_mp3, const gchar *, artist)
+G_DEFINE_PROPERTY_GET_SET (TestFileMp3, test_file_mp3, const gchar *, title)
+G_DEFINE_PROPERTY_GET_SET (TestFileMp3, test_file_mp3, const gchar *, album)
+G_DEFINE_PROPERTY_GET_SET (TestFileMp3, test_file_mp3, gint64, duration)
+
+void
+test_file_mp3_play (TestFileMp3 *file)
+{
+ g_return_if_fail (TEST_IS_FILE_MP3 (file));
+
+ g_print ("Playing...\n");
+}
+
+static void
+test_file_mp3_finalize (GObject *gobject)
+{
+ TestFileMp3Private *priv = TEST_FILE_MP3 (gobject)->priv;
+
+ g_free (priv->artist);
+ g_free (priv->album);
+ g_free (priv->title);
+
+ G_OBJECT_CLASS (test_file_mp3_parent_class)->finalize (gobject);
+}
+
+static void
+test_file_mp3_class_init (TestFileMp3Class *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = test_file_mp3_finalize;
+
+ g_type_class_add_private (klass, sizeof (TestFileMp3Private));
+
+ test_file_mp3_properties[PROP_ALBUM] =
+ g_string_property_new ("album", G_PROPERTY_READWRITE,
+ G_STRUCT_OFFSET (TestFileMp3Private, album),
+ NULL, NULL);
+ g_property_set_default (G_PROPERTY (test_file_mp3_properties[PROP_ALBUM]),
+ klass,
+ "Unknown Album");
+
+ test_file_mp3_properties[PROP_ARTIST] =
+ g_string_property_new ("artist", G_PROPERTY_READWRITE,
+ G_STRUCT_OFFSET (TestFileMp3Private, artist),
+ NULL, NULL);
+ g_property_set_default (G_PROPERTY (test_file_mp3_properties[PROP_ARTIST]),
+ klass,
+ "Unknown Author");
+
+ test_file_mp3_properties[PROP_TITLE] =
+ g_string_property_new ("title", G_PROPERTY_READWRITE,
+ G_STRUCT_OFFSET (TestFileMp3Private, title),
+ NULL, NULL);
+ g_property_set_default (G_PROPERTY (test_file_mp3_properties[PROP_TITLE]),
+ klass,
+ "Unknown Track");
+
+ test_file_mp3_properties[PROP_DURATION] =
+ g_int64_property_new ("duration", G_PROPERTY_READABLE,
+ G_STRUCT_OFFSET (TestFileMp3Private, duration),
+ NULL, NULL);
+
+ g_object_class_install_properties (G_OBJECT_CLASS (klass),
+ G_N_ELEMENTS (test_file_mp3_properties),
+ test_file_mp3_properties);
+}
+
+static void
+test_file_mp3_init (TestFileMp3 *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ TEST_TYPE_FILE_MP3,
+ TestFileMp3Private);
+
+ g_property_get_default (G_PROPERTY (test_file_mp3_properties[PROP_ARTIST]),
+ self,
+ &(self->priv->artist));
+ g_property_get_default (G_PROPERTY (test_file_mp3_properties[PROP_ALBUM]),
+ self,
+ &(self->priv->album));
+ g_property_get_default (G_PROPERTY (test_file_mp3_properties[PROP_TITLE]),
+ self,
+ &(self->priv->title));
+}
+
+/* }}} */
+
+/* main {{{ */
+int
+main (int argc,
+ char *argv[])
+{
+ TestFile *f;
+ int i;
+
+ g_type_init ();
+
+ f = g_object_new (TEST_TYPE_FILE_MP3, NULL);
+
+ for (i = 1; i < argc; i++)
+ {
+ test_file_set_path (f, argv[i]);
+
+ if (g_strcmp0 (test_file_get_extension (f), "mp3") != 0)
+ continue;
+
+ g_print ("File: %s, size: %" G_GINT64_FORMAT "\n",
+ test_file_get_path (f),
+ test_file_get_size (f));
+ g_print (" Track: %s - %s\n",
+ test_file_mp3_get_artist (TEST_FILE_MP3 (f)),
+ test_file_mp3_get_title (TEST_FILE_MP3 (f)));
+
+ test_file_mp3_play (TEST_FILE_MP3 (f));
+ }
+
+ g_object_unref (f);
+
+ return EXIT_SUCCESS;
+}
+/* }}} */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]