listitemmanager: Add tile types
authorBenjamin Otte <otte@redhat.com>
Wed, 5 Apr 2023 13:10:16 +0000 (15:10 +0200)
committerBenjamin Otte <otte@redhat.com>
Tue, 9 May 2023 15:00:39 +0000 (17:00 +0200)
We have a FILLER and a REMOVED type now.

Also makes gc() more sensitive to types.

gtk/gtkgridview.c
gtk/gtklistitemmanager.c
gtk/gtklistitemmanagerprivate.h

index ead43a8c8bc5a8714bce880b69d60e0a7a2a0380..6299766c2f513bae0929941a8fa97c7578141c3d 100644 (file)
@@ -886,7 +886,7 @@ gtk_grid_view_size_allocate (GtkWidget *widget,
     {
       GtkListTile *filler;
       tile = gtk_list_item_manager_get_last (self->item_manager);
-      filler = gtk_list_tile_split (self->item_manager, tile, tile->n_items);
+      filler = gtk_list_tile_append_filler (self->item_manager, tile);
       gtk_list_tile_set_area_position (self->item_manager,
                                        filler,
                                        column_start (self, xspacing, i),
index e73b1512bf7ea5bb5c3dc695cb03976fcb0c6fef..f976b0063e0506beaef97e69c4a5602c5f59636f 100644 (file)
@@ -597,6 +597,7 @@ gtk_list_item_manager_remove_items (GtkListItemManager *self,
       tile->widget = NULL;
       n_items -= tile->n_items;
       tile->n_items = 0;
+      tile->type = GTK_LIST_TILE_REMOVED;
       gtk_rb_tree_node_mark_dirty (tile);
 
       tile = next;
@@ -655,7 +656,7 @@ gtk_list_item_manager_merge_list_items (GtkListItemManager *self,
  * items will be given to the new tile, which will be
  * nserted after the tile.
  *
- * It is valid for either tile to have 0 items after
+ * It is not valid for either tile to have 0 items after
  * the split.
  *
  * Returns: The new tile
@@ -667,7 +668,8 @@ gtk_list_tile_split (GtkListItemManager *self,
 {
   GtkListTile *result;
 
-  g_assert (n_items <= tile->n_items);
+  g_assert (n_items > 0);
+  g_assert (n_items < tile->n_items);
   g_assert (tile->type == GTK_LIST_TILE_ITEM);
 
   result = gtk_rb_tree_insert_after (self->items, tile);
@@ -679,10 +681,38 @@ gtk_list_tile_split (GtkListItemManager *self,
   return result;
 }
 
+/*
+ * gtk_list_tile_append_filler:
+ * @self: the listitemmanager
+ * @previous: tile to append to
+ *
+ * Appends a filler tile.
+ *
+ * Filler tiles don't refer to any items or header and exist
+ * just to take up space, so that finding items by position gets
+ * easier.
+ *
+ * They ave a special garbage-collection behavior, see
+ * gtk_list_tile_gc().
+ *
+ * Returns: The new filler tile
+ **/
+GtkListTile *
+gtk_list_tile_append_filler (GtkListItemManager *self,
+                             GtkListTile        *previous)
+{
+  GtkListTile *result;
+
+  result = gtk_rb_tree_insert_after (self->items, previous);
+  result->type = GTK_LIST_TILE_FILLER;
+
+  return result;
+}
+
 /*
  * gtk_list_tile_gc:
  * @self: the listitemmanager
- * @tile: a tile
+ * @tile: a tile or NULL
  *
  * Tries to get rid of tiles when they aren't needed anymore,
  * either because their referenced listitems were deleted or
@@ -690,7 +720,11 @@ gtk_list_tile_split (GtkListItemManager *self,
  *
  * Note that this only looks forward, but never backward.
  *
- * Returns: The next tile
+ * A special case here are filler tiles. They only get
+ * collected, when they are explicitly passed in, but never
+ * otherwise.
+ *
+ * Returns: The next tile or NULL if everything was gc'ed
  **/
 GtkListTile *
 gtk_list_tile_gc (GtkListItemManager *self,
@@ -698,22 +732,47 @@ gtk_list_tile_gc (GtkListItemManager *self,
 {
   GtkListTile *next;
 
+  if (tile == NULL)
+    return NULL;
+
+  if (tile->type == GTK_LIST_TILE_FILLER)
+    {
+      next = gtk_rb_tree_node_get_next (tile);
+      gtk_rb_tree_remove (self->items, tile);
+      tile = next;
+    }
+
   while (tile)
     {
       next = gtk_rb_tree_node_get_next (tile);
+      while (next && next->type == GTK_LIST_TILE_REMOVED)
+        {
+          gtk_rb_tree_remove (self->items, next);
+          next = gtk_rb_tree_node_get_next (tile);
+        }
 
-      if (tile->n_items == 0)
+      switch (tile->type)
         {
+        case GTK_LIST_TILE_ITEM:
+          g_assert (tile->n_items > 0);
+          if (next == NULL)
+            break;
+          if (gtk_list_item_manager_merge_list_items (self, tile, next))
+            continue;
+          break;
+
+        case GTK_LIST_TILE_FILLER:
+          break;
+
+        case GTK_LIST_TILE_REMOVED:
           gtk_rb_tree_remove (self->items, tile);
           tile = next;
           continue;
-        }
-
-      if (next == NULL)
-        break;
 
-      if (gtk_list_item_manager_merge_list_items (self, tile, next))
-        continue;
+        default:
+          g_assert_not_reached ();
+          break;
+        }
 
       break;
     }
index a82e686266947629b5a687e9fecf23e0521a2d54..df6e0d1211eaa11e56cf89c3649160ce5b789673 100644 (file)
@@ -45,7 +45,9 @@ typedef struct _GtkListItemTracker GtkListItemTracker;
 
 typedef enum
 {
-  GTK_LIST_TILE_ITEM
+  GTK_LIST_TILE_ITEM,
+  GTK_LIST_TILE_FILLER,
+  GTK_LIST_TILE_REMOVED,
 } GtkListTileType;
 
 struct _GtkListTile
@@ -103,6 +105,8 @@ void                    gtk_list_tile_set_area_size             (GtkListItemMana
 GtkListTile *           gtk_list_tile_split                     (GtkListItemManager     *self,
                                                                  GtkListTile            *tile,
                                                                  guint                   n_items);
+GtkListTile *           gtk_list_tile_append_filler             (GtkListItemManager     *self,
+                                                                 GtkListTile            *previous);
 GtkListTile *           gtk_list_tile_gc                        (GtkListItemManager     *self,
                                                                  GtkListTile            *tile);