notify: don't focus/report on notification dismissal

Only do it when the notification was activated.

Here, activated means the 'click to activate' notification action was
triggered.

How do we tie everything together?

First, we add a new template parameter, ${action}. It's intended to be
used with e.g. notify-send's --action option.

When the action is triggered, notify-send prints its name on stdout,
on a separate line. Look for this in stdout. Only if we've seen it do
we focus/report the notification.
This commit is contained in:
Daniel Eklöf 2024-07-23 16:41:52 +02:00
parent 55a4e59ef9
commit 045ead985c
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
6 changed files with 46 additions and 19 deletions

View file

@ -75,7 +75,7 @@
* `desktop-notifications.command` option, replaces `notify`.
* `desktop-notifications.inhibit-when-focused` option, replaces
`notify-focus-inhibit`.
* `${icon}` and `${urgency}` added to the
* `${icon}`, `${urgency}` and `${action}` added to the
`desktop-notifications.command` template.
[1707]: https://codeberg.org/dnkl/foot/issues/1707

View file

@ -3225,7 +3225,7 @@ config_load(struct config *conf, const char *conf_path,
parse_modifiers(XKB_MOD_NAME_SHIFT, 5, &conf->mouse.selection_override_modifiers);
tokenize_cmdline(
"notify-send --wait --app-name ${app-id} --icon ${icon} --urgency ${urgency} -- ${title} ${body}",
"notify-send --wait --app-name ${app-id} --icon ${icon} --urgency ${urgency} --action ${action} -- ${title} ${body}",
&conf->desktop_notifications.command.argv.args);
tokenize_cmdline("xdg-open ${url}", &conf->url.launch.argv.args);

View file

@ -462,11 +462,32 @@ Note: do not set *TERM* here; use the *term* option in the main
behavior depends on the notification daemon in use, and how it
has been configured.
For this to work, foot needs an XDG activation token. To this
end, foot will read the command's stdout; a line prefixed with
*xdgtoken=* will be recognized as containing the XDG
activation token:
For this to work, foot needs to know when the notification was
activated (as opposed to just dismissed), and it needs an XDG
activation token.
There are two parts to handle this. First, the notification
must define an action. For this purpose, foot definse the
template parameter *${action}*. It is intended to be used with
e.g. notify-send's *-A,--action* option. The contents of
*${action}* is not configurable, but will be on the form
'name=label', where name is a notification internal reference
to the action, and label is what is displayed in the
notification.
Second, foot needs to know when the notification activated,
and it needs to get hold of the XDG activation token.
Both are expected to be printed on stdout.
Foot expects the action name (not label) to be printed on a
single line. No prefix, no postfix.
Foot expects the activation token to be printed on a single
line, prefixed with *xdgtoken=*.
Example:
activate-foot
xdgtoken=18179adf579a7a904ce73754964b1ec3
The expected format of stdout may change at any time. Please
@ -491,7 +512,7 @@ Note: do not set *TERM* here; use the *term* option in the main
For *notify-send*, this can be achieved with the *--wait*
option.
Default: _notify-send --wait --app-name ${app-id} --icon ${icon} --urgency ${urgency} -- ${title} ${body}_.
Default: _notify-send --wait --app-name ${app-id} --icon ${icon} --urgency ${urgency} --action ${action} -- ${title} ${body}_.
*inhibit-when-focused*
Boolean. If enabled, foot will not display notifications if the

View file

@ -47,7 +47,7 @@
# command-focused=no
[desktop-notifications]
# command=notify-send --wait --app-name ${app-id} --icon ${icon} --urgency ${urgency} -- ${title} ${body}
# command=notify-send --wait --app-name ${app-id} --icon ${icon} --urgency ${urgency} --action ${action} -- ${title} ${body}
# inhibit-when-focused=yes

View file

@ -54,8 +54,11 @@ consume_stdout(struct notification *notif, bool eof)
} else if (!eof)
break;
if (strcmp(line, "activate-foot") == 0)
notif->activated = true;
/* Check for 'xdgtoken=xyz' */
if (len > 9 && memcmp(line, "xdgtoken=", 9) == 0) {
else if (len > 9 && memcmp(line, "xdgtoken=", 9) == 0) {
notif->xdg_token = xstrndup(&line[9], len - 9);
LOG_DBG("XDG token: \"%s\"", notif->xdg_token);
}
@ -133,12 +136,13 @@ notif_done(struct reaper *reaper, pid_t pid, int status, void *data)
LOG_DBG("notification %s dismissed", notif->id);
if (notif->focus) {
LOG_DBG("focus window on notification activation: \"%s\"", notif->xdg_token);
if (notif->activated && notif->focus) {
LOG_DBG("focus window on notification activation: \"%s\"",
notif->xdg_token);
wayl_activate(term->wl, term->window, notif->xdg_token);
}
if (notif->report) {
if (notif->activated && notif->report) {
xassert(notif->id != NULL);
LOG_DBG("sending notification report to client");
@ -221,13 +225,14 @@ notify_notify(struct terminal *term, struct notification *notif)
? "normal" : "critical";
if (!spawn_expand_template(
&term->conf->desktop_notifications.command, 6,
(const char *[]){
"app-id", "window-title", "icon", "title", "body", "urgency"},
(const char *[]){
term->app_id ? term->app_id : term->conf->app_id,
term->window_title, icon_name_or_path, title, body, urgency_str},
&argc, &argv))
&term->conf->desktop_notifications.command, 7,
(const char *[]){
"app-id", "window-title", "icon", "title", "body", "urgency", "action"},
(const char *[]){
term->app_id ? term->app_id : term->conf->app_id,
term->window_title, icon_name_or_path, title, body, urgency_str,
"activate-foot=Click to activate"},
&argc, &argv))
{
return false;
}

View file

@ -45,6 +45,7 @@ struct notification {
* Used internally by notify
*/
bool activated; /* User 'activated' the notification */
char *xdg_token; /* XDG activation token, from daemon */
pid_t pid; /* Notifier command PID */