[glib/wip/gproperty-2: 17/23] gproperty: Add macros for defining properties



commit 696efd10e563ece6c45a0cd629bfa284d4c43d8f
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Wed Apr 24 17:41:15 2013 -0400

    gproperty: Add macros for defining properties
    
    Alongside the macros for defining accessors we may want to use simple
    macros for defining properties to install on a GObject class.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=648526

 gobject/gproperty.h      |  442 +++++++++++++++++++++++++++++++++++++++++-----
 gobject/tests/property.c |  170 +++++++++---------
 2 files changed, 486 insertions(+), 126 deletions(-)
---
diff --git a/gobject/gproperty.h b/gobject/gproperty.h
index b954714..53f5c3b 100644
--- a/gobject/gproperty.h
+++ b/gobject/gproperty.h
@@ -431,7 +431,360 @@ void            g_property_set_installed       (GProperty *property,
 void            g_property_init_default        (GProperty *property,
                                                 gpointer   object);
 
+/* property generation */
 
+/**
+ * G_PROPERTY_DESCRIBE:
+ * @p_nick: a human readable, translatable name for the property
+ * @p_blurb: a human readable, translatable description for the property
+ *
+ * Sets the property nick and blurb using two static strings.
+ *
+ * This macro can only be called inside %G_DEFINE_PROPERTY_EXTENDED.
+ *
+ * Since: 2.38
+ */
+#define G_PROPERTY_DESCRIBE(p_nick, p_blurb) \
+  { \
+    GParamSpec *__g_param_spec = (GParamSpec *) g_property; \
+    g_param_spec_set_static_nick (__g_param_spec, p_nick); \
+    g_param_spec_set_static_blurb (__g_param_spec, p_blurb); \
+  }
+
+/**
+ * G_PROPERTY_DEFAULT:
+ * @p_val: the default value of the property
+ *
+ * Sets the default value for the property.
+ *
+ * This macro can only be called inside %G_DEFINE_PROPERTY_EXTENDED.
+ *
+ * Since: 2.38
+ */
+#define G_PROPERTY_DEFAULT(p_val) \
+  g_property_set_default (g_property, p_val);
+
+/**
+ * G_PROPERTY_RANGE:
+ * @p_min: the minimum value of the valid range for the property
+ * @p_max: the maximum value of the valid range for the property
+ *
+ * Sets the range of valid values for the property.
+ *
+ * This macro can only be called inside %G_DEFINE_PROPERTY_EXTENDED.
+ *
+ * Since: 2.38
+ */
+#define G_PROPERTY_RANGE(p_min, p_max) \
+  g_property_set_range (g_property, p_min, p_max);
+
+/**
+ * G_DECLARE_PROPERTY:
+ * @T_N: the name of type type, in CamelCase
+ * @name: the name of the property, with '-' replaced by '_'
+ *
+ * Declares the property @name of type @T_N.
+ *
+ * Note that this macro can only be used inside the G_DECLARE_PROPERTIES() macro.
+ *
+ * Since: 2.38
+ */
+#define G_DECLARE_PROPERTY(T_N, name) \
+  PROP_##T_N##_##name,
+
+/**
+ * G_DECLARE_PROPERTIES:
+ * @T_N: the name of the type, in CamelCase
+ * @t_n: the name of the type, in lower case, with spaces replaced by underscores
+ * @_C_: a list of G_DECLARE_PROPERTY macros, one for each property
+ *
+ * Declares a list of properties for the type @T_N.
+ *
+ * |[
+ *   G_DECLARE_PROPERTIES (GtkGadget, gtk_gadget,
+ *                         G_DECLARE_PROPERTY (GtkGadget, width),
+ *                         G_DECLARE_PROPERTY (GtkGadget, height))
+ * ]|
+ * expands to
+ * |[
+ *   enum {
+ *     PROP_GtkGadget_0,
+ *     PROP_GtkGadget_width,
+ *     PROP_GtkGadget_height,
+ *     PROP_GtkGadget_LAST
+ *   };
+ *
+ *   static GProperty *gtk_gadget_properties[PROP_GtkGadget_LAST];
+ *
+ *   static GParamSpec *
+ *   gtk_gadget_find_property (GtkGadget   *self,
+ *                             const gchar *name)
+ *   {
+ *     const gchar *iname = g_intern_string (name);
+ *     gint i;
+ *
+ *     for (i = 1; i < PROP_GtkGadget_LAST; i++)
+ *       {
+ *         GParamSpec *pspec = (GParamSpec *) gtk_gadget_properties[i];
+ *         if (pspec != NULL && pspec->name == iname)
+ *           return pspec;
+ *       }
+ *
+ *     return g_object_class_find_property (G_OBJECT_GET_CLASS (self), name);
+ *   }
+ *
+ *   static void
+ *   gtk_gadget_notify_property (GtkGadget   *self,
+ *                               const gchar *name)
+ *   {
+ *     GParamSpec *pspec = gtk_gadget_find_property (self, name);
+ *
+ *     if (pspec != NULL)
+ *       g_object_notify_by_pspec (G_OBJECT (self), name);
+ *   }
+ *
+ *   static void
+ *   gtk_gadget_class_install_properties (GtkGadgetClass *g_class)
+ *   {
+ *     g_object_class_install_properties (G_OBJECT_CLASS (g_class),
+ *                                        PROP_GtkGadget_LAST,
+ *                                        (GParamSpec **) gtk_gadget_properties);
+ *   }
+ * ]|
+ *
+ * This macro should be used alongside G_DEFINE_PROPERTIES().
+ *
+ * Since: 2.38
+ */
+#define G_DECLARE_PROPERTIES(T_N, t_n, _C_) \
+enum { \
+  PROP_##T_N##_0, \
+  _C_ \
+  PROP_##T_N##_LAST \
+}; \
+\
+static GProperty *t_n##_properties[PROP_##T_N##_LAST] = { NULL, }; \
+\
+static inline GParamSpec * \
+t_n##_find_property (T_N        *self, \
+                     const char *name) \
+{ \
+  const char *iname = g_intern_string (name); \
+  gint i; \
+\
+  for (i = PROP_##T_N##_0 + 1; i < PROP_##T_N##_LAST; i++) \
+    { \
+      GParamSpec *pspec = (GParamSpec *) t_n##_properties[i]; \
+      if (pspec != NULL && pspec->name == iname) \
+        return pspec; \
+    } \
+\
+  return g_object_class_find_property (G_OBJECT_GET_CLASS (self), name); \
+} \
+\
+static inline void \
+t_n##_notify_property (T_N        *self, \
+                       const char *name) \
+{ \
+  GParamSpec *pspec = t_n##_find_property (self, name); \
+\
+  if (G_LIKELY (pspec != NULL)) \
+    g_object_notify_by_pspec (G_OBJECT (self), pspec); \
+} \
+\
+static inline void \
+t_n##_class_install_properties (T_N##Class *g_class) \
+{ \
+  g_object_class_install_properties (G_OBJECT_CLASS (g_class), \
+                                     PROP_##T_N##_LAST, \
+                                     (GParamSpec **) t_n##_properties); \
+}
+
+/**
+ * G_DEFINE_PROPERTIES:
+ * @T_N: the name of the type, in CamelCase
+ * @t_n: the name of the type, in lower case, with spaces replaced by underscores
+ * @g_class: a pointer to the class structure of the type
+ * @_C_: a list of G_DEFINE_PROPERTY_EXTENDED calls
+ *
+ * Defines a list of properties and installs them on the class.
+ *
+ * This macro should be used alongside the G_DECLARE_PROPERTIES() macro.
+ *
+ * Since: 2.38
+ */
+#define G_DEFINE_PROPERTIES(T_N, t_n, g_class, _C_) \
+  { \
+    _C_ \
+\
+    t_n##_class_install_properties (g_class); \
+  }
+
+#define _G_DEFINE_DIRECT_PROPERTY_EXTENDED_BEGIN(T_N, t_n, c_type, name, flags) \
+{ \
+  GProperty *g_property = (GProperty *) \
+    g_##c_type##_property_new (#name, flags, \
+                               G_STRUCT_OFFSET (T_N##Private, name), \
+                               NULL, \
+                               NULL);
+#define _G_DEFINE_PROPERTY_EXTENDED_BEGIN(T_N, t_n, c_type, name, offset, setterFunc, getterFunc, flags) \
+{ \
+  GProperty *g_property = (GProperty *) \
+    g_##c_type##_property_new (#name, flags, \
+                               offset, \
+                               setterFunc, \
+                               getterFunc);
+#define _G_DEFINE_PROPERTY_EXTENDED_END(T_N, t_n, name) \
+  t_n##_properties[PROP_##T_N##_##name] = g_property; \
+}
+
+/**
+ * G_DEFINE_PROPERTY_EXTENDED:
+ * @T_N: the name of the type, in CamelCase
+ * @t_n: the name of the type, in lower case, with spaces replaced by underscores
+ * @c_type: the C type of the property, in lower case, minus the "g" if the type
+ *   is defined by GLib; for instance "int" for "gint", "uint8" for "guint8",
+ *   "boolean" for "gboolean"; strings stored in a gchar* are defined as "string"
+ * @name: the name of the property, in lower case, with '-' replaced by '_'
+ * @offset: the offset of the field in the structure that stores the property, or 0
+ * @setterFunc: the explicit setter function, or %NULL for direct access
+ * @getterFunc: the explicit getter function, or %NULL for direct access
+ * @flags: #GPropertyFlags for the property
+ * @_C_: custom code to be called after the property has been defined; the
+ *   GProperty instance is available under the "g_property" variable
+ *
+ * The most generic property definition macro.
+ *
+ * |[
+ *   G_DEFINE_PROPERTY_EXTENDED (GtkGadget, gtk_gadget,
+ *                               int,
+ *                               width,
+ *                               G_STRUCT_OFFSET (GtkGadgetPrivate, width),
+ *                               NULL, NULL,
+ *                               G_PROPERTY_READWRITE,
+ *                               G_PROPERTY_RANGE (0, G_MAXINT))
+ * ]|
+ * expands to
+ * |[
+ *   {
+ *     GProperty *g_property =
+ *       g_int_property_new ("width", G_PROPERTY_READWRITE,
+ *                           G_STRUCT_OFFSET (GtkGadgetPrivate, width),
+ *                           NULL, NULL);
+ *     g_property_set_range (g_property, 0, G_MAXINT);
+ *     gtk_gadget_properties[PROP_GtkGadget_width] = g_property;
+ *   }
+ * ]|
+ *
+ * This macro should only be used with G_DEFINE_PROPERTIES() and
+ * G_DECLARE_PROPERTIES(), as it depends on variable names defined
+ * by those two macros.
+ *
+ * Since: 2.38
+ */
+#define G_DEFINE_PROPERTY_EXTENDED(T_N, t_n, c_type, name, offset, setterFunc, getterFunc, flags, _C_) \
+  _G_DEFINE_PROPERTY_EXTENDED_BEGIN (T_N, t_n, c_type, name, offset, setterFunc, getterFunc, flags) \
+  { _C_; } \
+  _G_DEFINE_PROPERTY_EXTENDED_END (T_N, t_n, name)
+
+/**
+ * G_DEFINE_PROPERTY_WITH_CODE:
+ * @T_N: the name of the type, in CamelCase
+ * @t_n: the name of the type, in lower case, with spaces replaced by underscores
+ * @c_type: the C type of the property, in lower case, minus the "g" if the type
+ *   is defined by GLib; for instance "int" for "gint", "uint8" for "guint8",
+ *   "boolean" for "gboolean"; strings stored in a gchar* are defined as "string"
+ * @name: the name of the property, in lower case, with '-' replaced by '_'; the
+ *   name of the property must exist as a member of the per-instance private data
+ *   structure of the type name
+ * @flags: #GPropertyFlags for the property
+ * @_C_: custom code to be called after the property has been defined; the
+ *   GProperty instance is available under the "g_property" variable
+ *
+ * A variant of G_DEFINE_PROPERTY_EXTENDED() that only allows properties
+ * with direct access, stored on the per-instance private data structure
+ * for the given type.
+ *
+ * Since: 2.38
+ */
+#define G_DEFINE_PROPERTY_WITH_CODE(T_N, t_n, c_type, name, flags, _C_) \
+  _G_DEFINE_DIRECT_PROPERTY_EXTENDED_BEGIN (T_N, t_n, c_type, name, flags) \
+  { _C_; } \
+  _G_DEFINE_PROPERTY_EXTENDED_END (T_N, t_n, name)
+
+/**
+ * G_DEFINE_PROPERTY_WITH_DEFAULT:
+ * @T_N: the name of the type, in CamelCase
+ * @t_n: the name of the type, in lower case, with spaces replaced by underscores
+ * @c_type: the C type of the property, in lower case, minus the "g" if the type
+ *   is defined by GLib; for instance "int" for "gint", "uint8" for "guint8",
+ *   "boolean" for "gboolean"; strings stored in a gchar* are defined as "string"
+ * @name: the name of the property, in lower case, with '-' replaced by '_'; the
+ *   name of the property must exist as a member of the per-instance private data
+ *   structure of the type name
+ * @flags: #GPropertyFlags for the property
+ * @defVal: the default value of the property
+ *
+ * A convenience macro for defining a direct access property with a default
+ * value.
+ *
+ * See G_DEFINE_PROPERTY_WITH_CODE() and G_PROPERTY_DEFAULT().
+ *
+ * Since: 2.38
+ */
+#define G_DEFINE_PROPERTY_WITH_DEFAULT(T_N, t_n, c_type, name, flags, defVal) \
+  _G_DEFINE_DIRECT_PROPERTY_EXTENDED_BEGIN (T_N, t_n, c_type, name, flags) \
+  G_PROPERTY_DEFAULT (defVal) \
+  _G_DEFINE_PROPERTY_EXTENDED_END (T_N, t_n, name)
+
+/**
+ * G_DEFINE_PROPERTY_WITH_RANGE:
+ * @T_N: the name of the type, in CamelCase
+ * @t_n: the name of the type, in lower case, with spaces replaced by underscores
+ * @c_type: the C type of the property, in lower case, minus the "g" if the type
+ *   is defined by GLib; for instance "int" for "gint", "uint8" for "guint8",
+ *   "boolean" for "gboolean"; strings stored in a gchar* are defined as "string"
+ * @name: the name of the property, in lower case, with '-' replaced by '_'; the
+ *   name of the property must exist as a member of the per-instance private data
+ *   structure of the type name
+ * @flags: #GPropertyFlags for the property
+ * @minVal: the minimum value of the property
+ * @maxVal: the maximum value of the property
+ *
+ * A convenience macro for defining a direct access property with a range
+ * of valid values.
+ *
+ * See G_DEFINE_PROPERTY_WITH_CODE() and G_PROPERTY_RANGE().
+ *
+ * Since: 2.38
+ */
+#define G_DEFINE_PROPERTY_WITH_RANGE(T_N, t_n, c_type, name, flags, minVal, maxVal) \
+  _G_DEFINE_DIRECT_PROPERTY_EXTENDED_BEGIN (T_N, t_n, c_type, name, flags) \
+  G_PROPERTY_RANGE (minVal, maxVal) \
+  _G_DEFINE_PROPERTY_EXTENDED_END (T_N, t_n, name)
+
+/**
+ * G_DEFINE_PROPERTY:
+ * @T_N: the name of the type, in CamelCase
+ * @t_n: the name of the type, in lower case, with spaces replaced by underscores
+ * @c_type: the C type of the property, in lower case, minus the "g" if the type
+ *   is defined by GLib; for instance "int" for "gint", "uint8" for "guint8",
+ *   "boolean" for "gboolean"; strings stored in a gchar* are defined as "string"
+ * @name: the name of the property, in lower case, with '-' replaced by '_'; the
+ *   name of the property must exist as a member of the per-instance private data
+ *   structure of the type name
+ * @flags: #GPropertyFlags for the property
+ *
+ * A convenience macro for defining a direct access property.
+ *
+ * See G_DEFINE_PROPERTY_WITH_CODE() and G_DEFINE_PROPERTY_EXTENDED() if
+ * you need more flexibility.
+ *
+ * Since: 2.38
+ */
+#define G_DEFINE_PROPERTY(T_N, t_n, c_type, name, flags) \
+  _G_DEFINE_DIRECT_PROPERTY_EXTENDED_BEGIN (T_N, t_n, c_type, name, flags) \
+  _G_DEFINE_PROPERTY_EXTENDED_END (T_N, t_n, name)
 
 /* 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)
@@ -443,7 +796,7 @@ void            g_property_init_default        (GProperty *property,
 \
   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 ()); \
+  priv = t_n##_get_private (self); \
   retval = priv->f_n; \
 \
   { /* custom code follows */
@@ -456,9 +809,7 @@ void            g_property_init_default        (GProperty *property,
   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); \
+    g_property = (GProperty *) t_n##_find_property (self, #f_n); \
     if (G_UNLIKELY (g_property == NULL)) \
       { \
         g_critical (G_STRLOC ": No property " #f_n " found for class %s", \
@@ -467,18 +818,6 @@ void            g_property_init_default        (GProperty *property,
       } \
   } \
 \
-  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); \
@@ -501,9 +840,7 @@ void            g_property_init_default        (GProperty *property,
   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); \
+    g_property = (GProperty *) t_n##_find_property (self, #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)); \
@@ -511,18 +848,6 @@ void            g_property_init_default        (GProperty *property,
       } \
   } \
 \
