From cbd419c4832975e3c8a83e9ead22d67f528bbc2b Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 29 Sep 2024 20:05:42 +0000 Subject: [PATCH 01/49] Fix grey colour, from Magnus Gross. --- colour.c | 2 +- tmux.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/colour.c b/colour.c index 0b787acb..5fd91c9c 100644 --- a/colour.c +++ b/colour.c @@ -948,7 +948,7 @@ colour_byname(const char *name) if (strncmp(name, "grey", 4) == 0 || strncmp(name, "gray", 4) == 0) { if (name[4] == '\0') - return (-1); + return (0xbebebe|COLOUR_FLAG_RGB); c = strtonum(name + 4, 0, 100, &errstr); if (errstr != NULL) return (-1); diff --git a/tmux.c b/tmux.c index a9619baf..30960245 100644 --- a/tmux.c +++ b/tmux.c @@ -408,9 +408,9 @@ main(int argc, char **argv) cfg_files[cfg_nfiles++] = xstrdup(optarg); cfg_quiet = 0; break; - case 'V': + case 'V': printf("tmux %s\n", getversion()); - exit(0); + exit(0); case 'l': flags |= CLIENT_LOGIN; break; From a1b7a3bcb32066a36367fbcd4ebbfedbd6ad8ec1 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 30 Sep 2024 07:54:51 +0000 Subject: [PATCH 02/49] Only use default-shell for popups, return to /bin/sh for run-shell, if-shell and #() - these have been documented as using /bin/sh for a long time and scripts rely on it. Pointed out by Gregory Pakosz. --- job.c | 23 +++++++++++++++-------- popup.c | 2 +- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/job.c b/job.c index cab91d2c..eeb90f42 100644 --- a/job.c +++ b/job.c @@ -69,9 +69,10 @@ static LIST_HEAD(joblist, job) all_jobs = LIST_HEAD_INITIALIZER(all_jobs); /* Start a job running. */ struct job * -job_run(const char *cmd, int argc, char **argv, struct environ *e, struct session *s, - const char *cwd, job_update_cb updatecb, job_complete_cb completecb, - job_free_cb freecb, void *data, int flags, int sx, int sy) +job_run(const char *cmd, int argc, char **argv, struct environ *e, + struct session *s, const char *cwd, job_update_cb updatecb, + job_complete_cb completecb, job_free_cb freecb, void *data, int flags, + int sx, int sy) { struct job *job; struct environ *env; @@ -81,6 +82,7 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio sigset_t set, oldset; struct winsize ws; char **argvp, tty[TTY_NAME_MAX], *argv0; + struct options *oo; /* * Do not set TERM during .tmux.conf (second argument here), it is nice @@ -91,12 +93,17 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio if (e != NULL) environ_copy(e, env); - if (s != NULL) - shell = options_get_string(s->options, "default-shell"); - else - shell = options_get_string(global_s_options, "default-shell"); - if (!checkshell(shell)) + if (~flags & JOB_DEFAULTSHELL) shell = _PATH_BSHELL; + else { + if (s != NULL) + oo = s->options; + else + oo = global_s_options; + shell = options_get_string(oo, "default-shell"); + if (!checkshell(shell)) + shell = _PATH_BSHELL; + } argv0 = shell_argv0(shell, 0); sigfillset(&set); diff --git a/popup.c b/popup.c index 706295fe..97f532c0 100644 --- a/popup.c +++ b/popup.c @@ -717,7 +717,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px, pd->job = job_run(shellcmd, argc, argv, env, s, cwd, popup_job_update_cb, popup_job_complete_cb, NULL, pd, - JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE, jx, jy); + JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE|JOB_DEFAULTSHELL, jx, jy); pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette); server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb, From 868ddf5d38584c3d67ae32a23aeafc415d3d287f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 30 Sep 2024 13:09:50 +0100 Subject: [PATCH 03/49] 3.5a bits. --- CHANGES | 7 +++++++ configure.ac | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index d88d4024..6185ddc6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +CHANGES FROM 3.5 TO 3.5a + +* Revert to using /bin/sh for #() and run-shell and if-shell; the change to use + default-shell only applies now to popups. + +* Fix grey colour without a number suffix in styles. + CHANGES FROM 3.4 TO 3.5 * Revamp extended keys support to more closely match xterm and support mode 2 diff --git a/configure.ac b/configure.ac index 2a834037..97e5ca50 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT([tmux], 3.5) +AC_INIT([tmux], 3.5a) AC_PREREQ([2.60]) AC_CONFIG_AUX_DIR(etc) From 834ec91b445721211d3eb3e21b780607b78453a8 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 2 Oct 2024 08:06:45 +0000 Subject: [PATCH 04/49] Report shifted keys like S-A as A not as S-A in mode 1 extended keys, from Stanislav Kljuhhin. --- input-keys.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/input-keys.c b/input-keys.c index 4dd42e1b..05971dae 100644 --- a/input-keys.c +++ b/input-keys.c @@ -553,6 +553,10 @@ input_key_mode1(struct bufferevent *bev, key_code key) (onlykey >= '@' && onlykey <= '~'))) return (input_key_vt10x(bev, key)); + /* Avoid reporting A as Shift-A, which is not expected in mode 1. */ + if ((key & KEYC_MASK_MODIFIERS) == KEYC_SHIFT) + return (input_key_vt10x(bev, key)); + /* * A regular key + Meta. In the absence of a standard to back this, we * mimic what iTerm 2 does. From 356887bca27b48e895eca261e0989319f432de73 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 3 Oct 2024 05:41:59 +0000 Subject: [PATCH 05/49] Improve fix for shifted keys so it works for all the keys it should, Stanislav Kljuhhin in GitHub issue 4146. --- input-keys.c | 4 ---- tty-keys.c | 30 ++++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/input-keys.c b/input-keys.c index 05971dae..4dd42e1b 100644 --- a/input-keys.c +++ b/input-keys.c @@ -553,10 +553,6 @@ input_key_mode1(struct bufferevent *bev, key_code key) (onlykey >= '@' && onlykey <= '~'))) return (input_key_vt10x(bev, key)); - /* Avoid reporting A as Shift-A, which is not expected in mode 1. */ - if ((key & KEYC_MASK_MODIFIERS) == KEYC_SHIFT) - return (input_key_vt10x(bev, key)); - /* * A regular key + Meta. In the absence of a standard to back this, we * mimic what iTerm 2 does. diff --git a/tty-keys.c b/tty-keys.c index 3debeea1..76e26a8b 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -930,7 +930,7 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, u_int number, modifiers; char tmp[64]; cc_t bspace; - key_code nkey; + key_code nkey, onlykey; struct utf8_data ud; utf8_char uc; @@ -994,13 +994,7 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, /* Update the modifiers. */ if (modifiers > 0) { modifiers--; - /* - * The Shift modifier may not be reported in some input modes, - * which is unfortunate, as in general case determining if a - * character is shifted or not requires knowing the input - * keyboard layout. So we only fix up the trivial case. - */ - if (modifiers & 1 || (nkey >= 'A' && nkey <= 'Z')) + if (modifiers & 1) nkey |= KEYC_SHIFT; if (modifiers & 2) nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Alt */ @@ -1014,6 +1008,26 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, if ((nkey & KEYC_MASK_KEY) == '\011' && (nkey & KEYC_SHIFT)) nkey = KEYC_BTAB | (nkey & ~KEYC_MASK_KEY & ~KEYC_SHIFT); + /* + * Deal with the Shift modifier when present alone. The problem is that + * in mode 2 some terminals would report shifted keys, like S-a, as + * just A, and some as S-A. + * + * Because we need an unambiguous internal representation, and because + * restoring the Shift modifier when it's missing would require knowing + * the keyboard layout, and because S-A would cause a lot of issues + * downstream, we choose to lose the Shift for all printable + * characters. + * + * That still leaves some ambiguity, such as C-S-A vs. C-A, but that's + * OK, and applications can handle that. + */ + onlykey = nkey & KEYC_MASK_KEY; + if (((onlykey > 0x20 && onlykey < 0x7f) || + KEYC_IS_UNICODE(nkey)) && + (nkey & KEYC_MASK_MODIFIERS) == KEYC_SHIFT) + nkey &= ~KEYC_SHIFT; + if (log_get_level() != 0) { log_debug("%s: extended key %.*s is %llx (%s)", c->name, (int)*size, buf, nkey, key_string_lookup_key(nkey, 1)); From 048db82041a9866e52306ea88169b8e5352ef386 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 4 Oct 2024 14:55:17 +0000 Subject: [PATCH 06/49] Do not translate BSpace as Unicode, GitHub issue 4156. --- tty-keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty-keys.c b/tty-keys.c index 76e26a8b..5416c78b 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -983,7 +983,7 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, nkey = number; /* Convert UTF-32 codepoint into internal representation. */ - if (nkey & ~0x7f) { + if (nkey != KEYC_BSPACE && nkey & ~0x7f) { if (utf8_fromwc(nkey, &ud) == UTF8_DONE && utf8_from_data(&ud, &uc) == UTF8_DONE) nkey = uc; From 7997fd315279a15e86cc1ee2649e74603007bb1b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 4 Oct 2024 18:59:53 +0100 Subject: [PATCH 07/49] Missing define. --- tmux.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tmux.h b/tmux.h index 0b14ccd0..071d9d29 100644 --- a/tmux.h +++ b/tmux.h @@ -2341,6 +2341,7 @@ typedef void (*job_free_cb) (void *); #define JOB_NOWAIT 0x1 #define JOB_KEEPWRITE 0x2 #define JOB_PTY 0x4 +#define JOB_DEFAULTSHELL 0x8 struct job *job_run(const char *, int, char **, struct environ *, struct session *, const char *, job_update_cb, job_complete_cb, job_free_cb, void *, int, int, int); From 42959db0a487ee655f53eaaf9d5d9920fca5a9e1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 Oct 2024 07:00:22 +0100 Subject: [PATCH 08/49] Update CHANGES. --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 6185ddc6..344a1ccc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,9 @@ CHANGES FROM 3.5 TO 3.5a +* Do not translate BSpace as Unicode with extended keys. + +* Fix so that keys with Shift are represented correctly with extended keys. + * Revert to using /bin/sh for #() and run-shell and if-shell; the change to use default-shell only applies now to popups. From 549c35b06165f6ae023115eb76f83f2cbf945395 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 5 Oct 2024 07:01:16 +0100 Subject: [PATCH 09/49] Update regression tests. --- regress/capture-pane-sgr0.sh | 4 +-- regress/combine-test.result | 2 +- regress/format-strings.sh | 2 +- regress/input-keys.sh | 23 +++++++------ regress/tty-keys.sh | 62 ++++++++++++++++++------------------ 5 files changed, 48 insertions(+), 45 deletions(-) diff --git a/regress/capture-pane-sgr0.sh b/regress/capture-pane-sgr0.sh index 6a19ac8a..5d21ccc4 100644 --- a/regress/capture-pane-sgr0.sh +++ b/regress/capture-pane-sgr0.sh @@ -22,8 +22,8 @@ $TMUX -f/dev/null new -d " sleep 1 ( - printf '\033[1m\033[31m\033[42mabc\033[0m\033[31m\033[49mdef\n' - printf '\033[39m\033[100m bright bg\n' + printf '\033[1m\033[31m\033[42mabc\033[0m\033[31mdef\033[39m\n' + printf '\033[100m bright bg \033[49m\n' ) | cmp - $TMP || exit 1 $TMUX has 2>/dev/null && exit 1 diff --git a/regress/combine-test.result b/regress/combine-test.result index 8fb411ba..0d2afb5e 100644 --- a/regress/combine-test.result +++ b/regress/combine-test.result @@ -6,7 +6,7 @@ 👍🏻3 👍🏻 👍🏻4 🤷‍♂️5 -♂️ 7 +♂️7 🤷‍♂️8 🤷‍♂️9 🤷‍♂️10 diff --git a/regress/format-strings.sh b/regress/format-strings.sh index 0ae27386..bc4b00f7 100644 --- a/regress/format-strings.sh +++ b/regress/format-strings.sh @@ -172,7 +172,7 @@ test_format "#{l:#{pane_in_mode}}" "#{pane_in_mode}" test_format "#{l:#{?pane_in_mode,#{?#{==:#{session_name},Summer},ABC,XYZ},xyz}}" "#{?pane_in_mode,#{?#{==:#{session_name},Summer},ABC,XYZ},xyz}" # With escapes (which escape but are returned literally) -test_format "#{l:##{}" "##{" +test_format "#{l:##{}" "#{" test_format "#{l:#{#}}}" "#{#}}" # Invalid formats: diff --git a/regress/input-keys.sh b/regress/input-keys.sh index 262d12a6..d3b90995 100644 --- a/regress/input-keys.sh +++ b/regress/input-keys.sh @@ -6,10 +6,10 @@ TERM=screen [ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux) TMUX="$TEST_TMUX -Ltest" $TMUX kill-server 2>/dev/null - +sleep 1 $TMUX -f/dev/null new -x20 -y2 -d || exit 1 - -sleep 0.1 +sleep 1 +$TMUX set -g escape-time 0 exit_status=0 @@ -17,11 +17,14 @@ assert_key () { key=$1 expected_code=$2 - $TMUX new-window -- sh -c 'stty raw -echo && cat -tv' - $TMUX send-keys "$key" $ + W=$($TMUX new-window -P -- sh -c 'stty raw -echo && cat -tv') + $TMUX send-keys -t$W "$key" 'EOL' || exit 1 + sleep 0.2 - actual_code=$($TMUX capturep -p | head -1 | sed -e 's/\$$//') - $TMUX kill-window + actual_code=$($TMUX capturep -pt$W | \ + head -1 | \ + sed -e 's/EOL.*$//') + $TMUX kill-window -t$W || exit 1 if [ "$actual_code" = "$expected_code" ]; then if [ -n "$VERBOSE" ]; then @@ -205,7 +208,7 @@ assert_key 'PageUp' '^[[5~' assert_key 'PgUp' '^[[5~' assert_key 'BTab' '^[[Z' -assert_key 'C-S-Tab' '^[[Z' +assert_key 'C-S-Tab' '^I' assert_key 'Up' '^[[A' assert_key 'Down' '^[[B' @@ -291,8 +294,8 @@ assert_extended_key 'Insert' '^[[2;_~' assert_extended_key 'DC' '^[[3;_~' assert_extended_key 'Delete' '^[[3;_~' -assert_key 'C-Tab' "^[[9;5u" -assert_key 'C-S-Tab' "^[[1;5Z" +assert_key 'C-Tab' "^[[27;5;9~" +assert_key 'C-S-Tab' "^[[27;6;9~" $TMUX kill-server 2>/dev/null diff --git a/regress/tty-keys.sh b/regress/tty-keys.sh index 1fcc3657..0a1fe6bf 100644 --- a/regress/tty-keys.sh +++ b/regress/tty-keys.sh @@ -14,7 +14,7 @@ trap "rm -f $TMP" 0 1 15 $TMUX2 -f/dev/null new -d || exit 1 $TMUX -f/dev/null new -d "$TMUX2 attach" || exit 1 -sleep 0.1 +sleep 1 exit_status=0 @@ -60,38 +60,38 @@ assert_key () { } -assert_key 0x00 'C-Space' # -- 'Escape 0x00' 'M-C-Space' -assert_key 0x01 'C-a' -- 'Escape 0x01' 'M-C-a' -assert_key 0x02 'C-b' -- 'Escape 0x02' 'M-C-b' -assert_key 0x03 'C-c' -- 'Escape 0x03' 'M-C-c' -assert_key 0x04 'C-d' -- 'Escape 0x04' 'M-C-d' -assert_key 0x05 'C-e' -- 'Escape 0x05' 'M-C-e' -assert_key 0x06 'C-f' -- 'Escape 0x06' 'M-C-f' -assert_key 0x07 'C-g' -- 'Escape 0x07' 'M-C-g' -assert_key 0x08 'C-h' -- 'Escape 0x08' 'M-C-h' +assert_key 0x00 'C-Space' # -- 'Escape 0x00' 'C-M-Space' +assert_key 0x01 'C-a' -- 'Escape 0x01' 'C-M-a' +assert_key 0x02 'C-b' -- 'Escape 0x02' 'C-M-b' +assert_key 0x03 'C-c' -- 'Escape 0x03' 'C-M-c' +assert_key 0x04 'C-d' -- 'Escape 0x04' 'C-M-d' +assert_key 0x05 'C-e' -- 'Escape 0x05' 'C-M-e' +assert_key 0x06 'C-f' -- 'Escape 0x06' 'C-M-f' +assert_key 0x07 'C-g' -- 'Escape 0x07' 'C-M-g' +assert_key 0x08 'C-h' -- 'Escape 0x08' 'C-M-h' assert_key 0x09 'Tab' -- 'Escape 0x09' 'M-Tab' -assert_key 0x0A 'C-j' -- 'Escape 0x0A' 'M-C-j' -assert_key 0x0B 'C-k' -- 'Escape 0x0B' 'M-C-k' -assert_key 0x0C 'C-l' -- 'Escape 0x0C' 'M-C-l' +assert_key 0x0A 'C-j' -- 'Escape 0x0A' 'C-M-j' +assert_key 0x0B 'C-k' -- 'Escape 0x0B' 'C-M-k' +assert_key 0x0C 'C-l' -- 'Escape 0x0C' 'C-M-l' assert_key 0x0D 'Enter' -- 'Escape 0x0D' 'M-Enter' -assert_key 0x0E 'C-n' -- 'Escape 0x0E' 'M-C-n' -assert_key 0x0F 'C-o' -- 'Escape 0x0F' 'M-C-o' -assert_key 0x10 'C-p' -- 'Escape 0x10' 'M-C-p' -assert_key 0x11 'C-q' -- 'Escape 0x11' 'M-C-q' -assert_key 0x12 'C-r' -- 'Escape 0x12' 'M-C-r' -assert_key 0x13 'C-s' -- 'Escape 0x13' 'M-C-s' -assert_key 0x14 'C-t' -- 'Escape 0x14' 'M-C-t' -assert_key 0x15 'C-u' -- 'Escape 0x15' 'M-C-u' -assert_key 0x16 'C-v' -- 'Escape 0x16' 'M-C-v' -assert_key 0x17 'C-w' -- 'Escape 0x17' 'M-C-w' -assert_key 0x18 'C-x' -- 'Escape 0x18' 'M-C-x' -assert_key 0x19 'C-y' -- 'Escape 0x19' 'M-C-y' -assert_key 0x1A 'C-z' -- 'Escape 0x1A' 'M-C-z' +assert_key 0x0E 'C-n' -- 'Escape 0x0E' 'C-M-n' +assert_key 0x0F 'C-o' -- 'Escape 0x0F' 'C-M-o' +assert_key 0x10 'C-p' -- 'Escape 0x10' 'C-M-p' +assert_key 0x11 'C-q' -- 'Escape 0x11' 'C-M-q' +assert_key 0x12 'C-r' -- 'Escape 0x12' 'C-M-r' +assert_key 0x13 'C-s' -- 'Escape 0x13' 'C-M-s' +assert_key 0x14 'C-t' -- 'Escape 0x14' 'C-M-t' +assert_key 0x15 'C-u' -- 'Escape 0x15' 'C-M-u' +assert_key 0x16 'C-v' -- 'Escape 0x16' 'C-M-v' +assert_key 0x17 'C-w' -- 'Escape 0x17' 'C-M-w' +assert_key 0x18 'C-x' -- 'Escape 0x18' 'C-M-x' +assert_key 0x19 'C-y' -- 'Escape 0x19' 'C-M-y' +assert_key 0x1A 'C-z' -- 'Escape 0x1A' 'C-M-z' assert_key 0x1B 'Escape' -- 'Escape 0x1B' 'M-Escape' -assert_key 0x1C "C-\\" -- 'Escape 0x1C' "M-C-\\" -assert_key 0x1D 'C-]' -- 'Escape 0x1D' 'M-C-]' -assert_key 0x1E 'C-^' -- 'Escape 0x1E' 'M-C-^' -assert_key 0x1F 'C-_' -- 'Escape 0x1F' 'M-C-_' +assert_key 0x1C "C-\\" -- 'Escape 0x1C' "C-M-\\" +assert_key 0x1D 'C-]' -- 'Escape 0x1D' 'C-M-]' +assert_key 0x1E 'C-^' -- 'Escape 0x1E' 'C-M-^' +assert_key 0x1F 'C-_' -- 'Escape 0x1F' 'C-M-_' assert_key 0x20 'Space' -- 'Escape 0x20' 'M-Space' assert_key 0x21 '!' -- 'Escape 0x21' 'M-!' assert_key 0x22 '"' -- 'Escape 0x22' 'M-"' @@ -304,7 +304,7 @@ assert_extended_key () { key_name=$2 assert_key "Escape [${code};5u" "C-$key_name" - assert_key "Escape [${code};7u" "M-C-$key_name" + assert_key "Escape [${code};7u" "C-M-$key_name" } # Extended keys From 1d89233047c68e5f16f302416436fbf478f9f8b2 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 25 Nov 2025 20:27:23 +0000 Subject: [PATCH 10/49] Add a resize callback for menus so that they are correctly moved on resize. From m-einfalt at gmx dot de in GitHub issue 4696. --- menu.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/menu.c b/menu.c index fd3a9fe4..7449d88d 100644 --- a/menu.c +++ b/menu.c @@ -438,6 +438,38 @@ chosen: return (1); } +static void +menu_resize_cb(struct client *c, void *data) +{ + struct menu_data *md = data; + u_int nx, ny, w, h; + + if (md == NULL) + return; + + nx = md->px; + ny = md->py; + + w = md->menu->width + 4; + h = md->menu->count + 2; + + if (nx + w > c->tty.sx) { + if (c->tty.sx <= w) + nx = 0; + else + nx = c->tty.sx - w; + } + + if (ny + h > c->tty.sy) { + if (c->tty.sy <= h) + ny = 0; + else + ny = c->tty.sy - h; + } + md->px = nx; + md->py = ny; +} + static void menu_set_style(struct client *c, struct grid_cell *gc, const char *style, const char *option) @@ -551,6 +583,6 @@ menu_display(struct menu *menu, int flags, int starting_choice, if (md == NULL) return (-1); server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb, - menu_key_cb, menu_free_cb, NULL, md); + menu_key_cb, menu_free_cb, menu_resize_cb, md); return (0); } From ca74fa1db0d631dcdcf8741f7fb6b470a1130750 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 25 Nov 2025 21:21:59 +0000 Subject: [PATCH 11/49] Update version and CHANGES. --- CHANGES | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++- configure.ac | 2 +- 2 files changed, 199 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index e1334c81..0cec4881 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,200 @@ +CHANGES FROM 3.5a TO 3.6 + +* Make -v to source-file pass through to subsequent source-file commands (issue + 4216). + +* If display-popup is used inside a popup, modify that popup (issue 4678). + +* Add selection-mode command to expilcitly set the selection mode in copy mode + (issue 3842). + +* Save and restore images in alternate screen (issue 3732). + +* Ignore Hangul filler character (issue 3998). + +* Improve handling of regional indicators and emoji modifiers (issue 3998). + +* Preserve marked pane with swap-window and move-window (issue 3443). + +* Set and check COLORTERM as a hint for RGB colour. + +* If tmux receives a palette request (OSC 4) in a pane and the palette entry + has not been set, send a request to the most recently used client and + forward any response instead (based on change from Tim Culverhouse, issue + 4665). + +* Add -l flag to command-prompt to disable splitting into multiple prompts + (issue 4483). + +* Don't enter copy mode on mouse wheel in alternate screen (issue 3705). + +* Add commands to centre the cursor in copy mode (issue 4662). + +* Support case insensitive search in modes in the same way as copy mode + (like emacs, so all-lowercase means case insensitive) (issue 4396). + +* Fix the logic of the no-detached case for the detach-on-destroy option (from + Martin Louazel, issue 4649). + +* Add buffer_full format variable (from Mohammad AlSaleh, issue 4630). + +* Introduce a new window option, tiled-layout-max-columns, which configures the + maximum number of columns in the tiled layout. + +* Add support for DECRQSS SP q (report cursor style), DECRQM ?12 (report cursor + blink state) and DECRQM ?2004, ?1004, ?1006 (report mouse state) ( rom + Andrea Alberti, issue 4618). + +* Fix missing argument from OSC 4 reply (issue 4596). + +* Add -k flag to display-popup which allows any key to dismiss the popup once + the command has exited (from Meriel Luna Mittelbach, issue 4612). + +* Add nicer default second and third status lines (from Michael Grant, issue + 4490). + +* Add a pane-border-lines "spaces" value to use spaces for pane borders (issue + 4587). + +* Replace invalid UTF-8 characters with the placeholder instead of ignoring + them (issue 4514). + +* Fix incorrect handling of Korean Hangul Jamo characters (from Roy Jung, issue + 4546). + +* Allow uppercase letters in gray/grey color names (from Pavel Roskin, issue + 4560). + +* Add sorting to W, P, L loop operators (from Michael Grant, issue 4516). + +* Detect support for OSC 52 using the device attributes report (from James + Holderness, issue 4539). + +* Add noattr for styles and use in mode-style to allow whether attributes are + ignored or used to be configured (issue 4498). + +* Add a set-default style attribute which replaces the current default colours + and attributes completely. + +* Add -E to run-shell to forward stderr as well as stdout (issue 4246). + +* Add an option variation-selector-always-wide to instruct tmux not to + always interpret VS16 as a wide character and assume the terminal does + likewise. + +* Switch to getopt_long from OpenSSH (from Koichi Murase, issue 4492). + +* Add more features for boolean expressions in formats: 1) extend && and || to + support arbitrarily many arguments and 2) add ! and !! for not and not-not + (from David Mandelberg). + +* Do not mistake other DCS sequences for SIXEL sequences (from James + Holderness, issue 4488). + +* Improve #? conditional expression in formats: add support for else if and + default empty string if no else value (from David Mandelberg, issue 4451). + +* Add default-client-command to set the command used if tmux is run without a + command; the default stays new-session (from David Mandelberg, issue + 4422). + +* Add S-Up and S-Down to move windows in tree mode (from David Mandelberg, + issue 4415). + +* Add mode 2031 support to automatically report dark or light theme. tmux will + guess the theme from the background colour on terminals which do not + themselves support the escape sequence (from Jonathan Slenders, issue 4353). + +* Add -M flag to capture-pane to use the copy mode screen (issue 4358). + +* Align index numbers in trees (from David Mandelberg, issue 4360). + +* Add display-message -C flag to update pane while message is displayed (from + Vitaly Ostrosablin, issue 4363). + +* Make list-commands command show only one command if an argument is given + (from Ilya Grigoriev, issue 4352). + +* Count line numbers correctly inside strings in configuration files (reported + by Pedro Navarro, issue 4325). + +* Map bright black (colour 8) to white (7) if the background is black on + terminals with only eight colours so the text is not invisible (from Dmytro + Bagrii, issue 4322). + +* New codepoint-widths option allowing users to override the width of + individual Unicode codepoints. + +* Add a nesting limit to source-file (from Fadi Afani, issue 4223). + +* Add copy-mode-position-style and copy-mode-selection-style options for copy + mode. + +* Add no-detach-on-destroy client option (issue 4242). + +* Add input-buffer-size option (from Ken Lau). + +* Add support for a scrollbar at the side of each pane. New options + pane-scrollbars turn them on or off, pane-scrollbars-position sets the + position (left or right), and pane-scrollbars-style to set the colours (from + Michael Grant, issue 4221). + +* Allow control characters to be entered at the command prompt by prefixing + with C-v (from Alexander Arch, issue 4206). + +* Do not attempt to search for zero length strings (from Alexander Arch, issue + 4209). + +* Preserve tabs for copying and capture-pane (from Alexander Arch, issue + 4201). + +* Increase the maximum for repeat-time. + +* Adjust how Ctrl and Meta keys are sent to use standard representation if + available in mode 1 (from Stanislav Kljuhhin, issue 4188). + +* Allow attributes in menu style (from Japin Li, issue 4194). + +* Add a sixel_support format variable which is 1 if SIXEL is supported, always + 0 on OpenBSD (requested by Misaki Masa, issue 4177). + +* Add prompt-cursor-colour and prompt-cursor-style to set the style of the + cursor in the command prompt and remove the emulated cursor (from Alexander + Arch, issue 4170). + +* Add initial-repeat-time option to allow the first repeat time to be increased + and later reduced (from David le Blanc, issue 4164). + +* Send focus events to pane when entering or leaving popup (issue 3991). + +* Add copy-mode-position-format to configure the position indicator. + +* Add -y flag to disable confirmation prompts in modes (issue 4152). + +* Add -C and -P flags to the copy commands in copy mode: -C prevents the + commands from sending the text to the clipboard and -P prevents them from + adding the text as a paste buffer (issue 4153). + +* Preserve transparency and raster attribute dimensions when sending a SIXEL + image, and avoid collapsing empty lines (issue 4149). + +* Bypass permission check for Cygwin (based on a change by Yuya Adachi via + Rafael Kitover, issue 4148). + +* Add MSYSTEM to default update-environment (for Cgywin). + +* Set client stdout file descriptor also for Cgywin (from Michael Wild via Rafael + Kitover, issue 4148). + +* Use global cursor style and colour options for modes instead of default + (issue 4117). + +* Fix pasting so it does not interpret keys but instead copies the input + without interpretation (reported by Mark Kelly). + +* Try to query window pixel size from the outside terminal if the values + returned by TIOCGWINSZ are zero (Dmitry Galchinsky, issue 4099). + CHANGES FROM 3.5 TO 3.5a * Do not translate BSpace as Unicode with extended keys. @@ -8,7 +205,7 @@ CHANGES FROM 3.5 TO 3.5a default-shell only applies now to popups. * Fix grey colour without a number suffix in styles. - + CHANGES FROM 3.4 TO 3.5 * Revamp extended keys support to more closely match xterm and support mode 2 diff --git a/configure.ac b/configure.ac index e6d4b548..4be9e03a 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT([tmux], next-3.7) +AC_INIT([tmux], 3.6) AC_PREREQ([2.60]) AC_CONFIG_AUX_DIR(etc) From f0dec832b893f23829a01edaba6733db1f9d3f5a Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 25 Nov 2025 21:24:27 +0000 Subject: [PATCH 12/49] Add seconds options for clock mode, from augustus7613 dot mail at pm dot me in GitHub issue 4697. --- options-table.c | 2 +- tmux.1 | 2 +- window-clock.c | 24 +++++++++++++++++------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/options-table.c b/options-table.c index e31178fa..980f8684 100644 --- a/options-table.c +++ b/options-table.c @@ -37,7 +37,7 @@ static const char *options_table_mode_keys_list[] = { "emacs", "vi", NULL }; static const char *options_table_clock_mode_style_list[] = { - "12", "24", NULL + "12", "24", "12-with-seconds", "24-with-seconds", NULL }; static const char *options_table_status_list[] = { "off", "on", "2", "3", "4", "5", NULL diff --git a/tmux.1 b/tmux.1 index 9a602927..51fb4002 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4925,7 +4925,7 @@ option is enabled. Set clock colour. .Pp .It Xo Ic clock-mode-style -.Op Ic 12 | 24 +.Op Ic 12 | 24 | 12-with-seconds | 24-with-seconds .Xc Set clock hour format. .Pp diff --git a/window-clock.c b/window-clock.c index 8cef3f9a..51620d4a 100644 --- a/window-clock.c +++ b/window-clock.c @@ -45,7 +45,7 @@ const struct window_mode window_clock_mode = { }; struct window_clock_mode_data { - struct screen screen; + struct screen screen; time_t tim; struct event timer; }; @@ -142,7 +142,7 @@ window_clock_timer_callback(__unused int fd, __unused short events, void *arg) t = time(NULL); gmtime_r(&t, &now); gmtime_r(&data->tim, &then); - if (now.tm_min == then.tm_min) + if (now.tm_sec == then.tm_sec) return; data->tim = t; @@ -207,11 +207,12 @@ window_clock_draw_screen(struct window_mode_entry *wme) { struct window_pane *wp = wme->wp; struct window_clock_mode_data *data = wme->data; - struct screen_write_ctx ctx; + struct screen_write_ctx ctx; int colour, style; struct screen *s = &data->screen; struct grid_cell gc; char tim[64], *ptr; + const char *timeformat; time_t t; struct tm *tm; u_int i, j, x, y, idx; @@ -223,14 +224,23 @@ window_clock_draw_screen(struct window_mode_entry *wme) t = time(NULL); tm = localtime(&t); - if (style == 0) { - strftime(tim, sizeof tim, "%l:%M ", localtime(&t)); + if (style == 0 || style == 2) { + if (style == 2) + timeformat = "%l:%M:%S "; + else + timeformat = "%l:%M "; + strftime(tim, sizeof tim, timeformat, localtime(&t)); if (tm->tm_hour >= 12) strlcat(tim, "PM", sizeof tim); else strlcat(tim, "AM", sizeof tim); - } else - strftime(tim, sizeof tim, "%H:%M", tm); + } else { + if (style == 3) + timeformat = "%H:%M:%S"; + else + timeformat = "%H:%M"; + strftime(tim, sizeof tim, timeformat, tm); + } screen_write_clearscreen(&ctx, 8); From 00cef3e6be2f6ca7bf4ae9dffe467b6bb7d71014 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 25 Nov 2025 22:07:09 +0000 Subject: [PATCH 13/49] Add to CHANGES. --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index 0cec4881..886d1673 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,8 @@ CHANGES FROM 3.5a TO 3.6 +* Add a resize callback for menus so that they are correctly moved on resize + (issue 4696). + * Make -v to source-file pass through to subsequent source-file commands (issue 4216). From a6690032adfaa20e307321f31bb51f308a90059d Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 25 Nov 2025 21:24:27 +0000 Subject: [PATCH 14/49] Add seconds options for clock mode, from augustus7613 dot mail at pm dot me in GitHub issue 4697. --- options-table.c | 2 +- tmux.1 | 2 +- window-clock.c | 24 +++++++++++++++++------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/options-table.c b/options-table.c index 6946a085..8989c264 100644 --- a/options-table.c +++ b/options-table.c @@ -36,7 +36,7 @@ static const char *options_table_mode_keys_list[] = { "emacs", "vi", NULL }; static const char *options_table_clock_mode_style_list[] = { - "12", "24", NULL + "12", "24", "12-with-seconds", "24-with-seconds", NULL }; static const char *options_table_status_list[] = { "off", "on", "2", "3", "4", "5", NULL diff --git a/tmux.1 b/tmux.1 index a25da1fb..5a17095d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4927,7 +4927,7 @@ option is enabled. Set clock colour. .Pp .It Xo Ic clock-mode-style -.Op Ic 12 | 24 +.Op Ic 12 | 24 | 12-with-seconds | 24-with-seconds .Xc Set clock hour format. .Pp diff --git a/window-clock.c b/window-clock.c index 8cef3f9a..51620d4a 100644 --- a/window-clock.c +++ b/window-clock.c @@ -45,7 +45,7 @@ const struct window_mode window_clock_mode = { }; struct window_clock_mode_data { - struct screen screen; + struct screen screen; time_t tim; struct event timer; }; @@ -142,7 +142,7 @@ window_clock_timer_callback(__unused int fd, __unused short events, void *arg) t = time(NULL); gmtime_r(&t, &now); gmtime_r(&data->tim, &then); - if (now.tm_min == then.tm_min) + if (now.tm_sec == then.tm_sec) return; data->tim = t; @@ -207,11 +207,12 @@ window_clock_draw_screen(struct window_mode_entry *wme) { struct window_pane *wp = wme->wp; struct window_clock_mode_data *data = wme->data; - struct screen_write_ctx ctx; + struct screen_write_ctx ctx; int colour, style; struct screen *s = &data->screen; struct grid_cell gc; char tim[64], *ptr; + const char *timeformat; time_t t; struct tm *tm; u_int i, j, x, y, idx; @@ -223,14 +224,23 @@ window_clock_draw_screen(struct window_mode_entry *wme) t = time(NULL); tm = localtime(&t); - if (style == 0) { - strftime(tim, sizeof tim, "%l:%M ", localtime(&t)); + if (style == 0 || style == 2) { + if (style == 2) + timeformat = "%l:%M:%S "; + else + timeformat = "%l:%M "; + strftime(tim, sizeof tim, timeformat, localtime(&t)); if (tm->tm_hour >= 12) strlcat(tim, "PM", sizeof tim); else strlcat(tim, "AM", sizeof tim); - } else - strftime(tim, sizeof tim, "%H:%M", tm); + } else { + if (style == 3) + timeformat = "%H:%M:%S"; + else + timeformat = "%H:%M"; + strftime(tim, sizeof tim, timeformat, tm); + } screen_write_clearscreen(&ctx, 8); From 0dac7fe434d029a4f0b819cba8eb7963df291990 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 26 Nov 2025 08:34:33 +0000 Subject: [PATCH 15/49] Add to CHANGES. --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 886d1673..eb0080ec 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,7 @@ CHANGES FROM 3.5a TO 3.6 +* Add seconds options for clock mode (issue 4697). + * Add a resize callback for menus so that they are correctly moved on resize (issue 4696). From 1decccace71b17a19dd3ec2355c73116e0812aa9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 26 Nov 2025 08:44:41 +0000 Subject: [PATCH 16/49] Update version. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4be9e03a..e6d4b548 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT([tmux], 3.6) +AC_INIT([tmux], next-3.7) AC_PREREQ([2.60]) AC_CONFIG_AUX_DIR(etc) From bfa2f733351da5b2ee2674408eac744b067622fb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 26 Nov 2025 10:41:17 +0000 Subject: [PATCH 17/49] Need signal.h for utempter, from Yasuhiro Kimura. --- server-fn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/server-fn.c b/server-fn.c index 6ab7fa48..29802a60 100644 --- a/server-fn.c +++ b/server-fn.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include From 6db6a30ab508c4a924245e2d8ccb7bac39838d5c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 26 Nov 2025 10:41:17 +0000 Subject: [PATCH 18/49] Need signal.h for utempter, from Yasuhiro Kimura. --- server-fn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/server-fn.c b/server-fn.c index 6ab7fa48..29802a60 100644 --- a/server-fn.c +++ b/server-fn.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include From a0dfef3b04ee446610ea5f5e85927216213221f8 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 26 Nov 2025 18:57:18 +0000 Subject: [PATCH 19/49] Place cursor on correct line if message-line is not 0, reported by Alexis Hildebrandt. --- server-client.c | 14 +++++++------- status.c | 13 +++++++++---- tmux.h | 1 + 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/server-client.c b/server-client.c index 14ebe5fb..184717a4 100644 --- a/server-client.c +++ b/server-client.c @@ -2905,8 +2905,8 @@ server_client_reset_state(struct client *c) struct window_pane *wp = server_client_get_pane(c), *loop; struct screen *s = NULL; struct options *oo = c->session->options; - int mode = 0, cursor, flags, n; - u_int cx = 0, cy = 0, ox, oy, sx, sy; + int mode = 0, cursor, flags; + u_int cx = 0, cy = 0, ox, oy, sx, sy, n; if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) return; @@ -2938,13 +2938,13 @@ server_client_reset_state(struct client *c) if (c->prompt_string != NULL) { n = options_get_number(oo, "status-position"); if (n == 0) - cy = 0; + cy = status_prompt_line_at(c); else { - n = status_line_size(c); - if (n == 0) - cy = tty->sy - 1; - else + n = status_line_size(c) - status_prompt_line_at(c); + if (n <= tty->sy) cy = tty->sy - n; + else + cy = tty->sy - 1; } cx = c->prompt_cursor; } else if (c->overlay_draw == NULL) { diff --git a/status.c b/status.c index 2786db7e..0551b547 100644 --- a/status.c +++ b/status.c @@ -264,14 +264,19 @@ status_line_size(struct client *c) } /* Get the prompt line number for client's session. 1 means at the bottom. */ -static u_int +u_int status_prompt_line_at(struct client *c) { struct session *s = c->session; + u_int line, lines; - if (c->flags & (CLIENT_STATUSOFF|CLIENT_CONTROL)) - return (1); - return (options_get_number(s->options, "message-line")); + lines = status_line_size(c); + if (lines == 0) + return (0); + line = options_get_number(s->options, "message-line"); + if (line >= lines) + return (lines - 1); + return (line); } /* Get window at window list position. */ diff --git a/tmux.h b/tmux.h index 99b80c68..20d3678a 100644 --- a/tmux.h +++ b/tmux.h @@ -2898,6 +2898,7 @@ extern u_int status_prompt_hsize[]; void status_timer_start(struct client *); void status_timer_start_all(void); void status_update_cache(struct session *); +u_int status_prompt_line_at(struct client *); int status_at_line(struct client *); u_int status_line_size(struct client *); struct style_range *status_get_range(struct client *, u_int, u_int); From ec4b5b52afa6e98f313896815018926911e39160 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 26 Nov 2025 19:00:17 +0000 Subject: [PATCH 20/49] Version and CHANGES. --- CHANGES | 4 ++++ configure.ac | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index eb0080ec..4abece81 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +CHANGES FROM 3.6 TO 3.6a + +* Fix compile error on FreeBSD (from Yasuhiro Kimura, issue 4701). + CHANGES FROM 3.5a TO 3.6 * Add seconds options for clock mode (issue 4697). diff --git a/configure.ac b/configure.ac index 4be9e03a..200e82de 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT([tmux], 3.6) +AC_INIT([tmux], 3.6a) AC_PREREQ([2.60]) AC_CONFIG_AUX_DIR(etc) From e3a54ed0f46a4ac65c0abcdc445b291388fcdbdc Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 26 Nov 2025 19:02:03 +0000 Subject: [PATCH 21/49] Newer libevents do not allow event_del on a zero'd event. --- tty.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tty.c b/tty.c index bd0c6b37..cfff58c4 100644 --- a/tty.c +++ b/tty.c @@ -35,6 +35,8 @@ static int tty_log_fd = -1; +static void tty_start_timer_callback(int, short, void *); +static void tty_clipboard_query_callback(int, short, void *); 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); @@ -291,6 +293,8 @@ tty_open(struct tty *tty, char **cause) if (tty->out == NULL) fatal("out of memory"); + evtimer_set(&tty->clipboard_timer, tty_clipboard_query_callback, tty); + evtimer_set(&tty->start_timer, tty_start_timer_callback, tty); evtimer_set(&tty->timer, tty_timer_callback, tty); tty_start_tty(tty); @@ -322,7 +326,6 @@ tty_start_start_timer(struct tty *tty) log_debug("%s: start timer started", c->name); evtimer_del(&tty->start_timer); - evtimer_set(&tty->start_timer, tty_start_timer_callback, tty); evtimer_add(&tty->start_timer, &tv); } @@ -440,6 +443,7 @@ tty_stop_tty(struct tty *tty) tty->flags &= ~TTY_STARTED; evtimer_del(&tty->start_timer); + evtimer_del(&tty->clipboard_timer); event_del(&tty->timer); tty->flags &= ~TTY_BLOCK; @@ -3106,6 +3110,5 @@ tty_clipboard_query(struct tty *tty) tty_putcode_ss(tty, TTYC_MS, "", "?"); tty->flags |= TTY_OSC52QUERY; - evtimer_set(&tty->clipboard_timer, tty_clipboard_query_callback, tty); evtimer_add(&tty->clipboard_timer, &tv); } From 0af04295f3cc622c711711e1d0b1befd06837493 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 26 Nov 2025 19:02:03 +0000 Subject: [PATCH 22/49] Newer libevents do not allow event_del on a zero'd event. --- tty.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tty.c b/tty.c index 889bee2c..71293f6b 100644 --- a/tty.c +++ b/tty.c @@ -35,6 +35,8 @@ static int tty_log_fd = -1; +static void tty_start_timer_callback(int, short, void *); +static void tty_clipboard_query_callback(int, short, void *); 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); @@ -296,6 +298,8 @@ tty_open(struct tty *tty, char **cause) if (tty->out == NULL) fatal("out of memory"); + evtimer_set(&tty->clipboard_timer, tty_clipboard_query_callback, tty); + evtimer_set(&tty->start_timer, tty_start_timer_callback, tty); evtimer_set(&tty->timer, tty_timer_callback, tty); tty_start_tty(tty); @@ -327,7 +331,6 @@ tty_start_start_timer(struct tty *tty) log_debug("%s: start timer started", c->name); evtimer_del(&tty->start_timer); - evtimer_set(&tty->start_timer, tty_start_timer_callback, tty); evtimer_add(&tty->start_timer, &tv); } @@ -445,6 +448,7 @@ tty_stop_tty(struct tty *tty) tty->flags &= ~TTY_STARTED; evtimer_del(&tty->start_timer); + evtimer_del(&tty->clipboard_timer); event_del(&tty->timer); tty->flags &= ~TTY_BLOCK; @@ -3228,6 +3232,5 @@ tty_clipboard_query(struct tty *tty) tty_putcode_ss(tty, TTYC_MS, "", "?"); tty->flags |= TTY_OSC52QUERY; - evtimer_set(&tty->clipboard_timer, tty_clipboard_query_callback, tty); evtimer_add(&tty->clipboard_timer, &tv); } From 2a0b078e1519bd710cfee9975bd6b0f885063dac Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 26 Nov 2025 18:57:18 +0000 Subject: [PATCH 23/49] Place cursor on correct line if message-line is not 0, reported by Alexis Hildebrandt. --- server-client.c | 14 +++++++------- status.c | 13 +++++++++---- tmux.h | 1 + 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/server-client.c b/server-client.c index b67ae7c2..047365a1 100644 --- a/server-client.c +++ b/server-client.c @@ -2901,8 +2901,8 @@ server_client_reset_state(struct client *c) struct window_pane *wp = server_client_get_pane(c), *loop; struct screen *s = NULL; struct options *oo = c->session->options; - int mode = 0, cursor, flags, n; - u_int cx = 0, cy = 0, ox, oy, sx, sy; + int mode = 0, cursor, flags; + u_int cx = 0, cy = 0, ox, oy, sx, sy, n; if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) return; @@ -2934,13 +2934,13 @@ server_client_reset_state(struct client *c) if (c->prompt_string != NULL) { n = options_get_number(oo, "status-position"); if (n == 0) - cy = 0; + cy = status_prompt_line_at(c); else { - n = status_line_size(c); - if (n == 0) - cy = tty->sy - 1; - else + n = status_line_size(c) - status_prompt_line_at(c); + if (n <= tty->sy) cy = tty->sy - n; + else + cy = tty->sy - 1; } cx = c->prompt_cursor; } else if (c->overlay_draw == NULL) { diff --git a/status.c b/status.c index 2786db7e..0551b547 100644 --- a/status.c +++ b/status.c @@ -264,14 +264,19 @@ status_line_size(struct client *c) } /* Get the prompt line number for client's session. 1 means at the bottom. */ -static u_int +u_int status_prompt_line_at(struct client *c) { struct session *s = c->session; + u_int line, lines; - if (c->flags & (CLIENT_STATUSOFF|CLIENT_CONTROL)) - return (1); - return (options_get_number(s->options, "message-line")); + lines = status_line_size(c); + if (lines == 0) + return (0); + line = options_get_number(s->options, "message-line"); + if (line >= lines) + return (lines - 1); + return (line); } /* Get window at window list position. */ diff --git a/tmux.h b/tmux.h index b2f10ca7..2184e6c6 100644 --- a/tmux.h +++ b/tmux.h @@ -2943,6 +2943,7 @@ extern u_int status_prompt_hsize[]; void status_timer_start(struct client *); void status_timer_start_all(void); void status_update_cache(struct session *); +u_int status_prompt_line_at(struct client *); int status_at_line(struct client *); u_int status_line_size(struct client *); struct style_range *status_get_range(struct client *, u_int, u_int); From 640e1a76438317303aefcd8b76d35a11e59594f6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 27 Nov 2025 07:26:09 +0000 Subject: [PATCH 24/49] Update CHANGES. --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 4abece81..d6b3013e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,9 @@ CHANGES FROM 3.6 TO 3.6a +* Newer libevents do not allow event_del on a zero'd event (issue 4706). + +* Place cursor on correct line if message-line is not 0 (issue 4707)). + * Fix compile error on FreeBSD (from Yasuhiro Kimura, issue 4701). CHANGES FROM 3.5a TO 3.6 From dfaf47d97c3ddc1f2879414ce32d91cf7b0e70ce Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 28 Nov 2025 09:14:17 +0000 Subject: [PATCH 25/49] session_index was never actually implemented, remove from man page. --- tmux.1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 51fb4002..832c0881 100644 --- a/tmux.1 +++ b/tmux.1 @@ -6133,7 +6133,6 @@ The following variables are available, where appropriate: .It Li "insert_flag" Ta "" Ta "Pane insert flag" .It Li "keypad_cursor_flag" Ta "" Ta "Pane keypad cursor flag" .It Li "keypad_flag" Ta "" Ta "Pane keypad flag" -.It Li "last_session_index" Ta "" Ta "Index of last session" .It Li "last_window_index" Ta "" Ta "Index of last window in session" .It Li "line" Ta "" Ta "Line number in the list" .It Li "loop_last_flag" Ta "" Ta "1 if last window, pane, session, client in the W:, P:, S:, or L: loop" @@ -6225,7 +6224,6 @@ The following variables are available, where appropriate: .It Li "session_group_size" Ta "" Ta "Size of session group" .It Li "session_grouped" Ta "" Ta "1 if session in a group" .It Li "session_id" Ta "" Ta "Unique session ID" -.It Li "session_index" Ta "" Ta "Index of session" .It Li "session_last_attached" Ta "" Ta "Time session last attached" .It Li "session_many_attached" Ta "" Ta "1 if multiple clients attached" .It Li "session_marked" Ta "" Ta "1 if this session contains the marked pane" From 55d660a548cbeb8cb3b6975cc67fa1b0b031a4e8 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 28 Nov 2025 09:42:48 +0000 Subject: [PATCH 26/49] Do not remove TERM etc for commands run from config file, reported by Dennis Eriksen. --- environ.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/environ.c b/environ.c index fb1c4902..0b4b3c31 100644 --- a/environ.c +++ b/environ.c @@ -263,11 +263,6 @@ environ_for_session(struct session *s, int no_TERM) environ_set(env, "TERM_PROGRAM", 0, "%s", "tmux"); environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion()); environ_set(env, "COLORTERM", 0, "truecolor"); - } else { - environ_unset(env, "TERM"); - environ_unset(env, "TERM_PROGRAM"); - environ_unset(env, "TERM_PROGRAM_VERSION"); - environ_unset(env, "COLORTERM"); } if (s != NULL) From 04f32073c0e1cea022634823b4fca5e2afd95405 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 1 Dec 2025 08:04:26 +0000 Subject: [PATCH 27/49] Add horizontal border case to server_client_check_mouse_in_pane to fix mouse resizing. GitHub issue 4720 from Michael Grant, reported by someone in GitHub issue 4715. --- server-client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server-client.c b/server-client.c index 184717a4..a48b9802 100644 --- a/server-client.c +++ b/server-client.c @@ -617,7 +617,8 @@ server_client_check_mouse_in_pane(struct window_pane *wp, u_int px, u_int py, line = wp->yoff + wp->sy; /* Check if point is within the pane or scrollbar. */ - if (((pane_status != PANE_STATUS_OFF && py != line) || + if (((pane_status != PANE_STATUS_OFF && + py != line && py != wp->yoff + wp->sy) || (wp->yoff == 0 && py < wp->sy) || (py >= wp->yoff && py < wp->yoff + wp->sy)) && ((sb_pos == PANE_SCROLLBARS_RIGHT && From e4c552f5a5526009d84917c0bc129e7503fe7590 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 1 Dec 2025 08:14:29 +0000 Subject: [PATCH 28/49] Change noattr to be an explicit attribute in the style so that it works correctly and does not delete attributes set in the style itself, GitHub issue 4713. --- attributes.c | 5 +++-- screen.c | 6 +++++- style.c | 35 +++++++++++++++++++---------------- tmux.h | 1 + 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/attributes.c b/attributes.c index b839f06d..8eaa8897 100644 --- a/attributes.c +++ b/attributes.c @@ -31,7 +31,7 @@ attributes_tostring(int attr) if (attr == 0) return ("none"); - len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", (attr & GRID_ATTR_CHARSET) ? "acs," : "", (attr & GRID_ATTR_BRIGHT) ? "bright," : "", (attr & GRID_ATTR_DIM) ? "dim," : "", @@ -45,7 +45,8 @@ attributes_tostring(int attr) (attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "", (attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "", (attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "", - (attr & GRID_ATTR_OVERLINE) ? "overline," : ""); + (attr & GRID_ATTR_OVERLINE) ? "overline," : "", + (attr & GRID_ATTR_NOATTR) ? "noattr," : ""); if (len > 0) buf[len - 1] = '\0'; diff --git a/screen.c b/screen.c index 626356b3..2b73cbce 100644 --- a/screen.c +++ b/screen.c @@ -577,8 +577,12 @@ screen_select_cell(struct screen *s, struct grid_cell *dst, if (COLOUR_DEFAULT(dst->bg)) dst->bg = src->bg; utf8_copy(&dst->data, &src->data); - dst->attr = src->attr; dst->flags = src->flags; + + if (dst->attr & GRID_ATTR_NOATTR) + dst->attr |= (src->attr & GRID_ATTR_CHARSET); + else + dst->attr |= src->attr; } /* Reflow wrapped lines. */ diff --git a/style.c b/style.c index ef3bb225..4acc17dd 100644 --- a/style.c +++ b/style.c @@ -218,20 +218,23 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in) sy->gc.attr = 0; else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) { if (strcmp(tmp + 2, "attr") == 0) - value = 0xffff & ~GRID_ATTR_CHARSET; - else if ((value = attributes_fromstring(tmp + 2)) == -1) - goto error; - sy->gc.attr &= ~value; + sy->gc.attr |= GRID_ATTR_NOATTR; + else { + value = attributes_fromstring(tmp + 2); + if (value == -1) + goto error; + sy->gc.attr &= ~value; + } } else if (end > 6 && strncasecmp(tmp, "width=", 6) == 0) { - n = strtonum(tmp + 6, 0, UINT_MAX, &errstr); - if (errstr != NULL) - goto error; - sy->width = (int)n; + n = strtonum(tmp + 6, 0, UINT_MAX, &errstr); + if (errstr != NULL) + goto error; + sy->width = (int)n; } else if (end > 4 && strncasecmp(tmp, "pad=", 4) == 0) { - n = strtonum(tmp + 4, 0, UINT_MAX, &errstr); - if (errstr != NULL) - goto error; - sy->pad = (int)n; + n = strtonum(tmp + 4, 0, UINT_MAX, &errstr); + if (errstr != NULL) + goto error; + sy->pad = (int)n; } else { if ((value = attributes_fromstring(tmp)) == -1) goto error; @@ -344,13 +347,13 @@ style_tostring(struct style *sy) attributes_tostring(gc->attr)); comma = ","; } - if (sy->width >= 0) { - xsnprintf(s + off, sizeof s - off, "%swidth=%u", comma, + if (sy->width >= 0) { + xsnprintf(s + off, sizeof s - off, "%swidth=%u", comma, sy->width); comma = ","; } - if (sy->pad >= 0) { - xsnprintf(s + off, sizeof s - off, "%spad=%u", comma, + if (sy->pad >= 0) { + xsnprintf(s + off, sizeof s - off, "%spad=%u", comma, sy->pad); comma = ","; } diff --git a/tmux.h b/tmux.h index 20d3678a..170183e7 100644 --- a/tmux.h +++ b/tmux.h @@ -718,6 +718,7 @@ struct colour_palette { #define GRID_ATTR_UNDERSCORE_4 0x800 #define GRID_ATTR_UNDERSCORE_5 0x1000 #define GRID_ATTR_OVERLINE 0x2000 +#define GRID_ATTR_NOATTR 0x4000 /* All underscore attributes. */ #define GRID_ATTR_ALL_UNDERSCORE \ From bfecbb068594bfbbc7ad8782abab4f5b11f89779 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 1 Dec 2025 08:21:04 +0000 Subject: [PATCH 29/49] Fix combine-test.result, GitHub issue 4717. --- regress/combine-test.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regress/combine-test.result b/regress/combine-test.result index 0d2afb5e..a08539fb 100644 --- a/regress/combine-test.result +++ b/regress/combine-test.result @@ -4,7 +4,7 @@ Λ̊1 🏻2 👍🏻3 -👍🏻 👍🏻4 +👍🏻 👍🏻4 🤷‍♂️5 ♂️7 🤷‍♂️8 From b2d6ebaa1067ddc7aa7b760318faa24822c77f8c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 1 Dec 2025 08:21:04 +0000 Subject: [PATCH 30/49] Fix combine-test.result, GitHub issue 4717. --- regress/combine-test.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regress/combine-test.result b/regress/combine-test.result index 0d2afb5e..a08539fb 100644 --- a/regress/combine-test.result +++ b/regress/combine-test.result @@ -4,7 +4,7 @@ Λ̊1 🏻2 👍🏻3 -👍🏻 👍🏻4 +👍🏻 👍🏻4 🤷‍♂️5 ♂️7 🤷‍♂️8 From 322adfbdde11c51af29def9ae85870c46bed1fd1 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 2 Dec 2025 08:20:32 +0000 Subject: [PATCH 31/49] Add a get-clipboard option which when enabled (the default is off) uses the same mechanism as palette requests to request clipboard from the terminal and forward to the requesting pane. Remove the now-redundant forward-to-pane ability from "refresh-client -l". GitHub issue 4275. --- cmd-refresh-client.c | 39 +++---------------- input.c | 91 +++++++++++++++++++++++++++++++++++++------- options-table.c | 15 ++++++++ tmux.1 | 35 +++++++++++++---- tmux.h | 9 ++++- tty-keys.c | 45 +++++++++------------- tty.c | 17 +++------ 7 files changed, 158 insertions(+), 93 deletions(-) diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 399c83de..cb30749e 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -34,7 +34,7 @@ const struct cmd_entry cmd_refresh_client_entry = { .name = "refresh-client", .alias = "refresh", - .args = { "A:B:cC:Df:r:F:l::LRSt:U", 0, 1, NULL }, + .args = { "A:B:cC:Df:r:F:lLRSt:U", 0, 1, NULL }, .usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] " "[-C XxY] [-f flags] [-r pane:report] " CMD_TARGET_CLIENT_USAGE " [adjustment]", @@ -163,37 +163,6 @@ out: free(copy); } -static enum cmd_retval -cmd_refresh_client_clipboard(struct cmd *self, struct cmdq_item *item) -{ - struct args *args = cmd_get_args(self); - struct client *tc = cmdq_get_target_client(item); - const char *p; - u_int i; - struct cmd_find_state fs; - - p = args_get(args, 'l'); - if (p == NULL) { - if (tc->flags & CLIENT_CLIPBOARDBUFFER) - return (CMD_RETURN_NORMAL); - tc->flags |= CLIENT_CLIPBOARDBUFFER; - } else { - if (cmd_find_target(&fs, item, p, CMD_FIND_PANE, 0) != 0) - return (CMD_RETURN_ERROR); - for (i = 0; i < tc->clipboard_npanes; i++) { - if (tc->clipboard_panes[i] == fs.wp->id) - break; - } - if (i != tc->clipboard_npanes) - return (CMD_RETURN_NORMAL); - tc->clipboard_panes = xreallocarray(tc->clipboard_panes, - tc->clipboard_npanes + 1, sizeof *tc->clipboard_panes); - tc->clipboard_panes[tc->clipboard_npanes++] = fs.wp->id; - } - tty_clipboard_query(&tc->tty); - return (CMD_RETURN_NORMAL); -} - static void cmd_refresh_report(struct tty *tty, const char *value) { @@ -284,8 +253,10 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_NORMAL); } - if (args_has(args, 'l')) - return (cmd_refresh_client_clipboard(self, item)); + if (args_has(args, 'l')) { + tty_clipboard_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')); diff --git a/input.c b/input.c index 139f9fd9..ce888887 100644 --- a/input.c +++ b/input.c @@ -3032,18 +3032,41 @@ input_osc_133(struct input_ctx *ictx, const char *p) } } +/* Handle OSC 52 reply. */ +static void +input_osc_52_reply(struct input_ctx *ictx) +{ + struct paste_buffer *pb; + int state; + const char *buf; + size_t len; + + state = options_get_number(global_options, "get-clipboard"); + if (state == 0) + return; + if (state == 1) { + if ((pb = paste_get_top(NULL)) == NULL) + return; + buf = paste_buffer_data(pb, &len); + if (ictx->input_end == INPUT_END_BEL) + input_reply_clipboard(ictx->event, buf, len, "\007"); + else + input_reply_clipboard(ictx->event, buf, len, "\033\\"); + return; + } + input_add_request(ictx, INPUT_REQUEST_CLIPBOARD, ictx->input_end); +} + /* Handle the OSC 52 sequence for setting the clipboard. */ static void input_osc_52(struct input_ctx *ictx, const char *p) { struct window_pane *wp = ictx->wp; + size_t len; char *end; - const char *buf = NULL; - size_t len = 0; u_char *out; int outlen, state; struct screen_write_ctx ctx; - struct paste_buffer *pb; const char* allow = "cpqs01234567"; char flags[sizeof "cpqs01234567"] = ""; u_int i, j = 0; @@ -3068,12 +3091,7 @@ input_osc_52(struct input_ctx *ictx, const char *p) log_debug("%s: %.*s %s", __func__, (int)(end - p - 1), p, flags); if (strcmp(end, "?") == 0) { - if ((pb = paste_get_top(NULL)) != NULL) - buf = paste_buffer_data(pb, &len); - if (ictx->input_end == INPUT_END_BEL) - input_reply_clipboard(ictx->event, buf, len, "\007"); - else - input_reply_clipboard(ictx->event, buf, len, "\033\\"); + input_osc_52_reply(ictx); return; } @@ -3132,6 +3150,7 @@ input_osc_104(struct input_ctx *ictx, const char *p) free(copy); } +/* Send a clipboard reply. */ void input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len, const char *end) @@ -3268,6 +3287,9 @@ input_add_request(struct input_ctx *ictx, enum input_request_type type, int idx) xsnprintf(s, sizeof s, "\033]4;%d;?\033\\", idx); tty_puts(&c->tty, s); break; + case INPUT_REQUEST_CLIPBOARD: + tty_putcode_ss(&c->tty, TTYC_MS, "", "?"); + break; case INPUT_REQUEST_QUEUE: break; } @@ -3275,6 +3297,39 @@ input_add_request(struct input_ctx *ictx, enum input_request_type type, int idx) return (0); } +/* Handle a palette reply. */ +static void +input_request_palette_reply(struct input_request *ir, void *data) +{ + struct input_request_palette_data *pd = data; + + input_osc_colour_reply(ir->ictx, 0, 4, pd->idx, pd->c, ir->end); +} + +/* Handle a clipboard reply. */ +static void +input_request_clipboard_reply(struct input_request *ir, void *data) +{ + struct input_ctx *ictx = ir->ictx; + struct input_request_clipboard_data *cd = data; + int state; + char *copy; + + state = options_get_number(global_options, "get-clipboard"); + if (state == 0 || state == 1) + return; + if (state == 3) { + copy = xmalloc(cd->len); + memcpy(copy, cd->buf, cd->len); + paste_add(NULL, copy, cd->len); + } + + if (ir->idx == INPUT_END_BEL) + input_reply_clipboard(ictx->event, cd->buf, cd->len, "\007"); + else + input_reply_clipboard(ictx->event, cd->buf, cd->len, "\033\\"); +} + /* Handle a reply to a request. */ void input_request_reply(struct client *c, enum input_request_type type, void *data) @@ -3284,11 +3339,18 @@ input_request_reply(struct client *c, enum input_request_type type, void *data) int complete = 0; TAILQ_FOREACH_SAFE(ir, &c->input_requests, centry, ir1) { - if (ir->type == type && pd->idx == ir->idx) { + if (ir->type != type) { + input_free_request(ir); + continue; + } + if (type == INPUT_REQUEST_PALETTE && pd->idx == ir->idx) { + found = ir; + break; + } + if (type == INPUT_REQUEST_CLIPBOARD) { found = ir; break; } - input_free_request(ir); } if (found == NULL) return; @@ -3298,8 +3360,11 @@ input_request_reply(struct client *c, enum input_request_type type, void *data) break; if (ir->type == INPUT_REQUEST_QUEUE) input_send_reply(ir->ictx, ir->data); - else if (ir == found && ir->type == INPUT_REQUEST_PALETTE) { - input_osc_colour_reply(ir->ictx, 0, 4, pd->idx, pd->c, ir->end); + else if (ir == found) { + if (ir->type == INPUT_REQUEST_PALETTE) + input_request_palette_reply(ir, data); + else if (ir->type == INPUT_REQUEST_CLIPBOARD) + input_request_clipboard_reply(ir, data); complete = 1; } input_free_request(ir); diff --git a/options-table.c b/options-table.c index 980f8684..b328a57f 100644 --- a/options-table.c +++ b/options-table.c @@ -85,6 +85,9 @@ static const char *options_table_popup_border_lines_list[] = { static const char *options_table_set_clipboard_list[] = { "off", "external", "on", NULL }; +static const char *options_table_get_clipboard_list[] = { + "off", "buffer", "request", "both", NULL +}; static const char *options_table_window_size_list[] = { "largest", "smallest", "manual", "latest", NULL }; @@ -406,6 +409,18 @@ const struct options_table_entry options_table[] = { .text = "Whether to send focus events to applications." }, + { .name = "get-clipboard", + .type = OPTIONS_TABLE_CHOICE, + .scope = OPTIONS_TABLE_SERVER, + .choices = options_table_get_clipboard_list, + .default_num = 1, + .text = "When an application requests the clipboard, whether to " + "ignore the request ('off'); respond with the newest buffer " + "('buffer'); request the clipboard from the most recently " + "used terminal ('request'); or to request the clipboard, " + "create a buffer, and send it to the application ('both')." + }, + { .name = "history-file", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SERVER, diff --git a/tmux.1 b/tmux.1 index 832c0881..dac3a648 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1361,12 +1361,11 @@ 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 cDLRSU +.Op Fl cDlLRSU .Op Fl A Ar pane:state .Op Fl B Ar name:what:format .Op Fl C Ar size .Op Fl f Ar flags -.Op Fl l Op Ar target-pane .Op Fl r Ar pane:report .Op Fl t Ar target-client .Op Ar adjustment @@ -1487,11 +1486,7 @@ a colon, then a report escape sequence. .Fl l requests the clipboard from the client using the .Xr xterm 1 -escape sequence. -If -.Ar target-pane -is given, the clipboard is sent (in encoded form), otherwise it is stored in a -new paste buffer. +escape sequence and stores it in a new paste buffer. .Pp .Fl L , .Fl R , @@ -4239,6 +4234,32 @@ passed through to applications running in .Nm . Attached clients should be detached and attached again after changing this option. +.It Xo Ic get-clipboard +.Op Ic both | request | buffer | off +.Xc +Controls the behaviour when an application requests the clipboard from +.Nm . +.Pp +If +.Ic off , +the request is ignored; +if +.Ic buffer , +.Nm +responds with the newest paste buffer; +.Ic request +causes +.Nm +to request the clipboard from the most recently used client (if possible) and +send the reply (if any) back to the application; +.Ic buffer +is the same as +.Ic request +but also creates a paste buffer. +.Pp +See also the +.Ic set-clipboard +option. .It Ic history-file Ar path If not empty, a file to which .Nm diff --git a/tmux.h b/tmux.h index 170183e7..9cd11609 100644 --- a/tmux.h +++ b/tmux.h @@ -1098,6 +1098,7 @@ struct window_mode_entry { /* Type of request to client. */ enum input_request_type { INPUT_REQUEST_PALETTE, + INPUT_REQUEST_CLIPBOARD, INPUT_REQUEST_QUEUE }; @@ -1107,6 +1108,12 @@ struct input_request_palette_data { int c; }; +/* Clipboard request reply data. */ +struct input_request_clipboard_data { + char *buf; + size_t len; +}; + /* Request sent to client on behalf of pane. */ TAILQ_HEAD(input_requests, input_request); @@ -1975,7 +1982,7 @@ struct client { #define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL #define CLIENT_CONTROL_WAITEXIT 0x200000000ULL #define CLIENT_WINDOWSIZECHANGED 0x400000000ULL -#define CLIENT_CLIPBOARDBUFFER 0x800000000ULL +/* 0x800000000ULL unused */ #define CLIENT_BRACKETPASTING 0x1000000000ULL #define CLIENT_ASSUMEPASTING 0x2000000000ULL #define CLIENT_REDRAWSCROLLBARS 0x4000000000ULL diff --git a/tty-keys.c b/tty-keys.c index 77254591..7474621c 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1301,12 +1301,11 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size, static int tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) { - struct client *c = tty->client; - struct window_pane *wp; - size_t end, terminator = 0, needed; - char *copy, *out; - int outlen; - u_int i; + struct client *c = tty->client; + size_t end, terminator = 0, needed; + char *copy, *out; + int outlen; + struct input_request_clipboard_data cd; *size = 0; @@ -1364,12 +1363,6 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) buf++; end--; - /* If we did not request this, ignore it. */ - if (~tty->flags & TTY_OSC52QUERY) - return (0); - tty->flags &= ~TTY_OSC52QUERY; - evtimer_del(&tty->clipboard_timer); - /* It has to be a string so copy it. */ copy = xmalloc(end + 1); memcpy(copy, buf, end); @@ -1384,22 +1377,22 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) return (0); } free(copy); - - /* Create a new paste buffer and forward to panes. */ log_debug("%s: %.*s", __func__, outlen, out); - if (c->flags & CLIENT_CLIPBOARDBUFFER) { - paste_add(NULL, out, outlen); - c->flags &= ~CLIENT_CLIPBOARDBUFFER; - } - for (i = 0; i < c->clipboard_npanes; i++) { - wp = window_pane_find_by_id(c->clipboard_panes[i]); - if (wp != NULL) - input_reply_clipboard(wp->event, out, outlen, "\033\\"); - } - free(c->clipboard_panes); - c->clipboard_panes = NULL; - c->clipboard_npanes = 0; + /* Set reply if any. */ + cd.buf = out; + cd.len = outlen; + input_request_reply(c, INPUT_REQUEST_CLIPBOARD, &cd); + + /* Create a buffer if requested. */ + if (tty->flags & TTY_OSC52QUERY) { + paste_add(NULL, out, outlen); + out = NULL; + evtimer_del(&tty->clipboard_timer); + tty->flags &= ~TTY_OSC52QUERY; + } + + free(out); return (0); } diff --git a/tty.c b/tty.c index cfff58c4..177d4953 100644 --- a/tty.c +++ b/tty.c @@ -3090,12 +3090,6 @@ static void tty_clipboard_query_callback(__unused int fd, __unused short events, void *data) { struct tty *tty = data; - struct client *c = tty->client; - - c->flags &= ~CLIENT_CLIPBOARDBUFFER; - free(c->clipboard_panes); - c->clipboard_panes = NULL; - c->clipboard_npanes = 0; tty->flags &= ~TTY_OSC52QUERY; } @@ -3105,10 +3099,9 @@ tty_clipboard_query(struct tty *tty) { struct timeval tv = { .tv_sec = TTY_QUERY_TIMEOUT }; - if ((~tty->flags & TTY_STARTED) || (tty->flags & TTY_OSC52QUERY)) - return; - tty_putcode_ss(tty, TTYC_MS, "", "?"); - - tty->flags |= TTY_OSC52QUERY; - evtimer_add(&tty->clipboard_timer, &tv); + if ((tty->flags & TTY_STARTED) && (~tty->flags & TTY_OSC52QUERY)) { + tty_putcode_ss(tty, TTYC_MS, "", "?"); + tty->flags |= TTY_OSC52QUERY; + evtimer_add(&tty->clipboard_timer, &tv); + } } From 2c78a5acebe5adfd90ca9f890d24d5bf3ee5e293 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 1 Dec 2025 08:04:26 +0000 Subject: [PATCH 32/49] Add horizontal border case to server_client_check_mouse_in_pane to fix mouse resizing. GitHub issue 4720 from Michael Grant, reported by someone in GitHub issue 4715. --- server-client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server-client.c b/server-client.c index 047365a1..2afec6a9 100644 --- a/server-client.c +++ b/server-client.c @@ -613,7 +613,8 @@ server_client_check_mouse_in_pane(struct window_pane *wp, u_int px, u_int py, line = wp->yoff + wp->sy; /* Check if point is within the pane or scrollbar. */ - if (((pane_status != PANE_STATUS_OFF && py != line) || + if (((pane_status != PANE_STATUS_OFF && + py != line && py != wp->yoff + wp->sy) || (wp->yoff == 0 && py < wp->sy) || (py >= wp->yoff && py < wp->yoff + wp->sy)) && ((sb_pos == PANE_SCROLLBARS_RIGHT && From a40f98df0ae80a04d57935b6e0a1913db8ad9bef Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 1 Dec 2025 08:14:29 +0000 Subject: [PATCH 33/49] Change noattr to be an explicit attribute in the style so that it works correctly and does not delete attributes set in the style itself, GitHub issue 4713. --- attributes.c | 5 +++-- screen.c | 6 +++++- style.c | 35 +++++++++++++++++++---------------- tmux.h | 1 + 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/attributes.c b/attributes.c index b839f06d..8eaa8897 100644 --- a/attributes.c +++ b/attributes.c @@ -31,7 +31,7 @@ attributes_tostring(int attr) if (attr == 0) return ("none"); - len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", (attr & GRID_ATTR_CHARSET) ? "acs," : "", (attr & GRID_ATTR_BRIGHT) ? "bright," : "", (attr & GRID_ATTR_DIM) ? "dim," : "", @@ -45,7 +45,8 @@ attributes_tostring(int attr) (attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "", (attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "", (attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "", - (attr & GRID_ATTR_OVERLINE) ? "overline," : ""); + (attr & GRID_ATTR_OVERLINE) ? "overline," : "", + (attr & GRID_ATTR_NOATTR) ? "noattr," : ""); if (len > 0) buf[len - 1] = '\0'; diff --git a/screen.c b/screen.c index a7a13af2..d82784c5 100644 --- a/screen.c +++ b/screen.c @@ -594,8 +594,12 @@ screen_select_cell(struct screen *s, struct grid_cell *dst, if (COLOUR_DEFAULT(dst->bg)) dst->bg = src->bg; utf8_copy(&dst->data, &src->data); - dst->attr = src->attr; dst->flags = src->flags; + + if (dst->attr & GRID_ATTR_NOATTR) + dst->attr |= (src->attr & GRID_ATTR_CHARSET); + else + dst->attr |= src->attr; } /* Reflow wrapped lines. */ diff --git a/style.c b/style.c index ef3bb225..4acc17dd 100644 --- a/style.c +++ b/style.c @@ -218,20 +218,23 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in) sy->gc.attr = 0; else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) { if (strcmp(tmp + 2, "attr") == 0) - value = 0xffff & ~GRID_ATTR_CHARSET; - else if ((value = attributes_fromstring(tmp + 2)) == -1) - goto error; - sy->gc.attr &= ~value; + sy->gc.attr |= GRID_ATTR_NOATTR; + else { + value = attributes_fromstring(tmp + 2); + if (value == -1) + goto error; + sy->gc.attr &= ~value; + } } else if (end > 6 && strncasecmp(tmp, "width=", 6) == 0) { - n = strtonum(tmp + 6, 0, UINT_MAX, &errstr); - if (errstr != NULL) - goto error; - sy->width = (int)n; + n = strtonum(tmp + 6, 0, UINT_MAX, &errstr); + if (errstr != NULL) + goto error; + sy->width = (int)n; } else if (end > 4 && strncasecmp(tmp, "pad=", 4) == 0) { - n = strtonum(tmp + 4, 0, UINT_MAX, &errstr); - if (errstr != NULL) - goto error; - sy->pad = (int)n; + n = strtonum(tmp + 4, 0, UINT_MAX, &errstr); + if (errstr != NULL) + goto error; + sy->pad = (int)n; } else { if ((value = attributes_fromstring(tmp)) == -1) goto error; @@ -344,13 +347,13 @@ style_tostring(struct style *sy) attributes_tostring(gc->attr)); comma = ","; } - if (sy->width >= 0) { - xsnprintf(s + off, sizeof s - off, "%swidth=%u", comma, + if (sy->width >= 0) { + xsnprintf(s + off, sizeof s - off, "%swidth=%u", comma, sy->width); comma = ","; } - if (sy->pad >= 0) { - xsnprintf(s + off, sizeof s - off, "%spad=%u", comma, + if (sy->pad >= 0) { + xsnprintf(s + off, sizeof s - off, "%spad=%u", comma, sy->pad); comma = ","; } diff --git a/tmux.h b/tmux.h index 2184e6c6..dd62382e 100644 --- a/tmux.h +++ b/tmux.h @@ -727,6 +727,7 @@ struct colour_palette { #define GRID_ATTR_UNDERSCORE_4 0x800 #define GRID_ATTR_UNDERSCORE_5 0x1000 #define GRID_ATTR_OVERLINE 0x2000 +#define GRID_ATTR_NOATTR 0x4000 /* All underscore attributes. */ #define GRID_ATTR_ALL_UNDERSCORE \ From 52917abe21c1f3c930399946c3b0bccbcc604439 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 2 Dec 2025 14:26:30 +0000 Subject: [PATCH 34/49] Update CHANGES. --- CHANGES | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index d6b3013e..d2b47190 100644 --- a/CHANGES +++ b/CHANGES @@ -1,8 +1,14 @@ CHANGES FROM 3.6 TO 3.6a +* Fix horizontal mouse resizing when pane status lines are on (from Michael + Grant, issue 4720). + +* Fix noattr so it does not delete attributes set in the style itself (issue + 4713). + * Newer libevents do not allow event_del on a zero'd event (issue 4706). -* Place cursor on correct line if message-line is not 0 (issue 4707)). +* Place cursor on correct line if message-line is not 0 (issue 4707). * Fix compile error on FreeBSD (from Yasuhiro Kimura, issue 4701). From ee9cf1bbaad7408807e491b42b4813424b4080fb Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 3 Dec 2025 07:35:32 +0000 Subject: [PATCH 35/49] Fix the size caluation for left-right windows used to spread out cells horizontally evenly. From Michael Grant in GitHub issue 4724. --- layout.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/layout.c b/layout.c index 2832039c..d3df5e7f 100644 --- a/layout.c +++ b/layout.c @@ -1100,9 +1100,8 @@ int layout_spread_cell(struct window *w, struct layout_cell *parent) { struct layout_cell *lc; - struct style *sb_style = &w->active->scrollbar_style; u_int number, each, size, this, remainder; - int change, changed, status, scrollbars; + int change, changed, status; number = 0; TAILQ_FOREACH (lc, &parent->cells, entry) @@ -1110,14 +1109,9 @@ layout_spread_cell(struct window *w, struct layout_cell *parent) if (number <= 1) return (0); status = options_get_number(w->options, "pane-border-status"); - scrollbars = options_get_number(w->options, "pane-scrollbars"); - if (parent->type == LAYOUT_LEFTRIGHT) { - if (scrollbars) - size = parent->sx - sb_style->width + sb_style->pad; - else - size = parent->sx; - } + if (parent->type == LAYOUT_LEFTRIGHT) + size = parent->sx; else if (parent->type == LAYOUT_TOPBOTTOM) { if (layout_add_horizontal_border(w, parent, status)) size = parent->sy - 1; From 820df0f551adc056024ed1d927b31c72bcde262d Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 3 Dec 2025 07:38:46 +0000 Subject: [PATCH 36/49] Add check that the pane is not in alternate screen mode when in copy-mode. From Michael Grant in GitHub issue 4728. --- window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/window.c b/window.c index 16f1ecb3..80bc57c2 100644 --- a/window.c +++ b/window.c @@ -1769,7 +1769,7 @@ window_pane_mode(struct window_pane *wp) int window_pane_show_scrollbar(struct window_pane *wp, int sb_option) { - if (SCREEN_IS_ALTERNATE(wp->screen)) + if (SCREEN_IS_ALTERNATE(&wp->base)) return (0); if (sb_option == PANE_SCROLLBARS_ALWAYS || (sb_option == PANE_SCROLLBARS_MODAL && From a28dbe3a599ef9baa3878bbb734489f3e352349e Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 3 Dec 2025 07:41:38 +0000 Subject: [PATCH 37/49] Improve code readability in colour_palette_get and colour_palette_set. GitHub issue 4730 from Pavel Roskin. --- colour.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/colour.c b/colour.c index 791c5fd5..88198e96 100644 --- a/colour.c +++ b/colour.c @@ -1082,22 +1082,22 @@ colour_palette_free(struct colour_palette *p) /* Get a colour from a palette. */ int -colour_palette_get(struct colour_palette *p, int c) +colour_palette_get(struct colour_palette *p, int n) { if (p == NULL) return (-1); - if (c >= 90 && c <= 97) - c = 8 + c - 90; - else if (c & COLOUR_FLAG_256) - c &= ~COLOUR_FLAG_256; - else if (c >= 8) + if (n >= 90 && n <= 97) + n = 8 + n - 90; + else if (n & COLOUR_FLAG_256) + n &= ~COLOUR_FLAG_256; + else if (n >= 8) return (-1); - if (p->palette != NULL && p->palette[c] != -1) - return (p->palette[c]); - if (p->default_palette != NULL && p->default_palette[c] != -1) - return (p->default_palette[c]); + if (p->palette != NULL && p->palette[n] != -1) + return (p->palette[n]); + if (p->default_palette != NULL && p->default_palette[n] != -1) + return (p->default_palette[n]); return (-1); } @@ -1107,15 +1107,14 @@ colour_palette_set(struct colour_palette *p, int n, int c) { u_int i; - if (p == NULL || n > 255) + if (p == NULL || n < 0 || n > 255) return (0); if (c == -1 && p->palette == NULL) return (0); - if (c != -1 && p->palette == NULL) { - if (p->palette == NULL) - p->palette = xcalloc(256, sizeof *p->palette); + if (p->palette == NULL) { + p->palette = xcalloc(256, sizeof *p->palette); for (i = 0; i < 256; i++) p->palette[i] = -1; } From 2fe1378d3a5bf867895df2344f9f7dbf6d7b88a7 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 4 Dec 2025 06:02:27 +0000 Subject: [PATCH 38/49] Allow characters to be combined in either order, reported by Jake Stewart in GitHub issue 4726. --- screen-write.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/screen-write.c b/screen-write.c index 43afb50d..39c15b39 100644 --- a/screen-write.c +++ b/screen-write.c @@ -2057,6 +2057,8 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc) case HANGULJAMO_STATE_NOT_HANGULJAMO: if (utf8_should_combine(&last.data, ud)) force_wide = 1; + else if (utf8_should_combine(ud, &last.data)) + force_wide = 1; else if (!utf8_has_zwj(&last.data)) return (0); break; From 1f2210a3cec0d3d6e912b31d369bcc5cd62e7046 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 4 Dec 2025 06:04:21 +0000 Subject: [PATCH 39/49] Add a missing skin tone, from Jake Stewart in GitHub issue 4736. --- utf8-combined.c | 1 + 1 file changed, 1 insertion(+) diff --git a/utf8-combined.c b/utf8-combined.c index 635ae92c..1eee3b82 100644 --- a/utf8-combined.c +++ b/utf8-combined.c @@ -122,6 +122,7 @@ utf8_should_combine(const struct utf8_data *with, const struct utf8_data *add) case 0x1F47C: case 0x1F481: case 0x1F482: + case 0x1F483: case 0x1F485: case 0x1F486: case 0x1F487: From 9d6c69ebdef6521d830b6911e25b9d969efa9559 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 4 Dec 2025 14:45:32 +0000 Subject: [PATCH 40/49] Fix y offset of mouse if status at top. GitHub issue 4738 from Michael Grant. --- screen-redraw.c | 5 +++++ server-client.c | 6 +++++- window-copy.c | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index f76854e8..db518708 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1024,6 +1024,11 @@ screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx, int sx = ctx->sx, sy = ctx->sy, xoff = wp->xoff; int yoff = wp->yoff; + if (ctx->statustop) { + sb_y += ctx->statuslines; + sy += ctx->statuslines; + } + /* Set up style for slider. */ gc = sb_style->gc; memcpy(&slgc, &gc, sizeof slgc); diff --git a/server-client.c b/server-client.c index a48b9802..2732f1fe 100644 --- a/server-client.c +++ b/server-client.c @@ -1275,7 +1275,11 @@ have_event: if (c->tty.mouse_scrolling_flag == 0 && where == SCROLLBAR_SLIDER) { c->tty.mouse_scrolling_flag = 1; - c->tty.mouse_slider_mpos = sl_mpos; + if (m->statusat == 0) { + c->tty.mouse_slider_mpos = sl_mpos + + m->statuslines; + } else + c->tty.mouse_slider_mpos = sl_mpos; } break; case WHEEL: diff --git a/window-copy.c b/window-copy.c index f056cebb..2d528496 100644 --- a/window-copy.c +++ b/window-copy.c @@ -627,7 +627,7 @@ window_copy_scroll1(struct window_mode_entry *wme, struct window_pane *wp, new_slider_y = sb_top - wp->yoff + (sb_height - slider_height); } else { /* Slider is somewhere in the middle. */ - new_slider_y = my - wp->yoff - sl_mpos + 1; + new_slider_y = my - wp->yoff - sl_mpos; } if (TAILQ_FIRST(&wp->modes) == NULL || From bd16b22daca9dba1f6aec63ff2b8fc63b849ef95 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 4 Dec 2025 20:49:57 +0000 Subject: [PATCH 41/49] Do not read over buffer if format is a single #, and do not loop forever if UTF-8 is unfinished in a format. Reported by Giorgi Kobakhia im GitHub issue 4735. --- format-draw.c | 2 -- format.c | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/format-draw.c b/format-draw.c index efc6ab1a..c8cb74b6 100644 --- a/format-draw.c +++ b/format-draw.c @@ -1104,8 +1104,6 @@ format_width(const char *expanded) more = utf8_append(&ud, *cp); if (more == UTF8_DONE) width += ud.width; - else - cp -= ud.have; } else if (*cp > 0x1f && *cp < 0x7f) { width++; cp++; diff --git a/format.c b/format.c index b5272422..afcf7535 100644 --- a/format.c +++ b/format.c @@ -5541,7 +5541,8 @@ format_expand1(struct format_expand_state *es, const char *fmt) buf[off++] = *fmt++; continue; } - fmt++; + if (*fmt++ == '\0') + break; ch = (u_char)*fmt++; switch (ch) { From 33c1ba154940461029eb45a9ba047bf8cf7307e7 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 4 Dec 2025 06:02:27 +0000 Subject: [PATCH 42/49] Allow characters to be combined in either order, reported by Jake Stewart in GitHub issue 4726. --- screen-write.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/screen-write.c b/screen-write.c index 76beffbc..a2755d35 100644 --- a/screen-write.c +++ b/screen-write.c @@ -2152,6 +2152,8 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc) case HANGULJAMO_STATE_NOT_HANGULJAMO: if (utf8_should_combine(&last.data, ud)) force_wide = 1; + else if (utf8_should_combine(ud, &last.data)) + force_wide = 1; else if (!utf8_has_zwj(&last.data)) return (0); break; From 3b57077d015a33ec9f7f4571f90f1cfd25132245 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 4 Dec 2025 06:04:21 +0000 Subject: [PATCH 43/49] Add a missing skin tone, from Jake Stewart in GitHub issue 4736. --- utf8-combined.c | 1 + 1 file changed, 1 insertion(+) diff --git a/utf8-combined.c b/utf8-combined.c index 635ae92c..1eee3b82 100644 --- a/utf8-combined.c +++ b/utf8-combined.c @@ -122,6 +122,7 @@ utf8_should_combine(const struct utf8_data *with, const struct utf8_data *add) case 0x1F47C: case 0x1F481: case 0x1F482: + case 0x1F483: case 0x1F485: case 0x1F486: case 0x1F487: From 2fc123cf4a72d32f7b8bdbce1223cf583d808354 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Dec 2025 20:54:44 +0000 Subject: [PATCH 44/49] Update CHANGES. --- CHANGES | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index d2b47190..e4657965 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,10 @@ CHANGES FROM 3.6 TO 3.6a +* Add a missing skin tone (from Jake Stewart, issue 4736). + +* Allow characters to be combined in either order (issue 4726, reported by Jake + Stewart). + * Fix horizontal mouse resizing when pane status lines are on (from Michael Grant, issue 4720). From 987e05ff3162ba943abb77525035c6f27a6b5ba3 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 4 Dec 2025 22:50:34 +0000 Subject: [PATCH 45/49] Allow drag in alternate screen again, GitHub issue 4743 reported by Brad King. --- key-bindings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key-bindings.c b/key-bindings.c index 7f8b20e0..a5e1f9c8 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -441,7 +441,7 @@ key_bindings_init(void) "bind -n MouseDown1Pane { select-pane -t=; send -M }", /* Mouse button 1 drag on pane. */ - "bind -n MouseDrag1Pane { if -F '#{||:#{alternate_on},#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M } }", + "bind -n MouseDrag1Pane { if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M } }", /* Mouse wheel up on pane. */ "bind -n WheelUpPane { if -F '#{||:#{alternate_on},#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -e } }", From ff207eb5834515580694a4623f7d45233794f7f1 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 4 Dec 2025 14:45:32 +0000 Subject: [PATCH 46/49] Fix y offset of mouse if status at top. GitHub issue 4738 from Michael Grant. --- screen-redraw.c | 5 +++++ server-client.c | 6 +++++- window-copy.c | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index 96081839..1c1b8503 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1028,6 +1028,11 @@ screen_redraw_draw_scrollbar(struct screen_redraw_ctx *ctx, int sx = ctx->sx, sy = ctx->sy, xoff = wp->xoff; int yoff = wp->yoff; + if (ctx->statustop) { + sb_y += ctx->statuslines; + sy += ctx->statuslines; + } + /* Set up style for slider. */ gc = sb_style->gc; memcpy(&slgc, &gc, sizeof slgc); diff --git a/server-client.c b/server-client.c index 2afec6a9..7f1942c7 100644 --- a/server-client.c +++ b/server-client.c @@ -1271,7 +1271,11 @@ have_event: if (c->tty.mouse_scrolling_flag == 0 && where == SCROLLBAR_SLIDER) { c->tty.mouse_scrolling_flag = 1; - c->tty.mouse_slider_mpos = sl_mpos; + if (m->statusat == 0) { + c->tty.mouse_slider_mpos = sl_mpos + + m->statuslines; + } else + c->tty.mouse_slider_mpos = sl_mpos; } break; case WHEEL: diff --git a/window-copy.c b/window-copy.c index f056cebb..2d528496 100644 --- a/window-copy.c +++ b/window-copy.c @@ -627,7 +627,7 @@ window_copy_scroll1(struct window_mode_entry *wme, struct window_pane *wp, new_slider_y = sb_top - wp->yoff + (sb_height - slider_height); } else { /* Slider is somewhere in the middle. */ - new_slider_y = my - wp->yoff - sl_mpos + 1; + new_slider_y = my - wp->yoff - sl_mpos; } if (TAILQ_FIRST(&wp->modes) == NULL || From 01962e25dc25b732361fa0b94ce630651891cd33 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 4 Dec 2025 22:50:34 +0000 Subject: [PATCH 47/49] Allow drag in alternate screen again, GitHub issue 4743 reported by Brad King. --- key-bindings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key-bindings.c b/key-bindings.c index 7f8b20e0..a5e1f9c8 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -441,7 +441,7 @@ key_bindings_init(void) "bind -n MouseDown1Pane { select-pane -t=; send -M }", /* Mouse button 1 drag on pane. */ - "bind -n MouseDrag1Pane { if -F '#{||:#{alternate_on},#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M } }", + "bind -n MouseDrag1Pane { if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M } }", /* Mouse wheel up on pane. */ "bind -n WheelUpPane { if -F '#{||:#{alternate_on},#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -e } }", From faebe7a70a43958ea69a4ddfa1812da3f97bd621 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 4 Dec 2025 20:49:57 +0000 Subject: [PATCH 48/49] Do not read over buffer if format is a single #, and do not loop forever if UTF-8 is unfinished in a format. Reported by Giorgi Kobakhia im GitHub issue 4735. --- format-draw.c | 2 -- format.c | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/format-draw.c b/format-draw.c index efc6ab1a..c8cb74b6 100644 --- a/format-draw.c +++ b/format-draw.c @@ -1104,8 +1104,6 @@ format_width(const char *expanded) more = utf8_append(&ud, *cp); if (more == UTF8_DONE) width += ud.width; - else - cp -= ud.have; } else if (*cp > 0x1f && *cp < 0x7f) { width++; cp++; diff --git a/format.c b/format.c index 17a9dd53..3d498b34 100644 --- a/format.c +++ b/format.c @@ -5545,7 +5545,8 @@ format_expand1(struct format_expand_state *es, const char *fmt) buf[off++] = *fmt++; continue; } - fmt++; + if (*fmt++ == '\0') + break; ch = (u_char)*fmt++; switch (ch) { From cc117b5048f77a4842820f8ebbe3a86e5c077224 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 5 Dec 2025 05:39:46 +0000 Subject: [PATCH 49/49] Update CHANGES. --- CHANGES | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGES b/CHANGES index e4657965..bcd1e1c6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,12 @@ CHANGES FROM 3.6 TO 3.6a +* Fix a buffer overread and an infinite loop in format processing (reported by + Giorgi Kobakhia, issue 4735). + +* Allow drag in alternate screen again (issue 4743 reported by Brad King). + +* Fix y offset of mouse if status at top (issue 4738 from Michael Grant). + * Add a missing skin tone (from Jake Stewart, issue 4736). * Allow characters to be combined in either order (issue 4726, reported by Jake