[libadwaita/wip/exalm/tab-overview: 7/15] tab: Extract AdwTabItem
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libadwaita/wip/exalm/tab-overview: 7/15] tab: Extract AdwTabItem
- Date: Tue, 12 Oct 2021 08:51:31 +0000 (UTC)
commit 81be5a6fe3c319477bd0814ad1ac2a027ef7c690
Author: Alexander Mikhaylenko <alexm gnome org>
Date: Sat Aug 21 03:57:08 2021 +0500
tab: Extract AdwTabItem
src/adw-tab-item-private.h | 67 ++++++
src/adw-tab-item.c | 566 +++++++++++++++++++++++++++++++++++++++++++
src/adw-tab-list-base.c | 89 +++----
src/adw-tab-private.h | 32 +--
src/adw-tab.c | 582 +++++++++------------------------------------
src/adw-tab.ui | 5 +-
6 files changed, 805 insertions(+), 536 deletions(-)
---
diff --git a/src/adw-tab-item-private.h b/src/adw-tab-item-private.h
new file mode 100644
index 00000000..ce085b6e
--- /dev/null
+++ b/src/adw-tab-item-private.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * Author: Alexander Mikhaylenko <alexander mikhaylenko puri sm>
+ */
+
+#pragma once
+
+#if !defined(_ADWAITA_INSIDE) && !defined(ADWAITA_COMPILATION)
+#error "Only <adwaita.h> can be included directly."
+#endif
+
+#include <gtk/gtk.h>
+#include "adw-tab-view.h"
+
+G_BEGIN_DECLS
+
+#define ADW_TYPE_TAB_ITEM (adw_tab_item_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (AdwTabItem, adw_tab_item, ADW, TAB_ITEM, GtkWidget)
+
+struct _AdwTabItemClass
+{
+ GtkWidgetClass parent_class;
+
+ void (*connect_page) (AdwTabItem *self);
+ void (*disconnect_page) (AdwTabItem *self);
+};
+
+AdwTabView *adw_tab_item_get_view (AdwTabItem *self);
+
+AdwTabPage *adw_tab_item_get_page (AdwTabItem *self);
+void adw_tab_item_set_page (AdwTabItem *self,
+ AdwTabPage *page);
+
+gboolean adw_tab_item_get_pinned (AdwTabItem *self);
+
+int adw_tab_item_get_display_width (AdwTabItem *self);
+void adw_tab_item_set_display_width (AdwTabItem *self,
+ int width);
+
+gboolean adw_tab_item_get_hovering (AdwTabItem *self);
+
+gboolean adw_tab_item_get_dragging (AdwTabItem *self);
+void adw_tab_item_set_dragging (AdwTabItem *self,
+ gboolean dragging);
+
+gboolean adw_tab_item_get_inverted (AdwTabItem *self);
+void adw_tab_item_set_inverted (AdwTabItem *self,
+ gboolean inverted);
+
+gboolean adw_tab_item_get_fully_visible (AdwTabItem *self);
+void adw_tab_item_set_fully_visible (AdwTabItem *self,
+ gboolean fully_visible);
+
+void adw_tab_item_setup_extra_drop_target (AdwTabItem *self,
+ GdkDragAction actions,
+ GType *types,
+ gsize n_types);
+
+void adw_tab_item_close (AdwTabItem *self);
+
+void adw_tab_item_activate_indicator (AdwTabItem *self);
+
+G_END_DECLS
diff --git a/src/adw-tab-item.c b/src/adw-tab-item.c
new file mode 100644
index 00000000..e9234f27
--- /dev/null
+++ b/src/adw-tab-item.c
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2020-2021 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * Author: Alexander Mikhaylenko <alexander mikhaylenko puri sm>
+ */
+
+#include "config.h"
+#include "adw-tab-item-private.h"
+
+typedef struct {
+ GtkDropTarget *drop_target;
+
+ AdwTabView *view;
+ AdwTabPage *page;
+ gboolean pinned;
+ gboolean hovering;
+ gboolean dragging;
+ gboolean fully_visible;
+ int display_width;
+ gboolean inverted;
+} AdwTabItemPrivate;
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (AdwTabItem, adw_tab_item, GTK_TYPE_WIDGET)
+
+enum {
+ PROP_0,
+ PROP_VIEW,
+ PROP_PAGE,
+ PROP_PINNED,
+ PROP_HOVERING,
+ PROP_DRAGGING,
+ PROP_FULLY_VISIBLE,
+ PROP_DISPLAY_WIDTH,
+ PROP_INVERTED,
+ LAST_PROP
+};
+
+static GParamSpec *props[LAST_PROP];
+
+enum {
+ SIGNAL_EXTRA_DRAG_DROP,
+ SIGNAL_LAST_SIGNAL,
+};
+
+static guint signals[SIGNAL_LAST_SIGNAL];
+
+static gboolean
+close_idle_cb (AdwTabItem *self)
+{
+ AdwTabItemPrivate *priv = adw_tab_item_get_instance_private (self);
+
+ adw_tab_view_close_page (priv->view, priv->page);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+motion_cb (AdwTabItem *self,
+ double x,
+ double y,
+ GtkEventController *controller)
+{
+ AdwTabItemPrivate *priv = adw_tab_item_get_instance_private (self);
+ GdkDevice *device = gtk_event_controller_get_current_event_device (controller);
+ GdkInputSource input_source = gdk_device_get_source (device);
+
+ if (input_source == GDK_SOURCE_TOUCHSCREEN)
+ return;
+
+ if (priv->hovering)
+ return;
+
+ priv->hovering = TRUE;
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HOVERING]);
+}
+
+static void
+leave_cb (AdwTabItem *self,
+ GtkEventController *controller)
+{
+ AdwTabItemPrivate *priv = adw_tab_item_get_instance_private (self);
+
+ if (priv->hovering)
+ return;
+
+ priv->hovering = FALSE;
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HOVERING]);
+}
+
+static gboolean
+drop_cb (AdwTabItem *self,
+ GValue *value)
+{
+ gboolean ret = GDK_EVENT_PROPAGATE;
+
+ g_signal_emit (self, signals[SIGNAL_EXTRA_DRAG_DROP], 0, value, &ret);
+
+ return ret;
+}
+
+static gboolean
+activate_cb (AdwTabItem *self,
+ GVariant *args)
+{
+ AdwTabItemPrivate *priv = adw_tab_item_get_instance_private (self);
+ GtkWidget *child;
+
+ if (!priv->page || !priv->view)
+ return GDK_EVENT_PROPAGATE;
+
+ child = adw_tab_page_get_child (priv->page);
+
+ gtk_widget_grab_focus (child);
+
+ return GDK_EVENT_STOP;
+}
+
+static void
+adw_tab_item_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ AdwTabItem *self = ADW_TAB_ITEM (object);
+
+ switch (prop_id) {
+ case PROP_VIEW:
+ g_value_set_object (value, adw_tab_item_get_view (self));
+ break;
+
+ case PROP_PAGE:
+ g_value_set_object (value, adw_tab_item_get_page (self));
+ break;
+
+ case PROP_PINNED:
+ g_value_set_boolean (value, adw_tab_item_get_pinned (self));
+ break;
+
+ case PROP_HOVERING:
+ g_value_set_boolean (value, adw_tab_item_get_hovering (self));
+ break;
+
+ case PROP_DRAGGING:
+ g_value_set_boolean (value, adw_tab_item_get_dragging (self));
+ break;
+
+ case PROP_FULLY_VISIBLE:
+ g_value_set_boolean (value, adw_tab_item_get_fully_visible (self));
+ break;
+
+ case PROP_DISPLAY_WIDTH:
+ g_value_set_int (value, adw_tab_item_get_display_width (self));
+ break;
+
+ case PROP_INVERTED:
+ g_value_set_boolean (value, adw_tab_item_get_inverted (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+adw_tab_item_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ AdwTabItem *self = ADW_TAB_ITEM (object);
+ AdwTabItemPrivate *priv = adw_tab_item_get_instance_private (self);
+
+ switch (prop_id) {
+ case PROP_VIEW:
+ priv->view = g_value_get_object (value);
+ break;
+
+ case PROP_PAGE:
+ adw_tab_item_set_page (self, g_value_get_object (value));
+ break;
+
+ case PROP_PINNED:
+ priv->pinned = g_value_get_boolean (value);
+ break;
+
+ case PROP_DRAGGING:
+ adw_tab_item_set_dragging (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_FULLY_VISIBLE:
+ adw_tab_item_set_fully_visible (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_DISPLAY_WIDTH:
+ adw_tab_item_set_display_width (self, g_value_get_int (value));
+ break;
+
+ case PROP_INVERTED:
+ adw_tab_item_set_inverted (self, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+adw_tab_item_dispose (GObject *object)
+{
+ AdwTabItem *self = ADW_TAB_ITEM (object);
+
+ adw_tab_item_set_page (self, NULL);
+
+ G_OBJECT_CLASS (adw_tab_item_parent_class)->dispose (object);
+}
+
+static void
+adw_tab_item_class_init (AdwTabItemClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->dispose = adw_tab_item_dispose;
+ object_class->get_property = adw_tab_item_get_property;
+ object_class->set_property = adw_tab_item_set_property;
+
+ props[PROP_VIEW] =
+ g_param_spec_object ("view",
+ "View",
+ "View",
+ ADW_TYPE_TAB_VIEW,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ props[PROP_PAGE] =
+ g_param_spec_object ("page",
+ "Page",
+ "Page",
+ ADW_TYPE_TAB_PAGE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+ props[PROP_PINNED] =
+ g_param_spec_boolean ("pinned",
+ "Pinned",
+ "Pinned",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ props[PROP_HOVERING] =
+ g_param_spec_boolean ("hovering",
+ "Hovering",
+ "Hovering",
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
+
+ props[PROP_DRAGGING] =
+ g_param_spec_boolean ("dragging",
+ "Dragging",
+ "Dragging",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+ props[PROP_FULLY_VISIBLE] =
+ g_param_spec_boolean ("fully-visible",
+ "Fully visible",
+ "Fully visible",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+ props[PROP_DISPLAY_WIDTH] =
+ g_param_spec_int ("display-width",
+ "Display Width",
+ "Display Width",
+ 0, G_MAXINT, 0,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+ props[PROP_INVERTED] =
+ g_param_spec_boolean ("inverted",
+ "Inverted",
+ "Inverted",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+ signals[SIGNAL_EXTRA_DRAG_DROP] =
+ g_signal_new ("extra-drag-drop",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ g_signal_accumulator_first_wins, NULL, NULL,
+ G_TYPE_BOOLEAN,
+ 1,
+ G_TYPE_VALUE);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+
+ gtk_widget_class_add_binding (widget_class, GDK_KEY_space, 0, (GtkShortcutFunc) activate_cb, NULL);
+ gtk_widget_class_add_binding (widget_class, GDK_KEY_KP_Space, 0, (GtkShortcutFunc) activate_cb, NULL);
+ gtk_widget_class_add_binding (widget_class, GDK_KEY_Return, 0, (GtkShortcutFunc) activate_cb, NULL);
+ gtk_widget_class_add_binding (widget_class, GDK_KEY_ISO_Enter, 0, (GtkShortcutFunc) activate_cb, NULL);
+ gtk_widget_class_add_binding (widget_class, GDK_KEY_KP_Enter, 0, (GtkShortcutFunc) activate_cb, NULL);
+}
+
+static void
+adw_tab_item_init (AdwTabItem *self)
+{
+ GtkEventController *controller = gtk_event_controller_motion_new ();
+ g_signal_connect_swapped (controller, "motion", G_CALLBACK (motion_cb), self);
+ g_signal_connect_swapped (controller, "leave", G_CALLBACK (leave_cb), self);
+ gtk_widget_add_controller (GTK_WIDGET (self), controller);
+}
+
+AdwTabView *
+adw_tab_item_get_view (AdwTabItem *self)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_val_if_fail (ADW_IS_TAB_ITEM (self), NULL);
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ return priv->view;
+}
+
+AdwTabPage *
+adw_tab_item_get_page (AdwTabItem *self)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_val_if_fail (ADW_IS_TAB_ITEM (self), NULL);
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ return priv->page;
+}
+
+void
+adw_tab_item_set_page (AdwTabItem *self,
+ AdwTabPage *page)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_if_fail (ADW_IS_TAB_ITEM (self));
+ g_return_if_fail (page == NULL || ADW_IS_TAB_PAGE (page));
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ if (priv->page == page)
+ return;
+
+ if (priv->page)
+ ADW_TAB_ITEM_GET_CLASS (self)->disconnect_page (self);
+
+ g_set_object (&priv->page, page);
+
+ if (priv->page)
+ ADW_TAB_ITEM_GET_CLASS (self)->connect_page (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PAGE]);
+}
+
+gboolean
+adw_tab_item_get_pinned (AdwTabItem *self)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_val_if_fail (ADW_IS_TAB_ITEM (self), FALSE);
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ return priv->pinned;
+}
+
+int
+adw_tab_item_get_display_width (AdwTabItem *self)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_val_if_fail (ADW_IS_TAB_ITEM (self), 0);
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ return priv->display_width;
+}
+
+void
+adw_tab_item_set_display_width (AdwTabItem *self,
+ int width)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_if_fail (ADW_IS_TAB_ITEM (self));
+ g_return_if_fail (width >= 0);
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ if (priv->display_width == width)
+ return;
+
+ priv->display_width = width;
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DISPLAY_WIDTH]);
+}
+
+gboolean
+adw_tab_item_get_hovering (AdwTabItem *self)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_val_if_fail (ADW_IS_TAB_ITEM (self), FALSE);
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ return priv->hovering;
+}
+
+gboolean
+adw_tab_item_get_dragging (AdwTabItem *self)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_val_if_fail (ADW_IS_TAB_ITEM (self), FALSE);
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ return priv->dragging;
+}
+
+void
+adw_tab_item_set_dragging (AdwTabItem *self,
+ gboolean dragging)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_if_fail (ADW_IS_TAB_ITEM (self));
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ dragging = !!dragging;
+
+ if (priv->dragging == dragging)
+ return;
+
+ priv->dragging = dragging;
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DRAGGING]);
+}
+
+gboolean
+adw_tab_item_get_inverted (AdwTabItem *self)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_val_if_fail (ADW_IS_TAB_ITEM (self), FALSE);
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ return priv->inverted;
+}
+
+void
+adw_tab_item_set_inverted (AdwTabItem *self,
+ gboolean inverted)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_if_fail (ADW_IS_TAB_ITEM (self));
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ inverted = !!inverted;
+
+ if (priv->inverted == inverted)
+ return;
+
+ priv->inverted = inverted;
+
+ gtk_widget_queue_allocate (GTK_WIDGET (self));
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INVERTED]);
+}
+
+gboolean
+adw_tab_item_get_fully_visible (AdwTabItem *self)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_val_if_fail (ADW_IS_TAB_ITEM (self), FALSE);
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ return priv->fully_visible;
+}
+
+void
+adw_tab_item_set_fully_visible (AdwTabItem *self,
+ gboolean fully_visible)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_if_fail (ADW_IS_TAB_ITEM (self));
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ fully_visible = !!fully_visible;
+
+ if (priv->fully_visible == fully_visible)
+ return;
+
+ priv->fully_visible = fully_visible;
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FULLY_VISIBLE]);
+}
+
+void
+adw_tab_item_setup_extra_drop_target (AdwTabItem *self,
+ GdkDragAction actions,
+ GType *types,
+ gsize n_types)
+{
+ AdwTabItemPrivate *priv;
+
+ g_return_if_fail (ADW_IS_TAB_ITEM (self));
+ g_return_if_fail (n_types == 0 || types != NULL);
+
+ priv = adw_tab_item_get_instance_private (self);
+
+ if (!priv->drop_target) {
+ priv->drop_target = gtk_drop_target_new (G_TYPE_INVALID, actions);
+ g_signal_connect_swapped (priv->drop_target, "drop", G_CALLBACK (drop_cb), self);
+ gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (priv->drop_target));
+ } else {
+ gtk_drop_target_set_actions (priv->drop_target, actions);
+ }
+
+ gtk_drop_target_set_gtypes (priv->drop_target, types, n_types);
+}
+
+void
+adw_tab_item_close (AdwTabItem *self)
+{
+ AdwTabItemPrivate *priv = adw_tab_item_get_instance_private (self);
+
+ if (!priv->page)
+ return;
+
+ /* When animations are disabled, we don't want to immediately remove the
+ * whole tab mid-click. Instead, defer it until the click has happened.
+ */
+ g_idle_add ((GSourceFunc) close_idle_cb, self);
+}
+
+void
+adw_tab_item_activate_indicator (AdwTabItem *self)
+{
+ AdwTabItemPrivate *priv = adw_tab_item_get_instance_private (self);
+
+ if (!priv->page)
+ return;
+
+ g_signal_emit_by_name (priv->view, "indicator-activated", priv->page);
+}
diff --git a/src/adw-tab-list-base.c b/src/adw-tab-list-base.c
index ddf453f5..ab96a0b6 100644
--- a/src/adw-tab-list-base.c
+++ b/src/adw-tab-list-base.c
@@ -14,6 +14,7 @@
#include "adw-animation-private.h"
#include "adw-gizmo-private.h"
#include "adw-tab-private.h"
+#include "adw-tab-item-private.h"
#include "adw-tab-view-private.h"
#include <math.h>
@@ -43,7 +44,7 @@ typedef enum {
typedef struct {
GdkDrag *drag;
- AdwTab *tab;
+ AdwTabItem *tab;
GtkBorder tab_margin;
int hotspot_x;
@@ -56,7 +57,7 @@ typedef struct {
typedef struct {
AdwTabPage *page;
- AdwTab *tab;
+ AdwTabItem *tab;
int pos;
int width;
@@ -352,7 +353,7 @@ calculate_tab_offset (AdwTabListBase *self,
if (!priv->reordered_tab)
return 0;
- width = (target ? adw_tab_get_display_width (priv->reordered_tab->tab) : priv->reordered_tab->width) -
OVERLAP;
+ width = (target ? adw_tab_item_get_display_width (priv->reordered_tab->tab) : priv->reordered_tab->width)
- OVERLAP;
if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL)
width = -width;
@@ -462,7 +463,7 @@ set_tab_resize_mode (AdwTabListBase *self,
TabInfo *info = l->data;
if (info->appear_animation)
- info->last_width = adw_tab_get_display_width (info->tab);
+ info->last_width = adw_tab_item_get_display_width (info->tab);
else
info->last_width = info->width;
}
@@ -688,9 +689,9 @@ update_visible (AdwTabListBase *self)
pos = get_tab_position (self, info);
- adw_tab_set_fully_visible (info->tab,
- pos + OVERLAP >= value &&
- pos + info->width - OVERLAP <= value + page_size);
+ adw_tab_item_set_fully_visible (info->tab,
+ pos + OVERLAP >= value &&
+ pos + info->width - OVERLAP <= value + page_size);
if (!adw_tab_page_get_needs_attention (info->page))
continue;
@@ -893,7 +894,7 @@ scroll_to_tab_full (AdwTabListBase *self,
}
if (info->appear_animation)
- tab_width = adw_tab_get_display_width (info->tab);
+ tab_width = adw_tab_item_get_display_width (info->tab);
value = gtk_adjustment_get_value (priv->adjustment);
page_size = gtk_adjustment_get_page_size (priv->adjustment);
@@ -1281,7 +1282,7 @@ update_drag_reodering (AdwTabListBase *self)
x = get_reorder_position (self);
- width = adw_tab_get_display_width (priv->reordered_tab->tab);
+ width = adw_tab_item_get_display_width (priv->reordered_tab->tab);
priv->reorder_window_x = x;
@@ -1670,12 +1671,12 @@ select_page (AdwTabListBase *self,
/* Opening */
static gboolean
-extra_drag_drop_cb (AdwTab *tab,
+extra_drag_drop_cb (AdwTabItem *tab,
GValue *value,
AdwTabListBase *self)
{
gboolean ret = GDK_EVENT_PROPAGATE;
- AdwTabPage *page = adw_tab_get_page (tab);
+ AdwTabPage *page = adw_tab_item_get_page (tab);
g_signal_emit (self, signals[SIGNAL_EXTRA_DRAG_DROP], 0, page, value, &ret);
@@ -1713,14 +1714,17 @@ create_tab_info (AdwTabListBase *self,
info->page = page;
info->pos = -1;
info->width = -1;
- info->tab = adw_tab_new (priv->view, priv->pinned);
-
- adw_tab_set_page (info->tab, page);
- adw_tab_set_inverted (info->tab, priv->inverted);
- adw_tab_setup_extra_drop_target (info->tab,
- priv->extra_drag_actions,
- priv->extra_drag_types,
- priv->extra_drag_n_types);
+ info->tab = g_object_new (ADW_TYPE_TAB,
+ "view", priv->view,
+ "pinned", priv->pinned,
+ NULL);
+
+ adw_tab_item_set_page (info->tab, page);
+ adw_tab_item_set_inverted (info->tab, priv->inverted);
+ adw_tab_item_setup_extra_drop_target (info->tab,
+ priv->extra_drag_actions,
+ priv->extra_drag_types,
+ priv->extra_drag_n_types);
gtk_widget_set_parent (GTK_WIDGET (info->tab), GTK_WIDGET (self));
@@ -1853,7 +1857,7 @@ page_detached_cb (AdwTabListBase *self,
if (info == priv->selected_tab)
adw_tab_list_base_select_page (self, NULL);
- adw_tab_set_page (info->tab, NULL);
+ adw_tab_item_set_page (info->tab, NULL);
if (info->notify_needs_attention_id > 0) {
g_signal_handler_disconnect (info->page, info->notify_needs_attention_id);
@@ -2033,7 +2037,7 @@ insert_placeholder (AdwTabListBase *self,
gtk_widget_set_opacity (GTK_WIDGET (info->tab), 0);
- adw_tab_set_dragging (info->tab, TRUE);
+ adw_tab_item_set_dragging (info->tab, TRUE);
info->reorder_ignore_bounds = TRUE;
@@ -2095,7 +2099,7 @@ replace_placeholder (AdwTabListBase *self,
priv->placeholder_scroll_offset = 0;
gtk_widget_set_opacity (GTK_WIDGET (priv->reorder_placeholder->tab), 1);
- adw_tab_set_dragging (info->tab, FALSE);
+ adw_tab_item_set_dragging (info->tab, FALSE);
if (!info->appear_animation) {
priv->reorder_placeholder = NULL;
@@ -2107,7 +2111,7 @@ replace_placeholder (AdwTabListBase *self,
priv->can_remove_placeholder = FALSE;
- adw_tab_set_page (info->tab, page);
+ adw_tab_item_set_page (info->tab, page);
info->page = page;
adw_animation_stop (info->appear_animation);
@@ -2134,7 +2138,7 @@ remove_animation_done_cb (gpointer user_data)
g_clear_object (&info->appear_animation);
if (!priv->can_remove_placeholder) {
- adw_tab_set_page (info->tab, priv->placeholder_page);
+ adw_tab_item_set_page (info->tab, priv->placeholder_page);
info->page = priv->placeholder_page;
return;
@@ -2181,7 +2185,7 @@ remove_placeholder (AdwTabListBase *self)
if (!info || !info->page)
return;
- adw_tab_set_page (info->tab, NULL);
+ adw_tab_item_set_page (info->tab, NULL);
info->page = NULL;
if (info->appear_animation)
@@ -2349,11 +2353,14 @@ create_drag_icon (AdwTabListBase *self,
icon->width = predict_tab_width (self, priv->reordered_tab, FALSE);
icon->target_width = icon->width;
- icon->tab = adw_tab_new (priv->view, FALSE);
- adw_tab_set_page (icon->tab, priv->reordered_tab->page);
- adw_tab_set_dragging (icon->tab, TRUE);
- adw_tab_set_inverted (icon->tab, priv->inverted);
- adw_tab_set_display_width (icon->tab, icon->width);
+ icon->tab = g_object_new (ADW_TYPE_TAB,
+ "view", priv->view,
+ "pinned", FALSE,
+ NULL);
+ adw_tab_item_set_page (icon->tab, priv->reordered_tab->page);
+ adw_tab_item_set_dragging (icon->tab, TRUE);
+ adw_tab_item_set_inverted (icon->tab, priv->inverted);
+ adw_tab_item_set_display_width (icon->tab, icon->width);
gtk_widget_set_halign (GTK_WIDGET (icon->tab), GTK_ALIGN_START);
gtk_drag_icon_set_child (GTK_DRAG_ICON (gtk_drag_icon_get_for_drag (drag)),
@@ -2387,7 +2394,7 @@ icon_resize_animation_value_cb (double value,
icon->width = (int) round (value);
- adw_tab_set_display_width (icon->tab, icon->width);
+ adw_tab_item_set_display_width (icon->tab, icon->width);
gtk_widget_set_size_request (GTK_WIDGET (icon->tab),
icon->width + icon->tab_margin.left + icon->tab_margin.right,
-1);
@@ -2445,7 +2452,7 @@ begin_drag (AdwTabListBase *self,
GdkContentProvider *content;
GdkDrag *drag;
TabInfo *detached_info;
- AdwTab *detached_tab;
+ AdwTabItem *detached_tab;
native = gtk_widget_get_native (GTK_WIDGET (self));
surface = gtk_native_get_surface (native);
@@ -2534,8 +2541,8 @@ tab_drag_enter_motion_cb (AdwTabListBase *self,
priv->indirect_reordering = TRUE;
resize_drag_icon (source_list, predict_tab_width (self, priv->reorder_placeholder, TRUE));
- adw_tab_set_display_width (priv->reorder_placeholder->tab, source_priv->drag_icon->target_width);
- adw_tab_set_inverted (source_priv->drag_icon->tab, priv->inverted);
+ adw_tab_item_set_display_width (priv->reorder_placeholder->tab, source_priv->drag_icon->target_width);
+ adw_tab_item_set_inverted (source_priv->drag_icon->tab, priv->inverted);
priv->drag_offset_x = source_priv->drag_icon->hotspot_x;
priv->drag_offset_y = source_priv->drag_icon->hotspot_y;
@@ -3105,9 +3112,9 @@ adw_tab_list_base_size_allocate (GtkWidget *widget,
TabInfo *info = l->data;
if (!info->appear_animation)
- adw_tab_set_display_width (info->tab, info->width);
+ adw_tab_item_set_display_width (info->tab, info->width);
else if (info->page && info != priv->reorder_placeholder)
- adw_tab_set_display_width (info->tab, predict_tab_width (self, info, FALSE));
+ adw_tab_item_set_display_width (info->tab, predict_tab_width (self, info, FALSE));
info->pos = pos + calculate_tab_offset (self, info, FALSE);
@@ -3726,10 +3733,10 @@ adw_tab_list_base_setup_extra_drop_target (AdwTabListBase *self,
for (l = priv->tabs; l; l = l->next) {
TabInfo *info = l->data;
- adw_tab_setup_extra_drop_target (info->tab,
- priv->extra_drag_actions,
- priv->extra_drag_types,
- priv->extra_drag_n_types);
+ adw_tab_item_setup_extra_drop_target (info->tab,
+ priv->extra_drag_actions,
+ priv->extra_drag_types,
+ priv->extra_drag_n_types);
}
}
@@ -3798,6 +3805,6 @@ adw_tab_list_base_set_inverted (AdwTabListBase *self,
for (l = priv->tabs; l; l = l->next) {
TabInfo *info = l->data;
- adw_tab_set_inverted (info->tab, inverted);
+ adw_tab_item_set_inverted (info->tab, inverted);
}
}
diff --git a/src/adw-tab-private.h b/src/adw-tab-private.h
index 11668612..cb162b27 100644
--- a/src/adw-tab-private.h
+++ b/src/adw-tab-private.h
@@ -12,40 +12,12 @@
#error "Only <adwaita.h> can be included directly."
#endif
-#include <gtk/gtk.h>
-#include "adw-tab-view.h"
+#include "adw-tab-item-private.h"
G_BEGIN_DECLS
#define ADW_TYPE_TAB (adw_tab_get_type())
-G_DECLARE_FINAL_TYPE (AdwTab, adw_tab, ADW, TAB, GtkWidget)
-
-AdwTab *adw_tab_new (AdwTabView *view,
- gboolean pinned) G_GNUC_WARN_UNUSED_RESULT;
-
-AdwTabPage *adw_tab_get_page (AdwTab *self);
-void adw_tab_set_page (AdwTab *self,
- AdwTabPage *page);
-
-int adw_tab_get_display_width (AdwTab *self);
-void adw_tab_set_display_width (AdwTab *self,
- int width);
-
-gboolean adw_tab_get_dragging (AdwTab *self);
-void adw_tab_set_dragging (AdwTab *self,
- gboolean dragging);
-
-gboolean adw_tab_get_inverted (AdwTab *self);
-void adw_tab_set_inverted (AdwTab *self,
- gboolean inverted);
-
-void adw_tab_set_fully_visible (AdwTab *self,
- gboolean fully_visible);
-
-void adw_tab_setup_extra_drop_target (AdwTab *self,
- GdkDragAction actions,
- GType *types,
- gsize n_types);
+G_DECLARE_FINAL_TYPE (AdwTab, adw_tab, ADW, TAB, AdwTabItem)
G_END_DECLS
diff --git a/src/adw-tab.c b/src/adw-tab.c
index 4f323c6c..6d505291 100644
--- a/src/adw-tab.c
+++ b/src/adw-tab.c
@@ -22,7 +22,7 @@
struct _AdwTab
{
- GtkWidget parent_instance;
+ AdwTabItem parent_instance;
GtkWidget *title;
GtkWidget *icon_stack;
@@ -33,19 +33,10 @@ struct _AdwTab
GtkWidget *close_btn;
GtkDropTarget *drop_target;
- AdwTabView *view;
- AdwTabPage *page;
- gboolean pinned;
- gboolean dragging;
- int display_width;
-
- gboolean hovering;
gboolean selected;
- gboolean inverted;
gboolean title_inverted;
gboolean close_overlap;
gboolean show_close;
- gboolean fully_visible;
AdwAnimation *close_btn_animation;
@@ -53,27 +44,7 @@ struct _AdwTab
gboolean shader_compiled;
};
-G_DEFINE_TYPE (AdwTab, adw_tab, GTK_TYPE_WIDGET)
-
-enum {
- PROP_0,
- PROP_VIEW,
- PROP_PINNED,
- PROP_DRAGGING,
- PROP_PAGE,
- PROP_DISPLAY_WIDTH,
- PROP_INVERTED,
- LAST_PROP
-};
-
-static GParamSpec *props[LAST_PROP];
-
-enum {
- SIGNAL_EXTRA_DRAG_DROP,
- SIGNAL_LAST_SIGNAL,
-};
-
-static guint signals[SIGNAL_LAST_SIGNAL];
+G_DEFINE_TYPE (AdwTab, adw_tab, ADW_TYPE_TAB_ITEM)
static inline void
set_style_class (GtkWidget *widget,
@@ -108,19 +79,22 @@ update_state (AdwTab *self)
{
GtkStateFlags new_state;
gboolean show_close;
+ gboolean dragging = adw_tab_item_get_dragging (ADW_TAB_ITEM (self));
+ gboolean hovering = adw_tab_item_get_hovering (ADW_TAB_ITEM (self));
+ gboolean fully_visible = adw_tab_item_get_fully_visible (ADW_TAB_ITEM (self));
new_state = gtk_widget_get_state_flags (GTK_WIDGET (self)) &
~(GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_CHECKED);
- if (self->dragging)
+ if (dragging)
new_state |= GTK_STATE_FLAG_PRELIGHT;
- if (self->selected || self->dragging)
+ if (self->selected || dragging)
new_state |= GTK_STATE_FLAG_CHECKED;
gtk_widget_set_state_flags (GTK_WIDGET (self), new_state, TRUE);
- show_close = (self->hovering && self->fully_visible) || self->selected || self->dragging;
+ show_close = (hovering && fully_visible) || self->selected || dragging;
if (self->show_close != show_close) {
double opacity = gtk_widget_get_opacity (self->close_btn);
@@ -150,19 +124,21 @@ update_state (AdwTab *self)
static void
update_tooltip (AdwTab *self)
{
- const char *tooltip = adw_tab_page_get_tooltip (self->page);
+ AdwTabPage *page = adw_tab_item_get_page (ADW_TAB_ITEM (self));
+ const char *tooltip = adw_tab_page_get_tooltip (page);
if (tooltip && g_strcmp0 (tooltip, "") != 0)
gtk_widget_set_tooltip_markup (GTK_WIDGET (self), tooltip);
else
gtk_widget_set_tooltip_text (GTK_WIDGET (self),
- adw_tab_page_get_title (self->page));
+ adw_tab_page_get_title (page));
}
static void
update_title (AdwTab *self)
{
- const char *title = adw_tab_page_get_title (self->page);
+ AdwTabPage *page = adw_tab_item_get_page (ADW_TAB_ITEM (self));
+ const char *title = adw_tab_page_get_title (page);
PangoDirection title_direction = PANGO_DIRECTION_NEUTRAL;
GtkTextDirection direction = gtk_widget_get_direction (GTK_WIDGET (self));
gboolean title_inverted;
@@ -185,7 +161,8 @@ update_title (AdwTab *self)
static void
update_spinner (AdwTab *self)
{
- gboolean loading = self->page && adw_tab_page_get_loading (self->page);
+ AdwTabPage *page = adw_tab_item_get_page (ADW_TAB_ITEM (self));
+ gboolean loading = page && adw_tab_page_get_loading (page);
gboolean mapped = gtk_widget_get_mapped (GTK_WIDGET (self));
/* Don't use CPU when not needed */
@@ -195,18 +172,21 @@ update_spinner (AdwTab *self)
static void
update_icons (AdwTab *self)
{
- GIcon *gicon = adw_tab_page_get_icon (self->page);
- gboolean loading = adw_tab_page_get_loading (self->page);
- GIcon *indicator = adw_tab_page_get_indicator_icon (self->page);
+ AdwTabView *view = adw_tab_item_get_view (ADW_TAB_ITEM (self));
+ AdwTabPage *page = adw_tab_item_get_page (ADW_TAB_ITEM (self));
+ gboolean pinned = adw_tab_item_get_pinned (ADW_TAB_ITEM (self));
+ GIcon *gicon = adw_tab_page_get_icon (page);
+ gboolean loading = adw_tab_page_get_loading (page);
+ GIcon *indicator = adw_tab_page_get_indicator_icon (page);
const char *name = loading ? "spinner" : "icon";
- if (self->pinned && !gicon)
- gicon = adw_tab_view_get_default_icon (self->view);
+ if (pinned && !gicon)
+ gicon = adw_tab_view_get_default_icon (view);
gtk_image_set_from_gicon (self->icon, gicon);
gtk_widget_set_visible (self->icon_stack,
(gicon != NULL || loading) &&
- (!self->pinned || indicator == NULL));
+ (!pinned || indicator == NULL));
gtk_stack_set_visible_child_name (GTK_STACK (self->icon_stack), name);
gtk_widget_set_visible (self->indicator_btn, indicator != NULL);
@@ -215,8 +195,11 @@ update_icons (AdwTab *self)
static void
update_indicator (AdwTab *self)
{
- gboolean activatable = self->page && adw_tab_page_get_indicator_activatable (self->page);
- gboolean clickable = activatable && (self->selected || (!self->pinned && self->fully_visible));
+ AdwTabPage *page = adw_tab_item_get_page (ADW_TAB_ITEM (self));
+ gboolean pinned = adw_tab_item_get_pinned (ADW_TAB_ITEM (self));
+ gboolean fully_visible = adw_tab_item_get_fully_visible (ADW_TAB_ITEM (self));
+ gboolean activatable = page && adw_tab_page_get_indicator_activatable (page);
+ gboolean clickable = activatable && (self->selected || (!pinned && fully_visible));
gtk_widget_set_can_target (self->indicator_btn, clickable);
}
@@ -224,98 +207,61 @@ update_indicator (AdwTab *self)
static void
update_needs_attention (AdwTab *self)
{
+ AdwTabPage *page = adw_tab_item_get_page (ADW_TAB_ITEM (self));
+
set_style_class (GTK_WIDGET (self), "needs-attention",
- adw_tab_page_get_needs_attention (self->page));
+ adw_tab_page_get_needs_attention (page));
}
static void
update_loading (AdwTab *self)
{
+ AdwTabPage *page = adw_tab_item_get_page (ADW_TAB_ITEM (self));
+
update_icons (self);
update_spinner (self);
set_style_class (GTK_WIDGET (self), "loading",
- adw_tab_page_get_loading (self->page));
+ adw_tab_page_get_loading (page));
}
static void
update_selected (AdwTab *self)
{
- self->selected = self->dragging;
+ AdwTabPage *page = adw_tab_item_get_page (ADW_TAB_ITEM (self));
+
+ self->selected = adw_tab_item_get_dragging (ADW_TAB_ITEM (self));
- if (self->page)
- self->selected |= adw_tab_page_get_selected (self->page);
+ if (page)
+ self->selected |= adw_tab_page_get_selected (page);
update_state (self);
update_indicator (self);
}
-static gboolean
-close_idle_cb (AdwTab *self)
-{
- adw_tab_view_close_page (self->view, self->page);
-
- return G_SOURCE_REMOVE;
-}
-
-static void
-close_clicked_cb (AdwTab *self)
-{
- if (!self->page)
- return;
-
- /* When animations are disabled, we don't want to immediately remove the
- * whole tab mid-click. Instead, defer it until the click has happened.
- */
- g_idle_add ((GSourceFunc) close_idle_cb, self);
-}
-
static void
-indicator_clicked_cb (AdwTab *self)
+notify_dragging_cb (AdwTab *self)
{
- if (!self->page)
- return;
-
- g_signal_emit_by_name (self->view, "indicator-activated", self->page);
+ update_state (self);
+ update_selected (self);
}
static void
-motion_cb (AdwTab *self,
- double x,
- double y,
- GtkEventController *controller)
+notify_fully_visible_cb (AdwTab *self)
{
- GdkDevice *device = gtk_event_controller_get_current_event_device (controller);
- GdkInputSource input_source = gdk_device_get_source (device);
-
- if (input_source == GDK_SOURCE_TOUCHSCREEN)
- return;
-
- if (self->hovering)
- return;
-
- self->hovering = TRUE;
-
update_state (self);
+ update_indicator (self);
}
static void
-leave_cb (AdwTab *self,
- GtkEventController *controller)
+close_clicked_cb (AdwTab *self)
{
- self->hovering = FALSE;
-
- update_state (self);
+ adw_tab_item_close (ADW_TAB_ITEM (self));
}
-static gboolean
-drop_cb (AdwTab *self,
- GValue *value)
+static void
+indicator_clicked_cb (AdwTab *self)
{
- gboolean ret = GDK_EVENT_PROPAGATE;
-
- g_signal_emit (self, signals[SIGNAL_EXTRA_DRAG_DROP], 0, value, &ret);
-
- return ret;
+ adw_tab_item_activate_indicator (ADW_TAB_ITEM (self));
}
static void
@@ -343,20 +289,61 @@ ensure_shader (AdwTab *self)
}
}
-static gboolean
-activate_cb (AdwTab *self,
- GVariant *args)
+static void
+adw_tab_connect_page (AdwTabItem *item)
{
- GtkWidget *child;
+ AdwTab *self = ADW_TAB (item);
+ AdwTabPage *page = adw_tab_item_get_page (item);
- if (!self->page || !self->view)
- return GDK_EVENT_PROPAGATE;
+ update_selected (self);
+ update_state (self);
+ update_title (self);
+ update_tooltip (self);
+ update_spinner (self);
+ update_icons (self);
+ update_indicator (self);
+ update_needs_attention (self);
+ update_loading (self);
- child = adw_tab_page_get_child (self->page);
+ g_signal_connect_object (page, "notify::selected",
+ G_CALLBACK (update_selected), self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (page, "notify::title",
+ G_CALLBACK (update_title), self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (page, "notify::tooltip",
+ G_CALLBACK (update_tooltip), self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (page, "notify::icon",
+ G_CALLBACK (update_icons), self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (page, "notify::indicator-icon",
+ G_CALLBACK (update_icons), self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (page, "notify::indicator-activatable",
+ G_CALLBACK (update_indicator), self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (page, "notify::needs-attention",
+ G_CALLBACK (update_needs_attention), self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (page, "notify::loading",
+ G_CALLBACK (update_loading), self,
+ G_CONNECT_SWAPPED);
+}
- gtk_widget_grab_focus (child);
+static void
+adw_tab_disconnect_page (AdwTabItem *item)
+{
+ AdwTab *self = ADW_TAB (item);
+ AdwTabPage *page = adw_tab_item_get_page (item);
- return GDK_EVENT_STOP;
+ g_signal_handlers_disconnect_by_func (page, update_selected, self);
+ g_signal_handlers_disconnect_by_func (page, update_title, self);
+ g_signal_handlers_disconnect_by_func (page, update_tooltip, self);
+ g_signal_handlers_disconnect_by_func (page, update_icons, self);
+ g_signal_handlers_disconnect_by_func (page, update_indicator, self);
+ g_signal_handlers_disconnect_by_func (page, update_needs_attention, self);
+ g_signal_handlers_disconnect_by_func (page, update_loading, self);
}
static void
@@ -369,10 +356,11 @@ adw_tab_measure (GtkWidget *widget,
int *natural_baseline)
{
AdwTab *self = ADW_TAB (widget);
+ gboolean pinned = adw_tab_item_get_pinned (ADW_TAB_ITEM (self));
int min = 0, nat = 0;
if (orientation == GTK_ORIENTATION_HORIZONTAL) {
- nat = self->pinned ? BASE_WIDTH_PINNED : BASE_WIDTH;
+ nat = pinned ? BASE_WIDTH_PINNED : BASE_WIDTH;
} else {
int child_min, child_nat;
@@ -445,6 +433,7 @@ allocate_contents (AdwTab *self,
int indicator_width, close_width, icon_width, title_width;
int center_x, center_width = 0;
int start_width = 0, end_width = 0;
+ gboolean inverted = adw_tab_item_get_inverted (ADW_TAB_ITEM (self));
measure_child (self->icon_stack, alloc->height, &icon_width);
measure_child (self->title, alloc->height, &title_width);
@@ -452,12 +441,12 @@ allocate_contents (AdwTab *self,
measure_child (self->close_btn, alloc->height, &close_width);
if (gtk_widget_get_visible (self->indicator_btn)) {
- if (self->pinned) {
+ if (adw_tab_item_get_pinned (ADW_TAB_ITEM (self))) {
/* Center it in a pinned tab */
allocate_child (self->indicator_btn, alloc,
(alloc->width - indicator_width) / 2, indicator_width,
baseline);
- } else if (self->inverted) {
+ } else if (inverted) {
allocate_child (self->indicator_btn, alloc,
alloc->width - indicator_width, indicator_width,
baseline);
@@ -471,7 +460,7 @@ allocate_contents (AdwTab *self,
}
if (gtk_widget_get_visible (self->close_btn)) {
- if (self->inverted) {
+ if (inverted) {
allocate_child (self->close_btn, alloc, 0, close_width, baseline);
start_width = close_width;
@@ -490,7 +479,7 @@ allocate_contents (AdwTab *self,
start_width,
alloc->width - center_width - end_width);
- self->close_overlap = !self->inverted &&
+ self->close_overlap = !inverted &&
!self->title_inverted &&
gtk_widget_get_visible (self->title) &&
gtk_widget_get_visible (self->close_btn) &&
@@ -514,6 +503,7 @@ adw_tab_size_allocate (GtkWidget *widget,
int baseline)
{
AdwTab *self = ADW_TAB (widget);
+ int display_width = adw_tab_item_get_display_width (ADW_TAB_ITEM (self));
GtkAllocation child_alloc;
int allocated_width, width_diff;
@@ -524,7 +514,7 @@ adw_tab_size_allocate (GtkWidget *widget,
return;
allocated_width = gtk_widget_get_allocated_width (widget);
- width_diff = MAX (0, self->display_width - allocated_width);
+ width_diff = MAX (0, display_width - allocated_width);
child_alloc.x = -width_diff / 2;
child_alloc.y = 0;
@@ -634,10 +624,11 @@ static void
adw_tab_constructed (GObject *object)
{
AdwTab *self = ADW_TAB (object);
+ AdwTabView *view = adw_tab_item_get_view (ADW_TAB_ITEM (self));
G_OBJECT_CLASS (adw_tab_parent_class)->constructed (object);
- if (self->pinned) {
+ if (adw_tab_item_get_pinned (ADW_TAB_ITEM (self))) {
gtk_widget_add_css_class (GTK_WIDGET (self), "pinned");
gtk_widget_hide (self->title);
gtk_widget_hide (self->close_btn);
@@ -645,94 +636,16 @@ adw_tab_constructed (GObject *object)
gtk_widget_set_margin_end (self->icon_stack, 0);
}
- g_signal_connect_object (self->view, "notify::default-icon",
+ g_signal_connect_object (view, "notify::default-icon",
G_CALLBACK (update_icons), self,
G_CONNECT_SWAPPED);
}
-static void
-adw_tab_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- AdwTab *self = ADW_TAB (object);
-
- switch (prop_id) {
- case PROP_VIEW:
- g_value_set_object (value, self->view);
- break;
-
- case PROP_PAGE:
- g_value_set_object (value, adw_tab_get_page (self));
- break;
-
- case PROP_PINNED:
- g_value_set_boolean (value, self->pinned);
- break;
-
- case PROP_DRAGGING:
- g_value_set_boolean (value, adw_tab_get_dragging (self));
- break;
-
- case PROP_DISPLAY_WIDTH:
- g_value_set_int (value, adw_tab_get_display_width (self));
- break;
-
- case PROP_INVERTED:
- g_value_set_boolean (value, adw_tab_get_inverted (self));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-adw_tab_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- AdwTab *self = ADW_TAB (object);
-
- switch (prop_id) {
- case PROP_VIEW:
- self->view = g_value_get_object (value);
- break;
-
- case PROP_PAGE:
- adw_tab_set_page (self, g_value_get_object (value));
- break;
-
- case PROP_PINNED:
- self->pinned = g_value_get_boolean (value);
- break;
-
- case PROP_DRAGGING:
- adw_tab_set_dragging (self, g_value_get_boolean (value));
- break;
-
- case PROP_DISPLAY_WIDTH:
- adw_tab_set_display_width (self, g_value_get_int (value));
- break;
-
- case PROP_INVERTED:
- adw_tab_set_inverted (self, g_value_get_boolean (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
static void
adw_tab_dispose (GObject *object)
{
AdwTab *self = ADW_TAB (object);
- adw_tab_set_page (self, NULL);
-
g_clear_object (&self->shader);
gtk_widget_unparent (self->indicator_btn);
gtk_widget_unparent (self->icon_stack);
@@ -747,11 +660,10 @@ adw_tab_class_init (AdwTabClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ AdwTabItemClass *item_class = ADW_TAB_ITEM_CLASS (klass);
object_class->dispose = adw_tab_dispose;
object_class->constructed = adw_tab_constructed;
- object_class->get_property = adw_tab_get_property;
- object_class->set_property = adw_tab_set_property;
widget_class->measure = adw_tab_measure;
widget_class->size_allocate = adw_tab_size_allocate;
@@ -761,59 +673,8 @@ adw_tab_class_init (AdwTabClass *klass)
widget_class->direction_changed = adw_tab_direction_changed;
widget_class->unrealize = adw_tab_unrealize;
- props[PROP_VIEW] =
- g_param_spec_object ("view",
- "View",
- "View",
- ADW_TYPE_TAB_VIEW,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
-
- props[PROP_PINNED] =
- g_param_spec_boolean ("pinned",
- "Pinned",
- "Pinned",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
-
- props[PROP_DRAGGING] =
- g_param_spec_boolean ("dragging",
- "Dragging",
- "Dragging",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
-
- props[PROP_PAGE] =
- g_param_spec_object ("page",
- "Page",
- "Page",
- ADW_TYPE_TAB_PAGE,
- G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
-
- props[PROP_DISPLAY_WIDTH] =
- g_param_spec_int ("display-width",
- "Display Width",
- "Display Width",
- 0, G_MAXINT, 0,
- G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
-
- props[PROP_INVERTED] =
- g_param_spec_boolean ("inverted",
- "Inverted",
- "Inverted",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
-
- signals[SIGNAL_EXTRA_DRAG_DROP] =
- g_signal_new ("extra-drag-drop",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0,
- g_signal_accumulator_first_wins, NULL, NULL,
- G_TYPE_BOOLEAN,
- 1,
- G_TYPE_VALUE);
-
- g_object_class_install_properties (object_class, LAST_PROP, props);
+ item_class->connect_page = adw_tab_connect_page;
+ item_class->disconnect_page = adw_tab_disconnect_page;
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/Adwaita/ui/adw-tab.ui");
@@ -824,226 +685,19 @@ adw_tab_class_init (AdwTabClass *klass)
gtk_widget_class_bind_template_child (widget_class, AdwTab, indicator_icon);
gtk_widget_class_bind_template_child (widget_class, AdwTab, indicator_btn);
gtk_widget_class_bind_template_child (widget_class, AdwTab, close_btn);
+ gtk_widget_class_bind_template_callback (widget_class, update_state);
+ gtk_widget_class_bind_template_callback (widget_class, notify_dragging_cb);
+ gtk_widget_class_bind_template_callback (widget_class, notify_fully_visible_cb);
gtk_widget_class_bind_template_callback (widget_class, close_clicked_cb);
gtk_widget_class_bind_template_callback (widget_class, indicator_clicked_cb);
- gtk_widget_class_add_binding (widget_class, GDK_KEY_space, 0, (GtkShortcutFunc) activate_cb, NULL);
- gtk_widget_class_add_binding (widget_class, GDK_KEY_KP_Space, 0, (GtkShortcutFunc) activate_cb, NULL);
- gtk_widget_class_add_binding (widget_class, GDK_KEY_Return, 0, (GtkShortcutFunc) activate_cb, NULL);
- gtk_widget_class_add_binding (widget_class, GDK_KEY_ISO_Enter, 0, (GtkShortcutFunc) activate_cb, NULL);
- gtk_widget_class_add_binding (widget_class, GDK_KEY_KP_Enter, 0, (GtkShortcutFunc) activate_cb, NULL);
-
gtk_widget_class_set_css_name (widget_class, "tab");
}
static void
adw_tab_init (AdwTab *self)
{
- GtkEventController *controller;
-
g_type_ensure (ADW_TYPE_FADING_LABEL);
gtk_widget_init_template (GTK_WIDGET (self));
-
- controller = gtk_event_controller_motion_new ();
- g_signal_connect_swapped (controller, "motion", G_CALLBACK (motion_cb), self);
- g_signal_connect_swapped (controller, "leave", G_CALLBACK (leave_cb), self);
- gtk_widget_add_controller (GTK_WIDGET (self), controller);
-}
-
-AdwTab *
-adw_tab_new (AdwTabView *view,
- gboolean pinned)
-{
- g_return_val_if_fail (ADW_IS_TAB_VIEW (view), NULL);
-
- return g_object_new (ADW_TYPE_TAB,
- "view", view,
- "pinned", pinned,
- NULL);
-}
-
-AdwTabPage *
-adw_tab_get_page (AdwTab *self)
-{
- g_return_val_if_fail (ADW_IS_TAB (self), NULL);
-
- return self->page;
-}
-
-void
-adw_tab_set_page (AdwTab *self,
- AdwTabPage *page)
-{
- g_return_if_fail (ADW_IS_TAB (self));
- g_return_if_fail (page == NULL || ADW_IS_TAB_PAGE (page));
-
- if (self->page == page)
- return;
-
- if (self->page) {
- g_signal_handlers_disconnect_by_func (self->page, update_selected, self);
- g_signal_handlers_disconnect_by_func (self->page, update_title, self);
- g_signal_handlers_disconnect_by_func (self->page, update_tooltip, self);
- g_signal_handlers_disconnect_by_func (self->page, update_icons, self);
- g_signal_handlers_disconnect_by_func (self->page, update_indicator, self);
- g_signal_handlers_disconnect_by_func (self->page, update_needs_attention, self);
- g_signal_handlers_disconnect_by_func (self->page, update_loading, self);
- }
-
- g_set_object (&self->page, page);
-
- if (self->page) {
- update_selected (self);
- update_state (self);
- update_title (self);
- update_tooltip (self);
- update_spinner (self);
- update_icons (self);
- update_indicator (self);
- update_needs_attention (self);
- update_loading (self);
-
- g_signal_connect_object (self->page, "notify::selected",
- G_CALLBACK (update_selected), self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (self->page, "notify::title",
- G_CALLBACK (update_title), self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (self->page, "notify::tooltip",
- G_CALLBACK (update_tooltip), self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (self->page, "notify::icon",
- G_CALLBACK (update_icons), self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (self->page, "notify::indicator-icon",
- G_CALLBACK (update_icons), self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (self->page, "notify::indicator-activatable",
- G_CALLBACK (update_indicator), self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (self->page, "notify::needs-attention",
- G_CALLBACK (update_needs_attention), self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (self->page, "notify::loading",
- G_CALLBACK (update_loading), self,
- G_CONNECT_SWAPPED);
- }
-
- g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PAGE]);
-}
-
-int
-adw_tab_get_display_width (AdwTab *self)
-{
- g_return_val_if_fail (ADW_IS_TAB (self), 0);
-
- return self->display_width;
-}
-
-void
-adw_tab_set_display_width (AdwTab *self,
- int width)
-{
- g_return_if_fail (ADW_IS_TAB (self));
- g_return_if_fail (width >= 0);
-
- if (self->display_width == width)
- return;
-
- self->display_width = width;
-
- gtk_widget_queue_resize (GTK_WIDGET (self));
-
- g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DISPLAY_WIDTH]);
-}
-
-gboolean
-adw_tab_get_dragging (AdwTab *self)
-{
- g_return_val_if_fail (ADW_IS_TAB (self), FALSE);
-
- return self->dragging;
-}
-
-void
-adw_tab_set_dragging (AdwTab *self,
- gboolean dragging)
-{
- g_return_if_fail (ADW_IS_TAB (self));
-
- dragging = !!dragging;
-
- if (self->dragging == dragging)
- return;
-
- self->dragging = dragging;
-
- update_state (self);
- update_selected (self);
-
- g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DRAGGING]);
-}
-
-gboolean
-adw_tab_get_inverted (AdwTab *self)
-{
- g_return_val_if_fail (ADW_IS_TAB (self), FALSE);
-
- return self->inverted;
-}
-
-void
-adw_tab_set_inverted (AdwTab *self,
- gboolean inverted)
-{
- g_return_if_fail (ADW_IS_TAB (self));
-
- inverted = !!inverted;
-
- if (self->inverted == inverted)
- return;
-
- self->inverted = inverted;
-
- gtk_widget_queue_allocate (GTK_WIDGET (self));
-
- g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INVERTED]);
-}
-
-void
-adw_tab_set_fully_visible (AdwTab *self,
- gboolean fully_visible)
-{
- g_return_if_fail (ADW_IS_TAB (self));
-
- fully_visible = !!fully_visible;
-
- if (self->fully_visible == fully_visible)
- return;
-
- self->fully_visible = fully_visible;
-
- update_state (self);
- update_indicator (self);
-}
-
-void
-adw_tab_setup_extra_drop_target (AdwTab *self,
- GdkDragAction actions,
- GType *types,
- gsize n_types)
-{
- g_return_if_fail (ADW_IS_TAB (self));
- g_return_if_fail (n_types == 0 || types != NULL);
-
- if (!self->drop_target) {
- self->drop_target = gtk_drop_target_new (G_TYPE_INVALID, actions);
- g_signal_connect_swapped (self->drop_target, "drop", G_CALLBACK (drop_cb), self);
- gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (self->drop_target));
- } else {
- gtk_drop_target_set_actions (self->drop_target, actions);
- }
-
- gtk_drop_target_set_gtypes (self->drop_target, types, n_types);
}
diff --git a/src/adw-tab.ui b/src/adw-tab.ui
index ef11e4b8..2e45ecd6 100644
--- a/src/adw-tab.ui
+++ b/src/adw-tab.ui
@@ -1,9 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="libadwaita">
<requires lib="gtk" version="4.0"/>
- <template class="AdwTab" parent="GtkWidget">
+ <template class="AdwTab" parent="AdwTabItem">
<property name="focusable">True</property>
<property name="overflow">hidden</property>
+ <signal name="notify::hovering" handler="update_state" swapped="true"/>
+ <signal name="notify::dragging" handler="notify_dragging_cb" swapped="true"/>
+ <signal name="notify::fully-visible" handler="notify_fully_visible_cb" swapped="true"/>
<child>
<object class="GtkButton" id="indicator_btn">
<property name="can-focus">False</property>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]