pcb-rnd knowledge pool
GTK4 rant: generalism vs. specialism
gtk4r_genspec by Tibor 'Igor2' Palinkas on 2021-12-23
Tags: insight, gtk4, rant, general, special
This rant is part of a series.
In gtk2 each widget class implemented its own events (glib signals). A button had a "clicked" event, because buttons are there to be clicked. An entry (text input) had a "move-cursor" event. Each widget had its special set of events, which were easy to use as long as you wanted to only do things the designer of the widget thought of.
Once you tried to use an event the widget was not prepared for, you had to start working around. For example a label doesn't have a "clicked" event because "why would you click on a label anyway". If your application needed to capture clicks on labels, the standard workaround was creating a so called "event box" widget and encapsulate the label in that. The event box is just a box, an invisible widget that can host other widgets and handle events. If an event is not handled by the child widget, it is propagated up and the parent widget has the chance to handle it.
The good thing about specialism is that each thing can have a different set of properties, in this example each widget can have a different set of events. The bad thing is that each will have a different set of events, often not matching your expectations. For example as an application developer I would expect to be able to capture mouse clicks on every type of widget, without exception.
Another mechanism in gtk2 is the "destroy" event. It is called if the widget is going to be destroyed. Since this event is defined in the widget class, every widget has it. This is a nice, generic approach.
Which is better?
I prefer the generic path, but I do see why some things need to be special. It's probably impossible to have everything generic, but I normally try to find a balance so that as many things as possible are implemented in the generic way. The hard part is not to overcomplicate APIs with too much generalism.
Where did gtk4 progress from that?
With the input events, gtk4 fortunately moved toward generalism. There is a new concept called event controller , which can be put on any widget. When put on a widget, it introduces input events that can be bound.
For some reason mouse clicks are not handled directly by event controllers but gestures, which are essentially event controllers. In fact there are different event controllers for different input devices anyway.
So far so good, gtk4 cleaned up some unnecessary specialism with the event controller so the policy is probably to have more generic APIs. Or maybe not.
A GUI in gtk is a tree of widgets. One normally implements such a tree as a list-of-lists: each parent node has a(n ordered) list of children nodes. In gtk2 that was more or less reflected in the API, for example there was a generic call for adding a widget inside another ("container") widget. You could add a button in a box or in a frame the same way. Gtk4 changed that and now every container widget has a specialized call for adding children. For example gtk_box_append() if the parent is a box or gtk_frame_set_child() if the parent is a frame.
Since librnd needs to build GUI from data with DAD dialogs, I had to add a helper function that can add a child under any parent. It looks at parent type and decides which special function to call.for adding under that parent.
So there doesn't seem to be a policy or preference, only change. On one part of the API change from special to generic, on the other side change from generic to special.