Technical details¶
Handling of ambiguous input¶
Terminal to application communicating doesn’t use a prefix free encoding. For example the escape key sends just ASCII 0x1b, but many function key sequences also begin with ASCII 0x1b. As the terminal communication is just a stream of bytes the library needs to use some strategy to decide when no further input is considered part of the input sequence.
Many terminal interface libraries use timeouts to disambiguate input. Which on one hand makes behavior timing dependent and too large timeouts interfere with using ESC followed by any other key.
Termpaint doesn’t use timeouts in the traditional way. Instead when termpaint encounters a sequence that needs disambiguation, it sends a request to the terminal which produces a fixed reply that allows to disambiguate the sequence.
In practical terms the sequence used is ESC[5n
to which the terminal replies
ESC[0n
.
The concrete implementation uses a short delay before sending ESC[5n
to
reduce overhead. It also only ever keeps one such request in flight at one time.
Safety¶
There are various rules an application has to follow to safely interact with functions in termpaint.
Parameters¶
unless otherwise specified all pointers need to point to valid objects of their type
pointers to opaque structures always need to point to a initialized and valid object. (Exceptions are of course functions that initialize the objects)
Life times¶
Objects derived from the terminal object need to have a bounded lifetime that does not exceed the lifetime of the terminal object.
The application is responsible for freeing all subobjects before freeing the terminal object.
Integrations have to take care not to call into the terminal object after it was freed.
Threading and signals¶
No function in termpaint is async signal safe. Applications must cache all needed information for signal handlers themselves.
All objects that are created (transitively) from a terminal and the terminals integration need to be handled as one item for threading. This whole collection of objects may only be called from a one thread at a time.
Switching the thread that calls into this collection needs to be mediated by a C happens-before relation.
Independent terminal instances can be used without interfering with each other.
Terminal update optimization¶
Each call to termpaint_terminal_flush()
takes a copy of the just
flushed primary surface. If the next call to flush
does not specify
a full redraw, only cells are redrawn that differ from the copy made in
the previous call.
Environments that need to handle malloc failure¶
A restricted subset of termpaint can be used in environments that need to handle malloc failure gracefully.
The default mode of operation of termpaint is to abort() on allocation failure for ease of usage and to avoid cluttering code using termpaint with checks. For many applications that are not carefully written to handle allocation failure this is a reasonable tradeoff. For applications that are written carefully enough to handle allocation failures there is an alternative mode, that avoids aborting.
For these applications three major differences in usage are needed.
The first difference is that for all functions where a variant ending with
_or_nullptr
or _mustcheck
is offered the application needs to call
these variants. These signal via a return value of NULL or false that
memory allocation failed. The application can try to work without their
effects or try calling them again later. Consult the header files for
which functions need these variants.
The next difference is that applications need to call
termpaint_terminal_glitch_on_out_of_memory()
to switch termpaint
to a mode where it does not abort, but potentially misrenders output when
memory allocation fails in code paths that can’t sensibly report an error.
The major parts where this can happen is when writing strings that need
more than 8 byte of utf8 encoded characters per cell (i.e. stacks of
composing characters or complex emoji sequences) or when using
termpaint_attr_set_patch()
.
The last difference is that the application may only use a limited subset of termpaint.
Currently there are the following known restrictions:
termpaint_surface_copy_rect()
must not be used with the same surface for source and destination. As workaround preallocate a surface to use as an intermediate surface for such copy operations.termpaintx is not yet allocation failure safe.
Some parts of termpaint like terminal type auto-detection and management of the restore sequence use preallocated memory to avoid memory allocation failures in many code paths. The preallocations might not be large enough if a terminal sends excessive amounts of identifying data or the application uses an extremely high amount of setup (i.e. more colors slots than predefined).