From f41b983e042774453b9a62e76b60b9dca12c2237 Mon Sep 17 00:00:00 2001 From: Michael Grant Date: Tue, 25 Aug 2026 10:49:46 +0100 Subject: [PATCH] screen-write, tty, popup, window: fix remaining untested damage gaps Two more fixes based on Michael K. Darling's branch (github.com/darlingm/tmux, pr5516-regression-fixes), taken as-is - neither is caught by any test in regress/ yet, found by code review rather than a failing test: - screen_write_redraw_cb() (screen-write.c) reported damage for only a single row, using ttyctx->ocy as if every fallback redraw were a single-cell write. But it's also the callback for cases that can legitimately span many rows - a large scroll-region fallback (tty_redraw_region(), when tty_large_region() or the pane is obscured), a full reset, and entering/leaving the alternate screen. For those, only the top row of the affected area ever got marked as damaged, leaving the rest stale until an unrelated redraw happened to cover it. Changed the shared tty_ctx_redraw_cb typedef to carry (py, ny) - the actual row range - and updated every call site to pass the range it actually knows about, instead of hardcoding a single row. - window_pane_redraw_floating() (window.c) never refreshed the status line after moving/resizing a floating pane, so a status format depending on that pane's geometry (e.g. #{pane_width}) could go stale until an unrelated status refresh happened. Added a server_status_window(w) call. Also confirmed the window_pane_scrollbar_intersects() parameter naming cleanup (loop -> wp) discussed earlier was already done in an earlier "Cleanup." commit - nothing left to do there. All 9 tests in regress/ plus the two pre-existing floating-pane tests plus a further 19-test sweep of redraw/tty/input/sync-adjacent regress tests pass. Co-Authored-By: Michael K. Darling Co-Authored-By: Claude Sonnet 5 --- popup.c | 3 ++- screen-write.c | 19 ++++++++----------- tmux.h | 2 +- tty.c | 6 +++--- window.c | 3 +++ 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/popup.c b/popup.c index a0a3cfbde..350ddd3c7 100644 --- a/popup.c +++ b/popup.c @@ -135,7 +135,8 @@ popup_reapply_styles(struct popup_data *pd) } static void -popup_redraw_cb(const struct tty_ctx *ttyctx) +popup_redraw_cb(const struct tty_ctx *ttyctx, __unused u_int py, + __unused u_int ny) { struct popup_data *pd = ttyctx->arg; diff --git a/screen-write.c b/screen-write.c index 5d39da4b7..e3dbef05d 100644 --- a/screen-write.c +++ b/screen-write.c @@ -122,21 +122,18 @@ screen_write_set_cursor(struct screen_write_ctx *ctx, int cx, int cy) /* * Called when a write could not be applied directly to the terminal and - * needs a redraw instead. Report damage for just the row the write was - * targeting rather than the whole pane - ttyctx->ocy is the cursor row - * within the pane's own screen at the point the write was issued, and - * wp->yoff is already adjusted past any top pane-border-status row, so - * wp->yoff + ocy is the correct window-coordinate row. + * needs a redraw instead. Report damage for the requested rows. wp->yoff is + * already adjusted past any top pane-border-status row, so wp->yoff + py is + * the correct window-coordinate row. */ static void -screen_write_redraw_cb(const struct tty_ctx *ttyctx) +screen_write_redraw_cb(const struct tty_ctx *ttyctx, u_int py, u_int ny) { struct window_pane *wp = ttyctx->arg; if (wp == NULL) return; - redraw_damage_window(wp->window, wp->xoff, wp->yoff + ttyctx->ocy, - wp->sx, 1); + redraw_damage_window(wp->window, wp->xoff, wp->yoff + py, wp->sx, ny); } /* Update context for client. */ @@ -2164,7 +2161,7 @@ screen_write_fullredraw(struct screen_write_ctx *ctx) screen_write_initctx(ctx, &ttyctx, 1, 0); if (ttyctx.redraw_cb != NULL) - ttyctx.redraw_cb(&ttyctx); + ttyctx.redraw_cb(&ttyctx, 0, ttyctx.sy); } /* Trim collected items. */ @@ -3184,7 +3181,7 @@ screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc, screen_write_initctx(ctx, &ttyctx, 1, 0); if (ttyctx.redraw_cb != NULL) - ttyctx.redraw_cb(&ttyctx); + ttyctx.redraw_cb(&ttyctx, 0, ttyctx.sy); } /* Turn alternate screen off. */ @@ -3209,5 +3206,5 @@ screen_write_alternateoff(struct screen_write_ctx *ctx, struct grid_cell *gc, screen_write_initctx(ctx, &ttyctx, 1, 0); if (ttyctx.redraw_cb != NULL) - ttyctx.redraw_cb(&ttyctx); + ttyctx.redraw_cb(&ttyctx, 0, ttyctx.sy); } diff --git a/tmux.h b/tmux.h index 0cd008bbd..b64373b0b 100644 --- a/tmux.h +++ b/tmux.h @@ -1844,7 +1844,7 @@ struct tty { }; /* Terminal command context. */ -typedef void (*tty_ctx_redraw_cb)(const struct tty_ctx *); +typedef void (*tty_ctx_redraw_cb)(const struct tty_ctx *, u_int, u_int); typedef int (*tty_ctx_set_client_cb)(struct tty_ctx *, struct client *); struct tty_ctx { struct screen *s; diff --git a/tty.c b/tty.c index e8a60c68d..4af996ca7 100644 --- a/tty.c +++ b/tty.c @@ -1104,7 +1104,7 @@ tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx) */ if (tty_large_region(tty, ctx) || ctx->flags & TTY_CTX_PANE_OBSCURED) { log_debug("%s: %s large region redraw", __func__, c->name); - ctx->redraw_cb(ctx); + ctx->redraw_cb(ctx, ctx->orupper, ctx->orlower - ctx->orupper + 1); return; } @@ -2016,7 +2016,7 @@ tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx) if ((ctx->flags & TTY_CTX_WINDOW_BIGGER) || c->overlay_check != NULL) { - ctx->redraw_cb(ctx); + ctx->redraw_cb(ctx, 0, ctx->sy); return; } @@ -2098,7 +2098,7 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx) tty->cy == tty->rlower) tty_draw_pane(tty, ctx, ctx->ocy); else - ctx->redraw_cb(ctx); + ctx->redraw_cb(ctx, ctx->ocy, 1); return; } diff --git a/window.c b/window.c index d5aed25c7..393446e4e 100644 --- a/window.c +++ b/window.c @@ -3009,4 +3009,7 @@ window_pane_redraw_floating(struct window *w, struct window_pane *wp, wp->yoff, wp->sx, wp->sy)) loop->flags |= PANE_REDRAWSCROLLBAR; } + + /* Session status formats may depend on the pane's new geometry. */ + server_status_window(w); }