listview: Add private GtkListFactoryWidget
authorBenjamin Otte <otte@redhat.com>
Mon, 20 Mar 2023 05:15:18 +0000 (06:15 +0100)
committerBenjamin Otte <otte@redhat.com>
Thu, 23 Mar 2023 03:45:03 +0000 (04:45 +0100)
This is a split of GtkListItemWidget into the generic parts of factory
using widgets.

On top of it there's GtkListItemWidget, which takes care of GtkListItem.

gtk/gtkcolumnlistitemfactory.c
gtk/gtkcolumnview.c
gtk/gtkdropdown.c
gtk/gtkgridview.c
gtk/gtklistfactorywidget.c [new file with mode: 0644]
gtk/gtklistfactorywidgetprivate.h [new file with mode: 0644]
gtk/gtklistitem.c
gtk/gtklistitemwidget.c
gtk/gtklistitemwidgetprivate.h
gtk/gtklistview.c
gtk/meson.build

index e60057ab10edfbd97d5762fa48d8e29618746c74..d36d911f1450689a9b2d49c6bfacbc6821021dc0 100644 (file)
@@ -119,7 +119,7 @@ gtk_column_list_item_factory_update (GtkListItemFactory *factory,
                                  gtk_list_item_get_item (list_item),
                                  gtk_list_item_get_selected (list_item));
 
-       cell_item = gtk_list_item_widget_get_list_item (GTK_LIST_ITEM_WIDGET (child));
+       cell_item = gtk_list_factory_widget_get_object (GTK_LIST_FACTORY_WIDGET (child));
        if (cell_item)
          {
            selectable &= gtk_list_item_get_selectable (cell_item);
index ff325f0a5b60b5dcb79262c149aeb16b9c16cdfd..ba1be8f42e548e70aab6a6b97fde4f57f5c3cc77 100644 (file)
@@ -146,7 +146,7 @@ gtk_column_list_view_create_list_widget (GtkListBase *base)
                                      "row",
                                      GTK_ACCESSIBLE_ROLE_ROW);
 
-  gtk_list_item_widget_set_single_click_activate (GTK_LIST_ITEM_WIDGET (result), self->single_click_activate);
+  gtk_list_factory_widget_set_single_click_activate (GTK_LIST_FACTORY_WIDGET (result), self->single_click_activate);
 
   return GTK_LIST_ITEM_BASE (result);
 }
index e0eea43d70090cadd06cdbdf717832b62c3372d5..3416bad72f09601694cf5c694ff6c3dab84f1440 100644 (file)
@@ -915,7 +915,7 @@ gtk_drop_down_set_factory (GtkDropDown        *self,
   if (!g_set_object (&self->factory, factory))
     return;
 
-  gtk_list_item_widget_set_factory (GTK_LIST_ITEM_WIDGET (self->button_item), factory);
+  gtk_list_factory_widget_set_factory (GTK_LIST_FACTORY_WIDGET (self->button_item), factory);
   if (self->list_factory == NULL)
     gtk_list_view_set_factory (GTK_LIST_VIEW (self->popup_list), factory);
 
index 991b76a5be296c68bd79446478f06ec3acce4b7e..2fcccb58d376877ac5861dbb5e0b245fecc98c9b 100644 (file)
@@ -268,7 +268,7 @@ gtk_grid_view_create_list_widget (GtkListBase *base)
                                      "child",
                                      GTK_ACCESSIBLE_ROLE_GRID_CELL);
 
-  gtk_list_item_widget_set_single_click_activate (GTK_LIST_ITEM_WIDGET (result), self->single_click_activate);
+  gtk_list_factory_widget_set_single_click_activate (GTK_LIST_FACTORY_WIDGET (result), self->single_click_activate);
 
   return GTK_LIST_ITEM_BASE (result);
 }
@@ -1230,7 +1230,7 @@ gtk_grid_view_set_factory (GtkGridView        *self,
        tile = gtk_rb_tree_node_get_next (tile))
     {
       if (tile->widget)
-        gtk_list_item_widget_set_factory (GTK_LIST_ITEM_WIDGET (tile->widget), factory);
+        gtk_list_factory_widget_set_factory (GTK_LIST_FACTORY_WIDGET (tile->widget), factory);
     }
 
 
@@ -1357,7 +1357,7 @@ gtk_grid_view_set_single_click_activate (GtkGridView *self,
        tile = gtk_rb_tree_node_get_next (tile))
     {
       if (tile->widget)
-        gtk_list_item_widget_set_single_click_activate (GTK_LIST_ITEM_WIDGET (tile->widget), single_click_activate);
+        gtk_list_factory_widget_set_single_click_activate (GTK_LIST_FACTORY_WIDGET (tile->widget), single_click_activate);
     }
 
 
