Addon termpaintx

termpaintx is an optional add-on to termpaint that offers a very simple premade integration and a few functions that might be useful for custom integrations.

For applications that deal with any kind of asynchronous events, apart from the terminal, it’s recommended to use a custom integration or an external integration into an general event loop. But for simple applications that only deal with synchronous data sources and time based events this simple integration can be used.

termpaintx has operating system specific dependencies and might not be available for all compilation environments.

The free callback of this integration frees the memory used, thus termpaint_terminal_new takes ownership of the integration.

These functions are contained in the header termpaintx.h

_Bool termpaintx_full_integration_available()

Checks if the program is connected to a terminal. (using isatty(3))

This function checks if termpaintx_full_integration() will likely succeed.

termpaint_integration *termpaintx_full_integration(const char *options)

Creates an integration object with the given options. It tries finding a connected terminal by looking at stdin, stdout, stderr and the process’ controlling terminal.

options is a space separated list of options.

Supported options:

+kbdsigint

Do not disable kernel keyboard interrupt handling (usually Ctrl-C)

+kbdsigquit

Do not disable kernel keyboard quit handling (usually Ctrl-\)

+kbdsigtstp

Do not disable kernel keyboard suspend handling (usually Ctrl-Z)

This integration does not offer any support for handling the needed SIGTSTP signal for proper suspend support. It’s your applications responsibility to supply the needed signal handling.

If an application wants to support keyboard suspend it has to arrange for a signal handler to restore the terminal and call termpaint_terminal_unpause() after the process is resumed and the kernel terminal interface is again configured for termpaint usage.

Returns NULL on failure.

termpaint_integration *termpaintx_full_integration_from_controlling_terminal(const char *options)

Creates an integration object with the given options. It tries finding a connected terminal by looking at the process’ controlling terminal.

Returns NULL on failure.

See here for allowed values of the options parameter.

termpaint_integration *termpaintx_full_integration_from_fd(int fd, _Bool auto_close, const char *options)

Creates an integration object with the given options. It uses file descriptor fd. If auto_close is true, the file descriptor will be closed when the integration is deallocated.

See here for allowed values of the options parameter.

termpaint_integration *termpaintx_full_integration_setup_terminal_fullscreen(const char *options, void (*event_handler)(void*, termpaint_event*), void *event_handler_user_data, termpaint_terminal **terminal_out, )

Creates an integration and a terminal object with the given options and connects them to work together. The integration is returned and the terminal object is made available via the terminal out-parameter.

It also runs terminal autodetection and applies detected input processing quirks, initializes full screen mode using termpaint_terminal_setup_fullscreen() and sets up a watchdog process to restore the terminal to it’s normal state if the main application suddenly terminates (e.g. a crash).

The event_handler and event_handler_user_data are passed to termpaint_terminal_set_event_cb().

Valid options are options for termpaint and options for termpaintx.

If the integration can not be initialized then the function prints an error message and returns NULL.

This function is currently equivalent to a manual setup like this:

termpaint_integration *integration = termpaintx_full_integration(options);
if (!integration) {
    const char* error = "Error: Terminal not available!";
    write(1, error, strlen(error));
    return nullptr;
}

termpaint_terminal *terminal = termpaint_terminal_new(integration);
termpaintx_full_integration_set_terminal(integration, terminal);
termpaint_terminal_set_event_cb(terminal, event_handler, event_handler_user_data);
termpaint_terminal_auto_detect(terminal);
termpaintx_full_integration_wait_for_ready_with_message(integration, 10000,
                                       "Terminal auto detection is taking unusually long, press space to abort.");
termpaintx_full_integration_apply_input_quirks(integration);
int width, height;
termpaintx_full_integration_terminal_size(integration, &width, &height);
termpaint_terminal_setup_fullscreen(terminal, width, height, options);
termpaintx_full_integration_ttyrescue_start(integration);
_Bool termpaintx_full_integration_do_iteration(termpaint_integration *integration)

Waits for input from the terminal and passes it to the connected terminal object.

Return false, if an error occurred while reading from the input file descriptor.

_Bool termpaintx_full_integration_do_iteration_with_timeout(termpaint_integration *integration, int *milliseconds)

Waits for input from the terminal for *milliseconds milliseconds and passes it to the connected terminal object.

After the call *milliseconds will contain the remaining milliseconds from the original timeout. If the call returned because the timeout expired *milliseconds will be zero, otherwise it will be the original value minus the time spend waiting for and processing input.

Return false, if an error occurred while reading from the input file descriptor.

void termpaintx_full_integration_wait_for_ready(termpaint_integration *integration)

Waits for the auto-detection to be finished. It internally calls termpaint_full_integration_do_iteration() while waiting.

void termpaintx_full_integration_wait_for_ready_with_message(termpaint_integration *integration, int milliseconds, const char *message)

