* Impose a maximum memfd size limit. In theory, this can be
2GB (wl_shm_create_pool() is the limiting factor - its size argument
is an int32_t). For now, use 256MB.
This is mainly to reduce the amount of virtual address space used by
the compositor, which keeps at least one mmapping (of the entire
memfd) around. One mmapping *per terminal window* that is.
Given that we have 128TB with 48-bit virtual addresses, we could
probably bump this to 2GB without any issues. However, 256MB should
be enough.
TODO: check how much we typically move the offset when scrolling in
a fullscreen window on a 4K monitor. 256MB may turn out to be too
small.
On 32-bit shm_scroll() is completely disabled. There simply isn't
enough address space.
* Wrapping is done by moving the offset to "the other end" of the
memfd, and copying the buffer contents to the new, wrapped offset.
The "normal" scrolling code then does the actual scrolling. This
means we'll re-instantiate all objects twice when wrapping.
KDE resets all surface damage when a buffer is attached. Add a quirk
that adds a full-buffer damage to the surface. This quirk is intended
to be called after attaching a buffer to a surface.
Implemented by truncating the file size and moving the offset
backwards. This means we can only reverse scroll when we've previously
scrolled forward.
TODO: figure out if we can somehow do fast reverse scrolling even
though offset is 0 (or well, less than required for scrolling).
Before, we applied delayed rendering (that is, we gave the client a
chance to do more writes before we scheduled a render refresh) only
when the renderer were idle.
However, with e.g. a high keyboard repeat rate, it is very much
possible to start the render loop and then never break out of it while
receiving keyboard input.
This causes screen flickering, as we're no longer even trying to
detect the clients transaction boundaries.
So, let's rewrite how this is done.
First, we give the user the ability to disable delayed rendering
altogether, by setting either the lower or upper timeout to 0.
Second, when delayed rendering is enabled, we ignore the frame
callback. That is, when receiving input, we *always* reschedule the
lower timeout timer, regardless of whether the render is idle or not.
The render's frame callback handler will *not* render the grid if the
delayed render timers are armed.
This means for longer client data bursts, we may now skip frames. That
is, we're trading screen flicker for the occasional frame hickup.
For short client data bursts we should behave roughly as before.
This greatly improves the behavior of fullscreen, or near fullscreen,
updates of large grids (example, scrolling in emacs in fullscreen,
with a vertical buffer split).
There's a race/chance that we'll have disarmed the delayed rendering
timers and still get the call.
While it _shouldn't_ be anything to read from the timers, it doesn't
hurt to try. And, if the timers *are* readable, not reading them means
we'll end up in an infinite FDM loop.
shm_scroll() is fast when memmove() is slow. That is, when scrolling
a *small* amount of lines, shm_scroll() is fast.
Conversely, when scrolling a *large* number of lines, memmove() is
fast.
For now, assume the two methods perform _roughly_ the same given a
certain number of bytes they have to touch.
This means we should use shm_scroll() when number of scroll lines is
less than half the screen. Otherwise we use memmove.
Since we need to repair the bottom scroll region after a shm_scroll,
those lines are added to the count when determining which method to
use.
TODO:
* Check if it's worth to do shm scrolling when we have a top scroll
region.
* Do more performance testing with a) various amount of scrolling
lines, and b) larger bottom scroll regions.
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
When resizing in alt mode, we never updated the saved 'normal'
cursor. This meant that when we exited alt mode, the cursor would be
positioned where it was in the old pre-resize/reflow grid.
Now, we update the saved cursor in the same way we update visible
cursor. The result is that when we exit the alt screen, the cursor
is restored to the same coordinates it would have been updated to had
the resize been done in the 'normal' screen.
They aren't really user configurable. At least not yet.
However, with this, we now handle raw key codes just like the normal
key bindings. Meaning, e.g. ctrl+g, ctrl+a, ctrl+e etc now works while
searching with e.g. a russian layout.
Before, when looking for a matching user key binding, we only
matched *symbols*.
This means that the physical keys that generate a specific key binding
is layout dependent. What's worse, it may not even be possible to
generate the key binding at all.
Russian is one such layout, where all the "normal" (us) symbols are
replaced.
By using raw key codes, we can get around this - the key code has a
direct mapping to the physical key.
However, matching raw key codes **only** doesn't always make sense
either. For now, match **both** symbols _and_ key codes. Symbols take
precedence.
TODO: we might have to make this configurable _per binding_.
Note: 'search' mode still uses mostly hardcoded shortcuts that still
have this problem (i.e. ctrl+g doesn't work with a russian layout).
This adds an undocumented 'tweak' section to footrc, with two new
options:
* delayed-render-lower
* delayed-render-upper
Both takes an integer value, representing the lower/upper timeout
values (in nano seconds) for delayed rendering.
This fixes an issue where we sometimes (depends on compositor?) tried
to signal a TIOCSWINSZ and failed. This caused us to log a misleading
error message.
This fixes an issue where an 'underline' cursor wasn't visible on
underlined text - the cursor was rendered first, and then shadowed by
the text underline.
Track whether app-sync updates were enabled or disabled while handling
the current chunk of PTMX data.
This fixes and issue where we called render_refresh() unnecessarily
under (at least) the following conditions:
* Application sent "BSU <data> ESU" in the *same* chunk. In this case
we never saw that app sync was enabled and triggered delayed
rendering as usual.
* Application sent ESU. While we had noticed app sync updates being
enabled in earlier PTMX reads, when it was disabled *in the current*
PTMX read, we treated it as if it had not been enabled at all.
This caused us to trigger delayed rendering.
Now we call render_refresh() directly from ESU, and detect the "flip
off" case in PTMX read and avoid triggering a delayed rendering.
The end result of all this is that each key press (for e.g. scrolling
in a pager application) went from two frames being rendered, to a
single frame.
This fixes an issue where we failed to restore the cursor correctly
when exiting from the alternate screen, if the client had sent escapes
to save the cursor position while inside the alternate screen.
This was because we used the *same* storage for saving the cursor
position through escapes, as for saving it when entering the alternate
screen.
Fix by using a custom variable dedicated to normal <--> alt screen
switching.