diff --git a/gtk/gtklistfactorywidget.c b/gtk/gtklistfactorywidget.c
new file mode 100644 (file)
index 0000000..8e0197e
--- /dev/null
@@ -0,0 +1,643 @@
+/*
+ * Copyright © 2023 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 "gtklistfactorywidgetprivate.h"
+
+#include "gtkbinlayout.h"
+#include "gtkeventcontrollermotion.h"
+#include "gtkgestureclick.h"
+#include "gtklistitemfactoryprivate.h"
+#include "gtklistbaseprivate.h"
+#include "gtkwidget.h"
+
+typedef struct _GtkListFactoryWidgetPrivate GtkListFactoryWidgetPrivate;
+struct _GtkListFactoryWidgetPrivate
+{
+  GtkListItemFactory *factory;
+
+  gpointer object;
+  gboolean single_click_activate;
+  gboolean selectable;
+  gboolean activatable;
+};
+
+enum {
+  PROP_0,
+  PROP_ACTIVATABLE,
+  PROP_FACTORY,
+  PROP_SELECTABLE,
+  PROP_SINGLE_CLICK_ACTIVATE,
+
+  N_PROPS
+};
+
+enum
+{
+  ACTIVATE_SIGNAL,
+  LAST_SIGNAL
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GtkListFactoryWidget, gtk_list_factory_widget, GTK_TYPE_LIST_ITEM_BASE)
+
+static GParamSpec *properties[N_PROPS] = { NULL, };
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+gtk_list_factory_widget_activate_signal (GtkListFactoryWidget *self)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  if (priv->activatable)
+    return;
+
+  gtk_widget_activate_action (GTK_WIDGET (self),
+                              "list.activate-item",
+                              "u",
+                              gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)));
+}
+
+static gpointer
+gtk_list_factory_widget_default_create_object (GtkListFactoryWidget *self)
+{
+  g_assert_not_reached ();
+  return NULL;
+}
+
+static void
+gtk_list_factory_widget_default_setup_object (GtkListFactoryWidget *self,
+                                              gpointer              object)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  priv->object = object;
+}
+
+static void
+gtk_list_factory_widget_setup_func (gpointer object,
+                                    gpointer data)
+{
+  GTK_LIST_FACTORY_WIDGET_GET_CLASS (data)->setup_object (data, object);
+}
+
+static void
+gtk_list_factory_widget_setup_factory (GtkListFactoryWidget *self)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+  gpointer object;
+
+  object = GTK_LIST_FACTORY_WIDGET_GET_CLASS (self)->create_object (self);
+
+  gtk_list_item_factory_setup (priv->factory,
+                               object,
+                               gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
+                               gtk_list_factory_widget_setup_func,
+                               self);
+
+  g_assert (priv->object == object);
+}
+
+static void
+gtk_list_factory_widget_default_teardown_object (GtkListFactoryWidget *self,
+                                                 gpointer              object)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  priv->object = NULL;
+}
+
+static void
+gtk_list_factory_widget_teardown_func (gpointer object,
+                                       gpointer data)
+{
+  GTK_LIST_FACTORY_WIDGET_GET_CLASS (data)->teardown_object (data, object);
+}
+
+static void
+gtk_list_factory_widget_teardown_factory (GtkListFactoryWidget *self)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+  gpointer item = priv->object;
+
+  gtk_list_item_factory_teardown (priv->factory,
+                                  item,
+                                  gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
+                                  gtk_list_factory_widget_teardown_func,
+                                  self);
+
+  g_assert (priv->object == NULL);
+  g_object_unref (item);
+}
+
+static void
+gtk_list_factory_widget_default_update_object (GtkListFactoryWidget *self,
+                                               gpointer              object,
+                                               guint                 position,
+                                               gpointer              item,
+                                               gboolean              selected)
+{
+  GTK_LIST_ITEM_BASE_CLASS (gtk_list_factory_widget_parent_class)->update (GTK_LIST_ITEM_BASE (self),
+                                                                           position,
+                                                                           item,
+                                                                           selected);
+}
+
+typedef struct {
+  GtkListFactoryWidget *widget;
+  guint position;
+  gpointer item;
+  gboolean selected;
+} GtkListFactoryWidgetUpdate;
+
+static void
+gtk_list_factory_widget_update_func (gpointer object,
+                                     gpointer data)
+{
+  GtkListFactoryWidgetUpdate *update = data;
+
+  GTK_LIST_FACTORY_WIDGET_GET_CLASS (update->widget)->update_object (update->widget,
+                                                                     object,
+                                                                     update->position,
+                                                                     update->item,
+                                                                     update->selected);
+}
+
+static void
+gtk_list_factory_widget_update (GtkListItemBase *base,
+                                guint            position,
+                                gpointer         item,
+                                gboolean         selected)
+{
+  GtkListFactoryWidget *self = GTK_LIST_FACTORY_WIDGET (base);
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+  GtkListFactoryWidgetUpdate update = { self, position, item, selected };
+
+  if (priv->object)
+    {
+      gtk_list_item_factory_update (priv->factory,
+                                    priv->object,
+                                    gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
+                                    item != NULL,
+                                    gtk_list_factory_widget_update_func,
+                                    &update);
+    }
+  else
+    {
+      gtk_list_factory_widget_update_func (NULL, &update);
+    }
+}
+
+static void
+gtk_list_factory_widget_root (GtkWidget *widget)
+{
+  GtkListFactoryWidget *self = GTK_LIST_FACTORY_WIDGET (widget);
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  GTK_WIDGET_CLASS (gtk_list_factory_widget_parent_class)->root (widget);
+
+  if (priv->factory)
+    gtk_list_factory_widget_setup_factory (self);
+}
+
+static void
+gtk_list_factory_widget_unroot (GtkWidget *widget)
+{
+  GtkListFactoryWidget *self = GTK_LIST_FACTORY_WIDGET (widget);
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  GTK_WIDGET_CLASS (gtk_list_factory_widget_parent_class)->unroot (widget);
+
+  if (priv->object)
+    gtk_list_factory_widget_teardown_factory (self);
+}
+
+static void
+gtk_list_factory_widget_set_property (GObject      *object,
+                                      guint         property_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
+{
+  GtkListFactoryWidget *self = GTK_LIST_FACTORY_WIDGET (object);
+
+  switch (property_id)
+    {
+    case PROP_ACTIVATABLE:
+      gtk_list_factory_widget_set_activatable (self, g_value_get_boolean (value));
+      break;
+
+    case PROP_FACTORY:
+      gtk_list_factory_widget_set_factory (self, g_value_get_object (value));
+      break;
+
+    case PROP_SELECTABLE:
+      gtk_list_factory_widget_set_selectable (self, g_value_get_boolean (value));
+      break;
+
+    case PROP_SINGLE_CLICK_ACTIVATE:
+      gtk_list_factory_widget_set_single_click_activate (self, g_value_get_boolean (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_list_factory_widget_dispose (GObject *object)
+{
+  GtkListFactoryWidget *self = GTK_LIST_FACTORY_WIDGET (object);
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  g_assert (priv->object == NULL);
+
+  g_clear_object (&priv->factory);
+
+  G_OBJECT_CLASS (gtk_list_factory_widget_parent_class)->dispose (object);
+}
+
+static void
+gtk_list_factory_widget_select_action (GtkWidget  *widget,
+                                       const char *action_name,
+                                       GVariant   *parameter)
+{
+  GtkListFactoryWidget *self = GTK_LIST_FACTORY_WIDGET (widget);
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+  gboolean modify, extend;
+
+  if (!priv->selectable)
+    return;
+
+  g_variant_get (parameter, "(bb)", &modify, &extend);
+
+  gtk_widget_activate_action (GTK_WIDGET (self),
+                              "list.select-item",
+                              "(ubb)",
+                              gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)), modify, extend);
+}
+
+static void
+gtk_list_factory_widget_scroll_to_action (GtkWidget  *widget,
+                                          const char *action_name,
+                                          GVariant   *parameter)
+{
+  gtk_widget_activate_action (widget,
+                              "list.scroll-to-item",
+                              "u",
+                              gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (widget)));
+}
+
+static void
+gtk_list_factory_widget_class_init (GtkListFactoryWidgetClass *klass)
+{
+  GtkListItemBaseClass *base_class = GTK_LIST_ITEM_BASE_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  klass->activate_signal = gtk_list_factory_widget_activate_signal;
+  klass->create_object = gtk_list_factory_widget_default_create_object;
+  klass->setup_object = gtk_list_factory_widget_default_setup_object;
+  klass->update_object = gtk_list_factory_widget_default_update_object;
+  klass->teardown_object = gtk_list_factory_widget_default_teardown_object;
+
+  base_class->update = gtk_list_factory_widget_update;
+
+  widget_class->root = gtk_list_factory_widget_root;
+  widget_class->unroot = gtk_list_factory_widget_unroot;
+
+  gobject_class->set_property = gtk_list_factory_widget_set_property;
+  gobject_class->dispose = gtk_list_factory_widget_dispose;
+
+  properties[PROP_ACTIVATABLE] =
+    g_param_spec_boolean ("activatable", NULL, NULL,
+                          FALSE,
+                          G_PARAM_WRITABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_FACTORY] =
+    g_param_spec_object ("factory", NULL, NULL,
+                         GTK_TYPE_LIST_ITEM_FACTORY,
+                         G_PARAM_WRITABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_SELECTABLE] =
+    g_param_spec_boolean ("selectable", NULL, NULL,
+                          FALSE,
+                          G_PARAM_WRITABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_SINGLE_CLICK_ACTIVATE] =
+    g_param_spec_boolean ("single-click-activate", NULL, NULL,
+                          FALSE,
+                          G_PARAM_WRITABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class, N_PROPS, properties);
+
+  signals[ACTIVATE_SIGNAL] =
+    g_signal_new (I_("activate-keybinding"),
+                  G_OBJECT_CLASS_TYPE (gobject_class),
+                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (GtkListFactoryWidgetClass, activate_signal),
+                  NULL, NULL,
+                  NULL,
+                  G_TYPE_NONE, 0);
+
+  gtk_widget_class_set_activate_signal (widget_class, signals[ACTIVATE_SIGNAL]);
+
+  /**
+   * GtkListItem|listitem.select:
+   * @modify: %TRUE to toggle the existing selection, %FALSE to select
+   * @extend: %TRUE to extend the selection
+   *
+   * Changes selection if the item is selectable.
+   * If the item is not selectable, nothing happens.
+   *
+   * This function will emit the list.select-item action and the resulting
+   * behavior, in particular the interpretation of @modify and @extend
+   * depends on the view containing this listitem. See for example
+   * GtkListView|list.select-item or GtkGridView|list.select-item.
+   */
+  gtk_widget_class_install_action (widget_class,
+                                   "listitem.select",
+                                   "(bb)",
+                                   gtk_list_factory_widget_select_action);
+
+  /**
+   * GtkListItem|listitem.scroll-to:
+   *
+   * Moves the visible area of the list to this item with the minimum amount
+   * of scrolling required. If the item is already visible, nothing happens.
+   */
+  gtk_widget_class_install_action (widget_class,
+                                   "listitem.scroll-to",
+                                   NULL,
+                                   gtk_list_factory_widget_scroll_to_action);
+
+  gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Return, 0,
+                                       "activate-keybinding", 0);
+  gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_ISO_Enter, 0,
+                                       "activate-keybinding", 0);
+  gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Enter, 0,
+                                       "activate-keybinding", 0);
+
+  /* note that some of these may get overwritten by child widgets,
+   * such as GtkTreeExpander */
+  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, 0,
+                                       "listitem.select", "(bb)", TRUE, FALSE);
+  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, GDK_CONTROL_MASK,
+                                       "listitem.select", "(bb)", TRUE, FALSE);
+  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, GDK_SHIFT_MASK,
+                                       "listitem.select", "(bb)", TRUE, FALSE);
+  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
+                                       "listitem.select", "(bb)", TRUE, FALSE);
+  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, 0,
+                                       "listitem.select", "(bb)", TRUE, FALSE);
+  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, GDK_CONTROL_MASK,
+                                       "listitem.select", "(bb)", TRUE, FALSE);
+  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, GDK_SHIFT_MASK,
+                                       "listitem.select", "(bb)", TRUE, FALSE);
+  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
+                                       "listitem.select", "(bb)", TRUE, FALSE);
+
+  /* This gets overwritten by gtk_list_factory_widget_new() but better safe than sorry */
+  gtk_widget_class_set_css_name (widget_class, I_("row"));
+}
+
+static void
+gtk_list_factory_widget_click_gesture_pressed (GtkGestureClick      *gesture,
+                                               int                   n_press,
+                                               double                x,
+                                               double                y,
+                                               GtkListFactoryWidget *self)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+  GtkWidget *widget = GTK_WIDGET (self);
+
+  if (!priv->selectable && !priv->activatable)
+    {
+      gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
+      return;
+    }
+
+  if (priv->activatable)
+    {
+      if (n_press == 2 && !priv->single_click_activate)
+        {
+          gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+          gtk_widget_activate_action (GTK_WIDGET (self),
+                                      "list.activate-item",
+                                      "u",
+                                      gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)));
+        }
+    }
+
+  if (gtk_widget_get_focus_on_click (widget))
+    gtk_widget_grab_focus (widget);
+}
+
+static void
+gtk_list_factory_widget_click_gesture_released (GtkGestureClick      *gesture,
+                                                int                   n_press,
+                                                double                x,
+                                                double                y,
+                                                GtkListFactoryWidget *self)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  if (priv->activatable)
+    {
+      if (n_press == 1 && priv->single_click_activate)
+        {
+          gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+          gtk_widget_activate_action (GTK_WIDGET (self),
+                                      "list.activate-item",
+                                      "u",
+                                      gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)));
+          return;
+        }
+    }
+
+  if (priv->selectable)
+    {
+      GdkModifierType state;
+      GdkEvent *event;
+      gboolean extend, modify;
+
+      event = gtk_gesture_get_last_event (GTK_GESTURE (gesture),
+                                          gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture)));
+      state = gdk_event_get_modifier_state (event);
+      extend = (state & GDK_SHIFT_MASK) != 0;
+      modify = (state & GDK_CONTROL_MASK) != 0;
+
+      gtk_widget_activate_action (GTK_WIDGET (self),
+                                  "list.select-item",
+                                  "(ubb)",
+                                  gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)), modify, extend);
+    }
+}
+
+static void
+gtk_list_factory_widget_hover_cb (GtkEventControllerMotion *controller,
+                                  double                    x,
+                                  double                    y,
+                                  GtkListFactoryWidget     *self)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  if (!priv->single_click_activate)
+    return;
+
+  if (priv->selectable)
+    {
+      gtk_widget_activate_action (GTK_WIDGET (self),
+                                  "list.select-item",
+                                  "(ubb)",
+                                  gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)), FALSE, FALSE);
+    }
+}
+
+static void
+gtk_list_factory_widget_init (GtkListFactoryWidget *self)
+{
+  GtkEventController *controller;
+  GtkGesture *gesture;
+
+  gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
+
+  gesture = gtk_gesture_click_new ();
+  gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture),
+                                              GTK_PHASE_BUBBLE);
+  gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture),
+                                     FALSE);
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture),
+                                 GDK_BUTTON_PRIMARY);
+  g_signal_connect (gesture, "pressed",
+                    G_CALLBACK (gtk_list_factory_widget_click_gesture_pressed), self);
+  g_signal_connect (gesture, "released",
+                    G_CALLBACK (gtk_list_factory_widget_click_gesture_released), self);
+  gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
+
+  controller = gtk_event_controller_motion_new ();
+  g_signal_connect (controller, "enter", G_CALLBACK (gtk_list_factory_widget_hover_cb), self);
+  gtk_widget_add_controller (GTK_WIDGET (self), controller);
+}
+
+gpointer
+gtk_list_factory_widget_get_object (GtkListFactoryWidget *self)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  return priv->object;
+}
+
+void
+gtk_list_factory_widget_set_factory (GtkListFactoryWidget *self,
+                                     GtkListItemFactory   *factory)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  if (priv->factory == factory)
+    return;
+
+  if (priv->factory)
+    {
+      if (priv->object)
+        gtk_list_factory_widget_teardown_factory (self);
+      g_clear_object (&priv->factory);
+    }
+
+  if (factory)
+    {
+      priv->factory = g_object_ref (factory);
+
+      if (gtk_widget_get_root (GTK_WIDGET (self)))
+        gtk_list_factory_widget_setup_factory (self);
+    }
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FACTORY]);
+}
+
+void
+gtk_list_factory_widget_set_single_click_activate (GtkListFactoryWidget *self,
+                                                   gboolean              single_click_activate)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  if (priv->single_click_activate == single_click_activate)
+    return;
+
+  priv->single_click_activate = single_click_activate;
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SINGLE_CLICK_ACTIVATE]);
+}
+
+gboolean
+gtk_list_factory_widget_get_single_click_activate (GtkListFactoryWidget *self)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  return priv->single_click_activate;
+}
+
+void
+gtk_list_factory_widget_set_activatable (GtkListFactoryWidget *self,
+                                         gboolean              activatable)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  if (priv->activatable == activatable)
+    return;
+
+  priv->activatable = activatable;
+
+  if (activatable)
+    gtk_widget_add_css_class (GTK_WIDGET (self), "activatable");
+  else
+    gtk_widget_remove_css_class (GTK_WIDGET (self), "activatable");
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SINGLE_CLICK_ACTIVATE]);
+}
+
+gboolean
+gtk_list_factory_widget_get_activatable (GtkListFactoryWidget *self)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  return priv->activatable;
+}
+
+void
+gtk_list_factory_widget_set_selectable (GtkListFactoryWidget *self,
+                                        gboolean              selectable)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  if (priv->selectable == selectable)
+    return;
+
+  priv->selectable = selectable;
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SINGLE_CLICK_ACTIVATE]);
+}
+
+gboolean
+gtk_list_factory_widget_get_selectable (GtkListFactoryWidget *self)
+{
+  GtkListFactoryWidgetPrivate *priv = gtk_list_factory_widget_get_instance_private (self);
+
+  return priv->selectable;
+}
diff --git a/gtk/gtklistfactorywidgetprivate.h b/gtk/gtklistfactorywidgetprivate.h
new file mode 100644 (file)
index 0000000..ee01a64
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright © 2023 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_LIST_FACTORY_WIDGET_PRIVATE_H__
+#define __GTK_LIST_FACTORY_WIDGET_PRIVATE_H__
+
+#include "gtklistitembaseprivate.h"
+
+#include "gtklistitemfactory.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_LIST_FACTORY_WIDGET         (gtk_list_factory_widget_get_type ())
+#define GTK_LIST_FACTORY_WIDGET(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_LIST_FACTORY_WIDGET, GtkListFactoryWidget))
+#define GTK_LIST_FACTORY_WIDGET_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_LIST_FACTORY_WIDGET, GtkListFactoryWidgetClass))
+#define GTK_IS_LIST_FACTORY_WIDGET(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_LIST_FACTORY_WIDGET))
+#define GTK_IS_LIST_FACTORY_WIDGET_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_LIST_FACTORY_WIDGET))
+#define GTK_LIST_FACTORY_WIDGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_LIST_FACTORY_WIDGET, GtkListFactoryWidgetClass))
+
+typedef struct _GtkListFactoryWidget GtkListFactoryWidget;
+typedef struct _GtkListFactoryWidgetClass GtkListFactoryWidgetClass;
+
+struct _GtkListFactoryWidget
+{
+  GtkListItemBase parent_instance;
+};
+
+struct _GtkListFactoryWidgetClass
+{
+  GtkListItemBaseClass parent_class;
+
+  void          (* activate_signal)                             (GtkListFactoryWidget         *self);
+
+  gpointer      (* create_object)                               (GtkListFactoryWidget         *self);
+  void          (* setup_object)                                (GtkListFactoryWidget         *self,
+                                                                 gpointer                      object);
+  void          (* update_object)                               (GtkListFactoryWidget         *self,
+                                                                 gpointer                      object,
+                                                                 guint                         position,
+                                                                 gpointer                      item,
+                                                                 gboolean                      selected);
+  void          (* teardown_object)                             (GtkListFactoryWidget         *self,
+                                                                 gpointer                      object);
+};
+
+GType                   gtk_list_factory_widget_get_type        (void) G_GNUC_CONST;
+
+gpointer                gtk_list_factory_widget_get_object      (GtkListFactoryWidget   *self);
+
+void                    gtk_list_factory_widget_set_factory     (GtkListFactoryWidget   *self,
+                                                                 GtkListItemFactory     *factory);
+GtkListItemFactory *    gtk_list_factory_widget_get_factory     (GtkListFactoryWidget   *self);
+
+void                    gtk_list_factory_widget_set_single_click_activate
+                                                                (GtkListFactoryWidget   *self,
+                                                                 gboolean                single_click_activate);
+gboolean                gtk_list_factory_widget_get_single_click_activate
+                                                                (GtkListFactoryWidget   *self);
+
+void                    gtk_list_factory_widget_set_activatable (GtkListFactoryWidget   *self,
+                                                                 gboolean                activatable);
+gboolean                gtk_list_factory_widget_get_activatable (GtkListFactoryWidget   *self);
+
+void                    gtk_list_factory_widget_set_selectable  (GtkListFactoryWidget   *self,
+                                                                 gboolean                activatable);
+gboolean                gtk_list_factory_widget_get_selectable  (GtkListFactoryWidget   *self);
+
+G_END_DECLS
+
+#endif  /* __GTK_LIST_FACTORY_WIDGET_PRIVATE_H__ */
index 837784bd479a0793a0c32b3cf79db619d5dbce96..3bea81c5dfad814cbaccab90c9a922bd67bdfcae 100644 (file)
@@ -417,6 +417,9 @@ gtk_list_item_set_selectable (GtkListItem *self,
 
   self->selectable = selectable;
 
+  if (self->owner)
+    gtk_list_factory_widget_set_selectable (GTK_LIST_FACTORY_WIDGET (self->owner), selectable);
+
   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTABLE]);
 }
 
