diff options
author | Emmanuele Bassi <ebassi@gnome.org> | 2013-04-24 16:05:57 -0400 |
---|---|---|
committer | Emmanuele Bassi <ebassi@gnome.org> | 2013-07-05 18:12:55 +0100 |
commit | 91a35e96e3534dcef17de0ae0b574e115176a87a (patch) | |
tree | 6c232dd170a3df0210b04eccf09605ff2f0e2340 | |
parent | 12947909b538f11296648f6f75e4343d33c0a038 (diff) | |
download | glib-91a35e96e3534dcef17de0ae0b574e115176a87a.tar.gz |
property: Add autogeneration of accessors
We can use macros to autogenerate accessor methods for GObject classes
using GProperty.
https://bugzilla.gnome.org/show_bug.cgi?id=648526
-rw-r--r-- | gobject/gproperty.h | 356 | ||||
-rw-r--r-- | gobject/tests/property.c | 30 |
2 files changed, 386 insertions, 0 deletions
diff --git a/gobject/gproperty.h b/gobject/gproperty.h index ee6a3eaa3..69ded229d 100644 --- a/gobject/gproperty.h +++ b/gobject/gproperty.h @@ -432,6 +432,362 @@ void g_property_init_default (GProperty *property, gpointer object); + +/* 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_DIRECT_GETTER_BEGIN(T_n, t_n, f_t, f_n) \ +{ \ + T_n##Private *priv; \ + f_t retval; \ +\ + g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, t_n##_get_type ()), (f_t) 0); \ +\ + priv = t_n##_get_instance_private (self); \ + retval = priv->f_n; \ +\ + { /* custom code follows */ + +#define _G_DEFINE_PROPERTY_INDIRECT_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 @TypeName<!-- -->Private structure + * @field_name: the name of the property, which must match the name of the + * field in the @TypeName<!-- -->Private structure + * + * Declares the accessor functions for a @field_name property in the + * class @TypeName. This macro should only be used in header files. + * + * Since: 2.38 + */ +#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.38 + */ +#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.38 + */ +#define G_DECLARE_PROPERTY_SET(T_n, t_n, f_t, f_n) _G_DECLARE_PROPERTY_SETTER (T_n, t_n, f_t, f_n); + +/** + * G_DEFINE_PROPERTY_SET_WITH_CODE: + * @TypeName: the name of the type, in Camel case + * @type_name: the name of the type, in lowercase, with words separated by '_' + * @field_type: the type of the property, which must match the type of the + * field in the @TypeName<!-- -->Private structure + * @field_name: the name of the property, which must match the name of the + * field in the @TypeName<!-- -->Private structure + * @_C_: C code that should be called after the property has been set + * + * Defines the setter function for a @field_name property in the + * class @TypeName, with the possibility of calling custom code. + * + * This macro should only be used in C source files. + * + * |[ + * G_DEFINE_PROPERTY_SET_WITH_CODE (ClutterActor, clutter_actor, + * int, margin_top, + * clutter_actor_queue_redraw (self)) + * ]| + * + * This macro should only be used for properties defined using #GProperty. + * + * This macro should only be used in C source files. + * + * The code in @_C_ will only be called if the property was successfully + * updated to a new value. + * + * Note that this macro should be used with types defined using G_DEFINE_TYPE_* + * macros, as it depends on variables and functions defined by those macros. + * + * Since: 2.38 + */ + +#define G_DEFINE_PROPERTY_SET_WITH_CODE(T_n, t_n, f_t, f_n, _C_) \ +_G_DECLARE_PROPERTY_SETTER (T_n, t_n, f_t, f_n) \ +_G_DEFINE_PROPERTY_SETTER_BEGIN (T_n, t_n, f_t, f_n) \ +{ _C_; } \ +_G_DEFINE_PROPERTY_SETTER_END + +/** + * G_DEFINE_PROPERTY_GET_WITH_CODE: + * @T_n: the name of the type, in Camel case + * @t_n: the name of the type, in lowercase, with words separated by '_' + * @f_t: the type of the property, which must match the type of the + * field in the @T_n<!-- -->Private structure + * @f_n: the name of the property, which must match the name of the + * field in the @T_n<!-- -->Private structure + * @_C_: C code to be called after the property has been retrieved + * + * Defines the getter function for a @f_n property in the + * class @T_n, with the possibility of calling custom code. + * + * This macro will directly access the field on the private + * data structure. + * + * This macro should only be used in C source files. + * + * Since: 2.38 + */ +#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_DIRECT_GETTER_BEGIN (T_n, t_n, f_t, f_n) \ +{ _C_; } \ +_G_DEFINE_PROPERTY_GETTER_END + +/** + * G_DEFINE_PROPERTY_INDIRECT_GET_WITH_CODE: + * @T_n: the name of the type, in Camel case + * @t_n: the name of the type, in lowercase, with words separated by '_' + * @f_t: the type of the property, which must match the type of the + * field in the @T_n<!-- -->Private structure + * @f_n: the name of the property, which must match the name of the + * field in the @T_n<!-- -->Private structure + * @_C_: C code to be called after the property has been retrieved + * + * Defines the getter function for a @f_n property in the + * class @T_n, with the possibility of calling custom code. + * + * This macro will call g_property_get(). + * + * This macro should only be used in C source files. + * + * Since: 2.38 + */ +#define G_DEFINE_PROPERTY_INDIRECT_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_INDIRECT_GETTER_BEGIN (T_n, t_n, f_t, f_n) \ +{ _C_; } \ +_G_DEFINE_PROPERTY_GETTER_END + +/** + * G_DEFINE_PROPERTY_SET: + * @TypeName: the name of the type, in Camel case + * @type_name: the name of the type, in lowercase, with words separated by '_' + * @field_type: the type of the property, which must match the type of the + * field in the @TypeName<!-- -->Private structure + * @field_name: the name of the property, which must match the name of the + * field in the @TypeName<!-- -->Private structure + * + * Defines the setter function for a @field_name property in the + * class @TypeName. This macro should only be used in C source files. + * + * See also: %G_DEFINE_PROPERTY_SET_WITH_CODE + * + * Since: 2.38 + */ +#define G_DEFINE_PROPERTY_SET(T_n, t_n, f_t, f_n) G_DEFINE_PROPERTY_SET_WITH_CODE (T_n, t_n, f_t, f_n, ;) + +/** + * G_DEFINE_PROPERTY_GET: + * @TypeName: the name of the type, in Camel case + * @type_name: the name of the type, in lowercase, with words separated by '_' + * @field_type: the type of the property, which must match the type of the + * field in the @TypeName<!-- -->Private structure + * @field_name: the name of the property, which must match the name of the + * field in the @TypeName<!-- -->Private structure + * + * Defines the getter function for a @field_name property in the + * class @TypeName. This macro should only be used in C source files. + * + * See also %G_DEFINE_PROPERTY_GET_WITH_CODE. + * + * Since: 2.38 + */ +#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_INDIRECT_GET: + * @TypeName: the name of the type, in Camel case + * @type_name: the name of the type, in lowercase, with words separated by '_' + * @field_type: the type of the property, which must match the type of the + * field in the @TypeName<!-- -->Private structure + * @field_name: the name of the property, which must match the name of the + * field in the @TypeName<!-- -->Private structure + * + * Defines the getter function for a @field_name property in the + * class @TypeName. This macro should only be used in C source files. + * + * See also %G_DEFINE_PROPERTY_COMPUTED_GET_WITH_CODE. + * + * Since: 2.38 + */ +#define G_DEFINE_PROPERTY_INDIRECT_GET(T_n, t_n, f_t, f_n) G_DEFINE_PROPERTY_INDIRECT_GET_WITH_CODE (T_n, t_n, f_t, f_n, ;) + +/** + * G_DEFINE_PROPERTY_GET_SET: + * @T_n: the name of the type, in Camel case + * @t_n: the name of the type, in lowercase, with words separated by '_' + * @f_t: the type of the property, which must match the type of the + * field in the @TypeName<!-- -->Private structure + * @f_n: the name of the property, which must match the name of the + * field in the @TypeName<!-- -->Private structure + * + * Defines the accessor functions for a @f_n property in the class @T_n. + * + * This macro should only be used in C source files, for instance: + * + * |[ + * G_DEFINE_PROPERTY_GET_SET (ClutterActor, clutter_actor, int, margin_top) + * ]| + * + * will synthesize the equivalent of the following code: + * + * |[ + * void + * clutter_actor_set_margin_top (ClutterActor *self, + * int value) + * { + * ClutterActorPrivate *priv; + * + * g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, clutter_actor_get_type ())); + * + * priv = clutter_actor_get_instance_private (self); + * + * 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); + * + * priv = clutter_actor_get_instance_private (self); + * + * return 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.38 + */ +#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/tests/property.c b/gobject/tests/property.c index bf3b02bb8..64a1fe503 100644 --- a/gobject/tests/property.c +++ b/gobject/tests/property.c @@ -177,6 +177,12 @@ test_object_init (TestObject *self) { } +G_DECLARE_PROPERTY_GET_SET (TestObject, test_object, gboolean, bool_val) + +G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, gboolean, bool_val) + +/* test units start here */ + static void check_notify_emission (GObject *object, GParamSpec *pspec, @@ -297,6 +303,29 @@ gproperty_default_init (void) g_object_unref (obj); } +static void +gproperty_accessors_get_set (void) +{ + TestObject *obj = g_object_new (test_object_get_type (), NULL); + gboolean did_emit_notify = FALSE; + + g_signal_connect (obj, "notify::bool-val", G_CALLBACK (check_notify_emission), &did_emit_notify); + + test_object_set_bool_val (obj, TRUE); + + g_assert (did_emit_notify); + g_assert (test_object_get_bool_val (obj)); + + did_emit_notify = FALSE; + + test_object_set_bool_val (obj, FALSE); + + g_assert (did_emit_notify); + g_assert (!test_object_get_bool_val (obj)); + + g_object_unref (obj); +} + int main (int argc, char *argv[]) { @@ -309,6 +338,7 @@ main (int argc, char *argv[]) g_test_add_func ("/gproperty/object-get", gproperty_object_get); g_test_add_func ("/gproperty/explicit-set", gproperty_explicit_set); g_test_add_func ("/gproperty/default/init", gproperty_default_init); + g_test_add_func ("/gproperty/accessors/get-set", gproperty_accessors_get_set); return g_test_run (); } |