Discussion:
Property Binding Support: Present and Future
Denis Washington
2011-09-01 07:58:53 UTC
Permalink
Hello,

As you may know, I took part in Google Summer of Code this year (thanks
to Juan for mentoring me!) and worked on "GObject property binding
support for GtkBuilder and Glade":

https://live.gnome.org/DenisWashington_GtkBuilder

While talking on IRC with Tristan yesterday, I realized that while I
sent out weekly reports to gnome-soc-list and blogged about my work
twice, I never actually wrote anything about the code's status or
technical details on this mailing list. I would like to apologize for my
failure to do so and will try to make up for it by telling you
*everything* in this message: what I have done, how I have done it, what
works now, where the remaining problems are, and how these issues could
be overcome (this is where I really need your feedback!).

For those who don't know, the objective of my work is to extend Glade
with support for creating bindings between widget properties in a
project. What this means is that you can define a property's value as
being directly dependent on the value of another property - whenever the
"source" property's value is set, the value of the "target" property is
automatically updated, either to the same value or a user-defined
transformation thereof (more on this later). GLib supports this through
its GBinding API [1]. The goal is to expose this functionality in Glade
so that the user can create, modify and delete property bindings in
Glade and save them as part of a UI file.

This feature requires changes to both GTK+ and Glade, so I created
git.gnome.org branches for both of them, named "gtkbuilder-gbinding" and
"gbinding", respectively [2][3]. The GTK+ branch adds support for a new
bit of GtkBuilder syntax - the <binding> element - which makes it
possible for GtkBuilder objects to read property bindings from UI files.
It is used like this:

<object name="button">
...
<binding to="sensitive" from="active" source="checkbutton"/>
</object>

which means: "Let the 'sensitive' property of 'button' always have the
same value as the 'active' property of 'checkbutton'." Thanks to the
existence of GBinding, the code changes required for this are pretty
small. No new API is introduced; all bindings are automatically created
at the time they are read in by gtk_builder_add_from*(). (But this might
change slightly; see the problem discussion later in this epic mail
message).

The "gbinding" Glade branch is where the bulk of my work happened. It
adds a new "binding-source" property to GladeProperty for representing
property bindings in the data model and supports serialization and
deserialization of this information to <binding> elements. (See
glade_property_binding_read() and glade_property_binding_write() in
glade-property.c, respectively.) Furthermore, it augments Glade's
undo/redo framework with a glade_command_bind_property() command for
creating and deleting property bindings. On the UI side, this command is
exposed through a "Bind to source..." context menu item in the property
inspector. (For screenshots of how the UI currently looks, see my blog
posts [4][5].)

The UI and data model has been adapted to reflect the defined property
bindings:

- glade_command_set_property() was modified to recursively set the value
of all properties bound to the originally set property. This means that
the effect of a property binding is immediately visible in the Glade
workspace.

- In the property inspector, the edit widgets for bound properties are
insensitive (setting the value of a bound property doesn't make much
sense). Also, the tooltip of a bound property shows which other property
it is bound to.
(See glade-editor-property.c)

Also, I made some precautions to avoid invalid property bindings:

- The "Bind to source..." dialog for choosing the source of a property
binding only allows you to select properties that have the same, or a
compatible, type, and are enabled (if they are optional) and sensitive
(if there are one of multiple alternative properties, e.g. "text",
"stock" and "embedded widget" in GtkButton). All other properties are
greyed out and moved to the end of the list.
(See glade_editor_property_show_bind_dialog() and its helper functions
in glade-editor-property.c)

- If the source or target of a property binding disappears because the
widget it belongs to is deleted, the binding is automatically removed
too. This is properly integrated into the undo/redo system, so undoing
the widget removal also brings the property binding back.
(See glade_command_delete_binding_refs() in glade-command.c)

One remaining issue with the current code is that it does not react to
property binding sources becoming disabled or insensitive. This is
currently not possible in a sane way as changes to a property's
enabled/sensitivity state are not tracked with the undo/redo framework
at the moment. (I had code to do this in the branch before, but it
worked with manual signal handling hackery and was removed later on
Tristan's request.) The obvious solution would be to change this by
introducing glade_command_set_property_enabled() and
glade_command_set_property_sensitive() and porting all of Glade to that.
If there is general agreement to do so, I would be willing to do that
work. In any case, this has to be fixed in some way before the branch is
ready to be merged into master.

Other than that, I don't know of any other major showstoppers, but an
extensive code review by Juan and Tristan might very well reveal some. ;)

The big question, however, it how to support transformation functions
for property bindings. This GBinding feature allows you to define a
function that processes the value of a binding's source property before
it is applied to the target, which allows you to create bindings between
properties of different types and generally make property bindings much
more useful and interesting. Adding this into the GTK+ and Glade
branches is not a big problem in principle, and in fact I did just that
during Summer of Code. However, I had to later remove the code again,
the reason being on the GTK+/GLib side.

The problem is when and how to resolve the transformation function names
that would be stored in the GtkBuilder file to the actual function
implementations. In my code, I moved all property binding creation to
two new API functions, gtk_builder_create_bindings() and
gtk_builder_create_bindings_full(), which take the same arguments as
gtk_builder_connect_signals*() and locate transformation functions the
same way (GModule or a custom callback, called GtkBuilderBindingFunc).

Unfortunately, this setup means more work for language binding authors:
because transformation functions are specified as an argument to
g_object_bind_property_full() rather than by connecting a signal, a
language-specific GtkBuilderConnectFunc for
gtk_builder_connect_signals*() cannot be reused and each language
binding would be required to provide a GtkBuilderBindingFunc to replace
the use of GModule with something appropriate for the language. Also,
the introduction of another function to be called for every loaded
GtkBuilder function is really not ideal.

