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...)
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
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
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
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
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
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.
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
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.
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 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
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
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.
* 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
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
* 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 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.
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.