@@ -464,7 +467,7 @@ gtk_list_item_set_activatable (GtkListItem *self,
   self->activatable = activatable;
 
   if (self->owner)
-    gtk_list_item_widget_set_activatable (self->owner, activatable);
+    gtk_list_factory_widget_set_activatable (GTK_LIST_FACTORY_WIDGET (self->owner), activatable);
 
   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIVATABLE]);
 }
index 5b770bf0305f41dfde75b64973c8a3da52864594..31489b4f81f5d564563e63e6da6a23e3284600e0 100644 (file)
 #include "gtkwidget.h"
 #include "gtkwidgetprivate.h"
 
-typedef struct _GtkListItemWidgetPrivate GtkListItemWidgetPrivate;
-struct _GtkListItemWidgetPrivate
-{
-  GtkListItemFactory *factory;
-  GtkListItem *list_item;
-
-  gboolean single_click_activate;
-};
-
-enum {
-  PROP_0,
-  PROP_FACTORY,
-  PROP_SINGLE_CLICK_ACTIVATE,
-
-  N_PROPS
-};
-
-enum
-{
-  ACTIVATE_SIGNAL,
-  LAST_SIGNAL
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (GtkListItemWidget, gtk_list_item_widget, GTK_TYPE_LIST_ITEM_BASE)
-
-static GParamSpec *properties[N_PROPS] = { NULL, };
-static guint signals[LAST_SIGNAL] = { 0 };
-
-static void
-gtk_list_item_widget_activate_signal (GtkListItemWidget *self)
-{
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-
-  if (priv->list_item && !priv->list_item->activatable)
-    return;
-
-  gtk_widget_activate_action (GTK_WIDGET (self),
-                              "list.activate-item",
-                              "u",
-                              gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)));
-}
+G_DEFINE_TYPE (GtkListItemWidget, gtk_list_item_widget, GTK_TYPE_LIST_FACTORY_WIDGET)
 
 static gboolean
 gtk_list_item_widget_focus (GtkWidget        *widget,
@@ -117,7 +77,6 @@ static gboolean
 gtk_list_item_widget_grab_focus (GtkWidget *widget)
 {
   GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (widget);
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
   GtkWidget *child;
 
   for (child = gtk_widget_get_first_child (widget);
@@ -128,28 +87,34 @@ gtk_list_item_widget_grab_focus (GtkWidget *widget)
         return TRUE;
     }
 
-  if (priv->list_item == NULL ||
-      !priv->list_item->selectable)
+  if (!gtk_list_factory_widget_get_selectable (GTK_LIST_FACTORY_WIDGET (self)))
     return FALSE;
 
   return GTK_WIDGET_CLASS (gtk_list_item_widget_parent_class)->grab_focus (widget);
 }
 
+static gpointer
+gtk_list_item_widget_create_object (GtkListFactoryWidget *fw)
+{
+  return gtk_list_item_new ();
+}
+
 static void
-gtk_list_item_widget_setup_func (gpointer object,
-                                 gpointer data)
+gtk_list_item_widget_setup_object (GtkListFactoryWidget *fw,
+                                   gpointer              object)
 {
-  GtkListItemWidget *self = data;
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
+  GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (fw);
   GtkListItem *list_item = object;
 
-  priv->list_item = list_item;
+  GTK_LIST_FACTORY_WIDGET_CLASS (gtk_list_item_widget_parent_class)->setup_object (fw, object);
+
   list_item->owner = self;
 
   if (list_item->child)
     gtk_list_item_widget_add_child (self, list_item->child);
 
-  gtk_list_item_widget_set_activatable (self, list_item->activatable);
+  gtk_list_factory_widget_set_activatable (fw, list_item->activatable);
+  gtk_list_factory_widget_set_selectable (fw, list_item->selectable);
 
   gtk_list_item_do_notify (list_item,
                            gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
@@ -158,432 +123,82 @@ gtk_list_item_widget_setup_func (gpointer object,
 }
 
 static void
-gtk_list_item_widget_setup_factory (GtkListItemWidget *self)
-{
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-  GtkListItem *list_item;
-
-  list_item = gtk_list_item_new ();
-
-  gtk_list_item_factory_setup (priv->factory,
-                               G_OBJECT (list_item),
-                               gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
-                               gtk_list_item_widget_setup_func,
-                               self);
-
-  g_assert (priv->list_item == list_item);
-}
-
-static void
-gtk_list_item_widget_teardown_func (gpointer object,
-                                    gpointer data)
+gtk_list_item_widget_teardown_object (GtkListFactoryWidget *fw,
+                                      gpointer              object)
 {
-  GtkListItemWidget *self = data;
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
+  GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (fw);
   GtkListItem *list_item = object;
 
-  g_assert (priv->list_item == list_item);
+  GTK_LIST_FACTORY_WIDGET_CLASS (gtk_list_item_widget_parent_class)->teardown_object (fw, object);
 
-  priv->list_item = NULL;
   list_item->owner = NULL;
 
   if (list_item->child)
     gtk_list_item_widget_remove_child (self, list_item->child);
 
-  gtk_list_item_widget_set_activatable (self, FALSE);
+  gtk_list_factory_widget_set_activatable (fw, FALSE);
+  gtk_list_factory_widget_set_selectable (fw, FALSE);
 
   gtk_list_item_do_notify (list_item,
                            gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
                            gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)) != GTK_INVALID_LIST_POSITION,
                            gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self)));
 
