diff --git a/docs/reference/gtk/gtk4-docs.xml b/docs/reference/gtk/gtk4-docs.xml index 2b15a9f0d5..ebe6b8feeb 100644 --- a/docs/reference/gtk/gtk4-docs.xml +++ b/docs/reference/gtk/gtk4-docs.xml @@ -102,6 +102,7 @@ + diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 49c7ea7dd2..01b51fffc6 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -530,6 +530,22 @@ GTK_TYPE_LIST_ITEM_FACTORY gtk_list_item_factory_get_type +
+gtksignallistitemfactory +GtkSignalListItemFactory +GtkSignalListItemFactory +gtk_signal_list_item_factory_new + +GTK_SIGNAL_LIST_ITEM_FACTORY +GTK_SIGNAL_LIST_ITEM_FACTORY_CLASS +GTK_SIGNAL_LIST_ITEM_FACTORY_GET_CLASS +GTK_IS_SIGNAL_LIST_ITEM_FACTORY +GTK_IS_SIGNAL_LIST_ITEM_FACTORY_CLASS +GTK_TYPE_SIGNAL_LIST_ITEM_FACTORY + +gtk_signal_list_item_factory_get_type +
+
gtklistview GtkListView diff --git a/docs/reference/gtk/gtk4.types.in b/docs/reference/gtk/gtk4.types.in index 54d67d630e..8bf1ee6f3b 100644 --- a/docs/reference/gtk/gtk4.types.in +++ b/docs/reference/gtk/gtk4.types.in @@ -188,6 +188,7 @@ gtk_shortcuts_window_get_type gtk_shortcuts_section_get_type gtk_shortcuts_group_get_type gtk_shortcuts_shortcut_get_type +gtk_signal_list_item_factory_get_type gtk_single_selection_get_type gtk_size_group_get_type gtk_slice_list_model_get_type diff --git a/gtk/gtk.h b/gtk/gtk.h index a944a24254..d534cacb3a 100644 --- a/gtk/gtk.h +++ b/gtk/gtk.h @@ -229,6 +229,7 @@ #include #include #include +#include #include #include #include diff --git a/gtk/gtksignallistitemfactory.c b/gtk/gtksignallistitemfactory.c new file mode 100644 index 0000000000..db6d0828fb --- /dev/null +++ b/gtk/gtksignallistitemfactory.c @@ -0,0 +1,292 @@ +/* + * Copyright © 2019 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 "gtksignallistitemfactory.h" + +#include "gtkintl.h" +#include "gtklistitemfactoryprivate.h" +#include "gtklistitem.h" + +/** + * SECTION:gtksignallistitemfactory + * @title: GtkSignalListItemFactory + * @short_description: A listitem factory providing signals + * @see_also: #GtkListItemFactory + * + * #GtkSignalListItemFactory is a #GtkListItemFactory that provides signals + * that user code can connect to to manage listitems. + * Signals are emitted for every listitem in the same order: + * + * 1. #GtkSignalListItemFactory::setup is emitted to set up permanent things + * on the listitem. This usually means constructing the widgets used in the + * row and adding them to the listitem. + * + * 2. #GtkSignalListItemFactory::bind is emitted to bind the item passed via + * #GtkListItem:item to the widgets that have been created in step 1 or to + * add item-specific widgets. Signals are connected to listen to changes - + * both to changes in the item to update the widgets or to changes in the + * widgets to update the item. After this signal has been called, the + * listitem may be shown in a list widget. + * + * 3. #GtkSignalListItemFactory::unbind is emitted to undo everything done + * in step 2. Usually this means disconnecting signal handlers. Once this + * signal has been called, the listitem will no longer be used in a list + * widget. + * + * 4. #GtkSignalListItemFactory::bind and #GtkSignalListItemFactory::unbind + * may be emitted multiple times again to bind the listitem for use with + * new items. By reusing listitems, potentially costly setup can be + * avoided. However, it means code needs to make sure to properly clean + * up the listitem in step 3 so that no information from the previous + * use leaks into the next use. + * + * 5. #GtkSignalListItemFactory::teardown is emitted to allow undoing the + * effects of #GtkSignalListItemFactory::setup. After this signal was emitted + * on a listitem, the listitem will be destroyed and not be used again. + * + * Note that during the signal emissions, changing properties on the + * #GtkListItems passed will not trigger notify signals as the listitem's + * notifications are frozen. See g_object_freeze_notify() for details. + * + * For tracking changes in other properties in the #GtkListItem, the + * #GtkListItem::notify signal is recommended. The signal can be connected + * in the #GtkSignalListItemFactory::setup signal and removed again during + * #GtkSignalListItemFactory::teardown. + */ + +struct _GtkSignalListItemFactory +{ + GtkListItemFactory parent_instance; +}; + +struct _GtkSignalListItemFactoryClass +{ + GtkListItemFactoryClass parent_class; + + void (* setup) (GtkListItemFactory *self, + GtkListItem *list_item); + void (* teardown) (GtkListItemFactory *self, + GtkListItem *list_item); + + void (* bind) (GtkListItemFactory *self, + GtkListItem *list_item, + guint position, + gpointer item, + gboolean selected); + void (* unbind) (GtkListItemFactory *self, + GtkListItem *list_item); +}; + +enum { + SETUP, + BIND, + UNBIND, + TEARDOWN, + + LAST_SIGNAL +}; + +G_DEFINE_TYPE (GtkSignalListItemFactory, gtk_signal_list_item_factory, GTK_TYPE_LIST_ITEM_FACTORY) +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +gtk_signal_list_item_factory_setup (GtkListItemFactory *factory, + GtkListItem *list_item) +{ + GTK_LIST_ITEM_FACTORY_CLASS (gtk_signal_list_item_factory_parent_class)->setup (factory, list_item); + + g_signal_emit (factory, signals[SETUP], 0, list_item); +} + +static void +gtk_signal_list_item_factory_bind (GtkListItemFactory *factory, + GtkListItem *list_item, + guint position, + gpointer item, + gboolean selected) +{ + GTK_LIST_ITEM_FACTORY_CLASS (gtk_signal_list_item_factory_parent_class)->bind (factory, list_item, position, item, selected); + + g_signal_emit (factory, signals[BIND], 0, list_item); +} + +static void +gtk_signal_list_item_factory_rebind (GtkListItemFactory *factory, + GtkListItem *list_item, + guint position, + gpointer item, + gboolean selected) +{ + g_signal_emit (factory, signals[UNBIND], 0, list_item); + + GTK_LIST_ITEM_FACTORY_CLASS (gtk_signal_list_item_factory_parent_class)->bind (factory, list_item, position, item, selected); + + g_signal_emit (factory, signals[BIND], 0, list_item); +} + +static void +gtk_signal_list_item_factory_unbind (GtkListItemFactory *factory, + GtkListItem *list_item) +{ + g_signal_emit (factory, signals[UNBIND], 0, list_item); + + GTK_LIST_ITEM_FACTORY_CLASS (gtk_signal_list_item_factory_parent_class)->unbind (factory, list_item); +} + +static void +gtk_signal_list_item_factory_teardown (GtkListItemFactory *factory, + GtkListItem *list_item) +{ + g_signal_emit (factory, signals[TEARDOWN], 0, list_item); + + GTK_LIST_ITEM_FACTORY_CLASS (gtk_signal_list_item_factory_parent_class)->teardown (factory, list_item); +} + +static void +gtk_signal_list_item_factory_class_init (GtkSignalListItemFactoryClass *klass) +{ + GtkListItemFactoryClass *factory_class = GTK_LIST_ITEM_FACTORY_CLASS (klass); + + factory_class->setup = gtk_signal_list_item_factory_setup; + factory_class->bind = gtk_signal_list_item_factory_bind; + factory_class->rebind = gtk_signal_list_item_factory_rebind; + factory_class->unbind = gtk_signal_list_item_factory_unbind; + factory_class->teardown = gtk_signal_list_item_factory_teardown; + + /** + * GtkSignalListItemFactory::setup: + * @self: The #GtkSignalListItemFactory + * @listitem: The #GtkListItem to set up + * + * The ::setup signal is emitted when a new listitem has been created and + * needs to be setup for use. It is the first signal emitted for every listitem. + * + * The GtkSignalListItemFactory::teardown signal is the opposite of this signal + * and can be used to undo everything done in this signal. + */ + signals[SETUP] = + g_signal_new (I_("setup"), + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkSignalListItemFactoryClass, setup), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + GTK_TYPE_LIST_ITEM); + g_signal_set_va_marshaller (signals[SETUP], + G_TYPE_FROM_CLASS (klass), + g_cclosure_marshal_VOID__OBJECTv); + + /** + * GtkSignalListItemFactory::bind: + * @self: The #GtkSignalListItemFactory + * @listitem: The #GtkListItem to bind + * + * The ::bind signal is emitted when a new GtkListItem:item has been set + * on the @listitem and should be bound for use. + * + * After this signal was emitted, the listitem might be shown in a #GtkListView + * or other list widget. + * + * The GtkSignalListItemFactory::unbind signal is the opposite of this signal + * and can be used to undo everything done in this signal. + */ + signals[BIND] = + g_signal_new (I_("bind"), + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkSignalListItemFactoryClass, bind), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + GTK_TYPE_LIST_ITEM); + g_signal_set_va_marshaller (signals[BIND], + G_TYPE_FROM_CLASS (klass), + g_cclosure_marshal_VOID__OBJECTv); + + /** + * GtkSignalListItemFactory::unbind: + * @self: The #GtkSignalListItemFactory + * @listitem: The #GtkListItem to unbind + * + * The ::unbind signal is emitted when a listitem has been removed from use + * in a list widget and its new GtkListItem:item is about to be unset. + * + * This signal is the opposite of the GtkSignalListItemFactory::bind signal + * and should be used to undo everything done in that signal. + */ + signals[UNBIND] = + g_signal_new (I_("unbind"), + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkSignalListItemFactoryClass, unbind), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + GTK_TYPE_LIST_ITEM); + g_signal_set_va_marshaller (signals[UNBIND], + G_TYPE_FROM_CLASS (klass), + g_cclosure_marshal_VOID__OBJECTv); + + /** + * GtkSignalListItemFactory::teardown: + * @self: The #GtkSignalListItemFactory + * @listitem: The #GtkListItem to teardown + * + * The ::teardown signal is emitted when a listitem is about to be destroyed. + * It is the last signal ever emitted for this @listitem. + * + * This signal is the opposite of the GtkSignalListItemFactory::setup signal + * and should be used to undo everything done in that signal. + */ + signals[TEARDOWN] = + g_signal_new (I_("teardown"), + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkSignalListItemFactoryClass, teardown), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + GTK_TYPE_LIST_ITEM); + g_signal_set_va_marshaller (signals[TEARDOWN], + G_TYPE_FROM_CLASS (klass), + g_cclosure_marshal_VOID__OBJECTv); +} + +static void +gtk_signal_list_item_factory_init (GtkSignalListItemFactory *self) +{ +} + +/** + * gtk_signal_list_item_factory_new: + * + * Creates a new #GtkSignalListItemFactory. You need to connect signal + * handlers before you use it. + * + * Returns: a new #GtkSignalListItemFactory + **/ +GtkListItemFactory * +gtk_signal_list_item_factory_new (void) +{ + return g_object_new (GTK_TYPE_SIGNAL_LIST_ITEM_FACTORY, NULL); +} + diff --git a/gtk/gtksignallistitemfactory.h b/gtk/gtksignallistitemfactory.h new file mode 100644 index 0000000000..56c2f10a49 --- /dev/null +++ b/gtk/gtksignallistitemfactory.h @@ -0,0 +1,56 @@ +/* + * Copyright © 2019 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_SIGNAL_LIST_ITEM_FACTORY_H__ +#define __GTK_SIGNAL_LIST_ITEM_FACTORY_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_SIGNAL_LIST_ITEM_FACTORY (gtk_signal_list_item_factory_get_type ()) +#define GTK_SIGNAL_LIST_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_SIGNAL_LIST_ITEM_FACTORY, GtkSignalListItemFactory)) +#define GTK_SIGNAL_LIST_ITEM_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_SIGNAL_LIST_ITEM_FACTORY, GtkSignalListItemFactoryClass)) +#define GTK_IS_SIGNAL_LIST_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_SIGNAL_LIST_ITEM_FACTORY)) +#define GTK_IS_SIGNAL_LIST_ITEM_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_SIGNAL_LIST_ITEM_FACTORY)) +#define GTK_SIGNAL_LIST_ITEM_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_SIGNAL_LIST_ITEM_FACTORY, GtkSignalListItemFactoryClass)) + +/** + * GtkSignalListItemFactory: + * + * The object for the #GtkSignalListItemFactory. + **/ +typedef struct _GtkSignalListItemFactory GtkSignalListItemFactory; +typedef struct _GtkSignalListItemFactoryClass GtkSignalListItemFactoryClass; + + +GDK_AVAILABLE_IN_ALL +GType gtk_signal_list_item_factory_get_type (void) G_GNUC_CONST; + +GDK_AVAILABLE_IN_ALL +GtkListItemFactory * gtk_signal_list_item_factory_new (void); + + +G_END_DECLS + +#endif /* __GTK_SIGNAL_LIST_ITEM_FACTORY_H__ */ diff --git a/gtk/meson.build b/gtk/meson.build index bb4495c01f..f6f6899461 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -371,6 +371,7 @@ gtk_public_sources = files([ 'gtkshortcutswindow.c', 'gtkshow.c', 'gtksidebarrow.c', + 'gtksignallistitemfactory.c', 'gtksingleselection.c', 'gtksizegroup.c', 'gtksizerequest.c', @@ -643,6 +644,7 @@ gtk_public_headers = files([ 'gtkshortcutsshortcut.h', 'gtkshortcutswindow.h', 'gtkshow.h', + 'gtksignallistitemfactory.h', 'gtksingleselection.h', 'gtksizegroup.h', 'gtksizerequest.h',