[libadwaita/wip/exalm/tab-overview] a



commit fb0f143522c05fbf1b69d2e6733f2811cee8262e
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Sun Aug 28 21:02:17 2022 +0400

    a

 src/adw-tab-grid.c                    |   3 +
 src/adw-tab-overview.c                |   5 +
 src/adw-tab-view-private.h            |   3 +
 src/adw-tab-view.c                    | 471 +++++++++++++++++++++++++++-------
 src/adw-tab-view.h                    |  12 +
 src/stylesheet/widgets/_tab-view.scss |   9 +-
 6 files changed, 407 insertions(+), 96 deletions(-)
---
diff --git a/src/adw-tab-grid.c b/src/adw-tab-grid.c
index 82609844..f7f9d610 100644
--- a/src/adw-tab-grid.c
+++ b/src/adw-tab-grid.c
@@ -442,6 +442,9 @@ get_max_n_columns (AdwTabGrid *self)
     other_max_columns += info->appear_progress;
   }
 
+  max_columns = MAX (1, max_columns);
+  other_max_columns = MAX (1, other_max_columns);
+
   return MAX (max_columns, other_max_columns);
 }
 
diff --git a/src/adw-tab-overview.c b/src/adw-tab-overview.c
index 9217e64b..bbc29b71 100644
--- a/src/adw-tab-overview.c
+++ b/src/adw-tab-overview.c
@@ -18,6 +18,7 @@
 #include "adw-style-manager.h"
 #include "adw-tab-grid-private.h"
 #include "adw-tab-thumbnail-private.h"
+#include "adw-tab-view-private.h"
 #include "adw-timed-animation.h"
 #include "adw-widget-utils-private.h"
 #include "adw-window-title.h"
@@ -894,6 +895,8 @@ open_animation_done_cb (AdwTabOverview *self)
     gtk_widget_set_can_target (self->child_bin, TRUE);
     gtk_widget_set_can_focus (self->child_bin, TRUE);
 
+    adw_tab_view_close_overview (self->view);
+
     gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (self->search_bar), FALSE);
 
     if (self->last_focus) {
@@ -1896,6 +1899,8 @@ adw_tab_overview_set_open (AdwTabOverview *self,
                                  (gpointer *) &self->last_focus);
     }
 
+    adw_tab_view_open_overview (self->view);
+
     gtk_widget_set_child_visible (self->overview, TRUE);
     gtk_widget_set_can_target (self->overview, TRUE);
     gtk_widget_set_can_focus (self->overview, TRUE);
diff --git a/src/adw-tab-view-private.h b/src/adw-tab-view-private.h
index 9a250bf8..e26b4f2b 100644
--- a/src/adw-tab-view-private.h
+++ b/src/adw-tab-view-private.h
@@ -29,4 +29,7 @@ void adw_tab_view_attach_page (AdwTabView *self,
 
 AdwTabView *adw_tab_view_create_window (AdwTabView *self) G_GNUC_WARN_UNUSED_RESULT;
 
+void adw_tab_view_open_overview (AdwTabView *self);
+void adw_tab_view_close_overview (AdwTabView *self);
+
 G_END_DECLS
diff --git a/src/adw-tab-view.c b/src/adw-tab-view.c
index f2de2ff7..12b1d1a2 100644
--- a/src/adw-tab-view.c
+++ b/src/adw-tab-view.c
@@ -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"
@@ -118,6 +119,7 @@ struct _AdwTabPage
 {
   GObject parent_instance;
 
+  GtkWidget *bin;
   GtkWidget *child;
   AdwTabPage *parent;
   gboolean selected;
@@ -135,9 +137,13 @@ struct _AdwTabPage
   float thumbnail_yalign;
 
   GtkWidget *last_focus;
+  GBinding *transfer_binding;
 
   gboolean closing;
   GdkPaintable *paintable;
+
+  gboolean live_thumbnail;
+  gboolean refresh_queued;
 };
 
 G_DEFINE_FINAL_TYPE (AdwTabPage, adw_tab_page, G_TYPE_OBJECT)
@@ -159,6 +165,7 @@ enum {
   PAGE_PROP_KEYWORD,
   PAGE_PROP_THUMBNAIL_XALIGN,
   PAGE_PROP_THUMBNAIL_YALIGN,
+  PAGE_PROP_LIVE_THUMBNAIL,
   LAST_PAGE_PROP
 };
 
@@ -178,6 +185,8 @@ struct _AdwTabView
   AdwTabViewShortcuts shortcuts;
 
   int transfer_count;
+  int overview_count;
+  gulong unmap_extra_pages_cb;
 
   GtkSelectionModel *pages;
 };
