summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2023-03-30 11:40:05 +0200
committerBenjamin Otte <otte@redhat.com>2023-04-01 20:49:40 +0200
commitc74ab7aaec9880726de7548789e06b9b5fdcee7b (patch)
treeea3b3b75da7ec388760abda2c2bc791f94a10ee4
parent00cb4c66cfb48b4dee5568be6ac6d60505ef88cf (diff)
downloadgtk+-c74ab7aaec9880726de7548789e06b9b5fdcee7b.tar.gz
columnviewcellwidget: Untangle from GtkListItemWidget
This is step 1 in switching cells to their own ListItem subclass.
-rw-r--r--gtk/gtkcolumnviewcellwidget.c158
-rw-r--r--gtk/gtkcolumnviewcellwidgetprivate.h3
-rw-r--r--gtk/gtklistitem.c31
-rw-r--r--gtk/gtklistitemprivate.h2
4 files changed, 185 insertions, 9 deletions
diff --git a/gtk/gtkcolumnviewcellwidget.c b/gtk/gtkcolumnviewcellwidget.c
index 82bd843bb4..fcb7b8b6b7 100644
--- a/gtk/gtkcolumnviewcellwidget.c
+++ b/gtk/gtkcolumnviewcellwidget.c
@@ -25,8 +25,8 @@
#include "gtkcolumnviewrowwidgetprivate.h"
#include "gtkcssboxesprivate.h"
#include "gtkcssnodeprivate.h"
+#include "gtklistfactorywidgetprivate.h"
#include "gtklistitemprivate.h"
-#include "gtklistitemwidgetprivate.h"
#include "gtkprivate.h"
#include "gtkwidgetprivate.h"
@@ -47,7 +47,72 @@ struct _GtkColumnViewCellWidgetClass
GtkListItemWidgetClass parent_class;
};
-G_DEFINE_TYPE (GtkColumnViewCellWidget, gtk_column_view_cell_widget, GTK_TYPE_LIST_ITEM_WIDGET)
+G_DEFINE_TYPE (GtkColumnViewCellWidget, gtk_column_view_cell_widget, GTK_TYPE_LIST_FACTORY_WIDGET)
+
+static gboolean
+gtk_column_view_cell_widget_focus (GtkWidget *widget,
+ GtkDirectionType direction)
+{
+ GtkWidget *child = gtk_widget_get_first_child (widget);
+
+ if (gtk_widget_get_focus_child (widget))
+ {
+ /* focus is in the child */
+ if (direction == GTK_DIR_TAB_BACKWARD)
+ return gtk_widget_grab_focus_self (widget);
+ else
+ return FALSE;
+ }
+ else if (gtk_widget_is_focus (widget))
+ {
+ /* The widget has focus */
+ if (direction == GTK_DIR_TAB_FORWARD)
+ {
+ if (child)
+ return gtk_widget_child_focus (child, direction);
+ }
+
+ return FALSE;
+ }
+ else
+ {
+ /* focus coming in from the outside */
+ if (direction == GTK_DIR_TAB_BACKWARD)
+ {
+ if (child &&
+ gtk_widget_child_focus (child, direction))
+ return TRUE;
+
+ return gtk_widget_grab_focus_self (widget);
+ }
+ else
+ {
+ if (gtk_widget_grab_focus_self (widget))
+ return TRUE;
+
+ if (child &&
+ gtk_widget_child_focus (child, direction))
+ return TRUE;
+
+ return FALSE;
+ }
+ }
+}
+
+static gboolean
+gtk_column_view_cell_widget_grab_focus (GtkWidget *widget)
+{
+ GtkWidget *child;
+
+ if (GTK_WIDGET_CLASS (gtk_column_view_cell_widget_parent_class)->grab_focus (widget))
+ return TRUE;
+
+ child = gtk_widget_get_first_child (widget);
+ if (child && gtk_widget_grab_focus (child))
+ return TRUE;
+
+ return FALSE;
+}
static gpointer
gtk_column_view_cell_widget_create_object (GtkListFactoryWidget *fw)
@@ -64,12 +129,80 @@ gtk_column_view_cell_widget_create_object (GtkListFactoryWidget *fw)
}
static void
+gtk_column_view_cell_widget_setup_object (GtkListFactoryWidget *fw,
+ gpointer object)
+{
+ GtkColumnViewCellWidget *self = GTK_COLUMN_VIEW_CELL_WIDGET (fw);
+ GtkListItem *list_item = object;
+
+ GTK_LIST_FACTORY_WIDGET_CLASS (gtk_column_view_cell_widget_parent_class)->setup_object (fw, object);
+
+ list_item->cell = self;
+
+ gtk_list_factory_widget_set_activatable (fw, list_item->activatable);
+ gtk_list_factory_widget_set_selectable (fw, list_item->selectable);
+ gtk_column_view_cell_widget_set_child (GTK_COLUMN_VIEW_CELL_WIDGET (self), list_item->child);
+
+ gtk_widget_set_focusable (GTK_WIDGET (self), list_item->focusable);
+
+ 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)));
+}
+
+static void
gtk_column_view_cell_widget_teardown_object (GtkListFactoryWidget *fw,
gpointer object)
{
+ GtkColumnViewCellWidget *self = GTK_COLUMN_VIEW_CELL_WIDGET (fw);
+ GtkListItem *list_item = object;
+
GTK_LIST_FACTORY_WIDGET_CLASS (gtk_column_view_cell_widget_parent_class)->teardown_object (fw, object);
- gtk_widget_set_focusable (GTK_WIDGET (fw), FALSE);
+ list_item->cell = NULL;
+
+ gtk_column_view_cell_widget_set_child (GTK_COLUMN_VIEW_CELL_WIDGET (self), NULL);
+
+ gtk_list_factory_widget_set_activatable (fw, FALSE);
+ gtk_list_factory_widget_set_selectable (fw, FALSE);
+ gtk_widget_set_focusable (GTK_WIDGET (self), 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_column_view_cell_widget_update_object (GtkListFactoryWidget *fw,
+ gpointer object,
+ guint position,
+ gpointer item,
+ gboolean selected)
+{
+ GtkColumnViewCellWidget *self = GTK_COLUMN_VIEW_CELL_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;
+
+ /* FIXME: It's kinda evil to notify external objects from here... */
+ 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;
+
+ GTK_LIST_FACTORY_WIDGET_CLASS (gtk_column_view_cell_widget_parent_class)->update_object (fw,
+ object,
+ position,
+ item,
+ selected);
+
+ if (list_item)
+ gtk_list_item_do_notify (list_item, notify_item, notify_position, notify_selected);
}
static int
@@ -193,8 +326,12 @@ gtk_column_view_cell_widget_class_init (GtkColumnViewCellWidgetClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
factory_class->create_object = gtk_column_view_cell_widget_create_object;
+ factory_class->setup_object = gtk_column_view_cell_widget_setup_object;
+ factory_class->update_object = gtk_column_view_cell_widget_update_object;
factory_class->teardown_object = gtk_column_view_cell_widget_teardown_object;
+ widget_class->focus = gtk_column_view_cell_widget_focus;
+ widget_class->grab_focus = gtk_column_view_cell_widget_grab_focus;
widget_class->measure = gtk_column_view_cell_widget_measure;
widget_class->size_allocate = gtk_column_view_cell_widget_size_allocate;
widget_class->get_request_mode = gtk_column_view_cell_widget_get_request_mode;
@@ -272,3 +409,18 @@ gtk_column_view_cell_widget_get_column (GtkColumnViewCellWidget *self)
{
return self->column;
}
+
+void
+gtk_column_view_cell_widget_set_child (GtkColumnViewCellWidget *self,
+ GtkWidget *child)
+{
+ GtkWidget *cur_child = gtk_widget_get_first_child (GTK_WIDGET (self));
+
+ if (cur_child == child)
+ return;
+
+ g_clear_pointer (&cur_child, gtk_widget_unparent);
+
+ if (child)
+ gtk_widget_set_parent (child, GTK_WIDGET (self));
+}
diff --git a/gtk/gtkcolumnviewcellwidgetprivate.h b/gtk/gtkcolumnviewcellwidgetprivate.h
index b50e69e477..57632adf9b 100644
--- a/gtk/gtkcolumnviewcellwidgetprivate.h
+++ b/gtk/gtkcolumnviewcellwidgetprivate.h
@@ -38,6 +38,9 @@ GType gtk_column_view_cell_widget_get_type (
GtkWidget * gtk_column_view_cell_widget_new (GtkColumnViewColumn *column,
gboolean inert);
+void gtk_column_view_cell_widget_set_child (GtkColumnViewCellWidget *self,
+ GtkWidget *child);
+
void gtk_column_view_cell_widget_remove (GtkColumnViewCellWidget *self);
GtkColumnViewCellWidget * gtk_column_view_cell_widget_get_next (GtkColumnViewCellWidget *self);
diff --git a/gtk/gtklistitem.c b/gtk/gtklistitem.c
index 59f450f97b..8890641a4a 100644
--- a/gtk/gtklistitem.c
+++ b/gtk/gtklistitem.c
@@ -70,6 +70,7 @@ gtk_list_item_dispose (GObject *object)
GtkListItem *self = GTK_LIST_ITEM (object);
g_assert (self->owner == NULL); /* would hold a reference */
+ g_assert (self->cell == NULL); /* would hold a reference */
g_clear_object (&self->child);
G_OBJECT_CLASS (gtk_list_item_parent_class)->dispose (object);
@@ -100,11 +101,15 @@ gtk_list_item_get_property (GObject *object,
case PROP_ITEM:
if (self->owner)
g_value_set_object (value, gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self->owner)));
+ else if (self->cell)
+ g_value_set_object (value, gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self->cell)));
break;
case PROP_POSITION:
if (self->owner)
g_value_set_uint (value, gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self->owner)));
+ else if (self->cell)
+ g_value_set_uint (value, gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self->cell)));
else
g_value_set_uint (value, GTK_INVALID_LIST_POSITION);
break;
@@ -116,6 +121,8 @@ gtk_list_item_get_property (GObject *object,
case PROP_SELECTED:
if (self->owner)
g_value_set_boolean (value, gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self->owner)));
+ if (self->cell)
+ g_value_set_boolean (value, gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self->cell)));
else
g_value_set_boolean (value, FALSE);
break;
@@ -287,10 +294,12 @@ gtk_list_item_get_item (GtkListItem *self)
{
g_return_val_if_fail (GTK_IS_LIST_ITEM (self), NULL);
- if (self->owner == NULL)
+ if (self->owner)
+ return gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self->owner));
+ else if (self->cell)
+ return gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self->cell));
+ else
return NULL;
-
- return gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self->owner));
}
/**
@@ -347,6 +356,8 @@ gtk_list_item_set_child (GtkListItem *self,
if (self->owner)
gtk_list_item_widget_set_child (self->owner, child);
+ else if (self->cell)
+ gtk_column_view_cell_widget_set_child (self->cell, child);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CHILD]);
}
@@ -388,10 +399,12 @@ gtk_list_item_get_selected (GtkListItem *self)
{
g_return_val_if_fail (GTK_IS_LIST_ITEM (self), FALSE);
- if (self->owner == NULL)
+ if (self->owner)
+ return gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self->owner));
+ if (self->cell)
+ return gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self->cell));
+ else
return FALSE;
-
- return gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self->owner));
}
/**
@@ -444,6 +457,8 @@ gtk_list_item_set_selectable (GtkListItem *self,
if (self->owner)
gtk_list_factory_widget_set_selectable (GTK_LIST_FACTORY_WIDGET (self->owner), selectable);
+ if (self->cell)
+ gtk_list_factory_widget_set_selectable (GTK_LIST_FACTORY_WIDGET (self->cell), selectable);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTABLE]);
}
@@ -493,6 +508,8 @@ gtk_list_item_set_activatable (GtkListItem *self,
if (self->owner)
gtk_list_factory_widget_set_activatable (GTK_LIST_FACTORY_WIDGET (self->owner), activatable);
+ if (self->cell)
+ gtk_list_factory_widget_set_activatable (GTK_LIST_FACTORY_WIDGET (self->cell), activatable);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIVATABLE]);
}
@@ -548,6 +565,8 @@ gtk_list_item_set_focusable (GtkListItem *self,
if (self->owner)
gtk_widget_set_focusable (GTK_WIDGET (self->owner), focusable);
+ if (self->cell)
+ gtk_widget_set_focusable (GTK_WIDGET (self->cell), focusable);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FOCUSABLE]);
}
diff --git a/gtk/gtklistitemprivate.h b/gtk/gtklistitemprivate.h
index 99adbeee4c..6858419821 100644
--- a/gtk/gtklistitemprivate.h
+++ b/gtk/gtklistitemprivate.h
@@ -22,6 +22,7 @@
#include "gtklistitem.h"
#include "gtklistitemwidgetprivate.h"
+#include "gtkcolumnviewcellwidgetprivate.h"
#include "gtkversion.h"
G_BEGIN_DECLS
@@ -31,6 +32,7 @@ struct _GtkListItem
GObject parent_instance;
GtkListItemWidget *owner; /* has a reference */
+ GtkColumnViewCellWidget *cell; /* has a reference */
GtkWidget *child;