[libadwaita/wip/exalm/tab-style: 1/5] tab-box: Refresh design




commit a26a878ed7a56aa79b989be56dd016f78bffdcc2
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Wed Apr 6 15:18:27 2022 +0400

    tab-box: Refresh design
    
    Ensure it's visible in dark variant.
    
    Replace borders with separators. Make sure separators never touch a tab
    with background.
    
    Replace the needs-attention gradient with a bar; animate it.
    
    Replace the undershoot gradient with a fade.
    
    Fixes https://gitlab.gnome.org/GNOME/libadwaita/-/issues/318

 src/adw-tab-bar-private.h             |   5 +
 src/adw-tab-bar.c                     |  58 ++---
 src/adw-tab-bar.ui                    |   4 -
 src/adw-tab-box.c                     | 462 +++++++++++++++++++++++++---------
 src/adw-tab.c                         |  72 +++++-
 src/adw-tab.ui                        |   6 +
 src/stylesheet/widgets/_tab-view.scss | 208 ++++-----------
 7 files changed, 487 insertions(+), 328 deletions(-)
---
diff --git a/src/adw-tab-bar-private.h b/src/adw-tab-bar-private.h
index e191f092..f6670c63 100644
--- a/src/adw-tab-bar-private.h
+++ b/src/adw-tab-bar-private.h
@@ -14,8 +14,13 @@
 
 #include "adw-tab-bar.h"
 
+#include "adw-tab-box-private.h"
+
 G_BEGIN_DECLS
 
 gboolean adw_tab_bar_tabs_have_visible_focus (AdwTabBar *self);
 
+AdwTabBox *adw_tab_bar_get_tab_box        (AdwTabBar *self);
+AdwTabBox *adw_tab_bar_get_pinned_tab_box (AdwTabBar *self);
+
 G_END_DECLS
diff --git a/src/adw-tab-bar.c b/src/adw-tab-bar.c
index 3c05f38d..b914a9f2 100644
--- a/src/adw-tab-bar.c
+++ b/src/adw-tab-bar.c
@@ -187,46 +187,6 @@ page_detached_cb (AdwTabBar  *self,
   g_signal_handlers_disconnect_by_func (page, notify_pinned_cb, self);
 }
 
-static void
-update_needs_attention (AdwTabBar *self,
-                        gboolean   pinned)
-{
-  GtkStyleContext *context;
-  gboolean left, right;
-
-  g_object_get (pinned ? self->pinned_box : self->box,
-                "needs-attention-left", &left,
-                "needs-attention-right", &right,
-                NULL);
-
-  if (pinned)
-    context = gtk_widget_get_style_context (GTK_WIDGET (self->pinned_scrolled_window));
-  else
-    context = gtk_widget_get_style_context (GTK_WIDGET (self->scrolled_window));
-
-  if (left)
-    gtk_style_context_add_class (context, "needs-attention-left");
-  else
-    gtk_style_context_remove_class (context, "needs-attention-left");
-
-  if (right)
-    gtk_style_context_add_class (context, "needs-attention-right");
-  else
-    gtk_style_context_remove_class (context, "needs-attention-right");
-}
-
-static void
-notify_needs_attention_cb (AdwTabBar *self)
-{
-  update_needs_attention (self, FALSE);
-}
-
-static void
-notify_needs_attention_pinned_cb (AdwTabBar *self)
-{
-  update_needs_attention (self, TRUE);
-}
-
 static inline gboolean
 is_overflowing (GtkAdjustment *adj)
 {
@@ -609,8 +569,6 @@ adw_tab_bar_class_init (AdwTabBarClass *klass)
   gtk_widget_class_bind_template_child (widget_class, AdwTabBar, pinned_scrolled_window);
   gtk_widget_class_bind_template_child (widget_class, AdwTabBar, start_action_bin);
   gtk_widget_class_bind_template_child (widget_class, AdwTabBar, end_action_bin);
-  gtk_widget_class_bind_template_callback (widget_class, notify_needs_attention_cb);
-  gtk_widget_class_bind_template_callback (widget_class, notify_needs_attention_pinned_cb);
   gtk_widget_class_bind_template_callback (widget_class, notify_resize_frozen_cb);
   gtk_widget_class_bind_template_callback (widget_class, stop_kinetic_scrolling_cb);
   gtk_widget_class_bind_template_callback (widget_class, extra_drag_drop_cb);
@@ -1094,3 +1052,19 @@ adw_tab_bar_get_is_overflowing (AdwTabBar *self)
 
   return self->is_overflowing;
 }
+
+AdwTabBox *
+adw_tab_bar_get_tab_box (AdwTabBar *self)
+{
+  g_return_val_if_fail (ADW_IS_TAB_BAR (self), NULL);
+
+  return self->box;
+}
+
+AdwTabBox *
+adw_tab_bar_get_pinned_tab_box (AdwTabBar *self)
+{
+  g_return_val_if_fail (ADW_IS_TAB_BAR (self), NULL);
+
+  return self->pinned_box;
+}
diff --git a/src/adw-tab-bar.ui b/src/adw-tab-bar.ui
index c6f68e0c..81583d7c 100644
--- a/src/adw-tab-bar.ui
+++ b/src/adw-tab-bar.ui
@@ -33,8 +33,6 @@
                   <object class="AdwTabBox" id="pinned_box">
                     <property name="pinned">True</property>
                     <property name="tab-bar">AdwTabBar</property>
-                    <signal name="notify::needs-attention-left" handler="notify_needs_attention_pinned_cb" 
swapped="true"/>
-                    <signal name="notify::needs-attention-right" handler="notify_needs_attention_pinned_cb" 
swapped="true"/>
                     <signal name="notify::resize-frozen" handler="notify_resize_frozen_cb" swapped="true"/>
                     <signal name="stop-kinetic-scrolling" handler="stop_kinetic_scrolling_cb" 
object="pinned_scrolled_window" swapped="true"/>
                     <signal name="extra-drag-drop" handler="extra_drag_drop_cb" swapped="true"/>
@@ -52,8 +50,6 @@
                 <child>
                   <object class="AdwTabBox" id="box">
                     <property name="tab-bar">AdwTabBar</property>
-                    <signal name="notify::needs-attention-left" handler="notify_needs_attention_cb" 
swapped="true"/>
-                    <signal name="notify::needs-attention-right" handler="notify_needs_attention_cb" 
swapped="true"/>
                     <signal name="notify::resize-frozen" handler="notify_resize_frozen_cb" swapped="true"/>
                     <signal name="stop-kinetic-scrolling" handler="stop_kinetic_scrolling_cb" 
