summaryrefslogtreecommitdiff
path: root/usr.bin/tmux/server-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/tmux/server-client.c')
-rw-r--r--usr.bin/tmux/server-client.c93
1 files changed, 90 insertions, 3 deletions
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);
+ }
+ }
+}