[libadwaita/wip/exalm/tab-overview: 10/18] tab-view: Port away from GtkStack
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libadwaita/wip/exalm/tab-overview: 10/18] tab-view: Port away from GtkStack
- Date: Thu, 15 Sep 2022 14:55:11 +0000 (UTC)
commit 3db81a0a3b65bba0abae19ecb72e5fce536540bd
Author: Alexander Mikhaylenko <alexm gnome org>
Date: Sat Aug 27 07:23:12 2022 +0400
tab-view: Port away from GtkStack
src/adw-tab-view.c | 153 ++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 128 insertions(+), 25 deletions(-)
---
diff --git a/src/adw-tab-view.c b/src/adw-tab-view.c
index ab727a56..a785f9d7 100644
--- a/src/adw-tab-view.c
+++ b/src/adw-tab-view.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020-2021 Purism SPC
+ * Copyright (C) 2020-2022 Purism SPC
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
@@ -10,6 +10,7 @@
#include "adw-tab-view-private.h"
+#include "adw-bin.h"
#include "adw-gizmo-private.h"
#include "adw-macros-private.h"
#include "adw-widget-utils-private.h"
@@ -115,6 +116,7 @@ struct _AdwTabPage
{
GObject parent_instance;
+ GtkWidget *bin;
GtkWidget *child;
AdwTabPage *parent;
gboolean selected;
@@ -128,6 +130,9 @@ struct _AdwTabPage
gboolean indicator_activatable;
gboolean needs_attention;
+ GtkWidget *last_focus;
+ GBinding *transfer_binding;
+
gboolean closing;
};
@@ -156,7 +161,6 @@ struct _AdwTabView
{
GtkWidget parent_instance;
- GtkWidget *stack;
GListStore *children;
int n_pages;
@@ -286,6 +290,8 @@ adw_tab_page_dispose (GObject *object)
set_page_parent (self, NULL);
+ g_clear_object (&self->bin);
+
G_OBJECT_CLASS (adw_tab_page_parent_class)->dispose (object);
}
@@ -301,6 +307,10 @@ adw_tab_page_finalize (GObject *object)
g_clear_object (&self->indicator_icon);
g_clear_pointer (&self->indicator_tooltip, g_free);
+ if (self->last_focus)
+ g_object_remove_weak_pointer (G_OBJECT (self->last_focus),
+ (gpointer *) &self->last_focus);
+
G_OBJECT_CLASS (adw_tab_page_parent_class)->finalize (object);
}
@@ -377,6 +387,7 @@ adw_tab_page_set_property (GObject *object,
switch (prop_id) {
case PAGE_PROP_CHILD:
g_set_object (&self->child, g_value_get_object (value));
+ adw_bin_set_child (ADW_BIN (self->bin), g_value_get_object (value));
break;
case PAGE_PROP_PARENT:
@@ -632,6 +643,7 @@ adw_tab_page_init (AdwTabPage *self)
self->title = g_strdup ("");
self->tooltip = g_strdup ("");
self->indicator_tooltip = g_strdup ("");
+ self->bin = g_object_ref_sink (adw_bin_new ());
}
#define ADW_TYPE_TAB_PAGES (adw_tab_pages_get_type ())
@@ -813,7 +825,24 @@ page_belongs_to_this_view (AdwTabView *self,
if (!page)
return FALSE;
- return gtk_widget_get_parent (page->child) == self->stack;
+ return gtk_widget_get_parent (page->bin) == GTK_WIDGET (self);
+}
+
+static inline gboolean
+child_belongs_to_this_view (AdwTabView *self,
+ GtkWidget *child)
+{
+ GtkWidget *parent;
+
+ if (!child)
+ return FALSE;
+
+ parent = gtk_widget_get_parent (child);
+
+ if (!parent)
+ return FALSE;
+
+ return gtk_widget_get_parent (parent) == GTK_WIDGET (self);
}
static inline gboolean
@@ -831,12 +860,18 @@ attach_page (AdwTabView *self,
AdwTabPage *page,
int position)
{
- GtkWidget *child = adw_tab_page_get_child (page);
AdwTabPage *parent;
g_list_store_insert (self->children, position, page);
- gtk_stack_add_child (GTK_STACK (self->stack), child);
+ gtk_widget_set_child_visible (page->bin, FALSE);
+ gtk_widget_set_parent (page->bin, GTK_WIDGET (self));
+ page->transfer_binding =
+ g_object_bind_property (self, "is-transferring-page",
+ page->bin, "can-target",
+ G_BINDING_SYNC_CREATE |
+ G_BINDING_INVERT_BOOLEAN);
+ gtk_widget_queue_resize (GTK_WIDGET (self));
g_object_freeze_notify (G_OBJECT (self));
@@ -862,14 +897,36 @@ set_selected_page (AdwTabView *self,
{
guint old_position = GTK_INVALID_LIST_POSITION;
guint new_position = GTK_INVALID_LIST_POSITION;
+ gboolean contains_focus = FALSE;
if (self->selected_page == selected_page)
return;
if (self->selected_page) {
+ GtkRoot *root = gtk_widget_get_root (GTK_WIDGET (self));
+ GtkWidget *focus = root ? gtk_root_get_focus (root) : NULL;
+
if (notify_pages && self->pages)
old_position = adw_tab_view_get_page_position (self, self->selected_page);
+ if (!gtk_widget_in_destruction (GTK_WIDGET (self)) &&
+ focus &&
+ self->selected_page &&
+ self->selected_page->bin &&
+ gtk_widget_is_ancestor (focus, self->selected_page->bin)) {
+ contains_focus = TRUE;
+
+ if (self->selected_page->last_focus)
+ g_object_remove_weak_pointer (G_OBJECT (self->selected_page->last_focus),
+ (gpointer *) &self->selected_page->last_focus);
+ self->selected_page->last_focus = focus;
+ g_object_add_weak_pointer (G_OBJECT (self->selected_page->last_focus),
+ (gpointer *) &self->selected_page->last_focus);
+ }
+
+ if (self->selected_page->bin)
+ gtk_widget_set_child_visible (self->selected_page->bin, FALSE);
+
set_page_selected (self->selected_page, FALSE);
}
@@ -879,8 +936,19 @@ set_selected_page (AdwTabView *self,
if (notify_pages && self->pages)
new_position = adw_tab_view_get_page_position (self, self->selected_page);
- gtk_stack_set_visible_child (GTK_STACK (self->stack),
- adw_tab_page_get_child (selected_page));
+ if (!gtk_widget_in_destruction (GTK_WIDGET (self))) {
+ gtk_widget_set_child_visible (selected_page->bin, TRUE);
+
+ if (contains_focus) {
+ if (selected_page->last_focus)
+ gtk_widget_grab_focus (selected_page->last_focus);
+ else
+ gtk_widget_child_focus (selected_page->bin, GTK_DIR_TAB_FORWARD);
+ }
+
+ gtk_widget_queue_allocate (GTK_WIDGET (self));
+ }
+
set_page_selected (self->selected_page, TRUE);
}
@@ -949,14 +1017,11 @@ detach_page (AdwTabView *self,
gboolean in_dispose)
{
int pos = adw_tab_view_get_page_position (self, page);
- GtkWidget *child;
select_previous_page (self, page);
- child = adw_tab_page_get_child (page);
-
g_object_ref (page);
- g_object_ref (child);
+ g_object_ref (page->bin);
if (self->n_pages == 1)
set_selected_page (self, NULL, !in_dispose);
@@ -972,14 +1037,18 @@ detach_page (AdwTabView *self,
g_object_thaw_notify (G_OBJECT (self));
- gtk_stack_remove (GTK_STACK (self->stack), child);
+ g_clear_pointer (&page->transfer_binding, g_binding_unbind);
+ gtk_widget_unparent (page->bin);
+
+ if (!in_dispose)
+ gtk_widget_queue_resize (GTK_WIDGET (self));
g_signal_emit (self, signals[SIGNAL_PAGE_DETACHED], 0, page, pos);
if (!in_dispose && self->pages)
g_list_model_items_changed (G_LIST_MODEL (self->pages), pos, 1, 0);
- g_object_unref (child);
+ g_object_unref (page->bin);
g_object_unref (page);
}
@@ -1281,6 +1350,47 @@ init_shortcuts (AdwTabView *self,
(i + 9) % 10); /* Alt+0 means page 10, not 0 */
}
+static void
+adw_tab_view_measure (GtkWidget *widget,
+ GtkOrientation orientation,
+ int for_size,
+ int *minimum,
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
+{
+ AdwTabView *self = ADW_TAB_VIEW (widget);
+ int i;
+
+ *minimum = 0;
+ *natural = 0;
+
+ for (i = 0; i < self->n_pages; i++) {
+ AdwTabPage *page = adw_tab_view_get_nth_page (self, i);
+ int child_min, child_nat;
+
+ gtk_widget_measure (page->bin, orientation, for_size,
+ &child_min, &child_nat, NULL, NULL);
+
+ *minimum = MAX (*minimum, child_min);
+ *natural = MAX (*natural, child_nat);
+ }
+}
+
+static void
+adw_tab_view_size_allocate (GtkWidget *widget,
+ int width,
+ int height,
+ int baseline)
+{
+ AdwTabView *self = ADW_TAB_VIEW (widget);
+
+ if (!self->selected_page)
+ return;
+
+ gtk_widget_allocate (self->selected_page->bin, width, height, baseline, NULL);
+}
+
static void
adw_tab_view_dispose (GObject *object)
{
@@ -1297,8 +1407,6 @@ adw_tab_view_dispose (GObject *object)
g_clear_object (&self->children);
- g_clear_pointer (&self->stack, gtk_widget_unparent);
-
G_OBJECT_CLASS (adw_tab_view_parent_class)->dispose (object);
}
@@ -1406,6 +1514,9 @@ adw_tab_view_class_init (AdwTabViewClass *klass)
object_class->get_property = adw_tab_view_get_property;
object_class->set_property = adw_tab_view_set_property;
+ widget_class->measure = adw_tab_view_measure;
+ widget_class->size_allocate = adw_tab_view_size_allocate;
+ widget_class->get_request_mode = adw_widget_get_request_mode;
widget_class->compute_expand = adw_widget_compute_expand;
/**
@@ -1731,7 +1842,7 @@ adw_tab_view_class_init (AdwTabViewClass *klass)
G_CALLBACK (close_page_cb));
gtk_widget_class_set_css_name (widget_class, "tabview");
- gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
+ gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
}
static void
@@ -1743,14 +1854,6 @@ adw_tab_view_init (AdwTabView *self)
self->default_icon = G_ICON (g_themed_icon_new ("adw-tab-icon-missing-symbolic"));
self->shortcuts = ADW_TAB_VIEW_SHORTCUT_ALL_SHORTCUTS;
- self->stack = gtk_stack_new ();
- gtk_widget_show (self->stack);
- gtk_widget_set_parent (self->stack, GTK_WIDGET (self));
-
- g_object_bind_property (self, "is-transferring-page",
- self->stack, "can-target",
- G_BINDING_INVERT_BOOLEAN);
-
tab_view_list = g_slist_prepend (tab_view_list, self);
controller = gtk_shortcut_controller_new ();
@@ -2779,7 +2882,7 @@ adw_tab_view_get_page (AdwTabView *self,
g_return_val_if_fail (ADW_IS_TAB_VIEW (self), NULL);
g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
- g_return_val_if_fail (gtk_widget_get_parent (child) == self->stack, NULL);
+ g_return_val_if_fail (child_belongs_to_this_view (self, child), NULL);
for (i = 0; i < self->n_pages; i++) {
AdwTabPage *page = adw_tab_view_get_nth_page (self, i);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]