object="scrolled_window" swapped="true"/>
                     <signal name="extra-drag-drop" handler="extra_drag_drop_cb" swapped="true"/>
diff --git a/src/adw-tab-box.c b/src/adw-tab-box.c
index 3f3be10b..55c9a7bd 100644
--- a/src/adw-tab-box.c
+++ b/src/adw-tab-box.c
@@ -21,8 +21,7 @@
 #include "adw-widget-utils-private.h"
 #include <math.h>
 
-/* Border collapsing without glitches */
-#define SPACING -1
+#define SPACING 3
 #define DND_THRESHOLD_MULTIPLIER 4
 #define DROP_SWITCH_TIMEOUT 500
 
@@ -38,6 +37,9 @@
 
 #define MAX_TAB_WIDTH_NON_EXPAND 220
 
+#define FADE_OFFSET 6.0f
+#define FADE_WIDTH 36.0f
+
 typedef enum {
   TAB_RESIZE_NORMAL,
   TAB_RESIZE_FIXED_TAB_WIDTH,
@@ -63,6 +65,7 @@ typedef struct {
   AdwTabPage *page;
   AdwTab *tab;
   GtkWidget *container;
+  GtkWidget *separator;
 
   int pos;
   int width;
@@ -89,8 +92,6 @@ struct _AdwTabBox
   AdwTabBar *tab_bar;
   AdwTabView *view;
   GtkAdjustment *adjustment;
-  gboolean needs_attention_left;
-  gboolean needs_attention_right;
   gboolean expand_tabs;
   gboolean inverted;
 
@@ -101,7 +102,6 @@ struct _AdwTabBox
   int n_tabs;
 
   GtkPopover *context_menu;
-  GtkWidget *background;
 
   int allocated_width;
   int last_width;
@@ -164,6 +164,12 @@ struct _AdwTabBox
   GdkDragAction extra_drag_actions;
   GType *extra_drag_types;
   gsize extra_drag_n_types;
+
+  GskGLShader *shader;
+  gboolean shader_compiled;
+
+  GtkWidget *needs_attention_left;
+  GtkWidget *needs_attention_right;
 };
 
 G_DEFINE_FINAL_TYPE_WITH_CODE (AdwTabBox, adw_tab_box, GTK_TYPE_WIDGET,
@@ -174,8 +180,6 @@ enum {
   PROP_PINNED,
   PROP_TAB_BAR,
   PROP_VIEW,
-  PROP_NEEDS_ATTENTION_LEFT,
-  PROP_NEEDS_ATTENTION_RIGHT,
   PROP_RESIZE_FROZEN,
   PROP_HADJUSTMENT,
   PROP_VADJUSTMENT,
@@ -200,6 +204,7 @@ static void
 remove_and_free_tab_info (TabInfo *info)
 {
   gtk_widget_unparent (GTK_WIDGET (info->container));
+  gtk_widget_unparent (GTK_WIDGET (info->separator));
 
   g_free (info);
 }
@@ -403,6 +408,93 @@ is_touchscreen (GtkGesture *gesture)
   return input_source == GDK_SOURCE_TOUCHSCREEN;
 }
 
+static void
+update_separators (AdwTabBox *self)
+{
+  GList *l;
+  GtkStateFlags mask = GTK_STATE_FLAG_PRELIGHT |
+                       GTK_STATE_FLAG_ACTIVE |
+                       GTK_STATE_FLAG_CHECKED;
+  TabInfo *last_pinned_tab = NULL;
+
+  /* We have a separator between pinned and non-pinned tabs, and we need to
+   * sync it same as the ones within each tab box */
+  if (!self->pinned) {
+    AdwTabBox *box = adw_tab_bar_get_pinned_tab_box (self->tab_bar);
+
+    l = g_list_last (box->tabs);
+
+    if (l) {
+      last_pinned_tab = l->data;
+
+      if (last_pinned_tab->end_reorder_offset < 0) {
+        last_pinned_tab = box->reordered_tab;
+      } else if (l->prev && last_pinned_tab == box->reordered_tab) {
+        TabInfo *prev = l->prev->data;
+
+        if (prev->end_reorder_offset > 0)
+          last_pinned_tab = prev;
+      }
+    }
+  }
+
+  for (l = self->tabs; l; l = l->next) {
+    TabInfo *info = l->data;
+    TabInfo *prev = NULL;
+    TabInfo *prev_prev = NULL;
+    TabInfo *visually_prev = NULL;
+    GtkStateFlags flags;
+
+    if (l->prev)
+      prev = l->prev->data;
+    else if (!self->pinned)
+      prev = last_pinned_tab;
+
+    if (l->prev && l->prev->prev)
+      prev_prev = l->prev->prev->data;
+    else if (!self->pinned)
+      prev_prev = last_pinned_tab;
+
+    if (prev && prev_prev) {
+      /* Since the reordered tab has been moved away, the 2 tabs around it are
+       * now adjacent. Treat them as such for the separator purposes. */
+      if (prev == self->reordered_tab && prev_prev->end_reorder_offset > 0)
+        visually_prev = prev_prev;
+
+      if (prev == self->reordered_tab && info->end_reorder_offset < 0)
+        visually_prev = prev_prev;
+    }
+
+    if (prev && self->reordered_tab) {
+      /* There's a gap between the current and the previous tab. This means the
+       * reordered tab is between them, so treat is as the previous tab. */
+      if (info->end_reorder_offset - prev->end_reorder_offset > 0)
+        visually_prev = self->reordered_tab;
+    }
+
+    if (!visually_prev)
+      visually_prev = prev;
+
+    flags = gtk_widget_get_state_flags (GTK_WIDGET (info->tab));
+
+    if (visually_prev)
+      flags |= gtk_widget_get_state_flags (GTK_WIDGET (visually_prev->tab));
+
+    if ((flags & mask) || !visually_prev)
+      gtk_widget_add_css_class (info->separator, "hidden");
+    else
+      gtk_widget_remove_css_class (info->separator, "hidden");
+  }
+
+  /* Since the first non-pinned separator depends on pinned tabs, we need to
+   * notify the non-pinned box. We don't need to do the opposite though. */
+  if (self->pinned) {
+    AdwTabBox *box = adw_tab_bar_get_tab_box (self->tab_bar);
+
+    update_separators (box);
+  }
+}
+
 /* Tab resize delay */
 
 static void
@@ -672,15 +764,8 @@ update_visible (AdwTabBox *self)
       right = TRUE;
   }
 
-  if (self->needs_attention_left != left) {
-    self->needs_attention_left = left;
-    g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NEEDS_ATTENTION_LEFT]);
-  }
-
-  if (self->needs_attention_right != right) {
-    self->needs_attention_right = right;
-    g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NEEDS_ATTENTION_RIGHT]);
-  }
+  gtk_revealer_set_reveal_child (GTK_REVEALER (self->needs_attention_left), left);
+  gtk_revealer_set_reveal_child (GTK_REVEALER (self->needs_attention_right), right);
 }
 
 static double
