diff --git a/docs/notify-send.xml b/docs/notify-send.xml
index e2c4b1d..c8eb6ef 100644
--- a/docs/notify-send.xml
+++ b/docs/notify-send.xml
@@ -58,6 +58,18 @@
Show help and exit.
+
+ , =APP_NAME
+
+ Specifies the app name for the notification.
+
+
+
+ , =[NAME=]Text...
+
+ Specifies the actions to display to the user. Implies 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 1).
+
+
, =LEVEL
@@ -104,6 +116,12 @@
The ID of the notification to replace.
+
+ ,
+
+ Wait for the notification to be closed before exiting. If the is set, it will be used as the maximum waiting time.
+
+
diff --git a/libnotify/notify.c b/libnotify/notify.c
index bf7d89b..7f72972 100644
--- a/libnotify/notify.c
+++ b/libnotify/notify.c
@@ -151,6 +151,14 @@ notify_init (const char *app_name)
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)
diff --git a/tools/notify-send.c b/tools/notify-send.c
index 937fb41..65963ff 100644
--- a/tools/notify-send.c
+++ b/tools/notify-send.c
@@ -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,
@@ -120,6 +121,33 @@ notify_notification_set_hint_variant (NotifyNotification *notification,
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;
+
+ g_printf ("%s\n", action_name);
+ 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[])
{
@@ -130,10 +158,12 @@ main (int argc, char *argv[])
static char *icon_str = 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, show_error = FALSE;
+ static gboolean wait = FALSE;
static glong expire_timeout = NOTIFY_EXPIRES_DEFAULT;
GOptionContext *opt_ctx;
NotifyNotification *notify;
@@ -165,6 +195,15 @@ main (int argc, char *argv[])
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},
@@ -262,7 +301,7 @@ main (int argc, char *argv[])
if (!retval) {
fprintf (stderr, "%s\n", error->message);
- g_error_free (error);
+ g_clear_error (&error);
hint_error = TRUE;
}
}
@@ -273,12 +312,74 @@ main (int argc, char *argv[])
}
}
+ 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_error_free (error);
+ g_clear_error (&error);
show_error = TRUE;
}
}
@@ -288,6 +389,13 @@ main (int argc, char *argv[])
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 ();