diff --git a/gio/gnotification-private.h b/gio/gnotification-private.h index 1219123f4..d6f07bd33 100644 --- a/gio/gnotification-private.h +++ b/gio/gnotification-private.h @@ -31,6 +31,8 @@ const gchar * g_notification_get_title (GNotifi const gchar * g_notification_get_body (GNotification *notification); +const gchar * g_notification_get_body_with_markup (GNotification *notification); + const gchar * g_notification_get_category (GNotification *notification); GIcon * g_notification_get_icon (GNotification *notification); diff --git a/gio/gnotification.c b/gio/gnotification.c index 678299d39..4daca9afe 100644 --- a/gio/gnotification.c +++ b/gio/gnotification.c @@ -87,6 +87,7 @@ struct _GNotification gchar *title; gchar *body; + gchar *markup_body; GIcon *icon; GNotificationSound *sound; GNotificationPriority priority; @@ -137,6 +138,7 @@ g_notification_finalize (GObject *object) g_free (notification->title); g_free (notification->body); + g_free (notification->markup_body); g_free (notification->category); g_free (notification->default_action); if (notification->default_action_target) @@ -161,6 +163,26 @@ g_notification_init (GNotification *notification) notification->buttons = g_ptr_array_new_full (2, button_free); } +static void +markup_parser_text (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error) +{ + GString *composed = user_data; + + g_string_append_len (composed, text, text_len); +} + +static const GMarkupParser markup_parser = { + NULL, + NULL, + markup_parser_text, + NULL, + NULL, +}; + /** * g_notification_new: * @title: the title of the notification @@ -243,16 +265,46 @@ g_notification_get_body (GNotification *notification) { g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL); + if (notification->body == NULL && notification->markup_body != NULL) + { + GMarkupParseContext *context = NULL; + GString *composed = NULL; + GError *error = NULL; + + composed = g_string_sized_new (strlen (notification->markup_body)); + context = g_markup_parse_context_new (&markup_parser, 0, composed, NULL); + + /* The markup parser expects the markup to start with an element, therefore add one */ + if (g_markup_parse_context_parse (context, "", -1, &error) && + g_markup_parse_context_parse (context, notification->markup_body, -1, &error) && + g_markup_parse_context_parse (context, "", -1, &error) && + g_markup_parse_context_end_parse (context, &error)) + { + return g_string_free_and_steal (composed); + } + else + { + g_warning ("Failed to parse markup body: %s", error->message); + g_clear_pointer (&error, g_error_free); + } + } + return notification->body; } /** * g_notification_set_body: - * @notification: a #GNotification + * @notification: a [class@Gio.Notification] * @body: (nullable): the new body for @notification, or %NULL * * Sets the body of @notification to @body. * + * If a body was set via [method@Gio.Notification.set_body_with_markup] then @body is + * only used for platforms that don't support markup. + * + * There is no need to set @body as a fallback when using + * [method@Gio.Notification.set_body_with_markup] since markup will be stripped as fallback. + * * Since: 2.40 */ void @@ -267,6 +319,52 @@ g_notification_set_body (GNotification *notification, notification->body = g_strdup (body); } +/*< private > + * g_notification_get_body_with_markup: + * @notification: a [class@Gio.Notification] + * + * Gets the current markup body of @notification. + * + * Returns: (nullable): the markup body of @notification + * + * Since: 2.85 + */ +const gchar * +g_notification_get_body_with_markup (GNotification *notification) +{ + g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL); + + return notification->markup_body; +} + +/** + * g_notification_set_body_with_markup: + * @notification: a [class@Gio.Notification] + * @markup_body: (nullable): the new body using markup for @notification, or %NULL + * + * If markup is supported by the platform @markup_body will be used as + * body for @notification, else the body set via [method@Gio.Notification.set_body] + * is used. If no body is set via [method@Gio.Notification.set_body] @markup_body + * is used as fallback by stripping the markup. + * + * This currently supports the following markup: + * + * - `...` for bold text + * - `...` for italic text + * - `...` for links + * + * Since: 2.85 + */ +void +g_notification_set_body_with_markup (GNotification *notification, + const gchar *markup_body) +{ + g_return_if_fail (G_IS_NOTIFICATION (notification)); + g_return_if_fail (markup_body == NULL || *markup_body != '\0'); + + g_set_str (¬ification->markup_body, markup_body); +} + /*< private > * g_notification_get_icon: * @notification: a #GNotification @@ -509,6 +607,7 @@ g_notification_add_button (GNotification *notification, if (!g_action_parse_detailed_name (detailed_action, &action, &target, &error)) { g_warning ("%s: %s", G_STRFUNC, error->message); + g_error_free (error); return; } diff --git a/gio/gnotification.h b/gio/gnotification.h index f7ff45820..d99533f0e 100644 --- a/gio/gnotification.h +++ b/gio/gnotification.h @@ -49,6 +49,10 @@ GIO_AVAILABLE_IN_2_40 void g_notification_set_body (GNotification *notification, const gchar *body); +GIO_AVAILABLE_IN_2_85 +void g_notification_set_body_with_markup (GNotification *notification, + const gchar *markup_body); + GIO_AVAILABLE_IN_2_40 void g_notification_set_icon (GNotification *notification, GIcon *icon); diff --git a/gio/tests/gnotification.c b/gio/tests/gnotification.c index 30ccac9c5..117b0de6a 100644 --- a/gio/tests/gnotification.c +++ b/gio/tests/gnotification.c @@ -169,6 +169,7 @@ struct _GNotification gchar *title; gchar *body; + gchar *markup_body; GIcon *icon; GNotificationSound *sound; GNotificationPriority priority; @@ -225,6 +226,7 @@ test_properties (void) g_notification_set_title (n, "title"); g_notification_set_body (n, "body"); + g_notification_set_body_with_markup (n, "markup-body"); g_notification_set_category (n, "cate.gory"); icon = g_themed_icon_new ("i-c-o-n"); g_notification_set_icon (n, icon); @@ -239,6 +241,7 @@ test_properties (void) g_assert_cmpstr (rn->title, ==, "title"); g_assert_cmpstr (rn->body, ==, "body"); + g_assert_cmpstr (rn->markup_body, ==, "markup-body"); g_assert_true (G_IS_THEMED_ICON (rn->icon)); names = g_themed_icon_get_names (G_THEMED_ICON (rn->icon)); g_assert_cmpstr (names[0], ==, "i-c-o-n");