From 2ab53d30d0bcfd920f9417fce0ff5896d768b77e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 10 Jun 2021 09:17:46 +0100 Subject: [PATCH 01/34] 3.2a version. --- CHANGES | 4 ++++ configure.ac | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 209d7d31..613fe40c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +CHANGES FROM 3.2 TO 3.2a + +XXX + CHANGES FROM 3.1c TO 3.2 * Add a flag to disable keys to close a message. diff --git a/configure.ac b/configure.ac index c1915f50..a8d3787c 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT([tmux], 3.2) +AC_INIT([tmux], 3.2a) AC_PREREQ([2.60]) AC_CONFIG_AUX_DIR(etc) From bab7a9a085293aa50e6994376e1beed57ba44b4b Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 13 Apr 2021 12:26:34 +0000 Subject: [PATCH 02/34] Change how extended ctrl keys are processed to fix C-S-Tab and C-;. --- tty-keys.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index c0aceb32..040e7005 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -955,23 +955,19 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, */ if (nkey & KEYC_CTRL) { onlykey = (nkey & KEYC_MASK_KEY); - if (onlykey < 32) { - if (onlykey != 9) - onlykey = (nkey & ~KEYC_CTRL); - else - onlykey = (9|KEYC_CTRL); - } else { - if (onlykey >= 97 && onlykey <= 122) - onlykey -= 96; - else if (onlykey >= 64 && onlykey <= 95) - onlykey -= 64; - else if (onlykey == 32) - onlykey = 0; - else if (onlykey == 63) - onlykey = 127; - onlykey |= ((nkey & KEYC_MASK_MODIFIERS) & ~KEYC_CTRL); - } - nkey = onlykey; + if (onlykey < 32 && onlykey != 9) + /* nothing */; + else if (onlykey >= 97 && onlykey <= 122) + onlykey -= 96; + else if (onlykey >= 64 && onlykey <= 95) + onlykey -= 64; + else if (onlykey == 32) + onlykey = 0; + else if (onlykey == 63) + onlykey = 127; + else + onlykey |= KEYC_CTRL; + nkey = onlykey|((nkey & KEYC_MASK_MODIFIERS) & ~KEYC_CTRL); } if (log_get_level() != 0) { From 57d5f675527d860595911b8ff480f500b93eb24a Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 13 Apr 2021 16:00:47 +0000 Subject: [PATCH 03/34] Include modifiers when looking up an individual key. --- cmd-list-keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-list-keys.c b/cmd-list-keys.c index ca4bf752..91715f93 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -165,7 +165,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item) cmdq_error(item, "invalid key: %s", args->argv[0]); return (CMD_RETURN_ERROR); } - only &= KEYC_MASK_KEY; + only &= (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS); } tablename = args_get(args, 'T'); From d8639784647045593353270ae1b04ffb288533ff Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 15 Apr 2021 05:38:11 +0000 Subject: [PATCH 04/34] %begin now has three arguments, not two. GitHubs issue 2646. --- tmux.1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index 2343ab89..84cddc55 100644 --- a/tmux.1 +++ b/tmux.1 @@ -6116,12 +6116,13 @@ and matching .Em %end or .Em %error -have two arguments: an integer time (as seconds from epoch) and command number. +have three arguments: an integer time (as seconds from epoch), command number and +flags (currently not used). For example: .Bd -literal -offset indent -%begin 1363006971 2 +%begin 1363006971 2 1 0: ksh* (1 panes) [80x24] [layout b25f,80x24,0,0,2] @2 (active) -%end 1363006971 2 +%end 1363006971 2 1 .Ed .Pp The From 0431d4d6396e01fb333bc2bd0f1716c81b450dcf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 15 Apr 2021 06:45:19 +0100 Subject: [PATCH 05/34] Add crosscompiling fallbacks, from Hasso Tepper. --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index a8d3787c..bfbec1d4 100644 --- a/configure.ac +++ b/configure.ac @@ -163,6 +163,7 @@ AC_RUN_IFELSE([AC_LANG_PROGRAM( [return (reallocarray(NULL, 1, 1) == NULL);] )], AC_MSG_RESULT(yes), + [AC_LIBOBJ(reallocarray) AC_MSG_RESULT([no])], [AC_LIBOBJ(reallocarray) AC_MSG_RESULT([no])] ) AC_MSG_CHECKING([for working recallocarray]) @@ -171,6 +172,7 @@ AC_RUN_IFELSE([AC_LANG_PROGRAM( [return (recallocarray(NULL, 1, 1, 1) == NULL);] )], AC_MSG_RESULT(yes), + [AC_LIBOBJ(recallocarray) AC_MSG_RESULT([no])], [AC_LIBOBJ(recallocarray) AC_MSG_RESULT([no])] ) From a11aa870b397f1711a36666582d41492933d75ff Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 15 Apr 2021 08:22:36 +0100 Subject: [PATCH 06/34] Handle modifier 9 as Meta, GitHub issue 2647. --- tty-keys.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tty-keys.c b/tty-keys.c index 040e7005..5bf4e4a5 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -252,7 +252,8 @@ static const key_code tty_default_xterm_modifiers[] = { KEYC_CTRL, KEYC_SHIFT|KEYC_CTRL, KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL, - KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL + KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL, + KEYC_META|KEYC_IMPLIED_META }; /* @@ -944,6 +945,9 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, case 8: nkey |= (KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL); break; + case 9: + nkey |= (KEYC_META|KEYC_IMPLIED_META); + break; default: *key = KEYC_NONE; break; From a25af7d0f3347dc7664d7c1c13795eb05178895d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 16 Apr 2021 11:59:08 +0100 Subject: [PATCH 07/34] Adjust latest client when a client detaches, GitHub issue 2657. --- server-client.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/server-client.c b/server-client.c index d3ffd682..0f8ad687 100644 --- a/server-client.c +++ b/server-client.c @@ -43,6 +43,7 @@ static void server_client_check_modes(struct client *); static void server_client_set_title(struct client *); static void server_client_reset_state(struct client *); static int server_client_assume_paste(struct session *); +static void server_client_update_latest(struct client *); static void server_client_dispatch(struct imsg *, void *); static void server_client_dispatch_command(struct client *, struct imsg *); @@ -271,6 +272,40 @@ server_client_open(struct client *c, char **cause) return (0); } +/* Lost an attached client. */ +static void +server_client_attached_lost(struct client *c) +{ + struct session *s = c->session; + struct window *w; + struct client *loop; + struct client *found; + + log_debug("lost attached client %p", c); + + /* + * By this point the session in the client has been cleared so walk all + * windows to find any with this client as the latest. + */ + RB_FOREACH(w, windows, &windows) { + if (w->latest != c) + continue; + + found = NULL; + TAILQ_FOREACH(loop, &clients, entry) { + s = loop->session; + if (loop == c || s == NULL || s->curw->window != w) + continue; + if (found == NULL || + timercmp(&loop->activity_time, &found->activity_time, + >)) + found = loop; + } + if (found != NULL) + server_client_update_latest(found); + } +} + /* Lost a client. */ void server_client_lost(struct client *c) @@ -296,8 +331,10 @@ server_client_lost(struct client *c) TAILQ_REMOVE(&clients, c, entry); log_debug("lost client %p", c); - if (c->flags & CLIENT_ATTACHED) + if (c->flags & CLIENT_ATTACHED) { + server_client_attached_lost(c); notify_client("client-detached", c); + } if (c->flags & CLIENT_CONTROL) control_stop(c); From 16b497e12b971443913e271f4d3e320b8693d411 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 16 Apr 2021 12:07:54 +0100 Subject: [PATCH 08/34] Apple have broken strtonum so check it works, from Teubel Gyorgy. --- configure.ac | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index bfbec1d4..158e228c 100644 --- a/configure.ac +++ b/configure.ac @@ -150,10 +150,19 @@ AC_REPLACE_FUNCS([ \ strlcpy \ strndup \ strsep \ - strtonum \ ]) AC_FUNC_STRNLEN +# Check if strtonum works. +AC_MSG_CHECKING([for working strtonum]) +AC_RUN_IFELSE([AC_LANG_PROGRAM( + [#include ], + [return (strtonum("0", 0, 1, NULL) == 0 ? 0 : 1);] + )], + [AC_DEFINE(HAVE_STRTONUM) AC_MSG_RESULT(yes)], + [AC_LIBOBJ(strtonum) AC_MSG_RESULT(no)] +) + # Clang sanitizers wrap reallocarray even if it isn't available on the target # system. When compiled it always returns NULL and crashes the program. To # detect this we need a more complicated test. From 9865ad27a53e69aa651608e356c5335e76bc54cf Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 16 Apr 2021 12:12:50 +0100 Subject: [PATCH 09/34] Fix display-menu -xR, from Alexis Hildebrandt. --- cmd-display-menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-display-menu.c b/cmd-display-menu.c index 5a5aabcd..de423e68 100644 --- a/cmd-display-menu.c +++ b/cmd-display-menu.c @@ -205,7 +205,7 @@ cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item, if (xp == NULL || strcmp(xp, "C") == 0) xp = "#{popup_centre_x}"; else if (strcmp(xp, "R") == 0) - xp = "#{popup_right}"; + xp = "#{popup_pane_right}"; else if (strcmp(xp, "P") == 0) xp = "#{popup_pane_left}"; else if (strcmp(xp, "M") == 0) From 33d4f854c04b993c57195030ca33429256919949 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 18 Apr 2021 08:47:11 +0100 Subject: [PATCH 10/34] back-to-indentation fixes, from Anindya Mukherjee. --- grid-reader.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/grid-reader.c b/grid-reader.c index 89fe90fb..df0dd450 100644 --- a/grid-reader.c +++ b/grid-reader.c @@ -371,19 +371,26 @@ void grid_reader_cursor_back_to_indentation(struct grid_reader *gr) { struct grid_cell gc; - u_int px, py, xx, yy; + u_int px, py, xx, yy, oldx, oldy; yy = gr->gd->hsize + gr->gd->sy - 1; + oldx = gr->cx; + oldy = gr->cy; grid_reader_cursor_start_of_line(gr, 1); for (py = gr->cy; py <= yy; py++) { xx = grid_line_length(gr->gd, py); for (px = 0; px < xx; px++) { grid_get_cell(gr->gd, px, py, &gc); - if (gc.data.size != 1 || *gc.data.data != ' ') - break; + if (gc.data.size != 1 || *gc.data.data != ' ') { + gr->cx = px; + gr->cy = py; + return; + } } if (~grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED) break; } + gr->cx = oldx; + gr->cy = oldy; } From d8c006925464ce50d92aee913aa452acf2033173 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 18 Apr 2021 08:48:03 +0100 Subject: [PATCH 11/34] Use = not ==, from Leonardo Taccari. --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 158e228c..9bbfd49e 100644 --- a/configure.ac +++ b/configure.ac @@ -34,10 +34,10 @@ AC_ARG_VAR( # Set up convenient fuzzing defaults before initializing compiler. if test "x$enable_fuzzing" = xyes; then AC_DEFINE(NEED_FUZZING) - test "x$CC" == x && CC=clang - test "x$FUZZING_LIBS" == x && \ + test "x$CC" = x && CC=clang + test "x$FUZZING_LIBS" = x && \ FUZZING_LIBS="-fsanitize=fuzzer" - test "x$SAVED_CFLAGS" == x && \ + test "x$SAVED_CFLAGS" = x && \ AM_CFLAGS="-g -fsanitize=fuzzer-no-link,address" fi From 825feac9f8f8aa10ec69932ab6ea52e58586e058 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Apr 2021 06:35:54 +0100 Subject: [PATCH 12/34] Add another couple of keys needed for extended keys, GitHub issue 2658. --- key-bindings.c | 6 ++++++ key-string.c | 10 +++++++--- tty-keys.c | 5 ++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/key-bindings.c b/key-bindings.c index b47f6ff7..467c7f93 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -215,6 +215,9 @@ key_bindings_add(const char *name, key_code key, const char *note, int repeat, if (repeat) bd->flags |= KEY_BINDING_REPEAT; bd->cmdlist = cmdlist; + + log_debug("%s: %#llx %s = %s", __func__, bd->key, + key_string_lookup_key(bd->key, 1), cmd_list_print(bd->cmdlist, 0)); } void @@ -231,6 +234,9 @@ key_bindings_remove(const char *name, key_code key) if (bd == NULL) return; + log_debug("%s: %#llx %s", __func__, bd->key, + key_string_lookup_key(bd->key, 1)); + RB_REMOVE(key_bindings, &table->key_bindings, bd); key_bindings_free(bd); diff --git a/key-string.c b/key-string.c index 8d60f132..c24a33fc 100644 --- a/key-string.c +++ b/key-string.c @@ -164,7 +164,7 @@ key_string_get_modifiers(const char **string) key_code key_string_lookup_string(const char *string) { - static const char *other = "!#()+,-.0123456789:;<=>'\r\t\177"; + static const char *other = "!#()+,-.0123456789:;<=>'\r\t\177`/"; key_code key, modifiers; u_int u, i; struct utf8_data ud, *udp; @@ -238,8 +238,12 @@ key_string_lookup_string(const char *string) } /* Convert the standard control keys. */ - if (key < KEYC_BASE && (modifiers & KEYC_CTRL) && - strchr(other, key) == NULL) { + if (key < KEYC_BASE && + (modifiers & KEYC_CTRL) && + strchr(other, key) == NULL && + key != 9 && + key != 13 && + key != 27) { if (key >= 97 && key <= 122) key -= 96; else if (key >= 64 && key <= 95) diff --git a/tty-keys.c b/tty-keys.c index 5bf4e4a5..3012be3d 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -959,7 +959,10 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, */ if (nkey & KEYC_CTRL) { onlykey = (nkey & KEYC_MASK_KEY); - if (onlykey < 32 && onlykey != 9) + if (onlykey < 32 && + onlykey != 9 && + onlykey != 13 && + onlykey != 27) /* nothing */; else if (onlykey >= 97 && onlykey <= 122) onlykey -= 96; From 736a276cc9bdb97bf35caa1995a54d328a839102 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Apr 2021 06:37:01 +0100 Subject: [PATCH 13/34] Minor CHANGES and tmux.1 fixed, from Daniel Hahler, GitHub issue 2664. --- CHANGES | 10 +++++----- tmux.1 | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGES b/CHANGES index 613fe40c..e50c061b 100644 --- a/CHANGES +++ b/CHANGES @@ -33,7 +33,7 @@ CHANGES FROM 3.1c TO 3.2 * Add a -S flag to new-window to make it select the existing window if one with the given name already exists rather than failing with an error. -* Addd a format modifier to check if a window or session name exists (N/w or +* Add a format modifier to check if a window or session name exists (N/w or N/s). * Add compat clock_gettime for older macOS. @@ -65,7 +65,7 @@ CHANGES FROM 3.1c TO 3.2 an option on all panes. * Make replacement of ##s consistent when drawing formats, whether followed by - [ or not. Add a flag (e) to the q: format modifier to double up #s + [ or not. Add a flag (e) to the q: format modifier to double up #s. * Add -N flag to display-panes to ignore keys. @@ -269,7 +269,7 @@ CHANGES FROM 3.1c TO 3.2 * Wait until the initial command sequence is done before sending a device attributes request and other bits that prompt a reply from the terminal. This - means that stray relies are not left on the terminal if the command has + means that stray replies are not left on the terminal if the command has attached and then immediately detached and tmux will not be around to receive them. @@ -284,7 +284,7 @@ CHANGES FROM 3.1c TO 3.2 window-renamed window-unlinked - And these now pane options: + And these are now pane options: pane-died pane-exited @@ -359,7 +359,7 @@ CHANGES FROM 3.1c TO 3.2 * Add a default binding for button 2 to paste. * Add -d flag to run-shell to delay before running the command and allow it to - run without a command so it just delays. + be used without a command so it just delays. * Add C-g to cancel command prompt with vi keys as well as emacs, and q in command mode. diff --git a/tmux.1 b/tmux.1 index 84cddc55..c4fc06ba 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3501,8 +3501,8 @@ capabilities to be set instead, is intended for classes of functionality supported in a standard way but not reported by .Xr terminfo 5 . -Care must be taken only to configure this with features the terminal actually -support. +Care must be taken to configure this only with features the terminal actually +supports. .Pp This is an array option where each entry is a colon-separated string made up of a terminal type pattern (matched using From 5107e848977640398843e720e26d45a66954e7f9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Apr 2021 09:32:48 +0100 Subject: [PATCH 14/34] Add an "always" value to the extended-keys option to always forward these keys to applications inside tmux. --- input.c | 2 ++ options-table.c | 6 +++++- screen.c | 4 +++- tmux.1 | 21 +++++++++++++++++---- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/input.c b/input.c index f6aeb027..b599f27d 100644 --- a/input.c +++ b/input.c @@ -1390,6 +1390,8 @@ input_csi_dispatch(struct input_ctx *ictx) case INPUT_CSI_MODSET: n = input_get(ictx, 0, 0, 0); m = input_get(ictx, 1, 0, 0); + if (options_get_number(global_options, "extended-keys") == 2) + break; if (n == 0 || (n == 4 && m == 0)) screen_write_mode_clear(sctx, MODE_KEXTENDED); else if (n == 4 && (m == 1 || m == 2)) diff --git a/options-table.c b/options-table.c index b185969c..8264d1b7 100644 --- a/options-table.c +++ b/options-table.c @@ -74,6 +74,9 @@ static const char *options_table_remain_on_exit_list[] = { static const char *options_table_detach_on_destroy_list[] = { "off", "on", "no-detached", NULL }; +static const char *options_table_extended_keys_list[] = { + "off", "on", "always", NULL +}; /* Status line format. */ #define OPTIONS_TABLE_STATUS_FORMAT1 \ @@ -266,8 +269,9 @@ const struct options_table_entry options_table[] = { }, { .name = "extended-keys", - .type = OPTIONS_TABLE_FLAG, + .type = OPTIONS_TABLE_CHOICE, .scope = OPTIONS_TABLE_SERVER, + .choices = options_table_extended_keys_list, .default_num = 0, .text = "Whether to request extended key sequences from terminals " "that support it." diff --git a/screen.c b/screen.c index 2b9d70de..2b83c285 100644 --- a/screen.c +++ b/screen.c @@ -100,7 +100,9 @@ screen_reinit(struct screen *s) s->rupper = 0; s->rlower = screen_size_y(s) - 1; - s->mode = MODE_CURSOR | MODE_WRAP; + s->mode = MODE_CURSOR|MODE_WRAP; + if (options_get_number(global_options, "extended-keys") == 2) + s->mode |= MODE_KEXTENDED; if (s->saved_grid != NULL) screen_alternate_off(s, NULL, 0); diff --git a/tmux.1 b/tmux.1 index c4fc06ba..6967c769 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3418,11 +3418,24 @@ sessions. .Xc If enabled, the server will exit when there are no attached clients. .It Xo Ic extended-keys -.Op Ic on | off +.Op Ic on | off | always .Xc -When enabled, extended keys are requested from the terminal and if supported -are recognised by -.Nm . +When +.Ic on +or +.Ic always , +the escape sequence to enable extended keys is sent to the terminal, if +.Nm +knows that it is supported. +.Nm +always recognises extended keys itself. +If this option is +.Ic on , +.Nm +will only forward extended keys to applications when they request them; if +.Ic always , +.Nm +will always forward the keys. .It Xo Ic focus-events .Op Ic on | off .Xc From 4cf595a4023acfd9fce2e589f0d01de3e7b5eff7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 21 Apr 2021 09:47:03 +0100 Subject: [PATCH 15/34] Include current client in size calcultion for new sessions, GitHub issue 2662. --- cmd-new-session.c | 1 + resize.c | 47 +++++++++++++++++++++++++++++++++-------------- status.c | 2 ++ window.c | 2 ++ 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index cc3494de..c47d66cd 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -269,6 +269,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) memset(&sc, 0, sizeof sc); sc.item = item; sc.s = s; + sc.tc = c; sc.name = args_get(args, 'n'); sc.argc = args->argc; diff --git a/resize.c b/resize.c index 172cbcb5..66cb9430 100644 --- a/resize.c +++ b/resize.c @@ -108,17 +108,19 @@ clients_with_window(struct window *w) } static int -clients_calculate_size(int type, int current, struct session *s, - struct window *w, int (*skip_client)(struct client *, int, int, - struct session *, struct window *), u_int *sx, u_int *sy, u_int *xpixel, - u_int *ypixel) +clients_calculate_size(int type, int current, struct client *c, + struct session *s, struct window *w, int (*skip_client)(struct client *, + int, int, struct session *, struct window *), u_int *sx, u_int *sy, + u_int *xpixel, u_int *ypixel) { struct client *loop; u_int cx, cy, n = 0; /* Manual windows do not have their size changed based on a client. */ - if (type == WINDOW_SIZE_MANUAL) + if (type == WINDOW_SIZE_MANUAL) { + log_debug("%s: type is manual", __func__); return (0); + } /* * Start comparing with 0 for largest and UINT_MAX for smallest or @@ -139,18 +141,24 @@ clients_calculate_size(int type, int current, struct session *s, /* Loop over the clients and work out the size. */ TAILQ_FOREACH(loop, &clients, entry) { - if (ignore_client_size(loop)) + if (loop != c && ignore_client_size(loop)) { + log_debug("%s: ignoring %s", __func__, loop->name); continue; - if (skip_client(loop, type, current, s, w)) + } + if (loop != c && skip_client(loop, type, current, s, w)) { + log_debug("%s: skipping %s", __func__, loop->name); continue; + } /* * If there are multiple clients attached, only accept the * latest client; otherwise let the only client be chosen as * for smallest. */ - if (type == WINDOW_SIZE_LATEST && n > 1 && loop != w->latest) + if (type == WINDOW_SIZE_LATEST && n > 1 && loop != w->latest) { + log_debug("%s: %s is not latest", __func__, loop->name); continue; + } /* Work out this client's size. */ cx = loop->tty.sx; @@ -175,16 +183,24 @@ clients_calculate_size(int type, int current, struct session *s, *xpixel = loop->tty.xpixel; *ypixel = loop->tty.ypixel; } + log_debug("%s: after %s (%ux%u), size is %ux%u", __func__, + loop->name, cx, cy, *sx, *sy); } /* Return whether a suitable size was found. */ - if (type == WINDOW_SIZE_LARGEST) + if (type == WINDOW_SIZE_LARGEST) { + log_debug("%s: type is largest", __func__); return (*sx != 0 && *sy != 0); + } + if (type == WINDOW_SIZE_LATEST) + log_debug("%s: type is latest", __func__); + else + log_debug("%s: type is smallest", __func__); return (*sx != UINT_MAX && *sy != UINT_MAX); } static int -default_window_size_skip_client (struct client *loop, int type, +default_window_size_skip_client(struct client *loop, int type, __unused int current, struct session *s, struct window *w) { /* @@ -221,23 +237,25 @@ default_window_size(struct client *c, struct session *s, struct window *w, *sy = c->tty.sy - status_line_size(c); *xpixel = c->tty.xpixel; *ypixel = c->tty.ypixel; + log_debug("%s: using %ux%u from %s", __func__, *sx, *sy, + c->name); goto done; } - if (w == NULL) - type = WINDOW_SIZE_MANUAL; } /* * Look for a client to base the size on. If none exists (or the type * is manual), use the default-size option. */ - if (!clients_calculate_size(type, 0, s, w, + if (!clients_calculate_size(type, 0, c, s, w, default_window_size_skip_client, sx, sy, xpixel, ypixel)) { value = options_get_string(s->options, "default-size"); if (sscanf(value, "%ux%u", sx, sy) != 2) { *sx = 80; *sy = 24; } + log_debug("%s: using %ux%u from default-size", __func__, *sx, + *sy); } done: @@ -250,6 +268,7 @@ done: *sy = WINDOW_MINIMUM; if (*sy > WINDOW_MAXIMUM) *sy = WINDOW_MAXIMUM; + log_debug("%s: resulting size is %ux%u", __func__, *sx, *sy); } static int @@ -289,7 +308,7 @@ recalculate_size(struct window *w, int now) current = options_get_number(w->options, "aggressive-resize"); /* Look for a suitable client and get the new size. */ - changed = clients_calculate_size(type, current, NULL, w, + changed = clients_calculate_size(type, current, NULL, NULL, w, recalculate_size_skip_client, &sx, &sy, &xpixel, &ypixel); /* diff --git a/status.c b/status.c index f9786f4b..271e1afa 100644 --- a/status.c +++ b/status.c @@ -226,6 +226,8 @@ status_line_size(struct client *c) if (c->flags & (CLIENT_STATUSOFF|CLIENT_CONTROL)) return (0); + if (s == NULL) + return (options_get_number(global_s_options, "status")); return (s->statuslines); } diff --git a/window.c b/window.c index 38c1913c..d8cff590 100644 --- a/window.c +++ b/window.c @@ -329,6 +329,8 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel) window_update_activity(w); + log_debug("%s: @%u create %ux%u (%ux%u)", __func__, w->id, sx, sy, + w->xpixel, w->ypixel); return (w); } From ddc67152a5e8761c3dd5b8807c7fa1b997292e96 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 22 Apr 2021 09:01:22 +0100 Subject: [PATCH 16/34] Three changes to fix problems with xterm in VT340 mode, reported by Thomas Sattler. 1) Do not include the DECSLRM or DECFRA features for xterm; they will be added instead if secondary DA responds as VT420 (this happens already). 2) Set or reset the individual flags after terminal-overrides is applied, so the user can properly disable them. 3) Add a capability for DECFRA ("Rect"). --- tmux.1 | 4 +++ tmux.h | 1 + tty-features.c | 13 +++++-- tty-term.c | 98 ++++++++++++++++++++++++++++++++------------------ 4 files changed, 80 insertions(+), 36 deletions(-) diff --git a/tmux.1 b/tmux.1 index 6967c769..522de231 100644 --- a/tmux.1 +++ b/tmux.1 @@ -6049,6 +6049,10 @@ Disable and enable focus reporting. These are set automatically if the .Em XT capability is present. +.It Em \&Rect +Tell +.Nm +that the terminal supports rectangle operations. .It Em \&Smol Enable the overline attribute. .It Em \&Smulx diff --git a/tmux.h b/tmux.h index 6be5b302..a67b30b9 100644 --- a/tmux.h +++ b/tmux.h @@ -452,6 +452,7 @@ enum tty_code_code { TTYC_MS, TTYC_OL, TTYC_OP, + TTYC_RECT, TTYC_REV, TTYC_RGB, TTYC_RI, diff --git a/tty-features.c b/tty-features.c index f167a2d3..b42cf74a 100644 --- a/tty-features.c +++ b/tty-features.c @@ -218,9 +218,13 @@ static const struct tty_feature tty_feature_margins = { }; /* Terminal supports DECFRA rectangle fill. */ +static const char *tty_feature_rectfill_capabilities[] = { + "Rect", + NULL +}; static const struct tty_feature tty_feature_rectfill = { "rectfill", - NULL, + tty_feature_rectfill_capabilities, TERM_DECFRA }; @@ -351,8 +355,13 @@ tty_default_features(int *feat, const char *name, u_int version) ",cstyle,extkeys,margins,sync" }, { .name = "XTerm", + /* + * xterm also supports DECSLRM and DECFRA, but they can be + * disabled so not set it here - they will be added if + * secondary DA shows VT420. + */ .features = TTY_FEATURES_BASE_MODERN_XTERM - ",ccolour,cstyle,extkeys,focus,margins,rectfill" + ",ccolour,cstyle,extkeys,focus" } }; u_int i; diff --git a/tty-term.c b/tty-term.c index 1d9b36da..4a7e7415 100644 --- a/tty-term.c +++ b/tty-term.c @@ -251,6 +251,7 @@ static const struct tty_term_code_entry tty_term_codes[] = { [TTYC_MS] = { TTYCODE_STRING, "Ms" }, [TTYC_OL] = { TTYCODE_STRING, "ol" }, [TTYC_OP] = { TTYCODE_STRING, "op" }, + [TTYC_RECT] = { TTYCODE_STRING, "Rect" }, [TTYC_REV] = { TTYCODE_STRING, "rev" }, [TTYC_RGB] = { TTYCODE_FLAG, "RGB" }, [TTYC_RIN] = { TTYCODE_STRING, "rin" }, @@ -434,10 +435,11 @@ tty_term_apply_overrides(struct tty_term *term) struct options_entry *o; struct options_array_item *a; union options_value *ov; - const char *s; + const char *s, *acs; size_t offset; char *first; + /* Update capabilities from the option. */ o = options_get_only(global_options, "terminal-overrides"); a = options_array_first(o); while (a != NULL) { @@ -450,6 +452,64 @@ tty_term_apply_overrides(struct tty_term *term) tty_term_apply(term, s + offset, 0); a = options_array_next(a); } + + /* Update the RGB flag if the terminal has RGB colours. */ + if (tty_term_has(term, TTYC_SETRGBF) && + tty_term_has(term, TTYC_SETRGBB)) + term->flags |= TERM_RGBCOLOURS; + else + term->flags &= ~TERM_RGBCOLOURS; + log_debug("RGBCOLOURS flag is %d", !!(term->flags & TERM_RGBCOLOURS)); + + /* + * Set or clear the DECSLRM flag if the terminal has the margin + * capabilities. + */ + if (tty_term_has(term, TTYC_CMG) && tty_term_has(term, TTYC_CLMG)) + term->flags |= TERM_DECSLRM; + else + term->flags &= ~TERM_DECSLRM; + log_debug("DECSLRM flag is %d", !!(term->flags & TERM_DECSLRM)); + + /* + * Set or clear the DECFRA flag if the terminal has the rectangle + * capability. + */ + if (tty_term_has(term, TTYC_RECT)) + term->flags |= TERM_DECFRA; + else + term->flags &= ~TERM_DECFRA; + log_debug("DECFRA flag is %d", !!(term->flags & TERM_DECFRA)); + + /* + * Terminals without am (auto right margin) wrap at at $COLUMNS - 1 + * rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1). + * + * Terminals without xenl (eat newline glitch) ignore a newline beyond + * the right edge of the terminal, but tmux doesn't care about this - + * it always uses absolute only moves the cursor with a newline when + * also sending a linefeed. + * + * This is irritating, most notably because it is painful to write to + * the very bottom-right of the screen without scrolling. + * + * Flag the terminal here and apply some workarounds in other places to + * do the best possible. + */ + if (!tty_term_flag(term, TTYC_AM)) + term->flags |= TERM_NOAM; + else + term->flags &= ~TERM_NOAM; + log_debug("NOAM flag is %d", !!(term->flags & TERM_NOAM)); + + /* Generate ACS table. If none is present, use nearest ASCII. */ + memset(term->acs, 0, sizeof term->acs); + if (tty_term_has(term, TTYC_ACSC)) + acs = tty_term_string(term, TTYC_ACSC); + else + acs = "a#j+k+l+m+n+o-p-q-r-s-t+u+v+w+x|y~."; + for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2) + term->acs[(u_char) acs[0]][0] = acs[1]; } struct tty_term * @@ -463,7 +523,7 @@ tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps, struct options_array_item *a; union options_value *ov; u_int i, j; - const char *s, *acs, *value; + const char *s, *value; size_t offset, namelen; char *first; @@ -566,40 +626,10 @@ tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps, (!tty_term_has(term, TTYC_SETRGBF) || !tty_term_has(term, TTYC_SETRGBB))) tty_add_features(feat, "RGB", ","); - if (tty_term_has(term, TTYC_SETRGBF) && - tty_term_has(term, TTYC_SETRGBB)) - term->flags |= TERM_RGBCOLOURS; /* Apply the features and overrides again. */ - tty_apply_features(term, *feat); - tty_term_apply_overrides(term); - - /* - * Terminals without am (auto right margin) wrap at at $COLUMNS - 1 - * rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1). - * - * Terminals without xenl (eat newline glitch) ignore a newline beyond - * the right edge of the terminal, but tmux doesn't care about this - - * it always uses absolute only moves the cursor with a newline when - * also sending a linefeed. - * - * This is irritating, most notably because it is painful to write to - * the very bottom-right of the screen without scrolling. - * - * Flag the terminal here and apply some workarounds in other places to - * do the best possible. - */ - if (!tty_term_flag(term, TTYC_AM)) - term->flags |= TERM_NOAM; - - /* Generate ACS table. If none is present, use nearest ASCII. */ - memset(term->acs, 0, sizeof term->acs); - if (tty_term_has(term, TTYC_ACSC)) - acs = tty_term_string(term, TTYC_ACSC); - else - acs = "a#j+k+l+m+n+o-p-q-r-s-t+u+v+w+x|y~."; - for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2) - term->acs[(u_char) acs[0]][0] = acs[1]; + if (tty_apply_features(term, *feat)) + tty_term_apply_overrides(term); /* Log the capabilities. */ for (i = 0; i < tty_term_ncodes(); i++) From fb52921a86f15cd781bc2b2e65a9c6dd2a437f06 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 23 Apr 2021 13:41:49 +0100 Subject: [PATCH 17/34] Do not count client if no window. --- resize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resize.c b/resize.c index 66cb9430..38cda23d 100644 --- a/resize.c +++ b/resize.c @@ -136,7 +136,7 @@ clients_calculate_size(int type, int current, struct client *c, * For latest, count the number of clients with this window. We only * care if there is more than one. */ - if (type == WINDOW_SIZE_LATEST) + if (type == WINDOW_SIZE_LATEST && w != NULL) n = clients_with_window(w); /* Loop over the clients and work out the size. */ From 7c28597e0f0a000e46aa7f42c00c9750fe6cff61 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 27 Apr 2021 08:29:54 +0100 Subject: [PATCH 18/34] Mention S- for Shift, GitHub issue 2683. --- tmux.1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tmux.1 b/tmux.1 index 522de231..22982b11 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2953,6 +2953,8 @@ Ctrl keys may be prefixed with .Ql C- or .Ql ^ , +Shift keys with +.Ql S- and Alt (meta) with .Ql M- . In addition, the following special key names are accepted: From cb2943faab2053719b13306f95ed58a2dae64e81 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 28 Apr 2021 09:16:30 +0100 Subject: [PATCH 19/34] Change resize timers and flags into one timer and a queue to fix problems with vim when resized multiple times. GitHub issue 2677. --- server-client.c | 117 +++++++++++++++++++++++------------------------- tmux.h | 25 ++++++++--- window.c | 51 +++++++++------------ 3 files changed, 94 insertions(+), 99 deletions(-) diff --git a/server-client.c b/server-client.c index 0f8ad687..e74d893d 100644 --- a/server-client.c +++ b/server-client.c @@ -1447,84 +1447,79 @@ server_client_resize_timer(__unused int fd, __unused short events, void *data) evtimer_del(&wp->resize_timer); } -/* Start the resize timer. */ -static void -server_client_start_resize_timer(struct window_pane *wp) -{ - struct timeval tv = { .tv_usec = 250000 }; - - log_debug("%s: %%%u resize timer started", __func__, wp->id); - evtimer_add(&wp->resize_timer, &tv); -} - -/* Force timer event. */ -static void -server_client_force_timer(__unused int fd, __unused short events, void *data) -{ - struct window_pane *wp = data; - - log_debug("%s: %%%u force timer expired", __func__, wp->id); - evtimer_del(&wp->force_timer); - wp->flags |= PANE_RESIZENOW; -} - -/* Start the force timer. */ -static void -server_client_start_force_timer(struct window_pane *wp) -{ - struct timeval tv = { .tv_usec = 10000 }; - - log_debug("%s: %%%u force timer started", __func__, wp->id); - evtimer_add(&wp->force_timer, &tv); -} - /* Check if pane should be resized. */ static void server_client_check_pane_resize(struct window_pane *wp) { + struct window_pane_resize *r; + struct window_pane_resize *r1; + struct window_pane_resize *first; + struct window_pane_resize *last; + struct timeval tv = { .tv_usec = 250000 }; + + if (TAILQ_EMPTY(&wp->resize_queue)) + return; + if (!event_initialized(&wp->resize_timer)) evtimer_set(&wp->resize_timer, server_client_resize_timer, wp); - if (!event_initialized(&wp->force_timer)) - evtimer_set(&wp->force_timer, server_client_force_timer, wp); - - if (~wp->flags & PANE_RESIZE) + if (evtimer_pending(&wp->resize_timer, NULL)) return; + log_debug("%s: %%%u needs to be resized", __func__, wp->id); - - if (evtimer_pending(&wp->resize_timer, NULL)) { - log_debug("%s: %%%u resize timer is running", __func__, wp->id); - return; + TAILQ_FOREACH(r, &wp->resize_queue, entry) { + log_debug("queued resize: %ux%u -> %ux%u", r->osx, r->osy, + r->sx, r->sy); } - server_client_start_resize_timer(wp); - if (~wp->flags & PANE_RESIZEFORCE) { - /* - * The timer is not running and we don't need to force a - * resize, so just resize immediately. - */ - log_debug("%s: resizing %%%u now", __func__, wp->id); - window_pane_send_resize(wp, 0); - wp->flags &= ~PANE_RESIZE; + /* + * There are three cases that matter: + * + * - Only one resize. It can just be applied. + * + * - Multiple resizes and the ending size is different from the + * starting size. We can discard all resizes except the most recent. + * + * - Multiple resizes and the ending size is the same as the starting + * size. We must resize at least twice to force the application to + * redraw. So apply the first and leave the last on the queue for + * next time. + */ + first = TAILQ_FIRST(&wp->resize_queue); + last = TAILQ_LAST(&wp->resize_queue, window_pane_resizes); + if (first == last) { + /* Only one resize. */ + window_pane_send_resize(wp, first->sx, first->sy); + TAILQ_REMOVE(&wp->resize_queue, first, entry); + free(first); + } else if (last->sx != first->osx || last->sy != first->osy) { + /* Multiple resizes ending up with a different size. */ + window_pane_send_resize(wp, last->sx, last->sy); + TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) { + TAILQ_REMOVE(&wp->resize_queue, r, entry); + free(r); + } } else { /* - * The timer is not running, but we need to force a resize. If - * the force timer has expired, resize to the real size now. - * Otherwise resize to the force size and start the timer. + * Multiple resizes ending up with the same size. There will + * not be more than one to the same size in succession so we + * can just use the last-but-one on the list and leave the last + * for later. We reduce the time until the next check to avoid + * a long delay between the resizes. */ - if (wp->flags & PANE_RESIZENOW) { - log_debug("%s: resizing %%%u after forced resize", - __func__, wp->id); - window_pane_send_resize(wp, 0); - wp->flags &= ~(PANE_RESIZE|PANE_RESIZEFORCE|PANE_RESIZENOW); - } else if (!evtimer_pending(&wp->force_timer, NULL)) { - log_debug("%s: forcing resize of %%%u", __func__, - wp->id); - window_pane_send_resize(wp, 1); - server_client_start_force_timer(wp); + r = TAILQ_PREV(last, window_pane_resizes, entry); + window_pane_send_resize(wp, r->sx, r->sy); + TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) { + if (r == last) + break; + TAILQ_REMOVE(&wp->resize_queue, r, entry); + free(r); } + tv.tv_usec = 10000; } + evtimer_add(&wp->resize_timer, &tv); } + /* Check pane buffer size. */ static void server_client_check_pane_buffer(struct window_pane *wp) diff --git a/tmux.h b/tmux.h index a67b30b9..1e496e6f 100644 --- a/tmux.h +++ b/tmux.h @@ -919,7 +919,7 @@ struct window_mode_entry { struct screen *screen; u_int prefix; - TAILQ_ENTRY (window_mode_entry) entry; + TAILQ_ENTRY(window_mode_entry) entry; }; /* Offsets into pane buffer. */ @@ -927,6 +927,18 @@ struct window_pane_offset { size_t used; }; +/* Queued pane resize. */ +struct window_pane_resize { + u_int sx; + u_int sy; + + u_int osx; + u_int osy; + + TAILQ_ENTRY(window_pane_resize) entry; +}; +TAILQ_HEAD(window_pane_resizes, window_pane_resize); + /* Child window structure. */ struct window_pane { u_int id; @@ -951,8 +963,8 @@ struct window_pane { #define PANE_REDRAW 0x1 #define PANE_DROP 0x2 #define PANE_FOCUSED 0x4 -#define PANE_RESIZE 0x8 -#define PANE_RESIZEFORCE 0x10 +/* 0x8 unused */ +/* 0x10 unused */ #define PANE_FOCUSPUSH 0x20 #define PANE_INPUTOFF 0x40 #define PANE_CHANGED 0x80 @@ -961,7 +973,6 @@ struct window_pane { #define PANE_STATUSDRAWN 0x400 #define PANE_EMPTY 0x800 #define PANE_STYLECHANGED 0x1000 -#define PANE_RESIZENOW 0x2000 int argc; char **argv; @@ -978,8 +989,8 @@ struct window_pane { struct window_pane_offset offset; size_t base_offset; + struct window_pane_resizes resize_queue; struct event resize_timer; - struct event force_timer; struct input_ctx *ictx; @@ -997,7 +1008,7 @@ struct window_pane { struct screen status_screen; size_t status_size; - TAILQ_HEAD (, window_mode_entry) modes; + TAILQ_HEAD(, window_mode_entry) modes; char *searchstr; int searchregex; @@ -2756,7 +2767,7 @@ void window_redraw_active_switch(struct window *, struct window_pane *window_add_pane(struct window *, struct window_pane *, u_int, int); void window_resize(struct window *, u_int, u_int, int, int); -void window_pane_send_resize(struct window_pane *, int); +void window_pane_send_resize(struct window_pane *, u_int, u_int); int window_zoom(struct window_pane *); int window_unzoom(struct window *); int window_push_zoom(struct window *, int, int); diff --git a/window.c b/window.c index d8cff590..f21a4d5f 100644 --- a/window.c +++ b/window.c @@ -425,25 +425,18 @@ window_resize(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel) } void -window_pane_send_resize(struct window_pane *wp, int force) +window_pane_send_resize(struct window_pane *wp, u_int sx, u_int sy) { struct window *w = wp->window; struct winsize ws; - u_int sy; if (wp->fd == -1) return; - if (!force) - sy = wp->sy; - else if (wp->sy <= 1) - sy = wp->sy + 1; - else - sy = wp->sy - 1; - log_debug("%s: %%%u resize to %u,%u", __func__, wp->id, wp->sx, sy); + log_debug("%s: %%%u resize to %u,%u", __func__, wp->id, sx, sy); memset(&ws, 0, sizeof ws); - ws.ws_col = wp->sx; + ws.ws_col = sx; ws.ws_row = sy; ws.ws_xpixel = w->xpixel * ws.ws_col; ws.ws_ypixel = w->ypixel * ws.ws_row; @@ -867,29 +860,19 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->id = next_window_pane_id++; RB_INSERT(window_pane_tree, &all_window_panes, wp); - wp->argc = 0; - wp->argv = NULL; - wp->shell = NULL; - wp->cwd = NULL; - wp->fd = -1; - wp->event = NULL; wp->fg = 8; wp->bg = 8; TAILQ_INIT(&wp->modes); - wp->layout_cell = NULL; - - wp->xoff = 0; - wp->yoff = 0; + TAILQ_INIT (&wp->resize_queue); wp->sx = sx; wp->sy = sy; wp->pipe_fd = -1; - wp->pipe_event = NULL; screen_init(&wp->base, sx, sy, hlimit); wp->screen = &wp->base; @@ -905,6 +888,9 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) static void window_pane_destroy(struct window_pane *wp) { + struct window_pane_resize *r; + struct window_pane_resize *r1; + window_pane_reset_mode_all(wp); free(wp->searchstr); @@ -929,8 +915,10 @@ window_pane_destroy(struct window_pane *wp) if (event_initialized(&wp->resize_timer)) event_del(&wp->resize_timer); - if (event_initialized(&wp->force_timer)) - event_del(&wp->force_timer); + TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) { + TAILQ_REMOVE(&wp->resize_queue, r, entry); + free(r); + } RB_REMOVE(window_pane_tree, &all_window_panes, wp); @@ -999,9 +987,18 @@ void window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) { struct window_mode_entry *wme; + struct window_pane_resize *r; if (sx == wp->sx && sy == wp->sy) return; + + r = xmalloc (sizeof *r); + r->sx = sx; + r->sy = sy; + r->osx = wp->sx; + r->osy = wp->sy; + TAILQ_INSERT_TAIL (&wp->resize_queue, r, entry); + wp->sx = sx; wp->sy = sy; @@ -1011,14 +1008,6 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) wme = TAILQ_FIRST(&wp->modes); if (wme != NULL && wme->mode->resize != NULL) wme->mode->resize(wme, sx, sy); - - /* - * If the pane has already been resized, set the force flag and make - * the application resize twice to force it to redraw. - */ - if (wp->flags & PANE_RESIZE) - wp->flags |= PANE_RESIZEFORCE; - wp->flags |= PANE_RESIZE; } void From 059580e0f72ebeb0538d0ef54808dae277388bf9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 28 Apr 2021 09:18:04 +0100 Subject: [PATCH 20/34] Move "special" keys into the Unicode PUA rather than making them high a top bit set, some compilers cannot handle enums that are larger than int. GitHub issue 2673. --- input-keys.c | 2 +- key-string.c | 6 +++--- status.c | 2 +- tmux.h | 33 ++++++++++++++++++++++++--------- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/input-keys.c b/input-keys.c index a3252855..ffd2201c 100644 --- a/input-keys.c +++ b/input-keys.c @@ -476,7 +476,7 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key) input_key_write(__func__, bev, &ud.data[0], 1); return (0); } - if (justkey > 0x7f && justkey < KEYC_BASE) { + if (KEYC_IS_UNICODE(justkey)) { if (key & KEYC_META) input_key_write(__func__, bev, "\033", 1); utf8_to_data(justkey, &ud); diff --git a/key-string.c b/key-string.c index c24a33fc..b41eaa73 100644 --- a/key-string.c +++ b/key-string.c @@ -238,7 +238,7 @@ key_string_lookup_string(const char *string) } /* Convert the standard control keys. */ - if (key < KEYC_BASE && + if (KEYC_IS_UNICODE(key) && (modifiers & KEYC_CTRL) && strchr(other, key) == NULL && key != 9 && @@ -368,8 +368,8 @@ key_string_lookup_key(key_code key, int with_flags) goto out; } - /* Is this a UTF-8 key? */ - if (key > 127 && key < KEYC_BASE) { + /* Is this a Unicode key? */ + if (KEYC_IS_UNICODE(key)) { utf8_to_data(key, &ud); off = strlen(out); memcpy(out + off, ud.data, ud.size); diff --git a/status.c b/status.c index 271e1afa..f4418500 100644 --- a/status.c +++ b/status.c @@ -1300,7 +1300,7 @@ process_key: return (0); append_key: - if (key <= 0x1f || key >= KEYC_BASE) + if (key <= 0x1f || (key >= KEYC_BASE && key < KEYC_BASE_END)) return (0); if (key <= 0x7f) utf8_set(&tmp, key); diff --git a/tmux.h b/tmux.h index 1e496e6f..735f4e68 100644 --- a/tmux.h +++ b/tmux.h @@ -109,11 +109,16 @@ struct winlink; #define VISUAL_ON 1 #define VISUAL_BOTH 2 -/* Special key codes. */ -#define KEYC_NONE 0x00ff000000000ULL -#define KEYC_UNKNOWN 0x00fe000000000ULL -#define KEYC_BASE 0x0001000000000ULL -#define KEYC_USER 0x0002000000000ULL +/* No key or unknown key. */ +#define KEYC_NONE 0x000ff000000000ULL +#define KEYC_UNKNOWN 0x000fe000000000ULL + +/* + * Base for special (that is, not Unicode) keys. An enum must be at most a + * signed int, so these are based in the highest Unicode PUA. + */ +#define KEYC_BASE 0x0000000010e000ULL +#define KEYC_USER 0x0000000010f000ULL /* Key modifier bits. */ #define KEYC_META 0x00100000000000ULL @@ -136,8 +141,15 @@ struct winlink; #define KEYC_NUSER 1000 /* Is this a mouse key? */ -#define KEYC_IS_MOUSE(key) (((key) & KEYC_MASK_KEY) >= KEYC_MOUSE && \ - ((key) & KEYC_MASK_KEY) < KEYC_BSPACE) +#define KEYC_IS_MOUSE(key) \ + (((key) & KEYC_MASK_KEY) >= KEYC_MOUSE && \ + ((key) & KEYC_MASK_KEY) < KEYC_BSPACE) + +/* Is this a Unicode key? */ +#define KEYC_IS_UNICODE(key) \ + (((key) & KEYC_MASK_KEY) > 0x7f && \ + (((key) & KEYC_MASK_KEY) < KEYC_BASE || \ + ((key) & KEYC_MASK_KEY) >= KEYC_BASE_END)) /* Multiple click timeout. */ #define KEYC_CLICK_TIMEOUT 300 @@ -159,8 +171,8 @@ struct winlink; { #s "Border", KEYC_ ## name ## _BORDER } /* - * A single key. This can be ASCII or Unicode or one of the keys starting at - * KEYC_BASE. + * A single key. This can be ASCII or Unicode or one of the keys between + * KEYC_BASE and KEYC_BASE_END. */ typedef unsigned long long key_code; @@ -253,6 +265,9 @@ enum { KEYC_KP_ENTER, KEYC_KP_ZERO, KEYC_KP_PERIOD, + + /* End of special keys. */ + KEYC_BASE_END }; /* Termcap codes. */ From ad2f7642f2795fc1073c02cfa6348e48dfdfc45d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 28 Apr 2021 20:20:53 +0100 Subject: [PATCH 21/34] Ctrl keys are < 0x7f, not Unicode. --- key-string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key-string.c b/key-string.c index b41eaa73..406d26dd 100644 --- a/key-string.c +++ b/key-string.c @@ -238,7 +238,7 @@ key_string_lookup_string(const char *string) } /* Convert the standard control keys. */ - if (KEYC_IS_UNICODE(key) && + if (key <= 127 && (modifiers & KEYC_CTRL) && strchr(other, key) == NULL && key != 9 && From bacb4d1b4df77c0f4ad940edcd75bbafef8efa9f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 May 2021 06:39:17 +0100 Subject: [PATCH 22/34] Fix warnings, from Jan Tache in GitHub issue 2692. --- format.c | 2 +- server.c | 3 ++- tty-term.c | 2 +- window-buffer.c | 6 +++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/format.c b/format.c index 5a12502e..c7960819 100644 --- a/format.c +++ b/format.c @@ -4199,7 +4199,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, value = xstrdup("0"); } else { format_log(es, "search '%s' pane %%%u", new, wp->id); - value = format_search(fm, wp, new); + value = format_search(search, wp, new); } free(new); } else if (cmp != NULL) { diff --git a/server.c b/server.c index 0b878d9e..29bcf88a 100644 --- a/server.c +++ b/server.c @@ -163,7 +163,8 @@ server_tidy_event(__unused int fd, __unused short events, __unused void *data) malloc_trim(0); #endif - log_debug("%s: took %llu milliseconds", __func__, get_timer() - t); + log_debug("%s: took %llu milliseconds", __func__, + (unsigned long long)(get_timer() - t)); evtimer_add(&server_ev_tidy, &tv); } diff --git a/tty-term.c b/tty-term.c index 4a7e7415..add71d89 100644 --- a/tty-term.c +++ b/tty-term.c @@ -697,7 +697,7 @@ tty_term_read_list(const char *name, int fd, char ***caps, u_int *ncaps, ent = &tty_term_codes[i]; switch (ent->type) { case TTYCODE_NONE: - break; + continue; case TTYCODE_STRING: s = tigetstr((char *)ent->name); if (s == NULL || s == (char *)-1) diff --git a/window-buffer.c b/window-buffer.c index 8d93558a..c1ddcc74 100644 --- a/window-buffer.c +++ b/window-buffer.c @@ -294,9 +294,9 @@ window_buffer_get_key(void *modedata, void *itemdata, u_int line) struct window_buffer_modedata *data = modedata; struct window_buffer_itemdata *item = itemdata; struct format_tree *ft; - struct session *s; - struct winlink *wl; - struct window_pane *wp; + struct session *s = NULL; + struct winlink *wl = NULL; + struct window_pane *wp = NULL; struct paste_buffer *pb; char *expanded; key_code key; From aaf87abfb4a93067c3fcb78d604636886252791a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 3 May 2021 10:49:51 +0100 Subject: [PATCH 23/34] Fire check callback after cleaning up event so it does not get stuck, from Jeongho Jang in GitHub issue 2695. --- file.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/file.c b/file.c index baa2bd58..974c8a37 100644 --- a/file.c +++ b/file.c @@ -503,14 +503,14 @@ file_write_error_callback(__unused struct bufferevent *bev, __unused short what, log_debug("write error file %d", cf->stream); - if (cf->cb != NULL) - cf->cb(NULL, NULL, 0, -1, NULL, cf->data); - bufferevent_free(cf->event); cf->event = NULL; close(cf->fd); cf->fd = -1; + + if (cf->cb != NULL) + cf->cb(NULL, NULL, 0, -1, NULL, cf->data); } /* Client file write callback. */ From 47af583a50db35e1fbf881845d0aa342e8fa57c8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 5 May 2021 07:23:23 +0100 Subject: [PATCH 24/34] Remove old shift function keys which interfere with xterm keys now. GitHub issue 2696. --- input-keys.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/input-keys.c b/input-keys.c index ffd2201c..be83600e 100644 --- a/input-keys.c +++ b/input-keys.c @@ -94,30 +94,6 @@ static struct input_key_entry input_key_defaults[] = { { .key = KEYC_F12, .data = "\033[24~" }, - { .key = KEYC_F1|KEYC_SHIFT, - .data = "\033[25~" - }, - { .key = KEYC_F2|KEYC_SHIFT, - .data = "\033[26~" - }, - { .key = KEYC_F3|KEYC_SHIFT, - .data = "\033[28~" - }, - { .key = KEYC_F4|KEYC_SHIFT, - .data = "\033[29~" - }, - { .key = KEYC_F5|KEYC_SHIFT, - .data = "\033[31~" - }, - { .key = KEYC_F6|KEYC_SHIFT, - .data = "\033[32~" - }, - { .key = KEYC_F7|KEYC_SHIFT, - .data = "\033[33~" - }, - { .key = KEYC_F8|KEYC_SHIFT, - .data = "\033[34~" - }, { .key = KEYC_IC, .data = "\033[2~" }, From 434ac8734af2a15d5661139acc06a9659f4feed9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 10 May 2021 07:42:35 +0100 Subject: [PATCH 25/34] Looks like evports on SunOS are broken also, disable them. GitHub issue 2702. --- osdep-sunos.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/osdep-sunos.c b/osdep-sunos.c index 138e6bad..c3563ca4 100644 --- a/osdep-sunos.c +++ b/osdep-sunos.c @@ -96,5 +96,17 @@ osdep_get_cwd(int fd) struct event_base * osdep_event_init(void) { - return (event_init()); + struct event_base *base; + + /* + * On Illumos, evports don't seem to work properly. It is not clear if + * this a problem in libevent, with the way tmux uses file descriptors, + * or with some types of file descriptor. But using poll instead is + * fine. + */ + setenv("EVENT_NOEVPORT", "1", 1); + + base = event_init(); + unsetenv("EVENT_NOEVPORT"); + return (base); } From 5ea6ccbb7f75b6a977fca0751ef0b81b18c375d1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 10 May 2021 07:51:30 +0100 Subject: [PATCH 26/34] Do not expand the file given with -f so it can contain :s. --- tmux.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tmux.c b/tmux.c index 3a49c803..29921781 100644 --- a/tmux.c +++ b/tmux.c @@ -328,7 +328,7 @@ main(int argc, char **argv) char *path = NULL, *label = NULL; char *cause, **var; const char *s, *cwd; - int opt, keys, feat = 0; + int opt, keys, feat = 0, fflag = 0; uint64_t flags = 0; const struct options_table_entry *oe; u_int i; @@ -373,10 +373,15 @@ main(int argc, char **argv) flags |= CLIENT_CONTROL; break; case 'f': - for (i = 0; i < cfg_nfiles; i++) - free(cfg_files[i]); - free(cfg_files); - expand_paths(optarg, &cfg_files, &cfg_nfiles, 0); + if (!fflag) { + fflag = 1; + for (i = 0; i < cfg_nfiles; i++) + free(cfg_files[i]); + cfg_nfiles = 0; + } + cfg_files = xreallocarray(cfg_files, cfg_nfiles + 1, + sizeof *cfg_files); + cfg_files[cfg_nfiles++] = xstrdup(optarg); cfg_quiet = 0; break; case 'V': From 8aa34f616fa6723f4a98c435ddcab0ecaaa5b4e7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 12 May 2021 07:08:58 +0100 Subject: [PATCH 27/34] Do not use NULL client when source-file finishes, GitHub issue 2707. --- cmd-source-file.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd-source-file.c b/cmd-source-file.c index 1da59193..c1eeba58 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -67,7 +67,9 @@ cmd_source_file_complete(struct client *c, struct cmd_source_file_data *cdata) struct cmdq_item *new_item; if (cfg_finished) { - if (cdata->retval == CMD_RETURN_ERROR && c->session == NULL) + if (cdata->retval == CMD_RETURN_ERROR && + c != NULL && + c->session == NULL) c->retval = 1; new_item = cmdq_get_callback(cmd_source_file_complete_cb, NULL); cmdq_insert_after(cdata->after, new_item); From 3b9b823df50202e466470d3cb557ef16a31b6af7 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 17 May 2021 06:58:45 +0100 Subject: [PATCH 28/34] Fix <= operator. --- format.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/format.c b/format.c index c7960819..3e640a6f 100644 --- a/format.c +++ b/format.c @@ -3991,7 +3991,7 @@ format_replace_expression(struct format_modifier *mexp, result = (mleft < mright); break; case LESS_THAN_EQUAL: - result = (mleft > mright); + result = (mleft >= mright); break; } if (use_fp) From 9b4c05b6b9aec916c0940aa704c5f2ec9e1a8a83 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 17 May 2021 06:59:29 +0100 Subject: [PATCH 29/34] Er, fix it properly. --- format.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/format.c b/format.c index 3e640a6f..6ac086cb 100644 --- a/format.c +++ b/format.c @@ -3991,7 +3991,7 @@ format_replace_expression(struct format_modifier *mexp, result = (mleft < mright); break; case LESS_THAN_EQUAL: - result = (mleft >= mright); + result = (mleft <= mright); break; } if (use_fp) From f06ee2b87b88d0889e8dfeb2ae85a2b7d4ce0d49 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 19 May 2021 09:04:45 +0100 Subject: [PATCH 30/34] Bump FORMAT_LOOOP_LIMIT and add a log message when hit, GitHub issue 2715. --- format.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/format.c b/format.c index 6ac086cb..512df009 100644 --- a/format.c +++ b/format.c @@ -103,7 +103,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2) #define FORMAT_CHARACTER 0x10000 /* Limit on recursion. */ -#define FORMAT_LOOP_LIMIT 10 +#define FORMAT_LOOP_LIMIT 100 /* Format expand flags. */ #define FORMAT_EXPAND_TIME 0x1 @@ -4441,8 +4441,10 @@ format_expand1(struct format_expand_state *es, const char *fmt) if (fmt == NULL || *fmt == '\0') return (xstrdup("")); - if (es->loop == FORMAT_LOOP_LIMIT) + if (es->loop == FORMAT_LOOP_LIMIT) { + format_log(es, "reached loop limit (%u)", FORMAT_LOOP_LIMIT); return (xstrdup("")); + } es->loop++; format_log(es, "expanding format: %s", fmt); From f48c46a76adb78527627894c07ca45a393d7fa2c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 19 May 2021 09:05:53 +0100 Subject: [PATCH 31/34] Fix rectangle selection, from Anindya Mukherjee, GitHub issue 2709. --- window-copy.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/window-copy.c b/window-copy.c index 423cce8f..f92e02ba 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1102,10 +1102,13 @@ static enum window_copy_cmd_action window_copy_cmd_cursor_right(struct window_copy_cmd_state *cs) { struct window_mode_entry *wme = cs->wme; + struct window_copy_mode_data *data = wme->data; u_int np = wme->prefix; - for (; np != 0; np--) - window_copy_cursor_right(wme, 0); + for (; np != 0; np--) { + window_copy_cursor_right(wme, data->screen.sel != NULL && + data->rectflag); + } return (WINDOW_COPY_CMD_NOTHING); } @@ -4425,10 +4428,12 @@ window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only) struct window_copy_mode_data *data = wme->data; struct screen *s = &data->screen; u_int ox, oy, px, py; + int norectsel; + norectsel = data->screen.sel == NULL || !data->rectflag; oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wme, oy); - if (data->cx != ox) { + if (norectsel && data->cx != ox) { data->lastcx = data->cx; data->lastsx = ox; } @@ -4437,7 +4442,8 @@ window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only) window_copy_other_end(wme); if (scroll_only || data->cy == 0) { - data->cx = data->lastcx; + if (norectsel) + data->cx = data->lastcx; window_copy_scroll_down(wme, 1); if (scroll_only) { if (data->cy == screen_size_y(s) - 1) @@ -4446,7 +4452,11 @@ window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only) window_copy_redraw_lines(wme, data->cy, 2); } } else { - window_copy_update_cursor(wme, data->lastcx, data->cy - 1); + if (norectsel) { + window_copy_update_cursor(wme, data->lastcx, + data->cy - 1); + } else + window_copy_update_cursor(wme, data->cx, data->cy - 1); if (window_copy_update_selection(wme, 1, 0)) { if (data->cy == screen_size_y(s) - 1) window_copy_redraw_lines(wme, data->cy, 1); @@ -4455,7 +4465,7 @@ window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only) } } - if (data->screen.sel == NULL || !data->rectflag) { + if (norectsel) { py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wme, py); if ((data->cx >= data->lastsx && data->cx != px) || @@ -4492,10 +4502,12 @@ window_copy_cursor_down(struct window_mode_entry *wme, int scroll_only) struct window_copy_mode_data *data = wme->data; struct screen *s = &data->screen; u_int ox, oy, px, py; + int norectsel; + norectsel = data->screen.sel == NULL || !data->rectflag; oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wme, oy); - if (data->cx != ox) { + if (norectsel && data->cx != ox) { data->lastcx = data->cx; data->lastsx = ox; } @@ -4504,17 +4516,22 @@ window_copy_cursor_down(struct window_mode_entry *wme, int scroll_only) window_copy_other_end(wme); if (scroll_only || data->cy == screen_size_y(s) - 1) { - data->cx = data->lastcx; + if (norectsel) + data->cx = data->lastcx; window_copy_scroll_up(wme, 1); if (scroll_only && data->cy > 0) window_copy_redraw_lines(wme, data->cy - 1, 2); } else { - window_copy_update_cursor(wme, data->lastcx, data->cy + 1); + if (norectsel) { + window_copy_update_cursor(wme, data->lastcx, + data->cy + 1); + } else + window_copy_update_cursor(wme, data->cx, data->cy + 1); if (window_copy_update_selection(wme, 1, 0)) window_copy_redraw_lines(wme, data->cy - 1, 2); } - if (data->screen.sel == NULL || !data->rectflag) { + if (norectsel) { py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wme, py); if ((data->cx >= data->lastsx && data->cx != px) || From d8feffd2bfd0c53a3323a4bda830acaafed259ed Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 8 Jun 2021 10:49:40 +0100 Subject: [PATCH 32/34] Feature for the mouse since FreeBSD termcap does not have kmous. --- tmux.1 | 4 ++++ tty-features.c | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index 22982b11..365b93f5 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3539,6 +3539,10 @@ Supports extended keys. Supports focus reporting. .It margins Supports DECSLRM margins. +.It mouse +Supports +.Xr xterm 1 +mouse sequences. .It overline Supports the overline SGR attribute. .It rectfill diff --git a/tty-features.c b/tty-features.c index b42cf74a..48ac51be 100644 --- a/tty-features.c +++ b/tty-features.c @@ -25,7 +25,6 @@ /* * Still hardcoded: - * - mouse (under kmous capability); * - default colours (under AX or op capabilities); * - AIX colours (under colors >= 16); * - alternate escape (if terminal is VT100-like). @@ -54,6 +53,17 @@ static const struct tty_feature tty_feature_title = { 0 }; +/* Terminal has mouse support. */ +static const char *tty_feature_mouse_capabilities[] = { + "kmous=\\E[M", + NULL +}; +static const struct tty_feature tty_feature_mouse = { + "mouse", + tty_feature_mouse_capabilities, + 0 +}; + /* Terminal can set the clipboard with OSC 52. */ static const char *tty_feature_clipboard_capabilities[] = { "Ms=\\E]52;%p1%s;%p2%s\\a", @@ -238,6 +248,7 @@ static const struct tty_feature *tty_features[] = { &tty_feature_extkeys, &tty_feature_focus, &tty_feature_margins, + &tty_feature_mouse, &tty_feature_overline, &tty_feature_rectfill, &tty_feature_rgb, @@ -338,7 +349,7 @@ tty_default_features(int *feat, const char *name, u_int version) const char *features; } table[] = { #define TTY_FEATURES_BASE_MODERN_XTERM \ - "256,RGB,bpaste,clipboard,strikethrough,title" + "256,RGB,bpaste,clipboard,mouse,strikethrough,title" { .name = "mintty", .features = TTY_FEATURES_BASE_MODERN_XTERM ",ccolour,cstyle,extkeys,margins,overline,usstyle" @@ -348,7 +359,7 @@ tty_default_features(int *feat, const char *name, u_int version) ",ccolour,cstyle,focus,overline,usstyle" }, { .name = "rxvt-unicode", - .features = "256,bpaste,ccolour,cstyle,title" + .features = "256,bpaste,ccolour,cstyle,mouse,title" }, { .name = "iTerm2", .features = TTY_FEATURES_BASE_MODERN_XTERM From c827f5092db2142af097e32d02fb73d70acbfa6d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 9 Jun 2021 14:46:24 +0100 Subject: [PATCH 33/34] Do not clear region based on current cursor position, this is not necessary anymore and causes problems, GitHub issue 2735. --- tty.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tty.c b/tty.c index e8a8cbaa..9e7dfde8 100644 --- a/tty.c +++ b/tty.c @@ -958,13 +958,8 @@ tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx) return; } - if (ctx->ocy < ctx->orupper || ctx->ocy > ctx->orlower) { - for (i = ctx->ocy; i < ctx->sy; i++) - tty_draw_pane(tty, ctx, i); - } else { - for (i = ctx->orupper; i <= ctx->orlower; i++) - tty_draw_pane(tty, ctx, i); - } + for (i = ctx->orupper; i <= ctx->orlower; i++) + tty_draw_pane(tty, ctx, i); } /* Is this position visible in the pane? */ From 3b929f332aafa7f1080eacc31feb11ffbb1d1841 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 10 Jun 2021 09:24:57 +0100 Subject: [PATCH 34/34] Update CHANGES. --- CHANGES | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index e50c061b..f9c9d007 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,15 @@ CHANGES FROM 3.2 TO 3.2a -XXX +* Add an "always" value for the "extended-keys" option; if set then tmux will + forward extended keys to applications even if they do not request them. + +* Add a "mouse" terminal feature so tmux can enable the mouse on terminals + where it is known to be supported even if terminfo(5) says otherwise. + +* Do not expand the filename given to -f so it can contain colons. + +* Fixes for problems with extended keys and modifiers, scroll region, + source-file, crosscompiling, format modifiers and other minor issues. CHANGES FROM 3.1c TO 3.2