Commit graph

6307 commits

Author SHA1 Message Date
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
Daniel Eklöf
57af75f988
osc: kitty notifications: use body as title, if no title is set
This mirrors kitty's behavior; if the user didn't set a title, but did
set the body/text, use the body as title instead.
2024-07-23 07:17:21 +02:00
Daniel Eklöf
b0bf8ca5f7
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-23 07:17:21 +02:00
Daniel Eklöf
45c7cd3f74
input: allow mouse selections to start inside the margins
Before this, margins were special cased:

* The mouse cursor was always a pointer, and never an I-beam (thus
  signaling selections cannot be made).
* The internal mouse coords where set to -1 when the cursor was inside
  the margins, causing:
    - text selections from being made
    - mouse events being passed to mouse grabbing applications

In particular, even with a one-pixel margin, making selections was
unnecessarily hard in e.g. fullscreen mode, where you'd expect to be
able to throw the cursor into the corner of the screen and then start
a selection.

With this patch, the cursor is treated as if it was in the first/last
column/row, when inside the margin(s).

An unintended side-effect of this, initially, was that auto-scrolling
selections where way too easy to trigger, since part of its logic is
checking if the cursor is inside the margins.

That problem has been reduced by two things:

* auto-scrolling does not occur unless a selection has been
  started. That is, just holding down the mouse in the margins and
  moving up/down doesn't cause scrolling. You have to first select at
  least one cell in the visible viewport.
* A selection isn't fully started (i.e. a cell is actually selected)
  unless the cursor is inside the actual grid, and *not* in the
  margins.

What does the last point mean? We now allow a selection to be
_started_ when clicking in the margin. What this means internally is
we set a start coordinate for a selection, but *not* and end
coordinate. At this point, we don't have an actual selection. Nothing
is selected, and no cells are highlighted, graphically.

This happens when we set an end coordinate. Without the last bullet
point, that would happen as soon as the cursor was _moved_, even if
still inside the margins. Now, we require the cursor to leave the
margins and touch an actual cell before we set an end coordinate.

Closes #1702
2024-07-19 06:55:28 +02:00
Daniel Eklöf
38461eef6f
csi: in-band window resize notifications, private mode 2048
This implements
https://gist.github.com/rockorager/e695fb2924d36b2bcf1fff4a3704bd83,
in-band window resize notifications.

When user enables private mode 2048 (in-band resize
notifications), *always* send current size, even if the mode is
already active.

This ensures applications can rely on getting a reply from the
terminal.
2024-07-19 06:54:32 +02:00
Daniel Eklöf
e11a4ab6af
wayland: #ifdef guard code related to wl_shm_release() 2024-07-18 14:27:40 +02:00
Daniel Eklöf
87aac8708d
foot.info: add setal (colored underlines)
This is an alias to Setulc. Upstream (ncurses) terminfo uses setal
instead of Setulc :/
2024-07-18 09:04:39 +02:00
Daniel Eklöf
065eb05e3e
meson/pgo: fix PGO build errors with recent meson(?) versions
The back-reference to 'tokenize.c' in the parent directory causes PGO
build failures, where gcc can't find the PGO data. Likely due to
path/naming issues caused by meson's generated build directories.
2024-07-18 09:02:42 +02:00
Daniel Eklöf
36e4435bbf
log: respect the NO_COLOR environment variable
http://no-color.org/

Closes #1771
2024-07-18 08:44:30 +02:00
Daniel Eklöf
4f25e1ba9f
wayland: use wl_shm v2 if available 2024-07-18 08:23:25 +02:00
abs3nt
1fd4076082
themes: catppuccin: replace with updated flavors
Pulled from https://github.com/catppuccin/foot
2024-07-18 08:21:14 +02:00
Daniel Eklöf
1136108c97
input: don't map wheel events to BTN_{BACK,FORWARD}
BTN_BACK and BTN_FORWARD are separate buttons. The scroll wheel don't
have any button mappings in libinput/wayland, so make up our own
defines.

This allows us to map them in mouse bindings.

Also expose BTN_WHEEL_{LEFT,RIGHT}. These were already defined, and
used, internally, to handle wheel tilt events. With this, they can
also be used in mouse bindings.

Finally, fix encoding used for BTN_{BACK,FORWARD} when sending mouse
button events to the client application. Before this, they were mapped
to buttons 4/5. But, button 4/5 are for the scroll wheel, and as
mentioned above, BTN_{BACK,FORWARD} are not the same as scroll wheel
"buttons".

