LeoNerd.org.uk

TICKIT (7)

NAME

tickit - Terminal Interface Construction KIT

DESCRIPTION

tickit is a library for building full-screen interactive programs that use a terminal interface. There are two levels of abstraction that a program might use the library via - a higher-level more abstracted system involving independent regions of the screen called "windows", or a lower-level system directly targetted at the actual terminal instance.

Window Level

At the higher level of abstraction, a program creates a heirarchial tree of "windows", each an instance of the TickitWindow type. These act to divide the screen area into independent regions of interest, able to receive input events such as keyboard or mouse interactions, and render content to be displayed within its area.

A typical program using this model would start by creating the underlying TickitTerm instance to represent the terminal by calling tickit_term_new(3), then create a root window on it by calling tickit_window_new_root(3). This root window can then be sub-divided into regions of interest by calling tickit_window_new(3) to build a tree of windows. Window can then have some event handlers attached by calling tickit_window_bind_event(3) - each window will need to handle the TICKIT_EV_EXPOSE event, but might also wish to handle other kinds like geometry change for dynamic resizing, or keyboard or mouse to react to user input. Finally, once the intial window tree is created, the program would enter its main event loop; see the EVENT LOOP section below.

Terminal Level

As an alternative to working at the level of windows, a program can operate on a lower level of abstraction by interacting directly with the TickitTerm instance. Operating at this level, it can use tickit_term_bind_event(3) to attach event handlers on the terminal instance itself in order to react to resize or input events. It can arrange for output to be drawn either by directly using the drawing functions on the terminal instance itself, or by constructing a TickitRenderBuffer instance to contain content, and flushing that to the terminal by calling tickit_renderbuffer_flush_to_term(3). As with the window level case, such a program will still need to use a main event loop; see below.

EVENT LOOP

Once a program has set up its initial objects and event handlers, it must then run the main event loop in order to react to input events and generate output. A later version of libtickit should provide better support for doing this, but at the current version this requires a certain amount of boilerplate code. This is explained here.

The simplest form of core of the event loop is a while loop that calls an tickit_term_input_wait function on the terminal, which will block awaiting for user input such as keyboard, mouse or resize interactions. If the windowing later is used, then tickit_window_flush(3) should be called before every blocking call to wait for input, so that pending damage can be flushed to the terminal, keeping the output up to date.

  while(1) {
    tickit_window_flush(rootwin);
    tickit_term_input_wait_msec(term, -1);
  }
 

It is a good idea to install a signal handler for SIGINT so that the terminal can be cleanly shut down on exit, restoring any alterations to altscreen, cursor settings, and so on that the application may have made.

  static bool still_running = true;
  static void sigint(int sig) { still_running = false; }
  ...

  while(still_running) {
    tickit_window_flush(rootwin);
    tickit_term_input_wait_msec(term, -1);
  }

  tickit_window_close(rootwin);
  tickit_window_unref(rootwin);
  tickit_term_unref(term);
 

A more complex program that wanted to perform other IO or timer operations at the same time, would instead make use of tickit_term_input_readable(3) and the tickit_term_input_check_timeout functions to keep the terminal IO working alongside other activity.

COMMON TYPES

The flags argument to the various _bind_event() functions should be zero, or a bitmask of the following constants.

typedef enum {
  TICKIT_BIND_FIRST,
} TickitBindFlags;
 

TICKIT_BIND_FIRST indicates that this handler should be inserted at the start of the list, rather than the default position at the end.

Some API functions take or return the following enum type, to represent a tri-state extended boolean concept of true, false, or some third condition typically indicating a "don't care" or "unknown" state; the exact semantics will vary between specific uses and should be documented specifically.

typedef enum {
  TICKIT_YES = 1,
  TICKIT_NO = 0,
  TICKIT_MAYBE = -1,
} TickitMaybeBool;

COMMON EVENTS

Every object instance that supports events supports the following type of event, in addition to the specific ones listed for that kind of object:

TICKIT_EV_DESTROY
Invoked when the object instance is being destroyed. This will be the last time the application can use the stored data argument; it may perform any resource reclaiming operations that are required at this time. The info pointer will be NULL.
TICKIT_EV_UNBIND
Invoked when the event handler is about to be removed, either because it was unbound individually, or because the object instance itself is being destroyed. In the former case, this event handler is invoked individually; in the latter case the entire list is invoked as normal and the TICKIT_EV_DESTROY flag will also be set.

SEE ALSO

tickit_window(7), tickit_term(7), tickit_pen(7), tickit_rect(7), tickit_rectset(7), tickit_renderbuffer(7), tickit_string_count(3)