diff --git a/docs/reference/gobject/gobject-docs.xml b/docs/reference/gobject/gobject-docs.xml
index 201d63bca..244e5f93c 100644
--- a/docs/reference/gobject/gobject-docs.xml
+++ b/docs/reference/gobject/gobject-docs.xml
@@ -83,6 +83,7 @@
+
diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt
index 5d142dd44..36f079653 100644
--- a/docs/reference/gobject/gobject-sections.txt
+++ b/docs/reference/gobject/gobject-sections.txt
@@ -944,3 +944,84 @@ G_IS_BINDING
g_binding_flags_get_type
g_binding_get_type
+
+
+gproperty
+GProperty
+GPropertyFlags
+GPropertyCollectFlags
+
+g_property_is_writable
+g_property_is_redable
+g_property_is_deprecated
+g_property_is_atomic
+g_property_is_copy_set
+g_property_is_copy_get
+g_property_describe
+g_property_set_range_values
+g_property_get_range_values
+g_property_set_range
+g_property_get_range
+g_property_set_default_value
+g_property_set_default
+g_property_override_default_value
+g_property_override_default
+g_property_get_default_value_for_type
+g_property_get_default_value
+g_property_get_default
+g_property_set_prerequisite
+g_property_validate_value
+g_property_validate
+g_property_set_value
+g_property_set_va
+g_property_set
+g_property_get_value
+g_property_get_va
+g_property_get
+GPropertyLockFunc
+GPropertyUnlockFunc
+g_property_set_lock_functions
+g_property_lock
+g_property_unlock
+g_property_canonicalize_name
+
+g_boolean_property_new
+g_int_property_new
+g_int8_property_new
+g_int16_property_new
+g_int32_property_new
+g_int64_property_new
+g_long_property_new
+g_char_property_new
+g_uint_property_new
+g_uint8_property_new
+g_uint16_property_new
+g_uint32_property_new
+g_uint64_property_new
+g_ulong_property_new
+g_uchar_property_new
+g_unichar_property_new
+g_float_property_new
+g_double_property_new
+g_enum_property_new
+g_flags_property_new
+g_string_property_new
+g_boxed_property_new
+g_object_property_new
+g_pointer_property_new
+
+G_DECLARE_PROPERTY_GET
+G_DECLARE_PROPERTY_SET
+G_DECLARE_PROPERTY_GET_SET
+G_DEFINE_PROPERTY_GET_WITH_CODE
+G_DEFINE_PROPERTY_GET
+G_DEFINE_PROPERTY_SET_WITH_CODE
+G_DEFINE_PROPERTY_SET
+G_DEFINE_PROPERTY_GET_SET
+
+G_PROPERTY
+G_IS_PROPERTY
+G_TYPE_PROPERTY
+
+g_property_get_type
+
diff --git a/glib/glib-object.h b/glib/glib-object.h
index 336ba931d..d760c88ea 100644
--- a/glib/glib-object.h
+++ b/glib/glib-object.h
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/gobject/Makefile.am b/gobject/Makefile.am
index 94fd777b2..937e910e1 100644
--- a/gobject/Makefile.am
+++ b/gobject/Makefile.am
@@ -97,6 +97,7 @@ gobject_public_h_sources = \
gobject.h \
gparam.h \
gparamspecs.h \
+ gproperty.h \
gsignal.h \
gsourceclosure.h \
gtype.h \
@@ -126,6 +127,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 5f60dd6da..3f35b93d5 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -545,9 +545,9 @@ g_object_class_install_property (GObjectClass *class,
class->flags |= CLASS_HAS_PROPS_FLAG;
g_return_if_fail (pspec->flags & (G_PARAM_READABLE | G_PARAM_WRITABLE));
- 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 */
@@ -558,6 +558,9 @@ g_object_class_install_property (GObjectClass *class,
install_property_internal (G_OBJECT_CLASS_TYPE (class), property_id, pspec);
+ if (G_IS_PROPERTY (pspec))
+ _g_property_set_installed (G_PROPERTY (pspec), class, G_OBJECT_CLASS_TYPE (class));
+
if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))
class->construct_properties = g_slist_prepend (class->construct_properties, pspec);
@@ -662,9 +665,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)
@@ -675,6 +678,9 @@ g_object_class_install_properties (GObjectClass *oclass,
oclass->flags |= CLASS_HAS_PROPS_FLAG;
install_property_internal (oclass_type, i, pspec);
+ if (G_IS_PROPERTY (pspec))
+ _g_property_set_installed (G_PROPERTY (pspec), oclass, oclass_type);
+
if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))
oclass->construct_properties = g_slist_prepend (oclass->construct_properties, pspec);
@@ -906,6 +912,129 @@ g_object_class_list_properties (GObjectClass *class,
return pspecs;
}
+static inline void
+override_property_default_value (GObjectClass *oclass,
+ GProperty *property,
+ const GValue *value)
+{
+ g_property_override_default_value (property, G_OBJECT_CLASS_TYPE (oclass), value);
+}
+
+/**
+ * g_object_class_override_property_default_value:
+ * @oclass: a #GObjectClass
+ * @property_name: the name of the property to override
+ * @value: a valid #GValue containing the new default value
+ *
+ * Overrides the default value of @property_name for @oclass with
+ * a new value.
+ *
+ * See g_object_class_override_property_default() for more information.
+ *
+ * This function is meant for language bindings.
+ *
+ * Since: 2.36
+ */
+void
+g_object_class_override_property_default_value (GObjectClass *oclass,
+ const gchar *property_name,
+ const GValue *default_value)
+{
+ GParamSpec *pspec;
+
+ pspec = g_object_class_find_property (oclass, property_name);
+ if (pspec == NULL)
+ {
+ g_critical ("The class '%s' does not have a property named '%s'",
+ g_type_name (G_OBJECT_CLASS_TYPE (oclass)),
+ property_name);
+ return;
+ }
+
+ if (!G_IS_PROPERTY (pspec))
+ {
+ g_critical ("The property '%s' of class '%s' is of type '%s' and "
+ "not a GProperty. Overriding the default is allowed "
+ "only on properties defined using the GProperty API.",
+ G_PARAM_SPEC (pspec)->name,
+ g_type_name (G_OBJECT_CLASS_TYPE (oclass)),
+ g_type_name (G_PARAM_SPEC_TYPE (pspec)));
+ return;
+ }
+
+ override_property_default_value (oclass, G_PROPERTY (pspec), default_value);
+}
+
+/**
+ * g_object_class_override_property_default:
+ * @oclass: a #GObjectClass
+ * @property_name: the name of the property to override
+ * @...: the new default value of the property
+ *
+ * Sets the default value of @property_name for the given #GObject
+ * class.
+ *
+ * This function can only be used with properties installed using
+ * the #GProperty API.
+ *
+ * This function is the equivalent of:
+ *
+ * |[
+ * GParamSpec *pspec = g_object_class_find_property (oclass, property_name);
+ *
+ * g_property_set_default (G_PROPERTY (pspec), oclass, new_value);
+ * ]|
+ *
+ * Since: 2.36
+ */
+void
+g_object_class_override_property_default (GObjectClass *oclass,
+ const gchar *property_name,
+ ...)
+{
+ GParamSpec *pspec;
+ GValue value = { 0, };
+ va_list args;
+ gchar *error = NULL;
+
+ pspec = g_object_class_find_property (oclass, property_name);
+ if (pspec == NULL)
+ {
+ g_critical ("The class '%s' does not have a property named '%s'",
+ g_type_name (G_OBJECT_CLASS_TYPE (oclass)),
+ property_name);
+ return;
+ }
+
+ if (!G_IS_PROPERTY (pspec))
+ {
+ g_critical ("The property '%s' of class '%s' is of type '%s' and "
+ "not a GProperty. Overriding the default is allowed "
+ "only on properties defined using the GProperty API.",
+ G_PARAM_SPEC (pspec)->name,
+ g_type_name (G_OBJECT_CLASS_TYPE (oclass)),
+ g_type_name (G_PARAM_SPEC_TYPE (pspec)));
+ return;
+ }
+
+ va_start (args, property_name);
+
+ G_VALUE_COLLECT_INIT (&value, G_PARAM_SPEC_VALUE_TYPE (pspec), args, 0, &error);
+ if (error != NULL)
+ {
+ g_critical (G_STRLOC ": %s", error);
+ g_free (error);
+ va_end (args);
+ return;
+ }
+
+ override_property_default_value (oclass, G_PROPERTY (pspec), &value);
+
+ g_value_unset (&value);
+
+ va_end (args);
+}
+
/**
* g_object_interface_list_properties:
* @g_iface: any interface vtable for the interface, or the default
@@ -1290,8 +1419,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
@@ -1352,14 +1488,21 @@ object_set_property (GObject *object,
}
else
{
- GParamSpec *notify_pspec;
+ if (G_IS_PROPERTY (pspec))
+ {
+ g_property_set_value ((GProperty *) pspec, object, &tmp_value);
+ }
+ else
+ {
+ GParamSpec *notify_pspec;
- class->set_property (object, param_id, &tmp_value, pspec);
+ class->set_property (object, param_id, &tmp_value, pspec);
- notify_pspec = get_notify_pspec (pspec);
+ notify_pspec = get_notify_pspec (pspec);
- if (notify_pspec != NULL)
- g_object_notify_queue_add (object, nqueue, notify_pspec);
+ if (notify_pspec != NULL)
+ g_object_notify_queue_add (object, nqueue, notify_pspec);
+ }
}
g_value_unset (&tmp_value);
}
@@ -1883,35 +2026,22 @@ g_object_constructed (GObject *object)
/* empty default impl to allow unconditional upchaining */
}
-/**
- * g_object_set_valist: (skip)
- * @object: a #GObject
- * @first_property_name: name of the first property to set
- * @var_args: value for the first property, followed optionally by more
- * name/value pairs, followed by %NULL
- *
- * Sets properties on an object.
- */
-void
-g_object_set_valist (GObject *object,
- const gchar *first_property_name,
- va_list var_args)
+static inline void
+object_set_valist_internal (GObject *object,
+ const gchar *first_property_name,
+ va_list *args)
{
GObjectNotifyQueue *nqueue;
const gchar *name;
-
- g_return_if_fail (G_IS_OBJECT (object));
-
+
g_object_ref (object);
nqueue = g_object_notify_queue_freeze (object, FALSE);
-
+
name = first_property_name;
while (name)
{
- GValue value = G_VALUE_INIT;
GParamSpec *pspec;
- gchar *error = NULL;
-
+
pspec = g_param_spec_pool_lookup (pspec_pool,
name,
G_OBJECT_TYPE (object),
@@ -1939,26 +2069,136 @@ 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;
+
+ g_property_set_va (property, object, 0, args);
+ }
+ else
+ {
+ GValue value = G_VALUE_INIT;
+ gchar *error = NULL;
+
+ G_VALUE_COLLECT_INIT (&value, pspec->value_type, *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*);
+ }
+
+ name = va_arg (*args, gchar*);
}
g_object_notify_queue_thaw (object, nqueue);
g_object_unref (object);
}
+/**
+ * g_object_set_valist: (skip)
+ * @object: a #GObject
+ * @first_property_name: name of the first property to set
+ * @var_args: value for the first property, followed optionally by more
+ * name/value pairs, followed by %NULL
+ *
+ * Sets properties on an object.
+ */
+void
+g_object_set_valist (GObject *object,
+ const gchar *first_property_name,
+ va_list var_args)
+{
+ va_list va_copy;
+
+ g_return_if_fail (G_IS_OBJECT (object));
+
+ G_VA_COPY (va_copy, var_args);
+ object_set_valist_internal (object, first_property_name, &va_copy);
+ va_end (va_copy);
+}
+
+static inline void
+object_get_valist_internal (GObject *object,
+ const gchar *first_property_name,
+ va_list *args)
+{
+ const gchar *name;
+
+ g_object_ref (object);
+
+ name = first_property_name;
+
+ while (name)
+ {
+ GParamSpec *pspec;
+
+ pspec = g_param_spec_pool_lookup (pspec_pool,
+ name,
+ G_OBJECT_TYPE (object),
+ TRUE);
+ if (!pspec)
+ {
+ g_warning ("%s: object class `%s' has no property named `%s'",
+ G_STRFUNC,
+ G_OBJECT_TYPE_NAME (object),
+ name);
+ break;
+ }
+ if (!(pspec->flags & G_PARAM_READABLE))
+ {
+ g_warning ("%s: property `%s' of object class `%s' is not readable",
+ G_STRFUNC,
+ pspec->name,
+ G_OBJECT_TYPE_NAME (object));
+ break;
+ }
+
+ if (G_IS_PROPERTY (pspec))
+ {
+ GProperty *property = (GProperty *) pspec;
+ GPropertyFlags flags = G_PROPERTY_COLLECT_REF
+ | G_PROPERTY_COLLECT_COPY;
+
+ /* 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
+ */
+ if (!g_property_get_va (property, object, flags, args))
+ break;
+ }
+ else
+ {
+ GValue value = G_VALUE_INIT;
+ gchar *error;
+
+ g_value_init (&value, pspec->value_type);
+
+ object_get_property (object, pspec, &value);
+
+ G_VALUE_LCOPY (&value, *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 (*args, gchar*);
+ }
+
+ g_object_unref (object);
+}
+
/**
* g_object_get_valist: (skip)
* @object: a #GObject
@@ -1979,60 +2219,13 @@ g_object_get_valist (GObject *object,
const gchar *first_property_name,
va_list var_args)
{
- const gchar *name;
-
+ va_list va_copy;
+
g_return_if_fail (G_IS_OBJECT (object));
-
- g_object_ref (object);
-
- name = first_property_name;
-
- while (name)
- {
- GValue value = G_VALUE_INIT;
- GParamSpec *pspec;
- gchar *error;
-
- pspec = g_param_spec_pool_lookup (pspec_pool,
- name,
- G_OBJECT_TYPE (object),
- TRUE);
- if (!pspec)
- {
- g_warning ("%s: object class `%s' has no property named `%s'",
- G_STRFUNC,
- G_OBJECT_TYPE_NAME (object),
- name);
- break;
- }
- if (!(pspec->flags & G_PARAM_READABLE))
- {
- g_warning ("%s: property `%s' of object class `%s' is not readable",
- G_STRFUNC,
- pspec->name,
- 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);
-
- name = va_arg (var_args, gchar*);
- }
-
- g_object_unref (object);
+
+ G_VA_COPY (va_copy, var_args);
+ object_get_valist_internal (object, first_property_name, &va_copy);
+ va_end (va_copy);
}
/**
@@ -2055,7 +2248,7 @@ g_object_set (gpointer _object,
g_return_if_fail (G_IS_OBJECT (object));
va_start (var_args, first_property_name);
- g_object_set_valist (object, first_property_name, var_args);
+ object_set_valist_internal (object, first_property_name, &var_args);
va_end (var_args);
}
@@ -2106,7 +2299,7 @@ g_object_get (gpointer _object,
g_return_if_fail (G_IS_OBJECT (object));
va_start (var_args, first_property_name);
- g_object_get_valist (object, first_property_name, var_args);
+ object_get_valist_internal (object, first_property_name, &var_args);
va_end (var_args);
}
diff --git a/gobject/gobject.h b/gobject/gobject.h
index f63e4d164..4da6cca63 100644
--- a/gobject/gobject.h
+++ b/gobject/gobject.h
@@ -402,6 +402,15 @@ GParamSpec* g_object_interface_find_property (gpointer g_iface,
GParamSpec**g_object_interface_list_properties (gpointer g_iface,
guint *n_properties_p);
+GLIB_AVAILABLE_IN_2_36
+void g_object_class_override_property_default (GObjectClass *oclass,
+ const gchar *property_name,
+ ...);
+GLIB_AVAILABLE_IN_2_36
+void g_object_class_override_property_default_value (GObjectClass *oclass,
+ const gchar *property_name,
+ const GValue *default_value);
+
GType g_object_get_type (void) G_GNUC_CONST;
gpointer g_object_new (GType object_type,
const gchar *first_property_name,
diff --git a/gobject/gobject.symbols b/gobject/gobject.symbols
index e5c53cc2e..f13351b61 100644
--- a/gobject/gobject.symbols
+++ b/gobject/gobject.symbols
@@ -222,8 +222,8 @@ g_param_spec_steal_qdata
g_param_spec_set_qdata
g_param_spec_set_qdata_full
g_param_spec_get_qdata
-g_param_spec_set_static_nick
g_param_spec_set_static_blurb
+g_param_spec_set_static_nick
g_param_value_convert
g_param_value_defaults
g_param_values_cmp
@@ -240,6 +240,58 @@ g_value_set_param
g_value_dup_param
g_value_take_param
g_value_set_param_take_ownership
+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_pointer_property_new
+g_property_canonicalize_name
+g_property_describe
+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_va
+g_property_get_value
+g_property_get_value_type
+g_property_is_atomic
+g_property_is_copy_get
+g_property_is_copy_set
+g_property_is_deprecated
+g_property_is_readable
+g_property_is_writable
+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_va
+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
g_pointer_type_register_static
g_strdup_value_contents
g_value_set_boolean
diff --git a/gobject/gproperty.c b/gobject/gproperty.c
new file mode 100644
index 000000000..55c69c0ca
--- /dev/null
+++ b/gobject/gproperty.c
@@ -0,0 +1,5604 @@
+/* gproperty.c: Property definitions for GObject
+ *
+ * Copyright © 2012 Emmanuele Bassi
+ *
+ * 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.
+ */
+
+/**
+ * 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
+ * as #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. For direct access to the private structure
+ * members, #GProperty will assume that the instance structure contains a
+ * pointer to the private data structure as its last member, e.g.:
+ *
+ * |[
+ * typedef struct _TestObject TestObject;
+ * typedef struct _TestObjectPrivate TestObjectPrivate;
+ *
+ * struct _TestObject
+ * {
+ * GObject parent_instance;
+ *
+ * TestObjectPrivate *priv;
+ * };
+ * ]|
+ *
+ * #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.
+ *
+ *
+ * Using GProperty
+ * A typical example of #GProperty usage is:
+ *
+ * |[
+ * /* 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);
+ * }
+ * ]|
+ * The main differences with the #GParamSpec creation and installation
+ * code are:
+ *
+ *
+ * the constructors take the same parameters
+ * there are not #GObject set_property and get_property
+ * virtual function assignments
+ * all properties use direct access of the member in the
+ * instance private data structure
+ *
+ *
+ *
+ * Setting and getting values
+ * 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:
+ * |[
+ * 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;
+ * }
+ * ]|
+ * Note that calling g_property_set() for a property holding a
+ * complex type (e.g. #GObject or #GBoxed) without a specific setter
+ * function will, by default, result in the pointer to the new value
+ * being copied in the private data structure's field; if you need to
+ * copy a boxed type, or take a reference on an object type, you will
+ * need to set the %G_PROPERTY_COPY_SET flag when creating the
+ * property.
+ *
+ * Calling g_property_get() will return a pointer to the private
+ * data structure's field, unless %G_PROPERTY_COPY_GET is set when
+ * creating the property, in which case the returned value will either
+ * be a copy of the private data structure field if it is a boxed type
+ * or the instance with its reference count increased if it is an object
+ * type.
+ *
+ *
+ *
+ * Ranges and validation
+ * 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.
+ *
+ * The range is set using g_property_set_range():
+ *
+ * |[
+ * 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 */)
+ * ]|
+ *
+ * The example above keeps the "width" and "height" properties as
+ * integers, but limits the range of valid values to [ 0, %G_MAXINT ].
+ *
+ * Validation is automatically performed when setting a property
+ * through g_property_set(); explicit setter methods can use g_property_validate()
+ * to perform the validation, e.g.:
+ *
+ * |[
+ * 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);
+ * }
+ * ]|
+ *
+ *
+ *
+ * Default values
+ * Default values are declared using g_property_set_default(), e.g.:
+ * |[
+ * 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);
+ * ]|
+ *
+ * Sub-classes can use g_property_override_default() on an existing property
+ * of their parent classes to override the default value:
+ *
+ * |[
+ * property = g_object_class_find_property (G_OBJECT_CLASS (klass), "width");
+ * g_property_override_default (G_PROPERTY (property),
+ * G_OBJECT_CLASS (klass),
+ * 200);
+ * ]|
+ *
+ * The default value can be retrieved using g_property_get_default(),
+ * for instance during instance initialization:
+ *
+ * |[
+ * 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));
+ * }
+ * ]|
+ *
+ * or to return the default value when writing a getter:
+ *
+ * |[
+ * 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;
+ * }
+ * ]|
+ *
+ * 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().
+ *
+ *
+ *
+ * Custom accessors
+ * 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:
+ *
+ * |[
+ * test_object_property[PROP_COMPLEX] =
+ * g_object_property_new ("complex", G_PROPERTY_READWRITE, -1,
+ * test_object_set_complex,
+ * test_object_get_complex);
+ * g_property_set_prerequisite (G_PROPERTY (test_object_property[PROP_COMPLEX]),
+ * TEST_TYPE_COMPLEX);
+ * ]|
+ *
+ * The accessors can be public or private functions. The implementation
+ * of an explicit setter will be called under the #GProperty lock if the
+ * property is declared using the %G_PROPERTY_ATOMIC flag; the setter should
+ * not notify the property on changes, and should return %TRUE if the value
+ * was modified. An example of a setter is:
+ *
+ * |[
+ * static gboolean
+ * test_object_set_complex (gpointer self_,
+ * gpointer value_)
+ * {
+ * TestObject *self = self_;
+ * TestComplex *value = value_;
+ *
+ * if (self->priv->complex == value)
+ * return FALSE;
+ *
+ * if (self->priv->complex != NULL)
+ * {
+ * test_complex_set_back_pointer (self->priv->complex, NULL);
+ * g_object_unref (self->priv->complex);
+ * }
+ *
+ * self->priv->complex = value;
+ *
+ * if (self->priv->complex != NULL)
+ * {
+ * g_object_ref (self->priv->complex);
+ * test_complex_set_back_pointer (self->priv->complex, self);
+ * }
+ *
+ * test_object_queue_foo (self);
+ *
+ * return TRUE;
+ * }
+ * ]|
+ *
+ * It is also possible to still pass the offset of the structure
+ * field, and provide either the setter or the getter function:
+ *
+ * |[
+ * test_object_property[PROP_WIDTH] =
+ * g_int_property_new ("width", G_PROPERTY_READWRITE | G_PROPERTY_COPY_SET,
+ * G_STRUCT_OFFSET (TestObjectPrivate, width),
+ * test_object_set_width, /* explicit setter */
+ * NULL /* implicit getter */);
+ * ]|
+ *
+ * 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.
+ *
+ * You must not call g_property_set() inside the implementation
+ * of test_object_set_width(), in order to avoid loops.
+ *
+ *
+ *
+ * Special flags
+ * #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:
+ *
+ *
+ * %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.
+ * %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.
+ *
+ *
+ *
+ *
+ *
+ *
+ * Auto-generating setters and getters
+ * 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.
+ * 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:
+ *
+ * |[
+ * 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)
+ * ]|
+ *
+ * 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.
+ *
+ * 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:
+ *
+ * |[
+ * G_DEFINE_PROPERTY_GET (TestObject, test_object, int, width)
+ * G_DEFINE_PROPERTY_SET_WITH_CODE (Test_object, test_object, int, width,
+ * test_object_queue_action (self))
+ * ]|
+ *
+ * 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.
+ *
+ *
+ *
+ * Base object class using GProperty
+ * The example below shows how to use #GProperty and the code
+ * generation macros to implement a simple base class called
+ * "TestFile".
+ *
+ *
+ * FIXME: MISSING XINCLUDE CONTENT
+ *
+ *
+ *
+ *
+ *
+ * Derived object class using GProperty
+ * 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".
+ *
+ *
+ * FIXME: MISSING XINCLUDE CONTENT
+ *
+ *
+ *
+ */
+
+#include "config.h"
+
+#include
+
+#include "gproperty.h"
+
+#include "gvaluecollector.h"
+#include "gparam.h"
+#include "gtype.h"
+#include "gvalue.h"
+#include "gvaluetypes.h"
+
+struct _GProperty
+{
+ GParamSpec parent_instance;
+
+ guint flags : 15;
+ guint is_installed : 1;
+
+ guint16 type_size;
+ guint16 priv_offset;
+ guint16 field_offset;
+
+ GQuark prop_id;
+
+ GPropertyLockFunc lock_func;
+ GPropertyUnlockFunc unlock_func;
+};
+
+/* 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 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_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); /* forward declaration for -Wmissing-prototypes */ \
+\
+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; \
+\
+ G_PARAM_SPEC (prop)->value_type = G_T; \
+\
+ 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 inline 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 inline 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 inline 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 inline gboolean \
+g_##g_t##_property_set_value (GProperty *property, \
+ gpointer gobject, \
+ c_t value) \
+{ \
+ gboolean retval; \
+\
+ if ((property->flags & G_PROPERTY_WRITABLE) == 0) \
+ { \
+ g_critical ("The property '%s' of object '%s' is not writable", \
+ G_PARAM_SPEC (property)->name, \
+ G_OBJECT_TYPE_NAME (gobject)); \
+ return FALSE; \
+ } \
+\
+ if (!g_##g_t##_property_validate (property, value)) \
+ { \
+ g_warning ("The value for the property '%s' of object '%s' is out of the valid range", \
+ G_PARAM_SPEC (property)->name, \
+ G_OBJECT_TYPE_NAME (gobject)); \
+ return FALSE; \
+ } \
+\
+ if (((G##G_t##Property *) property)->setter != NULL) \
+ { \
+ property_lock_internal (property, gobject); \
+\
+ retval = ((G##G_t##Property *) property)->setter (gobject, value); \
+\
+ property_unlock_internal (property, gobject); \
+\
+ if (retval) \
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property); \
+ } \
+ else if (property->field_offset >= 0) \
+ { \
+ gpointer priv_p, field_p; \
+\
+ property_lock_internal (property, gobject); \
+\
+ 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) \
+ { \
+ property_unlock_internal (property, gobject); \
+ return FALSE; \
+ } \
+\
+ (* (c_t *) field_p) = value; \
+\
+ property_unlock_internal (property, gobject); \
+\
+ 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; \
+ } \
+\
+ return retval; \
+} \
+\
+static inline c_t \
+g_##g_t##_property_get_value (GProperty *property, \
+ gpointer gobject) \
+{ \
+ if ((property->flags & G_PROPERTY_READABLE) == 0) \
+ { \
+ g_critical ("The property '%s' of object '%s' is not readable", \
+ G_PARAM_SPEC (property)->name, \
+ G_OBJECT_TYPE_NAME (gobject)); \
+ return FALSE; \
+ } \
+\
+ if (((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 void
+g_property_default_lock (GProperty *property,
+ gpointer gobject)
+{
+ gpointer bit_lock_p;
+
+ bit_lock_p = g_object_get_qdata (gobject, property->prop_id);
+ if (bit_lock_p == NULL)
+ {
+ bit_lock_p = g_new0 (gint, 1);
+ g_object_set_qdata_full (gobject, property->prop_id, bit_lock_p, g_free);
+ }
+
+ g_bit_lock (bit_lock_p, 0);
+}
+
+static void
+g_property_default_unlock (GProperty *property,
+ gpointer gobject)
+{
+ gpointer bit_lock_p;
+
+ bit_lock_p = g_object_get_qdata (gobject, property->prop_id);
+ if (bit_lock_p == NULL)
+ return;
+
+ g_bit_unlock (bit_lock_p, 0);
+ g_object_set_qdata (gobject, property->prop_id, NULL);
+}
+
+static inline void
+property_lock_internal (GProperty *property,
+ gpointer gobject)
+{
+ if (G_LIKELY ((property->flags & G_PROPERTY_ATOMIC) == 0))
+ return;
+
+ if (property->lock_func != NULL)
+ property->lock_func (property, gobject);
+ else
+ g_property_default_lock (property, gobject);
+}
+
+static inline void
+property_unlock_internal (GProperty *property,
+ gpointer gobject)
+{
+ if (G_LIKELY ((property->flags & G_PROPERTY_ATOMIC) == 0))
+ return;
+
+ if (property->unlock_func != NULL)
+ property->unlock_func (property, gobject);
+ else
+ g_property_default_unlock (property, gobject);
+}
+
+static inline 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 = 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;
+}
+
+/* forward declaration */
+static void property_set_default (GParamSpec *pspec,
+ GValue *value);
+
+static const GValue *
+property_get_default_for_type (GProperty *property,
+ GType gtype)
+{
+ GParamSpec *pspec = (GParamSpec *) property;
+
+ if (gtype == G_TYPE_INVALID)
+ {
+ if (G_UNLIKELY (property->prop_id == 0))
+ {
+ gchar *lock_name = g_strconcat ("__g_property_id_", pspec->name, NULL);
+
+ property->prop_id = g_quark_from_string (lock_name);
+ g_free (lock_name);
+ }
+
+ return g_param_spec_get_qdata (pspec, property->prop_id);
+ }
+ else
+ return g_param_spec_get_qdata (pspec, g_type_qname (gtype));
+}
+
+static void
+value_unset_and_free (gpointer data)
+{
+ GValue *value = data;
+
+ g_value_unset (value);
+ g_free (value);
+}
+
+static inline void
+property_set_default_for_type (GProperty *property,
+ GType gtype,
+ GValue *value)
+{
+ GParamSpec *pspec = (GParamSpec *) property;
+
+ if (gtype == G_TYPE_INVALID)
+ {
+ if (G_UNLIKELY (property->prop_id == 0))
+ {
+ gchar *lock_name = g_strconcat ("__g_property_id_", pspec->name, NULL);
+
+ property->prop_id = g_quark_from_string (lock_name);
+ g_free (lock_name);
+ }
+
+ if (g_param_spec_get_qdata (pspec, property->prop_id) != NULL)
+ {
+ g_critical (G_STRLOC ": The property '%s' already has a default "
+ "value. Use g_property_override_default() instead.",
+ pspec->name);
+ return;
+ }
+
+ g_param_spec_set_qdata_full (pspec, property->prop_id,
+ value,
+ value_unset_and_free);
+ }
+ else
+ g_param_spec_set_qdata_full (pspec, g_type_qname (gtype),
+ value,
+ value_unset_and_free);
+}
+
+/**
+ * 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.36
+ */
+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.36
+ */
+DEFINE_PROPERTY_INTEGER (Int, int, int, 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.36
+ */
+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.36
+ */
+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.36
+ */
+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.36
+ */
+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.36
+ */
+DEFINE_PROPERTY_INTEGER (Long, long, long, 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.36
+ */
+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.36
+ */
+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.36
+ */
+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.36
+ */
+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.36
+ */
+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.36
+ */
+DEFINE_PROPERTY_INTEGER (ULong, ulong, gulong, G_TYPE_ULONG, 0, 0, G_MAXULONG)
+
+/*
+ * GEnum
+ */
+
+/* forward declaration for -Wmissing-prototypes */
+GType _g_enum_property_get_type (void);
+
+typedef struct {
+ GProperty parent;
+
+ GEnumClass *e_class;
+
+ GPropertyEnumSet setter;
+ GPropertyEnumGet getter;
+} GEnumProperty;
+
+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_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_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.36
+ */
+GParamSpec *
+g_enum_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize offset,
+ GPropertyEnumSet setter,
+ GPropertyEnumGet getter)
+{
+ GProperty *prop;
+ GEnumProperty *internal;
+
+ if (setter == NULL && getter == NULL)
+ g_return_val_if_fail (offset >= 0, NULL);
+
+ prop = g_param_spec_internal (_g_enum_property_get_type (),
+ name, NULL, NULL,
+ property_flags_to_param_flags (flags));
+
+ prop->flags = flags;
+
+ G_PARAM_SPEC (prop)->value_type = G_TYPE_ENUM;
+
+ prop->field_offset = offset;
+
+ prop->is_installed = FALSE;
+
+ prop->type_size = sizeof (glong);
+
+ internal = (GEnumProperty *) prop;
+ internal->setter = setter;
+ internal->getter = getter;
+
+ return G_PARAM_SPEC (prop);
+}
+
+static inline gboolean
+g_enum_property_validate (GProperty *property,
+ glong 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 inline gboolean
+g_enum_property_set_value (GProperty *property,
+ gpointer gobject,
+ glong value)
+{
+ gboolean retval = FALSE;
+
+ if ((property->flags & G_PROPERTY_WRITABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not writable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (!g_enum_property_validate (property, value))
+ {
+ g_warning ("The value for the property '%s' of object '%s' is out of the valid range",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((GEnumProperty *) property)->setter != NULL)
+ {
+ property_lock_internal (property, gobject);
+
+ retval = ((GEnumProperty *) property)->setter (gobject, value);
+
+ property_unlock_internal (property, gobject);
+
+ if (retval)
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+ }
+ else if (property->field_offset >= 0)
+ {
+ gpointer priv_p, field_p;
+
+ property_lock_internal (property, gobject);
+
+ 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)
+ {
+ property_unlock_internal (property, gobject);
+ return FALSE;
+ }
+
+ (* (gulong *) field_p) = value;
+
+ property_unlock_internal (property, gobject);
+
+ 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);
+
+ return retval;
+}
+
+static inline gulong
+g_enum_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ if ((property->flags & G_PROPERTY_READABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not readable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((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 for -Wmissing-prototypes */
+GType _g_flags_property_get_type (void);
+
+typedef struct {
+ GProperty parent;
+
+ GFlagsClass *f_class;
+
+ GPropertyFlagsSet setter;
+ GPropertyFlagsGet getter;
+} GFlagsProperty;
+
+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_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_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.36
+ */
+GParamSpec *
+g_flags_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize offset,
+ GPropertyFlagsSet setter,
+ GPropertyFlagsGet getter)
+{
+ GProperty *prop;
+ GFlagsProperty *internal;
+
+ if (setter == NULL && getter == NULL)
+ g_return_val_if_fail (offset >= 0, NULL);
+
+ prop = g_param_spec_internal (_g_flags_property_get_type (),
+ name, NULL, NULL,
+ property_flags_to_param_flags (flags));
+
+ prop->flags = flags;
+
+ G_PARAM_SPEC (prop)->value_type = G_TYPE_FLAGS;
+
+ 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 inline 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 inline gboolean
+g_flags_property_set_value (GProperty *property,
+ gpointer gobject,
+ gulong value)
+{
+ gboolean retval = FALSE;
+
+ if ((property->flags & G_PROPERTY_WRITABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not writable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (!g_flags_property_validate (property, value))
+ {
+ g_warning ("The value for the property '%s' of object '%s' is out of the valid range",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((GFlagsProperty *) property)->setter != NULL)
+ {
+ property_lock_internal (property, gobject);
+
+ retval = ((GFlagsProperty *) property)->setter (gobject, value);
+
+ property_unlock_internal (property, gobject);
+
+ if (retval)
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+ }
+ else if (property->field_offset >= 0)
+ {
+ gpointer priv_p, field_p;
+
+ property_lock_internal (property, gobject);
+
+ 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)
+ {
+ property_unlock_internal (property, gobject);
+ return FALSE;
+ }
+
+ (* (gulong *) field_p) = value;
+
+ property_unlock_internal (property, gobject);
+
+ 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);
+
+ return retval;
+}
+
+static inline gulong
+g_flags_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ if ((property->flags & G_PROPERTY_READABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not readable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((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 for -Wmissing-prototypes */
+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 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_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_MAXFLOAT;
+ 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.36
+ */
+GParamSpec *
+g_float_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize offset,
+ GPropertyFloatSet setter,
+ GPropertyFloatGet getter)
+{
+ GProperty *prop;
+ GFloatProperty *internal;
+
+ if (setter == NULL && getter == NULL)
+ g_return_val_if_fail (offset >= 0, NULL);
+
+ prop = g_param_spec_internal (_g_float_property_get_type (),
+ name, NULL, NULL,
+ property_flags_to_param_flags (flags));
+
+ prop->flags = flags;
+
+ G_PARAM_SPEC (prop)->value_type = G_TYPE_FLOAT;
+
+ 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 inline void
+g_float_property_set_range (GProperty *property,
+ gfloat min_value,
+ gfloat max_value)
+{
+ if (min_value > max_value)
+ {
+ g_critical (G_STRLOC ": Invalid range for the property '%s'",
+ G_PARAM_SPEC (property)->name);
+ return;
+ }
+
+ ((GFloatProperty *) property)->min_value = min_value;
+ ((GFloatProperty *) property)->max_value = max_value;
+}
+
+static inline 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 inline 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 inline gboolean
+g_float_property_set_value (GProperty *property,
+ gpointer gobject,
+ gfloat value)
+{
+ gboolean retval = FALSE;
+
+ if ((property->flags & G_PROPERTY_WRITABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not writable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (!g_float_property_validate (property, value))
+ {
+ g_warning ("The value for the property '%s' of object '%s' is out of the valid range",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((GFloatProperty *) property)->setter != NULL)
+ {
+ property_lock_internal (property, gobject);
+
+ retval = ((GFloatProperty *) property)->setter (gobject, value);
+
+ property_unlock_internal (property, gobject);
+
+ if (retval)
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+ }
+ else if (property->field_offset >= 0)
+ {
+ gpointer priv_p, field_p;
+
+ property_lock_internal (property, gobject);
+
+ 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)
+ {
+ property_unlock_internal (property, gobject);
+ return FALSE;
+ }
+
+ (* (gfloat *) field_p) = value;
+
+ property_unlock_internal (property, gobject);
+
+ 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);
+
+ return retval;
+}
+
+static inline gfloat
+g_float_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ if ((property->flags & G_PROPERTY_READABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not readable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((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 for -Wmissing-prototypes */
+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 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_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_MAXDOUBLE;
+ 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.36
+ */
+GParamSpec *
+g_double_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize offset,
+ GPropertyDoubleSet setter,
+ GPropertyDoubleGet getter)
+{
+ GProperty *prop;
+ GDoubleProperty *internal;
+
+ if (setter == NULL && getter == NULL)
+ g_return_val_if_fail (offset >= 0, NULL);
+
+ prop = g_param_spec_internal (_g_double_property_get_type (),
+ name, NULL, NULL,
+ property_flags_to_param_flags (flags));
+
+ prop->flags = flags;
+
+ G_PARAM_SPEC (prop)->value_type = G_TYPE_DOUBLE;
+
+ 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 inline void
+g_double_property_set_range (GProperty *property,
+ gdouble min_value,
+ gdouble max_value)
+{
+ if (min_value > max_value)
+ {
+ g_critical (G_STRLOC ": Invalid range for property '%s'",
+ G_PARAM_SPEC (property)->name);
+ return;
+ }
+
+ ((GDoubleProperty *) property)->min_value = min_value;
+ ((GDoubleProperty *) property)->max_value = max_value;
+}
+
+static inline 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 inline 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 inline gboolean
+g_double_property_set_value (GProperty *property,
+ gpointer gobject,
+ gdouble value)
+{
+ gboolean retval = FALSE;
+
+ if ((property->flags & G_PROPERTY_WRITABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not writable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (!g_double_property_validate (property, value))
+ {
+ g_warning ("The value for the property '%s' of object '%s' is out of the valid range",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((GDoubleProperty *) property)->setter != NULL)
+ {
+ property_lock_internal (property, gobject);
+
+ retval = ((GDoubleProperty *) property)->setter (gobject, value);
+
+ property_unlock_internal (property, gobject);
+
+ if (retval)
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+ }
+ else if (property->field_offset >= 0)
+ {
+ gpointer priv_p, field_p;
+
+ property_lock_internal (property, gobject);
+
+ 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)
+ {
+ property_unlock_internal (property, gobject);
+ return FALSE;
+ }
+
+ (* (gdouble *) field_p) = value;
+
+ property_unlock_internal (property, gobject);
+
+ 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);
+
+ return retval;
+}
+
+static inline gdouble
+g_double_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ if ((property->flags & G_PROPERTY_READABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not readable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((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 for -Wmissing-prototypes */
+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.36
+ */
+GParamSpec *
+g_string_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize offset,
+ GPropertyStringSet setter,
+ GPropertyStringGet getter)
+{
+ GProperty *prop;
+ GStringProperty *internal;
+
+ if (setter == NULL && getter == NULL)
+ g_return_val_if_fail (offset >= 0, NULL);
+
+ prop = g_param_spec_internal (_g_string_property_get_type (),
+ name, NULL, NULL,
+ property_flags_to_param_flags (flags));
+
+ prop->flags = flags;
+
+ G_PARAM_SPEC (prop)->value_type = G_TYPE_STRING;
+
+ 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 inline gboolean
+g_string_property_validate (GProperty *property,
+ const gchar *value)
+{
+ return TRUE;
+}
+
+static inline gboolean
+g_string_property_set_value (GProperty *property,
+ gpointer gobject,
+ const gchar *value)
+{
+ gboolean retval = FALSE;
+
+ if ((property->flags & G_PROPERTY_WRITABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not writable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (!g_string_property_validate (property, value))
+ {
+ g_warning ("The value for the property '%s' of object '%s' is out of the valid range",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((GStringProperty *) property)->setter != NULL)
+ {
+ property_lock_internal (property, gobject);
+
+ retval = ((GStringProperty *) property)->setter (gobject, value);
+
+ property_unlock_internal (property, gobject);
+
+ if (retval)
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+ }
+ else if (property->field_offset >= 0)
+ {
+ gpointer priv_p, field_p;
+ gchar *str;
+
+ property_lock_internal (property, gobject);
+
+ 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)
+ {
+ property_unlock_internal (property, gobject);
+ return FALSE;
+ }
+
+ if (property->flags & G_PROPERTY_COPY_SET)
+ {
+ g_free (str);
+ (* (gpointer *) field_p) = g_strdup (value);
+ }
+ else
+ (* (gpointer *) field_p) = (gpointer) value;
+
+ property_unlock_internal (property, gobject);
+
+ 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);
+
+ return retval;
+}
+
+static inline const gchar *
+g_string_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ if ((property->flags & G_PROPERTY_READABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not readable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((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);
+
+ if (property->flags & G_PROPERTY_COPY_GET)
+ retval = g_strdup ((* (gpointer *) field_p));
+ else
+ 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 for -Wmissing-prototypes */
+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.36
+ */
+GParamSpec *
+g_boxed_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize offset,
+ GPropertyBoxedSet setter,
+ GPropertyBoxedGet getter)
+{
+ GProperty *prop;
+ GBoxedProperty *internal;
+
+ if (setter == NULL && getter == NULL)
+ g_return_val_if_fail (offset >= 0, NULL);
+
+ prop = g_param_spec_internal (_g_boxed_property_get_type (),
+ name, NULL, NULL,
+ property_flags_to_param_flags (flags));
+
+ prop->flags = flags;
+
+ G_PARAM_SPEC (prop)->value_type = G_TYPE_BOXED;
+
+ 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 inline gboolean
+g_boxed_property_validate (GProperty *property,
+ gconstpointer value)
+{
+ return TRUE;
+}
+
+static inline gboolean
+g_boxed_property_set_value (GProperty *property,
+ gpointer gobject,
+ gpointer value)
+{
+ gboolean retval = FALSE;
+
+ if ((property->flags & G_PROPERTY_WRITABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not writable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (!g_boxed_property_validate (property, value))
+ {
+ g_warning ("The value for the property '%s' of object '%s' is out of the valid range",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((GBoxedProperty *) property)->setter != NULL)
+ {
+ property_lock_internal (property, gobject);
+
+ retval = ((GBoxedProperty *) property)->setter (gobject, value);
+
+ property_unlock_internal (property, gobject);
+
+ if (retval)
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+ }
+ else if (property->field_offset >= 0)
+ {
+ gpointer priv_p, field_p;
+ gpointer old_value;
+
+ property_lock_internal (property, gobject);
+
+ priv_p = get_private_pointer (gobject, property->priv_offset);
+ field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
+
+ if (property->flags & G_PROPERTY_COPY_SET)
+ {
+ old_value = (* (gpointer *) field_p);
+
+ if (value != NULL)
+ (* (gpointer *) field_p) = g_boxed_copy (((GParamSpec *) property)->value_type, value);
+ else
+ (* (gpointer *) field_p) = NULL;
+
+ if (old_value != NULL)
+ g_boxed_free (((GParamSpec *) property)->value_type, old_value);
+ }
+ else
+ (* (gpointer *) field_p) = value;
+
+ property_unlock_internal (property, gobject);
+
+ 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);
+
+ return retval;
+}
+
+static inline gpointer
+g_boxed_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ if ((property->flags & G_PROPERTY_READABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not readable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((GBoxedProperty *) property)->getter != NULL)
+ {
+ return ((GBoxedProperty *) property)->getter (gobject);
+ }
+ else if (property->field_offset >= 0)
+ {
+ gpointer priv_p, field_p;
+ gpointer value;
+
+ priv_p = get_private_pointer (gobject, property->priv_offset);
+ field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
+
+ if (property->flags & G_PROPERTY_COPY_GET)
+ value = g_boxed_copy (((GParamSpec *) property)->value_type, (* (gpointer *) field_p));
+ else
+ value = (* (gpointer *) field_p);
+
+ return value;
+ }
+ 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 for -Wmissing-prototypes */
+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.36
+ */
+GParamSpec *
+g_object_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize offset,
+ GPropertyObjectSet setter,
+ GPropertyObjectGet getter)
+{
+ GProperty *prop;
+ GObjectProperty *internal;
+
+ if (setter == NULL && getter == NULL)
+ g_return_val_if_fail (offset >= 0, NULL);
+
+ prop = g_param_spec_internal (_g_object_property_get_type (),
+ name, NULL, NULL,
+ property_flags_to_param_flags (flags));
+
+ prop->flags = flags;
+
+ G_PARAM_SPEC (prop)->value_type = G_TYPE_OBJECT;
+
+ 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 inline gboolean
+g_object_property_validate (GProperty *property,
+ gconstpointer value)
+{
+ if (value == NULL)
+ return FALSE;
+
+ return g_type_is_a (G_OBJECT_TYPE (value), G_PARAM_SPEC (property)->value_type);
+}
+
+static inline gboolean
+g_object_property_set_value (GProperty *property,
+ gpointer gobject,
+ gpointer value)
+{
+ gboolean retval = FALSE;
+
+ if ((property->flags & G_PROPERTY_WRITABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not writable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (!g_object_property_validate (property, value))
+ {
+ g_warning ("The value for the property '%s' of object '%s' is out of the valid range",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((GObjectProperty *) property)->setter != NULL)
+ {
+ property_lock_internal (property, gobject);
+
+ retval = ((GObjectProperty *) property)->setter (gobject, value);
+
+ property_unlock_internal (property, gobject);
+
+ if (retval)
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+ }
+ 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);
+
+ property_lock_internal (property, gobject);
+
+ priv_p = get_private_pointer (gobject, property->priv_offset);
+ field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
+
+ if ((* (gpointer *) field_p) == value)
+ {
+ property_unlock_internal (property, gobject);
+ return FALSE;
+ }
+
+ if (property->flags & G_PROPERTY_COPY_SET)
+ {
+ 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);
+ }
+ }
+ else
+ (* (gpointer *) field_p) = value;
+
+ property_unlock_internal (property, gobject);
+
+ 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);
+
+ return retval;
+}
+
+static inline gpointer
+g_object_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ if ((property->flags & G_PROPERTY_READABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not readable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((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);
+
+ if (property->flags & G_PROPERTY_COPY_GET)
+ {
+ gpointer value = (* (gpointer *) field_p);
+
+ if (value != NULL)
+ return g_object_ref (value);
+ else
+ return NULL;
+ }
+ else
+ 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;
+ }
+}
+
+/*
+ * gpointer
+ */
+
+/* forward declaration for -Wmissing-prototypes */
+GType _g_pointer_property_get_type (void);
+
+typedef struct {
+ GProperty parent;
+
+ GPropertyPointerSet setter;
+ GPropertyPointerGet getter;
+} GPointerProperty;
+
+static void
+property_pointer_class_init (GParamSpecClass *klass)
+{
+ klass->value_type = G_TYPE_POINTER;
+}
+
+static void
+property_pointer_init (GParamSpec *pspec)
+{
+}
+
+GType
+_g_pointer_property_get_type (void)
+{
+ static volatile gsize pspec_type_id__volatile = 0;
+
+ if (g_once_init_enter (&pspec_type_id__volatile))
+ {
+ const GTypeInfo info = {
+ sizeof (GParamSpecClass),
+ NULL, NULL,
+ (GClassInitFunc) property_pointer_class_init,
+ NULL, NULL,
+ sizeof (GPointerProperty),
+ 0,
+ (GInstanceInitFunc) property_pointer_init,
+ };
+
+ GType pspec_type_id =
+ g_type_register_static (G_TYPE_PROPERTY,
+ g_intern_static_string ("GPointerProperty"),
+ &info, 0);
+
+ g_once_init_leave (&pspec_type_id__volatile, pspec_type_id);
+ }
+
+ return pspec_type_id__volatile;
+}
+
+/**
+ * g_pointer_property_new:
+ * @name: canonical name of the property
+ * @flags: flags for the property
+ * @offset: the offset in the private structure of the field
+ * that stores the property, or -1
+ * @setter: (allow-none): the setter function for the property
+ * @getter: (allow-none): the getter function for the property
+ *
+ * Creates a new #GProperty mapping to an untyped pointer.
+ *
+ * Return value: the newly created #GProperty
+ *
+ * Since: 2.36
+ */
+GParamSpec *
+g_pointer_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize offset,
+ GPropertyObjectSet setter,
+ GPropertyObjectGet getter)
+{
+ GProperty *prop;
+ GPointerProperty *internal;
+
+ if (setter == NULL && getter == NULL)
+ g_return_val_if_fail (offset >= 0, NULL);
+
+ prop = g_param_spec_internal (_g_pointer_property_get_type (),
+ name, NULL, NULL,
+ property_flags_to_param_flags (flags));
+
+ prop->flags = flags;
+
+ G_PARAM_SPEC (prop)->value_type = G_TYPE_POINTER;
+
+ prop->field_offset = offset;
+
+ prop->is_installed = FALSE;
+
+ prop->type_size = sizeof (gpointer);
+
+ internal = (GPointerProperty *) prop;
+ internal->setter = setter;
+ internal->getter = getter;
+
+ return G_PARAM_SPEC (prop);
+}
+
+static inline gboolean
+g_pointer_property_validate (GProperty *property,
+ gconstpointer value)
+{
+ return TRUE;
+}
+
+static inline gboolean
+g_pointer_property_set_value (GProperty *property,
+ gpointer gobject,
+ gpointer value)
+{
+ gboolean retval = FALSE;
+
+ if ((property->flags & G_PROPERTY_WRITABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not writable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (!g_pointer_property_validate (property, value))
+ {
+ g_warning ("The value for the property '%s' of object '%s' is out of the valid range",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((GPointerProperty *) property)->setter != NULL)
+ {
+ property_lock_internal (property, gobject);
+
+ retval = ((GPointerProperty *) property)->setter (gobject, value);
+
+ property_unlock_internal (property, gobject);
+
+ if (retval)
+ g_object_notify_by_pspec (gobject, (GParamSpec *) property);
+ }
+ else if (property->field_offset >= 0)
+ {
+ gpointer priv_p, field_p;
+
+ property_lock_internal (property, gobject);
+
+ priv_p = get_private_pointer (gobject, property->priv_offset);
+ field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
+
+ if ((* (gpointer *) field_p) == value)
+ {
+ property_unlock_internal (property, gobject);
+ return FALSE;
+ }
+
+ (* (gpointer *) field_p) = value;
+
+ property_unlock_internal (property, gobject);
+
+ 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);
+
+ return retval;
+}
+
+static inline gpointer
+g_pointer_property_get_value (GProperty *property,
+ gpointer gobject)
+{
+ if ((property->flags & G_PROPERTY_READABLE) == 0)
+ {
+ g_critical ("The property '%s' of object '%s' is not readable",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+ return FALSE;
+ }
+
+ if (((GPointerProperty *) property)->getter != NULL)
+ {
+ return ((GPointerProperty *) property)->getter (gobject);
+ }
+ else if (property->field_offset >= 0)
+ {
+ gpointer priv_p, field_p;
+
+ priv_p = g_type_instance_get_private (gobject, G_OBJECT_TYPE (gobject));
+ field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
+
+ return (* (gpointer *) field_p);
+ }
+ else
+ {
+ g_critical (G_STRLOC ": No getter function or field offset specified "
+ "for property '%s'",
+ G_PARAM_SPEC (property)->name);
+ return NULL;
+ }
+}
+
+/*
+ * GProperty common API
+ */
+
+/*< 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,
+ gpointer g_class,
+ GType class_gtype)
+{
+ if (property->field_offset >= 0)
+ {
+ gboolean is_interface = G_TYPE_IS_INTERFACE (class_gtype);
+
+ 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));
+ property->priv_offset = -1;
+ }
+
+ property->priv_offset = g_type_class_get_instance_private_offset (g_class, class_gtype);
+ }
+ else
+ property->priv_offset = -1;
+
+ /* if the property is using the default locking, pre-compute the
+ * quark for the lock
+ */
+ if ((property->flags & G_PROPERTY_ATOMIC) != 0 &&
+ property->prop_id == 0 &&
+ property->lock_func == NULL)
+ {
+ gchar *lock_n = g_strconcat ("-g-property-id-",
+ G_PARAM_SPEC (property)->name,
+ NULL);
+ property->prop_id = g_quark_from_string (lock_n);
+ g_free (lock_n);
+ }
+
+ 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.36
+ */
+gchar *
+g_property_canonicalize_name (const gchar *name)
+{
+ gchar *retval;
+
+ g_return_val_if_fail (name != NULL, NULL);
+
+ if (is_canonical (name))
+ return g_strdup (g_intern_string (name));
+
+ retval = g_strdup (name);
+ canonicalize_name (retval);
+ g_intern_string (retval);
+
+ return retval;
+}
+
+/**
+ * g_property_describe:
+ * @property: a #GProperty
+ * @nick: a static string with the user-readable name
+ * of the property
+ * @blurb: a static string with the user-readable description
+ * of the property
+ *
+ * Sets the user-readable, and optionally translatable, name and
+ * description of the property.
+ *
+ * This function cannot be called more than once.
+ *
+ * This function is a convenience wrapper around g_param_spec_set_static_nick()
+ * and g_param_spec_set_static_blurb().
+ *
+ * Since: 2.36
+ */
+void
+g_property_describe (GProperty *property,
+ const char *nick,
+ const char *blurb)
+{
+ GParamSpec *pspec;
+
+ g_return_if_fail (G_IS_PROPERTY (property));
+ g_return_if_fail (nick != NULL);
+ g_return_if_fail (blurb != NULL);
+
+ pspec = G_PARAM_SPEC (property);
+
+ g_param_spec_set_static_nick (pspec, nick);
+ g_param_spec_set_static_blurb (pspec, 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.36
+ */
+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 (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
+ g_return_if_fail (g_type_is_a (gtype, G_PARAM_SPEC (property)->value_type));
+
+ switch (G_PARAM_SPEC (property)->value_type)
+ {
+ case G_TYPE_BOXED:
+ case G_TYPE_OBJECT:
+ G_PARAM_SPEC (property)->value_type = gtype;
+ break;
+
+ case G_TYPE_ENUM:
+ G_PARAM_SPEC (property)->value_type = gtype;
+ ((GEnumProperty *) property)->e_class = g_type_class_ref (gtype);
+ break;
+
+ case G_TYPE_FLAGS:
+ G_PARAM_SPEC (property)->value_type = 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
+ *
+ * Sets the valid range of @property, using #GValues.
+ *
+ * This function is intended for language bindings.
+ *
+ * Since: 2.36
+ */
+void
+g_property_set_range_values (GProperty *property,
+ const GValue *min_value,
+ const GValue *max_value)
+{
+ GType gtype;
+
+ g_return_if_fail (G_IS_PROPERTY (property));
+ g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
+ g_return_if_fail (!property->is_installed);
+ g_return_if_fail (min_value != NULL && max_value != NULL);
+
+ gtype = G_PARAM_SPEC (property)->value_type;
+ g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (min_value), gtype));
+ g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (max_value), gtype));
+
+ switch (gtype)
+ {
+ case G_TYPE_BOOLEAN:
+ g_boolean_property_set_range (property,
+ 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.36
+ */
+gboolean
+g_property_get_range_values (GProperty *property,
+ GValue *min_value,
+ GValue *max_value)
+{
+ gboolean retval;
+ GType gtype;
+
+ g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+ g_return_val_if_fail (min_value != NULL, FALSE);
+ g_return_val_if_fail (max_value != NULL, FALSE);
+
+ gtype = G_PARAM_SPEC (property)->value_type;
+ g_return_val_if_fail (g_value_type_compatible (gtype, G_VALUE_TYPE (min_value)), FALSE);
+ g_return_val_if_fail (g_value_type_compatible (gtype, G_VALUE_TYPE (max_value)), FALSE);
+
+ switch (gtype)
+ {
+ case G_TYPE_BOOLEAN:
+ {
+ 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 (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.36
+ */
+void
+g_property_set_range (GProperty *property,
+ ...)
+{
+ GType gtype;
+ va_list args;
+
+ g_return_if_fail (G_IS_PROPERTY (property));
+ g_return_if_fail (!property->is_installed);
+
+ gtype = G_PARAM_SPEC (property)->value_type;
+ g_return_if_fail (gtype != G_TYPE_INVALID);
+
+ va_start (args, property);
+
+ switch (G_TYPE_FUNDAMENTAL (gtype))
+ {
+ case G_TYPE_BOOLEAN:
+ {
+ gboolean min_v = va_arg (args, gboolean);
+ gboolean max_v = va_arg (args, gboolean);
+
+ g_boolean_property_set_range (property, min_v, max_v);
+ }
+ break;
+
+ case G_TYPE_INT:
+ {
+ gint min_v = va_arg (args, gint);
+ gint max_v = va_arg (args, gint);
+
+ 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:
+ {
+ gint64 min_v = va_arg (args, gint64);
+ gint64 max_v = va_arg (args, gint64);
+
+ g_int64_property_set_range (property, min_v, max_v);
+ }
+ break;
+
+ case G_TYPE_LONG:
+ {
+ glong min_v = va_arg (args, glong);
+ glong max_v = va_arg (args, glong);
+
+ g_long_property_set_range (property, min_v, max_v);
+ }
+ break;
+
+ case G_TYPE_UINT:
+ {
+ guint min_v = va_arg (args, guint);
+ guint max_v = va_arg (args, guint);
+
+ 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:
+ {
+ guint64 min_v = va_arg (args, guint64);
+ guint64 max_v = va_arg (args, guint64);
+
+ g_uint64_property_set_range (property, min_v, max_v);
+ }
+ break;
+
+ case G_TYPE_ULONG:
+ {
+ gulong min_v = va_arg (args, gulong);
+ gulong max_v = va_arg (args, gulong);
+
+ g_ulong_property_set_range (property, min_v, max_v);
+ }
+ break;
+
+ case G_TYPE_FLOAT:
+ {
+ gfloat min_v = va_arg (args, gdouble);
+ gfloat max_v = va_arg (args, gdouble);
+
+ g_float_property_set_range (property, min_v, max_v);
+ }
+ break;
+
+ case G_TYPE_DOUBLE:
+ {
+ gdouble min_v = va_arg (args, gdouble);
+ gdouble max_v = va_arg (args, gdouble);
+
+ g_double_property_set_range (property, min_v, max_v);
+ }
+ break;
+
+ default:
+ g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype));
+ }
+
+ va_end (args);
+}
+
+/**
+ * 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.36
+ */
+gboolean
+g_property_get_range (GProperty *property,
+ ...)
+{
+ va_list var_args;
+ GType gtype;
+ gboolean retval;
+ gpointer min_p, max_p;
+
+ g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+ g_return_val_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID, FALSE);
+
+ gtype = G_PARAM_SPEC (property)->value_type;
+
+ va_start (var_args, property);
+
+ min_p = va_arg (var_args, gpointer);
+ max_p = va_arg (var_args, gpointer);
+
+ switch (G_TYPE_FUNDAMENTAL (gtype))
+ {
+ case G_TYPE_BOOLEAN:
+ g_boolean_property_get_range (property, (gboolean *) min_p, (gboolean *) max_p);
+ retval = TRUE;
+ break;
+
+ case G_TYPE_INT:
+ switch (property->type_size)
+ {
+ case 1:
+ g_int8_property_get_range (property, (gint8 *) min_p, (gint8 *) max_p);
+ retval = TRUE;
+ break;
+
+ case 2:
+ g_int16_property_get_range (property, (gint16 *) min_p, (gint16 *) max_p);
+ retval = TRUE;
+ break;
+
+ case 4:
+ g_int32_property_get_range (property, (gint32 *) min_p, (gint32 *) max_p);
+ retval = TRUE;
+ break;
+
+ default:
+ g_int_property_get_range (property, (gint *) min_p, (gint *) max_p);
+ retval = TRUE;
+ break;
+ }
+ break;
+
+ case G_TYPE_INT64:
+ g_int64_property_get_range (property, (gint64 *) min_p, (gint64 *) max_p);
+ retval = TRUE;
+ break;
+
+ case G_TYPE_LONG:
+ g_long_property_get_range (property, (glong *) min_p, (glong *) max_p);
+ retval = TRUE;
+ break;
+
+ case G_TYPE_UINT:
+ switch (property->type_size)
+ {
+ case 1:
+ g_uint8_property_get_range (property, (guint8 *) min_p, (guint8 *) max_p);
+ retval = TRUE;
+ break;
+
+ case 2:
+ g_uint16_property_get_range (property, (guint16 *) min_p, (guint16 *) max_p);
+ retval = TRUE;
+ break;
+
+ case 4:
+ g_uint32_property_get_range (property, (guint32 *) min_p, (guint32 *) max_p);
+ retval = TRUE;
+ break;
+
+ default:
+ g_uint_property_get_range (property, (guint *) min_p, (guint *) max_p);
+ retval = TRUE;
+ break;
+ }
+ break;
+
+ case G_TYPE_UINT64:
+ g_uint64_property_get_range (property, (guint64 *) min_p, (guint64 *) max_p);
+ retval = TRUE;
+ break;
+
+ case G_TYPE_ULONG:
+ g_ulong_property_get_range (property, (gulong *) min_p, (gulong *) max_p);
+ retval = TRUE;
+ break;
+
+ case G_TYPE_FLOAT:
+ g_float_property_get_range (property, (gfloat *) min_p, (gfloat *) max_p);
+ retval = TRUE;
+ break;
+
+ case G_TYPE_DOUBLE:
+ g_double_property_get_range (property, (gdouble *) min_p, (gdouble *) max_p);
+ retval = TRUE;
+ break;
+
+ default:
+ g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype));
+ retval = FALSE;
+ }
+
+ va_end (var_args);
+
+ return retval;
+}
+
+/**
+ * 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.36
+ */
+void
+g_property_set_default_value (GProperty *property,
+ const GValue *default_value)
+{
+ GValue *value;
+ GType gtype;
+
+ g_return_if_fail (G_IS_PROPERTY (property));
+ g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
+ g_return_if_fail (default_value != NULL);
+
+ gtype = G_PARAM_SPEC (property)->value_type;
+
+ g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (default_value), gtype));
+
+ value = g_new0 (GValue, 1);
+ g_value_init (value, gtype);
+ 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;
+ }
+
+ property_set_default_for_type (property, G_TYPE_INVALID, value);
+}
+
+/**
+ * g_property_override_default_value:
+ * @property: a #GProperty
+ * @class_gtype: the type of the class overriding the value
+ * @default_value: a #GValue containing a value with the type of the
+ * property or a transformable type
+ *
+ * Overrides the default value of a @property for the given class
+ * type.
+ *
+ * This function should only be called by language bindings.
+ *
+ * Since: 2.36
+ */
+void
+g_property_override_default_value (GProperty *property,
+ GType class_gtype,
+ const GValue *default_value)
+{
+ GValue *value;
+ GType gtype;
+
+ g_return_if_fail (G_IS_PROPERTY (property));
+ g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
+ g_return_if_fail (g_type_name (class_gtype) != 0);
+ g_return_if_fail (default_value != NULL);
+
+ gtype = G_PARAM_SPEC (property)->value_type;
+
+ g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (default_value), gtype));
+
+ value = g_new0 (GValue, 1);
+ g_value_init (value, gtype);
+ 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;
+ }
+
+ /* takes ownership of value */
+ property_set_default_for_type (property, class_gtype, 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.
+ *
+ * Return value: %TRUE if there is a default got the given type,
+ * and %FALSE otherwise.
+ *
+ * Since: 2.36
+ */
+gboolean
+g_property_get_default_value_for_type (GProperty *property,
+ GType gtype,
+ GValue *value)
+{
+ const GValue *default_value = NULL;
+ GType iter;
+
+ g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+ g_return_val_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID, FALSE);
+ g_return_val_if_fail (g_type_name (gtype) != 0, FALSE);
+
+ /* we need to recurse through the inheritance chain... */
+ iter = gtype;
+ while (iter != G_TYPE_INVALID && default_value == NULL)
+ {
+ default_value = property_get_default_for_type (property, iter);
+ gtype = g_type_parent (iter);
+ }
+
+ if (default_value != NULL)
+ goto out;
+
+ /* ... and eventually check the implemented interfaces */
+ if (default_value == NULL)
+ {
+ GType *ifaces;
+ guint n_ifaces;
+
+ ifaces = g_type_interfaces (gtype, &n_ifaces);
+ while (n_ifaces-- && default_value == NULL)
+ {
+ iter = ifaces[n_ifaces];
+ default_value = property_get_default_for_type (property, iter);
+ }
+
+ g_free (ifaces);
+ }
+
+ if (default_value != NULL)
+ goto out;
+
+ /* if the property hasn't been overridden then we look for the default */
+ default_value = property_get_default_for_type (property, G_TYPE_INVALID);
+
+ if (default_value == NULL)
+ {
+ g_critical (G_STRLOC ": No default value of property '%s' "
+ "was found for type '%s'",
+ G_PARAM_SPEC (property)->name,
+ g_type_name (gtype));
+
+ return FALSE;
+ }
+
+out:
+ if (!g_value_transform (default_value, value))
+ {
+ g_critical (G_STRLOC ": Unable to transform a value of type '%s' "
+ "into a value of type '%s'",
+ g_type_name (G_VALUE_TYPE (default_value)),
+ g_type_name (G_VALUE_TYPE (value)));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * 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.
+ *
+ * Return value: %TRUE if a default value was found, and %FALSE
+ * otherwise
+ *
+ * Since: 2.36
+ */
+gboolean
+g_property_get_default_value (GProperty *property,
+ gpointer gobject,
+ GValue *value)
+{
+ g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
+
+ return g_property_get_default_value_for_type (property,
+ G_OBJECT_TYPE (gobject),
+ value);
+}
+
+/**
+ * g_property_set_default:
+ * @property: a #GProperty
+ * @...: the default value for the property
+ *
+ * Sets the default value of @property.
+ *
+ * This function can only be called once for each property; derived
+ * types should call g_property_override_default() instead.
+ *
+ * See also g_property_override_default() and
+ * g_object_class_override_property_default().
+ *
+ * Since: 2.36
+ */
+void
+g_property_set_default (GProperty *property,
+ ...)
+{
+ GValue *value;
+ GType p_type;
+ gchar *error;
+ va_list var_args;
+
+ g_return_if_fail (G_IS_PROPERTY (property));
+ g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
+
+ p_type = G_PARAM_SPEC (property)->value_type;
+
+ va_start (var_args, property);
+
+ value = g_new0 (GValue, 1);
+ G_VALUE_COLLECT_INIT (value, p_type, var_args, 0, &error);
+ if (error != NULL)
+ {
+ g_critical (G_STRLOC ": %s", error);
+ g_free (error);
+ g_value_unset (value);
+ g_free (value);
+ }
+ else
+ {
+ /* takes ownership of the GValue */
+ property_set_default_for_type (property, G_TYPE_INVALID, value);
+ }
+
+ va_end (var_args);
+}
+
+/**
+ * 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.36
+ */
+void
+g_property_get_default (GProperty *property,
+ gpointer gobject,
+ ...)
+{
+ GValue value = { 0, };
+ GType gtype, p_type;
+ gchar *error;
+ va_list var_args;
+ const GValue *default_value = NULL;
+
+ g_return_if_fail (G_IS_PROPERTY (property));
+ g_return_if_fail (G_IS_OBJECT (gobject));
+ g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
+
+ p_type = G_PARAM_SPEC (property)->value_type;
+
+ /* we perform a copy here because if the default value was not found,
+ * we can use the pre-initialized value safely in G_VALUE_LCOPY and
+ * return something sensible
+ */
+ g_value_init (&value, p_type);
+
+ gtype = G_OBJECT_TYPE (gobject);
+
+ /* we need to recurse through the inheritance chain... */
+ while (gtype != G_TYPE_INVALID && default_value == NULL)
+ {
+ default_value = property_get_default_for_type (property, gtype);
+ gtype = g_type_parent (gtype);
+ }
+
+ if (default_value != NULL)
+ goto lcopy;
+
+ /* ... 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)
+ {
+ gtype = ifaces[n_ifaces];
+ default_value = property_get_default_for_type (property, gtype);
+ }
+
+ g_free (ifaces);
+ }
+
+ if (default_value != NULL)
+ goto lcopy;
+
+ /* if the property hasn't been overridden then we look for the default */
+ default_value = property_get_default_for_type (property, G_TYPE_INVALID);
+
+lcopy:
+ if (default_value != NULL)
+ g_value_copy (default_value, &value);
+ else
+ g_critical (G_STRLOC ": No default value of property '%s' "
+ "was found for type '%s'",
+ G_PARAM_SPEC (property)->name,
+ G_OBJECT_TYPE_NAME (gobject));
+
+ 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_override_default:
+ * @property: a #GProperty
+ * @class_gtype: the type of the class overriding the default
+ * @...: the new default value for the property
+ *
+ * Overrides the default value of @property for the given class type.
+ *
+ * Since: 2.36
+ */
+void
+g_property_override_default (GProperty *property,
+ GType class_gtype,
+ ...)
+{
+ GValue *value;
+ GType p_type;
+ gchar *error;
+ va_list var_args;
+
+ g_return_if_fail (G_IS_PROPERTY (property));
+ g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID);
+ g_return_if_fail (g_type_name (class_gtype) != 0);
+
+ p_type = G_PARAM_SPEC (property)->value_type;
+
+ va_start (var_args, class_gtype);
+
+ value = g_new0 (GValue, 1);
+ G_VALUE_COLLECT_INIT (value, p_type, var_args, 0, &error);
+ if (error != NULL)
+ {
+ g_critical (G_STRLOC ": %s", error);
+ g_free (error);
+ g_value_unset (value);
+ g_free (value);
+ }
+ else
+ {
+ /* takes ownership of the GValue */
+ property_set_default_for_type (property, class_gtype, value);
+ }
+
+ va_end (var_args);
+}
+
+/**
+ * g_property_set_va:
+ * @property: a #GProperty
+ * @gobject: a #GObject instance
+ * @flags: collection flags, as a bitwise or of #GPropertyCollectFlags values
+ * @args: the value to set, inside a pointer to 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.36
+ */
+gboolean
+g_property_set_va (GProperty *property,
+ gpointer gobject,
+ GPropertyCollectFlags flags,
+ 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);
+
+ g_object_ref (gobject);
+
+ gtype = ((GParamSpec *) property)->value_type;
+
+ 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;
+
+ case G_TYPE_POINTER:
+ retval = g_pointer_property_set_value (property, gobject, va_arg (*args, gpointer));
+ break;
+
+ default:
+ g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype));
+ retval = FALSE;
+ break;
+ }
+
+ g_object_unref (gobject);
+
+ return retval;
+}
+
+/**
+ * g_property_get_va:
+ * @property: a #GProperty
+ * @gobject: a #GObject instance
+ * @flags: collection flags
+ * @args: a pointer to 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.36
+ */
+gboolean
+g_property_get_va (GProperty *property,
+ gpointer gobject,
+ GPropertyCollectFlags flags,
+ 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);
+
+ gtype = G_PARAM_SPEC (property)->value_type;
+
+ ret_p = va_arg (*args, gpointer);
+ if (ret_p == NULL)
+ {
+ g_critical (G_STRLOC ": value location for a property of type '%s' passed as NULL",
+ g_type_name (gtype));
+ return FALSE;
+ }
+
+ 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:
+ {
+ const gchar *value;
+
+ value = g_string_property_get_value (property, gobject);
+
+ if (((flags & G_PROPERTY_COLLECT_COPY) != 0) &&
+ (property->flags & G_PROPERTY_COPY_GET) == 0)
+ {
+ (* (gchar **) ret_p) = g_strdup (value);
+ }
+ else
+ (* (gconstpointer *) ret_p) = value;
+ }
+ break;
+
+ case G_TYPE_BOXED:
+ {
+ gpointer boxed;
+
+ boxed = g_boxed_property_get_value (property, gobject);
+
+ if (((flags & G_PROPERTY_COLLECT_COPY) != 0) &&
+ (property->flags & G_PROPERTY_COPY_GET) == 0)
+ {
+ if (boxed != NULL)
+ (* (gpointer *) ret_p) = g_boxed_copy (gtype, boxed);
+ else
+ (* (gpointer *) ret_p) = NULL;
+ }
+ else
+ (* (gpointer *) ret_p) = (gpointer) boxed;
+ }
+ break;
+
+ case G_TYPE_OBJECT:
+ {
+ gpointer obj = g_object_property_get_value (property, gobject);
+
+ if ((((flags & G_PROPERTY_COLLECT_REF) != 0) &&
+ (property->flags & G_PROPERTY_COPY_GET) == 0) &&
+ (obj != NULL))
+ {
+ (* (gpointer *) ret_p) = g_object_ref (obj);
+ }
+ else
+ (* (gpointer *) ret_p) = obj;
+ }
+ break;
+
+ case G_TYPE_POINTER:
+ (* (gpointer *) ret_p) = g_pointer_property_get_value (property, gobject);
+ break;
+
+ default:
+ g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype));
+ return FALSE;
+ }
+
+ 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.36
+ */
+gboolean
+g_property_set (GProperty *property,
+ gpointer gobject,
+ ...)
+{
+ va_list args;
+ gboolean res;
+
+ va_start (args, gobject);
+ res = g_property_set_va (property, gobject, 0, &args);
+ va_end (args);
+
+ return res;
+}
+
+/**
+ * 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.
+ *
+ * Since: 2.36
+ */
+gboolean
+g_property_get (GProperty *property,
+ gpointer gobject,
+ ...)
+{
+ va_list args;
+ gboolean retval;
+
+ va_start (args, gobject);
+ retval = g_property_get_va (property, gobject, 0, &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.36
+ */
+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);
+
+ gtype = G_PARAM_SPEC (property)->value_type;
+
+ 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;
+ }
+
+ g_object_ref (gobject);
+
+ 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;
+
+ case G_TYPE_POINTER:
+ g_pointer_property_set_value (property, gobject, g_value_get_pointer (©));
+ break;
+
+ default:
+ g_critical (G_STRLOC ": Invalid type %s", g_type_name (G_VALUE_TYPE (©)));
+ break;
+ }
+
+ g_object_unref (gobject);
+
+ 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.36
+ */
+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);
+
+ gtype = G_PARAM_SPEC (property)->value_type;
+
+ 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_schar (©, 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;
+
+ case G_TYPE_POINTER:
+ g_value_set_pointer (©, g_pointer_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.36
+ */
+GType
+g_property_get_value_type (GProperty *property)
+{
+ g_return_val_if_fail (G_IS_PROPERTY (property), G_TYPE_INVALID);
+
+ return G_PARAM_SPEC (property)->value_type;
+}
+
+/**
+ * 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.36
+ */
+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);
+
+ gtype = G_PARAM_SPEC (property)->value_type;
+
+ 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 1:
+ retval = g_int8_property_validate (property, va_arg (args, gint));
+ break;
+
+ case 2:
+ retval = g_int16_property_validate (property, va_arg (args, gint));
+ break;
+
+ case 4:
+ 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 1:
+ retval = g_uint8_property_validate (property, va_arg (args, guint));
+ break;
+
+ case 2:
+ retval = g_uint16_property_validate (property, va_arg (args, guint));
+ break;
+
+ case 4:
+ 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.36
+ */
+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);
+
+ gtype = G_PARAM_SPEC (property)->value_type;
+
+ 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 1:
+ retval = g_int8_property_validate (property, val);
+ break;
+
+ case 2:
+ retval = g_int16_property_validate (property, val);
+ break;
+
+ case 4:
+ 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 1:
+ retval = g_uint8_property_validate (property, val);
+ break;
+
+ case 2:
+ retval = g_uint16_property_validate (property, val);
+ break;
+
+ case 4:
+ 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.36
+ */
+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.36
+ */
+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.36
+ */
+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.36
+ */
+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_is_copy_set:
+ * @property: a #GProperty
+ *
+ * Checks whether the @property has the %G_PROPERTY_COPY_SET flag set.
+ *
+ * Return value: %TRUE if the flag is set, and %FALSE otherwise
+ *
+ * Since: 2.36
+ */
+gboolean
+g_property_is_copy_set (GProperty *property)
+{
+ g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+
+ return (property->flags & G_PROPERTY_COPY_SET) != 0;
+}
+
+/**
+ * g_property_is_copy_get:
+ * @property: a #GProperty
+ *
+ * Checks whether the @property has the %G_PROPERTY_COPY_GET flag set.
+ *
+ * Return value: %TRUE if the flag is set, and %FALSE otherwise
+ *
+ * Since: 2.36
+ */
+gboolean
+g_property_is_copy_get (GProperty *property)
+{
+ g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+
+ return (property->flags & G_PROPERTY_COPY_GET) != 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.36
+ */
+void
+g_property_lock (GProperty *property,
+ gpointer gobject)
+{
+ g_return_if_fail (G_IS_PROPERTY (property));
+ g_return_if_fail (G_IS_OBJECT (gobject));
+
+ property_lock_internal (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.36
+ */
+void
+g_property_unlock (GProperty *property,
+ gpointer gobject)
+{
+ g_return_if_fail (G_IS_PROPERTY (property));
+ g_return_if_fail (G_IS_OBJECT (gobject));
+
+ property_unlock_internal (property, gobject);
+}
+
+/**
+ * g_property_set_lock_functions:
+ * @property: a #GProperty
+ * @lock_func: (allow-none): the function to be called when locking
+ * the @property, or %NULL for the default locking function
+ * @unlock_func: (allow-none): the function to be called when unlocking
+ * the @property, or %NULL for the default unlocking function
+ *
+ * Replaces the locking and unlocking functions for @property with
+ * custom functions.
+ *
+ * Since: 2.36
+ */
+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);
+
+ property->lock_func = lock_func;
+ property->unlock_func = unlock_func;
+}
+
+static void
+property_finalize (GParamSpec *pspec)
+{
+ GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (G_TYPE_PROPERTY));
+
+ parent_class->finalize (pspec);
+}
+
+static void
+property_set_default (GParamSpec *pspec,
+ GValue *value)
+{
+ GProperty *property = G_PROPERTY (pspec);
+ const GValue *default_value;
+
+ default_value = property_get_default_for_type (property, G_TYPE_INVALID);
+ if (default_value != NULL)
+ g_value_copy (default_value, value);
+}
+
+static gboolean
+property_validate (GParamSpec *pspec,
+ GValue *value)
+{
+ GProperty *property = G_PROPERTY (pspec);
+
+ if (!g_value_type_transformable (G_VALUE_TYPE (value), pspec->value_type))
+ return TRUE;
+
+ return !g_property_validate_value (property, 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);
+
+ pspec->value_type = G_TYPE_INVALID;
+
+ property->field_offset = -1;
+ property->priv_offset = -1;
+
+ property->lock_func = NULL;
+ property->unlock_func = NULL;
+}
+
+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 000000000..c78e44d28
--- /dev/null
+++ b/gobject/gproperty.h
@@ -0,0 +1,745 @@
+/* gproperty.h: Property definitions for GObject
+ *
+ * Copyright © 2012 Emmanuele Bassi
+ *
+ * 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.
+ */
+
+#if !defined (__GLIB_GOBJECT_H_INSIDE__) && !defined (GOBJECT_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#ifndef __G_PROPERTY_H__
+#define __G_PROPERTY_H__
+
+#include
+#include
+#include
+
+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 GProperty structure is an opaque structure
+ * whose members cannot be directly accessed.
+ *
+ * Since: 2.36
+ */
+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.
+ * @G_PROPERTY_COPY_SET: Whether the property will make a copy or
+ * take a reference when being set to a new value
+ * @G_PROPERTY_COPY_GET: Whether the property will make a copy or
+ * take a reference when the value is being retrieved
+ * @G_PROPERTY_COPY: Whether the property will make a copy, or take a
+ * reference, of the new value being set, and return a copy, or
+ * increase the reference count, of the value being retrieved
+ *
+ * Flags for properties declared using #GProperty and relative macros.
+ *
+ * This enumeration might be extended at later date.
+ *
+ * Since: 2.36
+ */
+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,
+ G_PROPERTY_COPY_SET = 1 << 4,
+ G_PROPERTY_COPY_GET = 1 << 5,
+ G_PROPERTY_COPY = (G_PROPERTY_COPY_SET | G_PROPERTY_COPY_GET)
+} GPropertyFlags;
+
+GLIB_AVAILABLE_IN_2_36
+GType g_property_get_type (void) G_GNUC_CONST;
+
+/* general purpose API */
+GLIB_AVAILABLE_IN_2_36
+gchar * g_property_canonicalize_name (const char *name);
+
+GLIB_AVAILABLE_IN_2_36
+GType g_property_get_value_type (GProperty *property);
+
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_is_writable (GProperty *property);
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_is_readable (GProperty *property);
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_is_deprecated (GProperty *property);
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_is_atomic (GProperty *property);
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_is_copy_set (GProperty *property);
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_is_copy_get (GProperty *property);
+
+GLIB_AVAILABLE_IN_2_36
+void g_property_describe (GProperty *property,
+ const char *nick,
+ const char *blurb);
+
+GLIB_AVAILABLE_IN_2_36
+void g_property_set_range_values (GProperty *property,
+ const GValue *min_value,
+ const GValue *max_value);
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_get_range_values (GProperty *property,
+ GValue *min_value,
+ GValue *max_value);
+GLIB_AVAILABLE_IN_2_36
+void g_property_set_range (GProperty *property,
+ ...);
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_get_range (GProperty *property,
+ ...);
+
+GLIB_AVAILABLE_IN_2_36
+void g_property_set_default_value (GProperty *property,
+ const GValue *value);
+GLIB_AVAILABLE_IN_2_36
+void g_property_set_default (GProperty *property,
+ ...);
+GLIB_AVAILABLE_IN_2_36
+void g_property_override_default_value (GProperty *property,
+ GType class_gtype,
+ const GValue *value);
+GLIB_AVAILABLE_IN_2_36
+void g_property_override_default (GProperty *property,
+ GType class_gtype,
+ ...);
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_get_default_value_for_type (GProperty *property,
+ GType gtype,
+ GValue *value);
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_get_default_value (GProperty *property,
+ gpointer gobject,
+ GValue *value);
+GLIB_AVAILABLE_IN_2_36
+void g_property_get_default (GProperty *property,
+ gpointer gobject,
+ ...);
+
+GLIB_AVAILABLE_IN_2_36
+void g_property_set_prerequisite (GProperty *property,
+ GType gtype);
+
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_validate (GProperty *property,
+ ...);
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_validate_value (GProperty *property,
+ GValue *value);
+
+GLIB_AVAILABLE_IN_2_36
+void g_property_set_value (GProperty *property,
+ gpointer gobject,
+ const GValue *value);
+GLIB_AVAILABLE_IN_2_36
+void g_property_get_value (GProperty *property,
+ gpointer gobject,
+ GValue *value);
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_set (GProperty *property,
+ gpointer gobject,
+ ...);
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_get (GProperty *property,
+ gpointer gobject,
+ ...);
+
+/**
+ * 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 when collecting
+ * pointer locations for object values
+ *
+ * Flags to pass to g_property_collect() and g_property_lcopy().
+ *
+ * Since: 2.36
+ */
+typedef enum { /*< prefix=G_PROPERTY_COLLECT >*/
+ G_PROPERTY_COLLECT_NONE = 0,
+
+ G_PROPERTY_COLLECT_COPY = 1 << 0,
+ G_PROPERTY_COLLECT_REF = 1 << 1
+} GPropertyCollectFlags;
+
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_set_va (GProperty *property,
+ gpointer gobject,
+ GPropertyCollectFlags flags,
+ va_list *app);
+GLIB_AVAILABLE_IN_2_36
+gboolean g_property_get_va (GProperty *property,
+ gpointer gobject,
+ GPropertyCollectFlags flags,
+ va_list *app);
+
+typedef void (* GPropertyLockFunc) (GProperty *property,
+ gpointer gobject);
+
+typedef void (* GPropertyUnlockFunc) (GProperty *property,
+ gpointer gobject);
+
+GLIB_AVAILABLE_IN_2_36
+void g_property_set_lock_functions (GProperty *property,
+ GPropertyLockFunc lock_func,
+ GPropertyUnlockFunc unlock_func);
+GLIB_AVAILABLE_IN_2_36
+void g_property_lock (GProperty *property,
+ gpointer gobject);
+GLIB_AVAILABLE_IN_2_36
+void g_property_unlock (GProperty *property,
+ gpointer gobject);
+
+/* private API */
+GLIB_AVAILABLE_IN_2_36
+void _g_property_set_installed (GProperty *property,
+ gpointer g_class,
+ GType class_gtype);
+
+/* per-type specific accessors */
+typedef gboolean (* GPropertyBooleanSet) (gpointer gobject,
+ gboolean value);
+typedef gboolean (* GPropertyBooleanGet) (gpointer gobject);
+
+typedef gboolean (* GPropertyIntSet) (gpointer gobject,
+ gint value);
+typedef gint (* GPropertyIntGet) (gpointer gobject);
+
+typedef gboolean (* GPropertyInt8Set) (gpointer gobject,
+ gint8 value);
+typedef gint8 (* GPropertyInt8Get) (gpointer gobject);
+
+typedef gboolean (* GPropertyInt16Set) (gpointer gobject,
+ gint16 value);
+typedef gint16 (* GPropertyInt16Get) (gpointer gobject);
+
+typedef gboolean (* GPropertyInt32Set) (gpointer gobject,
+ gint32 value);
+typedef gint32 (* GPropertyInt32Get) (gpointer gobject);
+
+typedef gboolean (* GPropertyInt64Set) (gpointer gobject,
+ gint64 value);
+typedef gint64 (* GPropertyInt64Get) (gpointer gobject);
+
+typedef gboolean (* GPropertyLongSet) (gpointer gobject,
+ glong value);
+typedef glong (* GPropertyLongGet) (gpointer gobject);
+
+typedef gboolean (* GPropertyUIntSet) (gpointer gobject,
+ guint value);
+typedef guint (* GPropertyUIntGet) (gpointer gobject);
+
+typedef gboolean (* GPropertyUInt8Set) (gpointer gobject,
+ guint8 value);
+typedef guint8 (* GPropertyUInt8Get) (gpointer gobject);
+
+typedef gboolean (* GPropertyUInt16Set) (gpointer gobject,
+ guint16 value);
+typedef guint16 (* GPropertyUInt16Get) (gpointer gobject);
+
+typedef gboolean (* GPropertyUInt32Set) (gpointer gobject,
+ guint32 value);
+typedef guint32 (* GPropertyUInt32Get) (gpointer gobject);
+
+typedef gboolean (* GPropertyUInt64Set) (gpointer gobject,
+ guint64 value);
+typedef guint64 (* GPropertyUInt64Get) (gpointer gobject);
+
+typedef gboolean (* GPropertyULongSet) (gpointer gobject,
+ gulong value);
+typedef gulong (* GPropertyULongGet) (gpointer gobject);
+
+typedef gboolean (* GPropertyEnumSet) (gpointer gobject,
+ glong value);
+typedef glong (* GPropertyEnumGet) (gpointer gobject);
+
+typedef gboolean (* GPropertyFlagsSet) (gpointer gobject,
+ glong value);
+typedef glong (* GPropertyFlagsGet) (gpointer gobject);
+
+typedef gboolean (* GPropertyFloatSet) (gpointer gobject,
+ gfloat value);
+typedef gfloat (* GPropertyFloatGet) (gpointer gobject);
+
+typedef gboolean (* GPropertyDoubleSet) (gpointer gobject,
+ gdouble value);
+typedef gdouble (* GPropertyDoubleGet) (gpointer gobject);
+
+typedef gboolean (* GPropertyStringSet) (gpointer gobject,
+ const char *value);
+typedef const char * (* GPropertyStringGet) (gpointer gobject);
+
+typedef gboolean (* GPropertyBoxedSet) (gpointer gobject,
+ gpointer value);
+typedef gpointer (* GPropertyBoxedGet) (gpointer gobject);
+
+typedef gboolean (* GPropertyObjectSet) (gpointer gobject,
+ gpointer value);
+typedef gpointer (* GPropertyObjectGet) (gpointer gobject);
+
+typedef gboolean (* GPropertyPointerSet) (gpointer gobject,
+ gpointer value);
+typedef gpointer (* GPropertyPointerGet) (gpointer gobject);
+
+/* per-type specific constructors */
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_boolean_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyBooleanSet setter,
+ GPropertyBooleanGet getter);
+
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_int_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyIntSet setter,
+ GPropertyIntGet getter);
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_int8_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyInt8Set setter,
+ GPropertyInt8Get getter);
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_int16_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyInt16Set setter,
+ GPropertyInt16Get getter);
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_int32_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyInt32Set setter,
+ GPropertyInt32Get getter);
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_int64_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyInt64Set setter,
+ GPropertyInt64Get getter);
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_long_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyLongSet setter,
+ GPropertyLongGet getter);
+
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_uint_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyUIntSet setter,
+ GPropertyUIntGet getter);
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_uint8_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyUInt8Set setter,
+ GPropertyUInt8Get getter);
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_uint16_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyUInt16Set setter,
+ GPropertyUInt16Get getter);
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_uint32_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyUInt32Set setter,
+ GPropertyUInt32Get getter);
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_uint64_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyUInt64Set setter,
+ GPropertyUInt64Get getter);
+GLIB_AVAILABLE_IN_2_36
+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
+
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_enum_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyEnumSet setter,
+ GPropertyEnumGet getter);
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_flags_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyFlagsSet setter,
+ GPropertyFlagsGet getter);
+
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_float_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyFloatSet setter,
+ GPropertyFloatGet getter);
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_double_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyDoubleSet setter,
+ GPropertyDoubleGet getter);
+
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_string_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyStringSet setter,
+ GPropertyStringGet getter);
+
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_boxed_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyBoxedSet setter,
+ GPropertyBoxedGet getter);
+
+GLIB_AVAILABLE_IN_2_36
+GParamSpec * g_object_property_new (const gchar *name,
+ GPropertyFlags flags,
+ gssize field_offset,
+ GPropertyObjectSet setter,
+ GPropertyObjectGet getter);
+
+GLIB_AVAILABLE_IN_2_36
+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_IS_PROPERTY (g_property)) \
+ { \
+ g_critical (G_STRLOC ": Property " #f_n " is not a GProperty"); \
+ return (f_t) 0; \
+ } \
+\
+ if (!g_property_is_readable (g_property)) \
+ { \
+ g_critical (G_STRLOC ": The property " #f_n " is not readable"); \
+ return (f_t) 0; \
+ } \
+\
+ 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_IS_PROPERTY (g_property)) \
+ { \
+ g_critical (G_STRLOC ": Property " #f_n " is not a GProperty"); \
+ 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 @TypeNamePrivate structure
+ * @field_name: the name of the property, which must match the name of the
+ * field in the @TypeNamePrivate structure
+ *
+ * Declares the accessor functions for a @field_name property in the
+ * class @TypeName. This macro should only be used in header files.
+ *
+ * Since: 2.30
+ */
+#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.30
+ */
+#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.30
+ */
+#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 @TypeNamePrivate structure
+ * @field_name: the name of the property, which must match the name of the
+ * field in the @TypeNamePrivate 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.30
+ */
+
+#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_nPrivate structure
+ * @f_n: the name of the property, which must match the name of the
+ * field in the @T_nPrivate 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.30
+ */
+#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 @TypeNamePrivate structure
+ * @field_name: the name of the property, which must match the name of the
+ * field in the @TypeNamePrivate 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.30
+ */
+#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 @TypeNamePrivate structure
+ * @field_name: the name of the property, which must match the name of the
+ * field in the @TypeNamePrivate 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 @TypeNamePrivate structure
+ * @f_n: the name of the property, which must match the name of the
+ * field in the @TypeNamePrivate 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.30
+ */
+#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/gtype.c b/gobject/gtype.c
index 96e82b946..a2dcf60cf 100644
--- a/gobject/gtype.c
+++ b/gobject/gtype.c
@@ -4501,16 +4501,82 @@ g_type_class_add_private (gpointer g_class,
G_WRITE_UNLOCK (&type_rw_lock);
}
-gpointer
-g_type_instance_get_private (GTypeInstance *instance,
- GType private_type)
+static gssize
+lookup_instance_private_offset (GTypeClass *class,
+ GType private_type)
{
TypeNode *instance_node;
TypeNode *private_node;
TypeNode *parent_node;
- GTypeClass *class;
gsize offset;
+ g_return_val_if_fail (class != NULL, -1);
+
+ instance_node = lookup_type_node_I (class->g_type);
+ if (G_UNLIKELY (!instance_node || !instance_node->is_instantiatable))
+ {
+ g_warning ("class of invalid non-instantiatable type `%s'",
+ type_descriptive_name_I (class->g_type));
+ return -1;
+ }
+
+ private_node = lookup_type_node_I (private_type);
+ if (G_UNLIKELY (!private_node || !NODE_IS_ANCESTOR (private_node, instance_node)))
+ {
+ g_warning ("attempt to retrieve private data for invalid type '%s'",
+ type_descriptive_name_I (private_type));
+ return -1;
+ }
+
+ offset = ALIGN_STRUCT (instance_node->data->instance.instance_size);
+
+ if (NODE_PARENT_TYPE (private_node))
+ {
+ parent_node = lookup_type_node_I (NODE_PARENT_TYPE (private_node));
+ g_assert (parent_node->data && NODE_REFCOUNT (parent_node) > 0);
+
+ if (G_UNLIKELY (private_node->data->instance.private_size == parent_node->data->instance.private_size))
+ {
+ g_warning ("g_type_class_get_instance_private_offset() requires a "
+ "prior call to g_type_class_add_private()");
+ return -1;
+ }
+
+ offset += ALIGN_STRUCT (parent_node->data->instance.private_size);
+ }
+
+ return offset;
+}
+
+gssize
+g_type_class_get_instance_private_offset (gpointer g_class,
+ GType private_type)
+{
+ gssize offset;
+
+ g_return_val_if_fail (g_class != NULL, -1);
+
+ /* unlike with g_type_instance_get_private(), we need to acquire the
+ * read lock here because we may be called during class initialization
+ * type, which means that nodes may not be filled yet.
+ */
+ G_READ_LOCK (&type_rw_lock);
+
+ offset = lookup_instance_private_offset (g_class, private_type);
+
+ G_READ_UNLOCK (&type_rw_lock);
+
+ return offset;
+}
+
+gpointer
+g_type_instance_get_private (GTypeInstance *instance,
+ GType private_type)
+{
+ GTypeClass *class;
+ TypeNode *instance_node;
+ gssize offset;
+
g_return_val_if_fail (instance != NULL && instance->g_class != NULL, NULL);
/* while instances are initialized, their class pointers change,
@@ -4524,15 +4590,7 @@ g_type_instance_get_private (GTypeInstance *instance,
if (G_UNLIKELY (!instance_node || !instance_node->is_instantiatable))
{
g_warning ("instance of invalid non-instantiatable type `%s'",
- type_descriptive_name_I (instance->g_class->g_type));
- return NULL;
- }
-
- private_node = lookup_type_node_I (private_type);
- if (G_UNLIKELY (!private_node || !NODE_IS_ANCESTOR (private_node, instance_node)))
- {
- g_warning ("attempt to retrieve private data for invalid type '%s'",
- type_descriptive_name_I (private_type));
+ type_descriptive_name_I (class->g_type));
return NULL;
}
@@ -4542,22 +4600,9 @@ g_type_instance_get_private (GTypeInstance *instance,
* and node->data->instance.private_size are not going to be changed.
* for any of the relevant types.
*/
-
- offset = ALIGN_STRUCT (instance_node->data->instance.instance_size);
-
- if (NODE_PARENT_TYPE (private_node))
- {
- parent_node = lookup_type_node_I (NODE_PARENT_TYPE (private_node));
- g_assert (parent_node->data && NODE_REFCOUNT (parent_node) > 0);
-
- if (G_UNLIKELY (private_node->data->instance.private_size == parent_node->data->instance.private_size))
- {
- g_warning ("g_type_instance_get_private() requires a prior call to g_type_class_add_private()");
- return NULL;
- }
-
- offset += ALIGN_STRUCT (parent_node->data->instance.private_size);
- }
+ offset = lookup_instance_private_offset (class, private_type);
+ if (offset < 0)
+ return NULL;
return G_STRUCT_MEMBER_P (instance, offset);
}
diff --git a/gobject/gtype.h b/gobject/gtype.h
index 80a4ddf24..a18cec2a1 100644
--- a/gobject/gtype.h
+++ b/gobject/gtype.h
@@ -1264,6 +1264,10 @@ gpointer g_type_class_get_private (GTypeClass *klass,
GLIB_AVAILABLE_IN_2_34
void g_type_ensure (GType type);
+GLIB_AVAILABLE_IN_2_36
+gssize g_type_class_get_instance_private_offset (gpointer g_class,
+ GType private_type);
+
/* --- GType boilerplate --- */
/**
* G_DEFINE_TYPE:
diff --git a/gobject/tests/.gitignore b/gobject/tests/.gitignore
index 30fcd4116..fd6462840 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 212cbda60..7117220b8 100644
--- a/gobject/tests/Makefile.am
+++ b/gobject/tests/Makefile.am
@@ -11,8 +11,8 @@ else
glib_genmarshal=$(top_builddir)/gobject/glib-genmarshal
endif
-noinst_PROGRAMS = $(TEST_PROGS)
LDADD = ../libgobject-2.0.la $(top_builddir)/gthread/libgthread-2.0.la $(top_builddir)/glib/libglib-2.0.la
+noinst_PROGRAMS = $(TEST_PROGS) $(SAMPLE_PROGS)
TEST_PROGS += \
qdata \
@@ -26,7 +26,14 @@ TEST_PROGS += \
properties \
reference \
ifaceproperties \
- valuearray
+ valuearray \
+ autoproperties \
+ $(NULL)
+
+SAMPLE_PROGS = \
+ gproperty-example-base \
+ gproperty-example-derived \
+ $(NULL)
signals_SOURCES = signals.c marshalers.c
diff --git a/gobject/tests/autoproperties.c b/gobject/tests/autoproperties.c
new file mode 100644
index 000000000..81e090a79
--- /dev/null
+++ b/gobject/tests/autoproperties.c
@@ -0,0 +1,596 @@
+#include
+#include
+
+/* XXX: yuck, but a lot of the functions are macro-ized */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+
+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 dummy;
+
+ 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); /* for -Wmissing-prototypes */
+
+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); /* for -Wmissing-prototypes */
+
+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 TestBoxed *
+test_boxed_new (int x,
+ int y,
+ int width,
+ int height)
+{
+ TestBoxed *retval = g_new (TestBoxed, 1);
+
+ retval->x = x;
+ retval->y = y;
+ retval->width = width;
+ retval->height = height;
+ retval->ref_count = 1;
+
+ return retval;
+}
+
+static gpointer
+test_boxed_copy (gpointer data)
+{
+ if (data != NULL)
+ {
+ TestBoxed *boxed = data;
+
+ if (g_test_verbose ())
+ g_print ("*** copy of boxed %p (ref count: %d) ***\n", boxed, boxed->ref_count);
+
+ if (boxed->ref_count < 0)
+ return test_boxed_new (boxed->x, boxed->y, boxed->width, boxed->height);
+
+ boxed->ref_count += 1;
+ }
+
+ return data;
+}
+
+static void
+test_boxed_free (gpointer data)
+{
+ if (data != NULL)
+ {
+ TestBoxed *boxed = data;
+
+ if (g_test_verbose ())
+ g_print ("*** free of boxed %p (ref count: %d) ***\n", boxed, boxed->ref_count);
+
+ if (boxed->ref_count < 0)
+ return;
+
+ boxed->ref_count -= 1;
+
+ if (boxed->ref_count == 0)
+ g_free (boxed);
+ }
+}
+
+GType test_boxed_get_type (void); /* for -Wmissing-prototypes */
+
+G_DEFINE_BOXED_TYPE (TestBoxed, test_boxed, test_boxed_copy, test_boxed_free)
+
+static GParamSpec *test_object_properties[LAST_PROP] = { NULL, };
+
+GType test_object_get_type (void); /* for -Wmissing-prototypes */
+
+G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
+
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, int, foo)
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, gboolean, bar)
+G_DEFINE_PROPERTY_GET (TestObject, test_object, gboolean, str_set)
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, gint8, single_byte)
+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_SET (TestObject, test_object, const TestBoxed *, boxed)
+
+void
+test_object_get_boxed (TestObject *self,
+ TestBoxed *value)
+{
+ TestBoxed *boxed;
+
+ g_property_get (G_PROPERTY (test_object_properties[PROP_BOXED]), self, &boxed);
+
+ /* make sure that g_property_get() didn't copy/ref the pointer */
+ g_assert (boxed == self->priv->boxed);
+ g_assert_cmpint (boxed->ref_count, ==, self->priv->boxed->ref_count);
+
+ *value = *boxed;
+}
+
+gboolean
+test_object_set_str (TestObject *self,
+ const gchar *value)
+{
+ TestObjectPrivate *priv;
+
+ g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, test_object_get_type ()), FALSE);
+
+ priv = self->priv;
+
+ if (g_strcmp0 (priv->str, value) == 0)
+ return FALSE;
+
+ 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_SET]);
+
+ return TRUE;
+}
+
+G_DEFINE_PROPERTY_GET (TestObject, test_object, const gchar *, str);
+
+static void
+test_object_finalize (GObject *gobject)
+{
+ TestObjectPrivate *priv = ((TestObject *) gobject)->priv;
+
+ test_boxed_free (priv->boxed);
+ g_free (priv->str);
+
+ G_OBJECT_CLASS (test_object_parent_class)->finalize (gobject);
+}
+
+static void
+test_object_class_init (TestObjectClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = test_object_finalize;
+
+ 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]), 50);
+
+ test_object_properties[PROP_BAR] =
+ g_boolean_property_new ("bar", G_PROPERTY_READWRITE,
+ 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]), 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]),
+ 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]),
+ TEST_FLAGS_VALUE_FOO);
+
+ test_object_properties[PROP_BOXED] =
+ g_boxed_property_new ("boxed", G_PROPERTY_READWRITE | G_PROPERTY_COPY_SET,
+ 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_constructor (void)
+{
+ TestObject *t = g_object_new (test_object_get_type (),
+ "str", "Hello, World!",
+ "x-align", 1.0,
+ NULL);
+
+ g_assert (G_TYPE_CHECK_INSTANCE_TYPE (t, test_object_get_type ()));
+ g_assert_cmpstr (test_object_get_str (t), ==, "Hello, World!");
+ g_assert_cmpfloat (test_object_get_x_align (t), ==, 1.0);
+
+ g_object_unref (t);
+}
+
+typedef TestObject TestDerived;
+typedef TestObjectClass TestDerivedClass;
+
+G_DEFINE_TYPE (TestDerived, test_derived, test_object_get_type ())
+
+static void
+test_derived_class_init (TestDerivedClass *klass)
+{
+ g_object_class_override_property_default (G_OBJECT_CLASS (klass), "foo", -1);
+ g_object_class_override_property_default (G_OBJECT_CLASS (klass), "enum-value", TEST_ENUM_VALUE_BAZ);
+}
+
+static void
+test_derived_init (TestDerived *self)
+{
+ GValue value = { 0, };
+
+ g_value_init (&value, g_property_get_value_type (G_PROPERTY (test_object_properties[PROP_FOO])));
+ g_property_get_default_value_for_type (G_PROPERTY (test_object_properties[PROP_FOO]),
+ test_derived_get_type (),
+ &value);
+
+ g_assert_cmpint (g_value_get_int (&value), !=, 50);
+ g_assert_cmpint (g_value_get_int (&value), ==, -1);
+
+ test_object_set_foo ((TestObject *) self, g_value_get_int (&value));
+
+ g_value_unset (&value);
+
+ test_object_set_enum_value ((TestObject *) self, TEST_ENUM_VALUE_BAZ);
+}
+
+static void
+autoproperties_default (void)
+{
+ TestObject *t = g_object_new (test_object_get_type (), NULL);
+
+ g_assert (g_type_is_a (G_OBJECT_TYPE (t), test_object_get_type ()));
+ 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);
+
+ t = g_object_new (test_derived_get_type (), NULL);
+
+ g_assert (g_type_is_a (G_OBJECT_TYPE (t), test_object_get_type ()));
+ g_assert (g_type_is_a (G_OBJECT_TYPE (t), test_derived_get_type ()));
+ g_assert_cmpint (test_object_get_foo (t), ==, -1);
+ g_assert (test_object_get_enum_value (t) == TEST_ENUM_VALUE_BAZ);
+
+ g_object_unref (t);
+}
+
+static void
+autoproperties_range (void)
+{
+ TestObject *t = g_object_new (test_object_get_type (), NULL);
+ GProperty *p;
+ gint i_min, i_max;
+ gdouble d_min, d_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, &i_min, &i_max);
+ g_assert_cmpint (i_min, ==, -1);
+ g_assert_cmpint (i_max, ==, 100);
+
+ p = (GProperty *) g_object_class_find_property (G_OBJECT_GET_CLASS (t), "x-align");
+ g_assert (G_IS_PROPERTY (p));
+
+ g_property_get_range (p, &d_min, &d_max);
+ g_assert_cmpfloat (d_min, ==, 0.0);
+ g_assert_cmpfloat (d_max, ==, 1.0);
+
+ 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 ();
+
+ 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 ();
+}
+
+static void
+autoproperties_object_set (void)
+{
+ TestObject *t = g_object_new (test_object_get_type (), NULL);
+ TestBoxed boxed = { 0, 0, 200, 200, -1 };
+ TestBoxed check;
+
+ 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);
+ test_object_get_boxed (t, &check);
+ g_assert_cmpint (boxed.y, ==, check.y);
+ g_assert_cmpint (boxed.width, ==, check.width);
+
+ 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);
+}
+
+#pragma GCC diagnostic pop
+
+int
+main (int argc, char *argv[])
+{
+ 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/constructor", autoproperties_constructor);
+ g_test_add_func ("/auto-properties/default", autoproperties_default);
+ g_test_add_func ("/auto-properties/range", autoproperties_range);
+ g_test_add_func ("/auto-properties/accessors", autoproperties_accessors);
+ g_test_add_func ("/auto-properties/validate", autoproperties_validate);
+ g_test_add_func ("/auto-properties/object-set", autoproperties_object_set);
+ g_test_add_func ("/auto-properties/object-get", autoproperties_object_get);
+
+ return g_test_run ();
+}
diff --git a/gobject/tests/gproperty-example-base.c b/gobject/tests/gproperty-example-base.c
new file mode 100644
index 000000000..1ffee63da
--- /dev/null
+++ b/gobject/tests/gproperty-example-base.c
@@ -0,0 +1,146 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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;
+};
+
+GType test_file_get_type (void); /* for -Wmissing-prototypes */
+
+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, };
+
+/* for -Wmissing-prototypes */
+G_DECLARE_PROPERTY_GET_SET (TestFile, test_file, const gchar *, path)
+
+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]);
+}
+
+/* for -Wmissing-prototypes */
+G_DECLARE_PROPERTY_GET (TestFile, test_file, gint64, 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_PROPERTY_COPY_SET,
+ 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;
+
+ 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 000000000..6334a94f8
--- /dev/null
+++ b/gobject/tests/gproperty-example-derived.c
@@ -0,0 +1,312 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* 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;
+};
+
+GType test_file_get_type (void); /* for -Wmissing-prototypes */
+
+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_DECLARE_PROPERTY_GET_SET (TestFile, test_file, const gchar *, path)
+
+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);
+
+ 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_DECLARE_PROPERTY_GET (TestFile, test_file, const gchar *, extension)
+G_DEFINE_PROPERTY_GET (TestFile, test_file, const gchar *, extension)
+
+G_DECLARE_PROPERTY_GET (TestFile, test_file, gint64, 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_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;
+};
+
+GType test_file_mp3_get_type (void); /* for -Wmissing-prototypes */
+
+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_DECLARE_PROPERTY_GET_SET (TestFileMp3, test_file_mp3, const gchar *, artist) /* for -Wmissing-prototypes */
+G_DEFINE_PROPERTY_GET_SET (TestFileMp3, test_file_mp3, const gchar *, artist)
+
+G_DECLARE_PROPERTY_GET_SET (TestFileMp3, test_file_mp3, const gchar *, title) /* for -Wmissing-prototypes */
+G_DEFINE_PROPERTY_GET_SET (TestFileMp3, test_file_mp3, const gchar *, title)
+
+G_DECLARE_PROPERTY_GET_SET (TestFileMp3, test_file_mp3, const gchar *, album) /* for -Wmissing-prototypes */
+G_DEFINE_PROPERTY_GET_SET (TestFileMp3, test_file_mp3, const gchar *, album)
+
+G_DECLARE_PROPERTY_GET_SET (TestFileMp3, test_file_mp3, gint64, duration) /* for -Wmissing-prototypes */
+G_DEFINE_PROPERTY_GET_SET (TestFileMp3, test_file_mp3, gint64, duration)
+
+static 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_PROPERTY_COPY_SET,
+ 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_PROPERTY_COPY_SET,
+ 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_PROPERTY_COPY_SET,
+ 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;
+
+ 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;
+}
+/* }}} */
diff --git a/tests/gobject/performance.c b/tests/gobject/performance.c
index e9310a587..13b0ec72b 100644
--- a/tests/gobject/performance.c
+++ b/tests/gobject/performance.c
@@ -424,6 +424,333 @@ complex_object_init (ComplexObject *complex_object)
complex_object->val2 = 43;
}
+/****************************************************************
+ * ParamspecObject is an object using GParamSpec for properties *
+ ****************************************************************/
+
+#define PARAMSPEC_TYPE_OBJECT (paramspec_object_get_type ())
+typedef struct _ParamspecObject ParamspecObject;
+typedef struct _ParamspecObjectClass ParamspecObjectClass;
+typedef struct _ParamspecObjectPrivate ParamspecObjectPrivate;
+
+struct _ParamspecObject
+{
+ GObject parent_instance;
+
+ ParamspecObjectPrivate *priv;
+};
+
+struct _ParamspecObjectClass
+{
+ GObjectClass parent_class;
+};
+
+GType paramspec_object_get_type (void); /* for -Wmissing-prototypes */
+
+G_DEFINE_TYPE (ParamspecObject, paramspec_object, G_TYPE_OBJECT)
+
+#define PARAMSPEC_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PARAMSPEC_TYPE_OBJECT, ParamspecObject))
+
+struct _ParamspecObjectPrivate
+{
+ int foo;
+ gchar *bar;
+ float baz;
+};
+
+enum {
+ PROP_PSPEC_0,
+ PROP_PSPEC_FOO,
+ PROP_PSPEC_BAR,
+ PROP_PSPEC_BAZ,
+ PROP_PSPEC_LAST
+};
+
+static GParamSpec *pspec_props[PROP_PSPEC_LAST] = { NULL, };
+
+static void
+paramspec_object_finalize (GObject *object)
+{
+ ParamspecObjectPrivate *priv = PARAMSPEC_OBJECT (object)->priv;
+
+ g_free (priv->bar);
+
+ G_OBJECT_CLASS (paramspec_object_parent_class)->finalize (object);
+}
+
+static void
+paramspec_object_set_foo (ParamspecObject *object,
+ int value)
+{
+ if (object->priv->foo == value)
+ return;
+
+ object->priv->foo = value;
+
+ g_object_notify_by_pspec (G_OBJECT (object), pspec_props[PROP_PSPEC_FOO]);
+}
+
+static int
+paramspec_object_get_foo (ParamspecObject *object)
+{
+ g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (object, paramspec_object_get_type ()), 0);
+
+ return object->priv->foo;
+}
+
+static void
+paramspec_object_set_bar (ParamspecObject *object,
+ const char *value)
+{
+ if (g_strcmp0 (object->priv->bar, value) == 0)
+ return;
+
+ g_free (object->priv->bar);
+ object->priv->bar = g_strdup (value);
+
+ g_object_notify_by_pspec (G_OBJECT (object), pspec_props[PROP_PSPEC_BAR]);
+}
+
+static void
+paramspec_object_set_baz (ParamspecObject *object,
+ float value)
+{
+ if (object->priv->baz == value)
+ return;
+
+ object->priv->baz = value;
+
+ g_object_notify_by_pspec (G_OBJECT (object), pspec_props[PROP_PSPEC_BAZ]);
+}
+
+static float
+paramspec_object_get_baz (ParamspecObject *object)
+{
+ g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (object, paramspec_object_get_type ()), 0.0);
+
+ return object->priv->baz;
+}
+
+static void
+paramspec_object_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ case PROP_PSPEC_FOO:
+ paramspec_object_set_foo (PARAMSPEC_OBJECT (object), g_value_get_int (value));
+ break;
+ case PROP_PSPEC_BAR:
+ paramspec_object_set_bar (PARAMSPEC_OBJECT (object), g_value_get_string (value));
+ break;
+ case PROP_PSPEC_BAZ:
+ paramspec_object_set_baz (PARAMSPEC_OBJECT (object), g_value_get_float (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+paramspec_object_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ case PROP_PSPEC_FOO:
+ g_value_set_int (value, PARAMSPEC_OBJECT (object)->priv->foo);
+ break;
+ case PROP_PSPEC_BAR:
+ g_value_set_string (value, PARAMSPEC_OBJECT (object)->priv->bar);
+ break;
+ case PROP_PSPEC_BAZ:
+ g_value_set_float (value, PARAMSPEC_OBJECT (object)->priv->baz);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+paramspec_object_class_init (ParamspecObjectClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ g_type_class_add_private (class, sizeof (ParamspecObjectPrivate));
+
+ object_class->finalize = paramspec_object_finalize;
+ object_class->set_property = paramspec_object_set_property;
+ object_class->get_property = paramspec_object_get_property;
+
+ pspec_props[PROP_PSPEC_FOO] =
+ g_param_spec_int ("foo",
+ NULL, NULL,
+ -100, 100, 50,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ pspec_props[PROP_PSPEC_BAR] =
+ g_param_spec_string ("bar",
+ NULL, NULL,
+ "Hello",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ pspec_props[PROP_PSPEC_BAZ] =
+ g_param_spec_float ("baz",
+ NULL, NULL,
+ 0.0f, G_MAXFLOAT, 0.0f,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, PROP_PSPEC_LAST, pspec_props);
+}
+
+static void
+paramspec_object_init (ParamspecObject *self)
+{
+ self->priv = g_type_instance_get_private ((GTypeInstance *) self, PARAMSPEC_TYPE_OBJECT);
+
+ self->priv->foo = 50;
+ self->priv->bar = g_strdup ("Hello");
+ self->priv->baz = 0.0f;
+}
+
+/**************************************************************
+ * PropertyObject is an object using GProperty for properties *
+ **************************************************************/
+
+#define PROPERTY_TYPE_OBJECT (property_object_get_type ())
+typedef struct _PropertyObject PropertyObject;
+typedef struct _PropertyObjectClass PropertyObjectClass;
+typedef struct _PropertyObjectPrivate PropertyObjectPrivate;
+
+struct _PropertyObject
+{
+ GObject parent_instance;
+
+ PropertyObjectPrivate *priv;
+};
+
+struct _PropertyObjectClass
+{
+ GObjectClass parent_class;
+};
+
+GType property_object_get_type (void); /* for -Wmissing-prototypes */
+
+G_DEFINE_TYPE (PropertyObject, property_object, G_TYPE_OBJECT)
+
+#define PROPERTY_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PROPERTY_TYPE_OBJECT, PropertyObject))
+
+struct _PropertyObjectPrivate
+{
+ int foo;
+ gchar *bar;
+ float baz;
+};
+
+enum {
+ PROP_PROPERTY_0,
+ PROP_PROPERTY_FOO,
+ PROP_PROPERTY_BAR,
+ PROP_PROPERTY_BAZ,
+ PROP_PROPERTY_LAST
+};
+
+static GParamSpec *property_props[PROP_PROPERTY_LAST] = { NULL, };
+
+static void
+property_object_finalize (GObject *object)
+{
+ PropertyObjectPrivate *priv = PROPERTY_OBJECT (object)->priv;
+
+ g_free (priv->bar);
+
+ G_OBJECT_CLASS (property_object_parent_class)->finalize (object);
+}
+
+static void
+property_object_class_init (PropertyObjectClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ g_type_class_add_private (class, sizeof (PropertyObjectPrivate));
+
+ object_class->finalize = property_object_finalize;
+
+ property_props[PROP_PROPERTY_FOO] =
+ g_int_property_new ("foo", G_PROPERTY_READWRITE,
+ G_STRUCT_OFFSET (PropertyObjectPrivate, foo),
+ NULL, NULL);
+ g_property_set_range ((GProperty *) property_props[PROP_PROPERTY_FOO], -100, 100);
+ g_property_set_default ((GProperty *) property_props[PROP_PROPERTY_FOO], 50);
+
+ property_props[PROP_PROPERTY_BAR] =
+ g_string_property_new ("bar", G_PROPERTY_READWRITE,
+ G_STRUCT_OFFSET (PropertyObjectPrivate, bar),
+ NULL, NULL);
+ g_property_set_default ((GProperty *) property_props[PROP_PROPERTY_BAR], "Hello");
+
+ property_props[PROP_PROPERTY_BAZ] =
+ g_float_property_new ("baz", G_PROPERTY_READWRITE,
+ G_STRUCT_OFFSET (PropertyObjectPrivate, baz),
+ NULL, NULL);
+ g_property_set_range ((GProperty *) property_props[PROP_PROPERTY_BAZ], 0.0f, G_MAXFLOAT);
+ g_property_set_default ((GProperty *) property_props[PROP_PROPERTY_BAZ], 0.0f);
+
+ g_object_class_install_properties (object_class, PROP_PROPERTY_LAST, property_props);
+}
+
+static void
+property_object_init (PropertyObject *self)
+{
+ self->priv = g_type_instance_get_private ((GTypeInstance *) self, PROPERTY_TYPE_OBJECT);
+
+ g_property_get_default ((GProperty *) property_props[PROP_PROPERTY_FOO],
+ self,
+ &(self->priv->foo));
+ g_property_get_default ((GProperty *) property_props[PROP_PROPERTY_BAR],
+ self,
+ &(self->priv->bar));
+ g_property_get_default ((GProperty *) property_props[PROP_PROPERTY_BAZ],
+ self,
+ &(self->priv->baz));
+}
+
+static void
+property_object_set_foo (PropertyObject *self, int value)
+{
+ g_property_set (((GProperty *) property_props[PROP_PROPERTY_FOO]), self, value);
+}
+
+static int
+property_object_get_foo (PropertyObject *self)
+{
+ gint value;
+
+ g_property_get (((GProperty *) property_props[PROP_PROPERTY_FOO]), self, &value);
+
+ return value;
+}
+
+static void
+property_object_set_baz (PropertyObject *self, float value)
+{
+ g_property_set (((GProperty *) property_props[PROP_PROPERTY_BAZ]), self, value);
+}
+
+static float
+property_object_get_baz (PropertyObject *self)
+{
+ float value;
+
+ g_property_get (((GProperty *) property_props[PROP_PROPERTY_BAZ]), self, &value);
+
+ return value;
+}
+
/*************************************************************
* Test object construction performance
*************************************************************/
@@ -508,6 +835,186 @@ test_construction_print_result (PerformanceTest *test,
data->n_objects / time);
}
+/*************************************************************
+ * Test property accessors using GParamSpec
+ *************************************************************/
+
+#define NUM_ACCESSES_PER_ROUND 10000
+
+struct PropertyTest {
+ gpointer object;
+ int n_accesses;
+};
+
+static gpointer
+test_property_setup (PerformanceTest *test)
+{
+ struct PropertyTest *data;
+ GType gtype;
+
+ gtype = ((GType (*)())test->extra_data)();
+
+ data = g_new0 (struct PropertyTest, 1);
+ data->object = g_object_new (gtype, NULL);
+
+ return data;
+}
+
+static void
+test_property_init (PerformanceTest *test,
+ gpointer _data,
+ double factor)
+{
+ struct PropertyTest *data = _data;
+
+ data->n_accesses = factor * NUM_ACCESSES_PER_ROUND;
+}
+
+static void
+test_paramspec_direct_set_run (PerformanceTest *test,
+ gpointer _data)
+{
+ struct PropertyTest *data = _data;
+ int n_accesses, i;
+
+ n_accesses = data->n_accesses;
+ for (i = 0; i < n_accesses; i++)
+ {
+ gint foo = i % 16;
+ gfloat baz = foo * 3.14f;
+
+ paramspec_object_set_foo (data->object, foo);
+ paramspec_object_set_baz (data->object, baz);
+ }
+}
+
+static void
+test_paramspec_direct_get_run (PerformanceTest *test,
+ gpointer _data)
+{
+ struct PropertyTest *data = _data;
+ int n_accesses, i;
+
+ n_accesses = data->n_accesses;
+ for (i = 0; i < n_accesses; i++)
+ {
+ gint foo;
+ gfloat baz;
+
+ foo = paramspec_object_get_foo (data->object);
+ baz = paramspec_object_get_baz (data->object);
+
+ g_assert_cmpfloat (baz, ==, 0);
+ g_assert_cmpint (foo, ==, 50);
+ }
+}
+
+
+static void
+test_paramspec_object_run (PerformanceTest *test,
+ gpointer _data)
+{
+ struct PropertyTest *data = _data;
+ int n_accesses, i;
+
+ n_accesses = data->n_accesses;
+ for (i = 0; i < n_accesses; i++)
+ {
+ gint foo = i % 16;
+ gfloat baz = foo * 3.14f;
+
+ g_object_set (data->object,
+ "foo", foo,
+ "baz", baz,
+ NULL);
+ }
+}
+
+static void
+test_property_direct_set_run (PerformanceTest *test,
+ gpointer _data)
+{
+ struct PropertyTest *data = _data;
+ int n_accesses, i;
+
+ n_accesses = data->n_accesses;
+ for (i = 0; i < n_accesses; i++)
+ {
+ gint foo = i % 16;
+ gfloat baz = foo * 3.14f;
+
+ property_object_set_foo (data->object, foo);
+ property_object_set_baz (data->object, baz);
+ }
+}
+
+static void
+test_property_direct_get_run (PerformanceTest *test,
+ gpointer _data)
+{
+ struct PropertyTest *data = _data;
+ int n_accesses, i;
+
+ n_accesses = data->n_accesses;
+ for (i = 0; i < n_accesses; i++)
+ {
+ gint foo;
+ gfloat baz;
+
+ foo = property_object_get_foo (data->object);
+ baz = property_object_get_baz (data->object);
+
+ g_assert_cmpfloat (baz, ==, 0);
+ g_assert_cmpint (foo, ==, 50);
+ }
+}
+
+static void
+test_property_object_run (PerformanceTest *test,
+ gpointer _data)
+{
+ struct PropertyTest *data = _data;
+ int n_accesses, i;
+
+ n_accesses = data->n_accesses;
+ for (i = 0; i < n_accesses; i++)
+ {
+ gint foo = i % 16;
+ gfloat baz = foo * 3.14f;
+
+ g_object_set (data->object,
+ "foo", foo,
+ "baz", baz,
+ NULL);
+ }
+}
+
+static void
+test_property_finish (PerformanceTest *test,
+ gpointer _data)
+{
+}
+
+static void
+test_property_print_result (PerformanceTest *test,
+ gpointer _data,
+ gdouble time)
+{
+ struct PropertyTest *data = _data;
+ g_print ("Number of accesses per second: %.0f\n",
+ data->n_accesses / time);
+}
+
+static void
+test_property_teardown (PerformanceTest *test,
+ gpointer _data)
+{
+ struct PropertyTest *data = _data;
+
+ g_object_unref (data->object);
+ g_free (data);
+}
+
/*************************************************************
* Test runtime type check performance
*************************************************************/
@@ -781,6 +1288,66 @@ static PerformanceTest tests[] = {
test_construction_teardown,
test_construction_print_result
},
+ {
+ "gparamspec-direct-get",
+ paramspec_object_get_type,
+ test_property_setup,
+ test_property_init,
+ test_paramspec_direct_get_run,
+ test_property_finish,
+ test_property_teardown,
+ test_property_print_result
+ },
+ {
+ "gproperty-direct-get",
+ property_object_get_type,
+ test_property_setup,
+ test_property_init,
+ test_property_direct_get_run,
+ test_property_finish,
+ test_property_teardown,
+ test_property_print_result
+ },
+ {
+ "gparamspec-direct-set",
+ paramspec_object_get_type,
+ test_property_setup,
+ test_property_init,
+ test_paramspec_direct_set_run,
+ test_property_finish,
+ test_property_teardown,
+ test_property_print_result
+ },
+ {
+ "gproperty-direct-set",
+ property_object_get_type,
+ test_property_setup,
+ test_property_init,
+ test_property_direct_set_run,
+ test_property_finish,
+ test_property_teardown,
+ test_property_print_result
+ },
+ {
+ "gparamspec-gobject-access",
+ paramspec_object_get_type,
+ test_property_setup,
+ test_property_init,
+ test_paramspec_object_run,
+ test_property_finish,
+ test_property_teardown,
+ test_property_print_result
+ },
+ {
+ "gproperty-gobject-access",
+ property_object_get_type,
+ test_property_setup,
+ test_property_init,
+ test_property_object_run,
+ test_property_finish,
+ test_property_teardown,
+ test_property_print_result
+ },
{
"type-check",
NULL,