-  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; \
 \
@@ -590,9 +915,8 @@ _G_DECLARE_PROPERTY_GETTER (T_n, t_n, f_t, f_n);
  * @_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.
+ * class @TypeName, with the possibility of calling custom code, for
+ * instance:
  *
  * |[
  * G_DEFINE_PROPERTY_SET_WITH_CODE (ClutterActor, clutter_actor,
@@ -608,7 +932,8 @@ _G_DECLARE_PROPERTY_GETTER (T_n, t_n, f_t, f_n);
  * 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.
+ * macros and properties declared using the G_DECLARE_PROPERTIES() macro, as it
+ * depends on variables and functions defined by those macros.
  *
  * Since: 2.38
  */
@@ -633,10 +958,17 @@ _G_DEFINE_PROPERTY_SETTER_END
  * class @T_n, with the possibility of calling custom code.
  *
  * This macro will directly access the field on the private
- * data structure.
+ * data structure, and should only be used if the property
+ * has been defined to use an offset instead of an explicit
+ * getter. Use G_DEFINE_PROPERTY_COMPUTED_GET_WITH_CODE() if
+ * you have an internal getter function.
  *
  * This macro should only be used in C source files.
  *
+ * Note that this macro should be used with types defined using G_DEFINE_TYPE_*
+ * macros and properties declared using the G_DECLARE_PROPERTIES() macro, as it
+ * depends on variables and functions defined by those macros.
+ *
  * Since: 2.38
  */
 #define G_DEFINE_PROPERTY_GET_WITH_CODE(T_n, t_n, f_t, f_n, _C_) \
@@ -662,6 +994,10 @@ _G_DEFINE_PROPERTY_GETTER_END
  *
  * This macro should only be used in C source files.
  *
+ * Note that this macro should be used with types defined using G_DEFINE_TYPE_*
+ * macros and properties declared using the G_DECLARE_PROPERTIES() macro, as it
+ * depends on variables and functions defined by those macros.
+ *
  * Since: 2.38
  */
 #define G_DEFINE_PROPERTY_INDIRECT_GET_WITH_CODE(T_n, t_n, f_t, f_n, _C_) \
@@ -682,6 +1018,10 @@ _G_DEFINE_PROPERTY_GETTER_END
  * Defines the setter function for a @field_name property in the
  * class @TypeName. This macro should only be used in C source files.
  *
+ * Note that this macro should be used with types defined using G_DEFINE_TYPE_*
+ * macros and properties declared using the G_DECLARE_PROPERTIES() macro, as it
+ * depends on variables and functions defined by those macros.
+ *
  * See also: %G_DEFINE_PROPERTY_SET_WITH_CODE
  *
  * Since: 2.38
@@ -700,6 +1040,10 @@ _G_DEFINE_PROPERTY_GETTER_END
  * Defines the getter function for a @field_name property in the
  * class @TypeName. This macro should only be used in C source files.
  *
+ * Note that this macro should be used with types defined using G_DEFINE_TYPE_*
+ * macros and properties declared using the G_DECLARE_PROPERTIES() macro, as it
+ * depends on variables and functions defined by those macros.
+ *
  * See also %G_DEFINE_PROPERTY_GET_WITH_CODE.
  *
  * Since: 2.38
@@ -718,6 +1062,10 @@ _G_DEFINE_PROPERTY_GETTER_END
  * Defines the getter function for a @field_name property in the
  * class @TypeName. This macro should only be used in C source files.
  *
+ * Note that this macro should be used with types defined using G_DEFINE_TYPE_*
+ * macros and properties declared using the G_DECLARE_PROPERTIES() macro, as it
+ * depends on variables and functions defined by those macros.
+ *
  * See also %G_DEFINE_PROPERTY_COMPUTED_GET_WITH_CODE.
  *
  * Since: 2.38
@@ -752,22 +1100,26 @@ _G_DEFINE_PROPERTY_GETTER_END
  *
  *   g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, clutter_actor_get_type ()));
  *
