From af36d7c4300d1fc12facf166948294049b4bd9a8 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 1 Sep 2025 07:53:49 +0000 Subject: [PATCH 1/3] Ensure break-pane -P prints when only one pane is left. From Chaoyi Yin in GitHub issue 4615. --- cmd-break-pane.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index a5582e46..add3743b 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -85,7 +85,10 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) options_set_number(w->options, "automatic-rename", 0); } server_unlink_window(src_s, wl); - return (CMD_RETURN_NORMAL); + wl = winlink_find_by_window(&dst_s->windows, w); + if (wl == NULL) + return (CMD_RETURN_ERROR); + goto out; } if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) { cmdq_error(item, "index in use: %d", idx); @@ -132,6 +135,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) if (src_s != dst_s) server_status_session_group(dst_s); +out: if (args_has(args, 'P')) { if ((template = args_get(args, 'F')) == NULL) template = BREAK_PANE_TEMPLATE; From cfb906a0ceb18846ac52561c5def88d155c5e54b Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 1 Sep 2025 07:58:09 +0000 Subject: [PATCH 2/3] Increase the escape delay when waiting for an RGB response no matter when it is triggered (they can also be sent on resize). GitHub issue 4569. --- server-client.c | 4 ++-- tty-keys.c | 7 ++++--- tty.c | 46 ++++++++++++++++++++++++++++++++-------------- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/server-client.c b/server-client.c index 6a82900a..67311458 100644 --- a/server-client.c +++ b/server-client.c @@ -3358,7 +3358,7 @@ server_client_dispatch(struct imsg *imsg, void *arg) break; server_client_update_latest(c); tty_resize(&c->tty); - tty_repeat_requests(&c->tty); + tty_repeat_requests(&c->tty, 0); recalculate_sizes(); if (c->overlay_resize == NULL) server_client_clear_overlay(c); @@ -3958,5 +3958,5 @@ server_client_report_theme(struct client *c, enum client_theme theme) * Request foreground and background colour again. Don't forward 2031 to * panes until a response is received. */ - tty_puts(&c->tty, "\033]10;?\033\\\033]11;?\033\\"); + tty_repeat_requests(&c->tty, 1); } diff --git a/tty-keys.c b/tty-keys.c index 267b5379..a367d022 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -937,7 +937,8 @@ partial_key: delay = options_get_number(global_options, "escape-time"); if (delay == 0) delay = 1; - if ((tty->flags & TTY_ALL_REQUEST_FLAGS) != TTY_ALL_REQUEST_FLAGS) { + if ((tty->flags & (TTY_WAITFG|TTY_WAITBG) || + (tty->flags & TTY_ALL_REQUEST_FLAGS) != TTY_ALL_REQUEST_FLAGS)) { log_debug("%s: increasing delay for active query", c->name); if (delay < 500) delay = 500; @@ -1686,14 +1687,14 @@ tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size, else log_debug("fg is %s", colour_tostring(n)); *fg = n; - tty->flags |= TTY_HAVEFG; + tty->flags &= ~TTY_WAITFG; } else if (n != -1) { if (c != NULL) log_debug("%s bg is %s", c->name, colour_tostring(n)); else log_debug("bg is %s", colour_tostring(n)); *bg = n; - tty->flags |= TTY_HAVEBG; + tty->flags &= ~TTY_WAITBG; } return (0); diff --git a/tty.c b/tty.c index 0fd0ce71..9ecc0ca9 100644 --- a/tty.c +++ b/tty.c @@ -44,11 +44,11 @@ static void tty_cursor_pane_unless_wrap(struct tty *, const struct tty_ctx *, u_int, u_int); static void tty_colours(struct tty *, const struct grid_cell *); static void tty_check_fg(struct tty *, struct colour_palette *, - struct grid_cell *); + struct grid_cell *); static void tty_check_bg(struct tty *, struct colour_palette *, - struct grid_cell *); + struct grid_cell *); static void tty_check_us(struct tty *, struct colour_palette *, - struct grid_cell *); + struct grid_cell *); static void tty_colours_fg(struct tty *, const struct grid_cell *); static void tty_colours_bg(struct tty *, const struct grid_cell *); static void tty_colours_us(struct tty *, const struct grid_cell *); @@ -306,9 +306,23 @@ tty_start_timer_callback(__unused int fd, __unused short events, void *data) struct client *c = tty->client; log_debug("%s: start timer fired", c->name); + if ((tty->flags & (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA)) == 0) tty_update_features(tty); tty->flags |= TTY_ALL_REQUEST_FLAGS; + + tty->flags &= ~(TTY_WAITBG|TTY_WAITFG); +} + +static void +tty_start_start_timer(struct tty *tty) +{ + struct client *c = tty->client; + struct timeval tv = { .tv_sec = TTY_QUERY_TIMEOUT }; + + log_debug("%s: start timer started", c->name); + evtimer_set(&tty->start_timer, tty_start_timer_callback, tty); + evtimer_add(&tty->start_timer, &tv); } void @@ -316,7 +330,6 @@ tty_start_tty(struct tty *tty) { struct client *c = tty->client; struct termios tio; - struct timeval tv = { .tv_sec = TTY_QUERY_TIMEOUT }; setblocking(c->fd, 0); event_add(&tty->event_in, NULL); @@ -356,8 +369,7 @@ tty_start_tty(struct tty *tty) tty_puts(tty, "\033[?2031h\033[?996n"); } - evtimer_set(&tty->start_timer, tty_start_timer_callback, tty); - evtimer_add(&tty->start_timer, &tv); + tty_start_start_timer(tty); tty->flags |= TTY_STARTED; tty_invalidate(tty); @@ -383,29 +395,35 @@ tty_send_requests(struct tty *tty) tty_puts(tty, "\033[>c"); if (~tty->flags & TTY_HAVEXDA) tty_puts(tty, "\033[>q"); - tty_puts(tty, "\033]10;?\033\\"); - tty_puts(tty, "\033]11;?\033\\"); + tty_puts(tty, "\033]10;?\033\\\033]11;?\033\\"); + tty->flags |= (TTY_WAITBG|TTY_WAITFG); } else tty->flags |= TTY_ALL_REQUEST_FLAGS; tty->last_requests = time(NULL); } void -tty_repeat_requests(struct tty *tty) +tty_repeat_requests(struct tty *tty, int force) { + struct client *c = tty->client; time_t t = time(NULL); + u_int n = t - tty->last_requests; if (~tty->flags & TTY_STARTED) return; - if (t - tty->last_requests <= TTY_REQUEST_LIMIT) + if (!force && n <= TTY_REQUEST_LIMIT) { + log_debug("%s: not repeating requests (%u seconds)", c->name, n); return; + } + log_debug("%s: %srepeating requests (%u seconds)", c->name, force ? "(force) " : "" , n); tty->last_requests = t; if (tty->term->flags & TERM_VT100LIKE) { - tty_puts(tty, "\033]10;?\033\\"); - tty_puts(tty, "\033]11;?\033\\"); - } + tty_puts(tty, "\033]10;?\033\\\033]11;?\033\\"); + tty->flags |= (TTY_WAITBG|TTY_WAITFG); + } + tty_start_start_timer(tty); } void @@ -1643,7 +1661,7 @@ tty_sync_end(struct tty *tty) tty->flags &= ~TTY_SYNCING; if (tty_term_has(tty->term, TTYC_SYNC)) { - log_debug("%s sync end", tty->client->name); + log_debug("%s sync end", tty->client->name); tty_putcode_i(tty, TTYC_SYNC, 2); } } From 5c89d835a60fd5957c9ff6446eab4a54d52dd7bd Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 1 Sep 2025 08:03:07 +0000 Subject: [PATCH 3/3] Add -k flag to display-popup which allows any key to dismiss the popup once the command has exited. From Meriel Luna Mittelbach in GitHub issue 4612. --- cmd-display-menu.c | 6 ++++-- popup.c | 3 +++ tmux.1 | 7 ++++++- tmux.h | 9 +++++---- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/cmd-display-menu.c b/cmd-display-menu.c index ab1b7047..bd5012f2 100644 --- a/cmd-display-menu.c +++ b/cmd-display-menu.c @@ -55,8 +55,8 @@ const struct cmd_entry cmd_display_popup_entry = { .name = "display-popup", .alias = "popup", - .args = { "Bb:Cc:d:e:Eh:s:S:t:T:w:x:y:", 0, -1, NULL }, - .usage = "[-BCE] [-b border-lines] [-c target-client] " + .args = { "Bb:Cc:d:e:Eh:ks:S:t:T:w:x:y:", 0, -1, NULL }, + .usage = "[-BCEk] [-b border-lines] [-c target-client] " "[-d start-directory] [-e environment] [-h height] " "[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE " [-T title] [-w width] [-x position] [-y position] " @@ -485,6 +485,8 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item) flags |= POPUP_CLOSEEXITZERO; else if (args_has(args, 'E')) flags |= POPUP_CLOSEEXIT; + if (args_has(args, 'k')) + flags |= POPUP_CLOSEANYKEY; if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc, argv, cwd, title, tc, s, style, border_style, NULL, NULL) != 0) { cmd_free_argv(argc, argv); diff --git a/popup.c b/popup.c index 138085a0..619a32ce 100644 --- a/popup.c +++ b/popup.c @@ -549,6 +549,9 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) pd->job == NULL) && (event->key == '\033' || event->key == ('c'|KEYC_CTRL))) return (1); + if (pd->job == NULL && (pd->flags & POPUP_CLOSEANYKEY) && + !KEYC_IS_MOUSE(event->key) && !KEYC_IS_PASTE(event->key)) + return (1); if (pd->job != NULL) { if (KEYC_IS_MOUSE(event->key)) { /* Must be inside, checked already. */ diff --git a/tmux.1 b/tmux.1 index f7ea02d8..73c4ad9d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -6967,7 +6967,7 @@ forwards any input read from stdin to the empty pane given by .Ar target-pane . .Tg popup .It Xo Ic display-popup -.Op Fl BCE +.Op Fl BCEk .Op Fl b Ar border-lines .Op Fl c Ar target-client .Op Fl d Ar start-directory @@ -7001,6 +7001,11 @@ Two closes the popup only if .Ar shell-command exited with success. +.Fl k +allows any key to dismiss the popup instead of only +.Ql Escape +or +.Ql C-c . .Pp .Fl x and diff --git a/tmux.h b/tmux.h index 84821746..02d8d1fb 100644 --- a/tmux.h +++ b/tmux.h @@ -1543,10 +1543,10 @@ struct tty { #define TTY_SYNCING 0x400 #define TTY_HAVEDA2 0x800 #define TTY_WINSIZEQUERY 0x1000 -#define TTY_HAVEFG 0x2000 -#define TTY_HAVEBG 0x4000 +#define TTY_WAITFG 0x2000 +#define TTY_WAITBG 0x4000 #define TTY_ALL_REQUEST_FLAGS \ - (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA|TTY_HAVEFG|TTY_HAVEBG) + (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA) int flags; struct tty_term *term; @@ -2474,7 +2474,7 @@ void 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 *); -void tty_repeat_requests(struct tty *); +void tty_repeat_requests(struct tty *, int); void tty_stop_tty(struct tty *); void tty_set_title(struct tty *, const char *); void tty_set_path(struct tty *, const char *); @@ -3523,6 +3523,7 @@ int menu_key_cb(struct client *, void *, struct key_event *); #define POPUP_CLOSEEXIT 0x1 #define POPUP_CLOSEEXITZERO 0x2 #define POPUP_INTERNAL 0x4 +#define POPUP_CLOSEANYKEY 0x8 typedef void (*popup_close_cb)(int, void *); typedef void (*popup_finish_edit_cb)(char *, size_t, void *); int popup_display(int, enum box_lines, struct cmdq_item *, u_int,