From 5ad552a55c12bfc7f13e548e9a6d979cfbc1f880 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 14 Oct 2026 11:29:50 +0100 Subject: [PATCH 1/4] Put #error back. --- tmux-image.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux-image.h b/tmux-image.h index 9616e739b..bb9735e0e 100644 --- a/tmux-image.h +++ b/tmux-image.h @@ -21,7 +21,7 @@ #define TMUX_IMAGE_H #ifdef ENABLE_IMAGES -//#error image support is not ready yet +#error image support is not ready yet struct grid; struct grid_cell; From 126dea8828ae33dd66b514a76b9960a5305eedc3 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 14 Oct 2026 08:33:19 +0000 Subject: [PATCH 2/4] Redraw when pixel sizes change. --- tmux.h | 4 ++-- tty-keys.c | 8 +++++--- tty.c | 10 ++++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/tmux.h b/tmux.h index aff0779ee..a52999a9e 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1459 2026/10/13 10:21:58 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1460 2026/10/14 08:33:19 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -2922,7 +2922,7 @@ void tty_cell(struct tty *, const struct grid_cell *, const struct tty_style_ctx *); int tty_init(struct tty *, struct client *); void tty_resize(struct tty *); -void tty_set_size(struct tty *, u_int, u_int, u_int, u_int); +int tty_set_size(struct tty *, u_int, u_int, u_int, u_int); void tty_invalidate(struct tty *); void tty_start_tty(struct tty *); void tty_send_requests(struct tty *); diff --git a/tty-keys.c b/tty-keys.c index b9ca2f019..f82d901ff 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tty-keys.c,v 1.217 2026/10/12 12:26:46 nicm Exp $ */ +/* $OpenBSD: tty-keys.c,v 1.218 2026/10/14 08:33:19 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -1914,7 +1914,8 @@ tty_keys_winsz(struct tty *tty, const char *buf, size_t len, size_t *size, return (0); /* Window size in characters. */ - tty_set_size(tty, sx, sy, tty->xpixel, tty->ypixel); + if (tty_set_size(tty, sx, sy, tty->xpixel, tty->ypixel)) + server_redraw_client(c); return (0); } else if (sscanf(tmp, "4;%u;%u", &ypixel, &xpixel) == 2) { *size = end + 1; @@ -1924,7 +1925,8 @@ tty_keys_winsz(struct tty *tty, const char *buf, size_t len, size_t *size, /* Window size in pixels. */ char_x = (xpixel && tty->sx) ? xpixel / tty->sx : 0; char_y = (ypixel && tty->sy) ? ypixel / tty->sy : 0; - tty_set_size(tty, tty->sx, tty->sy, char_x, char_y); + if (tty_set_size(tty, tty->sx, tty->sy, char_x, char_y)) + server_redraw_client(c); tty_invalidate(tty); tty->flags &= ~TTY_WINSIZEQUERY; diff --git a/tty.c b/tty.c index ad2853d42..b8531c7e6 100644 --- a/tty.c +++ b/tty.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tty.c,v 1.486 2026/10/12 10:39:05 nicm Exp $ */ +/* $OpenBSD: tty.c,v 1.487 2026/10/14 08:33:19 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -155,13 +155,19 @@ tty_resize(struct tty *tty) tty_invalidate(tty); } -void +int tty_set_size(struct tty *tty, u_int sx, u_int sy, u_int xpixel, u_int ypixel) { + if (tty->sx == sx && + tty->sy == sy && + tty->xpixel == xpixel && + tty->ypixel == ypixel) + return (0); tty->sx = sx; tty->sy = sy; tty->xpixel = xpixel; tty->ypixel = ypixel; + return (1); } static void From a5d7247602322ad85ced22627d55cb78bcd7680a Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 14 Oct 2026 08:33:19 +0000 Subject: [PATCH 3/4] Redraw when pixel sizes change. --- tmux.h | 2 +- tty-keys.c | 2 +- tty.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tmux.h b/tmux.h index 7c86555e1..5e1c8838b 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1459 2026/10/13 10:21:58 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1460 2026/10/14 08:33:19 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott diff --git a/tty-keys.c b/tty-keys.c index 122786e1d..f82d901ff 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tty-keys.c,v 1.217 2026/10/12 12:26:46 nicm Exp $ */ +/* $OpenBSD: tty-keys.c,v 1.218 2026/10/14 08:33:19 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott diff --git a/tty.c b/tty.c index 6251b991d..0f2e35a52 100644 --- a/tty.c +++ b/tty.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tty.c,v 1.486 2026/10/12 10:39:05 nicm Exp $ */ +/* $OpenBSD: tty.c,v 1.487 2026/10/14 08:33:19 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott From 93e55bb86dfd1fe404cf8e40dbad44e137ed0cea Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 14 Oct 2026 10:34:14 +0000 Subject: [PATCH 4/4] Do redraw as two phases for text and images. --- screen-redraw.c | 217 +++++++++++++++++++++++++++++------------------- tmux.h | 4 +- 2 files changed, 134 insertions(+), 87 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index c68b35478..38a56b3ca 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: screen-redraw.c,v 1.163 2026/10/02 12:48:52 nicm Exp $ */ +/* $OpenBSD: screen-redraw.c,v 1.164 2026/10/14 10:34:14 nicm Exp $ */ /* * Copyright (c) 2026 Nicholas Marriott @@ -72,6 +72,13 @@ enum redraw_span_type { }; #define REDRAW_SPAN_TYPES 7 +/* Draw phases. */ +enum redraw_phase { + REDRAW_TEXT, + REDRAW_IMAGES +}; +#define REDRAW_PHASE_COUNT 2 + /* Border connections to adjacent cells. */ #define REDRAW_BORDER_L 0x1 #define REDRAW_BORDER_R 0x2 @@ -1503,31 +1510,35 @@ redraw_draw_menu_span(struct redraw_draw_ctx *dctx, /* Draw a span. */ static void redraw_draw_span(struct redraw_draw_ctx *dctx, struct redraw_span *span, - u_int y) + u_int y, enum redraw_phase phase) { struct redraw_span_data *data = &span->data; enum redraw_span_type type = data->type; + u_int width = span->width; if (type == REDRAW_SPAN_STATUS && ~data->st.wp->flags & PANE_NEWSTATUS) return; + if (phase != REDRAW_TEXT && type != REDRAW_SPAN_PANE) + return; switch (span->data.type) { case REDRAW_SPAN_PANE: - redraw_draw_pane_span(dctx, span, span->x, y, span->width); + if (phase == REDRAW_TEXT) + redraw_draw_pane_span(dctx, span, span->x, y, width); break; case REDRAW_SPAN_BORDER: case REDRAW_SPAN_EMPTY: case REDRAW_SPAN_OUTSIDE: - redraw_draw_border_span(dctx, span, span->x, y, span->width); + redraw_draw_border_span(dctx, span, span->x, y, width); break; case REDRAW_SPAN_STATUS: - redraw_draw_status_span(dctx, span, span->x, y, span->width); + redraw_draw_status_span(dctx, span, span->x, y, width); break; case REDRAW_SPAN_SCROLLBAR: - redraw_draw_scrollbar_span(dctx, span, span->x, y, span->width); + redraw_draw_scrollbar_span(dctx, span, span->x, y, width); break; case REDRAW_SPAN_MENU: - redraw_draw_menu_span(dctx, span, span->x, y, span->width); + redraw_draw_menu_span(dctx, span, span->x, y, width); break; } } @@ -1541,6 +1552,7 @@ redraw_draw_pane_lines(struct redraw_draw_ctx *dctx, struct window_pane *wp, struct redraw_line *line; struct redraw_spans *spans; struct redraw_span *span; + enum redraw_phase phase; u_int cy; int y, top, bottom; @@ -1553,29 +1565,65 @@ redraw_draw_pane_lines(struct redraw_draw_ctx *dctx, struct window_pane *wp, if (bottom > (int)scene->sy) bottom = scene->sy; - for (y = top; y < bottom; y++) { - line = &scene->lines[y]; - if (dctx->flags & REDRAW_STATUS_TOP) - cy = dctx->status_lines + y; - else - cy = y; - if (flags & REDRAW_PANE) { - spans = &line->spans[REDRAW_SPAN_PANE]; - TAILQ_FOREACH(span, spans, entry) { - if (span->data.p.wp == wp) - redraw_draw_span(dctx, span, cy); - } - } - if (flags & REDRAW_PANE_SCROLLBAR) { - spans = &line->spans[REDRAW_SPAN_SCROLLBAR]; - TAILQ_FOREACH(span, spans, entry) { - if (span->data.sb.wp == wp) - redraw_draw_span(dctx, span, cy); + /* Draw each phase. */ + for (phase = 0; phase < REDRAW_PHASE_COUNT; phase++) { + for (y = top; y < bottom; y++) { + line = &scene->lines[y]; + if (dctx->flags & REDRAW_STATUS_TOP) + cy = dctx->status_lines + y; + else + cy = y; + if (flags & REDRAW_PANE) { + spans = &line->spans[REDRAW_SPAN_PANE]; + TAILQ_FOREACH(span, spans, entry) { + if (span->data.p.wp != wp) + continue; + redraw_draw_span(dctx, span, cy, phase); + } + } + if (phase == REDRAW_TEXT && + (flags & REDRAW_PANE_SCROLLBAR)) { + spans = &line->spans[REDRAW_SPAN_SCROLLBAR]; + TAILQ_FOREACH(span, spans, entry) { + if (span->data.sb.wp != wp) + continue; + redraw_draw_span(dctx, span, cy, phase); + } } } } } +/* Return whether to draw a span type in this phase for these flags. */ +static int +redraw_should_draw(enum redraw_span_type type, int flags, + enum redraw_phase phase) +{ + if (phase != REDRAW_TEXT && type != REDRAW_SPAN_PANE) + return (0); + if (REDRAW_IS_ALL(flags)) + return (1); + + switch (type) { + case REDRAW_SPAN_PANE: + return (flags & REDRAW_PANE); + case REDRAW_SPAN_OUTSIDE: + return (flags & REDRAW_OUTSIDE); + case REDRAW_SPAN_EMPTY: + return (flags & REDRAW_EMPTY); + case REDRAW_SPAN_BORDER: + return (flags & REDRAW_PANE_BORDER); + case REDRAW_SPAN_STATUS: + return (flags & REDRAW_PANE_STATUS); + case REDRAW_SPAN_SCROLLBAR: + return (flags & REDRAW_PANE_SCROLLBAR); + case REDRAW_SPAN_MENU: + return (flags & REDRAW_MENU); + default: + return (0); + } +} + /* Draw lines. */ static void redraw_draw_lines(struct redraw_draw_ctx *dctx, int flags) @@ -1584,52 +1632,24 @@ redraw_draw_lines(struct redraw_draw_ctx *dctx, int flags) struct redraw_line *line; struct redraw_spans *spans; struct redraw_span *span; + enum redraw_phase phase; u_int y, cy, type; - for (y = 0; y < scene->sy; y++) { - line = &scene->lines[y]; - if (dctx->flags & REDRAW_STATUS_TOP) - cy = dctx->status_lines + y; - else - cy = y; - for (type = 0; type < REDRAW_SPAN_TYPES; type++) { - if (!REDRAW_IS_ALL(flags)) { - switch (type) { - case REDRAW_SPAN_PANE: - if (~flags & REDRAW_PANE) - continue; - break; - case REDRAW_SPAN_OUTSIDE: - if (~flags & REDRAW_OUTSIDE) - continue; - break; - case REDRAW_SPAN_EMPTY: - if (~flags & REDRAW_EMPTY) - continue; - break; - case REDRAW_SPAN_BORDER: - if (~flags & REDRAW_PANE_BORDER) - continue; - break; - case REDRAW_SPAN_STATUS: - if (~flags & REDRAW_PANE_STATUS) - continue; - break; - case REDRAW_SPAN_SCROLLBAR: - if (~flags & REDRAW_PANE_SCROLLBAR) - continue; - break; - case REDRAW_SPAN_MENU: - if (~flags & REDRAW_MENU) - continue; - break; - default: + /* Draw each phase. */ + for (phase = 0; phase < REDRAW_PHASE_COUNT; phase++) { + for (y = 0; y < scene->sy; y++) { + line = &scene->lines[y]; + if (dctx->flags & REDRAW_STATUS_TOP) + cy = dctx->status_lines + y; + else + cy = y; + for (type = 0; type < REDRAW_SPAN_TYPES; type++) { + if (!redraw_should_draw(type, flags, phase)) continue; - } + spans = &line->spans[type]; + TAILQ_FOREACH(span, spans, entry) + redraw_draw_span(dctx, span, cy, phase); } - spans = &line->spans[type]; - TAILQ_FOREACH(span, spans, entry) - redraw_draw_span(dctx, span, cy); } } } @@ -1650,7 +1670,7 @@ redraw_draw_menu_lines(struct redraw_draw_ctx *dctx) else cy = y; TAILQ_FOREACH(span, &line->spans[REDRAW_SPAN_MENU], entry) - redraw_draw_span(dctx, span, cy); + redraw_draw_span(dctx, span, cy, REDRAW_TEXT); } } @@ -2053,6 +2073,7 @@ redraw_draw_damage_rectangle(struct redraw_draw_ctx *dctx, u_int x, u_int y, struct redraw_line *line; struct redraw_spans *spans; struct redraw_span *span; + enum redraw_phase phase; u_int cy, yy, type; if (x >= scene->sx || y >= scene->sy) @@ -2064,29 +2085,55 @@ redraw_draw_damage_rectangle(struct redraw_draw_ctx *dctx, u_int x, u_int y, if (sx == 0 || sy == 0) return; + /* Draw each phase in the damaged spans. */ + for (phase = 0; phase < REDRAW_PHASE_COUNT; phase++) { + for (yy = y; yy < y + sy; yy++) { + line = &scene->lines[yy]; + if (dctx->flags & REDRAW_STATUS_TOP) + cy = dctx->status_lines + yy; + else + cy = yy; + for (type = 0; type < REDRAW_SPAN_TYPES; type++) { + if (phase != REDRAW_TEXT && + type != REDRAW_SPAN_PANE) + continue; + if (type == REDRAW_SPAN_STATUS) + continue; + spans = &line->spans[type]; + TAILQ_FOREACH(span, spans, entry) { + if (span->x >= x + sx) + continue; + if (span->x + span->width <= x) + continue; + redraw_draw_span(dctx, span, cy, phase); + } + } + } + } + + /* Draw prompts and pane status lines last. */ for (yy = y; yy < y + sy; yy++) { line = &scene->lines[yy]; if (dctx->flags & REDRAW_STATUS_TOP) cy = dctx->status_lines + yy; else cy = yy; - for (type = 0; type < REDRAW_SPAN_TYPES; type++) { - spans = &line->spans[type]; - TAILQ_FOREACH(span, spans, entry) { - if (span->x >= x + sx) - continue; - if (span->x + span->width <= x) - continue; - if (type == REDRAW_SPAN_STATUS) { - redraw_damage_refresh_status(dctx, - span->data.st.wp); - } - redraw_draw_span(dctx, span, cy); - if (type == REDRAW_SPAN_PANE) { - redraw_damage_draw_pane_prompt(dctx, - span, cy); - } - } + spans = &line->spans[REDRAW_SPAN_PANE]; + TAILQ_FOREACH(span, spans, entry) { + if (span->x >= x + sx) + continue; + if (span->x + span->width <= x) + continue; + redraw_damage_draw_pane_prompt(dctx, span, cy); + } + spans = &line->spans[REDRAW_SPAN_STATUS]; + TAILQ_FOREACH(span, spans, entry) { + if (span->x >= x + sx) + continue; + if (span->x + span->width <= x) + continue; + redraw_damage_refresh_status(dctx, span->data.st.wp); + redraw_draw_span(dctx, span, cy, REDRAW_TEXT); } } } diff --git a/tmux.h b/tmux.h index a52999a9e..c42115aef 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1460 2026/10/14 08:33:19 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1461 2026/10/14 10:34:14 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -2328,7 +2328,7 @@ struct client { int references; - int theme_colours[COLOUR_THEME_COUNT]; + int theme_colours[COLOUR_THEME_COUNT]; void *pan_window; u_int pan_ox;