@@ -217,6 +226,16 @@ enum {
 
 static guint signals[SIGNAL_LAST_SIGNAL];
 
+static gboolean
+page_should_be_visible (AdwTabView *view,
+                        AdwTabPage *page)
+{
+  if (!view->overview_count)
+    return FALSE;
+
+  return page->live_thumbnail || page->refresh_queued;
+}
+
 static void
 set_page_selected (AdwTabPage *self,
                    gboolean    selected)
@@ -290,6 +309,33 @@ set_page_parent (AdwTabPage *self,
   g_object_notify_by_pspec (G_OBJECT (self), props[PAGE_PROP_PARENT]);
 }
 
+static void
+map_or_unmap_page (AdwTabPage *self)
+{
+  GtkWidget *parent;
+  AdwTabView *view;
+  gboolean should_be_visible;
+
+  parent = gtk_widget_get_parent (self->bin);
+
+  if (!ADW_IS_TAB_VIEW (parent))
+    return;
+
+  view = ADW_TAB_VIEW (parent);
+
+  if (!view->overview_count)
+    return;
+
+  should_be_visible = self == view->selected_page ||
+  page_should_be_visible (view, self);
+
+  if (gtk_widget_get_child_visible (self->bin) == should_be_visible)
+    return;
+
+  gtk_widget_set_child_visible (self->bin, should_be_visible);
+  gtk_widget_queue_allocate (parent);
+}
+
 static void
 adw_tab_page_dispose (GObject *object)
 {
@@ -297,6 +343,7 @@ adw_tab_page_dispose (GObject *object)
 
   set_page_parent (self, NULL);
 
+  g_clear_object (&self->bin);
   g_clear_object (&self->paintable);
 
   G_OBJECT_CLASS (adw_tab_page_parent_class)->dispose (object);
@@ -391,6 +438,10 @@ adw_tab_page_get_property (GObject    *object,
     g_value_set_float (value, adw_tab_page_get_thumbnail_yalign (self));
     break;
 
+  case PAGE_PROP_LIVE_THUMBNAIL:
+    g_value_set_boolean (value, adw_tab_page_get_live_thumbnail (self));
+    break;
+
   default:
     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   }
@@ -407,6 +458,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:
@@ -457,6 +509,10 @@ adw_tab_page_set_property (GObject      *object,
     adw_tab_page_set_thumbnail_yalign (self, g_value_get_float (value));
     break;
 
+  case PAGE_PROP_LIVE_THUMBNAIL:
+    adw_tab_page_set_live_thumbnail (self, g_value_get_boolean (value));
+    break;
+
   default:
     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   }
@@ -703,6 +759,18 @@ adw_tab_page_class_init (AdwTabPageClass *klass)
                         0.0,
                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
 
+  /**
+   * AdwTabPage:live-thumbnail: (attributes org.gtk.Property.get=adw_tab_page_get_live_thumbnail 
org.gtk.Property.set=adw_tab_page_set_live_thumbnail)
+   *
+   * TODO
+   *
+   * Since: 1.3
+   */
+  page_props[PAGE_PROP_LIVE_THUMBNAIL] =
+    g_param_spec_boolean ("live-thumbnail", NULL, NULL,
+                          FALSE,
+                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
   g_object_class_install_properties (object_class, LAST_PAGE_PROP, page_props);
 }
 
@@ -714,6 +782,7 @@ adw_tab_page_init (AdwTabPage *self)
   self->indicator_tooltip = g_strdup ("");
   self->thumbnail_xalign = 0;
   self->thumbnail_yalign = 0;
+  self->bin = g_object_ref_sink (adw_bin_new ());
 }
 
 #define ADW_TYPE_TAB_PAINTABLE (adw_tab_paintable_get_type ())
@@ -728,12 +797,16 @@ struct _AdwTabPaintable
   AdwTabPage *page;
 
   GdkPaintable *view_paintable;
+  GdkPaintable *child_paintable;
 
   GdkPaintable *cached_paintable;
-  GdkRGBA cached_bg;
+  double cached_aspect_ratio;
 
-  gboolean schedule_clear_cache;
   gboolean frozen;
+
+  double last_xalign;
+  double last_yalign;
+  GdkRGBA last_bg_color;
 };
 
 static void
