aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan Araps <dylan.araps@gmail.com>2026-02-28 09:35:10 +0200
committerDylan Araps <dylan.araps@gmail.com>2026-02-28 09:35:10 +0200
commitf700440f9ca9be7dd6e5615b3a84c1c9e1ca18c2 (patch)
tree6941e2d48c3b2c5f3c2a2f9b0c730a6d75d0b199
parentfc339fa3cb9c03fdebd300f7018b23931a3eb7bd (diff)
dfm: also wake on winch
This adds responsive resize whilst still allowing dfm to do nothing at idle. Nifty.
-rw-r--r--README.txt4
-rw-r--r--dfm.c10
-rw-r--r--lib/term.h52
3 files changed, 42 insertions, 24 deletions
diff --git a/README.txt b/README.txt
index 37a21dd..1256f70 100644
--- a/README.txt
+++ b/README.txt
@@ -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.
diff --git a/dfm.c b/dfm.c
index f6a30dc..695b0aa 100644
--- a/dfm.c
+++ b/dfm.c
@@ -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;
diff --git a/lib/term.h b/lib/term.h
index 4c0c2c5..3b35ade 100644
--- a/lib/term.h
+++ b/lib/term.h
@@ -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)
{