1 /* $OpenBSD$ */
2
3 /*
4 * Copyright (c) 2012 Nicholas Marriott <nicm@users.sourceforge.net>
5 * Copyright (c) 2012 George Nachman <tmux@georgester.com>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/types.h>
21
22 #include "tmux.h"
23
24 #define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
25 ((c) != NULL && ((c)->flags & CLIENT_CONTROL))
26
27 void
control_notify_input(struct client * c,struct window_pane * wp,struct evbuffer * input)28 control_notify_input(struct client *c, struct window_pane *wp,
29 struct evbuffer *input)
30 {
31 u_char *buf;
32 size_t len;
33 struct evbuffer *message;
34 u_int i;
35
36 if (c->session == NULL)
37 return;
38
39 buf = EVBUFFER_DATA(input);
40 len = EVBUFFER_LENGTH(input);
41
42 /*
43 * Only write input if the window pane is linked to a window belonging
44 * to the client's session.
45 */
46 if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) {
47 message = evbuffer_new();
48 evbuffer_add_printf(message, "%%output %%%u ", wp->id);
49 for (i = 0; i < len; i++) {
50 if (buf[i] < ' ' || buf[i] == '\\')
51 evbuffer_add_printf(message, "\\%03o", buf[i]);
52 else
53 evbuffer_add_printf(message, "%c", buf[i]);
54 }
55 control_write_buffer(c, message);
56 evbuffer_free(message);
57 }
58 }
59
60 void
control_notify_window_layout_changed(struct window * w)61 control_notify_window_layout_changed(struct window *w)
62 {
63 struct client *c;
64 struct session *s;
65 struct format_tree *ft;
66 struct winlink *wl;
67 u_int i;
68 const char *template;
69
70 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
71 c = ARRAY_ITEM(&clients, i);
72 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
73 continue;
74 s = c->session;
75
76 if (winlink_find_by_window_id(&s->windows, w->id) == NULL)
77 continue;
78
79 /*
80 * When the last pane in a window is closed it won't have a
81 * layout root and we don't need to inform the client about the
82 * layout change because the whole window will go away soon.
83 */
84 if (w->layout_root == NULL)
85 continue;
86 template = "%layout-change #{window_id} #{window_layout}";
87
88 ft = format_create();
89 wl = winlink_find_by_window(&s->windows, w);
90 if (wl != NULL) {
91 format_winlink(ft, c->session, wl);
92 control_write(c, "%s", format_expand(ft, template));
93 }
94 format_free(ft);
95 }
96 }
97
98 void
control_notify_window_unlinked(unused struct session * s,struct window * w)99 control_notify_window_unlinked(unused struct session *s, struct window *w)
100 {
101 struct client *c;
102 u_int i;
103
104 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
105 c = ARRAY_ITEM(&clients, i);
106 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
107 continue;
108
109 control_write(c, "%%window-close @%u", w->id);
110 }
111 }
112
113 void
control_notify_window_linked(unused struct session * s,struct window * w)114 control_notify_window_linked(unused struct session *s, struct window *w)
115 {
116 struct client *c;
117 struct session *cs;
118 u_int i;
119
120 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
121 c = ARRAY_ITEM(&clients, i);
122 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
123 continue;
124 cs = c->session;
125
126 if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
127 control_write(c, "%%window-add @%u", w->id);
128 else
129 control_write(c, "%%unlinked-window-add @%u", w->id);
130 }
131 }
132
133 void
control_notify_window_renamed(struct window * w)134 control_notify_window_renamed(struct window *w)
135 {
136 struct client *c;
137 u_int i;
138
139 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
140 c = ARRAY_ITEM(&clients, i);
141 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
142 continue;
143
144 control_write(c, "%%window-renamed @%u %s", w->id, w->name);
145 }
146 }
147
148 void
control_notify_attached_session_changed(struct client * c)149 control_notify_attached_session_changed(struct client *c)
150 {
151 struct session *s;
152
153 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
154 return;
155 s = c->session;
156
157 control_write(c, "%%session-changed $%u %s", s->id, s->name);
158 }
159
160 void
control_notify_session_renamed(struct session * s)161 control_notify_session_renamed(struct session *s)
162 {
163 struct client *c;
164 u_int i;
165
166 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
167 c = ARRAY_ITEM(&clients, i);
168 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
169 continue;
170
171 control_write(c, "%%session-renamed $%u %s", s->id, s->name);
172 }
173 }
174
175 void
control_notify_session_created(unused struct session * s)176 control_notify_session_created(unused struct session *s)
177 {
178 struct client *c;
179 u_int i;
180
181 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
182 c = ARRAY_ITEM(&clients, i);
183 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
184 continue;
185
186 control_write(c, "%%sessions-changed");
187 }
188 }
189
190 void
control_notify_session_close(unused struct session * s)191 control_notify_session_close(unused struct session *s)
192 {
193 struct client *c;
194 u_int i;
195
196 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
197 c = ARRAY_ITEM(&clients, i);
198 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
199 continue;
200
201 control_write(c, "%%sessions-changed");
202 }
203 }
204