These functions update the OSC-8 URI state in the terminal.
term_osc8_open() tracks the beginning of an URL, by storing the start
coordinate (i.e. the current cursor location), along with the URL
itself.
Note that term_osc8_open() may not be called with an empty URL. This
is important to notice, since the way OSC-8 works, applications close
an URL by “opening” a new, empty one:
\E]8;;https://foo.bar\e\\this is an OSC-8 URL\E]8;;\e\\
It is up to the caller to check for this, and call term_osc8_close()
instead of term_osc8_open() when the URL is empty.
However, it is *also* valid to switch directly from one URL to
another:
\E]8;;http://123\e\\First URL\E]8;;http//456\e\\Second URL\E]8;;\e\\
This use-case *is* handled by term_osc8_open().
term_osc8_close() uses the information from term_osc8_open() to add
per-row URL data (using the new ‘extra’ row data).
This patch adds an ‘extra’ member to the row struct. It is a pointer
to a struct containing extra data to be associated with this row.
Initially, this struct contains a list of URL ranges. These
define (OSC-8) URLs on this row.
The ‘extra’ data is allocated on-demand. I.e. the pointer is NULL by
default; it is *not* allocated by grid_row_alloc().
The only time the URL is actually in UTF-32 is when we’re collecting
it (auto-detecting it) from the grid, since cells store their
character(s) in UTF-32.
Everything *after* that prefers the URL in UTF-8. So, do the
conversion while collecting the URL.
This patch also changes the URL activation code to strip the
‘file://user@host/’ prefix from file URIs that refer to files
on the *local* computer.
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
* We were using the ‘back’ element of the list as prefix for the next
iteration of sequences, instead of the element at index ‘offset’
* ALEN() on a wchar_t[] includes the NULL terminator. We don’t want
that.
This is implemented by allocating one of the (few!) remaining bits in
the cells’ attribute struct to indicate the cell should be “URL
highlighted”.
render_cell() looks at this bit and draws an underline using the color
from colors.urls (defaults to regular3 - i.e. yellow).
A new function, url_tag_cells(), iterates the currently detected URLs
and sets the new ‘url’ attribute flag on the affected cells.
Note: this is done in a separate function to keep urls_collect() free
from as many dependencies as possible.
urls_reset() is updated to *clear* the ‘url’ flag (and thus implicitly
also results in a grid refresh, _if_ there were any URLs).
We now exit URL mode on *any* client application input. This needs to
be so since we can’t know if the URLs we previously detected are still
valid.
This works just like show-urls-launch, except that instead of opening
the URL (typically using xdg-open), it is placed in the clipboard when
activated.
If the value is specified without a unit, then the value is assumed to
be in points, subject to DPI scaling.
The value can optionally have a ‘px’ suffix, in which case the value
is treated as a raw pixel count.
Extend selection pivoting to allow selections to pivot around a
range.
Use this in word- and row-based selections to pivot around the initial
word/row that was selected.
This mimics the behavior of at least urxvt and xterm.
* ‘term’ struct contains an array of 160 fcft glyph pointers
* the glyph pointers are lazily allocated when we need to draw a box
drawings character
* Filtering out box drawings characters is easy - they are (except
unicode 13, which isn’t handled yet )all in a single range.
Take ‘\E(#0’ for example - this is *not* the same as ‘\E(0’.
Up until now, foot has however treated them as the same escape,
because the handler for ‘\E(0’ didn’t verify there weren’t any _other_
private characters present.
Fix this by turning the ‘private’ array into a single 4-byte
integer. This allows us to match *all* privates with a single
comparison.
Private characters are added to the LSB first, and MSB last. This
means we can check for single privates in pretty much the same way as
before:
switch (term->vt.private) {
case ‘?’:
...
break;
}
Checking for two (or more) is much uglier, but foot only supports
a *single* escape with two privates, and no escapes with three or
more:
switch (term->vt.private) {
case 0x243f: /* ‘?$’ */
...
break;
}
The ‘clear’ action remains simple (and fast), with a single write
operation.
Collecting privates is potentially _slightly_ more complex than
before; we now need mask and compare, instead of simply comparing,
when checking how many privates we already have.
We _could_ add a counter, which would make collecting privates easier,
but this would add an additional write to the ‘clean’ action which is
really bad since it’s in the hot path.
This fixes issues with de-synchronized frames being rendered; we may
have scheduled a redraw earlier, that hasn’t yet triggered (probably
because we’re waiting for a frame callback), when we enable
application synchronized updates.
This means we risk rendering a partially updated state when the frame
callback finally arrives, if the application hasn’t yet ended its
synchronized update.
We may want to be able to enable/disable IME run-time, even though we
have received an ‘enter’ IME event.
This enables us to do that.
Also add functions to enable/disable IME on a per-terminal instance
basis.
A terminal may have multiple seats focusing it, and enabling/disabling
IME in a terminal instance enables/disables IME on all those seats.
Finally, the code to enable IME is simplified; the *only* surface that
can ever receive ‘enter’ IME events is the main grid. All other
surfaces are sub-surfaces, without their own keyboard focus.
This is done by allocating cells for the pre-edit text when receiving
the text-input::done() call, and populating them by converting the
utf-8 formatted pre-edit text to wchars.
We also convert the pre-edit cursor position to cell positions (it can
cover multiple cells).
When rendering, we simply render the pre-edit cells on-top off the
regular grid. While doing so, we also mark the underlying, “real”,
cells as dirty, to ensure they are re-rendered when the pre-edit text
is modified or removed.
This mode can be set by client programs with the DECSET, DECRST,
XTSAVE and XTRESTORE sequences by using 27127 as the parameter.
The sequence "\E[27;1;27~" is encoded in the same way as is done by
xterm's "modifyOtherKeys" mode. Even though xterm itself never emits
such a sequence for the Escape key, many programs already have
support for parsing this style of key sequence.
There are two different escape sequences that can be used to set the
cursor blink state: ‘CSI ? 12 h/l’ and ‘CSI Ps SP q’.
Up until now, they both modified the same internal state in foot. This
meant you could enable a blinking cursor with e.g. ‘CSI ? 12 h’ and
then disable it with ‘CSI 2 SP q’.
Since the ‘CSI ? 12’ escapes are used in the civis/cnorm/cvvis
terminfo entries, applications often ended up disabling the blink
state on exit (typically be emitting ‘cnorm’), requiring users to
manually re-enable blinking.
By splitting the internal state into two separate states, we can
improve the situation.
The cursor will blink if at least one of the two have been enabled.
The setting in foot.ini sets the default state of the ‘CSI Ps SP q’
escape.
This means if the user has enabled blinking in the configuration, the
cursor will blink regardless of civis/cnorm/cvvis. Which probably is
what the user wants.
If the user has NOT enabled blinking, civis/cnorm/cvvis act as
intended: cvvis blink, civis and cnorm do not.
If an application overrides the cursor blink/style with ‘CSI Ps SP q’,
that will override the user’s setting in foot.ini. But most likely
that too is intended (for example, the user may have configured the
application to use a different cursor style). And, a well written
application will emit the ‘Se’ terminfo sequence on exit, which in
foot is defined to ‘CSI SP q’, which will reset both the style and
blink state to the user configured style/state.
Closes#218
When disabled, foot no longers uses outputs’ DPI to scale the
font. Instead, it uses the outputs’ scaling factor.
That is, instead of appending “:dpi=123” to the fontconfig string,
modify the “:pixelsize” or “:size” attribute.
Closes#206
These options lets the user configure custom fonts and styles, to use
with the bold and italic cell attributes.
By default, they are unset, meaning we use the bold/italic variants of
the regular font.
Closes#169.
Bind to xdg-shell version 2 if available, as this enables us to
track our window’s ‘tiled’ state in the ‘configure’ events.
This in turn allows us to stash the ‘old’ window size when being
tiled, to be used again when restoring the window size when un-tiled.
Moving the mouse outside the grid while we have an on-going selection
now starts a timer. The interval of this timer depends on the mouse’s
distance from the grid - the further away the mouse is, the shorter
interval.
On each timer timeout, we scroll one line, and update the
selection. Thus, the shorter the interval, the faster we scroll.
The timer is canceled as soon as the mouse enters the grid again, or
the selection is either canceled or finalized.
The timer FD is created and destroyed on-demand.
Most of the logic is now in selection.c. The exception is the
calculation of the timer interval, which depends on the mouse’s
position. Thus, this is done in input.c.
The scroll+selection update logic needs to know a) which direction
we’re scrolling in, and b) which *column* the selection should be
updated with.
If the mouse is outside the grid’s left or right margins, the stored
mouse column will be -1. I.e. we don’t know whether the mouse is on
the left or right side of the grid. This is why the caller, that
starts the timer, must provide this value.
The same applies to top and bottom margins, but since we already have
the scroll *direction*, which row value to use can be derived from this.
Add anew config option, ‘bell=none|set-urgency’. When set to
‘set-urgency’, the margins will be painted in red (if the window did
not have keyboard focus).
This is intended as a cheap replacement for the ‘urgency’ hint, that
doesn’t (yet) exist on Wayland.
Closes#157
term_damage_cursor() damages the cell where the cursor is currently
at. This can be used to ensure the cursor is re-drawn, if there aren’t
any other pending updates.
term_damage_margins() requests the margins be redrawn the next time we
render the grid.