mirror of
https://github.com/dankamongmen/notcurses.git
synced 2024-11-02 09:40:15 +00:00
notcurses_stop_minimal: use reliable I/O
fflush(), so far as i can tell, cannot be reliably used in glibc. after it fails once, subsequent calls return 0 and do not set errno -- only the persistent ferror() serves to indicate that flushing is not going on. instead, write into the render state's memstream, and then use reliable blocking_write() to dump it to stdout. closes #1872.
This commit is contained in:
parent
ed8c369d4e
commit
dc02a8f04b
@ -1250,12 +1250,7 @@ bool ncdirect_canutf8(const ncdirect* n){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ncdirect_flush(const ncdirect* nc){
|
int ncdirect_flush(const ncdirect* nc){
|
||||||
while(fflush(nc->ttyfp) == EOF){
|
return ncflush(nc->ttyfp);
|
||||||
if(errno != EAGAIN){
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ncdirect_check_pixel_support(const ncdirect* n){
|
int ncdirect_check_pixel_support(const ncdirect* n){
|
||||||
|
@ -1204,14 +1204,24 @@ tty_emit(const char* seq, int fd){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reliably flush a FILE*
|
int set_fd_nonblocking(int fd, unsigned state, unsigned* oldstate);
|
||||||
|
|
||||||
|
// reliably flush a FILE*...except you can't, so far as i can tell. at least
|
||||||
|
// on glibc, a single fflush() error latches the FILE* error, but ceases to
|
||||||
|
// perform any work (even following a clearerr()), despite returning 0 from
|
||||||
|
// that point on. thus, after a fflush() error, even on EAGAIN and friends,
|
||||||
|
// you can't use the stream any further. doesn't this make fflush() pretty
|
||||||
|
// much useless? it sure would seem to, which is why we use a memstream for
|
||||||
|
// all our important I/O, which we then blit with blocking_write(). if you
|
||||||
|
// care about your data, you'll do the same.
|
||||||
static inline int
|
static inline int
|
||||||
ncflush(FILE* out){
|
ncflush(FILE* out){
|
||||||
while(fflush(out) == EOF){
|
if(ferror(out)){
|
||||||
if(errno != EAGAIN && errno != EINTR && errno != EBUSY){
|
logerror("Not attempting a flush following error\n");
|
||||||
logerror("Unrecoverable error flushing io (%s)\n", strerror(errno));
|
}
|
||||||
return -1;
|
if(fflush(out) == EOF){
|
||||||
}
|
logerror("Unrecoverable error flushing io (%s)\n", strerror(errno));
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1304,6 +1314,24 @@ coerce_styles(FILE* out, const tinfo* ti, uint16_t* curstyle,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SET_BTN_EVENT_MOUSE "1002"
|
||||||
|
#define SET_FOCUS_EVENT_MOUSE "1004"
|
||||||
|
#define SET_SGR_MODE_MOUSE "1006"
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
mouse_enable(FILE* out){
|
||||||
|
return term_emit("\x1b[?" SET_BTN_EVENT_MOUSE ";"
|
||||||
|
/*SET_FOCUS_EVENT_MOUSE ";" */SET_SGR_MODE_MOUSE "h",
|
||||||
|
out, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
mouse_disable(FILE* out){
|
||||||
|
return term_emit("\x1b[?" SET_BTN_EVENT_MOUSE ";"
|
||||||
|
/*SET_FOCUS_EVENT_MOUSE ";" */SET_SGR_MODE_MOUSE "l",
|
||||||
|
out, false);
|
||||||
|
}
|
||||||
|
|
||||||
// how many edges need touch a corner for it to be printed?
|
// how many edges need touch a corner for it to be printed?
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
box_corner_needs(unsigned ctlword){
|
box_corner_needs(unsigned ctlword){
|
||||||
@ -1591,8 +1619,6 @@ cellcmp_and_dupfar(egcpool* dampool, nccell* damcell,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_fd_nonblocking(int fd, unsigned state, unsigned* oldstate);
|
|
||||||
|
|
||||||
int get_tty_fd(FILE* ttyfp);
|
int get_tty_fd(FILE* ttyfp);
|
||||||
|
|
||||||
// Given the four channels arguments, verify that:
|
// Given the four channels arguments, verify that:
|
||||||
|
@ -53,7 +53,12 @@ int reset_term_attributes(const tinfo* ti, FILE* fp){
|
|||||||
static int
|
static int
|
||||||
notcurses_stop_minimal(void* vnc){
|
notcurses_stop_minimal(void* vnc){
|
||||||
notcurses* nc = vnc;
|
notcurses* nc = vnc;
|
||||||
|
// collect output into the memstream buffer, and then dump it directly using
|
||||||
|
// blocking_write(), to avoid problems with unreliable fflush().
|
||||||
|
FILE* out = nc->rstate.mstreamfp;
|
||||||
|
fseeko(out, 0, SEEK_SET);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
ret |= drop_signals(nc);
|
||||||
// be sure to write the restoration sequences *prior* to running rmcup, as
|
// be sure to write the restoration sequences *prior* to running rmcup, as
|
||||||
// they apply to the screen (alternate or otherwise) we're actually using.
|
// they apply to the screen (alternate or otherwise) we're actually using.
|
||||||
const char* esc;
|
const char* esc;
|
||||||
@ -61,35 +66,32 @@ notcurses_stop_minimal(void* vnc){
|
|||||||
// byte. if we leave an active escape open, it can lock up the terminal.
|
// byte. if we leave an active escape open, it can lock up the terminal.
|
||||||
// we only want to do it when in the middle of a rasterization, though. FIXME
|
// we only want to do it when in the middle of a rasterization, though. FIXME
|
||||||
if(nc->tcache.pixel_shutdown){
|
if(nc->tcache.pixel_shutdown){
|
||||||
ret |= nc->tcache.pixel_shutdown(nc->ttyfp);
|
ret |= nc->tcache.pixel_shutdown(out);
|
||||||
}
|
}
|
||||||
ret |= notcurses_mouse_disable(nc);
|
ret |= mouse_disable(out);
|
||||||
ret |= reset_term_attributes(&nc->tcache, nc->ttyfp);
|
ret |= reset_term_attributes(&nc->tcache, out);
|
||||||
if(nc->ttyfd >= 0){
|
if(nc->ttyfd >= 0){
|
||||||
if((esc = get_escape(&nc->tcache, ESCAPE_RMCUP))){
|
if((esc = get_escape(&nc->tcache, ESCAPE_RMCUP))){
|
||||||
if(sprite_clear_all(&nc->tcache, nc->ttyfp)){
|
if(sprite_clear_all(&nc->tcache, out)){
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
if(term_emit(esc, nc->ttyfp, false)){
|
if(term_emit(esc, out, false)){
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret |= tcsetattr(nc->ttyfd, TCSANOW, &nc->tcache.tpreserved);
|
ret |= tcsetattr(nc->ttyfd, TCSANOW, &nc->tcache.tpreserved);
|
||||||
}
|
}
|
||||||
if((esc = get_escape(&nc->tcache, ESCAPE_RMKX)) && term_emit(esc, nc->ttyfp, false)){
|
if((esc = get_escape(&nc->tcache, ESCAPE_RMKX)) && term_emit(esc, out, false)){
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
const char* cnorm = get_escape(&nc->tcache, ESCAPE_CNORM);
|
const char* cnorm = get_escape(&nc->tcache, ESCAPE_CNORM);
|
||||||
if(cnorm && term_emit(cnorm, nc->ttyfp, false)){
|
if(cnorm && term_emit(cnorm, out, false)){
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
if(ncflush(nc->ttyfp)){
|
if(fflush(out)){
|
||||||
ret = -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// see #1872; without keeping this at the end, we run into mysterious,
|
return blocking_write(fileno(nc->ttyfp), nc->rstate.mstream, nc->rstate.mstrsize);
|
||||||
// poorly-understood issues during shutdown =[. cowardly. FIXME
|
|
||||||
ret |= drop_signals(nc);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a heap-allocated wchar_t expansion of the multibyte string at s
|
// make a heap-allocated wchar_t expansion of the multibyte string at s
|
||||||
@ -2159,14 +2161,8 @@ ncplane* ncplane_above(ncplane* n){
|
|||||||
return n->above;
|
return n->above;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SET_BTN_EVENT_MOUSE "1002"
|
|
||||||
#define SET_FOCUS_EVENT_MOUSE "1004"
|
|
||||||
#define SET_SGR_MODE_MOUSE "1006"
|
|
||||||
int notcurses_mouse_enable(notcurses* n){
|
int notcurses_mouse_enable(notcurses* n){
|
||||||
if(n->ttyfd >= 0){
|
if(n->ttyfd >= 0){
|
||||||
return term_emit(ESC "[?" SET_BTN_EVENT_MOUSE ";"
|
|
||||||
/*SET_FOCUS_EVENT_MOUSE ";" */SET_SGR_MODE_MOUSE "h",
|
|
||||||
n->ttyfp, false);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2175,9 +2171,6 @@ int notcurses_mouse_enable(notcurses* n){
|
|||||||
// the sequences 1000 etc?
|
// the sequences 1000 etc?
|
||||||
int notcurses_mouse_disable(notcurses* n){
|
int notcurses_mouse_disable(notcurses* n){
|
||||||
if(n->ttyfd >= 0){
|
if(n->ttyfd >= 0){
|
||||||
return term_emit(ESC "[?" SET_BTN_EVENT_MOUSE ";"
|
|
||||||
/*SET_FOCUS_EVENT_MOUSE ";" */SET_SGR_MODE_MOUSE "l",
|
|
||||||
n->ttyfp, false);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user