[libadwaita/wip/exalm/tab-overview: 1/3] Add AdwTabButton




commit 512d6f385b2c22a3192f41a0afce26583d18b4dc
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Thu Aug 19 18:42:03 2021 +0500

    Add AdwTabButton

 src/adw-tab-button.c                               | 510 +++++++++++++++++++++
 src/adw-tab-button.h                               |  36 ++
 src/adw-tab-button.ui                              |  38 ++
 src/adwaita.gresources.xml                         |   3 +
 src/adwaita.h                                      |   1 +
 .../scalable/status/adw-tab-counter-symbolic.svg   |  69 +++
 .../scalable/status/adw-tab-overflow-symbolic.svg  |  41 ++
 src/meson.build                                    |   2 +
 src/stylesheet/widgets/_buttons.scss               |  11 +
 9 files changed, 711 insertions(+)
---
diff --git a/src/adw-tab-button.c b/src/adw-tab-button.c
new file mode 100644
index 00000000..9e6a6719
--- /dev/null
+++ b/src/adw-tab-button.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2019 Alexander Mikhaylenko <exalm7659 gmail com>
+ * Copyright (C) 2021 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ *
+ * Author: Alexander Mikhaylenko <alexander mikhaylenko puri sm>
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include "adw-tab-button.h"
+
+#include "adw-indicator-bin-private.h"
+#include "adw-macros-private.h"
+
+/* Copied from GtkInspector code */
+#define XFT_DPI_MULTIPLIER (96.0 * PANGO_SCALE)
+
+/**
+ * AdwTabButton:
+ *
+ * A button that displays the number of [class@TabView] pages.
+ *
+ * The `AdwTabButton` widget is a button that displays the number of pages in a
+ * given `AdwTabView`.
+ *
+ * It can be used to open a tab switcher view in a mobile UI.
+ *
+ * ## CSS nodes
+ *
+ * `AdwTabButton` has a main CSS node with name tabbutton.
+ *
+ * It contains the subnode `button`, which contains the subnode `overlay`, which
+ * contains nodes `image` and `label`. The `label` subnode can have the `.small`
+ * style class for 10 or more tabs.
+ *
+ * # Accessibility
+ *
+ * `AdwTabButton` uses the `GTK_ACCESSIBLE_ROLE_BUTTON` role.
+ *
+ * Since: 1.0
+ */
+
+struct _AdwTabButton
+{
+  GtkWidget parent_instance;
+
+  GtkWidget *button;
+  GtkLabel *label;
+  GtkImage *icon;
+  AdwIndicatorBin *indicator;
+
+  AdwTabView *view;
+
+  int needs_attention;
+};
+
+static void adw_tab_button_actionable_init (GtkActionableInterface *iface);
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (AdwTabButton, adw_tab_button, GTK_TYPE_WIDGET,
+                               G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, adw_tab_button_actionable_init))
+
+enum {
+  PROP_0,
+  PROP_VIEW,
+
+  /* actionable properties */
+  PROP_ACTION_NAME,
+  PROP_ACTION_TARGET,
+  LAST_PROP = PROP_ACTION_NAME
+};
+
+static GParamSpec *props[LAST_PROP];
+
+enum {
+  SIGNAL_CLICKED,
+  SIGNAL_ACTIVATE,
+  SIGNAL_LAST_SIGNAL,
+};
+
+static guint signals[SIGNAL_LAST_SIGNAL];
+
+static void
+clicked_cb (AdwTabButton *self)
+{
+  g_signal_emit (self, signals[SIGNAL_CLICKED], 0);
+}
+
+static void
+activate_cb (AdwTabButton *self)
+{
+  g_signal_emit_by_name (self->button, "activate");
+}
+
+/* FIXME: I hope there is a better way to prevent the label from changing scale */
+static void
+update_label_scale (AdwTabButton *self,
+                    GtkSettings  *settings)
+{
+  int xft_dpi;
+  PangoAttrList *attrs;
+  PangoAttribute *scale_attribute;
+
+  g_object_get (settings, "gtk-xft-dpi", &xft_dpi, NULL);
+
+  attrs = pango_attr_list_new ();
+
+  scale_attribute = pango_attr_scale_new (XFT_DPI_MULTIPLIER / (double) xft_dpi);
+
+  pango_attr_list_change (attrs, scale_attribute);
+
+  gtk_label_set_attributes (self->label, attrs);
+
+  pango_attr_list_unref (attrs);
+}
+
+static void
+xft_dpi_changed (AdwTabButton *self,
+                 GParamSpec   *pspec,
+                 GtkSettings  *settings)
+{
+  update_label_scale (self, settings);
+}
+
+static void
+update_icon (AdwTabButton *self)
+{
+  gboolean display_label = FALSE;
+  gboolean small_label = FALSE;
+  const char *icon_name = "adw-tab-counter-symbolic";
+  char *label_text = NULL;
+  GtkStyleContext *context;
+
+  if (self->view) {
+    guint n_pages = adw_tab_view_get_n_pages (self->view);
+
+    small_label = n_pages >= 10;
+
+    if (n_pages < 100) {
+      display_label = TRUE;
+      label_text = g_strdup_printf ("%u", n_pages);
+    } else {
+      icon_name = "adw-tab-overflow-symbolic";
+    }
+  }
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (self->label));
+
+  if (small_label)
+    gtk_style_context_add_class (context, "small");
+  else
+    gtk_style_context_remove_class (context, "small");
+
+  gtk_widget_set_visible (GTK_WIDGET (self->label), display_label);
+  gtk_label_set_text (self->label, label_text);
+  gtk_image_set_from_icon_name (self->icon, icon_name);
+
+  g_free (label_text);
+}
+
+static void
+update_needs_attention (AdwTabButton *self)
+{
+  int needs_attention = self->needs_attention;
+
+  if (self->view) {
+    AdwTabPage *selected_page = adw_tab_view_get_selected_page (self->view);
+
+    if (selected_page && adw_tab_page_get_needs_attention (selected_page))
+      needs_attention--;
+  }
+
+  adw_indicator_bin_set_needs_attention (ADW_INDICATOR_BIN (self->indicator),
+                                         needs_attention > 0);
+}
+
+static void
+notify_needs_attention_cb (AdwTabButton *self,
+                           GParamSpec   *pspec,
+                           AdwTabPage   *page)
+{
+  if (adw_tab_page_get_needs_attention (page))
+    self->needs_attention++;
+  else
+    self->needs_attention--;
+
+  update_needs_attention (self);
+}
+
+static void
+page_attached_cb (AdwTabButton *self,
+                  AdwTabPage   *page)
+{
+  g_signal_connect_object (page, "notify::needs-attention",
+                           G_CALLBACK (notify_needs_attention_cb), self,
+                           G_CONNECT_SWAPPED);
+}
+
+static void
+page_detached_cb (AdwTabButton *self,
+                  AdwTabPage   *page)
+{
+  g_signal_handlers_disconnect_by_func (page, notify_needs_attention_cb, self);
+}
+
+static void
+adw_tab_button_dispose (GObject *object)
+{
+  AdwTabButton *self = ADW_TAB_BUTTON (object);
+
+  adw_tab_button_set_view (self, NULL);
+
+  gtk_widget_unparent (GTK_WIDGET (self->button));
+
+  G_OBJECT_CLASS (adw_tab_button_parent_class)->dispose (object);
+}
+
+static void
+adw_tab_button_get_property (GObject    *object,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+  AdwTabButton *self = ADW_TAB_BUTTON (object);
+
+  switch (prop_id) {
+  case PROP_VIEW:
+    g_value_set_object (value, adw_tab_button_get_view (self));
+    break;
+  case PROP_ACTION_NAME:
+    g_value_set_string (value, gtk_actionable_get_action_name (GTK_ACTIONABLE (self)));
+    break;
+  case PROP_ACTION_TARGET:
+    g_value_set_variant (value, gtk_actionable_get_action_target_value (GTK_ACTIONABLE (self)));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+adw_tab_button_set_property (GObject      *object,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+  AdwTabButton *self = ADW_TAB_BUTTON (object);
+
+  switch (prop_id) {
+  case PROP_VIEW:
+    adw_tab_button_set_view (self, g_value_get_object (value));
+    break;
+  case PROP_ACTION_NAME:
+    gtk_actionable_set_action_name (GTK_ACTIONABLE (self), g_value_get_string (value));
+    break;
+  case PROP_ACTION_TARGET:
+    gtk_actionable_set_action_target_value (GTK_ACTIONABLE (self), g_value_get_variant (value));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+adw_tab_button_class_init (AdwTabButtonClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->dispose = adw_tab_button_dispose;
+  object_class->get_property = adw_tab_button_get_property;
+  object_class->set_property = adw_tab_button_set_property;
+
+  /**
+   * AdwTabButton:view: (attributes org.gtk.Property.get=adw_tab_button_get_view 
org.gtk.Property.set=adw_tab_button_set_view)
+   *
+   * The view the tab button displays.
+   *
+   * Since: 1.3
+   */
+  props[PROP_VIEW] =
+    g_param_spec_object ("view", NULL, NULL,
+                         ADW_TYPE_TAB_VIEW,
+                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+  g_object_class_install_properties (object_class, LAST_PROP, props);
+
+  g_object_class_override_property (object_class, PROP_ACTION_NAME, "action-name");
+  g_object_class_override_property (object_class, PROP_ACTION_TARGET, "action-target");
+
+  /**
+   * AdwTabButton::clicked:
+   * @self: the object that received the signal
+   *
+   * Emitted when the button has been activated (pressed and released).
+   *
+   * Since: 1.3
+   */
+  signals[SIGNAL_CLICKED] =
+    g_signal_new ("clicked",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                  0,
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE,
+                  0);
+
+  /**
+   * AdwTabButton::activate:
+   * @self: the object which received the signal.
+   *
+   * Emitted to animate press then release.
+   *
+   * This is an action signal. Applications should never connect to this signal,
+   * but use the [signal@TabButton::clicked] signal.
+   *
+   * Since: 1.3
+   */
+  signals[SIGNAL_ACTIVATE] =
+    g_signal_new ("activate",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                  0,
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE,
+                  0);
+
+  gtk_widget_class_set_activate_signal (widget_class, signals[SIGNAL_ACTIVATE]);
+
+  g_signal_override_class_handler ("activate",
+                                   G_TYPE_FROM_CLASS (klass),
+                                   G_CALLBACK (activate_cb));
+
+  gtk_widget_class_set_template_from_resource (widget_class,
+                                               "/org/gnome/Adwaita/ui/adw-tab-button.ui");
+
+  gtk_widget_class_bind_template_child (widget_class, AdwTabButton, button);
+  gtk_widget_class_bind_template_child (widget_class, AdwTabButton, label);
+  gtk_widget_class_bind_template_child (widget_class, AdwTabButton, icon);
+  gtk_widget_class_bind_template_child (widget_class, AdwTabButton, indicator);
+  gtk_widget_class_bind_template_callback (widget_class, clicked_cb);
+
+  gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
+  gtk_widget_class_set_css_name (widget_class, "tabbutton");
+  gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_BUTTON);
+
+  g_type_ensure (ADW_TYPE_INDICATOR_BIN);
+}
+
+static void
+adw_tab_button_init (AdwTabButton *self)
+{
+  GtkSettings *settings;
+
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  update_icon (self);
+
+  settings = gtk_widget_get_settings (GTK_WIDGET (self));
+
+  update_label_scale (self, settings);
+  g_signal_connect_object (settings, "notify::gtk-xft-dpi",
+                           G_CALLBACK (xft_dpi_changed), self,
+                           G_CONNECT_SWAPPED);
+}
+
+static const char *
+adw_tab_button_get_action_name (GtkActionable *actionable)
+{
+  AdwTabButton *self = ADW_TAB_BUTTON (actionable);
+
+  return gtk_actionable_get_action_name (GTK_ACTIONABLE (self->button));
+}
+
+static void
+adw_tab_button_set_action_name (GtkActionable *actionable,
+                                const char    *action_name)
+{
+  AdwTabButton *self = ADW_TAB_BUTTON (actionable);
+
+  return gtk_actionable_set_action_name (GTK_ACTIONABLE (self->button),
+                                         action_name);
+}
+
+static GVariant *
+adw_tab_button_get_action_target_value (GtkActionable *actionable)
+{
+  AdwTabButton *self = ADW_TAB_BUTTON (actionable);
+
+  return gtk_actionable_get_action_target_value (GTK_ACTIONABLE (self->button));
+}
+
+static void
+adw_tab_button_set_action_target_value (GtkActionable *actionable,
+                                        GVariant      *action_target)
+{
+  AdwTabButton *self = ADW_TAB_BUTTON (actionable);
+
+  return gtk_actionable_set_action_target_value (GTK_ACTIONABLE (self->button),
+                                                 action_target);
+}
+
+static void
+adw_tab_button_actionable_init (GtkActionableInterface *iface)
+{
+  iface->get_action_name = adw_tab_button_get_action_name;
+  iface->set_action_name = adw_tab_button_set_action_name;
+  iface->get_action_target_value = adw_tab_button_get_action_target_value;
+  iface->set_action_target_value = adw_tab_button_set_action_target_value;
+}
+
+/**
+ * adw_tab_button_new:
+ *
+ * Creates a new `AdwTabButton`.
+ *
+ * Returns: the newly created `AdwTabButton`
+ *
+ * Since: 1.3
+ */
+GtkWidget *
+adw_tab_button_new (void)
+{
+  return g_object_new (ADW_TYPE_TAB_BUTTON, NULL);
+}
+
+/**
+ * adw_tab_button_get_view: (attributes org.gtk.Method.get_property=view)
+ * @self: a tab button
+ *
+ * Gets the tab view @self displays.
+ *
+ * Returns: (transfer none) (nullable): the tab view
+ *
+ * Since: 1.3
+ */
+AdwTabView *
+adw_tab_button_get_view (AdwTabButton *self)
+{
+  g_return_val_if_fail (ADW_IS_TAB_BUTTON (self), NULL);
+
+  return self->view;
+}
+
+/**
+ * adw_tab_button_set_view: (attributes org.gtk.Method.set_property=view)
+ * @self: a tab button
+ * @view: (nullable): a tab view
+ *
+ * Sets the tab view to display.
+ *
+ * Since: 1.3
+ */
+void
+adw_tab_button_set_view (AdwTabButton *self,
+                         AdwTabView   *view)
+{
+  g_return_if_fail (ADW_IS_TAB_BUTTON (self));
+  g_return_if_fail (view == NULL || ADW_IS_TAB_VIEW (view));
+
+  if (self->view == view)
+    return;
+
+  if (self->view) {
+    int i, n;
+
+    g_signal_handlers_disconnect_by_func (self->view, update_icon, self);
+    g_signal_handlers_disconnect_by_func (self->view, update_needs_attention, self);
+    g_signal_handlers_disconnect_by_func (self->view, page_attached_cb, self);
+    g_signal_handlers_disconnect_by_func (self->view, page_detached_cb, self);
+
+    n = adw_tab_view_get_n_pages (self->view);
+
+    for (i = 0; i < n; i++)
+      page_detached_cb (self, adw_tab_view_get_nth_page (self->view, i));
+
+    self->needs_attention = 0;
+  }
+
+  g_set_object (&self->view, view);
+
+  if (self->view) {
+    int i, n;
+
+    g_signal_connect_object (self->view, "notify::n-pages",
+                             G_CALLBACK (update_icon), self,
+                             G_CONNECT_SWAPPED);
+    g_signal_connect_object (self->view, "notify::selected-page",
+                             G_CALLBACK (update_needs_attention), self,
+                             G_CONNECT_SWAPPED);
+    g_signal_connect_object (self->view, "page-attached",
+                             G_CALLBACK (page_attached_cb), self,
+                             G_CONNECT_SWAPPED);
+    g_signal_connect_object (self->view, "page-detached",
+                             G_CALLBACK (page_detached_cb), self,
+                             G_CONNECT_SWAPPED);
+
+    n = adw_tab_view_get_n_pages (self->view);
+
+    for (i = 0; i < n; i++)
+      page_attached_cb (self, adw_tab_view_get_nth_page (self->view, i));
+  }
+
+  update_icon (self);
+  update_needs_attention (self);
+
+  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_VIEW]);
+}
diff --git a/src/adw-tab-button.h b/src/adw-tab-button.h
new file mode 100644
index 00000000..8f6f943e
--- /dev/null
+++ b/src/adw-tab-button.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ *
+ * Author: Alexander Mikhaylenko <alexander mikhaylenko puri sm>
+ */
+
+#pragma once
+
+#if !defined(_ADWAITA_INSIDE) && !defined(ADWAITA_COMPILATION)
+#error "Only <adwaita.h> can be included directly."
+#endif
+
+#include "adw-version.h"
+
+#include <gtk/gtk.h>
+#include "adw-tab-view.h"
+
+G_BEGIN_DECLS
+
+#define ADW_TYPE_TAB_BUTTON (adw_tab_button_get_type())
+
+ADW_AVAILABLE_IN_1_2
+G_DECLARE_FINAL_TYPE (AdwTabButton, adw_tab_button, ADW, TAB_BUTTON, GtkWidget)
+
+ADW_AVAILABLE_IN_1_2
+GtkWidget *adw_tab_button_new (void) G_GNUC_WARN_UNUSED_RESULT;
+
+ADW_AVAILABLE_IN_1_2
+AdwTabView *adw_tab_button_get_view (AdwTabButton *self);
+ADW_AVAILABLE_IN_1_2
+void        adw_tab_button_set_view (AdwTabButton *self,
+                                     AdwTabView   *view);
+
+G_END_DECLS
diff --git a/src/adw-tab-button.ui b/src/adw-tab-button.ui
new file mode 100644
index 00000000..b8354860
--- /dev/null
+++ b/src/adw-tab-button.ui
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk" version="4.0"/>
+  <template class="AdwTabButton" parent="GtkWidget">
+    <child>
+      <object class="GtkButton" id="button">
+        <property name="tooltip-text" translatable="yes">View Open Tabs</property>
+        <signal name="clicked" handler="clicked_cb" swapped="yes"/>
+        <property name="child">
+          <object class="AdwIndicatorBin" id="indicator">
+            <property name="halign">center</property>
+            <property name="valign">center</property>
+            <property name="child">
+              <object class="GtkOverlay">
+                <child>
+                  <object class="GtkImage" id="icon"/>
+                </child>
+                <child type="overlay">
+                  <object class="GtkLabel" id="label">
+                    <property name="xalign">0.5</property>
+                    <property name="justify">center</property>
+                    <property name="width-chars">2</property>
+                    <style>
+                      <class name="numeric"/>
+                    </style>
+                  </object>
+                </child>
+              </object>
+            </property>
+          </object>
+        </property>
+        <style>
+          <class name="image-button"/>
+        </style>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/adwaita.gresources.xml b/src/adwaita.gresources.xml
index 58a0d7c4..095d250e 100644
--- a/src/adwaita.gresources.xml
+++ b/src/adwaita.gresources.xml
@@ -8,7 +8,9 @@
     <file preprocess="xml-stripblanks">icons/scalable/actions/adw-expander-arrow-symbolic.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/actions/adw-mail-send-symbolic.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/status/avatar-default-symbolic.svg</file>
+    <file preprocess="xml-stripblanks">icons/scalable/status/adw-tab-counter-symbolic.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/status/adw-tab-icon-missing-symbolic.svg</file>
+    <file preprocess="xml-stripblanks">icons/scalable/status/adw-tab-overflow-symbolic.svg</file>
   </gresource>
   <gresource prefix="/org/gnome/Adwaita/ui">
     <file preprocess="xml-stripblanks">adw-about-window.ui</file>
@@ -24,6 +26,7 @@
     <file preprocess="xml-stripblanks">adw-status-page.ui</file>
     <file preprocess="xml-stripblanks">adw-tab.ui</file>
     <file preprocess="xml-stripblanks">adw-tab-bar.ui</file>
+    <file preprocess="xml-stripblanks">adw-tab-button.ui</file>
     <file preprocess="xml-stripblanks">adw-toast-widget.ui</file>
     <file preprocess="xml-stripblanks">adw-view-switcher-bar.ui</file>
     <file preprocess="xml-stripblanks">adw-view-switcher-button.ui</file>
diff --git a/src/adwaita.h b/src/adwaita.h
index 509a9740..6707b57c 100644
--- a/src/adwaita.h
+++ b/src/adwaita.h
@@ -64,6 +64,7 @@ G_BEGIN_DECLS
 #include "adw-swipe-tracker.h"
 #include "adw-swipeable.h"
 #include "adw-tab-bar.h"
+#include "adw-tab-button.h"
 #include "adw-tab-view.h"
 #include "adw-timed-animation.h"
 #include "adw-toast-overlay.h"
diff --git a/src/icons/scalable/status/adw-tab-counter-symbolic.svg 
b/src/icons/scalable/status/adw-tab-counter-symbolic.svg
new file mode 100644
index 00000000..5837085c
--- /dev/null
+++ b/src/icons/scalable/status/adw-tab-counter-symbolic.svg
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="16"
+   version="1.1"
+   id="svg7384"
+   height="16"
+   sodipodi:docname="tab-counter-symbolic.svg"
+   inkscape:version="0.92.4 5da689c313, 2019-01-14">
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1016"
+     id="namedview8"
+     showgrid="true"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-paths="true"
+     inkscape:bbox-nodes="true"
+     inkscape:snap-text-baseline="true"
+     inkscape:zoom="11.313708"
+     inkscape:cx="-14.248148"
+     inkscape:cy="15.003638"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="g4572">
+    <inkscape:grid
+       type="xygrid"
+       id="grid4519" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata90">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title>Gnome Symbolic Icon Theme</dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <title
+     id="title9167">Gnome Symbolic Icon Theme</title>
+  <defs
+     id="defs7386" />
+  <g
+     id="g4572">
+    <path
+       
style="color:#bebebe;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;
 
stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="M 2.1992188,0 C 0.94446612,0 0,1.0997689 0,2.3183594 V 13.681641 C 0,14.900231 0.94447706,16 
2.1992188,16 H 13.800781 C 15.055523,16 16,14.90024 16,13.681641 V 2.3183594 C 16,1.0997598 15.055534,0 
13.800781,0 Z m 0,2 H 13.800781 C 13.874369,2 14,2.0752716 14,2.3183594 V 13.681641 C 14,13.924729 
13.87438,14 13.800781,14 H 2.1992188 C 2.1256204,14 2,13.924738 2,13.681641 V 2.3183594 C 2,2.0752625 
2.1256314,2 2.1992188,2 Z"
+       id="rect11749-5-9"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ssssssssssssssssss" />
+  </g>
+</svg>
diff --git a/src/icons/scalable/status/adw-tab-overflow-symbolic.svg 
b/src/icons/scalable/status/adw-tab-overflow-symbolic.svg
new file mode 100644
index 00000000..602b7ce2
--- /dev/null
+++ b/src/icons/scalable/status/adw-tab-overflow-symbolic.svg
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   height="16"
+   id="svg7384"
+   version="1.1"
+   width="16">
+  <metadata
+     id="metadata90">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title>Gnome Symbolic Icon Theme</dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <title
+     id="title9167">Gnome Symbolic Icon Theme</title>
+  <defs
+     id="defs7386" />
+  <path
+     id="path859"
+     d="M 2.199219,0 C 0.944466,0 0,1.0997689 0,2.3183594 V 13.681641 C 0,14.900231 0.944477,16 2.199219,16 
H 13.80078 C 15.05552,16 16,14.90024 16,13.681641 V 2.3183594 C 16,1.0997598 15.05553,0 13.80078,0 Z m 0,2 H 
13.80078 C 13.87437,2 14,2.0752716 14,2.3183594 V 13.681641 C 14,13.924729 13.87438,14 13.80078,14 H 2.199219 
C 2.12562,14 2,13.924738 2,13.681641 V 2.3183594 C 2,2.0752625 2.125631,2 2.199219,2 Z"
+     
style="color:#bebebe;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#241f31;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;st
 
roke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
 />
+  <g
+     transform="translate(20)"
+     id="text863"
+     
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:12px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:'Cantarell
 
Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#241f31;fill-opacity:1;stroke:none"
+     aria-label="∞">
+    <path
+       id="path880"
+       d="m -14.519998,10.488 c 1.14,0 1.836,-0.66 2.388,-1.44 0.504,0.78 1.176,1.44 2.388,1.44 1.572,0 
2.628,-1.068 2.628,-2.64 0,-1.488 -0.972,-2.472 -2.376,-2.472 -1.104,0 -1.8,0.624 -2.352,1.356 -0.48,-0.732 
-1.14,-1.356 -2.352,-1.356 -1.596,0 -2.688,1.056 -2.688,2.64 0,1.476 0.972,2.472 2.364,2.472 z m -0.804,-2.58 
c 0,-0.744 0.396,-1.236 1.056,-1.236 0.744,0 1.152,0.624 1.56,1.38 -0.42,0.636 -0.864,1.14 -1.524,1.14 
-0.672,0 -1.092,-0.516 -1.092,-1.284 z m 5.544,-1.236 c 0.648,0 1.104,0.492 1.104,1.32 0,0.72 -0.36,1.2 
-1.02,1.2 -0.78,0 -1.176,-0.672 -1.572,-1.452 0.408,-0.6 0.852,-1.068 1.488,-1.068 z" />
+  </g>
+</svg>
diff --git a/src/meson.build b/src/meson.build
index 54664c1e..dd6536a0 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -125,6 +125,7 @@ src_headers = [
   'adw-swipe-tracker.h',
   'adw-swipeable.h',
   'adw-tab-bar.h',
+  'adw-tab-button.h',
   'adw-tab-view.h',
   'adw-timed-animation.h',
   'adw-toast.h',
@@ -189,6 +190,7 @@ src_sources = [
   'adw-swipe-tracker.c',
   'adw-swipeable.c',
   'adw-tab-bar.c',
+  'adw-tab-button.c',
   'adw-tab-view.c',
   'adw-timed-animation.c',
   'adw-toast.c',
diff --git a/src/stylesheet/widgets/_buttons.scss b/src/stylesheet/widgets/_buttons.scss
index 5f1ee606..3e1f78dd 100644
--- a/src/stylesheet/widgets/_buttons.scss
+++ b/src/stylesheet/widgets/_buttons.scss
@@ -598,3 +598,14 @@ buttoncontent {
     }
   }
 }
+
+tabbutton {
+  label {
+    font-weight: 800;
+    font-size: 8pt;
+
+    &.small {
+      font-size: 6pt;
+    }
+  }
+}


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