@@ -743,7 +816,7 @@ get_background_color (AdwTabPaintable *self,
   GtkWidget *child = adw_tab_page_get_child (self->page);
   GtkStyleContext *context = gtk_widget_get_style_context (child);
 
-  if (gtk_style_context_lookup_color (context, "window_bg_color", rgba))
+  if (gtk_style_context_lookup_color (context, "thumbnail_bg_color", rgba))
     return;
 
   rgba->red = 1;
@@ -757,48 +830,41 @@ invalidate_contents_and_clear_cache (AdwTabPaintable *self)
 {
   gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
 
-  if (self->schedule_clear_cache) {
+  if (!self->frozen &&
+      self->page->bin &&
+      gtk_widget_get_mapped (self->page->bin))
     g_clear_object (&self->cached_paintable);
-    self->schedule_clear_cache = FALSE;
-  }
 }
 
-static void
-child_map_cb (AdwTabPaintable *self)
+static double
+get_unclamped_aspect_ratio (AdwTabPaintable *self)
 {
-  if (self->frozen)
-    return;
+  if (self->frozen || !self->view_paintable)
+    return self->cached_aspect_ratio;
 
-  gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
-
-  self->schedule_clear_cache = TRUE;
+  return gdk_paintable_get_intrinsic_aspect_ratio (self->view_paintable);
 }
 
 static void
 child_unmap_cb (AdwTabPaintable *self)
 {
-  if (self->frozen || self->cached_paintable || !self->view)
+  if (self->frozen)
     return;
 
   g_clear_object (&self->cached_paintable);
-  self->cached_paintable = gdk_paintable_get_current_image (self->view_paintable);
-
-  get_background_color (self, &self->cached_bg);
+  self->cached_paintable = gdk_paintable_get_current_image (self->child_paintable);
+  self->cached_aspect_ratio = get_unclamped_aspect_ratio (self);
 }
 
 static void
 connect_to_view (AdwTabPaintable *self)
 {
-  GtkWidget *child = adw_tab_page_get_child (self->page);
-
-  if (self->view || !gtk_widget_get_parent (child))
+  if (self->view || !gtk_widget_get_parent (self->page->bin))
     return;
 
-  self->view = gtk_widget_get_ancestor (child, ADW_TYPE_TAB_VIEW);
+  self->view = gtk_widget_get_parent (self->page->bin);
   self->view_paintable = gtk_widget_paintable_new (self->view);
 
-  g_signal_connect_swapped (self->view_paintable, "invalidate-contents",
-                            G_CALLBACK (invalidate_contents_and_clear_cache), self);
   g_signal_connect_swapped (self->view_paintable, "invalidate-size",
                             G_CALLBACK (gdk_paintable_invalidate_size), self);
 }
@@ -807,7 +873,6 @@ static void
 disconnect_from_view (AdwTabPaintable *self)
 {
   g_clear_object (&self->view_paintable);
-
   self->view = NULL;
 }
 
@@ -822,28 +887,21 @@ static double
 adw_tab_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
 {
   AdwTabPaintable *self = ADW_TAB_PAINTABLE (paintable);
-  double ratio;
-
-  if (self->view_paintable)
-    ratio = gdk_paintable_get_intrinsic_aspect_ratio (self->view_paintable);
-  else if (self->cached_paintable)
-    ratio = gdk_paintable_get_intrinsic_aspect_ratio (self->cached_paintable);
-  else
-    ratio = 0;
+  double ratio = get_unclamped_aspect_ratio (self);
 
   return CLAMP (ratio, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO);
 }
 
 static void
-snapshot_paintable (GtkSnapshot       *snapshot,
-                    double             width,
-                    double             height,
-                    GdkPaintable      *paintable,
-                    double             xalign,
-                    double             yalign)
+snapshot_paintable (GtkSnapshot  *snapshot,
+                    double        width,
+                    double        height,
+                    GdkPaintable *paintable,
+                    double        paintable_ratio,
+                    double        xalign,
+                    double        yalign)
 {
   double snapshot_ratio = width / height;
-  double paintable_ratio = gdk_paintable_get_intrinsic_aspect_ratio (paintable);
 
   if (paintable_ratio > snapshot_ratio) {
     double new_width = height * paintable_ratio;
@@ -894,35 +952,42 @@ adw_tab_paintable_snapshot (GdkPaintable *paintable,
   GdkRGBA bg;
   double xalign, yalign;
 
-  if (!self->view)
-    return;
-
-  child = adw_tab_page_get_child (self->page);
-  xalign = adw_tab_page_get_thumbnail_xalign (self->page);
-  yalign = adw_tab_page_get_thumbnail_yalign (self->page);
+  if (self->frozen) {
+    xalign = self->last_xalign;
+    yalign = self->last_yalign;
+    child = NULL;
+  } else {
+    xalign = adw_tab_page_get_thumbnail_xalign (self->page);
+    yalign = adw_tab_page_get_thumbnail_yalign (self->page);
+    child = self->page->bin;
 
-  if (gtk_widget_get_direction (child) == GTK_TEXT_DIR_RTL)
-    xalign = 1 - xalign;
+    if (gtk_widget_get_direction (child) == GTK_TEXT_DIR_RTL)
+      xalign = 1 - xalign;
+  }
 
   if (self->cached_paintable) {
-    gtk_snapshot_append_color (GTK_SNAPSHOT (snapshot), &self->cached_bg,
-                               &GRAPHENE_RECT_INIT (0, 0, width, height));
-
     snapshot_paintable (GTK_SNAPSHOT (snapshot), width, height,
-                        self->cached_paintable, xalign, yalign);
-
+                        self->cached_paintable, self->cached_aspect_ratio,
+                        xalign, yalign);
     return;
   }
 
-  if (!gtk_widget_get_mapped (child) || self->schedule_clear_cache)
+  if (child && gtk_widget_get_mapped (child)) {
+    double aspect_ratio = get_unclamped_aspect_ratio (self);
+
+    snapshot_paintable (GTK_SNAPSHOT (snapshot), width, height,
+                        self->child_paintable, aspect_ratio,
+                        xalign, yalign);
     return;
+  }
+
+  if (self->frozen)
+    bg = self->last_bg_color;
+  else
+    get_background_color (self, &bg);
 
-  get_background_color (self, &bg);
   gtk_snapshot_append_color (GTK_SNAPSHOT (snapshot), &bg,
                              &GRAPHENE_RECT_INIT (0, 0, width, height));
-
-  snapshot_paintable (GTK_SNAPSHOT (snapshot), width, height,
-                      self->view_paintable, xalign, yalign);
 }
 
 static void
@@ -943,6 +1008,7 @@ adw_tab_paintable_dispose (GObject *object)
 
   disconnect_from_view (self);
 
+  g_clear_object (&self->child_paintable);
   g_clear_object (&self->cached_paintable);
 
   G_OBJECT_CLASS (adw_tab_paintable_parent_class)->dispose (object);
@@ -965,14 +1031,16 @@ static GdkPaintable *
 adw_tab_paintable_new (AdwTabPage *page)
 {
   AdwTabPaintable *self = g_object_new (ADW_TYPE_TAB_PAINTABLE, NULL);
-  GtkWidget *child;
 
   self->page = page;
 
-  child = adw_tab_page_get_child (page);
-
   connect_to_view (self);
 
+  self->child_paintable = gtk_widget_paintable_new (page->bin);
+
+  g_signal_connect_swapped (self->child_paintable, "invalidate-contents",
+                            G_CALLBACK (invalidate_contents_and_clear_cache), self);
+
   g_signal_connect_object (self->page, "notify::thumbnail-xalign",
                            G_CALLBACK (gdk_paintable_invalidate_contents), self,
                            G_CONNECT_SWAPPED);
@@ -980,13 +1048,10 @@ adw_tab_paintable_new (AdwTabPage *page)
                            G_CALLBACK (gdk_paintable_invalidate_contents), self,
                            G_CONNECT_SWAPPED);
 
-  g_signal_connect_object (child, "notify::parent",
+  g_signal_connect_object (page->bin, "notify::parent",
                            G_CALLBACK (child_parent_changed), self,
                            G_CONNECT_SWAPPED);
-  g_signal_connect_object (child, "map",
-                           G_CALLBACK (child_map_cb), self,
-                           G_CONNECT_SWAPPED);
-  g_signal_connect_object (child, "unmap",
+  g_signal_connect_object (page->bin, "unmap",
                            G_CALLBACK (child_unmap_cb), self,
                            G_CONNECT_SWAPPED);
 
@@ -997,8 +1062,16 @@ static void
 adw_tab_paintable_freeze (AdwTabPaintable *self)
 {
   child_unmap_cb (self);
-  self->schedule_clear_cache = FALSE;
+  self->last_xalign = adw_tab_page_get_thumbnail_xalign (self->page);
+  self->last_yalign = adw_tab_page_get_thumbnail_yalign (self->page);
+  get_background_color (self, &self->last_bg_color);
+
+  if (gtk_widget_get_direction (self->page->bin) == GTK_TEXT_DIR_RTL)
+    self->last_xalign = 1 - self->last_xalign;
+
   self->frozen = TRUE;
+
+  g_clear_object (&self->child_paintable);
 }
 
 #define ADW_TYPE_TAB_PAGES (adw_tab_pages_get_type ())
@@ -1180,7 +1253,7 @@ page_belongs_to_this_view (AdwTabView *self,
   if (!page)
     return FALSE;
 
-  return gtk_widget_get_parent (page->child) == GTK_WIDGET (self);
+  return gtk_widget_get_parent (page->bin) == GTK_WIDGET (self);
 }
 
 static inline gboolean
@@ -1198,13 +1271,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_widget_set_child_visible (child, FALSE);
-  gtk_widget_set_parent (child, GTK_WIDGET (self));
+  gtk_widget_set_child_visible (page->bin,
+                                page_should_be_visible (self, page));
+  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));
@@ -1246,8 +1324,8 @@ set_selected_page (AdwTabView *self,
     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)) {
+        self->selected_page->bin &&
+        gtk_widget_is_ancestor (focus, self->selected_page->bin)) {
       contains_focus = TRUE;
 
       if (self->selected_page->last_focus)
@@ -1258,8 +1336,9 @@ set_selected_page (AdwTabView *self,
                                  (gpointer *) &self->selected_page->last_focus);
     }
 
-    if (self->selected_page->child)
-      gtk_widget_set_child_visible (self->selected_page->child, FALSE);
+    if (self->selected_page->bin)
+      gtk_widget_set_child_visible (self->selected_page->bin,
+                                    page_should_be_visible (self, self->selected_page));
 
     set_page_selected (self->selected_page, FALSE);
   }
