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.
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.
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.
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/
When changing part of the color palette, through either OSC-4, or
OSC-10 and OSC-11 (and the corresponding reset OSCs: 104, 110 and
111), only dirty affected cells.
We've always done this, but only for OSC-4.
This patch breaks out that logic, and extends it to handle default
fg/bg too.
It also fixes a bug where cells with colored underlines were not
dirtied if the underline was the only part of the cell that was
affected by a OSC-4 change.
10/11/17/19 were already merged, so this patch just stops special
casing 12 (cursor color).
In preparation for XTPUSHCOLORS/XTPOPCOLORS, the cursor colors are
moved from their own struct, into the 'colors' struct.
Also fix a bug where OSC 17/19 queries returned OSC-11 data.
This fixes an issue where other data (such as replies to other
requests) being interleaved with the OSC-52 reply.
The patch piggy backs on the already existing mechanism for handling
regular pastes, where other data is queued up until the paste is done.
There's one corner case that won't work; if the user *just* did a
normal paste (i.e. at virtually the same time the application
requested OSC-52 data), the OSC-52 request will return an empty reply.
Likewise, if there are multiple OSC-52 requests at the same time, only
the first will return data.
Closes#1734
This adds support for a new OSC escape sequence: OSC 176, that lets
terminal programs tell the terminal the name of the app that is
running. foot then sets the app ID of the toplevel to that ID,
which lets the compositor know which app is running, and typically
sets the appropriate icon, window grouping, ...
See: https://gist.github.com/delthas/d451e2cc1573bb2364839849c7117239
When background alpha is changed at runtime (using OSC-11), we (may)
have to update the opaque hint we send to the compositor.
We must also update the subpixel mode used when rendering font
glyphs.
Why?
When the window is fully opaque, we use wl_surface_set_opaque_region()
on the entire surface, to hint to the compositor that it doesn’t have
to blend the window content with whatever is behind the
window. Obviously, if alpha is changed from opaque, to transparent (or
semi-transparent), that hint must be removed.
Sub-pixel mode is harder to explain, but in short, we can’t do
subpixel hinting with a (semi-)transparent background. Thus, similar
to the opaque hint, subpixel antialiasing must be enabled/disabled
when background alpha is changed.
This patch adds support for the OSC-133;A sequence, introduced by
FinalTerm and implemented by iTerm2, Kitty and more. See
https://iterm2.com/documentation-one-page.html#documentation-escape-codes.html.
The shell emits the OSC just before printing the prompt. This lets the
terminal know where, in the scrollback, there are prompts.
We implement this using a simple boolean in the row struct ("this row
has a prompt"). The prompt marker must be reflowed along with the text
on window resizes.
In an ideal world, erasing, or overwriting the cell where the OSC was
emitted, would remove the prompt mark. Since we don't store this
information in the cell struct, we can't do that. The best we can do
is reset it in erase_line(). This works well enough in the "normal"
screen, when used with a "normal" shell. It doesn't really work in
fullscreen apps, on the alt screen. But that doesn't matter since we
don't support jumping between prompts on the alt screen anyway.
To be able to jump between prompts, two new key bindings have been
added: prompt-prev and prompt-next, bound to ctrl+shift+z and
ctrl+shift+x respectively.
prompt-prev will jump to the previous, not currently visible, prompt,
by moving the viewport, ensuring the prompt is at the top of the
screen.
prompt-next jumps to the next prompt, visible or not. Again, by moving
the viewport to ensure the prompt is at the top of the screen. If
we're at the bottom of the scrollback, the viewport is instead moved
as far down as possible.
Closes#30
Checking for specific strings of length 0 or 1 can be done with e.g.:
if (str[0] == '\0') {...}
if (str[0] == '?' && str[1] == '\0') {...}
Doing it this way instead of using strlen(3) means we avoid the
function call overhead and also avoid scanning through more of the
string than is neceessary.
A compiler could perhaps optimize away calls to strlen(3) when the
result is compared to a small constant, but GCC 11.2 only seems to
actually do this[1] for lengths of 0.
[1]: https://godbolt.org/z/qxoW8qqW6
With fixed increments of 128 bytes, an OSC 52 copy operation could end
up doing thousands or tens of thousands of realloc(3) calls just to
copy a few MB.
When using indexed colors (i.e. SGR 30/40/90/100), store the index
into the cell’s fg/bg attributes, not the actual color value.
This has a couple of consequences:
Color table lookup is now done when rendering. This means a rendered
cell will always reflect the *current* color table, not the color
table that was in use when the cell was printed to.
This simplifies the OSC-4/104 logic, since we no longer need to update
the grid - we just have to damage it to trigger rendering.
Furthermore, this change simplifies the VT parsing, since we no longer
need to do any memory loads (except loading the SGR parameter values),
only writes.
OSC 4/104 changes the 256-color palette. We also run a pass over the
visible cells, and update their colors.
This was previously done by comparing the actual color of the cell,
with the “old” color in the palette. If they matched, the cell was
updated.
This meant that cells with an RGB color (i.e. not a palette based
color) was also updated, _if_ its color matched the palette color.
Now that each cell tracks its color *source*, we can ignore all
non-palette based cells.
Note that this still isn’t perfect: if the palette contains multiple
entries with the same color, we’ll end up updating the “wrong” cells.
Closes#678
Each cell now tracks it’s current color source:
* default fg/bg
* base16 fg/bg (maps to *both* the regular and bright colors)
* base256 fg/bg
* RGB
Note that we don’t have enough bits to separate the regular from the
bright colors. These _shouldn’t_ be the same, so we ought to be
fine...
Doing so means the next OSC-8 URL emitted by the client application,
with the same ID, will get a *new* id internally.
Instead, hash the string and use that as ID.
Applications can assign an ID to the URL. This is used to associate
the parts of a split up URL with each other:
╔═ file1 ════╗
║ ╔═ file2 ═══╗
║http://exa║Lorem ipsum║
║le.com ║ dolor sit ║
║ ║amet, conse║
╚══════════║ctetur adip║
╚═══════════╝
In the example above, ‘http://exa’ and ‘le.com’ are part of the same
URL, but by necessity split up into two OSC-8 URLs.
If the application sets the same ID for those two OSC-8 URLs, the
terminal can ensure they are handled as one.