When enabled, the mouse cursor is hidden when the user types in the
terminal. It is un-hidden when the user moves the mouse, or when the
window loses keyboard focus.
Compiler, in release builds, complains about 'cell_count' "may be used
uninitialized". This isn't true, as it is initialized in every
possible switch case below.
But, make the compiler happy and zero-initialize it before the switch
statement.
When scrollback indicator has been enabled, and the viewport isn't at
the bottom, we now render a *static* indicator with the position in
percent.
We use the color scheme's blue color as background, and it's white
color as foreground. This is subject to change... Should maybe be
configurable as well.
The Wayland surface + sub-surface are instantiated on-demand, and
automatically destroyed when no longer used.
And turn it from a boolean to an enum. It can be set to:
* `none` - disables the indicator
* `static` - always rendered near the top of the window
* `moving` - position reflects the scrollback position
When printing a multi-column character, write CELL_MULT_COL_SPACER
instead of '0' to both padding cells (when character doesn't fit at
the end of the line), and to the cells following the actual character.
When applying scroll damage, we may have to re-render the
margins.
This is because when we SHM-scroll, we actually move the entire
surface, and thus we end up overwriting the top margin area with old
window content, and scroll in uninitialized memory in the bottom
margin.
But, we don't have to tell the compositor about this - the last frame
always contains correct margins; i.e. there's no change between the
last frame and current frame being rendered.
TODO: we _could_ micro-optimize and only damage the margins after a
surface resize. We do it slightly more often now, when dealing with
state changes in screen flash or scrollback searching. But I don't
think it's worth the effort.
Instead of locking the queue for each dirty row we append, and
signaling a condition variable, just keep the lock while going through
the visible rows.
Release the lock once done.
Since we take the lock *before* posting the 'start' semaphore, all
workers will be waiting for the lock to be released.
Then, one at a time they'll get the lock and pick a row to
render. The queue will never get empty - when all rows have been
rendered, each worker will pick a 'frame done' "job" from the queue,
and break the rendering loop.
Previously, we had to explicitly render the old cursor cell *before*
applying scrolling damage.
We then rendered all the dirty rows, *without* rendering the cursor -
even if the cursor cell was among the dirty rows.
Finally, when everything else was done, we explicitly rendered the
cursor cell.
This meant a lot of code, and unnecessary render_cell() calls, along
with unnecessary wl_surface_damage_buffer() calls.
This was a necessary in the early design of foot, but not anymore.
We can simply mark both the old cursor cell, and the current one, as
dirty and let the normal rendering framework render it. All we need to
do is pass the cursor column to render_row(), so that it can pass
has_cursor=true in the appropriate call to render_cell(). We pass -1
here for all rows, except the cursor's row, where we pass the actual
cursor column.
With this, there's no need to calculate whether the cursor is visible
or not; just mark it's cell as dirty, and if that row is visible, the
normal rendering will take care of it.
This also simplifies the state needed to be saved between two frames;
we only need a row pointer, and the cursor column index.
Part of https://codeberg.org/dnkl/foot/issues/35
When determining whether we should render a hollow block cursor,
i.e. to signal that we're unfocused, base the decision on the
terminals current keyboard focus, not visual focus.
* xcursor always set for all pointers
* xcursor sometimes not updated when it should be
* mouse grabbed state wasn't per seat, but global (i.e. "does at least
one seat enable mouse grabbing")
* selection enabled state wasn't per seat
The sixel images are sorted, that's true. But in order for our row
numer comparisons to actually work, we need to rebase all numbers
against the current scrollback offset (or, the scrollback *end*, to be
precise).
The sixel list is sorted, with the most recent images *first* in the
list (and thus the "oldest" images are at the back).
This means we can break out of the loop when we see a sixel
that *ends before* the current view starts.
As a minor optimization, we also recognize sixels that *start after*
the current view ends. We can't break out of the loop, but we can skip
trying to render them (they wouldn't have been rendered, but more work
would have been done in render_sixel() to reach this conclusion).
This used to work before because we had a "global" clip region on the
text area, excluding the margins.
When we introduced per-cell clipping, this global clip region was
removed, and the background drawing code could now overflow into the
margins.
This fixes it by setting the cell clip region not just when rendering
a glyph, but before we render the cell background.
Our home rolled clip-to-cell code was, obviously, not correct.
The original problem was that we couldn't use pixman clipping since we
have multiple threads writing to the same pixman image, and thus there
would be races between the threads setting clipping.
The fix is actually simple - just instantiate one pixman
image (referencing the same backing image data) for each rendering
thread.
This would be done cleaner by using destination clipping in pixman,
but since we have multiple threads rendering cells simultaneously,
that is not possible.
We also cannot use source clipping since we need to offset the
destination x,y coordinates with the glyph offsets.
So, roll our own clipping by not allowing the x,y offsets to go
outside the cell boundaries, and adjusting the glyph offset
accordingly.
Closes#21
For performance reasons, we track whether a cell is selected or not
using a bit in a cell's attributes.
This makes it easy for the renderer to determine if the cells should
be rendered as selected or not - it just have to look at the
'selected' bit instead of doing a complex range check against the
current selection.
This works nicely in most cases. But, if the cell is updated, the
'selected' bit is cleared. This results in the renderer rendering the
cell normally, i.e. _not_ selected.
Checking for this, and re-setting the 'selected' bit when the cell is
updated (printed to) is way too expensive as it is in the hot path.
Instead, sync the 'selected' bits just before rendering. This isn't so
bad as it may sound; if there is no selection this is a no-op. Even if
there is a selection, only those cells whose 'selected' bit have been
cleared are dirtied (and thus re-rendered) - these cells would have
been re-rendered anyway.
Instead of storing combining data per cell, realize that most
combinations are re-occurring and that there's lots of available space
left in the unicode range, and store seen base+combining combinations
chains in a per-terminal array.
When we encounter a combining character, we first try to pre-compose,
like before. If that fails, we then search for the current
base+combining combo in the list of previously seen combinations. If
not found there either, we allocate a new combo and add it to the
list. Regardless, the result is an index into this array. We store
this index, offsetted by COMB_CHARS_LO=0x40000000ul in the cell.
When rendering, we need to check if the cell character is a plain
character, or if it's a composed character (identified by checking if
the cell character is >= COMB_CHARS_LO).
Then we render the grapheme pretty much like before.
We only used utf8proc to try to pre-compose a glyph from a base and
combining character.
We can do this ourselves by using a pre-compiled table of valid
pre-compositions. This table isn't _that_ big, and binary searching it
is fast.
That is, for a very small amount of code, and not too much extra RO
data, we can get rid of the utf8proc dependency.
This is basically just a loop that renders additional glyphs on top
off the base glyph.
Since we now need access to the row struct, for the combining
characters, the function prototype for 'render_cell()' has changed.
When rendering the combining characters we also need to deal with
broken fonts; some fonts use positive offsets (as if the combining
character was a regular character), while others use a negative
offset (to be used as if you had already advanced the pen position).
We handle both - a positive offset is rendered just like a regular
glyph. When we see a negative offset we simply add the width of a cell
first.