mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 17:19:03 -04:00
always send DSRCPR at init, use it to verify u7
for NCOPTION_PRESERVE_CURSOR, we want to know the location of the cursor at startup. go ahead and always send a DSRCPR in terminal interrogation. if we get a reply to it, hey, we just verified that the terminal knows DSRCPR. if we find a u7 value in terminfo that's different from the standard DSRCPR, we ought send that in addition. #1816
This commit is contained in:
parent
166212f234
commit
9f92986a6b
6
USAGE.md
6
USAGE.md
@ -106,6 +106,12 @@ typedef enum {
|
|||||||
// registration of these signal handlers.
|
// registration of these signal handlers.
|
||||||
#define NCOPTION_NO_QUIT_SIGHANDLERS 0x0008
|
#define NCOPTION_NO_QUIT_SIGHANDLERS 0x0008
|
||||||
|
|
||||||
|
// Initialize the standard plane's virtual cursor to match the physical cursor
|
||||||
|
// at context creation time. Together with NCOPTION_NO_ALTERNATE_SCREEN and a
|
||||||
|
// scrolling standard plane, this facilitates easy scrolling-style programs in
|
||||||
|
// rendered mode.
|
||||||
|
#define NCOPTION_PRESERVE_CURSOR 0x0010ull
|
||||||
|
|
||||||
// Notcurses typically prints version info in notcurses_init() and performance
|
// Notcurses typically prints version info in notcurses_init() and performance
|
||||||
// info in notcurses_stop(). This inhibits that output.
|
// info in notcurses_stop(). This inhibits that output.
|
||||||
#define NCOPTION_SUPPRESS_BANNERS 0x0020
|
#define NCOPTION_SUPPRESS_BANNERS 0x0020
|
||||||
|
@ -117,7 +117,7 @@ tinfo_debug_styles(struct ncplane* n, const char* indent){
|
|||||||
// notcurses_render() without the alternate screen, no?
|
// notcurses_render() without the alternate screen, no?
|
||||||
int main(void){
|
int main(void){
|
||||||
notcurses_options nopts = {
|
notcurses_options nopts = {
|
||||||
.flags = NCOPTION_NO_ALTERNATE_SCREEN,
|
.flags = NCOPTION_NO_ALTERNATE_SCREEN | NCOPTION_PRESERVE_CURSOR,
|
||||||
};
|
};
|
||||||
struct notcurses* nc = notcurses_init(&nopts, NULL);
|
struct notcurses* nc = notcurses_init(&nopts, NULL);
|
||||||
if(nc == NULL){
|
if(nc == NULL){
|
||||||
|
@ -650,6 +650,8 @@ typedef enum {
|
|||||||
STATE_XTSMGRAPHICS_DRAIN, // drain out XTSMGRAPHICS to 'S'
|
STATE_XTSMGRAPHICS_DRAIN, // drain out XTSMGRAPHICS to 'S'
|
||||||
STATE_APPSYNC_REPORT, // got DECRPT ?2026
|
STATE_APPSYNC_REPORT, // got DECRPT ?2026
|
||||||
STATE_APPSYNC_REPORT_DRAIN, // drain out decrpt to 'y'
|
STATE_APPSYNC_REPORT_DRAIN, // drain out decrpt to 'y'
|
||||||
|
STATE_CURSOR, // reading row of cursor location to ';'
|
||||||
|
STATE_CURSOR_COL, // reading col of cursor location to 'R'
|
||||||
} initstates_e;
|
} initstates_e;
|
||||||
|
|
||||||
typedef struct query_state {
|
typedef struct query_state {
|
||||||
@ -665,6 +667,7 @@ typedef struct query_state {
|
|||||||
char runstring[80]; // running string
|
char runstring[80]; // running string
|
||||||
size_t stridx; // position to write in string
|
size_t stridx; // position to write in string
|
||||||
uint32_t bg; // queried default background or 0
|
uint32_t bg; // queried default background or 0
|
||||||
|
int cursor_y, cursor_x;// cursor location
|
||||||
bool xtgettcap_good; // high when we've received DCS 1
|
bool xtgettcap_good; // high when we've received DCS 1
|
||||||
bool appsync; // application-synchronized updates advertised
|
bool appsync; // application-synchronized updates advertised
|
||||||
} query_state;
|
} query_state;
|
||||||
@ -879,10 +882,38 @@ pump_control_read(query_state* inits, unsigned char c){
|
|||||||
inits->state = STATE_DA; // could also be DECRPM/XTSMGRAPHICS
|
inits->state = STATE_DA; // could also be DECRPM/XTSMGRAPHICS
|
||||||
}else if(c == '>'){
|
}else if(c == '>'){
|
||||||
inits->state = STATE_SDA;
|
inits->state = STATE_SDA;
|
||||||
|
}else if(isdigit(c)){
|
||||||
|
inits->numeric = 0;
|
||||||
|
inits->state = STATE_CURSOR;
|
||||||
}else if(c >= 0x40 && c <= 0x7E){
|
}else if(c >= 0x40 && c <= 0x7E){
|
||||||
inits->state = STATE_NULL;
|
inits->state = STATE_NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case STATE_CURSOR:
|
||||||
|
if(isdigit(c)){
|
||||||
|
if(ruts_hex(&inits->numeric, c)){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}else if(c == ';'){
|
||||||
|
inits->cursor_y = inits->numeric;
|
||||||
|
inits->state = STATE_CURSOR_COL;
|
||||||
|
inits->numeric = 0;
|
||||||
|
}else{
|
||||||
|
inits->state = STATE_NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STATE_CURSOR_COL:
|
||||||
|
if(isdigit(c)){
|
||||||
|
if(ruts_hex(&inits->numeric, c)){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}else if(c == 'R'){
|
||||||
|
inits->cursor_x = inits->numeric;
|
||||||
|
inits->state = STATE_NULL;
|
||||||
|
}else{
|
||||||
|
inits->state = STATE_NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case STATE_DCS: // terminated by ST
|
case STATE_DCS: // terminated by ST
|
||||||
if(c == '\\'){
|
if(c == '\\'){
|
||||||
//fprintf(stderr, "terminated DCS\n");
|
//fprintf(stderr, "terminated DCS\n");
|
||||||
@ -1168,7 +1199,7 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ncinputlayer_init(tinfo* tcache, FILE* infp, queried_terminals_e* detected,
|
int ncinputlayer_init(tinfo* tcache, FILE* infp, queried_terminals_e* detected,
|
||||||
unsigned* appsync){
|
unsigned* appsync, int* cursor_y, int* cursor_x){
|
||||||
ncinputlayer* nilayer = &tcache->input;
|
ncinputlayer* nilayer = &tcache->input;
|
||||||
setbuffer(infp, NULL, 0);
|
setbuffer(infp, NULL, 0);
|
||||||
nilayer->inputescapes = NULL;
|
nilayer->inputescapes = NULL;
|
||||||
@ -1188,6 +1219,8 @@ int ncinputlayer_init(tinfo* tcache, FILE* infp, queried_terminals_e* detected,
|
|||||||
.tcache = tcache,
|
.tcache = tcache,
|
||||||
.state = STATE_NULL,
|
.state = STATE_NULL,
|
||||||
.qterm = TERMINAL_UNKNOWN,
|
.qterm = TERMINAL_UNKNOWN,
|
||||||
|
.cursor_x = -1,
|
||||||
|
.cursor_y = -1,
|
||||||
};
|
};
|
||||||
if(control_read(csifd, &inits)){
|
if(control_read(csifd, &inits)){
|
||||||
input_free_esctrie(&nilayer->inputescapes);
|
input_free_esctrie(&nilayer->inputescapes);
|
||||||
@ -1198,6 +1231,8 @@ int ncinputlayer_init(tinfo* tcache, FILE* infp, queried_terminals_e* detected,
|
|||||||
tcache->termversion = inits.version;
|
tcache->termversion = inits.version;
|
||||||
*detected = inits.qterm;
|
*detected = inits.qterm;
|
||||||
*appsync = inits.appsync;
|
*appsync = inits.appsync;
|
||||||
|
*cursor_x = inits.cursor_x;
|
||||||
|
*cursor_y = inits.cursor_y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -34,7 +34,8 @@ typedef enum {
|
|||||||
// advertised support for application-sychronized updates, |appsync| will be
|
// advertised support for application-sychronized updates, |appsync| will be
|
||||||
// non-zero.
|
// non-zero.
|
||||||
int ncinputlayer_init(struct tinfo* tcache, FILE* infp,
|
int ncinputlayer_init(struct tinfo* tcache, FILE* infp,
|
||||||
queried_terminals_e* detected, unsigned* appsync);
|
queried_terminals_e* detected, unsigned* appsync,
|
||||||
|
int* cursor_y, int* cursor_x);
|
||||||
|
|
||||||
void ncinputlayer_stop(struct ncinputlayer* nilayer);
|
void ncinputlayer_stop(struct ncinputlayer* nilayer);
|
||||||
|
|
||||||
|
@ -150,6 +150,46 @@ grow_esc_table(tinfo* ti, const char* tstr, escape_e esc,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Device Attributes; replies with (depending on decTerminalID resource):
|
||||||
|
// ⇒ CSI ? 1 ; 2 c ("VT100 with Advanced Video Option")
|
||||||
|
// ⇒ CSI ? 1 ; 0 c ("VT101 with No Options")
|
||||||
|
// ⇒ CSI ? 4 ; 6 c ("VT132 with Advanced Video and Graphics")
|
||||||
|
// ⇒ CSI ? 6 c ("VT102")
|
||||||
|
// ⇒ CSI ? 7 c ("VT131")
|
||||||
|
// ⇒ CSI ? 1 2 ; Ps c ("VT125")
|
||||||
|
// ⇒ CSI ? 6 2 ; Ps c ("VT220")
|
||||||
|
// ⇒ CSI ? 6 3 ; Ps c ("VT320")
|
||||||
|
// ⇒ CSI ? 6 4 ; Ps c ("VT420")
|
||||||
|
|
||||||
|
// query background, replies in X color https://www.x.org/releases/X11R7.7/doc/man/man7/X.7.xhtml#heading11
|
||||||
|
#define CSI_BGQ "\e]11;?\e\\"
|
||||||
|
|
||||||
|
// ought be using the u7 terminfo string here, if it exists. the great thing
|
||||||
|
// is, if we get a response to this, we know we can use it for u7!
|
||||||
|
#define DSRCPR "\e[6n"
|
||||||
|
|
||||||
|
// we send an XTSMGRAPHICS to set up 256 color registers (the most we can
|
||||||
|
// currently take advantage of; we need at least 64 to use sixel at all.
|
||||||
|
// maybe that works, maybe it doesn't. then query both color registers
|
||||||
|
// and geometry. send XTGETTCAP for terminal name.
|
||||||
|
static int
|
||||||
|
send_initial_queries(int fd){
|
||||||
|
const char queries[] = CSI_BGQ
|
||||||
|
DSRCPR
|
||||||
|
"\x1b[?2026$p" // query for App-sync updates
|
||||||
|
"\x1b[=0c" // Tertiary Device Attributes
|
||||||
|
"\x1b[>0q" // XTVERSION
|
||||||
|
"\x1bP+q544e\x1b\\" // XTGETTCAP['TN']
|
||||||
|
"\x1b[?1;3;256S" // try to set 256 cregs
|
||||||
|
"\x1b[?2;1;0S" // XTSMGRAPHICS (cregs)
|
||||||
|
"\x1b[?1;1;0S" // XTSMGRAPHICS (geometry)
|
||||||
|
"\x1b[c"; // Device Attributes
|
||||||
|
if(blocking_write(fd, queries, strlen(queries))){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
init_terminfo_esc(tinfo* ti, const char* name, escape_e idx,
|
init_terminfo_esc(tinfo* ti, const char* name, escape_e idx,
|
||||||
size_t* tablelen, size_t* tableused){
|
size_t* tablelen, size_t* tableused){
|
||||||
@ -164,14 +204,15 @@ init_terminfo_esc(tinfo* ti, const char* name, escape_e idx,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// older kitty terminfo doesn't include u7. remove this when we can FIXME.
|
// if we get a response to the standard cursor locator escape, we know this
|
||||||
|
// terminal supports it, hah.
|
||||||
static int
|
static int
|
||||||
add_u7_escape(tinfo* ti, size_t* tablelen, size_t* tableused){
|
add_u7_escape(tinfo* ti, size_t* tablelen, size_t* tableused){
|
||||||
const char* u7 = get_escape(ti, ESCAPE_DSRCPR);
|
const char* u7 = get_escape(ti, ESCAPE_DSRCPR);
|
||||||
if(u7){
|
if(u7){
|
||||||
return 0; // already present
|
return 0; // already present
|
||||||
}
|
}
|
||||||
if(grow_esc_table(ti, "\e[6n", ESCAPE_DSRCPR, tablelen, tableused)){
|
if(grow_esc_table(ti, DSRCPR, ESCAPE_DSRCPR, tablelen, tableused)){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -221,9 +262,6 @@ apply_term_heuristics(tinfo* ti, const char* termname, int fd,
|
|||||||
if(add_smulx_escapes(ti, tablelen, tableused)){
|
if(add_smulx_escapes(ti, tablelen, tableused)){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(add_u7_escape(ti, tablelen, tableused)){
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}else if(qterm == TERMINAL_ALACRITTY){
|
}else if(qterm == TERMINAL_ALACRITTY){
|
||||||
termname = "Alacritty";
|
termname = "Alacritty";
|
||||||
ti->caps.quadrants = true;
|
ti->caps.quadrants = true;
|
||||||
@ -286,41 +324,6 @@ apply_term_heuristics(tinfo* ti, const char* termname, int fd,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device Attributes; replies with (depending on decTerminalID resource):
|
|
||||||
// ⇒ CSI ? 1 ; 2 c ("VT100 with Advanced Video Option")
|
|
||||||
// ⇒ CSI ? 1 ; 0 c ("VT101 with No Options")
|
|
||||||
// ⇒ CSI ? 4 ; 6 c ("VT132 with Advanced Video and Graphics")
|
|
||||||
// ⇒ CSI ? 6 c ("VT102")
|
|
||||||
// ⇒ CSI ? 7 c ("VT131")
|
|
||||||
// ⇒ CSI ? 1 2 ; Ps c ("VT125")
|
|
||||||
// ⇒ CSI ? 6 2 ; Ps c ("VT220")
|
|
||||||
// ⇒ CSI ? 6 3 ; Ps c ("VT320")
|
|
||||||
// ⇒ CSI ? 6 4 ; Ps c ("VT420")
|
|
||||||
|
|
||||||
// query background, replies in X color https://www.x.org/releases/X11R7.7/doc/man/man7/X.7.xhtml#heading11
|
|
||||||
#define CSI_BGQ "\e]11;?\e\\"
|
|
||||||
|
|
||||||
// we send an XTSMGRAPHICS to set up 256 color registers (the most we can
|
|
||||||
// currently take advantage of; we need at least 64 to use sixel at all.
|
|
||||||
// maybe that works, maybe it doesn't. then query both color registers
|
|
||||||
// and geometry. send XTGETTCAP for terminal name.
|
|
||||||
static int
|
|
||||||
send_initial_queries(int fd){
|
|
||||||
const char queries[] = CSI_BGQ
|
|
||||||
"\x1b[?2026$p" // query for App-sync updates
|
|
||||||
"\x1b[=0c" // Tertiary Device Attributes
|
|
||||||
"\x1b[>0q" // XTVERSION
|
|
||||||
"\x1bP+q544e\x1b\\" // XTGETTCAP['TN']
|
|
||||||
"\x1b[?1;3;256S" // try to set 256 cregs
|
|
||||||
"\x1b[?2;1;0S" // XTSMGRAPHICS (cregs)
|
|
||||||
"\x1b[?1;1;0S" // XTSMGRAPHICS (geometry)
|
|
||||||
"\x1b[c"; // Device Attributes
|
|
||||||
if(blocking_write(fd, queries, strlen(queries))){
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// termname is just the TERM environment variable. some details are not
|
// termname is just the TERM environment variable. some details are not
|
||||||
// exposed via terminfo, and we must make heuristic decisions based on
|
// exposed via terminfo, and we must make heuristic decisions based on
|
||||||
// the detected terminal type, yuck :/.
|
// the detected terminal type, yuck :/.
|
||||||
@ -501,7 +504,9 @@ int interrogate_terminfo(tinfo* ti, int fd, const char* termname, unsigned utf8,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsigned appsync_advertised;
|
unsigned appsync_advertised;
|
||||||
if(ncinputlayer_init(ti, stdin, &qterm, &appsync_advertised)){
|
int cursor_x = -1;
|
||||||
|
int cursor_y = -1;
|
||||||
|
if(ncinputlayer_init(ti, stdin, &qterm, &appsync_advertised, &cursor_y, &cursor_x)){
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if(nocbreak){
|
if(nocbreak){
|
||||||
@ -512,6 +517,12 @@ int interrogate_terminfo(tinfo* ti, int fd, const char* termname, unsigned utf8,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(cursor_x >= 0 && cursor_y >= 0){
|
||||||
|
if(add_u7_escape(ti, &tablelen, &tableused)){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// FIXME set cursor up
|
||||||
|
}
|
||||||
if(appsync_advertised){
|
if(appsync_advertised){
|
||||||
if(add_appsync_escapes(ti, &tablelen, &tableused)){
|
if(add_appsync_escapes(ti, &tablelen, &tableused)){
|
||||||
goto err;
|
goto err;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user