term_cursor_blink_update() is called when the visual focus changes
state (i.e. when our top-level surface is activated de-activated).
Checking keyboard focus worked on Sway, but on e.g. GNOME, the order
in which keyboard focus and visual focus are updated is different, and
we ended up either making the cursor invisible, or visible, but not
blinking, when changing focus back to the window.
Closes#686
Before this patch, pt-or-px values, like letter-spacing, were *always*
scaled using the current DPI value.
This is wrong; if the fonts are scaled using the output’s scaling
factor, then so should all other point values.
This also fixes an issue where e.g. letter-spacing would use one DPI
value at startup, but then when increasing/decreasing or resetting the
font size, would be re-calculated using a different DPI value, leading
to completely different spacing.
This happened when there were multiple monitors, with different DPI
values, and foot guessed the initial DPI value wrong. Normally, foot
would correct itself as soon as the window was mapped, and the
“correct” DPI value known. But if the fonts were scaled using the
scaling factor, it was possible that the font reload never happened.
This patch also updates the thickness calculation (for LIGHT and HEAVY
box drawing characters) to use the scaling factor when appropriate.
Closes#680
We now emit button 6/7 events (when the client application grabs the
mouse). This buttons map to mouse wheel horizontal scroll events. Or, left/right
tilting, if you like.
Wayland report these as ‘axis’ events (just like regular scroll wheel events),
and thus we need to translate those scroll events to button events.
libinput does not define any mouse buttons for wheel tilts, so we add our own
defitions. These are added last in the BTN_* range, just before the BTN_JOYSTICK
events.
When the foot window is closed, and we need to terminate the client application,
do this in an asynchronous fashion:
* Don’t do a blocking call to waitpid(), instead, rely on the reaper callback
* Use a timer FD to implement the timeout before sending SIGKILL (instead of
using SIGALRM).
* Send SIGTERM immediately (we used to *just* close the PTY, and then wait 2
seconds before sending SIGTERM).
* Raise the timeout from 2 seconds to 60
Full shutdown now depends on *two* asynchronous tasks - unmapping the window,
and waiting for the client application to terminate.
Only when *both* of these have completed do we proceed and call term_destroy(),
and the user provided shutdown callback.
This breaks out the scrollback erasing logic for \E[3J from csi.c, and
moves it to the new function term_erase_scrollback(), and changes the
logic to calculate the start and end row (absolute) numbers of the
scrollback, and only iterate those, instead of iterating *all* rows,
filtering out those that are on-screen.
It also adds an intersection range check of the selection range, and
cancels the selection if it touches any of the deleted scrollback
rows.
This fixes a crash when trying to render the next frame, since the
selection now references rows that have been freed.
Closes#633
Up until now, *all* buffers have been tracked in a single, global
buffer list. We've used 'cookies' to separate buffers from different
contexts (so that shm_get_buffer() doesn't try to re-use e.g. a
search-box buffer for the main grid).
This patch refactors this, and completely removes the global
list.
Instead of cookies, we now use 'chains'. A chain tracks both the
properties to apply to newly created buffers (scrollable, number of
pixman instances to instantiate etc), as well as the instantiated
buffers themselves.
This means there's strictly speaking not much use for shm_fini()
anymore, since its up to the chain owner to call shm_chain_free(),
which will also purge all buffers.
However, since purging a buffer may be deferred, if the buffer is
owned by the compositor at the time of the call to shm_purge() or
shm_chain_free(), we still keep a global 'deferred' list, on to which
deferred buffers are pushed. shm_fini() iterates this list and
destroys the buffers _even_ if they are still owned by the
compositor. This only happens at program termination, and not when
destroying a terminal instance. I.e. closing a window in a “foot
--server” does *not* trigger this.
Each terminal instatiates a number of chains, and these chains are
destroyed when the terminal instance is destroyed. Note that some
buffers may be put on the deferred list, as mentioned above.
The initial ref-count is either 1 or 0, depending on whether the
buffer is supposed to be released "immeidately" (meaning, as soon as
the compositor releases it).
Two new user facing functions have been added: shm_addref() and
shm_unref().
Our renderer now uses these two functions instead of manually setting
and clearing the 'locked' attribute.
shm_unref() will decrement the ref-counter, and destroy the buffer
when the counter reaches zero. Except if the buffer is currently
"busy" (compositor owned), in which case destruction is deferred to
the release event. The buffer is still removed from the list though.
That is, instead of requiring a ‘\n’ to be printed, non-empty lines
are now treated as having a hard linebreak by default.
The linebreak is cleared on an explicit wrap.
The previous implementation stored compose chains in a dynamically
allocated array. Adding a chain was easy: resize the array and append
the new chain at the end. Looking up a compose chain given a compose
chain key/index was also easy: just index into the array.
However, searching for a pre-existing chain given a codepoint sequence
was very slow. Since the array wasn’t sorted, we typically had to scan
through the entire array, just to realize that there is no
pre-existing chain, and that we need to add a new one.
Since this happens for *each* codepoint in a grapheme cluster, things
quickly became really slow.
Things were ok:ish as long as the compose chain struct was small, as
that made it possible to hold all the chains in the cache. Once the
number of chains reached a certain point, or when we were forced to
bump maximum number of allowed codepoints in a chain, we started
thrashing the cache and things got much much worse.
So what can we do?
We can’t sort the array, because
a) that would invalidate all existing chain keys in the grid (and
iterating the entire scrollback and updating compose keys is *not* an
option).
b) inserting a chain becomes slow as we need to first find _where_ to
insert it, and then memmove() the rest of the array.
This patch uses a binary search tree to store the chains instead of a
simple array.
The tree is sorted on a “key”, which is the XOR of all codepoints,
truncated to the CELL_COMB_CHARS_HI-CELL_COMB_CHARS_LO range.
The grid now stores CELL_COMB_CHARS_LO+key, instead of
CELL_COMB_CHARS_LO+index.
Since the key is truncated, collisions may occur. This is handled by
incrementing the key by 1.
Lookup is of course slower than before, O(log n) instead of
O(1).
Insertion is slightly slower as well: technically it’s O(log n)
instead of O(1). However, we also need to take into account the
re-allocating the array will occasionally force a full copy of the
array when it cannot simply be growed.
But finding a pre-existing chain is now *much* faster: O(log n)
instead of O(n). In most cases, the first lookup will either
succeed (return a true match), or fail (return NULL). However, since
key collisions are possible, it may also return false matches. This
means we need to verify the contents of the chain before deciding to
use it instead of inserting a new chain. But remember that this
comparison was being done for each and every chain in the previous
implementation.
With lookups being much faster, and in particular, no longer requiring
us to check the chain contents for every singlec chain, we can now use
a dynamically allocated ‘chars’ array in the chain. This was
previously a hardcoded array of 10 chars.
Using a dynamic allocated array means looking in the array is slower,
since we now need two loads: one to load the pointer, and a second to
load _from_ the pointer.
As a result, the base size of a compose chain (i.e. an “empty” chain)
has now been reduced from 48 bytes to 32. A chain with two codepoints
is 40 bytes. This means we have up to 4 codepoints while still using
less, or the same amount, of memory as before.
Furthermore, the Unicode random test (i.e. write random “unicode”
chars) is now **faster** than current master (i.e. before text-shaping
support was added), **with** test-shaping enabled. With text-shaping
disabled, we’re _even_ faster.
Using the frame callback works most of the time, but e.g. Sway doesn’t
call it while the window is hidden, and thus prevents us from updating
the title in e.g. stacked views.
This patch uses a timer FD instead. We store a timestamp from when the
title was last updated. When the application wants to update the
title, we first check if we already have a timer running, and if so,
does nothing.
If no timer is running, check the timestamp. If enough time has
passed, update the title immediately.
If not, instantiate a timer and wait for it to trigger.
Set the minimum time between two updates to ~8ms (twice per frame, for
a 60Hz output, and ~once per frame on a 120Hz output).
Closes#591
tllists are great when dealing with dynamically changing lists. They
are also very easy to use when building lists/arrays where the final
size is unknown.
However, this ease of use comes at a price: code size. tll-macros
expand to a lot of code.
Since things in the config are static, once the config has been
loaded, using tllists for configuration data structures doesn’t make
much sense.
This patch replaces nearly all tllists used by the configuration, with
dynamically allocated arrays.
When printing a character to a cell, we copy the current VT state’s
attributes to the cell. And then clear the ‘clean’ bit.
But the ‘clean’ bit is part of the VT state, and is *always*
zero. Thus there’s no need to explicitly clear it right after copying
the VT state.
This commit also renames the term_set_single_shift_ascii_printer()
function to term_single_shift(), since the former is overly verbose
and not really even accurate.
These sequences are supposed to affect the next printable ASCII
character and then reset to the previous character set, but before
this commit they were behaving like locking shifts.
Without this fix, setting LOG_ENABLE_DBG to 1 in terminal.c would
cause the following error:
> terminal.c:1787: 'struct terminal' has no member named 'font_scale'
The 'font_scale' member was removed in commit
2afc678236.
Long OSC-8 URIs, that are split up over multiple rows, are handled by
emitting one URI range on each row the URL touches.
This was done by initializing a row index variable, and then
incrementing it each loop iteration.
This caused an out-of-bounds array access when the row index reached
the maximum number of scrollback lines.
The fix is simple: make sure the row index variable wraps around,
instead of incrementing without any bounds.
Closes#552
extract_finish() returns the extracted text in UTF-8, while
extract_finish_wide() returns the extracted text in Unicode.
This patch also adds a new argument to extract_finish{,_wide},
that when set to true, skips stripping trailing empty cells.
We only needed term->font_scale to be able to detect scaling factor
changes (term->font_scale != term->scale).
But, we already have the old scaling factor in all places where
term_font_dpi_changed() is called, so let’s pass the old scaling
factor as an argument instead.
get_font_scale() was used to get the new scaling factor when loading
fonts. This was then compared to the last seen font scaling factor. If
there was no difference, the fonts were not reloaded.
The problem was, the initial term->scale was set differently. This
sometimes led to term->scale=2, while get_font_scale() return 1. That
meant, fonts were initially scaled by 2 (when dpi-aware=no). Later,
when mapped on an output (and thus term->scale being set to 1), the
fonts weren’t reloaded with the correct scaling factor since the
cached term->font_scale value was already 1.
Since term->scale always reflects the *new* scaling factor when
term_font_dpi_changed() is called, use that directly, and remove
get_font_scale().
Also rename the following functions:
* font_should_size_by_dpi() -> font_size_by_dpi_for_scale()
* font_size_by_dpi() -> font_sized_by_dpi()
* font_size_by_scale() -> font_sized_by_scale()
Instead of using CELL_SPACER for *all* cells that previously used
CELL_MULT_COL_SPACER, include the remaining number of spacers
following, and including, itself. This is encoded by adding to the
CELL_SPACER value.
So, a double width character will now store the character itself in
the first cell (just like before), and CELL_SPACER+1 in the second
cell.
A three-cell character would store the character itself, then
CELL_SPACER+2, and finally CELL_SPACER+1.
In other words, the last spacer is always CELL_SPACER+1.
CELL_SPACER+0 is used when padding at the right margin. I.e. when
writing e.g. a double width character in the last column, we insert a
CELL_SPACER+0 pad character, and then write the double width character
in the first column on the next row.
1. Free buffers and strings
2. memset() the vt struct
3. re-initialize members that must not be zero
We _could_ replace the memset() with explicit zeroing of all the
members. It’s just that there’s a lot of arrays, so this is much
easier.
Closes#495
Add a separate section for bell configuration, with a bell-specific
command option and a setting to allow that command to run without regard
to keyboard focus (for those of us who enjoy being beeped at at all
times, for example). The actions are also no longer mutually exclusive;
this is primarily anticipating urgency support which cannot be
replicated outside the process (in server mode anyway) and would thus be
complementary to any notification or arbitrary command.
* Rename cursor.style value ‘bar’ to ‘beam’. ‘bar’ remains recognized,
but should eventually be deprecated and then removed.
* Add ‘cursor.beam-thickness’ option, a pt-or-px value specifying the
thickness of the beam cursor. Defaults to 1.5pt.
* Rename (and export) pt_or_px_as_pixels() to
term_pt_or_px_as_pixels()
* Change term_pt_or_px_as_pixels() to round point values instead of
truncating them.
Foot currently does reverse-wrapping (‘auto_left_margin’, or ’bw’) on
everything that calls ‘term_cursor_left()’. This is wrong; it should
only be done for cub1. From man terminfo:
auto_left_margin | bw | bw | cub1 wraps from column 0 to last
column
This patch moves the reverse-wrapping logic from term_cursor_left() to
the handling of BS (backspace).
Closes#441