- *   priv = self->priv;
- *
- *   if (priv->margin_top == value)
- *     return;
+ *   priv = clutter_actor_get_private (self);
  *
- *   priv->value = value;
+ *   if (priv->margin_top != value)
+ *     {
+ *       priv->value = value;
  *
- *   g_object_notify (G_OBJECT (self), "margin-top");
+ *       g_object_notify (G_OBJECT (self), "margin-top");
+ *     }
  * }
  *
  * int
  * clutter_actor_get_margin_top (ClutterActor *self)
  * {
+ *   ClutterActorPrivate *priv;
+ *
  *   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, clutter_actor_get_type ()), 0);
  *
- *   return self->priv->margin_top;
+ *   priv = clutter_actor_get_private (self);
+ *
+ *   return priv->margin_top;
  * }
  * ]|
  *
@@ -780,6 +1132,10 @@ _G_DEFINE_PROPERTY_GETTER_END
  * %G_DEFINE_PROPERTY_GET_WITH_CODE and %G_DEFINE_PROPERTY_SET_WITH_CODE
  * variants.
  *
+ * Note that this macro should only be used with types defined using
+ * G_DEFINE_TYPE_* macros and properties declared using G_DECLARE_PROPERTIES()
+ * macro, as it depends on variable and functions defined by those macros.
+ *
  * Since: 2.38
  */
 #define G_DEFINE_PROPERTY_GET_SET(T_n, t_n, f_t, f_n)      \