+  /* FIXME: This is technically not correct, the child is user code, isn't it? */
   gtk_list_item_set_child (list_item, NULL);
 }
 
 static void
-gtk_list_item_widget_teardown_factory (GtkListItemWidget *self)
-{
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-  GtkListItem *list_item = priv->list_item;
-
-  gtk_list_item_factory_teardown (priv->factory,
-                                  G_OBJECT (list_item),
-                                  gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
-                                  gtk_list_item_widget_teardown_func,
-                                  self);
-
-  g_assert (priv->list_item == NULL);
-  g_object_unref (list_item);
-}
-
-typedef struct {
-  GtkListItemWidget *widget;
-  guint position;
-  gpointer item;
-  gboolean selected;
-} GtkListItemWidgetUpdate;
-
-static void
-gtk_list_item_widget_update_func (gpointer object,
-                                  gpointer data)
+gtk_list_item_widget_update_object (GtkListFactoryWidget *fw,
+                                    gpointer              object,
+                                    guint                 position,
+                                    gpointer              item,
+                                    gboolean              selected)
 {
-  GtkListItemWidgetUpdate *update = data;
+  GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (fw);
+  GtkListItemBase *base = GTK_LIST_ITEM_BASE (self);
   GtkListItem *list_item = object;
   /* Track notify manually instead of freeze/thaw_notify for performance reasons. */
   gboolean notify_item = FALSE, notify_position = FALSE, notify_selected = FALSE;
-  GtkListItemWidget *self = update->widget;
-  GtkListItemBase *base = GTK_LIST_ITEM_BASE (self);
 
   /* FIXME: It's kinda evil to notify external objects from here... */
-  notify_item = gtk_list_item_base_get_item (base) != update->item;
-  notify_position = gtk_list_item_base_get_position (base) != update->position;
-  notify_selected = gtk_list_item_base_get_selected (base) != update->selected;
-
-  GTK_LIST_ITEM_BASE_CLASS (gtk_list_item_widget_parent_class)->update (base,
-                                                                        update->position,
-                                                                        update->item,
-                                                                        update->selected);
-  if (list_item)
-    gtk_list_item_do_notify (list_item, notify_item, notify_position, notify_selected);
-}
-
-static void
-gtk_list_item_widget_update (GtkListItemBase *base,
-                             guint            position,
-                             gpointer         item,
-                             gboolean         selected)
-{
-  GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (base);
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-  GtkListItemWidgetUpdate update = { self, position, item, selected };
-
-  if (priv->list_item)
-    {
-      gtk_list_item_factory_update (priv->factory,
-                                    G_OBJECT (priv->list_item),
-                                    gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
-                                    item != NULL,
-                                    gtk_list_item_widget_update_func,
-                                    &update);
-    }
-  else
-    {
-      gtk_list_item_widget_update_func (NULL, &update);
-    }
-}
-
-static void
-gtk_list_item_widget_root (GtkWidget *widget)
-{
-  GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (widget);
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-
-  GTK_WIDGET_CLASS (gtk_list_item_widget_parent_class)->root (widget);
-
-  if (priv->factory)
-    gtk_list_item_widget_setup_factory (self);
-}
-
-static void
-gtk_list_item_widget_unroot (GtkWidget *widget)
-{
-  GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (widget);
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-
-  GTK_WIDGET_CLASS (gtk_list_item_widget_parent_class)->unroot (widget);
-
-  if (priv->list_item)
-    gtk_list_item_widget_teardown_factory (self);
-}
-
-static void
-gtk_list_item_widget_set_property (GObject      *object,
-                                   guint         property_id,
-                                   const GValue *value,
-                                   GParamSpec   *pspec)
-{
-  GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (object);
-
-  switch (property_id)
-    {
-    case PROP_FACTORY:
-      gtk_list_item_widget_set_factory (self, g_value_get_object (value));
-      break;
-
-    case PROP_SINGLE_CLICK_ACTIVATE:
-      gtk_list_item_widget_set_single_click_activate (self, g_value_get_boolean (value));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_list_item_widget_dispose (GObject *object)
-{
-  GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (object);
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-
-  g_assert (priv->list_item == NULL);
-
-  g_clear_object (&priv->factory);
-
-  G_OBJECT_CLASS (gtk_list_item_widget_parent_class)->dispose (object);
-}
-
-static void
-gtk_list_item_widget_select_action (GtkWidget  *widget,
-                                    const char *action_name,
-                                    GVariant   *parameter)
-{
-  GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (widget);
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-  gboolean modify, extend;
-
-  if (priv->list_item && !priv->list_item->selectable)
-    return;
+  notify_item = gtk_list_item_base_get_item (base) != item;
+  notify_position = gtk_list_item_base_get_position (base) != position;
+  notify_selected = gtk_list_item_base_get_selected (base) != selected;
 
-  g_variant_get (parameter, "(bb)", &modify, &extend);
+  GTK_LIST_FACTORY_WIDGET_CLASS (gtk_list_item_widget_parent_class)->update_object (fw,
+                                                                                    object,
+                                                                                    position,
+                                                                                    item,
+                                                                                    selected);
 
-  gtk_widget_activate_action (GTK_WIDGET (self),
-                              "list.select-item",
-                              "(ubb)",
-                              gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)), modify, extend);
-}
-
-static void
-gtk_list_item_widget_scroll_to_action (GtkWidget  *widget,
-                                       const char *action_name,
-                                       GVariant   *parameter)
-{
-  gtk_widget_activate_action (widget,
-                              "list.scroll-to-item",
-                              "u",
-                              gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (widget)));
+  if (list_item)
+    gtk_list_item_do_notify (list_item, notify_item, notify_position, notify_selected);
 }
 
 static void
 gtk_list_item_widget_class_init (GtkListItemWidgetClass *klass)
 {
-  GtkListItemBaseClass *base_class = GTK_LIST_ITEM_BASE_CLASS (klass);
+  GtkListFactoryWidgetClass *factory_class = GTK_LIST_FACTORY_WIDGET_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
-  klass->activate_signal = gtk_list_item_widget_activate_signal;
-
-  base_class->update = gtk_list_item_widget_update;
+  factory_class->create_object = gtk_list_item_widget_create_object;
+  factory_class->setup_object = gtk_list_item_widget_setup_object;
+  factory_class->update_object = gtk_list_item_widget_update_object;
+  factory_class->teardown_object = gtk_list_item_widget_teardown_object;
 
   widget_class->focus = gtk_list_item_widget_focus;
   widget_class->grab_focus = gtk_list_item_widget_grab_focus;
-  widget_class->root = gtk_list_item_widget_root;
-  widget_class->unroot = gtk_list_item_widget_unroot;
-
-  gobject_class->set_property = gtk_list_item_widget_set_property;
-  gobject_class->dispose = gtk_list_item_widget_dispose;
-
-  properties[PROP_FACTORY] =
-    g_param_spec_object ("factory", NULL, NULL,
-                         GTK_TYPE_LIST_ITEM_FACTORY,
-                         G_PARAM_WRITABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
-
-  properties[PROP_SINGLE_CLICK_ACTIVATE] =
-    g_param_spec_boolean ("single-click-activate", NULL, NULL,
-                          FALSE,
-                          G_PARAM_WRITABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
-
-  g_object_class_install_properties (gobject_class, N_PROPS, properties);
-
-  signals[ACTIVATE_SIGNAL] =
-    g_signal_new (I_("activate-keybinding"),
-                  G_OBJECT_CLASS_TYPE (gobject_class),
-                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
-                  G_STRUCT_OFFSET (GtkListItemWidgetClass, activate_signal),
-                  NULL, NULL,
-                  NULL,
-                  G_TYPE_NONE, 0);
-
-  gtk_widget_class_set_activate_signal (widget_class, signals[ACTIVATE_SIGNAL]);
-
-  /**
-   * GtkListItem|listitem.select:
-   * @modify: %TRUE to toggle the existing selection, %FALSE to select
-   * @extend: %TRUE to extend the selection
-   *
-   * Changes selection if the item is selectable.
-   * If the item is not selectable, nothing happens.
-   *
-   * This function will emit the list.select-item action and the resulting
-   * behavior, in particular the interpretation of @modify and @extend
-   * depends on the view containing this listitem. See for example
-   * GtkListView|list.select-item or GtkGridView|list.select-item.
-   */
-  gtk_widget_class_install_action (widget_class,
-                                   "listitem.select",
-                                   "(bb)",
-                                   gtk_list_item_widget_select_action);
-
-  /**
-   * GtkListItem|listitem.scroll-to:
-   *
-   * Moves the visible area of the list to this item with the minimum amount
-   * of scrolling required. If the item is already visible, nothing happens.
-   */
-  gtk_widget_class_install_action (widget_class,
-                                   "listitem.scroll-to",
-                                   NULL,
-                                   gtk_list_item_widget_scroll_to_action);
-
-  gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Return, 0,
-                                       "activate-keybinding", 0);
-  gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_ISO_Enter, 0,
-                                       "activate-keybinding", 0);
-  gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Enter, 0,
-                                       "activate-keybinding", 0);
-
-  /* note that some of these may get overwritten by child widgets,
-   * such as GtkTreeExpander */
-  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, 0,
-                                       "listitem.select", "(bb)", TRUE, FALSE);
-  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, GDK_CONTROL_MASK,
-                                       "listitem.select", "(bb)", TRUE, FALSE);
-  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, GDK_SHIFT_MASK,
-                                       "listitem.select", "(bb)", TRUE, FALSE);
-  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
-                                       "listitem.select", "(bb)", TRUE, FALSE);
-  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, 0,
-                                       "listitem.select", "(bb)", TRUE, FALSE);
-  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, GDK_CONTROL_MASK,
-                                       "listitem.select", "(bb)", TRUE, FALSE);
-  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, GDK_SHIFT_MASK,
-                                       "listitem.select", "(bb)", TRUE, FALSE);
-  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
-                                       "listitem.select", "(bb)", TRUE, FALSE);
 
   /* This gets overwritten by gtk_list_item_widget_new() but better safe than sorry */
   gtk_widget_class_set_css_name (widget_class, I_("row"));
   gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
 }
 
