listview: Add concept of inertness

An inert listview is a listview that does not use the factory. This
allows faster updates because no calls into user code need to happen.

A listview is inert when either:
 - It is not rooted.
 - It is not visible.
 - No factory is set (that one is obvious)

The listview does not need to be inert without a model, as that case is
handled by the item manager.

This should allow Nautilus to keep both the gridview and the columnview
around, and just gtk_widget_hide() the unused widget.

The code for now does not disable the item manager, as some
functionality of the item manager is required to allow setting scroll
positions and such.
But that is a place where more gains could be found if profiling showed
that was useful to do.
This commit is contained in:
Benjamin Otte
2023-03-27 06:54:10 +02:00
parent 3fb10ff2d8
commit 62e9d1e470

View File

@@ -215,13 +215,58 @@ gtk_list_view_split (GtkListBase *base,
return new_tile;
}
/* We define the listview as **inert** when the factory isn't used. */
static gboolean
gtk_list_view_is_inert (GtkListView *self)
{
GtkWidget *widget = GTK_WIDGET (self);
return !gtk_widget_get_visible (widget) ||
gtk_widget_get_root (widget) == NULL ||
self->factory == NULL;
}
static void
gtk_list_view_update_factories_with (GtkListView *self,
GtkListItemFactory *factory)
{
GtkListTile *tile;
for (tile = gtk_list_item_manager_get_first (self->item_manager);
tile != NULL;
tile = gtk_rb_tree_node_get_next (tile))
{
if (tile->widget)
gtk_list_factory_widget_set_factory (GTK_LIST_FACTORY_WIDGET (tile->widget), factory);
}
}
static void
gtk_list_view_update_factories (GtkListView *self)
{
gtk_list_view_update_factories_with (self,
gtk_list_view_is_inert (self) ? NULL : self->factory);
}
static void
gtk_list_view_clear_factories (GtkListView *self)
{
gtk_list_view_update_factories_with (self, NULL);
}
static GtkListItemBase *
gtk_list_view_create_list_widget (GtkListBase *base)
{
GtkListView *self = GTK_LIST_VIEW (base);
GtkListItemFactory *factory;
GtkWidget *result;
result = gtk_list_item_widget_new (self->factory,
if (gtk_list_view_is_inert (self))
factory = NULL;
else
factory = self->factory;
result = gtk_list_item_widget_new (factory,
"row",
GTK_ACCESSIBLE_ROLE_LIST_ITEM);
@@ -606,6 +651,50 @@ gtk_list_view_size_allocate (GtkWidget *widget,
gtk_list_base_allocate (GTK_LIST_BASE (self));
}
static void
gtk_list_view_root (GtkWidget *widget)
{
GtkListView *self = GTK_LIST_VIEW (widget);
GTK_WIDGET_CLASS (gtk_list_view_parent_class)->root (widget);
if (!gtk_list_view_is_inert (self))
gtk_list_view_update_factories (self);
}
static void
gtk_list_view_unroot (GtkWidget *widget)
{
GtkListView *self = GTK_LIST_VIEW (widget);
if (!gtk_list_view_is_inert (self))
gtk_list_view_clear_factories (self);
GTK_WIDGET_CLASS (gtk_list_view_parent_class)->unroot (widget);
}
static void
gtk_list_view_show (GtkWidget *widget)
{
GtkListView *self = GTK_LIST_VIEW (widget);
GTK_WIDGET_CLASS (gtk_list_view_parent_class)->show (widget);
if (!gtk_list_view_is_inert (self))
gtk_list_view_update_factories (self);
}
static void
gtk_list_view_hide (GtkWidget *widget)
{
GtkListView *self = GTK_LIST_VIEW (widget);
if (!gtk_list_view_is_inert (self))
gtk_list_view_clear_factories (self);
GTK_WIDGET_CLASS (gtk_list_view_parent_class)->hide (widget);
}
static void
gtk_list_view_dispose (GObject *object)
{
@@ -731,6 +820,10 @@ gtk_list_view_class_init (GtkListViewClass *klass)
widget_class->measure = gtk_list_view_measure;
widget_class->size_allocate = gtk_list_view_size_allocate;
widget_class->root = gtk_list_view_root;
widget_class->unroot = gtk_list_view_unroot;
widget_class->show = gtk_list_view_show;
widget_class->hide = gtk_list_view_hide;
gobject_class->dispose = gtk_list_view_dispose;
gobject_class->get_property = gtk_list_view_get_property;
@@ -961,21 +1054,18 @@ void
gtk_list_view_set_factory (GtkListView *self,
GtkListItemFactory *factory)
{
GtkListTile *tile;
gboolean was_inert;
g_return_if_fail (GTK_IS_LIST_VIEW (self));
g_return_if_fail (factory == NULL || GTK_IS_LIST_ITEM_FACTORY (factory));
was_inert = gtk_list_view_is_inert (self);
if (!g_set_object (&self->factory, factory))
return;
for (tile = gtk_list_item_manager_get_first (self->item_manager);
tile != NULL;
tile = gtk_rb_tree_node_get_next (tile))
{
if (tile->widget)
gtk_list_factory_widget_set_factory (GTK_LIST_FACTORY_WIDGET (tile->widget), factory);
}
if (!was_inert || !gtk_list_view_is_inert (self))
gtk_list_view_update_factories (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FACTORY]);
}