get look_for_clrs() down on paper #1692

pull/1923/head
nick black 3 years ago committed by nick black
parent d6ef7ccacd
commit fb8b453d61

@ -470,7 +470,7 @@ handle_queued_input(ncinputlayer* nc, ncinput* ni,
// is attempt to fill up the input ringbuffer, exiting either when that
// condition is met, or when we get an EAGAIN. it does no processing.
static int
fill_buffer(ncinputlayer* nc, const sigset_t* sigmask){
fill_buffer(ncinputlayer* nc){
ssize_t r = 0;
size_t rlen;
//fprintf(stderr, "OCCUPY: %u@%u read: %d %zd\n", nc->inputbuf_occupied, nc->inputbuf_write_at, nc->inputbuf[nc->inputbuf_write_at], r);
@ -480,23 +480,13 @@ fill_buffer(ncinputlayer* nc, const sigset_t* sigmask){
if(rlen >= sizeof(nc->inputbuf) / sizeof(*nc->inputbuf) - nc->inputbuf_write_at){
rlen = sizeof(nc->inputbuf) / sizeof(*nc->inputbuf) - nc->inputbuf_write_at;
}
while((r = read(nc->infd, nc->inputbuf + nc->inputbuf_write_at, rlen)) > 0){
if((r = read(nc->infd, nc->inputbuf + nc->inputbuf_write_at, rlen)) > 0){
nc->inputbuf_write_at += r;
if(nc->inputbuf_write_at == sizeof(nc->inputbuf) / sizeof(*nc->inputbuf)){
nc->inputbuf_write_at = 0;
}
nc->inputbuf_occupied += r;
// specify a 0 timeout, meaning we only check to see if there's more
// input available immediately. basically, if we only read through the
// end of the ringbuffer, this gets us the first part filled as well.
// this is less about performance, and more about avoiding partial
// reads of multibyte characters and control sequences.
const struct timespec ts = {};
if(block_on_input(nc->infd, &ts, sigmask) < 1){
break;
}
}
if(r < 0){
}else if(r < 0){
if(errno != EAGAIN && errno != EBUSY && errno != EWOULDBLOCK){
return -1;
}
@ -508,9 +498,8 @@ fill_buffer(ncinputlayer* nc, const sigset_t* sigmask){
// user-mode call to actual input i/o, which will get the next character from
// the input buffer.
static char32_t
handle_input(ncinputlayer* nc, ncinput* ni, int leftmargin, int topmargin,
const sigset_t* sigmask){
fill_buffer(nc, sigmask);
handle_input(ncinputlayer* nc, ncinput* ni, int leftmargin, int topmargin){
fill_buffer(nc);
// highest priority is resize notifications, since they don't queue
if(resize_seen){
resize_seen = 0;
@ -520,12 +509,11 @@ handle_input(ncinputlayer* nc, ncinput* ni, int leftmargin, int topmargin,
}
static char32_t
handle_ncinput(ncinputlayer* nc, ncinput* ni, int leftmargin, int topmargin,
const sigset_t* sigmask){
handle_ncinput(ncinputlayer* nc, ncinput* ni, int leftmargin, int topmargin){
if(ni){
memset(ni, 0, sizeof(*ni));
}
char32_t r = handle_input(nc, ni, leftmargin, topmargin, sigmask);
char32_t r = handle_input(nc, ni, leftmargin, topmargin);
// ctrl (*without* alt) + letter maps to [1..26], and is independent of shift
// FIXME need to distinguish between:
// - Enter and ^J
@ -563,7 +551,7 @@ ncinputlayer_prestamp(ncinputlayer* nc, const struct timespec *ts,
errno = 0;
if(block_on_input(nc->infd, ts, sigmask) > 0){
//fprintf(stderr, "%d events from input!\n", events);
return handle_ncinput(nc, ni, leftmargin, topmargin, sigmask);
return handle_ncinput(nc, ni, leftmargin, topmargin);
}
//fprintf(stderr, "ERROR: %d events from input!\n", events);
return -1;
@ -1414,6 +1402,8 @@ int ncinputlayer_init(tinfo* tcache, FILE* infp, queried_terminals_e* detected,
nilayer->inputbuf_write_at = 0;
nilayer->input_events = 0;
nilayer->creport_queue = NULL;
nilayer->user_wants_data = false;
nilayer->inner_wants_data = false;
pthread_cond_init(&nilayer->creport_cond, NULL);
int csifd = nilayer->ttyfd >= 0 ? nilayer->ttyfd : nilayer->infd;
if(isatty(csifd)){
@ -1444,3 +1434,49 @@ int ncinputlayer_init(tinfo* tcache, FILE* infp, queried_terminals_e* detected,
}
return 0;
}
// assuming the user context is not active, go through current data looking
// for a cursor location report. if we find none, block on input, and read if
// appropriate. we can be interrupted by a new user context. we enter holding
// the input lock, and leave holding the input lock, giving it up only while
// blocking for readable action.
void ncinput_extract_clrs(ncinputlayer* ni){
do{
// FIXME optimize this via remembered offset + invalidation
if(ni->inputbuf_occupied){
// FIXME look through outstanding data
if(ni->creport_queue){
return;
}
}
size_t rlen = input_queue_space(ni);
if(rlen){
if(rlen >= sizeof(ni->inputbuf) / sizeof(*ni->inputbuf) - ni->inputbuf_write_at){
rlen = sizeof(ni->inputbuf) / sizeof(*ni->inputbuf) - ni->inputbuf_write_at;
}
logdebug("Reading %zu from %d\n", rlen, ni->infd);
ssize_t r;
if((r = read(ni->infd, ni->inputbuf + ni->inputbuf_write_at, rlen)) > 0){
logdebug("Read %zu from %d\n", r, ni->infd);
ni->inputbuf_write_at += r;
if(ni->inputbuf_write_at == sizeof(ni->inputbuf) / sizeof(*ni->inputbuf)){
ni->inputbuf_write_at = 0;
}
ni->inputbuf_occupied += r;
continue;
}
ni->inner_wants_data = true;
pthread_mutex_unlock(&ni->lock);
// specify a NULL timeout, meaning we block as long as we need, until
// there's input available, or we are interrupted by a signal.
logdebug("Blocking on input");
if(block_on_input(ni->infd, NULL, NULL) < 1){
pthread_mutex_lock(&ni->lock); // interrupted?
break;
}
ni->inner_wants_data = false;
logdebug("Reacquiring input lock");
pthread_mutex_lock(&ni->lock);
}
}while(!ni->user_wants_data);
}

@ -44,6 +44,11 @@ void ncinputlayer_stop(struct ncinputlayer* nilayer);
// FIXME absorb into ncinputlayer_init()
int cbreak_mode(int ttyfd, const struct termios* tpreserved);
// assuming the user context is not active, go through current data looking
// for a cursor location report. if we find none, block on input, and read if
// appropriate. we can be interrupted by a new user context.
void ncinput_extract_clrs(struct ncinputlayer* nilayer);
#ifdef __cplusplus
}
#endif

@ -784,9 +784,12 @@ int locate_cursor(tinfo* ti, int fd, int* cursor_y, int* cursor_x){
}
bool emitted_u7 = false; // only want to send one max
cursorreport* clr;
loginfo("Acquiring input lock\n");
pthread_mutex_lock(&ti->input.lock);
while((clr = ti->input.creport_queue) == NULL){
logdebug("No report yet\n");
if(!emitted_u7){
logdebug("Emitting u7\n");
// FIXME i'd rather not do this while holding the lock =[
if(tty_emit(u7, fd)){
pthread_mutex_unlock(&ti->input.lock);
@ -794,9 +797,18 @@ int locate_cursor(tinfo* ti, int fd, int* cursor_y, int* cursor_x){
}
emitted_u7 = true;
}
// this can block. we must enter holding the input lock, and it will
// return to us holding the input lock.
ncinput_extract_clrs(&ti->input);
if((clr = ti->input.creport_queue) == NULL){
logdebug("Hustled up a CL report\n");
break;
}
pthread_cond_wait(&ti->input.creport_cond, &ti->input.lock);
}
ti->input.creport_queue = clr->next;
pthread_mutex_unlock(&ti->input.lock);
loginfo("Got a report %d/%d\n", clr->y, clr->x);
*cursor_y = clr->y;
*cursor_x = clr->x;
if(ti->inverted_cursor){
@ -804,5 +816,6 @@ int locate_cursor(tinfo* ti, int fd, int* cursor_y, int* cursor_x){
*cursor_y = *cursor_x;
*cursor_x = tmp;
}
free(clr);
return 0;
}

@ -107,6 +107,8 @@ typedef struct ncinputlayer {
struct esctrie* inputescapes; // trie of input escapes -> ncspecial_keys
cursorreport* creport_queue; // queue of cursor reports
pthread_cond_t creport_cond;
bool user_wants_data; // a user context is active
bool inner_wants_data; // if we're blocking on input
} ncinputlayer;
// terminal interface description. most of these are acquired from terminfo(5)

Loading…
Cancel
Save