diff --git a/gobject/tests/property.c b/gobject/tests/property.c
index 60af5ce..048f3fc 100644
--- a/gobject/tests/property.c
+++ b/gobject/tests/property.c
@@ -5,10 +5,11 @@ typedef struct _TestObjectPrivate       TestObjectPrivate;
 typedef struct _TestObjectClass         TestObjectClass;
 
 typedef enum {
-  TEST_ENUM_UNSET,
   TEST_ENUM_ONE,
   TEST_ENUM_TWO,
-  TEST_ENUM_THREE
+  TEST_ENUM_THREE,
+
+  TEST_ENUM_UNSET = -1
 } TestEnum;
 
 struct _TestObject
@@ -27,14 +28,17 @@ struct _TestObjectPrivate
 
   double double_val;
 
-  char *str_val;
+  char *string_val;
 
   gboolean bool_val;
 
   TestEnum enum_val;
-  guint enum_val_set : 1;
+  gboolean enum_val_set;
 
   guint8 with_default;
+
+  float width;
+  float height;
 };
 
 GType test_enum_get_type (void);
@@ -64,28 +68,23 @@ test_enum_get_type (void)
 
 G_DEFINE_TYPE_WITH_PRIVATE (TestObject, test_object, G_TYPE_OBJECT)
 
