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 On Thu, Sep 1, 2011 at 9:58 AM, Denis Washington <[email protected]> wrote: > 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 - [email protected] > 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 - [email protected] http://lists.ximian.com/mailman/listinfo/glade-devel
