Re: GProperty -- a proposal on top of GParamSpec (with code)
- From: Stefan Kost <ensonic hora-obscura de>
- To: Rob Staudinger <robsta linux intel com>
- Cc: gtk-devel-list gnome org
- Subject: Re: GProperty -- a proposal on top of GParamSpec (with code)
- Date: Sat, 26 Mar 2011 14:53:18 +0200
Hi Rob,
Am 06.12.2010 11:46, schrieb Rob Staudinger:
> Hello,
>
> I've written out so many gobject property handlers in the last few
> years, and they are always looking similar, so the desire to prune some
> boilerplate code has been growing. The idea behind GProperty (actually
> G<Foo>Property) is to subclass a GParamSpec<Foo> and add data and code
> so the property can update the object it applies to itself. For e.g. a
> string property this would of course include freeing the previous value.
>
You should also post this to bugzilla. I have been looking for this in bugzilla
now for quite some time. I am not sure yet, how much it will help. I small
benefit could be that it allows to supress notifies if the value has not changed
on a g_object_set.
Stefan
> What does GProperty offer over GParamSpec?
> * Remove the need for implementing GObject::get_property()
> and ::set_property() on your object (see "Boxed property access").
> * Remove the need for an enum of property-ids.
> * Remove the need for explicit property accessors with just a small
> amount of extra boilerplate code (see "Unboxed property access").
> * By subclassing GParamSpec, full compatibility is retained.
>
> My prototype [1] is currently using the Egg namespace, implementing
> EggBooleanProperty, EggDoubleProperty, EggIntProperty and
> EggStringProperty with examples that demonstrate usage. The following
> code snippets will use EggStringProperty for being easier to read than
> "<Foo>" all over the place.
>
> If this approach is adjudged positively I would like to import it into
> git.gnome.org's libegg module for hashing out the details and finishing
> up the implementation. Feedback would be appreciated.
>
>
> Boxed property access
> =====================
>
> Let's look at how the API is going to be used first:
>
> typedef struct {
> gchar *string_foo;
> } TestOffsetPrivate;
>
> static void
> test_offset_class_init (TestOffsetClass *klass)
> {
> GObjectClass *object_class = G_OBJECT_CLASS (klass);
> gpointer pspec;
> guint id = 0;
>
> g_type_class_add_private (klass, sizeof (TestOffsetPrivate));
>
> object_class->get_property = egg_object_get_property_impl;
> object_class->set_property = egg_object_set_property_impl;
>
> pspec = egg_string_property_for_field (
> "string-foo",
> G_STRUCT_OFFSET (TestOffsetPrivate,
> string_foo),
> NULL,
> G_PARAM_READWRITE);
> g_object_class_install_property (object_class, ++id, pspec);
> }
>
> * EggStringProperty is a subclass of GParamSpecString and implements
> EggProperty:
>
> typedef struct {
> GTypeInterface parent;
> void (*set_value) (EggProperty *p, GObject *o, const GValue *v);
> void (*get_value) (EggProperty *p, GObject *o, GValue *v);
> } EggPropertyInterface;
>
> * The generic GObject::get_property() and ::set_property()
> implementations egg_object_{get,set}_property_impl() are dispatching
> access through g_object_{get,set}() to the EggProperty interface. This
> makes per-class overrides and property-id enums obsolete.
>
> * The egg_string_property_for_field() constructor takes the offset of
> the "string_foo" member in the private data blob so it knows where to
> look for the actual value in the implementation of the EggProperty
> interface methods. (Alternative property constructors are discussed
> further below.)
>
>
> Unboxed property access
> =======================
>
> The code above covers boxed property access through the
> g_object_{get,set}() API. In addition, explicit property accessors are
> very common for their compile-time traits, as well as avoiding the
> boxing overhead. To that end, every property-class also implements
> unboxed accessors:
>
> typedef struct {
> GParamSpecClass parent_class;
> const gchar * (*get) (EggStringProperty *p, GObject *o);
> void (*set) (EggStringProperty *p, GObject *o, const gchar *v);
> } EggStringPropertyClass;
>
> Together with unboxed accessors on GObject level we can retain a certain
> level of type safety (exactly how should become clearer just a bit
> further down):
>
> const gchar * egg_object_get_string (gpointer object,
> EggStringProperty *property);
>
> void egg_object_set_string (gpointer object,
> EggStringProperty *property,
> const gchar *val);
>
>
> Putting it all together
> =======================
>
> For a complete example how to use the GProperty API please look at [2]
> (files matching *unboxed-offset*).
>
> Again, code snippet first, for a GObject called "TestUnboxedOffset":
>
> /* test-unboxed-offset.h */
>
> #define TEST_UNBOXED_OFFSET_AND_PROPERTY(obj, prop) \
> (TEST_UNBOXED_OFFSET (obj)), \
> (TEST_UNBOXED_OFFSET_GET_CLASS (obj)->prop)
>
> typedef struct {
> GObjectClass parent;
> EggStringProperty *string_foo;
> } TestUnboxedOffsetClass;
>
> /* test-unboxed-offset.c */
>
> static void
> test_unboxed_offset_class_init (TestUnboxedOffsetClass *klass)
> {
> ...
> klass->string_foo = egg_string_property_for_field ("string-foo",
> ...
> g_object_class_install_property (object_class,
> ++id,
> klass->string_foo);
>
> /* test-unboxed-offset.c */
>
> egg_object_set_string (
> TEST_UNBOXED_OFFSET_AND_PROPERTY (object, string_foo),
> "foo");
>
> In addition to g_object_class_install_property(), I would recommend to
> put a pointer to the property into the class structure. This makes sure
> the property is immediately at hand with an object instance. A (slightly
> quirky) new boilerplate macro like TEST_UNBOXED_OFFSET_AND_PROPERTY that
> produces two values (object and property) should help keeping the RSI
> under control. Accessing a property like this checks property name and
> type at compile time, so it's pretty much as good as an explicit setter
> test_unboxed_offset_set_string_foo() would be.
>
> Notes
> =====
>
> == Overriding properties
>
> I have not investigated this in depth yet, but it should be possible to
> override a property by also overriding the property pointer in the
> parent's class, in addition to g_object_class_override_property().
>
> == Alternative property constructors
>
> At this point there are three flavours of properties in place:
>
> * Properties operating on a field in the object's private data blob --
> see the *unboxed-offset* and *offset* examples.
>
> * Properties proxying a property of an aggregate object -- see the
> *proxy* examples.
>
> * Properties based on custom accessors, getter and setter function have
> to be passed to the property constructor -- see the *accessors*
> examples.
>
> == Code snippets in this mail
>
> A few instances of "const" qualifiers have been dropped and variable
> names have been changed for more compact formatting.
>
>
> [1] http://gitorious.org/egg-gobject
> [2] http://gitorious.org/egg-gobject/egg-gobject/trees/master/examples/
>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]