death to sigset_t #1967

This commit is contained in:
nick black 2021-07-25 00:38:33 -04:00
parent 14ca7b6bf5
commit 0d289958f9
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
14 changed files with 148 additions and 143 deletions

11
NEWS.md
View File

@ -2,6 +2,17 @@ This document attempts to list user-visible changes and any major internal
rearrangements of Notcurses. rearrangements of Notcurses.
* 2.3.12 (not yet released) * 2.3.12 (not yet released)
* `notcurses_getc()` and `ncdirect_getc()` no longer accept a `sigset_t*`
as their third argument. Instead, they accept a `void*`, with which
they will do nothing. This is due to POSIX signals being unportable in
addition to terrible, and this one wart complicating wrappers a great
deal. If you were using this functionality, you were probably using it
incorrectly, no offense. If you're certain you were doing it right,
roll your own with `pthread_sigmask()`, and accept the race condition.
For ABI3, these functions will be dropped entirely; for now they have
only been marked deprecated. New functions `ncdirect_get()` and
`notcurses_get()` elide this parameter entirely, and ought be used in
new code. All callers have been updated.
* 2.3.11 (2021-07-20) * 2.3.11 (2021-07-20)
* Notcurses now requires libz to build. In exchange, it can now generate * Notcurses now requires libz to build. In exchange, it can now generate

View File