@@ -945,6 +1030,8 @@ check_end_reordering (AdwTabBox *self)
   gtk_widget_queue_allocate (GTK_WIDGET (self));
 
   self->reordered_tab = NULL;
+
+  update_separators (self);
 }
 
 static void
@@ -955,7 +1042,9 @@ start_reordering (AdwTabBox *self,
 
   /* The reordered tab should be displayed above everything else */
   gtk_widget_insert_before (GTK_WIDGET (self->reordered_tab->container),
-                            GTK_WIDGET (self), NULL);
+                            GTK_WIDGET (self), self->needs_attention_left);
+  gtk_widget_insert_before (GTK_WIDGET (self->reordered_tab->separator),
+                            GTK_WIDGET (self), self->needs_attention_left);
 
   gtk_widget_queue_allocate (GTK_WIDGET (self));
 }
@@ -1096,6 +1185,8 @@ reset_reorder_animations (AdwTabBox *self)
       l = l->prev;
       animate_reorder_offset (self, l->data, 0);
     }
+
+  update_separators (self);
 }
 
 static void
@@ -1167,6 +1258,8 @@ page_reordered_cb (AdwTabBox  *self,
   }
 
   self->continue_reorder = FALSE;
+
+  update_separators (self);
 }
 
 static void
@@ -1218,6 +1311,8 @@ update_drag_reodering (AdwTabBox *self)
 
     animate_reorder_offset (self, info, offset);
   }
+
+  update_separators (self);
 }
 
 static gboolean
@@ -1622,6 +1717,20 @@ allocate_tab (AdwGizmo *widget,
                        gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (-width_diff / 2, 0)));
 }
 
+static void
+state_flags_changed_cb (GtkWidget     *tab,
+                        GtkStateFlags  previous,
+                        AdwTabBox     *self)
+{
+  GtkStateFlags flags = gtk_widget_get_state_flags (tab);
+  GtkStateFlags mask = GTK_STATE_FLAG_PRELIGHT |
+                       GTK_STATE_FLAG_ACTIVE |
+                       GTK_STATE_FLAG_CHECKED;
+
+  if ((flags ^ previous) & mask)
+    update_separators (self);
+}
+
 static TabInfo *
 create_tab_info (AdwTabBox  *self,
                  AdwTabPage *page)
@@ -1650,10 +1759,15 @@ create_tab_info (AdwTabBox  *self,
                                    self->extra_drag_types,
                                    self->extra_drag_n_types);
 
+  info->separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
+  gtk_widget_set_can_target (info->separator, FALSE);
+
   gtk_widget_set_parent (GTK_WIDGET (info->tab), info->container);
-  gtk_widget_set_parent (info->container, GTK_WIDGET (self));
+  gtk_widget_insert_before (info->separator, GTK_WIDGET (self), self->needs_attention_left);
+  gtk_widget_insert_before (info->container, GTK_WIDGET (self), self->needs_attention_left);
 
   g_signal_connect_object (info->tab, "extra-drag-drop", G_CALLBACK (extra_drag_drop_cb), self, 0);
+  g_signal_connect_object (info->tab, "state-flags-changed", G_CALLBACK (state_flags_changed_cb), self, 0);
 
   return info;
 }
@@ -1706,6 +1820,8 @@ page_attached_cb (AdwTabBox  *self,
     adw_tab_box_select_page (self, page);
   else
     scroll_to_tab_full (self, info, -1, FOCUS_ANIMATION_DURATION, TRUE);
+
+  update_separators (self);
 }
 
 /* Closing */
@@ -1734,6 +1850,8 @@ close_animation_done_cb (TabInfo *info)
   remove_and_free_tab_info (info);
 
   self->n_tabs--;
+
+  update_separators (self);
 }
 
 static void
@@ -2001,6 +2119,8 @@ insert_placeholder (AdwTabBox  *self,
                             G_CALLBACK (open_animation_done_cb), info);
 
   adw_animation_play (info->appear_animation);
+
+  update_separators (self);
 }
 
 static void
@@ -2086,6 +2206,8 @@ remove_animation_done_cb (TabInfo *info)
   self->n_tabs--;
 
   self->reorder_placeholder = NULL;
+
+  update_separators (self);
 }
 
 static gboolean
