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