@ -98,7 +98,7 @@ typedef enum {
#define NCOPTION_NO_CLEAR_BITMAPS 0x0002ull #define NCOPTION_NO_CLEAR_BITMAPS 0x0002ull
// We typically install a signal handler for SIGWINCH that generates a resize // We typically install a signal handler for SIGWINCH that generates a resize
// event in the notcurses_getc() queue. Set to inhibit this handler. // event in the notcurses_get() queue. Set to inhibit this handler.
#define NCOPTION_NO_WINCH_SIGHANDLER 0x0004 #define NCOPTION_NO_WINCH_SIGHANDLER 0x0004
// We typically install a signal handler for SIG{INT, SEGV, ABRT, QUIT} that // We typically install a signal handler for SIG{INT, SEGV, ABRT, QUIT} that
@ -575,20 +575,20 @@ control timing. Notcurses brooks no delay; all characters of an escape sequence
must be readable without delay for it to be interpreted as such. must be readable without delay for it to be interpreted as such.
```c ```c
// All input is currently taken from stdin, though this will likely change. We // All input is taken from stdin. We attempt to read a single UTF8-encoded
// attempt to read a single UTF8-encoded Unicode codepoint, *not* an entire // Unicode codepoint, *not* an entire Extended Grapheme Cluster. It is also
// Extended Grapheme Cluster. It is also possible that we will read a special // possible that we will read a special keypress, i.e. anything that doesn't
// keypress, i.e. anything that doesn't correspond to a Unicode codepoint (e.g. // correspond to a Unicode codepoint (e.g. arrow keys, function keys, screen
// arrow keys, function keys, screen resize events, etc.). These are mapped // resize events, etc.). These are mapped into Unicode's Supplementary
// into Unicode's Supplementary Private Use Area-B, starting at U+100000. // Private Use Area-B, starting at U+100000. See <notcurses/nckeys.h>.
// //
// notcurses_getc() and notcurses_getc_nblock() are both nonblocking. // notcurses_getc_nblock() is nonblocking. notcurses_getc_blocking() blocks
// notcurses_getc_blocking() blocks until a codepoint or special key is read, // until a codepoint or special key is read, or until interrupted by a signal.
// or until interrupted by a signal. // notcurses_get() allows an optional timeout to be controlled.
// //
// In the case of a valid read, a 32-bit Unicode codepoint is returned. 0 is // In the case of a valid read, a 32-bit Unicode codepoint is returned. 0 is
// returned to indicate that no input was available, but only by // returned to indicate that no input was available. Otherwise (including on
// notcurses_getc(). Otherwise (including on EOF) (char32_t)-1 is returned. // EOF) (uint32_t)-1 is returned.
#define suppuabize(w) ((w) + 0x100000) #define suppuabize(w) ((w) + 0x100000)
@ -627,7 +627,7 @@ must be readable without delay for it to be interpreted as such.
#define NCKEY_EXIT suppuabize(133) #define NCKEY_EXIT suppuabize(133)
#define NCKEY_PRINT suppuabize(134) #define NCKEY_PRINT suppuabize(134)
#define NCKEY_REFRESH suppuabize(135) #define NCKEY_REFRESH suppuabize(135)
// Mouse events. We try to encode some details into the char32_t (i.e. which // Mouse events. We try to encode some details into the uint32_t (i.e. which
// button was pressed), but some is embedded in the ncinput event. The release // button was pressed), but some is embedded in the ncinput event. The release
// event is generic across buttons; callers must maintain state, if they care. // event is generic across buttons; callers must maintain state, if they care.
#define NCKEY_BUTTON1 suppuabize(201) #define NCKEY_BUTTON1 suppuabize(201)
@ -636,15 +636,15 @@ must be readable without delay for it to be interpreted as such.
// ... up to 11 mouse buttons // ... up to 11 mouse buttons
#define NCKEY_RELEASE suppuabize(212) #define NCKEY_RELEASE suppuabize(212)
// Is this char32_t a Supplementary Private Use Area-B codepoint? // Is this uint32_t a Supplementary Private Use Area-B codepoint?
static inline bool static inline bool
nckey_supppuab_p(char32_t w){ nckey_supppuab_p(uint32_t w){
return w >= 0x100000 && w <= 0x10fffd; return w >= 0x100000 && w <= 0x10fffd;
} }
// An input event. Cell coordinates are currently defined only for mouse events. // An input event. Cell coordinates are currently defined only for mouse events.
typedef struct ncinput { typedef struct ncinput {
char32_t id; // identifier. Unicode codepoint or synthesized NCKEY event uint32_t id; // identifier. Unicode codepoint or synthesized NCKEY event
int y; // y cell coordinate of event, -1 for undefined int y; // y cell coordinate of event, -1 for undefined
int x; // x cell coordinate of event, -1 for undefined int x; // x cell coordinate of event, -1 for undefined
bool alt; // was alt held? bool alt; // was alt held?
@ -653,33 +653,28 @@ typedef struct ncinput {
uint64_t seqnum; // input event number uint64_t seqnum; // input event number
} ncinput; } ncinput;
// See ppoll(2) for more detail. Provide a NULL 'ts' to block at length, a 'ts' // Read a UTF-32-encoded Unicode codepoint from input. This might only be part
// of 0 for non-blocking operation, and otherwise a timespec to bound blocking. // of a larger EGC. Provide a NULL 'ts' to block at length, and otherwise a
// Signals in sigmask (less several we handle internally) will be atomically // timespec to bound blocking. Returns a single Unicode code point, or
// masked and unmasked per ppoll(2). It should generally contain all signals. // (uint32_t)-1 on error. 'sigmask' may be NULL. Returns 0 on a timeout. If an
// Returns a single Unicode code point, or (char32_t)-1 on error. 'sigmask' may // event is processed, the return value is the 'id' field from that event.
// be NULL. Returns 0 on a timeout. If an event is processed, the return value // 'ni' may be NULL.
// is the 'id' field from that event. 'ni' may be NULL. uint32_t notcurses_get(struct notcurses* n, const struct timespec* ts,
char32_t notcurses_getc(struct notcurses* n, const struct timespec* ts, ncinput* ni)
sigset_t* sigmask, ncinput* ni);
// '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 char32_t static inline uint32_t
notcurses_getc_nblock(struct notcurses* n, ncinput* ni){ notcurses_getc_nblock(struct notcurses* n, ncinput* ni){
sigset_t sigmask;
sigfillset(&sigmask);
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
return notcurses_getc(n, &ts, &sigmask, ni); return notcurses_get(n, &ts, 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 char32_t static inline uint32_t
notcurses_getc_blocking(struct notcurses* n, ncinput* ni){ notcurses_getc_blocking(struct notcurses* n, ncinput* ni){
sigset_t sigmask; return notcurses_get(n, NULL, ni);
sigemptyset(&sigmask);
return notcurses_getc(n, NULL, &sigmask, ni);
} }
static inline bool static inline bool
@ -712,7 +707,7 @@ successful call to `notcurses_mouse_enable()`, and can later be disabled.
```c ```c
// Enable the mouse in "button-event tracking" mode with focus detection and // Enable the mouse in "button-event tracking" mode with focus detection and
// UTF8-style extended coordinates. On failure, -1 is returned. On success, 0 // UTF8-style extended coordinates. On failure, -1 is returned. On success, 0
// is returned, and mouse events will be published to notcurses_getc(). // is returned, and mouse events will be published to notcurses_get().
int notcurses_mouse_enable(struct notcurses* n); int notcurses_mouse_enable(struct notcurses* n);
// Disable mouse events. Any events in the input queue can still be delivered. // Disable mouse events. Any events in the input queue can still be delivered.
@ -720,7 +715,7 @@ int notcurses_mouse_disable(struct notcurses* n);
// Is the event a synthesized mouse event? // Is the event a synthesized mouse event?
static inline bool static inline bool
nckey_mouse_p(char32_t r){ nckey_mouse_p(uint32_t r){
return r >= NCKEY_BUTTON1 && r <= NCKEY_RELEASE; return r >= NCKEY_BUTTON1 && r <= NCKEY_RELEASE;
} }
``` ```

View File

@ -15,7 +15,7 @@ struct timespec;
struct notcurses; struct notcurses;
typedef struct ncinput { typedef struct ncinput {
char32_t id; // Unicode codepoint uint32_t id; // Unicode codepoint
int y; // Y cell coordinate of event, -1 for undefined int y; // Y cell coordinate of event, -1 for undefined
int x; // X cell coordinate of event, -1 for undefined int x; // X cell coordinate of event, -1 for undefined
bool alt; // Was Alt held during the event? bool alt; // Was Alt held during the event?
@ -25,15 +25,15 @@ typedef struct ncinput {
} ncinput; } ncinput;
``` ```
**bool nckey_mouse_p(char32_t ***r***);** **bool nckey_mouse_p(uint32_t ***r***);**
**bool ncinput_nomod_p(const ncinput* ***ni***);** **bool ncinput_nomod_p(const ncinput* ***ni***);**
**char32_t notcurses_getc(struct notcurses* ***n***, const struct timespec* ***ts***, const sigset_t* ***sigmask***, ncinput* ***ni***);** **uint32_t notcurses_get(struct notcurses* ***n***, const struct timespec* ***ts***, ncinput* ***ni***);**
**char32_t notcurses_getc_nblock(struct notcurses* ***n***, ncinput* ***ni***);** **uint32_t notcurses_getc_nblock(struct notcurses* ***n***, ncinput* ***ni***);**
**char32_t notcurses_getc_blocking(struct notcurses* ***n***, ncinput* ***ni***);** **uint32_t notcurses_getc_blocking(struct notcurses* ***n***, ncinput* ***ni***);**
**int notcurses_mouse_enable(struct notcurses* ***n***);** **int notcurses_mouse_enable(struct notcurses* ***n***);**
@ -62,8 +62,8 @@ non-canonical mode (see **termios(3)**), and thus keys are received without line
notcurses maintains its own buffer of input characters, which it will attempt notcurses maintains its own buffer of input characters, which it will attempt
to fill whenever it reads. to fill whenever it reads.
**notcurses_getc** allows a **struct timespec** to be specified as a timeout. **notcurses_get** allows a **struct timespec** to be specified as a timeout.
If **ts** is **NULL**, **notcurses_getc** will block until it reads input, or If **ts** is **NULL**, **notcurses_get** will block until it reads input, or
is interrupted by a signal. If its values are zeroes, there will be no blocking. is interrupted by a signal. If its values are zeroes, there will be no blocking.
Otherwise, **ts** specifies a minimum time to wait for input before giving up. Otherwise, **ts** specifies a minimum time to wait for input before giving up.
On timeout, 0 is returned. Signals in **sigmask** will be masked and blocked in On timeout, 0 is returned. Signals in **sigmask** will be masked and blocked in
@ -72,7 +72,7 @@ details will be reported in **ni**, unless **ni** is NULL.
**notcurses_inputready_fd** provides a file descriptor suitable for use with **notcurses_inputready_fd** provides a file descriptor suitable for use with
I/O multiplexors such as **poll(2)**. This file descriptor might or might not I/O multiplexors such as **poll(2)**. This file descriptor might or might not
be the actual input file descriptor. If it readable, **notcurses_getc** can be the actual input file descriptor. If it readable, **notcurses_get** can
be called without the possibility of blocking. be called without the possibility of blocking.
**ncinput_equal_p** compares two **ncinput** structs for data equality (i.e. **ncinput_equal_p** compares two **ncinput** structs for data equality (i.e.
@ -122,11 +122,11 @@ generated.
# RETURN VALUES # RETURN VALUES
On error, the **getc** family of functions return **(char32_t)-1**. The cause of the error may be determined On error, the **get** family of functions return **(uint32_t)-1**. The cause
using **errno(3)**. Unless the error was a temporary one (especially e.g. **EINTR**), of the error may be determined using **errno(3)**. Unless the error was a
**notcurses_getc** probably cannot be usefully called forthwith. On a temporary one (especially e.g. **EINTR**), **notcurses_get** probably cannot
timeout, 0 is returned. Otherwise, the UCS-32 value of a Unicode codepoint, or be usefully called forthwith. On a timeout, 0 is returned. Otherwise, the
a synthesized event, is returned. UCS-32 value of a Unicode codepoint, or a synthesized event, is returned.
**notcurses_mouse_enable** returns 0 on success, and non-zero on failure, as **notcurses_mouse_enable** returns 0 on success, and non-zero on failure, as
does **notcurses_mouse_disable**. does **notcurses_mouse_disable**.
@ -137,12 +137,12 @@ the same input (though not necessarily the same input event), and
# NOTES # NOTES
Like any other notcurses function, it is an error to call **notcurses_getc** Like any other notcurses function, it is an error to call **notcurses_get**
during or after a call to **notcurses_stop**. If a thread is always sitting during or after a call to **notcurses_stop**. If a thread is always sitting
on blocking input, it can be tricky to guarantee that this doesn't happen. on blocking input, it can be tricky to guarantee that this doesn't happen.
Only one thread may call into the input stack at once, but unlike almost every Only one thread may call into the input stack at once, but unlike almost every
other function in notcurses, **notcurses_getc** and friends can be called other function in notcurses, **notcurses_get** and friends can be called
concurrently with **notcurses_render**. concurrently with **notcurses_render**.
Do not simply **poll** the input file descriptor. Instead, use the file Do not simply **poll** the input file descriptor. Instead, use the file

View File

@ -207,16 +207,16 @@ namespace ncpp
return error_guard (ncdirect_flush (direct), -1); return error_guard (ncdirect_flush (direct), -1);
} }
char32_t getc (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_getc_blocking (direct, ni);
return ncdirect_getc_nblock (direct, ni); return ncdirect_getc_nblock (direct, ni);
} }
char32_t getc (const struct timespec *ts, sigset_t *sigmask, ncinput *ni) const noexcept char32_t get (const struct timespec *ts, ncinput *ni) const noexcept
{ {
return ncdirect_getc (direct, ts, sigmask, ni); return ncdirect_get (direct, ts, ni);
} }
int get_inputready_fd () const noexcept int get_inputready_fd () const noexcept

View File

@ -240,12 +240,12 @@ namespace ncpp
return static_cast<CellStyle>(notcurses_supported_styles (nc)); return static_cast<CellStyle>(notcurses_supported_styles (nc));
} }
uint32_t getc (const timespec *ts, sigset_t *sigmask = nullptr, ncinput *ni = nullptr) const noexcept uint32_t get (const timespec *ts, ncinput *ni = nullptr) const noexcept
{ {
return notcurses_getc (nc, ts, sigmask, ni); return notcurses_get (nc, ts, ni);
} }
uint32_t getc (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_getc_blocking (nc, ni);

View File

@ -306,15 +306,13 @@ API int ncdirect_double_box(struct ncdirect* n, uint64_t ul, uint64_t ur,
int ylen, int xlen, unsigned ctlword) int ylen, int xlen, unsigned ctlword)
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1)));
// See ppoll(2) for more detail. Provide a NULL 'ts' to block at length, a 'ts' // Provide a NULL 'ts' to block at length, a 'ts' of 0 for non-blocking
// of 0 for non-blocking operation, and otherwise a timespec to bound blocking. // operation, and otherwise a timespec to bound blocking. Returns a single
// Signals in sigmask (less several we handle internally) will be atomically // Unicode code point, or (uint32_t)-1 on error. Returns 0 on a timeout. If
// masked and unmasked per ppoll(2). '*sigmask' should generally contain all // an event is processed, the return value is the 'id' field from that
// signals. Returns a single Unicode code point, or (uint32_t)-1 on error. // event. 'ni' may be NULL.
// 'sigmask' may be NULL. Returns 0 on a timeout. If an event is processed, the API uint32_t ncdirect_get(struct ncdirect* n, const struct timespec* ts,
// return value is the 'id' field from that event. 'ni' may be NULL. ncinput* ni)
API uint32_t ncdirect_getc(struct ncdirect* n, const struct timespec* ts,
sigset_t* sigmask, 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
@ -328,19 +326,15 @@ API int ncdirect_inputready_fd(struct ncdirect* n)
// 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_getc_nblock(struct ncdirect* n, ncinput* ni){
sigset_t sigmask;
sigfillset(&sigmask);
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
return ncdirect_getc(n, &ts, &sigmask, ni); return ncdirect_get(n, &ts, 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_getc_blocking(struct ncdirect* n, ncinput* ni){
sigset_t sigmask; return ncdirect_get(n, NULL, ni);
sigemptyset(&sigmask);
return ncdirect_getc(n, NULL, &sigmask, ni);
} }
// Release 'nc' and any associated resources. 0 on success, non-0 on failure. // Release 'nc' and any associated resources. 0 on success, non-0 on failure.
@ -495,6 +489,11 @@ ncdirect_canbraille(const struct ncdirect* nc){
API bool ncdirect_canget_cursor(const struct ncdirect* nc) API bool ncdirect_canget_cursor(const struct ncdirect* nc)
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1)));
// Deprecated, to be removed for ABI3. Use ncdirect_get() in new code.
API uint32_t ncdirect_getc(struct ncdirect* n, const struct timespec* ts,
const void* unused, ncinput* ni)
__attribute__ ((deprecated)) __attribute__ ((nonnull (1)));
#undef ALLOC #undef ALLOC
#undef API #undef API

