From 83e71f3c4ddd3c12c54e94d39a4c1b01fc8b951a Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 5 Aug 2021 16:56:09 -0400 Subject: [PATCH] detect kitty graphics support via query #1998 --- src/lib/input.c | 33 ++++++++++++++++++++++++++++++++- src/lib/input.h | 3 ++- src/lib/termdesc.c | 25 +++++++++++++++++-------- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/src/lib/input.c b/src/lib/input.c index a2e0e8dc93..486f82838d 100644 --- a/src/lib/input.c +++ b/src/lib/input.c @@ -777,6 +777,9 @@ typedef enum { STATE_XTGETTCAP_TERMNAME1, // got property 544E, 'TN' (terminal name) first hex nibble STATE_XTGETTCAP_TERMNAME2, // got property 544E, 'TN' (terminal name) second hex nibble STATE_DCS_DRAIN, // throw away input until we hit escape + STATE_APC, // application programming command, starts with \x1b_ + STATE_APC_DRAIN, // looking for \x1b + STATE_APC_ST, // looking for ST STATE_BG1, // got '1' STATE_BG2, // got second '1' STATE_BGSEMI, // got '11;', draining string to ESC ST @@ -831,6 +834,7 @@ typedef struct query_state { bool xtgettcap_good; // high when we've received DCS 1 bool appsync; // application-synchronized updates advertised + bool kittygraphics; // kitty graphics were advertised } query_state; static int @@ -1038,6 +1042,26 @@ pump_control_read(query_state* inits, unsigned char c){ inits->state = STATE_NULL; }else if(c == '1'){ inits->state = STATE_BG1; + }else if(c == '_'){ + inits->state = STATE_APC; + } + break; + case STATE_APC: + if(c == 'G'){ + inits->kittygraphics = true; + } + inits->state = STATE_APC_DRAIN; + break; + case STATE_APC_DRAIN: + if(c == '\x1b'){ + inits->state = STATE_APC_ST; + } + break; + case STATE_APC_ST: + if(c == '\\'){ + inits->state = STATE_NULL; + }else{ + inits->state = STATE_APC_DRAIN; } break; case STATE_BG1: @@ -1464,7 +1488,7 @@ control_read(int ttyfd, query_state* qstate){ int ncinputlayer_init(tinfo* tcache, FILE* infp, queried_terminals_e* detected, unsigned* appsync, int* cursor_y, int* cursor_x, - ncsharedstats* stats){ + ncsharedstats* stats, unsigned* kittygraphs){ ncinputlayer* nilayer = &tcache->input; if(pthread_mutex_init(&nilayer->lock, NULL)){ return -1; @@ -1515,6 +1539,13 @@ int ncinputlayer_init(tinfo* tcache, FILE* infp, queried_terminals_e* detected, tcache->pixy = inits.pixelheight; tcache->pixx = inits.pixelwidth; } + if(inits.kittygraphics){ // kitty trumps sixel + loginfo("advertised kitty; disabling sixel\n"); + tcache->color_registers = 0; + tcache->sixel_maxx = 0; + tcache->sixel_maxy = 0; + *kittygraphs = true; + } } return 0; } diff --git a/src/lib/input.h b/src/lib/input.h index af2d58f1d5..acd09780e1 100644 --- a/src/lib/input.h +++ b/src/lib/input.h @@ -46,7 +46,8 @@ typedef enum { int ncinputlayer_init(struct tinfo* tcache, FILE* infp, queried_terminals_e* detected, unsigned* appsync, int* cursor_y, int* cursor_x, - struct ncsharedstats* stats); + struct ncsharedstats* stats, + unsigned* kittygraphs); void ncinputlayer_stop(struct ncinputlayer* nilayer); diff --git a/src/lib/termdesc.c b/src/lib/termdesc.c index ae80c9db7e..014d1e42a1 100644 --- a/src/lib/termdesc.c +++ b/src/lib/termdesc.c @@ -345,7 +345,12 @@ init_terminfo_esc(tinfo* ti, const char* name, escape_e idx, // non-standard CSI for total pixel geometry #define GEOMPIXEL "\x1b[14t" +// query for kitty graphics. if they are supported, we'll get a response to +// this using the kitty response syntax. otherwise, we'll get nothing. +#define KITTYQUERY "\x1b_Gi=1,a=q;\x1b\\" + #define DIRECTIVES CSI_BGQ \ + KITTYQUERY \ SUMQUERY \ "\x1b[?1;3;256S" /* try to set 256 cregs */ \ CREGSXTSM \ @@ -542,8 +547,6 @@ apply_term_heuristics(tinfo* ti, const char* termname, int fd, return -1; } } - // wezterm supports iTerm2's graphic protocol, but we'd rather use Sixel. - // once it adds Kitty, we'll prefer that. }else if(qterm == TERMINAL_XTERM){ termname = "XTerm"; // xterm 357 added color palette escapes XT{PUSH,POP,REPORT}COLORS @@ -830,8 +833,9 @@ int interrogate_terminfo(tinfo* ti, int fd, unsigned utf8, unsigned noaltscreen, cursor_y = &foolcursor_y; } *cursor_x = *cursor_y = -1; + unsigned kittygraphs = 0; if(ncinputlayer_init(ti, stdin, &qterm, &appsync_advertised, - cursor_y, cursor_x, stats)){ + cursor_y, cursor_x, stats, &kittygraphs)){ goto err; } if(nocbreak){ @@ -859,11 +863,16 @@ int interrogate_terminfo(tinfo* ti, int fd, unsigned utf8, unsigned noaltscreen, goto err; } build_supported_styles(ti); - // our current sixel quantization algorithm requires at least 64 color - // registers. we make use of no more than 256. this needs to happen - // after heuristics, since the choice of sixel_init() depends on it. - if(ti->color_registers >= 64){ - setup_sixel_bitmaps(ti, fd, invertsixel); + if(ti->pixel_draw == NULL){ + if(kittygraphs){ + setup_kitty_bitmaps(ti, fd, KITTY_SELFREF); + } + // our current sixel quantization algorithm requires at least 64 color + // registers. we make use of no more than 256. this needs to happen + // after heuristics, since the choice of sixel_init() depends on it. + if(ti->color_registers >= 64){ + setup_sixel_bitmaps(ti, fd, invertsixel); + } } return 0;