diff options
| author | Dylan Araps <dylan.araps@gmail.com> | 2026-02-28 09:35:10 +0200 |
|---|---|---|
| committer | Dylan Araps <dylan.araps@gmail.com> | 2026-02-28 09:35:10 +0200 |
| commit | f700440f9ca9be7dd6e5615b3a84c1c9e1ca18c2 (patch) | |
| tree | 6941e2d48c3b2c5f3c2a2f9b0c730a6d75d0b199 | |
| parent | fc339fa3cb9c03fdebd300f7018b23931a3eb7bd (diff) | |
dfm: also wake on winch
This adds responsive resize whilst still allowing dfm to do nothing at idle.
Nifty.
| -rw-r--r-- | README.txt | 4 | ||||
| -rw-r--r-- | dfm.c | 10 | ||||
| -rw-r--r-- | lib/term.h | 52 |
3 files changed, 42 insertions, 24 deletions
@@ -371,10 +371,6 @@ See the config_key.h.in and config_cmd.h.in files for more information. DESIGN CONSIDERATIONS ________________________________________________________________________________ -* I wanted DFM to do absolutely nothing when idle so SIGWINCH (resize handling) - will not automatically perform a size adjustment and redraw until the next - keypress. - * I employed many tricks in order to keep memory usage low whilst still allowing for fast operations and relatively large directory trees. @@ -3342,9 +3342,6 @@ static inline void fm_update(struct fm *p) { term_reap(); - if (unlikely(term_resize(&p->t))) - if (fm_term_resize(p) < 0) - fm_draw_err(p, S("resize failed"), errno); fm_watch_handle(p); if (!(p->f & FM_DIRTY)) return; p->f &= ~FM_DIRTY; @@ -3403,7 +3400,12 @@ fm_run(struct fm *p) for (; likely(!term_dead(&p->t)); ) { fm_update(p); fm_draw(p); - fm_input(p); + int e = term_wait(&p->t); + if (e & TERM_WAIT_WCH) + if (fm_term_resize(p) < 0) + fm_draw_err(p, S("resize failed"), errno); + if (e & TERM_WAIT_KEY) + fm_input(p); } fm_term_free(p); if (!(p->f & FM_PRINT_PWD)) p->pwd.l = 0; @@ -23,6 +23,7 @@ #define DYLAN_TERM_H #include <assert.h> +#include <errno.h> #include <fcntl.h> #include <signal.h> #include <termios.h> @@ -36,8 +37,9 @@ #include "vt.h" enum { - TERM_LOADED = 1 << 0, - TERM_RESIZE = 1 << 1, + TERM_LOADED = 1 << 0, + TERM_WAIT_WCH = 1 << 1, + TERM_WAIT_KEY = 1 << 2, }; static struct term { @@ -45,6 +47,7 @@ static struct term { int fd; int null; volatile sig_atomic_t flag; + volatile sig_atomic_t resize; volatile sig_atomic_t dead; } *TERM; @@ -60,12 +63,6 @@ term_dead(const struct term *t) return t->dead; } -static inline int -term_resize(const struct term *t) -{ - return t->flag & TERM_RESIZE; -} - static inline void term_restore_on_signal(int s) { @@ -105,7 +102,7 @@ static inline void term_signal_sigwinch(int s) { (void) s; - if (TERM) TERM->flag |= TERM_RESIZE; + if (TERM) TERM->resize = 1; } static inline void @@ -123,6 +120,7 @@ term_signal_setup(void) { sigaction(SIGBUS, &sa, NULL); sigaction(SIGFPE, &sa, NULL); sigaction(SIGILL, &sa, NULL); + sa.sa_flags = 0; sa.sa_handler = term_signal_sigwinch; sigaction(SIGWINCH, &sa, NULL); } @@ -130,13 +128,15 @@ term_signal_setup(void) { static inline int term_size_update(struct term *t, u16 *row, u16 *col) { - struct winsize ws; - if (ioctl(t->fd, TIOCGWINSZ, &ws) < 0) - return -1; - t->flag &= ~TERM_RESIZE; - *row = ws.ws_row; - *col = ws.ws_col; - return 0; + for (;;) { + t->resize = 0; + struct winsize ws; + if (ioctl(t->fd, TIOCGWINSZ, &ws) < 0) + return -1; + *row = ws.ws_row; + *col = ws.ws_col; + if (!t->resize) return 0; + } } static inline int @@ -192,6 +192,26 @@ term_reap(void) for (int st; waitpid(-1, &st, WNOHANG) > 0; ); } +static inline int +term_wait(struct term *t) +{ + for (;;) { + if (t->resize) return TERM_WAIT_WCH; + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(t->fd, &rfds); + int r = select(t->fd + 1, &rfds, NULL, NULL, NULL); + if (r < 0) { + if (errno != EINTR) return 0; + if (t->resize) return TERM_WAIT_WCH; + continue; + } + if (FD_ISSET(t->fd, &rfds)) + return TERM_WAIT_KEY; + return 0; + } +} + static inline void term_destroy(const struct term *t) { |