Migrating to Gtk4 - a problem with composite templates

I’m interested in migrating to Gtk4, but am rather stumped about how to adapt to its new restrictions on inheritance when working with composite widgets.

In existing Gtk3 code I have one class per file with classes corresponding to logical units of functionality: tab responsible for uploading images, tab with misc. functionality, etc… Each of classes utilizes composite templates for loading Gtk interface. For example:

[GtkTemplate (ui = "/org/v1993/geohashingwikihelper/GalleryTab.ui")]
public class GalleryTab : Gtk.Paned {
	[GtkChild]
	private unowned Gtk.Button upload_button;
	[GtkChild]
	private unowned Gtk.Container uploading_part_container;
	[GtkChild]
	private unowned Gtk.Entry filename;
	[GtkChild]
	private unowned Gtk.Entry description;

	...
}

However, Gtk4 makes it impossible to derive from Gtk.Paned - which makes sense to me, since my class isn’t really an extension of it but rather a widget on its own. But the issue is that the suggested alternative of deriving directly from Gtk.Widget and having Gtk.Paned as its child does not seem viable to me in this case since it’s impossible to have GtkWidget as top-level template in Cambalache (and GtkWidget itself can’t be a composite template at all due to being abstract class if I got it right).

Now, it looks like an alternative it to have top-level Gtk.Box with actual widgets as its single child, since it is not declared final/sealed, but it appears to be more of a hack rather than an actual intended solution, given that reason for having it as non-sealed class is to avoid breaking too many applications at time of the initial migration AFAIK.

Is there already a nice solution to this problem? If not, it seems like having a simple “wrapper” widget that has a single child and can be derived from explicitly for the purpose of being a base for composite template widgets would work well.

Your top-level widget will not be a GtkWidget, because it will necessarily be a subclass. All template widgets are subclasses of some parent type.

What you want to do is create a GtkWidget subclass (i.e. GalleryTab), using a GtkBinLayout layout manager (single-child), then set the GtkPaned as the bin child. Thus your UI file will look something like:

<interface>
  <template class="GalleryTab" parent="GtkWidget">
    <child>
      <object class="GtkPaned"/>
    </child>
  </template>
</interface>
1 Like

Use Adw.Bin. It does exactly what you want. A Gtk.Widget subclass with one child.

2 Likes

Thanks a ton, this indeed looks like what I wanted! I’ve managed to make solution by @andyholmes work as well, but it does not cooperate well with Cambalache (which erases top level templated widget when editing).

Coming from Gtk3 made me overlook libadwaita which looks like a very, ahem, handy addition.

1 Like

While subclassing from Gtk.Widget is perfectly ok, you have to take some extra steps to make it work properly, like give it a proper bin layout and unparenting children at dispose.