detect sixel using device attributes request #200

pull/1377/head
nick black 3 years ago committed by Nick Black
parent 9a544488db
commit d09fec0648

@ -282,7 +282,7 @@ typedef struct tinfo {
uint32_t bg_collides_default;
bool sextants; // do we have (good, vetted) Unicode 13 sextant support?
bool braille; // do we have Braille support? (linux console does not)
bool libsixel; // do we have Sixel support?
bool sixel; // do we have Sixel support?
} tinfo;
typedef struct ncinputlayer {
@ -373,8 +373,16 @@ void sigwinch_handler(int signo);
void init_lang(notcurses* nc); // nc may be NULL, only used for logging
int terminfostr(char** gseq, const char* name);
// load |ti| from the terminfo database, which must already have been
// initialized. set |utf8| if we've verified UTF8 output encoding.
int interrogate_terminfo(tinfo* ti, const char* termname, unsigned utf8);
// perform queries that require writing to the terminal, and reading a
// response, rather than simply reading the terminfo database. can result
// in a lengthy delay or even block if the terminal doesn't respond.
int query_term(tinfo* ti, int fd);
// if there were missing elements we wanted from terminfo, bitch about them here
void warn_terminfo(const notcurses* nc, const tinfo* ti);
@ -507,26 +515,30 @@ rgb_greyscale(int r, int g, int b){
return fg * 255;
}
// write(2) with retry on partial write or interrupted write
static inline ssize_t
writen(int fd, const void* buf, size_t len){
ssize_t r;
size_t w = 0;
while(w < len){
if((r = write(fd, (const char*)buf + w, len - w)) < 0){
if(errno == EAGAIN || errno == EBUSY || errno == EINTR){
continue;
}
return -1;
}
w += r;
}
return w;
}
static inline int
tty_emit(const char* seq, int fd){
if(!seq){
return -1;
}
size_t slen = strlen(seq);
size_t written = 0;
do{
ssize_t ret = write(fd, seq, slen);
if(ret > 0){
written += ret;
}
if(ret < 0){
if(errno != EAGAIN){
break;
}
}
}while(written < slen);
if(written < slen){
//fprintf(stderr, "Error emitting %zub escape (%s)\n", strlen(seq), strerror(errno));
if(writen(fd, seq, slen) < 0){
return -1;
}
return 0;

@ -1018,9 +1018,6 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){
if(ncinputlayer_init(&ret->input, stdin)){
goto err;
}
if(make_nonblocking(ret->input.ttyinfd)){
goto err;
}
// Neither of these is supported on e.g. the "linux" virtual console.
if(!(opts->flags & NCOPTION_NO_ALTERNATE_SCREEN)){
terminfostr(&ret->tcache.smcup, "smcup");
@ -1034,6 +1031,12 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){
goto err;
}
if(ret->ttyfd >= 0){
if(opts->flags & NCOPTION_VERIFY_SIXEL){
if(query_term(&ret->tcache, ret->ttyfd)){
free_plane(ret->stdplane);
goto err;
}
}
if(ret->tcache.smkx && tty_emit(ret->tcache.smkx, ret->ttyfd)){
free_plane(ret->stdplane);
goto err;
@ -1044,6 +1047,9 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){
}
reset_term_attributes(ret);
}
if(make_nonblocking(ret->input.ttyinfd)){
goto err;
}
if((ret->rstate.mstreamfp = open_memstream(&ret->rstate.mstream, &ret->rstate.mstrsize)) == NULL){
free_plane(ret->stdplane);
goto err;
@ -2065,7 +2071,7 @@ bool notcurses_canchangecolor(const notcurses* nc){
}
bool notcurses_cansixel(const notcurses* nc){
return nc->tcache.libsixel;
return nc->tcache.sixel;
}
palette256* palette256_new(notcurses* nc){

@ -189,3 +189,59 @@ int interrogate_terminfo(tinfo* ti, const char* termname, unsigned utf8){
}
return 0;
}
static int
query_sixel(tinfo* ti, int fd){
if(writen(fd, "\033[c", 3) != 3){
return -1;
}
char in;
enum {
WANT_CSI,
WANT_QMARK,
WANT_SEMI,
WANT_C,
DONE
} state = WANT_CSI;
while(read(fd, &in, 1) == 1){
switch(state){
case WANT_CSI:
if(in == NCKEY_ESC){
state = WANT_QMARK;
}
break;
case WANT_QMARK:
if(in == '?'){
state = WANT_SEMI;
}
break;
case WANT_SEMI:
if(in == ';'){
state = WANT_C;
}
break;
case WANT_C:
if(in == 'c'){
state = DONE;
}else if(in == '4'){
ti->sixel = true;
}
break;
case DONE:
default:
break;
}
if(state == DONE){
break;
}
}
return 0;
}
// fd must be a real terminal, and must not be in nonblocking mode
int query_term(tinfo* ti, int fd){
if(query_sixel(ti, fd)){
return -1;
}
return 0;
}

@ -303,6 +303,7 @@ auto main(int argc, char** argv) -> int {
float timescale, displaytime;
ncscale_e scalemode;
notcurses_options ncopts{};
ncopts.flags = NCOPTION_VERIFY_SIXEL;
ncblitter_e blitter = NCBLIT_DEFAULT;
bool quiet = false;
bool loop = false;

Loading…
Cancel
Save