@@ -2843,15 +2965,12 @@ adw_tab_box_measure (GtkWidget      *widget,
   AdwTabBox *self = ADW_TAB_BOX (widget);
   int min, nat;
 
-  gtk_widget_measure (self->background, orientation, -1,
-                      &min, &nat, NULL, NULL);
-
   if (self->n_tabs == 0) {
     if (minimum)
-      *minimum = min;
+      *minimum = 0;
 
     if (natural)
-      *natural = nat;
+      *natural = 0;
 
     if (minimum_baseline)
       *minimum_baseline = -1;
@@ -2877,30 +2996,41 @@ adw_tab_box_measure (GtkWidget      *widget,
     }
 
     if (!self->pinned)
-      width += SPACING;
+     width += SPACING;
 
     width = MAX (self->last_width, width);
 
-    min = MAX (min, width);
-    nat = MAX (nat, width);
+    min = nat = width;
   } else {
     GList *l;
+    int child_min, child_nat;
 
     min = nat = 0;
 
     for (l = self->tabs; l; l = l->next) {
       TabInfo *info = l->data;
-      int child_min, child_nat;
 
       gtk_widget_measure (info->container, orientation, -1,
                           &child_min, &child_nat, NULL, NULL);
 
-      if (child_min > min)
-        min = child_min;
+      min = MAX (min, child_min);
+      nat = MAX (nat, child_nat);
 
-      if (child_nat > nat)
-        nat = child_nat;
+      gtk_widget_measure (info->separator, orientation, -1,
+                          &child_min, NULL, NULL, NULL);
+
+      min = MAX (min, child_min);
     }
+
+    gtk_widget_measure (self->needs_attention_left, orientation, -1,
+                        &child_min, NULL, NULL, NULL);
+
+    min = MAX (min, child_min);
+
+    gtk_widget_measure (self->needs_attention_right, orientation, -1,
+                        &child_min, NULL, NULL, NULL);
+
+    min = MAX (min, child_min);
   }
 
   if (minimum)
@@ -2928,8 +3058,8 @@ adw_tab_box_size_allocate (GtkWidget *widget,
   GtkAllocation child_allocation;
   int pos;
   double value;
-
-  gtk_widget_allocate (self->background, width, height, baseline, NULL);
+  int indicator_size;
+  GskTransform *transform;
 
   adw_tab_box_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1,
                        &self->allocated_width, NULL, NULL, NULL);
@@ -3002,6 +3132,8 @@ adw_tab_box_size_allocate (GtkWidget *widget,
 
   for (l = self->tabs; l; l = l->next) {
     TabInfo *info = l->data;
+    GtkAllocation separator_allocation;
+    int separator_width;
 
     if (!info->appear_animation)
       info->display_width = info->width;
@@ -3015,10 +3147,25 @@ adw_tab_box_size_allocate (GtkWidget *widget,
 
     child_allocation.x = ((info == self->reordered_tab) ? self->reorder_window_x : info->pos) - (int) floor 
(value);
     child_allocation.y = 0;
-    child_allocation.width = info->width;
+    child_allocation.width = MAX (0, info->width);
     child_allocation.height = height;
 
+    gtk_widget_measure (info->separator, GTK_ORIENTATION_HORIZONTAL, -1,
+                        &separator_width, NULL, NULL, NULL);
+    separator_allocation.x = child_allocation.x + child_allocation.width;
+    if (is_rtl) {
+      separator_allocation.x = child_allocation.x + child_allocation.width;
+      separator_allocation.x += (SPACING - separator_width) / 2;
+    } else {
+      separator_allocation.x = child_allocation.x;
+      separator_allocation.x -= (SPACING + separator_width) / 2;
+    }
+    separator_allocation.y = 0;
+    separator_allocation.width = separator_width;
+    separator_allocation.height = height;
+
     gtk_widget_size_allocate (info->container, &child_allocation, baseline);
+    gtk_widget_size_allocate (info->separator, &separator_allocation, baseline);
 
     pos += (is_rtl ? -1 : 1) * (info->width + SPACING);
   }
@@ -3045,58 +3192,124 @@ adw_tab_box_size_allocate (GtkWidget *widget,
     }
   }
 
+  gtk_widget_measure (self->needs_attention_left, GTK_ORIENTATION_HORIZONTAL, -1,
+                      &indicator_size, NULL, NULL, NULL);
+  gtk_widget_allocate (self->needs_attention_left, indicator_size, height, baseline, NULL);
+
+  gtk_widget_measure (self->needs_attention_right, GTK_ORIENTATION_HORIZONTAL, -1,
+                      &indicator_size, NULL, NULL, NULL);
+  transform = gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (width - indicator_size, 0));
+  gtk_widget_allocate (self->needs_attention_right, indicator_size, height, baseline, transform);
+
   update_visible (self);
 }
 
 static void
-snapshot_tab (AdwTabBox      *self,
-              GtkSnapshot    *snapshot,
-              TabInfo        *info,
-              cairo_region_t *clip_region)
+ensure_shader (AdwTabBox *self)
 {
-  cairo_rectangle_int_t rect = { 0, 0, 0, 0 };
-  gboolean clip = FALSE;
-  int pos, width, scroll_pos;
-  int i, n;
+  GtkNative *native;
+  GskRenderer *renderer;
+  GError *error = NULL;
 
-  if (gtk_widget_get_opacity (info->container) <= 0)
+  if (self->shader)
     return;
 
-  rect.height = gtk_widget_get_height (GTK_WIDGET (self));
-  scroll_pos = (int) floor (gtk_adjustment_get_value (self->adjustment));
+  self->shader = gsk_gl_shader_new_from_resource ("/org/gnome/Adwaita/glsl/fade.glsl");
 
-  pos = get_tab_position (self, info);
-  width = info->width;
+  native = gtk_widget_get_native (GTK_WIDGET (self));
+  renderer = gtk_native_get_renderer (native);
 
-  n = cairo_region_num_rectangles (clip_region);
-  for (i = 0; i < n; i++) {
-    cairo_rectangle_int_t clip_rect;
-    int x1, x2;
+  self->shader_compiled = gsk_gl_shader_compile (self->shader, renderer, &error);
 
-    cairo_region_get_rectangle (clip_region, i, &clip_rect);
-    x1 = clip_rect.x + scroll_pos;
-    x2 = x1 + clip_rect.width;
+  if (error) {
+    /* If shaders aren't supported, the error doesn't matter and we just
+     * silently fall back */
+    if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
+      g_critical ("Couldn't compile shader: %s\n", error->message);
+  }
 
-    if (x1 < pos && x2 > pos + width) {
-      clip = FALSE;
-      break;
+  g_clear_error (&error);
+}
+
+static void
+snapshot_tabs (AdwTabBox   *self,
+               GtkSnapshot *snapshot)
+{
+  int w = gtk_widget_get_width (GTK_WIDGET (self));
+  int h = gtk_widget_get_height (GTK_WIDGET (self));
+  int scroll_start, scroll_end;
+  int reordered_pos = -1, reordered_width = -1;
+  GList *l;
+  gboolean is_rtl, is_clipping = FALSE;
+
+  scroll_start = (int) floor (gtk_adjustment_get_value (self->adjustment));
+  scroll_end = scroll_start + (int) ceil (gtk_adjustment_get_page_size (self->adjustment));
+  is_rtl = gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL;
+
+  if (self->reordered_tab && gtk_widget_get_opacity (self->reordered_tab->container) > 0) {
+    int clip_x, clip_width;
+
+    reordered_pos = get_tab_position (self, self->reordered_tab);
+    reordered_width = gtk_widget_get_allocated_width (self->reordered_tab->container);
+
+    if (is_rtl) {
+      clip_x = reordered_pos + reordered_width - scroll_start;
+      clip_width = w - clip_x;
+    } else {
+      clip_x = 0;
+      clip_width = reordered_pos - scroll_start;
     }
 
-    if (x2 < pos || x1 > pos + width)
+    gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (clip_x, 0, clip_width, h));
+    is_clipping = TRUE;
+  }
+
+  for (l = self->tabs; l; l = l->next) {
+    TabInfo *info = l->data;
+    int pos, width;
+
+    pos = get_tab_position (self, info);
+    width = gtk_widget_get_allocated_width (info->container);
+
+    if (pos + width < scroll_start)
+      continue;
+
+    if (pos > scroll_end)
+      continue;
+
+    if (info == self->reordered_tab)
       continue;
 
-    gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (clip_rect.x, clip_rect.y, clip_rect.width, 
clip_rect.height));
+    if (is_clipping &&
+        reordered_pos > 0 && reordered_width > 0 &&
+        ((is_rtl && pos < reordered_pos) ||
+        (!is_rtl && pos + width > reordered_pos + reordered_width))) {
+      int clip_x, clip_width;
+
+      if (is_rtl) {
+        clip_x = 0;
+        clip_width = reordered_pos - scroll_start;
+      } else {
+        clip_x = reordered_pos + reordered_width - scroll_start;
+        clip_width = w - clip_x;
+      }
+
+      reordered_pos = reordered_width = -1;
+
+      gtk_snapshot_pop (snapshot);
+      gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (clip_x, 0, clip_width, h));
+    }
+
     gtk_widget_snapshot_child (GTK_WIDGET (self), info->container, snapshot);
-    gtk_snapshot_pop (snapshot);
-    clip = TRUE;
+    gtk_widget_snapshot_child (GTK_WIDGET (self), info->separator, snapshot);
   }
 
