summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd-break-pane.c1
-rw-r--r--cmd-find.c23
-rw-r--r--cmd-join-pane.c1
-rw-r--r--cmd-kill-pane.c1
-rw-r--r--cmd-queue.c2
-rw-r--r--cmd-select-pane.c18
-rw-r--r--cmd-split-window.c1
-rw-r--r--cmd-swap-pane.c3
-rw-r--r--screen-redraw.c15
-rw-r--r--server-client.c91
-rw-r--r--server-fn.c2
-rw-r--r--spawn.c1
-rw-r--r--tmux.19
-rw-r--r--tmux.h17
-rw-r--r--tty.c5
15 files changed, 164 insertions, 26 deletions
diff --git a/cmd-break-pane.c b/cmd-break-pane.c
index 87892d73..9483aa7e 100644
--- a/cmd-break-pane.c
+++ b/cmd-break-pane.c
@@ -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/cmd-find.c b/cmd-find.c
index 9c8bcbc1..9f04c4a8 100644
--- a/cmd-find.c
+++ b/cmd-find.c
@@ -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/cmd-join-pane.c b/cmd-join-pane.c
index 3efe769b..9802083d 100644
--- a/cmd-join-pane.c
+++ b/cmd-join-pane.c
@@ -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/cmd-kill-pane.c b/cmd-kill-pane.c
index 2302d7bb..3bf6e26e 100644
--- a/cmd-kill-pane.c
+++ b/cmd-kill-pane.c
@@ -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/cmd-queue.c b/cmd-queue.c
index 6bc6d0d2..5620fdad 100644
--- a/cmd-queue.c
+++ b/cmd-queue.c
@@ -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/cmd-select-pane.c b/cmd-select-pane.c
index 224370ab..3b639e06 100644
--- a/cmd-select-pane.c
+++ b/cmd-select-pane.c
@@ -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/cmd-split-window.c b/cmd-split-window.c
index c0e0e22a..c9d92fae 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -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/cmd-swap-pane.c b/cmd-swap-pane.c
index 021ac224..dd981b9a 100644
--- a/cmd-swap-pane.c
+++ b/cmd-swap-pane.c
@@ -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/screen-redraw.c b/screen-redraw.c
index 0f83479c..ffa7aecf 100644
--- a/screen-redraw.c
+++ b/screen-redraw.c
@@ -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/server-client.c b/server-client.c
index 1e0d992d..3ce393cd 100644
--- a/server-client.c
+++ b/server-client.c
@@ -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/server-fn.c b/server-fn.c
index fde1d8e8..d66aed0b 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -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/spawn.c b/spawn.c
index f05887b2..01f19097 100644
--- a/spawn.c
+++ b/spawn.c
@@ -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/tmux.1 b/tmux.1
index baa296fb..0b03becc 100644
--- a/tmux.1
+++ b/tmux.1
@@ -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/tmux.h b/tmux.h
index 3ccb005a..3bd37f05 100644
--- a/tmux.h
+++ b/tmux.h
@@ -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/tty.c b/tty.c
index a1e2f2c6..a4f2acee 100644
--- a/tty.c
+++ b/tty.c
@@ -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);