Commit graph

666 commits

Author SHA1 Message Date
Daniel Eklöf
49fb0cf359
sixel: re-scale images when the cell dimensions change
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
2023-06-30 08:29:35 +02:00
Daniel Eklöf
d71e588800
wayland: refactor: surface_scale(): pass wl_window pointer, instead of wayland global 2023-06-29 15:38:24 +02:00
Daniel Eklöf
5a60bbc119
wayland: refactor: add a buffer argument to wayl_*_scale() functions
This will be needed later, when using fractional scaling + viewporter
to scale.
2023-06-29 15:38:23 +02:00
Daniel Eklöf
434fd6aa1f
wayland: refactor: wayl_surface_scale(): pass wayl_surface pointer
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).
2023-06-29 15:38:23 +02:00
Daniel Eklöf
ba46a039ac
wayland: refactor: wrap wl_surface pointers in a wayl_surface struct
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).
2023-06-29 15:38:23 +02:00
Daniel Eklöf
0a5073f570
wayland: add wayl_surface_scale(), and wayl_win_scale()
These functions scale a surface+buffer.

For now, only using the legacy scaling
method (wl_surface_set_buffer_scale()).
2023-06-29 15:38:23 +02:00
Daniel Eklöf
4bd62b1005
render: maybe_resize(): convert local variable ‘scale’ to float 2023-06-29 15:38:23 +02:00
Daniel Eklöf
2bb7b28837
render: xcursor_update(): convert local ‘scale’ variable to float 2023-06-29 15:38:22 +02:00
Daniel Eklöf
d8f64d1047
render: urls(): round scaling factor 2023-06-29 15:38:22 +02:00
Daniel Eklöf
30c8d3e652
render: search_box(): round scaling factor 2023-06-29 15:38:22 +02:00
Daniel Eklöf
cf280e6655
render: render_timer(): round scaling factor 2023-06-29 15:38:22 +02:00
Daniel Eklöf
b656124791
render: csd_border: round scaled border width, instead of truncating 2023-06-29 15:38:22 +02:00
Daniel Eklöf
44743b5635
render: draw_unfocused_block(): round scale, instead of truncating 2023-06-29 15:38:22 +02:00
Daniel Eklöf
c1f374cc8d
term: convert ‘scale’ to a float 2023-06-29 15:38:22 +02:00
Daniel Eklöf
3a59cbbaa3
render: resize: fix crash when reflowing the alt screen
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
2023-06-20 15:59:16 +02:00
locture
d2f81443f1
customized gnome-like csd buttons 2023-05-18 17:49:44 +02:00
Daniel Eklöf
3b41379be4
quirks: sway does not damage surface beneath sub-surface, when unmapped
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
2023-05-12 14:51:05 +02:00
Daniel Eklöf
a2db3cdd5b
render: regression: keep empty bottom scroll margin empty after resize 2023-04-12 18:09:41 +02:00
Daniel Eklöf
e2baa65238
render: ensure scroll region’s endpoint is valid after a window resize
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.
2023-04-12 17:57:53 +02:00
Daniel Eklöf
7bc22862fa
render: protect against integer underflow when calculating scroll area
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
2023-03-30 16:13:18 +02:00
Daniel Eklöf
296e75f4f5
render: fix glitchy selection while resizing the ‘normal’ screen
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.
2023-03-27 16:53:41 +02:00
Daniel Eklöf
514fcc20a7
render: resize: call xdg_toplevel_set_min_size()
This is a hint to the compositor, not to set a smaller size than this.
2023-03-02 17:22:27 +01:00
Daniel Eklöf
8a849b4b08
render: fix inversed cursor fg color when alpha != 1.0, take #2
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
2023-02-28 17:49:57 +01:00
Daniel Eklöf
7a43737745
render: fix selected cursor cell being ‘invisble’ when background alpha is used
... by taking the cell ‘selected’ state into account when determining
whether to use the default fg or bg as the ‘text’ color.
2023-02-27 17:51:29 +01:00
Craig Barnes
b81b98d47c render: fix incorrect indent introduced by previous commit 2023-01-17 23:49:32 +00:00
Daniel Eklöf
a9298959a1
render: fix double-width glyphs glitching when surrounding cells overflow into it
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
2023-01-17 19:43:47 +01:00
Daniel Eklöf
30d088376c
render: maybe_resize(): remove debug assert
This, depending on which compiler being used, caused issues not only
in debug builds, but release builds as well (with NDEBUG defined).
2022-11-01 17:12:16 +01:00
Daniel Eklöf
2c2a39317b
render: never apply alpha to text color
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
2022-10-30 19:43:18 +01:00
Daniel Eklöf
59c9dfe109
render: resize: do full text reflow immediately if resize-delay-ms == 0
That is, skip all custom grid handling when doing an interactive
resize, if resize-delay-ms == 0.
2022-10-23 10:34:18 +02:00
Daniel Eklöf
0ac0d0647a
interactive resize: improve user experience
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.
2022-10-17 18:49:57 +02:00
Daniel Eklöf
298f210ed9
render: rename term->render.resizing -> term->interactive_resizing
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...
2022-10-10 17:19:18 +02:00
Daniel Eklöf
c550d67cd8
render: resize: do delayed reflow immediately when failing to arm tiocswinsz timer 2022-10-10 17:19:18 +02:00
Daniel Eklöf
d4b0b0887e
render: delayed reflow: not enough to damage current view; need to refresh too 2022-10-10 17:19:18 +02:00
Daniel Eklöf
f4f1989b6e
render: resize: ignore ptmx read events during interactive resize 2022-10-10 17:19:18 +02:00
Daniel Eklöf
3565cbd636
render: performance improvements during interactive resize
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.
2022-10-10 17:19:17 +02:00
Daniel Eklöf
8179d73daa
render: delay reflow for ‘resize-delay-ms’ milliseconds
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.
2022-10-10 17:19:17 +02:00
Alexey Sakovets
37218be648
render: fix nanosec "overflow" when calculating timeout value 2022-10-05 16:51:25 +02:00
Daniel Eklöf
3be44fb316
render: overlay: fix visual glitches when double buffering
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.
2022-09-23 20:33:02 +02:00
Daniel Eklöf
4340f8a3b4
render: fix application of old scroll damage when double buffering
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
2022-09-23 20:33:02 +02:00
Daniel Eklöf
b7ba842237
render: timer: print/log *total* rendering time 2022-09-23 20:31:08 +02:00
Yorick Peterse
a0942f950d
config: add setting for underline thickness
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
2022-08-20 22:16:32 +02:00
Daniel Eklöf
e249b52abd
render: apply a dimmed overlay while in Unicode input mode 2022-08-08 16:31:28 +02:00
Simon Ser
129e1a9b8e Add support for xdg_toplevel.wm_capabilities
See https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/122
2022-08-04 14:23:03 +02:00
Daniel Eklöf
d79a3b9350
config: add colors.search-box-{no-,}match
Closes #1112
2022-07-28 19:02:56 +02:00
Daniel Eklöf
24c2d56804
render: it’s unlikely() the current cell is where the cursor is 2022-07-28 18:55:34 +02:00
Daniel Eklöf
96f23b4c64
ime: track IME focus independently from keyboard focus
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.
2022-06-15 19:25:33 +02:00
Daniel Eklöf
2cbcfb3159
render: fix refresh logic of pending csd|search|url
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
2022-04-24 12:04:06 +02:00
Daniel Eklöf
2085621bf4
render: overlay: reset ‘start_col’ after handling the first row 2022-04-17 19:26:54 +02:00
Daniel Eklöf
24ee3dcc10
wayland: refactor: remove ‘struct config’ pointer from wayland struct
The global config doesn’t necessarily reflect the correct
configuration to use - we should *always* use the current terminal
instance’s conf pointer.

* Move selection override modifier mask to the key_binding_set struct
* Always warn if XDG activation is unavailable, not just if
  bell.urgent is set (we no longer have access to this information)
* Pass ‘bool presentation_timings’ as a parameter to wayl_init()
* Remove ‘presentation_timings’ member from the ‘terminal’ struct

Closes #932
2022-04-17 16:34:04 +02:00
Daniel Eklöf
9e3c71c277
render: overlay: apply weston quirk 2022-04-17 11:04:27 +02:00