From a909d3f168066ab379ca279490c1f730f8cb381a Mon Sep 17 00:00:00 2001 From: git-bruh Date: Wed, 15 Dec 2021 16:42:01 +0530 Subject: [PATCH] expose internal fds for external polling --- termbox.h | 121 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 37 deletions(-) diff --git a/termbox.h b/termbox.h index dbf27f9..f716a57 100644 --- a/termbox.h +++ b/termbox.h @@ -37,6 +37,11 @@ SOFTWARE. #include #include #include +#if !TB_OPT_SELECT +#include +#else +#include +#endif #include #include #include @@ -227,15 +232,17 @@ extern "C" { // __ffi_strip #define TB_ERR_RESIZE_IOCTL -11 #define TB_ERR_RESIZE_PIPE -12 #define TB_ERR_RESIZE_SIGACTION -13 -#define TB_ERR_SELECT -14 +#define TB_ERR_POLL -14 #define TB_ERR_TCGETATTR -15 #define TB_ERR_TCSETATTR -16 #define TB_ERR_UNSUPPORTED_TERM -17 #define TB_ERR_RESIZE_WRITE -18 -#define TB_ERR_RESIZE_SELECT -19 +#define TB_ERR_RESIZE_POLL -19 #define TB_ERR_RESIZE_READ -20 #define TB_ERR_RESIZE_SSCANF -21 #define TB_ERR_CAP_COLLISION -22 +#define TB_ERR_SELECT TB_ERR_POLL +#define TB_ERR_RESIZE_SELECT TB_ERR_RESIZE_POLL /* Function types to be used with tb_set_func() */ #define TB_FUNC_EXTRACT_PRE 0 @@ -311,7 +318,7 @@ struct tb_cell { * TB_MOD_CTRL and TB_MOD_SHIFT are only set as * modifiers to TB_KEY_ARROW_*. * - * when TB_EVENT_RESIZE: w, h + * when TB_EVENT_RESIZE: w, h * * when TB_EVENT_MOUSE: key (TB_KEY_MOUSE_*), x, y */ @@ -426,8 +433,8 @@ int tb_set_output_mode(int mode); /* Wait for an event up to timeout_ms milliseconds and fill the event structure * with it. If no event is available within the timeout period, TB_ERR_NO_EVENT - * is returned. On a resize event, the underlying select(2) call may be - * interrupted, yielding a return code of TB_ERR_SELECT. In this case, you may + * is returned. On a resize event, the underlying poll(2) call may be + * interrupted, yielding a return code of TB_ERR_POLL. In this case, you may * check errno via tb_last_errno(). If it's EINTR, you can safely ignore that * and call tb_peek_event() again. */ @@ -436,6 +443,10 @@ int tb_peek_event(struct tb_event *event, int timeout_ms); /* Same as tb_peek_event except no timeout. */ int tb_poll_event(struct tb_event *event); +/* Internal termbox FDs that can be used with poll() / select(). Must call + * tb_poll_event() / tb_peek_event() if activity is detected. */ +int tb_get_fds(int *ttyfd, int *resizefd); + /* Print and printf functions. Specify param out_w to determine width of printed * string. */ @@ -1262,7 +1273,7 @@ static int read_terminfo_path(const char *path); static int parse_terminfo_caps(); static int load_builtin_caps(); static const char * get_terminfo_string(int16_t str_offsets_pos, int16_t str_table_pos, int16_t str_table_len, int16_t str_index); -static int wait_event(struct tb_event *event, struct timeval *timeout); +static int wait_event(struct tb_event *event, int timeout); static int extract_event(struct tb_event *event); static int extract_esc(struct tb_event *event); static int extract_esc_user(struct tb_event *event, int is_post); @@ -1509,17 +1520,23 @@ int tb_set_output_mode(int mode) { return TB_OK; } -int tb_peek_event(struct tb_event *event, int timeout) { +int tb_peek_event(struct tb_event *event, int timeout_ms) { if_not_init_return(); - struct timeval tv; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000; - return wait_event(event, &tv); + return wait_event(event, timeout_ms); } int tb_poll_event(struct tb_event *event) { if_not_init_return(); - return wait_event(event, NULL); + return wait_event(event, -1); +} + +int tb_get_fds(int *ttyfd, int *resizefd) { + if_not_init_return(); + + *ttyfd = global.rfd; + *resizefd = global.resize_pipefd[0]; + + return TB_OK; } int tb_print(int x, int y, uintattr_t fg, uintattr_t bg, const char *str) { @@ -1787,7 +1804,7 @@ static int init_cap_trie() { static int cap_trie_add(const char *cap, uint16_t key, uint8_t mod) { struct cap_trie_t *next, *node = &global.cap_trie; size_t i, j; - for (i = 0; i < strlen(cap); i++) { + for (i = 0; cap[i] != '\0'; i++) { char c = cap[i]; next = NULL; @@ -1830,7 +1847,7 @@ static int cap_trie_find(const char *buf, struct cap_trie_t **last, size_t *dept size_t i, j; *last = node; *depth = 0; - for (i = 0; i < strlen(buf); i++) { + for (i = 0; buf[i] != '\0'; i++) { char c = buf[i]; next = NULL; @@ -1937,22 +1954,29 @@ static int update_term_size_via_esc() { #define TB_RESIZE_FALLBACK_MS 1000 #endif - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = TB_RESIZE_FALLBACK_MS * 1000; - char *move_and_report = "\x1b[9999;9999H\x1b[6n"; ssize_t write_rv = write(global.wfd, move_and_report, strlen(move_and_report)); if (write_rv != (ssize_t)strlen(move_and_report)) { return TB_ERR_RESIZE_WRITE; } - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(global.rfd, &rfds); - int select_rv = select(global.rfd + 1, &rfds, NULL, NULL, &timeout); - if (select_rv != 1) { - return TB_ERR_RESIZE_SELECT; +#if !TB_OPT_SELECT + struct pollfd fd = {.fd = global.rfd, .events = POLLIN}; + int poll_rv = poll(&fd, 1, TB_RESIZE_FALLBACK_MS); +#else + fd_set fds; + FD_ZERO(&fds); + FD_SET(global.rfd, &fds); + + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = TB_RESIZE_FALLBACK_MS * 1000; + + int poll_rv = select(global.rfd + 1, &fds, NULL, NULL, &timeout); +#endif + + if (poll_rv != 1) { + return TB_ERR_RESIZE_POLL; } char buf[64]; @@ -2236,34 +2260,57 @@ static const char * get_terminfo_string(int16_t str_offsets_pos, int16_t str_tab + (int)*str_offset); } -static int wait_event(struct tb_event *event, struct timeval *timeout) { +static int wait_event(struct tb_event *event, int timeout) { int rv; - fd_set rfds; char buf[64]; memset(event, 0, sizeof(*event)); if_ok_return(rv, extract_event(event)); +#if !TB_OPT_SELECT + struct pollfd fds[2] = { + {.fd = global.rfd, .events = POLLIN}, + {.fd = global.resize_pipefd[0], .events = POLLIN} + }; +#else + fd_set fds; + struct timeval tv; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000; +#endif + do { - FD_ZERO(&rfds); - FD_SET(global.rfd, &rfds); - FD_SET(global.resize_pipefd[0], &rfds); +#if !TB_OPT_SELECT + int poll_rv = poll(fds, 2, timeout); +#else + FD_ZERO(&fds); + FD_SET(global.rfd, &fds); + FD_SET(global.resize_pipefd[0], &fds); int maxfd = global.resize_pipefd[0] > global.rfd ? global.resize_pipefd[0] : global.rfd; - int select_rv = select(maxfd + 1, &rfds, NULL, NULL, timeout); + int poll_rv = select(maxfd + 1, &fds, NULL, NULL, (timeout < 0) ? NULL : &tv); +#endif - if (select_rv < 0) { + if (poll_rv < 0) { // Let EINTR/EAGAIN bubble up global.last_errno = errno; - return TB_ERR_SELECT; - } else if (select_rv == 0) { + return TB_ERR_POLL; + } else if (poll_rv == 0) { return TB_ERR_NO_EVENT; } - if (FD_ISSET(global.rfd, &rfds)) { +#if !TB_OPT_SELECT + int tty_has_events = (fds[0].revents & POLLIN); + int resize_has_events = (fds[1].revents & POLLIN); +#else + int tty_has_events = (FD_ISSET(global.rfd, &fds)); + int resize_has_events = (FD_ISSET(global.resize_pipefd[0], &fds)); +#endif + + if (tty_has_events) { ssize_t read_rv = read(global.rfd, buf, sizeof(buf)); if (read_rv < 0) { global.last_errno = errno; @@ -2273,7 +2320,7 @@ static int wait_event(struct tb_event *event, struct timeval *timeout) { } } - if (FD_ISSET(global.resize_pipefd[0], &rfds)) { + if (resize_has_events) { int ignore = 0; read(global.resize_pipefd[0], &ignore, sizeof(ignore)); if_err_return(rv, update_term_size()); @@ -2286,9 +2333,9 @@ static int wait_event(struct tb_event *event, struct timeval *timeout) { memset(event, 0, sizeof(*event)); if_ok_return(rv, extract_event(event)); - } while (!timeout || timeout->tv_sec > 0 || timeout->tv_usec > 0); + } while (timeout == -1); - return TB_ERR_NO_EVENT; + return rv; } static int extract_event(struct tb_event *event) { -- 2.39.5