-static void
-gtk_list_item_widget_click_gesture_pressed (GtkGestureClick   *gesture,
-                                            int                n_press,
-                                            double             x,
-                                            double             y,
-                                            GtkListItemWidget *self)
-{
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-  GtkWidget *widget = GTK_WIDGET (self);
-
-  if (priv->list_item && !priv->list_item->selectable && !priv->list_item->activatable)
-    {
-      gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
-      return;
-    }
-
-  if (!priv->list_item || priv->list_item->activatable)
-    {
-      if (n_press == 2 && !priv->single_click_activate)
-        {
-          gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
-          gtk_widget_activate_action (GTK_WIDGET (self),
-                                      "list.activate-item",
-                                      "u",
-                                      gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)));
-        }
-    }
-
-  if (gtk_widget_get_focus_on_click (widget))
-    gtk_widget_grab_focus (widget);
-}
-
-static void
-gtk_list_item_widget_click_gesture_released (GtkGestureClick   *gesture,
-                                             int                n_press,
-                                             double             x,
-                                             double             y,
-                                             GtkListItemWidget *self)
-{
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-
-  if (!priv->list_item || priv->list_item->activatable)
-    {
-      if (n_press == 1 && priv->single_click_activate)
-        {
-          gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
-          gtk_widget_activate_action (GTK_WIDGET (self),
-                                      "list.activate-item",
-                                      "u",
-                                      gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)));
-          return;
-        }
-    }
-
-  if (!priv->list_item || priv->list_item->selectable)
-    {
-      GdkModifierType state;
-      GdkEvent *event;
-      gboolean extend, modify;
-
-      event = gtk_gesture_get_last_event (GTK_GESTURE (gesture),
-                                          gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture)));
-      state = gdk_event_get_modifier_state (event);
-      extend = (state & GDK_SHIFT_MASK) != 0;
-      modify = (state & GDK_CONTROL_MASK) != 0;
-
-      gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
-      gtk_widget_activate_action (GTK_WIDGET (self),
-                                  "list.select-item",
-                                  "(ubb)",
-                                  gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)), modify, extend);
-    }
-}
-
-static void
-gtk_list_item_widget_hover_cb (GtkEventControllerMotion *controller,
-                               double                    x,
-                               double                    y,
-                               GtkListItemWidget        *self)
-{
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-
-  if (!priv->single_click_activate)
-    return;
-
-  if (!priv->list_item || priv->list_item->selectable)
-    {
-      gtk_widget_activate_action (GTK_WIDGET (self),
-                                  "list.select-item",
-                                  "(ubb)",
-                                  gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)), FALSE, FALSE);
-    }
-}
-
 static void
 gtk_list_item_widget_init (GtkListItemWidget *self)
 {
-  GtkEventController *controller;
-  GtkGesture *gesture;
-
   gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
-
-  gesture = gtk_gesture_click_new ();
-  gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture),
-                                              GTK_PHASE_BUBBLE);
-  gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture),
-                                     FALSE);
-  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture),
-                                 GDK_BUTTON_PRIMARY);
-  g_signal_connect (gesture, "pressed",
-                    G_CALLBACK (gtk_list_item_widget_click_gesture_pressed), self);
-  g_signal_connect (gesture, "released",
-                    G_CALLBACK (gtk_list_item_widget_click_gesture_released), self);
-  gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
-
-  controller = gtk_event_controller_motion_new ();
-  g_signal_connect (controller, "enter", G_CALLBACK (gtk_list_item_widget_hover_cb), self);
-  gtk_widget_add_controller (GTK_WIDGET (self), controller);
 }
 
 GtkWidget *
