summaryrefslogtreecommitdiff
path: root/src/core/gtd-notification.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/gtd-notification.c')
-rw-r--r--src/core/gtd-notification.c441
1 files changed, 441 insertions, 0 deletions
diff --git a/src/core/gtd-notification.c b/src/core/gtd-notification.c
new file mode 100644
index 0000000..eee3e46
--- /dev/null
+++ b/src/core/gtd-notification.c
@@ -0,0 +1,441 @@
+/* gtd-notification.c
+ *
+ * Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
+ * Copyright (C) 2022 Jamie Murphy <hello@itsjamie.dev>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "GtdNotification"
+
+#include "gtd-notification.h"
+#include "gtd-object.h"
+
+#include <glib/gi18n.h>
+
+/**
+ * SECTION: gtd-notification
+ * @short_description: An auxiliary class around #AdwToast
+ * @title: GtdNotification
+ * @stability: Stable
+ *
+ * The #GtdNotification represents a notification shown at the top of
+ * the window. It is an auxiliary class around #AdwToast, and is used only
+ * to store toast data and callbacks.
+ *
+ * A notification may have a dismissal action that is called when the toast
+ * is dismissed, whether by user interaction or a timeout
+ *
+ * Optionally, the notification may have a secondary action
+ * (see gtd_notification_set_secondary_action()), shown as a button.
+ *
+ * A user should not create a UI for a #GtdNotification and should instead
+ * pass it to a #GtdManager, via gtd_manager_send_notification()
+ *
+ * Example:
+ * |[
+ * GtdNotification *notification;
+ *
+ * notification = gtd_notification_new ("Something happened!");
+ *
+ * gtd_notification_set_dismissal_action (notification,
+ * called_when_notification_is_dismissed,
+ * self);
+ *
+ * gtd_notification_set_secondary_action (notification,
+ * "Details",
+ * show_details,
+ * self);
+ * [...]
+ * ]|
+ */
+
+typedef struct
+{
+ gchar *text;
+
+ GtdNotificationActionFunc dismissal_action;
+ gboolean has_dismissal_action;
+ gpointer dismissal_action_data;
+
+ GtdNotificationActionFunc secondary_action;
+ gboolean has_secondary_action;
+ gpointer secondary_action_data;
+ gchar *secondary_action_name;
+} GtdNotificationPrivate;
+
+struct _GtdNotification
+{
+ GtdObject parent;
+
+ /*< private >*/
+ GtdNotificationPrivate *priv;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GtdNotification, gtd_notification, GTD_TYPE_OBJECT)
+
+enum
+{
+ PROP_0,
+ PROP_HAS_DISMISSAL_ACTION,
+ PROP_HAS_SECONDARY_ACTION,
+ PROP_SECONDARY_ACTION_NAME,
+ PROP_TEXT,
+ LAST_PROP
+};
+
+enum
+{
+ EXECUTED,
+ NUM_SIGNALS
+};
+
+static guint signals[NUM_SIGNALS] = { 0, };
+
+static void
+gtd_notification_finalize (GObject *object)
+{
+ GtdNotification *self = (GtdNotification *)object;
+ GtdNotificationPrivate *priv = gtd_notification_get_instance_private (self);
+
+ g_clear_pointer (&priv->secondary_action_name, g_free);
+ g_clear_pointer (&priv->text, g_free);
+
+ G_OBJECT_CLASS (gtd_notification_parent_class)->finalize (object);
+}
+
+static void
+gtd_notification_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtdNotification *self = GTD_NOTIFICATION (object);
+
+ switch (prop_id)
+ {
+ case PROP_HAS_DISMISSAL_ACTION:
+ g_value_set_boolean (value, self->priv->has_dismissal_action);
+ break;
+
+ case PROP_HAS_SECONDARY_ACTION:
+ g_value_set_boolean (value, self->priv->has_secondary_action);
+ break;
+
+ case PROP_SECONDARY_ACTION_NAME:
+ g_value_set_string (value, self->priv->secondary_action_name ? self->priv->secondary_action_name : "");
+ break;
+
+ case PROP_TEXT:
+ g_value_set_string (value, gtd_notification_get_text (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtd_notification_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtdNotification *self = GTD_NOTIFICATION (object);
+
+ switch (prop_id)
+ {
+ case PROP_SECONDARY_ACTION_NAME:
+ gtd_notification_set_secondary_action (self,
+ g_value_get_string (value),
+ self->priv->secondary_action,
+ self->priv->secondary_action_data);
+ break;
+
+ case PROP_TEXT:
+ gtd_notification_set_text (self, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtd_notification_class_init (GtdNotificationClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtd_notification_finalize;
+ object_class->get_property = gtd_notification_get_property;
+ object_class->set_property = gtd_notification_set_property;
+
+ /**
+ * GtdNotification::has-dismissal-action:
+ *
+ * @TRUE if the notification has a dismissal action or @FALSE otherwise.
+ */
+ g_object_class_install_property (
+ object_class,
+ PROP_HAS_DISMISSAL_ACTION,
+ g_param_spec_boolean ("has-dismissal-action",
+ "Whether the notification has a dismissal action",
+ "Whether the notification has the dismissal action.",
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY));
+
+ /**
+ * GtdNotification::has-secondary-action:
+ *
+ * @TRUE if the notification has a secondary action or @FALSE otherwise. The
+ * secondary action is triggered only by user explicit input.
+ */
+ g_object_class_install_property (
+ object_class,
+ PROP_HAS_SECONDARY_ACTION,
+ g_param_spec_boolean ("has-secondary-action",
+ "Whether the notification has a secondary action",
+ "Whether the notification has the secondary action, activated by the user",
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY));
+
+ /**
+ * GtdNotification::secondary-action-name:
+ *
+ * The main text of the notification, usually a markuped text.
+ */
+ g_object_class_install_property (
+ object_class,
+ PROP_SECONDARY_ACTION_NAME,
+ g_param_spec_string ("secondary-action-name",
+ "Text of the secondary action button",
+ "The text of the secondary action button",
+ "",
+ G_PARAM_READWRITE));
+
+ /**
+ * GtdNotification::text:
+ *
+ * The main text of the notification, usually a markuped text.
+ */
+ g_object_class_install_property (
+ object_class,
+ PROP_TEXT,
+ g_param_spec_string ("text",
+ "Notification message",
+ "The main message of the notification",
+ "",
+ G_PARAM_READWRITE));
+
+ /**
+ * GtdNotification::executed:
+ *
+ * The ::executed signal is emitted after the primary or secondary
+ * #GtdNotification action is executed.
+ */
+ signals[EXECUTED] = g_signal_new ("executed",
+ GTD_TYPE_NOTIFICATION,
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+gtd_notification_init (GtdNotification *self)
+{
+ self->priv = gtd_notification_get_instance_private (self);
+ self->priv->secondary_action_name = NULL;
+ self->priv->text = NULL;
+}
+
+/**
+ * gtd_notification_new:
+ * @text: (nullable): text of the notification
+ *
+ * Creates a new notification with @text.
+ *
+ * Returns: (transfer full): a new #GtdNotification
+ */
+GtdNotification*
+gtd_notification_new (const gchar *text)
+{
+ return g_object_new (GTD_TYPE_NOTIFICATION,
+ "text", text,
+ NULL);
+}
+
+/**
+ * gtd_notification_set_dismissal_action:
+ * @notification: a #GtdNotification
+ * @func: (closure user_data) (scope call) (nullable): the dismissal action function
+ * @user_data: data passed to @func
+ *
+ * Sets the dismissal action of @notification
+ */
+void
+gtd_notification_set_dismissal_action (GtdNotification *notification,
+ GtdNotificationActionFunc func,
+ gpointer user_data)
+{
+ GtdNotificationPrivate *priv;
+ gboolean has_action;
+
+ g_return_if_fail (GTD_IS_NOTIFICATION (notification));
+
+ priv = notification->priv;
+ has_action = (func != NULL);
+
+ if (has_action != priv->has_dismissal_action)
+ {
+ priv->has_dismissal_action = has_action;
+
+ priv->dismissal_action = has_action ? func : NULL;
+ priv->dismissal_action_data = has_action ? user_data : NULL;
+
+ g_object_notify (G_OBJECT (notification), "has-dismissal-action");
+ }
+}
+
+/**
+ * gtd_notification_set_secondary_action:
+ * @notification: a #GtdNotification
+ * @name: the name of the secondary action
+ * @func: (closure user_data) (scope call) (nullable): the secondary action function
+ * @user_data: data passed to @func
+ *
+ * Sets the secondary action of @notification, which is triggered
+ * only on user explicit input.
+ */
+void
+gtd_notification_set_secondary_action (GtdNotification *notification,
+ const gchar *name,
+ GtdNotificationActionFunc func,
+ gpointer user_data)
+{
+ GtdNotificationPrivate *priv;
+ gboolean has_action;
+
+ g_return_if_fail (GTD_IS_NOTIFICATION (notification));
+
+ priv = notification->priv;
+ has_action = (func != NULL);
+
+ if (has_action != priv->has_secondary_action)
+ {
+ priv->has_secondary_action = has_action;
+
+ priv->secondary_action = has_action ? func : NULL;
+ priv->secondary_action_data = has_action ? user_data : NULL;
+
+ if (priv->secondary_action_name != name)
+ {
+ g_clear_pointer (&priv->secondary_action_name, g_free);
+ priv->secondary_action_name = g_strdup (name);
+
+ g_object_notify (G_OBJECT (notification), "secondary-action-name");
+ }
+
+ g_object_notify (G_OBJECT (notification), "has-secondary-action");
+ }
+}
+
+/**
+ * gtd_notification_get_text:
+ * @notification: a #GtdNotification
+ *
+ * Gets the text of @notification.
+ *
+ * Returns: (transfer none): the text of @notification.
+ */
+const gchar*
+gtd_notification_get_text (GtdNotification *notification)
+{
+ g_return_val_if_fail (GTD_IS_NOTIFICATION (notification), NULL);
+
+ return notification->priv->text ? notification->priv->text : "";
+}
+
+/**
+ * gtd_notification_set_text:
+ * @notification: a #GtdNotification
+ * @text: the user-visible text of @notification
+ *
+ * Sets the text of @notification to @text.
+ */
+void
+gtd_notification_set_text (GtdNotification *notification,
+ const gchar *text)
+{
+ GtdNotificationPrivate *priv;
+
+ g_return_if_fail (GTD_IS_NOTIFICATION (notification));
+
+ priv = notification->priv;
+
+ if (g_strcmp0 (priv->text, text) != 0)
+ {
+ g_clear_pointer (&priv->text, g_free);
+ priv->text = g_strdup (text);
+
+ g_object_notify (G_OBJECT (notification), "text");
+ }
+}
+
+/**
+ * gtd_notification_execute_dismissal_action:
+ * @notification: a #GtdNotification
+ *
+ * Executes the dismissal action of @notification if any.
+ */
+void
+gtd_notification_execute_dismissal_action (GtdNotification *notification)
+{
+ GtdNotificationPrivate *priv;
+
+ g_return_if_fail (GTD_IS_NOTIFICATION (notification));
+
+ priv = notification->priv;
+
+ if (priv->dismissal_action)
+ priv->dismissal_action (notification, priv->dismissal_action_data);
+
+ g_signal_emit (notification, signals[EXECUTED], 0);
+}
+
+/**
+ * gtd_notification_execute_secondary_action:
+ * @notification: a #GtdNotification
+ *
+ * Executes the secondary action of @notification if any.
+ */
+void
+gtd_notification_execute_secondary_action (GtdNotification *notification)
+{
+ GtdNotificationPrivate *priv;
+
+ g_return_if_fail (GTD_IS_NOTIFICATION (notification));
+
+ priv = notification->priv;
+
+ if (priv->secondary_action)
+ {
+ priv->secondary_action (notification, priv->secondary_action_data);
+
+ g_signal_emit (notification, signals[EXECUTED], 0);
+ }
+}