Assume it could be a copy-paste typo. We should check PRIMARY, not
CLIPBOARD. Without this fix, we can't use PRIMARY until we copy anything
to CLIPBOARD.
While pasting data from the clipboard, block *all* other data from
being sent to the client. This includes keyboard and mouse events, but
also replies for VT queries.
This is particularly important when bracketed paste has been enabled,
since then the client will interpret *everything* between the
bracketed paste start and end as paste data.
When reading clipboard data, a malicious clipboard provider could
stall us forever, by not sending any data, and not closing the pipe.
This commit adds a timer_fd based timeout of 2 seconds. If the timer
triggers, we abort the clipboard receive.
Check for ongoing selection, and *clear* it before bailing out due to
the selection not having an end-point.
This fixes an issue where a selection was kept as ongoing, even though
the button had been released. Typically triggered by clicking without
moving the mouse; this started a new selection, then (tried to)
finalize it, but failed since the selection didn't have an end-point.
This extends the "normal" bind action enum with mouse specific
actions.
When parsing key bindings, we only check up to the last valid keyboard
binding, while mouse bindings support *both* key actions and mouse
actions.
The new actions are:
* select-begin: starts an interactive selection
* select-extend: interactively extend an existing selection
* select-word: select word under cursor
* select-word-whitespace: select word under cursor, where the only
word separating characters are whitespace characters.
The old hard-coded selection "bindings" have been converted to instead
use these actions, via default bindings added to the configuration.
Without this, the initial cell will always be selected, regardless of
how the selection is moved to the left or right.
With this patch, the initial cell will only be selected while the
selection is being made in the original direction. Changing direction
of the selection moves the start point to next/previous character.
* Fix col/row calculation in pointer-enter event; we did not take the
margins into account.
* seat->mouse.col,row are now set to -1 if the cursor is inside the
margins. That is, col/row are only ever valid when the mouse is
actually over the grid, and not in the margins.
* Use regular 'left-ptr' mouse cursor when mouse is inside the
margins, to not make the user think he/she can start a selection.
Besides making things clearer, this also fixes a crash that occurred
if you started a selection in e.g. the right margin.
As that breaks e.g. selection marking (SPACER cells didn't get
inverted when rendered).
Instead, skip them in extract_one() only. I.e. when copying text from
the grid.
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 printing a multi-column character at the end of the line, and it
doesn't fit, we currently insert a forced line-wrap. This means the
last character(s) on the previous line will be empty, followed by a
multi-column character in the first cell on the next line.
Without special code to handle this, the selection text extraction
code will insert a hard newline, since this is normally the correct
thing to do.
Add a TODO, to consider writing a special place holder value to these
padding cells.
* 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
When scrolling, there are a couple of cases where an existing
selection must be canceled because we cannot meaningfully represent it
after scrolling.
These are when the selection is (partly) inside:
* The top scrolling region
* The bottom scrolling region
* The new lines scrolled in. I.e. re-used lines
For the scrolling regions, the real problem is when the selection
crosses the scrolling region boundary; a selection that is completely
inside a scrolling regions _might_ be possible to keep, but we would
need to translate the selection coordinates to the new scrolling
region lines.
For simplicity, we cancel the selection if it touches the scrolling
region. Period.
The last item, newly scrolled in lines is when the selection covers
very old lines and we're now wrapping around the scrollback history.
Then there's a fourth problem case: when the user has started a
selection, but hasn't yet moved the cursor. In this case, we have no
end point.
What's more problematic is that when the user (after scrolling) moves
the cursor, we try to create a huge selection that covers mostly
empty (NULL) rows, causing us to crash.
This can happen e.g. when reverse scrolling in such a way that we wrap
around the scrollback history.
The actual viewport in this case is something like `-n - m`. But the
selection we'll end up trying to create will be `m - (rows - n)`. This
range may very well contain NULL rows.
To deal with this, we simply cancel the selection.
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.