Module Name:    src
Committed By:   wiz
Date:           Sat Nov  9 13:13:25 UTC 2024

Modified Files:
        src/external/bsd/tmux/dist: arguments.c client.c cmd-display-menu.c
            cmd-parse.y cmd-queue.c cmd-split-window.c colour.c compat.h
            environ.c format.c grid.c hyperlinks.c image-sixel.c input-keys.c
            input.c job.c key-bindings.c menu.c mode-tree.c options.c resize.c
            screen-write.c screen.c server-client.c server-fn.c server.c
            status.c style.c tmux.1 tmux.c tmux.h tty-keys.c tty-term.c tty.c
            utf8.c window-buffer.c window-copy.c window.c

Log Message:
merge tmux-3.5a and add some more casts


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/external/bsd/tmux/dist/arguments.c \
    src/external/bsd/tmux/dist/hyperlinks.c \
    src/external/bsd/tmux/dist/image-sixel.c
cvs rdiff -u -r1.13 -r1.14 src/external/bsd/tmux/dist/client.c \
    src/external/bsd/tmux/dist/grid.c src/external/bsd/tmux/dist/job.c \
    src/external/bsd/tmux/dist/key-bindings.c
cvs rdiff -u -r1.7 -r1.8 src/external/bsd/tmux/dist/cmd-display-menu.c
cvs rdiff -u -r1.6 -r1.7 src/external/bsd/tmux/dist/cmd-parse.y
cvs rdiff -u -r1.9 -r1.10 src/external/bsd/tmux/dist/cmd-queue.c
cvs rdiff -u -r1.12 -r1.13 src/external/bsd/tmux/dist/cmd-split-window.c \
    src/external/bsd/tmux/dist/colour.c src/external/bsd/tmux/dist/environ.c \
    src/external/bsd/tmux/dist/server-client.c
cvs rdiff -u -r1.5 -r1.6 src/external/bsd/tmux/dist/compat.h \
    src/external/bsd/tmux/dist/menu.c src/external/bsd/tmux/dist/resize.c
cvs rdiff -u -r1.15 -r1.16 src/external/bsd/tmux/dist/format.c \
    src/external/bsd/tmux/dist/screen-write.c \
    src/external/bsd/tmux/dist/screen.c \
    src/external/bsd/tmux/dist/server-fn.c src/external/bsd/tmux/dist/tmux.c
cvs rdiff -u -r1.14 -r1.15 src/external/bsd/tmux/dist/input-keys.c \
    src/external/bsd/tmux/dist/options.c
cvs rdiff -u -r1.18 -r1.19 src/external/bsd/tmux/dist/input.c \
    src/external/bsd/tmux/dist/tmux.1 src/external/bsd/tmux/dist/tty-keys.c \
    src/external/bsd/tmux/dist/tty-term.c
cvs rdiff -u -r1.10 -r1.11 src/external/bsd/tmux/dist/mode-tree.c \
    src/external/bsd/tmux/dist/utf8.c \
    src/external/bsd/tmux/dist/window-buffer.c
cvs rdiff -u -r1.4 -r1.5 src/external/bsd/tmux/dist/server.c
cvs rdiff -u -r1.16 -r1.17 src/external/bsd/tmux/dist/status.c \
    src/external/bsd/tmux/dist/window-copy.c
cvs rdiff -u -r1.8 -r1.9 src/external/bsd/tmux/dist/style.c
cvs rdiff -u -r1.22 -r1.23 src/external/bsd/tmux/dist/tmux.h
cvs rdiff -u -r1.11 -r1.12 src/external/bsd/tmux/dist/tty.c
cvs rdiff -u -r1.17 -r1.18 src/external/bsd/tmux/dist/window.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/external/bsd/tmux/dist/arguments.c
diff -u src/external/bsd/tmux/dist/arguments.c:1.2 src/external/bsd/tmux/dist/arguments.c:1.3
--- src/external/bsd/tmux/dist/arguments.c:1.2	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/arguments.c	Sat Nov  9 13:13:24 2024
@@ -164,10 +164,14 @@ args_parse_flag_argument(struct args_val
 		argument = &values[*i];
 		if (argument->type != ARGS_STRING) {
 			xasprintf(cause, "-%c argument must be a string", flag);
+			args_free_value(new);
+			free(new);
 			return (-1);
 		}
 	}
 	if (argument == NULL) {
+		args_free_value(new);
+		free(new);
 		if (optional_argument) {
 			log_debug("%s: -%c (optional)", __func__, flag);
 			args_set(args, flag, NULL, ARGS_ENTRY_OPTIONAL_VALUE);
@@ -662,6 +666,8 @@ args_set(struct args *args, u_char flag,
 		entry->count++;
 	if (value != NULL && value->type != ARGS_NONE)
 		TAILQ_INSERT_TAIL(&entry->values, value, entry);
+	else
+		free(value);
 }
 
 /* Get argument value. Will be NULL if it isn't present. */
Index: src/external/bsd/tmux/dist/hyperlinks.c
diff -u src/external/bsd/tmux/dist/hyperlinks.c:1.2 src/external/bsd/tmux/dist/hyperlinks.c:1.3
--- src/external/bsd/tmux/dist/hyperlinks.c:1.2	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/hyperlinks.c	Sat Nov  9 13:13:25 2024
@@ -68,6 +68,7 @@ struct hyperlinks {
 	u_int				next_inner;
 	struct hyperlinks_by_inner_tree	by_inner;
 	struct hyperlinks_by_uri_tree	by_uri;
+	u_int				references;
 };
 
 static int
@@ -205,6 +206,15 @@ hyperlinks_init(void)
 	hl->next_inner = 1;
 	RB_INIT(&hl->by_uri);
 	RB_INIT(&hl->by_inner);
+	hl->references = 1;
+	return (hl);
+}
+
+/* Copy hyperlink set. */
+struct hyperlinks *
+hyperlinks_copy(struct hyperlinks *hl)
+{
+	hl->references++;
 	return (hl);
 }
 
@@ -222,6 +232,8 @@ hyperlinks_reset(struct hyperlinks *hl)
 void
 hyperlinks_free(struct hyperlinks *hl)
 {
-	hyperlinks_reset(hl);
-	free(hl);
+	if (--hl->references == 0) {
+		hyperlinks_reset(hl);
+		free(hl);
+	}
 }
Index: src/external/bsd/tmux/dist/image-sixel.c
diff -u src/external/bsd/tmux/dist/image-sixel.c:1.2 src/external/bsd/tmux/dist/image-sixel.c:1.3
--- src/external/bsd/tmux/dist/image-sixel.c:1.2	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/image-sixel.c	Sat Nov  9 13:13:25 2024
@@ -489,6 +489,9 @@ sixel_print(struct sixel_image *si, stru
 		colours = si->colours;
 		ncolours = si->ncolours;
 	}
+
+	if (ncolours == 0)
+		return (NULL);
 	contains = xcalloc(1, ncolours);
 
 	len = 8192;

Index: src/external/bsd/tmux/dist/client.c
diff -u src/external/bsd/tmux/dist/client.c:1.13 src/external/bsd/tmux/dist/client.c:1.14
--- src/external/bsd/tmux/dist/client.c:1.13	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/client.c	Sat Nov  9 13:13:25 2024
@@ -452,11 +452,12 @@ client_send_identify(const char *ttynam,
 {
 	char	**ss;
 	size_t	  sslen;
-	int	  fd, flags = client_flags;
+	int	  fd;
+	uint64_t  flags = client_flags;
 	pid_t	  pid;
 	u_int	  i;
 
-	proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
+	proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &flags, sizeof flags);
 	proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags,
 	    sizeof client_flags);
 
@@ -497,20 +498,10 @@ client_send_identify(const char *ttynam,
 static __dead void
 client_exec(const char *shell, const char *shellcmd)
 {
-	const char	*name, *ptr;
-	char		*argv0;
+	char	*argv0;
 
 	log_debug("shell %s, command %s", shell, shellcmd);
-
-	ptr = strrchr(shell, '/');
-	if (ptr != NULL && *(ptr + 1) != '\0')
-		name = ptr + 1;
-	else
-		name = shell;
-	if (client_flags & CLIENT_LOGIN)
-		xasprintf(&argv0, "-%s", name);
-	else
-		xasprintf(&argv0, "%s", name);
+	argv0 = shell_argv0(shell, !!(client_flags & CLIENT_LOGIN));
 	setenv("SHELL", shell, 1);
 
 	proc_clear_signals(client_proc, 1);
Index: src/external/bsd/tmux/dist/grid.c
diff -u src/external/bsd/tmux/dist/grid.c:1.13 src/external/bsd/tmux/dist/grid.c:1.14
--- src/external/bsd/tmux/dist/grid.c:1.13	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/grid.c	Sat Nov  9 13:13:25 2024
@@ -88,7 +88,7 @@ grid_need_extended_cell(const struct gri
 		return (1);
 	if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB))
 		return (1);
-	if (gc->us != 0) /* only supports 256 or RGB */
+	if (gc->us != 8) /* only supports 256 or RGB */
 		return (1);
 	if (gc->link != 0)
 		return (1);
Index: src/external/bsd/tmux/dist/job.c
diff -u src/external/bsd/tmux/dist/job.c:1.13 src/external/bsd/tmux/dist/job.c:1.14
--- src/external/bsd/tmux/dist/job.c:1.13	Wed Jun 28 22:21:26 2023
+++ src/external/bsd/tmux/dist/job.c	Sat Nov  9 13:13:25 2024
@@ -69,27 +69,43 @@ static LIST_HEAD(joblist, job) 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;
 	pid_t		  pid;
 	int		  nullfd, out[2], master;
-	const char	 *home;
+	const char	 *home, *shell;
 	sigset_t	  set, oldset;
 	struct winsize	  ws;
-	char		**argvp, tty[TTY_NAME_MAX];
+	char		**argvp, tty[TTY_NAME_MAX], *argv0;
+	struct options	 *oo;
 
 	/*
-	 * Do not set TERM during .tmux.conf, it is nice to be able to use
-	 * if-shell to decide on default-terminal based on outside TERM.
+	 * Do not set TERM during .tmux.conf (second argument here), it is nice
+	 * to be able to use if-shell to decide on default-terminal based on
+	 * outside TERM.
 	 */
 	env = environ_for_session(s, !cfg_finished);
 	if (e != NULL)
 		environ_copy(e, env);
 
+	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);
 	sigprocmask(SIG_BLOCK, &set, &oldset);
 
@@ -105,10 +121,11 @@ job_run(const char *cmd, int argc, char 
 	}
 	if (cmd == NULL) {
 		cmd_log_argv(argc, argv, "%s:", __func__);
-		log_debug("%s: cwd=%s", __func__, cwd == NULL ? "" : cwd);
+		log_debug("%s: cwd=%s, shell=%s", __func__,
+		    cwd == NULL ? "" : cwd, shell);
 	} else {
-		log_debug("%s: cmd=%s, cwd=%s", __func__, cmd,
-		    cwd == NULL ? "" : cwd);
+		log_debug("%s: cmd=%s, cwd=%s, shell=%s", __func__, cmd,
+		    cwd == NULL ? "" : cwd, shell);
 	}
 
 	switch (pid) {
@@ -150,7 +167,8 @@ job_run(const char *cmd, int argc, char 
 		closefrom(STDERR_FILENO + 1);
 
 		if (cmd != NULL) {
-			execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
+			setenv("SHELL", shell, 1);
+			execl(shell, argv0, "-c", cmd, (char *)NULL);
 			fatal("execl failed");
 		} else {
 			argvp = cmd_copy_argv(argc, argv);
@@ -161,6 +179,7 @@ job_run(const char *cmd, int argc, char 
 
 	sigprocmask(SIG_SETMASK, &oldset, NULL);
 	environ_free(env);
+	free(argv0);
 
 	job = xmalloc(sizeof *job);
 	job->state = JOB_RUNNING;
@@ -194,12 +213,13 @@ job_run(const char *cmd, int argc, char 
 		fatalx("out of memory");
 	bufferevent_enable(job->event, EV_READ|EV_WRITE);
 
-	log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
+	log_debug("run job %p: %s, pid %ld", job, job->cmd, (long)job->pid);
 	return (job);
 
 fail:
 	sigprocmask(SIG_SETMASK, &oldset, NULL);
 	environ_free(env);
+	free(argv0);
 	return (NULL);
 }
 
Index: src/external/bsd/tmux/dist/key-bindings.c
diff -u src/external/bsd/tmux/dist/key-bindings.c:1.13 src/external/bsd/tmux/dist/key-bindings.c:1.14
--- src/external/bsd/tmux/dist/key-bindings.c:1.13	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/key-bindings.c	Sat Nov  9 13:13:25 2024
@@ -413,6 +413,8 @@ key_bindings_init(void)
 		"bind -N 'Set the main-horizontal layout' M-3 { select-layout main-horizontal }",
 		"bind -N 'Set the main-vertical layout' M-4 { select-layout main-vertical }",
 		"bind -N 'Select the tiled layout' M-5 { select-layout tiled }",
+		"bind -N 'Set the main-horizontal-mirrored layout' M-6 { select-layout main-horizontal-mirrored }",
+		"bind -N 'Set the main-vertical-mirrored layout' M-7 { select-layout main-vertical-mirrored }",
 		"bind -N 'Select the next window with an alert' M-n { next-window -a }",
 		"bind -N 'Rotate through the panes in reverse' M-o { rotate-window -D }",
 		"bind -N 'Select the previous window with an alert' M-p { previous-window -a }",

Index: src/external/bsd/tmux/dist/cmd-display-menu.c
diff -u src/external/bsd/tmux/dist/cmd-display-menu.c:1.7 src/external/bsd/tmux/dist/cmd-display-menu.c:1.8
--- src/external/bsd/tmux/dist/cmd-display-menu.c:1.7	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/cmd-display-menu.c	Sat Nov  9 13:13:25 2024
@@ -38,8 +38,8 @@ const struct cmd_entry cmd_display_menu_
 	.name = "display-menu",
 	.alias = "menu",
 
-	.args = { "b:c:C:H:s:S:Ot:T:x:y:", 1, -1, cmd_display_menu_args_parse },
-	.usage = "[-O] [-b border-lines] [-c target-client] "
+	.args = { "b:c:C:H:s:S:MOt:T:x:y:", 1, -1, cmd_display_menu_args_parse },
+	.usage = "[-MO] [-b border-lines] [-c target-client] "
 		 "[-C starting-choice] [-H selected-style] [-s style] "
 		 "[-S border-style] " CMD_TARGET_PANE_USAGE "[-T title] "
 		 "[-x position] [-y position] name key command ...",
@@ -373,7 +373,7 @@ cmd_display_menu_exec(struct cmd *self, 
 
 	if (args_has(args, 'O'))
 		flags |= MENU_STAYOPEN;
-	if (!event->m.valid)
+	if (!event->m.valid && !args_has(args, 'M'))
 		flags |= MENU_NOMOUSE;
 	if (menu_display(menu, flags, starting_choice, item, px, py, tc, lines,
 	    style, selected_style, border_style, target, NULL, NULL) != 0)

Index: src/external/bsd/tmux/dist/cmd-parse.y
diff -u src/external/bsd/tmux/dist/cmd-parse.y:1.6 src/external/bsd/tmux/dist/cmd-parse.y:1.7
--- src/external/bsd/tmux/dist/cmd-parse.y:1.6	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/cmd-parse.y	Sat Nov  9 13:13:25 2024
@@ -1273,6 +1273,16 @@ yylex(void)
 			continue;
 		}
 
+		if (ch == '\r') {
+			/*
+			 * Treat \r\n as \n.
+			 */
+			ch = yylex_getc();
+			if (ch != '\n') {
+				yylex_ungetc(ch);
+				ch = '\r';
+			}
+		}
 		if (ch == '\n') {
 			/*
 			 * End of line. Update the line number.
@@ -1619,6 +1629,13 @@ yylex_token(int ch)
 			log_debug("%s: end at EOF", __func__);
 			break;
 		}
+		if (state == NONE && ch == '\r') {
+			ch = yylex_getc();
+			if (ch != '\n') {
+				yylex_ungetc(ch);
+				ch = '\r';
+			}
+		}
 		if (state == NONE && ch == '\n') {
 			log_debug("%s: end at EOL", __func__);
 			break;

Index: src/external/bsd/tmux/dist/cmd-queue.c
diff -u src/external/bsd/tmux/dist/cmd-queue.c:1.9 src/external/bsd/tmux/dist/cmd-queue.c:1.10
--- src/external/bsd/tmux/dist/cmd-queue.c:1.9	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/cmd-queue.c	Sat Nov  9 13:13:25 2024
@@ -664,9 +664,18 @@ cmdq_fire_command(struct cmdq_item *item
 
 out:
 	item->client = saved;
-	if (retval == CMD_RETURN_ERROR)
+	if (retval == CMD_RETURN_ERROR) {
+		fsp = NULL;
+		if (cmd_find_valid_state(&item->target))
+			fsp = &item->target;
+		else if (cmd_find_valid_state(&item->state->current))
+			fsp = &item->state->current;
+		else if (cmd_find_from_client(&fs, item->client, 0) == 0)
+			fsp = &fs;
+		cmdq_insert_hook(fsp != NULL ? fsp->s : NULL, item, fsp,
+		    "command-error");
 		cmdq_guard(item, "error", flags);
-	else
+	} else
 		cmdq_guard(item, "end", flags);
 	return (retval);
 }
@@ -805,10 +814,10 @@ cmdq_running(struct client *c)
 	struct cmdq_list	*queue = cmdq_get(c);
 
 	if (queue->item == NULL)
-        return (NULL);
-    if (queue->item->flags & CMDQ_WAITING)
-        return (NULL);
-    return (queue->item);
+		return (NULL);
+	if (queue->item->flags & CMDQ_WAITING)
+		return (NULL);
+	return (queue->item);
 }
 
 /* Print a guard line. */

Index: src/external/bsd/tmux/dist/cmd-split-window.c
diff -u src/external/bsd/tmux/dist/cmd-split-window.c:1.12 src/external/bsd/tmux/dist/cmd-split-window.c:1.13
--- src/external/bsd/tmux/dist/cmd-split-window.c:1.12	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/cmd-split-window.c	Sat Nov  9 13:13:25 2024
@@ -93,10 +93,10 @@ cmd_split_window_exec(struct cmd *self, 
 	size = -1;
 	if (args_has(args, 'l')) {
 		size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
-			   item, &cause);
+		    item, &cause);
 	} else if (args_has(args, 'p')) {
-		size = args_strtonum_and_expand(args, 'l', 0, 100, item,
-			    &cause);
+		size = args_strtonum_and_expand(args, 'p', 0, 100, item,
+		    &cause);
 		if (cause == NULL)
 			size = curval * size / 100;
 	}
Index: src/external/bsd/tmux/dist/colour.c
diff -u src/external/bsd/tmux/dist/colour.c:1.12 src/external/bsd/tmux/dist/colour.c:1.13
--- src/external/bsd/tmux/dist/colour.c:1.12	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/colour.c	Sat Nov  9 13:13:25 2024
@@ -942,13 +942,17 @@ colour_byname(const char *name)
 		{ "yellow3", 0xcdcd00 },
 		{ "yellow4", 0x8b8b00 }
 	};
-	u_int	i;
-	int	c;
+	u_int		 i;
+	int		 c;
+	const char	*errstr;
 
 	if (strncmp(name, "grey", 4) == 0 || strncmp(name, "gray", 4) == 0) {
-		if (!isdigit((u_char)name[4]))
+		if (name[4] == '\0')
 			return (0xbebebe|COLOUR_FLAG_RGB);
-		c = round(2.55 * atoi(name + 4));
+		c = strtonum(name + 4, 0, 100, &errstr);
+		if (errstr != NULL)
+			return (-1);
+		c = round(2.55 * c);
 		if (c < 0 || c > 255)
 			return (-1);
 		return (colour_join_rgb(c, c, c));
Index: src/external/bsd/tmux/dist/environ.c
diff -u src/external/bsd/tmux/dist/environ.c:1.12 src/external/bsd/tmux/dist/environ.c:1.13
--- src/external/bsd/tmux/dist/environ.c:1.12	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/environ.c	Sat Nov  9 13:13:25 2024
@@ -264,6 +264,12 @@ environ_for_session(struct session *s, i
 		environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion());
 	}
 
+#ifdef HAVE_SYSTEMD
+	environ_clear(env, "LISTEN_PID");
+	environ_clear(env, "LISTEN_FDS");
+	environ_clear(env, "LISTEN_FDNAMES");
+#endif
+
 	if (s != NULL)
 		idx = s->id;
 	else
Index: src/external/bsd/tmux/dist/server-client.c
diff -u src/external/bsd/tmux/dist/server-client.c:1.12 src/external/bsd/tmux/dist/server-client.c:1.13
--- src/external/bsd/tmux/dist/server-client.c:1.12	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/server-client.c	Sat Nov  9 13:13:25 2024
@@ -222,6 +222,17 @@ server_client_set_key_table(struct clien
 	key_bindings_unref_table(c->keytable);
 	c->keytable = key_bindings_get_table(name, 1);
 	c->keytable->references++;
+	if (gettimeofday(&c->keytable->activity_time, NULL) != 0)
+		fatal("gettimeofday failed");
+}
+
+static uint64_t
+server_client_key_table_activity_diff(struct client *c)
+{
+	struct timeval	diff;
+
+	timersub(&c->activity_time, &c->keytable->activity_time, &diff);
+	return ((diff.tv_sec * 1000ULL) + (diff.tv_usec / 1000ULL));
 }
 
 /* Get default key table. */
@@ -622,6 +633,8 @@ server_client_check_mouse(struct client 
 	} else if (MOUSE_RELEASE(m->b)) {
 		type = UP;
 		x = m->x, y = m->y, b = m->lb;
+		if (m->sgr_type == 'm')
+			b = m->sgr_b;
 		log_debug("up at %u,%u", x, y);
 	} else {
 		if (c->flags & CLIENT_DOUBLECLICK) {
@@ -642,7 +655,10 @@ server_client_check_mouse(struct client 
 				log_debug("triple-click at %u,%u", x, y);
 				goto have_event;
 			}
-		} else {
+		}
+
+		/* DOWN is the only remaining event type. */
+		if (type == NOTYPE) {
 			type = DOWN;
 			x = m->x, y = m->y, b = m->b;
 			log_debug("down at %u,%u", x, y);
@@ -774,8 +790,7 @@ have_event:
 			log_debug("mouse on pane %%%u border", wp->id);
 		m->wp = wp->id;
 		m->w = wp->window->id;
-	} else
-		m->wp = -1;
+	}
 
 	/* Stop dragging if needed. */
 	if (type != DRAG && type != WHEEL && c->tty.mouse_drag_flag != 0) {
@@ -1861,7 +1876,8 @@ server_client_key_callback(struct cmdq_i
 	struct timeval			 tv;
 	struct key_table		*table, *first;
 	struct key_binding		*bd;
-	int				 xtimeout, flags;
+	int				 xtimeout;
+	uint64_t			 flags, prefix_delay;
 	struct cmd_find_state		 fs;
 	key_code			 key0, prefix, prefix2;
 
@@ -1956,8 +1972,34 @@ try_again:
 	if (c->flags & CLIENT_REPEAT)
 		log_debug("currently repeating");
 
-	/* Try to see if there is a key binding in the current table. */
 	bd = key_bindings_get(table, key0);
+
+	/*
+	 * If prefix-timeout is enabled and we're in the prefix table, see if
+	 * the timeout has been exceeded. Revert to the root table if so.
+	 */
+	prefix_delay = options_get_number(global_options, "prefix-timeout");
+	if (prefix_delay > 0 &&
+	    strcmp(table->name, "prefix") == 0 &&
+	    server_client_key_table_activity_diff(c) > prefix_delay) {
+		/*
+		 * If repeating is active and this is a repeating binding,
+		 * ignore the timeout.
+		 */
+		if (bd != NULL &&
+		    (c->flags & CLIENT_REPEAT) &&
+		    (bd->flags & KEY_BINDING_REPEAT)) {
+			log_debug("prefix timeout ignored, repeat is active");
+		} else {
+			log_debug("prefix timeout exceeded");
+			server_client_set_key_table(c, NULL);
+			first = table = c->keytable;
+			server_status_client(c);
+			goto table_changed;
+		}
+	}
+
+	/* Try to see if there is a key binding in the current table. */
 	if (bd != NULL) {
 		/*
 		 * Key was matched in this table. If currently repeating but a
@@ -2015,7 +2057,19 @@ try_again:
 	}
 
 	/*
-	 * No match in this table. If not in the root table or if repeating,
+	 * Binding movement keys is useless since we only turn them on when the
+	 * application requests, so don't let them exit the prefix table.
+	 */
+	if (key == KEYC_MOUSEMOVE_PANE ||
+	    key == KEYC_MOUSEMOVE_STATUS ||
+	    key == KEYC_MOUSEMOVE_STATUS_LEFT ||
+	    key == KEYC_MOUSEMOVE_STATUS_RIGHT ||
+	    key == KEYC_MOUSEMOVE_STATUS_DEFAULT ||
+	    key == KEYC_MOUSEMOVE_BORDER)
+		goto forward_key;
+
+	/*
+	 * No match in this table. If not in the root table or if repeating
 	 * switch the client back to the root table and try again.
 	 */
 	log_debug("not found in key table %s", table->name);
@@ -2560,7 +2614,8 @@ server_client_check_redraw(struct client
 	struct tty		*tty = &c->tty;
 	struct window		*w = c->session->curw->window;
 	struct window_pane	*wp;
-	int			 needed, flags, mode = tty->mode, new_flags = 0;
+	int			 needed, tty_flags, mode = tty->mode;
+	uint64_t		 client_flags = 0;
 	int			 redraw;
 	u_int			 bit = 0;
 	struct timeval		 tv = { .tv_usec = 1000 };
@@ -2594,7 +2649,7 @@ server_client_check_redraw(struct client
 			}
 		}
 		if (needed)
-			new_flags |= CLIENT_REDRAWPANES;
+			client_flags |= CLIENT_REDRAWPANES;
 	}
 	if (needed && (left = EVBUFFER_LENGTH(tty->out)) != 0) {
 		log_debug("%s: redraw deferred (%zu left)", c->name, left);
@@ -2617,20 +2672,20 @@ server_client_check_redraw(struct client
 					 * If more that 64 panes, give up and
 					 * just redraw the window.
 					 */
-					new_flags &= CLIENT_REDRAWPANES;
-					new_flags |= CLIENT_REDRAWWINDOW;
+					client_flags &= CLIENT_REDRAWPANES;
+					client_flags |= CLIENT_REDRAWWINDOW;
 					break;
 				}
 			}
 			if (c->redraw_panes != 0)
 				c->flags |= CLIENT_REDRAWPANES;
 		}
-		c->flags |= new_flags;
+		c->flags |= client_flags;
 		return;
 	} else if (needed)
 		log_debug("%s: redraw needed", c->name);
 
-	flags = tty->flags & (TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR);
+	tty_flags = tty->flags & (TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR);
 	tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE))|TTY_NOCURSOR;
 
 	if (~c->flags & CLIENT_REDRAWWINDOW) {
@@ -2662,9 +2717,10 @@ server_client_check_redraw(struct client
 		screen_redraw_screen(c);
 	}
 
-	tty->flags = (tty->flags & ~TTY_NOCURSOR)|(flags & TTY_NOCURSOR);
+	tty->flags = (tty->flags & ~TTY_NOCURSOR)|(tty_flags & TTY_NOCURSOR);
 	tty_update_mode(tty, mode, NULL);
-	tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR))|flags;
+	tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR))|
+	    tty_flags;
 
 	c->flags &= ~(CLIENT_ALLREDRAWFLAGS|CLIENT_STATUSFORCE);
 