Like termpaintx_full_integration_wait_for_ready() but if detection did not finish after milliseconds milliseconds, will print message.

Please note, printing a message while fingerprinting is in it’s start phase might interfere with fingerprinting. So don’t use too small values for milliseconds. Nevertheless a timeout can help for terminals that are not compatible with running terminal autodetection, by at least altering the user that something likly has gone wrong.

void termpaintx_full_integration_apply_input_quirks(termpaint_integration *integration)

Setup input handling based on the auto detection result and tty parameters.

Needs to be called after auto detection is finished.

It internally calls termpaint_terminal_auto_detect_apply_input_quirks()

void termpaintx_full_integration_set_terminal(termpaint_integration *integration, termpaint_terminal *terminal)

Sets the terminal object to be managed by this integration object. This needs to be called before using termpaint_full_integration_do_iteration() when not using termpaintx_full_integration_setup_terminal_fullscreen() (which already does that).

const struct termios *termpaintx_full_integration_original_terminal_attributes(termpaint_integration *integration)

Returns a pointer to the saved terminal attributes in termios format. The pointer is valid until the integration is freed.

Note: As all functions in termpaint this function is not async-signal safe. If the application needs this information in a signal handler it needs to call this function while initializing and store the value for the signal handler to use.

_Bool termpaintx_full_integration_ttyrescue_start(termpaint_integration *integration)

Sets up a watchdog process to restore the terminal to it’s normal state if the main application suddenly terminates (e.g. a crash).

Returns false on failure.

_Bool termpaintx_full_integration_terminal_size(termpaint_integration *integration, int *width, int *height)

Stores the current terminal size into *width and *height. This function relies on the terminal size cached in the kernel.

Returns false on failure.

termpaint_logging_func termpaintx_enable_tk_logging(void)

This function starts a helper process that uses python3 to create a window (using tkinter with logging messages. The window will appear when the first log message is output.

It returns a function suitable as logging callback for a integration.

If an error occurred setting up the helper process returns a no-op logging function.

This function is meant to easy development and debugging of an application using termpaint. It’s not meant for usage in the final application.

This function is only available if enabled at compile time.

Functions for custom integrations

_Bool termpaintx_fd_set_termios(int fd, const char *options)

This function can be used to get the kernel terminal setup without using the full integration. Instead of a pointer to an integration object this accesses the terminal directly by the file descriptor fd.

It accepts the same options as termpaintx_full_integration()

Returns false on failure.

_Bool termpaintx_fd_terminal_size(int fd, int *width, int *height)

This function can be used to get the terminal size from the kernel without using the full integration. Instead of a pointer to an integration object this accesses the terminal directly by the file descriptor fd.

Otherwise it works like termpaintx_full_integration_terminal_size().

Returns false on failure.

Terminal restore watchdog

type termpaintx_ttyrescue

termpaintx has a functions to create a watchdog subprocess to restore the terminal to a usable state on sudden program termination (e.g. a crash).

This watchdog process uses a socket pair (similar to a pipe) to monitor that the main process is still running. If the main process terminates without first signaling a clean shutdown by calling termpaintx_ttyrescue_stop() the watchdog restores the terminal and kernel interface settings.

When using the integration from termpaintx the watchdog is started by calling termpaintx_full_integration_ttyrescue_start(). The integration takes care of updating the restore sequence as it changes over time and communicating the original kernel terminal interface layer settings to the watchdog. The watchdog is automatically shut down, when the integration is freed.

If the watchdog is used with a custom terminal integration it is started using termpaintx_ttyrescue_start(), passing it the initial restore sequence and the file descriptor of the terminal. The integration has to call termpaintx_ttyrescue_set_restore_termios() to set the original struct termios contents and if the restore sequence changes it has to call termpaintx_ttyrescue_update() with the new restore sequence.

Functions

These functions are contained in the header termpaintx_ttyrescue.h

See Safety for general rules for calling functions in termpaint.

termpaintx_ttyrescue *termpaintx_ttyrescue_start_or_nullptr(int fd, const char *restore_seq)

Setup the watchdog process. The watchdog uses terminal file descriptor fd when a restore is triggered, sending the string restore_seq to the terminal.

Returns NULL on error.

void termpaintx_ttyrescue_stop(termpaintx_ttyrescue *tpr)

Cleanly stop the watchdog process.

_Bool termpaintx_ttyrescue_update(termpaintx_ttyrescue *tpr, const char *data, int len)

Update the restore sequence used by the watchdog process.

Returns false on failure.

_Bool termpaintx_ttyrescue_set_restore_termios(termpaintx_ttyrescue *tpr, const struct termios *original_terminal_attributes)

Set or update the struct termios to reset the terminal kernel interface to when the watchdog triggers.

Returns false on failure.