Commit graph

6346 commits

Author SHA1 Message Date
Daniel Eklöf
a9e462d952
Remove a number of unused includes 2024-08-02 08:28:13 +02:00
Daniel Eklöf
09ab8c6c7c
notify: codespell: programatically -> programmatically 2024-08-02 08:25:29 +02:00
Daniel Eklöf
1a89538700
notify: codespell: notificaton -> notification 2024-08-02 08:24:03 +02:00
Daniel Eklöf
ebd8ad8937
doc: foot.ini: codespell: furhermore -> furthermore 2024-08-02 08:24:03 +02:00
Daniel Eklöf
ea2f0e7c3f
osc: kitty notifications: cleanup and update to latest version of spec
* Don't store a list of unfinished notifications. Use a single one. If
  the notification ID of the 'current' notification doesn't match the
  previous, unfinished one, the 'current' notification replaces the
  previous one, instead of updating it.

* Update xstrjoin() to take an optional delimiter (for example ','),
  and use that when joining categories and 'alive IDs'.

* Rename ${action-arg} to ${action-argument}

* Update handling of the 'n' parameter (symbolic icon name); the spec
  allows it to be used multiple times, and the terminal is supposed to
  pick the first one it can resolve. Foot can't resolve icons at all,
  neither can 'notify-send' or 'fyi' (which is what foot typically
  executes to display a notification); it's the notification daemon that
  resolves icons.

  The spec _could_ be interpreted to mean the terminal should lookup
  .desktop files, and use the value of the 'Icon' key from the first
  matching .desktop files. But foot doesn't read .desktop files, and I
  don't intend to implement XDG directory scanning and parsing of
  .desktop files just to figure out which icon to use.

  Instead, use a simple heuristics; use the *shortest* symbolic
  names. The idea is pretty simple: plain icon names are typically
  shorter than .desktop file IDs.
2024-08-02 08:07:13 +02:00
Daniel Eklöf
18b87b2e20
notify: don't forget terminating NULL when patching notify helper's argv 2024-07-31 18:33:24 +02:00
Daniel Eklöf
76ac910b11
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.
2024-07-31 16:22:17 +02:00
Daniel Eklöf
d87b81dd52
notify: disable debug logging 2024-07-30 17:31:15 +02:00
Daniel Eklöf
259a75e957
notify: remove debug assertion
(FD 0 _is_ valid, after all)
2024-07-30 17:24:48 +02:00
Daniel Eklöf
ba79bf1602
notify: ${icon}: don't fallback to app-id
* Revert --icon to ${app-id}
* Use --hint STRING:image-path:${icon} instead
* ${icon} no longer expands to ${app-id} if notification has no icon
2024-07-30 17:16:02 +02:00
Daniel Eklöf
0a5ba708e4
notify: don't close FD 0
This fixes a regression where closing a terminal instance, or hard- or
soft-resetting a terminal caused FD 0 to be closed.

This meant it became re-usable. Usually, by memfd_create() when
allocating a new surface buffer. So far nothing _really_ bad has
happened.

But what if FD 0 is now used by a memfd, and we close _another_
terminal instance?

This causes our memfd to be closed. And then, when e.g. trying to
scroll the terminal content: fallocate() fails with bad FD.
2024-07-30 16:33:19 +02:00
Daniel Eklöf
a3ad740251
readme: IRC: update link to point to the web interface 2024-07-27 08:48:32 +02:00
Daniel Eklöf
00ec2a8f09
readme: update mastodon link 2024-07-27 08:37:41 +02:00
Daniel Eklöf
9cf99ea4bf
notify: close notification by sending SIGINT to helper
If the user hasn't configured a custom 'desktop-notifications.close'
command, try to close the notification by sending SIGINT to the
notification helper.

This is best-effort:

* If there's no helper running, we do nothing (except warn)
* We don't verify, in any way, the notification is actually closed
* We don't send any other signals, under any circumstances. That is,
  no SIGTERM, no SIGKILL. Ever.
2024-07-26 16:28:47 +02:00
Daniel Eklöf
8f16fe54d3
pgo: add notify_close() stub 2024-07-25 19:31:27 +02:00
Daniel Eklöf
c4d9f8a8ff
osc: kitty notifications: implement the 'close' request
Add a new config option, desktop-notifications.close, defining what to
execute to close a notification. It has a single template parameter,
${id}, that is expanded to the external notification ID foot may have
picked up from the notification helper.

