[Glade-devel] Property Binding Support: Present and Future



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/




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