[glib/wip/gproperty-2: 5/7] property: Add autogeneration of accessors



commit 42a04e3e126fea4f44965d6592df358d831bd350
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Wed Apr 24 16:05:57 2013 -0400

    property: Add autogeneration of accessors
    
    We can use macros to autogenerate accessor methods for GObject classes
    using GProperty.

 gobject/gproperty.h      |  344 ++++++++++++++++++++++++++++++++++++++++++++++
 gobject/tests/property.c |   30 ++++
 2 files changed, 374 insertions(+), 0 deletions(-)
---
diff --git a/gobject/gproperty.h b/gobject/gproperty.h
index 46a9cc5..f8ee156 100644
--- a/gobject/gproperty.h
+++ b/gobject/gproperty.h
@@ -455,6 +455,350 @@ void            _g_property_set_installed       (GProperty           *property,
                                                  gpointer             g_class,
                                                  GType                class_gtype);
 
+
+/* 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 = g_type_instance_get_private ((GTypeInstance *) self, t_n##_get_type ()); \
+  retval = priv->f_n; \
+\
+  { /* custom code follows */
+
+#define _G_DEFINE_PROPERTY_WRAPPER_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))
+ * ]|
+ *
+ * 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_COMPUTED_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_COMPUTED_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_WRAPPER_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_COMPUTED_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_COMPUTED_GET(T_n, t_n, f_t, f_n)  G_DEFINE_PROPERTY_COMPUTED_GET_WITH_CODE (T_n, 
t_n, f_t, f_n, ;)
+
+/**
+ * G_DEFINE_PROPERTY_GET_SET:
+ * @T_n: the name of the type, in Camel case
+ * @t_n: the name of the type, in lowercase, with words separated by '_'
+ * @f_t: the type of the property, which must match the type of the
+ *   field in the @TypeName<!-- -->Private structure
+ * @f_n: the name of the property, which must match the name of the
+ *   field in the @TypeName<!-- -->Private structure
+ *
+ * Defines the accessor functions for a @f_n property in the class @T_n.
+ *
+ * This macro should only be used in C source files, for instance:
+ *
+ * |[
+ *   G_DEFINE_PROPERTY_GET_SET (ClutterActor, clutter_actor, int, margin_top)
+ * ]|
+ *
+ * will synthesize the equivalent of the following code:
+ *
+ * |[
+ * void
+ * clutter_actor_set_margin_top (ClutterActor *self,
+ *                               int           value)
+ * {
+ *   ClutterActorPrivate *priv;
+ *
+ *   g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, clutter_actor_get_type ()));
+ *
+ *   priv = self->priv;
+ *
+ *   if (priv->margin_top == value)
+ *     return;
+ *
+ *   priv->value = value;
+ *
+ *   g_object_notify (G_OBJECT (self), "margin-top");
+ * }
+ *
+ * int
+ * clutter_actor_get_margin_top (ClutterActor *self)
+ * {
+ *   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, clutter_actor_get_type ()), 0);
+ *
+ *   return self->priv->margin_top;
+ * }
+ * ]|
+ *
+ * This macro will generate both the setter and getter functions; if the
+ * property is not readable and writable, the generated functions will
+ * warn at run-time.
+ *
+ * For greater control on the setter and getter implementation, see also the
+ * %G_DEFINE_PROPERTY_GET and %G_DEFINE_PROPERTY_SET macros, along with their
+ * %G_DEFINE_PROPERTY_GET_WITH_CODE and %G_DEFINE_PROPERTY_SET_WITH_CODE
+ * variants.
+ *
+ * Since: 2.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 00a6b89..7ef330f 100644
--- a/gobject/tests/property.c
+++ b/gobject/tests/property.c
@@ -174,6 +174,12 @@ test_object_init (TestObject *self)
   g_property_init_default ((GProperty *) test_object_properties[PROP_WITH_DEFAULT], 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 ();
 }


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