Composite GtkBuilder template

I meant to address the list by the end of last week but 
some issues cropped proving that the work was not yet finished.

I have been working closely with Benjamin, refining the API
and discussing some of the finer points. This has been a
huge effort that ate up my last two weeks full time work.

The work can be viewed here:

And while it's a huge list of changes, any thorough peer reviews
would be greatly appreciated of course.

A version of Glade which can be used with this branch can 
be built from:

Since it's nice and early in the 3.10 cycle, I would like
to finally land this by the end of this week if there are
no objections (I say finally, because I prototyped this years
ago but never got around to really cleaning it up until now).

So here below follows my detailed report.


What is Composite Templates ?
This feature is an association of GtkWidget class data
with GtkBuilder xml.

It allows automation of the creation of composite widgets
without directly accessing the GtkBuilder APIs and comes
with a few features that help to bind a GtkWidget with
it's GtkBuilder xml.

What has been done ?

  o The implementation of the API, of course

  o A total of 23 composite widgets in GTK+ have been
    ported to use GtkBuilder xml to define their content.

    The actual xml data is stored in GTK+'s global resources
    in a compressed format.

    Each widget migration has it's own individual commit
    on the branch, which should give any observer a clear
    picture of what a migrated composite widget looks like.

  o A catalog file for Glade was added to the gtk+/gtk/glade

    This catalog is not meant to be installed, but rather
    it gives GTK+ developers access to GTK+'s private
    widget classes so that, for instance, a GtkColorSwatch
    can be added to a GtkColorEditor, or a GtkPathBar
    to a GtkFileChooserDefault interface description.

    When running Glade with this custom catalog, a new
    section with "GTK+ Private Widgets" appears in
    Glade's palette.

  o Glade itself has seen improvements in stability
    and features, supporting new widgets and the like
    up until GTK+ 3.8

    I've verified that all of GTK+'s composite widget
    xml files can be saved without any data loss or
    any meaningless changes (so that commits should be
    as relevant as possible).

  o A test case has been added which verifies that each of
    these classes construct and finalize properly (and
    that all of the object which they refer to in the
    xml also finalize properly).

  o The <template> format is moderately documented in

  o gtk_widget_push/pop_composite_child and relevant
    APIs (set/get_composite_name()) have been deprecated.

    As far as I know, they were never actually useful for
    anything, but now we have a real story for composite
    widgets so I would like the old APIs gone.

Some critical points

As it currently stands, there are two critical points which
I think need discussion, I'll list four points here for

  o Intltool

    In order to properly extract translations of strings
    defined in .ui files, the files need to be listed
    with lines like the following in

      [type: gettext/glade]gtk/gtkfilechooserdefault.ui

    This breaks the build without adding IT_PROG_INTLTOOL()

    Most projects however do use intltool in

    Matthias, does this make your life maintaining GTK+
    difficult in any specific way ?

    Can we merge this and live with it at least until a
    newer version of gettext is released that supports
    the ".ui" suffix or the [type: ] annotation properly ?

  o Private widget types

    In order for Glade to load private widget types (which is
    needed to edit some of GTK+'s composite widgets), Glade
    needs the types to be registered in advance, since they
    cannot be loaded with g_module_lookup() in the normal way.

    I've added gtk/gtkgladecatalog.c which exports an initialization
    function and that registers the private types.

    GTK+'s internal catalog (gtk/glade/gtk-private-widgets.xml)
    declares this symbol as it's catalog initializer, which
    I think is an elegant enough solution.

    Benjamin also noted that gtk_test_register_all_types() also
    exists but currently does not register the private types.

    I could alternatively make that function register private
    types and have Glade call it explicitly at initialization

  o Ryan's work on overriding default properties.

    Ryan is addressing some issues currently in GObject which
    will allow us to declare new default values for properties
    registered in parent classes.

    This will particularly address a problem that exists with
    G_PARAM_CONSTRUCT properties.

    While this is not directly tied into the composite work,
    some additional enhancements should be made after Ryan
    land's his new feature.

    I can promise to do this additional enhancement work but I
    don't think that we should be blocking on it currently.

  o Test case requires an environment variable

    Currently I have code in gtkwidget.c to assert that
    all composite children finalize properly at gtk_widget_destroy()

    The problem is that it cannot be done at finalization of
    every composite widget, mostly because we cannot assume
    that some API accessor to the composite widget caused
    a third party to take an additional reference to one
    of the composite widget's children. However it can and
    should be asserted while testing a composite widget
    in a completely stand-alone test case.

    This little bit is up for discussion, it's a minor
    detail but I don't currently like the fact that I use
    an environment variable to enhance testing of composite
    widget destruction.

    The relevant code can be found here:

    And I think my preference would be to add a new API for
    GTK+ widget authors _and_ third party widget authors
    to properly test finalization of their GTK+ composite widgets.

    I would propose something like:

      gtk_widget_test_template (GType widget_type);

    However, we could leave it as is (at least for now), or
    remove the assertions completely. But they did help me
    find bugs so I would very much like to keep the assertions.

Presentation and Explanation of the API and features
The APIs I'm about to discuss are defined here:

  o Binding a widget class to it's template

    This is done by calling gtk_widget_class_set_template()
    in your composite widget's class initializer.

    The implementation requires that any widget class
    that installs a template must also call
    gtk_widget_init_template() in the instance initializer.

    Previous iterations of the branch did not require this,
    however we've found some problems with interface construction
    being done at GObjectClass.constructed() time, which is
    often too late, so that one function call must be called
    at instance initialization time.

  o Binding an instance variable to an object defined in the
    GtkBuilder xml associated to a template.

    Instead of requiring manual management of objects using
    gtk_builder_get_object() in the normal way, we provide
    an api to associate a widget's private data structure
    offset at class initialization time.

    Furthermore we automatically memory-manage the object
    pointers of your composite widget class, the instance
    will own one strong reference to an object referred to
    from GtkBuilder XML until GtkWidgetClass.destroy() runs
    (you can still access the object one last time in
    your own GtkWidgetClass->destroy() implementation) at
    which point the strong reference is released and the
    private data pointer set to NULL.

  gtk_widget_class_automate_child (GtkWidgetClass *widget_class,
                                   const gchar     *name,
                                   gboolean         internal_child,
                                   gssize           struct_offset);

    An invocation of the above function generally looks like:

  gtk_widget_class_automate_child (class, "name_entry", FALSE,
                                   G_STRUCT_OFFSET (FooPrivate, name_entry);

    or with the convenience macro:

  gtk_widget_class_bind_child (class, FooPrivate, name_entry);

  o Automation of the GtkBuildableIface.get_internal_child() method.

    In the above API, if 'internal_child' is specified, then an
    automated version of GtkBuildableIface.get_internal_child()
    will run while building your composite widget inside another
    GtkBuilder xml interface description.

  o Declaration of signal callbacks

    Finally, to allow <signal> definitions to work in an encapsulated
    way, within the scope of your own object, another API is provided
    to declare them at class initialization time.

  gtk_widget_class_declare_callback (GtkWidgetClass *widget_class,
                                     const gchar    *callback_name,
                                     GCallback       callback_symbol);

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