-enum
-{
-  PROP_0,
-
-  PROP_INTEGER_VAL,
-  PROP_DOUBLE_VAL,
-  PROP_STRING_VAL,
-  PROP_BOOL_VAL,
-  PROP_ENUM_VAL,
-  PROP_WITH_DEFAULT,
-
-  LAST_PROP
-};
-
-static GParamSpec *test_object_properties[LAST_PROP] = { NULL, };
+G_DECLARE_PROPERTIES (TestObject, test_object,
+                      G_DECLARE_PROPERTY (TestObject, integer_val)
+                      G_DECLARE_PROPERTY (TestObject, double_val)
+                      G_DECLARE_PROPERTY (TestObject, string_val)
+                      G_DECLARE_PROPERTY (TestObject, bool_val)
+                      G_DECLARE_PROPERTY (TestObject, enum_val)
+                      G_DECLARE_PROPERTY (TestObject, enum_val_set)
+                      G_DECLARE_PROPERTY (TestObject, with_default)
+                      G_DECLARE_PROPERTY (TestObject, width)
+                      G_DECLARE_PROPERTY (TestObject, height))
 
 static void
 test_object_finalize (GObject *gobject)
 {
   TestObjectPrivate *priv = test_object_get_private ((TestObject *) gobject);
 
-  g_free (priv->str_val);
+  g_free (priv->string_val);
 
   if (priv->enum_val != TEST_ENUM_UNSET)
     g_assert (priv->enum_val_set);
@@ -94,8 +93,8 @@ test_object_finalize (GObject *gobject)
 }
 
 static gboolean
