How to remove children from Adw.PreferencesGroup?

I’m pretty new to GTK, libadwaita and Vala.

I use Adw.PreferencesGroups in a Gtk.ListView. I use a Gtk.SignalListItemFactory to populate the Adw.PreferencesGroups with Adw.ActionRow children by using Adw.PreferencesGroup#add. On the Gtk.SignalListItemFactory.unbind signal, I’d like to remove the the children using Adw.PreferencesGroup#remove. However, I have difficulty retrieving the children from Adw.PreferencesGroup.

Minimal example to show what I mean:

public static int main(string[] args) {
    var app = new Gtk.Application("foo.bar.baz", GLib.ApplicationFlags.FLAGS_NONE);

    app.activate.connect(() => {
        var group = new Adw.PreferencesGroup();
        group.add(new Adw.ActionRow());
        for (Gtk.Widget? child = group.get_first_child();
             child != null;
             child = child.get_next_sibling()) {
            stdout.printf("child: %s\n", child.name);
            group.remove(child);
        }
    });

    return app.run(args);
}

I compile and run:

valac --pkg gtk4 --pkg libadwaita-1 test.vala && ./test

This prints:

child: GtkBox

(test:4914): Adwaita-CRITICAL **: 10:57:43.872: ../libadwaita/src/adw-preferences-group.c:424: tried to remove non-child 0x55a9b455c190 of type 'GtkBox' from 0x55a9b455b1d0 of type 'AdwPreferencesGroup'

The child turns out to be a Gtk.Box, not the Adw.ActionRow I put in.

Do you consider this a bug? Is there something I’m missing? What would be a way to remove a child from a Adw.PreferencesGroup (when I don’t have a reference to the child lying around)?

Versions I use:

$ pacman -Q gtk4 libadwaita
gtk4 1:4.8.3-3
libadwaita 1:1.2.1-1

gtk_widget_get_first_child () and friends are meant to be used when writing widget implementations. You should never user them to iterate over an external widget’s children. If the widget provides an API to iterate over children use that. If not, you should keep track of what children you add yourself. If you need a dynamic list inside an AdwPreferencesGroup, I would recommend packing your own GtkListBox with the boxed-list style class applied instead of using the built in one.

I use Adw.PreferencesGroups in a Gtk.ListView.

This doesn’t seem right though - what type design are you trying to achieve here?

You are right, this is contrived. I use Adw.PreferencesGroup only because it provides a nice visual. I could use anything else if I could replicate the visual:

2023-01-16-081109_618x494_scrot

What I’m actually trying to achieve, is to create a list that can hold thousands of entries that contain grouped-by-date children (“sessions” in my domain model) that, when clicked, show a popup allowing the user to edit or remove the entry.

Now, using a Gtk.ListView with Adw.PreferencesGroups works, but is very, very slow even for “as little as” 2300 entries (my test data set). “Slow”: loading the list on my Librem 5 takes upwards of 10 seconds, and scrolling is sluggish at best if it doesn’t crash halfway through. It’s probably slow, because of the problem described above where I can’t reuse widgets and have to recreate them from scratch on every bind signal. Also, I imagine these widgets were not meant nor optimized for use in a Gtk.ListView to begin with.

I would be very grateful if you could provide some pointers on how to improve this situation!

Yes, that’s exactly what Chris suggested here:

I would recommend packing your own GtkListBox with the boxed-list style class applied instead of using the built in one.

However,

is to create a list that can hold thousands of entries that contain

is impossible with this style. You are absolutely correct that it’s slow, you should never use it for more than 100 or so items.

I did that, but like you predicted, performance is still unacceptable.

So, I’m abandoning this idea. I’m now looking into splitting the list up into pages of, let’s say, 20. I was looking at the GTK4 widget factory:

2023-01-17-091049_363x318_scrot

Is there a standard widget that has something like “Next page”, “Previous page” that takes a list of items? Or do you know of another GNOME app that uses something similar?