[libadwaita] Add AdwToastWidget
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libadwaita] Add AdwToastWidget
- Date: Sat, 6 Nov 2021 17:20:18 +0000 (UTC)
commit 61a1dccccd7925b2524bd75f7dc7335b876fbfaf
Author: Maximiliano Sandoval R <msandova gnome org>
Date: Sat Nov 6 22:09:29 2021 +0500
Add AdwToastWidget
Co-authored-by: Alexander Mikhaylenko <alexm gnome org>
src/adw-toast-widget-private.h | 26 +++++
src/adw-toast-widget.c | 206 ++++++++++++++++++++++++++++++++++++++
src/adw-toast-widget.ui | 80 +++++++++++++++
src/adwaita.gresources.xml | 1 +
src/meson.build | 1 +
src/stylesheet/widgets/_misc.scss | 26 +++++
6 files changed, 340 insertions(+)
---
diff --git a/src/adw-toast-widget-private.h b/src/adw-toast-widget-private.h
new file mode 100644
index 00000000..ff523f71
--- /dev/null
+++ b/src/adw-toast-widget-private.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#if !defined(_ADWAITA_INSIDE) && !defined(ADWAITA_COMPILATION)
+#error "Only <adwaita.h> can be included directly."
+#endif
+
+#include "adw-version.h"
+#include "adw-toast.h"
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define ADW_TYPE_TOAST_WIDGET (adw_toast_widget_get_type())
+
+G_DECLARE_FINAL_TYPE (AdwToastWidget, adw_toast_widget, ADW, TOAST_WIDGET, GtkWidget)
+
+GtkWidget *adw_toast_widget_new (AdwToast *toast) G_GNUC_WARN_UNUSED_RESULT;
+
+G_END_DECLS
diff --git a/src/adw-toast-widget.c b/src/adw-toast-widget.c
new file mode 100644
index 00000000..a9fcb018
--- /dev/null
+++ b/src/adw-toast-widget.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2021 Maximiliano Sandoval <msandova gnome org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include "adw-toast-widget-private.h"
+
+#define TOAST_DURATION 5000
+
+struct _AdwToastWidget {
+ GtkWidget parent_instance;
+
+ AdwToast *toast;
+
+ guint hide_timeout_id;
+ gint inhibit_count;
+};
+
+enum {
+ PROP_0,
+ PROP_TOAST,
+ LAST_PROP,
+};
+
+static GParamSpec *props[LAST_PROP];
+
+G_DEFINE_TYPE (AdwToastWidget, adw_toast_widget, GTK_TYPE_WIDGET)
+
+static gboolean
+string_is_not_empty (gpointer user_data,
+ const char *string)
+{
+ return string && string[0];
+}
+
+static gboolean
+timeout_cb (AdwToastWidget *self)
+{
+ self->hide_timeout_id = 0;
+
+ adw_toast_dismiss (self->toast);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+start_timeout (AdwToastWidget *self)
+{
+ if (!self->hide_timeout_id)
+ self->hide_timeout_id =
+ g_timeout_add (TOAST_DURATION,
+ G_SOURCE_FUNC (timeout_cb),
+ self);
+}
+
+static void
+end_timeout (AdwToastWidget *self)
+{
+ g_clear_handle_id (&self->hide_timeout_id, g_source_remove);
+}
+
+static void
+inhibit_hide (AdwToastWidget *self)
+{
+ if (self->inhibit_count++ == 0)
+ end_timeout (self);
+}
+
+static void
+uninhibit_hide (AdwToastWidget *self)
+{
+ g_assert (self->inhibit_count);
+
+ if (--self->inhibit_count == 0)
+ start_timeout (self);
+}
+
+static void
+dismiss (AdwToastWidget *self)
+{
+ end_timeout (self);
+
+ adw_toast_dismiss (self->toast);
+}
+
+static gboolean
+close_idle_cb (AdwToastWidget *self)
+{
+ dismiss (self);
+ g_object_unref (self);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+action_clicked_cb (AdwToastWidget *self)
+{
+ end_timeout (self);
+
+ /* Keep the widget alive through the idle. Otherwise it may be immediately
+ * destroyed if animations are disabled */
+ g_idle_add (G_SOURCE_FUNC (close_idle_cb), g_object_ref (self));
+}
+
+static void
+adw_toast_widget_dispose (GObject *object)
+{
+ AdwToastWidget *self = ADW_TOAST_WIDGET (object);
+ GtkWidget *child;
+
+ end_timeout (self);
+
+ while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))))
+ gtk_widget_unparent (child);
+
+ g_clear_pointer (&self->toast, g_object_unref);
+
+ G_OBJECT_CLASS (adw_toast_widget_parent_class)->dispose (object);
+}
+
+static void
+adw_toast_widget_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ AdwToastWidget *self = ADW_TOAST_WIDGET (object);
+
+ switch (prop_id) {
+ case PROP_TOAST:
+ g_value_set_object (value, self->toast);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+adw_toast_widget_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ AdwToastWidget *self = ADW_TOAST_WIDGET (object);
+
+ switch (prop_id) {
+ case PROP_TOAST:
+ g_set_object (&self->toast, g_value_get_object (value));
+ end_timeout (self);
+ start_timeout (self);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+adw_toast_widget_class_init (AdwToastWidgetClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->dispose = adw_toast_widget_dispose;
+ object_class->get_property = adw_toast_widget_get_property;
+ object_class->set_property = adw_toast_widget_set_property;
+
+ props[PROP_TOAST] =
+ g_param_spec_object ("toast",
+ "Toast",
+ "The displayed toast",
+ ADW_TYPE_TOAST,
+ G_PARAM_READWRITE);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gnome/Adwaita/ui/adw-toast-widget.ui");
+
+ gtk_widget_class_bind_template_callback (widget_class, string_is_not_empty);
+ gtk_widget_class_bind_template_callback (widget_class, action_clicked_cb);
+ gtk_widget_class_bind_template_callback (widget_class, dismiss);
+ gtk_widget_class_bind_template_callback (widget_class, inhibit_hide);
+ gtk_widget_class_bind_template_callback (widget_class, uninhibit_hide);
+
+ gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT);
+ gtk_widget_class_set_css_name (widget_class, "toast");
+}
+
+static void
+adw_toast_widget_init (AdwToastWidget *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+GtkWidget *
+adw_toast_widget_new (AdwToast *toast)
+{
+ g_assert (ADW_IS_TOAST (toast));
+
+ return g_object_new (ADW_TYPE_TOAST_WIDGET,
+ "toast", toast,
+ NULL);
+}
diff --git a/src/adw-toast-widget.ui b/src/adw-toast-widget.ui
new file mode 100644
index 00000000..bb69ba3b
--- /dev/null
+++ b/src/adw-toast-widget.ui
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.0"/>
+ <template class="AdwToastWidget">
+ <property name="hexpand">False</property>
+ <child>
+ <object class="GtkEventControllerFocus">
+ <signal name="enter" handler="inhibit_hide" swapped="yes"/>
+ <signal name="leave" handler="uninhibit_hide" swapped="yes"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkEventControllerMotion">
+ <signal name="enter" handler="inhibit_hide" swapped="yes"/>
+ <signal name="leave" handler="uninhibit_hide" swapped="yes"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkGestureClick">
+ <signal name="pressed" handler="inhibit_hide" swapped="yes"/>
+ <signal name="released" handler="uninhibit_hide" swapped="yes"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="title">
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <property name="hexpand">True</property>
+ <property name="use-markup">True</property>
+ <binding name="label">
+ <lookup name="title" type="AdwToast">
+ <lookup name="toast">AdwToastWidget</lookup>
+ </lookup>
+ </binding>
+ <style>
+ <class name="heading"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="action_button">
+ <property name="valign">center</property>
+ <binding name="visible">
+ <closure type="gboolean" function="string_is_not_empty">
+ <lookup name="button-label" type="AdwToast">
+ <lookup name="toast">AdwToastWidget</lookup>
+ </lookup>
+ </closure>
+ </binding>
+ <binding name="label">
+ <lookup name="button-label" type="AdwToast">
+ <lookup name="toast">AdwToastWidget</lookup>
+ </lookup>
+ </binding>
+ <binding name="action-name">
+ <lookup name="action-name" type="AdwToast">
+ <lookup name="toast">AdwToastWidget</lookup>
+ </lookup>
+ </binding>
+ <binding name="action-target">
+ <lookup name="action-target" type="AdwToast">
+ <lookup name="toast">AdwToastWidget</lookup>
+ </lookup>
+ </binding>
+ <signal name="clicked" handler="action_clicked_cb" swapped="yes"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="close_button">
+ <property name="valign">center</property>
+ <property name="icon-name">window-close-symbolic</property>
+ <signal name="clicked" handler="dismiss" swapped="yes"/>
+ <style>
+ <class name="circular"/>
+ <class name="flat"/>
+ </style>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/adwaita.gresources.xml b/src/adwaita.gresources.xml
index 69f5f483..ea354366 100644
--- a/src/adwaita.gresources.xml
+++ b/src/adwaita.gresources.xml
@@ -17,6 +17,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-toast-widget.ui</file>
<file preprocess="xml-stripblanks">adw-view-switcher-bar.ui</file>
<file preprocess="xml-stripblanks">adw-view-switcher-button.ui</file>
<file preprocess="xml-stripblanks">adw-view-switcher-title.ui</file>
diff --git a/src/meson.build b/src/meson.build
index 48871090..d54208ef 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -170,6 +170,7 @@ src_sources = [
'adw-tab-box.c',
'adw-tab-view.c',
'adw-toast.c',
+ 'adw-toast-widget.c',
'adw-version.c',
'adw-view-stack.c',
'adw-view-switcher.c',
diff --git a/src/stylesheet/widgets/_misc.scss b/src/stylesheet/widgets/_misc.scss
index fbf5fdd6..51f10bb0 100644
--- a/src/stylesheet/widgets/_misc.scss
+++ b/src/stylesheet/widgets/_misc.scss
@@ -49,6 +49,32 @@ separator {
border { border: none; }
}
+/**********
+ * Toasts *
+ **********/
+
+toast {
+ @extend %osd;
+
+ margin: 12px;
+ margin-bottom: 24px;
+
+ border-radius: 150px;
+ border-spacing: 6px;
+ padding: 6px;
+
+ &:dir(ltr) { padding-left: 12px; }
+ &:dir(rtl) { padding-right: 12px; }
+
+ > label {
+ margin: 0 6px;
+ }
+
+ @if $contrast == 'high' {
+ box-shadow: 0 0 0 1px $border_color;
+ }
+}
+
/**************
* GtkVideo *
**************/
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]