-test_object_set_enum_val (gpointer obj,
-                          gint     val)
+test_object_set_enum_val_internal (gpointer obj,
+                                   gint     val)
 {
   TestObjectPrivate *priv = test_object_get_private (obj);
 
@@ -115,60 +114,73 @@ test_object_class_init (TestObjectClass *klass)
 
   gobject_class->finalize = test_object_finalize;
 
-  test_object_properties[PROP_INTEGER_VAL] =
-    g_int_property_new ("integer-val",
-                        G_PROPERTY_READWRITE,
-                        G_STRUCT_OFFSET (TestObjectPrivate, integer_val),
-                        NULL, NULL);
-
-  test_object_properties[PROP_DOUBLE_VAL] =
-    g_double_property_new ("double-val",
-                           G_PROPERTY_READWRITE,
-                           G_STRUCT_OFFSET (TestObjectPrivate, double_val),
-                           NULL, NULL);
-
-  test_object_properties[PROP_STRING_VAL] =
-    g_string_property_new ("string-val",
-                           G_PROPERTY_READWRITE | G_PROPERTY_COPY_SET,
-                           G_STRUCT_OFFSET (TestObjectPrivate, str_val),
-                           NULL, NULL);
-
-  test_object_properties[PROP_BOOL_VAL] =
-    g_boolean_property_new ("bool-val",
-                            G_PROPERTY_READWRITE,
-                            G_STRUCT_OFFSET (TestObjectPrivate, bool_val),
-                            NULL, NULL);
-
-  test_object_properties[PROP_ENUM_VAL] =
-    g_enum_property_new ("enum-val",
-                         G_PROPERTY_READWRITE,
-                         G_STRUCT_OFFSET (TestObjectPrivate, enum_val),
-                         test_object_set_enum_val,
-                         NULL);
-  g_property_set_prerequisite ((GProperty *) test_object_properties[PROP_ENUM_VAL],
-                               test_enum_get_type ());
-  g_property_set_default ((GProperty *) test_object_properties[PROP_ENUM_VAL],
-                          TEST_ENUM_UNSET);
-
-  test_object_properties[PROP_WITH_DEFAULT] =
-    g_uint8_property_new ("with-default",
-                          G_PROPERTY_READWRITE,
-                          G_STRUCT_OFFSET (TestObjectPrivate, with_default),
-                          NULL,
-                          NULL);
-  g_property_set_default ((GProperty *) test_object_properties[PROP_WITH_DEFAULT], 255);
-
-  g_object_class_install_properties (gobject_class, LAST_PROP, test_object_properties);
+  G_DEFINE_PROPERTIES (TestObject, test_object, klass,
+                       G_DEFINE_PROPERTY (TestObject, test_object,
+                                          int,
+                                          integer_val,
+                                          G_PROPERTY_READWRITE)
+                       G_DEFINE_PROPERTY (TestObject, test_object,
+                                          double,
+                                          double_val,
+                                          G_PROPERTY_READWRITE)
+                       G_DEFINE_PROPERTY (TestObject, test_object,
+                                          string,
+                                          string_val,
+                                          G_PROPERTY_READWRITE | G_PROPERTY_COPY_SET)
+                       G_DEFINE_PROPERTY (TestObject, test_object,
+                                          boolean,
+                                          bool_val,
+                                          G_PROPERTY_READWRITE)
+                       G_DEFINE_PROPERTY (TestObject, test_object,
+                                          float,
+                                          width,
+                                          G_PROPERTY_READWRITE)
+                       G_DEFINE_PROPERTY (TestObject, test_object,
+                                          float,
+                                          height,
+                                          G_PROPERTY_READWRITE)
+                       G_DEFINE_PROPERTY_EXTENDED (TestObject, test_object,
+                                                   enum,
+                                                   enum_val,
+                                                   G_STRUCT_OFFSET (TestObjectPrivate, enum_val),
+                                                   test_object_set_enum_val_internal,
+                                                   NULL,
+                                                   G_PROPERTY_READWRITE,
+                                                   G_PROPERTY_DEFAULT (TEST_ENUM_UNSET)
+                                                   g_property_set_prerequisite (g_property, 
test_enum_get_type ());)
+                       G_DEFINE_PROPERTY (TestObject, test_object,
+                                          boolean,
+                                          enum_val_set,
+                                          G_PROPERTY_READABLE);
+                       G_DEFINE_PROPERTY_WITH_CODE (TestObject, test_object,
+                                                    uint8,
+                                                    with_default,
+                                                    G_PROPERTY_READWRITE,
+                                                    G_PROPERTY_DEFAULT (255)
+                                                    G_PROPERTY_DESCRIBE ("With Default",
+                                                                         "A property with a default value")))
 }
 
 static void
 test_object_init (TestObject *self)
 {
+  TestObjectPrivate *priv = test_object_get_private (self);
+
+  g_assert (priv->enum_val == TEST_ENUM_UNSET);
+  g_assert (!priv->enum_val_set);
 }
 
 G_DECLARE_PROPERTY_GET_SET (TestObject, test_object, gboolean, bool_val)
