From e845e93f5863174d51dfc4016fa92ce069b54af1 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 3 Nov 2019 03:34:56 +0100 Subject: [PATCH] listitem: Move position/item/selected tracking to widget This way, we can ensure it's always there when we need it (before the item gets created) and gone when we don't (if some GC language holds on to the item after we've destroyed the widget). --- gtk/gtklistitem.c | 71 ++++++++++++---------------------------- gtk/gtklistitemprivate.h | 9 ----- gtk/gtklistitemwidget.c | 67 ++++++++++++++++++++++++++++--------- 3 files changed, 72 insertions(+), 75 deletions(-) diff --git a/gtk/gtklistitem.c b/gtk/gtklistitem.c index 79d3e12e78..01db2cdac4 100644 --- a/gtk/gtklistitem.c +++ b/gtk/gtklistitem.c @@ -98,11 +98,15 @@ gtk_list_item_get_property (GObject *object, break; case PROP_ITEM: - g_value_set_object (value, self->item); + if (self->owner) + g_value_set_object (value, gtk_list_item_widget_get_item (self->owner)); break; case PROP_POSITION: - g_value_set_uint (value, self->position); + if (self->owner) + g_value_set_uint (value, gtk_list_item_widget_get_position (self->owner)); + else + g_value_set_uint (value, GTK_INVALID_LIST_POSITION); break; case PROP_SELECTABLE: @@ -110,7 +114,10 @@ gtk_list_item_get_property (GObject *object, break; case PROP_SELECTED: - g_value_set_boolean (value, self->selected); + if (self->owner) + g_value_set_boolean (value, gtk_list_item_widget_get_selected (self->owner)); + else + g_value_set_boolean (value, FALSE); break; default: @@ -259,7 +266,10 @@ gtk_list_item_get_item (GtkListItem *self) { g_return_val_if_fail (GTK_IS_LIST_ITEM (self), NULL); - return self->item; + if (self->owner == NULL) + return NULL; + + return gtk_list_item_widget_get_item (self->owner); } /** @@ -316,23 +326,6 @@ gtk_list_item_set_child (GtkListItem *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]); } -void -gtk_list_item_set_item (GtkListItem *self, - gpointer item) -{ - g_return_if_fail (GTK_IS_LIST_ITEM (self)); - g_return_if_fail (item == NULL || G_IS_OBJECT (item)); - - if (self->item == item) - return; - - g_clear_object (&self->item); - if (item) - self->item = g_object_ref (item); - - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]); -} - /** * gtk_list_item_get_position: * @self: a #GtkListItem @@ -345,23 +338,12 @@ gtk_list_item_set_item (GtkListItem *self, guint gtk_list_item_get_position (GtkListItem *self) { - g_return_val_if_fail (GTK_IS_LIST_ITEM (self), 0); + g_return_val_if_fail (GTK_IS_LIST_ITEM (self), GTK_INVALID_LIST_POSITION); - return self->position; -} + if (self->owner == NULL) + return GTK_INVALID_LIST_POSITION; -void -gtk_list_item_set_position (GtkListItem *self, - guint position) -{ - g_return_if_fail (GTK_IS_LIST_ITEM (self)); - - if (self->position == position) - return; - - self->position = position; - - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_POSITION]); + return gtk_list_item_widget_get_position (self->owner); } /** @@ -379,21 +361,10 @@ gtk_list_item_get_selected (GtkListItem *self) { g_return_val_if_fail (GTK_IS_LIST_ITEM (self), FALSE); - return self->selected; -} + if (self->owner == NULL) + return FALSE; -void -gtk_list_item_set_selected (GtkListItem *self, - gboolean selected) -{ - g_return_if_fail (GTK_IS_LIST_ITEM (self)); - - if (self->selected == selected) - return; - - self->selected = selected; - - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]); + return gtk_list_item_widget_get_selected (self->owner); } /** diff --git a/gtk/gtklistitemprivate.h b/gtk/gtklistitemprivate.h index b84057f838..d8f8833313 100644 --- a/gtk/gtklistitemprivate.h +++ b/gtk/gtklistitemprivate.h @@ -32,23 +32,14 @@ struct _GtkListItem GtkListItemWidget *owner; /* has a reference */ - GObject *item; GtkWidget *child; - guint position; guint activatable : 1; guint selectable : 1; - guint selected : 1; }; GtkListItem * gtk_list_item_new (void); -void gtk_list_item_set_item (GtkListItem *self, - gpointer item); -void gtk_list_item_set_position (GtkListItem *self, - guint position); -void gtk_list_item_set_selected (GtkListItem *self, - gboolean selected); G_END_DECLS diff --git a/gtk/gtklistitemwidget.c b/gtk/gtklistitemwidget.c index fe314db13a..54f1eb0c96 100644 --- a/gtk/gtklistitemwidget.c +++ b/gtk/gtklistitemwidget.c @@ -30,6 +30,7 @@ #include "gtklistitemfactoryprivate.h" #include "gtklistitemprivate.h" #include "gtkmain.h" +#include "gtkselectionmodel.h" #include "gtkwidget.h" #include "gtkwidgetprivate.h" @@ -38,6 +39,10 @@ struct _GtkListItemWidgetPrivate { GtkListItemFactory *factory; GtkListItem *list_item; + + GObject *item; + guint position; + gboolean selected; }; enum @@ -55,13 +60,13 @@ gtk_list_item_widget_activate_signal (GtkListItemWidget *self) { GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self); - if (!priv->list_item->activatable) + if (priv->list_item && !priv->list_item->activatable) return; gtk_widget_activate_action (GTK_WIDGET (self), "list.activate-item", "u", - priv->list_item->position); + priv->position); } static gboolean @@ -122,6 +127,7 @@ gtk_list_item_widget_dispose (GObject *object) gtk_list_item_factory_teardown (priv->factory, self); g_assert (priv->list_item == NULL); } + g_clear_object (&priv->item); g_clear_object (&priv->factory); G_OBJECT_CLASS (gtk_list_item_widget_parent_class)->dispose (object); @@ -136,7 +142,7 @@ gtk_list_item_widget_select_action (GtkWidget *widget, GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self); gboolean modify, extend; - if (!priv->list_item->selectable) + if (priv->list_item && !priv->list_item->selectable) return; g_variant_get (parameter, "(bb)", &modify, &extend); @@ -144,7 +150,7 @@ gtk_list_item_widget_select_action (GtkWidget *widget, gtk_widget_activate_action (GTK_WIDGET (self), "list.select-item", "(ubb)", - priv->list_item->position, modify, extend); + priv->position, modify, extend); } static void @@ -233,13 +239,13 @@ gtk_list_item_widget_click_gesture_pressed (GtkGestureClick *gesture, GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self); GtkWidget *widget = GTK_WIDGET (self); - if (!priv->list_item->selectable && !priv->list_item->activatable) + 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->selectable) + if (!priv->list_item || priv->list_item->selectable) { GdkModifierType state; GdkModifierType mask; @@ -258,17 +264,17 @@ gtk_list_item_widget_click_gesture_pressed (GtkGestureClick *gesture, gtk_widget_activate_action (GTK_WIDGET (self), "list.select-item", "(ubb)", - priv->list_item->position, modify, extend); + priv->position, modify, extend); } - if (priv->list_item->activatable) + if (!priv->list_item || priv->list_item->activatable) { if (n_press == 2) { gtk_widget_activate_action (GTK_WIDGET (self), "list.activate-item", "u", - priv->list_item->position); + priv->position); } } @@ -291,7 +297,7 @@ gtk_list_item_widget_focus_changed_cb (GtkEventControllerKey *controller, gtk_widget_activate_action (widget, "list.scroll-to-item", "u", - priv->list_item->position); + priv->position); } } @@ -393,6 +399,13 @@ gtk_list_item_widget_default_setup (GtkListItemWidget *self, if (list_item->child) gtk_list_item_widget_add_child (self, list_item->child); + + if (priv->item) + g_object_notify (G_OBJECT (list_item), "item"); + if (priv->position != GTK_INVALID_LIST_POSITION) + g_object_notify (G_OBJECT (list_item), "position"); + if (priv->selected) + g_object_notify (G_OBJECT (list_item), "selected"); } void @@ -408,6 +421,13 @@ gtk_list_item_widget_default_teardown (GtkListItemWidget *self, if (list_item->child) gtk_list_item_widget_remove_child (self, list_item->child); + + if (priv->item) + g_object_notify (G_OBJECT (list_item), "item"); + if (priv->position != GTK_INVALID_LIST_POSITION) + g_object_notify (G_OBJECT (list_item), "position"); + if (priv->selected) + g_object_notify (G_OBJECT (list_item), "selected"); } void @@ -417,9 +437,24 @@ gtk_list_item_widget_default_update (GtkListItemWidget *self, gpointer item, gboolean selected) { - gtk_list_item_set_item (list_item, item); - gtk_list_item_set_position (list_item, position); - gtk_list_item_set_selected (list_item, selected); + GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self); + + /* FIXME: It's kinda evil to notify external objects from here... */ + + if (g_set_object (&priv->item, item)) + g_object_notify (G_OBJECT (list_item), "item"); + + if (priv->position != position) + { + priv->position = position; + g_object_notify (G_OBJECT (list_item), "position"); + } + + if (priv->selected != selected) + { + priv->selected = selected; + g_object_notify (G_OBJECT (list_item), "selected"); + } } void @@ -449,7 +484,7 @@ gtk_list_item_widget_get_position (GtkListItemWidget *self) { GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self); - return priv->list_item->position; + return priv->position; } gpointer @@ -457,7 +492,7 @@ gtk_list_item_widget_get_item (GtkListItemWidget *self) { GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self); - return priv->list_item->item; + return priv->item; } gboolean @@ -465,6 +500,6 @@ gtk_list_item_widget_get_selected (GtkListItemWidget *self) { GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self); - return priv->list_item->selected; + return priv->selected; }