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.
When the client is capturing the mouse, selection can only be done by
holding done shift.
This is why a lot of selection functions are no-ops if selection isn't
currently enabled.
However, there are many cases where we actually need to modify the
selection. In particular, selection_cancel().
Thus, only check for enabled selection when we're dealing with user
input.
Bonus: this also fixes a bug where an ongoing selection were finalized
as soon as the user released shift, even if he was still holding down
the mouse button.
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 function extends an existing selection in the following way:
If the extension point is *before* the upper boundary of the current
selection, extend the selection upwards.
If the extension point is *after* the bottom boundary of the current
selection, extend the selection downwards.
If the extension point is *inside* the current selection, shrink the
selection such that the new size is maximized. This means we move the
*closest* start/end point from in the current selection.
To do text reflow, we only need to know if a line has been explicitly
linebreaked or not. If not, that means it wrapped, and that we
should *not* insert a linebreak when reflowing text.
When reflowing text, when reaching the end of a row in the old grid,
only insert a linebreak in the new grid if the old row had been
explicitly linebreaked.
Furthermore, when reflowing text and wrapping a row in the new grid,
mark the previous row as linebreaked if either the last cell was
(the last column in the last row) empty, or the current cell (the
first column in the new row) is empty. If both are non-empty, then we
assume a linewrap.
This fixes an issue where a "forced" selection (shift being pressed
while slave is tracking mouse events) would not finalize if the user
released shift *before* releasing the mouse button.
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).
When we extract text, we may insert '\n' at the end of each line (or
last column of selection, for block selections).
These newlines doesn't occupy any physical cells, and thus we
must **make** room for them in the extraction buffer.
When extracting text from the selection, we lost the first column on
all rows but the first.
This is because the algorithm changed slightly when we moved to
foreach_selection(); the end-of-line detection is now done on the
first column of the new line, instead of the last column on the
previous line.
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.
Instead of first memmoving, possibly lots of data lots of times, the
received buffer, and _then_ calling the callback, simply call the
callback multiple times, and just skip the \r character(s).
When this returns true, it means we have keyboard focus and are
grabbing the mouse (for e.g. selections), regardless of whether the
client has enabled mouse tracking or not.
Up the requirements for enabling "forced" selection (that is, allowing
selections even though mouse tracking has been disabled).
* Require keyboard focus (if we don't have it, then the shift-key
isn't is for us)
* Don't just require shift being pressed, but that all other modifiers
are *not* pressed.
When trying to write (to e.g. the slave, or to a clipboard receiver),
we first try to send the data synchronously, and only if that fails do
we switch to asynchronous mode.
However, the first synchronous may (in fact, is likely to) succeed
partially.
This callback is *always* called, including when there has been an
error.
This is in preparation for making text_from_{clipboard,primary}
asynchronous.
We do however need access to it, so provide a pointer. The difference
is that now we can have a *single* wayland instance, but multiple
terminal instances.