Previously when updating a selection, we would unmark *all* cells in
the old selection, and then mark all cells in the new selection.
This caused *all* cells to be dirtied and thus re-rendered.
Avoid this, by adding a temporary state to the cells' selected state.
Before unmarking the old selection, pre-mark the new selection using a
temporary state.
When unmarking the old selection, ignore cells in this temporary state.
When marking the new selection, ignore cells in this temporary
state (except clearing the temporary state).
Maintain a view 'offset' (which glyph from the search string to start
rendering at).
This defines the start of the viewable area. The end is the offset +
the search box size (which is limited to the window size).
Adjust this offset whenever the cursor moves outside the viewable
area. For now, this is always done in the same way: set the offset to
the cursor position.
This means that when we're entering text at the end of the search
criteria (i.e. the normal case; we're simply typing), and the search
box reaches the window size, the cursor will jump to the start of the
search box, which will be empty. This could be confusing, but let's go
with for now.
This way, we don't have to manually insert flushes in code paths that
may execute outside of a wl_display_dispatch_pending().
(Those that execute inside a wl_display_dispatch_pending() are subject
to the flush performed at the end of the normal wayland FDM handler).
There are now three hook priorities: low, normal, high.
High priority hooks are executed *first*. Normal next, and last the
low priority hooks.
The renderer's terminal refresh hook now runs as a normal priority
hook.
With a bad behaving client (e.g. 'less' with mouse support enabled),
we can end up with a *lot* of xcursor updates (so much, that we
flooded the wayland socket before we implemented a blocking
wayl_flush()).
Since there's little point in updating the cursor more than once per
frame interval, use frame callbacks to throttle the updates.
This works more or lesslike normal terminal refreshes:
render_xcursor_set() stores the last terminal (window) that had (and
updated) the cursor.
The renderer's FDM hook checks if we have such a pending terminal set,
and if so, tries to refresh the cursor.
This is done by first checking if we're already waiting for a callback
from a previous cursor update, and if so we do nothing; the callback
will update the cursor for the next frame. If we're *not* already
waiting for a callback, we update the cursor immediately.
Since it doesn't block, we need to detect EAGAIN failures and ensure
we actually flush everything.
If we don't, we sooner or later end up in a wayland client library
call that aborts due to the socket buffer being full.
Ideally, we'd simply enable POLLOUT in the FDM. However, we cannot
write *anything* to the wayland socket until we've actually managed to
send everything. This means enabling POLLOUT in the FDM wont work
since we may (*will*) end up trying to write more data to it before
we've flushed it.
So, add a wrapper function, wayl_flush(), that acts as a blocking
variant of wl_display_flush(), by detecting EAGAIN failiures and
calling poll() itself, on the wayland socket only, until all data has
been sent.
In some cases, we end up calling render_refresh() multiple times in
the same FDM iteration. This means will render the first update
immediately, and then set the 'pending' flag, causing the updated
content to be rendered in the next frame.
This can cause flicker, or flashes, since we're presenting one or more
intermediate frames until the final content is shown.
Not to mention that it is inefficient to render multiple frames like
this.
Fix by:
* render_refresh() only sets a flag in the terminal
* install an FDM hook; this hook loops all terminals and executes what
render_refresh() _used_ to do (that is, render immediately if we're
not waiting for a frame callback, otherwise set 'pending' flag). for
all terminals that have the 'refresh_needed' flag set.
Instead of having the renderer calculate, for each cell, whether that
cell is currently selected or not, make selection_update() mark/unmark
the selected cells.
The renderer now only has to look at the cells' 'selected'
attribute. This makes the renderer both smaller and faster.
This fixes an issue where rendering the 'search' box caused the last
normal buffer from being purged.
This meant the terminal had a pointer to a now freed buffer, which we
de-referenced and occasionally memcpy:ied from.
This adds a flag, -p,--presentation-timings, that enables input lag
measuring using the presentation time Wayland protocol.
When enabled, we store a timestamp when we *send* a key to the
slave. Then, when we commit a frame for rendering to the compositor,
we request presentation feedback. We also store a timestamp for when
the frame was committed.
The 'presented' callback then looks at the input and commit
timestamps, and compares it with the presented timestamp.
The delay is logged at INFO when the delay was less than one frame
interval, at WARN when it was one frame interval, and at ERR when it
was two or more frame intervals.
We also update statistic counters that we log when foot is shut down.
Instead of trying to figure out if we had to render
something (i.e. something in the grid was dirty), and using that to
determine whether to post a callback or not, we now let
render_refresh() set a flag indication we need to render another
frame.
This simplifies render_grid(), which now _always_ renders, and pushes
it to the compositor.
The callback handler checks the pending flag and simply doesn't call
render_grid() when there's no more pending state to render.
This ends up reducing the number of wakeups when e.g. having a
blinking cursor.
Blinking can be enabled either by setting the cursor style with
CSI Ps SP q
and selecting a blinking style.
Or, with 'CSI ? 12 h'
Note that both affect the same internal state. I.e. you can disable
blinking with CSI ? 12l after having selected a blinking cursor
style. This is consistent with XTerm behavior.