From bb0af8b7c806733b3e39696d96f5b7c778fd6d97 Mon Sep 17 00:00:00 2001 From: "jabber.developer2" Date: Fri, 29 May 2026 08:54:30 +0300 Subject: [PATCH] refactor(ui): centralize physical paint through prof_doupdate() Upstream's "guard terminal writes while suspended" fix and commit 2 of this branch both work by sprinkling `if (!isendwin())` (or `!is_suspended && !isendwin()`) guards around every doupdate() reachable during a suspended session. That keeps isendwin() a valid signal but turns the no-stray-write invariant into a whitelist: every new doupdate / refresh / wrefresh added later in src/ has to remember the guard, and the original bug class came from exactly such an oversight in _inp_write. Introduce a single primitive, prof_doupdate(), that flushes only when not suspended (via the existing _ui_redraw_suspended() helper). Replace every direct doupdate() in src/ui/inputwin.c (inp_get_line, inp_get_password, _inp_write) and the trailing doupdate in ui_update with the wrapper, collapsing their inline guards. ui_suspend() now flushes via prof_doupdate() before flipping ui_suspended, so upstream's pre-endwin flush is preserved. The flag-based gate in ui_update / ui_resize / ui_redraw is kept as belt-and-suspenders: even if a future raw doupdate slips in elsewhere, ui_update has not been refreshing the virtual screen, so the blit finds stale content rather than a fresh status-bar clock or chat line. --- src/ui/core.c | 15 ++++++++++++--- src/ui/inputwin.c | 14 +++----------- src/ui/ui.h | 4 ++++ tests/unittests/ui/stub_ui.c | 4 ++++ 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/ui/core.c b/src/ui/core.c index 93d240cd..b9f0fdeb 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -148,7 +148,7 @@ ui_update(void) title_bar_update_virtual(); status_bar_draw(); inp_put_back(); - doupdate(); + prof_doupdate(); if (perform_resize) { perform_resize = FALSE; @@ -189,9 +189,10 @@ ui_reset_idle_time(void) void ui_suspend(void) { - ui_suspended = TRUE; inp_suspend(); - doupdate(); + // Flush before flipping the flag (prof_doupdate skips while suspended). + prof_doupdate(); + ui_suspended = TRUE; endwin(); } @@ -219,6 +220,14 @@ ui_flash(void) } } +void +prof_doupdate(void) +{ + if (!_ui_redraw_suspended()) { + doupdate(); + } +} + void ui_resize(void) { diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c index fd8a8835..cea4290c 100644 --- a/src/ui/inputwin.c +++ b/src/ui/inputwin.c @@ -317,10 +317,7 @@ inp_get_line(void) werase(inp_win); wmove(inp_win, 0, 0); _inp_win_update_virtual(); - // Don't write to the terminal while suspended (external editor active). - if (!is_suspended && !isendwin()) { - doupdate(); - } + prof_doupdate(); char* line = NULL; while (!line) { line = inp_readline(); @@ -351,10 +348,7 @@ inp_get_password(void) werase(inp_win); wmove(inp_win, 0, 0); _inp_win_update_virtual(); - // Don't write to the terminal while suspended (external editor active). - if (!is_suspended && !isendwin()) { - doupdate(); - } + prof_doupdate(); char* password = NULL; get_password = TRUE; while (!password) { @@ -479,9 +473,7 @@ _inp_write(char* line, int offset) _inp_win_handle_scroll(); _inp_win_update_virtual(); - if (!isendwin()) { - doupdate(); - } + prof_doupdate(); } static int diff --git a/src/ui/ui.h b/src/ui/ui.h index 4622ca1c..5134f6d4 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -43,6 +43,10 @@ void ui_load_colours(void); void ui_update(void); void ui_redraw(void); void ui_resize(void); +// Centralised physical-paint primitive: flushes the virtual screen unless the +// UI is suspended (external editor active) or the screen has been closed. Use +// this instead of raw doupdate() in any path reachable while suspended. +void prof_doupdate(void); void ui_focus_win(ProfWin* window); void ui_sigwinch_handler(int sig); void ui_handle_otr_error(const char* const barejid, const char* const message); diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index ad338403..7ac85dbe 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -85,6 +85,10 @@ void ui_resize(void) { } +void +prof_doupdate(void) +{ +} void ui_focus_win(ProfWin* win)