@@ -600,57 +215,6 @@ gtk_list_item_widget_new (GtkListItemFactory *factory,
                        NULL);
 }
 
-void
-gtk_list_item_widget_set_factory (GtkListItemWidget  *self,
-                                  GtkListItemFactory *factory)
-{
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-
-  if (priv->factory == factory)
-    return;
-
-  if (priv->factory)
-    {
-      if (priv->list_item)
-        gtk_list_item_widget_teardown_factory (self);
-      g_clear_object (&priv->factory);
-    }
-
-  if (factory)
-    {
-      priv->factory = g_object_ref (factory);
-
-      if (gtk_widget_get_root (GTK_WIDGET (self)))
-        gtk_list_item_widget_setup_factory (self);
-    }
-
-  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FACTORY]);
-}
-
-void
-gtk_list_item_widget_set_single_click_activate (GtkListItemWidget *self,
-                                                gboolean           single_click_activate)
-{
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-
-  if (priv->single_click_activate == single_click_activate)
-    return;
-
-  priv->single_click_activate = single_click_activate;
-
-  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SINGLE_CLICK_ACTIVATE]);
-}
-
-void
-gtk_list_item_widget_set_activatable (GtkListItemWidget *self,
-                                      gboolean           activatable)
-{
-  if (activatable)
-    gtk_widget_add_css_class (GTK_WIDGET (self), "activatable");
-  else
-    gtk_widget_remove_css_class (GTK_WIDGET (self), "activatable");
-}
-
 void
 gtk_list_item_widget_add_child (GtkListItemWidget *self,
                                 GtkWidget         *child)