Talking with Juan and Tristan, we concluded that a proper solution
probably requires changes to GBinding itself. More specifically, if
GBinding implemented the transformation function as being the handler of
a "transform" signal instead of an anonymous callback, one could reuse
gtk_builder_connect_signals*() to locate transformation functions and
move property binding creation there. For backwards compatibility and
convenience, the g_object_bind_property() API could still stay as it is
now. There would be some issues to sort out - for instance, how to
behave if multiple signal handlers are connected to the "transform"
signal - but it might be doable without breaking anything. This still
needs to be talked about with both the GLib and GTK+ team, though.

For reference, you can still find my code with transformation function
support in the "gtkbuilder-gbinding" GTK+ and "gbinding-transform" Glade
branch.

Well, this is all there is to say about the code now. (This mail is
already way too long as it is. ;) I hope you now have a better insight
wrt what I have done during GSoC and what is still to do.

As I wrote in the beginning, I need your feedback! If you have any
questions, remarks, or suggestions regarding the issues I outlined -
especially regarding the transformation function situation - I would be
excited to hear them! Thanks. :)

Regards,
Denis

[1] http://developer.gnome.org/gobject/unstable/GBinding.html
[2] http://git.gnome.org/browse/gtk+/log/?h=gtkbuilder-gbinding
[3] http://git.gnome.org/browse/glade/log/?h=gbinding
[4]
http://denwash.wordpress.com/2011/06/10/glade-and-property-binding-finally-something-to-see/
[5]
http://denwash.wordpress.com/2011/07/20/glade-and-property-binding-create-your-own-bindings-now/
_______________________________________________
Glade-devel maillist - Glade-***@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/glade-devel
Alexandre Mazari
2011-09-01 08:32:58 UTC
Permalink
Hi Denis,

Thanks you very much for this amazing work.

I was wondering if the current code allows the binding of a 'model'
instance property to a widget's one. By model I mean non-graphical
non-glade-handled GObject. Is there some way to expose some arbitrary
GObject in the GtkBuilder context so we can bind its properties ?

Regarding transformation, would'nt providing default transformations
(int <-> string, percentage <-> double in 0...1, etc.. ) make you life
easier by not supporting user provided functs while covering 90%
percent of use cases ?

Happy Coding,
Alexandre
Post by Denis Washington
Hello,
As you may know, I took part in Google Summer of Code this year (thanks
to Juan for mentoring me!) and worked on "GObject property binding
https://live.gnome.org/DenisWashington_GtkBuilder
While talking on IRC with Tristan yesterday, I realized that while I
sent out weekly reports to gnome-soc-list and blogged about my work
twice, I never actually wrote anything about the code's status or
technical details on this mailing list. I would like to apologize for my
failure to do so and will try to make up for it by telling you
*everything* in this message: what I have done, how I have done it, what
works now, where the remaining problems are, and how these issues could
be overcome (this is where I really need your feedback!).
For those who don't know, the objective of my work is to extend Glade
with support for creating bindings between widget properties in a
project. What this means is that you can define a property's value as
being directly dependent on the value of another property - whenever the
"source" property's value is set, the value of the "target" property is
automatically updated, either to the same value or a user-defined
transformation thereof (more on this later). GLib supports this through
its GBinding API [1]. The goal is to expose this functionality in Glade
so that the user can create, modify and delete property bindings in
Glade and save them as part of a UI file.
This feature requires changes to both GTK+ and Glade, so I created
git.gnome.org branches for both of them, named "gtkbuilder-gbinding" and
"gbinding", respectively [2][3]. The GTK+ branch adds support for a new
bit of GtkBuilder syntax - the <binding> element - which makes it
possible for GtkBuilder objects to read property bindings from UI files.
  <object name="button">
    ...
    <binding to="sensitive" from="active" source="checkbutton"/>
  </object>