@@ -1271,13 +1350,13 @@ set_selected_page (AdwTabView *self,
       new_position = adw_tab_view_get_page_position (self, self->selected_page);
 
     if (!gtk_widget_in_destruction (GTK_WIDGET (self))) {
-      gtk_widget_set_child_visible (selected_page->child, TRUE);
+      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->child, GTK_DIR_TAB_FORWARD);
+          gtk_widget_child_focus (selected_page->bin, GTK_DIR_TAB_FORWARD);
       }
 
       gtk_widget_queue_allocate (GTK_WIDGET (self));
@@ -1351,14 +1430,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);
@@ -1374,7 +1450,8 @@ detach_page (AdwTabView *self,
 
   g_object_thaw_notify (G_OBJECT (self));
 
-  gtk_widget_unparent (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));
@@ -1384,7 +1461,7 @@ detach_page (AdwTabView *self,
   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);
 }
 
@@ -1703,16 +1780,13 @@ adw_tab_view_measure (GtkWidget      *widget,
 
   for (i = 0; i < self->n_pages; i++) {
     AdwTabPage *page = adw_tab_view_get_nth_page (self, i);
+    int child_min, child_nat;
 
-    if (gtk_widget_get_visible (page->child)) {
-      int child_min, child_nat;
+    gtk_widget_measure (page->bin, orientation, for_size,
+                        &child_min, &child_nat, NULL, NULL);
 
-      gtk_widget_measure (page->child, orientation, for_size,
-                          &child_min, &child_nat, NULL, NULL);
-
-      *minimum = MAX (*minimum, child_min);
-      *natural = MAX (*natural, child_nat);
-    }
+    *minimum = MAX (*minimum, child_min);
+    *natural = MAX (*natural, child_nat);
   }
 }
 
