After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 612036 - Allow the encoding of GtkBuilder files into widget classes
Allow the encoding of GtkBuilder files into widget classes
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Class: GtkBuilder
unspecified
Other All
: Normal enhancement
: 3.0
Assigned To: GtkBuilder maintainers
GtkBuilder maintainers
: 618739 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2010-03-06 23:19 UTC by Tristan Van Berkom
Modified: 2013-08-14 21:42 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
header file defining GtkComposite abstract class... (4.07 KB, text/plain)
2010-03-06 23:19 UTC, Tristan Van Berkom
  Details
C file implementing GtkComposite class (12.83 KB, text/plain)
2010-03-06 23:20 UTC, Tristan Van Berkom
  Details
A demo written in C (2.12 KB, application/x-compressed-tar)
2010-03-06 23:22 UTC, Tristan Van Berkom
  Details
New composite widgets patch (29.18 KB, patch)
2010-03-14 02:05 UTC, Tristan Van Berkom
none Details | Review
Another demo in C (2.67 KB, application/x-compressed-tar)
2010-03-14 02:10 UTC, Tristan Van Berkom
  Details

Description Tristan Van Berkom 2010-03-06 23:19:47 UTC
Created attachment 155449 [details]
header file defining GtkComposite abstract class...

Hi,
   I've been turning this idea around in my head and talking to 
various people about it on irc for a while, obviously this construct
is going to suit higher level language bindings better than writing
objects in C, but since my added api would need bindings, I attached
a prototype written in C for reference.

I'm going to come up with a more formal proposal and target it at
gtk-devel-list on monday, this is a pre-submit implementation of
the enhancement for reference for now.

I'm about to attach gtkcomposite.[ch] as separate files, all that
needs doing to build is to add it to gtk/Makefile.am and to <gtk/gtk.h>.

This work depends on an api introduced by Marco in bug 447972.

For a simple outline of this construct, basically we have a GtkBin
superclass taking care of interfacing with the lower levels of
GTK+; GtkBuilder.

An implementor of the superclass can simply define callbacks in the
UI to invoke methods dealing with his "Composite" object (generally
you swap the data and make Composite come first, they can be derivable...).

Then the implementor declares some variables on its instance, if
the implementor declares properties that are "connect", then the value
is resolved to the internally built instance which the connector desired
to connect to - currently the correlation is by property name <--> 
GtkBuilder instance name, but could be changed by extending the
added GtkParamSpecComposite.

GtkParamSpecComposite:
   This is introduced as a property type to be handled and
installed by GtkComposite implementors, in C the raw ugly mechanics 
of GObject are exposed, you do this by installing and handling properties 
with g_object_class_install_property().

Ideally, in some of our language bindings we can do this by simply
adding syntactic sugar to the definition of the instance variable.

Again, obviously this is better targetted at language bindings but
IMO still very useful in C.

The main reason why I want to target GTK+ is because I think it would
do wonders for our devtools front, if we can have tools that assume this
paradigm with all languages, we reduce complexity all around I think.
Comment 1 Tristan Van Berkom 2010-03-06 23:20:33 UTC
Created attachment 155450 [details]
C file implementing GtkComposite class
Comment 2 Tristan Van Berkom 2010-03-06 23:22:52 UTC
Created attachment 155451 [details]
A demo written in C

So heres a little test case of how it can initially be used.

Attention much boiler plate code ahead ;-)
Comment 3 Matthias Clasen 2010-03-08 17:51:56 UTC
It sounds interesting, but I need more time to study this. 

From what I understand, this is some way to nicely create composite widgets in glade that behave just like builtin composite widgets ?
Comment 4 Tristan Van Berkom 2010-03-08 20:59:20 UTC
Ok so I sent the mail to the list this morning and tried pretty
hard to explain this patch in not-so-technical terms here:

http://mail.gnome.org/archives/gtk-devel-list/2010-March/msg00040.html

Noting some technical things that turned up since saturday:

  a.) GtkComposite should be just api extending GtkContainer, allowing
      any container widget to be extended as a composite widget when
      providing a .ui for the class.

  b.) The composite building should traverse and build every builder 
      file specified for every composite class of an instance starting from the 
      superclass and then descending, currently with this implementation
      every concrete class can only have one builder definition - instead
      they should extend the superclass by either appending themselves to 
      the UI (i.e. if the base composite class is a GtkHBox, every subclass
      adds portions to the ui horizontally) - OR - more tricky - subclasses
      extending composite implementations should be able to insert their
      UI fragments into specified container widgets from the parent
      (those could be exposed automatically using composite properties of
      the parent class by name/key in the child builder file).

      For example, a GtkDialog defined by a builder file can expose an
      action area and vbox as composite children (or composite properties,
      same thing), then a dialog subclass could extend the dialog UI by
      defining toplevels in its UI file which register to the said extension
      points; the action area and vbox (this ofcourse would need some added
      metadata for toplevels in GtkBuilder files to decide what child to
      add themselves to automagically at load time).

