osc: kitty notifications: buttons, icons, app-name, categories etc

First, icons have been finalized in the specification. There were only
three things we needed to adjust:

* symbolic names are base64 encoded
* there are a couple of OSC-99 defined symbolic names that need to be
  translated to the corresponding XDG icon name.
* allow in-band icons without a cache ID (that is, allow applications
  to use p=icon without having to cache the icon first).

Second, add support for the following new additions to the protocol:

* 'f': custom app-name, overrides the terminal's app-id
* 't': categories
* 'p=alive': lets applications poll for currently active notifications
* 'id' is now 'unset' by default, rather than "0"
* 'w': expire time (i.e. notification timeout)
* "buttons": aka actions. This lets applications add additional (to
  the terminal defined "default" action) actions. The 'activated' event
  has been updated to report which button/action was used to activate
  the notification.

To support button/actions, desktop-notifications.command had to be
reworked a bit.

There's now a new config option:
desktop-notifications.command-action-arg. It has two template
arguments ${action-name} and ${action-label}.

command-action-arg gets expanded for *each* action.

${action-name} and ${action-label} has been replaced by ${action-arg}
in command. This is a somewhat special template, in that it gets
replaced by *all* instances of the expanded actions.
This commit is contained in:
Daniel Eklöf 2024-07-31 16:22:17 +02:00
parent d87b81dd52
commit 76ac910b11
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
9 changed files with 580 additions and 78 deletions

View file

@ -806,6 +806,11 @@ value_to_spawn_template(struct context *ctx,
char **argv = NULL;
if (ctx->value[0] == '"' && ctx->value[1] == '"' && ctx->value[2] == '\0') {
template->argv.args = NULL;
return true;
}
if (!tokenize_cmdline(ctx->value, &argv)) {
LOG_CONTEXTUAL_ERR("syntax error in command line");
return false;
@ -1110,6 +1115,9 @@ parse_section_desktop_notifications(struct context *ctx)
if (streq(key, "command"))
return value_to_spawn_template(
ctx, &conf->desktop_notifications.command);
else if (streq(key, "command-action-arg"))
return value_to_spawn_template(
ctx, &conf->desktop_notifications.command_action_arg);
else if (streq(key, "close"))
return value_to_spawn_template(
ctx, &conf->desktop_notifications.close);
@ -3189,6 +3197,9 @@ config_load(struct config *conf, const char *conf_path,
.command = {
.argv = {.args = NULL},
},
.command_action_arg = {
.argv = {.args = NULL},
},
.close = {
.argv = {.args = NULL},
},
@ -3231,8 +3242,9 @@ 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 ${app-id} --urgency ${urgency} --hint STRING:image-path:${icon} --action ${action-name}=${action-label} --print-id -- ${title} ${body}",
"notify-send --wait --app-name ${app-id} --icon ${app-id} --category ${category} --urgency ${urgency} --expire-time ${expire-time} --hint STRING:image-path:${icon} --replace-id ${replace-id} ${action-arg} --print-id -- ${title} ${body}",
&conf->desktop_notifications.command.argv.args);
tokenize_cmdline("--action ${action-name}=${action-label}", &conf->desktop_notifications.command_action_arg.argv.args);
tokenize_cmdline("xdg-open ${url}", &conf->url.launch.argv.args);
static const char32_t *url_protocols[] = {
@ -3487,6 +3499,8 @@ config_clone(const struct config *old)
spawn_template_clone(&conf->bell.command, &old->bell.command);
spawn_template_clone(&conf->desktop_notifications.command,
&old->desktop_notifications.command);
spawn_template_clone(&conf->desktop_notifications.command_action_arg,
&old->desktop_notifications.command_action_arg);
spawn_template_clone(&conf->desktop_notifications.close,
&old->desktop_notifications.close);
@ -3571,6 +3585,7 @@ config_free(struct config *conf)
spawn_template_free(&conf->bell.command);
free(conf->scrollback.indicator.text);
spawn_template_free(&conf->desktop_notifications.command);
spawn_template_free(&conf->desktop_notifications.command_action_arg);
spawn_template_free(&conf->desktop_notifications.close);
for (size_t i = 0; i < ALEN(conf->fonts); i++)
config_font_list_destroy(&conf->fonts[i]);