diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index cd631e914..b886255f3 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-refresh-client.c,v 1.56 2026/10/09 13:12:14 nicm Exp $ */ +/* $OpenBSD: cmd-refresh-client.c,v 1.57 2026/10/26 10:14:59 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -35,8 +35,8 @@ const struct cmd_entry cmd_refresh_client_entry = { .description = "Refresh or resize a client.", .alias = "refresh", - .args = { "A:B:cC:Df:r:F:lLRSt:U", 0, 1, NULL }, - .usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] " + .args = { "A:B:cC:Df:r:F:lLqRSt:U", 0, 1, NULL }, + .usage = "[-cDlLqRSU] [-A pane:state] [-B name:what:format] " "[-C XxY] [-f flags] [-r pane:report] " CMD_TARGET_CLIENT_USAGE " [adjustment]", @@ -240,6 +240,11 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_NORMAL); } + if (args_has(args, 'q')) { + tty_size_query(&tc->tty); + return (CMD_RETURN_NORMAL); + } + if (args_has(args, 'F')) /* -F is an alias for -f */ server_client_set_flags(tc, args_get(args, 'F')); if (args_has(args, 'f')) diff --git a/server-client.c b/server-client.c index 3c314bfdf..a9dd32ec8 100644 --- a/server-client.c +++ b/server-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server-client.c,v 1.527 2026/10/23 06:45:15 nicm Exp $ */ +/* $OpenBSD: server-client.c,v 1.528 2026/10/26 10:14:59 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -338,6 +338,36 @@ server_client_fire_resized(struct client *c, u_int old_sx, u_int old_sy) events_fire("client-resized", ep); } +/* Recalculate sizes and notify a resized client. */ +static void +server_client_apply_resize(struct client *c, u_int old_sx, u_int old_sy) +{ + if (c->session != NULL) { + recalculate_sizes(); + server_redraw_client(c); + server_client_fire_resized(c, old_sx, old_sy); + } +} + +/* Apply a new reported size. */ +void +server_client_size_changed(struct client *c, u_int sx, u_int sy) +{ + u_int old_sx = c->tty.sx, old_sy = c->tty.sy; + + if (c->flags & CLIENT_CONTROL) + return; + if (sx == 0 || sy == 0 || (sx == old_sx && sy == old_sy)) + return; + + log_debug("%s: reported size %ux%u (was %ux%u)", c->name, sx, sy, + old_sx, old_sy); + server_client_update_latest(c); + tty_set_size(&c->tty, sx, sy, c->tty.xpixel, c->tty.ypixel); + tty_invalidate(&c->tty); + server_client_apply_resize(c, old_sx, old_sy); +} + /* Set client session. */ void server_client_set_session(struct client *c, struct session *s) @@ -2699,10 +2729,7 @@ server_client_dispatch(struct imsg *imsg, void *arg) old_sy = c->tty.sy; tty_resize(&c->tty); tty_repeat_requests(&c->tty, 0); - recalculate_sizes(); - server_redraw_client(c); - if (c->session != NULL) - server_client_fire_resized(c, old_sx, old_sy); + server_client_apply_resize(c, old_sx, old_sy); break; case MSG_EXITING: if (datalen != 0) diff --git a/tmux.1 b/tmux.1 index 786de9acd..5554d28a5 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tmux.1,v 1.1191 2026/10/20 06:45:56 nicm Exp $ +.\" $OpenBSD: tmux.1,v 1.1192 2026/10/26 10:14:59 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -14,7 +14,7 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 20 2026 $ +.Dd $Mdocdate: October 26 2026 $ .Dt TMUX 1 .Os .Sh NAME @@ -1448,7 +1448,7 @@ and sets an environment variable for the newly created session; it may be specified multiple times. .Tg refresh .It Xo Ic refresh\-client -.Op Fl cDlLRSU +.Op Fl cDlLqRSU .Op Fl A Ar pane:state .Op Fl B Ar name:what:format .Op Fl C Ar size @@ -1575,6 +1575,9 @@ requests the clipboard from the client using the .Xr xterm 1 escape sequence and stores it in a new paste buffer. .Pp +.Fl q +queries the client terminal for its size. +.Pp .Fl L , .Fl R , .Fl U diff --git a/tmux.h b/tmux.h index 3a062db61..98f456a9e 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1470 2026/10/23 06:45:15 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1471 2026/10/26 10:14:59 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -1759,6 +1759,9 @@ struct tty_style_ctx { struct hyperlinks *hyperlinks; }; +/* Maximum reported terminal size. */ +#define CLIENT_MAX_TERM_SIZE 10000 + /* Client terminal. */ struct tty { struct client *client; @@ -1824,6 +1827,8 @@ struct tty { #define TTY_BRACKETPASTE 0x8000 #define TTY_HAVESYNC 0x10000 #define TTY_HAVEKITTYGRAPHICS 0x20000 +#define TTY_WINSZPIXELS 0x40000 +#define TTY_WINSZAPPLY 0x80000 #define TTY_ALL_REQUEST_FLAGS \ (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA|TTY_HAVESYNC|TTY_HAVEKITTYGRAPHICS) int flags; @@ -2957,6 +2962,7 @@ void tty_cell(struct tty *, const struct grid_cell *, int tty_init(struct tty *, struct client *); void tty_resize(struct tty *); int tty_set_size(struct tty *, u_int, u_int, u_int, u_int); +void tty_size_query(struct tty *); void tty_invalidate(struct tty *); void tty_start_tty(struct tty *); void tty_send_requests(struct tty *); @@ -3337,6 +3343,7 @@ void server_client_exec(struct client *, const char *); void server_client_loop(void); const char *server_client_get_cwd(struct client *, struct session *); void server_client_set_flags(struct client *, const char *); +void server_client_size_changed(struct client *, u_int, u_int); const char *server_client_get_flags(struct client *); void server_client_remove_pane(struct window_pane *); void server_client_print(struct client *, int, struct evbuffer *); diff --git a/tty-keys.c b/tty-keys.c index 91852ba04..9bc664aca 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tty-keys.c,v 1.221 2026/10/22 07:16:40 nicm Exp $ */ +/* $OpenBSD: tty-keys.c,v 1.222 2026/10/26 10:14:59 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -937,8 +937,8 @@ partial_key: if (delay < 500) delay = 500; } - if (tty->flags & (TTY_WAITFG|TTY_WAITBG) || - tty->flags & (TTY_OSC52QUERY|TTY_WINSZQUERY) || + if (tty->flags & (TTY_WAITFG|TTY_WAITBG|TTY_OSC52QUERY) || + tty->flags & (TTY_WINSZQUERY|TTY_WINSZPIXELS) || (tty->flags & TTY_ALL_REQUEST_FLAGS) != TTY_ALL_REQUEST_FLAGS || !TAILQ_EMPTY(&c->input_requests)) { log_debug("%s: increasing delay (active query)", c->name); @@ -1875,11 +1875,12 @@ tty_keys_winsz(struct tty *tty, const char *buf, size_t len, size_t *size, size_t end; char tmp[64]; u_int sx, sy, xpixel, ypixel, char_x, char_y; + int resize; *size = 0; /* If we did not request this, ignore it. */ - if (!(tty->flags & TTY_WINSZQUERY)) + if (!(tty->flags & (TTY_WINSZQUERY|TTY_WINSZPIXELS))) return (-1); /* First two bytes are always \033[. */ @@ -1892,10 +1893,7 @@ tty_keys_winsz(struct tty *tty, const char *buf, size_t len, size_t *size, if (len == 2) return (1); - /* - * Stop at either 't' or anything that isn't a - * number or ';'. - */ + /* Stop at either 't' or anything that isn't a number or ';'. */ for (end = 2; end < len && end != sizeof tmp; end++) { if (buf[end] == 't') break; @@ -1913,28 +1911,42 @@ tty_keys_winsz(struct tty *tty, const char *buf, size_t len, size_t *size, /* Try to parse the window size sequence. */ if (sscanf(tmp, "8;%u;%u", &sy, &sx) == 2) { + if (!(tty->flags & TTY_WINSZQUERY)) + return (-1); *size = end + 1; if (!apply) return (0); - /* Window size in characters. */ - if (tty_set_size(tty, sx, sy, tty->xpixel, tty->ypixel)) + resize = (tty->flags & TTY_WINSZAPPLY); + tty->flags &= ~(TTY_WINSZQUERY|TTY_WINSZAPPLY); + + if (sx == 0 || + sy == 0 || + sx > CLIENT_MAX_TERM_SIZE || + sy > CLIENT_MAX_TERM_SIZE) { + log_debug("%s: ignoring reported size %ux%u", + c->name, sx, sy); + return (0); + } + if (resize) + server_client_size_changed(c, sx, sy); + else 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) { + if (!(tty->flags & TTY_WINSZPIXELS)) + return (-1); *size = end + 1; if (!apply) return (0); + tty->flags &= ~TTY_WINSZPIXELS; - /* Window size in pixels. */ char_x = (xpixel && tty->sx) ? xpixel / tty->sx : 0; char_y = (ypixel && tty->sy) ? ypixel / tty->sy : 0; if (tty_set_size(tty, tty->sx, tty->sy, char_x, char_y)) server_redraw_client(c); tty_invalidate(tty); recalculate_sizes(); - - tty->flags &= ~TTY_WINSZQUERY; return (0); } diff --git a/tty.c b/tty.c index ea18af935..7c531dcea 100644 --- a/tty.c +++ b/tty.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tty.c,v 1.496 2026/10/22 07:16:40 nicm Exp $ */ +/* $OpenBSD: tty.c,v 1.497 2026/10/26 10:14:59 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -38,6 +38,7 @@ static int tty_log_fd = -1; static void tty_start_timer_callback(int, short, void *); static void tty_start_start_timer(struct tty *); static void tty_clipboard_query_callback(int, short, void *); +static void tty_send_size_query(struct tty *, int); static void tty_set_italics(struct tty *); static int tty_try_colour(struct tty *, int, const char *); static void tty_force_cursor_colour(struct tty *, int); @@ -116,6 +117,16 @@ tty_init(struct tty *tty, struct client *c) return (0); } +static void +tty_send_size_query(struct tty *tty, int apply) +{ + tty_puts(tty, "\033[18t\033[14t"); + tty->flags |= (TTY_WINSZQUERY|TTY_WINSZPIXELS); + if (apply) + tty->flags |= TTY_WINSZAPPLY; + tty_start_start_timer(tty); +} + void tty_resize(struct tty *tty) { @@ -139,12 +150,9 @@ tty_resize(struct tty *tty) if ((xpixel == 0 || ypixel == 0) && (tty->flags & TTY_STARTED) && - !(tty->flags & TTY_WINSZQUERY) && - (tty->term->flags & TERM_VT100LIKE)) { - tty_puts(tty, "\033[18t\033[14t"); - tty->flags |= TTY_WINSZQUERY; - tty_start_start_timer(tty); - } + !(tty->flags & (TTY_WINSZQUERY|TTY_WINSZPIXELS)) && + (tty->term->flags & TERM_VT100LIKE)) + tty_send_size_query(tty, 0); } else { sx = 80; sy = 24; @@ -322,7 +330,11 @@ tty_start_timer_callback(__unused int fd, __unused short events, void *data) tty_update_features(tty); tty->flags |= TTY_ALL_REQUEST_FLAGS; - tty->flags &= ~(TTY_WAITBG|TTY_WAITFG|TTY_WINSZQUERY); + if (tty->flags & TTY_WINSZQUERY) + log_debug("%s: size query timed out", c->name); + + tty->flags &= ~(TTY_WAITBG|TTY_WAITFG); + tty->flags &= ~(TTY_WINSZQUERY|TTY_WINSZPIXELS|TTY_WINSZAPPLY); } static void @@ -470,7 +482,7 @@ tty_stop_tty(struct tty *tty) evtimer_del(&tty->start_timer); evtimer_del(&tty->clipboard_timer); - tty->flags &= ~TTY_WINSZQUERY; + tty->flags &= ~(TTY_WINSZQUERY|TTY_WINSZPIXELS|TTY_WINSZAPPLY); event_del(&tty->timer); tty->flags &= ~TTY_BLOCK; @@ -2990,6 +3002,19 @@ tty_clipboard_query(struct tty *tty) } } +void +tty_size_query(struct tty *tty) +{ + if (!(tty->flags & TTY_STARTED) || + tty->out == NULL || + tty->client->flags & CLIENT_CONTROL || + !(tty->term->flags & TERM_VT100LIKE) || + tty->flags & (TTY_WINSZQUERY|TTY_WINSZPIXELS)) + return; + log_debug("%s: querying terminal size", tty->client->name); + tty_send_size_query(tty, 1); +} + void tty_set_progress_bar(struct tty *tty, struct progress_bar *pb) {