diff options
Diffstat (limited to 'usr.bin/tmux/server-client.c')
-rw-r--r-- | usr.bin/tmux/server-client.c | 93 |
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); + } + } +} |