@@ -694,11 +258,3 @@ gtk_list_item_widget_remove_child (GtkListItemWidget *self,
   gtk_widget_unparent (child);
 }
 
-GtkListItem *
-gtk_list_item_widget_get_list_item (GtkListItemWidget *self)
-{
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-
-  return priv->list_item;
-}
-
index 5345419a193e9c16a7a54732edee6d949ecd260c..154eb2cbd20453919ba1f75c5d49d2c0fd348a41 100644 (file)
@@ -20,9 +20,7 @@
 #ifndef __GTK_LIST_ITEM_WIDGET_PRIVATE_H__
 #define __GTK_LIST_ITEM_WIDGET_PRIVATE_H__
 
-#include "gtklistitembaseprivate.h"
-
-#include "gtklistitemfactory.h"
+#include "gtklistfactorywidgetprivate.h"
 
 G_BEGIN_DECLS
 
@@ -38,14 +36,12 @@ typedef struct _GtkListItemWidgetClass GtkListItemWidgetClass;
 
 struct _GtkListItemWidget
 {
-  GtkListItemBase parent_instance;
+  GtkListFactoryWidget parent_instance;
 };
 
 struct _GtkListItemWidgetClass
 {
-  GtkListItemBaseClass parent_class;
-
-  void          (* activate_signal)                             (GtkListItemWidget            *self);
+  GtkListFactoryWidgetClass parent_class;
 };
 
 GType                   gtk_list_item_widget_get_type           (void) G_GNUC_CONST;
