[libadwaita/wip/exalm/tab-overview] tab-view: Port away from GtkStack



commit 6ff6dbfb57a8b2628301d4b1834481105984b47e
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 | 128 +++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 104 insertions(+), 24 deletions(-)
---
diff --git a/src/adw-tab-view.c b/src/adw-tab-view.c
index e09db5ab..f2de2ff7 100644
--- a/src/adw-tab-view.c
+++ b/src/adw-tab-view.c
@@ -134,6 +134,8 @@ struct _AdwTabPage
   float thumbnail_xalign;
   float thumbnail_yalign;
 
+  GtkWidget *last_focus;
+
   gboolean closing;
   GdkPaintable *paintable;
 };
@@ -166,7 +168,6 @@ struct _AdwTabView
 {
   GtkWidget parent_instance;
 
-  GtkWidget *stack;
   GListStore *children;
 
   int n_pages;
@@ -314,6 +315,10 @@ adw_tab_page_finalize (GObject *object)
   g_clear_pointer (&self->indicator_tooltip, g_free);
   g_clear_pointer (&self->keyword, 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);
 }
 
@@ -1175,7 +1180,7 @@ 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->child) == GTK_WIDGET (self);
 }
 
 static inline gboolean
@@ -1198,7 +1203,9 @@ attach_page (AdwTabView *self,
 
   g_list_store_insert (self->children, position, page);
 
-  gtk_stack_add_child (GTK_STACK (self->stack), child);
+  gtk_widget_set_child_visible (child, FALSE);
+  gtk_widget_set_parent (child, GTK_WIDGET (self));
+  gtk_widget_queue_resize (GTK_WIDGET (self));
 
   g_object_freeze_notify (G_OBJECT (self));
 
@@ -1224,14 +1231,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->child &&
+        gtk_widget_is_ancestor (focus, self->selected_page->child)) {
+      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->child)
+      gtk_widget_set_child_visible (self->selected_page->child, FALSE);
+
     set_page_selected (self->selected_page, FALSE);
   }
 
@@ -1241,8 +1270,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->child, TRUE);
+
+      if (contains_focus) {
+        if (selected_page->last_focus)
+          gtk_widget_grab_focus (selected_page->last_focus);
+        else
+          gtk_widget_child_focus (selected_page->child, GTK_DIR_TAB_FORWARD);
+      }
+
+      gtk_widget_queue_allocate (GTK_WIDGET (self));
+    }
+
     set_page_selected (self->selected_page, TRUE);
   }
 
@@ -1308,7 +1348,7 @@ select_previous_page (AdwTabView *self,
 static void
 detach_page (AdwTabView *self,
              AdwTabPage *page,
-             gboolean    notify_pages)
+             gboolean    in_dispose)
 {
   int pos = adw_tab_view_get_page_position (self, page);
   GtkWidget *child;
@@ -1321,7 +1361,7 @@ detach_page (AdwTabView *self,
   g_object_ref (child);
 
   if (self->n_pages == 1)
-    set_selected_page (self, NULL, notify_pages);
+    set_selected_page (self, NULL, !in_dispose);
 
   g_list_store_remove (self->children, pos);
 
@@ -1334,11 +1374,14 @@ detach_page (AdwTabView *self,
 
   g_object_thaw_notify (G_OBJECT (self));
 
-  gtk_stack_remove (GTK_STACK (self->stack), child);
+  gtk_widget_unparent (child);
+
+  if (!in_dispose)
+    gtk_widget_queue_resize (GTK_WIDGET (self));
 
   g_signal_emit (self, signals[SIGNAL_PAGE_DETACHED], 0, page, pos);
 
-  if (notify_pages && self->pages)
+  if (!in_dispose && self->pages)
     g_list_model_items_changed (G_LIST_MODEL (self->pages), pos, 1, 0);
 
   g_object_unref (child);
@@ -1643,6 +1686,50 @@ 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);
+
+    if (gtk_widget_get_visible (page->child)) {
+      int child_min, child_nat;
+
+      gtk_widget_measure (page->child, 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->child, width, height, baseline, NULL);
+}
+
 static void
 adw_tab_view_dispose (GObject *object)
 {
@@ -1654,13 +1741,11 @@ adw_tab_view_dispose (GObject *object)
   while (self->n_pages) {
     AdwTabPage *page = adw_tab_view_get_nth_page (self, 0);
 
-    detach_page (self, page, FALSE);
+    detach_page (self, page, TRUE);
   }
 
   g_clear_object (&self->children);
 
-  g_clear_pointer (&self->stack, gtk_widget_unparent);
-
   G_OBJECT_CLASS (adw_tab_view_parent_class)->dispose (object);
 }
 
@@ -1768,6 +1853,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;
 
   /**
@@ -2093,7 +2181,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
@@ -2105,14 +2193,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 ();
@@ -3280,7 +3360,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 (gtk_widget_get_parent (child) == GTK_WIDGET (self), NULL);
 
   for (i = 0; i < self->n_pages; i++) {
     AdwTabPage *page = adw_tab_view_get_nth_page (self, i);
@@ -3625,7 +3705,7 @@ adw_tab_view_close_page_finish (AdwTabView *self,
     adw_tab_paintable_freeze (ADW_TAB_PAINTABLE (page->paintable));
 
   if (confirm)
-    detach_page (self, page, TRUE);
+    detach_page (self, page, FALSE);
 }
 
 /**
@@ -3905,7 +3985,7 @@ adw_tab_view_detach_page (AdwTabView *self,
 
   begin_transfer_for_group (self);
 
-  detach_page (self, page, TRUE);
+  detach_page (self, page, FALSE);
 }
 
 void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]