which means: "Let the 'sensitive' property of 'button' always have the
same value as the 'active' property of 'checkbutton'." Thanks to the
existence of GBinding, the code changes required for this are pretty
small. No new API is introduced; all bindings are automatically created
at the time they are read in by gtk_builder_add_from*(). (But this might
change slightly; see the problem discussion later in this epic mail
message).
The "gbinding" Glade branch is where the bulk of my work happened. It
adds a new "binding-source" property to GladeProperty for representing
property bindings in the data model and supports serialization and
deserialization of this information to <binding> elements. (See
glade_property_binding_read() and glade_property_binding_write() in
glade-property.c, respectively.) Furthermore, it augments Glade's
undo/redo framework with a glade_command_bind_property() command for
creating and deleting property bindings. On the UI side, this command is
exposed through a "Bind to source..." context menu item in the property
inspector. (For screenshots of how the UI currently looks, see my blog
posts [4][5].)
The UI and data model has been adapted to reflect the defined property
- glade_command_set_property() was modified to recursively set the value
of all properties bound to the originally set property. This means that
the effect of a property binding is immediately visible in the Glade
workspace.
- In the property inspector, the edit widgets for bound properties are
insensitive (setting the value of a bound property doesn't make much
sense). Also, the tooltip of a bound property shows which other property
it is bound to.
(See glade-editor-property.c)
- The "Bind to source..." dialog for choosing the source of a property
binding only allows you to select properties that have the same, or a
compatible, type, and are enabled (if they are optional) and sensitive
(if there are one of multiple alternative properties, e.g. "text",
"stock" and "embedded widget" in GtkButton). All other properties are
greyed out and moved to the end of the list.
(See glade_editor_property_show_bind_dialog() and its helper functions
in glade-editor-property.c)
- If the source or target of a property binding disappears because the
widget it belongs to is deleted, the binding is automatically removed
too. This is properly integrated into the undo/redo system, so undoing
the widget removal also brings the property binding back.
(See glade_command_delete_binding_refs() in glade-command.c)
One remaining issue with the current code is that it does not react to
property binding sources becoming disabled or insensitive. This is
currently not possible in a sane way as changes to a property's
enabled/sensitivity state are not tracked with the undo/redo framework
at the moment. (I had code to do this in the branch before, but it
worked with manual signal handling hackery and was removed later on
Tristan's request.) The obvious solution would be to change this by
introducing glade_command_set_property_enabled() and
glade_command_set_property_sensitive() and porting all of Glade to that.
If there is general agreement to do so, I would be willing to do that
work. In any case, this has to be fixed in some way before the branch is
ready to be merged into master.
Other than that, I don't know of any other major showstoppers, but an
extensive code review by Juan and Tristan might very well reveal some. ;)
The big question, however, it how to support transformation functions
for property bindings. This GBinding feature allows you to define a
function that processes the value of a binding's source property before
it is applied to the target, which allows you to create bindings between
properties of different types and generally make property bindings much
more useful and interesting. Adding this into the GTK+ and Glade
branches is not a big problem in principle, and in fact I did just that
during Summer of Code. However, I had to later remove the code again,
the reason being on the GTK+/GLib side.
The problem is when and how to resolve the transformation function names
that would be stored in the GtkBuilder file to the actual function
implementations. In my code, I moved all property binding creation to
two new API functions, gtk_builder_create_bindings() and
gtk_builder_create_bindings_full(), which take the same arguments as
gtk_builder_connect_signals*() and locate transformation functions the
same way (GModule or a custom callback, called GtkBuilderBindingFunc).
because transformation functions are specified as an argument to
g_object_bind_property_full() rather than by connecting a signal, a
language-specific GtkBuilderConnectFunc for
gtk_builder_connect_signals*() cannot be reused and each language
binding would be required to provide a GtkBuilderBindingFunc to replace
the use of GModule with something appropriate for the language. Also,
the introduction of another function to be called for every loaded
GtkBuilder function is really not ideal.
Talking with Juan and Tristan, we concluded that a proper solution
probably requires changes to GBinding itself. More specifically, if
GBinding implemented the transformation function as being the handler of
a "transform" signal instead of an anonymous callback, one could reuse
gtk_builder_connect_signals*() to locate transformation functions and
move property binding creation there. For backwards compatibility and
convenience, the g_object_bind_property() API could still stay as it is
now. There would be some issues to sort out - for instance, how to
behave if multiple signal handlers are connected to the "transform"
signal - but it might be doable without breaking anything. This still
needs to be talked about with both the GLib and GTK+ team, though.
For reference, you can still find my code with transformation function
support in the "gtkbuilder-gbinding" GTK+ and "gbinding-transform" Glade
branch.
Well, this is all there is to say about the code now. (This mail is
already way too long as it is. ;) I hope you now have a better insight
wrt what I have done during GSoC and what is still to do.
As I wrote in the beginning, I need your feedback! If you have any
questions, remarks, or suggestions regarding the issues I outlined -
especially regarding the transformation function situation - I would be
excited to hear them! Thanks. :)
Regards,
Denis
[1] http://developer.gnome.org/gobject/unstable/GBinding.html
[2] http://git.gnome.org/browse/gtk+/log/?h=gtkbuilder-gbinding
[3] http://git.gnome.org/browse/glade/log/?h=gbinding
[4]
http://denwash.wordpress.com/2011/06/10/glade-and-property-binding-finally-something-to-see/
[5]
http://denwash.wordpress.com/2011/07/20/glade-and-property-binding-create-your-own-bindings-now/
_______________________________________________
http://lists.ximian.com/mailman/listinfo/glade-devel
--
"If you open your mind too much, you brain will fall out"
Tim Minchin
_______________________________________________
Glade-devel maillist - Glade-***@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/glade-devel
Denis Washington
2011-09-01 15:32:05 UTC
Permalink
Post by Alexandre Mazari
Hi Denis,
Thanks you very much for this amazing work.
:)
Post by Alexandre Mazari
I was wondering if the current code allows the binding of a 'model'
instance property to a widget's one. By model I mean non-graphical
non-glade-handled GObject. Is there some way to expose some arbitrary
GObject in the GtkBuilder context so we can bind its properties ?
This is currently not supported. It would also be problematic, as we
could not check if the property binding is valid (that is, whether the
type is correct etc.) when an external object is involved. Also, one
would still have to match any referred-to placeholder objects with real
ones in code, so I'm afraif that declaring bindings with external
objects in the UI file wouldn't by you much.

A special case, however, is bindings to GSettings objects, which might
be supported in the future.
Post by Alexandre Mazari
Regarding transformation, would'nt providing default transformations
(int<-> string, percentage<-> double in 0...1, etc.. ) make you life
easier by not supporting user provided functs while covering 90%
percent of use cases ?
That's a nice idea and would also benefit programmatic uses of
g_object_bind_property(). These functions would have to be in GLib,
though; otherwise, using them would require an external library where
they are defined in.

