summaryrefslogtreecommitdiff
path: root/usr.bin/tmux
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2020-05-16 16:21:00 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2020-05-16 16:21:00 +0000
commit40cf1ab9daf002bd661e82a40e95176c69ed3c59 (patch)
tree5a7e2ef3e1bff5843cfb3b3c68b29125e44104d1 /usr.bin/tmux
parent8854050c960c6ab1e744243d698071d542020a01 (diff)
Add a client flag 'active-pane' which stores the active pane in the
client and allows it to be changed independently from the real active pane stored in the window. This is can be used with session groups which allow an independent current window (although it would be nice to have a flag for this too and remove session groups). The client active pane is only really useful interactively, many things (hooks, window-style, zooming) still use the window active pane.
Diffstat (limited to 'usr.bin/tmux')
-rw-r--r--usr.bin/tmux/cmd-break-pane.c3
-rw-r--r--usr.bin/tmux/cmd-find.c25
-rw-r--r--usr.bin/tmux/cmd-join-pane.c3
-rw-r--r--usr.bin/tmux/cmd-kill-pane.c3
-rw-r--r--usr.bin/tmux/cmd-queue.c4
-rw-r--r--usr.bin/tmux/cmd-select-pane.c20
-rw-r--r--usr.bin/tmux/cmd-split-window.c3
-rw-r--r--usr.bin/tmux/cmd-swap-pane.c5
-rw-r--r--usr.bin/tmux/screen-redraw.c17
-rw-r--r--usr.bin/tmux/server-client.c93
-rw-r--r--usr.bin/tmux/server-fn.c4
-rw-r--r--usr.bin/tmux/spawn.c3
-rw-r--r--usr.bin/tmux/tmux.111
-rw-r--r--usr.bin/tmux/tmux.h19
-rw-r--r--usr.bin/tmux/tty.c7
15 files changed, 179 insertions, 41 deletions
diff --git a/usr.bin/tmux/cmd-break-pane.c b/usr.bin/tmux/cmd-break-pane.c
index e0b1ad89b59..5fee3bac629 100644
--- a/usr.bin/tmux/cmd-break-pane.c
+++ b/usr.bin/tmux/cmd-break-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-break-pane.c,v 1.56 2020/04/22 21:15:33 nicm Exp $ */
+/* $OpenBSD: cmd-break-pane.c,v 1.57 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -89,6 +89,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
}
TAILQ_REMOVE(&w->panes, wp, entry);
+ server_client_remove_pane(wp);
window_lost_pane(w, wp);
layout_close_pane(wp);
diff --git a/usr.bin/tmux/cmd-find.c b/usr.bin/tmux/cmd-find.c
index 7de7bcd3ad0..9311d1d6a6c 100644
--- a/usr.bin/tmux/cmd-find.c
+++ b/usr.bin/tmux/cmd-find.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-find.c,v 1.78 2020/04/13 14:46:04 nicm Exp $ */
+/* $OpenBSD: cmd-find.c,v 1.79 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -588,22 +588,22 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
return (-1);
return (0);
} else if (strcmp(pane, "{up-of}") == 0) {
- fs->wp = window_pane_find_up(fs->w->active);
+ fs->wp = window_pane_find_up(fs->current->wp);
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{down-of}") == 0) {
- fs->wp = window_pane_find_down(fs->w->active);
+ fs->wp = window_pane_find_down(fs->current->wp);
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{left-of}") == 0) {
- fs->wp = window_pane_find_left(fs->w->active);
+ fs->wp = window_pane_find_left(fs->current->wp);
if (fs->wp == NULL)
return (-1);
return (0);
} else if (strcmp(pane, "{right-of}") == 0) {
- fs->wp = window_pane_find_right(fs->w->active);
+ fs->wp = window_pane_find_right(fs->current->wp);
if (fs->wp == NULL)
return (-1);
return (0);
@@ -615,7 +615,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
n = strtonum(pane + 1, 1, INT_MAX, NULL);
else
n = 1;
- wp = fs->w->active;
+ wp = fs->current->wp;
if (pane[0] == '+')
fs->wp = window_pane_next_by_number(fs->w, wp, n);
else
@@ -867,7 +867,18 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
/* If this is an attached client, all done. */
if (c->session != NULL) {
- cmd_find_from_session(fs, c->session, flags);
+ cmd_find_clear_state(fs, flags);
+
+ fs->wp = server_client_get_pane(c);
+ if (fs->wp == NULL) {
+ cmd_find_from_session(fs, c->session, flags);
+ return (0);
+ }
+ fs->s = c->session;
+ fs->wl = fs->s->curw;
+ fs->w = fs->wl->window;
+
+ cmd_find_log_state(__func__, fs);
return (0);
}
cmd_find_clear_state(fs, flags);
diff --git a/usr.bin/tmux/cmd-join-pane.c b/usr.bin/tmux/cmd-join-pane.c
index c7310e8cd04..082897cc708 100644
--- a/usr.bin/tmux/cmd-join-pane.c
+++ b/usr.bin/tmux/cmd-join-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-join-pane.c,v 1.44 2020/04/22 21:15:33 nicm Exp $ */
+/* $OpenBSD: cmd-join-pane.c,v 1.45 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2011 George Nachman <tmux@georgester.com>
@@ -136,6 +136,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
layout_close_pane(src_wp);
+ server_client_remove_pane(src_wp);
window_lost_pane(src_w, src_wp);
TAILQ_REMOVE(&src_w->panes, src_wp, entry);
diff --git a/usr.bin/tmux/cmd-kill-pane.c b/usr.bin/tmux/cmd-kill-pane.c
index c57f1e84177..1b845c19943 100644
--- a/usr.bin/tmux/cmd-kill-pane.c
+++ b/usr.bin/tmux/cmd-kill-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-kill-pane.c,v 1.29 2020/04/13 10:59:58 nicm Exp $ */
+/* $OpenBSD: cmd-kill-pane.c,v 1.30 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -54,6 +54,7 @@ cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
if (loopwp == wp)
continue;
+ server_client_remove_pane(loopwp);
layout_close_pane(loopwp);
window_remove_pane(wl->window, loopwp);
}
diff --git a/usr.bin/tmux/cmd-queue.c b/usr.bin/tmux/cmd-queue.c
index d210b62a0c4..f7223080875 100644
--- a/usr.bin/tmux/cmd-queue.c
+++ b/usr.bin/tmux/cmd-queue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-queue.c,v 1.95 2020/05/16 16:16:07 nicm Exp $ */
+/* $OpenBSD: cmd-queue.c,v 1.96 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -809,7 +809,7 @@ cmdq_print(struct cmdq_item *item, const char *fmt, ...)
}
file_print(c, "%s\n", msg);
} else {
- wp = c->session->curw->window->active;
+ wp = server_client_get_pane(c);
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode) {
window_pane_set_mode(wp, NULL, &window_view_mode, NULL,
diff --git a/usr.bin/tmux/cmd-select-pane.c b/usr.bin/tmux/cmd-select-pane.c
index a767e28e791..57309bbab0b 100644
--- a/usr.bin/tmux/cmd-select-pane.c
+++ b/usr.bin/tmux/cmd-select-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-select-pane.c,v 1.60 2020/05/16 15:01:31 nicm Exp $ */
+/* $OpenBSD: cmd-select-pane.c,v 1.61 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -87,10 +87,11 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
const struct cmd_entry *entry = cmd_get_entry(self);
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state *target = cmdq_get_target(item);
+ struct client *c = cmdq_get_client(item);
struct winlink *wl = target->wl;
struct window *w = wl->window;
struct session *s = target->s;
- struct window_pane *wp = target->wp, *lastwp, *markedwp;
+ struct window_pane *wp = target->wp, *activewp, *lastwp, *markedwp;
struct options *oo = wp->options;
char *title;
const char *style;
@@ -201,16 +202,21 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
- if (wp == w->active)
+ if (c->session != NULL && (c->flags & CLIENT_ACTIVEPANE))
+ activewp = server_client_get_pane(c);
+ else
+ activewp = w->active;
+ if (wp == activewp)
return (CMD_RETURN_NORMAL);
if (window_push_zoom(w, args_has(args, 'Z')))
server_redraw_window(w);
window_redraw_active_switch(w, wp);
- if (window_set_active_pane(w, wp, 1)) {
+ if (c->session != NULL && (c->flags & CLIENT_ACTIVEPANE))
+ server_client_set_pane(c, wp);
+ else if (window_set_active_pane(w, wp, 1))
cmd_find_from_winlink_pane(current, wl, wp, 0);
- cmdq_insert_hook(s, item, current, "after-select-pane");
- cmd_select_pane_redraw(w);
- }
+ cmdq_insert_hook(s, item, current, "after-select-pane");
+ cmd_select_pane_redraw(w);
if (window_pop_zoom(w))
server_redraw_window(w);
diff --git a/usr.bin/tmux/cmd-split-window.c b/usr.bin/tmux/cmd-split-window.c
index b94a9806c25..a0ed48dcae7 100644
--- a/usr.bin/tmux/cmd-split-window.c
+++ b/usr.bin/tmux/cmd-split-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-split-window.c,v 1.103 2020/04/13 20:51:57 nicm Exp $ */
+/* $OpenBSD: cmd-split-window.c,v 1.104 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -160,6 +160,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
if (input && window_pane_start_input(new_wp, item, &cause) != 0) {
+ server_client_remove_pane(new_wp);
layout_close_pane(new_wp);
window_remove_pane(wp->window, new_wp);
cmdq_error(item, "%s", cause);
diff --git a/usr.bin/tmux/cmd-swap-pane.c b/usr.bin/tmux/cmd-swap-pane.c
index 6b1dcf11494..04fc89ac84a 100644
--- a/usr.bin/tmux/cmd-swap-pane.c
+++ b/usr.bin/tmux/cmd-swap-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-swap-pane.c,v 1.37 2020/04/13 10:59:58 nicm Exp $ */
+/* $OpenBSD: cmd-swap-pane.c,v 1.38 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -79,6 +79,9 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
if (src_wp == dst_wp)
goto out;
+ server_client_remove_pane(src_wp);
+ server_client_remove_pane(dst_wp);
+
tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry);
TAILQ_REMOVE(&dst_w->panes, dst_wp, entry);
TAILQ_REPLACE(&src_w->panes, src_wp, dst_wp, entry);
diff --git a/usr.bin/tmux/screen-redraw.c b/usr.bin/tmux/screen-redraw.c
index 789b40189c7..1e0670c5a91 100644
--- a/usr.bin/tmux/screen-redraw.c
+++ b/usr.bin/tmux/screen-redraw.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: screen-redraw.c,v 1.76 2020/05/16 15:34:08 nicm Exp $ */
+/* $OpenBSD: screen-redraw.c,v 1.77 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -242,7 +242,7 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
struct window_pane **wpp)
{
struct window *w = c->session->curw->window;
- struct window_pane *wp;
+ struct window_pane *wp, *active;
int border;
u_int right, line;
@@ -254,7 +254,7 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
return (screen_redraw_type_of_cell(c, px, py, pane_status));
if (pane_status != PANE_STATUS_OFF) {
- wp = w->active;
+ active = wp = server_client_get_pane(c);
do {
if (!window_pane_visible(wp))
goto next1;
@@ -272,10 +272,10 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
wp = TAILQ_NEXT(wp, entry);
if (wp == NULL)
wp = TAILQ_FIRST(&w->panes);
- } while (wp != w->active);
+ } while (wp != active);
}
- wp = w->active;
+ active = wp = server_client_get_pane(c);
do {
if (!window_pane_visible(wp))
goto next2;
@@ -296,7 +296,7 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
wp = TAILQ_NEXT(wp, entry);
if (wp == NULL)
wp = TAILQ_FIRST(&w->panes);
- } while (wp != w->active);
+ } while (wp != active);
return (CELL_OUTSIDE);
}
@@ -330,7 +330,7 @@ screen_redraw_make_pane_status(struct client *c, struct window *w,
ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
format_defaults(ft, c, c->session, c->session->curw, wp);
- if (wp == w->active)
+ if (wp == server_client_get_pane(c))
style_apply(&gc, w->options, "pane-active-border-style", ft);
else
style_apply(&gc, w->options, "pane-border-style", ft);
@@ -558,6 +558,7 @@ screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x,
struct client *c = ctx->c;
struct session *s = c->session;
struct window *w = s->curw->window;
+ struct window_pane *active = server_client_get_pane(c);
struct options *oo = w->options;
struct grid_cell *gc;
struct format_tree *ft;
@@ -569,7 +570,7 @@ screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x,
ft = format_create_defaults(NULL, c, s, s->curw, wp);
gc = &wp->border_gc;
- if (screen_redraw_check_is(x, y, ctx->pane_status, w->active)) {
+ if (screen_redraw_check_is(x, y, ctx->pane_status, active)) {
style_apply(gc, oo, "pane-active-border-style", ft);
gc->attr |= GRID_ATTR_CHARSET;
} else {
diff --git a/usr.bin/tmux/server-client.c b/usr.bin/tmux/server-client.c
index a3efa3505f5..c44d767b557 100644
--- a/usr.bin/tmux/server-client.c
+++ b/usr.bin/tmux/server-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-client.c,v 1.340 2020/05/16 16:16:07 nicm Exp $ */
+/* $OpenBSD: server-client.c,v 1.341 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -56,6 +56,19 @@ static void server_client_dispatch_read_data(struct client *,
static void server_client_dispatch_read_done(struct client *,
struct imsg *);
+/* Compare client windows. */
+static int
+server_client_window_cmp(struct client_window *cw1,
+ struct client_window *cw2)
+{
+ if (cw1->window < cw2->window)
+ return (-1);
+ if (cw1->window > cw2->window)
+ return (1);
+ return (0);
+}
+RB_GENERATE(client_windows, client_window, entry, server_client_window_cmp);
+
/* Number of attached clients. */
u_int
server_client_how_many(void)
@@ -211,6 +224,7 @@ server_client_create(int fd)
c->cwd = NULL;
c->queue = cmdq_new();
+ RB_INIT(&c->windows);
c->tty.fd = -1;
c->tty.sx = 80;
@@ -272,6 +286,7 @@ void
server_client_lost(struct client *c)
{
struct client_file *cf, *cf1;
+ struct client_window *cw, *cw1;
c->flags |= CLIENT_DEAD;
@@ -283,6 +298,10 @@ server_client_lost(struct client *c)
cf->error = EINTR;
file_fire_done(cf);
}
+ RB_FOREACH_SAFE(cw, client_windows, &c->windows, cw1) {
+ RB_REMOVE(client_windows, &c->windows, cw);
+ free(cw);
+ }
TAILQ_REMOVE(&clients, c, entry);
log_debug("lost client %p", c);
@@ -1126,7 +1145,7 @@ server_client_key_callback(struct cmdq_item *item, void *data)
/* Find affected pane. */
if (!KEYC_IS_MOUSE(key) || cmd_find_from_mouse(&fs, m, 0) != 0)
- cmd_find_from_session(&fs, s, 0);
+ cmd_find_from_client(&fs, c, 0);
wp = fs.wp;
/* Forward mouse keys if disabled. */
@@ -1535,7 +1554,7 @@ server_client_reset_state(struct client *c)
{
struct tty *tty = &c->tty;
struct window *w = c->session->curw->window;
- struct window_pane *wp = w->active, *loop;
+ struct window_pane *wp = server_client_get_pane(c), *loop;
struct screen *s = NULL;
struct options *oo = c->session->options;
int mode = 0, cursor, flags;
@@ -2236,6 +2255,8 @@ server_client_set_flags(struct client *c, const char *flags)
flag = CLIENT_READONLY;
else if (strcmp(next, "ignore-size") == 0)
flag = CLIENT_IGNORESIZE;
+ else if (strcmp(next, "active-pane") == 0)
+ flag = CLIENT_ACTIVEPANE;
else
continue;
@@ -2266,6 +2287,8 @@ server_client_get_flags(struct client *c)
strlcat(s, "no-output,", sizeof s);
if (c->flags & CLIENT_READONLY)
strlcat(s, "read-only,", sizeof s);
+ if (c->flags & CLIENT_ACTIVEPANE)
+ strlcat(s, "active-pane,", sizeof s);
if (c->flags & CLIENT_SUSPENDED)
strlcat(s, "suspended,", sizeof s);
if (c->flags & CLIENT_UTF8)
@@ -2274,3 +2297,67 @@ server_client_get_flags(struct client *c)
s[strlen(s) - 1] = '\0';
return (s);
}
+
+/* Get client window. */
+static struct client_window *
+server_client_get_client_window(struct client *c, u_int id)
+{
+ struct client_window cw = { .window = id };
+
+ return (RB_FIND(client_windows, &c->windows, &cw));
+}
+
+/* Get client active pane. */
+struct window_pane *
+server_client_get_pane(struct client *c)
+{
+ struct session *s = c->session;
+ struct client_window *cw;
+
+ if (s == NULL)
+ return (NULL);
+
+ if (~c->flags & CLIENT_ACTIVEPANE)
+ return (s->curw->window->active);
+ cw = server_client_get_client_window(c, s->curw->window->id);
+ if (cw == NULL)
+ return (s->curw->window->active);
+ return (cw->pane);
+}
+
+/* Set client active pane. */
+void
+server_client_set_pane(struct client *c, struct window_pane *wp)
+{
+ struct session *s = c->session;
+ struct client_window *cw;
+
+ if (s == NULL)
+ return;
+
+ cw = server_client_get_client_window(c, s->curw->window->id);
+ if (cw == NULL) {
+ cw = xcalloc(1, sizeof *cw);
+ cw->window = s->curw->window->id;
+ RB_INSERT(client_windows, &c->windows, cw);
+ }
+ cw->pane = wp;
+ log_debug("%s pane now %%%u", c->name, wp->id);
+}
+
+/* Remove pane from client lists. */
+void
+server_client_remove_pane(struct window_pane *wp)
+{
+ struct client *c;
+ struct window *w = wp->window;
+ struct client_window *cw;
+
+ TAILQ_FOREACH(c, &clients, entry) {
+ cw = server_client_get_client_window(c, w->id);
+ if (cw != NULL && cw->pane == wp) {
+ RB_REMOVE(client_windows, &c->windows, cw);
+ free(cw);
+ }
+ }
+}
diff --git a/usr.bin/tmux/server-fn.c b/usr.bin/tmux/server-fn.c
index 6ceb2d27939..4acb14aa707 100644
--- a/usr.bin/tmux/server-fn.c
+++ b/usr.bin/tmux/server-fn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-fn.c,v 1.125 2020/05/16 15:34:08 nicm Exp $ */
+/* $OpenBSD: server-fn.c,v 1.126 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -187,6 +187,7 @@ server_kill_pane(struct window_pane *wp)
recalculate_sizes();
} else {
server_unzoom_window(w);
+ server_client_remove_pane(wp);
layout_close_pane(wp);
window_remove_pane(w, wp);
server_redraw_window(w);
@@ -348,6 +349,7 @@ server_destroy_pane(struct window_pane *wp, int notify)
notify_pane("pane-exited", wp);
server_unzoom_window(w);
+ server_client_remove_pane(wp);
layout_close_pane(wp);
window_remove_pane(w, wp);
diff --git a/usr.bin/tmux/spawn.c b/usr.bin/tmux/spawn.c
index c19d7e37dea..c8bf91da939 100644
--- a/usr.bin/tmux/spawn.c
+++ b/usr.bin/tmux/spawn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: spawn.c,v 1.22 2020/04/23 05:48:42 nicm Exp $ */
+/* $OpenBSD: spawn.c,v 1.23 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -362,6 +362,7 @@ spawn_pane(struct spawn_context *sc, char **cause)
xasprintf(cause, "fork failed: %s", strerror(errno));
new_wp->fd = -1;
if (~sc->flags & SPAWN_RESPAWN) {
+ server_client_remove_pane(new_wp);
layout_close_pane(new_wp);
window_remove_pane(w, new_wp);
}
diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1
index a8f6597f616..e18ab5b68aa 100644
--- a/usr.bin/tmux/tmux.1
+++ b/usr.bin/tmux/tmux.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.768 2020/05/16 16:10:28 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.769 2020/05/16 16:20:59 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
.\"
@@ -986,6 +986,8 @@ the client is read-only
the client does not affect the size of other clients
.It no-output
the client does not receive pane output in control mode
+.It active-pane
+the client has an independent active pane
.El
.Pp
A leading
@@ -1000,6 +1002,13 @@ When a client is read-only, only keys bound to the
or
.Ic switch-client
commands have any effect.
+A client with the
+.Ar active-pane
+flag allows the active pane to be selected independently of the window's active
+pane used by clients without the flag.
+This only affects the cursor position and commands issued from the client;
+other features such as hooks and styles continue to use the window's active
+pane.
.Pp
If no server is started,
.Ic attach-session
diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h
index 34ffd4d8955..88753e721a1 100644
--- a/usr.bin/tmux/tmux.h
+++ b/usr.bin/tmux/tmux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1040 2020/05/16 16:16:07 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1041 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1508,6 +1508,14 @@ struct client_file {
};
RB_HEAD(client_files, client_file);
+/* Client window. */
+struct client_window {
+ u_int window;
+ struct window_pane *pane;
+ RB_ENTRY(client_window) entry;
+};
+RB_HEAD(client_windows, client_window);
+
/* Client connection. */
typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
typedef void (*prompt_free_cb)(void *);
@@ -1521,6 +1529,8 @@ struct client {
struct tmuxpeer *peer;
struct cmdq_list *queue;
+ struct client_windows windows;
+
pid_t pid;
int fd;
struct event event;
@@ -1585,6 +1595,7 @@ struct client {
#define CLIENT_STARTSERVER 0x10000000
#define CLIENT_REDRAWPANES 0x20000000
#define CLIENT_NOFORK 0x40000000
+#define CLIENT_ACTIVEPANE 0x80000000ULL
#define CLIENT_ALLREDRAWFLAGS \
(CLIENT_REDRAWWINDOW| \
CLIENT_REDRAWSTATUS| \
@@ -1600,7 +1611,7 @@ struct client {
(CLIENT_DEAD| \
CLIENT_SUSPENDED| \
CLIENT_DETACHING)
- int flags;
+ uint64_t flags;
struct key_table *keytable;
uint64_t redraw_panes;
@@ -2299,6 +2310,7 @@ void server_add_accept(int);
void printflike(1, 2) server_add_message(const char *, ...);
/* server-client.c */
+RB_PROTOTYPE(client_windows, client_window, entry, server_client_window_cmp);
u_int server_client_how_many(void);
void server_client_set_overlay(struct client *, u_int, overlay_check_cb,
overlay_mode_cb, overlay_draw_cb, overlay_key_cb,
@@ -2321,6 +2333,9 @@ 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 *);
+struct window_pane *server_client_get_pane(struct client *);
+void server_client_set_pane(struct client *, struct window_pane *);
+void server_client_remove_pane(struct window_pane *);
/* server-fn.c */
void server_redraw_client(struct client *);
diff --git a/usr.bin/tmux/tty.c b/usr.bin/tmux/tty.c
index f9ae50a3ff4..001820b91d5 100644
--- a/usr.bin/tmux/tty.c
+++ b/usr.bin/tmux/tty.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty.c,v 1.375 2020/05/16 16:07:55 nicm Exp $ */
+/* $OpenBSD: tty.c,v 1.376 2020/05/16 16:20:59 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -693,8 +693,7 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
}
if (s != NULL && tty->cstyle != s->cstyle) {
if (tty_term_has(tty->term, TTYC_SS)) {
- if (s->cstyle == 0 &&
- tty_term_has(tty->term, TTYC_SE))
+ if (s->cstyle == 0 && tty_term_has(tty->term, TTYC_SE))
tty_putcode(tty, TTYC_SE);
else
tty_putcode1(tty, TTYC_SS, s->cstyle);
@@ -792,7 +791,7 @@ tty_window_offset1(struct tty *tty, u_int *ox, u_int *oy, u_int *sx, u_int *sy)
{
struct client *c = tty->client;
struct window *w = c->session->curw->window;
- struct window_pane *wp = w->active;
+ struct window_pane *wp = server_client_get_pane(c);
u_int cx, cy, lines;
lines = status_line_size(c);