-  if (!clip)
-    gtk_widget_snapshot_child (GTK_WIDGET (self), info->container, snapshot);
+  if (is_clipping) {
+    gtk_snapshot_pop (snapshot);
 
-  rect.x = pos - scroll_pos;
-  rect.width = width;
-  cairo_region_subtract_rectangle (clip_region, &rect);
+    gtk_widget_snapshot_child (GTK_WIDGET (self), self->reordered_tab->container, snapshot);
+    gtk_widget_snapshot_child (GTK_WIDGET (self), self->reordered_tab->separator, snapshot);
+  }
 }
 
 static void
@@ -3104,42 +3317,54 @@ adw_tab_box_snapshot (GtkWidget   *widget,
                       GtkSnapshot *snapshot)
 {
   AdwTabBox *self = ADW_TAB_BOX (widget);
-  int w = gtk_widget_get_width (widget);
-  int h = gtk_widget_get_height (widget);
-  cairo_rectangle_int_t rect = { 0, 0, 0, 0 };
-  cairo_region_t *region;
-  int i, n;
-  GList *l;
+  double value = gtk_adjustment_get_value (self->adjustment);
+  double page_size = gtk_adjustment_get_page_size (self->adjustment);
+  double upper = gtk_adjustment_get_upper (self->adjustment);
+  gboolean draw_fade = value > 0 || value + page_size < upper;
 
-  rect.width = w;
-  rect.height = h;
-  region = cairo_region_create_rectangle (&rect);
+  if (!self->n_tabs)
+    return;
 
-  if (self->reordered_tab)
-    snapshot_tab (self, snapshot, self->reordered_tab, region);
+  if (draw_fade) {
+    int width, height;
+    graphene_rect_t bounds;
 
-  if (self->selected_tab)
-    snapshot_tab (self, snapshot, self->selected_tab, region);
+    ensure_shader (self);
 
-  for (l = self->tabs; l; l = l->next) {
-    TabInfo *info = l->data;
+    width = gtk_widget_get_width (widget);
+    height = gtk_widget_get_height (widget);
 
-    if (info == self->reordered_tab || info == self->selected_tab)
-      continue;
+    graphene_rect_init (&bounds, 0, 0, width, height);
 
-    snapshot_tab (self, snapshot, info, region);
+    if (self->shader_compiled) {
+      gboolean fadeLeft = value > 0;
+      gboolean fadeRight = value + page_size < upper;
+
+      gtk_snapshot_push_gl_shader (snapshot, self->shader, &bounds,
+                                   gsk_gl_shader_format_args (self->shader,
+                                                              "offsetLeft", FADE_OFFSET,
+                                                              "offsetRight", FADE_OFFSET,
+                                                              "strengthLeft", fadeLeft ? 1.0f : 0.0f,
+                                                              "strengthRight", fadeRight ? 1.0f : 0.0f,
+                                                              "widthLeft", FADE_WIDTH,
+                                                              "widthRight", FADE_WIDTH,
+                                                              NULL));
+    } else {
+      gtk_snapshot_push_clip (snapshot, &bounds);
+    }
   }
 
-  n = cairo_region_num_rectangles (region);
-  for (i = 0; i < n; i++) {
-    cairo_region_get_rectangle (region, i, &rect);
+  snapshot_tabs (self, snapshot);
+
+  if (draw_fade) {
+    if (self->shader_compiled)
+      gtk_snapshot_gl_shader_pop_texture (snapshot);
 
-    gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (rect.x, rect.y, rect.width, rect.height));
-    gtk_widget_snapshot_child (widget, self->background, snapshot);
     gtk_snapshot_pop (snapshot);
   }
 
-  cairo_region_destroy (region);
+  gtk_widget_snapshot_child (GTK_WIDGET (self), self->needs_attention_left, snapshot);
+  gtk_widget_snapshot_child (GTK_WIDGET (self), self->needs_attention_right, snapshot);
 }
 
 static gboolean
@@ -3162,6 +3387,8 @@ adw_tab_box_unrealize (GtkWidget *widget)
   g_clear_pointer ((GtkWidget **) &self->context_menu, gtk_widget_unparent);
 
   GTK_WIDGET_CLASS (adw_tab_box_parent_class)->unrealize (widget);
+
+  g_clear_object (&self->shader);
 }
 
 static void
@@ -3216,8 +3443,6 @@ adw_tab_box_dispose (GObject *object)
 
   g_clear_handle_id (&self->drop_switch_timeout_id, g_source_remove);
 
-  g_clear_pointer (&self->background, gtk_widget_unparent);
-
   self->drag_gesture = NULL;
   self->tab_bar = NULL;
   adw_tab_box_set_view (self, NULL);
@@ -3226,6 +3451,9 @@ adw_tab_box_dispose (GObject *object)
   g_clear_object (&self->resize_animation);
   g_clear_object (&self->scroll_animation);
 
+  g_clear_pointer (&self->needs_attention_left, gtk_widget_unparent);
+  g_clear_pointer (&self->needs_attention_right, gtk_widget_unparent);
+
   G_OBJECT_CLASS (adw_tab_box_parent_class)->dispose (object);
 }
 
