After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 710414 - GtkListBox should have a model for huge lists
GtkListBox should have a model for huge lists
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Widget: Other
unspecified
Other Linux
: Normal enhancement
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on:
Blocks: 710204
 
 
Reported: 2013-10-17 19:24 UTC by Xavier Claessens
Modified: 2015-02-17 12:25 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Xavier Claessens 2013-10-17 19:24:14 UTC
Empathy and gnome-contacts uses a GtkListBox to display the contact list. It has big performance issues, partly because of folks, but also because of GtkListBox. It is not unusual to have 5000+ contacts.

With current GtkListBox design, every row is a GtkListBoxRow widget. They all have to be created and size-request is called on them all AFAIK. This is taking a lot of time... In practice only a few are displayed on screen, so I think we need a way to create only visible widgets.

One of the problems when not creating all widgets is that we cannot know in advance the size of the scrollbar. There are 2 solutions for that: a) the user says all rows have the same height so we calculate only the height of the first row and multiply by the number of rows. b) we calculate the height of X rows and use the mean value. In all cases, when the list is huge the scrollbar is pretty useless anyway. The UI will have to provide a GtkSearchEntry to filter.

So I think we need a model backing the GtkListBox. The view would ask the model for example "give me GtkListBoxRow 150 to 170" when the user scroll.

I'm not sure how that will work with filtering, do we want to filter on the view or the model? If the view filter it means that when it asks for more rows the widgets are created then it realize that they don't have to be displayed and they get destroyed right away and it will have to pull more widgets... I think that's suboptimal. This needs to be taken into account when solving bug #710204 I think.
Comment 1 Jim Nelson 2014-05-29 21:00:46 UTC
I'll start by saying that I wrote a simple GtkListBox model for California.  When I say simple, I mean simple:

https://git.gnome.org/browse/california/tree/src/toolkit/toolkit-listbox-model.vala

After writing it (and dealing with similar problems in Geary and Shotwell), I know what I would like to see w/ a model:

* Filtering and sorting in the model, not ListBox.

* Start using this model in other widgets, i.e. combo boxes.

* Have ListBox accept an interface, not a class, as the model; this allows for different backings to be plugged in.

* Allow for the representative widget (i.e. the widget embedded in the ListBox) to signal mutation, i.e. that it needs to be resorted.  The class that wraps its backing data is better suited to monitor the backing data for changes than some outside collection class, and it's a better place to put the logic that decides which changes require re-sorting.

* For extra credit, support Gee.Comparable, although I can already hear the reasons why that shouldn't be done.

And the Big Kahuna:

* So often in apps there's three layers (if not more) at work in this problem:

  * A master collection of objects: a big bag of every instance of whatevers being organized.  This survives the lifetime of the app.
  * A container widget that displays a slice or a "view" of the master collection, i.e. ListBox: almost always sorted, sometimes filtered (to show only a portion of the master collection, i.e. all songs in an A/V media library), and sometimes temporary (only shown in a dialog box, but could be open in the main window for the lifetime of the session).

This ticket is, I think, asking for a layer in the middle of these two: a model that sorts and filters and holds the entire "slice" of data objects to be displayed, while the widget itself uses the viewport to create/destroy child widgets representing those objects.

My point here is that the middle layer is tied to the first layer, the master collection, and the container widget, ListBox.  It's a kind of translation layer.  As objects are added to the master collection, they have to be added to the view.  If the container widget is always present or intended to be dynamic, it requires a lot of signal handling and monitoring or redundant code to ensure the view model is up-to-date.

What we did in Shotwell was make the master collection *and* the view models signaled collections.  The view model monitors the master collection's signals and, with filters and sort comparators installed, builds its own sub-collection.  Any changes to the master are reflected in the view model.

I could go on, but that's the crux of it.  Even in a "small" app (like California) I'm already butting up against this problem.  It strikes me as something a lot of apps have to deal with.

I realize this is a bigger task than just adding a model for ListBox, but I wanted to get this out there and see if it resonates with anyone else.
Comment 2 Matthias Clasen 2015-02-15 20:22:32 UTC
We have gtk_list_box_bind_model now
Comment 3 Xavier Claessens 2015-02-16 01:32:03 UTC
Reopening. I checked the implementation of gtk_list_box_bind_model() and it won't fix this bug because it always create and add all widgets to the view. The intention of this bug (not well reflected in title, I rekon) is that widgets gets created on the flight while scrolling. Otherwise adding thousands of rows can freeze the application for several seconds. In this use case, gtk_list_box_bind_model() is actually even worse because the freeze can't be mitigated by adding widgets in small batches, returning to mainloop times to times.
Comment 4 Xavier Claessens 2015-02-16 01:41:37 UTC
Otoh, that's a detail of implementation. GListModel and gtk_list_box_bind_model() are great, implementation could be changed so it calls create_widget_func() only on items that's going to be visible. So maybe we have another bug about changing the current naïve implementation? In which case this bug can be closed dup of it? If not, I suggest keeping this bug for doing that work.
Comment 5 Lars Karlitski 2015-02-16 06:21:37 UTC
GtkListBox will never have support for huge models, because its API doesn't lend itself for creating widgets on the fly. We'll get a new widget for that.

As such, this bug is closed. (Technically as WONTFIX, because this bugs has the dreaded "should" in the title.)
Comment 6 Xavier Claessens 2015-02-16 11:56:45 UTC
OK fair enough. Do we have a bug opened for that new widget?
Comment 7 Lars Karlitski 2015-02-16 12:34:13 UTC
(In reply to Xavier Claessens from comment #6)
> OK fair enough. Do we have a bug opened for that new widget?

I'm not aware of one. Feel free to open if it doesn't exist yet ;)
Comment 8 Carl 2015-02-17 12:25:54 UTC
I'm also interested in a "heavy duty" api for huge lists as Elementary Noise is used to display 100.000+ tracks in a treeview (and 5 000 artists in an IconView).

Noise would really need the new GTK widgets to provide a way to handle large volume of data (with fixed width and recyled row widgets) to migration away from TreeView and IconView.

If there is another bug report to follow, don't hesitate to post it there as a follow up.