notify-send does not support closing notifications, and it appears
impossible to pass an *unsigned* integer as argument to gdbus. Hence
no default value for the new 'close' option.

Example:

    printf '\e]99;i=123;this is a notification\e\\'
    printf '\e]99;i=123:p=close;\e\\'
2024-07-25 19:24:28 +02:00
Daniel Eklöf
c797222930
osc: kitty notification: implement 'close' events
Application can now request to receive a 'close' event when the
notification is closed (but not necessarily activated), by adding
'c=1' to the notification request.
2024-07-25 18:47:23 +02:00
Daniel Eklöf
d53f0aea75
notify: rename 'report' -> 'report_activated' 2024-07-25 18:45:58 +02:00
Daniel Eklöf
0ce4ef6000
notify: kitty notifications: fix ID string in activation event
We forgot to prefix the notification ID with 'i='
2024-07-25 18:45:04 +02:00
Daniel Eklöf
a213e14ca3
Merge branch 'kitty-notifications' 2024-07-25 18:32:57 +02:00
Daniel Eklöf
a6bc9cafaf
osc+notify: strcmp() -> streq() 2024-07-24 16:04:14 +02:00
Daniel Eklöf
f56da385fe
notify: try to read the daemon assigned notification ID from stdout
And document the things we recognize in the notification helper's
stdout.
2024-07-24 16:02:19 +02:00
Daniel Eklöf
e271027c0c
config: notify-send: it's "action=label", not "action,label" 2024-07-24 16:01:42 +02:00
Daniel Eklöf
37ab3b1603
notify: don't create icon file on disk when we're not going to use it
We always prefer the symbolic name. Thus, there's no need to write raw
PNG data to disk if we have a symbolic name.

Furthermore, keep the file open until the cache entry is evicted.
2024-07-24 15:59:52 +02:00
Daniel Eklöf
24168ed86e
osc: kitty notifications: don't include '?' in the query reply
No need to say we support queries, in the query reply...
2024-07-24 15:58:19 +02:00
Daniel Eklöf
ecbec57a47
notify: split up the ${action} template parameter
Split it up into two, ${action-name} and ${action-label}.

Dunstify, for example, has a different syntax compared to notify-send:

notify-send: default=foobar
dunstify: default,foobar
2024-07-23 19:08:21 +02:00
Daniel Eklöf
d5c773a58b
notify: bug: always adjust amount of data left in stdout buffer 2024-07-23 18:48:45 +02:00
Daniel Eklöf
70b4638a75
osc: kitty notifications: implement query 2024-07-23 18:32:23 +02:00
Daniel Eklöf
511d4817d3
doc: foot.ini: desktop-notification: remove 'notification dismissal' 2024-07-23 16:52:18 +02:00
Daniel Eklöf
79832c16e2
notify: name the activation action 'default'
This is less unique, but also works better with notification daemons
that trigger the 'default' action when e.g. clicked.
2024-07-23 16:48:15 +02:00
Daniel Eklöf
045ead985c
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.
2024-07-23 16:41:52 +02:00
Daniel Eklöf
55a4e59ef9
notify: if there's a symbolic icon name, use it
even if there's no graphical ID set.

In other words, if there *is* a graphical ID, use the icon cache. Only
if there is no graphical ID in the notification request do we fallback
to the symbolic name. This means no icon will be displayed if there's
no matching icon in the cache.

Some examples. You can either pre-load the cache (with inline PNG
data, a symbolic name, or both):

    printf '\e]99;g=123:n=firefox:p=icon:e=1;<PNG data>\e\\'
    printf '\e]99;g=123;this is a notification\e\\'

or

    printf '\e]99;n=firefox;this is a notification\e\\'
2024-07-23 15:30:01 +02:00
Daniel Eklöf
fabfef9c82
notify: consume_stdout(): fix ASAN warning
This is an ASAN false positive; size is always 0 when we're passing a
NULL pointer.

Still, the warning is easy to avoid, so let's do that to reduce the
noise level.
2024-07-23 15:29:08 +02:00
Daniel Eklöf
e59efb1233
osc: remove unused includes 2024-07-23 15:28:47 +02:00
Daniel Eklöf
50efd9726d
pgo: updated stubs for notification functions 2024-07-23 12:15:50 +02:00
Daniel Eklöf
d0a5425155
notify: add_icon(): check return value of write() 2024-07-23 12:15:29 +02:00
Daniel Eklöf
9814cf5779
notify: clean up logging messages 2024-07-23 12:12:50 +02:00
Daniel Eklöf
efa5b9cea6
osc: cleanup 2024-07-23 12:12:38 +02:00
Daniel Eklöf
b3108e1ad2
notify: separate active notifications from unfinished kitty notifications
This fixes an issue where it wasn't possible to trigger multiple
notifications with the same kitty notification ID. This is something
that works in kitty, and there's no reason why it shouldn't work.