@@ -54,15 +50,6 @@ GtkWidget *             gtk_list_item_widget_new                (GtkListItemFact
                                                                  const char             *css_name,
                                                                  GtkAccessibleRole       role);
 
-GtkListItem *           gtk_list_item_widget_get_list_item      (GtkListItemWidget      *self);
-
-void                    gtk_list_item_widget_set_factory        (GtkListItemWidget      *self,
-                                                                 GtkListItemFactory     *factory);
-void                    gtk_list_item_widget_set_single_click_activate
-                                                                (GtkListItemWidget     *self,
-                                                                 gboolean               single_click_activate);
-void                    gtk_list_item_widget_set_activatable    (GtkListItemWidget     *self,
-                                                                 gboolean               activatable);
 void                    gtk_list_item_widget_add_child          (GtkListItemWidget      *self,
                                                                  GtkWidget              *child);
 void                    gtk_list_item_widget_reorder_child      (GtkListItemWidget      *self,
index eff45468f9778f921888e1d9e030194fb3256976..3e0f277b607ea23612205da97588ba216f9998f2 100644 (file)
@@ -226,7 +226,7 @@ gtk_list_view_create_list_widget (GtkListBase *base)
                                      "row",
                                      GTK_ACCESSIBLE_ROLE_LIST_ITEM);
 
-  gtk_list_item_widget_set_single_click_activate (GTK_LIST_ITEM_WIDGET (result), self->single_click_activate);
+  gtk_list_factory_widget_set_single_click_activate (GTK_LIST_FACTORY_WIDGET (result), self->single_click_activate);
 
   return GTK_LIST_ITEM_BASE (result);
 }
@@ -954,7 +954,7 @@ gtk_list_view_set_factory (GtkListView        *self,
        tile = gtk_rb_tree_node_get_next (tile))
     {
       if (tile->widget)
-        gtk_list_item_widget_set_factory (GTK_LIST_ITEM_WIDGET (tile->widget), factory);
+        gtk_list_factory_widget_set_factory (GTK_LIST_FACTORY_WIDGET (tile->widget), factory);
     }
 
   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FACTORY]);
@@ -1030,7 +1030,7 @@ gtk_list_view_set_single_click_activate (GtkListView *self,
        tile = gtk_rb_tree_node_get_next (tile))
     {
       if (tile->widget)
-        gtk_list_item_widget_set_single_click_activate (GTK_LIST_ITEM_WIDGET (tile->widget), single_click_activate);
+        gtk_list_factory_widget_set_single_click_activate (GTK_LIST_FACTORY_WIDGET (tile->widget), single_click_activate);
     }
 
   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SINGLE_CLICK_ACTIVATE]);
index bcb92fe4435ce461c5752d07bafec509172a1a5a..c22900ff6025d25f542070843ac17c78d033636c 100644 (file)
@@ -269,6 +269,7 @@ gtk_public_sources = files([
   'gtklistbase.c',
   'gtklinkbutton.c',
   'gtklistbox.c',
+  'gtklistfactorywidget.c',
   'gtklistitem.c',
   'gtklistitembase.c',
   'gtklistitemfactory.c',