Closes #1763
2024-07-13 10:41:10 +02:00
Daniel Eklöf
15c0078c2d
changelog: remove entry for change that hasn't yet been merged 2024-07-13 10:40:37 +02:00
Daniel Eklöf
56556e5f23
render: hollow-cursor: use correct cursor color 2024-07-13 10:37:21 +02:00
Daniel Eklöf
c46c124363
render: cursor: use default fg/bg if cell fg/bg are the same
When deciding which colors to use for the cursor, and the cursor text
and background colors are the same, use the default fg/bg instead.

Closes #1761
2024-07-13 10:30:23 +02:00
Nicolas Kolling Ribas
f066fe47f0 themes: add nvim-dark and nvim-light themes
Both based on the new "Nvim branded" default color scheme in
Neovim 0.10.
2024-07-09 01:22:37 -03:00
Daniel Eklöf
85b2fb1e32
doc: foot.ini: line-height: add warning about runtime font size changes 2024-07-07 16:31:40 +02:00
Daniel Eklöf
22c8637610
osc: extend damage-cells-by-color to default fg/bg as well
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.
2024-07-03 10:53:33 +02:00
Daniel Eklöf
e5ed387426
Merge branch 'color-stack'
Closes #856
2024-07-03 09:59:56 +02:00
Daniel Eklöf
dd58dad15a
csi: redraw margins after restoring the palette 2024-07-03 09:47:51 +02:00
Daniel Eklöf
d440d5aa2c
osc: 10/11/12/17/19: don't apply overly much damage 2024-07-03 09:47:51 +02:00
Daniel Eklöf
5edb0deffe
changelog: XTPUSHCOLORS, XTPOPCOLORS and XTREPORTCOLORS 2024-07-03 09:47:49 +02:00
Daniel Eklöf
bebd5ce415
doc: foot-ctlseq: document XTPUSHCOLORS, XTPOPCOLORS and XTREPORTCOLORS 2024-07-03 09:47:30 +02:00
Daniel Eklöf
dd6fc99ae1
csi: implement XTPUSHCOLORS+XTPOPCOLORS+XTREPORTCOLORS
The documentation of these sequences are vague and lacking, as is
often the case with XTerm invented control sequences.

I've tried to replicate what XTerm does (as of xterm-392).

The stack represents *stashed/stored* palettes. The currently active
palette is *not* stored on the stack.

The stack is dynamically allocated, and starts out with zero elements.

Now, XTerm has a somewhat weird definition of "pushing" and "popping"
in this context, and the documentation is somewhat misleading.

What a push does is this: it stores the current palette to the stack
at the specified slot. If the specified slot number (Pm) is 0, the
slot used is the current slot index incremented by 1.

The "current" slot index is then set to the specified slot (which is
current slot + 1 if Pm == 0).

Thus, "push" (i.e. when Pm == 0 is used) means store to the "next"
slot. This is true even if the current slot index points into the
middle of stack.

Pop works in a similar way. The palette is restored from the specified
slot index. If the specified slot number is 0, we use the current slot
index.

The "current" slot index is then set to the specified slot -
1 (current slot - 1 if Pm == 0).

XTREPORTCOLORS return the current slot index, and the number of
palettes stored on the stack, on the format

    CSI ? <slot index> ; <palette count> # Q

When XTPUSHCOLORS grows the stack with more than one element (i.e. via
a 'CSI N # P' sequence), make sure *all* new slots are initialized (to
the current color palette). This avoids uninitialized slots, that
could then be popped with XTPOPCOLORS.

Closes #856
2024-07-03 09:47:30 +02:00
Daniel Eklöf
5d4a002413
osc: merge OSC 10/11/12/17/19 handling
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.
2024-07-03 09:47:30 +02:00
Daniel Eklöf
e708d19ea3
csi: implement SGR 21, double underlines 2024-07-03 09:46:41 +02:00
Craig Barnes
970b95509c render: fix "maybe-uninitialized" error in draw_styled_underline()
Reproducer:

    CFLAGS='-Og -g' meson setup --buildtype=debug bld
    ninja -C bld

Error message:

    ../render.c: In function ‘draw_styled_underline’:
    ../render.c:490:19: error: ‘y_ofs’ may be used uninitialized
    [-Werror=maybe-uninitialized]
      490 |         const int top = y + y_ofs;
          |                   ^~~
    ../render.c:405:9: note: ‘y_ofs’ was declared here
      405 |     int y_ofs;
          |         ^~~~~
