Warning when a custom widget with a layout manager is finalized, except when instantiated in a UI template
System information
What is your operating system and version? GNOME 42 flatpak runtime
What is your version of GJS? 1.72.0
Bug information
Steps to reproduce
- Create a custom GTK widget with a layout manager
- Instantiate it in code
- Then instantiate it in a UI file
Current behaviour
When instantiating the widget from code like this:
import Gtk from 'gi://Gtk?version=4.0';
import GObject from 'gi://GObject';
const Widget = GObject.registerClass({
GTypeName: 'Widget',
Template: new TextEncoder().encode(
`<interface>
<template class="Widget">
<property name="layout-manager">
<object class="GtkBinLayout"/>
</property>
<child>
<object class="GtkLabel">
<property name="label">TEST</property>
</object>
</child>
</template>
</interface>`),
}, class extends Gtk.Widget {});
const Application = GObject.registerClass(
class extends Gtk.Application {
vfunc_activate() {
new Gtk.ApplicationWindow({
application: this,
child: new Widget()
}).present();
}
}
);
new Application().run(ARGV);
GTK prints these warnings:
(gjs:385324): Gtk-WARNING **: 22:14:04.695: Finalizing Widget 0x5613897f7150, but it still has children left:
(gjs:385324): Gtk-WARNING **: 22:14:04.695: - GtkLabel 0x5613897be330
However, when the same widget is instantiated in a UI template, like this:
import Gtk from 'gi://Gtk?version=4.0';
import GObject from 'gi://GObject';
const Widget = GObject.registerClass({
GTypeName: 'Widget',
Template: new TextEncoder().encode(
`<interface>
<template class="Widget">
<property name="layout-manager">
<object class="GtkBinLayout"/>
</property>
<child>
<object class="GtkLabel">
<property name="label">TEST</property>
</object>
</child>
</template>
</interface>`),
}, class extends Gtk.Widget {});
const Window = GObject.registerClass({
GTypeName: 'Window',
Template: new TextEncoder().encode(`
<interface>
<template class="Window">
<property name="child">
<object class="Widget"/>
</property>
</template>
</interface>`)
}, class extends Gtk.ApplicationWindow {});
const Application = GObject.registerClass(
class extends Gtk.Application {
vfunc_activate() {
new Window({ application: this }).present();
}
}
);
new Application().run(ARGV);
No warnings are printed.
The difference really lies in the instantiation, as even when the widget is only instantiated and not added as the child of the window in the first example, warnings are still printed:
vfunc_activate() {
new Widget();
new Gtk.ApplicationWindow({ application: this }).present();
}
Expected behaviour
The warnings don't happen, or happen in both cases.
It might not be specific to GJS, as it happens as well in Python:
Python scripts
Warnings:
import gi
import sys
gi.require_version("Gtk", "4.0")
from gi.repository import GObject, Gtk
@Gtk.Template(string="""
<interface>
<template class="Widget">
<property name="layout-manager">
<object class="GtkBinLayout"/>
</property>
<child>
<object class="GtkLabel">
<property name="label">TEST</property>
</object>
</child>
</template>
</interface>
""")
class Widget(Gtk.Widget):
__gtype_name__ = "Widget"
class Application(Gtk.Application):
def do_activate(self):
win = Gtk.ApplicationWindow(
application=self,
child=Widget()
)
win.present()
if __name__ == "__main__":
app = Application()
sys.exit(app.run(sys.argv))
No warnings:
import gi
import sys
gi.require_version("Gtk", "4.0")
from gi.repository import GObject, Gtk
@Gtk.Template(string="""
<interface>
<template class="Widget">
<property name="layout-manager">
<object class="GtkBinLayout"/>
</property>
<child>
<object class="GtkLabel">
<property name="label">TEST</property>
</object>
</child>
</template>
</interface>
""")
class Widget(Gtk.Widget):
__gtype_name__ = "Widget"
@Gtk.Template(string="""
<interface>
<template class="Window">
<property name="child">
<object class="Widget"/>
</property>
</template>
</interface>
""")
class Window(Gtk.ApplicationWindow):
__gtype_name__ = "Window"
class Application(Gtk.Application):
def do_activate(self):
win = Window(application=self)
win.present()
if __name__ == "__main__":
app = Application()
sys.exit(app.run(sys.argv))
The only different thing is that when instantiating the widget without adding to the window, the warning are immediately printed while in GJS they are only printed when the window is closed:
def do_activate(self):
Widget()
win = Window(application=self)
win.present()