+G_DECLARE_PROPERTY_GET_SET (TestObject, test_object, float, width)
+G_DECLARE_PROPERTY_GET_SET (TestObject, test_object, float, height)
+G_DECLARE_PROPERTY_GET_SET (TestObject, test_object, TestEnum, enum_val)
+G_DECLARE_PROPERTY_GET (TestObject, test_object, gboolean, enum_val_set)
 
 G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, gboolean, bool_val)
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, float, width)
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, float, height)
+G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, TestEnum, enum_val)
+G_DEFINE_PROPERTY_GET (TestObject, test_object, gboolean, enum_val_set)
 
 /* test units start here */
 
@@ -191,12 +203,11 @@ gproperty_construct (void)
                                   "double-val", 3.14159,
                                   NULL);
 
-  TestObjectPrivate *priv =
-    g_type_instance_get_private ((GTypeInstance *) obj, test_object_get_type ());
+  TestObjectPrivate *priv = test_object_get_private (obj);
 
   g_assert_cmpint (priv->integer_val, ==, 42);
   g_assert (priv->bool_val);
-  g_assert_cmpstr (priv->str_val, ==, "Hello, world");
+  g_assert_cmpstr (priv->string_val, ==, "Hello, world");
   g_assert_cmpfloat ((float) priv->double_val, ==, 3.14159f);
 
   g_object_unref (obj);
