1/* $OpenBSD$ */
2
3/*
4 * Copyright (c) 2007 Nicholas Marriott <[email protected]>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20
21#include <stdlib.h>
22#include <string.h>
23
24#include "tmux.h"
25
26/*
27 * Switch client to a different session.
28 */
29
30static enum cmd_retval cmd_switch_client_exec(struct cmd *,
31 struct cmdq_item *);
32
33const struct cmd_entry cmd_switch_client_entry = {
34 .name = "switch-client",
35 .alias = "switchc",
36
37 .args = { "lc:Enpt:rT:Z", 0, 0 },
38 .usage = "[-ElnprZ] [-c target-client] [-t target-session] "
39 "[-T key-table]",
40
41 /* -t is special */
42
43 .flags = CMD_READONLY,
44 .exec = cmd_switch_client_exec
45};
46
47static enum cmd_retval
48cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
49{
50 struct args *args = self->args;
51 const char *tflag = args_get(args, 't');
52 enum cmd_find_type type;
53 int flags;
54 struct client *c;
55 struct session *s;
56 struct winlink *wl;
57 struct window *w;
58 struct window_pane *wp;
59 const char *tablename;
60 struct key_table *table;
61
62 if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
63 return (CMD_RETURN_ERROR);
64
65 if (tflag != NULL && tflag[strcspn(tflag, ":.%")] != '\0') {
66 type = CMD_FIND_PANE;
67 flags = 0;
68 } else {
69 type = CMD_FIND_SESSION;
70 flags = CMD_FIND_PREFER_UNATTACHED;
71 }
72 if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
73 return (CMD_RETURN_ERROR);
74 s = item->target.s;
75 wl = item->target.wl;
76 w = wl->window;
77 wp = item->target.wp;
78
79 if (args_has(args, 'r'))
80 c->flags ^= CLIENT_READONLY;
81
82 tablename = args_get(args, 'T');
83 if (tablename != NULL) {
84 table = key_bindings_get_table(tablename, 0);
85 if (table == NULL) {
86 cmdq_error(item, "table %s doesn't exist", tablename);
87 return (CMD_RETURN_ERROR);
88 }
89 table->references++;
90 key_bindings_unref_table(c->keytable);
91 c->keytable = table;
92 return (CMD_RETURN_NORMAL);
93 }
94
95 if (args_has(args, 'n')) {
96 if ((s = session_next_session(c->session)) == NULL) {
97 cmdq_error(item, "can't find next session");
98 return (CMD_RETURN_ERROR);
99 }
100 } else if (args_has(args, 'p')) {
101 if ((s = session_previous_session(c->session)) == NULL) {
102 cmdq_error(item, "can't find previous session");
103 return (CMD_RETURN_ERROR);
104 }
105 } else if (args_has(args, 'l')) {
106 if (c->last_session != NULL && session_alive(c->last_session))
107 s = c->last_session;
108 else
109 s = NULL;
110 if (s == NULL) {
111 cmdq_error(item, "can't find last session");
112 return (CMD_RETURN_ERROR);
113 }
114 } else {
115 if (item->client == NULL)
116 return (CMD_RETURN_NORMAL);
117 if (wl != NULL && wp != NULL) {
118 if (window_push_zoom(w, args_has(self->args, 'Z')))
119 server_redraw_window(w);
120 window_redraw_active_switch(w, wp);
121 window_set_active_pane(w, wp, 1);
122 if (window_pop_zoom(w))
123 server_redraw_window(w);
124 }
125 if (wl != NULL) {
126 session_set_current(s, wl);
127 cmd_find_from_session(&item->shared->current, s, 0);
128 }
129 }
130
131 if (!args_has(args, 'E'))
132 environ_update(s->options, c->environ, s->environ);
133
134 if (c->session != NULL && c->session != s)
135 c->last_session = c->session;
136 c->session = s;
137 if (~item->shared->flags & CMDQ_SHARED_REPEAT)
138 server_client_set_key_table(c, NULL);
139 tty_update_client_offset(c);
140 status_timer_start(c);
141 notify_client("client-session-changed", c);
142 session_update_activity(s, NULL);
143 gettimeofday(&s->last_attached_time, NULL);
144
145 server_check_unattached();
146 server_redraw_client(c);
147 s->curw->flags &= ~WINLINK_ALERTFLAGS;
148 s->curw->window->latest = c;
149 recalculate_sizes();
150 alerts_check_session(s);
151
152 return (CMD_RETURN_NORMAL);
153}
154