Regards,
Denis
_______________________________________________
Glade-devel maillist - Glade-***@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/glade-devel
Tristan Van Berkom
2011-09-01 18:55:35 UTC
Permalink
Hi,
I haven't read the mail in full detail and will make a
statement soon, first I just wanted to clarify some things
in this response.
Post by Denis Washington
Post by Alexandre Mazari
Hi Denis,
Thanks you very much for this amazing work.
:)
Post by Alexandre Mazari
I was wondering if the current code allows the binding of a 'model'
instance property to a widget's one. By model I mean non-graphical
non-glade-handled GObject. Is there some way to expose some arbitrary
GObject in the GtkBuilder context so we can bind its properties ?
This is currently not supported. It would also be problematic, as we
could not check if the property binding is valid (that is, whether the
type is correct etc.) when an external object is involved. Also, one
would still have to match any referred-to placeholder objects with real
ones in code, so I'm afraif that declaring bindings with external
objects in the UI file wouldn't by you much.
A special case, however, is bindings to GSettings objects, which might
be supported in the future.
Alexandre: you should know that GtkBuilder can create *any* gobject,
GtkBuildable interface is only used to extend GObjects to parse
custom xml.

Also, Glade allows you to include your own widgets/objects in Glade's
palette, so... What is very easily possible is:

o Create your GObject that has properties
o Create an entry point for Glade, this can be a full
plugin or a simple xml catalog (some methods apply,
if the GObject you write is in a library, Glade can
introspect the possible properties you install on it,
otherwise it's possible to declare it virtually and
specify the properties and their types manually in the xml).
o In Glade, you will be able to assign bindings for your
own custom GObject that you exposed in Glade's palette.

So with this technique you really need to create the GObject
in the GtkBuilder file (that might not be a problem if you
create it early and assign it some state at init time).

Other than that... I've had plans to add something like:
gtk_builder_expose_object (builder, object, "name");

If we land that then you could "export" objects by name
after creating the GtkBuilder and before parsing a .ui file,
this will be useful equally for assigning GObject type
properties, connecting signals and could also be used
for bindings.

However even though it's a very simple patch to GTK+ I
haven't managed to land it yet. I had intended to land
that as part of the 'composite-containers' branch I was
working on.. but stopped working on... perhaps it's
a good idea to go ahead with that addition separately
since it's very easy to do...
Post by Denis Washington
Post by Alexandre Mazari
Regarding transformation, would'nt providing default transformations
(int<-> string, percentage<-> double in 0...1, etc.. ) make you life
easier by not supporting user provided functs while covering 90%
percent of use cases ?
That's a nice idea and would also benefit programmatic uses of
g_object_bind_property(). These functions would have to be in GLib,
though; otherwise, using them would require an external library where
they are defined in.
GBinding already defaults to using default transformation functions.

The application developer is also free to augment the GValue transform
functions in it's own environment.

The transform function is only really useful for doing custom
transformations... for example you want your label to update
to the value "5 bottles of milk", when the 'milk_amount' integer
value is 5... or "1 bottle of milk" when the value is 1.

The transform function can be very useful for that type of case
where you need a specific transformation in context with the said
binding.

It's my opinion that the bindings integration will still be a big
win in this first iteration... without the transform functions.

Cheers,
-Tristan


_______________________________________________
Glade-devel maillist - Glade-***@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/glade-devel
Denis Washington
2011-09-01 20:07:48 UTC
Permalink
Post by Tristan Van Berkom
Post by Denis Washington
Post by Alexandre Mazari
Regarding transformation, would'nt providing default transformations
(int<-> string, percentage<-> double in 0...1, etc.. ) make you life
easier by not supporting user provided functs while covering 90%
percent of use cases ?
That's a nice idea and would also benefit programmatic uses of
g_object_bind_property(). These functions would have to be in GLib,
though; otherwise, using them would require an external library where
they are defined in.
GBinding already defaults to using default transformation functions.
Really? This isn't documented anywhere. Thanks for mentioning! I admit
that this makes the need for transformation functions much less
pressing, but they are still a very useful feature.

Regards,
Denis
_______________________________________________
Glade-devel maillist - Glade-***@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/glade-devel
Tristan Van Berkom
2011-09-01 20:49:12 UTC
Permalink
Post by Denis Washington
Post by Tristan Van Berkom
Post by Denis Washington
Post by Alexandre Mazari
Regarding transformation, would'nt providing default transformations
(int<->   string, percentage<->   double in 0...1, etc.. ) make you life
easier by not supporting user provided functs while covering 90%
percent of use cases ?
That's a nice idea and would also benefit programmatic uses of
g_object_bind_property(). These functions would have to be in GLib,
though; otherwise, using them would require an external library where
they are defined in.
GBinding already defaults to using default transformation functions.
Really? This isn't documented anywhere. Thanks for mentioning! I admit
that this makes the need for transformation functions much less
pressing, but they are still a very useful feature.
Yeah, the best documentation I find is, when calling the _bind_full() function
and passing a NULL transform function "the default will be used" ;-)

In gbinding.c its quite clear... the default is to try g_value_copy() first and
then resort to g_value_transform().

