[gtk/wip/otte/listview: 150/183] Add GtkSignalListItemFactory



commit 6e7b43d226b056432790507955229cc69606ad94
Author: Benjamin Otte <otte redhat com>
Date:   Tue Oct 29 05:58:02 2019 +0100

    Add GtkSignalListItemFactory
    
    So the poor Rust users can actually use this.
    
    I would totally not use this ever!

 docs/reference/gtk/gtk4-docs.xml     |   1 +
 docs/reference/gtk/gtk4-sections.txt |  16 ++
 gtk/gtk.h                            |   1 +
 gtk/gtksignallistitemfactory.c       | 292 +++++++++++++++++++++++++++++++++++
 gtk/gtksignallistitemfactory.h       |  56 +++++++
 gtk/meson.build                      |   2 +
 6 files changed, 368 insertions(+)
---
diff --git a/docs/reference/gtk/gtk4-docs.xml b/docs/reference/gtk/gtk4-docs.xml
index 785bb1ae06..6fa530e11e 100644
--- a/docs/reference/gtk/gtk4-docs.xml
+++ b/docs/reference/gtk/gtk4-docs.xml
@@ -89,6 +89,7 @@
       <xi:include href="xml/gtkrevealer.xml" />
       <xi:include href="xml/gtklistbox.xml" />
       <xi:include href="xml/gtkflowbox.xml" />
+      <xi:include href="xml/gtksignallistitemfactory.xml" />
       <xi:include href="xml/gtklistview.xml" />
       <xi:include href="xml/gtkgridview.xml" />
       <xi:include href="xml/gtktreeexpander.xml" />
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index 3b17a20897..43a2adb19f 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -515,6 +515,22 @@ GTK_TYPE_LIST_ITEM
 gtk_list_item_get_type
 </SECTION>
 
+<SECTION>
+<FILE>gtksignallistitemfactory</FILE>
+<TITLE>GtkSignalListItemFactory</TITLE>
+GtkSignalListItemFactory
+gtk_signal_list_item_factory_new
+<SUBSECTION Standard>
+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
+<SUBSECTION Private>
+gtk_signal_list_item_factory_get_type
+</SECTION>
+
 <SECTION>
 <FILE>gtklistview</FILE>
 <TITLE>GtkListView</TITLE>
diff --git a/gtk/gtk.h b/gtk/gtk.h
index e38933a7a7..673d02affd 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -225,6 +225,7 @@
 #include <gtk/gtkshortcutsshortcut.h>
 #include <gtk/gtkshortcutswindow.h>
 #include <gtk/gtkshow.h>
+#include <gtk/gtksignallistitemfactory.h>
 #include <gtk/gtksingleselection.h>
 #include <gtk/gtkslicelistmodel.h>
 #include <gtk/gtksnapshot.h>
diff --git a/gtk/gtksignallistitemfactory.c b/gtk/gtksignallistitemfactory.c
new file mode 100644
index 0000000000..0665b2a603
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#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 called 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 called 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 called 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 called 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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_SIGNAL_LIST_ITEM_FACTORY_H__
+#define __GTK_SIGNAL_LIST_ITEM_FACTORY_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtklistitemfactory.h>
+
+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 499467adfd..8cb06befeb 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -367,6 +367,7 @@ gtk_public_sources = files([
   'gtkshortcutswindow.c',
   'gtkshow.c',
   'gtksidebarrow.c',
+  'gtksignallistitemfactory.c',
   'gtksingleselection.c',
   'gtksizegroup.c',
   'gtksizerequest.c',
@@ -633,6 +634,7 @@ gtk_public_headers = files([
   'gtkshortcutsshortcut.h',
   'gtkshortcutswindow.h',
   'gtkshow.h',
+  'gtksignallistitemfactory.h',
   'gtksingleselection.h',
   'gtksizegroup.h',
   'gtksizerequest.h',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]