Way to remove widgets

Is there any way to remove widgets from top level container? In gtk3 there was gtk_widget_destroy() but now it is removed.

It depends on what you are doing.

If you are removing a child widget from its parent, then every container has its own remove method—either an explicit “remove”, like gtk_box_remove(), or an implicit "remove the only child by resetting it to NULL", like gtk_window_set_child(). Removing the child will release the reference on it held by its parent, and the widget will be collected.

If you are implementing a widget, the dual method of gtk_widget_set_parent() is gtk_widget_unparent(). That has been true in GTK3 as well, but GtkContainer implemented destruction, so it removed its own children automatically—something that GtkWidget does not do for you.

If you are removing a child widget from its parent, then every container has its own remove method

I just wonder why there isn’t one unified method to do one and same operation, i.e. remove a widget?

GtkContainer implemented destruction, so it removed its own children automatically—something that GtkWidget does not do for you.

To me this is a step backward. Why getting rid of something that it was done automatically in favor of manual operation?

Because there’s really nothing “unified” about it: all widgets can contain children, which is why gtk_widget_unparent() exists for people implementing a complex widget with children; but actual containers exposing an API to add children should have their own removal as well. I mean: it’s pretty standard fare, and even GTK3 had those cases. Using gtk_container_add() on every container, for instance, didn’t always do the right thing. So if adding a widget does not have a “generic” API, why would removing it ought to have it?

At the end of the day, there are no “generic” cases: you have to know what the container is, just like you need to know what the child is.

If you want to remove a child from a container, there are only two options:

  1. you are the implementor of the container, which means you call gtk_widget_unparent() on the child
  2. you are a consumer of the container API, in which case the container must provide you with API to remove the child

So, yes: GTK3 “lied” to you. Just because GTK3 did something it does not mean it’s right. In many cases, GTK3 did something because of API design inertia from 1997, but it’s been more than 20 years, and things change in the toolkit design space.

This is slightly more complicated, but it has to do with the management of the lifetime of widgets, and the cross-section between API that is meant to be used by people implementing composite widgets, and API that is meant to be used by people using those composite widgets.

Let’s assume you have written your own GtkWidget-derived type, and it contains three widgets: an image, a label, and a button. You must have access to those three child widgets for the duration of the lifetime of your widget, between instance initialisation and finalisation.

The approach of GTK3 of having GtkContainer override the destroy virtual function and destroying all child widgets worked in a very broad sense; since GtkWidgetClass.destroy was invoked once you entered the GObjectClass.dispose implementation, the children were available to you until your own dispose implementation chained up to its parent’s implementation. What happened if you had widgets included via a GtkBuilder UI template? What happened to “private” children? What happened if the code re-entered dispose because of a reference cycle somewhere? What happened to signals emitted during destruction? The old code assumed a lot of cases could not happen, or would not be a problem, because not many people implemented GtkContainer, and if they did, they knew what they were doing.

In GTK4 we made it very easy to implement GtkWidget-derived types; we actually encourage people to do so, instead of deriving complex, composite widgets with their own internal behaviours. This means that the rules must be fewer and simpler, and the edge cases minimised. Now the rule is:

If you added a widget using gtk_widget_set_parent() then you’re responsible for it until you call gtk_widget_unparent()

Just like if you acquire a reference on a plain object using g_object_ref() then you’re responsible for it until you call g_object_unref().

Of course, all of the above applies to widgets you create. For widgets you use, you’re supposed to use the API of the widget to remove a child whenever you need to. The widget itself will take care of unparenting the child when getting disposed, just like before.

Thank you for the reply.

Because there’s really nothing “unified” about it: all widgets can contain children

There is. If widget can contain a child, that widget should now how to remove that child. Because it is very specific to that widget. So having one “remove_child” method for a widget and let the widget deal with the implementation should be the natural way.

Why would I? Wouldn’t it be more natural and user friendly that the user wouldn’t have to know what container it is and what child it is in order to be able to remove it? The container should “know” how to remove its child. I see a problem in design here.

As for the rest, I really do appreciate the time you’ve put in the answer, but from the explanation, it is (the mechanism of removing child from user created widgets vs built in widgets) it is a total mess.
There should be one, unified way to add and remove child from a widget. Irrelevant it if that widget is built-in or custom made.

But why? I mean: you can keep saying that, but it hardly makes it true, does it?

You put a child in a specific container widget.

You know which container you’re using.

You have a reference to both child and parent.

Why would you need an untyped “random container remove child” method?

Additionally, there’s no GtkContainer any more, and we cannot have gtk_widget_remove_child() which would then require a virtual function to let widgets “know” how to remove a child, and remove ancillary data associated to the child. Since we have a remove_child() we’d also need an add_child(), with the same semantics, and now you just recreated GtkContainer inside GtkWidget, and people don’t know what to call when implementing a composite widget: should the call gtk_widget_set_parent()/gtk_widget_unparent()? Or should they call gtk_widget_add_child()/gtk_widget_remove_child()? What happens when the code re-enters into each widget’s implementation?

The problem is that you’re looking at this issue from a very narrow perspective, and what you call “user friendly” is mainly your convenience. If I had to venture a guess, you’re porting some code from GTK3 to GTK4 and you just noticed that you call gtk_container_remove() a lot.

Yes, it’s an annoying bit of the porting process. It’s kind of unavoidable, in light of the changes that happened in GTK4. We cannot add a “generic” removal API because there’s no more “generic” type for it; there’s no “generic” type because the hierarchy was flattened to allow composite widgets to be easier to write.

Instead of trying to reimplement GTK3 in GTK4, maybe you should be looking at ways to work within the toolkit’s design:

  1. use UI definition templates
  2. use composite custom widgets
  3. limit the amount of widget removal to build your UI, and instead use separate states
  4. use models and view widgets that keep track of objects, like GtkListBox, GtkListView, etc

On the contrary. I actually look at the issue from a generic point of view, which implies wider “use case”. It is actually you who is hooked on the fact that there must be specific and thus narrow, method to remove specific child from a specific container.

It does not make true for gtk4 but when you think about it, why would you want to have two different ways of performing the same action on two different widgets?

On the contrary (I’m referring to the untyped). Compiler knows what type of both container and child it is. So no untyped. It is simply lifted from the users shoulders to remember the type. User is simply calling:
Widget->remove_child(), without actually caring about the container type nor child type. That is very different to untyped. Types are known all the way from the beginning to the end of lifetime.

It is not about porting. It is about the abstraction and philosophy.
It is very, very wrong state of affair that the user in order to remove a child from a widget needs to know the type of the widget and the type of the child.
I wonder if here the C language gets in your way of thinking and you simply cannot imagine the situation that having:
Widget->remove_child is a viable and user friendly way.

We can keep dancing around all day, but it’s clear you’re not listening to me, so it’s really unproductive for the both of us.

Well, for starter, I write the C API that you consume in some other language, so I must think in C. Additionally, you’re inferring a lot about what I think or not. Of course widget->remove_child() is easier to type if you’re using some higher level language; but if you thought about this for more than 15 minutes, you’ll realise that there’s a lot more to do underneath the binding to make that happen in a safe way.

Anyway, I’ve given you the complete explanation as to what you want is not really achievable within the confines of what GTK is, does, and provides.