Adding bindings to custom widgets causes them to never get destroyed
Take the following program:
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, Gio, GObject, GLib
class MyItem(GObject.Object):
__gtype_name__ = 'MyItem'
name = GObject.Property(type=str)
class MyLabel(Gtk.Label):
__gtype_name__ = 'MyLabel'
factory_xml = """
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<template class="GtkListItem">
<property name="child">
<object class="MyLabel">
<property name="wrap">true</property>
<property name="wrap-mode">word-char</property>
<binding name="label">
<lookup name="name" type="MyItem">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
"""
window_xml = """
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<template class="MyWindow" parent="GtkApplicationWindow">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchEntry" id="entry"/>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="vexpand">true</property>
<property name="hscrollbar-policy">never</property>
<child>
<object class="GtkListView" id="list_view"/>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>
"""
@Gtk.Template.from_string(window_xml)
class MyWindow(Gtk.ApplicationWindow):
__gtype_name__ = 'MyWindow'
list_view = Gtk.Template.Child()
entry = Gtk.Template.Child()
def __init__(self, app):
super().__init__(application=app)
test_model = Gio.ListStore.new(MyItem)
for i in range(1, 100):
item = MyItem()
item.props.name = 'asdf' * i
test_model.append(item)
self.filter = Gtk.CustomFilter.new(self.filter_func)
test_filter_model = Gtk.FilterListModel.new(test_model, self.filter)
self.entry.connect('search-changed', self.update_filter)
factory = Gtk.BuilderListItemFactory.new_from_bytes(None, GLib.Bytes.new(str.encode(factory_xml)))
self.list_view.set_model(Gtk.SingleSelection.new(test_filter_model))
self.list_view.set_factory(factory)
def update_filter(self, *args):
self.filter.changed(Gtk.FilterChange.DIFFERENT)
def filter_func(self, item, *args):
query = self.entry.get_text()
return query in item.name
def on_activate(app):
win = MyWindow(app)
win.present()
if __name__ == "__main__":
app = Gtk.Application(application_id='com.example.GtkApplication')
app.connect('activate', on_activate)
app.run()
If you type something into the search entry (that isn't contained in the generated labels - e.g. gggg
), then remove your query, the memory usage will start to quickly rise. The longer you repeat this, the higher the memory usage will go.
If you replace "MyLabel" with "GtkLabel" in line 19 (in the factory XML), and do the same thing, memory will rise and fall accordingly to the amount of labels on-screen.
Tested with Python 3.11.6, PyGObject 3.46.0, GTK 4.12.4, GLib 2.78.3, on Alpine Linux edge.
Edited by knuxify