@@ -1723,11 +1797,80 @@ adw_tab_view_size_allocate (GtkWidget *widget,
                             int        baseline)
 {
   AdwTabView *self = ADW_TAB_VIEW (widget);
+  int i;
 
-  if (!self->selected_page)
-    return;
+  for (i = 0; i < self->n_pages; i++) {
+    AdwTabPage *page = adw_tab_view_get_nth_page (self, i);
+
+    if (gtk_widget_get_child_visible (page->bin))
+      gtk_widget_allocate (page->bin, width, height, baseline, NULL);
+  }
+}
+
+static gboolean
+unmap_extra_pages (AdwTabView *self)
+{
+  int i;
+
+  for (i = 0; i < self->n_pages; i++) {
+    AdwTabPage *page = adw_tab_view_get_nth_page (self, i);
+
+    if (page == self->selected_page)
+      continue;
+
+    if (!gtk_widget_get_child_visible (page->bin))
+      continue;
+
+    if (page_should_be_visible (self, page))
+      continue;
+
+    gtk_widget_set_child_visible (page->bin, FALSE);
+  }
+
+  self->unmap_extra_pages_cb = 0;
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+adw_tab_view_snapshot (GtkWidget   *widget,
+                       GtkSnapshot *snapshot)
+{
+  AdwTabView *self = ADW_TAB_VIEW (widget);
+  int i;
 
-  gtk_widget_allocate (self->selected_page->child, width, height, baseline, NULL);
+  if (self->selected_page)
+    gtk_widget_snapshot_child (widget, self->selected_page->bin, snapshot);
+
+  for (i = 0; i < self->n_pages; i++) {
+    AdwTabPage *page = adw_tab_view_get_nth_page (self, i);
+
+    if (page == self->selected_page) {
+      page->refresh_queued = FALSE;
+      continue;
+    }
+
+    if (!gtk_widget_get_child_visible (page->bin))
+      continue;
+
+    if (page->paintable) {
+      /* We don't want to actually draw the child, but we do need it
+       * to redraw so that it can be displayed by its paintable */
+      GtkSnapshot *child_snapshot = gtk_snapshot_new ();
+
+      gtk_widget_snapshot_child (widget, page->bin, child_snapshot);
+
+      child_unmap_cb (ADW_TAB_PAINTABLE (page->paintable));
+
+      g_object_unref (child_snapshot);
+    }
+
+    page->refresh_queued = FALSE;
+
+    if (!self->unmap_extra_pages_cb)
+      self->unmap_extra_pages_cb =
+        g_idle_add ((GSourceFunc) unmap_extra_pages, self);
+  }
 }
 
 static void
@@ -1735,6 +1878,11 @@ adw_tab_view_dispose (GObject *object)
 {
   AdwTabView *self = ADW_TAB_VIEW (object);
 
+  if (self->unmap_extra_pages_cb) {
+    g_source_remove (self->unmap_extra_pages_cb);
+    self->unmap_extra_pages_cb = 0;
+  }
+
   if (self->pages)
     g_list_model_items_changed (G_LIST_MODEL (self->pages), 0, self->n_pages, 0);
 
@@ -1855,6 +2003,7 @@ adw_tab_view_class_init (AdwTabViewClass *klass)
 
   widget_class->measure = adw_tab_view_measure;
   widget_class->size_allocate = adw_tab_view_size_allocate;
+  widget_class->snapshot = adw_tab_view_snapshot;
   widget_class->get_request_mode = adw_widget_get_request_mode;
   widget_class->compute_expand = adw_widget_compute_expand;
 
@@ -2819,6 +2968,70 @@ adw_tab_page_set_thumbnail_yalign (AdwTabPage *self,
   g_object_notify_by_pspec (G_OBJECT (self), page_props[PAGE_PROP_THUMBNAIL_YALIGN]);
 }
 
+/**
+ * adw_tab_page_get_live_thumbnail: (attributes org.gtk.Method.get_property=live-thumbnail)
+ * @self: a tab overview
+ *
+ * Gets TODO
+ *
+ * Returns: TODO
+ *
+ * Since: 1.3
+ */
+gboolean
+adw_tab_page_get_live_thumbnail (AdwTabPage *self)
+{
+  g_return_val_if_fail (ADW_IS_TAB_PAGE (self), FALSE);
+
+  return self->live_thumbnail;
+}
+
+/**
+ * adw_tab_page_set_live_thumbnail: (attributes org.gtk.Method.set_property=live-thumbnail)
+ * @self: a tab page
+ * @live_thumbnail: TODO
+ *
+ * Sets TODO
+ *
+ * Since: 1.3
+ */
+void
+adw_tab_page_set_live_thumbnail (AdwTabPage *self,
+                                 gboolean    live_thumbnail)
+{
+  g_return_if_fail (ADW_IS_TAB_PAGE (self));
+
+  live_thumbnail = !!live_thumbnail;
+
+  if (self->live_thumbnail == live_thumbnail)
+    return;
+
+  self->live_thumbnail = live_thumbnail;
+
+  map_or_unmap_page (self);
+
+  g_object_notify_by_pspec (G_OBJECT (self), page_props[PAGE_PROP_LIVE_THUMBNAIL]);
+}
+
+
+/**
+ * adw_tab_page_queue_refresh_thumbnail:
+ * @self: a tab page
+ *
+ * TODO
+ *
+ * Since: 1.3
+ */
+void
+adw_tab_page_queue_refresh_thumbnail (AdwTabPage *self)
+{
+  g_return_if_fail (ADW_IS_TAB_PAGE (self));
+
+  self->refresh_queued = TRUE;
+
+  map_or_unmap_page (self);
+}
+
 GdkPaintable *
 adw_tab_page_get_paintable (AdwTabPage *self)
 {
@@ -3356,11 +3569,15 @@ AdwTabPage *
 adw_tab_view_get_page (AdwTabView *self,
                        GtkWidget  *child)
 {
+  GtkWidget *parent;
   int i;
 
   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) == GTK_WIDGET (self), NULL);
+
+  parent = gtk_widget_get_parent (child);
+
+  g_return_val_if_fail (parent && gtk_widget_get_parent (parent) == GTK_WIDGET (self), NULL);
 
   for (i = 0; i < self->n_pages; i++) {
     AdwTabPage *page = adw_tab_view_get_nth_page (self, i);
@@ -4080,6 +4297,27 @@ adw_tab_view_get_pages (AdwTabView *self)
   return self->pages;
 }
 
+/**
+ * adw_tab_view_queue_refresh_thumbnails:
+ * @self: a tab view
+ *
+ * TODO
+ *
+ * Since: 1.3
+ */
+void
+adw_tab_view_queue_refresh_thumbnails (AdwTabView *self)
+{
+  int i;
+  g_return_if_fail (ADW_IS_TAB_VIEW (self));
+
+  for (i = 0; i < self->n_pages; i++) {
+    AdwTabPage *page = adw_tab_view_get_nth_page (self, i);
+
+    adw_tab_page_queue_refresh_thumbnail (page);
+  }
+}
+
 AdwTabView *
 adw_tab_view_create_window (AdwTabView *self)
 {
@@ -4097,3 +4335,48 @@ adw_tab_view_create_window (AdwTabView *self)
 
   return new_view;
 }
+
+void
+adw_tab_view_open_overview (AdwTabView *self)
+{
+  g_return_if_fail (ADW_IS_TAB_VIEW (self));
+
+  if (self->overview_count == 0) {
+    int i;
+
+    for (i = 0; i < self->n_pages; i++) {
+      AdwTabPage *page = adw_tab_view_get_nth_page (self, i);
+
+      if (page->live_thumbnail || page->refresh_queued)
+        gtk_widget_set_child_visible (page->bin, TRUE);
+    }
+
+    gtk_widget_queue_allocate (GTK_WIDGET (self));
+  }
+
+  self->overview_count++;
+}
+
+void
+adw_tab_view_close_overview (AdwTabView *self)
+{
+  g_return_if_fail (ADW_IS_TAB_VIEW (self));
+
+  self->overview_count--;
+
+  if (self->overview_count == 0) {
+    int i;
+
+    for (i = 0; i < self->n_pages; i++) {
+      AdwTabPage *page = adw_tab_view_get_nth_page (self, i);
+
+      if (page->live_thumbnail || page->refresh_queued)
+        gtk_widget_set_child_visible (page->bin,
+                                      page == self->selected_page);
+    }
+
+    gtk_widget_queue_allocate (GTK_WIDGET (self));
+  }
+
+  g_assert (self->overview_count >= 0);
+}
diff --git a/src/adw-tab-view.h b/src/adw-tab-view.h
index ad4fdf11..51e01900 100644
--- a/src/adw-tab-view.h
+++ b/src/adw-tab-view.h
@@ -119,6 +119,15 @@ ADW_AVAILABLE_IN_1_2
 void  adw_tab_page_set_thumbnail_yalign (AdwTabPage *self,
                                          float       yalign);
 
+ADW_AVAILABLE_IN_1_2
+gboolean adw_tab_page_get_live_thumbnail (AdwTabPage *self);
+ADW_AVAILABLE_IN_1_2
+void     adw_tab_page_set_live_thumbnail (AdwTabPage *self,
+                                          gboolean    live_thumbnail);
+
+ADW_AVAILABLE_IN_1_2
+void adw_tab_page_queue_refresh_thumbnail (AdwTabPage *self);
+
 #define ADW_TYPE_TAB_VIEW (adw_tab_view_get_type())
 
 ADW_AVAILABLE_IN_ALL
@@ -258,4 +267,7 @@ void adw_tab_view_transfer_page (AdwTabView *self,
 ADW_AVAILABLE_IN_ALL
 GtkSelectionModel *adw_tab_view_get_pages (AdwTabView *self) G_GNUC_WARN_UNUSED_RESULT;
 
+ADW_AVAILABLE_IN_1_2
+void adw_tab_view_queue_refresh_thumbnails (AdwTabView *self);
+
 G_END_DECLS
diff --git a/src/stylesheet/widgets/_tab-view.scss b/src/stylesheet/widgets/_tab-view.scss
index 31ed8cfd..9dc8cadc 100644
--- a/src/stylesheet/widgets/_tab-view.scss
+++ b/src/stylesheet/widgets/_tab-view.scss
@@ -178,8 +178,8 @@ tabthumbnail {
       border-radius: $card_radius;
     }
 
-    background-color: $thumbnail_bg_color;
-    color: $thumbnail_fg_color;
+    background: none;
+    color: inherit;
 
     @if $contrast == 'high' {
       box-shadow: 0 0 0 1px transparentize(black, 0.5),
@@ -188,6 +188,11 @@ tabthumbnail {
     }
   }
 
+  &.pinned .card {
+    background-color: $thumbnail_bg_color;
+    color: $thumbnail_fg_color;
+  }
+
   .pinned-box {
     margin-left: 10px;
     margin-right: 10px;


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