2 * Copyright © 2013 Lars Uebernickel
4 * SPDX-License-Identifier: LGPL-2.1-or-later
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 * Authors: Lars Uebernickel <lars@uebernic.de>
24 #include "gnotification-private.h"
25 #include "gdbusutils.h"
28 #include "gioenumtypes.h"
31 * SECTION:gnotification
32 * @short_description: User Notifications (pop up messages)
35 * #GNotification is a mechanism for creating a notification to be shown
36 * to the user -- typically as a pop-up notification presented by the
37 * desktop environment shell.
39 * The key difference between #GNotification and other similar APIs is
40 * that, if supported by the desktop environment, notifications sent
41 * with #GNotification will persist after the application has exited,
42 * and even across system reboots.
44 * Since the user may click on a notification while the application is
45 * not running, applications using #GNotification should be able to be
46 * started as a D-Bus service, using #GApplication.
48 * In order for #GNotification to work, the application must have installed
49 * a `.desktop` file. For example:
52 * Name=Test Application
53 * Comment=Description of what Test Application does
54 * Exec=gnome-test-application
55 * Icon=org.gnome.TestApplication
58 * Categories=GNOME;GTK;TestApplication Category;
60 * DBusActivatable=true
61 * X-GNOME-UsesNotifications=true
64 * The `X-GNOME-UsesNotifications` key indicates to GNOME Control Center
65 * that this application uses notifications, so it can be listed in the
66 * Control Center’s ‘Notifications’ panel.
68 * The `.desktop` file must be named as `org.gnome.TestApplication.desktop`,
69 * where `org.gnome.TestApplication` is the ID passed to g_application_new().
71 * User interaction with a notification (either the default action, or
72 * buttons) must be associated with actions on the application (ie:
73 * "app." actions). It is not possible to route user interaction
74 * through the notification itself, because the object will not exist if
75 * the application is autostarted as a result of a notification being
78 * A notification can be sent with g_application_send_notification().
86 * This structure type is private and should only be accessed using the
92 typedef GObjectClass GNotificationClass;
101 GNotificationPriority priority;
104 gchar *default_action;
105 GVariant *default_action_target; /* (nullable) (owned), not floating */
115 G_DEFINE_TYPE (GNotification, g_notification, G_TYPE_OBJECT)
118 button_free (gpointer data)
120 Button *button = data;
122 g_free (button->label);
123 g_free (button->action_name);
125 g_variant_unref (button->target);
127 g_slice_free (Button, button);
131 g_notification_dispose (GObject *object)
133 GNotification *notification = G_NOTIFICATION (object);
135 g_clear_object (¬ification->icon);
137 G_OBJECT_CLASS (g_notification_parent_class)->dispose (object);
141 g_notification_finalize (GObject *object)
143 GNotification *notification = G_NOTIFICATION (object);
145 g_free (notification->title);
146 g_free (notification->body);
147 g_free (notification->category);
148 g_free (notification->default_action);
149 if (notification->default_action_target)
150 g_variant_unref (notification->default_action_target);
151 g_ptr_array_free (notification->buttons, TRUE);
153 G_OBJECT_CLASS (g_notification_parent_class)->finalize (object);
157 g_notification_class_init (GNotificationClass *klass)
159 GObjectClass *object_class = G_OBJECT_CLASS (klass);
161 object_class->dispose = g_notification_dispose;
162 object_class->finalize = g_notification_finalize;
166 g_notification_init (GNotification *notification)
168 notification->buttons = g_ptr_array_new_full (2, button_free);
172 * g_notification_new:
173 * @title: the title of the notification
175 * Creates a new #GNotification with @title as its title.
177 * After populating @notification with more details, it can be sent to
178 * the desktop shell with g_application_send_notification(). Changing
179 * any properties after this call will not have any effect until
180 * resending @notification.
182 * Returns: a new #GNotification instance
187 g_notification_new (const gchar *title)
189 GNotification *notification;
191 g_return_val_if_fail (title != NULL, NULL);
193 notification = g_object_new (G_TYPE_NOTIFICATION, NULL);
194 notification->title = g_strdup (title);
200 * g_notification_get_title:
201 * @notification: a #GNotification
203 * Gets the title of @notification.
205 * Returns: the title of @notification
210 g_notification_get_title (GNotification *notification)
212 g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL);
214 return notification->title;
218 * g_notification_set_title:
219 * @notification: a #GNotification
220 * @title: the new title for @notification
222 * Sets the title of @notification to @title.
227 g_notification_set_title (GNotification *notification,
230 g_return_if_fail (G_IS_NOTIFICATION (notification));
231 g_return_if_fail (title != NULL);
233 g_free (notification->title);
235 notification->title = g_strdup (title);
239 * g_notification_get_body:
240 * @notification: a #GNotification
242 * Gets the current body of @notification.
244 * Returns: (nullable): the body of @notification
249 g_notification_get_body (GNotification *notification)
251 g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL);
253 return notification->body;
257 * g_notification_set_body:
258 * @notification: a #GNotification
259 * @body: (nullable): the new body for @notification, or %NULL
261 * Sets the body of @notification to @body.
266 g_notification_set_body (GNotification *notification,
269 g_return_if_fail (G_IS_NOTIFICATION (notification));
270 g_return_if_fail (body != NULL);
272 g_free (notification->body);
274 notification->body = g_strdup (body);
278 * g_notification_get_icon:
279 * @notification: a #GNotification
281 * Gets the icon currently set on @notification.
283 * Returns: (transfer none): the icon associated with @notification
288 g_notification_get_icon (GNotification *notification)
290 g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL);
292 return notification->icon;
296 * g_notification_set_icon:
297 * @notification: a #GNotification
298 * @icon: the icon to be shown in @notification, as a #GIcon
300 * Sets the icon of @notification to @icon.
305 g_notification_set_icon (GNotification *notification,
308 g_return_if_fail (G_IS_NOTIFICATION (notification));
310 if (notification->icon)
311 g_object_unref (notification->icon);
313 notification->icon = g_object_ref (icon);
317 * g_notification_get_priority:
318 * @notification: a #GNotification
320 * Returns the priority of @notification
324 GNotificationPriority
325 g_notification_get_priority (GNotification *notification)
327 g_return_val_if_fail (G_IS_NOTIFICATION (notification), G_NOTIFICATION_PRIORITY_NORMAL);
329 return notification->priority;
333 * g_notification_set_urgent:
334 * @notification: a #GNotification
335 * @urgent: %TRUE if @notification is urgent
337 * Deprecated in favor of g_notification_set_priority().
340 * Deprecated: 2.42: Since 2.42, this has been deprecated in favour of
341 * g_notification_set_priority().
344 g_notification_set_urgent (GNotification *notification,
347 g_return_if_fail (G_IS_NOTIFICATION (notification));
349 notification->priority = urgent ?
350 G_NOTIFICATION_PRIORITY_URGENT :
351 G_NOTIFICATION_PRIORITY_NORMAL;
355 * g_notification_get_category:
356 * @notification: a #GNotification
358 * Gets the category of @notification.
360 * This will be %NULL if no category is set.
362 * Returns: (nullable): the category of @notification
367 g_notification_get_category (GNotification *notification)
369 g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL);
371 return notification->category;
375 * g_notification_set_category:
376 * @notification: a #GNotification
377 * @category: (nullable): the category for @notification, or %NULL for no category
379 * Sets the type of @notification to @category. Categories have a main
380 * type like `email`, `im` or `device` and can have a detail separated
381 * by a `.`, e.g. `im.received` or `email.arrived`. Setting the category
382 * helps the notification server to select proper feedback to the user.
384 * Standard categories are [listed in the specification](https://specifications.freedesktop.org/notification-spec/latest/ar01s06.html).
389 g_notification_set_category (GNotification *notification,
390 const gchar *category)
392 g_return_if_fail (G_IS_NOTIFICATION (notification));
393 g_return_if_fail (category == NULL || *category != '\0');
395 g_free (notification->category);
397 notification->category = g_strdup (category);
401 * g_notification_set_priority:
402 * @notification: a #GNotification
403 * @priority: a #GNotificationPriority
405 * Sets the priority of @notification to @priority. See
406 * #GNotificationPriority for possible values.
409 g_notification_set_priority (GNotification *notification,
410 GNotificationPriority priority)
412 g_return_if_fail (G_IS_NOTIFICATION (notification));
414 notification->priority = priority;
418 * g_notification_add_button:
419 * @notification: a #GNotification
420 * @label: label of the button
421 * @detailed_action: a detailed action name
423 * Adds a button to @notification that activates the action in
424 * @detailed_action when clicked. That action must be an
425 * application-wide action (starting with "app."). If @detailed_action
426 * contains a target, the action will be activated with that target as
429 * See g_action_parse_detailed_name() for a description of the format
430 * for @detailed_action.
435 g_notification_add_button (GNotification *notification,
437 const gchar *detailed_action)
441 GError *error = NULL;
443 g_return_if_fail (detailed_action != NULL);
445 if (!g_action_parse_detailed_name (detailed_action, &action, &target, &error))
447 g_warning ("%s: %s", G_STRFUNC, error->message);
448 g_error_free (error);
452 g_notification_add_button_with_target_value (notification, label, action, target);
456 g_variant_unref (target);
460 * g_notification_add_button_with_target: (skip)
461 * @notification: a #GNotification
462 * @label: label of the button
463 * @action: an action name
464 * @target_format: (nullable): a #GVariant format string, or %NULL
465 * @...: positional parameters, as determined by @target_format
467 * Adds a button to @notification that activates @action when clicked.
468 * @action must be an application-wide action (it must start with "app.").
470 * If @target_format is given, it is used to collect remaining
471 * positional parameters into a #GVariant instance, similar to
472 * g_variant_new(). @action will be activated with that #GVariant as its
478 g_notification_add_button_with_target (GNotification *notification,
481 const gchar *target_format,
485 GVariant *target = NULL;
489 va_start (args, target_format);
490 target = g_variant_new_va (target_format, NULL, &args);
494 g_notification_add_button_with_target_value (notification, label, action, target);
498 * g_notification_add_button_with_target_value: (rename-to g_notification_add_button_with_target)
499 * @notification: a #GNotification
500 * @label: label of the button
501 * @action: an action name
502 * @target: (nullable): a #GVariant to use as @action's parameter, or %NULL
504 * Adds a button to @notification that activates @action when clicked.
505 * @action must be an application-wide action (it must start with "app.").
507 * If @target is non-%NULL, @action will be activated with @target as
513 g_notification_add_button_with_target_value (GNotification *notification,
520 g_return_if_fail (G_IS_NOTIFICATION (notification));
521 g_return_if_fail (label != NULL);
522 g_return_if_fail (action != NULL && g_action_name_is_valid (action));
524 if (!g_str_has_prefix (action, "app."))
526 g_warning ("%s: action '%s' does not start with 'app.'."
527 "This is unlikely to work properly.", G_STRFUNC, action);
530 button = g_slice_new0 (Button);
531 button->label = g_strdup (label);
532 button->action_name = g_strdup (action);
535 button->target = g_variant_ref_sink (target);
537 g_ptr_array_add (notification->buttons, button);
541 * g_notification_get_n_buttons:
542 * @notification: a #GNotification
544 * Returns: the amount of buttons added to @notification.
547 g_notification_get_n_buttons (GNotification *notification)
549 return notification->buttons->len;
553 * g_notification_get_button:
554 * @notification: a #GNotification
555 * @index: index of the button
556 * @label: (): return location for the button's label
557 * @action: (): return location for the button's associated action
558 * @target: (): return location for the target @action should be
561 * Returns a description of a button that was added to @notification
562 * with g_notification_add_button().
564 * @index must be smaller than the value returned by
565 * g_notification_get_n_buttons().
568 g_notification_get_button (GNotification *notification,
576 button = g_ptr_array_index (notification->buttons, index);
579 *label = g_strdup (button->label);
582 *action = g_strdup (button->action_name);
585 *target = button->target ? g_variant_ref (button->target) : NULL;
589 * g_notification_get_button_with_action:
590 * @notification: a #GNotification
591 * @action: an action name
593 * Returns the index of the button in @notification that is associated
594 * with @action, or -1 if no such button exists.
597 g_notification_get_button_with_action (GNotification *notification,
602 for (i = 0; i < notification->buttons->len; i++)
606 button = g_ptr_array_index (notification->buttons, i);
607 if (g_str_equal (action, button->action_name))
616 * g_notification_get_default_action:
617 * @notification: a #GNotification
618 * @action: (out) (optional) (nullable) (transfer full): return location for the
619 * default action, or %NULL if unset
620 * @target: (out) (optional) (nullable) (transfer full): return location for the
621 * target of the default action, or %NULL if unset
623 * Gets the action and target for the default action of @notification.
625 * If this function returns %TRUE, @action is guaranteed to be set to a non-%NULL
626 * value (if a pointer is passed to @action). @target may still return a %NULL
627 * value, as the default action may have no target.
629 * Returns: %TRUE if @notification has a default action
632 g_notification_get_default_action (GNotification *notification,
636 if (notification->default_action == NULL)
640 *action = g_strdup (notification->default_action);
644 if (notification->default_action_target)
645 *target = g_variant_ref (notification->default_action_target);
654 * g_notification_set_default_action:
655 * @notification: a #GNotification
656 * @detailed_action: a detailed action name
658 * Sets the default action of @notification to @detailed_action. This
659 * action is activated when the notification is clicked on.
661 * The action in @detailed_action must be an application-wide action (it
662 * must start with "app."). If @detailed_action contains a target, the
663 * given action will be activated with that target as its parameter.
664 * See g_action_parse_detailed_name() for a description of the format
665 * for @detailed_action.
667 * When no default action is set, the application that the notification
668 * was sent on is activated.
673 g_notification_set_default_action (GNotification *notification,
674 const gchar *detailed_action)
678 GError *error = NULL;
680 if (!g_action_parse_detailed_name (detailed_action, &action, &target, &error))
682 g_warning ("%s: %s", G_STRFUNC, error->message);
683 g_error_free (error);
687 g_notification_set_default_action_and_target_value (notification, action, target);
691 g_variant_unref (target);
695 * g_notification_set_default_action_and_target: (skip)
696 * @notification: a #GNotification
697 * @action: an action name
698 * @target_format: (nullable): a #GVariant format string, or %NULL
699 * @...: positional parameters, as determined by @target_format
701 * Sets the default action of @notification to @action. This action is
702 * activated when the notification is clicked on. It must be an
703 * application-wide action (it must start with "app.").
705 * If @target_format is given, it is used to collect remaining
706 * positional parameters into a #GVariant instance, similar to
707 * g_variant_new(). @action will be activated with that #GVariant as its
710 * When no default action is set, the application that the notification
711 * was sent on is activated.
716 g_notification_set_default_action_and_target (GNotification *notification,
718 const gchar *target_format,
722 GVariant *target = NULL;
726 va_start (args, target_format);
727 target = g_variant_new_va (target_format, NULL, &args);
731 g_notification_set_default_action_and_target_value (notification, action, target);
735 * g_notification_set_default_action_and_target_value: (rename-to g_notification_set_default_action_and_target)
736 * @notification: a #GNotification
737 * @action: an action name
738 * @target: (nullable): a #GVariant to use as @action's parameter, or %NULL
740 * Sets the default action of @notification to @action. This action is
741 * activated when the notification is clicked on. It must be an
742 * application-wide action (start with "app.").
744 * If @target is non-%NULL, @action will be activated with @target as
745 * its parameter. If @target is floating, it will be consumed.
747 * When no default action is set, the application that the notification
748 * was sent on is activated.
753 g_notification_set_default_action_and_target_value (GNotification *notification,
757 g_return_if_fail (G_IS_NOTIFICATION (notification));
758 g_return_if_fail (action != NULL && g_action_name_is_valid (action));
760 if (!g_str_has_prefix (action, "app."))
762 g_warning ("%s: action '%s' does not start with 'app.'."
763 "This is unlikely to work properly.", G_STRFUNC, action);
766 g_free (notification->default_action);
767 g_clear_pointer (¬ification->default_action_target, g_variant_unref);
769 notification->default_action = g_strdup (action);
772 notification->default_action_target = g_variant_ref_sink (target);
776 g_notification_serialize_button (Button *button)
778 GVariantBuilder builder;
780 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
782 g_variant_builder_add (&builder, "{sv}", "label", g_variant_new_string (button->label));
783 g_variant_builder_add (&builder, "{sv}", "action", g_variant_new_string (button->action_name));
786 g_variant_builder_add (&builder, "{sv}", "target", button->target);
788 return g_variant_builder_end (&builder);
792 g_notification_get_priority_nick (GNotification *notification)
794 GEnumClass *enum_class;
798 enum_class = g_type_class_ref (G_TYPE_NOTIFICATION_PRIORITY);
799 value = g_enum_get_value (enum_class, g_notification_get_priority (notification));
800 g_assert (value != NULL);
801 nick = g_variant_new_string (value->value_nick);
802 g_type_class_unref (enum_class);
808 * g_notification_serialize:
810 * Serializes @notification into a floating variant of type a{sv}.
812 * Returns: the serialized @notification as a floating variant.
815 g_notification_serialize (GNotification *notification)
817 GVariantBuilder builder;
819 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
821 if (notification->title)
822 g_variant_builder_add (&builder, "{sv}", "title", g_variant_new_string (notification->title));
824 if (notification->body)
825 g_variant_builder_add (&builder, "{sv}", "body", g_variant_new_string (notification->body));
827 if (notification->icon)
829 GVariant *serialized_icon;
831 if ((serialized_icon = g_icon_serialize (notification->icon)))
833 g_variant_builder_add (&builder, "{sv}", "icon", serialized_icon);
834 g_variant_unref (serialized_icon);
838 g_variant_builder_add (&builder, "{sv}", "priority", g_notification_get_priority_nick (notification));
840 if (notification->default_action)
842 g_variant_builder_add (&builder, "{sv}", "default-action",
843 g_variant_new_string (notification->default_action));
845 if (notification->default_action_target)
846 g_variant_builder_add (&builder, "{sv}", "default-action-target",
847 notification->default_action_target);
850 if (notification->buttons->len > 0)
852 GVariantBuilder actions_builder;
855 g_variant_builder_init (&actions_builder, G_VARIANT_TYPE ("aa{sv}"));
857 for (i = 0; i < notification->buttons->len; i++)
859 Button *button = g_ptr_array_index (notification->buttons, i);
860 g_variant_builder_add (&actions_builder, "@a{sv}", g_notification_serialize_button (button));
863 g_variant_builder_add (&builder, "{sv}", "buttons", g_variant_builder_end (&actions_builder));
866 return g_variant_builder_end (&builder);