Also, it would be nice if we could use this paradigm all over GTK+ internally
and then deprecate the push/pop_composite_child() apis and provide a
_get_composite_child() that generically works for everyone (this could also
eventually be useful for Glade to expose internal composite children
for configuration and/or adding children).
Comment 5 Matthias Clasen 2010-03-08 23:30:43 UTC
... then deprecate the push/pop_composite_child() apis ...

Those are really easy to deprecate since they don't do anything.


Here are some questions I didn't really see answered yet in your attempts to describe this:

- GtkBuildable has this concept of child-types, ie you have named slots that define the places where the app can add further child widgets. Do your Composites allow me to define such slots ? 

- Relatedly, there is the somewhat thorny issue that if I add a widget in one of these slots, it is a 'logical' child of the composite widget, but actually, it is the child of some internal container widget inside the composite widget hierarchy. Thus, it is not possible to have child properties that relate the 'logical' child and the composite widget. I assume your work does not solve this ? :-(
Comment 6 Tristan Van Berkom 2010-03-09 03:45:02 UTC
Actually, I hadn't thought about how composite widgets were going
to cascade in detail when I wrote up the patch, and thats right the 
patch doesnt address that in detail.

I'm pretty sure this is going to take some minor extensions to the format,
what I'm aiming for is, 
  - An interface (.ui) can include a composite widget and add children to it.
  - A class who extends the composite widget can also add children to it from 
    its own added .ui fragment 

Well, I just wrote 3 paragraphs about how we could go and generically
support 'child-type's of added children, basically it starts with adding
a 'is-child-slot' attribute to the composite param spec and... work from
there, it works but Im going to replace the paragraphs with...

Don't use the 'slots' when defining composite classes; its made for 
customized code that always knows how to position it manually, its 
better to just use internal children.

If a composite parent exposes an entry point to add widgets, it
does so by defining an internal container widget, then it gets treated
like the 'vbox' or 'action-area' of a GtkDialog, its an exposed
container you can add widgets to with packing property detail.

On a side note, this means we should be able to begin a composite
GtkBuilder fragment with <child> instead of <object>, the <child>
can optionally then come with an internal="internal-name" property
and start adding to the parent from there.

And it also means we need gtk_builder_set_parent_context() or such,
to give GtkBuilder knowlage of the composite parent instance while
trying to build/add children (builder would behave the same way
in every respect except it would be started with a parent in "context"
and expect <child> instead of <object> as the first relevant tag).

I'm going to let it boil in my head for a while and hope people have
some interesting comments, then I might give her another run through
this coming weekend.

-----------------------

Another side note about 'child-type'; take GtkNotebook as an example; 
probably the trickiest of these, but it could have been implemented 
using a collection of "Page" widgets with tab-label attributes individually, 
and that would remove the need to color in individual child types - Im not sure 
that the 'child-types' feature is justified outside the use cases of already 
written GTK+ code (seeing as we already have <child internal="internal-name">, 
and that gives us more context when adding widgets).
Comment 7 Torsten Schoenfeld 2010-03-09 19:31:55 UTC
In your blog post about this, you asked for feedback from a language binding's point of view.  After a couple of minutes of looking at this with my Perl bindings glasses on, I can see only one problem: the automatic connection of signal handlers.  Your current code simply calls gtk_builder_connect_signals.  Language bindings would need to be able to completely control this.  I think this can be done by using gtk_builder_connect_signals_full with a GtkBuilderConnectFunc that defaults to the gtk_builder_connect_signals behavior but which can be changed by language bindings.
Comment 8 Tristan Van Berkom 2010-03-14 02:05:56 UTC
Created attachment 156091 [details] [review]
New composite widgets patch

This patch implements the same functionality in a new way with
a few corrections:

  - Instead of introducing a class it implements the functionality
    extending the GtkContainer api, allowing any already existing widget
    to be derived and extended using this automated composite code.
  - GtkBuilder takes 2 new apis:
     o gtk_builder_add_to_parent_from_string()
     o gtk_builder_add_to_parent_from_file()
    These apis parse builder format in the normal way except provide
    a contextual parent GObject, the builder fragment that is parsed 
    by this api should start with <child> instead of <object>
  - GtkContainer now allows you to setup the template file or buffer on
    a per class level
  - GtkContainer now exposes a GtkBuilderConnect func on a per class
    level to be used to connect signals to the proper code in the proper
    language (as code is written by class, it makes sence to expose this
    by class).
  - GtkContainer exposes a new api:
      gtk_container_get_composite_child()
    This is implemented automatically by introspection of GtkParamSpecComposite
    properties.
  - GtkBuilder now uses gtk_container_get_composite_child() if 
    gtk_buildable_get_internal_child() was unsuccessful (allowing automatic
    exposure of internal composite children).

Note that this patch currently comes all in one including Marco's patch for
gtk_builder_expose_object().

... Here comes another example tarball.
Comment 9 Tristan Van Berkom 2010-03-14 02:10:30 UTC
Created attachment 156092 [details]
Another demo in C

This test includes the same test-composite.c except now it derives
directly from GtkWindow without the needed extra bin class.

It also extends TestComposite to expose a composite child 'content-area'.

A new test is added: TextExtended, which simply derives TestComposite
and adds widgets to its internal 'content-area'.

Note that using gtk_buildable_add_child() child-type 'slots' is still
possible using this method, it means that the implementor still needs
to know how to hand position the child widget and it still needs to
implement gtk_buildable_add_child() in order to place it.

Although I think its all around easier to just expose internal 
container widgets for the purpose of packing more widgets into
a composite widget...
Comment 10 Marco Diego Aurélio Mesquita 2010-03-15 12:50:47 UTC
It looks like you used and older version of my patch. Take a look at the newer one: http://bugzilla-attachments.gnome.org/attachment.cgi?id=155380
Comment 11 Tristan Van Berkom 2010-03-19 17:41:19 UTC
Updating bug title to reflect the newer patch, hopefully the new
title is more meaningful...
Comment 12 Matthias Clasen 2010-05-17 22:41:17 UTC
*** Bug 618739 has been marked as a duplicate of this bug. ***
Comment 13 Matthias Clasen 2010-05-18 03:59:28 UTC
Review of attachment 156091 [details] [review]:

::: gtk/gtkcontainer.c
@@ +1105,3 @@
+
+  if (container_class->template)
+    g_free (container_class->template);

No need for the if here, g_free is NULL-safe

@@ +1111,3 @@
+  if (container_class->template_file)
+    container_class->template_file =
+      (g_free (container_class->template_file), NULL);

This is just sneaky. I prefer straight assignments instead of such trickery.

@@ +1137,3 @@
+  if (container_class->template)
+    container_class->template =
+      (g_free (container_class->template), NULL);

Same comments apply here.

@@ +1266,3 @@
+	      
+	      if ((composite_child = 
+		   gtk_builder_get_object (builder, (pspecs[i])->name)) != NULL)

Please put the assignment before the if.

@@ +3016,3 @@
+      static const GParamSpecTypeInfo pspec_info = {
+	sizeof (GtkParamSpecComposite), /* instance_size */
+	16,                        /* n_preallocs */

no point:

 * @n_preallocs: Prior to GLib 2.10, it specified the number of pre-allocated (cached) instances to reserve memory for (0 indicates no caching). Since GLib 2.10, it is ignored, since instances are allocated with the slice allocator
Comment 14 Matthias Clasen 2010-05-18 04:18:21 UTC
Another comment: template is a C++ keyword and can't be used in headers, so the GtkContainer member needs a different name, e.g. template_.
Comment 15 Tristan Van Berkom 2010-06-07 19:08:36 UTC
I've created a branch "composite-widget-templates" for this and 
added some things:

  - Amended patch as per your comments, used shortened term 'tmpl' in
    some places.
  - Changed Marco's patch for gtk_builder_expose_object() a bit
     o Now 'external' is called 'external-object'
     o Now an 'external-object' can also be referred to as object
       property values (not directly relevant but interesting to have)
     o The new attribute for <signal>/<property> tags are documented
  - Transformed GtkDialog and GtkMessageDialog to use 
    gtk_container_class_set_template().

So, the dialog portion is an example of how this stuff can be used
but to be able to include the dialog stuff we need to convert the
remaining dialogs to be composite containers too (or at least migrate
some of their code from _init() --> _contstructor())

The issue here is simply that you cannot access the widgets of
a GtkDialog from a subclass at subclass_init() time because the
child widgets dont exist yet; they will be built only once the
container class constructor runs.

Another annoying thing is if you have construct properties
that want to access composite child widgets directly, in this
case care needs to be taken when setting up those properties
the first time (see GtkMessageDialogPrivate->message_type/buttons_type
in the patch for an example of this dance).

I guess those are the limitations but all in all I dont think
its a bad trade-off and there's no way around it I can see (the
automatic assignment of properties <--> composite children needs
to happen in the constructor).
Comment 16 Matthias Clasen 2013-08-14 04:26:52 UTC
this is done
Comment 17 Mathias Brodala 2013-08-14 15:50:16 UTC
(In reply to comment #16)
> this is done

When and how exactly?
Comment 18 Tristan Van Berkom 2013-08-14 16:14:43 UTC
(In reply to comment #17)
> (In reply to comment #16)
> > this is done
> 
> When and how exactly?

See:
   https://mail.gnome.org/archives/gtk-devel-list/2013-April/msg00001.html

And:
   http://blogs.gnome.org/tvb/2013/04/09/announcing-composite-widget-templates/

And:
   http://blogs.gnome.org/tvb/2013/05/29/composite-templates-lands-in-vala/

The C API can be found here:
   https://developer.gnome.org/gtk3/unstable/GtkWidget.html#gtk-widget-class-set-template
(see all the 'template' related GtkWidgetClass APIs).

Cheers
Comment 19 Mathias Brodala 2013-08-14 21:42:51 UTC
Thanks a lot for the pointers, this looks exactly like I imagined. :-)

Can't wait for this become usable in PyGtk/Gi.