listview: cull listitems that are out of view
authorBenjamin Otte <otte@redhat.com>
Wed, 1 Jun 2022 02:29:15 +0000 (04:29 +0200)
committerBenjamin Otte <otte@redhat.com>
Tue, 7 Jun 2022 01:20:11 +0000 (03:20 +0200)
Use set_child_visible(FALSE) on those widgets and don't allocate them.

This should usually be the majority of items, so it's quite a worthwhile
addition.

Idea by Ivan Molodetskikh.

Related: #3334

gtk/gtklistbase.c

index bf0657a04f742f8c9ec920e81d73a79d688af94c..81c95d1a4d0c68419a1ca46e98dca99208fc2e69 100644 (file)
 #include "gtktypebuiltins.h"
 #include "gtkwidgetprivate.h"
 
+/* Allow shadows to overdraw without immediately culling the widget at the viewport
+ * boundary.
+ * Choose this so that roughly 1 extra widget gets drawn on each side of the viewport,
+ * but not more. Icons are 16px, text height is somewhere there, too.
+ */
+#define GTK_LIST_BASE_CHILD_MAX_OVERDRAW 10
+
 typedef struct _RubberbandData RubberbandData;
 
 struct _RubberbandData
@@ -1351,6 +1358,22 @@ gtk_list_base_size_allocate_child (GtkListBase *self,
                                    int          height)
 {
   GtkAllocation child_allocation;
+  int self_width, self_height;
+
+  self_width = gtk_widget_get_width (GTK_WIDGET (self));
+  self_height = gtk_widget_get_height (GTK_WIDGET (self));
+
+  if (y + height + GTK_LIST_BASE_CHILD_MAX_OVERDRAW <= 0 ||
+      y - GTK_LIST_BASE_CHILD_MAX_OVERDRAW >= self_height ||
+      x + width + GTK_LIST_BASE_CHILD_MAX_OVERDRAW <= 0 ||
+      x - GTK_LIST_BASE_CHILD_MAX_OVERDRAW >= self_width)
+    {
+      /* child is fully outside the viewport, hide it and don't allocate it */
+      gtk_widget_set_child_visible (child, FALSE);
+      return;
+    }
+
+  gtk_widget_set_child_visible (child, TRUE);
 
   if (gtk_list_base_get_orientation (GTK_LIST_BASE (self)) == GTK_ORIENTATION_VERTICAL)
     {
@@ -1363,9 +1386,7 @@ gtk_list_base_size_allocate_child (GtkListBase *self,
         }
       else
         {
-          int mirror_point = gtk_widget_get_width (GTK_WIDGET (self));
-
-          child_allocation.x = mirror_point - x - width;
+          child_allocation.x = self_width - x - width;
           child_allocation.y = y;
           child_allocation.width = width;
           child_allocation.height = height;
@@ -1382,9 +1403,7 @@ gtk_list_base_size_allocate_child (GtkListBase *self,
         }
       else
         {
-          int mirror_point = gtk_widget_get_width (GTK_WIDGET (self));
-
-          child_allocation.x = mirror_point - y - height;
+          child_allocation.x = self_width - y - height;
           child_allocation.y = x;
           child_allocation.width = height;
           child_allocation.height = width;