Cheers,
-Tristan
_______________________________________________
Glade-devel maillist - Glade-***@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/glade-devel
Tristan Van Berkom
2011-09-17 17:32:30 UTC
Permalink
Hi Denis,
Sorry it took me a while to get back to you, I just got back to
montreal and should have a little time...
Post by Denis Washington
Hello,
As you may know, I took part in Google Summer of Code this year (thanks
to Juan for mentoring me!) and worked on "GObject property binding
https://live.gnome.org/DenisWashington_GtkBuilder
While talking on IRC with Tristan yesterday, I realized that while I
sent out weekly reports to gnome-soc-list and blogged about my work
twice, I never actually wrote anything about the code's status or
technical details on this mailing list. I would like to apologize for my
failure to do so and will try to make up for it by telling you
*everything* in this message: what I have done, how I have done it, what
works now, where the remaining problems are, and how these issues could
be overcome (this is where I really need your feedback!).
For those who don't know, the objective of my work is to extend Glade
with support for creating bindings between widget properties in a
project. What this means is that you can define a property's value as
being directly dependent on the value of another property - whenever the
"source" property's value is set, the value of the "target" property is
automatically updated, either to the same value or a user-defined
transformation thereof (more on this later). GLib supports this through
its GBinding API [1]. The goal is to expose this functionality in Glade
so that the user can create, modify and delete property bindings in
Glade and save them as part of a UI file.
This feature requires changes to both GTK+ and Glade, so I created
git.gnome.org branches for both of them, named "gtkbuilder-gbinding" and
"gbinding", respectively [2][3]. The GTK+ branch adds support for a new
bit of GtkBuilder syntax - the <binding> element - which makes it
possible for GtkBuilder objects to read property bindings from UI files.
<object name="button">
...
<binding to="sensitive" from="active" source="checkbutton"/>
</object>
which means: "Let the 'sensitive' property of 'button' always have the
same value as the 'active' property of 'checkbutton'." Thanks to the
existence of GBinding, the code changes required for this are pretty
small. No new API is introduced; all bindings are automatically created
at the time they are read in by gtk_builder_add_from*(). (But this might
change slightly; see the problem discussion later in this epic mail
message).
The "gbinding" Glade branch is where the bulk of my work happened. It
adds a new "binding-source" property to GladeProperty for representing
property bindings in the data model and supports serialization and
deserialization of this information to <binding> elements. (See
glade_property_binding_read() and glade_property_binding_write() in
glade-property.c, respectively.) Furthermore, it augments Glade's
undo/redo framework with a glade_command_bind_property() command for
creating and deleting property bindings. On the UI side, this command is
exposed through a "Bind to source..." context menu item in the property
inspector. (For screenshots of how the UI currently looks, see my blog
posts [4][5].)
The dialog is nice enough in general, I think it needs to expose the
real untranslated property name as well, perhaps with the translated
name in italic/grey beside it. It would even be interesting to include
the proper class name introducing that property in the list.

i.e.:

GtkWidget:tooltip-text /Tooltip Text/
GtkEntry:text /Text/

(its nice to have the translated titles around, but it's usually
more important to show something untranslated and informative here).
Post by Denis Washington
The UI and data model has been adapted to reflect the defined property
- glade_command_set_property() was modified to recursively set the value
of all properties bound to the originally set property. This means that
the effect of a property binding is immediately visible in the Glade
workspace.
It sounds like a nice feature but I'm not sure it's the right place.

Perhaps the implementation of glade_property_sync() would be a better
location for this.

Which also brings to mind, there should be some protection to avoid
circular references and feedback loops which could be easily introduced
by using bindings, perhaps Glade should simply allow the user to create
dangerous documents and forcefully avoid feedback internally, or just
refuse to create circular loops all together (not such a bad limitation
at first thought...).
Post by Denis Washington
- In the property inspector, the edit widgets for bound properties are
insensitive (setting the value of a bound property doesn't make much
sense). Also, the tooltip of a bound property shows which other property
it is bound to.
(See glade-editor-property.c)
If I understand correctly, you are updating property sensitivity
directly based on whether a property is bound or not, this will
probably fail in some conditions as the backend is responsible
currently for updating state.

