diff options
Diffstat (limited to 'src/bar.c')
-rw-r--r-- | src/bar.c | 66 |
1 files changed, 40 insertions, 26 deletions
@@ -1,21 +1,26 @@ // Copyright © Tavian Barnes <tavianator@tavianator.com> // SPDX-License-Identifier: 0BSD -#include "prelude.h" #include "bar.h" + #include "alloc.h" #include "atomic.h" +#include "bfs.h" #include "bfstd.h" #include "bit.h" #include "dstring.h" #include "sighook.h" + #include <errno.h> #include <fcntl.h> #include <signal.h> #include <stdarg.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <sys/ioctl.h> +#include <termios.h> +#include <unistd.h> struct bfs_bar { int fd; @@ -28,10 +33,16 @@ struct bfs_bar { /** Get the terminal size, if possible. */ static int bfs_bar_getsize(struct bfs_bar *bar) { -#ifdef TIOCGWINSZ +#if BFS_HAS_TCGETWINSIZE || defined(TIOCGWINSZ) struct winsize ws; - if (ioctl(bar->fd, TIOCGWINSZ, &ws) != 0) { - return -1; + +# if BFS_HAS_TCGETWINSIZE + int ret = tcgetwinsize(bar->fd, &ws); +# else + int ret = ioctl(bar->fd, TIOCGWINSZ, &ws); +# endif + if (ret != 0) { + return ret; } store(&bar->width, ws.ws_col, relaxed); @@ -72,8 +83,26 @@ static char *ass_itoa(char *str, unsigned int n) { return str + len; } +/** Reset the scrollable region and hide the bar. */ +static int bfs_bar_reset(struct bfs_bar *bar) { + return bfs_bar_puts(bar, + "\0337" // DECSC: Save cursor + "\033[r" // DECSTBM: Reset scrollable region + "\0338" // DECRC: Restore cursor + "\033[J" // ED: Erase display from cursor to end + ); +} + +/** Hide the bar if the terminal is shorter than this. */ +#define BFS_BAR_MIN_HEIGHT 3 + /** Update the size of the scrollable region. */ static int bfs_bar_resize(struct bfs_bar *bar) { + unsigned int height = load(&bar->height, relaxed); + if (height < BFS_BAR_MIN_HEIGHT) { + return bfs_bar_reset(bar); + } + static const char PREFIX[] = "\033D" // IND: Line feed, possibly scrolling "\033[1A" // CUU: Move cursor up 1 row @@ -87,10 +116,8 @@ static int bfs_bar_resize(struct bfs_bar *bar) { char esc_seq[sizeof(PREFIX) + ITOA_DIGITS + sizeof(SUFFIX)]; // DECSTBM takes the height as the second argument - unsigned int height = load(&bar->height, relaxed) - 1; - char *cur = stpcpy(esc_seq, PREFIX); - cur = ass_itoa(cur, height); + cur = ass_itoa(cur, height - 1); cur = stpcpy(cur, SUFFIX); return bfs_bar_write(bar, esc_seq, cur - esc_seq); @@ -105,16 +132,6 @@ static void bfs_bar_sigwinch(int sig, siginfo_t *info, void *arg) { } #endif -/** Reset the scrollable region and hide the bar. */ -static int bfs_bar_reset(struct bfs_bar *bar) { - return bfs_bar_puts(bar, - "\0337" // DECSC: Save cursor - "\033[r" // DECSTBM: Reset scrollable region - "\0338" // DECRC: Restore cursor - "\033[J" // ED: Erase display from cursor to end - ); -} - /** Signal handler for process-terminating signals. */ static void bfs_bar_sigexit(int sig, siginfo_t *info, void *arg) { struct bfs_bar *bar = arg; @@ -122,7 +139,7 @@ static void bfs_bar_sigexit(int sig, siginfo_t *info, void *arg) { } /** printf() to the status bar with a single write(). */ -attr(printf(2, 3)) +_printf(2, 3) static int bfs_bar_printf(struct bfs_bar *bar, const char *format, ...) { va_list args; va_start(args, format); @@ -144,14 +161,7 @@ struct bfs_bar *bfs_bar_show(void) { return NULL; } - char term[L_ctermid]; - ctermid(term); - if (strlen(term) == 0) { - errno = ENOTTY; - goto fail; - } - - bar->fd = open(term, O_RDWR | O_CLOEXEC); + bar->fd = open_cterm(O_RDWR | O_CLOEXEC); if (bar->fd < 0) { goto fail; } @@ -190,6 +200,10 @@ unsigned int bfs_bar_width(const struct bfs_bar *bar) { int bfs_bar_update(struct bfs_bar *bar, const char *str) { unsigned int height = load(&bar->height, relaxed); + if (height < BFS_BAR_MIN_HEIGHT) { + return 0; + } + return bfs_bar_printf(bar, "\0337" // DECSC: Save cursor "\033[%u;0f" // HVP: Move cursor to row, column |