@@ -206,23 +217,21 @@ static void
 gproperty_object_set (void)
 {
   TestObject *obj = g_object_new (test_object_get_type (), NULL);
-
-  TestObjectPrivate *priv =
-    g_type_instance_get_private ((GTypeInstance *) obj, test_object_get_type ());
+  TestObjectPrivate *priv = test_object_get_private (obj);
 
   gboolean did_emit_notify = FALSE;
 
   g_signal_connect (obj, "notify::string-val", G_CALLBACK (check_notify_emission), &did_emit_notify);
 
   g_object_set (obj, "string-val", "Hello!", NULL);
-  g_assert_cmpstr (priv->str_val, ==, "Hello!");
+  g_assert_cmpstr (priv->string_val, ==, "Hello!");
 
   g_assert (did_emit_notify);
 
   did_emit_notify = FALSE;
 
   g_object_set (obj, "string-val", "Hello!", NULL);
-  g_assert_cmpstr (priv->str_val, ==, "Hello!");
+  g_assert_cmpstr (priv->string_val, ==, "Hello!");
 
   g_assert (!did_emit_notify);
 
@@ -256,23 +265,18 @@ gproperty_explicit_set (void)
   gboolean did_emit_notify = FALSE;
   TestEnum enum_val;
 
-  TestObjectPrivate *priv =
-    g_type_instance_get_private ((GTypeInstance *) obj, test_object_get_type ());
-
   g_signal_connect (obj, "notify::enum-val", G_CALLBACK (check_notify_emission), &did_emit_notify);
 
   g_object_set (obj, "enum-val", TEST_ENUM_THREE, NULL);
-  g_assert_cmpint (priv->enum_val, ==, TEST_ENUM_THREE);
-  g_assert (priv->enum_val_set);
-
+  g_assert_cmpint (test_object_get_enum_val (obj), ==, TEST_ENUM_THREE);
+  g_assert (test_object_get_enum_val_set (obj));
   g_assert (did_emit_notify);
 
   did_emit_notify = FALSE;
-  g_object_set (obj, "enum-val", TEST_ENUM_THREE, NULL);
-  g_assert (!did_emit_notify);
-
+  test_object_set_enum_val (obj, TEST_ENUM_THREE);
   g_object_get (obj, "enum-val", &enum_val, NULL);
   g_assert_cmpint (enum_val, ==, TEST_ENUM_THREE);
+  g_assert (!did_emit_notify);
 
   g_object_unref (obj);
 }


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