If for instance, you bind the "label" property of a GtkButton
and then set the button to be "custom content" or such (using
the radio buttons in the button editor), then undo... will the
tooltip of the insensitive "label" property be correct ?
Post by Denis Washington
- The "Bind to source..." dialog for choosing the source of a property
binding only allows you to select properties that have the same, or a
compatible, type, and are enabled (if they are optional) and sensitive
(if there are one of multiple alternative properties, e.g. "text",
"stock" and "embedded widget" in GtkButton). All other properties are
greyed out and moved to the end of the list.
(See glade_editor_property_show_bind_dialog() and its helper functions
in glade-editor-property.c)
Right, this should at least take care of possible runtime warnings.
Post by Denis Washington
- If the source or target of a property binding disappears because the
widget it belongs to is deleted, the binding is automatically removed
too. This is properly integrated into the undo/redo system, so undoing
the widget removal also brings the property binding back.
(See glade_command_delete_binding_refs() in glade-command.c)
Will have to eventually review that in detail, but sounds like the
right approach there.
Post by Denis Washington
One remaining issue with the current code is that it does not react to
property binding sources becoming disabled or insensitive. This is
currently not possible in a sane way as changes to a property's
enabled/sensitivity state are not tracked with the undo/redo framework
at the moment. (I had code to do this in the branch before, but it
worked with manual signal handling hackery and was removed later on
Tristan's request.) The obvious solution would be to change this by
introducing glade_command_set_property_enabled() and
glade_command_set_property_sensitive() and porting all of Glade to that.
If there is general agreement to do so, I would be willing to do that
work. In any case, this has to be fixed in some way before the branch is
ready to be merged into master.
Those are the blockers for this integration.

Porting that will take time and effort though, take a look at
glade-gtk.c and note how sensitivity is generally driven, all of
that needs to be ported to control sensitivity while updating
property values at the editor level (that is, things now belong
on the 'calling' side of GladeCommand instead of the other,
'data model' side).

This might mean extending GladeEditorProperty api to give the
widget class adaptor code easy control on when to control
sensitivity (the pre/post-commit signals sound like the right
place to couple in sensitivity commands with property commands).

It's also important that sensitivity cannot be controlled alone
in a single command... because commands usually should represent
an action taken in the document (a document is dirty after executing
any command).
Post by Denis Washington
Other than that, I don't know of any other major showstoppers, but an
extensive code review by Juan and Tristan might very well reveal some. ;)
The big question, however, it how to support transformation functions
for property bindings. This GBinding feature allows you to define a
function that processes the value of a binding's source property before
it is applied to the target, which allows you to create bindings between
properties of different types and generally make property bindings much
more useful and interesting. Adding this into the GTK+ and Glade
branches is not a big problem in principle, and in fact I did just that
during Summer of Code. However, I had to later remove the code again,
the reason being on the GTK+/GLib side.
The problem is when and how to resolve the transformation function names
that would be stored in the GtkBuilder file to the actual function
implementations. In my code, I moved all property binding creation to
two new API functions, gtk_builder_create_bindings() and
gtk_builder_create_bindings_full(), which take the same arguments as
gtk_builder_connect_signals*() and locate transformation functions the
same way (GModule or a custom callback, called GtkBuilderBindingFunc).
because transformation functions are specified as an argument to
g_object_bind_property_full() rather than by connecting a signal, a
language-specific GtkBuilderConnectFunc for
gtk_builder_connect_signals*() cannot be reused and each language
binding would be required to provide a GtkBuilderBindingFunc to replace
the use of GModule with something appropriate for the language. Also,
the introduction of another function to be called for every loaded
GtkBuilder function is really not ideal.
Talking with Juan and Tristan, we concluded that a proper solution
probably requires changes to GBinding itself. More specifically, if
GBinding implemented the transformation function as being the handler of
a "transform" signal instead of an anonymous callback, one could reuse
gtk_builder_connect_signals*() to locate transformation functions and
move property binding creation there. For backwards compatibility and
convenience, the g_object_bind_property() API could still stay as it is
now. There would be some issues to sort out - for instance, how to
behave if multiple signal handlers are connected to the "transform"
signal - but it might be doable without breaking anything. This still
needs to be talked about with both the GLib and GTK+ team, though.
For reference, you can still find my code with transformation function
support in the "gtkbuilder-gbinding" GTK+ and "gbinding-transform" Glade
branch.
I don't want to discuss transformation functions in depth until
finished landing this code in GTK+/Glade.

If transformation functions are implemented at a later date, they should
use similar semantics as signals, actually reading the code at this
moment I don't see any reason why the normal GtkBuilderConnectFunc
couldnt be used by the GtkBuilder during gtk_builder_connect_signals()
to resolve any gbinding transform function signals.

So *when* we look into this, my vague proposal runs like this:
a.) Introduce "transform" signals on GBinding object and
probably prefer the signal (the default handler falls
back on invoking any registered transform function for
backwards compatibility and then defaults to usual GValue
transforms and copies).

b.) Extend GtkBuilder binding parsing slightly to allow specification
of a transform function... collect the GBinding objects and
transform function data during the parse and cache them for use
in gtk_builder_connect_signals() (possibly even in the same cache
as the actual <signals>).

c.) Connect the transform signal callbacks later in the normal way
from gtk_builder_connect_signals()

This will imply an api extension in GtkBuilder, so when it gets
introduced in GTK+ Glade will need to be careful not to register
transform functions for projects targeting a too old version of GTK+.

Which leads me to another observation, the binding feature itself
should not be available of the project is targeting < GTK+ 3.2
(or whatever GTK+ version we get the feature into).
Post by Denis Washington
Well, this is all there is to say about the code now. (This mail is
already way too long as it is. ;) I hope you now have a better insight
wrt what I have done during GSoC and what is still to do.
As I wrote in the beginning, I need your feedback! If you have any
questions, remarks, or suggestions regarding the issues I outlined -
especially regarding the transformation function situation - I would be
excited to hear them! Thanks. :)
Thanks a lot for the great effort done this year.

Again, sorry for taking so long to give you some attention.

Best Regards,
-Tristan


