mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-07-30 05:43:28 +02:00
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
This commit is contained in:
@@ -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__ */
|
||||
|
@@ -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 ();
|
||||
}
|
||||
|
Reference in New Issue
Block a user