2020-12-10 18:06:24 +01:00
|
|
|
#include "notify.h"
|
|
|
|
|
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
#include <errno.h>
|
2020-12-10 18:06:24 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
#include <sys/epoll.h>
|
2020-12-10 18:06:24 +01:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
|
|
#define LOG_MODULE "notify"
|
2024-07-23 11:29:05 +02:00
|
|
|
#define LOG_ENABLE_DBG 1
|
2020-12-10 18:06:24 +01:00
|
|
|
#include "log.h"
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include "spawn.h"
|
osc/notify: add support for OSC-99, kitty desktop notifications
This adds limited support for OSC-99, kitty desktop notifications[^1]. We
support everything defined by the "protocol", except:
* 'a': action to perform on notification activation. Since we don't
trigger the notification ourselves (over D-Bus), we don't know a)
which ID the notification got, or b) when it is clicked.
* ... and that's it. Everything else is supported
To be explicit, we *do* support:
* Chunked notifications (d=0|1), allowing the application to append
data to a notification in chunks, before it's finally displayed.
* Plain UTF-8, or base64-encoded UTF-8 payload (e=0|1).
* Notification identifier (i=xyz).
* Payload type (p=title|body).
* When to honor the notification (o=always|unfocused|invisible), with
the following quirks:
- we don't know when the window is invisible, thus it's treated as
'unfocused'.
- the foot option 'notify-focus-inhibit' overrides 'always'
* Urgency (u=0|1|2)
[^1]: https://sw.kovidgoyal.net/kitty/desktop-notifications/
2024-07-19 15:04:28 +02:00
|
|
|
#include "terminal.h"
|
2024-07-23 11:29:05 +02:00
|
|
|
#include "util.h"
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
#include "wayland.h"
|
2020-12-10 18:06:24 +01:00
|
|
|
#include "xmalloc.h"
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
#include "xsnprintf.h"
|
2020-12-10 18:06:24 +01:00
|
|
|
|
|
|
|
|
void
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
notify_free(struct terminal *term, struct notification *notif)
|
2020-12-10 18:06:24 +01:00
|
|
|
{
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
fdm_del(term->fdm, notif->stdout_fd);
|
|
|
|
|
free(notif->id);
|
|
|
|
|
free(notif->title);
|
|
|
|
|
free(notif->body);
|
2024-07-23 11:29:05 +02:00
|
|
|
free(notif->icon_id);
|
|
|
|
|
free(notif->icon_symbolic_name);
|
|
|
|
|
free(notif->icon_data);
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
free(notif->xdg_token);
|
2024-07-23 09:42:14 +02:00
|
|
|
free(notif->stdout_data);
|
2024-07-23 09:33:18 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-24 16:02:19 +02:00
|
|
|
static bool
|
|
|
|
|
to_integer(const char *line, size_t len, uint32_t *res)
|
|
|
|
|
{
|
|
|
|
|
bool is_id = true;
|
|
|
|
|
uint32_t maybe_id = 0;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < len; i++) {
|
|
|
|
|
char digit = line[i];
|
|
|
|
|
if (digit < '0' || digit > '9') {
|
|
|
|
|
is_id = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
maybe_id *= 10;
|
|
|
|
|
maybe_id += digit - '0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*res = maybe_id;
|
|
|
|
|
return is_id;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 09:33:18 +02:00
|
|
|
static void
|
|
|
|
|
consume_stdout(struct notification *notif, bool eof)
|
|
|
|
|
{
|
2024-07-23 09:42:14 +02:00
|
|
|
char *data = notif->stdout_data;
|
2024-07-23 09:33:18 +02:00
|
|
|
const char *line = data;
|
|
|
|
|
size_t left = notif->stdout_sz;
|
|
|
|
|
|
|
|
|
|
/* Process stdout, line-by-line */
|
|
|
|
|
while (left > 0) {
|
|
|
|
|
line = data;
|
|
|
|
|
size_t len = left;
|
|
|
|
|
char *eol = memchr(line, '\n', left);
|
|
|
|
|
|
|
|
|
|
if (eol != NULL) {
|
|
|
|
|
*eol = '\0';
|
|
|
|
|
len = strlen(line);
|
|
|
|
|
data = eol + 1;
|
|
|
|
|
} else if (!eof)
|
|
|
|
|
break;
|
|
|
|
|
|
2024-07-24 16:02:19 +02:00
|
|
|
uint32_t maybe_id = 0;
|
|
|
|
|
|
|
|
|
|
/* Check for daemon assigned ID, either '123', or 'id=123' */
|
|
|
|
|
if (to_integer(line, len, &maybe_id) ||
|
|
|
|
|
(len > 3 && memcmp(line, "id=", 3) == 0 &&
|
|
|
|
|
to_integer(&line[3], len - 3, &maybe_id)))
|
|
|
|
|
{
|
|
|
|
|
notif->external_id = maybe_id;
|
|
|
|
|
LOG_DBG("external ID: %u", notif->external_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check for triggered action, either 'default' or 'action=default' */
|
|
|
|
|
else if ((len == 7 && memcmp(line, "default", 7) == 0) ||
|
|
|
|
|
(len == 7 + 7 && memcmp(line, "action=default", 7 + 7) == 0))
|
|
|
|
|
{
|
2024-07-23 16:41:52 +02:00
|
|
|
notif->activated = true;
|
2024-07-24 16:02:19 +02:00
|
|
|
LOG_DBG("notification's default action was triggered");
|
|
|
|
|
}
|
2024-07-23 16:41:52 +02:00
|
|
|
|
2024-07-24 16:02:19 +02:00
|
|
|
/* Check for XDG activation token, 'xdgtoken=xyz' */
|
2024-07-23 16:41:52 +02:00
|
|
|
else if (len > 9 && memcmp(line, "xdgtoken=", 9) == 0) {
|
2024-07-23 09:33:18 +02:00
|
|
|
notif->xdg_token = xstrndup(&line[9], len - 9);
|
|
|
|
|
LOG_DBG("XDG token: \"%s\"", notif->xdg_token);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
left -= len + (eol != NULL ? 1 : 0);
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 18:48:45 +02:00
|
|
|
if (left > 0)
|
2024-07-23 15:29:08 +02:00
|
|
|
memmove(notif->stdout_data, data, left);
|
2024-07-23 18:48:45 +02:00
|
|
|
|
|
|
|
|
notif->stdout_sz = left;
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
fdm_notify_stdout(struct fdm *fdm, int fd, int events, void *data)
|
|
|
|
|
{
|
|
|
|
|
const struct terminal *term = data;
|
|
|
|
|
struct notification *notif = NULL;
|
|
|
|
|
|
|
|
|
|
/* Find notification */
|
2024-07-23 11:53:30 +02:00
|
|
|
tll_foreach(term->active_notifications, it) {
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
if (it->item.stdout_fd == fd) {
|
|
|
|
|
notif = &it->item;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (events & EPOLLIN) {
|
|
|
|
|
char buf[512];
|
|
|
|
|
ssize_t count = read(fd, buf, sizeof(buf) - 1);
|
|
|
|
|
|
|
|
|
|
if (count < 0) {
|
|
|
|
|
if (errno == EINTR)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
LOG_ERRNO("failed to read notification activation token");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 09:33:18 +02:00
|
|
|
if (count > 0 && notif != NULL) {
|
2024-07-23 09:42:14 +02:00
|
|
|
if (notif->stdout_data == NULL) {
|
2024-07-23 09:33:18 +02:00
|
|
|
xassert(notif->stdout_sz == 0);
|
2024-07-23 09:42:14 +02:00
|
|
|
notif->stdout_data = xmemdup(buf, count);
|
2024-07-23 09:33:18 +02:00
|
|
|
} else {
|
2024-07-23 09:42:14 +02:00
|
|
|
notif->stdout_data = xrealloc(notif->stdout_data, notif->stdout_sz + count);
|
|
|
|
|
memcpy(¬if->stdout_data[notif->stdout_sz], buf, count);
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
}
|
2024-07-23 09:33:18 +02:00
|
|
|
|
|
|
|
|
notif->stdout_sz += count;
|
|
|
|
|
consume_stdout(notif, false);
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (events & EPOLLHUP) {
|
|
|
|
|
fdm_del(fdm, fd);
|
2024-07-23 09:33:18 +02:00
|
|
|
if (notif != NULL) {
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
notif->stdout_fd = -1;
|
2024-07-23 09:33:18 +02:00
|
|
|
consume_stdout(notif, true);
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
notif_done(struct reaper *reaper, pid_t pid, int status, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct terminal *term = data;
|
|
|
|
|
|
2024-07-23 11:53:30 +02:00
|
|
|
tll_foreach(term->active_notifications, it) {
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
struct notification *notif = &it->item;
|
|
|
|
|
if (notif->pid != pid)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
LOG_DBG("notification %s dismissed", notif->id);
|
|
|
|
|
|
2024-07-23 16:41:52 +02:00
|
|
|
if (notif->activated && notif->focus) {
|
|
|
|
|
LOG_DBG("focus window on notification activation: \"%s\"",
|
|
|
|
|
notif->xdg_token);
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
wayl_activate(term->wl, term->window, notif->xdg_token);
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 16:41:52 +02:00
|
|
|
if (notif->activated && notif->report) {
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
xassert(notif->id != NULL);
|
|
|
|
|
|
|
|
|
|
LOG_DBG("sending notification report to client");
|
2020-12-10 18:06:24 +01:00
|
|
|
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
char reply[5 + strlen(notif->id) + 1 + 2 + 1];
|
|
|
|
|
int n = xsnprintf(
|
|
|
|
|
reply, sizeof(reply), "\033]99;%s;\033\\", notif->id);
|
|
|
|
|
term_to_slave(term, reply, n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
notify_free(term, notif);
|
2024-07-23 11:53:30 +02:00
|
|
|
tll_remove(term->active_notifications, it);
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2024-07-23 11:53:30 +02:00
|
|
|
notify_notify(struct terminal *term, struct notification *notif)
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
{
|
|
|
|
|
xassert(notif->xdg_token == NULL);
|
|
|
|
|
xassert(notif->pid == 0);
|
2024-07-23 11:53:30 +02:00
|
|
|
xassert(notif->stdout_fd <= 0);
|
2024-07-23 09:42:14 +02:00
|
|
|
xassert(notif->stdout_data == NULL);
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
|
|
|
|
|
notif->pid = -1;
|
|
|
|
|
notif->stdout_fd = -1;
|
|
|
|
|
|
|
|
|
|
/* Use body as title, if title is unset */
|
|
|
|
|
const char *title = notif->title != NULL ? notif->title : notif->body;
|
|
|
|
|
const char *body = notif->title != NULL && notif->body != NULL ? notif->body : "";
|
|
|
|
|
|
|
|
|
|
/* Icon: use symbolic name from notification, if present,
|
|
|
|
|
otherwise fallback to the application ID */
|
2024-07-23 11:29:05 +02:00
|
|
|
const char *icon_name_or_path = term->app_id != NULL
|
|
|
|
|
? term->app_id
|
|
|
|
|
: term->conf->app_id;
|
|
|
|
|
|
|
|
|
|
if (notif->icon_id != NULL) {
|
|
|
|
|
for (size_t i = 0; i < ALEN(term->notification_icons); i++) {
|
|
|
|
|
const struct notification_icon *icon = &term->notification_icons[i];
|
|
|
|
|
|
2024-07-24 16:04:14 +02:00
|
|
|
if (icon->id != NULL && streq(icon->id, notif->icon_id)) {
|
2024-07-23 11:29:05 +02:00
|
|
|
icon_name_or_path = icon->symbolic_name != NULL
|
|
|
|
|
? icon->symbolic_name
|
2024-07-24 15:59:52 +02:00
|
|
|
: icon->tmp_file_name;
|
2024-07-23 11:29:05 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-23 15:30:01 +02:00
|
|
|
} else if (notif->icon_symbolic_name != NULL) {
|
|
|
|
|
icon_name_or_path = notif->icon_symbolic_name;
|
2024-07-23 11:29:05 +02:00
|
|
|
}
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
|
2024-07-23 11:53:30 +02:00
|
|
|
bool track_notification = notif->focus || notif->report;
|
|
|
|
|
|
2024-07-23 12:12:50 +02:00
|
|
|
LOG_DBG("notify: title=\"%s\", body=\"%s\", icon=\"%s\" (tracking: %s)",
|
|
|
|
|
title, body, icon_name_or_path, track_notification ? "yes" : "no");
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
|
|
|
|
|
xassert(title != NULL);
|
|
|
|
|
if (title == NULL)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if ((term->conf->desktop_notifications.inhibit_when_focused ||
|
|
|
|
|
notif->when != NOTIFY_ALWAYS)
|
osc/notify: add support for OSC-99, kitty desktop notifications
This adds limited support for OSC-99, kitty desktop notifications[^1]. We
support everything defined by the "protocol", except:
* 'a': action to perform on notification activation. Since we don't
trigger the notification ourselves (over D-Bus), we don't know a)
which ID the notification got, or b) when it is clicked.
* ... and that's it. Everything else is supported
To be explicit, we *do* support:
* Chunked notifications (d=0|1), allowing the application to append
data to a notification in chunks, before it's finally displayed.
* Plain UTF-8, or base64-encoded UTF-8 payload (e=0|1).
* Notification identifier (i=xyz).
* Payload type (p=title|body).
* When to honor the notification (o=always|unfocused|invisible), with
the following quirks:
- we don't know when the window is invisible, thus it's treated as
'unfocused'.
- the foot option 'notify-focus-inhibit' overrides 'always'
* Urgency (u=0|1|2)
[^1]: https://sw.kovidgoyal.net/kitty/desktop-notifications/
2024-07-19 15:04:28 +02:00
|
|
|
&& term->kbd_focus)
|
|
|
|
|
{
|
2024-02-06 12:36:45 +01:00
|
|
|
/* No notifications while we're focused */
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
return false;
|
2020-12-10 18:07:50 +01:00
|
|
|
}
|
|
|
|
|
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
if (term->conf->desktop_notifications.command.argv.args == NULL)
|
|
|
|
|
return false;
|
2020-12-10 18:06:24 +01:00
|
|
|
|
2021-01-31 14:40:27 +01:00
|
|
|
char **argv = NULL;
|
|
|
|
|
size_t argc = 0;
|
|
|
|
|
|
osc/notify: add support for OSC-99, kitty desktop notifications
This adds limited support for OSC-99, kitty desktop notifications[^1]. We
support everything defined by the "protocol", except:
* 'a': action to perform on notification activation. Since we don't
trigger the notification ourselves (over D-Bus), we don't know a)
which ID the notification got, or b) when it is clicked.
* ... and that's it. Everything else is supported
To be explicit, we *do* support:
* Chunked notifications (d=0|1), allowing the application to append
data to a notification in chunks, before it's finally displayed.
* Plain UTF-8, or base64-encoded UTF-8 payload (e=0|1).
* Notification identifier (i=xyz).
* Payload type (p=title|body).
* When to honor the notification (o=always|unfocused|invisible), with
the following quirks:
- we don't know when the window is invisible, thus it's treated as
'unfocused'.
- the foot option 'notify-focus-inhibit' overrides 'always'
* Urgency (u=0|1|2)
[^1]: https://sw.kovidgoyal.net/kitty/desktop-notifications/
2024-07-19 15:04:28 +02:00
|
|
|
const char *urgency_str =
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
notif->urgency == NOTIFY_URGENCY_LOW
|
osc/notify: add support for OSC-99, kitty desktop notifications
This adds limited support for OSC-99, kitty desktop notifications[^1]. We
support everything defined by the "protocol", except:
* 'a': action to perform on notification activation. Since we don't
trigger the notification ourselves (over D-Bus), we don't know a)
which ID the notification got, or b) when it is clicked.
* ... and that's it. Everything else is supported
To be explicit, we *do* support:
* Chunked notifications (d=0|1), allowing the application to append
data to a notification in chunks, before it's finally displayed.
* Plain UTF-8, or base64-encoded UTF-8 payload (e=0|1).
* Notification identifier (i=xyz).
* Payload type (p=title|body).
* When to honor the notification (o=always|unfocused|invisible), with
the following quirks:
- we don't know when the window is invisible, thus it's treated as
'unfocused'.
- the foot option 'notify-focus-inhibit' overrides 'always'
* Urgency (u=0|1|2)
[^1]: https://sw.kovidgoyal.net/kitty/desktop-notifications/
2024-07-19 15:04:28 +02:00
|
|
|
? "low"
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
: notif->urgency == NOTIFY_URGENCY_NORMAL
|
osc/notify: add support for OSC-99, kitty desktop notifications
This adds limited support for OSC-99, kitty desktop notifications[^1]. We
support everything defined by the "protocol", except:
* 'a': action to perform on notification activation. Since we don't
trigger the notification ourselves (over D-Bus), we don't know a)
which ID the notification got, or b) when it is clicked.
* ... and that's it. Everything else is supported
To be explicit, we *do* support:
* Chunked notifications (d=0|1), allowing the application to append
data to a notification in chunks, before it's finally displayed.
* Plain UTF-8, or base64-encoded UTF-8 payload (e=0|1).
* Notification identifier (i=xyz).
* Payload type (p=title|body).
* When to honor the notification (o=always|unfocused|invisible), with
the following quirks:
- we don't know when the window is invisible, thus it's treated as
'unfocused'.
- the foot option 'notify-focus-inhibit' overrides 'always'
* Urgency (u=0|1|2)
[^1]: https://sw.kovidgoyal.net/kitty/desktop-notifications/
2024-07-19 15:04:28 +02:00
|
|
|
? "normal" : "critical";
|
|
|
|
|
|
2021-01-31 14:40:27 +01:00
|
|
|
if (!spawn_expand_template(
|
2024-07-23 19:08:21 +02:00
|
|
|
&term->conf->desktop_notifications.command, 8,
|
2024-07-23 16:41:52 +02:00
|
|
|
(const char *[]){
|
2024-07-23 19:08:21 +02:00
|
|
|
"app-id", "window-title", "icon", "title", "body", "urgency", "action-name", "action-label"},
|
2024-07-23 16:41:52 +02:00
|
|
|
(const char *[]){
|
|
|
|
|
term->app_id ? term->app_id : term->conf->app_id,
|
|
|
|
|
term->window_title, icon_name_or_path, title, body, urgency_str,
|
2024-07-23 19:08:21 +02:00
|
|
|
"default", "Click to activate"},
|
2024-07-23 16:41:52 +02:00
|
|
|
&argc, &argv))
|
2021-01-31 14:40:27 +01:00
|
|
|
{
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
return false;
|
2020-12-10 18:06:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_DBG("notify command:");
|
2021-01-31 14:40:27 +01:00
|
|
|
for (size_t i = 0; i < argc; i++)
|
2020-12-10 18:06:24 +01:00
|
|
|
LOG_DBG(" argv[%zu] = \"%s\"", i, argv[i]);
|
|
|
|
|
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
int stdout_fds[2] = {-1, -1};
|
2024-07-23 11:53:30 +02:00
|
|
|
if (track_notification) {
|
|
|
|
|
if (pipe2(stdout_fds, O_CLOEXEC | O_NONBLOCK) < 0) {
|
|
|
|
|
LOG_WARN("failed to create stdout pipe");
|
|
|
|
|
track_notification = false;
|
|
|
|
|
/* Non-fatal */
|
|
|
|
|
} else {
|
|
|
|
|
tll_push_back(term->active_notifications, *notif);
|
|
|
|
|
notif->id = NULL;
|
|
|
|
|
notif->title = NULL;
|
|
|
|
|
notif->body = NULL;
|
|
|
|
|
notif->icon_id = NULL;
|
2024-07-23 19:08:21 +02:00
|
|
|
notif->icon_symbolic_name = NULL;
|
2024-07-23 11:53:30 +02:00
|
|
|
notif->icon_data = NULL;
|
|
|
|
|
notif->icon_data_sz = 0;
|
|
|
|
|
notif = &tll_back(term->active_notifications);
|
|
|
|
|
}
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 11:53:30 +02:00
|
|
|
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
if (stdout_fds[0] >= 0) {
|
|
|
|
|
fdm_add(term->fdm, stdout_fds[0], EPOLLIN,
|
|
|
|
|
&fdm_notify_stdout, (void *)term);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-10 18:06:24 +01:00
|
|
|
/* Redirect stdin to /dev/null, but ignore failure to open */
|
|
|
|
|
int devnull = open("/dev/null", O_RDONLY);
|
2024-07-23 06:57:30 +02:00
|
|
|
pid_t pid = spawn(
|
|
|
|
|
term->reaper, NULL, argv, devnull, stdout_fds[1], -1,
|
2024-07-23 11:53:30 +02:00
|
|
|
track_notification ? ¬if_done : NULL, (void *)term, NULL);
|
2024-07-23 06:57:30 +02:00
|
|
|
|
|
|
|
|
if (stdout_fds[1] >= 0) {
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
/* Close write-end of stdout pipe */
|
|
|
|
|
close(stdout_fds[1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pid < 0 && stdout_fds[0] >= 0) {
|
|
|
|
|
/* Remove FDM callback if we failed to spawn */
|
|
|
|
|
fdm_del(term->fdm, stdout_fds[0]);
|
|
|
|
|
}
|
2020-12-10 18:06:24 +01:00
|
|
|
|
|
|
|
|
if (devnull >= 0)
|
|
|
|
|
close(devnull);
|
|
|
|
|
|
2021-01-31 14:40:27 +01:00
|
|
|
for (size_t i = 0; i < argc; i++)
|
2020-12-10 18:06:24 +01:00
|
|
|
free(argv[i]);
|
|
|
|
|
free(argv);
|
osc: kitty notifications: implement focus|report
This patch adds support for window focusing, and sending events back
to the client application when a notification is closed.
* Refactor notification related configuration options:
- add desktop-notifications sub-section
- deprecate 'notify' in favor of 'desktop-notifications.command'
- deprecate 'notify-focus-inhibit' in favor of
'desktop-notifications.inhibit-when-focused'
* Refactor: rename 'struct kitty_notification' to 'struct
notification'
* Pass a 'struct notification' to notify_notify(), instead of many
arguments.
* notify_notify() now registers a reaper callback. When the notifier
process has terminated, the notification is considered closed, and we
either try to focus (activate) the window, or send an event to the
client application, depending on the notification setting.
* For the window activation, we need an XDG activation token. For now,
assume *everything* written on stdout is part of the token.
* Refactor: remove much of the warnings from OSC-99; we don't
typically log anything when an OSC/CSI has invalid values.
* Add icon support to OSC-99. This isn't part of the upstream
spec. Foot's implementation:
- uses the 'I' parameter
- the value is expected to be a symbolic icon name
- a quick check for absolute paths is done, and such icon requests
are ignored.
* Added ${icon} to the 'desktop-notifications.command' template. Uses
the icon specified in the notification, or ${app-id} if not set.
2024-07-23 06:59:46 +02:00
|
|
|
|
|
|
|
|
notif->pid = pid;
|
|
|
|
|
notif->stdout_fd = stdout_fds[0];
|
|
|
|
|
return true;
|
2020-12-10 18:06:24 +01:00
|
|
|
}
|
2024-07-23 11:29:05 +02:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
add_icon(struct notification_icon *icon, const char *id, const char *symbolic_name,
|
|
|
|
|
const uint8_t *data, size_t data_sz)
|
|
|
|
|
{
|
|
|
|
|
icon->id = xstrdup(id);
|
|
|
|
|
icon->symbolic_name = symbolic_name != NULL ? xstrdup(symbolic_name) : NULL;
|
2024-07-24 15:59:52 +02:00
|
|
|
icon->tmp_file_name = NULL;
|
|
|
|
|
icon->tmp_file_fd = -1;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Dump in-line data to a temporary file. This allows us to pass
|
|
|
|
|
* the filename as a parameter to notification helpers
|
|
|
|
|
* (i.e. notify-send -i <path>).
|
|
|
|
|
*
|
|
|
|
|
* Optimization: since we always prefer (i.e. use) the symbolic
|
|
|
|
|
* name if present, there's no need to create a file on disk if we
|
|
|
|
|
* have a symbolic name.
|
|
|
|
|
*/
|
|
|
|
|
if (symbolic_name == NULL && data_sz > 0) {
|
2024-07-23 11:29:05 +02:00
|
|
|
char name[64] = "/tmp/foot-notification-icon-cache-XXXXXX";
|
2024-07-24 15:59:52 +02:00
|
|
|
int fd = mkostemp(name, O_CLOEXEC);
|
2024-07-23 11:29:05 +02:00
|
|
|
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
LOG_ERRNO("failed to create temporary file for icon cache");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 12:15:29 +02:00
|
|
|
if (write(fd, data, data_sz) != (ssize_t)data_sz) {
|
|
|
|
|
LOG_ERRNO("failed to write icon data to temporary file");
|
2024-07-24 15:59:52 +02:00
|
|
|
close(fd);
|
2024-07-23 12:15:29 +02:00
|
|
|
} else {
|
|
|
|
|
LOG_DBG("wrote icon data to %s", name);
|
2024-07-24 15:59:52 +02:00
|
|
|
icon->tmp_file_name = xstrdup(name);
|
|
|
|
|
icon->tmp_file_fd = fd;
|
2024-07-23 12:15:29 +02:00
|
|
|
}
|
2024-07-23 11:29:05 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 12:12:50 +02:00
|
|
|
LOG_DBG("added icon to cache: ID=%s: sym=%s, file=%s",
|
2024-07-24 15:59:52 +02:00
|
|
|
icon->id, icon->symbolic_name, icon->tmp_file_name);
|
2024-07-23 11:29:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
notify_icon_add(struct terminal *term, const char *id,
|
|
|
|
|
const char *symbolic_name, const uint8_t *data, size_t data_sz)
|
|
|
|
|
{
|
|
|
|
|
#if defined(_DEBUG)
|
|
|
|
|
for (size_t i = 0; i < ALEN(term->notification_icons); i++) {
|
|
|
|
|
struct notification_icon *icon = &term->notification_icons[i];
|
2024-07-24 16:04:14 +02:00
|
|
|
if (icon->id != NULL && streq(icon->id, id)) {
|
2024-07-23 11:29:05 +02:00
|
|
|
BUG("notification icon cache already contains \"%s\"", id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < ALEN(term->notification_icons); i++) {
|
|
|
|
|
struct notification_icon *icon = &term->notification_icons[i];
|
|
|
|
|
if (icon->id == NULL) {
|
|
|
|
|
add_icon(icon, id, symbolic_name, data, data_sz);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Cache full - throw out first entry, add new entry last */
|
|
|
|
|
notify_icon_free(&term->notification_icons[0]);
|
|
|
|
|
memmove(&term->notification_icons[0],
|
|
|
|
|
&term->notification_icons[1],
|
|
|
|
|
((ALEN(term->notification_icons) - 1) *
|
|
|
|
|
sizeof(term->notification_icons[0])));
|
|
|
|
|
|
|
|
|
|
add_icon(
|
|
|
|
|
&term->notification_icons[ALEN(term->notification_icons) - 1],
|
|
|
|
|
id, symbolic_name, data, data_sz);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
notify_icon_del(struct terminal *term, const char *id)
|
|
|
|
|
{
|
|
|
|
|
for (size_t i = 0; i < ALEN(term->notification_icons); i++) {
|
|
|
|
|
struct notification_icon *icon = &term->notification_icons[i];
|
|
|
|
|
|
2024-07-24 16:04:14 +02:00
|
|
|
if (icon->id == NULL || !streq(icon->id, id))
|
2024-07-23 11:29:05 +02:00
|
|
|
continue;
|
|
|
|
|
|
2024-07-23 12:12:50 +02:00
|
|
|
LOG_DBG("expelled %s from the notification icon cache", icon->id);
|
2024-07-23 11:29:05 +02:00
|
|
|
notify_icon_free(icon);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
notify_icon_free(struct notification_icon *icon)
|
|
|
|
|
{
|
2024-07-24 15:59:52 +02:00
|
|
|
if (icon->tmp_file_fd >= 0)
|
|
|
|
|
close(icon->tmp_file_fd);
|
|
|
|
|
if (icon->tmp_file_name != NULL)
|
|
|
|
|
unlink(icon->tmp_file_name);
|
2024-07-23 11:29:05 +02:00
|
|
|
|
|
|
|
|
free(icon->id);
|
|
|
|
|
free(icon->symbolic_name);
|
2024-07-24 15:59:52 +02:00
|
|
|
free(icon->tmp_file_name);
|
2024-07-23 11:29:05 +02:00
|
|
|
|
|
|
|
|
icon->id = NULL;
|
|
|
|
|
icon->symbolic_name = NULL;
|
2024-07-24 15:59:52 +02:00
|
|
|
icon->tmp_file_name = NULL;
|
|
|
|
|
icon->tmp_file_fd = -1;
|
2024-07-23 11:29:05 +02:00
|
|
|
}
|