From d78914317c0c6b55b655f49b55b445316670948f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 14 Oct 2026 13:47:12 +0100 Subject: [PATCH] Track window scrolling for damage. --- screen-redraw.c | 34 ++++++++++++++++++++++++++++++++++ tmux.h | 8 ++++++++ tty.c | 8 ++++++++ 3 files changed, 50 insertions(+) diff --git a/screen-redraw.c b/screen-redraw.c index 77b81132a..122b14eb5 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1111,6 +1111,7 @@ redraw_free_damage(struct window *w) free(rd); } w->damage_count = 0; + w->scroll_pending = 0; } /* Collapse all pending damage for a window into one rectangle. */ @@ -1209,6 +1210,39 @@ redraw_damage_window(struct window *w, u_int x, u_int y, u_int sx, u_int sy) redraw_apply_window_damage(w, x, y, sx, sy, 0); } +/* Record damage caused by terminal scrolling. */ +void +redraw_damage_scroll(struct window *w, u_int x, u_int y, u_int sx, u_int sy) +{ + if (!w->scroll_pending) { + w->scroll_generation++; + w->scroll_pending = 1; + } + redraw_apply_window_damage(w, x, y, sx, sy, REDRAW_DAMAGE_SCROLL); +} + +/* Remember whether this client used terminal scrolling for the damage. */ +void +redraw_scroll_result(struct tty *tty, const struct tty_ctx *ctx, int failed) +{ + struct window_pane *wp = ctx->arg; + struct window *w; + + if (wp == NULL) + return; + w = wp->window; + if (!w->scroll_pending) + return; + if (tty->scroll_window != w || + tty->scroll_generation != w->scroll_generation) { + tty->scroll_window = w; + tty->scroll_generation = w->scroll_generation; + tty->scroll_failed = 0; + } + if (failed) + tty->scroll_failed = 1; +} + /* Mark all cached redraw scenes as out of date. */ void redraw_invalidate_all_scenes(void) diff --git a/tmux.h b/tmux.h index 9962aef5f..0703af264 100644 --- a/tmux.h +++ b/tmux.h @@ -1479,6 +1479,8 @@ struct window { struct redraw_damages damage; u_int damage_count; + uint64_t scroll_generation; + int scroll_pending; struct menu_data *menu; u_int menu_last_px; @@ -1854,6 +1856,10 @@ struct tty { struct event key_timer; struct tty_key *key_tree; + struct window *scroll_window; + uint64_t scroll_generation; + int scroll_failed; + #ifdef ENABLE_IMAGES struct image_backend *image_backend; void *image_data; @@ -3645,6 +3651,8 @@ int redraw_client_has_window(struct client *, struct window *); void redraw_invalidate_scene(struct window *); void redraw_invalidate_all_scenes(void); void redraw_damage_window(struct window *, u_int, u_int, u_int, u_int); +void redraw_damage_scroll(struct window *, u_int, u_int, u_int, u_int); +void redraw_scroll_result(struct tty *, const struct tty_ctx *, int); void redraw_free_damage(struct window *); void redraw_client_damage(struct client *); int redraw_get_status_border_cell_type(struct redraw_span **, u_int); diff --git a/tty.c b/tty.c index 233deb491..8f2566b04 100644 --- a/tty.c +++ b/tty.c @@ -1682,10 +1682,12 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) !tty_term_has(tty->term, TTYC_RIN)) || ctx->sx == 1 || ctx->sy == 1) { + redraw_scroll_result(tty, ctx, 1); tty_redraw_region(tty, ctx); return; } + redraw_scroll_result(tty, ctx, 0); tty_default_attributes(tty, ctx->bg, &ctx->style_ctx); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); @@ -1710,10 +1712,12 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) !tty_term_has(tty->term, TTYC_CSR) || ctx->sx == 1 || ctx->sy == 1) { + redraw_scroll_result(tty, ctx, 1); tty_redraw_region(tty, ctx); return; } + redraw_scroll_result(tty, ctx, 0); tty_default_attributes(tty, ctx->bg, &ctx->style_ctx); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); @@ -1748,10 +1752,12 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx) !tty_term_has(tty->term, TTYC_CSR) || ctx->sx == 1 || ctx->sy == 1) { + redraw_scroll_result(tty, ctx, 1); tty_redraw_region(tty, ctx); return; } + redraw_scroll_result(tty, ctx, 0); tty_default_attributes(tty, ctx->bg, &ctx->style_ctx); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); @@ -1786,10 +1792,12 @@ tty_cmd_scrolldown(struct tty *tty, const struct tty_ctx *ctx) !tty_term_has(tty->term, TTYC_RIN)) || ctx->sx == 1 || ctx->sy == 1) { + redraw_scroll_result(tty, ctx, 1); tty_redraw_region(tty, ctx); return; } + redraw_scroll_result(tty, ctx, 0); tty_default_attributes(tty, ctx->bg, &ctx->style_ctx); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);