Hello,
I’m trying to use a GtkListView to display a PDF file, where each item corresponds to a page of the PDF file. I’m using the list view with a GtkSignalListItemFactory, and I expected the bind signal to be called only when an item in the list view becomes visible on the screen (or at least when an element is not far in terms of scrolling). The factory does indeed do that, but it does so for the first 200 items (with some behaviour I don’t exactly understand when scrolling).
Rendering 200 pages at once is way too much, and I’d rather keep a dozen or so pages in memory at once, however I can’t seem to figure out how to implement this. I noticed that the GTK Inspector actually shows you which items of the GtkListView are currently visible, so getting a hold of that would be fairly convenient to implement this lazy loading.
I’m a bit new to GTK so I really don’t know if this is the right approach.
It seems like there’s no simple solution to this using a GtkListView, because the 200 pages loaded comes from the hardcoded GTK_LIST_VIEW_MAX_LIST_ITEMS constant (see GtkColumnView excessively creating column cells (#6557) · Issues · GNOME / gtk · GitLab ).
I’ll try implementing this with a GtkBox instead when I have more time, that way I can maybe control the widgets a bit more.
I’m curious to know how the GTK Inspector determines which items are visible.
I ran into the same issue in my app (also displaying pages in a GtkListView). Ideally, I’d like to modify that hard 200 limit. In the absence of that, my workaround was to monitor the vadjustment’s value, page-size, and upper properties, then manually calculate which pages fall within the viewport by dividing the total scroll height evenly across all pages. I then render only those pages (plus a small buffer of ~5 pages above and below), and clear textures from pages that scroll out of range to keep memory usage down.
The obvious limitation is that the calculations can break down for documents with a large number of mixed page sizes. It would be much more accurate if we could replicate whatever GtkListView is exposing to the Inspector, which presumably knows the actual allocated position of each row.
I might have found the solution. I looked into the code for the inspector, and it uses the map and unmap signals on GtkWidget, so in this case it would require setting signal handlers on the list item (or their children, whichever you want).
I noticed nonetheless that the first 200-ish pages are mapped at first, and then all but the first one (the only one that’s visible) are unmapped. This may or may not be intentional (I assume that GTK does this to determine the space the GtkListView needs ? or maybe not).
My solution (maybe not the most optimal), is to keep track of which pages have been mapped once. That way, in my GtkWidget::map signal handler, if my list item is being mapped and it has already been unmapped before, it means (most likely) that the list item is actually visible and the page corresponding to it should be rendered.
Doing this works very well, although I’m not quite keen of my solution since it feels like a hack. Feel free to let me know if you thought of a better way.