2024-07-03 06:55:01 +01:00
Craig Barnes
ab4b3cbd34 doc: foot-ctlseq: add missing "E" to DECRQSS sequence
This omission seems to have been a typo in commit add530e66d.
2024-07-03 06:09:59 +01:00
Craig Barnes
674a535fc3 Rename various uses of "curly" in the source code with "underline"
Since "curly" could make it seem as if all underline styles are curled
(to people unfamiliar with the codebase), whereas in reality only 1 is.
2024-07-01 20:00:16 +01:00
Daniel Eklöf
64e7f25124
dcs: DECRQSS: styled+colored underlines 2024-07-01 16:25:45 +02:00
Daniel Eklöf
7341ba5ee3
render: cursor color: remove assertion that both cursor fg/bg be set
Before this patch, we asserted both the cursor foreground, and
background colors had been set. This is true in most cases; the config
system enforces it.

It is however possible to set only the cursor background color, while
leaving the foreground (text) color unset:

* Use a foot config that does *not* configure the cursor colors. This
  means foot will invert the default fg/bg colors when rendering the
  cursor.
* Override the cursor color using an OSC-12 sequence. OSC-12 only sets
  the background color of the cursor, and there is no other OSC sequence
  to set the cursor's text color.

To handle this, remove the assertion, and simply split the logic for
the cursor backgound and foreground colors:

* Use the configured background color if set (either through config or
  OSC-12), otherwise use the default foreground color.
* Use the configured foreground color if set (through config),
  otherwise use the default background color.
2024-07-01 10:53:21 +02:00
Daniel Eklöf
94b9014f95
Merge branch 'curly-underlines'
Closes #828
2024-07-01 10:09:44 +02:00
Daniel Eklöf
b503c0d6d9
reaadme: add styled and colored underlines to the feature list 2024-06-27 19:28:04 +02:00
Daniel Eklöf
73f6982cbe
grid: merge reflow_{uri,curly}_range_start(), and reflow_{uri,curly}_range_end() 2024-06-27 19:22:01 +02:00
Daniel Eklöf
0c7725217a
render: draw_styled_underline(): respect main.underline-thickness
Also refactor a bit, and break out early to draw_underline() for
legacy underlines.
2024-06-27 19:21:23 +02:00
Daniel Eklöf
19bf558e6c
render: underlines: improve the appearance of the 'dotted' style
Try to make the 'dotted' style appear more even, and less like each
cell is rendered separately (even though they are).

Algorithm:

Each dot is a square; it's sides are that of the font's line
thickness.

The spacing (gaps) between the dots is initially the same width as the
dots themselves.

This means the number of dots per cell is the cell width divided by
the dots' length/width, divided by two.

At this point, there may be "left-over" pixels.I.e. the widths of the
dots and the gaps between them may not add up to the width of the
cell.

These pixels are evenly (as possible) across the gaps.

There are still visual inaccuracies at small font sizes. This is
impossible to fix without changing the way underlines are rendered, to
render an entire line in one go. This is not something we want to do,
since it'll make styled underlines, for a specific cell/character,
look differently, depending on the surrounding context.
2024-06-27 18:36:17 +02:00
Daniel Eklöf
0d3f2f27e3
grid: refactor: replace {uri,curly}_range_append() with range_append()
Also add range_append_by_ref(), with replaces
uri_range_append_no_strdup().
2024-06-26 19:01:54 +02:00
Daniel Eklöf
cb4a74e10b
grid: row_range_put(): use correct type in call to range_delete() 2024-06-26 18:39:24 +02:00
Daniel Eklöf
45f4eb48fb
grid: refactor: remove union range_data_for_insertion
This union is identical to row_range_data, except the URI char pointer
is const. Let's ignore that, and re-use row_range_data, casting the
URI pointer when necessary.

Also remove uri_range_insert() and curly_range_insert(), and use the
generic version of range_insert() everywhere.
2024-06-26 18:39:24 +02:00
Daniel Eklöf
6a0110446c
grid: grid_row_{uri,curly}_range_put(): share code
grid_row_uri_range_put() and grid_row_curly_range_put() now share the
same base logic.

Range specific data is passed through a union, and range specific
checks are done through switched functions.
2024-06-26 18:39:24 +02:00