notcurses_getc -> notcurses_get, absolute deadlines

This commit is contained in:
nick black 2021-11-09 00:54:29 -05:00
parent fe924be5ef
commit b42587a1b9
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
19 changed files with 50 additions and 68 deletions

View File

@ -10,6 +10,8 @@ rearrangements of Notcurses.
without an obvious replacement is the `renderfp` field of without an obvious replacement is the `renderfp` field of
`notcurses_options`, for which I make no apology. If you've been avoiding `notcurses_options`, for which I make no apology. If you've been avoiding
deprecated functionality, ABI3 ought require small changes, if any. deprecated functionality, ABI3 ought require small changes, if any.
* `notcurses_get()` and `ncdirect_get()` now require an absolute deadline
rather than a delay bound; it ought be calculated using `CLOCK_MONOTONIC`.
* The handling of geometry and distance has been normalized across all * The handling of geometry and distance has been normalized across all
functions. Lengths are now `unsigned` as opposed to `int`. Where -1 was functions. Lengths are now `unsigned` as opposed to `int`. Where -1 was
being used to indicate "everything", 0 is now required. This affects being used to indicate "everything", 0 is now required. This affects

View File

@ -652,7 +652,7 @@ must be readable without delay for it to be interpreted as such.
// resize events, etc.). These are mapped into Unicode's Supplementary // resize events, etc.). These are mapped into Unicode's Supplementary
// Private Use Area-B, starting at U+100000. See <notcurses/nckeys.h>. // Private Use Area-B, starting at U+100000. See <notcurses/nckeys.h>.
// //
// notcurses_getc_nblock() is nonblocking. notcurses_getc_blocking() blocks // notcurses_get_nblock() is nonblocking. notcurses_get_blocking() blocks
// until a codepoint or special key is read, or until interrupted by a signal. // until a codepoint or special key is read, or until interrupted by a signal.
// notcurses_get() allows an optional timeout to be controlled. // notcurses_get() allows an optional timeout to be controlled.
// //
@ -730,10 +730,10 @@ typedef struct ncinput {
// Read a UTF-32-encoded Unicode codepoint from input. This might only be part // Read a UTF-32-encoded Unicode codepoint from input. This might only be part
// of a larger EGC. Provide a NULL 'ts' to block at length, and otherwise a // of a larger EGC. Provide a NULL 'ts' to block at length, and otherwise a
// timespec to bound blocking. Returns a single Unicode code point, or // timespec specifying an absolute deadline calculated using CLOCK_MONOTONIC.
// (uint32_t)-1 on error. Returns 0 on a timeout. If an event is processed, the // Returns a single Unicode code point, or a synthesized special key constant,
// return value is the 'id' field from that event. 'ni' may be NULL. 'ts' is an // or (uint32_t)-1 on error. Returns 0 on a timeout. If an event is processed,
// a delay bound against CLOCK_MONOTONIC (see clock_gettime(2)). // the return value is the 'id' field from that event. 'ni' may be NULL.
uint32_t notcurses_get(struct notcurses* n, const struct timespec* ts, uint32_t notcurses_get(struct notcurses* n, const struct timespec* ts,
ncinput* ni); ncinput* ni);
@ -742,10 +742,10 @@ uint32_t notcurses_get(struct notcurses* n, const struct timespec* ts,
int notcurses_getvec(struct notcurses* n, const struct timespec* ts, int notcurses_getvec(struct notcurses* n, const struct timespec* ts,
ncinput* ni, int vcount); ncinput* ni, int vcount);
// 'ni' may be NULL if the caller is uninterested in event details. If no event // 'ni' may be NULL if the caller is uninterested in event details. If no
// is ready, returns 0. // event is ready, returns 0.
static inline uint32_t static inline uint32_t
notcurses_getc_nblock(struct notcurses* n, ncinput* ni){ notcurses_get_nblock(struct notcurses* n, ncinput* ni){
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
return notcurses_get(n, &ts, ni); return notcurses_get(n, &ts, ni);
} }
@ -753,7 +753,7 @@ notcurses_getc_nblock(struct notcurses* n, ncinput* ni){
// 'ni' may be NULL if the caller is uninterested in event details. Blocks // 'ni' may be NULL if the caller is uninterested in event details. Blocks
// until an event is processed or a signal is received. // until an event is processed or a signal is received.
static inline uint32_t static inline uint32_t
notcurses_getc_blocking(struct notcurses* n, ncinput* ni){ notcurses_get_blocking(struct notcurses* n, ncinput* ni){
return notcurses_get(n, NULL, ni); return notcurses_get(n, NULL, ni);
} }

View File

@ -118,6 +118,8 @@ notcurses_direct - minimal notcurses instances for styling text
**bool ncdirect_canget_cursor(const struct ncdirect* ***nc***);** **bool ncdirect_canget_cursor(const struct ncdirect* ***nc***);**
**uint32_t ncdirect_get(struct ncdirect* ***n***, const struct timespec* ***absdl***, ncinput* ***ni***);**
```c ```c
typedef struct ncvgeom { typedef struct ncvgeom {
int pixy, pixx; // true pixel geometry of ncvisual data int pixy, pixx; // true pixel geometry of ncvisual data

View File

@ -210,8 +210,8 @@ namespace ncpp
char32_t get (ncinput *ni, bool blocking) const noexcept char32_t get (ncinput *ni, bool blocking) const noexcept
{ {
if (blocking) if (blocking)
return ncdirect_getc_blocking (direct, ni); return ncdirect_get_blocking (direct, ni);
return ncdirect_getc_nblock (direct, ni); return ncdirect_get_nblock (direct, ni);
} }
char32_t get (const struct timespec *ts, ncinput *ni) const noexcept char32_t get (const struct timespec *ts, ncinput *ni) const noexcept

View File

@ -248,9 +248,9 @@ namespace ncpp
uint32_t get (bool blocking = false, ncinput *ni = nullptr) const noexcept uint32_t get (bool blocking = false, ncinput *ni = nullptr) const noexcept
{ {
if (blocking) if (blocking)
return notcurses_getc_blocking (nc, ni); return notcurses_get_blocking (nc, ni);
return notcurses_getc_nblock (nc, ni); return notcurses_get_nblock (nc, ni);
} }
char* get_at (int yoff, int xoff, uint16_t* attr, uint64_t* channels) const noexcept char* get_at (int yoff, int xoff, uint16_t* attr, uint64_t* channels) const noexcept

View File

@ -241,16 +241,16 @@ API int ncdirect_double_box(struct ncdirect* n, uint64_t ul, uint64_t ur,
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1)));
// Provide a NULL 'ts' to block at length, a 'ts' of 0 for non-blocking // Provide a NULL 'ts' to block at length, a 'ts' of 0 for non-blocking
// operation, and otherwise a timespec to bound blocking. Returns a single // operation, and otherwise an absolute deadline in terms of CLOCK_MONOTONIC.
// Unicode code point, or (uint32_t)-1 on error. Returns 0 on a timeout. If // Returns a single Unicode code point, a synthesized special key constant,
// an event is processed, the return value is the 'id' field from that // or (uint32_t)-1 on error. Returns 0 on a timeout. If an event is processed,
// event. 'ni' may be NULL. // the return value is the 'id' field from that event. 'ni' may be NULL.
API uint32_t ncdirect_get(struct ncdirect* n, const struct timespec* ts, API uint32_t ncdirect_get(struct ncdirect* n, const struct timespec* absdl,
ncinput* ni) ncinput* ni)
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1)));
// Get a file descriptor suitable for input event poll()ing. When this // Get a file descriptor suitable for input event poll()ing. When this
// descriptor becomes available, you can call ncdirect_getc_nblock(), // descriptor becomes available, you can call ncdirect_get_nblock(),
// and input ought be ready. This file descriptor is *not* necessarily // and input ought be ready. This file descriptor is *not* necessarily
// the file descriptor associated with stdin (but it might be!). // the file descriptor associated with stdin (but it might be!).
API int ncdirect_inputready_fd(struct ncdirect* n) API int ncdirect_inputready_fd(struct ncdirect* n)
@ -259,7 +259,7 @@ API int ncdirect_inputready_fd(struct ncdirect* n)
// 'ni' may be NULL if the caller is uninterested in event details. If no event // 'ni' may be NULL if the caller is uninterested in event details. If no event
// is ready, returns 0. // is ready, returns 0.
static inline uint32_t static inline uint32_t
ncdirect_getc_nblock(struct ncdirect* n, ncinput* ni){ ncdirect_get_nblock(struct ncdirect* n, ncinput* ni){
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
return ncdirect_get(n, &ts, ni); return ncdirect_get(n, &ts, ni);
} }
@ -267,7 +267,7 @@ ncdirect_getc_nblock(struct ncdirect* n, ncinput* ni){
// 'ni' may be NULL if the caller is uninterested in event details. Blocks // 'ni' may be NULL if the caller is uninterested in event details. Blocks
// until an event is processed or a signal is received. // until an event is processed or a signal is received.
static inline uint32_t static inline uint32_t
ncdirect_getc_blocking(struct ncdirect* n, ncinput* ni){ ncdirect_get_blocking(struct ncdirect* n, ncinput* ni){
return ncdirect_get(n, NULL, ni); return ncdirect_get(n, NULL, ni);
} }

View File

@ -1048,7 +1048,7 @@ API void notcurses_drop_planes(struct notcurses* nc)
// resize events, etc.). These are mapped into Unicode's Supplementary // resize events, etc.). These are mapped into Unicode's Supplementary
// Private Use Area-B, starting at U+100000. See <notcurses/nckeys.h>. // Private Use Area-B, starting at U+100000. See <notcurses/nckeys.h>.
// //
// notcurses_getc_nblock() is nonblocking. notcurses_getc_blocking() blocks // notcurses_get_nblock() is nonblocking. notcurses_get_blocking() blocks
// until a codepoint or special key is read, or until interrupted by a signal. // until a codepoint or special key is read, or until interrupted by a signal.
// notcurses_get() allows an optional timeout to be controlled. // notcurses_get() allows an optional timeout to be controlled.
// //
@ -1107,10 +1107,10 @@ ncinput_equal_p(const ncinput* n1, const ncinput* n2){
// Read a UTF-32-encoded Unicode codepoint from input. This might only be part // Read a UTF-32-encoded Unicode codepoint from input. This might only be part
// of a larger EGC. Provide a NULL 'ts' to block at length, and otherwise a // of a larger EGC. Provide a NULL 'ts' to block at length, and otherwise a
// timespec to bound blocking. Returns a single Unicode code point, or // timespec specifying an absolute deadline calculated using CLOCK_MONOTONIC.
// (uint32_t)-1 on error. Returns 0 on a timeout. If an event is processed, the // Returns a single Unicode code point, or a synthesized special key constant,
// return value is the 'id' field from that event. 'ni' may be NULL. 'ts' is an // or (uint32_t)-1 on error. Returns 0 on a timeout. If an event is processed,
// a delay bound against CLOCK_MONOTONIC (see clock_gettime(2)). // the return value is the 'id' field from that event. 'ni' may be NULL.
API uint32_t notcurses_get(struct notcurses* n, const struct timespec* ts, API uint32_t notcurses_get(struct notcurses* n, const struct timespec* ts,
ncinput* ni) ncinput* ni)
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1)));
@ -1122,7 +1122,7 @@ API int notcurses_getvec(struct notcurses* n, const struct timespec* ts,
__attribute__ ((nonnull (1, 3))); __attribute__ ((nonnull (1, 3)));
// Get a file descriptor suitable for input event poll()ing. When this // Get a file descriptor suitable for input event poll()ing. When this
// descriptor becomes available, you can call notcurses_getc_nblock(), // descriptor becomes available, you can call notcurses_get_nblock(),
// and input ought be ready. This file descriptor is *not* necessarily // and input ought be ready. This file descriptor is *not* necessarily
// the file descriptor associated with stdin (but it might be!). // the file descriptor associated with stdin (but it might be!).
API int notcurses_inputready_fd(struct notcurses* n) API int notcurses_inputready_fd(struct notcurses* n)
@ -1131,7 +1131,7 @@ API int notcurses_inputready_fd(struct notcurses* n)
// 'ni' may be NULL if the caller is uninterested in event details. If no event // 'ni' may be NULL if the caller is uninterested in event details. If no event
// is immediately ready, returns 0. // is immediately ready, returns 0.
static inline uint32_t static inline uint32_t
notcurses_getc_nblock(struct notcurses* n, ncinput* ni){ notcurses_get_nblock(struct notcurses* n, ncinput* ni){
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
return notcurses_get(n, &ts, ni); return notcurses_get(n, &ts, ni);
} }
@ -1139,7 +1139,7 @@ notcurses_getc_nblock(struct notcurses* n, ncinput* ni){
// 'ni' may be NULL if the caller is uninterested in event details. Blocks // 'ni' may be NULL if the caller is uninterested in event details. Blocks
// until an event is processed or a signal is received (including resize events). // until an event is processed or a signal is received (including resize events).
static inline uint32_t static inline uint32_t
notcurses_getc_blocking(struct notcurses* n, ncinput* ni){ notcurses_get_blocking(struct notcurses* n, ncinput* ni){
return notcurses_get(n, NULL, ni); return notcurses_get(n, NULL, ni);
} }

View File

@ -129,7 +129,7 @@ ultramegaok_demo(void* vnc){
ncinput ni; ncinput ni;
struct notcurses* nc = vnc; struct notcurses* nc = vnc;
uint32_t id; uint32_t id;
while((id = notcurses_getc_blocking(nc, &ni)) != (uint32_t)-1){ while((id = notcurses_get_blocking(nc, &ni)) != (uint32_t)-1){
if(id == 0){ if(id == 0){
continue; continue;
} }

View File

@ -982,7 +982,7 @@ char* ncdirect_readline(ncdirect* n, const char* prompt){
ncinput ni; ncinput ni;
uint32_t id; uint32_t id;
unsigned oldx = xstart; unsigned oldx = xstart;
while((id = ncdirect_getc_blocking(n, &ni)) != (uint32_t)-1){ while((id = ncdirect_get_blocking(n, &ni)) != (uint32_t)-1){
if(ni.evtype == NCTYPE_RELEASE){ if(ni.evtype == NCTYPE_RELEASE){
continue; continue;
} }

View File

@ -2146,29 +2146,9 @@ internal_get(inputctx* ictx, const struct timespec* ts, ncinput* ni){
return id; return id;
} }
// FIXME kill off for API3, and expect an absolute deadline directly
static inline void
delaybound_to_deadline(const struct timespec* ts, struct timespec* absdl){
if(ts){
// incoming ts is a delay bound, but we want an absolute deadline for
// pthread_cond_timedwait(). convert it, using CLOCK_MONOTONIC (we
// initialized the condvar with pthread_condmonotonic_init()).
struct timespec tspec;
clock_gettime(CLOCK_MONOTONIC, &tspec);
absdl->tv_sec = ts->tv_sec + tspec.tv_sec;
absdl->tv_nsec = ts->tv_nsec + tspec.tv_nsec;
if(absdl->tv_nsec > 1000000000){
++absdl->tv_sec;
absdl->tv_nsec -= 1000000000;
}
}
}
// infp has already been set non-blocking // infp has already been set non-blocking
uint32_t notcurses_get(notcurses* nc, const struct timespec* ts, ncinput* ni){ uint32_t notcurses_get(notcurses* nc, const struct timespec* absdl, ncinput* ni){
struct timespec absdl; uint32_t id = internal_get(nc->tcache.ictx, absdl, ni);
delaybound_to_deadline(ts, &absdl);
uint32_t id = internal_get(nc->tcache.ictx, ts ? &absdl : NULL, ni);
if(ni){ if(ni){
if(id == (uint32_t)-1){ if(id == (uint32_t)-1){
ni->id = id; ni->id = id;
@ -2178,12 +2158,10 @@ uint32_t notcurses_get(notcurses* nc, const struct timespec* ts, ncinput* ni){
} }
// FIXME better performance if we move this within the locked area // FIXME better performance if we move this within the locked area
int notcurses_getvec(notcurses* n, const struct timespec* ts, int notcurses_getvec(notcurses* n, const struct timespec* absdl,
ncinput* ni, int vcount){ ncinput* ni, int vcount){
struct timespec absdl;
delaybound_to_deadline(ts, &absdl);
for(int v = 0 ; v < vcount ; ++v){ for(int v = 0 ; v < vcount ; ++v){
uint32_t u = notcurses_get(n, ts ? &absdl : NULL, &ni[v]); uint32_t u = notcurses_get(n, absdl, &ni[v]);
if(u == (uint32_t)-1){ if(u == (uint32_t)-1){
if(v == 0){ if(v == 0){
return -1; return -1;
@ -2196,8 +2174,8 @@ int notcurses_getvec(notcurses* n, const struct timespec* ts,
return vcount; return vcount;
} }
uint32_t ncdirect_get(ncdirect* n, const struct timespec* ts, ncinput* ni){ uint32_t ncdirect_get(ncdirect* n, const struct timespec* absdl, ncinput* ni){
return internal_get(n->tcache.ictx, ts, ni); return internal_get(n->tcache.ictx, absdl, ni);
} }
int get_cursor_location(inputctx* ictx, const char* u7, unsigned* y, unsigned* x){ int get_cursor_location(inputctx* ictx, const char* u7, unsigned* y, unsigned* x){

View File

@ -10,7 +10,7 @@ int main(void){
} }
ncinput ni; ncinput ni;
uint32_t i; uint32_t i;
while((i = ncdirect_getc_blocking(n, &ni)) != (uint32_t)-1){ while((i = ncdirect_get_blocking(n, &ni)) != (uint32_t)-1){
unsigned char utf8[5] = {}; unsigned char utf8[5] = {};
notcurses_ucs32_to_utf8(&i, 1, utf8, sizeof(utf8)); notcurses_ucs32_to_utf8(&i, 1, utf8, sizeof(utf8));
printf("Read input: [%c%c%c] %s\n", ni.ctrl ? 'C' : 'c', printf("Read input: [%c%c%c] %s\n", ni.ctrl ? 'C' : 'c',

View File

@ -111,7 +111,7 @@ int main(void){
} }
ncinput ni; ncinput ni;
do{ do{
notcurses_getc_blocking(nc, &ni); notcurses_get_blocking(nc, &ni);
}while(ni.id != (uint32_t)-1 && ni.evtype != NCTYPE_RELEASE); }while(ni.id != (uint32_t)-1 && ni.evtype != NCTYPE_RELEASE);
notcurses_stop(nc); notcurses_stop(nc);
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -28,7 +28,7 @@ run_menu(struct notcurses* nc, struct ncmenu* ncm){
uint32_t keypress; uint32_t keypress;
ncinput ni; ncinput ni;
notcurses_render(nc); notcurses_render(nc);
while((keypress = notcurses_getc_blocking(nc, &ni)) != (uint32_t)-1){ while((keypress = notcurses_get_blocking(nc, &ni)) != (uint32_t)-1){
if(!ncmenu_offer_input(ncm, &ni)){ if(!ncmenu_offer_input(ncm, &ni)){
if(ni.evtype == NCTYPE_RELEASE){ if(ni.evtype == NCTYPE_RELEASE){
continue; continue;

View File

@ -43,7 +43,7 @@ run_mselect(struct notcurses* nc, struct ncmultiselector* ns){
notcurses_render(nc); notcurses_render(nc);
uint32_t keypress; uint32_t keypress;
ncinput ni; ncinput ni;
while((keypress = notcurses_getc_blocking(nc, &ni)) != (uint32_t)-1){ while((keypress = notcurses_get_blocking(nc, &ni)) != (uint32_t)-1){
if(ni.evtype == NCTYPE_RELEASE){ if(ni.evtype == NCTYPE_RELEASE){
continue; continue;
} }

View File

@ -75,7 +75,7 @@ int main(int argc, char** argv){
notcurses_render(nc); notcurses_render(nc);
ncinput ni; ncinput ni;
do{ do{
notcurses_getc_blocking(nc, &ni); notcurses_get_blocking(nc, &ni);
}while(ni.evtype == NCTYPE_RELEASE); }while(ni.evtype == NCTYPE_RELEASE);
if(notcurses_stop(nc)){ if(notcurses_stop(nc)){
return EXIT_FAILURE; return EXIT_FAILURE;

View File

@ -33,7 +33,7 @@ run_selector(struct notcurses* nc, struct ncselector* ns){
notcurses_render(nc); notcurses_render(nc);
uint32_t keypress; uint32_t keypress;
ncinput ni; ncinput ni;
while((keypress = notcurses_getc_blocking(nc, &ni)) != (uint32_t)-1){ while((keypress = notcurses_get_blocking(nc, &ni)) != (uint32_t)-1){
if(!ncselector_offer_input(ns, &ni)){ if(!ncselector_offer_input(ns, &ni)){
if(ni.evtype == NCTYPE_RELEASE){ if(ni.evtype == NCTYPE_RELEASE){
continue; continue;

View File

@ -105,7 +105,7 @@ int main(int argc, char** argv){
int tabnameind = 0; int tabnameind = 0;
uint32_t c; uint32_t c;
ncinput ni; ncinput ni;
while((c = notcurses_getc_blocking(nc, &ni)) != 'q'){ while((c = notcurses_get_blocking(nc, &ni)) != 'q'){
if(ni.evtype == NCTYPE_RELEASE){ if(ni.evtype == NCTYPE_RELEASE){
continue; continue;
} }

View File

@ -391,7 +391,7 @@ callback(struct ncplane* ncp, void* curry, int dizzy){
static int static int
tree_ui(struct notcurses* nc, struct nctree* tree){ tree_ui(struct notcurses* nc, struct nctree* tree){
ncinput ni; ncinput ni;
while(notcurses_getc_blocking(nc, &ni) != (uint32_t)-1){ while(notcurses_get_blocking(nc, &ni) != (uint32_t)-1){
if(nctree_offer_input(tree, &ni)){ if(nctree_offer_input(tree, &ni)){
if(nctree_redraw(tree)){ if(nctree_redraw(tree)){
return -1; return -1;

View File

@ -120,7 +120,7 @@ int runreels(struct notcurses* nc, struct ncreel* nr){
int y, x; int y, x;
char32_t key; char32_t key;
ncinput ni; ncinput ni;
while((key = notcurses_getc_blocking(nc, &ni)) != (char32_t)-1){ while((key = notcurses_get_blocking(nc, &ni)) != (char32_t)-1){
if(ni.evtype == EvType::Release){ if(ni.evtype == EvType::Release){
continue; continue;
} }