diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index beb6b2df87..3479a557b2 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -393,6 +393,20 @@ gtk_single_selection_get_type
+gtklistitemfactory
+GtkListItemFactory
+GtkListItemFactory
+
+GTK_LIST_ITEM_FACTORY
+GTK_LIST_ITEM_FACTORY_CLASS
+GTK_LIST_ITEM_FACTORY_GET_CLASS
+GTK_IS_LIST_ITEM_FACTORY
+GTK_IS_LIST_ITEM_FACTORY_CLASS
+GTK_TYPE_LIST_ITEM_FACTORY
+
+gtk_list_item_factory_get_type
+
+
gtklistview
GtkListView
GtkListView
diff --git a/docs/reference/gtk/gtk4.types.in b/docs/reference/gtk/gtk4.types.in
index 6ada01a6b7..30292ea74a 100644
--- a/docs/reference/gtk/gtk4.types.in
+++ b/docs/reference/gtk/gtk4.types.in
@@ -119,6 +119,7 @@ gtk_label_get_type
gtk_layout_child_get_type
gtk_layout_manager_get_type
gtk_link_button_get_type
+gtk_list_item_factory_get_type
gtk_list_store_get_type
gtk_list_box_get_type
gtk_list_box_row_get_type
diff --git a/docs/reference/gtk/meson.build b/docs/reference/gtk/meson.build
index 07536264eb..bc28cbc7ed 100644
--- a/docs/reference/gtk/meson.build
+++ b/docs/reference/gtk/meson.build
@@ -132,6 +132,7 @@ private_headers = [
'gtkimmoduleprivate.h',
'gtkkineticscrollingprivate.h',
'gtklabelprivate.h',
+ 'gtklistitemfactoryprivate.h',
'gtklockbuttonprivate.h',
'gtkmagnifierprivate.h',
'gtkmediafileprivate.h',
diff --git a/gtk/gtklistitemfactory.c b/gtk/gtklistitemfactory.c
new file mode 100644
index 0000000000..7519bc01bb
--- /dev/null
+++ b/gtk/gtklistitemfactory.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright © 2018 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Benjamin Otte
+ */
+
+#include "config.h"
+
+#include "gtklistitemfactoryprivate.h"
+
+/**
+ * SECTION:gtklistitemfactory
+ * @Title: GtkListItemFactory
+ * @Short_description: Mapping list items to widgets
+ *
+ * #GtkListItemFactory is one of the core concepts of handling list widgets.
+ * It is the object tasked with creating widgets for items taken from a
+ * #GListModel when the views need them and updating them as the items
+ * displayed by the view change.
+ *
+ * A view is usually only able to display anything after both a factory
+ * and a model have been set on the view. So it is important that you do
+ * not skip this step when setting up your first view.
+ *
+ * Because views do not display the whole list at once but only a few
+ * items, they only need to maintain a few widgets at a time. They will
+ * instruct the #GtkListItemFactory to create these widgets and bind them
+ * to the items that are currently displayed.
+ * As the list model changes or the user scrolls to the list, the items will
+ * change and the view will instruct the factory to bind the widgets to those
+ * new items.
+ *
+ * The actual widgets used for displaying those widgets is provided by you.
+ *
+ * When the factory needs widgets created, it will create a #GtkListItem and
+ * hand it to your code to set up a widget for. This list item will provide
+ * various properties with information about what item to display and provide
+ * you with some opportunities to configure its behavior. See the #GtkListItem
+ * documentation for further details.
+ *
+ * Various implementations of #GtkListItemFactory exist to allow you different
+ * ways to provide those widgets. The most common implementations are
+ * #GtkBuilderListItemFactory which takes a #GtkBuilder .ui file and then creates
+ * and manages widgets everything automatically from the information in that file
+ * and #GtkSignalListItemFactory which allows you to connect to signals with your
+ * own code and retain full control over how the widgets are setup and managed.
+ *
+ * A #GtkListItemFactory is supposed to be final - that means its behavior should
+ * not change and the first widget created from it should behave the same way as
+ * the last widget created from it.
+ * If you intend to do changes to the behavior, it is recommended that you create
+ * a new #GtkListItemFactory which will allow the views to recreate its widgets.
+ *
+ * Once you have chosen your factory and created it, you need to set it on the
+ * view widget you want to use it with, such as via gtk_list_view_set_factory().
+ * Reusing factories across different views is allowed, but very uncommon.
+ */
+
+struct _GtkListItemFactory
+{
+ GObject parent_instance;
+
+ GtkListCreateWidgetFunc create_func;
+ GtkListBindWidgetFunc bind_func;
+ gpointer user_data;
+ GDestroyNotify user_destroy;
+};
+
+struct _GtkListItemFactoryClass
+{
+ GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkListItemFactory, gtk_list_item_factory, G_TYPE_OBJECT)
+
+static void
+gtk_list_item_factory_finalize (GObject *object)
+{
+ GtkListItemFactory *self = GTK_LIST_ITEM_FACTORY (object);
+
+ if (self->user_destroy)
+ self->user_destroy (self->user_data);
+
+ G_OBJECT_CLASS (gtk_list_item_factory_parent_class)->finalize (object);
+}
+
+static void
+gtk_list_item_factory_class_init (GtkListItemFactoryClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtk_list_item_factory_finalize;
+}
+
+static void
+gtk_list_item_factory_init (GtkListItemFactory *self)
+{
+}
+
+GtkListItemFactory *
+gtk_list_item_factory_new (GtkListCreateWidgetFunc create_func,
+ GtkListBindWidgetFunc bind_func,
+ gpointer user_data,
+ GDestroyNotify user_destroy)
+{
+ GtkListItemFactory *self;
+
+ g_return_val_if_fail (create_func, NULL);
+ g_return_val_if_fail (bind_func, NULL);
+ g_return_val_if_fail (user_data != NULL || user_destroy == NULL, NULL);
+
+ self = g_object_new (GTK_TYPE_LIST_ITEM_FACTORY, NULL);
+
+ self->create_func = create_func;
+ self->bind_func = bind_func;
+ self->user_data = user_data;
+ self->user_destroy = user_destroy;
+
+ return self;
+}
+
+GtkWidget *
+gtk_list_item_factory_create (GtkListItemFactory *self)
+{
+ g_return_val_if_fail (GTK_IS_LIST_ITEM_FACTORY (self), NULL);
+
+ return self->create_func (self->user_data);
+}
+
+void
+gtk_list_item_factory_bind (GtkListItemFactory *self,
+ GtkWidget *widget,
+ gpointer item)
+{
+ g_return_if_fail (GTK_IS_LIST_ITEM_FACTORY (self));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ self->bind_func (widget, item, self->user_data);
+}
+
diff --git a/gtk/gtklistitemfactoryprivate.h b/gtk/gtklistitemfactoryprivate.h
new file mode 100644
index 0000000000..28ae55b4aa
--- /dev/null
+++ b/gtk/gtklistitemfactoryprivate.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2018 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Benjamin Otte
+ */
+
+
+#ifndef __GTK_LIST_ITEM_FACTORY_H__
+#define __GTK_LIST_ITEM_FACTORY_H__
+
+#include
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_LIST_ITEM_FACTORY (gtk_list_item_factory_get_type ())
+#define GTK_LIST_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_LIST_ITEM_FACTORY, GtkListItemFactory))
+#define GTK_LIST_ITEM_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_LIST_ITEM_FACTORY, GtkListItemFactoryClass))
+#define GTK_IS_LIST_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_LIST_ITEM_FACTORY))
+#define GTK_IS_LIST_ITEM_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_LIST_ITEM_FACTORY))
+#define GTK_LIST_ITEM_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_LIST_ITEM_FACTORY, GtkListItemFactoryClass))
+
+typedef struct _GtkListItemFactory GtkListItemFactory;
+typedef struct _GtkListItemFactoryClass GtkListItemFactoryClass;
+
+GType gtk_list_item_factory_get_type (void) G_GNUC_CONST;
+
+GtkListItemFactory * gtk_list_item_factory_new (GtkListCreateWidgetFunc create_func,
+ GtkListBindWidgetFunc bind_func,
+ gpointer user_data,
+ GDestroyNotify user_destroy);
+
+GtkWidget * gtk_list_item_factory_create (GtkListItemFactory *self);
+
+void gtk_list_item_factory_bind (GtkListItemFactory *self,
+ GtkWidget *widget,
+ gpointer item);
+
+
+G_END_DECLS
+
+#endif /* __GTK_LIST_ITEM_FACTORY_H__ */
diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c
index d5f2ca3841..b8a5337d8a 100644
--- a/gtk/gtklistview.c
+++ b/gtk/gtklistview.c
@@ -22,7 +22,7 @@
#include "gtklistview.h"
#include "gtkintl.h"
-#include "gtkprivate.h"
+#include "gtklistitemfactoryprivate.h"
/**
* SECTION:gtklistview
@@ -38,6 +38,7 @@ struct _GtkListView
GtkWidget parent_instance;
GListModel *model;
+ GtkListItemFactory *item_factory;
};
enum
@@ -116,6 +117,8 @@ gtk_list_view_dispose (GObject *object)
gtk_list_view_clear_model (self);
+ g_clear_object (&self->item_factory);
+
G_OBJECT_CLASS (gtk_list_view_parent_class)->dispose (object);
}
@@ -258,3 +261,20 @@ gtk_list_view_set_model (GtkListView *self,
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
}
+void
+gtk_list_view_set_functions (GtkListView *self,
+ GtkListCreateWidgetFunc create_func,
+ GtkListBindWidgetFunc bind_func,
+ gpointer user_data,
+ GDestroyNotify user_destroy)
+{
+ g_return_if_fail (GTK_IS_LIST_VIEW (self));
+ g_return_if_fail (create_func);
+ g_return_if_fail (bind_func);
+ g_return_if_fail (user_data != NULL || user_destroy == NULL);
+
+ g_clear_object (&self->item_factory);
+
+ self->item_factory = gtk_list_item_factory_new (create_func, bind_func, user_data, user_destroy);
+}
+
diff --git a/gtk/gtklistview.h b/gtk/gtklistview.h
index 9329e21d75..541bf14874 100644
--- a/gtk/gtklistview.h
+++ b/gtk/gtklistview.h
@@ -28,6 +28,36 @@
G_BEGIN_DECLS
+/**
+ * GtkListCreateWidgetFunc:
+ * @user_data: (closure): user data
+ *
+ * Called whenever a new widget needs to be created for managing a row in
+ * the list.
+ *
+ * The widget will later be bound to an item via the #GtkListBindWidgetFunc.
+ *
+ * Returns: (transfer full): a #GtkWidget
+ */
+typedef GtkWidget * (* GtkListCreateWidgetFunc) (gpointer user_data);
+
+/**
+ * GtkListBindWidgetFunc:
+ * @widget: The #GtkWidget to bind
+ * @item: (type GObject) (allow-none): item to bind or %NULL to unbind
+ * the widget.
+ * @user_data: (closure): user data
+ *
+ * Binds a widget previously created via a #GtkListCreateWidgetFunc to
+ * an @item.
+ *
+ * Rebinding a @widget to different @items is supported as well as
+ * unbinding it by setting @item to %NULL.
+ */
+typedef void (* GtkListBindWidgetFunc) (GtkWidget *widget,
+ gpointer item,
+ gpointer user_data);
+
#define GTK_TYPE_LIST_VIEW (gtk_list_view_get_type ())
GDK_AVAILABLE_IN_ALL
@@ -41,7 +71,12 @@ GListModel * gtk_list_view_get_model (GtkListView
GDK_AVAILABLE_IN_ALL
void gtk_list_view_set_model (GtkListView *self,
GListModel *model);
-
+GDK_AVAILABLE_IN_ALL
+void gtk_list_view_set_functions (GtkListView *self,
+ GtkListCreateWidgetFunc create_func,
+ GtkListBindWidgetFunc bind_func,
+ gpointer user_data,
+ GDestroyNotify user_destroy);
G_END_DECLS
diff --git a/gtk/meson.build b/gtk/meson.build
index 8b221d7c3d..c1cb68daf4 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -271,6 +271,7 @@ gtk_public_sources = files([
'gtklevelbar.c',
'gtklinkbutton.c',
'gtklistbox.c',
+ 'gtklistitemfactory.c',
'gtklistlistmodel.c',
'gtkliststore.c',
'gtklistview.c',