_______________________________________________
Glade-devel maillist - Glade-***@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/glade-devel
Denis Washington
2011-09-22 09:50:04 UTC
Permalink
Post by Tristan Van Berkom
Hi Denis,
Sorry it took me a while to get back to you, I just got back to
montreal and should have a little time...
No problem. Thanks for the comments!
Post by Tristan Van Berkom
Post by Denis Washington
Hello,
As you may know, I took part in Google Summer of Code this year (thanks
to Juan for mentoring me!) and worked on "GObject property binding
https://live.gnome.org/DenisWashington_GtkBuilder
While talking on IRC with Tristan yesterday, I realized that while I
sent out weekly reports to gnome-soc-list and blogged about my work
twice, I never actually wrote anything about the code's status or
technical details on this mailing list. I would like to apologize for my
failure to do so and will try to make up for it by telling you
*everything* in this message: what I have done, how I have done it, what
works now, where the remaining problems are, and how these issues could
be overcome (this is where I really need your feedback!).
For those who don't know, the objective of my work is to extend Glade
with support for creating bindings between widget properties in a
project. What this means is that you can define a property's value as
being directly dependent on the value of another property - whenever the
"source" property's value is set, the value of the "target" property is
automatically updated, either to the same value or a user-defined
transformation thereof (more on this later). GLib supports this through
its GBinding API [1]. The goal is to expose this functionality in Glade
so that the user can create, modify and delete property bindings in
Glade and save them as part of a UI file.
This feature requires changes to both GTK+ and Glade, so I created
git.gnome.org branches for both of them, named "gtkbuilder-gbinding" and
"gbinding", respectively [2][3]. The GTK+ branch adds support for a new
bit of GtkBuilder syntax - the<binding> element - which makes it
possible for GtkBuilder objects to read property bindings from UI files.
<object name="button">
...
<binding to="sensitive" from="active" source="checkbutton"/>
</object>
which means: "Let the 'sensitive' property of 'button' always have the
same value as the 'active' property of 'checkbutton'." Thanks to the
existence of GBinding, the code changes required for this are pretty
small. No new API is introduced; all bindings are automatically created
at the time they are read in by gtk_builder_add_from*(). (But this might
change slightly; see the problem discussion later in this epic mail
message).
The "gbinding" Glade branch is where the bulk of my work happened. It
adds a new "binding-source" property to GladeProperty for representing
property bindings in the data model and supports serialization and
deserialization of this information to<binding> elements. (See
glade_property_binding_read() and glade_property_binding_write() in
glade-property.c, respectively.) Furthermore, it augments Glade's
undo/redo framework with a glade_command_bind_property() command for
creating and deleting property bindings. On the UI side, this command is
exposed through a "Bind to source..." context menu item in the property
inspector. (For screenshots of how the UI currently looks, see my blog
posts [4][5].)
The dialog is nice enough in general, I think it needs to expose the
real untranslated property name as well, perhaps with the translated
name in italic/grey beside it. It would even be interesting to include
the proper class name introducing that property in the list.
GtkWidget:tooltip-text /Tooltip Text/
GtkEntry:text /Text/
(its nice to have the translated titles around, but it's usually
more important to show something untranslated and informative here).
I used the translated names because these are what the property
inspector shows, so it would be arguably inconsistent if we highlighted
the internal property names as the primary identification means. I think
better would be:

Tooltip Text /GtkWidget:tooltip-text/
Post by Tristan Van Berkom
Post by Denis Washington
The UI and data model has been adapted to reflect the defined property
- glade_command_set_property() was modified to recursively set the value
of all properties bound to the originally set property. This means that
the effect of a property binding is immediately visible in the Glade
workspace.
It sounds like a nice feature but I'm not sure it's the right place.
Perhaps the implementation of glade_property_sync() would be a better
location for this.
I chose this location so that all property set operations are recorded
in the command system (grouped with the original set command,
naturally), which makes undo trivial.
Post by Tristan Van Berkom
Which also brings to mind, there should be some protection to avoid
circular references and feedback loops which could be easily introduced
by using bindings, perhaps Glade should simply allow the user to create
dangerous documents and forcefully avoid feedback internally, or just
refuse to create circular loops all together (not such a bad limitation
at first thought...).
I think prohibit cycles, we would need to provide explicit support for
two-way bindings (such as offered by a g_object_bind_property() flag) to
retain the whole power, but this probably wouldn't be worth the
complication in the code.

