Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libnotify for openSUSE:Factory checked in at 2022-05-08 21:52:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libnotify (Old) and /work/SRC/openSUSE:Factory/.libnotify.new.1538 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libnotify" Sun May 8 21:52:25 2022 rev:41 rq:975333 version:0.7.11 Changes: -------- --- /work/SRC/openSUSE:Factory/libnotify/libnotify.changes 2020-04-13 12:50:03.808562977 +0200 +++ /work/SRC/openSUSE:Factory/.libnotify.new.1538/libnotify.changes 2022-05-08 21:52:37.527483735 +0200 @@ -1,0 +2,11 @@ +Thu May 5 09:24:05 UTC 2022 - Christophe Giboudeaux <christo...@krop.fr> + +- Update to 0.7.11 + * Fix potential build errors with old glib version we require + * notify-send: Add support for boolean hints + * notify-send: Support passing any hint value, by parsing + variant strings + * notify-send: Add explicit option to create transient + notifications + +------------------------------------------------------------------- Old: ---- libnotify-0.7.9.tar.xz New: ---- libnotify-0.7.11.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libnotify.spec ++++++ --- /var/tmp/diff_new_pack.jNULJE/_old 2022-05-08 21:52:37.943484259 +0200 +++ /var/tmp/diff_new_pack.jNULJE/_new 2022-05-08 21:52:37.947484264 +0200 @@ -1,7 +1,7 @@ # # spec file for package libnotify # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,16 +17,15 @@ Name: libnotify -Version: 0.7.9 +Version: 0.7.11 Release: 0 Summary: Notifications Library License: LGPL-2.1-or-later Group: Development/Libraries/X11 -URL: http://galago-project.org/ +URL: https://galago-project.org/ Source: https://download.gnome.org/sources/libnotify/0.7/%{name}-%{version}.tar.xz Source98: libnotify-rpmlintrc Source99: baselibs.conf - BuildRequires: docbook5-xsl-stylesheets BuildRequires: gobject-introspection-devel BuildRequires: gtk-doc @@ -107,7 +106,7 @@ %files tools %{_bindir}/notify-send -%{_mandir}/man1/notify-send.1%{ext_man} +%{_mandir}/man1/notify-send.1%{?ext_man} %files devel %{_libdir}/*.so ++++++ libnotify-0.7.9.tar.xz -> libnotify-0.7.11.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/.gitlab-ci.yml new/libnotify-0.7.11/.gitlab-ci.yml --- old/libnotify-0.7.9/.gitlab-ci.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/libnotify-0.7.11/.gitlab-ci.yml 2022-04-27 21:05:49.000000000 +0200 @@ -0,0 +1,37 @@ +variables: + DEBIAN_FRONTEND: noninteractive + +stages: + - build + +build:ubuntu: + stage: build + image: ubuntu:devel + before_script: + - apt-get update && + - apt-get install -q -y --no-install-recommends + gobject-introspection + gtk-doc-tools + libgdk-pixbuf2.0-dev + libgirepository1.0-dev + libglib2.0-dev + libgtk-3-dev + libpopt-dev + xmlto + ninja-build + python3-pip + python3-setuptools + xsltproc + docbook-xsl-ns + - pip3 install meson + script: + - meson _build -Ddocbook_docs=enabled + - ninja -C _build install + artifacts: + expose_as: "Build artifacts" + paths: + - _build/docs/notification-spec.html + - _build/docs/reference/html + - _build/docs/reference/html/index.html + - _build/meson-logs + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/NEWS new/libnotify-0.7.11/NEWS --- old/libnotify-0.7.9/NEWS 2020-02-26 20:07:28.388563900 +0100 +++ new/libnotify-0.7.11/NEWS 2022-04-27 21:05:49.000000000 +0200 @@ -1,3 +1,33 @@ +New in 0.7.11 +============= +* Fix potential build errors with old glib version we require +* notify-send: Add support for boolean hints +* notify-send: Support passing any hint value, by parsing variant strings +* notify-send: Add explicit option to create transient notifications + +Contributors: + Marco Trevisan + +New in 0.7.10 +============= +* notify-send: Support commas in icon filenames [Thorsten; !15] +* notify-send: Give failing exit code if showing notification fails [Ray, !13] +* notify-send: Support for replacing an existing notification [Paul; !17] +* notify-send: Add option to wait until notification has been closed [Ben; !18] +* notify-send: Add support for notification actions and responses [Ben; !18] +* notification: Send the application ID when possible [Corentin; !1] +* notification: Use g_memdup2 when available [Marco; !22] +* notification: Improve SNAP detection and confined desktop ID [Marco; !23] +* notification: Add support for getting actions activation token [Marco; !24] +* notify: Use application ID if any to set the fallback app name [Marco; !18] +* Build fixes and improvements [Marco; !22] +* Docs updates [Boris, David; !14, !20] + +Contributors: + Marco Trevisan, Boris Shtrasman, Matthias Sweertvaegher, Thorsten Wi??mann, + Ray Strode, Maximiliano Sandoval R, David King, Corentin No??l, Paul Collins, + Matthias Sweertvaegher, Ben Blain + New in 0.7.9 ============ * Fixed linking in darwin [Iain, Marco; !5] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/README.md new/libnotify-0.7.11/README.md --- old/libnotify-0.7.9/README.md 1970-01-01 01:00:00.000000000 +0100 +++ new/libnotify-0.7.11/README.md 2022-04-27 21:05:49.000000000 +0200 @@ -0,0 +1,16 @@ +# libnotify + +## Description + +libnotify is a library for sending desktop notifications to a notification +daemon, as defined in the [org.freedesktop.Notifications][fdo-spec] Desktop +Specification. These notifications can be used to inform the user about an event +or display some form of information without getting in the user's way. + +## Notice + +For GLib based applications the [GNotification][gnotif] API should be used +instead. + +[fdo-spec]: https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html +[gnotif]: https://docs.gtk.org/gio/class.Notification.html diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/docs/config.xsl new/libnotify-0.7.11/docs/config.xsl --- old/libnotify-0.7.9/docs/config.xsl 2020-02-26 20:07:28.388563900 +0100 +++ new/libnotify-0.7.11/docs/config.xsl 2022-04-27 21:05:49.000000000 +0200 @@ -3,4 +3,5 @@ xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0"> <xsl:param name="html.stylesheet" select="'docbook.css'"/> + <xsl:param name="generate.consistent.ids" select="1"/> </xsl:stylesheet> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/docs/notification-spec.xml new/libnotify-0.7.11/docs/notification-spec.xml --- old/libnotify-0.7.9/docs/notification-spec.xml 2020-02-26 20:07:28.388563900 +0100 +++ new/libnotify-0.7.11/docs/notification-spec.xml 2022-04-27 21:05:49.000000000 +0200 @@ -1272,6 +1272,65 @@ </para> </note> </sect3> + + <sect3 id="signal-activation-token"> + <title><literal>org.freedesktop.Notifications.ActivationToken</literal></title> + <funcsynopsis> + <funcprototype> + <funcdef> + <function>org.freedesktop.Notifications.ActivationToken</function> + </funcdef> + <paramdef>UINT32 <parameter>id</parameter></paramdef> + <paramdef>STRING <parameter>activation_token</parameter></paramdef> + </funcprototype> + </funcsynopsis> + <para> + This signal can be emitted before a <literal>ActionInvoked</literal> + signal. It carries an activation token that can be used to activate a + toplevel. + </para> + <table> + <title>ActivationToken Parameters</title> + <tgroup cols="2"> + <thead> + <row> + <entry>Name</entry> + <entry>Type</entry> + <entry>Description</entry> + </row> + </thead> + <tbody valign="top"> + <row> + <entry><parameter>id</parameter></entry> + <entry>UINT32</entry> + <entry> + The ID of the notification emitting the <literal>ActionInvoked</literal> + signal. + </entry> + </row> + <row> + <entry><parameter>activation_token</parameter></entry> + <entry>STRING</entry> + <entry> + An activation token. This can be either an X11-style startup ID (see + <ulink url="https://specifications.freedesktop.org/startup-notification-spec/startup-notification-latest.txt">Startup notification protocol</ulink>) + or a + <ulink url="https://gitlab.freedesktop.org/wayland/wayland-protocols/-/tree/main/staging/xdg-activation">Wayland xdg-activation</ulink> + token. + </entry> + </row> + </tbody> + </tgroup> + </table> + <note> + <para> + Clients should not assume the server will generate this signal. Some + servers may not support user interaction at all, or may not support + the concept of being able to generate an activation token for a + notification. + </para> + </note> + </sect3> </sect2> </sect1> </article> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/docs/notify-send.xml new/libnotify-0.7.11/docs/notify-send.xml --- old/libnotify-0.7.9/docs/notify-send.xml 2020-02-26 20:07:28.388563900 +0100 +++ new/libnotify-0.7.11/docs/notify-send.xml 2022-04-27 21:05:49.000000000 +0200 @@ -59,6 +59,18 @@ </listitem> </varlistentry> <varlistentry> + <term><option>-a</option>, <option>--app-name</option>=<replaceable>APP_NAME</replaceable></term> + <listitem> + <para>Specifies the app name for the notification.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>-A</option>, <option>--action</option>=[<replaceable>NAME</replaceable>=]<replaceable>Text...</replaceable></term> + <listitem> + <para>Specifies the actions to display to the user. Implies <option>--wait</option> to wait for user input. May be set multiple times. The <replaceable>NAME</replaceable> of the action is output to <literal>stdout</literal>. If <replaceable>NAME</replaceable> is not specified, the numerical index of the option is used (starting with <literal>1</literal>).</para> + </listitem> + </varlistentry> + <varlistentry> <term><option>-u</option>, <option>--urgency</option>=<replaceable>LEVEL</replaceable></term> <listitem> <para>Specifies the urgency level (<literal>low</literal>, <literal>normal</literal>, <literal>critical</literal>).</para> @@ -69,11 +81,11 @@ </term> <listitem> <para>The duration, in milliseconds, for the notification to appear on screen.</para> - <para>(Ubuntu's Notify OSD and GNOME Shell both ignore this parameter.)</para> + <para>Not all implementations use this parameter. GNOME Shell and Notify OSD always ignore it, while Plasma ignores it for notifications with the critical urgency level.</para> </listitem> </varlistentry> <varlistentry> - <term><option>-i</option>, <option>--icon</option>=<replaceable>ICON</replaceable>[,<replaceable>ICON</replaceable>???] + <term><option>-i</option>, <option>--icon</option>=<replaceable>ICON</replaceable> </term> <listitem> <para>Specifies an icon filename or stock icon to display.</para> @@ -89,7 +101,25 @@ <varlistentry> <term><option>-h</option>, <option>--hint</option>=<replaceable>TYPE</replaceable>:<replaceable>NAME</replaceable>:<replaceable>VALUE</replaceable> </term> <listitem> - <para>Specifies basic extra data to pass. Valid types are <literal>INT</literal>, <literal>DOUBLE</literal>, <literal>STRING</literal> and <literal>BYTE</literal>.</para> + <para>Specifies basic extra data to pass. Valid types are <literal>BOOLEAN</literal>, <literal>INT</literal>, <literal>DOUBLE</literal>, <literal>STRING</literal>, <literal>BYTE</literal> and <literal>VARIANT</literal>.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>-p</option>, <option>--print-id</option></term> + <listitem> + <para>Print the notification ID.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>-r</option>, <option>--replace-id</option>=<replaceable>REPLACE_ID</replaceable></term> + <listitem> + <para>The ID of the notification to replace.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>-w</option>, <option>--wait</option></term> + <listitem> + <para>Wait for the notification to be closed before exiting. If the <option>expire-time</option> is set, it will be used as the maximum waiting time.</para> </listitem> </varlistentry> </variablelist> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/docs/reference/libnotify-sections.txt new/libnotify-0.7.11/docs/reference/libnotify-sections.txt --- old/libnotify-0.7.9/docs/reference/libnotify-sections.txt 2020-02-26 20:07:28.388563900 +0100 +++ new/libnotify-0.7.11/docs/reference/libnotify-sections.txt 2022-04-27 21:05:49.000000000 +0200 @@ -27,6 +27,7 @@ notify_notification_add_action notify_notification_clear_actions notify_notification_close +notify_notification_get_activation_token notify_notification_get_closed_reason <SUBSECTION Standard> NotifyNotificationPrivate diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/libnotify/meson.build new/libnotify-0.7.11/libnotify/meson.build --- old/libnotify-0.7.9/libnotify/meson.build 2020-02-26 20:07:28.392563800 +0100 +++ new/libnotify-0.7.11/libnotify/meson.build 2022-04-27 21:05:49.000000000 +0200 @@ -69,8 +69,9 @@ ) introspection = get_option('introspection') -if not introspection.disabled() - find_program('g-ir-scanner', required: introspection.enabled()) +g_ir_scanner = find_program('g-ir-scanner', required: introspection.enabled()) + +if g_ir_scanner.found() and not introspection.disabled() gnome.generate_gir(libnotify_lib, sources: headers + sources + enum_types, namespace: 'Notify', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/libnotify/notification.c new/libnotify-0.7.11/libnotify/notification.c --- old/libnotify-0.7.9/libnotify/notification.c 2020-02-26 20:07:28.392563800 +0100 +++ new/libnotify-0.7.11/libnotify/notification.c 2022-04-27 21:05:49.000000000 +0200 @@ -68,6 +68,11 @@ char *app_name; char *summary; char *body; + char *activation_token; + + const char *snap_path; + const char *snap_name; + char *snap_app; /* NULL to use icon data. Anything else to have server lookup icon */ char *icon_name; @@ -84,6 +89,7 @@ GHashTable *hints; gboolean has_nondefault_actions; + gboolean activating; gboolean updates_pending; gulong proxy_signal_handler; @@ -351,6 +357,104 @@ } static void +maybe_initialize_snap (NotifyNotification *obj) +{ + NotifyNotificationPrivate *priv = obj->priv; + gchar *cgroup_contents = NULL; + + priv->snap_path = g_getenv ("SNAP"); + if (priv->snap_path == NULL) + return; + + if (*priv->snap_path == '\0' || + !strchr (priv->snap_path, G_DIR_SEPARATOR)) { + priv->snap_path = NULL; + return; + } + + priv->snap_name = g_getenv ("SNAP_NAME"); + if (priv->snap_name && *priv->snap_name == '\0') { + priv->snap_name = NULL; + } + + if (g_file_get_contents ("/proc/self/cgroup", &cgroup_contents, + NULL, NULL)) { + gchar **lines = g_strsplit (cgroup_contents, "\n", -1); + gchar *found_snap_name = NULL; + gint i; + + for (i = 0; lines[i]; ++i) { + gchar **parts = g_strsplit (lines[i], ":", 3); + gchar *basename; + gchar **ns; + guint ns_length; + + if (g_strv_length (parts) != 3) { + g_strfreev (parts); + continue; + } + + basename = g_path_get_basename (parts[2]); + g_strfreev (parts); + + if (!basename) { + continue; + } + + ns = g_strsplit (basename, ".", -1); + ns_length = g_strv_length (ns); + g_free (basename); + + if (ns_length < 2 || !g_str_equal (ns[0], "snap")) { + g_strfreev (ns); + continue; + } + + if (priv->snap_name == NULL) { + g_free (found_snap_name); + found_snap_name = g_strdup (ns[1]); + } + + if (ns_length < 3) { + g_strfreev (ns); + continue; + } + + if (priv->snap_name == NULL) { + priv->snap_name = found_snap_name; + found_snap_name = NULL; + } + + if (g_str_equal (ns[1], priv->snap_name)) { + priv->snap_app = g_strdup (ns[2]); + g_strfreev (ns); + break; + } + + g_strfreev (ns); + } + + if (priv->snap_name == NULL && found_snap_name != NULL) { + priv->snap_name = found_snap_name; + found_snap_name = NULL; + } + + g_strfreev (lines); + g_free (found_snap_name); + } + + if (priv->snap_app == NULL) { + priv->snap_app = g_strdup (priv->snap_name); + } + + g_debug ("SNAP path: %s", priv->snap_path); + g_debug ("SNAP name: %s", priv->snap_name); + g_debug ("SNAP app: %s", priv->snap_app); + + g_free (cgroup_contents); +} + +static void notify_notification_init (NotifyNotification *obj) { obj->priv = g_new0 (NotifyNotificationPrivate, 1); @@ -365,6 +469,8 @@ g_str_equal, g_free, (GDestroyNotify) destroy_pair); + + maybe_initialize_snap (obj); } static void @@ -380,6 +486,8 @@ g_free (priv->summary); g_free (priv->body); g_free (priv->icon_name); + g_free (priv->activation_token); + g_free (priv->snap_app); if (priv->actions != NULL) { g_slist_foreach (priv->actions, (GFunc) g_free, NULL); @@ -431,30 +539,52 @@ { gchar *path_filename; gchar *path_ret; + gboolean was_uri; if (!path || *path == '\0') return NULL; + was_uri = TRUE; path_ret = NULL; path_filename = g_filename_from_uri (base_path, NULL, NULL); if (path_filename == NULL) { + was_uri = FALSE; + if (base_path && base_path[0] == G_DIR_SEPARATOR) { path_filename = g_strdup (base_path); } else { path_filename = realpath (base_path, NULL); + + if (path_filename == NULL) { + /* File path is not existing, but let's check + * if it's under the base path before giving up + */ + path_filename = g_strdup (base_path); + } } } - g_debug ("Trying to look at file '%s' in the '%s' prefix.", - base_path, - path); - - path_ret = g_build_filename (path, path_filename, NULL); + if (g_str_has_prefix (path_filename, path)) { + path_ret = g_strdup (path_filename); + } else { + g_debug ("Trying to look at file '%s' in the '%s' prefix.", + base_path, + path); + path_ret = g_build_filename (path, path_filename, NULL); + } if (!g_file_test (path_ret, G_FILE_TEST_EXISTS)) { + g_debug ("Nothing found at %s", path_ret); g_free (path_ret); path_ret = NULL; + } else if (was_uri) { + gchar *uri = g_filename_to_uri (path_ret, NULL, NULL); + + if (uri != NULL) { + g_free (path_ret); + path_ret = uri; + } } g_free (path_filename); @@ -463,33 +593,33 @@ } static gchar * -try_prepend_desktop (const gchar *desktop) +try_prepend_snap_desktop (NotifyNotification *notification, + const gchar *desktop) { - gchar *ret; + NotifyNotificationPrivate *priv = notification->priv; + gchar *ret = NULL; /* * if it's an absolute path, try prepending $SNAP, otherwise try - * $SNAP_NAME_; snap .desktop files are in the format + * ${SNAP_NAME}_; snap .desktop files are in the format * ${SNAP_NAME}_desktop_file_name */ - ret = try_prepend_path (desktop, g_getenv ("SNAP")); - - if (ret == NULL) { - const gchar *snap_name = g_getenv ("SNAP_NAME"); + ret = try_prepend_path (desktop, priv->snap_path); - if (snap_name != NULL && snap_name[0] != '\0') { - ret = g_strdup_printf ("%s_%s", snap_name, desktop); - } + if (ret == NULL && priv->snap_name != NULL && + strchr (desktop, G_DIR_SEPARATOR) == NULL) { + ret = g_strdup_printf ("%s_%s", priv->snap_name, desktop); } return ret; } static gchar * -try_prepend_snap (const gchar *value) +try_prepend_snap (NotifyNotification *notification, + const gchar *value) { /* hardcoded paths to icons might be relocated under $SNAP */ - return try_prepend_path (value, g_getenv ("SNAP")); + return try_prepend_path (value, notification->priv->snap_path); } @@ -524,7 +654,8 @@ g_free (notification->priv->icon_name); notification->priv->icon_name = (icon != NULL && *icon != '\0' ? g_strdup (icon) : NULL); - snapped_icon = try_prepend_desktop (notification->priv->icon_name); + snapped_icon = try_prepend_snap_desktop (notification, + notification->priv->icon_name); if (snapped_icon != NULL) { g_debug ("Icon updated in snap environment: '%s' -> '%s'\n", notification->priv->icon_name, snapped_icon); @@ -608,8 +739,25 @@ g_warning ("Received unknown action %s", action); } } else { + notification->priv->activating = TRUE; pair->cb (notification, (char *) action, pair->user_data); + notification->priv->activating = FALSE; + + g_free (notification->priv->activation_token); + notification->priv->activation_token = NULL; } + } else if (g_strcmp0 (signal_name, "ActivationToken") == 0 && + g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(us)"))) { + guint32 id; + const char *activation_token; + + g_variant_get (parameters, "(u&s)", &id, &activation_token); + + if (id != notification->priv->id) + return; + + g_free (notification->priv->activation_token); + notification->priv->activation_token = g_strdup (activation_token); } } @@ -634,6 +782,9 @@ GHashTableIter iter; gpointer key, data; GVariant *result; +#ifdef GLIB_VERSION_2_32 + GApplication *application = NULL; +#endif g_return_val_if_fail (notification != NULL, FALSE); g_return_val_if_fail (NOTIFY_IS_NOTIFICATION (notification), FALSE); @@ -668,6 +819,38 @@ g_variant_builder_add (&hints_builder, "{sv}", key, data); } + if (priv->snap_app && + g_hash_table_lookup (priv->hints, "desktop-entry") == NULL) { + gchar *snap_desktop; + + snap_desktop = g_strdup_printf ("%s_%s", + priv->snap_name, + priv->snap_app); + + g_debug ("Using desktop entry: %s", snap_desktop); + g_variant_builder_add (&hints_builder, "{sv}", + "desktop-entry", + g_variant_new_take_string (snap_desktop)); + } + +#ifdef GLIB_VERSION_2_32 + if (!priv->snap_app) { + application = g_application_get_default (); + } + + if (application != NULL) { + GVariant *desktop_entry = g_hash_table_lookup (priv->hints, "desktop-entry"); + + if (desktop_entry == NULL) { + const char *application_id = g_application_get_application_id (application); + + g_debug ("Using desktop entry: %s", application_id); + g_variant_builder_add (&hints_builder, "{sv}", "desktop-entry", + g_variant_new_string (application_id)); + } + } +#endif + /* TODO: make this nonblocking */ result = g_dbus_proxy_call_sync (proxy, "Notify", @@ -855,13 +1038,20 @@ notify_notification_set_hint (notification, hint_name, value); } -static GVariant * -get_parsed_variant (GVariant *variant, - gchar *(*str_parser)(const gchar *)) -{ - gchar *parsed = str_parser (g_variant_get_string (variant, NULL)); +typedef gchar * (*StringParserFunc) (NotifyNotification *, const gchar *); - if (parsed != NULL) { +static GVariant * +get_parsed_variant (NotifyNotification *notification, + const char *key, + GVariant *variant, + StringParserFunc str_parser) +{ + const char *str = g_variant_get_string (variant, NULL); + gchar *parsed = str_parser (notification, str); + + if (parsed != NULL && g_strcmp0 (str, parsed) != 0) { + g_debug ("Hint %s updated in snap environment: '%s' -> '%s'\n", + key, str, parsed); g_variant_unref (variant); variant = g_variant_new_take_string (parsed); } @@ -870,18 +1060,28 @@ } static GVariant * -maybe_parse_snap_hint_value (const gchar *key, +maybe_parse_snap_hint_value (NotifyNotification *notification, + const gchar *key, GVariant *value) { + StringParserFunc parse_func = NULL; + + if (!notification->priv->snap_path) + return value; + if (g_strcmp0 (key, "desktop-entry") == 0) { - value = get_parsed_variant (value, try_prepend_desktop); + parse_func = try_prepend_snap_desktop; } else if (g_strcmp0 (key, "image-path") == 0 || g_strcmp0 (key, "image_path") == 0 || g_strcmp0 (key, "sound-file") == 0) { - value = get_parsed_variant (value, try_prepend_snap); + parse_func = try_prepend_snap; + } + + if (parse_func == NULL) { + return value; } - return value; + return get_parsed_variant (notification, key, value, parse_func); } /** @@ -906,7 +1106,7 @@ g_return_if_fail (key != NULL && *key != '\0'); if (value != NULL) { - value = maybe_parse_snap_hint_value (key, value); + value = maybe_parse_snap_hint_value (notification, key, value); g_hash_table_insert (notification->priv->hints, g_strdup (key), g_variant_ref_sink (value)); @@ -1038,7 +1238,11 @@ g_return_if_fail (value != NULL || len == 0); +#ifdef GLIB_VERSION_2_68 + value_dup = g_memdup2 (value, len); +#else value_dup = g_memdup (value, len); +#endif notify_notification_set_hint (notification, key, g_variant_new_from_data (G_VARIANT_TYPE ("ay"), value_dup, @@ -1167,6 +1371,29 @@ } } +/** + * notify_notification_get_activation_token: + * + * If an an action is currently being activated, return the activation token. + * This function is intended to be used in a #NotifyActionCallback to get + * the activation token for the activated action, if the notification daemon + * supports it. + * + * Return value: (transfer none): The current activation token, or %NULL if none + * + * Since: 0.7.10 + */ +const char * +notify_notification_get_activation_token (NotifyNotification *notification) +{ + g_return_val_if_fail (NOTIFY_IS_NOTIFICATION (notification), NULL); + + if (notification->priv->activating) + return notification->priv->activation_token; + + return NULL; +} + gboolean _notify_notification_has_nondefault_actions (const NotifyNotification *n) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/libnotify/notification.h new/libnotify-0.7.11/libnotify/notification.h --- old/libnotify-0.7.9/libnotify/notification.h 2020-02-26 20:07:28.392563800 +0100 +++ new/libnotify-0.7.11/libnotify/notification.h 2022-04-27 21:05:49.000000000 +0200 @@ -180,6 +180,8 @@ gpointer user_data, GFreeFunc free_func); +const char *notify_notification_get_activation_token (NotifyNotification *notification); + void notify_notification_clear_actions (NotifyNotification *notification); gboolean notify_notification_close (NotifyNotification *notification, GError **error); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/libnotify/notify.c new/libnotify-0.7.11/libnotify/notify.c --- old/libnotify-0.7.9/libnotify/notify.c 2020-02-26 20:07:28.392563800 +0100 +++ new/libnotify-0.7.11/libnotify/notify.c 2022-04-27 21:05:49.000000000 +0200 @@ -151,9 +151,17 @@ if (_initted) return TRUE; +#ifdef GLIB_VERSION_2_32 + if (app_name == NULL && g_application_get_default ()) { + GApplication *application = g_application_get_default (); + + app_name = g_application_get_application_id (application); + } +#endif + notify_set_app_name (app_name); -#if !GLIB_CHECK_VERSION (2, 36, 0) +#ifndef GLIB_VERSION_2_36 g_type_init (); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/meson.build new/libnotify-0.7.11/meson.build --- old/libnotify-0.7.9/meson.build 2020-02-26 20:07:28.392563800 +0100 +++ new/libnotify-0.7.11/meson.build 2022-04-27 21:05:49.000000000 +0200 @@ -1,6 +1,6 @@ project('libnotify', 'c', - version: '0.7.9', + version: '0.7.11', meson_version: '>= 0.47.0') gnome = import('gnome') @@ -66,7 +66,7 @@ '@INPUT@', ] - testrun = run_command(xsltproc, '--nonet', stylesheet) + testrun = run_command(xsltproc, '--nonet', stylesheet, check: false) if testrun.returncode() != 0 error('DocBook stylesheet for generating man pages not found, you need to install docbook-xsl-ns or similar package.') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/tests/test-error.c new/libnotify-0.7.11/tests/test-error.c --- old/libnotify-0.7.9/tests/test-error.c 2020-02-26 20:07:28.396563800 +0100 +++ new/libnotify-0.7.11/tests/test-error.c 2022-04-27 21:05:49.000000000 +0200 @@ -29,7 +29,7 @@ { NotifyNotification *n; -#if !GLIB_CHECK_VERSION (2, 36, 0) +#ifndef GLIB_VERSION_2_36 g_type_init (); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/tests/test-replace.c new/libnotify-0.7.11/tests/test-replace.c --- old/libnotify-0.7.9/tests/test-replace.c 2020-02-26 20:07:28.396563800 +0100 +++ new/libnotify-0.7.11/tests/test-replace.c 2022-04-27 21:05:49.000000000 +0200 @@ -28,7 +28,7 @@ GError *error; error = NULL; -#if !GLIB_CHECK_VERSION (2, 36, 0) +#ifndef GLIB_VERSION_2_36 g_type_init (); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libnotify-0.7.9/tools/notify-send.c new/libnotify-0.7.11/tools/notify-send.c --- old/libnotify-0.7.9/tools/notify-send.c 2020-02-26 20:07:28.396563800 +0100 +++ new/libnotify-0.7.11/tools/notify-send.c 2022-04-27 21:05:49.000000000 +0200 @@ -32,6 +32,7 @@ #define GETTEXT_PACKAGE NULL static NotifyUrgency urgency = NOTIFY_URGENCY_NORMAL; +static GMainLoop *loop = NULL; static gboolean g_option_arg_urgency_cb (const char *option_name, @@ -99,6 +100,26 @@ key, (guchar) h_byte); } + } else if (g_ascii_strcasecmp (type, "boolean") == 0) { + gboolean h_boolean = FALSE; + + if (g_ascii_strcasecmp (value, "true") == 0) { + h_boolean = TRUE; + } else if (g_ascii_isdigit (*value)) { + h_boolean = !!g_ascii_strtoull (value, NULL, 10); + } + + notify_notification_set_hint (notification, key, + g_variant_new_boolean (h_boolean)); + } else if (g_ascii_strcasecmp (type, "variant") == 0) { + GVariant *variant = g_variant_parse (NULL, value, NULL, NULL, NULL); + + if (variant != NULL) { + notify_notification_set_hint (notification, key, variant); + } else { + conv_error = TRUE; + } + } else { *error = g_error_new (G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, @@ -120,6 +141,41 @@ return TRUE; } +static void +handle_closed (NotifyNotification *notify, + gpointer user_data) +{ + g_main_loop_quit (loop); +} + +static void +handle_action (NotifyNotification *notify, + char *action, + gpointer user_data) +{ + const char *action_name = user_data; + const char *activation_token; + + activation_token = notify_notification_get_activation_token (notify); + + g_printf ("%s\n", action_name); + + if (activation_token) { + g_debug ("Activation Token: %s", activation_token); + } + + notify_notification_close (notify, NULL); +} + +static gboolean +on_wait_timeout (gpointer data) +{ + fprintf (stderr, "Wait timeout expired\n"); + g_main_loop_quit (loop); + + return FALSE; +} + int main (int argc, char *argv[]) { @@ -128,11 +184,15 @@ static const char *type = NULL; static char *app_name = NULL; static char *icon_str = NULL; - static char *icons = NULL; static char **n_text = NULL; static char **hints = NULL; + static char **actions = NULL; + static gboolean print_id = FALSE; + static gint notification_id = 0; static gboolean do_version = FALSE; - static gboolean hint_error = FALSE; + static gboolean hint_error = FALSE, show_error = FALSE; + static gboolean transient = FALSE; + static gboolean wait = FALSE; static glong expire_timeout = NOTIFY_EXPIRES_DEFAULT; GOptionContext *opt_ctx; NotifyNotification *notify; @@ -150,16 +210,32 @@ "notification."), N_("TIME")}, {"app-name", 'a', 0, G_OPTION_ARG_STRING, &app_name, N_("Specifies the app name for the icon"), N_("APP_NAME")}, - {"icon", 'i', 0, G_OPTION_ARG_FILENAME, &icons, + {"icon", 'i', 0, G_OPTION_ARG_FILENAME, &icon_str, N_("Specifies an icon filename or stock icon to display."), - N_("ICON[,ICON...]")}, + N_("ICON")}, {"category", 'c', 0, G_OPTION_ARG_FILENAME, &type, N_("Specifies the notification category."), N_("TYPE[,TYPE...]")}, + {"transient", 'e', 0, G_OPTION_ARG_NONE, &transient, + N_("Create a transient notification"), + NULL}, {"hint", 'h', 0, G_OPTION_ARG_FILENAME_ARRAY, &hints, N_ - ("Specifies basic extra data to pass. Valid types are int, double, string and byte."), + ("Specifies basic extra data to pass. Valid types are boolean, int, double, string, byte and variant."), N_("TYPE:NAME:VALUE")}, + {"print-id", 'p', 0, G_OPTION_ARG_NONE, &print_id, + N_ ("Print the notification ID."), NULL}, + {"replace-id", 'r', 0, G_OPTION_ARG_INT, ¬ification_id, + N_ ("The ID of the notification to replace."), N_("REPLACE_ID")}, + {"wait", 'w', 0, G_OPTION_ARG_NONE, &wait, + N_("Wait for the notification to be closed before exiting."), + NULL}, + {"action", 'A', 0, G_OPTION_ARG_FILENAME_ARRAY, &actions, + N_ + ("Specifies the actions to display to the user. Implies --wait to wait for user input." + " May be set multiple times. The name of the action is output to stdout. If NAME is " + "not specified, the numerical index of the option is used (starting with 0)."), + N_("[NAME=]Text...")}, {"version", 'v', 0, G_OPTION_ARG_NONE, &do_version, N_("Version of the package."), NULL}, @@ -173,7 +249,7 @@ setlocale (LC_ALL, ""); -#if !GLIB_CHECK_VERSION (2, 36, 0) +#ifndef GLIB_VERSION_2_36 g_type_init (); #endif @@ -215,27 +291,26 @@ } } - if (icons != NULL) { - char *c; - - /* XXX */ - if ((c = strchr (icons, ',')) != NULL) - *c = '\0'; - - icon_str = icons; - } - if (!notify_init ("notify-send")) exit (1); - notify = notify_notification_new (summary, - body, - icon_str); + notify = g_object_new (NOTIFY_TYPE_NOTIFICATION, + "summary", summary, + "body", body, + "icon-name", icon_str, + "id", notification_id, + NULL); + notify_notification_set_category (notify, type); notify_notification_set_urgency (notify, urgency); notify_notification_set_timeout (notify, expire_timeout); notify_notification_set_app_name (notify, app_name); + if (transient) { + notify_notification_set_hint (notify, "transient", + g_variant_new_boolean (TRUE)); + } + g_free (body); /* Set hints */ @@ -263,7 +338,7 @@ if (!retval) { fprintf (stderr, "%s\n", error->message); - g_error_free (error); + g_clear_error (&error); hint_error = TRUE; } } @@ -274,12 +349,96 @@ } } - if (!hint_error) - notify_notification_show (notify, NULL); + if (actions != NULL) { + GList *server_caps = notify_get_server_caps (); + gint i = 0; + char *action = NULL; + gchar **spl = NULL; + gboolean have_actions; + + have_actions = + !!g_list_find_custom (server_caps, + "actions", + (GCompareFunc) g_ascii_strcasecmp); + g_list_foreach (server_caps, (GFunc) g_free, NULL); + g_list_free (server_caps); + + if (!have_actions) { + g_printerr (N_("Actions are not supported by this " + "notifications server. " + "Displaying non-interactively.\n")); + show_error = TRUE; + } + + while (have_actions && (action = actions[i++])) { + gchar *name; + const gchar *label; + + spl = g_strsplit (action, "=", 2); + + if (g_strv_length (spl) == 1) { + name = g_strdup_printf ("%d", i - 1); + label = g_strstrip (spl[0]); + } else { + name = g_strdup (g_strstrip (spl[0])); + label = g_strstrip (spl[1]); + } + + if (*label != '\0' && *name != '\0') { + notify_notification_add_action (notify, + name, + label, + handle_action, + name, + g_free); + wait = TRUE; + } + + g_strfreev (spl); + } + + g_strfreev (actions); + } + + if (wait) { + g_signal_connect (G_OBJECT (notify), + "closed", + G_CALLBACK (handle_closed), + NULL); + + if (expire_timeout > 0) { + g_timeout_add (expire_timeout, on_wait_timeout, NULL); + } + } + + if (!hint_error) { + retval = notify_notification_show (notify, &error); + + if (!retval) { + fprintf (stderr, "%s\n", error->message); + g_clear_error (&error); + show_error = TRUE; + } + } + + if (print_id) { + g_object_get (notify, "id", ¬ification_id, NULL); + g_printf ("%d\n", notification_id); + } + + if (wait) { + loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (loop); + g_main_loop_unref (loop); + loop = NULL; + } g_object_unref (G_OBJECT (notify)); notify_uninit (); - exit (hint_error); + if (hint_error || show_error) + exit (1); + + return 0; }