View File

@ -27,7 +27,6 @@ extern "C" {
#define wcwidth(w) 1 #define wcwidth(w) 1
#define wcswidth(w, s) (s) #define wcswidth(w, s) (s)
#define sigset_t int #define sigset_t int
#define sigfillset(x)
#define sigemptyset(x) #define sigemptyset(x)
#define O_CLOEXEC O_NOINHERIT #define O_CLOEXEC O_NOINHERIT
#define O_DIRECTORY 0 #define O_DIRECTORY 0

View File

@ -94,7 +94,7 @@ typedef enum {
// -1 if a non-printable/illegal character is encountered. // -1 if a non-printable/illegal character is encountered.
API int ncstrwidth(const char* mbs); API int ncstrwidth(const char* mbs);
// input functions like notcurses_getc() return ucs32-encoded uint32_t. convert // input functions like notcurses_get() return ucs32-encoded uint32_t. convert
// a series of uint32_t to utf8. result must be at least 4 bytes per input // a series of uint32_t to utf8. result must be at least 4 bytes per input
// uint32_t (6 bytes per uint32_t will future-proof against Unicode expansion). // uint32_t (6 bytes per uint32_t will future-proof against Unicode expansion).
// the number of bytes used is returned, or -1 if passed illegal ucs32, or too // the number of bytes used is returned, or -1 if passed illegal ucs32, or too
@ -857,7 +857,7 @@ typedef enum {
#define NCOPTION_NO_CLEAR_BITMAPS 0x0002ull #define NCOPTION_NO_CLEAR_BITMAPS 0x0002ull
// We typically install a signal handler for SIGWINCH that generates a resize // We typically install a signal handler for SIGWINCH that generates a resize
// event in the notcurses_getc() queue. Set to inhibit this handler. // event in the notcurses_get() queue. Set to inhibit this handler.
#define NCOPTION_NO_WINCH_SIGHANDLER 0x0004ull #define NCOPTION_NO_WINCH_SIGHANDLER 0x0004ull
// We typically install a signal handler for SIG{INT, ILL, SEGV, ABRT, TERM, // We typically install a signal handler for SIG{INT, ILL, SEGV, ABRT, TERM,
@ -976,20 +976,20 @@ API struct ncplane* notcurses_bottom(struct notcurses* n);
// Destroy all ncplanes other than the stdplane. // Destroy all ncplanes other than the stdplane.
API void notcurses_drop_planes(struct notcurses* nc); API void notcurses_drop_planes(struct notcurses* nc);
// All input is currently taken from stdin, though this will likely change. We // All input is taken from stdin. We attempt to read a single UTF8-encoded
// attempt to read a single UTF8-encoded Unicode codepoint, *not* an entire // Unicode codepoint, *not* an entire Extended Grapheme Cluster. It is also
// Extended Grapheme Cluster. It is also possible that we will read a special // possible that we will read a special keypress, i.e. anything that doesn't
// keypress, i.e. anything that doesn't correspond to a Unicode codepoint (e.g. // correspond to a Unicode codepoint (e.g. arrow keys, function keys, screen
// arrow keys, function keys, screen resize events, etc.). These are mapped // resize events, etc.). These are mapped into Unicode's Supplementary
// into Unicode's Supplementary Private Use Area-B, starting at U+100000. // Private Use Area-B, starting at U+100000. See <notcurses/nckeys.h>.
// //
// notcurses_getc() and notcurses_getc_nblock() are both nonblocking. // notcurses_getc_nblock() is nonblocking. notcurses_getc_blocking() blocks
// notcurses_getc_blocking() blocks until a codepoint or special key is read, // until a codepoint or special key is read, or until interrupted by a signal.
// or until interrupted by a signal. // notcurses_get() allows an optional timeout to be controlled.
// //
// In the case of a valid read, a 32-bit Unicode codepoint is returned. 0 is // In the case of a valid read, a 32-bit Unicode codepoint is returned. 0 is
// returned to indicate that no input was available, but only by // returned to indicate that no input was available. Otherwise (including on
// notcurses_getc(). Otherwise (including on EOF) (uint32_t)-1 is returned. // EOF) (uint32_t)-1 is returned.
// Is this uint32_t a Supplementary Private Use Area-B codepoint? // Is this uint32_t a Supplementary Private Use Area-B codepoint?
static inline bool static inline bool
@ -1031,15 +1031,14 @@ ncinput_equal_p(const ncinput* n1, const ncinput* n2){
return true; return true;
} }
// See ppoll(2) for more detail. Provide a NULL 'ts' to block at length, a 'ts' // Read a UTF-32-encoded Unicode codepoint from input. This might only be part
// of 0 for non-blocking operation, and otherwise a timespec to bound blocking. // of a larger EGC. Provide a NULL 'ts' to block at length, and otherwise a
// Signals in sigmask (less several we handle internally) will be atomically // timespec to bound blocking. Returns a single Unicode code point, or
// masked and unmasked per ppoll(2). It should generally contain all signals. // (uint32_t)-1 on error. 'sigmask' may be NULL. Returns 0 on a timeout. If an
// Returns a single Unicode code point, or (uint32_t)-1 on error. 'sigmask' may // event is processed, the return value is the 'id' field from that event.
// be NULL. Returns 0 on a timeout. If an event is processed, the return value // 'ni' may be NULL.
// 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_getc(struct notcurses* n, const struct timespec* ts, ncinput* ni)
const sigset_t* sigmask, 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
@ -1053,19 +1052,15 @@ API int notcurses_inputready_fd(struct notcurses* n)
// is ready, returns 0. // is ready, returns 0.
static inline uint32_t static inline uint32_t
notcurses_getc_nblock(struct notcurses* n, ncinput* ni){ notcurses_getc_nblock(struct notcurses* n, ncinput* ni){
sigset_t sigmask;
sigfillset(&sigmask);
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
return notcurses_getc(n, &ts, &sigmask, ni); return notcurses_get(n, &ts, 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_getc_blocking(struct notcurses* n, ncinput* ni){
sigset_t sigmask; return notcurses_get(n, NULL, ni);
sigemptyset(&sigmask);
return notcurses_getc(n, NULL, &sigmask, ni);
} }
static inline bool static inline bool
@ -1075,7 +1070,7 @@ ncinput_nomod_p(const ncinput* ni){
// Enable the mouse in "button-event tracking" mode with focus detection and // Enable the mouse in "button-event tracking" mode with focus detection and
// UTF8-style extended coordinates. On failure, -1 is returned. On success, 0 // UTF8-style extended coordinates. On failure, -1 is returned. On success, 0
// is returned, and mouse events will be published to notcurses_getc(). // is returned, and mouse events will be published to notcurses_get().
API int notcurses_mouse_enable(struct notcurses* n); API int notcurses_mouse_enable(struct notcurses* n);
// Disable mouse events. Any events in the input queue can still be delivered. // Disable mouse events. Any events in the input queue can still be delivered.
@ -4408,6 +4403,12 @@ typedef nccell cell; // FIXME backwards-compat, remove in ABI3
API void notcurses_debug_caps(const struct notcurses* nc, FILE* debugfp) API void notcurses_debug_caps(const struct notcurses* nc, FILE* debugfp)
__attribute__ ((deprecated)) __attribute__ ((nonnull (1, 2))); __attribute__ ((deprecated)) __attribute__ ((nonnull (1, 2)));
// Backwards-compatibility wrapper; this will be removed for ABI3.
// Use notcurses_get() in new code.
API uint32_t notcurses_getc(struct notcurses* n, const struct timespec* ts,
const void* unused, ncinput* ni)
__attribute__ ((deprecated)) __attribute__ ((nonnull (1)));
#define CELL_ALPHA_HIGHCONTRAST NCALPHA_HIGHCONTRAST #define CELL_ALPHA_HIGHCONTRAST NCALPHA_HIGHCONTRAST
#define CELL_ALPHA_TRANSPARENT NCALPHA_TRANSPARENT #define CELL_ALPHA_TRANSPARENT NCALPHA_TRANSPARENT
#define CELL_ALPHA_BLEND NCALPHA_BLEND #define CELL_ALPHA_BLEND NCALPHA_BLEND

View File

@ -252,7 +252,7 @@ int input_demo(ncpp::NotCurses* nc) {
start = timenow_to_ns(); start = timenow_to_ns();
std::thread tid(Ticker, nc); std::thread tid(Ticker, nc);
ncinput ni; ncinput ni;
while(errno = 0, (r = nc->getc(true, &ni)) != (char32_t)-1){ while(errno = 0, (r = nc->get(true, &ni)) != (char32_t)-1){
if(r == 0){ // interrupted by signal if(r == 0){ // interrupted by signal
continue; continue;
} }

View File

@ -391,39 +391,27 @@ handle_getc(ncinputlayer* nc, int kpress, ncinput* ni, int leftmargin, int topma
// blocks up through ts (infinite with NULL ts), returning number of events // blocks up through ts (infinite with NULL ts), returning number of events
// (0 on timeout) or -1 on error/interruption. // (0 on timeout) or -1 on error/interruption.
#ifndef __MINGW64__
static int static int
block_on_input(int fd, const struct timespec* ts, const sigset_t* sigmask){ block_on_input(int fd, const struct timespec* ts){
struct pollfd pfd = { struct pollfd pfd = {
.fd = fd, .fd = fd,
.events = POLLIN, .events = POLLIN,
.revents = 0, .revents = 0,
}; };
// we don't want to persistently modify the provided sigmask sigset_t smask;
sigset_t scratchmask; sigfillset(&smask);
if(sigmask){ sigdelset(&smask, SIGCONT);
memcpy(&scratchmask, sigmask, sizeof(*sigmask)); sigdelset(&smask, SIGWINCH);
}else{
sigfillset(&scratchmask);
}
sigdelset(&scratchmask, SIGCONT);
sigdelset(&scratchmask, SIGWINCH);
sigdelset(&scratchmask, SIGILL);
sigdelset(&scratchmask, SIGFPE);
sigdelset(&scratchmask, SIGSEGV);
sigdelset(&scratchmask, SIGABRT);
// now add those which we don't want while writing
sigaddset(&scratchmask, SIGINT);
sigaddset(&scratchmask, SIGQUIT);
sigaddset(&scratchmask, SIGTERM);
#ifdef POLLRDHUP #ifdef POLLRDHUP
pfd.events |= POLLRDHUP; pfd.events |= POLLRDHUP;
#endif #endif
int events; int events;
#ifdef __APPLE__ #ifdef __APPLE__
int timeoutms = ts ? ts->tv_sec * 1000 + ts->tv_nsec / 1000000 : -1; int timeoutms = ts ? ts->tv_sec * 1000 + ts->tv_nsec / 1000000 : -1;
while((events = poll(&pfd, 1, timeoutms)) < 0){ // FIXME scratchmask? while((events = poll(&pfd, 1, timeoutms)) < 0){ // FIXME smask?
#else #else
while((events = ppoll(&pfd, 1, ts, &scratchmask)) < 0){ while((events = ppoll(&pfd, 1, ts, &smask)) < 0){
#endif #endif
if(events == 0){ if(events == 0){
return 0; return 0;
@ -437,6 +425,9 @@ block_on_input(int fd, const struct timespec* ts, const sigset_t* sigmask){
} }
return events; return events;
} }
#else
// FIXME windows block_on_input()
#endif
static inline size_t static inline size_t
input_queue_space(const ncinputlayer* nc){ input_queue_space(const ncinputlayer* nc){
@ -563,14 +554,13 @@ handle_ncinput(ncinputlayer* nc, ncinput* ni, int leftmargin, int topmargin){
// helper so we can do counter increment at a single location // helper so we can do counter increment at a single location
static inline uint32_t static inline uint32_t
ncinputlayer_prestamp(ncinputlayer* nc, const struct timespec *ts, ncinputlayer_prestamp(ncinputlayer* nc, const struct timespec *ts,
const sigset_t* sigmask, ncinput* ni, int leftmargin, ncinput* ni, int leftmargin, int topmargin){
int topmargin){
//fprintf(stderr, "PRESTAMP OCCUPADO: %d\n", nc->inputbuf_occupied); //fprintf(stderr, "PRESTAMP OCCUPADO: %d\n", nc->inputbuf_occupied);
if(nc->inputbuf_occupied){ if(nc->inputbuf_occupied){
return handle_queued_input(nc, ni, leftmargin, topmargin); return handle_queued_input(nc, ni, leftmargin, topmargin);
} }
errno = 0; errno = 0;
if(block_on_input(nc->infd, ts, sigmask) > 0){ if(block_on_input(nc->infd, ts) > 0){
//fprintf(stderr, "%d events from input!\n", events); //fprintf(stderr, "%d events from input!\n", events);
return handle_ncinput(nc, ni, leftmargin, topmargin); return handle_ncinput(nc, ni, leftmargin, topmargin);
} }
@ -579,9 +569,8 @@ ncinputlayer_prestamp(ncinputlayer* nc, const struct timespec *ts,
} }
// infp has already been set non-blocking // infp has already been set non-blocking
uint32_t notcurses_getc(notcurses* nc, const struct timespec *ts, uint32_t notcurses_get(notcurses* nc, const struct timespec* ts, ncinput* ni){
const sigset_t* sigmask, ncinput* ni){ uint32_t r = ncinputlayer_prestamp(&nc->tcache.input, ts, ni,
uint32_t r = ncinputlayer_prestamp(&nc->tcache.input, ts, sigmask, ni,
nc->margin_l, nc->margin_t); nc->margin_l, nc->margin_t);
if(r != (uint32_t)-1){ if(r != (uint32_t)-1){
uint64_t stamp = nc->tcache.input.input_events++; // need increment even if !ni uint64_t stamp = nc->tcache.input.input_events++; // need increment even if !ni
@ -593,11 +582,16 @@ uint32_t notcurses_getc(notcurses* nc, const struct timespec *ts,
return r; return r;
} }
uint32_t ncdirect_getc(ncdirect* nc, const struct timespec *ts, uint32_t notcurses_getc(notcurses* nc, const struct timespec* ts,
sigset_t* sigmask, ncinput* ni){ const void* unused, ncinput* ni){
uint32_t r = ncinputlayer_prestamp(&nc->tcache.input, ts, sigmask, ni, 0, 0); (void)unused; // FIXME remove for abi3
return notcurses_get(nc, ts, ni);
}
uint32_t ncdirect_get(struct ncdirect* n, const struct timespec* ts, ncinput* ni){
uint32_t r = ncinputlayer_prestamp(&n->tcache.input, ts, ni, 0, 0);
if(r != (uint32_t)-1){ if(r != (uint32_t)-1){
uint64_t stamp = nc->tcache.input.input_events++; // need increment even if !ni uint64_t stamp = n->tcache.input.input_events++; // need increment even if !ni
if(ni){ if(ni){
ni->seqnum = stamp; ni->seqnum = stamp;
} }
@ -605,6 +599,12 @@ uint32_t ncdirect_getc(ncdirect* nc, const struct timespec *ts,
return r; return r;
} }
uint32_t ncdirect_getc(ncdirect* nc, const struct timespec *ts,
const void* unused, ncinput* ni){
(void)unused; // FIXME remove for abi3
return ncdirect_get(nc, ts, ni);
}
// load all known special keys from terminfo, and build the input sequence trie // load all known special keys from terminfo, and build the input sequence trie
static int static int
prep_special_keys(ncinputlayer* nc){ prep_special_keys(ncinputlayer* nc){
@ -1527,7 +1527,7 @@ void ncinput_extract_clrs(ncinputlayer* ni){
// specify a NULL timeout, meaning we block as long as we need, until // specify a NULL timeout, meaning we block as long as we need, until
// there's input available, or we are interrupted by a signal. // there's input available, or we are interrupted by a signal.
logdebug("Blocking on input"); logdebug("Blocking on input");
if(block_on_input(ni->infd, NULL, NULL) < 1){ if(block_on_input(ni->infd, NULL) < 1){
pthread_mutex_lock(&ni->lock); // interrupted? pthread_mutex_lock(&ni->lock); // interrupted?
break; break;
} }

View File

@ -131,19 +131,19 @@ auto perframe(struct ncvisual* ncv, struct ncvisual_options* vopts,
struct timespec interval; struct timespec interval;
clock_gettime(CLOCK_MONOTONIC, &interval); clock_gettime(CLOCK_MONOTONIC, &interval);
uint64_t nsnow = timespec_to_ns(&interval); uint64_t nsnow = timespec_to_ns(&interval);
char32_t keyp; uint32_t keyp;
ncinput ni; ncinput ni;
if(absnow > nsnow){ if(absnow > nsnow){
ns_to_timespec(absnow - nsnow, &interval); ns_to_timespec(absnow - nsnow, &interval);
keyp = nc.getc(&interval, nullptr, &ni); keyp = nc.get(&interval, &ni);
}else{ }else{
keyp = nc.getc(); keyp = nc.get();
} }
if(keyp == (char32_t)-1){ if(keyp == (uint32_t)-1){
break; break;
} }
if(keyp == ' '){ if(keyp == ' '){
if((keyp = nc.getc(true)) == (char32_t)-1){ if((keyp = nc.get(true)) == (uint32_t)-1){
return -1; return -1;
} }
} }
@ -438,8 +438,8 @@ int rendered_mode_player_inner(NotCurses& nc, int argc, char** argv,
ncplane_destroy(n); ncplane_destroy(n);
return -1; return -1;
} }
char32_t ie = nc.getc(true); uint32_t ie = nc.get(true);
if(ie == (char32_t)-1){ if(ie == (uint32_t)-1){
return -1; return -1;
}else if(ie == 'q'){ }else if(ie == 'q'){
return 0; return 0;

View File

@ -69,7 +69,7 @@ int main(int argc, char** argv){
ncplane_set_fg_rgb(n, 0x00bcaa); ncplane_set_fg_rgb(n, 0x00bcaa);
ncplane_printf_aligned(n, -1, NCALIGN_CENTER, "press any key to continue (%s)", *argv); ncplane_printf_aligned(n, -1, NCALIGN_CENTER, "press any key to continue (%s)", *argv);
notcurses_render(nc); notcurses_render(nc);
notcurses_getc(nc, NULL, NULL, NULL); notcurses_get(nc, NULL, NULL);
} }
done: done:

View File

@ -56,7 +56,7 @@ auto main(int argc, const char** argv) -> int {
} }
ncinput ni; ncinput ni;
nc.render(); nc.render();
while(nc.getc(true, &ni) != (char32_t)-1){ while(nc.get(true, &ni) != (char32_t)-1){
if(ni.ctrl && ni.id == 'L'){ if(ni.ctrl && ni.id == 'L'){
notcurses_refresh(nc, NULL, NULL); notcurses_refresh(nc, NULL, NULL);
}else if((ni.ctrl && ni.id == 'D') || ni.id == NCKEY_ENTER){ }else if((ni.ctrl && ni.id == 'D') || ni.id == NCKEY_ENTER){

View File

@ -2,7 +2,7 @@ bool IOLoop(ncpp::NotCurses& nc, Tetris& t, std::atomic_bool& gameover) {
ncpp::Plane* stdplane = nc.get_stdplane(); ncpp::Plane* stdplane = nc.get_stdplane();
char32_t input = 0; char32_t input = 0;
ncinput ni; ncinput ni;
while(!gameover && (input = nc.getc(true, &ni)) != (char32_t)-1){ while(!gameover && (input = nc.get(true, &ni)) != (char32_t)-1){
if(input == 'q'){ if(input == 'q'){
break; break;
} }