@@ -3260,14 +3488,6 @@ adw_tab_box_get_property (GObject    *object,
     g_value_set_object (value, self->view);
     break;
 
-  case PROP_NEEDS_ATTENTION_LEFT:
-    g_value_set_boolean (value, self->needs_attention_left);
-    break;
-
-  case PROP_NEEDS_ATTENTION_RIGHT:
-    g_value_set_boolean (value, self->needs_attention_right);
-    break;
-
   case PROP_RESIZE_FROZEN:
     g_value_set_boolean (value, self->tab_resize_mode != TAB_RESIZE_NORMAL);
     break;
@@ -3361,20 +3581,6 @@ adw_tab_box_class_init (AdwTabBoxClass *klass)
                          ADW_TYPE_TAB_VIEW,
                          G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
 
-  props[PROP_NEEDS_ATTENTION_LEFT] =
-    g_param_spec_boolean ("needs-attention-left",
-                          "Needs Attention Left",
-                          "Needs Attention Left",
-                          FALSE,
-                          G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
-
-  props[PROP_NEEDS_ATTENTION_RIGHT] =
-    g_param_spec_boolean ("needs-attention-right",
-                          "Needs Attention Right",
-                          "Needs Attention Right",
-                          FALSE,
-                          G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
-
   props[PROP_RESIZE_FROZEN] =
     g_param_spec_boolean ("resize-frozen",
                           "Resize Frozen",
@@ -3434,17 +3640,13 @@ adw_tab_box_init (AdwTabBox *self)
 {
   GtkEventController *controller;
   AdwAnimationTarget *target;
+  GtkWidget *widget;
 
   self->can_remove_placeholder = TRUE;
   self->expand_tabs = TRUE;
 
   gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN);
 
-  self->background = adw_gizmo_new ("background", NULL, NULL, NULL, NULL, NULL, NULL);
-  gtk_widget_set_can_target (self->background, FALSE);
-  gtk_widget_set_can_focus (self->background, FALSE);
-  gtk_widget_set_parent (self->background, 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);
@@ -3511,6 +3713,28 @@ adw_tab_box_init (AdwTabBox *self)
 
   g_signal_connect_swapped (self->scroll_animation, "done",
                             G_CALLBACK (scroll_animation_done_cb), self);
+
+  self->needs_attention_left = gtk_revealer_new ();
+  gtk_revealer_set_transition_type (GTK_REVEALER (self->needs_attention_left),
+                                    GTK_REVEALER_TRANSITION_TYPE_CROSSFADE);
+  gtk_widget_set_can_target (self->needs_attention_left, FALSE);
+  gtk_widget_set_can_focus (self->needs_attention_left, FALSE);
+  gtk_widget_set_parent (self->needs_attention_left, GTK_WIDGET (self));
+
+  widget = adw_gizmo_new ("indicator", NULL, NULL, NULL, NULL, NULL, NULL);
+  gtk_widget_add_css_class (widget, "left");
+  gtk_revealer_set_child (GTK_REVEALER (self->needs_attention_left), widget);
+
+  self->needs_attention_right = gtk_revealer_new ();
+  gtk_revealer_set_transition_type (GTK_REVEALER (self->needs_attention_right),
+                                    GTK_REVEALER_TRANSITION_TYPE_CROSSFADE);
+  gtk_widget_set_can_target (self->needs_attention_right, FALSE);
+  gtk_widget_set_can_focus (self->needs_attention_right, FALSE);
+  gtk_widget_set_parent (self->needs_attention_right, GTK_WIDGET (self));
+
+  widget = adw_gizmo_new ("indicator", NULL, NULL, NULL, NULL, NULL, NULL);
+  gtk_widget_add_css_class (widget, "right");
+  gtk_revealer_set_child (GTK_REVEALER (self->needs_attention_right), widget);
 }
 
 void
diff --git a/src/adw-tab.c b/src/adw-tab.c
index 36978829..a9e0eb9c 100644
--- a/src/adw-tab.c
+++ b/src/adw-tab.c
@@ -20,6 +20,12 @@
 #define BASE_WIDTH 118
 #define BASE_WIDTH_PINNED 28
 
+#define ATTENTION_INDICATOR_PINNED_WIDTH 14
+#define ATTENTION_INDICATOR_WIDTH_MULTIPLIER 0.6
+#define ATTENTION_INDICATOR_MIN_WIDTH 20
+#define ATTENTION_INDICATOR_MAX_WIDTH 180
+#define ATTENTION_INDICATOR_ANIMATION_DURATION 250
+
 struct _AdwTab
 {
   GtkWidget parent_instance;
@@ -31,6 +37,7 @@ struct _AdwTab
   GtkImage *indicator_icon;
   GtkWidget *indicator_btn;
   GtkWidget *close_btn;
+  GtkWidget *needs_attention_indicator;
   GtkDropTarget *drop_target;
 
   AdwTabView *view;
@@ -47,6 +54,7 @@ struct _AdwTab
   gboolean fully_visible;
 
   AdwAnimation *close_btn_animation;
+  AdwAnimation *needs_attention_animation;
 
   GskGLShader *shader;
   gboolean shader_compiled;
@@ -93,6 +101,13 @@ close_btn_animation_value_cb (double  value,
   gtk_widget_queue_draw (GTK_WIDGET (self));
 }
 
+static void
+attention_indicator_animation_value_cb (double  value,
+                                        AdwTab *self)
+{
+  gtk_widget_queue_allocate (GTK_WIDGET (self));
+}
+
 static void
 update_state (AdwTab *self)
 {
@@ -197,8 +212,15 @@ update_indicator (AdwTab *self)
 static void
 update_needs_attention (AdwTab *self)
 {
-  set_style_class (GTK_WIDGET (self), "needs-attention",
-                   adw_tab_page_get_needs_attention (self->page));
+  gboolean needs_attention = adw_tab_page_get_needs_attention (self->page);
+
+  adw_timed_animation_set_value_from (ADW_TIMED_ANIMATION (self->needs_attention_animation),
+                                      adw_animation_get_value (self->needs_attention_animation));
+  adw_timed_animation_set_value_to (ADW_TIMED_ANIMATION (self->needs_attention_animation),
+                                    needs_attention ? 1 : 0);
+  adw_animation_play (self->needs_attention_animation);
+
+  set_style_class (GTK_WIDGET (self), "needs-attention", needs_attention);
 }
 
 static void
@@ -381,6 +403,11 @@ adw_tab_measure (GtkWidget      *widget,
                         &child_min, &child_nat, NULL, NULL);
     min = MAX (min, child_min);
     nat = MAX (nat, child_nat);
+
+    gtk_widget_measure (self->needs_attention_indicator, orientation, for_size,
+                        &child_min, &child_nat, NULL, NULL);
+    min = MAX (min, child_min);
+    nat = MAX (nat, child_nat);
   }
 
   if (minimum)
@@ -426,6 +453,22 @@ allocate_child (GtkWidget *child,
   gtk_widget_size_allocate (child, &child_alloc, baseline);
 }
 
+static int
+get_attention_indicator_width (AdwTab *self,
+                               int     center_width)
+{
+  double base_width;
+
+  if (self->pinned) {
+    base_width = ATTENTION_INDICATOR_PINNED_WIDTH;
+  } else {
+    base_width = center_width * ATTENTION_INDICATOR_WIDTH_MULTIPLIER;
+    base_width = CLAMP (base_width, ATTENTION_INDICATOR_MIN_WIDTH, ATTENTION_INDICATOR_MAX_WIDTH);
+  }
+
+  return base_width * adw_animation_get_value (self->needs_attention_animation);
+}
+
 static void
 adw_tab_size_allocate (GtkWidget *widget,
                        int        width,
@@ -433,14 +476,16 @@ adw_tab_size_allocate (GtkWidget *widget,
                        int        baseline)
 {
   AdwTab *self = ADW_TAB (widget);
-  int indicator_width, close_width, icon_width, title_width;
+  int indicator_width, close_width, icon_width, title_width, needs_attention_width;
   int center_x, center_width = 0;
   int start_width = 0, end_width = 0;
+  int needs_attention_x;
 
   measure_child (self->icon_stack, height, &icon_width);
   measure_child (self->title, height, &title_width);
   measure_child (self->indicator_btn, height, &indicator_width);
   measure_child (self->close_btn, height, &close_width);
+  measure_child (self->needs_attention_indicator, height, &needs_attention_width);
 
   if (gtk_widget_get_visible (self->indicator_btn)) {
     if (self->pinned) {
@@ -489,6 +534,13 @@ adw_tab_size_allocate (GtkWidget *widget,
                         gtk_widget_get_visible (self->close_btn) &&
                         center_x + center_width > width - close_width;
 
+  needs_attention_width = MAX (needs_attention_width,
+                               get_attention_indicator_width (self, center_width));
+  needs_attention_x = (width - needs_attention_width) / 2;
+
+  allocate_child (self->needs_attention_indicator, width, height,
+                  needs_attention_x, needs_attention_width, baseline);
+
   if (gtk_widget_get_visible (self->icon_stack)) {
     allocate_child (self->icon_stack, width, height,
                     center_x, icon_width, baseline);
@@ -530,6 +582,7 @@ adw_tab_snapshot (GtkWidget   *widget,
   float opacity = gtk_widget_get_opacity (self->close_btn);
   gboolean draw_fade = self->close_overlap && opacity > 0;
 
+  gtk_widget_snapshot_child (widget, self->needs_attention_indicator, snapshot);
   gtk_widget_snapshot_child (widget, self->indicator_btn, snapshot);
   gtk_widget_snapshot_child (widget, self->icon_stack, snapshot);
 
@@ -697,10 +750,12 @@ adw_tab_dispose (GObject *object)
 
   g_clear_object (&self->shader);
   g_clear_object (&self->close_btn_animation);
+  g_clear_object (&self->needs_attention_animation);
   gtk_widget_unparent (self->indicator_btn);
   gtk_widget_unparent (self->icon_stack);
   gtk_widget_unparent (self->title);
   gtk_widget_unparent (self->close_btn);
+  gtk_widget_unparent (self->needs_attention_indicator);
 
   G_OBJECT_CLASS (adw_tab_parent_class)->dispose (object);
 }
@@ -780,6 +835,7 @@ 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_child (widget_class, AdwTab, needs_attention_indicator);
   gtk_widget_class_bind_template_child (widget_class, AdwTab, drop_target);
   gtk_widget_class_bind_template_callback (widget_class, close_clicked_cb);
   gtk_widget_class_bind_template_callback (widget_class, indicator_clicked_cb);
@@ -815,6 +871,16 @@ adw_tab_init (AdwTab *self)
 
   adw_timed_animation_set_easing (ADW_TIMED_ANIMATION (self->close_btn_animation),
                                   ADW_EASE_IN_OUT_CUBIC);
+
+  target = adw_callback_animation_target_new ((AdwAnimationTargetFunc)
+                                              attention_indicator_animation_value_cb,
+                                              self, NULL);
+  self->needs_attention_animation =
+    adw_timed_animation_new (GTK_WIDGET (self), 0, 0,
+                             ATTENTION_INDICATOR_ANIMATION_DURATION, target);
+
+  adw_timed_animation_set_easing (ADW_TIMED_ANIMATION (self->needs_attention_animation),
+                                  ADW_EASE_IN_OUT_CUBIC);
 }
 
 AdwTab *
diff --git a/src/adw-tab.ui b/src/adw-tab.ui
index ff16772f..ef9c3730 100644
--- a/src/adw-tab.ui
+++ b/src/adw-tab.ui
@@ -88,5 +88,11 @@
         </style>
       </object>
     </child>
+    <child>
+      <object class="AdwGizmo" id="needs_attention_indicator">
+        <property name="css-name">indicator</property>
+        <property name="valign">end</property>
+      </object>
+    </child>
   </template>
 </interface>
diff --git a/src/stylesheet/widgets/_tab-view.scss b/src/stylesheet/widgets/_tab-view.scss
index 551e1d14..bc720f98 100644
--- a/src/stylesheet/widgets/_tab-view.scss
+++ b/src/stylesheet/widgets/_tab-view.scss
@@ -1,128 +1,62 @@
-$tab_needs_attention_gradient: radial-gradient(ellipse at bottom,
-                                               transparentize(white, .2),
-                                               gtkalpha($accent_color, .4) 10%,
-                                               gtkalpha($accent_color, 0) 30%);
-
-
-@mixin undershoot-gradient($dir, $color) {
-  background: linear-gradient(to #{$dir},
-                              $color,
-                              transparentize(black, 1) 20px);
-}
-
-@mixin need-attention-gradient($dir) {
-  background: linear-gradient(to #{$dir},
-                              gtkalpha($accent_color, .5),
-                              gtkalpha($accent_color, .3) 1px,
-                              gtkalpha($accent_color, 0) 20px);
-}
-
 tabbar {
   .box {
     min-height: 38px;
   }
 
-  scrolledwindow.pinned {
-    undershoot {
-      border: 0 solid $border_color;
-    }
-
-    &:dir(rtl) undershoot.left {
-      border-left-width: 1px;
-    }
-
-    &:dir(ltr) undershoot.right {
-      border-right-width: 1px;
+  tabbox {
+    > widget {
+      @include focus-ring();
+      border-radius: $button_radius;
+      margin-bottom: 3px;
+      margin-top: 3px;
     }
 
-    tabbox > background {
-      &:dir(ltr) {
-        box-shadow: inset -1px 0 $border_color;
-      }
+    > separator {
+      margin-top: 9px;
+      margin-bottom: 9px;
+      transition: opacity 150ms ease-in-out;
 
-      &:dir(rtl) {
-        box-shadow: inset 1px 0 $border_color;
+      &.hidden {
+        opacity: 0;
       }
     }
   }
 
-  undershoot {
+  tab {
     transition: background 150ms ease-in-out;
 
-    &.left {
-      @include undershoot-gradient("right", $shade_color);
-    }
-
-    &.right {
-      @include undershoot-gradient("left", $shade_color);
-    }
-  }
-
-  .needs-attention-left undershoot.left {
-    @include need-attention-gradient("right");
-  }
-
-  .needs-attention-right undershoot.right {
-    @include need-attention-gradient("left");
-  }
-
-  tabbox {
-    > background {
-      background-color: $shade_color;
+    @if $contrast == 'high' {
+      &:hover,
+      &:active,
+      &:checked {
+        box-shadow: inset 0 0 0 1px $border_color;
+      }
     }
 
-    > widget {
-      @include focus-ring();
-    }
-  }
+    &:checked {
+      background-color: $view_selected_color;
 
-  tab {
-    border-style: solid;
-    border-color: $border_color;
-    border-width: 0 1px 0 1px;
-    transition: background 150ms ease-in-out;
-    background-color: gtkalpha($shade_color, .6);
-    background-clip: padding-box;
+      &:hover {
+        background-color: $view_selected_hover_color;
 
-    &:checked {
-      background-color: transparent;
+        &:active {
+          background-color: $view_selected_active_color;
+        }
+      }
     }
 
     &:hover {
-      background-image: image(gtkalpha(currentColor, .03));
-    }
-
-    &.needs-attention {
-      background-image: $tab_needs_attention_gradient;
+      background-color: $view_hover_color;
 
-      &:hover {
-        background-image: image(gtkalpha(currentColor, .03)), $tab_needs_attention_gradient;
+      &:active {
+        background-color: $view_active_color;
       }
     }
   }
 
   .start-action,
   .end-action {
-    background-color: gtkalpha($shade_color, .6);
-    background-clip: padding-box;
-    border-color: $border_color;
-    border-style: solid;
-    transition: background 150ms ease-in-out;
-
-    button {
-      border: none;
-      border-radius: 0;
-    }
-  }
-
-  .start-action:dir(ltr),
-  .end-action:dir(rtl) {
-    border-right-width: 1px;
-  }
-
-  .start-action:dir(rtl),
-  .end-action:dir(ltr) {
-    border-left-width: 1px;
+    padding: 3px;
   }
 
   &:not(.inline) {
@@ -132,59 +66,6 @@ tabbar {
       border-bottom: 1px solid $headerbar_border_color;
     }
 
-    scrolledwindow.pinned {
-      undershoot {
-        border-color: $headerbar_border_color;
-      }
-
-      tabbox > background {
-        &:dir(ltr) {
-          box-shadow: inset -1px 0 $headerbar_border_color;
-        }
-
-        &:dir(rtl) {
-          box-shadow: inset 1px 0 $headerbar_border_color;
-        }
-      }
-    }
-
-    undershoot {
-      &.left {
-        @include undershoot-gradient("right", $headerbar_shade_color);
-      }
-
-      &.right {
-        @include undershoot-gradient("left", $headerbar_shade_color);
-      }
-    }
-
-    .needs-attention-left undershoot.left {
-      @include need-attention-gradient("right");
-    }
-
-    .needs-attention-right undershoot.right {
-      @include need-attention-gradient("left");
-    }
-
-    tabbox > background {
-      background-color: $headerbar_shade_color;
-    }
-
-    tab {
-      border-color: $headerbar_border_color;
-      background-color: gtkalpha($headerbar_shade_color, .6);
-
-      &:checked {
-        background-color: transparent;
-      }
-    }
-
-    .start-action,
-    .end-action {
-      background-color: gtkalpha($headerbar_shade_color, .6);
-      border-color: $headerbar_border_color;
-    }
-
     &:backdrop .box {
       background-color: $headerbar_backdrop_color;
       transition: $backdrop_transition;
@@ -193,20 +74,18 @@ tabbar {
 }
 
 dnd tab {
-  min-height: 26px;
   background-color: $headerbar_bg_color;
+  background-image: image($view_selected_active_color);
   color: $headerbar_fg_color;
 
-  &.needs-attention {
-    background-image: $tab_needs_attention_gradient;
-  }
+  box-shadow: 0 0 0 1px transparentize(black, 0.97),
+              0 1px 3px 1px transparentize(black, .93),
+              0 2px 6px 2px transparentize(black, .97);
 
-  box-shadow: 0 1px 5px 1px transparentize(black, .91),
-              0 2px 14px 3px transparentize(black, .95),
-              0 0 0 1px transparentize(black, if($contrast == 'high', .2, .95));
-
-  outline: 1px solid $window_outline_color;
-  outline-offset: -1px;
+  @if $contrast == 'high' {
+    outline: 1px solid $border_color;
+    outline-offset: -1px;
+  }
 
   margin: 25px;
 }
@@ -214,7 +93,9 @@ dnd tab {
 tabbar,
 dnd {
   tab {
+    min-height: 24px;
     padding: 6px;
+    border-radius: $button_radius;
 
     button.image-button {
       padding: 0;
@@ -223,6 +104,13 @@ dnd {
       min-height: 24px;
       border-radius: 99px;
     }
+
+    indicator {
+      min-height: 2px;
+      border-radius: 2px;
+      background: if($contrast == 'high', $accent_color, gtkalpha($accent_color, 0.5));
+      transform: translateY(6px);
+    }
   }
 }
 


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