[mlterm] sixel cursor hack

At least mlterm unhides the cursor after emitting a
Sixel, even if it was hidden beforehand. Track this
behavior using 'sprixel_cursor_hack' in the tinfo cache.
Set this based on an "mlterm" TERM heuristic match.
When it is set, supply the 'civis' capability as
cursor_hack in blitterargs, and emit it at the end of
the sixel in sixel_blit() #1524.
pull/1535/head
nick black 4 years ago
parent 03a1e66bf9
commit 669bc5fa33
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -299,7 +299,8 @@ typedef struct nctabbed {
nctabbed_options opts; // copied in nctabbed_create()
} nctabbed;
// terminfo cache
// terminfo cache. FIXME shrink this and kill a pointer deref by writing them
// all into one buffer, and storing 1-biased indices with 0 for NULL.
typedef struct tinfo {
unsigned colors;// number of colors terminfo reported usable for this screen
char* sgr; // set many graphics properties at once
@ -340,12 +341,6 @@ typedef struct tinfo {
char* getm; // get mouse events
char* smcup; // enter alternate mode
char* rmcup; // restore primary mode
bool RGBflag; // "RGB" flag for 24bpc truecolor
bool CCCflag; // "CCC" flag for palette set capability
bool BCEflag; // "BCE" flag for erases with background color
bool AMflag; // "AM" flag for automatic movement to next line
bool utf8; // are we using utf-8 encoding, as hoped?
// we use the cell's size in pixels for pixel blitting. this information can
// be acquired on all terminals with pixel support.
int cellpixy; // cell pixel height, might be 0
@ -356,10 +351,14 @@ typedef struct tinfo {
// background_opaque is in use. detect this, and avoid the default if so.
// bg_collides_default is either 0x0000000 or 0x1RRGGBB.
uint32_t bg_collides_default;
// sprixel support. there are several different sprixel protocols, of
// which we support sixel and kitty. the kitty protocol is used based
// on TERM heuristics. otherwise, we attempt to detect sixel support, and
// query the details of the implementation.
pthread_mutex_t pixel_query; // only query for pixel support once
int color_registers; // sixel color registers (post pixel_query_done)
int sixel_maxx, sixel_maxy; // sixel size maxima (post pixel_query_done)
bool bitmap_supported; // do we support bitmaps (post pixel_query_done)?
int sprixelnonce; // next sprixel id
int (*pixel_destroy)(const struct notcurses* nc, const struct ncpile* p, FILE* out, sprixel* s);
// wipe out a cell's worth of pixels from within a sprixel. for sixel, this
@ -368,16 +367,27 @@ typedef struct tinfo {
int (*pixel_cell_wipe)(const struct notcurses* nc, sprixel* s, int y, int x);
int (*pixel_init)(int fd);
int (*pixel_draw)(const struct notcurses* n, const struct ncpile* p, sprixel* s, FILE* out);
bool pixel_query_done; // have we yet performed pixel query?
bool quadrants; // do we have (good, vetted) Unicode 1 quadrant support?
bool sextants; // do we have (good, vetted) Unicode 13 sextant support?
bool braille; // do we have Braille support? (linux console does not)
bool bitmap_supported; // do we support bitmaps (post pixel_query_done)?
bool sprixel_cursor_hack; // do sprixels reset the cursor? (mlterm)
bool pixel_query_done; // have we yet performed pixel query?
// alacritty went rather off the reservation for their sixel support. they
// reply to DSA with CSI?6c, meaning VT102, but no VT102 had Sixel support,
// and indeed they don't respond to XTSMGRAPHICS (which we need to query
// after validating basic Sixel). so if the TERM variable contains
// "alacritty", *and* we get VT102, we go ahead and query XTSMGRAPHICS.
// so if the TERM variable contains "alacritty", *and* we get VT102, we go
// ahead and query XTSMGRAPHICS.
bool alacritty_sixel_hack;
bool RGBflag; // "RGB" flag for 24bpc truecolor
bool CCCflag; // "CCC" flag for palette set capability
bool BCEflag; // "BCE" flag for erases with background color
bool AMflag; // "AM" flag for automatic movement to next line
// assigned based off nl_langinfo() in notcurses_core_init()
bool utf8; // are we using utf-8 encoding, as hoped?
// these are assigned wholly through TERM-based heuristics
bool quadrants; // do we have (good, vetted) Unicode 1 quadrant support?
bool sextants; // do we have (good, vetted) Unicode 13 sextant support?
bool braille; // do we have Braille support? (linux console does not)
} tinfo;
typedef struct ncinputlayer {
@ -516,6 +526,10 @@ typedef struct {
int celldimy; // vertical pixels per cell
int colorregs; // number of color registers
sprixel* spx; // sprixel object
// in at least mlterm, emitting a sixel makes the cursor visible.
// if the cursor is hidden, and sprixel_cursor_hack is set, this
// is set to the civis capability.
const char* cursor_hack;
} pixel; // for pixels
} u;
} blitterargs;

@ -137,9 +137,13 @@ update_deets(uint32_t rgb, cdetails* deets){
// count, and a sum of all three channels. in addition, we track whether we've
// seen at least two colors in the chunk.
static inline int
extract_color_table(const uint32_t* data, int linesize, int begy, int begx, int cols,
int leny, int lenx, int cdimy, int cdimx, sixeltable* stab,
sprixcell_e* tacache, uint32_t transcolor){
extract_color_table(const uint32_t* data, int linesize, int cols,
int leny, int lenx, sixeltable* stab,
sprixcell_e* tacache, const blitterargs* bargs){
const int begx = bargs->begx;
const int begy = bargs->begy;
const int cdimy = bargs->u.pixel.celldimy;
const int cdimx = bargs->u.pixel.celldimx;
unsigned char mask = 0xc0;
int pos = 0; // pixel position
for(int visy = begy ; visy < (begy + leny) ; visy += 6){ // pixel row
@ -147,7 +151,7 @@ extract_color_table(const uint32_t* data, int linesize, int begy, int begx, int
for(int sy = visy ; sy < (begy + leny) && sy < visy + 6 ; ++sy){ // offset within sprixel
const uint32_t* rgb = (data + (linesize / 4 * sy) + visx);
int txyidx = (sy / cdimy) * cols + (visx / cdimx);
if(rgba_trans_p(*rgb, transcolor)){
if(rgba_trans_p(*rgb, bargs->transcolor)){
if(tacache[txyidx] == SPRIXCELL_NORMAL){
tacache[txyidx] = SPRIXCELL_CONTAINS_TRANS;
}
@ -316,7 +320,8 @@ write_rle(int* printed, int color, FILE* fp, int seenrle, unsigned char crle){
// Emit the sprixel in its entirety, plus enable and disable pixel mode.
// Closes |fp| on all paths.
static int
write_sixel_data(FILE* fp, int leny, int lenx, const sixeltable* stab, int* parse_start){
write_sixel_data(FILE* fp, int leny, int lenx, const sixeltable* stab, int* parse_start,
const char* cursor_hack){
// Set P2=1, turning empty pixels transparent
*parse_start = fprintf(fp, "\eP0;1;0q");
// Set Raster Attributes - pan/pad=1 (pixel aspect ratio), Ph=lenx, Pv=leny
@ -377,6 +382,9 @@ write_sixel_data(FILE* fp, int leny, int lenx, const sixeltable* stab, int* pars
// \x9c: 8-bit "string terminator" (end sixel) doesn't work on at
// least xterm; we instead use '\e\\'
fprintf(fp, "\e\\");
if(cursor_hack){
fprintf(fp, "%s", cursor_hack);
}
if(fclose(fp) == EOF){
return -1;
}
@ -398,7 +406,8 @@ sixel_blit_inner(int leny, int lenx, const sixeltable* stab, int rows, int cols,
}
int parse_start = 0;
// calls fclose() on success
if(write_sixel_data(fp, leny, lenx, stab, &parse_start)){
if(write_sixel_data(fp, leny, lenx, stab, &parse_start,
bargs->u.pixel.cursor_hack)){
free(buf);
return -1;
}
@ -459,9 +468,8 @@ int sixel_blit(ncplane* n, int linesize, const void* data,
}
memset(tacache, 0, sizeof(*tacache) * rows * cols);
}
if(extract_color_table(data, linesize, bargs->begy, bargs->begx, cols, leny, lenx,
bargs->u.pixel.celldimy, bargs->u.pixel.celldimx,
&stable, tacache, bargs->transcolor)){
if(extract_color_table(data, linesize, cols, leny, lenx,
&stable, tacache, bargs)){
if(!reuse){
free(tacache);
}

@ -80,6 +80,7 @@ apply_term_heuristics(tinfo* ti, const char* termname){
// st had neithersextants nor quadrants last i checked (0.8.4)
}else if(strstr(termname, "mlterm")){
ti->quadrants = true; // good quadrants, no sextants as of 3.9.0
ti->sprixel_cursor_hack = true;
}else if(strstr(termname, "xterm")){
// xterm has nothing beyond halfblocks. this is going to catch all kinds
// of people using xterm when they shouldn't be, or even real database
@ -88,6 +89,7 @@ apply_term_heuristics(tinfo* ti, const char* termname){
}else if(strcmp(termname, "linux") == 0){
ti->braille = false; // no braille, no sextants in linux console
// FIXME if the NCOPTION_NO_FONT_CHANGES, this isn't true
// FIXME we probably want to do this based off ioctl()s in linux.c
ti->quadrants = true; // we program quadrants on the console
}
// run a wcwidth(⣿) to guarantee libc Unicode 3 support, independent of term

@ -686,6 +686,12 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits
ncv->spx = sprixel_recycle(n, ncv);
}
bargs.u.pixel.spx = ncv->spx;
// FIXME only set this if cursor is indeed hidden
if(nc->tcache.sprixel_cursor_hack){
bargs.u.pixel.cursor_hack = nc->tcache.civis;
}else{
bargs.u.pixel.cursor_hack = NULL;
}
if(ncvisual_blit(ncv, disprows, dispcols, n, bset, disprows, dispcols, &bargs)){
goto err;
}

Loading…
Cancel
Save