The issue was that we track stdout, and the notification helper's PID
in the notification struct. Thus, when a notification is being
displayed, we can't re-use the same notification struct instance for
another notification.

This patch fixes this by adding a new notification list,
'active_notifications'. Whenever we detect that we need to track the
helper (notification want's to either focus the window on activation,
or send an event to the application), we add a copy of the
notification to the 'active' list.

The notification can then be removed from the 'kitty' list, allowing
kitty notifications to re-use the same ID over and over again, even if
old notifications are still being displayed.
2024-07-23 11:53:30 +02:00
Daniel Eklöf
ccb184ae64
osc: kitty notifications: updated support for icons
This implements the suggested protocol discussed in
https://github.com/kovidgoyal/kitty/issues/7657.

Icons are handled by loading a cache. Both in-band PNG data, and
symbolic names are allowed.

Applications use a graphical ID to reference the icon both when
loading the cache, and when showing a notification.

* 'g' is the graphical ID
* 'n' is optional, and assigns a symbolic name to the icon
* 'p=icon' - the payload is icon PNG data. It needs to be base64
  encoded, but this is *not* implied. I.e. the application *must* use
  e=1 explicitly.

To load an icon (in-band PNG data):

    printf '\e]99;g=123:p=icon;<base64-encoded-png-data>\e\\'

or (symbolic name)

    printf '\e]99;g=123:n=firefox:p=icon;\e\\'

Of course, we can combine the two, assigning *both* a symbolic
name, *and* PNG data:

    printf '\e]99;g=123:n=firefox:p=icon;<base64-encoded-png>\e\\'

Then, to use the icon in a notification:

    printf '\e]99;g=123;this is a notification\e\\'

Foot also allows a *symbolic* icon to be defined and used at the same
time:

    printf '\e]99;g=123:n=firefox;this is a notification\e\\'

This obviously won't work with PNG data, since it uses the payload
portion of the escape sequence.
2024-07-23 11:29:05 +02:00
Daniel Eklöf
c7cffea9ee
notify: stdout is a bad name 2024-07-23 09:42:14 +02:00
Daniel Eklöf
b319618af1
notify: XDG token is now expected to be prefixed with xdgtoken=
This patch modifies our stdout reader to consume input as we go,
instead of all at once when stdout is closed. This will make it easier
to add support for reading e.g. the daemon assigned notification ID in
the future, and also ensures we see the XDG activation token "as soon
as possible".

Furthermore, to be more future proof, require the XDG activation token
to be prefixed with 'xdgtoken=', and ignore other lines.

Thus, instead of treating *all* of stdout as the XDG activation token,
parse stdout line-by-line, and ignore everything that does not begin
with 'xdgtoken='. Everything (on that line) following 'xdgtoken=' is
treated as the activation token.
2024-07-23 09:33:18 +02:00
Daniel Eklöf
e52d6e3fb8
osc: kitty notifications: use xstrjoin() instead of xasprintf() 2024-07-23 08:05:19 +02:00
Daniel Eklöf
e88ec86c93
pgo: update notify_notify() prototype, add notify_free() 2024-07-23 07:43:56 +02:00
Daniel Eklöf
7268ee9078
pgo: update spawn() prototype 2024-07-23 07:43:42 +02:00
Daniel Eklöf
0209458cc0
changelog: new desktop-notifications config section 2024-07-23 07:17:21 +02:00
Daniel Eklöf
5905ea0d84
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 07:17:21 +02:00
Daniel Eklöf
12152a8ae4
unicode-mode: disable debug logging 2024-07-23 07:17:21 +02:00
Daniel Eklöf
69f56b86b7
wayland: add wayl_activate()
wayl_activate() takes an XDG activation token and does an XDG
activation request.
2024-07-23 07:17:21 +02:00
Daniel Eklöf
a42f990818
spawn: add optional reaper callback, return pid_t
This will allow spawn() callers to do things when the spawned process
has terminated.
2024-07-23 07:17:21 +02:00