When writing paste data to the terminal (either interactively, or as
an OSC-52 reply), we enqueue other data (key presses, for examples, or
query replies) while the paste is happening.
The idea is to send the key press _after_ all paste data has been
written, to ensure consistency.
Unfortunately, we only checked for an on-going paste. I.e. where the
paste itself hasn't yet finished. It is also possible the paste itself
has finished, but we haven't yet flushed all the paste buffers. That
is, if we were able to *receive* paste data faster than the terminal
client was able to *consume* it. In this case, we've queued up paste
data in the terminal. These are in separate queues, and when emitting
e.g. a key press, we didn't check if all _those_ queues had been
flushed yet.
Closes#2307
The pre-apply damage thread may be running when we destroy a terminal
instance, and we need to wait for it to finish before destroying the
underlying buffer.
c291194a4e did this, but failed to
realize the thread may get re-started in the roundtrips done later in
wayl_win_destroy(); after the wait added in
c291194a4e, we unmap all
surfaces (including the main grid), and roundtrip. This means the
compositor will release the currently active buffer, and that means
_we_ will trigger the pre-apply damage thread on it. This introduces a
race, where wayl_win_destroy() may reach its shm_purge() calls before
the pre-apply damage thread has finished. That typically causes foot
to crash.
Closes#2288
Recent clang versions warn on __COUNTER__, unless compiling with
-std=c2y (which breaks other things).
"Fixes" '__COUNTER__' is a C2y extension (__COUNTER__ is used by our
UNITTEST macro).
This patch adds a new config option: colors{,2}.blur=no|yes. When
enabled, transparent background are also blurred.
Note that this requires the brand new ext-background-effect-v1
protocol, and specifically, that the compositor implements the blur
effect.
It's possible, but unlikely, that we've pushed a "pre-apply damage"
job to the renderer thread queue (or that we've pushed it, and the
a thread is now working on it) when we shutdown a terminal instance.
This is sometimes caught in an assertion in term_destroy(), where we
check the queue length is 0. Other times, or in release builds, we
might crash in the thread, or in the shutdown logic when freeing the
buffer chains associated with the terminal instance.
Fix by ensuring there's no pre-apply damage operation queued, or
running, before shutting down a terminal instance.
Closes#2263
Applications often prefix the sixel with a raster attributes (RA)
sequence, where they tell us how large the sixel is. Strictly
speaking, this just tells us the size of the area to clear, but we use
it as a hint and pre-allocates the image buffer.
It's important to stress that it is valid to emit a MxN RA, and then
write sixel data outside of that area.
Foot handles this, in _most_ cases. We didn't handle the corner case
Mx0. I.e. a width > 0, but height == 0. No image buffer was allocated,
and we also failed to detect a resize was necessary when the
application started printing sixel data.
Much of this is for performance reason; we only check the minimum
necessary. For example, we only check if going outside the
pre-allocated *column* while printing sixels. *Rows* are checked on a
graphical newline.
In other words, the *current* row has to be valid when writing
sixels. And in case of Mx0, it wasn't.
Fix by forcing a height of at least one sixel (typically 6 pixels).
Closes#2267
This fixes an issue with the kitty keyboard protocol, where 'release'
events associated with a shortcut was sent to the client application.
Example: user triggers "scroll up". We scroll up. No key event(s) are
sent to the client application. Then the user releases the keys. we
don't do any shortcut handling on release events, and so we continue
with the normal input processing. If the kitty keyboard protocol has
been enabled (and specifically, release event reporting has been
enabled), then we'll emit a 'release' escape sequence. This in itself
is wrong, since the client application never saw the corresponding
press event. But we _also_ reset the viewport. The effect (in this
example), is that it's impossible to scroll up in the scrollback
history.
Note that we don't ignore _any_ release event, only the release event
for the (final) symbol that triggered the shortcut.
This should allow e.g. modifier keys release events to be processed
normally, if released before the shortcut key.
This is somewhat important, since the client application will have
received press events for the modifier keys leading up to the
shortcut (if modifier press/release events have been enabled in the
kitty keyboard protocol - _Report all keys as escape codes_).
Closes#2257
Without this, the input handling code won't understand the key/mouse
event was consumed (i.e. triggered a shortcut), and will continue
processing normally (e.g. sending event to the client application).
Before this patch, foot used xrgb surfaces for all fully opaque
surfaces, and only used argb surfaces for the main window when the
user enabled translucency.
However, several compositors have damage-like issues when we switch
between opaque and non-opaque surfaces (for example, when switching
color theme, or when toggling fullscreen).
Since the performance benefit of using non-alpha aware surfaces are
likely minor (if there's any measurable performance difference at
all!), lets workaround these compositor issues by always using argb
surfaces.
Otherwise, a sequence like
\E[4:2;4m # Enable double-underline, then immediately switch to single
Will switch to the slow printer, and then get stuck there even though
we immediately switch to plain underlines (which don't need the slow
printer).
The main reason for having two color sections is to be able to switch
between dark and light. Thus, it's better if the section names reflect
this, rather than the more generic 'colors' and 'colors2' (which was
the dark one and which was the light one, now again?)
When the second color section was added, we kept the original name,
colors, to make sure we didn't break existing configurations, and
third-party themes.
However, in the long run, it's probably better to be specific in the
section naming, to avoid confusion.
So, add 'colors-dark', and 'colors-light'. Keep 'colors' and 'colors2'
as aliases for now, but mark them as deprecated. They WILL be removed
in a future release.
Also rename the option values for initial-color-theme, from 1/2, to
dark/light. Keep the old ones for now, marked as deprecated.
Update all bundled themes to use the new names. In the light-only
themes (i.e. themes that define a single, light, theme), use
colors-light, and set initial-color-theme=light.
Possible improvements: disable color switching if only one color
section has been explicitly configured (todo: figure out how to handle
the default color theme values...)
299186a654 introduced a regression,
where we don't handle SHM buffer "hiccups" correctly.
If foot, for some reason is forced to render a frame "too soon", we
might end up having multiple buffers "in flight" (i.e. committed to
the compositor). This could happen if the compositor pushes multiple
configure events rapidly, for example. Or anything else that forces
foot to render something "immediately", without waiting for a frame
callback.
The compositor typically releases both buffers at the same time (or
close to it), so the _next_ time we want to render a frame, we
have *two* buffers to pick between. The problem here is that after
299186a654, foot no longer purges the
additional buffer(s), but keeps all of them around. This messes up
foot's age tracking, and the _next_ time we're forced to pull two
buffers (without the compositor releasing the first one in between),
we try to apply damage tracking that is no longer valid. This results
in visual glitches. This never self-repairs, and we're stuck with
visual glitches until the window is resized, and we're forced to
allocate completely new buffers.
It is unclear why 299186a654 stopped
removing the buffers. It was likely done early in the development, and
is no longer needed. So far, I haven't noticed any bugs by
re-introducing the buffer purging, but further testing is needed.
When reporting the column/row pixel value in mouse SGR mode, we
emitted negative values when the cursor was being dragged outside the
window.
Unfortunately, negative values aren't allowed in CSI parameters, as
'-' is an intermediate value.
It was done this way, to be consistent with XTerm behavior. Allegedly,
XTerm has changed its behavior in patch 404.
With that in mind, and seeing that foot has never emitted negative
values in any other mouse mode, let's stop emitting negative values in
SGR mode too.
Closes#2226
If the viewport has been scrolled up, it is possible for a
reverse-scroll (rin) to cause the viewport to point to lines outside
the scrollback. This is an issue if the scrollback isn't full, since
in that case, the viewport will contain NULL lines. This will
potentially trigger assertions in a couple of different places.
Example backtrace:
#2 0x555555cd230c in bug ../../debug.c:44
#3 0x555555ad485e in grid_row_in_view ../../grid.h:83
#4 0x555555b15a89 in grid_render ../../render.c:3465
#5 0x555555b3b0ab in fdm_hook_refresh_pending_terminals ../../render.c:5165
#6 0x555555a74980 in fdm_poll ../../fdm.c:435
#7 0x555555ac2b85 in main ../../main.c:676
Detect when this happens, and force-move the viewport to ensure it is
valid.
Closes#2232
Add support for the new xdg-toplevel-tag-v1 Wayland protocol, by
exposing a new config option, `toplevel-tag`, and a corresponding
command option, `--toplevel-tag` (in both `foot` and `footclient`).
This can help the compositor with session management, or custom window
rules.
Closes#2212
By default, triple-click tries to select quoted strings within a
logical line. This also works if the line spans multiple screen lines.
If there is a quote character in the last column:
printf %"$COLUMNS"s \'; printf wrapped; sleep inf
and I triple-click on the following soft-wrapped line, there's an
assertion failure because the column next to the quote is out of range.
The quote position has been found by walking at least one cell
backwards from "pos". This means that if the quote position is in
the very last column, there must be a row below.
Also move the assertion to be a pre-condition, though that's debatable.
This is needed, since we disable alpha in fullscreen, and since we use
different image buffer formats (XRGB vs. ARGB) when we have alpha
vs. when we don't (and fullscreen always disables alpha).
Normally, this happens anyway, as the window is resized when going in
or out from fullscreen. But, it's technically possible for a
compositor to change an application's fullscreen state without
resizing the window.
This fixes an off by one, where we sometimes "ate" an extra space when
extracting contents with tabs. This happened if the tab (and its
subsequent spaces) were followed by an additional space.
Closes#2194
Before this patch, we always blended towards black when dimming
text. However, with light color themes, it usually looks better if we
dim towards white instead.
This option allows you to choose which color to blend towards.
The default is 'black' in '[colors]', and 'white' in '[colors2]'.
Closes#2187
When exiting fullscreen mode, the window's transparency was not being
restored, leaving it opaque until another window was fullscreened.
This occurred because the Wayland opaque region was set based only on
the configured alpha value, without considering the fullscreen state.
Since commit
899b768b74 ("render: disable transparency when we're fullscreened")
transparency is disabled during fullscreen to avoid
compositor-mandated black backgrounds affecting the intended colors.
However, the opaque region was not being updated when the fullscreen
state changed.
Fixes: https://codeberg.org/dnkl/foot/issues/2180
Signed-off-by: Charalampos Mitrodimas <charmitro@posteo.net>
Foot likes it when compositor releases buffer immediately, as that
means we only have to re-render the cells that have changed since the
last frame.
For various reasons, not all compositors do this. In this case, foot
is typically forced to switch between two buffers, i.e. double-buffer.
In this case, each frame starts with copying over the damage from the
previous frame, to the new frame. Then we start rendering the updated
cells.
Bringing over the previous frame's damage can be slow, if the changed
area was large (e.g. when scrolling one or a few lines, or on full
screen updates). It's also done single-threaded. Thus it not only
slows down frame rendering, but pauses everything else (i.e. input
processing). All in all, it reduces performance and increases input
latency.
But we don't have to wait until it's time to render a frame to copy
over the previous frame's damage. We can do that as soon as the
compositor has released the buffer (for the frame _before_ the
previous frame). And we can do this in a thread.
This frees up foot to continue processing input, and reduces frame
rendering time since we can now start rendering the modified cells
immediately, without first doing a large memcpy(3).
In worst case scenarios (or perhaps we should consider them best case
scenarios...), I've seen up to a 10x performance increase in frame
rendering times (this obviously does *not* include the time it takes
to copy over the previous frame's damage, since that doesn't affect
neither input processing nor frame rendering).
Implemented by adding a callback mechanism to the shm abstraction
layer. Use it for the grid buffers, and kick off a thread that copies
the previous frame's damage, and resets the buffers age to 0 (so that
foot understands it can start render to it immediately when it later
needs to render a frame).
Since we have certain way of knowing if a compositor releases buffers
immediately or not, use a bit of heuristics; if we see 10 consecutive
non-immediate releases (that is, we reset the counter as soon as we do
see an immediate release), this new "pre-apply damage" logic is
enabled. It can be force-disabled with tweak.pre-apply-damage=no.
We also need to take care to wait for the thread before resetting the
render's "last_buf" pointer (or we'll SEGFAULT in the thread...).
We must also ensure we wait for the thread to finish before we start
rendering a new frame. Under normal circumstances, the wait time is
always 0, the thread has almost always finished long before we need to
render the next frame. But it _can_ happen.
Closes#2188
This allows the user to configure the value by which a surface
buffer's stride must be an even multiple of.
This can be used to ensure the stride meets the GPU driver's
requirements for direct import.
Defaults to 256. Set to 0 to disable.
Closes#2182
When we print a character to the grid, we must also update its OSC-8
state if an OSC-8 URI is currently active.
For double-width characters, this was only being done for the first
cell.
This causes the labels in URL mode to be off, as the link was
effectively chopped up into multiple pieces.
Closes#2179
This makes the "uppercase hint character inserts selected text"
behavior added in #1975 configurable, as it can have unexpected
behavior for some users.
It defaults to "on", preserving the new behavior of `foot`, after
Fixes#2159.
Some of the value_to_*() functions wrote directly to the output
variable, even when the value was invalid. This often resulted in the
an actual configuration option (i.e. a member in the config struct) to
be overwritten by an invalid value.
For example, -o initial-color-theme=0 would set
conf->initial_color_theme to -1, resulting in a crash later, when
initializing a terminal instance.
This patch adds the IPC infrastructure necessary to propagate
SIGUSR1/SIGUSR2 from a footclient process to the server process.
By targeting a particular footclient instance, only that particular
instance changes theme. This is different from when targeting the
server process, where all instances change theme.
Closes#2156
When sending SIGUSR1/SIGUSR2 to a server process, all currently
running client instances change their theme. But before this patch,
all future instances used the original theme. With this patch, the
server owned config object is updated with the selected theme, thus
making new instances use the same theme as well.
This ensures applications don't mistake foot for another terminal
emulator. Not that applications _should_ rely on environment
variables, but some do anyway...
When selecting 16-bit surfaces, we set pixman_fmt_without_alpha twice,
and never set pixman_fmt_with_alpha.
This caused 10-bit surfaces to be used instead, since it checks if
pixman_fmt_with_alpha has been overridden or not.
Before this patch, SIGUSR1 toggled between [colors] and
[colors2].
Now, SIGUSR1 changes to [colors], regardless of what the current color
theme is, and SIGUSR2 changes to [colors2].
Closes#2144
Sway used to have an issue where unmapping a subsurface did not damage
the surface below (https://github.com/swaywm/sway/issues/6960).
This has been fixed for quite some time now, so let's remove the
quirk.
Before this patch, the grid content was *always* centered when the
window was maximized or fullscreened, regardless of how the user had
configured padding.
Now, the behavior is controlled by the 'pad' option. Before this
patch, the syntax was
pad MxN [center]
Now it is
pad MxN [center|center-when-fullscreen|center-when-maximized-and-fullscreen]
The default is "pad 0x0 center-when-maximized-and-fullscreen", to
match current behavior.
Closes#2111
These (non-css) cursor shapes were added to the cursor-shape-v1
protocol in wayland-protocols 1.42.
We don't need (or use them at all) internally, but add them to the
list we use to translate from shape names to shape enums. This allows
users to set a custom shape (via OSC-22), while still using server
side cursors (i.e. no need to fallback to client-side cursors).
If we try to set a shape not implemented by the server, we get a
protocol error and foot exits. This is bad.
So, make sure we don't do that:
1. First, we need to explicitly bind v2 if implemented by the server
2. Track the bound version number in the wayland struct
3. When matching shape enum, skip shapes not supported in the
currently bound version of the cursor-shape protocol
Currently, if the following occurs:
1. foot has AxB size
2. Compositor sends CxD size
3. foot detects a resize, acks and saves CxD, but doesn't redraw immediately
4. Compositor sends CxD size again (due to a toplevel state array
change, for example)
Then foot will detect no resize occurred, and will do an "empty"
commit immediately.
In this particular case that's wrong, since we're effectively
acking+committing the initial AxB size.
Fix by only doing the immediate commit if there's no size
change **and** there's no pending refresh.
Note: normally, we'd resize and refresh+commit immediately, but if
we're waiting for a frame callback, then the refresh+commit will be
delayed (i.e. scheduled). This is what we're checking here.
Closes#2105
The version bump was done since we now use XKB_VMOD_NAME_*; macros
added in libxkbcommon 1.8.0.
Not all distros have updated libxkbcommon yet (read: Debian). Since
it's fairly easy to work around, let's do that.
Closes#2103
Before this patch, we just called c32width(), which only works on
actual codepoints. If the last printed character is a "combining"
character, i.e. a key into our lookup table for multi-codepoint
graphemes, we need to lookup the grapheme and pick the width from
there.
See https://gitlab.com/AutumnMeowMeow/jexer/-/issues/119#note_2499712901
Before this, we only applied custom selection colors, if *both* the
selection bg and fg had been set.
Since the options are already split up into two separate options, and
since it makes sense to at least be able to keep the foreground colors
unchanged (i.e. only setting the selection background), let's allow
only having one of the selection colors set.
Closes#1846
This adds supports for 16-bit surfaces, using the new
PIXMAN_a16b16g16r16 buffer format. This maps to
WL_SHM_FORMAT_ABGR16161616 (little-endian).
Use the new 16-bit surfaces by default, when
gamma-correct-blending=yes.
When parsing an OSC-11 without an alpha value (i.e. standard OSC-11,
not rxvt's extended variant), restore the alpha value from the
configuration, rather than keeping whatever the current alpha is.
This fixes an issue where protocol errors aren't reported. I'm
guessing the read succeeds, but that prepare_read() _also_ succeeds
immediately, since there aren't any events to dispatch (only log the
protocol error).
By calling dispatch unconditionally, we ensure any error messages are
printed. Then we proceed to loop prepare_read() + dispatch_pending()
until the queue is empty.
In copy-regex/show-urls-copy mode, if the last input character was
uppercase, copy the selection to the clipboard _and_ paste it. This is
useful for taking a file path from a command output:(log, git, test
failure, etc.) and using it in another command.
This is inspired by the behavior of copy mode in wezterm:
https://wezterm.org/quickselect.html
I could have made it check every character in the hint, but it seemed
fine to assume that if the last character was uppercase, the user
wanted this behavior.
Closes#1975.
When set to 'auto', use 10-bit surfaces if gamma-correct blending is
enabled, and 8-bit surfaces otherwise.
Note that we may still fallback to 8-bit surfaces (without disabling
gamma-correct blending) if the compositor does not support 10-bit
surfaces.
Closes#2082
When set to 'auto', use 10-bit surfaces if gamma-correct blending is
enabled, and 8-bit surfaces otherwise.
Note that we may still fallback to 8-bit surfaces (without disabling
gamma-correct blending) if the compositor does not support 10-bit
surfaces.
Closes#2082
This option selects which color theme to use by default. I.e. at
startup, and after a reset.
This is useful with combined theme files, where a single file defines
e.g. both a dark and light version of the theme.
* Recognize 'CSI ? 996 n', and respond with
- 'CSI ? 997 ; 1 n' if the primary theme is active
- 'CSI ? 997 ; 2 n' if the alternative theme is actice
* Implement private mode 2031, where changing the color
theme (currently only possible via key bindings) causes the terminal
to send the same CSI sequences as above.
In this context, foot's primary theme is considered dark, and the
alternative theme light (since the default theme is dark).
Closes#2025
* color-theme-switch-1: select the primary color theme
* color-theme-switch-2: select the alternative color theme
* color-theme-toggle: toggle between the primary and alternative color themes
This section defines an alternative color theme. The keys are the same
as in the 'colors' section, as are the default values.
Values are *not* inherited from 'colors'. That is, if you set a value
in 'colors', but not in 'colors2', it is *not* inherited by 'colors2'.
Foot doesn't implement RTL, and explicit LTR markers is neither
needed, nor used in anyway. In fact, they cause issues with font
lookup, as fcft often fails to find the marker codepoint in the
primary font, causing a fallback font to be used instead.
Closes#2049
d3f692990e moved emoji-variation-sequences.h header inclusion from
vt.c to terminal.c. these two files are part of different libraries
hence target for generating emoji-variation-sequences.h needs to be
moved too.
Before this patch, it only matched RGB color sources. It did not match
the default bg color, or indexed colors. That is, e.g. CSI 43m didn't
apply alpha, even if the color3 matched the default background color.
Move main.alpha-mode to colors.alpha-mode.
Fix (inverted) cursor handling, by always using the bg color without
alpha.
Do a minor optimization, where we don't even lock at colors.alpha-mode
if there's no transparency configured.
When a regex matches a string containing double-width characters, the
CELL_SPACER values were included in the URL string. This meant the
final URL (either launched, or copied) weren't handled correctly, as
invalid UTF-8 sequences were inserted in the middle of the string.
Closes#2027
Edge constraints are new (not yet available in a wayland-protocols
release) toplevel states, acting as a complement to the existing tiled
states.
Tiled tells us we shouldn't draw shadows etc *outside our window
geometry*.
Constrained tells us the window cannot be resized in the constrained
direction.
This patch does a couple of things:
* Recognize the new states when debug logging
* Change is_top_left() etc to look at the new constrained state
instead of the tiled state. These functions are used when both
choosing cursor shape, and when determining if/how to resize a
window on a CSD edge click-and-drag.
* Update cursor shape selection to use the default (left_ptr) shape
when on a constrained edge (or corner).
* Update CSD resize triggering, to not trigger a resize when attempted
on a constrained edge (or corner).
See
86750c99ed:
An edge constraint is an complementery state to the tiled state,
meaning that it's not only tiled, but constrained in a way that it
can't resize in that direction.
This typically means that the constrained edge is tiled against a
monitor edge. An example configuration is two windows tiled next
to each other on a single monitor. Together they cover the whole
work area.
The left window would have the following tiled and edge constraint
state:
[ tiled_top, tiled_right, tiled_bottom, tiled_left,
constrained_top, constrained_bottom, constrained_left ]
while the right window would have the following:
[ tiled_top, tiled_right, tiled_bottom, tiled_left,
constrained_top, constrained_bottom, constrained_right ]
This aims to replace and deprecate the
`gtk_surface1.configure_edges` event and the
`gtk_surface1.edge_constraint` enum.
wayland-protocols commit 86750c99ed06 ("xdg-shell: Add edge
constraints") added a few more enums to handle, making the build fail
with -Werror:
../wayland.c: In function ‘xdg_toplevel_configure’:
../wayland.c:878:9: error: enumeration value ‘XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT’ not handled in switch [-Werror=switch]
878 | switch (*state) {
| ^~~~~~
../wayland.c:878:9: error: enumeration value ‘XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT’ not handled in switch [-Werror=switch]
../wayland.c:878:9: error: enumeration value ‘XDG_TOPLEVEL_STATE_CONSTRAINED_TOP’ not handled in switch [-Werror=switch]
../wayland.c:878:9: error: enumeration value ‘XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM’ not handled in switch [-Werror=switch]
(This is not part of any release yet, but can be used when building with
the submodule)
From a quick look it sounds like the meaning is the same as tiling as
far as we are concerned so handle these as we do of tiling.
Trying to build with an older libxkbcommon fails as follow:
```
../input.c: In function ‘keyboard_keymap’:
../input.c:648:82: error: ‘XKB_VMOD_NAME_ALT’ undeclared (first use in this function); did you mean ‘XKB_MOD_NAME_ALT’?
648 | xkb_mod_index_t alt = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_VMOD_NAME_ALT);
| ^~~~~~~~~~~~~~~~~
| XKB_MOD_NAME_ALT
../input.c:648:82: note: each undeclared identifier is reported only once for each function it appears in
../input.c:649:83: error: ‘XKB_VMOD_NAME_META’ undeclared (first use in this function); did you mean XKB_MOD_NAME_ALT’?
649 | xkb_mod_index_t meta = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_VMOD_NAME_META);
| ^~~~~~~~~~~~~~~~~~
| XKB_MOD_NAME_ALT
../input.c:650:84: error: ‘XKB_VMOD_NAME_SUPER’ undeclared (first use in this function); did you mean ‘XKB_MOD_NAME_NUM’?
650 | xkb_mod_index_t super = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_VMOD_NAME_SUPER);
| ^~~~~~~~~~~~~~~~~~~
| XKB_MOD_NAME_NUM
../input.c:651:84: error: ‘XKB_VMOD_NAME_HYPER’ undeclared (first use in this function); did you mean ‘XKB_MOD_NAME_CAPS’?
651 | xkb_mod_index_t hyper = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_VMOD_NAME_HYPER);
| ^~~~~~~~~~~~~~~~~~~
| XKB_MOD_NAME_CAPS
../input.c:652:87: error: ‘XKB_VMOD_NAME_NUM’ undeclared (first use in this function); did you mean ‘XKB_MOD_NAME_NUM’?
652 | xkb_mod_index_t num_lock = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_VMOD_NAME_NUM);
| ^~~~~~~~~~~~~~~~~
| XKB_MOD_NAME_NUM
../input.c:653:90: error: ‘XKB_VMOD_NAME_SCROLL’ undeclared (first use in this function); did you mean ‘XKB_LED_NAME_SCROLL’?
653 | xkb_mod_index_t scroll_lock = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_VMOD_NAME_SCROLL);
| ^~~~~~~~~~~~~~~~~~~~
| XKB_LED_NAME_SCROLL
../input.c:654:90: error: ‘XKB_VMOD_NAME_LEVEL3’ undeclared (first use in this function); did you mean ‘XKB_MOD_NAME_CTRL’?
654 | xkb_mod_index_t level_three = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_VMOD_NAME_LEVEL3);
| ^~~~~~~~~~~~~~~~~~~~
| XKB_MOD_NAME_CTRL
../input.c:655:89: error: ‘XKB_VMOD_NAME_LEVEL5’ undeclared (first use in this function); did you mean ‘XKB_MOD_NAME_CTRL’?
655 | xkb_mod_index_t level_five = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, XKB_VMOD_NAME_LEVEL5);
| ^~~~~~~~~~~~~~~~~~~~
| XKB_MOD_NAME_CTRL
```
The old one is in some cases too liberal. The new one is stricter in
two ways:
1. The protocol list is now explicit, rather than matching anything://
2. Allowed characters are now limited to the "safe character set", the
"reserved character set", and some from the "unsafe character set"
Furthermore, some of the characters are restricted in how/when they
are allowed:
1. Periods, commas, question marks etc are allowed inside an URL, but
not at the end.
2. [ ], ( ), " " and ' ' are allowed but only when balanced. This
allows us to match e.g. [http://foo.bar/foo[bar]] correctly.
Closes#2016
Some compositors (mutter/GNOME is one) adds _virtual_ modifiers to the
set of active modifiers when e.g. Alt, Meta, Super or Hyper is
pressed. For example, pressing Alt+b would result in *both* the Alt
*and* the Mod1 modifier being set.
Since foot makes close to zero assumptions on how the modifiers should
be interpreted, this causes various breakages.
For example, a foot shortcut defined as Mod1+b will not match, since
the Alt modifiers is also set. This has forced users to
redefine/override some of the default key bindings to include the
additional modifiers.
It also causes issues with the kitty keyboard protocol, for some key
combinations. Mainly whether or not to use unshifted key or not,
resulting in incorrect escape sequences.
Since all the "real" modifiers are always set as well, we can safely
ignore the virtual modifiers.
Closes#2009
otherwise, depending on ninja dependency resolution order and parallel
build, srgb.h may not be built in time
Fixes: ccf625b991 ("render: gamma-correct blending")
Example:
printf "pok\xe9mon\n"
would result in 'pokon' - the 'm' has been discarded along with E9.
While correct, in some sense, it's perhaps not intuitive.
This patch changes the VT parser to instead discard everything up to
the invalid byte, but then try the invalid byte from the ground
state. This way, invalid UTF-8 sequences followed by both plain ASCII,
or longer (and valid) UTF-8 sequences are printed as expected instead
of being discarded.
Update tweak.scaling-filter to recognize the new scaling filters added
in fcft-3.3.0.
Since fcft_set_scaling_filter() is deprecated in 3.3.0, don't use it
anymore, and set the scaling filter via fcft_font_options instead.
This ensures empty lines are treated correctly, and is also more in
line with how lines are handled at runtime, when filling the
scrollback.
For now, set linebreak=false as soon as something is printed on a
line. It will remain like that *until* we reach the end of an old row
with linebreak=true, at which point we set linebreak=true on the
current new line.
This way, all lines are treated as having a hard linebreak, until it's
cleared when we do an auto-wrap.
This change alone causes issues when reflowing text, as now all
trailing lines in an otherwise empty window are treated as hard
linebreaks, causing the new grid to insert lots of unwanted, empty
lines.
Fix by doing two things:
* *clear* the linebreak flag when we pull in new lines for the new
grid. We only want to set it explicitly, when an old row has its
linebreak flag set.
* Coalesce empty lines with linebreak=true, and only "emit" them as
new liens in the new grid if they are followed by non-empty lines.
Don't set linebreak on linefeed. Instead, rely on the default value of
true, and that it is only cleared when a character is printed while
LCF=1.
Note that printing to a row that has linebreak cleared, will set the
linebreak flag again.
This implements gamma-correct blending, which mainly affects font
rendering.
The implementation requires compile-time availability of the new
color-management protocol (available in wayland-protocols >= 1.41),
and run-time support for the same in the compositor (specifically, the
EXT_LINEAR TF function and sRGB primaries).
How it works: all colors are decoded from sRGB to linear (using a
lookup table, generated in the exact same way pixman generates it's
internal conversion tables) before being used by pixman. The resulting
image buffer is thus in decoded/linear format. We use the
color-management protocol to inform the compositor of this, by tagging
the wayland surfaces with the 'ext_linear' image attribute.
Sixes: all colors are sRGB internally, and decoded to linear before
being used in any sixels. Thus, the image buffers will contain linear
colors. This is important, since otherwise there would be a
decode/encode penalty every time a sixel is blended to the grid.
Emojis: we require fcft >= 3.2, which adds support for sRGB decoding
color glyphs. Meaning, the emoji pixman surfaces can be blended
directly to the grid, just like sixels.
Gamma-correct blending is enabled by default *when the compositor
supports it*. There's a new option to explicitly enable/disable it:
gamma-correct-blending=no|yes. If set to 'yes', and the compositor
does not implement the required color-management features, warning
logs are emitted.
There's a loss of precision when storing linear pixels in 8-bit
channels. For this reason, this patch also adds supports for 10-bit
surfaces. For now, this is disabled by default since such surfaces
only have 2 bits for alpha. It can be enabled with
tweak.surface-bit-depth=10-bit.
Perhaps, in the future, we can enable it by default if:
* gamma-correct blending is enabled
* the user has not enabled a transparent background
If the user has configured cursor.style=hollow, make DECSCUSR 1/2 set
the cursor to hollow rather than block, and make DECRQSS DECSCUSR
respond as if cursor.style=block.
The idea is to not expose the hollow variant in DECSCUSR in any way,
to avoid having to extend it with custom encodings.
Another way to think about it is this is just a slightly more
discoverable way of doing:
cursor.style=block
cursor.block-cursor-is-hollow=yes
When compiled with grapheme clustering support, zero-width characters
that also are grapheme breaks, were ignored (not stored in the
grid).
When utf8proc says the character is a grapheme break, we try to print
the character to the current cell. But this is only done when width >
0. As a result, zero width grapheme breaks were simply discarded.
This only happens when grapheme clustering is enabled; when disabled,
all zero width characters are appended.
Fix this by also requiring the width to be non-zero when if we should
append the character or not.
Closes#1960
When the cursor is at the end of the line, with a pending wrap (LCF
set), the lcf flag should be cleared *and* the cursor moved one cell
to the right.
Before this patch, we cleared LCF, but didn't move the cursor.
Closes#1954
Wrap *all* cell copying logic in a for-loop for the characters
width. This _should_, in theory, mean reflow of e.g. cursor
coordinates in the middle of a multi-column character works correctly.
Also fix reflow of cmd start/end integration.
We've been trying to performance optimize reflow by "chunking" cells;
try to gather as many as possible, and memcpy a chunk at once.
The problem is that a) this quickly becomes very complex, and b) is
very hard to get right for multi-column characters, especially when we
need to truncate long ones due to the window being too small.
Refactor, and once again walk and copy all cells one by one. This is
slower, but at least it's correct.
Commit 859b4c89 (url-mode: wip: more work on regex matching,
2025-01-30) regressed URL detection in weechat. Some of the URLs
still work but others don't. This is because regexec() stops at the
first NUL, thus skipping the rest of the line. weechat seems create
NUL cells between their UI widgets.
Work around this by replacing NUL with space. This is probably correct
because selecting and copying those cells also translates to space
(not sure where in the code).
Zero-initialize the 'launch' spawn template before calling
value_to_spawn_template(). This is needed since
value_to_spawn_template() tries to free the old value before assigning
the new one.
Closes#1951
When checking if we're breaking in the middle of a multi-column
character, we counted spacers starting from the break point. But,
the character may be wider than that. Use the fact that the spacers
cells encode how many *more* there are after them; when we get to the
first one, we know exactly how wide the character is.
When appending to an existing composed character, "inherit" its forced
width, if set.
Also make sure to actually _use_ the forced width, if set, rather than
the calculated width.
This fixes an issue when appending zero-width codepoints to a
forced-width combining character.
If there's a single codepoint in the text portion of the OSC sequence,
and its calculated width matches the forced width, print it directly
to the grid instead of emitting a combining character.
When w=0, we split up the text string "as we normally would". Since we
don't support any other text-sizing parameters, this means simply
printing each codepoint to the grid.
This function "prints" any non-ascii character (i.e. any character
that ends up in the action_utf8_print() function in vt.c) to the
grid. This includes grapheme cluster processing etc.
action_utf8_print() now simply calls this function.
This allows us to re-use the same functionality from other
places (like the text-sizing protocol).
This brings initial support for the new kitty text-sizing
protocol. Note hat only the width-parameter ('w') is supported. That
is, no font scaling, and no multi-line cells.
For now, only explicit widths are supported. That is, w=0 does not yet
work.
There are a couple of changes to the renderer, to handle e.g.
OSC 66 ; w=6 ; foobar ST
There are two ways this can get rendered, depending on whether
grapheme shaping has been enabled. We either shape it, and get an
array of glyphs back that we render. Or, we rasterize each codepoint
ourselves, and render each resulting glyph.
The two cases ends up in two different renderer loops, that worked
somewhat different. In particular, the first case has probably never
been tested/used at all...
With this patch, both are changed, and now uses some heuristic to
differentiate between multi-cell text strings (like in the example
above), or single-cell combining characters. The difference is mainly
in which offset to use for the secondary glyphs.
In a multi-cell string, each glyph is mapped to its own cell, while in
the combining case, we try to map all glyphs to the same cell.
The logic that tries to ensure we don't break a line in the middle of
a multi-cell character was flawed when the number of cells were larger
than 2.
In particular, if the number of cells to copy were limited by the
number of cells left on the current (new) line, and were less than the
length of the multi-cell character, then we failed to insert the
correct number of spacers, and also ended up misplacing the multi-cell
character; instead of pushing it to the next line, it was inserted on
the current line, even though it doesn't fit.
Also change how trailing SPACER cells are rendered (cells that are
"fillers" at then end of a line, when a multi-column character was
pushed over to the next line): don't copy the previous cell's
attributes (which may be wrong anyway), use default attributes
instead.
When the client application emits combining characters, for example
multi-codepoint emojis, in insert-mode, we ended up pushing partial
graphemes to the right, for each codepoint, resulting in too many
cells (and with the wrong content) being inserted.
The fix is fairly simple; don't "insert" when appending characters to
an existing grapheme cluster.
This isn't something we can detect easily in print_insert() (it would
require us to do grapheme clustering again). Fortunately, we do have
the required information in action_utf8_print(). So, pass this
information as a boolean to term_print().
Closes#1947
When auto-matching URLs (or custom regular expressions), use the
first *subexpression* as URL, rather than the while regex match.
This allows us to write custom regular expressions with prefix/suffix
strings that should not be included in the presented match.
Users can now define their own regex patterns, and use them via key
bindings:
[regex:foo]
regex=foo(bar)?
launch=path-to-script-or-application {match}
[key-bindings]
regex-launch=[foo] Control+Shift+q
regex-copy=[foo] Control+Mod1+Shift+q
That is, add a section called 'regex:', followed by an
identifier. Define a regex and a launcher command line.
Add a key-binding, regex-launch and/or regex-copy (similar to
show-urls-launch and show-urls-copy), and connect them to the regex
with the "[regex-name]" syntax (similar to how the pipe-* bindings
work).
Currently, architecture using soft-floats doesn't support instructions
FE_INVALID, FE_DIVBYZERO, FE_OVERFLOW and FE_UNDERFLOW and so building
on those architectures results with a build error.
As the sqrt math function should set errno to EDOM if an error occurs,
fetestexcept shouldn't be mandatory.
This commit removes the float environment error handling.
Signed-off-by: Thomas Bonnefille <thomas.bonnefille@bootlin.com>
That is, try to match e.g. Control+shift+a, before trying to match
Control+A.
In most cases, order doesn't matter. There are however a couple of
symbols where the layout consumes the shift-modifier, and the
generated symbol is the same in both the shifted and unshifted
form. One such example is backspace.
Before this patch, key-bindings with shift-backspace would be ignored,
if there were another key-binding with backspace.
So, for example, if we had one key-binding with Control+Backspace, and
another with Control+Shift+Backspace, the latter would never trigger,
as we would always match the first one.
By checking for unshifted matches first, we ensure
Control+Shift+Backspace does match.
When matching the unshifted symbol, or the raw key code, ignore all
key bindings that don't have any modifiers.
This fixes an issue where it was impossible to enter (some of the)
numbers on the keypad, **if** there was a key-binding for
e.g. KP_Page_Up, or KP_Page_Down.
When trying to match key bindings, we do three types of matching:
* Match the _translated_ symbol (e.g. Control+C)
* Match the _untranslated_ symbol (e.g. Control+Shift+c)
* Match raw keyboard codes
This was done for *each* key binding. This meant we sometimes matched
a keybinding in raw mode, even though there was a
translated/untranslated binding that would match it too. All depending
on the internal order of the key binding list.
This patch changes it, so that we first try all bindings in translated
mode, then all bindings in untranslated mode, and finally all bindings
in raw mode.
Closes#1929
The protocol states:
If the width or height arguments are zero, it means the client
should decide its own window dimension. This may happen when the
compositor needs to configure the state of the surface but doesn't
have any information about any previous or expected dimension.
The wording is a bit ambiguous; does it mean we should set *both*
width and height to values we choose, even if only one dimension is
zero in the configure event? Or does it mean that we should choose the
value for the dimension that is zero in the configure event?
Regardless, it's pretty clear that it does *not* mean we should *only*
choose width and height if *both* dimensions are zero in the configure
event. This is foot's behavior before this patch, meaning if only one
of them is zero, foot assumed the compositor wanted us to set the
width (or height) to zero...
Change this, so that we now choose value for the "missing" dimension,
but do use the compositor provided value for the other dimension.
Closes#1925
Relevant issues:
* https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/155
* https://github.com/YaLTeR/niri/issues/1050
When printing a double-width glyph at the end of the line, it will get
pushed to the next line if there's only one cell left on the current
line.
That last cell on the current line is filled with a SPACER value.
When reflowing the text, the SPACER cell should be "removed", so that
the double-width glyph continues directly after the text on the
previous line.
9567694bab fixed an issue where
reflowing e.g. neofetch output incorrectly removed spaces between the
logo, and the system info. But also introduced a regression where
SPACER values no longer are removed.
This patch tries to fix it, by adding back empty cells, but NOT SPACER
cells.
The code reads cwd into a buffer, which is expanded while errno is ERANGE, with the intent of growing the buffer until the path fits.
While getcwd will set errno on error, it will not reset it once the path fits into the buffer.
So to not get an infinite loop once errno is ERANGE, we need to make sure to reset errno, such that the loop behaves as expected.
Use better named variables while juggling the shifted vs. unshifted
key codes.
Switch to variable names appropriate for the kitty keyboard protocol
once we have all the unshifted, shifted and base key codes done. It's
not until then we can decide which key code to use as the main key,
and whether or not to report the alternate key code.
Test a couple of key combos from the se and de(neo) layouts.
This unit test isn't intended to test _all_ key combinations, for all
kitty flag combinations, but to be more of a regression test -
whenever we discover a buggy, weird combo, add it here.
* Always do a base key lookup. Before this, we didn't do that if we
matched the XKB sym to a lookup table entry (i.e. keypads, cursor keys
etc.)
* Try to retrieve the unshifted symbol also when we matched the symbol
to a lookup table entry. When successful, we now report an alternate
key for keypad and cursor keys; before this patch, we only did that
for keys that didn't have an entry in the lookup table (i.e. ASCII
chars etc).
This improves compatibility with kitty (and the kitty keyboard
protocol) in more corner cases. One particular example is the neo
keyboard layout, where part of the regular keys act as keypad keys
when num-lock is active.
When alternate key reporting is enabled (i.e. when we're supposed to
report the shifted key along with the unshifted key), we try to figure
out whether the key really is shifted or not (and thus which xkb
keysym to use for the unshifted and shifted keys in the escape).
This was done by getting the layout's *all* modifier combinations that
produce the shifted keysym, and if any of of them contained a modifier
that isn't supported by the kitty protocol, the shifted and unshifted
keys are derived from the same keysym. This is to ensure we handle
things like AltGr-combos correctly.
The issue is, since there may be more than one modifier combination
generating the shifted keysym, we may end up using the wrong keysym
just because _another_ combination set contains modifiers not
supported by the kitty protocol. What we're interrested in is whether
the *pressed* set of modifiers contains such modifiers.
Closes#1918
When there's a key collision, we increment the key and check
again. When doing this, we need to ensure the key is withing range,
and wrap around to 0 if the key value is too large.
If the compositor sends a keyboard enter event before our window has
been mapped, foot crashes; the enter event triggers a cursor
refresh (hollow -> non-hollow block cursor), which crashes since we
haven't yet allocated a grid.
Fix by no-op:ing the refresh if the window hasn't been configured yet.
Closes#1910
If we call render_refresh, that will wait for a callback to the main
surface. In the case of a flash, the main surface might not get callbacks
if the compositor implements fancy culling optimizations like wlroots
wlr_scene compositors such as sway version >=1.10.
From the release notes:
system bell - allowing e.g. terminal emulators to hand off system
bell alerts to the compositor for among other things accessibility
purposes
The new protocol is used when the new config option
bell.system=yes (and the compositor implements the protocol,
obviously).
The system bell is rung independent of whether the foot window has
keyboard focus or not (thus relying on compositor configuration to
determine whether anything should be done or not in response to the
bell).
The new option is enabled by default.
If the compositor sends a keyboard enter event before our window has
been mapped, foot crashes; the enter event triggers a cursor
refresh (hollow -> non-hollow block cursor), which crashes since we
haven't yet allocated a grid.
Fix by no-op:ing the refresh if the window hasn't been configured yet.
Closes#1910
If we call render_refresh, that will wait for a callback to the main
surface. In the case of a flash, the main surface might not get callbacks
if the compositor implements fancy culling optimizations like wlroots
wlr_scene compositors such as sway version >=1.10.
A compositor will not send a frame callback for our main window if it
is fully occluded (for example, by a fully opaque overlay...). This
causes the overlay to stuck.
For regular buffers, it _should_ be enough to *not* hint the
compositor it's opaque. But at least some compositor special cases
single-pixel buffers, and actually look at their pixel value.
Thus, we have two options: implement frame callback handling for the
overlay sub-surface, or ensure we don't use a fully opaque
surface. Since no overlays are fully opaque by default, and the flash
surface is the only one that can be configured to be
opaque (colors.flash-alpha), and since adding frame callback handling
adds a lot of boilerplate code... let's go with the simpler solution
of
Unsure if the protocol imposes a limit (haven't found any
documentation), or if the issue is in the libwayland implementation,
or wlroots (triggers in at least sway+river).
The issue is that setting a too long app-id causes the
compositor (river at least) to peg the CPU at 100%, and stop sending
e.g. frame callbacks to foot.
Closes#1897
From the specification:
The Enter, Tab and Backspace keys will not have release events
unless Report all keys as escape codes is also set, so that the
user can still type reset at a shell prompt when a program that
sets this mode ends without resetting it.
Closes#1892
When building foot with pgo under gentoo's portage, LLVM tried to
generate profile data files directly under system root, triggering
sandbox violation and causing build to fail. Setting this envvar fixes
the issue by explicitly specifying profiling data location.
Reference: https://clang.llvm.org/docs/UsersManual.html#profiling-with-instrumentation
It appears to be slightly more up-to-date with recent Unicode
versions.
In particular, it handles the new "Symbols for Legacy Computing
Supplement" block, introduced in Unicode 16.
Closes#1865
This fixes flickering when foot is forced to double-buffer (e.g when
running under KDE, or smithay based compositors).
Since the damage region isn't updated, the sixel images aren't
included in the memcpy that is done to transfer the last frame's
updated regions to the next frame.
As a result, every other frame will have the sixels, while the others
don't.
Closes#1851
When scanning the grid for all-dirty rows (that we can remove from the
damage region we're about to memcpy from the old frame), check the
row->dirty bit, and skip scanning the cells of that row altogether.
We're only looking for rows where all cells are dirty - those rows can
be removed from the region we copy from the old frame, since the
entire row will be re-rendered anyway.
If a row is clean, it *must* be copied from the old frame.
When trying to set a custom cursor shape, we first validate it. This
is done by checking against known server-side names, and then trying
to load the cursor from the client side cursor theme.
But, if we're using server side names, there is no theme loaded, and
foot crashed.
Fix by checking if we have a theme loaded, and if not, fail the cursor
shape name validation.
In fact, there appears there *is* no escape sequence to set the icon.
Keep most of the logic in place, but in practice, we'll always set the
icon to the app-id. That is, at startup, we set it to the configured
app-id (either from config, or the command line).
OSC-176, which sets the app-id, also updates the icon (to the app-id).
* The toplevel icon is now set to the app-id, unless "overridden" by
OSC-1 or OSC-0.
* Implemented OSC-1
* OSC-0 extended to also set the icon
* Implemented CSI 20 t - report window icon
* Implemented CSI 21 t - report window title
* Implemented CSI 22 ; 1 t - push window icon
* Implemented CS 23 ; 1 t - pop window icon
* Extended CSI 22/23 ; 0 t to also push/pop the icon
* Verify app-id set by OSC-176 is valid UTF-8
* Verify icon set by OSC-0/1 is valid UTF-8
If the xdg-toplevel-icon-v1 protocol is available, and we have the
corresponding manager global, set the toplevel icon to "foot".
Note: we do *not* provide any pixel data. This is by design; we want
to keep things simple.
To be able to provide pixel data, we would have to either:
* embed the raw pixel data in the foot binary
* link against either libpng or/and e.g. nanosvg, locate, at run-time,
the paths to our own icons, and load them at run-time.
* link against either libpng or/and e.g. nanosvg, and, at run-time, do
a full icon lookup. This would also require us to add a config option
for which icon theme to use.
Of the two, I would prefer the first option. But, let's skip this
completely for now.
By providing the icon as a name, the compositor will have to lookup
the icon itself. Compositors supporting icons is likely to already
support this.
So what do we gain by implementing this protocol? Compositors no
longer has to parse .desktop files and map our app-id to find the icon
to use.
There's one question remaining. With this patch, the icon name is
hardcoded to "foot", just like our .desktop files. But, perhaps we
should use the app-id instead? And if so, should we also change the
icon when the app-id changes?
My gut feeling is, yes, we should use the app-id instead, and yes, we
should update the icon when the app-id is changed at run-time.
Summary of changes:
* Make xvsnprintf() static
* restrict-qualify pointer arguments (as done by the libc equivalents)
* Make comments and spec references more thorough
* Remove pointless `n <= INT_MAX` assertion (see comment)
* Use FATAL_ERROR() instead of xassert() (since the assertion is inside
a shared util function but the caller is responsible for ensuring the
condition holds true)
* Change some callers to use size_t instead of int for the return value
(negative returns are impossible and all subsequent uses are size_t)
The updated comments and code were taken (and adapted) from:
49260bb154/src/util/xsnprintf.c (L6-50)
This work was entirely authored by me and I hereby license this
contribution under the MIT license (stated explicitly, so that
there's no ambiguity w.r.t. the original license).
The config system allows setting the scrollback lines to
2**32-1.
However, the total number of grid lines is the scrollback lines plus
the window size, and then rounded *up* to the nearest power of two.
Furthermore, the number of rows is represented with a plain 'int'
throughout the code base.
The largest positive integer that fits in an int is 2**31-1. That
however, is not a power of two.
The largest positive integer, that also is a power of two, that fits
in an int is 2**30, or 1073741824.
Ideally, we'd just cast the line count to a 64-bit integer, and call
__builtin_clzl{,l}() on it, and then take the smallest value of that,
or 2**30. But, for some reason, __builtin_clzl(), and
__builtin_clzll() appears to ignore bits above 32, despite they being
typed to long and long long. Bug?
Instead, ensure we never call __builtin_clz() on anything larger than
2**30.
Closes#1828
That is, skip the reverse DNS naming scheme suggested by the .desktop
specification, and directly match our app-ids ("foot", and
"footclient").
This simplifies .desktop -> window instance mapping, allowing DEs to
match the filenames directly, without having to look at the
StartupWMClass key in the .desktop files.
These are the original names of the .desktop files. There were
renamed (to use the reverse DNS syntax) to please the flathub people,
who *required* this scheme to accept the foot package.
But, since:
* We don't package foot ourselves
* We don't go out of our way to support non-distro packaging schemes
* Flathub still hasn't merged the foot PR (it's now 2 years old)
* There are no know issues in any known DE that prevents a non-reverse
DNS .desktop filename from working
* There are plenty of other applications that doesn't use reverse DNS
names (a very clear majority, in my case)
Let's just revert back to the simpler naming scheme.
Closes#1607
The wording in the original VT340 documentation is vague:
Pixel positions specified as 0 are set to the current background
color.
What does that mean? We _thought_ it meant the current ANSI background
color, as set with e.g. CSI 4x m.
It's still all a bit vague, but seeing that we have separate palettes
for text and graphic (should we?), it doesn't make sense to use the
ANSI background color as the default sixel background color.
So, use entry 0 from the sixel palette instead.
Or put more propertly; if the notification daemon, and the
notification helper used by foot has been configured
properly (i.e. they both support XDG activation tokens), notifications
generated by BEL and OSC-777 will now raise/focus the window when the
default action of the notification is activated - typically by
clicking the notification.
Closes#1822
When the background alpha changes from fully opaque, to transparent,
or vice versa, we need to do more than just repaint the affected
cells.
For example, we need to create new surfaces with the correct pixel
format.
OSC-11 (set background color) already does this, but the same alpha
checking logic was missing in OSC-111 (reset background color).
Fixes#1801
When doing locale fallback, and printing user notifications and log
warnings, better separate the case "locale is invalid" from "locale is
valid but not UTF-8".
Closes#1798
* The spec now defines a couple of "standard" names. Translate these
to the freedesktop compliant names.
* The query response no longer contains 'xdg-names', but instead list
the supported standard names.
* Render button as highlighted only when pointer is above them
* Releasing the mouse button while *not* on the button does *not*
activate the button
When pressing, and holding, a mouse button, the compositor keeps
sending motion events for the surface where the button was pressed,
even if the mouse has moved outside it.
We also don't get any surface leave/enter events.
This meant that the button was rendered as highlighted, and a click
registered, if the user pressed the mouse button while on the button,
and then moved the cursor away from the button before releasing the
button.
This patch fixes it, by checking if the current cursor coordinates
fall within the button surface.
This is how most UIs work.
Note that we (at least on River) don't get any surface enter/leave
events while a button is held. This means we can't detect if the user
pressed the mouse button while on a CSD button, but then moves the
mouse outside. Releasing the mouse button will still activate the CSD
button.
Closes#1787
This implements part of the new 's' (sound) parameter; the 'silent'
value. When s=silent, we set the ${muted} template argument to
"true". It is intended to set the 'suppress-sound' hint:
notify-send --hint BOOLEAN:suppress-sound:${muted}
Notification IDs must only use characters from [a-zA-Z0-9_-+.]
Terminals **must** sanitize ids received from client programs
before sending them back in responses, to mitigate input injection
based attacks. That is, they must either reject ids containing
characters not from the above set, or remove bad characters when
reading ids sent to them.
Foot implements the first: reject IDs containing characters not from
the above set.
This avoids the need for an unused third argument for most xstrjoin()
calls and replaces the cases where it's needed with a more flexible
function. Code generation is the same in both cases, when there are 2
string params and a compile-time known delimiter.
This commit also converts 4 uses of xasprintf() to use xstrjoin*().
See also: https://godbolt.org/z/xsjrhv9b6
* 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.
First, icons have been finalized in the specification. There were only
three things we needed to adjust:
* symbolic names are base64 encoded
* there are a couple of OSC-99 defined symbolic names that need to be
translated to the corresponding XDG icon name.
* allow in-band icons without a cache ID (that is, allow applications
to use p=icon without having to cache the icon first).
Second, add support for the following new additions to the protocol:
* 'f': custom app-name, overrides the terminal's app-id
* 't': categories
* 'p=alive': lets applications poll for currently active notifications
* 'id' is now 'unset' by default, rather than "0"
* 'w': expire time (i.e. notification timeout)
* "buttons": aka actions. This lets applications add additional (to
the terminal defined "default" action) actions. The 'activated' event
has been updated to report which button/action was used to activate
the notification.
To support button/actions, desktop-notifications.command had to be
reworked a bit.
There's now a new config option:
desktop-notifications.command-action-arg. It has two template
arguments ${action-name} and ${action-label}.
command-action-arg gets expanded for *each* action.
${action-name} and ${action-label} has been replaced by ${action-arg}
in command. This is a somewhat special template, in that it gets
replaced by *all* instances of the expanded actions.
This 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.
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.
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\\'
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.
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.
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
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.
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\\'
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.
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 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.
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/
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
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.
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.
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
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.
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
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.
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;
| ^~~~~
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.
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.
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.
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.
The things affecting which ASCII printer we use have grown...
Instead of checking everything inside term_update_ascii_printer(), use
a bitfield.
Anything affecting the printer used, must now set a bit in this
bitfield. This makes term_update_ascii_printer() much faster, since
all it needs to do is check if the bitfield is zero or not.
Only clear OSC-8 hyperlinks at the target columns if we don't have an
active OSC-8 URI. This corresponds to normal VT attributes; the
currently active attributes are set, and all others are cleared.
Handle styled underlines in the same way
When doing an interactive resize, we create a small grid copy of the
current viewport, and then do a non-reflow resize.
When the interactive resize is done, we do a proper reflow. This is
for performance reasons.
When creating the viewport copy, we also need to copy the styled
underlines. Otherwise, styled underlines will be rendered as plain
underlines *while resizing*.
This was originally contributed by @kraftwerk28 in
https://codeberg.org/dnkl/foot/pulls/1099
Here, we re-use the rendering logic only, as attribute tracking has
been completely rewritten.
This is work in progress, and fairly untested.
This adds initial tracking of styled underlines. Setting attributes
seems to work (both color and underline style). Grid reflow has *not*
been tested.
When rendering, style is currently ignored (all styles are rendered as
a plain, legacy underline).
Color however, *is* applied.
Right now (Unicode 15.1), all valid variation sequences consist of a
single Unicode codepoint (followed by either VS-15 or VS-16).
Don't assume this is the case.
We don't actually handle longer sequences. But now we at least catch
such escapes, and error out.
Lookups in this table is not performance critical at all.
Thus, let's compact it to bring down the binary size of foot.
This brings the size of each entry down from 9 bytes to 6, bringing
the size of the whole thing down from 1647 bytes to 1098 bytes, saving
us 549 bytes.
At compile time, build a lookup table from the Unicode data file
'emoji-variation-sequences.txt'.
At run-time, when we detect a VS-15/16 sequence, do a lookup in this
table, and enforce the variation selector iff the sequence is valid.
Closes#1742
When the compositor sends a new keymap, don't reset the XKB compose
state.
This is done by initializing the XKB context, along with the compose
state, when binding the seat, instead of in keymap().
Then, in keymap(), simply stop destroying the old xkb state. Only
destroy, and re-create the keymap state.
Closes#1744
This implements high resolution mouse wheel scroll events. A "normal"
scroll step corresponds to the value 120. Anything less than that is a
partial scroll step.
This event replaces axis_discrete(), when we bind wl_seat v8 (which we
now do, when available).
We calculate the number of degrees that is required to scroll a single
line, based off of the scrollback.multiplier value.
Each high-res event accumulates, until we have at least the number of
degress required to scroll one, or more lines.
The remaining degrees are kept, and added to in the next scroll event.
Closes#1738
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
Don't retry memfd_create() without MFD_NOEXEC_SEAL is 0.
The overall logic is this:
* Try memfd_create() with MFD_NOEXEC_SEAL
* If that fails (which it does, on older kernels), try without the flag
If compiling against an older kernel, or on a system that doesn't
support the noexec seal, MFD_NOEXEC_SEAL is 0.
In this case, there's little point in retrying memfd_create a second
time, with the exact same set of flags.
Don't re-create the single-pixel buffer, unless necessary.
The buffer itself doesn't have a size. That means we can re-use the
buffer if the last frame's overlay style matches the current frame's
style.
What we *do not* know is whether the current frame's size is the same
as the last frame's.
This means we still have to set the viewport destination, and commit
the surface.
The unicode-mode, and flash overlays are single color buffers. This
means we can use the single-pixel buffer protocol.
It's undefined whether the compositor will release the buffer or not;
to make things easier, simply destroy the buffer as soon as we've
committed it.
Note that since compositors don't necessarily release single-pixel
buffers, we can't plug them into our own buffer interface. This means
we can't use buffer pointers to check if we can re-use the previous
buffer (i.e. we can skip comitting a new buffer), or if we have to
create a new one.
It's _almost_ enough to just check if the last overlay style is the
same as the current one. Except that that doesn't take window resizes
into account...
This fixes an issue where entering unicode-mode in one foot client,
also enabled unicode-mode on other foot clients. Both
visually (although glitchy), and in effect.
The reason the state was originally in the seat objects, was to fully
support multi-seat. That is, one seat/keyboard entering unicode-mode
should not affect other seats/keyboards.
The issue with this is that seat objects are Wayland global. Thus, in
server mode, all seat objects are shared between the foot clients.
There is a similarity with IME, which also keeps state in the
seat. There's one big difference, however, and that is IME has Wayland
native enter/leave events, that the compositor emits when windows are
focused/unfocused. These events allow us to reset IME state. For our
own Unicode mode, there is nothing similar.
This patch moves the Unicode state from seats, to the terminal
struct. This does mean that if one seat/keyboard enters Unicode mode,
then *all* seats/keyboards will affect the unicode state. This
potential downside is outweighed by the fact that different foot
clients no longer affect each other.
Closes#1717
That is, instead of sometimes replying with a "source" encoded
string (where e.g. '\E' are returned just like that, and not as an
actual ESC), always unescape all string values.
This also includes \n \r \t \b \f \s, \^ \\ \ \:, as well as ^x-styled
escapes.
Closes#1701
A compositor may unmap, and then remap the window, for example when
the window is minimized, or if the user switches workspace.
With DPI aware rendering, we *need* to know on which output we're
mapped, in order to use the correct DPI. This means the first frame we
render, before being mapped, always guesses the DPI.
In an unmap/map sequence, guessing the wrong DPI means the window will
flicker.
Fix by stashing the last used DPI value, and use that instead of
guessing.
This means the *only* time we _actually_ guess the DPI, is the very
first frame, when starting up foot.
Changing pan/pad changes the sixel's aspect ratio. While I don't know
for certain what a real VT340 would do, I suspect it would change the
aspect ratio of all subsequent sixels, but not those already emitted.
The way we implement sixels in foot, makes this behavior hard to
implement. We currently don't resize the image properly if the aspect
ratio is changed, but not the RA area. We have code that assumes all
sixel lines have the same aspect ratio, etc.
Since no "normal" applications change the aspect ratio in the middle
of a sixel, simply disallow it, and print a warning.
This also fixes a crash, when writing sixels after having modified the
aspect ratio.
In some cases, a sixel may be resized vertically, while still having a
zero-width. In this case, the resize operations are short-cutted, and
no actual allocations are done.
However, we forgot to set 'alloc_height' when doing so. As a result,
the trimming code (when the sixel is "done"), trimmed away the entire
sixel.
When auto-wrap is disabled, a multi-column character may be printed on
a line that doesn't fit the entire character. That is, the "spacers"
we print, as place holders in the columns after the first one, may
reach outside the grid.
We did (try to) check for this, but the check was off by one. Meaning,
we could, in some cases, print outside the grid.
We deviate slightly from the specification, in that we don't assume a
preferred buffer scale of 1. Instead, we "guess" the scale *until we
receive a surface_preferred_buffer_scale event.
Because of this, we don't need the has_wl_compositor_v6 member, as
it's enough to check if we have a non-zero 'preferred buffer scale'.
This option controls how we render the cursor when the terminal window
is unfocused.
Possible values are:
* hollow: the default, and how we rendered the cursor before this
patch.
* unchanged: render the cursor exactly the same way as when the window
is focused.
* none: do not render any cursor at all
Closes#1582
If we're the ones initiating shutdown, start by sending SIGHUP. Only
if the client application does not terminate, send SIGTERM (and if it
still refuses to terminate, send SIGKILL).
Also reduce the timeout between the signals from 60s to 30s.
Unless --pty has been used, we do *not* want to shutdown the terminal
when the PTY is closed by the client application; we want to wait for
the client application to actually terminate.
This was the behavior before the --pty patch.
This was changed in the --pty patch, since then, we don't *have* a
client application. That is, foot has not forked+exec:ed anything. The
only way to trigger a shutdown (from the client side) is to close the
PTY.
This patch restores the old behavior, when --pty is *not* used.
Closes#1666
Before this patch, we would, in some cases, fallback to the surface
preferred (not fractional) scaling, even though the compositor hadn't
actually published a preferred buffer scale; the presence of a v6
compositor interface doesn't mean we've actually received a preferred
scale yet.
These are new capabilities, recently added to ncurses. Applications
are supposed to use these, instead of XM (to enable focus events). So,
remove "CSI ? 1004h" from XM.
wmemset() is heavily optimized, and in some cases, *much* faster than
manually initializing the new image pixels.
Furthermore, assume calloc() is better at initializing memory to zero,
and use that when initializing new pixels in a transparent image.
When trimming trailing empty rows from the final image, handle the RA
region correctly:
* If image is transparent, trim down to the last non-empty pixel row,
regardless of whether it is inside or outside the RA region.
* If image is opaque, trim down to either the last non-empty pixel
row, or the RA region, whatever is the largest height.
The raster attributes is, really, just a way to erase an area. And, if
the sixel is transparent, it's a nop.
The final text cursor position depends, not on our image size (which
is based on RA), but on the final graphical cursor position.
However, we do want to continue using it as a hint of the final image
size, to be able to pre-allocate the backing buffer.
So, here's what we do:
* When trimming trailing transparent rows, only trim the *image*, if
the graphical cursor is positioned on the last sixel row, *and* the
sixel is transparent.
* Opaque sixels aren't trimmed at all, since RA in this acts as an
erase that fills the RA region with the background color.
* The graphical cursor position is always adjusted (i.e. trimmed),
since it affects the text cursor position.
* The text cursor position is now calculated from the graphical cursor
position, instead of the image height.
After emitting a sixel, place the cursor on the character row touched
by the last sixel. The last sixel _may_ not be a multiple of 6
pixels, *if* the sixel had an explicit width/height set via raster
attributes.
This is an intended deviation from the DEC cursor placement algorithm,
where the cursor is placed on the character row touched by the last
sixel's *upper* pixel.
The adjusted algorithm implemented here makes it much easier for
applications to handle text-after-sixels, since they can now simply
assume a single text newline is required to move the cursor to a
character row not touched by the sixel.
Virtual machine monitor programs (e.g. QEMU, Cloud Hypervisor) expose
guest consoles as PTYs. With this patch, foot can access these guest
consoles.
Usually, the program used for accessing these PTYs is screen, but
screen is barely developed, doesn't support resizing, and has a bunch
of other unrelated stuff going on. It would be nice to have a
terminal emulator that properly supported opening an existing PTY.
The VMM controls the master end of the PTY, so to the other end (in
this case foot), it just behaves like any application running in a
directly-opened PTY, and all that's needed is to change foot's code to
support opening an existing PTY rather than creating one.
Co-authored-by: tanto <tanto@ccc.ac>
Before this patch, we reported scaled pixel values. This was rather
useless, since applications have no way of getting the scaling factor,
to "scale up" e.g. images.
Furthermore, the most common use of these queries are probably to
calculate the dimensions to use when emitting sixels.
Closes#1643
This functions reads the four top/left/bottom/right parameters,
validates them, and converts relative row numbers to absolute.
Returns true if the params are valid, otherwise false.
* DECCARA - change attributes in rectangular area
* DECRARA - reverse attributes in rectangular area
* DECCRA - copy rectangular area
* DECFRA - fill rectangular area
* DECERA - erase rectangular area
Not implemented:
* DECSERA - selective erase rectangular area
This function prints a single, non-double width, character to the
grid. It handles OSC-8 hyperlinks, but does not:
* update the cursor location
* erase sixels
* Store pointer to current pixel (i.e. pixel we're about to write to),
instead of a row-byte-offset. This way, we don't have to calculate the
offset into the backing image every time we emit a sixel band.
* Pass data pointer directly to sixel_add_*(), to avoid having to
calculate an offset into the backing image.
* Special case adding a single 1:1 sixel. This removes a for loop, and
simplifies state (position) updates. It is likely LTO does this for
us, but this way, we get it optimized in non-LTO builds as well.
In resize_vertically(), we assumed a sixel is 6 pixels tall. This is
mostly true, but not for non-1:1 sixels. Or, to be more precise, not
for sixels where 'pan' != 1.
This caused us to allocate too little backing memory, resulting in a
crash when we later tried to write to the image.
The kitty keyboard specification has been updated/clarified yet
again. Locked modifiers are to be ignored if the key event would
result in plain text without the locked modifier being enabled.
In short, locked modifiers are included in the set of modifiers
reported in a key event. But having a locked modifier enabled doesn't
turn all key events into CSIu sequences.
For example, with only the disambiguate mode enabled, pressing 'a', or
'shift+a' results in a/A regardless of the state of Caps- or NumLock.
But 'ctrl+a', which always results in a CSIu, will have a different
modifier list, depending on whether Caps- or NumLock are enabled.
This fixes an issue where some key combinations resulted in different
output (e.g. escape code vs. plain text) depending on the state of
e.g. the NumLock key. One such example is Shift+space. Another example
is Shift+BackSpace.
This patch also removes the hardcoded CapsLock filter, when
determining whether a key combo produces text or not, and instead uses
the locked modifiers as reported by XKB.
Before this patch, we used legacy X11 xcursor names, and didn't really
have any fallback handling in place (we only tried to fallback to
"xterm", regardless of which cursor shape we were trying to load).
This patch changes two things:
1. Improved fallback support. cursor_shape_to_string() now returns a
list of strings. This allows us to have per-shape fallbacks, and any
number of fallbacks.
2. We prefer CSS xcursor names over legacy X11 names.
render_xcursor_update() is called when we've loaded a new xcursor
image, and needs to display it. The reason it's not pushed to the
compositor immediately is to ensure we don't flood the Wayland socket
with xcursor updates.
Normally, it's only called when we *succeed* to load a new xcursor
image. I.e. if we try to load a non-existing xcursor image, we never
schedule an update.
However, we _can_ still end up in render_xcursor_update() without a
valid xcursor image. For example, we have loaded a valid xcursor
image, and scheduled an update. But before the update runs, the user
moves the cursor, and we try to load a new xcursor image. If it fails,
we crash when the previously scheduled update finally runs.
Closes#1624
When erroring out due to a key combo being "empty", we incorrectly
tried to free one key binding. This is because 'used_combos' is
initialized to '1'. And it should, but an empty key binding is a
special case.
Fixes a test failure, and closes#1620
When kitty keyboard is enabled, pressing a modifier key will clear the
text selection. This makes it difficult to copy text because the
selection clears as soon as the user presses "ctrl".
Tested-by: Robin Jarry <robin@jarry.cc>
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
This fixes:
a) a compilation error with -Dgrapheme-clustering=disabled
b) ensures U+FE0F does *not* allocate a two cells when grapheme
clustering has been disabled (either compile time, in config, or
run-time).
If scrollback.lines == 0, and the window size (number of rows) is a
power of two, all rows are always visible. I.e. there is no scrollback
history.
This threw off the scrollback erase logic, causing visible rows to be
erased, and set to NULL. This triggered a crash when trying to update
the view.
Closes#1610
When an output property (such as scaling factor) has changed, we need
to call render_resize() to ensure the window surface is correct (for
example, we may have to change its scale).
The width/height parameters are in *logical* pixels (i.e. already
scaled). For render_resize() to work correctly when the scale is being
changed, it needs to be called with *current* logical size. This means
we need to scale our current width/height using the *old* scaling
factor.
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
This boolean isn't needed. The idea was probably to not re-program the
timer unnecessarily, or even to prevent it from being moved forward in
time indefinitely.
However, the logic has (probably) gone through some changes, that now
makes it irrelevant.
The timer isn't moved forward indefinitely; it is always set to 8ms
from the last title update. The closer we get to that point in time,
the smaller the timeout we set.
Now, is_armed _did_ prevent the timer from being re-programmed. But
that tiny performance tweak isn't really necessary, as the title
should, in normal cases, not be set that often anyway.
Setting the title ultimately leads to a call to
xdg_toplevel::set_title(). It is a protocol violation to try to set a
title that contains an invalid UTF-8 sequence:
The string must be encoded in UTF-8.
Closes#1552
To enable 8-bit meta mode, we need to:
* disable "send ESC when meta modifies a key" (private mode 1036)
* enable "8-bit meta mode" (private mode 1034)
rmm reverses the above.
Closes#1584
For the purpose of matching key bindings, "significant" modifiers are
no more.
We're really only interested in filtering out "locked"
modifiers. We're already doing this, so there's no need to *also*
match against a set of "significant" modifiers.
Furthermore, we *never* want to consider locked keys (e.g. when
emitting escapes to the client application), thus we can filter those
out already when retrieving the set of active modifiers.
The exception is the kitty keyboard protocol, which has support for
CapsLock and NumLock. Since we're already re-retrieving the "consumed"
modifiers (using the GTK style, rather than normal "XKB" style, to
better match the kitty terminal), we might as well re-retrieve the
effective modifiers as well.
That is, allow custom modifiers (i.e. other than ctrl/shift/alt etc)
in key bindings.
This is done by no longer validating/translating modifier names to
booleans for a pre-configured set of modifiers (ctrl, shift, alt,
super).
Instead, we keep the modifier *names* in a list, in the key binding
struct.
When a keymap is loaded, and we "convert" the key binding, _then_ we
do modifier translation. For invalid modifier names, we print an
error, and then ignore it. I.e. we no longer fail to load a config due
to invalid modifier names.
We also need to update how we determine the set of significant
modifiers. Any modifier not in this list will be ignored when matching
key bindings.
Before this patch, we hardcoded this to shift/alt/ctrl/super. Now, to
handle custom modifiers as well, we simply treat *all* modifiers
defined by the current layout as significant.
Typically, the only unwanted modifiers are "locked" modifiers. We are
already filtering these out.
Starting with kitty 0.32.0, the modifier bits during modifier key
events behave differently, compared to before. Or, rather, they have
now been spec:ed; before, behavior was different on e.g. MacOS, and
Linux.
The new behavior is this:
On key press, the modifier bits in the kitty key event *includes* the
pressed modifier key.
On key release, the modifier bits in the kitty key event does *not*
include the released modifier key.
In other words, The modifier bits reflects the state *after* the key
event.
This is the exact opposite of what foot did before this patch.
The patch is really pretty small: in order to include the key in the
modifier set, we simulate a key press to update the XKB state, using
xkb_state_uppate_key(). For key pressed, we simulate an XKB_KEY_DOWN
event, and for key releases we simulate an XKB_KEY_UP event.
Then we re-retrieve the modifers, both the full set, and the consumed
set.
Closes#1561
```
../slave.c: In function 'slave_spawn':
../slave.c:441:21: error: 'custom_envp' undeclared (first use in this function); did you mean 'custom_env'?
441 | add_to_env(&custom_envp, "TERMINFO", FOOT_TERMINFO_PATH);
| ^~~~~~~~~~~
| custom_env
../slave.c:441:21: note: each undeclared identifier is reported only once for each function it appears in
```
When launching footclient with -E,--client-environment the environment
variables that should be set by foot, wasn't.
Those variables are:
* TERM
* COLORTERM
* PWD
* SHELL
and all variables defined by the user in the [environment] section in
foot.ini.
In the same way, we did not *unset* TERM_PROGRAM and
TERM_PROGRAM_VERSION.
This patch fixes it by "cloning" the custom environment, making it
mutable, and then adding/removing the variables above from it.
Instead of calling setenv()/unsetenv() directly, we add the wrapper
functions add_to_env() and del_from_env().
When *not* using a custom environment, they simply call
setenv()/unsetenv().
When we *are* using a custom environment, add_to_env() first loops all
existing variables, looking for a match. If a match is found, it's
updated with the new value. If it's not found, a new entry is added.
del_from_env() loops all entries, and removes it when a match is
found. If no match is found, nothing is done.
The mutable environment is allocated on the heap, but never free:d. We
don't need to free it, since it's only allocated after forking, in the
child process.
Closes#1568
When cloning a config struct, the env_vars tllist wasn't correctly
copied. We did correctly iterate and duplicate all old entries, but we
did *not* reset the list in the cloned struct before doing so.
This meant the list contained entries shared with the original list,
causing double free:s in --server mode.
764248bb0d modified
wayl_surface_scale_explicit_width_height() to not assert the surface
size is valid for the given scaling factor. This, since that function
is only used when scaling a mouse pointer surface.
However, that commit only updated the code path run when fractional
scaling is available (i.e. when the compositor implements the
fractional-scale-v1 protocol).
The legacy code path, that does integer scaling, was still asserting
the surface width/height were divisible with the scaling factor.
For the same reasons this isn't true with fractional scaling
available, it's not true with integer scaling. Fix by skipping the
assertions.
This patch also converts the assertions to more verbose BUG() calls,
that prints more information on the numbers involved.
Closes#1573
It's not critical.
Fixes
../slave.c: In function ‘slave_spawn’:
../slave.c:410:9: error: ignoring return value of ‘chdir’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
410 | chdir("/");
| ^~~~~~~~~~
With this patch, the terminal process now changes PWD to / after
spawning the client application.
This ensures the terminal process itself does not "lock" a
directory. For example, we may keep a mount point from being
unmounted.
Closes#1528
conf file descriptor is closed once again during cleanup at the end of
config_load() if descriptor >= 0. avoid double closing by assigning
negative value to fd after first close.
by the time second close happens some other descriptor might be opened
reusing previous number ie it might happen during foot server startup
when syslog message is logged between one close and the other. in this
particular situation, as of this writing, it considers fd=3 for which
following events apply:
1. conf file is opened and fclosed()
2. warning is logged with syslog which leads to opening socket to
/dev/log which is kept open by glibc (gets fd=3)
3. second close during config_load() closes /dev/log socket descriptor
4. epoll_create() in fdm.c reuses fd=3 again
5. another message is being logged with syslog. glibc notices sendto()
failure on saved /dev/log descriptor hence it closes it and opens
new one
Due to epoll descriptor closure foot starts a chain of errors that
lead to startup failure.
Fixes#1531
Reject color values that aren't in either RGB, or ARGB format. That
is, color values that aren't hexadecimal numbers with either 6 or 8
digits.
Also, if a color value is allowed to have an alpha component, and the
user left it out, default to 0xff (opaque) rather than 0x00 (fully
transparent).
Closes#1526
An opaque sixel that isn't a multiple of the cell size will have some
cells partially visible (either the entire last row, the entire last
column, or both).
These must be rendered before blitting the sixel.
f5f2f5a954 introduced a regression,
where all such cells were rendered as if the cursor was there, giving
them the wrong appearance.
Closes#1520
Pass a damage region to render_row()/render_cell() when rendering
partially visible cells underneath a sixel.
This ensures the affected regions are later reported as 'damaged' to
the Wayland compositor.
Closes#1515
When erasing a sixel, the cells underneath it must be marked as
'dirty', in order to be re-rendered.
This was not being done correctly; the for loop loops *from* the start
col, meaning the *end* col is *not* sixel->pos.col, as that's
the *number* of columns, not the *end* column.
MFD_NOEXEC_SEAL was introduced in linux 6.3. Kernels before that
will *reject* memfd_create() calls that set it.
This caused foot to exit (i.e. not start at all), when compiled on
linux >= 6.3, but run on linux < 6.3.
We _do_ want to use MFD_NOEXEC_SEAL, since a) our memory mapped really
shouldn't be executable, and b) to silence a warning on linux >= 6.3.
To handle all cases, first try *with* MFD_NOEXEC_SEAL. If that fails
with EINVAL, retry *without* it.
Closes#1514
When using the font's own line-height, simply set the baseline
'descent' pixels above the bottom of the cell.
This fixes an issue where some fonts appeared "glued" to the top of
the cell, and sometimes getting partially clipped.
This reverts commit fd813d0e6c.
The intent of the reverted commit was to align font height calculation
with cell height calculation. However, it turns out this breaks some
fonts. Typically those with large:ish differences in their 'height'
attribute, and their ascent+descent value.
Closes#1511
Before this patch. Wayland surface damage tracking was done on a
per-row basis. That is, even if just one cell was updated, the entire
row was "damaged".
Now, damage is per cell. This hopefully results in lower latencies in
many use cases, and especially on high DPI monitors.
The has_wrapped_around_{right,left} functions were mixed up, causing
false positives and false negatives, resulting in bad search matches.
Also make all search_extend_find* functions return a boolean; false
means no change in the selection. In this case, we can skip trying to
extend the selection, and updating the UI.
This patch adds the following new search key bindings:
* extend-char (shift+right)
* extend-line-down (shift+down)
* extend-backward-char (shift+left)
* extend-backward-to-word-boundary (ctrl+shift+left)
* extend-backward-to-next-whitespace (ctrl+shift+alt+left)
* extend-line-up (shift+up)
They can be used to extend the search match (i.e. the selection).
This patch also adds an initial set of key bindings to scroll in the
scrollback history:
* scrollback-up-page
* scrollback-down-page
These work just like the key bindings for the normal mode. Also note
that it was already possible to scroll using the mouse.
This patch also fixes a couple of search mode bugs:
* crashing when a search match ends in the last column
* grapheme clusters not being matched correctly
* Search match not being "extendable" after a pointer leave event
* A few others, related to either large matches, or extending matches
after moving the viewport.
There are still a couple of (known) issues:
* A search match isn't correctly highlighted if its *starting* point
is outside the viewport.
* Extending the match to end of the scrollback (i.e. the most recent
output) is simply buggy.
Related to #419
Effective from Linux 6.3.0 onward, this creates the memfd without
execute permissions and prevents that setting from ever being changed.
This is a defense-in-depth security measure and prevents a respective
kernel warning from being emitted.
See https://lwn.net/Articles/918106/ for more information.
Seen on plasma; monitor is turned off, and then back on again. Before
the "new" output global is emitted, the compositor calls
fractional_scale::preferred_scale().
This results in a call to get_font_dpi(), where we crash, since it
assumes there is at least one monitor available.
Fix by falling back to a DPI of 96.
Hopefully closes#1498
Previously, foot -a test wouldn't actually set the app ID if there was
no config file and the defaults were used, which was very
counterintuitive.
Now, load_config() will carry on until the end, even if there's no
config file, so overrides still work.
This implements private mode 2027 - grapheme cluster processing, as
defined in the "Terminal Unicode Core"[1] specification.
Internally, we just flip the already existing option "grapheme
shaping". Since it's now runtime changeable, we need a copy of it in
the terminal struct, rather than referencing the conf object.
[1]: 13fc5a8993/spec/terminal-unicode-core.tex (L50-L53)
When we receive an XTGETTCAP query, where the capability is not
correctly hex encoded, ignore it.
Before this patch, we echo:ed it back to the TTY inside an error
resonse.
Before this patch, the file://<host> prefix was stripped from URIs,
when the hostname matched the current host (that is, for "local"
URLs).
Unfortunately, the way this was done caused other parts of the URI to
be stripped as well. For example, the 'query' and 'fragment' parts.
This patch simply removes all special casing of file:// URIs.
Since the URL is passed to a generic opener (i.e. we don't have a
special opener application for file:// URIs), the opener helper must
handle the file:// prefix anyway.
Closes#1474
It's possible for token to be set when the compositor doesn't support
activation, and this caused a segfault. For example, this can happen
when overriding WAYLAND_DISPLAY to point to a compositor that doesn't
support activation, in a terminal running under one that does, and so
has set XDG_ACTIVATION_TOKEN.
This patch changes the default of triple clicking, from selecting the
current logical row, to first trying to select the contents of the
quote under the cursor, and if failing to find a quote, selecting the
current row (like before).
This is implemented by adding a new key binding, 'select-quote'.
It will search for surrounding quote characters, and if one is found
on each side of the cursor, the quote is selected. If not, the entire
row is selected instead.
Subsequent selection operations will behave as if the selection is
either a word selection (a quote was found), or a row selection (no
quote found).
Escaped quote characters are not supported: "foo \" bar" will match
'foo \', and not 'foo " bar'.
Mismatched quotes are not custom handled. They will simply not match.
Nested quotes ("123 'abc def' 456") are supported.
Closes#1364
Un-grabbed wheel events are now passed through the mouse binding
matching logic, instead of being hardcoded to scrolling the terminal
contents.
They are mappable through the BTN_BACK and BTN_FORWARD buttons.
Since they're not actually button *presses*, they never generate a
click count other than 1. This limitation is documented, but not
checked in the config. This means it's possible to create bindings
like "BTN_BACK+3" (i.e. triple "click"). They will however never
trigger.
The old, hardcoded logic is now accessible through the new
scrollback-up-mouse and scrollback-down-mouse mouse
bindings. They (obiously) default to BTN_BACK and BTN_FORWARD,
respectively.
Example usage: keep the default of scrolling terminal contents with
the wheel, when used without modifiers, but map Control+wheel to font
zoom in/out:
[mouse-bindings]
font-increase=Control+BTN_FORWARD
font-decrease=Control+BTN_BACK
(this also keeps the default key bindings to zoom in/out; ctrl-+ and
ctrl+-)
Closes#1077
No longer inhibits touch event handling when terminal window
has pointer focus. Instead, inhibit touch event when at least
one pointer button is held down.
This change improves user experience when using foot with both
a mouse and a touchscreen.
Closes#1428.
* Skip spacer cells. This fixes an issue where characters following a
double-width character weren't detect properly.
* Unpack grapheme clusters (i.e. cells with multiple codepoints), and
iterate all their codepoints.
Closes#1465
The foot window may, for various reasons, become completely
unmapped (that is, being removed from all outputs) at run time.
One example is wlroots based compositors; they unmap all other windows
when an opaque window is fullscreened.
21d99f8dce introduced a regression,
where instead of picking the scaling factor from one of the available
outputs (at random), we started falling back to '1' as soon as we were
unmapped.
This patch restores the original logic, but also improves upon it.
As soon as a scaling factor has been assigned to the window, we store
a copy of it in the term struct ('scale_before_unmap').
When unmapped, we check if it has a valid value (the only time it
doesn't is before the initial map). If so, we use it.
Only if it hasn't been set do we fall back to picking an output at
random, and using its scaling factor.
Closes#1464
This fixes services in Wayland session where WAYLAND_DISPLAY is only
imported into the systemd user instance environment after
graphical-session.target is reached (such as GNOME).
../vt.c:648:13: runtime error: signed integer overflow: 3924432811 * 2654435761 cannot be represented in type 'long'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../vt.c:648:13 in
Closes#1456
Rewrite render_osd(), and instead of passing in an y-offset, let
render_osd() itself center the text inside the OSD buffer.
This is done using the same baseline calculation term_font_baseline()
does, except we use the buffer height instead of the line height.
Note that most OSDs are sized based on the line height...
Closes#1430
Instead of special casing configuration affecting command line
options (like --font, --fullscreen, --maximized etc), translate them
to overrides, and let the configuration system handle them.
This also fixes an issue where -f,--font did not set csd.font, if
csd.font were otherwise unset.
../vt.c:648:13: runtime error: signed integer overflow: 3924432811 * 2654435761 cannot be represented in type 'long'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../vt.c:648:13 in
Closes#1456
Rewrite render_osd(), and instead of passing in an y-offset, let
render_osd() itself center the text inside the OSD buffer.
This is done using the same baseline calculation term_font_baseline()
does, except we use the buffer height instead of the line height.
Note that most OSDs are sized based on the line height...
Closes#1430
Instead of special casing configuration affecting command line
options (like --font, --fullscreen, --maximized etc), translate them
to overrides, and let the configuration system handle them.
This also fixes an issue where -f,--font did not set csd.font, if
csd.font were otherwise unset.
Before this patch, we didn’t ensure width and height were valid for
the current scaling factor, when fractional scaling _is_
available. That is, we didn’t ensure the width/height values
multiplied back to their original values after dividing with the
scaling factor.
Closes#1446
This function is only called directly when scaling the mouse
pointer. The mouse pointer is never guaranteed to have a valid width
and height, so skip the width/height assertions for it.
* Ensure buffer sizes are valid. That is, ensure that
size / scale * scale == size.
* Do size calculation of the window geometry in the same way we
calculate the CSD offsets.
And calculation of compounded offsets/widths/heights, to compensate
for compositor rounding when positioning and scaling/sizing
subsurfaces.
Closes#1441
When instantiating the viewport for a pointer surface, we didn't first
check if the compositor implements the viewporter interface.
This triggered a crash when a) foot was compiled with fractional
scaling, and b) the compositor did not implement the viewporter
interface.
Closes#1444
This defines the base name of the generated terminfo files. It
defaults to the value of -Ddefault-terminfo (i.e. 'foot')
Example:
meson -Ddefault-terminfo=foot-bananas -Dterminfo-base-name=foot-apples
The generated terminfo files will be
* terminfo/f/foot-apples
* terminfo/f/foot-apples-direct
The default value of $TERM will be 'foot-bananas'
By how much to increase the luminance when brightening bold
fonts. This was previously hard-coded to a factor of 1.3, which is now
the default value of the new config option.
Closes#1434
render_osd() shouldn't use term_font_baseline().
This is because term_font_baseline() uses the line height to determine
the position, while render_osd() renders to surfaces that aren't sized
like the grid.
This fixes a regression, where the CSD title were sometimes rendered
too high up, and sometimes too low.
* In all calls to wl_subsurface_set_position()
* (wp_viewport_set_destination() already does this)
* Whenever we use the scale to calculate margins (search box,
scrollback indicator etc)
* Since the scaling factor is stored as a float (and not a double),
use roundf() instead of round()
Monitor DPI depends on information from both the wl_output and the
xdg_output interfaces.
Before this patch, terminals were only updated after changes to the
wl_output interfaces (thus depending on xdg output changes being
pushed by the compositor before wl_output changes).
That assumption (xdg_output happening before wl_output) isn’t always
true.
This patch fixes the issue by updating the terminals in the
xdg_output’s “done” event.
Closes#1431
This patch detects invalid codepoints in the UTF-8 EDxxxx range, and
the F4xxxxxx range.
Note that we still allow the E0xxxx and F0xxxxxx ranges. These
contains overlong encodings. We allow them, because they still decode
into correct UTF-32.
Closes#1423
- wayland-instance template target was a mistake.
Systemd does not support simultaneous same user session, so stop
trying to go against that.
- Only start systemd units in Wayland environments.
Even if WAYLAND_DISPLAY / XDG_RUNTIME_DIR are defined, if we can't
find the corresponding socket, we fallback to the path used when they
are not defined.
Do not insert existing positions into the tab stop list.
This prevents a performance issue when iterating through
an extremely long tab stop list.
Also corrects the behaviour of CBT.
The wayland protocol recommends (or mandates?) that compositors render
a black background behind fullscreened transparent windows. I.e. you
never see what’s _actually_ behind the window.
So, if you have a white, but semi-transparent background in foot,
it’ll be rendered in a shade of gray.
Given this, it’s better to simply disable transparency while we’re
fullscreened. That way, we at least get the "correct" background
color.
Closes#1416
This fixes a crash-on-exit on compositors that emit a _"keyboard
leave"_ event when a surface is unmapped.
In our case, destroying the window (where we unmap it) in
term_destroy(), lead to a crash in term_mouse_grabbed(), due to
key_binding_for() returning NULL.
The call chain in this is case is, roughly:
term_destroy() ->
wayl_win_destroy() ->
keyboard_leave() ->
term_xcursor_update_for_seat() ->
term_mouse_grabbed()
Break out the logic that updates the terminal’s scaling factor value,
from render_resize(), to a new function, term_update_scale(). This
allows us to update the scaling factor without a full grid resize.
We also change how we pick the scaling factor (when fractional scaling
is not in use). Before, we’d use the highest scaling factor from all
monitors we were mapped on. Now, we use the scaling factor from the
monitor we were *last* mapped on.
Then, add a boolean parameter to term_set_fonts(), and when
false, *don’t* call render_resize_force().
Also change term_font_dpi_changed() to only return true if the font
was changed in any way.
Finally, rewrite update_term_for_output_change() to:
* Call term_update_scale() before doing anything else
* Call render_resize{,_force} *last*, and *only* if either the scale
or the fonts were updated.
This fixes several things:
* A bug where we failed to update the fonts when fractional scaling
was in use, and we guessed the initial scale/DPI wrong. The bug
happened because updated the internal "preferred" scale value, and a
later call to render_resize() updated the terminal’s scale value,
but since that code path didn’t call term_font_dpi_changed() (and it
shouldn’t), the fonts weren’t resized properly.
* It ensures we only resize the grid *once* when the scaling factor,
or DPI is changed. Before this, we’d resize it twice. And this
happened when e.g. dragging the window between monitors.
With legacy scaling, we need to use a "scaled", or "logical" DPI
value, that is basically the real DPI value scaled by the monitor’s
scaling factor.
This is necessary to compensate for the compositor downscaling the
surface, for "fake" fractional scaling.
But with true fractional scaling, *we* scale the surface to the final
size. This means we should *not* use the scaled DPI, but the monitor’s
actual DPI.
To facilitate this, store both the scaled and the unscaled DPI value
in the monitor struct.
This patch also changes how we pick the DPI value. Before, we would
use the highest DPI value from all the monitors we were mapped
on. Now, we use the DPI value from the monitor we were *last* mapped
on (typically the window we’re dragging the window *to*).
When enabled, double-clicking the CSD titlebar will (un)maximize the
window.
Defaults to ‘yes’ (since this is the old hard-coded behavior).
Closes#1293
Not all themes have/define custom cursor colors. But of those that do,
nearly all already enabled them (by setting "cursor.color"), except
three themes:
* aeroroot
* ayu-mirage
* material-amber
This patch makes all themes consistent, by enabling cursor.color in
these last three themes too.
When the user has configured custom cursor colors (cursor.color is set
in foot.ini), don’t invert those colors when the cell is either
selected, or has the ‘reverse’ attribute set.
This aligns foot’s behavior with Alacritty, Kitty and Wezterm. Contour
also behaves similarly, except mouse selections override the cursor
colors (turning the cursor invisible).
Closes#1347
Having a keybinding to invoke arbitrary unicode characters is very
useful. It's often used as a method of last resort to communicate with
people outside of your main language. For example, if you want to type
the last letter of my real name, you can invoke the latin-1 character
0xe9 or unicode 0x00e9.
You can also use this to type special characters, for example, unicode
U+1F4A9 is of course, the infamous PILE OF POO, which is sure to
produce million laughs everywhere you go.
In foot, there's no keybinding by default to invoke the very useful
unicode-input command. There is no "standard" (as in "ISO") keybinding
this either. But there *is* a de-facto standard currently deployed
by *both* GTK and Qt (a rare feat) *and* Chrome OS (an even rarer
feat) and it's control-shift-u.
Alternatives include Control-x 8 (emacs), Control V u (vim),
Alt (Windows, LibreOffice), or Option (Mac). I doubt we want to adopt
any of those.
So let's use control-shift-u for this. Unfortunately, it's currently
assigned to show-urls-launch, which is unfortunate, but
insurmountable. We can reassign this keybinding elsewhere. I have
picked control-shift-o in my configuration, because "o" is a good
mnemonic for "open URLs". Others have suggested "m" instead.
Closes: #1183
When using muon[1] instead of meson, this was causing the following
error:
$ muon setup bld
.../meson_options.txt:26:124: error unterminated hex escape
.../meson_options.txt:26:223: error unterminated string
[1]: https://muon.build/
When compiling *without* cursor-shape-v1 support,
term_xcursor_update_for_seat() would incorrectly set
shape=CURSOR_SHAPE_CUSTOM, even though no custom cursor had been set
by the user.
This resulted in a crash in render_xcursor_set(), when trying to use a
NULL-string as custom cursor.
Using a lookup table, try to map the user-provided xcursor string to a
cursor-shape-v1 known shape.
If we succeed, set the user’s custom cursor using server side
cursors (i.e. using cursor-shape-v1).
If not, fallback to trying to load the image ourselves (using
wl_cursor_theme_get_cursor()), and set it using the legacy
wl_pointer_set_cursor().
This patch assumes a git snapshot of wayland-protocols are
installed.
We need to bump the version number as soon as the next version of
wayland-protocols have been released.
This implements support for the new cursor-shape-v1 protocol. When
available, we use it, instead of client-side cursor surfaces, to
select the xcursor shape.
Note that we still need to keep client side pointers, for:
* backward compatibility
* to be able to "hide" the cursor
Closes#1379
Before this patch, when the cell dimensions changed (i.e. when the
font size changes), sixel images were either removed (the new cell
dimensions are smaller than the old), or simply kept at their original
size (new cell dimensions are larger).
With this patch, sixels are instead resized. This means a
sixel *always* occupies the same number of rows and columns,
regardless of how much the font size is changed.
This is done by maintaining two sets of image data and pixman images,
as well as their dimensions. These two sets are the new ‘original’ and
‘scaled’ members of the sixel struct.
The "top-level" pixman image pointer, and the ‘width’ and ‘height’
members either point to the "original", or the "scaled" version.
They are invalidated as soon as the cell dimensions change. They, and
the ‘scaled’ image is updated on-demand (when we need to render a
sixel).
Note that the ‘scaled’ image is always NULL when the current cell
dimensions matches the ones used when emitting the sixel (to save
run-time memory).
Closes#1383
Images with an aspect ratio of 1:1 are by far the most common (though
not the default).
It makes a lot of sense, performance wise, to special case
them.
Specifically, the sixel_add() function benefits greatly from this, as
it is the inner most, most heavily executed function when parsing a
sixel image.
sixel_add_many() also benefits, since allows us to drop a
multiplication. Since sixel_add_many() always called first (no other
call sites call sixel_add() directly), this has a noticeable effect on
performance.
Another thing that helps (though not as much), and not specifically
with AR 1:1 images, is special casing DECGRI a bit.
Up until now, it simply updated the current sixel parameter value. The
problem is that the default parameter value is 0. But, a value of 0
should be treated as 1. By adding a special ‘repeat_count’ variable to
the sixel struct, we can initialize it to ‘1’ when we see DECGRI, and
then simply overwrite it as the parameter value gets updated. This
allows us to drop an if..else when emitting the sixel.
This way, the initial frame is more likely to get scaled correctly;
foot will guess the initial (integer) scale from the available
monitors, and use that. By using legacy scaling, we force the
compositor to down-scale the image to the correct scale factor.
If we use the new fraction scaling method with an integer scaling
factor, the initial frame gets rendered way too big.
We now default to scaling fonts using the scaling factor, not monitor
DPI.
The ‘auto’ value for dpi-aware has been removed.
Documentation (man pages and README) have been updated to reflect the
new default.
When the window’s preferred scaling factor is changed (through the
fractional-scaling protocol), update the terminal; resize font, resize
sub-surfaces etc.
Instead of passing a raw wl_surface pointer, pass a wayl_surface
pointer.
This is needed later, when using fractional scaling to scale the
surface (since then we need the surface’s viewport object).
And add a viewport object to accompany the surface (to be used when
scaling the surface).
Also rename the wl_surf_subsurf struct to wayl_sub_surface, and add a
wayl_surface object to it, rather than a plain wl_surface pointer (to
also get the viewport pointer).
* Bind the wp-viewporter and wp-fractional-scale-manager globals.
* Create a viewport and fractional-scale when instantiating a window.
* Add fractional-scale listener (that does nothing at the moment).
* Destroy everything on teardown.
When emitting a sixel, we need to:
a) scroll terminal content to ensure the new image fits
b) position the text cursor
Recent changes in the cursor positioning logic meant we reduced the
number of linefeeds, to ensure 1) sixels could be printed to the
bottom row without scrolling the terminal contents, and 2) the cursor
was positioned on the last sixel row.
Except, we’re not actually positioning the cursor on the last sixel
row. We’re positioning it on the text row that maps to the *upper*
pixel of the last sixel.
In most cases, this _is_ the last row of the sixel. But for certain
combinations of font and image sizes, it may be higher up.
This patch fixes a regression, where the terminal contents weren’t
scrolled up enough for certain images, causing a crash when trying to
dirty a not-yet scrolled in row.
The fix is this:
* Always scroll by the number of rows occupied by the image, minus
one. This ensures the image "fits".
* Adjust the cursor position, if necessary.
* Lazy initialize image height. This is necessary to prevent garbage
from being rendered for "empty" sixels.
* Fix plotting of non-1:1 pixels
* Fix calculation of height in resize(), for non-1:1 aspect ratios
That is, parse P1 when initializing a new sixel, and don’t ignore
pad/pad in the raster attributes command.
The default aspect ratio is 2:1, but most sixels will override it in
the raster attributes command (to 1:1).
This adjusts the logic that positions the text cursor after emitting a
sixel, when sixel scrolling mode is *enabled*.
We’ve always mimicked XTerm’s behavior. However, XTerm recently
changed its behavior, to better match that of an VT382.
Now, the cursor is placed *on* the last row of the sixel, instead of
on a new row after the sixel.
This allows applications to print sixels to the bottom row of the
terminal, without causing the content to scroll.
Finally, there was a bug in the horizontal positioning of the cursor;
it was placed on the *first* column of the row, instead of on the
first column of the sixel.
We don’t need to record scroll damage if the viewport isn’t at the
bottom, since in this case, the renderer ignores the scroll damage
anyway.
This fixes a performance corner case, when the viewport is at the top
of the scrollback history.
When application scrolls the terminal contents, and the scrollback
history is full, and the viewport is at top of the history, then the
viewport needs to be moved (the scrollback history is a circular
buffer, and thus the top of the history “moves” when we’re scrolling
in new contents).
Moving the viewport typically results in another type of scroll
damage (DAMAGE_SCROLL_IN_VIEW, instead of the “normal” DAMAGE_SCROLL).
Thus, each application triggered scroll, will result in two scroll
damage records: one DAMAGE_SCROLL, and one
DAMAGE_SCROLL_IN_VIEW. These two are incompatible, meaning they can’t
be merged. What’s worse, it also means the DAMAGE_SCROLL records from
two application triggered scrolls cannot be merged (since there’s a
DAMAGE_SCROLL_IN_VIEW in between).
As a result, the renderer will not see one, or “a few” scroll damage
events, but a *ton*. _Each_ one typically a single line, or so. And
each one resulting in lots of traffic on the wayland socket, as we
create and destroy new buffer pools, when doing “shm scrolling”.
This eventually leads to the socket not being able to keep up, and the
socket is closed on us, forcing us to exit.
The fix is really simple: don’t record “normal” scroll damage when
scrolling, _unless_ the viewport is at the bottom (and thus “follows”
the application output).
As soon as the user scrolls up in the history, we’ll stop emitting
normal scroll damage records. This is just fine, since, as mentioned
above, the renderer ignores them when the viewport isn’t at the
bottom.
What if the viewport is moved back down again, before the next frame
has been rendered? Wont there be “missing” scroll damage records? No,
because moving the viewport results in scroll damage records by
itself.
Closes#1380
When doing an interactive resize, and `resize-delay-ms` > 0 (the
default), we would crash if the original screen size (i.e. the size
before the interactive resize started) was larger than the last window
size.
For example, if we interactively go from 85 rows to 75, and then
non-interactively went from 75 to 80, we’d crash.
The resizes had to be made in a single go. One way to trigger this was
to start an interactive resize on a floating window, and then *while
resizing* toggle the window’s floating mode.
Closes#1377
Set cursor column, absolute.
term_cursor_to() needs to reload the current row pointer, and is thus
not very effective when we only need to modify the column.
We’re already switching on the next VT input byte in the state
machine; no need to if...else if in action_param() too.
That is, split up action_param() into three:
* action_param_new()
* action_param_new_subparam()
* action_param()
This makes the code cleaner, and hopefully slightly faster.
Next, to improve performance further, only check for (sub)parameter
overflow in action_param_new() and action_param_subparam().
Add pointers to the VT struct that points to the currently active
parameter and sub-parameter.
When the number of parameters (or sub-parameters) overflow, warn, and
then point the parameter pointer to a "dummy" value in the VT struct.
This way, we don’t have to check anything in action_param().
This is a new ‘extended’ capability. ‘TS’ has been around for a while,
but was originally not part of foot’s terminfo. Not sure when it was
added to ncurses’ foot terminfo.
In any case, ncurses has this to say about TS:
These building-blocks allow access to the X titlebar and icon name as a
status line. There are a few problems in using them in entries:
a) tsl should have a parameter to denote the column on which to transfer to
the status line.
...
But that issue regarding the parameter for tsl means that applications may
not rely on it. The SVr4 documentation says tsl will "move to status line,
column #1". At the point in time when ESR added DJM's "pseudo-color" entry
with the split-up escape sequence for tsl/fsl, there were 65 entries using
tsl:
32 used a parameter, matching the documentation (including x10term).
21 used a parameterless control, exiting from the status line on ^M.
6 used parameterless controls for tsl and fsl
6 used a split-up escape sequence, e.g., the same approach.
The extension "TS" is preferable, because it does not accept a parameter.
However, if you are using a non-extended terminfo, "TS" is not visible.
If the locale isn't UTF-8, foot tries to fall back to C.UTF-8 and
prints a warning. The warning was garbled because the name of the
original locale is no longer valid after calling setlocale() a
second time. Use strdup to stash the original string.
Closes#1362
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.
For this to work, the default app-id of footclient has been changed
from ‘foot’ to ‘footclient’.
By using distinct StartupWMClasses, the compositor can connect a
running foot/footclient instance to the correct .desktop-file. This
ensures the correct icon is being used in e.g. docks, and that actions
like “open another window” works correctly.
Note that the user can override the app-id, either by setting app-id
in foot.ini, or with the -a,--app-id command line option.
Closes#1355
This patch generalizes the utmp support, to not only support
libutempter, but also ulog (and in the future, even more interfaces).
* Rename config option main.utempter to main.utmp-helper
* Add meson option -Dutmp-backend=none|libutempter|ulog|auto
* Rename meson option -Ddefault-utempter-path to -Dutmp-default-helper-path
* utmp is no longer detected at compile time, but at runtime instead.
Meson will configure the following pre-processor macros, based on the
selected utmp backend:
* UTMP_ADD - argument to pass to utmp helper when adding a record (starting foot)
* UTMP_DEL - argument to pass to utmp helper when removing a record (exiting foot)
* UTMP_DEL_HAVE_ARGUMENT - if defined, UTMP_DEL expects an extra argument ($WAYLAND_DISPLAY)
* UTMP_DEFAULT_HELPER_PATH - path to the default utmp helper binary
The documentation has been updated to mention which arguments are
passed to the helper binary.
Closes#1314
Foot’s policy is to not set environment variables that identifies
it (except the well-known and established `TERM` variable).
We encourage applications to use terminfo to determine capabilities,
or terminal queries, when available. Or, at least use terminal queries
to detect the terminal and its version.
Setting environment variables is a bad idea since they are inherited
by all applications started by the terminal (which is the whole
point). But, this includes other terminal emulators, making it very
possible a terminal emulator gets mis-detected just because it was
started from another terminal.
Since there are a couple of terminal emulators that _do_ set
TERM_PROGRAM and TERM_PROGRAM_VERSION, unset these environment
variables to avoid being misdetected.
Closes#1349
3b41379be4 introduced a regression,
where canceling a scrollback search didn’t refresh the viewport
correctly; the viewport was changed, but the screen content was not
refreshed.
This worked before, because the workaround for
https://github.com/swaywm/sway/issues/6960 always called
term_damage_view() when exiting scrollback search mode.
3b41379be4 removed that call since it’s
no longer required. *Except* when executing the
BIND_ACTION_SEARCH_CANCEL binding, since then the viewport may be
moved.
Note that this regression affected *all* compositors, not just Sway.
Closes#1354
When unmapping a sub-surface, Sway <= 1.8 does not damage the surface
beneath the sub-surface.
https://github.com/swaywm/sway/issues/6960
The workaround is to manually damage the main surface. Previously,
this was done when exiting scrollback search, and after the ‘flash’
OSC. But other sub-surfaces, that may also be unmapped, did not.
This patch adds a quirk handler that does this, and calls it when:
* Exiting scrollback search
* Ending the ‘flash’ OSC
* Exiting unicode input mode
* Clearing URL labels
* Removing the scrollback position indicator
Closes#1335
The original kitty keyboard specification allowed F3 to emit either
CSI R, or CSI 13~.
Support for CSI R was removed in later revisions of the protocol,
since it collides with "Cursor Position Report" sequences.
If we had a non-empty bottom scroll region, and the window was resized
to a smaller size, the scroll region was not reset correctly.
This led to a crash when scrolling the screen content.
Fix by making sure the scroll region’s endpoint is within range.
At least Gnome needs this in order to link running instances of foot
to their corresponding .desktop file, used e.g. when determining which
icon to display for running applications.
Closes#1317
We’ve never supported neither 132-column mode, nor smooth
scrolling. But we _did_ recognize the escape sequences.
We don’t, anymore. Thus it makes very little sense to include these
escapes in any of our terminfo capabilities. So, remove them.
We don’t support neither 132 column mode, nor smooth scrolling. Thus
it makes little sense to recognize these control condes.
Note that while XTerm does support 132 columns, it is disabled by
default. In this mode, XTerm also doesn’t trigger the
side-effects (i.e. clearing the screen).
Closes#1265
Some of the config options we’re testing result in calls to FontConfig
APIs. Without calling FcIni()+FcFini(), we leak memory:
Direct leak of 768 byte(s) in 3 object(s) allocated from:
#0 0x7f7e95cbfa89 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7f7e95bd1fe5 (/usr/lib/libfontconfig.so.1+0x20fe5)
Indirect leak of 96 byte(s) in 3 object(s) allocated from:
#0 0x7f7e95cbf411 in __interceptor_calloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7f7e95bd63fd (/usr/lib/libfontconfig.so.1+0x253fd)
Indirect leak of 19 byte(s) in 2 object(s) allocated from:
#0 0x7f7e95c72faa in __interceptor_strdup /build/gcc/src/gcc/libsanitizer/asan/asan_interceptors.cpp:439
#1 0x7f7e95bd1898 in FcValueSave (/usr/lib/libfontconfig.so.1+0x20898)
When accumulating scroll damage, we check if the last scroll damage’s
scrolling region, and type, matches the new/current scroll damage. If
so, the number of lines in the last scroll damage is increased,
instead of adding a new scroll damage instance to the list.
If the scroll damage list isn’t consumed, this build up of scroll
damage would eventually overflow.
And, even if it didn’t overflow, it could become large enough, that
when later used to calculate e.g. the affected surface area, while
rendering a frame, would cause an overflow there instead.
This patch fixes both issues by:
a) do an overflow check before increasing the line count
b) limit the line count to UINT16_MAX
When applying scroll damage, we calculate the affected region’s
height (in pixels), by subtracting the number of rows to scroll, from
the scrolling region, and finally multiply by the cell height.
If the number of rows to scroll is very large, the subtraction may
underflow, resulting in a very large height value instead of a
negative one.
This caused the check for "scrolling too many lines" to fail. That in
turn resulted in an integer overflow when calculating the source
offset into the rendered surface buffer, which typically triggered a
segfault.
This bug happened when there was continuous output in the terminal
without any new frames being rendered. This caused a buildup of scroll
damage, that triggered the underflow+overflow when we finally did
render a new frame.
For example, a compositor that doesn’t send any frame callbacks (for
example because the terminal window is minimized, or on a different
workspace/tag) would cause this.
Closes#1305
When this happened (for example, by specifying a custom compose
sequence), the kitty keyboard protocol didn’t emit any text at all.
This was caused by the utf32 codepoint being -1. This in turned was
caused by us trying to convert the utf8 sequence to a *single* utf32
codepoint.
This patch replaces the use of mbrtoc32() with a call to
ambstoc32(), and the utf32 codepoint with an utf32 string.
The kitty keyboard protocol is updated:
* When determining if we’re dealing with text, check *all* codepoints
in the utf32 string.
* Add support for multiple codepoints when reporting "associated
text". The first codepoint is the actual parameter in the emitted
sequence, and the remaining codepoints are sub-parameters. I.e. the
codepoints are colon separated.
Closes#1288
The selection coordinates are in absolute row numbers. As such,
selection breaks when interactively resizing the normal grid, since we
then instantiate a temporary grid mapping directly to the current
viewport (for performance reason, to avoid reflowing the entire grid
over and over again).
Fix by stashing the actual selection coordinates, and ajusting the
"active" ones to the temporary grid.
If the user didn’t explicitly set the font size (e.g. font=monospace,
instead of font=monospace:size=12), our initial attempt to read the
FC_SIZE and FC_PIXEL_SIZE attributes will fail, and we used to
fallback to setting the size to 8pt.
Change this slightly, so that when we fail to read the FC_*_SIZE
attributes, apply the fontconfig rules, but *without expanding*
them (i.e. without calling FcDefaultSubstitute()).
Then try reading FC_*_SIZE again.
If that too fails, _then_ set size to 8pt. This allows us to pick up
rules that set a default {pixel}size:
<fontconfig>
<match>
<edit name="pixelsize" mode="append"><double>14</double></edit>
</fontconfig>
Closes#1287
Sort bindings such that bindings with the same symbol are sorted with
the binding having the most modifiers comes first.
This fixes an issue where the “wrong” key binding are triggered when
used with “consumed” modifiers.
For example: if Control+BackSpace is bound before
Control+Shift+BackSpace, then the latter binding is never triggered.
Why? Because Shift is a consumed modifier. This means
Control+BackSpace is “the same” as Control+Shift+BackSpace.
By sorting bindings with more modifiers first, we work around the
problem. But note that it is *just* a workaround, and I’m not
confident there aren’t cases where it doesn’t work.
Closes#1280
No need to check if terminal colors have been reversed - this is done
by the cell rendering logic.
This hopefully fixes all remaining issues with invisible text when
background alpha < 1.0
Closes#1249
Note that it is still unclear whether ack:ing a configure event for an
unmapped surface is a protocol violation, or something that should be
handled by the compositor.
According to
https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/108,
Kwin, Mutter and Weston handles it, while wlroots does not.
If cells overflowed (for example, by using an italic font that isn’t
truly monospaced) into a double-width glyph (that itself is *not*
overflowing), then the double-width glyph would glitch when being
rendered; typically the second half of it would occasionally
disappear.
This happened because we tried to rasterize the second cell of the
double-width glyph. This cell contains a special “spacer”
value. Rasterizing that typically results the font’s “not available”
glyph.
If _that_ glyph overflows, things broke; we’d later end up forcing a
re-render of it (thus erasing half the double-width glyph). But since
the double-width glyph _itself_ doesn’t overflow, _it_ wouldn’t be
re-rendered, leaving it half erased.
Fix by recognizing spacer cells, and not trying to rasterize them (set
glyph count to 0, and cell count to 1).
Closes#1256
Key bindings with multiple key mappings share auxiliary data (e.g. the
command to execute in pipe-* bindings, or the escape sequence in
text-bindings).
The first one is the designated “master” copy. Only that one should be
freed.
This fixed a double-free on exit, with e.g.
[text-bindings]
\x1b\x23=Mod4+space Mod4+equal
Closes#1259
This pointer ends up being passed to various printf-family functions,
where passing a NULL pointer for an "%s" format specifier invokes
undefined behaviour.
Ncurses added these in 2022-12-24, but they have been used/supported
by vim since 2017.
* BE - Bracketed paste Enable
* BD - Bracketed paste Disable
* PE - Paste Enable (i.e. "begin")
* PD - Paste Disable (i.e. "end")
The old default, wcswidth, simply calls wcswidth() on the grapheme
cluster. This was supposedly the implementation with the highest
application compatibility. Except we never even tried to measure
it. It was just assumed.
A lot of modern applications have better implementations. Let’s try to
push support for better emoji support by changing our default method
from wcswith to double-width.
While far from correct (it’s not based on the Unicode tables), the
‘double-width’ method produces accurate results anyway.
double-width is like wcswidth(), in that it adds together the
individual wcwidths of all codepoints in the grapheme cluster. But, it
limits the maximum width to 2.
This patch adds a new config option, font-size-adjustment.
It lets you configure how much the font size should be
incremented/decremented when zooming in or out (ctrl-+, ctrl+-).
Values can be specified in points, pixels or percent.
Closes#1188
* Both double and single quotes are recognized. There’s no difference
in how they are handled.
* The entire string must be quoted:
- “a quoted string” - OK
- quotes “in the middle” of a string - NOT ok
* Two escape characters are regonized:
- Backslash
- The quote character itself
Initialize the global ‘do_syslog’ variable to false. This ensures any
log calls done before log_init() has been called (e.g. unit tests)
doesn’t syslog anything.
As a side effect, such log calls no longer open an implicit syslog
file descriptor; this is how this “bug” was found: valgrind detected
an unclosed file descriptor at exit.
Finally, completely disable syslogging if log-level is “none”.
Before this patch, hyperlinked cells were tagged with the “URL”
attribute (thus instructing the renderer to draw an
underline) *before* the grid was snapshot.
When exiting URL mode, the cells were once again updated, this time
removing the URL attribute.
But what if an escape sequence had modified the grid _while we were in
URL mode_? Depending on the sequence, it could move cells around in
such a way, that when exiting URL mode, the affected cells weren’t
updated correctly. I.e. we left some cells with the URL attribute
still set.
The fix is simple: tag cells in the snapshot:ed grid only (which isn’t
affected by any escape sequence received while in URL mode). Not in
the *actual* grid (which _is_ affected).
This fixes an issue where selections in the scroll margins were not
detected correctly. This meant they weren’t canceled as they should
have been, which in turn caused a visual glitch where text appeared to
be selected, but were in fact not.
Before this patch, a user-set line-height was increased/decreased by
the exact same amount of pt’s as the font(s).
This means, that when there’s a large discrepancy between the
line-height and the font size, the proportion between the line’s
height and the font size will change as we increase or decrease the
font size.
This patch changes how the line height is adjusted when the font size
is incremented or decremented. We calculate the difference, in
percent, between the primary font’s original (default) size, and its
current size, and then apply that to the configured line-height.
Closes#1218
The default foot output looks like this, in Debian testing "bookworm"
at the time of writing:
anarcat@angela:pubpaste$ foot true
info: main.c:421: version: 1.13.1 +pgo +ime +graphemes -assertions
info: main.c:428: arch: Linux x86_64/64-bit
info: main.c:440: locale: fr_CA.UTF-8
info: config.c:3003: loading configuration from /home/anarcat/.config/foot/foot.ini
info: fcft.c:338: fcft: 3.1.5 +graphemes -runs +svg(nanosvg) -assertions
info: fcft.c:377: fontconfig: 2.13.1, freetype: 2.12.1, harfbuzz: 5.2.0
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Regular.otf: size=8.00pt/8px, dpi=75.00
info: wayland.c:1353: eDP-1: 2256x1504+0x0@60Hz 0x095F 13.32" scale=2 PPI=205x214 (physical) PPI=136x143 (logical), DPI=271.31
info: wayland.c:1509: requesting SSD decorations
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Bold.otf: size=24.00pt/32px, dpi=96.00
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Regular.otf: size=24.00pt/32px, dpi=96.00
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Bold.otf: size=24.00pt/32px, dpi=96.00
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Regular.otf: size=24.00pt/32px, dpi=96.00
info: terminal.c:700: cell width=19, height=39
info: terminal.c:588: using 16 rendering threads
info: wayland.c:859: using SSD decorations
info: main.c:680: goodbye
anarcat@angela:pubpaste$
That's 17 lines of output that are *mostly* useless for most use
cases. I might understand having this output during the project's
startup, when it's helpful for diagnostics, but now Foot just mostly
works everywhere, and I've never had a use for any of that stuff in
the (arguably short) time I've been using Foot so far.
And if I do, there's the `--log-level` commandline option to tweak
this. At first, I looked at tweaking the log level through the config
file. But as explained in this issue:
https://codeberg.org/dnkl/foot/issues/1142
... there's a chicken and egg problem there that makes it hard to
implement and possibly confusing for users as well.
There's also the possibility for users to change the shortcut with
which they start foot, for example a `.desktop` file so that menu
systems that support those start foot properly. But that only works in
that environment, and not through the so many things that will just
call `foot` and hope it will do the right thing.
In my case, I have `foot` hardcoded in a lot of places now, between
sway and waybar, and this is only going to grow. Others have suggested
adding the flag to a $TERMINAL global variable, but that won't help
.desktop users.
So, instead of playing whack-a-mole with the log levels, just make it
so that, by default, foot is silent. This is actually one of the
[basics of UNIX philosophy][1]:
> Rule of Silence: When a program has nothing surprising to say, it
> should say nothing.
And yes, I am aware I am severely violating that principle by writing
a way too long commit log for a one-line patch, but there you go, I
figured it was good to document the why of this properly.
[1]: https://web.archive.org/web/20031102053334/http://www.faqs.org/docs/artu/ch01s06.html
If an output has a bogus physical width or height, the DPI can become
so high that the cell width/height is too large for
pixman_image_fill_rectangles(), resulting in a crash in pixman_fill().
Since it doesn’t make any sense to use a DPI that is obviously bogus,
don’t. Force it 96 instead.
When drawing a block cursor using inversed fg/bg colors, we didn’t
strip the alpha from the background color. This meant that the text
"behind" the cursor was rendered with transparency. If alpha was set
to 0, the text was completely invisible.
We should never apply alpha to the text color. So, detect this, and
force alpha to 1.0.
Normally, when selecting the cursor’s color, we don’t really know
_where_ the background color is coming from (or more accurately,
_what_ it is).
However, the *only* background color that can have a non-1.0 alpha is
the *default* background color.
This is why we can ignore the bg parameter, and use term->colors.fg/bg
instead.
Closes#1205
The Appstream metadata file introduced in commit
335612cfa4
has been submitted as licensed under the CC0-1.0 license. People
generally use the CC0-1.0 to put the file in the "public domain", but
this isn't actually possible in lots of countries, so the file ends up
being licensed under CC0's fallback permissive license; unfortunately,
the fallback license contains some terms that are seen as problematic to
some (notably, Fedora has recently decided to consider the license
pretty much non-free).
As foot is already MIT-licensed, and since this license is in the list
of allowed [metadata licenses], this patch changes the license of the
metadata file from CC0-1.0 to MIT.
[metadata licenses]: https://freedesktop.org/software/appstream/docs/chap-Metadata.html#tag-metadata_license
On my system, GCC doesn't output its name when passing the --version
flag:
$ cc --version
cc (Debian 12.2.0-3) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
As the Free Software Foundation is unlikely to write another compiler, I
think that searching for the foundation's name instead of GCC is a good
enough fix (and I'm almost sure we wouldn't be the first ones to do so).
This used to work because we never free:d any of the rows. Now
however, we do free (some of) them when reverse scrolling. This means
we can no longer re-use the rows between the two screens.
Closes#1196
Re-initialize the temporary ‘normal’ grid instance each time we
receive a configure event while doing an interactive resize.
This way, window content will not be "erased" when the window is first
made smaller, then larger again.
And, if the viewport is up in the scrollback history, increasing the
window size will reveal more of the scrollback, instead of just being
black.
The last issue is the cursor; it’s currently not "stuck" where it
should be. Instead, it follows the window around. This is due to two
things:
1) the temporary grid we create is large enough to contain the current
viewport, but not more than that. That means we can’t "scroll up", to
hide the cursor.
2) grid_resize_without_reflow() doesn’t know anything about
"interactive resizing". As such, it will ensure the cursor is bound
to the new grid dimensions.
I don’t yet have a solution for this. This patch implements a
workaround to at least reduce the impact, by simply hiding the cursor
while we’re doing an interactive resize.
When determining whether or not to cancel a selection (due to it, or
part of it, being "scrolled out"), we assumed the scrollback was full.
This patch changes the implementation to compare the scrollback
relative selection coordinates with the scrollback relative
end-of-the-scrollback coordinates.
This ensures *everything* in the circular scrollback history, after
the bottom of the screen, is either NULL rows, or belong to the
scrollback *history* (as opposed to the future history).
This fixes an issue when calculating the scrollback start, which for
example would trigger a crash when moving the viewport (i.e. scrolling
with the mouse, or PgUp/PgDown).
Closes#1190
When we try to resize a sixel past the current max height, we set
col > image-width to signal this.
This means ‘width’ could be smaller than ‘col’. When calculating how
many sixels to emit in sixel_add_many(), we didnt’ account for this.
The resulting value was -1, converted to ‘unsigned’. I.e. a very large
value. This resulted in an assert triggering in sixel_add() in debug
builds, and a crash in release builds.
But also, more importantly, logical fixes:
* Stash the number of new scrollback lines the stashed ‘normal’ grid
should be resized *to*.
There’s also a couple of performance changes here:
* When doing a delayed reflow (tiocswinsz timer), call
sixel_reflow_grid(term, &term->normal) - there’s no need to reflow
sixels in the ‘alt’ screen.
* When doing a delayed reflow, free all scroll damage. It’s not
needed, since we’re damaging the entire window anyway.
* Use minimum size for the temporary ‘normal’ grid (that contains the
current viewport). We just need it to be large enough to fit the
current viewport, and be a valid grid row count (power of 2). This
just so happens to be the current ‘alt’ grid’s row count...
This function reflows all sixels in the specified grid.
The pre-existing sixel_reflow() function is a shortcut for
sixel_reflow_grid(term, &term->normal)
sixel_reflow_grid(term, &term->alt);
Instead of copying the entire grid when an interactive resize is
started, stash the complete grid (to be used in the final reflow).
Copy the current viewport only, to be used during the interactive
resize.
This gets rid of the initial "pause" when snapshotting the grid when
an interactive resize is started.
Reflowing a large scrollback is *slow*. During an interactive resize,
it can easily take long enough that the compositor fills the Wayland
socket with configure events. Eventually, the socket becomes full and
the compositor terminates the connection, causing foot to exit.
This patch is work-in-progress, and the first step towards alleviating
this.
It delays the reflow by:
* Snapshotting (copying) the original grid when an interactive resize
is started.
* While resizing, we apply a simple truncation resize of the
grid (like we handle the alt screen).
* When the resize is done, or paused for ‘resize-delay-ms’, the grid
is reflowed.
TODO: we *must* not allow any changes to the temporary (truncated)
grid during the resize. Any changes to the grid would be lost when the
final reflow is applied. That is, we must completely pause the ptmx
pipe while a resize is in progress.
Future improvements:
The initial copy can be slow. We should be able to avoid it by
rewriting the reflow algorithm to not free anything. This is
complicated by the fact that some resources (e.g. sixel images) are
currently *moved* to the new grid. They’d instead have to be copied.
We execute xtgettcap in the parent terminal. Thus we don’t know if it
implements XTGETTCAP, and thus it’s not guaranteed to exit - it may
hang indefinitely waiting for a reply.
Fix by not actually quering anything.
Fixes:
../utils/xtgettcap.c:175:1: error: ‘/home/daniel/src/foot/src/utils/xtgettcap.p/xtgettcap.c.gcda’ profile count data file not found [-Werror=missing-profile]
If $PWD is set, and its resolved path matches the *actual* working
directory, use $PWD for cwd when instantiating the terminal.
This makes a difference when $PWD refers to a symlink; before this
patch, we’d instantiate the terminal in the *resolved* path. Now it’ll
use the symlink instead.
This improves handling of symlinks (in CWD) when launching a new
terminal instance, either through ctrl+shift+n, or using the
--working-directory command line option.
Closes#1179
These capabilities are not included in the standard ‘xterm’ or
‘xterm-256color’ terminfos. They’re used in
‘xterm+focus’ ->
‘xterm+sm+1002’ ->
‘xterm-1002|xterm+sm+1003’ ->
‘xterm-1003’
(https://invisible-island.net/ncurses/terminfo.ti.html#tic-xterm_focus)
However, as far as I can tell, ncurses doesn’t use these capabilities
at all.
This patch adds support for creating utmp records using the ‘utempter’
helper binary from the ‘libutempter’ package.
* New config option ‘main.utempter’
* New meson command line option, -Ddefault-utempter-path. Defaults to
auto-detecting the path.
The default value of the new ‘main.utempter’ config option depends on
the meson command line option ‘-Ddefault-utempter-path’.
If ‘main.utempter’ is *not* set to ‘none’, foot will try to execute
the utempter helper binary to create utmp records when a new terminal
is instantiated. The record is removed when the terminal instance is
destroyed.
When rendering the overlay for scrollback search, the logic assumed
buffer re-use. On some compositors this isn’t happening (on
e.g. KDE/plasma we’re forced to double buffer).
This resulted in matches not being highlighted correctly.
The problem is in how we calculated the region for which areas to
clear ("un-dim"). It uses the "previous frame’s see-through area"
minus the current frame’s see-through area.
However, when we’ve detected that the current buffer isn’t the same as
the last one, we set the last frame’s see-through region to "the
entire buffer". Thus, when calculating the diff, we end up with an
empty region, and nothing is highlighted.
Fix by simply using the current frame’s see-through region as-is when
we’ve detected we’re not re-using the last frame’s buffer.
On compositors that forces us to double buffer, we need to re-apply
the last frame’s damage to the current frame (which uses the buffer
from the next-to-last frame).
General cell updates are handled by simply copying from the last
frame’s pixman buffer to the current frame’s.
In an attempt to improve performance, scroll damage were up until now
handled by re-playing the last frame’s scroll damage (on the current
frame’s buffer). This does not work, and resulted in glitches when
scrolling in the scrollback.
This patch does the following:
* grid_render_scroll{,_reverse}() now update the buffer’s "dirty"
region. This means the generic copy-old-frames-buffer handles the
scroll damage (albeit in, potentially, a less efficient way).
* Tracking of, and re-applying old scroll damage is completely
removed.
Closes#1173
The status value 4 means "permanently reset", as opposed to 2, which
means "reset". The former implies that there's no way to enable the
mode because it's unsupported (but recognized).
Note: this commit also fixes an unrelated typo in CHANGELOG.md.
Using GCC 12.2.0 with the following build steps:
CFLAGS=-Og meson bld
ninja -C bld
...produces the compiler error:
../config.c:2000:18: error: ‘sym_equal’ may be used uninitialized
[-Werror=maybe-uninitialized]
This commit fixes that by using BUG() to assert that all possible
values are accounted for in the offending switch statement.
Key-binding sets are bound to a seat/configuration pair. The conf
reference is done when a new terminal instance is created.
When that same terminal instance is destroyed, the key binding set is
unref:ed.
If the terminal instance is destroyed *before* the key binding set has
been referenced, we’ll still unref it. This creates an imbalance.
In particular, when the there is exactly one other terminal instance
referencing that same key binding set, that terminal instance will
trigger a foot server crash as soon as it receives a key press/release
event. This happens because the next-to-last terminal instance brought
the reference count of the binding set down to 0, causing it to be
free:d.
Thus, we *must* reference the binding set *before* we can error
out (when instantiating a new terminal instance).
At this point, we don’t yet have a valid terminal instance. But,
that’s ok, because all the key_binding_new_for_term() did with the
terminal instance was get the "struct wayland" and "struct config"
pointers. So, rename the function and simply pass these pointers
explicitly.
Similarly, change key_binding_for() to take a "struct config" pointer,
rather than a "struct terminal" pointer.
Also rename key_binding_unref_term() -> key_binding_unref().
Before this patch, we would line-wrap the last row, just like any
other row, and then afterwards try to reverse this, by adjusting the
offset and free:ing and NULL:ing the "last row".
The problem with this is if the scrollback is full. In this case, the
row we’re freeing is the first row in the scrollback history. This
means we’ll crash as soon as the viewport is moved to the top of the
scrollback.
The fix is fairly, simple. Skip the post-processing logic, and instead
detect when we’re line-wrapping the last row, and skip the call to
line_wrap().
This way, the last row in the new grid corresponds to the last row in
the old grid.
Do this by using scrollback relative coordinates, and ensure the new
viewport is not larger than (grid_rows - screen_rows), as that would
mean the viewport crosses the scrollback wrap-around.
Foot 1.13.0 introduced a regression where non-trailing empty cells
were highlighted inconsistently (cells that shouldn’t be highlighted,
were, seemingly at random).
86663522d5 “fixed” this by never
highlighting *any* empty cells.
This meant the behavior, compared to foot 1.12 and earlier,
changed. In foot 1.12 and older versions, non-trailing empty cells
were highlighted, as long as the selection covered at least one of the
trailing non-empty cells.
This patch restores that behavior.
To understand how this works, lets first take a look at how selection
works:
When a selection is made, and updated (i.e. the mouse is dragged, or
the selection is extended through RMB etc), we need to (un)tag and dirty
the cells that are a) newly selected, or b) newly deselected. That is,
we look at the diff between the “old” and the “new” selection, and
only update those cells.
This is for performance reasons: iterating the entire selection is not
feasible with large selections. However, it also means we cannot
reason about empty cells; we simply don’t know if an empty cells is a
trailing empty cell, or a non-trailing one.
Then, when we render a frame, we iterate all the *visible*
and *selected* cells, once again tagging them as selected (this is
needed since a selected cell might have lost its selected tag if the
cell was written to, by the client application, after the selection
was made).
At this point, we *can* reason about empty cells.
So, to restore the highlighting behavior to that of foot 1.12, we do
this:
When working with the selection diffs when a selection is updated, we
don’t special case empty cells at all. Thus, all empty cells covered
by the selection is highlighted, and dirtied.
But, when rendering the frame, we _do_ special case them. The only
difference (compared to foot 1.12) is that we *must*
explicitly *clear* the selection tag, and dirty the empty cells. This
is to ensure the empty cells that were incorrectly highlighted by the
selection update algorithm, isn’t rendered as that.
This does have a slight performance impact, as empty cells are now
always re-rendered. The impact should however be small.
This fixes a regression, where empty cells "between" non-empty
cells (i.e. non-trailing empty cells) sometimes were incorrectly
highlighted.
The idea has always been to highlight exactly those cells that will
get extracted when they’re copied. This means we’ve not highlighted
trailing empty cells, but we _have_ highlighted other empty cells,
since they are converted to spaces when copied (whereas trailing empty
cells are skipped).
fa2d9f8699 changed how a selection is
updated. That is, which cells gets marked as selected, and which ones
gets unmarked.
Since we no longer walk all the cells, but instead work with pixman
regions representing selection diffs, we can no longer determine (with
certainty) which empty cells should be selected and which shouldn’t.
Before this patch (but after
fa2d9f8699), we sometimes incorrectly
highlighted empty cells that should not have been highlighted. This
happened when we’ve first (correctly) highlighted a region of empty
cells, but then shrink the selection such that all those empty cells
should be de-selected.
This patch changes the selection behavior to *never* highlight empty
cells. This fixes the regression, but also means slightly different
behavior, compared to pre-fa2d9f86996467ba33cc381f810ea966a4323381.
The other alternative is to always highlight all empty cells. But,
since I personally like the fact that we’re skipping trailing empty
cells, I prefer the approach taken by this patch.
Before this patch, we would line-wrap the last row, just like any
other row, and then afterwards try to reverse this, by adjusting the
offset and free:ing and NULL:ing the "last row".
The problem with this is if the scrollback is full. In this case, the
row we’re freeing is the first row in the scrollback history. This
means we’ll crash as soon as the viewport is moved to the top of the
scrollback.
The fix is fairly, simple. Skip the post-processing logic, and instead
detect when we’re line-wrapping the last row, and skip the call to
line_wrap().
This way, the last row in the new grid corresponds to the last row in
the old grid.
Do this by using scrollback relative coordinates, and ensure the new
viewport is not larger than (grid_rows - screen_rows), as that would
mean the viewport crosses the scrollback wrap-around.
Foot 1.13.0 introduced a regression where non-trailing empty cells
were highlighted inconsistently (cells that shouldn’t be highlighted,
were, seemingly at random).
86663522d5 “fixed” this by never
highlighting *any* empty cells.
This meant the behavior, compared to foot 1.12 and earlier,
changed. In foot 1.12 and older versions, non-trailing empty cells
were highlighted, as long as the selection covered at least one of the
trailing non-empty cells.
This patch restores that behavior.
To understand how this works, lets first take a look at how selection
works:
When a selection is made, and updated (i.e. the mouse is dragged, or
the selection is extended through RMB etc), we need to (un)tag and dirty
the cells that are a) newly selected, or b) newly deselected. That is,
we look at the diff between the “old” and the “new” selection, and
only update those cells.
This is for performance reasons: iterating the entire selection is not
feasible with large selections. However, it also means we cannot
reason about empty cells; we simply don’t know if an empty cells is a
trailing empty cell, or a non-trailing one.
Then, when we render a frame, we iterate all the *visible*
and *selected* cells, once again tagging them as selected (this is
needed since a selected cell might have lost its selected tag if the
cell was written to, by the client application, after the selection
was made).
At this point, we *can* reason about empty cells.
So, to restore the highlighting behavior to that of foot 1.12, we do
this:
When working with the selection diffs when a selection is updated, we
don’t special case empty cells at all. Thus, all empty cells covered
by the selection is highlighted, and dirtied.
But, when rendering the frame, we _do_ special case them. The only
difference (compared to foot 1.12) is that we *must*
explicitly *clear* the selection tag, and dirty the empty cells. This
is to ensure the empty cells that were incorrectly highlighted by the
selection update algorithm, isn’t rendered as that.
This does have a slight performance impact, as empty cells are now
always re-rendered. The impact should however be small.
This is my variant of the solarized theme, were only the first eight
colors (i.e. the "normal") colors are from the solarized theme. The
remaining eight (the "bright" colors) are brightened versions of the
"normal" colors. This results in a theme that is usually in all
applications, not just those that are "aware" that the terminal color
theme is "solarized".
This fixes a regression, where empty cells "between" non-empty
cells (i.e. non-trailing empty cells) sometimes were incorrectly
highlighted.
The idea has always been to highlight exactly those cells that will
get extracted when they’re copied. This means we’ve not highlighted
trailing empty cells, but we _have_ highlighted other empty cells,
since they are converted to spaces when copied (whereas trailing empty
cells are skipped).
fa2d9f8699 changed how a selection is
updated. That is, which cells gets marked as selected, and which ones
gets unmarked.
Since we no longer walk all the cells, but instead work with pixman
regions representing selection diffs, we can no longer determine (with
certainty) which empty cells should be selected and which shouldn’t.
Before this patch (but after
fa2d9f8699), we sometimes incorrectly
highlighted empty cells that should not have been highlighted. This
happened when we’ve first (correctly) highlighted a region of empty
cells, but then shrink the selection such that all those empty cells
should be de-selected.
This patch changes the selection behavior to *never* highlight empty
cells. This fixes the regression, but also means slightly different
behavior, compared to pre-fa2d9f86996467ba33cc381f810ea966a4323381.
The other alternative is to always highlight all empty cells. But,
since I personally like the fact that we’re skipping trailing empty
cells, I prefer the approach taken by this patch.
This adds an "underline-thickness" setting to the "main" section,
similar to the existing "underline-offset" setting. This setting is used
to specify a custom height for regular (= non-cursor) underlines.
Fixes#1136
In some cases, the compositor sends a pointer enter event with a NULL
surface. It’s unclear if this is a compositor bug, or a race (where
the compositor sends an enter event on a CSD surface at the same time
foot unmaps the CSDs). Regardless, this causes seat->mouse_focus to be
unset, which triggers a crash in foot on the next pointer motion
event.
This patch does two things:
a) log a warning when we receive a pointer event with a NULL surface
b) ignore motion events where seat->mouse_focus is NULL
In some cases, the compositor sends a pointer enter event with a NULL
surface. It’s unclear if this is a compositor bug, or a race (where
the compositor sends an enter event on a CSD surface at the same time
foot unmaps the CSDs). Regardless, this causes seat->mouse_focus to be
unset, which triggers a crash in foot on the next pointer motion
event.
This patch does two things:
a) log a warning when we receive a pointer event with a NULL surface
b) ignore motion events where seat->mouse_focus is NULL
When the window is resized and we reflow the text, we ended up
inserting an empty row at the bottom.
This happens whenever the actual last row has a hard linebreak (which
almost always is the case); we then end the reflow with a line break,
causing an extra, empty, row to be allocated and inserted.
This patch fixes this by detecting when:
1) the last row is empty
2) the next to last row has a hard line break
In this case, we roll back the last line break, by adjusting the new
offset we just calculated, and free:ing the empty row.
TODO: it would be nice if we could detect this in the reflow loop
instead, and avoid doing the last line break all together. I haven’t
yet been able to find a way to do this correctly.
Closes#1108
Systemd, when doing socket activation, pass file descriptors in a
non-stable order when there is multiples ones.
But we only use one, so we don't need to identify it, and the file
descriptors always start at 3.
So use 3 for the systemd service.
Source : sd_listen_fds (systemd man pages)
We also need to unset variables systemd pass to socket activated
process, since we don't need them and sub-process (footclient and
theirs forks) could be confused by those.
Closes#1107
This mode is activated through the new key-bindings.unicode-input and
search-bindings.unicode-input key bindings.
When active, the user can “build” a Unicode codepoint by typing its
hexadecimal value.
Note that there’s no visual feedback in this mode. This is
intentional. This mode is intended to be a fallback for users that
don’t use an IME.
Closes#1116
Before this patch, each selection update would result in grid covered
by the selection being walked *three* times. First to “premark” the
area that *will* be selected after the update, then again to unmark
the previous selection (excluding the cells that were premarked - but
the cells are still iterated), and then one more time to finalize the
selection state in the grid.
Furthermore, each time a frame is rendered, the entire selection were
iterated again, to ensure all the cells have their ‘selected’ bit
set.
This quickly gets *very* slow.
This patch takes a completely different approach. Instead of looking
at the selection as a range of cells to iterate, we view it as an
area, or region. Thus, on each update, we have to regions: the region
representing the previous selection, and the region representing the
to-be selection.
By diffing these two regions, we get two new regions: one that
represents the cells that were selected, but aren’t any more, and one
that represents the cells that previously were not selected, but now
will be.
We implement the regions using pixman regions. By subtracting the
current selection from the previous selection, we get the region
representing the cells that are no longer selected, and that should be
unmarked.
By subtracting the previous selection from the current, we get the
region representing the cells that was added to the selection in this
update, and that should be marked.
selection_dirty_cells() is rewritten in a similar manner. We create
pixman regions for the selection, and the current scrollback view. The
intersection represents the (selected) cells that are visible. These
need to iterated and marked as being selected.
Closes#1114
When extending a selection, we determine *how* to extend it (which
endpoint to move, and whether to grow or shrink the selection) by
comparing the extension point with the old start and end coordinates.
For this to work correctly, we need to use scrollback relative
coordinates.
This fixes an issue where extending a very large selection (covering
many pages) sometimes shrunk the selection instead of growing it, or
just misbehaving in general.
When checking if the current selection intersects with the
region (passed as parameter to the function), use scrollback relative
coordinates.
This fixes an issue where selections crossing the scrollback
wrap-around being misdetected, resulting in either the selection being
canceled while scrolling, even though it wasn’t scrolled out, or the
selection _not_ being canceled, when it _was_ scrolled out.
Make sure to increment match_end_col to account for trailing SPACER
cells after a match.
This fixes an issue where search matches weren’t highlighted correctly
when the match *ends* with a double-width character.
Certain dead key combinations results different escape sequences in
foot, compared to kitty, when the kitty keyboard protocol is used.
if (composed && is_text)
key = utf32;
else {
key = xkb_keysym_to_utf32(sym_to_use);
if (key == 0)
return false;
/* The *shifted* key. May be the same as the unshifted
* key - if so, this is filtered out below, when
* emitting the CSI */
alternate = xkb_keysym_to_utf32(sym);
}
If is_text=false, we’ll fall through to the non-composed
logic. is_text is set to true if the character is printable *and*
there aren’t any non-consumed modifiers enabled.
shift+space is one example where shift is *not* consumed (typically -
may be layouts where it is).
As a result, pressing ", followed by shift+space with the
international english keyboard layout (where " is a dead key) results
in different sequences in foot and kitty.
This patch fixes this by always treating composed characters as
printable.
Closes#1120
Indexed color values are stored in the cell attributes as color
indices (into the 256-color table). However, the index from the CSI
was not validated in any way, meaning you can do something like this:
echo -e ‘\e[38:5:1024m CRASH \e[m’
and foot will crash on an out-of-bounds access.
Fix by clamping the color index.
Closes#1111
When reflowing the grid, we truncate lines with a hard linebreak after
the last non-empty cell. This way we don’t reflow trailing empty cells
to a new line when resizing the window to a smaller size.
However, “logical” lines (i.e. those without a hard linebreak)
are *not* truncated. This is to ensure we don’t trim empty cells in
the middle of a logical line spanning multiple physical lines.
Since newly allocated rows are initialized with linebreak=false, we
need to ensure _those_ are still truncated - otherwise all that empty
space under the current prompt will be reflowed.
Note that this is a temporary workaround. The correct solution, I
think, is to track whether a line has been printed to or not, and
simply ignore (not reflow) lines that haven’t yet been touched.
The compositor _usually_ sends the keymap event *before* the enter
event. But not always.
Not (yet) having a keymap is not a reason to ignore the enter
event (now, on the other hand, getting a key press/release event
without a keymap is a compositor bug).
Closes#1097
Specifically, make sure we do *not* call wl_data_offer_receive() with
a NULL mime-type, as this causes libwayland to error out, which in
turn causes foot to exit.
Closes#1092
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
Replace the seat->ime.focused boolean with a terminal instace pointer,
seat->ime_focus.
Set and reset this on ime::enter() and ime::leave() events, and use
this instead of seat->kbd_focus on all other IME events.
This fixes two issues:
a) buggy compositors that sometimes sends an IME enter event without
first having sent a keyboard enter event.
b) seats may be IME capable while still lacking the keyboard
capability. Such seats will *always* see IME enter events without a
corresponding keyboard enter event.
* Don’t assume 32 bits when rotating the old key. Use the number of
actual bits available, as determined by CELL_COMB_CHARS_{HI,LO}
* Multiply with magic hash constant
This greatly reduces the number of collisions seen. For example, the
Emoji test file (from the Unicode specification), now has zero
collisions.
Composed characters are stored in a tree structure, using a key as
identifier. The key is calculated from the individual characters that
make up the composed character sequence.
Since the address space for keys is limited, collisions may occur. In
this case, we simply increment the key and try again.
It is theoretically possible to saturate the key space, in which case
we’ll get stuck in an endless loop.
Even if the key space isn’t fully saturated, we fairly easy reach a
point where there are so many collisions for each insertion, that
performance drops significantly.
Since key space is limited (it’s not like a hash table that we can
grow), our only option is to limit the number of collisions. If we
can’t find a slot within a hard code amount of collisions, the
character is simply dropped.
This syncs foot with more recent versions of XTerm, where it’s
“disallowedPasteControls” resource has changed its default value to
BS,DEL,ENQ,EOT,ESC,NULL
Note that we’re already stripping out ENQ,EOT,ESC in all modes.
What does it mean for foot:
* HT, VT and FF are now allowed, regardless of paste mode
* NUL is now stripped in non-bracketed paste mode
Closes#1084
When scrolling the viewport up, we need to ensure we don’t go past the
scrollback wrap around.
This was previously done using “custom” logic that tried to calculate
many rows away from the scrollback start the current viewport is.
But this is *exactly* what grid_row_abs_to_sb() does, except it
doesn’t account for uninitialized scrollback.
So, copy the logic from grid_row_abs_to_sb(), but ensure scrollback
start points to valid scrollback data. The maximum number of rows
we’re allowed to scroll is now the same as the current viewport’s
sb-relative coordinate.
Maybe closes#1074
When a line in the old grid (the one being reflowed) doesn’t have a
hard linebreak, don’t trim trailing empty cells.
Doing so means we’ll “compress” (remove) empty cells between text
if/when we revert to a larger window size.
The output from neofetch suffers from this; it prints a logo to the
left, and system information to the right. The logo and the system
info column is separated by empty cells (i.e. *not* spaces).
If the window is reduced in size such that the system info is pushed
to a new line, each logo line ends with a number of empty cells. The
next time the window is resized, these empty cells were
ignored (i.e. removed).
That meant that once the window was enlarged again, the system info
column was a) no longer aligned, and b) had been pulled closer to the
logo.
This patch doesn’t special case trailing empty cells when the line
being reflowed doesn’t have a hard linebreak. This means e.g. ‘ls’
output is unaffected.
Closes#1055
This allows package maintainers to override the location to which our
systemd service files are installed.
It’s value is an *absolute* path, and *not* relative ${prefix}.
The default is ${systemduserunitdir}.
When XDG activation support was added to URL mode, we introduced a
regression, where it is possible to flood the Wayland socket with XDG
activation token requests.
Start foot with “foot -o bell.urgency=yes”, then run:
while true; do echo -en ‘\a’; done
Finally, switch keyboard focus to another window. Foot crashes.
Throttle the token requests by limiting the number of outstanding
urgency token requests to 1.
Closes#1065
If the viewport is at the top of the scrollback, and a program is
scrolling (e.g. by emitting newlines), the viewport needs to be
moved. Otherwise, the top of the viewport will show the *bottom* of
the scrollback (i.e. the newly emitted lines), and the bottom of the
viewport shows the top of the scrollback.
How do we detect if the viewport needs to be moved?
We convert its absolute row number to a scrollback relative row. This
number is also the maximum number of rows we can scroll without the
viewport being scrolled out.
In other words, if the number of rows to scroll is larger than the
viewports scrollback relative row number, the viewport needs to
moved.
How much do we need to move it? The difference between the number of
rows to scroll, and the viewports scrollback relative row number.
Example:
if the viewport is at the very top of the scrollback, its scrollback
relative row number is 0. In this case, it needs to be moved the same
number of rows as is being scrolled.
First, add a ‘token’ argument to spawn(). When non-NULL, spawn() will
set the ‘XDG_ACTIVATION_TOKEN’ environment variable in the forked
process. If DISPLAY is non-NULL, we also set DESKTOP_STARTUP_ID, for
compatibility with X11 applications. Note that failing to set either
of these environment variables are considered non-fatal - i.e. we
ignore failures.
Next, add a helper function, wayl_get_activation_token(), to generate
an XDG activation token, and call a user-provided callback when it’s
‘done (since token generation is asynchronous). This function takes an
optional ‘seat’ and ‘serial’ arguments - when both are non-NULL/zero,
we set the serial on the token. ‘win’ is a required argument, used to
set the surface on the token.
Re-write wayl_win_set_urgent() to use the new helper function.
Finally, rewrite activate_url() to first try to get an activation
token (and spawn the URL launcher in the token callback). If that
fails, or if we don’t have XDG activation support, spawn the URL
launcher immediately (like before this patch).
Closes#1058
When true, selection_find_word_boundary_right() behaves as before - it
stops as soon as it encounters a character that isn’t of the
same *type* as the “initial” character (the last character in the
selection).
Take this, for example:
The Quick Brown Fox
The selection will first stop at the end of “the”, then just *before*
“quick”, then at the end of “quick”. Then just *before* “brown”, and
then at the end of “brown”, and so on.
This suits mouse selections pretty good. But when
selection_find_word_boundary_right() is used to extend a search match,
it’s better to ignore space-to-word character transitions. That is, we
want
The Quick Brown Fox
to first extend to the end of “the”, then immediately to the end of
“quick”, then to the end of “brown”, and so on.
Setting the ‘stop_to_space_to_word_boundary’ argument to false results
in latter behavior.
This is now done by search, when executing the
“extend-to-word-boundary” and “extend-to-next-whitespace” key
bindings.
We now bind ctrl+v, ctrl+shift+v, ctrl+y and XF86Paste to pasting from
the clipboard into the scrollback search buffer.
Why all these? Because we can, and because all are common shortcuts
for pasting:
* ctrl+v: “normal” apps use this by default
* ctrl+shift+v: used in terminals (including foot)
* ctrl+y: Emacs
* XF86Paste: special keyboard key, for pasting
find_next() did not always terminate correctly, causing
search_matches_next() to never terminate, which finally leads to an
infinite loop when rendering the search overlay surface, while finding
all matches to highlight.
The problem is that find_next(), after having found the initial
matching characters, enters a nested while loop that tries to match
the rest of the search criteria. This inner while loop did not check
if we’ve reached the last cell, and happily continued past
it (eventually wrappping around the scrollback buffer).
Closes#1047
5c4ddebc3c refactored
search_update_selection(), specifically, the logic that moves the
viewport.
It did so by converting the absolute row number (of the match) to
scrollback relative coordinates. This way we could ensure the viewport
wasn’t moved “too much” (e.g. beyond the scrollback start).
However, grid_row_abs_to_sb() and grid_row_sb_to_abs() doesn’t take a
partially filled scrollback into account. This means the row (numbers)
it returns may refer to *uninitialized* rows.
Since:
* The match row itself is valid (we *know* it has text on it)
* We *subtract* from it, when setting the new viewport (to center the
match on the screen).
it’s only the *upper* part of the new viewport that may be
uninitialized. I.e. we may have adjusted it too much.
So, what we need to do is move the viewport forward until its *first*
row is initialized. Then we know the rest will be too.
Unmapping a sub-surface in Sway does not damage the underlying
surface.
As a result, the OSC-555 escape (“flash”) will leave yellow margins on
~every second frame.
Out of sway, river, weston and mutter, only Sway needs this
workaround.
This is a workaround for https://github.com/swaywm/sway/issues/6960Closes#1046
Unmapping a sub-surface in Sway does not damage the underlying
surface.
As a result, "committing" a scrollback search will typically leave
most of the foot window dimmed.
It can be seen when "cancelling" a search as well, but there it's less
obvious - only the margins are left dimmed. This is because cancelling
a search damaged the current viewport (something that shouldn't be
needed).
Out of sway, river, weston and mutter, only Sway needs this
workaround.
This is a workaround for https://github.com/swaywm/sway/issues/6960
* When extending the selection to the next word boundary, ensure the
row numbers are valid:
- use selection_get_end() when retrieving the current end
coordinate. This alone fixes a crash where we previously would
crash in an out-of-bounds array access in grid->rows[], due to
term->selection.coords.end being unbounded.
- ensure the new end coordinate is bounded before and after calling
selection_find_word_boundary_right().
* When moving the viewport (to ensure a new match is visible), make
sure we don’t end up with the match outside the new viewport.
Under certain, unusual, circumstances, the moved viewport _still_
did not contain the match. This resulted in assertions triggering
later, that assumed the match(es) are *always* visible.
It’s fairly easy to trigger this one by running foot with e.g.
foot -o scrollback.lines=0 --window-size-chars 25x3
and then hitting enter a couple of times, to fill the scrollback
history (which should consist of a single row in the example above),
and the do a scrollback search for (part of) the prompt, and keep
searching backward until it crashes.
This would happen if calculated (new) viewport had to be adjusted
(for example, to ensure it didn’t go past the scrollback end).
This patch changes the logic used when calculating the new
viewport. Instead of calculating the wanted viewport (match is
vertically centered) and then trying to adjust it to ensure the new
viewport is valid, start with a “safe” new viewport value, and then
determine how much we can move it, if at all, to center the match.
This is done by using scrollback relative coordinates. In this
coordinate system, the new viewport must be
>= 0, and < grid->num_lines - term->rows
This makes it very easy to limit the amount by which the viewport is
adjusted.
As a side-effect, we can remove all the old re-adjustment logic.
* The match iterator no longer special cases the primary match. This
was needed before, when the search iterator did not handle
overlapping matches correctly. Now that we do, the iterator is
guaranteed to find the primary match, and thus we no longer need to
special case it.
This fixes a bug where the primary match was returned twice, due to
the logic checking if a secondary match is the same as the primary
match was flawed...
Closes#1036
Internally, selection coordinates are *unbounded* (that is, the row
numbers may be larger than grid->num_rows) while a selection is
ongoing. Only after it has been finalized are the coordinates bounded.
This means it isn’t safe to use term->selection.coords.* directly.
These functions convert row numbers between absolute coordinates and
“scrollback relative” coordinates.
Absolute row numbers can be used to index into the grid->rows[] array.
Scrollback relative numbers are ordered with the *oldest* row first,
and the *newest* row last. That is, in these coordinates, row 0 is the
*first* (oldest) row in the scrollback history, and row N is the
*last* (newest) row.
Scrollback relative numbers are used when we need to sort things after
their age, when determining if something has scrolled out, or when
limiting an operation to ensure we don’t go past the scrollback
wrap-around.
As this means the last call to sarch_matches_next() found a match at
the bottom of the view, and then set the iter’s *next* start position
to a row outside the view.
This is fine, but we need to handle it, by immediately stopping the
iter.
When bumping the iter’s start.row, we’re working with view-local
coordinates. That is, 0 >= row < term->rows.
This means it is wrong to and with grid->num_rows - 1, because a),
‘row’ should **never** be that big. And b), if we do, we’ll just end
up in an infinite loop, where the next call to matches_next() just
starts over from the beginning again (and eventually hitting the exact
same place that got us started).
Our CSDs, the search-box and URL labels are all implemented using
sub-surfaces, synchronized with the main grid.
This means we *must* commit the main surface as well, when updating
one of these sub-surfaces.
The logic for doing so in the frame callback was flawed, and only
triggered when the main grid was actually dirty.
That is, e.g. search box updates that did not also resulted in grid
updates (for example - pasting a search criteria that doesn’t match),
did not result in a UI refresh.
Closes#1040
description:"The name and version of your compositor"
placeholder:"sway version 1.9"
validations:
required:true
- type:input
id:distro
attributes:
label:Distribution
description:"The name of the Linux distribution, or BSD flavor, you are running. And, if applicable, the version"
placeholder:"Fedora Workstation 41"
validations:
required:true
- type:input
id:multiplexer
attributes:
label:Terminal multiplexer
description:"Terminal multiplexers are terminal emulators themselves, therefore the issue may be in the multiplexer, not foot. Please list which multiplexer(s) you use here (and mention in the problem description below if the issue only occurs in the multiplexer, but not in bare metal foot)"
placeholder:"tmux, zellij"
- type:input
id:application
attributes:
label:Shell, TUI, application
description:"Application(s) in which the problem occurs (list all known)"
placeholder:"bash, neovim"
- type:checkboxes
id:server
attributes:
label:Server/standalone mode
description:Does the issue occur in foot server, or standalone mode, or both? Note that you **cannot** test standalone mode by manually running `foot` from a `footclient` instance, since then the standalone foot will simply inherit the server process' context.
options:
- label:Standalone
- label:Server
- type:textarea
id:config
attributes:
label:Foot config
description:Paste your entire `foot.ini` here (do not forget to sanitize it!)
render:ini
validations:
required:true
- type:textarea
id:repro
attributes:
label:Description of Bug and Steps to Reproduce
description:|
Exactly what steps can someone else take to see the bug
themselves? What happens?
validations:
required:true
- type:markdown
attributes:
value:|
Please provide as many details as possible, we must be able to
understand the bug in order to fix it.
Other software
--------------
**Compositors**:have you tested other compositors? Does the
issue happen on all of them, or only your main compositor?
**Terminalmultiplexers**:are you using tmux, zellij, or any
other terminal multiplexer? Does the bug happen in a plain
foot instance?
**IME**do you use an IME (e.g. fcitx5, ibus etc)? Which one?
if [[ ${COMP_WORDS[i-1]} =~ ^(--app-id|--config|--font|--log-level|--term|--title|--window-size-pixels|--window-size-chars|--working-directory)$ ]] ; then
if [[ ${COMP_WORDS[i-1]} =~ ^(--app-id|--toplevel-tag|--config|--font|--log-level|--pty|--term|--title|--window-size-pixels|--window-size-chars|--working-directory)$ ]] ; then
(( i++ ))
continue
fi
# positional argument found
# Positional argument found
offset=$i
fi
(( i++ ))
done
if [[ ! -z "$offset" ]] ; then
# depends on bash_completion being available
# Depends on bash_completion being available
declare -F _command_offset >/dev/null || return 1
_command_offset $offset
return 0
elif [[ ${cur} == --* ]] ; then
COMPREPLY=( $(compgen -W "${flags}" -- ${cur}) )
elif [[ ${prev} =~ ^(--config|--print-pid|--server)$ ]] ; then
compopt -o default
elif [[ ${prev} == '--working-directory' ]] ; then
if [[ ${COMP_WORDS[i-1]} =~ ^(--app-id|--log-level|--server-socket|--term|--title|--window-size-pixels|--window-size-chars|--working-directory)$ ]] ; then
if [[ ${COMP_WORDS[i-1]} =~ ^(--app-id|--toplevel-tag|--log-level|--server-socket|--term|--title|--window-size-pixels|--window-size-chars|--working-directory)$ ]] ; then
(( i++ ))
continue
fi
# positional argument found
# Positional argument found
offset=$i
fi
(( i++ ))
done
if [[ ! -z "$offset" ]] ; then
# depends on bash_completion being available
# Depends on bash_completion being available
declare -F _command_offset >/dev/null || return 1
_command_offset $offset
return 0
elif [[ ${cur} == --* ]] ; then
COMPREPLY=( $(compgen -W "${flags}" -- ${cur}) )
elif [[ ${prev} == '--server-socket' ]] ; then
compopt -o default
elif [[ ${prev} == '--working-directory' ]] ; then
description:'Which utmp logging backend to use. This affects how (with what arguments) the utmp helper binary (see \'utmp-default-helper-path\')is called. Default: auto (linux=libutempter, freebsd=ulog, others=none)')