Index: src/external/bsd/tmux/dist/compat.h
diff -u src/external/bsd/tmux/dist/compat.h:1.5 src/external/bsd/tmux/dist/compat.h:1.6
--- src/external/bsd/tmux/dist/compat.h:1.5	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/compat.h	Sat Nov  9 13:13:25 2024
@@ -289,6 +289,11 @@ void		 explicit_bzero(void *, size_t);
 int		 getdtablecount(void);
 #endif
 
+#ifndef HAVE_GETDTABLESIZE
+/* getdtablesize.c */
+int		 getdtablesize(void);
+#endif
+
 #ifndef HAVE_CLOSEFROM
 /* closefrom.c */
 void		 closefrom(int);
Index: src/external/bsd/tmux/dist/menu.c
diff -u src/external/bsd/tmux/dist/menu.c:1.5 src/external/bsd/tmux/dist/menu.c:1.6
--- src/external/bsd/tmux/dist/menu.c:1.5	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/menu.c	Sat Nov  9 13:13:25 2024
@@ -335,7 +335,7 @@ menu_key_cb(struct client *c, void *data
 		c->flags |= CLIENT_REDRAWOVERLAY;
 		return (0);
 	case KEYC_PPAGE:
-	case '\002': /* C-b */
+	case 'b'|KEYC_CTRL:
 		if (md->choice < 6)
 			md->choice = 0;
 		else {
@@ -394,13 +394,13 @@ menu_key_cb(struct client *c, void *data
 		}
 		c->flags |= CLIENT_REDRAWOVERLAY;
 		break;
-	case '\006': /* C-f */
+	case 'f'|KEYC_CTRL:
 		break;
 	case '\r':
 		goto chosen;
 	case '\033': /* Escape */
-	case '\003': /* C-c */
-	case '\007': /* C-g */
+	case 'c'|KEYC_CTRL:
+	case 'g'|KEYC_CTRL:
 	case 'q':
 		return (1);
 	}
Index: src/external/bsd/tmux/dist/resize.c
diff -u src/external/bsd/tmux/dist/resize.c:1.5 src/external/bsd/tmux/dist/resize.c:1.6
--- src/external/bsd/tmux/dist/resize.c:1.5	Wed Jun 28 22:21:26 2023
+++ src/external/bsd/tmux/dist/resize.c	Sat Nov  9 13:13:25 2024
@@ -40,7 +40,7 @@ resize_window(struct window *w, u_int sx
 	/* If the window is zoomed, unzoom. */
 	zoomed = w->flags & WINDOW_ZOOMED;
 	if (zoomed)
-		window_unzoom(w);
+		window_unzoom(w, 1);
 
 	/* Resize the layout first. */
 	layout_resize(w, sx, sy);

Index: src/external/bsd/tmux/dist/format.c
diff -u src/external/bsd/tmux/dist/format.c:1.15 src/external/bsd/tmux/dist/format.c:1.16
--- src/external/bsd/tmux/dist/format.c:1.15	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/format.c	Sat Nov  9 13:13:25 2024
@@ -1136,8 +1136,7 @@ format_cb_mouse_word(struct format_tree 
 		return (NULL);
 
 	if (!TAILQ_EMPTY(&wp->modes)) {
-		if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode ||
-		    TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
+		if (window_pane_mode(wp) != WINDOW_PANE_NO_MODE)
 			return (window_copy_get_word(wp, x, y));
 		return (NULL);
 	}
@@ -1181,8 +1180,7 @@ format_cb_mouse_line(struct format_tree 
 		return (NULL);
 
 	if (!TAILQ_EMPTY(&wp->modes)) {
-		if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode ||
-		    TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
+		if (window_pane_mode(wp) != WINDOW_PANE_NO_MODE)
 			return (window_copy_get_line(wp, y));
 		return (NULL);
 	}
@@ -1962,6 +1960,23 @@ format_cb_pane_unseen_changes(struct for
 	return (NULL);
 }
 
+/* Callback for pane_key_mode. */
+static void *
+format_cb_pane_key_mode(struct format_tree *ft)
+{
+	if (ft->wp != NULL && ft->wp->screen != NULL) {
+		switch (ft->wp->screen->mode & EXTENDED_KEY_MODES) {
+		case MODE_KEYS_EXTENDED:
+			return (xstrdup("Ext 1"));
+		case MODE_KEYS_EXTENDED_2:
+			return (xstrdup("Ext 2"));
+		default:
+			return (xstrdup("VT10x"));
+		}
+	}
+	return (NULL);
+}
+
 /* Callback for pane_last. */
 static void *
 format_cb_pane_last(struct format_tree *ft)
@@ -2997,6 +3012,9 @@ static const struct format_table_entry f
 	{ "pane_input_off", FORMAT_TABLE_STRING,
 	  format_cb_pane_input_off
 	},
+	{ "pane_key_mode", FORMAT_TABLE_STRING,
+	  format_cb_pane_key_mode
+	},
 	{ "pane_last", FORMAT_TABLE_STRING,
 	  format_cb_pane_last
 	},
Index: src/external/bsd/tmux/dist/screen-write.c
diff -u src/external/bsd/tmux/dist/screen-write.c:1.15 src/external/bsd/tmux/dist/screen-write.c:1.16
--- src/external/bsd/tmux/dist/screen-write.c:1.15	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/screen-write.c	Sat Nov  9 13:13:25 2024
@@ -326,8 +326,9 @@ screen_write_reset(struct screen_write_c
 	screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
 
 	s->mode = MODE_CURSOR|MODE_WRAP;
+
 	if (options_get_number(global_options, "extended-keys") == 2)
-		s->mode |= MODE_KEXTENDED;
+		s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED;
 
 	screen_write_clearscreen(ctx, 8);
 	screen_write_set_cursor(ctx, 0, 0);
@@ -2148,7 +2149,7 @@ screen_write_combine(struct screen_write
 	/* Set the new cell. */
 	grid_view_set_cell(gd, cx - n, cy, &last);
 	if (force_wide)
-		grid_view_set_padding(gd, cx, cy);
+		grid_view_set_padding(gd, cx - 1, cy);
 
 	/*
 	 * Redraw the combined cell. If forcing the cell to width 2, reset the
@@ -2283,6 +2284,10 @@ screen_write_sixelimage(struct screen_wr
 		new = sixel_scale(si, 0, 0, 0, y - sy, sx, sy, 1);
 		sixel_free(si);
 		si = new;
+
+		/* Bail out if the image cannot be scaled. */
+		if (si == NULL)
+			return;
 		sixel_size_in_cells(si, &x, &y);
 	}
 
Index: src/external/bsd/tmux/dist/screen.c
diff -u src/external/bsd/tmux/dist/screen.c:1.15 src/external/bsd/tmux/dist/screen.c:1.16
--- src/external/bsd/tmux/dist/screen.c:1.15	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/screen.c	Sat Nov  9 13:13:25 2024
@@ -110,8 +110,9 @@ screen_reinit(struct screen *s)
 	s->rlower = screen_size_y(s) - 1;
 
 	s->mode = MODE_CURSOR|MODE_WRAP|(s->mode & MODE_CRLF);
+
 	if (options_get_number(global_options, "extended-keys") == 2)
-		s->mode |= MODE_KEXTENDED;
+		s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED;
 
 	if (s->saved_grid != NULL)
 		screen_alternate_off(s, NULL, 0);
@@ -308,12 +309,12 @@ screen_resize_cursor(struct screen *s, u
 	if (sy != screen_size_y(s))
 		screen_resize_y(s, sy, eat_empty, &cy);
 
-	if (reflow) {
 #ifdef ENABLE_SIXEL
-		image_free_all(s);
+	image_free_all(s);
 #endif
+
+	if (reflow)
 		screen_reflow(s, sx, &cx, &cy, cursor);
-	}
 
 	if (cy >= s->grid->hsize) {
 		s->cx = cx;
@@ -400,7 +401,7 @@ screen_resize_y(struct screen *s, u_int 
 
 		/*
 		 * Try to pull as much as possible out of scrolled history, if
-		 * is is enabled.
+		 * it is enabled.
 		 */
 		available = gd->hscrolled;
 		if (gd->flags & GRID_HISTORY && available > 0) {
@@ -730,8 +731,10 @@ screen_mode_to_string(int mode)
 		strlcat(tmp, "ORIGIN,", sizeof tmp);
 	if (mode & MODE_CRLF)
 		strlcat(tmp, "CRLF,", sizeof tmp);
-	if (mode & MODE_KEXTENDED)
-		strlcat(tmp, "KEXTENDED,", sizeof tmp);
+	if (mode & MODE_KEYS_EXTENDED)
+		strlcat(tmp, "KEYS_EXTENDED,", sizeof tmp);
+	if (mode & MODE_KEYS_EXTENDED_2)
+		strlcat(tmp, "KEYS_EXTENDED_2,", sizeof tmp);
 	tmp[strlen(tmp) - 1] = '\0';
 	return (tmp);
 }
Index: src/external/bsd/tmux/dist/server-fn.c
diff -u src/external/bsd/tmux/dist/server-fn.c:1.15 src/external/bsd/tmux/dist/server-fn.c:1.16
--- src/external/bsd/tmux/dist/server-fn.c:1.15	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/server-fn.c	Sat Nov  9 13:13:25 2024
@@ -411,7 +411,7 @@ server_find_session(struct session *s,
 static int
 server_newer_session(struct session *s_loop, struct session *s_out)
 {
-	return (timercmp(&s_loop->activity_time, &s_out->activity_time, <));
+	return (timercmp(&s_loop->activity_time, &s_out->activity_time, >));
 }
 
 static int
@@ -488,6 +488,6 @@ server_check_unattached(void)
 void
 server_unzoom_window(struct window *w)
 {
-	if (window_unzoom(w) == 0)
+	if (window_unzoom(w, 1) == 0)
 		server_redraw_window(w);
 }
Index: src/external/bsd/tmux/dist/tmux.c
diff -u src/external/bsd/tmux/dist/tmux.c:1.15 src/external/bsd/tmux/dist/tmux.c:1.16
--- src/external/bsd/tmux/dist/tmux.c:1.15	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/tmux.c	Sat Nov  9 13:13:25 2024
@@ -235,6 +235,24 @@ fail:
 	return (NULL);
 }
 
+char *
+shell_argv0(const char *shell, int is_login)
+{
+	const char	*slash, *name;
+	char		*argv0;
+
+	slash = strrchr(shell, '/');
+	if (slash != NULL && slash[1] != '\0')
+		name = slash + 1;
+	else
+		name = shell;
+	if (is_login)
+		xasprintf(&argv0, "-%s", name);
+	else
+		xasprintf(&argv0, "%s", name);
+	return (argv0);
+}
+
 void
 setblocking(int fd, int state)
 {
@@ -390,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;

Index: src/external/bsd/tmux/dist/input-keys.c
diff -u src/external/bsd/tmux/dist/input-keys.c:1.14 src/external/bsd/tmux/dist/input-keys.c:1.15
--- src/external/bsd/tmux/dist/input-keys.c:1.14	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/input-keys.c	Sat Nov  9 13:13:25 2024
@@ -307,20 +307,6 @@ static struct input_key_entry input_key_
 	{ .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
 	  .data = "\033[3;_~"
 	},
-
-	/* Tab and modifiers. */
-	{ .key = '\011'|KEYC_CTRL,
-	  .data = "\011"
-	},
-	{ .key = '\011'|KEYC_CTRL|KEYC_EXTENDED,
-	  .data = "\033[9;5u"
-	},
-	{ .key = '\011'|KEYC_CTRL|KEYC_SHIFT,
-	  .data = "\033[Z"
-	},
-	{ .key = '\011'|KEYC_CTRL|KEYC_SHIFT|KEYC_EXTENDED,
-	  .data = "\033[1;5Z"
-	}
 };
 static const key_code input_key_modifiers[] = {
 	0,
@@ -426,14 +412,164 @@ input_key_write(const char *from, struct
 	bufferevent_write(bev, data, size);
 }
 
+/*
+ * Encode and write an extended key escape sequence in one of the two
+ * possible formats, depending on the configured output mode.
+ */
+static int
+input_key_extended(struct bufferevent *bev, key_code key)
+{
+	char		 tmp[64], modifier;
+	struct utf8_data ud;
+	wchar_t		 wc;
+
+	switch (key & KEYC_MASK_MODIFIERS) {
+	case KEYC_SHIFT:
+		modifier = '2';
+		break;
+	case KEYC_META:
+		modifier = '3';
+		break;
+	case KEYC_SHIFT|KEYC_META:
+		modifier = '4';
+		break;
+	case KEYC_CTRL:
+		modifier = '5';
+		break;
+	case KEYC_SHIFT|KEYC_CTRL:
+		modifier = '6';
+		break;
+	case KEYC_META|KEYC_CTRL:
+		modifier = '7';
+		break;
+	case KEYC_SHIFT|KEYC_META|KEYC_CTRL:
+		modifier = '8';
+		break;
+	default:
+		return (-1);
+	}
+
+	if (KEYC_IS_UNICODE(key)) {
+		utf8_to_data(key & KEYC_MASK_KEY, &ud);
+		if (utf8_towc(&ud, &wc) == UTF8_DONE)
+			key = wc;
+		else
+			return (-1);
+	} else
+		key &= KEYC_MASK_KEY;
+
+	if (options_get_number(global_options, "extended-keys-format") == 1)
+		xsnprintf(tmp, sizeof tmp, "\033[27;%c;%llu~", modifier, key);
+	else
+		xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", key, modifier);
+
+	input_key_write(__func__, bev, tmp, strlen(tmp));
+	return (0);
+}
+
+/*
+ * Outputs the key in the "standard" mode. This is by far the most
+ * complicated output mode, with a lot of remapping in order to
+ * emulate quirks of terminals that today can be only found in museums.
+ */
+static int
+input_key_vt10x(struct bufferevent *bev, key_code key)
+{
+	struct utf8_data	 ud;
+	key_code		 onlykey;
+	char			*p;
+	static const char	*standard_map[2] = {
+		"1!9(0)=+;:'\",<.>/-8? 2",
+		"119900=+;;'',,..\x1f\x1f\x7f\x7f\0\0",
+	};
+
+	log_debug("%s: key in %llx", __func__, key);
+
+	if (key & KEYC_META)
+		input_key_write(__func__, bev, "\033", 1);
+
+	/*
+	 * There's no way to report modifiers for unicode keys in standard mode
+	 * so lose the modifiers.
+	 */
+	if (KEYC_IS_UNICODE(key)) {
+		utf8_to_data(key, &ud);
+                input_key_write(__func__, bev, (const char *)ud.data, ud.size);
+		return (0);
+	}
+
+	/* Prevent TAB and RET from being swallowed by C0 remapping logic. */
+	onlykey = key & KEYC_MASK_KEY;
+	if (onlykey == '\r' || onlykey == '\t')
+		key &= ~KEYC_CTRL;
+
+	/*
+	 * Convert keys with Ctrl modifier into corresponding C0 control codes,
+	 * with the exception of *some* keys, which are remapped into printable
+	 * ASCII characters.
+	 *
+	 * There is no special handling for Shift modifier, which is pretty
+	 * much redundant anyway, as no terminal will send <base key>|SHIFT,
+	 * but only <shifted key>|SHIFT.
+	 */
+	if (key & KEYC_CTRL) {
+		p = strchr(standard_map[0], onlykey);
+		if (p != NULL)
+			key = standard_map[1][p - standard_map[0]];
+		else if (onlykey >= '3' && onlykey <= '7')
+			key = onlykey - '\030';
+		else if (onlykey >= '@' && onlykey <= '~')
+			key = onlykey & 0x1f;
+		else
+			return (-1);
+	}
+
+	log_debug("%s: key out %llx", __func__, key);
+
+	ud.data[0] = key & 0x7f;
+	input_key_write(__func__, bev, (const char *)&ud.data[0], 1);
+	return (0);
+}
+
+/* Pick keys that are reported as vt10x keys in modifyOtherKeys=1 mode. */
+static int
+input_key_mode1(struct bufferevent *bev, key_code key)
+{
+	key_code	 onlykey;
+
+	log_debug("%s: key in %llx", __func__, key);
+
+	/*
+	 * As per
+	 * https://invisible-island.net/xterm/modified-keys-us-pc105.html.
+	 */
+	onlykey = key & KEYC_MASK_KEY;
+	if ((key & (KEYC_META | KEYC_CTRL)) == KEYC_CTRL &&
+	    (onlykey == ' ' ||
+	     onlykey == '/' ||
+	     onlykey == '@' ||
+	     onlykey == '^' ||
+	     (onlykey >= '2' && onlykey <= '8') ||
+	     (onlykey >= '@' && onlykey <= '~')))
+		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.
+	 */
+	if ((key & (KEYC_CTRL | KEYC_META)) == KEYC_META)
+		return (input_key_vt10x(bev, key));
+
+	return (-1);
+}
+
 /* Translate a key code into an output key sequence. */
 int
 input_key(struct screen *s, struct bufferevent *bev, key_code key)
 {
 	struct input_key_entry	*ike = NULL;
-	key_code		 justkey, newkey, outkey, modifiers;
+	key_code		 newkey;
 	struct utf8_data	 ud;
-	char			 tmp[64], modifier;
 
 	/* Mouse keys need a pane. */
 	if (KEYC_IS_MOUSE(key))
@@ -454,36 +590,46 @@ input_key(struct screen *s, struct buffe
 		key = newkey|(key & (KEYC_MASK_MODIFIERS|KEYC_MASK_FLAGS));
 	}
 
+	/* Is this backtab? */
+	if ((key & KEYC_MASK_KEY) == KEYC_BTAB) {
+		if ((s->mode & EXTENDED_KEY_MODES) != 0) {
+			/* When in xterm extended mode, remap into S-Tab. */
+			key = '\011' | (key & ~KEYC_MASK_KEY) | KEYC_SHIFT;
+		} else {
+			/* Otherwise clear modifiers. */
+			key &= ~KEYC_MASK_MODIFIERS;
+		}
+	}
+
 	/*
-	 * If this is a normal 7-bit key, just send it, with a leading escape
-	 * if necessary. If it is a UTF-8 key, split it and send it.
+	 * A trivial case, that is a 7-bit key, excluding C0 control characters
+	 * that can't be entered from the keyboard, and no modifiers; or a UTF-8
+	 * key and no modifiers.
 	 */
-	justkey = (key & ~(KEYC_META|KEYC_IMPLIED_META));
-	if (justkey <= 0x7f) {
-		if (key & KEYC_META)
-			input_key_write(__func__, bev, "\033", 1);
-		ud.data[0] = justkey;
-		input_key_write(__func__, bev, (const char *)ud.data, 1);
-		return (0);
-	}
-	if (KEYC_IS_UNICODE(justkey)) {
-		if (key & KEYC_META)
-			input_key_write(__func__, bev, "\033", 1);
-		utf8_to_data(justkey, &ud);
-		input_key_write(__func__, bev, (const char *)ud.data, ud.size);
-		return (0);
+	if (!(key & ~KEYC_MASK_KEY)) {
+		if (key == C0_HT ||
+		    key == C0_CR ||
+		    key == C0_ESC ||
+		    (key >= 0x20 && key <= 0x7f)) {
+			ud.data[0] = key;
+			input_key_write(__func__, bev, (const char *)&ud.data[0], 1);
+			return (0);
+		}
+		if (KEYC_IS_UNICODE(key)) {
+			utf8_to_data(key, &ud);
+			input_key_write(__func__, bev, (const char *)ud.data, ud.size);
+			return (0);
+		}
 	}
 
 	/*
-	 * Look up in the tree. If not in application keypad or cursor mode,
-	 * remove the flags from the key.
+	 * Look up the standard VT10x keys in the tree. If not in application
+	 * keypad or cursor mode, remove the respective flags from the key.
 	 */
 	if (~s->mode & MODE_KKEYPAD)
 		key &= ~KEYC_KEYPAD;
 	if (~s->mode & MODE_KCURSOR)
 		key &= ~KEYC_CURSOR;
-	if (s->mode & MODE_KEXTENDED)
-		ike = input_key_get(key|KEYC_EXTENDED);
 	if (ike == NULL)
 		ike = input_key_get(key);
 	if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META))
@@ -492,10 +638,9 @@ input_key(struct screen *s, struct buffe
 		ike = input_key_get(key & ~KEYC_CURSOR);
 	if (ike == NULL && (key & KEYC_KEYPAD))
 		ike = input_key_get(key & ~KEYC_KEYPAD);
-	if (ike == NULL && (key & KEYC_EXTENDED))
-		ike = input_key_get(key & ~KEYC_EXTENDED);
 	if (ike != NULL) {
-		log_debug("found key 0x%llx: \"%s\"", key, ike->data);
+		log_debug("%s: found key 0x%llx: \"%s\"", __func__, key,
+		    ike->data);
 		if ((key == KEYC_PASTE_START || key == KEYC_PASTE_END) &&
 		    (~s->mode & MODE_BRACKETPASTE))
 			return (0);
@@ -505,78 +650,41 @@ input_key(struct screen *s, struct buffe
 		return (0);
 	}
 
-	/* No builtin key sequence; construct an extended key sequence. */
-	if (~s->mode & MODE_KEXTENDED) {
-		if ((key & KEYC_MASK_MODIFIERS) != KEYC_CTRL)
-			goto missing;
-		justkey = (key & KEYC_MASK_KEY);
-		switch (justkey) {
-		case ' ':
-		case '2':
-			key = 0|(key & ~KEYC_MASK_KEY);
-			break;
-		case '|':
-			key = 28|(key & ~KEYC_MASK_KEY);
-			break;
-		case '6':
-			key = 30|(key & ~KEYC_MASK_KEY);
-			break;
-		case '-':
-		case '/':
-			key = 31|(key & ~KEYC_MASK_KEY);
-			break;
-		case '?':
-			key = 127|(key & ~KEYC_MASK_KEY);
-			break;
-		default:
-			if (justkey >= 'A' && justkey <= '_')
-				key = (justkey - 'A')|(key & ~KEYC_MASK_KEY);
-			else if (justkey >= 'a' && justkey <= '~')
-				key = (justkey - 96)|(key & ~KEYC_MASK_KEY);
-			else
-				return (0);
-			break;
-		}
-		return (input_key(s, bev, key & ~KEYC_CTRL));
-	}
-	outkey = (key & KEYC_MASK_KEY);
-	modifiers = (key & KEYC_MASK_MODIFIERS);
-	if (outkey < 32 && outkey != 9 && outkey != 13 && outkey != 27) {
-		outkey = 64 + outkey;
-		modifiers |= KEYC_CTRL;
+	/* Ignore internal function key codes. */
+	if ((key >= KEYC_BASE && key < KEYC_BASE_END) ||
+	    (key >= KEYC_USER && key < KEYC_USER_END)) {
+		log_debug("%s: ignoring key 0x%llx", __func__, key);
+		return (0);
 	}
-	switch (modifiers) {
-	case KEYC_SHIFT:
-		modifier = '2';
-		break;
-	case KEYC_META:
-		modifier = '3';
-		break;
-	case KEYC_SHIFT|KEYC_META:
-		modifier = '4';
-		break;
-	case KEYC_CTRL:
-		modifier = '5';
-		break;
-	case KEYC_SHIFT|KEYC_CTRL:
-		modifier = '6';
-		break;
-	case KEYC_META|KEYC_CTRL:
-		modifier = '7';
-		break;
-	case KEYC_SHIFT|KEYC_META|KEYC_CTRL:
-		modifier = '8';
-		break;
+
+	/*
+	 * No builtin key sequence; construct an extended key sequence
+	 * depending on the client mode.
+	 *
+	 * If something invalid reaches here, an invalid output may be
+	 * produced. For example Ctrl-Shift-2 is invalid (as there's
+	 * no way to enter it). The correct form is Ctrl-Shift-@, at
+	 * least in US English keyboard layout.
+	 */
+	switch (s->mode & EXTENDED_KEY_MODES) {
+	case MODE_KEYS_EXTENDED_2:
+		/*
+		 * The simplest mode to handle - *all* modified keys are
+		 * reported in the extended form.
+		 */
+		return (input_key_extended(bev, key));
+        case MODE_KEYS_EXTENDED:
+		/*
+		 * Some keys are still reported in standard mode, to maintain
+		 * compatibility with applications unaware of extended keys.
+		 */
+		if (input_key_mode1(bev, key) == -1)
+			return (input_key_extended(bev, key));
+		return (0);
 	default:
-		goto missing;
+		/* The standard mode. */
+		return (input_key_vt10x(bev, key));
 	}
-	xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", outkey, modifier);
-	input_key_write(__func__, bev, tmp, strlen(tmp));
-	return (0);
-
-missing:
-	log_debug("key 0x%llx missing", key);
-	return (-1);
 }
 
 /* Get mouse event string. */
Index: src/external/bsd/tmux/dist/options.c
diff -u src/external/bsd/tmux/dist/options.c:1.14 src/external/bsd/tmux/dist/options.c:1.15
--- src/external/bsd/tmux/dist/options.c:1.14	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/options.c	Sat Nov  9 13:13:25 2024
@@ -578,10 +578,28 @@ char *
 options_to_string(struct options_entry *o, int idx, int numeric)
 {
 	struct options_array_item	*a;
+	char				*result = NULL;
+	char				*last = NULL;
+	char				*next;
 
 	if (OPTIONS_IS_ARRAY(o)) {
-		if (idx == -1)
-			return (xstrdup(""));
+		if (idx == -1) {
+			RB_FOREACH(a, options_array, &o->value.array) {
+				next = options_value_to_string(o, &a->value,
+				    numeric);
+				if (last == NULL)
+					result = next;
+				else {
+					xasprintf(&result, "%s %s", last, next);
+					free(last);
+					free(next);
+				}
+				last = result;
+			}
+			if (result == NULL)
+				return (xstrdup(""));
+			return (result);
+		}
 		a = options_array_item(o, idx);
 		if (a == NULL)
 			return (xstrdup(""));

Index: src/external/bsd/tmux/dist/input.c
diff -u src/external/bsd/tmux/dist/input.c:1.18 src/external/bsd/tmux/dist/input.c:1.19
--- src/external/bsd/tmux/dist/input.c:1.18	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/input.c	Sat Nov  9 13:13:25 2024
@@ -109,10 +109,11 @@ struct input_ctx {
 	int			utf8started;
 
 	int			ch;
-	int			last;
+	struct utf8_data	last;
 
 	int			flags;
 #define INPUT_DISCARD 0x1
+#define INPUT_LAST 0x2
 
 	const struct input_state *state;
 
@@ -867,8 +868,6 @@ input_reset(struct input_ctx *ictx, int 
 
 	input_clear(ictx);
 
-	ictx->last = -1;
-
 	ictx->state = &input_state_ground;
 	ictx->flags = 0;
 }
@@ -1149,7 +1148,9 @@ input_print(struct input_ctx *ictx)
 
 	utf8_set(&ictx->cell.cell.data, ictx->ch);
 	screen_write_collect_add(sctx, &ictx->cell.cell);
-	ictx->last = ictx->ch;
+
+	utf8_copy(&ictx->last, &ictx->cell.cell.data);
+	ictx->flags |= INPUT_LAST;
 
 	ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
 
@@ -1261,7 +1262,7 @@ input_c0_dispatch(struct input_ctx *ictx
 		break;
 	}
 
-	ictx->last = -1;
+	ictx->flags &= ~INPUT_LAST;
 	return (0);
 }
 
@@ -1337,7 +1338,7 @@ input_esc_dispatch(struct input_ctx *ict
 		break;
 	}
 
-	ictx->last = -1;
+	ictx->flags &= ~INPUT_LAST;
 	return (0);
 }
 
@@ -1348,7 +1349,7 @@ input_csi_dispatch(struct input_ctx *ict
 	struct screen_write_ctx	       *sctx = &ictx->ctx;
 	struct screen		       *s = sctx->s;
 	struct input_table_entry       *entry;
-	int				i, n, m;
+	int				i, n, m, ek;
 	u_int				cx, bg = ictx->cell.cell.bg;
 
 	if (ictx->flags & INPUT_DISCARD)
@@ -1406,18 +1407,36 @@ input_csi_dispatch(struct input_ctx *ict
 		break;
 	case INPUT_CSI_MODSET:
 		n = input_get(ictx, 0, 0, 0);
+		if (n != 4)
+			break;
 		m = input_get(ictx, 1, 0, 0);
-		if (options_get_number(global_options, "extended-keys") == 2)
+
+		/*
+		 * Set the extended key reporting mode as per the client
+		 * request, unless "extended-keys" is set to "off".
+		 */
+		ek = options_get_number(global_options, "extended-keys");
+		if (ek == 0)
 			break;
-		if (n == 0 || (n == 4 && m == 0))
-			screen_write_mode_clear(sctx, MODE_KEXTENDED);
-		else if (n == 4 && (m == 1 || m == 2))
-			screen_write_mode_set(sctx, MODE_KEXTENDED);
+		screen_write_mode_clear(sctx, EXTENDED_KEY_MODES);
+		if (m == 2)
+			screen_write_mode_set(sctx, MODE_KEYS_EXTENDED_2);
+		else if (m == 1 || ek == 2)
+			screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
 		break;
 	case INPUT_CSI_MODOFF:
 		n = input_get(ictx, 0, 0, 0);
-		if (n == 4)
-			screen_write_mode_clear(sctx, MODE_KEXTENDED);
+		if (n != 4)
+			break;
+
+		/*
+		 * Clear the extended key reporting mode as per the client
+		 * request, unless "extended-keys always" forces into mode 1.
+		 */
+		screen_write_mode_clear(sctx,
+		    MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2);
+		if (options_get_number(global_options, "extended-keys") == 2)
+			screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
 		break;
 	case INPUT_CSI_WINOPS:
 		input_csi_dispatch_winops(ictx);
@@ -1574,12 +1593,12 @@ input_csi_dispatch(struct input_ctx *ict
 		if (n > m)
 			n = m;
 
-		if (ictx->last == -1)
+		if (~ictx->flags & INPUT_LAST)
 			break;
-		ictx->ch = ictx->last;
 
+		utf8_copy(&ictx->cell.cell.data, &ictx->last);
 		for (i = 0; i < n; i++)
-			input_print(ictx);
+			screen_write_collect_add(sctx, &ictx->cell.cell);
 		break;
 	case INPUT_CSI_RCP:
 		input_restore_state(ictx);
@@ -1649,7 +1668,7 @@ input_csi_dispatch(struct input_ctx *ict
 
 	}
 
-	ictx->last = -1;
+	ictx->flags &= ~INPUT_LAST;
 	return (0);
 }
 
@@ -1839,7 +1858,7 @@ input_csi_dispatch_sm_private(struct inp
 
 /* Handle CSI graphics SM. */
 static void
-input_csi_dispatch_sm_graphics(struct input_ctx *ictx)
+input_csi_dispatch_sm_graphics(__unused struct input_ctx *ictx)
 {
 #ifdef ENABLE_SIXEL
 	int	n, m, o;
@@ -2284,7 +2303,7 @@ input_enter_dcs(struct input_ctx *ictx)
 
 	input_clear(ictx);
 	input_start_timer(ictx);
-	ictx->last = -1;
+	ictx->flags &= ~INPUT_LAST;
 }
 
 /* DCS terminator (ST) received. */
@@ -2341,7 +2360,7 @@ input_enter_osc(struct input_ctx *ictx)
 
 	input_clear(ictx);
 	input_start_timer(ictx);
-	ictx->last = -1;
+	ictx->flags &= ~INPUT_LAST;
 }
 
 /* OSC terminator (ST) received. */
@@ -2372,7 +2391,9 @@ input_exit_osc(struct input_ctx *ictx)
 	switch (option) {
 	case 0:
 	case 2:
-		if (screen_set_title(sctx->s, p) && wp != NULL) {
+		if (wp != NULL &&
+		    options_get_number(wp->options, "allow-set-title") &&
+		    screen_set_title(sctx->s, p)) {
 			notify_pane("pane-title-changed", wp);
 			server_redraw_window_borders(wp->window);
 			server_status_window(wp->window);
@@ -2434,7 +2455,7 @@ input_enter_apc(struct input_ctx *ictx)
 
 	input_clear(ictx);
 	input_start_timer(ictx);
-	ictx->last = -1;
+	ictx->flags &= ~INPUT_LAST;
 }
 
 /* APC terminator (ST) received. */
@@ -2464,7 +2485,7 @@ input_enter_rename(struct input_ctx *ict
 
 	input_clear(ictx);
 	input_start_timer(ictx);
-	ictx->last = -1;
+	ictx->flags &= ~INPUT_LAST;
 }
 
 /* Rename terminator (ST) received. */
@@ -2509,7 +2530,7 @@ input_top_bit_set(struct input_ctx *ictx
 	struct screen_write_ctx	*sctx = &ictx->ctx;
 	struct utf8_data	*ud = &ictx->utf8data;
 
-	ictx->last = -1;
+	ictx->flags &= ~INPUT_LAST;
 
 	if (!ictx->utf8started) {
 		if (utf8_open(ud, ictx->ch) != UTF8_MORE)
@@ -2535,6 +2556,9 @@ input_top_bit_set(struct input_ctx *ictx
 	utf8_copy(&ictx->cell.cell.data, ud);
 	screen_write_collect_add(sctx, &ictx->cell.cell);
 
+	utf8_copy(&ictx->last, &ictx->cell.cell.data);
+	ictx->flags |= INPUT_LAST;
+
 	return (0);
 }
 
@@ -2683,6 +2707,44 @@ input_get_bg_client(struct window_pane *
 	return (-1);
 }
 
+/*
+ * If any control mode client exists that has provided a bg color, return it.
+ * Otherwise, return -1.
+ */
+static int
+input_get_bg_control_client(struct window_pane *wp)
+{
+	struct client	*c;
+
+	if (wp->control_bg == -1)
+		return (-1);
+
+	TAILQ_FOREACH(c, &clients, entry) {
+		if (c->flags & CLIENT_CONTROL)
+			return (wp->control_bg);
+	}
+	return (-1);
+}
+
+/*
+ * If any control mode client exists that has provided a fg color, return it.
+ * Otherwise, return -1.
+ */
+static int
+input_get_fg_control_client(struct window_pane *wp)
+{
+	struct client	*c;
+
+	if (wp->control_fg == -1)
+		return (-1);
+
+	TAILQ_FOREACH(c, &clients, entry) {
+		if (c->flags & CLIENT_CONTROL)
+			return (wp->control_fg);
+	}
+	return (-1);
+}
+
 /* Handle the OSC 10 sequence for setting and querying foreground colour. */
 static void
 input_osc_10(struct input_ctx *ictx, const char *p)
@@ -2694,11 +2756,14 @@ input_osc_10(struct input_ctx *ictx, con
 	if (strcmp(p, "?") == 0) {
 		if (wp == NULL)
 			return;
-		tty_default_colours(&defaults, wp);
-		if (COLOUR_DEFAULT(defaults.fg))
-			c = input_get_fg_client(wp);
-		else
-			c = defaults.fg;
+		c = input_get_fg_control_client(wp);
+		if (c == -1) {
+			tty_default_colours(&defaults, wp);
+			if (COLOUR_DEFAULT(defaults.fg))
+				c = input_get_fg_client(wp);
+			else
+				c = defaults.fg;
+		}
 		input_osc_colour_reply(ictx, 10, c);
 		return;
 	}
@@ -2742,11 +2807,14 @@ input_osc_11(struct input_ctx *ictx, con
 	if (strcmp(p, "?") == 0) {
 		if (wp == NULL)
 			return;
-		tty_default_colours(&defaults, wp);
-		if (COLOUR_DEFAULT(defaults.bg))
-			c = input_get_bg_client(wp);
-		else
-			c = defaults.bg;
+		c = input_get_bg_control_client(wp);
+		if (c == -1) {
+			tty_default_colours(&defaults, wp);
+			if (COLOUR_DEFAULT(defaults.bg))
+				c = input_get_bg_client(wp);
+			else
+				c = defaults.bg;
+		}
 		input_osc_colour_reply(ictx, 11, c);
 		return;
 	}
Index: src/external/bsd/tmux/dist/tmux.1
diff -u src/external/bsd/tmux/dist/tmux.1:1.18 src/external/bsd/tmux/dist/tmux.1:1.19
--- src/external/bsd/tmux/dist/tmux.1:1.18	Sat Jun 22 23:33:50 2024
+++ src/external/bsd/tmux/dist/tmux.1	Sat Nov  9 13:13:25 2024
@@ -140,10 +140,9 @@ By default,
 loads the system configuration file from
 .Pa @SYSCONFDIR@/tmux.conf ,
 if present, then looks for a user configuration file at
-.Pa \[ti]/.tmux.conf,
-.Pa $XDG_CONFIG_HOME/tmux/tmux.conf
+.Pa \[ti]/.tmux.conf
 or
-.Pa \[ti]/.tmux.conf .
+.Pa $XDG_CONFIG_HOME/tmux/tmux.conf .
 .Pp
 The configuration file is a set of
 .Nm
@@ -373,8 +372,10 @@ Enter copy mode and scroll one page up.
 Change to the pane above, below, to the left, or to the right of the current
 pane.
 .It M-1 to M-5
-Arrange panes in one of the five preset layouts: even-horizontal,
-even-vertical, main-horizontal, main-vertical, or tiled.
+Arrange panes in one of the seven preset layouts:
+even-horizontal, even-vertical,
+main-horizontal, main-horizontal-mirrored,
+main-vertical, main-vertical, or tiled.
 .It Space
 Arrange the current window in the next preset layout.
 .It M-n
@@ -1039,9 +1040,17 @@ The following commands are available to 
 .D1 Pq alias: Ic attach
 If run from outside
 .Nm ,
-create a new client in the current terminal and attach it to
+attach to
+.Ar target-session
+in the current terminal.
+.Ar target-session
+must already exist - to create a new session, see the
+.Ic new-session
+command (with
+.Fl A
+to create or attach).
+If used from inside, switch the currently attached session to
 .Ar target-session .
-If used from inside, switch the current client.
 If
 .Fl d
 is specified, any other clients attached to the session are detached.
@@ -1353,6 +1362,7 @@ specified multiple times.
 .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
 .Xc
@@ -1462,6 +1472,12 @@ for all windows in the attached session.
 .Fl f
 sets a comma-separated list of client flags, see
 .Ic attach-session .
+.Fl r
+allows a control mode client to provide information about a pane via a report
+(such as the response to OSC 10).
+The argument is a pane ID (with a leading
+.Ql % ) ,
+a colon, then a report escape sequence.
 .Pp
 .Fl l
 requests the clipboard from the client using the
@@ -1798,6 +1814,23 @@ is used to name the new paste buffer.
 .Xc
 Copy from the cursor position and exit copy mode.
 .It Xo
+.Ic copy-pipe-end-of-line
+.Op Ar command
+.Op Ar prefix
+.Xc
+Copy from the cursor position to the end of the line and pipe the text to
+.Ar command .
+.Ar prefix
+is used to name the new paste buffer.
+.It Xo
+.Ic copy-pipe-end-of-line-and-cancel
+.Op Ar command
+.Op Ar prefix
+.Xc
+Same as
+.Ic copy-pipe-end-of-line
+but also exit copy mode.
+.It Xo
 .Ic copy-line
 .Op Ar prefix
 .Xc
@@ -1808,11 +1841,60 @@ Copy the entire line.
 .Xc
 Copy the entire line and exit copy mode.
 .It Xo
+.Ic copy-pipe-line
+.Op Ar command
+.Op Ar prefix
+.Xc
+Copy the entire line and pipe the text to
+.Ar command .
+.Ar prefix
+is used to name the new paste buffer.
+.It Xo
+.Ic copy-pipe-line-and-cancel
+.Op Ar command
+.Op Ar prefix
+.Xc
+Same as
+.Ic copy-pipe-line
+but also exit copy mode.
+.It Xo
+.Ic copy-pipe
+.Op Ar command
+.Op Ar prefix
+.Xc
+Copy the selection, clear it and pipe its text to
+.Ar command .
+.Ar prefix
+is used to name the new paste buffer.
+.It Xo
+.Ic copy-pipe-no-clear
+.Op Ar command
+.Op Ar prefix
+.Xc
+Same as
+.Ic copy-pipe
+but do not clear the selection.
+.It Xo
+.Ic copy-pipe-and-cancel
+.Op Ar command
+.Op Ar prefix
+.Xc
+Same as
+.Ic copy-pipe
+but also exit copy mode.
+.It Xo
 .Ic copy-selection
 .Op Ar prefix
 .Xc
 Copies the current selection.
 .It Xo
+.Ic copy-selection-no-clear
+.Op Ar prefix
+.Xc
+Same as
+.Ic copy-selection
+but do not clear the selection.
+.It Xo
 .Ic copy-selection-and-cancel
 .Op Ar prefix
 (vi: Enter)
@@ -1826,6 +1908,12 @@ Copy the current selection and exit copy
 .Xc
 Move the cursor down.
 .It Xo
+.Ic cursor-down-and-cancel
+.Xc
+Same as
+.Ic cursor-down
+but also exit copy mode if reaching the bottom.
+.It Xo
 .Ic cursor-left
 (vi: h)
 (emacs: Left)
@@ -1857,6 +1945,24 @@ Move the cursor to the end of the line.
 .Xc
 Move the cursor to a specific line.
 .It Xo
+.Ic halfpage-down
+(vi: C-d)
+(emacs: M-Down)
+.Xc
+Scroll down by half a page.
+.It Xo
+.Ic halfpage-down-and-cancel
+.Xc
+Same as
+.Ic halfpage-down
+but also exit copy mode if reaching the bottom.
+.It Xo
+.Ic halfpage-up
+(vi: C-u)
+(emacs: M-Up)
+.Xc
+Scroll up by half a page.
+.It Xo
 .Ic history-bottom
 (vi: G)
 (emacs: M->)
@@ -1889,6 +1995,27 @@ Jump backwards to the specified text.
 .Xc
 Jump forward to the specified text.
 .It Xo
+.Ic jump-reverse
+(vi: ,)
+(emacs: ,)
+.Xc
+Repeat the last jump in the reverse direction (forward becomes backward and
+backward becomes forward).
+.It Xo
+.Ic jump-to-backward
+.Ar to
+(vi: T)
+.Xc
+Jump backwards, but one character less, placing the cursor on the character
+after the target.
+.It Xo
+.Ic jump-to-forward
+.Ar to
+(vi: t)
+.Xc
+Jump forward, but one character less, placing the cursor on the character
+before the target.
+.It Xo
 .Ic jump-to-mark
 (vi: M-x)
 (emacs: M-x)
@@ -1923,18 +2050,71 @@ Move to the next prompt.
 .Xc
 Move to the next word.
 .It Xo
+.Ic next-word-end
+(vi: e)
+(emacs: M-f)
+.Xc
+Move to the end of the next word.
+.It Xo
+.Ic next-space
+(vi: W)
+.Xc
+Same as
+.Ic next-word
+but use a space alone as the word separator.
+.It Xo
+.Ic next-space-end
+(vi: E)
+.Xc
+Same as
+.Ic next-word-end
+but use a space alone as the word separator.
+.It Xo
+.Ic other-end
+(vi: o)
+.Xc
+Switch at which end of the selection the cursor sits.
+.It Xo
 .Ic page-down
 (vi: C-f)
 (emacs: PageDown)
 .Xc
 Scroll down by one page.
 .It Xo
+.Ic page-down-and-cancel
+.Xc
+Same as
+.Ic page-down
+but also exit copy mode if reaching the bottom.
+.It Xo
 .Ic page-up
 (vi: C-b)
 (emacs: PageUp)
 .Xc
 Scroll up by one page.
 .It Xo
+.Ic pipe
+.Op Ar command
+.Xc
+Pipe the selected text to
+.Ar command
+and clear the selection.
+.It Xo
+.Ic pipe-no-clear
+.Op Ar command
+.Xc
+Same as
+.Ic pipe
+but do not clear the selection.
+.It Xo
+.Ic pipe-and-cancel
+.Op Ar command
+.Op Ar prefix
+.Xc
+Same as
+.Ic pipe
+but also exit copy mode.
+.It Xo
 .Ic previous-matching-bracket
 (emacs: M-C-b)
 .Xc
@@ -1957,6 +2137,21 @@ Move to the previous prompt.
 .Xc
 Move to the previous word.
 .It Xo
+.Ic previous-space
+(vi: B)
+.Xc
+Same as
+.Ic previous-word
+but use a space alone as the word separator.
+.It Xo
+.Ic rectangle-on
+.Xc
+Turn on rectangle selection mode.
+.It Xo
+.Ic rectangle-off
+.Xc
+Turn off rectangle selection mode.
+.It Xo
 .Ic rectangle-toggle
 (vi: v)
 (emacs: R)
@@ -1969,6 +2164,40 @@ Toggle rectangle selection mode.
 .Xc
 Refresh the content from the pane.
 .It Xo
+.Ic scroll-bottom
+.Xc
+Scroll up until the current line is at the bottom while keeping the cursor on
+that line.
+.It Xo
+.Ic scroll-down
+(vi: C-e)
+(emacs: C-Down)
+.Xc
+Scroll down.
+.It Xo
+.Ic scroll-down-and-cancel
+.Xc
+Same as
+.Ic scroll-down
+but also exit copy mode if the cursor reaches the bottom.
+.It Xo
+.Ic scroll-middle
+(vi: z)
+.Xc
+Scroll so that the current line becomes the middle one while keeping the
+cursor on that line.
+.It Xo
+.Ic scroll-top
+.Xc
+Scroll down until the current line is at the top while keeping the cursor on
+that line.
+.It Xo
+.Ic scroll-up
+(vi: C-y)
+(emacs: C-Up)
+.Xc
+Scroll up.
+.It Xo
 .Ic search-again
 (vi: n)
 (emacs: n)
@@ -1981,12 +2210,51 @@ Repeat the last search.
 .Xc
 Search backwards for the specified text.
 .It Xo
+.Ic search-backward-incremental
+.Ar text
+(emacs: C-r)
+.Xc
+Search backwards incrementally for the specified text.
+Is expected to be used with the
+.Fl i
+flag to the
+.Ic command-prompt
+command.
+.It Xo
+.Ic search-backward-text
+.Ar text
+.Xc
+Search backwards for the specified plain text.
+.It Xo
 .Ic search-forward
 .Ar text
 (vi: /)
 .Xc
 Search forward for the specified text.
 .It Xo
+.Ic search-forward-incremental
+.Ar text
+(emacs: C-s)
+.Xc
+Search forward incrementally for the specified text.
+Is expected to be used with the
+.Fl i
+flag to the
+.Ic command-prompt
+command.
+.It Xo
+.Ic search-forward-text
+.Ar text
+.Xc
+Search forward for the specified plain text.
+.It Xo
+.Ic search-reverse
+(vi: N)
+(emacs: N)
+.Xc
+Repeat the last search in the reverse direction (forward becomes backward and
+backward becomes forward).
+.It Xo
 .Ic select-line
 (vi: V)
 .Xc
@@ -1996,12 +2264,28 @@ Select the current line.
 .Xc
 Select the current word.
 .It Xo
+.Ic set-mark
+(vi: X)
+(emacs: X)
+.Xc
+Mark the current line.
+.It Xo
 .Ic start-of-line
 (vi: 0)
 (emacs: C-a)
 .Xc
 Move the cursor to the start of the line.
 .It Xo
+.Ic stop-selection
+.Xc
+Stop selecting without clearing the current selection.
+.It Xo
+.Ic toggle-position
+(vi: P)
+(emacs: P)
+.Xc
+Toggle the visibility of the position indicator in the top right.
+.It Xo
 .Ic top-line
 (vi: H)
 (emacs: M-R)
@@ -2094,14 +2378,15 @@ The synopsis for the
 command is:
 .Bl -tag -width Ds
 .It Xo Ic copy-mode
-.Op Fl eHMqu
+.Op Fl deHMqu
 .Op Fl s Ar src-pane
 .Op Fl t Ar target-pane
 .Xc
 Enter copy mode.
-The
 .Fl u
-option scrolls one page up.
+also scrolls one page up after entering and
+.Fl d
+one page down if already in copy mode.
 .Fl M
 begins a mouse drag (only valid if bound to a mouse key binding, see
 .Sx MOUSE SUPPORT ) .
@@ -2124,6 +2409,7 @@ This is intended to allow fast scrolling
 example with:
 .Bd -literal -offset indent
 bind PageUp copy-mode -eu
+bind PageDown copy-mode -ed
 .Ed
 .El
 .Pp
@@ -2150,14 +2436,20 @@ are spread from left to right in the lef
 Use the
 .Em main-pane-height
 window option to specify the height of the top pane.
-.It Ic main-vertical
-Similar to
+.It Ic main-horizontal-mirrored
+The same as
 .Ic main-horizontal
-but the large pane is placed on the left and the others spread from top to
-bottom along the right.
-See the
+but mirrored so the main pane is at the bottom of the window.
+.It Ic main-vertical
+A large (main) pane is shown on the left of the window and the remaining panes
+are spread from top to bottom in the leftover space on the right.
+Use the
 .Em main-pane-width
-window option.
+window option to specify the width of the left pane.
+.It Ic main-vertical-mirrored
+The same as
+.Ic main-vertical
+but mirrored so the main pane is on the right of the window.
 .It Ic tiled
 Panes are spread out as evenly as possible over the window in both rows and
 columns.
@@ -2290,7 +2582,8 @@ The following keys may be used in client
 .It Li "Up" Ta "Select previous client"
 .It Li "Down" Ta "Select next client"
 .It Li "C-s" Ta "Search by name"
-.It Li "n" Ta "Repeat last search"
+.It Li "n" Ta "Repeat last search forwards"
+.It Li "N" Ta "Repeat last search backwards"
 .It Li "t" Ta "Toggle if client is tagged"
 .It Li "T" Ta "Tag no clients"
 .It Li "C-t" Ta "Tag all clients"
@@ -2377,7 +2670,8 @@ The following keys may be used in tree m
 .It Li "C-s" Ta "Search by name"
 .It Li "m" Ta "Set the marked pane"
 .It Li "M" Ta "Clear the marked pane"
-.It Li "n" Ta "Repeat last search"
+.It Li "n" Ta "Repeat last search forwards"
+.It Li "N" Ta "Repeat last search backwards"
 .It Li "t" Ta "Toggle if item is tagged"
 .It Li "T" Ta "Tag no items"
 .It Li "C-t" Ta "Tag all items"
@@ -2455,7 +2749,8 @@ The following keys may be used in custom
 .It Li "u" Ta "Unset an option (set to default value if global) or unbind a key"
 .It Li "U" Ta "Unset tagged options and unbind tagged keys"
 .It Li "C-s" Ta "Search by name"
-.It Li "n" Ta "Repeat last search"
+.It Li "n" Ta "Repeat last search forwards"
+.It Li "N" Ta "Repeat last search backwards"
 .It Li "t" Ta "Toggle if item is tagged"
 .It Li "T" Ta "Tag no items"
 .It Li "C-t" Ta "Tag all items"
@@ -3718,6 +4013,10 @@ Note that aliases are expanded when a co
 executed, so binding an alias with
 .Ic bind-key
 will bind the expanded form.
+.It Ic copy-command Ar shell-command
+Give the command to pipe to if the
+.Ic copy-pipe
+copy mode command is used without arguments.
 .It Ic default-terminal Ar terminal
 Set the default terminal for new windows created in this session - the
 default value of the
@@ -3731,16 +4030,11 @@ be set to
 .Ql screen ,
 .Ql tmux
 or a derivative of them.
-.It Ic copy-command Ar shell-command
-Give the command to pipe to if the
-.Ic copy-pipe
-copy mode command is used without arguments.
 .It Ic escape-time Ar time
 Set the time in milliseconds for which
 .Nm
 waits after an escape is input to determine if it is part of a function or meta
 key sequences.
-The default is 500 milliseconds.
 .It Ic editor Ar shell-command
 Set the command used when
 .Nm
@@ -3757,22 +4051,54 @@ If enabled, the server will exit when th
 .It Xo Ic extended-keys
 .Op Ic on | off | always
 .Xc
-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
+Controls how modified keys (keys pressed together with Control, Meta, or Shift)
+are reported.
+This is the equivalent of the
+.Ic modifyOtherKeys
+.Xr xterm 1
+resource.
+.Pp
+When set to
 .Ic on ,
-.Nm
-will only forward extended keys to applications when they request them; if
+the program inside the pane can request one of two modes: mode 1 which changes
+the sequence for only keys which lack an existing well-known representation; or
+mode 2 which changes the sequence for all keys.
+When set to
 .Ic always ,
+modes 1 and 2 can still be requested by applications, but mode 1 will be forced
+instead of the standard mode.
+When set to
+.Ic off ,
+this feature is disabled and only standard keys are reported.
+.Pp
 .Nm
-will always forward the keys.
+will always request extended keys itself if the terminal supports them.
+See also the
+.Ic extkeys
+feature for the
+.Ic terminal-features
+option, the
+.Ic extended-keys-format
+option and the
+.Ic pane_key_mode
+variable.
+.It Xo Ic extended-keys-format
+.Op Ic csi-u | xterm
+.Xc
+Selects one of the two possible formats for reporting modified keys to
+applications.
+This is the equivalent of the
+.Ic formatOtherKeys
+.Xr xterm 1
+resource.
+For example, C-S-a will be reported as
+.Ql ^[[27;6;65~
+when set to
+.Ic xterm ,
+and as
+.Ql ^[[65;6u
+when set to
+.Ic csi-u .
 .It Xo Ic focus-events
 .Op Ic on | off
 .Xc
@@ -4036,10 +4362,12 @@ If
 (the default), leave the session orphaned.
 If
 .Ic keep-last ,
-destroy the session only if it is in a group and has other sessions in that group.
+destroy the session only if it is in a group and has other sessions in that
+group.
 If
 .Ic keep-group ,
-destroy the session unless it is in a group and is the only session in that group.
+destroy the session unless it is in a group and is the only session in that
+group.
 .It Xo Ic detach-on-destroy
 .Op Ic off | on | no-detached | previous | next
 .Xc
@@ -4173,6 +4501,13 @@ Like
 .Ic prefix2
 can be set to
 .Ql None .
+.It Ic prefix-timeout Ar time
+Set the time in milliseconds for which
+.Nm
+waits after
+.Ic prefix
+is input before dismissing it.
+Can be set to zero to disable any timeout.
 .It Xo Ic renumber-windows
 .Op Ic on | off
 .Xc
@@ -4438,9 +4773,11 @@ Set the character used to fill areas of 
 .It Ic main-pane-height Ar height
 .It Ic main-pane-width Ar width
 Set the width or height of the main (left or top) pane in the
-.Ic main-horizontal
+.Ic main-horizontal ,
+.Ic main-horizontal-mirrored ,
+.Ic main-vertical ,
 or
-.Ic main-vertical
+.Ic main-vertical-mirrored
 layouts.
 If suffixed by
 .Ql % ,
@@ -4514,7 +4851,9 @@ An interval of zero disables the monitor
 .It Ic other-pane-height Ar height
 Set the height of the other panes (not the main pane) in the
 .Ic main-horizontal
-layout.
+and
+.Ic main-horizontal-mirrored
+layouts.
 If this option is set to 0 (the default), it will have no effect.
 If both the
 .Ic main-pane-height
@@ -4531,7 +4870,9 @@ Like
 .Ic other-pane-height ,
 but set the width of other panes in the
 .Ic main-vertical
-layout.
+and
+.Ic main-vertical-mirrored
+layouts.
 .Pp
 .It Ic pane-active-border-style Ar style
 Set the pane border style for the currently active pane.
@@ -4746,6 +5087,12 @@ they will be allowed even if the pane is
 Allow programs in the pane to change the window name using a terminal escape
 sequence (\eek...\ee\e\e).
 .Pp
+.It Xo Ic allow-set-title
+.Op Ic on | off
+.Xc
+Allow programs in the pane to change the title using the terminal escape
+sequences (\ee]2;...\ee\e\e or \ee]0;...\ee\e\e).
+.Pp
 .It Xo Ic alternate-screen
 .Op Ic on | off
 .Xc
@@ -4871,6 +5218,14 @@ layout after every
 set-hook -g after-split-window "selectl even-vertical"
 .Ed
 .Pp
+If a command fails, the
+.Ql command-error
+hook will be fired.
+For example, this could be used to write to a log file:
+.Bd -literal -offset indent
+set-hook -g command-error "run-shell \\"echo 'a tmux command failed' >>/tmp/log\\""
+.Ed
+.Pp
 All the notifications listed in the
 .Sx CONTROL MODE
 section are hooks (without any arguments), except
@@ -4903,6 +5258,8 @@ Run when focus exits a client
 Run when a client is resized.
 .It client-session-changed
 Run when a client's attached session is changed.
+.It command-error
+Run when a command fails.
 .It pane-died
 Run when the program running in a pane exits, but
 .Ic remain-on-exit
@@ -5421,6 +5778,7 @@ The following variables are available, w
 .It Li "command_list_name" Ta "" Ta "Command name if listing commands"
 .It Li "command_list_usage" Ta "" Ta "Command usage if listing commands"
 .It Li "config_files" Ta "" Ta "List of configuration files loaded"
+.It Li "copy_cursor_hyperlink" Ta "" Ta "Hyperlink under cursor in copy mode"
 .It Li "copy_cursor_line" Ta "" Ta "Line the cursor is on in copy mode"
 .It Li "copy_cursor_word" Ta "" Ta "Word under cursor in copy mode"
 .It Li "copy_cursor_x" Ta "" Ta "Cursor X position in copy mode"
@@ -5482,6 +5840,7 @@ The following variables are available, w
 .It Li "pane_in_mode" Ta "" Ta "1 if pane is in a mode"
 .It Li "pane_index" Ta "#P" Ta "Index of pane"
 .It Li "pane_input_off" Ta "" Ta "1 if input to pane is disabled"
+.It Li "pane_key_mode" Ta "" Ta "Extended key reporting mode in this pane"
 .It Li "pane_last" Ta "" Ta "1 if last pane"
 .It Li "pane_left" Ta "" Ta "Left of pane"
 .It Li "pane_marked" Ta "" Ta "1 if this is the marked pane"
@@ -5506,6 +5865,8 @@ The following variables are available, w
 .It Li "scroll_position" Ta "" Ta "Scroll position in copy mode"
 .It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane"
 .It Li "scroll_region_upper" Ta "" Ta "Top of scroll region in pane"
+.It Li "search_count" Ta "" Ta "Count of search results"
+.It Li "search_count_partial" Ta "" Ta "1 if search count is partial count"
 .It Li "search_match" Ta "" Ta "Search match if any"
 .It Li "search_present" Ta "" Ta "1 if search started in copy mode"
 .It Li "selection_active" Ta "" Ta "1 if selection started and changes with the cursor in copy mode"
@@ -6111,7 +6472,7 @@ the default is
 .Ql y .
 .Tg menu
 .It Xo Ic display-menu
-.Op Fl O
+.Op Fl OM
 .Op Fl b Ar border-lines
 .Op Fl c Ar target-client
 .Op Fl C Ar starting-choice
@@ -6218,7 +6579,13 @@ changes this behaviour so that the menu 
 released without an item selected the menu is not closed and a mouse button
 must be clicked to choose an item.
 .Pp
-The following keys are also available:
+.Fl M
+tells
+.Nm
+the menu should handle mouse events; by default only menus opened from mouse
+key bindings do so.
+.Pp
+The following keys are available in menus:
 .Bl -column "Key" "Function" -offset indent
 .It Sy "Key" Ta Sy "Function"
 .It Li "Enter" Ta "Choose selected item"
@@ -6441,7 +6808,8 @@ The following keys may be used in buffer
 .It Li "Up" Ta "Select previous buffer"
 .It Li "Down" Ta "Select next buffer"
 .It Li "C-s" Ta "Search by name or content"
-.It Li "n" Ta "Repeat last search"
+.It Li "n" Ta "Repeat last search forwards"
+.It Li "N" Ta "Repeat last search backwards"
 .It Li "t" Ta "Toggle if buffer is tagged"
 .It Li "T" Ta "Tag no buffers"
 .It Li "C-t" Ta "Tag all buffers"
@@ -6464,7 +6832,7 @@ is replaced by the buffer name in
 and the result executed as a command.
 If
 .Ar template
-is not given, "paste-buffer -b \[aq]%%\[aq]" is used.
+is not given, "paste-buffer -p -b \[aq]%%\[aq]" is used.
 .Pp
 .Fl O
 specifies the initial sort field: one of
@@ -6533,6 +6901,11 @@ is given, the buffer is also sent to the
 using the
 .Xr xterm 1
 escape sequence, if possible.
+If
+.Ar path
+is
+.Ql - ,
+the contents are read from stdin.
 .Tg pasteb
 .It Xo Ic paste-buffer
 .Op Fl dpr
@@ -6570,6 +6943,11 @@ Save the contents of the specified paste
 The
 .Fl a
 option appends to rather than overwriting the file.
+If
+.Ar path
+is
+.Ql - ,
+the contents are read from stdin.
 .It Xo Ic set-buffer
 .Op Fl aw
 .Op Fl b Ar buffer-name
Index: src/external/bsd/tmux/dist/tty-keys.c
diff -u src/external/bsd/tmux/dist/tty-keys.c:1.18 src/external/bsd/tmux/dist/tty-keys.c:1.19
--- src/external/bsd/tmux/dist/tty-keys.c:1.18	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/tty-keys.c	Sat Nov  9 13:13:25 2024
@@ -59,7 +59,6 @@ static int	tty_keys_device_attributes2(s
 		    size_t *);
 static int	tty_keys_extended_device_attributes(struct tty *, const char *,
 		    size_t, size_t *);
-static int	tty_keys_colours(struct tty *, const char *, size_t, size_t *);
 
 /* A key tree entry. */
 struct tty_key {
@@ -665,7 +664,7 @@ tty_keys_next(struct tty *tty)
 	size_t			 len, size;
 	cc_t			 bspace;
 	int			 delay, expired = 0, n;
-	key_code		 key;
+	key_code		 key, onlykey;
 	struct mouse_event	 m = { 0 };
 	struct key_event	*event;
 
@@ -721,7 +720,7 @@ tty_keys_next(struct tty *tty)
 	}
 
 	/* Is this a colours response? */
-	switch (tty_keys_colours(tty, buf, len, &size)) {
+	switch (tty_keys_colours(tty, buf, len, &size, &tty->fg, &tty->bg)) {
 	case 0:		/* yes */
 		key = KEYC_UNKNOWN;
 		goto complete_key;
@@ -802,6 +801,27 @@ first_key:
 		key = (u_char)buf[0];
 		size = 1;
 	}
+
+	/* C-Space is special. */
+	if ((key & KEYC_MASK_KEY) == C0_NUL)
+		key = ' ' | KEYC_CTRL | (key & KEYC_META);
+
+	/*
+	 * Fix up all C0 control codes that don't have a dedicated key into
+	 * corresponding Ctrl keys. Convert characters in the A-Z range into
+	 * lowercase, so ^A becomes a|CTRL.
+	 */
+	onlykey = key & KEYC_MASK_KEY;
+	if (onlykey < 0x20 &&
+	    onlykey != C0_HT &&
+	    onlykey != C0_CR &&
+	    onlykey != C0_ESC) {
+		onlykey |= 0x40;
+		if (onlykey >= 'A' && onlykey <= 'Z')
+			onlykey |= 0x20;
+		key = onlykey | KEYC_CTRL | (key & KEYC_META);
+	}
+
 	goto complete_key;
 
 partial_key:
@@ -910,8 +930,9 @@ tty_keys_extended_key(struct tty *tty, c
 	u_int		 number, modifiers;
 	char		 tmp[64];
 	cc_t		 bspace;
-	key_code	 nkey;
-	key_code	 onlykey;
+	key_code	 nkey, onlykey;
+	struct utf8_data ud;
+	utf8_char        uc;
 
 	*size = 0;
 
@@ -961,6 +982,15 @@ tty_keys_extended_key(struct tty *tty, c
 	else
 		nkey = number;
 
+	/* Convert UTF-32 codepoint into internal representation. */
+	if (nkey != KEYC_BSPACE && nkey & ~0x7f) {
+		if (utf8_fromwc(nkey, &ud) == UTF8_DONE &&
+		    utf8_from_data(&ud, &uc) == UTF8_DONE)
+			nkey = uc;
+		else
+			return (-1);
+	}
+
 	/* Update the modifiers. */
 	if (modifiers > 0) {
 		modifiers--;
@@ -974,34 +1004,35 @@ tty_keys_extended_key(struct tty *tty, c
 			nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Meta */
 	}
 
+	/* Convert S-Tab into Backtab. */
+	if ((nkey & KEYC_MASK_KEY) == '\011' && (nkey & KEYC_SHIFT))
+		nkey = KEYC_BTAB | (nkey & ~KEYC_MASK_KEY & ~KEYC_SHIFT);
+
 	/*
-	 * Don't allow both KEYC_CTRL and as an implied modifier. Also convert
-	 * C-X into C-x and so on.
+	 * 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.
 	 */
-	if (nkey & KEYC_CTRL) {
-		onlykey = (nkey & KEYC_MASK_KEY);
-		if (onlykey < 32 &&
-		    onlykey != 9 &&
-		    onlykey != 13 &&
-		    onlykey != 27)
-			/* 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);
-	}
+	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));
 	}
+
 	*key = nkey;
 	return (0);
 }
@@ -1203,7 +1234,7 @@ tty_keys_clipboard(struct tty *tty, cons
 	}
 	if (end == len)
 		return (1);
-	*size = end + terminator;
+	*size = end + 1;
 
 	/* Skip the initial part. */
 	buf += 5;
@@ -1315,26 +1346,21 @@ tty_keys_device_attributes(struct tty *t
 			break;
 	}
 
-	/*
-	 * Add terminal features. Hardware level 5 does not offer SIXEL but
-	 * some terminal emulators report it anyway and it does not harm
-	 * to check it here.
-	 *
-	 * DECSLRM and DECFRA should be supported by level 5 as well as level
-	 * 4, but VTE has rather ruined it by advertising level 5 despite not
-	 * supporting them.
-	 */
+	/* Add terminal features. */
 	switch (p[0]) {
-	case 64: /* level 4 */
-		tty_add_features(features, "margins,rectfill", ",");
-		/* FALLTHROUGH */
+	case 61: /* level 1 */
 	case 62: /* level 2 */
 	case 63: /* level 3 */
+	case 64: /* level 4 */
 	case 65: /* level 5 */
 		for (i = 1; i < n; i++) {
 			log_debug("%s: DA feature: %d", c->name, p[i]);
 			if (p[i] == 4)
 				tty_add_features(features, "sixel", ",");
+			if (p[i] == 21)
+				tty_add_features(features, "margins", ",");
+			if (p[i] == 28)
+				tty_add_features(features, "rectfill", ",");
 		}
 		break;
 	}
@@ -1406,11 +1432,6 @@ tty_keys_device_attributes2(struct tty *
 	 * we can't use level 5 from DA because of VTE.
 	 */
 	switch (p[0]) {
-	case 41: /* VT420 */
-	case 61: /* VT510 */
-	case 64: /* VT520 */
-		tty_add_features(features, "margins,rectfill", ",");
-		break;
 	case 'M': /* mintty */
 		tty_default_features(features, "mintty", 0);
 		break;
@@ -1501,8 +1522,9 @@ tty_keys_extended_device_attributes(stru
  * Handle foreground or background input. Returns 0 for success, -1 for
  * failure, 1 for partial.
  */
-static int
-tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size)
+int
+tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size,
+    int *fg, int *bg)
 {
 	struct client	*c = tty->client;
 	u_int		 i;
@@ -1553,11 +1575,17 @@ tty_keys_colours(struct tty *tty, const 
 
 	n = colour_parseX11(tmp);
 	if (n != -1 && buf[3] == '0') {
-		log_debug("%s: foreground is %s", c->name, colour_tostring(n));
-		tty->fg = n;
+		if (c != NULL)
+			log_debug("%s fg is %s", c->name, colour_tostring(n));
+		else
+			log_debug("fg is %s", colour_tostring(n));
+		*fg = n;
 	} else if (n != -1) {
-		log_debug("%s: background is %s", c->name, colour_tostring(n));
-		tty->bg = n;
+		if (c != NULL)
+			log_debug("%s bg is %s", c->name, colour_tostring(n));
+		else
+			log_debug("bg is %s", colour_tostring(n));
+		*bg = n;
 	}
 
 	return (0);
Index: src/external/bsd/tmux/dist/tty-term.c
diff -u src/external/bsd/tmux/dist/tty-term.c:1.18 src/external/bsd/tmux/dist/tty-term.c:1.19
--- src/external/bsd/tmux/dist/tty-term.c:1.18	Sat Jun 22 23:45:53 2024
+++ src/external/bsd/tmux/dist/tty-term.c	Sat Nov  9 13:13:25 2024
@@ -531,9 +531,10 @@ tty_term_create(struct tty *tty, char *n
 	struct options_array_item		*a;
 	union options_value			*ov;
 	u_int					 i, j;
-	const char				*s, *value;
+	const char				*s, *value, *errstr;
 	size_t					 offset, namelen;
 	char					*first;
+	int					 n;
 
 	log_debug("adding term %s", name);
 
@@ -567,8 +568,13 @@ tty_term_create(struct tty *tty, char *n
 				code->value.string = tty_term_strip(value);
 				break;
 			case TTYCODE_NUMBER:
-				code->type = TTYCODE_NUMBER;
-				code->value.number = atoi(value);
+				n = strtonum(value, 0, INT_MAX, &errstr);
+				if (errstr != NULL)
+					log_debug("%s: %s", ent->name, errstr);
+				else {
+					code->type = TTYCODE_NUMBER;
+					code->value.number = n;
+				}
 				break;
 			case TTYCODE_FLAG:
 				code->type = TTYCODE_FLAG;

Index: src/external/bsd/tmux/dist/mode-tree.c
diff -u src/external/bsd/tmux/dist/mode-tree.c:1.10 src/external/bsd/tmux/dist/mode-tree.c:1.11
--- src/external/bsd/tmux/dist/mode-tree.c:1.10	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/mode-tree.c	Sat Nov  9 13:13:25 2024
@@ -25,6 +25,11 @@
 
 #include "tmux.h"
 
+enum mode_tree_search_dir {
+	MODE_TREE_SEARCH_FORWARD,
+	MODE_TREE_SEARCH_BACKWARD
+};
+
 struct mode_tree_item;
 TAILQ_HEAD(mode_tree_list, mode_tree_item);
 
@@ -68,6 +73,7 @@ struct mode_tree_data {
 	char			 *search;
 	char			 *filter;
 	int			  no_matches;
+	enum mode_tree_search_dir search_dir;
 };
 
 struct mode_tree_item {
@@ -255,19 +261,21 @@ mode_tree_up(struct mode_tree_data *mtd,
 	}
 }
 
-void
+int
 mode_tree_down(struct mode_tree_data *mtd, int wrap)
 {
 	if (mtd->current == mtd->line_size - 1) {
 		if (wrap) {
 			mtd->current = 0;
 			mtd->offset = 0;
-		}
+		} else
+			return (0);
 	} else {
 		mtd->current++;
 		if (mtd->current > mtd->offset + mtd->height - 1)
 			mtd->offset++;
 	}
+	return (1);
 }
 
 void *
@@ -786,7 +794,49 @@ done:
 }
 
 static struct mode_tree_item *
-mode_tree_search_for(struct mode_tree_data *mtd)
+mode_tree_search_backward(struct mode_tree_data *mtd)
+{
+    struct mode_tree_item	*mti, *last, *prev;
+
+    if (mtd->search == NULL)
+	    return (NULL);
+
+    mti = last = mtd->line_list[mtd->current].item;
+    for (;;) {
+        if ((prev = TAILQ_PREV(mti, mode_tree_list, entry)) != NULL) {
+		/* Point to the last child in the previous subtree. */
+		while (!TAILQ_EMPTY(&prev->children))
+			prev = TAILQ_LAST(&prev->children, mode_tree_list);
+		mti = prev;
+        } else {
+		/* If prev is NULL, jump to the parent. */
+		mti = mti->parent;
+        }
+
+	if (mti == NULL) {
+		/* Point to the last child in the last root subtree. */
+		prev = TAILQ_LAST(&mtd->children, mode_tree_list);
+		while (!TAILQ_EMPTY(&prev->children))
+			prev = TAILQ_LAST(&prev->children, mode_tree_list);
+		mti = prev;
+	}
+	if (mti == last)
+		break;
+
+	if (mtd->searchcb == NULL) {
+		if (strstr(mti->name, mtd->search) != NULL)
+			return (mti);
+		continue;
+	}
+	if (mtd->searchcb(mtd->modedata, mti->itemdata, mtd->search))
+		return (mti);
+    }
+    return (NULL);
+}
+
+
+static struct mode_tree_item *
+mode_tree_search_forward(struct mode_tree_data *mtd)
 {
 	struct mode_tree_item	*mti, *last, *next;
 
@@ -832,7 +882,10 @@ mode_tree_search_set(struct mode_tree_da
 	struct mode_tree_item	*mti, *loop;
 	uint64_t		 tag;
 
-	mti = mode_tree_search_for(mtd);
+	if (mtd->search_dir == MODE_TREE_SEARCH_FORWARD)
+		mti = mode_tree_search_forward(mtd);
+	else
+		mti = mode_tree_search_backward(mtd);
 	if (mti == NULL)
 		return;
 	tag = mti->tag;
@@ -1035,22 +1088,22 @@ mode_tree_key(struct mode_tree_data *mtd
 	switch (*key) {
 	case 'q':
 	case '\033': /* Escape */
-	case '\007': /* C-g */
+	case 'g'|KEYC_CTRL:
 		return (1);
 	case KEYC_UP:
 	case 'k':
 	case KEYC_WHEELUP_PANE:
-	case '\020': /* C-p */
+	case 'p'|KEYC_CTRL:
 		mode_tree_up(mtd, 1);
 		break;
 	case KEYC_DOWN:
 	case 'j':
 	case KEYC_WHEELDOWN_PANE:
-	case '\016': /* C-n */
+	case 'n'|KEYC_CTRL:
 		mode_tree_down(mtd, 1);
 		break;
 	case KEYC_PPAGE:
-	case '\002': /* C-b */
+	case 'b'|KEYC_CTRL:
 		for (i = 0; i < mtd->height; i++) {
 			if (mtd->current == 0)
 				break;
@@ -1058,7 +1111,7 @@ mode_tree_key(struct mode_tree_data *mtd
 		}
 		break;
 	case KEYC_NPAGE:
-	case '\006': /* C-f */
+	case 'f'|KEYC_CTRL:
 		for (i = 0; i < mtd->height; i++) {
 			if (mtd->current == mtd->line_size - 1)
 				break;
@@ -1102,7 +1155,7 @@ mode_tree_key(struct mode_tree_data *mtd
 		for (i = 0; i < mtd->line_size; i++)
 			mtd->line_list[i].item->tagged = 0;
 		break;
-	case '\024': /* C-t */
+	case 't'|KEYC_CTRL:
 		for (i = 0; i < mtd->line_size; i++) {
 			if ((mtd->line_list[i].item->parent == NULL &&
 			    !mtd->line_list[i].item->no_tag) ||
@@ -1158,13 +1211,18 @@ mode_tree_key(struct mode_tree_data *mtd
 		break;
 	case '?':
 	case '/':
-	case '\023': /* C-s */
+	case 's'|KEYC_CTRL:
 		mtd->references++;
 		status_prompt_set(c, NULL, "(search) ", "",
 		    mode_tree_search_callback, mode_tree_search_free, mtd,
 		    PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
 		break;
 	case 'n':
+		mtd->search_dir = MODE_TREE_SEARCH_FORWARD;
+		mode_tree_search_set(mtd);
+		break;
+	case 'N':
+		mtd->search_dir = MODE_TREE_SEARCH_BACKWARD;
 		mode_tree_search_set(mtd);
 		break;
 	case 'f':
Index: src/external/bsd/tmux/dist/utf8.c
diff -u src/external/bsd/tmux/dist/utf8.c:1.10 src/external/bsd/tmux/dist/utf8.c:1.11
--- src/external/bsd/tmux/dist/utf8.c:1.10	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/utf8.c	Sat Nov  9 13:13:25 2024
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <wchar.h>
 
+#include "compat.h"
 #include "tmux.h"
 
 static const wchar_t utf8_force_wide[] = {
@@ -449,6 +450,32 @@ utf8_towc(const struct utf8_data *ud, wc
 	return (UTF8_DONE);
 }
 
+/* Convert wide character to UTF-8 character. */
+enum utf8_state
+utf8_fromwc(wchar_t wc, struct utf8_data *ud)
+{
+	int	size, width;
+
+#ifdef HAVE_UTF8PROC
+	size = utf8proc_wctomb(ud->data, wc);
+#else
+	size = wctomb((char *)ud->data, wc);
+#endif
+	if (size < 0) {
+		log_debug("UTF-8 %d, wctomb() %d", wc, errno);
+		wctomb(NULL, 0);
+		return (UTF8_ERROR);
+	}
+	if (size == 0)
+		return (UTF8_ERROR);
+	ud->size = ud->have = size;
+	if (utf8_width(ud, &width) == UTF8_DONE) {
+		ud->width = width;
+		return (UTF8_DONE);
+	}
+	return (UTF8_ERROR);
+}
+
 /*
  * Open UTF-8 sequence.
  *
@@ -525,7 +552,7 @@ utf8_strvis(char *dst, const char *src, 
 			/* Not a complete, valid UTF-8 character. */
 			src -= ud.have;
 		}
-		if (src[0] == '$' && src < end - 1) {
+		if ((flag & VIS_DQ) && src[0] == '$' && src < end - 1) {
 			if (isalpha((u_char)src[1]) ||
 			    src[1] == '_' ||
 			    src[1] == '{')
Index: src/external/bsd/tmux/dist/window-buffer.c
diff -u src/external/bsd/tmux/dist/window-buffer.c:1.10 src/external/bsd/tmux/dist/window-buffer.c:1.11
--- src/external/bsd/tmux/dist/window-buffer.c:1.10	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/window-buffer.c	Sat Nov  9 13:13:25 2024
@@ -36,7 +36,7 @@ static void		 window_buffer_key(struct w
 			     struct client *, struct session *,
 			     struct winlink *, key_code, struct mouse_event *);
 
-#define WINDOW_BUFFER_DEFAULT_COMMAND "paste-buffer -b '%%'"
+#define WINDOW_BUFFER_DEFAULT_COMMAND "paste-buffer -p -b '%%'"
 
 #define WINDOW_BUFFER_DEFAULT_FORMAT \
 	"#{t/p:buffer_created}: #{buffer_sample}"
@@ -409,8 +409,17 @@ window_buffer_do_delete(void *modedata, 
 	struct window_buffer_itemdata	*item = itemdata;
 	struct paste_buffer		*pb;
 
-	if (item == mode_tree_get_current(data->data))
-		mode_tree_down(data->data, 0);
+	if (item == mode_tree_get_current(data->data) &&
+	    !mode_tree_down(data->data, 0)) {
+		/*
+		 *If we were unable to select the item further down we are at
+		 * the end of the list. Move one element up instead, to make
+		 * sure that we preserve a valid selection or we risk having
+		 * the tree build logic reset it to the first item.
+		 */
+		mode_tree_up(data->data, 0);
+	}
+
 	if ((pb = paste_get_name(item->name)) != NULL)
 		paste_free(pb);
 }
@@ -509,7 +518,7 @@ window_buffer_key(struct window_mode_ent
 	struct window_buffer_itemdata	*item;
 	int				 finished;
 
-	if (paste_get_top(NULL) == NULL) {
+	if (paste_is_empty()) {
 		finished = 1;
 		goto out;
 	}
@@ -542,7 +551,7 @@ window_buffer_key(struct window_mode_ent
 	}
 
 out:
-	if (finished || paste_get_top(NULL) == NULL)
+	if (finished || paste_is_empty())
 		window_pane_reset_mode(wp);
 	else {
 		mode_tree_draw(mtd);

Index: src/external/bsd/tmux/dist/server.c
diff -u src/external/bsd/tmux/dist/server.c:1.4 src/external/bsd/tmux/dist/server.c:1.5
--- src/external/bsd/tmux/dist/server.c:1.4	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/server.c	Sat Nov  9 13:13:25 2024
@@ -103,7 +103,7 @@ server_check_marked(void)
 
 /* Create server socket. */
 int
-server_create_socket(int flags, char **cause)
+server_create_socket(uint64_t flags, char **cause)
 {
 	struct sockaddr_un	sa;
 	size_t			size;
@@ -171,7 +171,7 @@ server_tidy_event(__unused int fd, __unu
 
 /* Fork new server. */
 int
-server_start(struct tmuxproc *client, int flags, struct event_base *base,
+server_start(struct tmuxproc *client, uint64_t flags, struct event_base *base,
     int lockfd, char *lockfile)
 {
 	int		 fd;
@@ -263,7 +263,7 @@ server_loop(void)
 	struct client	*c;
 	u_int		 items;
 
-	current_time = time (NULL);
+	current_time = time(NULL);
 
 	do {
 		items = cmdq_next(NULL);

Index: src/external/bsd/tmux/dist/status.c
diff -u src/external/bsd/tmux/dist/status.c:1.16 src/external/bsd/tmux/dist/status.c:1.17
--- src/external/bsd/tmux/dist/status.c:1.16	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/status.c	Sat Nov  9 13:13:25 2024
@@ -607,6 +607,8 @@ status_prompt_set(struct client *c, stru
 	struct format_tree	*ft;
 	char			*tmp;
 
+	server_client_clear_overlay(c);
+
 	if (fs != NULL)
 		ft = format_create_from_state(NULL, c, fs);
 	else
@@ -839,19 +841,19 @@ status_prompt_translate_key(struct clien
 {
 	if (c->prompt_mode == PROMPT_ENTRY) {
 		switch (key) {
-		case '\001': /* C-a */
-		case '\003': /* C-c */
-		case '\005': /* C-e */
-		case '\007': /* C-g */
-		case '\010': /* C-h */
+		case 'a'|KEYC_CTRL:
+		case 'c'|KEYC_CTRL:
+		case 'e'|KEYC_CTRL:
+		case 'g'|KEYC_CTRL:
+		case 'h'|KEYC_CTRL:
 		case '\011': /* Tab */
-		case '\013': /* C-k */
-		case '\016': /* C-n */
-		case '\020': /* C-p */
-		case '\024': /* C-t */
-		case '\025': /* C-u */
-		case '\027': /* C-w */
-		case '\031': /* C-y */
+		case 'k'|KEYC_CTRL:
+		case 'n'|KEYC_CTRL:
+		case 'p'|KEYC_CTRL:
+		case 't'|KEYC_CTRL:
+		case 'u'|KEYC_CTRL:
+		case 'w'|KEYC_CTRL:
+		case 'y'|KEYC_CTRL:
 		case '\n':
 		case '\r':
 		case KEYC_LEFT|KEYC_CTRL:
@@ -890,7 +892,7 @@ status_prompt_translate_key(struct clien
 	case 'S':
 		c->prompt_mode = PROMPT_ENTRY;
 		c->flags |= CLIENT_REDRAWSTATUS;
-		*new_key = '\025'; /* C-u */
+		*new_key = 'u'|KEYC_CTRL;
 		return (1);
 	case 'i':
 	case '\033': /* Escape */
@@ -911,7 +913,7 @@ status_prompt_translate_key(struct clien
 		return (1);
 	case 'C':
 	case 'D':
-		*new_key = '\013'; /* C-k */
+		*new_key = 'k'|KEYC_CTRL;
 		return (1);
 	case KEYC_BSPACE:
 	case 'X':
@@ -924,7 +926,7 @@ status_prompt_translate_key(struct clien
 		*new_key = 'B'|KEYC_VI;
 		return (1);
 	case 'd':
-		*new_key = '\025'; /* C-u */
+		*new_key = 'u'|KEYC_CTRL;
 		return (1);
 	case 'e':
 		*new_key = 'e'|KEYC_VI;
@@ -939,10 +941,10 @@ status_prompt_translate_key(struct clien
 		*new_key = 'W'|KEYC_VI;
 		return (1);
 	case 'p':
-		*new_key = '\031'; /* C-y */
+		*new_key = 'y'|KEYC_CTRL;
 		return (1);
 	case 'q':
-		*new_key = '\003'; /* C-c */
+		*new_key = 'c'|KEYC_CTRL;
 		return (1);
 	case 's':
 	case KEYC_DC:
@@ -966,8 +968,8 @@ status_prompt_translate_key(struct clien
 	case 'k':
 		*new_key = KEYC_UP;
 		return (1);
-	case '\010' /* C-h */:
-	case '\003' /* C-c */:
+	case 'h'|KEYC_CTRL:
+	case 'c'|KEYC_CTRL:
 	case '\n':
 	case '\r':
 		return (1);
@@ -994,8 +996,7 @@ status_prompt_paste(struct client *c)
 		if ((pb = paste_get_top(NULL)) == NULL)
 			return (0);
 		bufdata = paste_buffer_data(pb, &bufsize);
-		ud = xreallocarray(NULL, bufsize + 1, sizeof *ud);
-		udp = ud;
+		ud = udp = xreallocarray(NULL, bufsize + 1, sizeof *ud);
 		for (i = 0; i != bufsize; /* nothing */) {
 			more = utf8_open(udp, bufdata[i]);
 			if (more == UTF8_MORE) {
@@ -1016,25 +1017,24 @@ status_prompt_paste(struct client *c)
 		udp->size = 0;
 		n = udp - ud;
 	}
-	if (n == 0)
-		return (0);
-
-	c->prompt_buffer = xreallocarray(c->prompt_buffer, size + n + 1,
-	    sizeof *c->prompt_buffer);
-	if (c->prompt_index == size) {
-		memcpy(c->prompt_buffer + c->prompt_index, ud,
-		    n * sizeof *c->prompt_buffer);
-		c->prompt_index += n;
-		c->prompt_buffer[c->prompt_index].size = 0;
-	} else {
-		memmove(c->prompt_buffer + c->prompt_index + n,
-		    c->prompt_buffer + c->prompt_index,
-		    (size + 1 - c->prompt_index) * sizeof *c->prompt_buffer);
-		memcpy(c->prompt_buffer + c->prompt_index, ud,
-		    n * sizeof *c->prompt_buffer);
-		c->prompt_index += n;
+	if (n != 0) {
+		c->prompt_buffer = xreallocarray(c->prompt_buffer, size + n + 1,
+		    sizeof *c->prompt_buffer);
+		if (c->prompt_index == size) {
+			memcpy(c->prompt_buffer + c->prompt_index, ud,
+			    n * sizeof *c->prompt_buffer);
+			c->prompt_index += n;
+			c->prompt_buffer[c->prompt_index].size = 0;
+		} else {
+			memmove(c->prompt_buffer + c->prompt_index + n,
+			    c->prompt_buffer + c->prompt_index,
+			    (size + 1 - c->prompt_index) *
+			    sizeof *c->prompt_buffer);
+			memcpy(c->prompt_buffer + c->prompt_index, ud,
+			    n * sizeof *c->prompt_buffer);
+			c->prompt_index += n;
+		}
 	}
-
 	if (ud != c->prompt_saved)
 		free(ud);
 	return (1);
@@ -1265,28 +1265,28 @@ status_prompt_key(struct client *c, key_
 process_key:
 	switch (key) {
 	case KEYC_LEFT:
-	case '\002': /* C-b */
+	case 'b'|KEYC_CTRL:
 		if (c->prompt_index > 0) {
 			c->prompt_index--;
 			break;
 		}
 		break;
 	case KEYC_RIGHT:
-	case '\006': /* C-f */
+	case 'f'|KEYC_CTRL:
 		if (c->prompt_index < size) {
 			c->prompt_index++;
 			break;
 		}
 		break;
 	case KEYC_HOME:
-	case '\001': /* C-a */
+	case 'a'|KEYC_CTRL:
 		if (c->prompt_index != 0) {
 			c->prompt_index = 0;
 			break;
 		}
 		break;
 	case KEYC_END:
-	case '\005': /* C-e */
+	case 'e'|KEYC_CTRL:
 		if (c->prompt_index != size) {
 			c->prompt_index = size;
 			break;
@@ -1297,7 +1297,7 @@ process_key:
 			goto changed;
 		break;
 	case KEYC_BSPACE:
-	case '\010': /* C-h */
+	case 'h'|KEYC_CTRL:
 		if (c->prompt_index != 0) {
 			if (c->prompt_index == size)
 				c->prompt_buffer[--c->prompt_index].size = 0;
@@ -1312,7 +1312,7 @@ process_key:
 		}
 		break;
 	case KEYC_DC:
-	case '\004': /* C-d */
+	case 'd'|KEYC_CTRL:
 		if (c->prompt_index != size) {
 			memmove(c->prompt_buffer + c->prompt_index,
 			    c->prompt_buffer + c->prompt_index + 1,
@@ -1321,17 +1321,17 @@ process_key:
 			goto changed;
 		}
 		break;
-	case '\025': /* C-u */
+	case 'u'|KEYC_CTRL:
 		c->prompt_buffer[0].size = 0;
 		c->prompt_index = 0;
 		goto changed;
-	case '\013': /* C-k */
+	case 'k'|KEYC_CTRL:
 		if (c->prompt_index < size) {
 			c->prompt_buffer[c->prompt_index].size = 0;
 			goto changed;
 		}
 		break;
-	case '\027': /* C-w */
+	case 'w'|KEYC_CTRL:
 		separators = options_get_string(oo, "word-separators");
 		idx = c->prompt_index;
 
@@ -1399,7 +1399,7 @@ process_key:
 		status_prompt_backward_word(c, separators);
 		goto changed;
 	case KEYC_UP:
-	case '\020': /* C-p */
+	case 'p'|KEYC_CTRL:
 		histstr = status_prompt_up_history(c->prompt_hindex,
 		    c->prompt_type);
 		if (histstr == NULL)
@@ -1409,7 +1409,7 @@ process_key:
 		c->prompt_index = utf8_strlen(c->prompt_buffer);
 		goto changed;
 	case KEYC_DOWN:
-	case '\016': /* C-n */
+	case 'n'|KEYC_CTRL:
 		histstr = status_prompt_down_history(c->prompt_hindex,
 		    c->prompt_type);
 		if (histstr == NULL)
@@ -1418,11 +1418,11 @@ process_key:
 		c->prompt_buffer = utf8_fromcstr(histstr);
 		c->prompt_index = utf8_strlen(c->prompt_buffer);
 		goto changed;
-	case '\031': /* C-y */
+	case 'y'|KEYC_CTRL:
 		if (status_prompt_paste(c))
 			goto changed;
 		break;
-	case '\024': /* C-t */
+	case 't'|KEYC_CTRL:
 		idx = c->prompt_index;
 		if (idx < size)
 			idx++;
@@ -1445,12 +1445,12 @@ process_key:
 		free(s);
 		break;
 	case '\033': /* Escape */
-	case '\003': /* C-c */
-	case '\007': /* C-g */
+	case 'c'|KEYC_CTRL:
+	case 'g'|KEYC_CTRL:
 		if (c->prompt_inputcb(c, c->prompt_data, NULL, 1) == 0)
 			status_prompt_clear(c);
 		break;
-	case '\022': /* C-r */
+	case 'r'|KEYC_CTRL:
 		if (~c->prompt_flags & PROMPT_INCREMENTAL)
 			break;
 		if (c->prompt_buffer[0].size == 0) {
@@ -1461,7 +1461,7 @@ process_key:
 		} else
 			prefix = '-';
 		goto changed;
-	case '\023': /* C-s */
+	case 's'|KEYC_CTRL:
 		if (~c->prompt_flags & PROMPT_INCREMENTAL)
 			break;
 		if (c->prompt_buffer[0].size == 0) {
@@ -1628,8 +1628,9 @@ status_prompt_complete_list(u_int *size,
 	struct options_entry			 *o;
 	struct options_array_item		 *a;
 	const char				 *layouts[] = {
-		"even-horizontal", "even-vertical", "main-horizontal",
-		"main-vertical", "tiled", NULL
+		"even-horizontal", "even-vertical",
+		"main-horizontal", "main-horizontal-mirrored",
+		"main-vertical", "main-vertical-mirrored", "tiled", NULL
 	};
 
 	*size = 0;
@@ -1839,6 +1840,7 @@ status_prompt_complete_window_menu(struc
 	}
 	if (size == 0) {
 		menu_free(menu);
+		free(spm);
 		return (NULL);
 	}
 	if (size == 1) {
@@ -1849,6 +1851,7 @@ status_prompt_complete_window_menu(struc
 		} else
 			tmp = list[0];
 		free(list);
+		free(spm);
 		return (tmp);
 	}
 	if (height > size)
Index: src/external/bsd/tmux/dist/window-copy.c
diff -u src/external/bsd/tmux/dist/window-copy.c:1.16 src/external/bsd/tmux/dist/window-copy.c:1.17
--- src/external/bsd/tmux/dist/window-copy.c:1.16	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/window-copy.c	Sat Nov  9 13:13:25 2024
@@ -41,7 +41,7 @@ static void	window_copy_resize(struct wi
 static void	window_copy_formats(struct window_mode_entry *,
 		    struct format_tree *);
 static void	window_copy_pageup1(struct window_mode_entry *, int);
-static int	window_copy_pagedown(struct window_mode_entry *, int, int);
+static int	window_copy_pagedown1(struct window_mode_entry *, int, int);
 static void	window_copy_next_paragraph(struct window_mode_entry *);
 static void	window_copy_previous_paragraph(struct window_mode_entry *);
 static void	window_copy_redraw_selection(struct window_mode_entry *, u_int);
@@ -450,6 +450,8 @@ window_copy_init(struct window_mode_entr
 	data->scroll_exit = args_has(args, 'e');
 	data->hide_position = args_has(args, 'H');
 
+	if (base->hyperlinks != NULL)
+		data->screen.hyperlinks = hyperlinks_copy(base->hyperlinks);
 	data->screen.cx = data->cx;
 	data->screen.cy = data->cy;
 	data->mx = data->cx;
@@ -646,8 +648,18 @@ window_copy_pageup1(struct window_mode_e
 	window_copy_redraw_screen(wme);
 }
 
+void
+window_copy_pagedown(struct window_pane *wp, int half_page, int scroll_exit)
+{
+	if (window_copy_pagedown1(TAILQ_FIRST(&wp->modes), half_page,
+	    scroll_exit)) {
+		window_pane_reset_mode(wp);
+		return;
+	}
+}
+
 static int
-window_copy_pagedown(struct window_mode_entry *wme, int half_page,
+window_copy_pagedown1(struct window_mode_entry *wme, int half_page,
     int scroll_exit)
 {
 	struct window_copy_mode_data	*data = wme->data;
@@ -755,6 +767,18 @@ window_copy_get_line(struct window_pane 
 }
 
 static void *
+window_copy_cursor_hyperlink_cb(struct format_tree *ft)
+{
+	struct window_pane		*wp = format_get_pane(ft);
+	struct window_mode_entry	*wme = TAILQ_FIRST(&wp->modes);
+	struct window_copy_mode_data	*data = wme->data;
+	struct grid			*gd = data->screen.grid;
+
+	return (format_grid_hyperlink(gd, data->cx, gd->hsize + data->cy,
+	    &data->screen));
+}
+
+static void *
 window_copy_cursor_word_cb(struct format_tree *ft)
 {
 	struct window_pane		*wp = format_get_pane(ft);
@@ -795,22 +819,36 @@ window_copy_formats(struct window_mode_e
 	format_add(ft, "copy_cursor_x", "%d", data->cx);
 	format_add(ft, "copy_cursor_y", "%d", data->cy);
 
-	format_add(ft, "selection_present", "%d", data->screen.sel != NULL);
 	if (data->screen.sel != NULL) {
 		format_add(ft, "selection_start_x", "%d", data->selx);
 		format_add(ft, "selection_start_y", "%d", data->sely);
 		format_add(ft, "selection_end_x", "%d", data->endselx);
 		format_add(ft, "selection_end_y", "%d", data->endsely);
-		format_add(ft, "selection_active", "%d",
-		    data->cursordrag != CURSORDRAG_NONE);
-	} else
-		format_add(ft, "selection_active", "%d", 0);
+
+		if (data->cursordrag != CURSORDRAG_NONE)
+			format_add(ft, "selection_active", "1");
+		else
+			format_add(ft, "selection_active", "0");
+		if (data->endselx != data->selx || data->endsely != data->sely)
+			format_add(ft, "selection_present", "1");
+		else
+			format_add(ft, "selection_present", "0");
+	} else {
+		format_add(ft, "selection_active", "0");
+		format_add(ft, "selection_present", "0");
+	}
 
 	format_add(ft, "search_present", "%d", data->searchmark != NULL);
+	if (data->searchcount != -1) {
+		format_add(ft, "search_count", "%d", data->searchcount);
+		format_add(ft, "search_count_partial", "%d", data->searchmore);
+	}
 	format_add_cb(ft, "search_match", window_copy_search_match_cb);
 
 	format_add_cb(ft, "copy_cursor_word", window_copy_cursor_word_cb);
 	format_add_cb(ft, "copy_cursor_line", window_copy_cursor_line_cb);
+	format_add_cb(ft, "copy_cursor_hyperlink",
+	    window_copy_cursor_hyperlink_cb);
 }
 
 static void
@@ -1339,7 +1377,7 @@ window_copy_cmd_halfpage_down(struct win
 	u_int				 np = wme->prefix;
 
 	for (; np != 0; np--) {
-		if (window_copy_pagedown(wme, 1, data->scroll_exit))
+		if (window_copy_pagedown1(wme, 1, data->scroll_exit))
 			return (WINDOW_COPY_CMD_CANCEL);
 	}
 	return (WINDOW_COPY_CMD_NOTHING);
@@ -1353,7 +1391,7 @@ window_copy_cmd_halfpage_down_and_cancel
 	u_int				 np = wme->prefix;
 
 	for (; np != 0; np--) {
-		if (window_copy_pagedown(wme, 1, 1))
+		if (window_copy_pagedown1(wme, 1, 1))
 			return (WINDOW_COPY_CMD_CANCEL);
 	}
 	return (WINDOW_COPY_CMD_NOTHING);
@@ -1781,7 +1819,7 @@ window_copy_cmd_page_down(struct window_
 	u_int				 np = wme->prefix;
 
 	for (; np != 0; np--) {
-		if (window_copy_pagedown(wme, 0, data->scroll_exit))
+		if (window_copy_pagedown1(wme, 0, data->scroll_exit))
 			return (WINDOW_COPY_CMD_CANCEL);
 	}
 	return (WINDOW_COPY_CMD_NOTHING);
@@ -1794,7 +1832,7 @@ window_copy_cmd_page_down_and_cancel(str
 	u_int				 np = wme->prefix;
 
 	for (; np != 0; np--) {
-		if (window_copy_pagedown(wme, 0, 1))
+		if (window_copy_pagedown1(wme, 0, 1))
 			return (WINDOW_COPY_CMD_CANCEL);
 	}
 	return (WINDOW_COPY_CMD_NOTHING);
@@ -2464,7 +2502,8 @@ window_copy_cmd_refresh_from_pane(struct
 
 	screen_free(data->backing);
 	free(data->backing);
-	data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL,   NULL, wme->swp != wme->wp);
+	data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL,
+	    NULL, wme->swp != wme->wp);
 
 	window_copy_size_changed(wme);
 	return (WINDOW_COPY_CMD_REDRAW);
@@ -3606,11 +3645,10 @@ window_copy_search_jump(struct window_mo
     struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap,
     int direction, int regex)
 {
-	u_int			 i, px, sx, ssize = 1;
-	int			 found = 0, cflags = REG_EXTENDED;
-	char			*sbuf = NULL;
-	regex_t			 reg;
-	struct grid_line	*gl;
+	u_int	 i, px, sx, ssize = 1;
+	int	 found = 0, cflags = REG_EXTENDED;
+	char	*sbuf;
+	regex_t	 reg;
 
 	if (regex) {
 		sbuf = xmalloc(ssize);
@@ -3627,9 +3665,6 @@ window_copy_search_jump(struct window_mo
 
 	if (direction) {
 		for (i = fy; i <= endline; i++) {
-			gl = grid_get_line(gd, i);
-			if (i != endline && gl->flags & GRID_LINE_WRAPPED)
-				continue;
 			if (regex) {
 				found = window_copy_search_lr_regex(gd,
 				    &px, &sx, i, fx, gd->sx, &reg);
@@ -3643,9 +3678,6 @@ window_copy_search_jump(struct window_mo
 		}
 	} else {
 		for (i = fy + 1; endline < i; i--) {
-			gl = grid_get_line(gd, i - 1);
-			if (i != endline && gl->flags & GRID_LINE_WRAPPED)
-				continue;
 			if (regex) {
 				found = window_copy_search_rl_regex(gd,
 				    &px, &sx, i - 1, 0, fx + 1, &reg);
@@ -4686,7 +4718,7 @@ window_copy_get_selection(struct window_
 	if (keys == MODEKEY_EMACS || lastex <= ey_last) {
 		if (~grid_get_line(data->backing->grid, ey)->flags &
 		    GRID_LINE_WRAPPED || lastex != ey_last)
-		off -= 1;
+			off -= 1;
 	}
 	*len = off;
 	return (buf);

Index: src/external/bsd/tmux/dist/style.c
diff -u src/external/bsd/tmux/dist/style.c:1.8 src/external/bsd/tmux/dist/style.c:1.9
--- src/external/bsd/tmux/dist/style.c:1.8	Sat Jun 22 23:33:20 2024
+++ src/external/bsd/tmux/dist/style.c	Sat Nov  9 13:13:25 2024
@@ -58,10 +58,11 @@ int
 style_parse(struct style *sy, const struct grid_cell *base, const char *in)
 {
 	struct style	saved;
-	const char	delimiters[] = " ,\n", *cp;
+	const char	delimiters[] = " ,\n", *errstr;
 	char		tmp[256], *found;
 	int		value;
 	size_t		end;
+	u_int		n;
 
 	if (*in == '\0')
 		return (0);
@@ -137,34 +138,31 @@ style_parse(struct style *sy, const stru
 					goto error;
 				if (*found != '%' || found[1] == '\0')
 					goto error;
-				for (cp = found + 1; *cp != '\0'; cp++) {
-					if (!isdigit((u_char)*cp))
-						goto error;
-				}
+				n = strtonum(found + 1, 0, UINT_MAX, &errstr);
+				if (errstr != NULL)
+					goto error;
 				sy->range_type = STYLE_RANGE_PANE;
-				sy->range_argument = atoi(found + 1);
+				sy->range_argument = n;
 				style_set_range_string(sy, "");
 			} else if (strcasecmp(tmp + 6, "window") == 0) {
 				if (found == NULL)
 					goto error;
-				for (cp = found; *cp != '\0'; cp++) {
-					if (!isdigit((u_char)*cp))
-						goto error;
-				}
+				n = strtonum(found, 0, UINT_MAX, &errstr);
+				if (errstr != NULL)
+					goto error;
 				sy->range_type = STYLE_RANGE_WINDOW;
-				sy->range_argument = atoi(found);
+				sy->range_argument = n;
 				style_set_range_string(sy, "");
 			} else if (strcasecmp(tmp + 6, "session") == 0) {
 				if (found == NULL)
 					goto error;
 				if (*found != '$' || found[1] == '\0')
 					goto error;
-				for (cp = found + 1; *cp != '\0'; cp++) {
-					if (!isdigit((u_char)*cp))
-						goto error;
-				}
+				n = strtonum(found + 1, 0, UINT_MAX, &errstr);
+				if (errstr != NULL)
+					goto error;
 				sy->range_type = STYLE_RANGE_SESSION;
-				sy->range_argument = atoi(found + 1);
+				sy->range_argument = n;
 				style_set_range_string(sy, "");
 			} else if (strcasecmp(tmp + 6, "user") == 0) {
 				if (found == NULL)

Index: src/external/bsd/tmux/dist/tmux.h
diff -u src/external/bsd/tmux/dist/tmux.h:1.22 src/external/bsd/tmux/dist/tmux.h:1.23
--- src/external/bsd/tmux/dist/tmux.h:1.22	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/tmux.h	Sat Nov  9 13:13:25 2024
@@ -134,6 +134,7 @@ struct winlink;
  */
 #define KEYC_BASE            0x0000000010e000ULL
 #define KEYC_USER            0x0000000010f000ULL
+#define KEYC_USER_END	     (KEYC_USER + KEYC_NUSER)
 
 /* Key modifier bits. */
 #define KEYC_META            0x00100000000000ULL
@@ -147,8 +148,7 @@ struct winlink;
 #define KEYC_IMPLIED_META    0x08000000000000ULL
 #define KEYC_BUILD_MODIFIERS 0x10000000000000ULL
 #define KEYC_VI		     0x20000000000000ULL
-#define KEYC_EXTENDED	     0x40000000000000ULL
-#define KEYC_SENT	     0x80000000000000ULL
+#define KEYC_SENT	     0x40000000000000ULL
 
 /* Masks for key bits. */
 #define KEYC_MASK_MODIFIERS  0x00f00000000000ULL
@@ -169,7 +169,7 @@ struct winlink;
 	 (((key) & KEYC_MASK_KEY) < KEYC_BASE || \
 	  ((key) & KEYC_MASK_KEY) >= KEYC_BASE_END) && \
 	 (((key) & KEYC_MASK_KEY) < KEYC_USER || \
-	  ((key) & KEYC_MASK_KEY) >= KEYC_USER + KEYC_NUSER))
+	  ((key) & KEYC_MASK_KEY) >= KEYC_USER_END))
 
 /* Multiple click timeout. */
 #define KEYC_CLICK_TIMEOUT 300
@@ -196,6 +196,42 @@ struct winlink;
  */
 typedef unsigned long long key_code;
 
+/* C0 control characters */
+enum {
+	C0_NUL,
+	C0_SOH,
+	C0_STX,
+	C0_ETX,
+	C0_EOT,
+	C0_ENQ,
+	C0_ASC,
+	C0_BEL,
+	C0_BS,
+	C0_HT,
+	C0_LF,
+	C0_VT,
+	C0_FF,
+	C0_CR,
+	C0_SO,
+	C0_SI,
+	C0_DLE,
+	C0_DC1,
+	C0_DC2,
+	C0_DC3,
+	C0_DC4,
+	C0_NAK,
+	C0_SYN,
+	C0_ETB,
+	C0_CAN,
+	C0_EM,
+	C0_SUB,
+	C0_ESC,
+	C0_FS,
+	C0_GS,
+	C0_RS,
+	C0_US
+};
+
 /* Special key codes. */
 enum {
 	/* Focus events. */
@@ -591,14 +627,16 @@ enum tty_code_code {
 #define MODE_MOUSE_ALL 0x1000
 #define MODE_ORIGIN 0x2000
 #define MODE_CRLF 0x4000
-#define MODE_KEXTENDED 0x8000
+#define MODE_KEYS_EXTENDED 0x8000
 #define MODE_CURSOR_VERY_VISIBLE 0x10000
 #define MODE_CURSOR_BLINKING_SET 0x20000
+#define MODE_KEYS_EXTENDED_2 0x40000
 
 #define ALL_MODES 0xffffff
 #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
 #define MOTION_MOUSE_MODES (MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
 #define CURSOR_MODES (MODE_CURSOR|MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE)
+#define EXTENDED_KEY_MODES (MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2)
 
 /* Mouse protocol constants. */
 #define MOUSE_PARAM_MAX 0xff
@@ -877,7 +915,7 @@ struct screen_sel;
 struct screen_titles;
 struct screen {
 	char				*title;
-	char				*path;
+	char *path;
 	struct screen_titles		*titles;
 
 	struct grid			*grid;	  /* grid data */
@@ -959,6 +997,11 @@ enum pane_lines {
 #define PANE_BORDER_ARROWS 2
 #define PANE_BORDER_BOTH 3
 
+/* Mode returned by window_pane_mode function. */
+#define WINDOW_PANE_NO_MODE 0
+#define WINDOW_PANE_COPY_MODE 1
+#define WINDOW_PANE_VIEW_MODE 2
+
 /* Screen redraw context. */
 struct screen_redraw_ctx {
 	struct client	*c;
@@ -1131,6 +1174,9 @@ struct window_pane {
 	int		 border_gc_set;
 	struct grid_cell border_gc;
 
+	int		 control_bg;
+	int		 control_fg;
+
 	TAILQ_ENTRY(window_pane) entry;  /* link in list of all panes */
 	TAILQ_ENTRY(window_pane) sentry; /* link in list of last visited */
 	RB_ENTRY(window_pane) tree_entry;
@@ -1970,6 +2016,7 @@ RB_HEAD(key_bindings, key_binding);
 
 struct key_table {
 	const char		*name;
+	struct timeval		 activity_time;
 	struct key_bindings	 key_bindings;
 	struct key_bindings	 default_key_bindings;
 
@@ -2096,6 +2143,7 @@ extern int		 ptm_fd;
 extern const char	*shell_command;
 int		 checkshell(const char *);
 void		 setblocking(int, int);
+char 		*shell_argv0(const char *, int);
 uint64_t	 get_timer(void);
 const char	*sig2name(int);
 const char	*find_cwd(void);
@@ -2293,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);
@@ -2390,7 +2439,6 @@ void	tty_cmd_clearstartofscreen(struct t
 void	tty_cmd_deletecharacter(struct tty *, const struct tty_ctx *);
 void	tty_cmd_clearcharacter(struct tty *, const struct tty_ctx *);
 void	tty_cmd_deleteline(struct tty *, const struct tty_ctx *);
-void	tty_cmd_erasecharacter(struct tty *, const struct tty_ctx *);
 void	tty_cmd_insertcharacter(struct tty *, const struct tty_ctx *);
 void	tty_cmd_insertline(struct tty *, const struct tty_ctx *);
 void	tty_cmd_linefeed(struct tty *, const struct tty_ctx *);
@@ -2451,6 +2499,8 @@ const struct utf8_data *tty_acs_rounded_
 void		tty_keys_build(struct tty *);
 void		tty_keys_free(struct tty *);
 int		tty_keys_next(struct tty *);
+int		tty_keys_colours(struct tty *, const char *, size_t, size_t *,
+		     int *, int *);
 
 /* arguments.c */
 void		 args_set(struct args *, u_char, struct args_value *, int);
@@ -2567,7 +2617,6 @@ enum cmd_retval	 cmd_attach_session(stru
 		     int, const char *, int, const char *);
 
 /* cmd-parse.c */
-void		 cmd_parse_empty(struct cmd_parse_input *);
 struct cmd_parse_result *cmd_parse_from_file(FILE *, struct cmd_parse_input *);
 struct cmd_parse_result *cmd_parse_from_string(const char *,
 		     struct cmd_parse_input *);
@@ -2700,11 +2749,12 @@ void	 server_clear_marked(void);
 int	 server_is_marked(struct session *, struct winlink *,
 	     struct window_pane *);
 int	 server_check_marked(void);
-int	 server_start(struct tmuxproc *, int, struct event_base *, int, char *);
+int	 server_start(struct tmuxproc *, uint64_t, struct event_base *, int,
+	     char *);
 void	 server_update_socket(void);
 void	 server_add_accept(int);
 void printflike(1, 2) server_add_message(const char *, ...);
-int	 server_create_socket(int, char **);
+int	 server_create_socket(uint64_t, char **);
 
 /* server-client.c */
 RB_PROTOTYPE(client_windows, client_window, entry, server_client_window_cmp);
@@ -2728,8 +2778,6 @@ void	 server_client_suspend(struct clien
 void	 server_client_detach(struct client *, enum msgtype);
 void	 server_client_exec(struct client *, const char *);
 void	 server_client_loop(void);
-void	 server_client_push_stdout(struct client *);
-void	 server_client_push_stderr(struct client *);
 const char *server_client_get_cwd(struct client *, struct session *);
 void	 server_client_set_flags(struct client *, const char *);
 const char *server_client_get_flags(struct client *);
@@ -3070,7 +3118,7 @@ struct window_pane *window_add_pane(stru
 void		 window_resize(struct window *, u_int, u_int, int, 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_unzoom(struct window *, int);
 int		 window_push_zoom(struct window *, int, int);
 int		 window_pop_zoom(struct window *);
 void		 window_lost_pane(struct window *, struct window_pane *);
@@ -3121,6 +3169,7 @@ void		 window_pane_update_used_data(stru
 		     struct window_pane_offset *, size_t);
 void		 window_set_fill_character(struct window *);
 void		 window_pane_default_cursor(struct window_pane *);
+int		 window_pane_mode(struct window_pane *);
 
 /* layout.c */
 u_int		 layout_count_cells(struct layout_cell *);
@@ -3185,7 +3234,7 @@ int	 mode_tree_set_current(struct mode_t
 void	 mode_tree_each_tagged(struct mode_tree_data *, mode_tree_each_cb,
 	     struct client *, key_code, int);
 void	 mode_tree_up(struct mode_tree_data *, int);
-void	 mode_tree_down(struct mode_tree_data *, int);
+int	 mode_tree_down(struct mode_tree_data *, int);
 struct mode_tree_data *mode_tree_start(struct window_pane *, struct args *,
 	     mode_tree_build_cb, mode_tree_draw_cb, mode_tree_search_cb,
 	     mode_tree_menu_cb, mode_tree_height_cb, mode_tree_key_cb, void *,
@@ -3227,6 +3276,7 @@ void printflike(3, 4) window_copy_add(st
 void printflike(3, 0) window_copy_vadd(struct window_pane *, int, const char *,
 		     va_list);
 void		 window_copy_pageup(struct window_pane *, int);
+void		 window_copy_pagedown(struct window_pane *, int, int);
 void		 window_copy_start_drag(struct client *, struct mouse_event *);
 char		*window_copy_get_word(struct window_pane *, u_int, u_int);
 char		*window_copy_get_line(struct window_pane *, u_int);
@@ -3259,8 +3309,6 @@ void	control_add_sub(struct client *, co
 void	control_remove_sub(struct client *, const char *);
 
 /* control-notify.c */
-void	control_notify_input(struct client *, struct window_pane *,
-	    const u_char *, size_t);
 void	control_notify_pane_mode_changed(int);
 void	control_notify_window_layout_changed(struct window *);
 void	control_notify_window_pane_changed(struct window *);
@@ -3294,8 +3342,6 @@ char		*session_check_name(const char *);
 void		 session_update_activity(struct session *, struct timeval *);
 struct session	*session_next_session(struct session *);
 struct session	*session_previous_session(struct session *);
-struct winlink	*session_new(struct session *, const char *, int, char **,
-		     const char *, const char *, int, char **);
 struct winlink	*session_attach(struct session *, struct window *, int,
 		     char **);
 int		 session_detach(struct session *, struct winlink *);
@@ -3318,6 +3364,7 @@ void		 session_renumber_windows(struct s
 
 /* utf8.c */
 enum utf8_state	 utf8_towc (const struct utf8_data *, wchar_t *);
+enum utf8_state	 utf8_fromwc(wchar_t wc, struct utf8_data *);
 int		 utf8_in_table(wchar_t, const wchar_t *, u_int);
 utf8_char	 utf8_build_one(u_char);
 enum utf8_state	 utf8_from_data(const struct utf8_data *, utf8_char *);
@@ -3463,6 +3510,7 @@ u_int	 		 hyperlinks_put(struct hyperlin
 int			 hyperlinks_get(struct hyperlinks *, u_int,
 			     const char **, const char **, const char **);
 struct hyperlinks	*hyperlinks_init(void);
+struct hyperlinks	*hyperlinks_copy(struct hyperlinks *);
 void			 hyperlinks_reset(struct hyperlinks *);
 void			 hyperlinks_free(struct hyperlinks *);
 

Index: src/external/bsd/tmux/dist/tty.c
diff -u src/external/bsd/tmux/dist/tty.c:1.11 src/external/bsd/tmux/dist/tty.c:1.12
--- src/external/bsd/tmux/dist/tty.c:1.11	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/tty.c	Sat Nov  9 13:13:25 2024
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <termios.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "tmux.h"
@@ -379,13 +380,13 @@ tty_send_requests(struct tty *tty)
 		tty_puts(tty, "\033]11;?\033\\");
 	} else
 		tty->flags |= TTY_ALL_REQUEST_FLAGS;
-	tty->last_requests = time (NULL);
+	tty->last_requests = time(NULL);
 }
 
 void
 tty_repeat_requests(struct tty *tty)
 {
-	time_t	t = time (NULL);
+	time_t	t = time(NULL);
 
 	if (~tty->flags & TTY_STARTED)
 		return;
@@ -2777,7 +2778,6 @@ static void
 tty_colours(struct tty *tty, const struct grid_cell *gc)
 {
 	struct grid_cell	*tc = &tty->cell;
-	int			 have_ax;
 
 	/* No changes? Nothing is necessary. */
 	if (gc->fg == tc->fg && gc->bg == tc->bg && gc->us == tc->us)
@@ -2791,28 +2791,18 @@ tty_colours(struct tty *tty, const struc
 	 */
 	if (COLOUR_DEFAULT(gc->fg) || COLOUR_DEFAULT(gc->bg)) {
 		/*
-		 * If don't have AX but do have op, send sgr0 (op can't
-		 * actually be used because it is sometimes the same as sgr0
-		 * and sometimes isn't). This resets both colours to default.
-		 *
+		 * If don't have AX, send sgr0. This resets both colours to default.
 		 * Otherwise, try to set the default colour only as needed.
 		 */
-		have_ax = tty_term_flag(tty->term, TTYC_AX);
-		if (!have_ax && tty_term_has(tty->term, TTYC_OP))
+		if (!tty_term_flag(tty->term, TTYC_AX))
 			tty_reset(tty);
 		else {
 			if (COLOUR_DEFAULT(gc->fg) && !COLOUR_DEFAULT(tc->fg)) {
-				if (have_ax)
-					tty_puts(tty, "\033[39m");
-				else if (tc->fg != 7)
-					tty_putcode_i(tty, TTYC_SETAF, 7);
+				tty_puts(tty, "\033[39m");
 				tc->fg = gc->fg;
 			}
 			if (COLOUR_DEFAULT(gc->bg) && !COLOUR_DEFAULT(tc->bg)) {
-				if (have_ax)
-					tty_puts(tty, "\033[49m");
-				else if (tc->bg != 0)
-					tty_putcode_i(tty, TTYC_SETAB, 0);
+				tty_puts(tty, "\033[49m");
 				tc->bg = gc->bg;
 			}
 		}
@@ -2824,7 +2814,7 @@ tty_colours(struct tty *tty, const struc
 
 	/*
 	 * Set the background colour. This must come after the foreground as
-	 * tty_colour_fg() can call tty_reset().
+	 * tty_colours_fg() can call tty_reset().
 	 */
 	if (!COLOUR_DEFAULT(gc->bg) && gc->bg != tc->bg)
 		tty_colours_bg(tty, gc);
@@ -2972,6 +2962,15 @@ tty_colours_fg(struct tty *tty, const st
 	struct grid_cell	*tc = &tty->cell;
 	char			 s[32];
 
+	/*
+	 * If the current colour is an aixterm bright colour and the new is not,
+	 * reset because some terminals do not clear bright correctly.
+	 */
+	if (tty->cell.fg >= 90 &&
+	    tty->cell.bg <= 97 &&
+	    (gc->fg < 90 || gc->fg > 97))
+		tty_reset(tty);
+
 	/* Is this a 24-bit or 256-colour colour? */
 	if (gc->fg & COLOUR_FLAG_RGB || gc->fg & COLOUR_FLAG_256) {
 		if (tty_try_colour(tty, gc->fg, "38") == 0)

Index: src/external/bsd/tmux/dist/window.c
diff -u src/external/bsd/tmux/dist/window.c:1.17 src/external/bsd/tmux/dist/window.c:1.18
--- src/external/bsd/tmux/dist/window.c:1.17	Sat Jun 22 20:07:14 2024
+++ src/external/bsd/tmux/dist/window.c	Sat Nov  9 13:13:25 2024
@@ -338,7 +338,7 @@ window_destroy(struct window *w)
 {
 	log_debug("window @%u destroyed (%d references)", w->id, w->references);
 
-	window_unzoom(w);
+	window_unzoom(w, 0);
 	RB_REMOVE(windows, &windows, w);
 
 	if (w->layout_root != NULL)
@@ -481,7 +481,7 @@ window_pane_update_focus(struct window_p
 	struct client	*c;
 	int		 focused = 0;
 
-	if (wp != NULL) {
+	if (wp != NULL && (~wp->flags & PANE_EXITED)) {
 		if (wp != wp->window->active)
 			focused = 0;
 		else {
@@ -673,7 +673,7 @@ window_zoom(struct window_pane *wp)
 }
 
 int
-window_unzoom(struct window *w)
+window_unzoom(struct window *w, int notify)
 {
 	struct window_pane	*wp;
 
@@ -690,7 +690,9 @@ window_unzoom(struct window *w)
 		wp->saved_layout_cell = NULL;
 	}
 	layout_fix_panes(w, NULL);
-	notify_window("window-layout-changed", w);
+
+	if (notify)
+		notify_window("window-layout-changed", w);
 
 	return (0);
 }
@@ -704,7 +706,7 @@ window_push_zoom(struct window *w, int a
 		w->flags |= WINDOW_WASZOOMED;
 	else
 		w->flags &= ~WINDOW_WASZOOMED;
-	return (window_unzoom(w) == 0);
+	return (window_unzoom(w, 1) == 0);
 }
 
 int
@@ -942,6 +944,9 @@ window_pane_create(struct window *w, u_i
 
 	wp->pipe_fd = -1;
 
+	wp->control_bg = -1;
+	wp->control_fg = -1;
+
 	colour_palette_init(&wp->palette);
 	colour_palette_from_option(&wp->palette, wp->options);
 
@@ -1667,3 +1672,15 @@ window_pane_default_cursor(struct window
 	s->default_mode = 0;
 	screen_set_cursor_style(c, &s->default_cstyle, &s->default_mode);
 }
+
+int
+window_pane_mode(struct window_pane *wp)
+{
+	if (TAILQ_FIRST(&wp->modes) != NULL) {
+		if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode)
+			return (WINDOW_PANE_COPY_MODE);
+		if (TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
+			return (WINDOW_PANE_VIEW_MODE);
+	}
+	return (WINDOW_PANE_NO_MODE);
+}

Reply via email to