Notcurses 3.0.17
a blingful library for TUIs and character graphics
Loading...
Searching...
No Matches
termdesc.h
Go to the documentation of this file.
1#ifndef NOTCURSES_TERMDESC
2#define NOTCURSES_TERMDESC
3
4#ifdef __cplusplus
5extern "C" {
6#endif
7
8// internal header, not installed
9
10#include "version.h"
11#include "builddef.h"
12#include <stdint.h>
13#include <pthread.h>
14#include <stdbool.h>
15#include <notcurses/notcurses.h>
16#include "sprite.h"
17#include "blit.h"
18#include "fbuf.h"
19#include "in.h"
20
21// kitty keyboard protocol pop, used at end when kitty is verified.
22#define KKEYBOARD_POP "\x1b[<u"
23
24// disable key modifier options; this corresponds to a resource value of
25// "-1", which cannot be set with the [>m sequence. supposedly, "[>m" by
26// itself ought reset all of them, but this doesn't seem to work FIXME.
27#define XTMODKEYSUNDO "\x1b[>2m\x1b[>4m"
28
29struct ncpile;
30struct notcurses;
31struct ncsharedstats;
32
33// we store all our escape sequences in a single large block, and use
34// 16-bit one-biased byte-granularity indices to get the location in said
35// block. we'd otherwise be using 32 or 64-bit pointers to get locations
36// scattered all over memory. this way the lookup elements require two or four
37// times fewer cachelines total, and the actual escape sequences are packed
38// tightly into minimal cachelines. if an escape is not defined, that index
39// is 0. the first escape defined has an index of 1, and so on. an escape
40// thus cannot actually start at byte 65535.
41
42// indexes into the table of fixed-width (16-bit) indices
43typedef enum {
44 ESCAPE_CUP, // "cup" move cursor to absolute x, y position
45 ESCAPE_HPA, // "hpa" move cursor to absolute horizontal position
46 ESCAPE_VPA, // "vpa" move cursor to absolute vertical position
47 ESCAPE_SETAF, // "setaf" set foreground color
48 ESCAPE_SETAB, // "setab" set background color
49 ESCAPE_OP, // "op" set foreground and background color to defaults
50 ESCAPE_FGOP, // set foreground only to default
51 ESCAPE_BGOP, // set background only to default
52 ESCAPE_SGR0, // "sgr0" turn off all styles
53 ESCAPE_CIVIS, // "civis" make the cursor invisiable
54 ESCAPE_CNORM, // "cnorm" restore the cursor to normal
55 ESCAPE_OC, // "oc" restore original colors
56 ESCAPE_SITM, // "sitm" start italics
57 ESCAPE_RITM, // "ritm" end italics
58 ESCAPE_CUU, // "cuu" move n cells up
59 ESCAPE_CUB, // "cub" move n cells back (left)
60 ESCAPE_CUF, // "cuf" move n cells forward (right)
61 ESCAPE_BOLD, // "bold" enter bold mode
62 ESCAPE_NOBOLD, // disable bold (ANSI but not terminfo, SGR 22)
63 ESCAPE_CUD, // "cud" move n cells down
64 ESCAPE_SMKX, // "smkx" keypad_xmit (keypad transmit mode)
65 ESCAPE_RMKX, // "rmkx" keypad_local
66 ESCAPE_EL, // "el" clear to end of line, inclusive
67 ESCAPE_SMCUP, // "smcup" enter alternate screen
68 ESCAPE_RMCUP, // "rmcup" leave alternate screen
69 ESCAPE_SMXX, // "smxx" start struckout
70 ESCAPE_SMUL, // "smul" start underline
71 ESCAPE_RMUL, // "rmul" end underline
72 ESCAPE_SMULX, // "Smulx" deparameterized: start extended underline
73 ESCAPE_SMULNOX, // "Smulx" deparameterized: kill underline
74 ESCAPE_RMXX, // "rmxx" end struckout
75 ESCAPE_IND, // "ind" scroll 1 line up
76 ESCAPE_INDN, // "indn" scroll n lines up
77 ESCAPE_SC, // "sc" push the cursor onto the stack
78 ESCAPE_RC, // "rc" pop the cursor off the stack
79 ESCAPE_CLEAR, // "clear" clear screen and home cursor
80 ESCAPE_INITC, // "initc" set up palette entry
81 ESCAPE_U7, // "u7" cursor position report
82 // Application synchronized updates, not present in terminfo
83 // (https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec)
84 ESCAPE_BSUM, // Begin Synchronized Update Mode
85 ESCAPE_ESUM, // End Synchronized Update Mode
86 ESCAPE_SAVECOLORS, // XTPUSHCOLORS (push palette/fg/bg)
87 ESCAPE_RESTORECOLORS, // XTPOPCOLORS (pop palette/fg/bg)
88 ESCAPE_DECERA, // rectangular erase
91
92// when we read a cursor report, we put it on the queue for internal
93// processing. this is necessary since it can be arbitrarily interleaved with
94// other input when stdin is connected to our terminal. these are already
95// processed to be 0-based.
96typedef struct cursorreport {
97 int x, y;
100
101// terminal interface description. most of these are acquired from terminfo(5)
102// (using a database entry specified by TERM). some are determined via
103// heuristics based off terminal interrogation or the TERM environment
104// variable. some are determined via ioctl(2). treat all of them as if they
105// can change over the program's life (don't cache them locally).
106typedef struct tinfo {
107 uint16_t escindices[ESCAPE_MAX]; // table of 1-biased indices into esctable
108 int ttyfd; // connected to true terminal, might be -1
109 char* esctable; // packed table of escape sequences
110 nccapabilities caps; // exported to the user, when requested
111 unsigned pixy; // total pixel geometry, height
112 unsigned pixx; // total pixel geometry, width
113 // we use the cell's size in pixels for pixel blitting. this information can
114 // be acquired on all terminals with pixel support.
115 unsigned cellpxy; // cell pixel height, might be 0
116 unsigned cellpxx; // cell pixel width, might be 0
117 unsigned dimy, dimx; // most recent cell geometry
118
119 unsigned supported_styles; // bitmask over NCSTYLE_* driven via sgr/ncv
120
121 // kitty interprets an RGB background that matches the default background
122 // color *as* the default background, meaning it'll be translucent if
123 // background_opaque is in use. detect this, and avoid the default if so.
124 // bg_collides_default is either:
125 // 0xfexxxxxxx (unknown), 0x00RRGGBB (no collide), or 0x01RRGGBB (collides).
127
128 // 0xffxxxxxxx (unknown), or 0x00RRGGBB (foreground)
129 uint32_t fg_default;
130
131 // bitmap support. if we support bitmaps, pixel_implementation will be a
132 // value other than NCPIXEL_NONE.
134 // wipe out a cell's worth of pixels from within a sprixel. for sixel, this
135 // means leaving out the pixels (and likely resizes the string). for kitty,
136 // this means dialing down their alpha to 0 (in equivalent space).
137 int (*pixel_wipe)(sprixel* s, int y, int x);
138 // perform the inverse of pixel_wipe, restoring an annihilated sprixcell.
139 int (*pixel_rebuild)(sprixel* s, int y, int x, uint8_t* auxvec);
140 // called in phase 1 when INVALIDATED; this damages cells that have been
141 // redrawn in a sixel (when old was not transparent, and new is not opaque).
142 // it leaves the sprixel in INVALIDATED so that it's drawn in phase 2.
143 void (*pixel_refresh)(const struct ncpile* p, sprixel* s);
144 int (*pixel_remove)(int id, fbuf* f); // kitty only, issue actual delete command
145 int (*pixel_init)(struct tinfo* ti, int fd); // called when support is detected
146 int (*pixel_draw)(const struct tinfo*, const struct ncpile* p,
147 sprixel* s, fbuf* f, int y, int x);
148 int (*pixel_draw_late)(const struct tinfo*, sprixel* s, int yoff, int xoff);
149 // execute move (erase old graphic, place at new location) if non-NULL
150 int (*pixel_move)(sprixel* s, fbuf* f, unsigned noscroll, int yoff, int xoff);
151 int (*pixel_scrub)(const struct ncpile* p, sprixel* s);
152 int (*pixel_clear_all)(fbuf* f); // called during context startup
153 // make a loaded graphic visible. only used with kitty.
154 int (*pixel_commit)(fbuf* f, sprixel* s, unsigned noscroll);
155 // scroll all graphics up. only used with fbcon.
156 void (*pixel_scroll)(const struct ncpile* p, struct tinfo*, int rows);
157 void (*pixel_cleanup)(struct tinfo*); // called at shutdown
158 uint8_t* (*pixel_trans_auxvec)(const struct ncpile* p); // create tranparent auxvec
159 // sprixel parameters. there are several different sprixel protocols, of
160 // which we support sixel and kitty. the kitty protocol is used based
161 // on TERM heuristics. otherwise, we attempt to detect sixel support, and
162 // query the details of the implementation.
163 int color_registers; // sixel color registers (post pixel_query_done)
164 unsigned sixel_maxx; // maximum theoretical sixel width
165 // in sixel, we can't render to the bottom row, lest we force a one-line
166 // scroll. we thus clamp sixel_maxy_pristine to the minimum of
167 // sixel_maxy_pristine (the reported sixel_maxy), and the number of rows
168 // less one times the cell height. sixel_maxy is thus recomputed whenever
169 // we get a resize event. it is only defined if we have sixel_maxy_pristine,
170 // so kitty graphics (which don't force a scroll) never deal with this.
171 unsigned sixel_maxy; // maximum working sixel height
172 unsigned sixel_maxy_pristine; // maximum theoretical sixel height, as queried
173 unsigned sprixel_scale_height;// sprixel must be a multiple of this many rows
174 void* sixelengine; // opaque threaded engine used by sixel dispatch
175 const char* termname; // terminal name from environment variables/init
176 char* termversion; // terminal version (freeform) from query responses
177 queried_terminals_e qterm; // detected terminal class
178 // we heap-allocate this one (if we use it), as it's not fully defined on Windows
179 struct termios *tpreserved;// terminal state upon entry
180 struct inputctx* ictx; // new input layer
181 unsigned stdio_blocking_save; // was stdio blocking at entry? restore on stop.
182 // ought we issue gratuitous HPAs to work around ambiguous widths?
184
185 // if we get a reply to our initial \e[18t cell geometry query, it will
186 // replace these values. note that LINES/COLUMNS cannot be used to limit
187 // the output region; use margins for that, if necessary.
188 int default_rows; // LINES environment var / lines terminfo / 24
189 int default_cols; // COLUMNS environment var / cols terminfo / 80
190
191 ncpalette originalpalette; // palette as read from initial queries
192 int maxpaletteread; // maximum palette entry read
193 pthread_t gpmthread; // thread handle for GPM watcher
194 int gpmfd; // connection to GPM daemon
195 char mouseproto; // DECSET level (100x, '0', '2', '3')
196 bool pixelmice; // do we support pixel-precision mice?
197#ifdef __linux__
198 int linux_fb_fd; // linux framebuffer device fd
199 char* linux_fb_dev; // device corresponding to linux_fb_dev
200 uint8_t* linux_fbuffer; // mmap()ed framebuffer
201 size_t linux_fb_len; // size of map
202#elif defined(__MINGW32__)
203 HANDLE inhandle;
204 HANDLE outhandle;
205#endif
206
207 // kitty keyboard protocol level. we initialize this to UINT_MAX, in case we
208 // crash while running the initialization automata (in that case, we want to
209 // pop the keyboard support level, which we normally do only if we detected
210 // actual support. at that point, we obviously haven't detected anything).
211 // after getting the initialization package back, if it's still UINT_MAX, we
212 // set it to 0, and also indicate a lack of support via kittykbdsupport (we
213 // need distinguish between level 0, used with DRAININPUT, and an absolute
214 // lack of support, in which case we move to XTMODKEYS, for notcurses-info).
215 unsigned kbdlevel; // kitty keyboard support level
216 bool kittykbdsupport; // do we support the kitty keyboard protocol?
217 bool bce; // is the bce property advertised?
218 bool in_alt_screen; // are we in the alternate screen?
220
221// retrieve the terminfo(5)-style escape 'e' from tdesc (NULL if undefined).
222static inline __attribute__ ((pure)) const char*
223get_escape(const tinfo* tdesc, escape_e e){
224 unsigned idx = tdesc->escindices[e];
225 if(idx){
226 return tdesc->esctable + idx - 1;
227 }
228 return NULL;
229}
230
231static inline uint16_t
232term_supported_styles(const tinfo* ti){
233 return ti->supported_styles;
234}
235
236// prepare |ti| from the terminfo database and other sources. set |utf8| if
237// we've verified UTF8 output encoding. set |noaltscreen| to inhibit alternate
238// screen detection. |stats| may be NULL; either way, it will be handed to the
239// input layer so that its stats can be recorded.
240int interrogate_terminfo(tinfo* ti, FILE* out, unsigned utf8,
241 unsigned noaltscreen, unsigned nocbreak,
242 unsigned nonewfonts, int* cursor_y, int* cursor_x,
243 struct ncsharedstats* stats, int lmargin, int tmargin,
244 int rmargin, int bmargin, unsigned draininput)
245 __attribute__ ((nonnull (1, 2, 9)));
246
248
249// return a heap-allocated copy of termname + termversion
250char* termdesc_longterm(const tinfo* ti);
251
252int locate_cursor(tinfo* ti, unsigned* cursor_y, unsigned* cursor_x);
253
254int grow_esc_table(tinfo* ti, const char* tstr, escape_e esc,
255 size_t* tlen, size_t* tused);
256
257static inline int
258ncfputs(const char* ext, FILE* out){
259 int r;
260#ifdef __USE_GNU
261 r = fputs_unlocked(ext, out);
262#else
263 r = fputs(ext, out);
264#endif
265 return r;
266}
267
268static inline int
269ncfputc(char c, FILE* out){
270#ifdef __USE_GNU
271 return putc_unlocked(c, out);
272#else
273 return putc(c, out);
274#endif
275}
276
277// reliably flush a FILE*...except you can't, so far as i can tell. at least
278// on glibc, a single fflush() error latches the FILE* error, but ceases to
279// perform any work (even following a clearerr()), despite returning 0 from
280// that point on. thus, after a fflush() error, even on EAGAIN and friends,
281// you can't use the stream any further. doesn't this make fflush() pretty
282// much useless? it sure would seem to, which is why we use an fbuf for
283// all our important I/O, which we then blit with blocking_write(). if you
284// care about your data, you'll do the same.
285static inline int
286ncflush(FILE* out){
287 if(ferror(out)){
288 logerror("Not attempting a flush following error\n");
289 }
290 if(fflush(out) == EOF){
291 logerror("Unrecoverable error flushing io (%s)\n", strerror(errno));
292 return -1;
293 }
294 return 0;
295}
296
297static inline int
298term_emit(const char* seq, FILE* out, bool flush){
299 if(!seq){
300 return -1;
301 }
302 if(ncfputs(seq, out) == EOF){
303 logerror("Error emitting %lub escape (%s)\n",
304 (unsigned long)strlen(seq), strerror(errno));
305 return -1;
306 }
307 return flush ? ncflush(out) : 0;
308}
309
310// |drain| is set iff we're draining input.
311int enter_alternate_screen(int ttyfd, FILE* ttyfp, tinfo* ti, unsigned drain);
312int leave_alternate_screen(int ttyfd, FILE* ttyfp, tinfo* ti, unsigned drain);
313
314int cbreak_mode(tinfo* ti);
315
316// execute termios's TIOCGWINSZ ioctl(). returns -1 on failure.
317int tiocgwinsz(int fd, struct winsize* ws);
318
319#ifdef __cplusplus
320}
321#endif
322
323#endif
__attribute__((nonnull(1)))
Definition egcpool.c:4
const nccell * c
Definition egcpool.h:207
uint32_t idx
Definition egcpool.h:209
int r
Definition fbuf.h:226
queried_terminals_e
Definition in.h:31
#define logerror(fmt,...)
Definition logging.h:32
int y
Definition notcurses.h:1905
int int x
Definition notcurses.h:1905
ncpixelimpl_e
Definition notcurses.h:1672
struct cursorreport * next
Definition termdesc.h:98
Definition fbuf.h:25
Definition in.c:52
unsigned drain
Definition in.c:99
ncsharedstats * stats
Definition in.c:100
int lmargin
Definition in.c:66
int tmargin
Definition in.c:66
int bmargin
Definition in.c:67
tinfo * ti
Definition in.c:91
int rmargin
Definition in.c:67
queried_terminals_e qterm
Definition termdesc.h:177
unsigned supported_styles
Definition termdesc.h:119
int maxpaletteread
Definition termdesc.h:192
ncpixelimpl_e pixel_implementation
Definition termdesc.h:133
void * sixelengine
Definition termdesc.h:174
unsigned cellpxx
Definition termdesc.h:116
int(* pixel_init)(struct tinfo *ti, int fd)
Definition termdesc.h:145
const char * termname
Definition termdesc.h:175
unsigned gratuitous_hpa
Definition termdesc.h:183
int(* pixel_remove)(int id, fbuf *f)
Definition termdesc.h:144
bool bce
Definition termdesc.h:217
char mouseproto
Definition termdesc.h:195
unsigned pixx
Definition termdesc.h:112
bool pixelmice
Definition termdesc.h:196
int gpmfd
Definition termdesc.h:194
unsigned pixy
Definition termdesc.h:111
int(* pixel_rebuild)(sprixel *s, int y, int x, uint8_t *auxvec)
Definition termdesc.h:139
uint32_t bg_collides_default
Definition termdesc.h:126
unsigned kbdlevel
Definition termdesc.h:215
void(* pixel_refresh)(const struct ncpile *p, sprixel *s)
Definition termdesc.h:143
unsigned dimx
Definition termdesc.h:117
void(* pixel_cleanup)(struct tinfo *)
Definition termdesc.h:157
int(* pixel_wipe)(sprixel *s, int y, int x)
Definition termdesc.h:137
ncpalette originalpalette
Definition termdesc.h:191
bool kittykbdsupport
Definition termdesc.h:216
unsigned sprixel_scale_height
Definition termdesc.h:173
nccapabilities caps
Definition termdesc.h:110
struct termios * tpreserved
Definition termdesc.h:179
bool in_alt_screen
Definition termdesc.h:218
char * esctable
Definition termdesc.h:109
unsigned sixel_maxx
Definition termdesc.h:164
uint32_t fg_default
Definition termdesc.h:129
int default_rows
Definition termdesc.h:188
unsigned dimy
Definition termdesc.h:117
unsigned sixel_maxy
Definition termdesc.h:171
int(* pixel_draw_late)(const struct tinfo *, sprixel *s, int yoff, int xoff)
Definition termdesc.h:148
int(* pixel_scrub)(const struct ncpile *p, sprixel *s)
Definition termdesc.h:151
int(* pixel_clear_all)(fbuf *f)
Definition termdesc.h:152
unsigned stdio_blocking_save
Definition termdesc.h:181
char * termversion
Definition termdesc.h:176
unsigned sixel_maxy_pristine
Definition termdesc.h:172
struct inputctx * ictx
Definition termdesc.h:180
pthread_t gpmthread
Definition termdesc.h:193
int default_cols
Definition termdesc.h:189
void(* pixel_scroll)(const struct ncpile *p, struct tinfo *, int rows)
Definition termdesc.h:156
unsigned cellpxy
Definition termdesc.h:115
int(* pixel_move)(sprixel *s, fbuf *f, unsigned noscroll, int yoff, int xoff)
Definition termdesc.h:150
int color_registers
Definition termdesc.h:163
int(* pixel_commit)(fbuf *f, sprixel *s, unsigned noscroll)
Definition termdesc.h:154
int ttyfd
Definition termdesc.h:108
int(* pixel_draw)(const struct tinfo *, const struct ncpile *p, sprixel *s, fbuf *f, int y, int x)
Definition termdesc.h:146
uint16_t escindices[ESCAPE_MAX]
Definition termdesc.h:107
return NULL
Definition termdesc.h:228
escape_e
Definition termdesc.h:43
@ ESCAPE_CUU
Definition termdesc.h:58
@ ESCAPE_RMKX
Definition termdesc.h:65
@ ESCAPE_CIVIS
Definition termdesc.h:53
@ ESCAPE_SC
Definition termdesc.h:77
@ ESCAPE_BOLD
Definition termdesc.h:61
@ ESCAPE_CUP
Definition termdesc.h:44
@ ESCAPE_CUD
Definition termdesc.h:63
@ ESCAPE_CNORM
Definition termdesc.h:54
@ ESCAPE_MAX
Definition termdesc.h:89
@ ESCAPE_SMULX
Definition termdesc.h:72
@ ESCAPE_SETAB
Definition termdesc.h:48
@ ESCAPE_RESTORECOLORS
Definition termdesc.h:87
@ ESCAPE_CUF
Definition termdesc.h:60
@ ESCAPE_IND
Definition termdesc.h:75
@ ESCAPE_NOBOLD
Definition termdesc.h:62
@ ESCAPE_VPA
Definition termdesc.h:46
@ ESCAPE_SMXX
Definition termdesc.h:69
@ ESCAPE_ESUM
Definition termdesc.h:85
@ ESCAPE_OP
Definition termdesc.h:49
@ ESCAPE_OC
Definition termdesc.h:55
@ ESCAPE_RMCUP
Definition termdesc.h:68
@ ESCAPE_SMCUP
Definition termdesc.h:67
@ ESCAPE_SMKX
Definition termdesc.h:64
@ ESCAPE_FGOP
Definition termdesc.h:50
@ ESCAPE_SITM
Definition termdesc.h:56
@ ESCAPE_SAVECOLORS
Definition termdesc.h:86
@ ESCAPE_RMXX
Definition termdesc.h:74
@ ESCAPE_DECERA
Definition termdesc.h:88
@ ESCAPE_INDN
Definition termdesc.h:76
@ ESCAPE_BSUM
Definition termdesc.h:84
@ ESCAPE_SMUL
Definition termdesc.h:70
@ ESCAPE_CLEAR
Definition termdesc.h:79
@ ESCAPE_INITC
Definition termdesc.h:80
@ ESCAPE_RITM
Definition termdesc.h:57
@ ESCAPE_SETAF
Definition termdesc.h:47
@ ESCAPE_U7
Definition termdesc.h:81
@ ESCAPE_BGOP
Definition termdesc.h:51
@ ESCAPE_HPA
Definition termdesc.h:45
@ ESCAPE_RMUL
Definition termdesc.h:71
@ ESCAPE_RC
Definition termdesc.h:78
@ ESCAPE_SMULNOX
Definition termdesc.h:73
@ ESCAPE_EL
Definition termdesc.h:66
@ ESCAPE_CUB
Definition termdesc.h:59
@ ESCAPE_SGR0
Definition termdesc.h:52
int grow_esc_table(tinfo *ti, const char *tstr, escape_e esc, size_t *tlen, size_t *tused)
Definition termdesc.c:14
int enter_alternate_screen(int ttyfd, FILE *ttyfp, tinfo *ti, unsigned drain)
Definition termdesc.c:559
int locate_cursor(tinfo *ti, unsigned *cursor_y, unsigned *cursor_x)
Definition termdesc.c:1585
int cbreak_mode(tinfo *ti)
Definition termdesc.c:1622
int void free_terminfo_cache(tinfo *ti)
Definition termdesc.c:197
int interrogate_terminfo(tinfo *ti, FILE *out, unsigned utf8, unsigned noaltscreen, unsigned nocbreak, unsigned nonewfonts, int *cursor_y, int *cursor_x, struct ncsharedstats *stats, int lmargin, int tmargin, int rmargin, int bmargin, unsigned draininput) __attribute__((nonnull(1
char * termdesc_longterm(const tinfo *ti)
Definition termdesc.c:1562
static escape_e e
Definition termdesc.h:223
int leave_alternate_screen(int ttyfd, FILE *ttyfp, tinfo *ti, unsigned drain)
Definition termdesc.c:611
int tiocgwinsz(int fd, struct winsize *ws)
Definition termdesc.c:1603