I don't know how well GBinding handles cycles currently. It would be
best if we could avoid infinite loops on that level (e.g. by suspending
the binding while syncing the target's value to the source, so that a
resulting update of the source itself doesn't trigger a new sync), but
I'm not sure how feasible that is.
Post by Tristan Van Berkom
Post by Denis Washington
- In the property inspector, the edit widgets for bound properties are
insensitive (setting the value of a bound property doesn't make much
sense). Also, the tooltip of a bound property shows which other property
it is bound to.
(See glade-editor-property.c)
If I understand correctly, you are updating property sensitivity
directly based on whether a property is bound or not, this will
probably fail in some conditions as the backend is responsible
currently for updating state.
If for instance, you bind the "label" property of a GtkButton
and then set the button to be "custom content" or such (using
the radio buttons in the button editor), then undo... will the
tooltip of the insensitive "label" property be correct ?
I don't set the sensitivity in the sense of
glade_property_set_sensitive(). Rather, I just control the sensitivity
of the associated GladeEditorProperty in
glade_editor_property_sensitivity_cb(). Thus, the example you described
works correctly.
Post by Tristan Van Berkom
Post by Denis Washington
- The "Bind to source..." dialog for choosing the source of a property
binding only allows you to select properties that have the same, or a
compatible, type, and are enabled (if they are optional) and sensitive
(if there are one of multiple alternative properties, e.g. "text",
"stock" and "embedded widget" in GtkButton). All other properties are
greyed out and moved to the end of the list.
(See glade_editor_property_show_bind_dialog() and its helper functions
in glade-editor-property.c)
Right, this should at least take care of possible runtime warnings.
Post by Denis Washington
- If the source or target of a property binding disappears because the
widget it belongs to is deleted, the binding is automatically removed
too. This is properly integrated into the undo/redo system, so undoing
the widget removal also brings the property binding back.
(See glade_command_delete_binding_refs() in glade-command.c)
Will have to eventually review that in detail, but sounds like the
right approach there.
Post by Denis Washington
One remaining issue with the current code is that it does not react to
property binding sources becoming disabled or insensitive. This is
currently not possible in a sane way as changes to a property's
enabled/sensitivity state are not tracked with the undo/redo framework
at the moment. (I had code to do this in the branch before, but it
worked with manual signal handling hackery and was removed later on
Tristan's request.) The obvious solution would be to change this by
introducing glade_command_set_property_enabled() and
glade_command_set_property_sensitive() and porting all of Glade to that.
If there is general agreement to do so, I would be willing to do that
work. In any case, this has to be fixed in some way before the branch is
ready to be merged into master.
Those are the blockers for this integration.
Porting that will take time and effort though, take a look at
glade-gtk.c and note how sensitivity is generally driven, all of
that needs to be ported to control sensitivity while updating
property values at the editor level (that is, things now belong
on the 'calling' side of GladeCommand instead of the other,
'data model' side).
I will look into that.
Post by Tristan Van Berkom
This might mean extending GladeEditorProperty api to give the
widget class adaptor code easy control on when to control
sensitivity (the pre/post-commit signals sound like the right
place to couple in sensitivity commands with property commands).
It's also important that sensitivity cannot be controlled alone
in a single command... because commands usually should represent
an action taken in the document (a document is dirty after executing
any command).
What about enabling/disabling? Does that invoke "set property" commands
currently?
Post by Tristan Van Berkom
Post by Denis Washington
Other than that, I don't know of any other major showstoppers, but an
extensive code review by Juan and Tristan might very well reveal some. ;)
The big question, however, it how to support transformation functions
for property bindings. This GBinding feature allows you to define a
function that processes the value of a binding's source property before
it is applied to the target, which allows you to create bindings between
properties of different types and generally make property bindings much
more useful and interesting. Adding this into the GTK+ and Glade
branches is not a big problem in principle, and in fact I did just that
during Summer of Code. However, I had to later remove the code again,
the reason being on the GTK+/GLib side.
The problem is when and how to resolve the transformation function names
that would be stored in the GtkBuilder file to the actual function
implementations. In my code, I moved all property binding creation to
two new API functions, gtk_builder_create_bindings() and
gtk_builder_create_bindings_full(), which take the same arguments as
gtk_builder_connect_signals*() and locate transformation functions the
same way (GModule or a custom callback, called GtkBuilderBindingFunc).
because transformation functions are specified as an argument to
g_object_bind_property_full() rather than by connecting a signal, a
language-specific GtkBuilderConnectFunc for
gtk_builder_connect_signals*() cannot be reused and each language
binding would be required to provide a GtkBuilderBindingFunc to replace
the use of GModule with something appropriate for the language. Also,
the introduction of another function to be called for every loaded
GtkBuilder function is really not ideal.
Talking with Juan and Tristan, we concluded that a proper solution
probably requires changes to GBinding itself. More specifically, if
GBinding implemented the transformation function as being the handler of
a "transform" signal instead of an anonymous callback, one could reuse
gtk_builder_connect_signals*() to locate transformation functions and
move property binding creation there. For backwards compatibility and
convenience, the g_object_bind_property() API could still stay as it is
now. There would be some issues to sort out - for instance, how to
behave if multiple signal handlers are connected to the "transform"
signal - but it might be doable without breaking anything. This still
needs to be talked about with both the GLib and GTK+ team, though.
For reference, you can still find my code with transformation function
support in the "gtkbuilder-gbinding" GTK+ and "gbinding-transform" Glade
branch.
I don't want to discuss transformation functions in depth until
finished landing this code in GTK+/Glade.
If transformation functions are implemented at a later date, they should
use similar semantics as signals, actually reading the code at this
moment I don't see any reason why the normal GtkBuilderConnectFunc
couldnt be used by the GtkBuilder during gtk_builder_connect_signals()
to resolve any gbinding transform function signals.
*If* we have a GBinding transformation function facility based on
function, naturally, GtkBuilderConnectFunc is just fine. My comment
about it unsuitability was based on the assumption that GBinding is like
it is now, with transformation functions having to be specified on
g_object_bind_property().
Post by Tristan Van Berkom
a.) Introduce "transform" signals on GBinding object and
probably prefer the signal (the default handler falls
back on invoking any registered transform function for
backwards compatibility and then defaults to usual GValue
transforms and copies).
b.) Extend GtkBuilder binding parsing slightly to allow specification
of a transform function... collect the GBinding objects and
transform function data during the parse and cache them for use
in gtk_builder_connect_signals() (possibly even in the same cache
as the actual<signals>).
c.) Connect the transform signal callbacks later in the normal way
from gtk_builder_connect_signals()
This assumes that GValue provides default conversions between all pairs
of types. Is this the case? If not, creating the property bindings first
and adding transformation functions later won't work. Assuming that
GValue does handle all of this, however, this seems like a good plan.
Post by Tristan Van Berkom
This will imply an api extension in GtkBuilder, so when it gets
introduced in GTK+ Glade will need to be careful not to register
transform functions for projects targeting a too old version of GTK+.
Which leads me to another observation, the binding feature itself
should not be available of the project is targeting< GTK+ 3.2
(or whatever GTK+ version we get the feature into).
True.
Post by Tristan Van Berkom
Post by Denis Washington
Well, this is all there is to say about the code now. (This mail is
already way too long as it is. ;) I hope you now have a better insight
wrt what I have done during GSoC and what is still to do.
As I wrote in the beginning, I need your feedback! If you have any
questions, remarks, or suggestions regarding the issues I outlined -
especially regarding the transformation function situation - I would be
excited to hear them! Thanks. :)
Thanks a lot for the great effort done this year.
Thanks for your guidance.
Post by Tristan Van Berkom
Again, sorry for taking so long to give you some attention.
No problem. :)

Regards,
Denis
_______________________________________________
Glade-devel maillist - Glade-***@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/glade-devel

Loading...