control-notify.c revision 1.10
1/* $OpenBSD: control-notify.c,v 1.10 2015/02/05 10:29:43 nicm Exp $ */
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
27void
28control_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
60void
61control_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_defaults(ft, c, NULL, wl, NULL);
92			control_write(c, "%s", format_expand(ft, template));
93		}
94		format_free(ft);
95	}
96}
97
98void
99control_notify_window_unlinked(unused struct session *s, struct window *w)
100{
101	struct client	*c;
102	struct session	*cs;
103	u_int		 i;
104
105	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
106		c = ARRAY_ITEM(&clients, i);
107		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
108			continue;
109		cs = c->session;
110
111		if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
112			control_write(c, "%%window-close @%u", w->id);
113		else
114			control_write(c, "%%unlinked-window-close @%u", w->id);
115	}
116}
117
118void
119control_notify_window_linked(unused struct session *s, struct window *w)
120{
121	struct client	*c;
122	struct session	*cs;
123	u_int		 i;
124
125	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
126		c = ARRAY_ITEM(&clients, i);
127		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
128			continue;
129		cs = c->session;
130
131		if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
132			control_write(c, "%%window-add @%u", w->id);
133		else
134			control_write(c, "%%unlinked-window-add @%u", w->id);
135	}
136}
137
138void
139control_notify_window_renamed(struct window *w)
140{
141	struct client	*c;
142	struct session	*cs;
143	u_int		 i;
144
145	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
146		c = ARRAY_ITEM(&clients, i);
147		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
148			continue;
149		cs = c->session;
150
151		if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) {
152			control_write(c, "%%window-renamed @%u %s", w->id,
153			    w->name);
154		} else {
155			control_write(c, "%%unlinked-window-renamed @%u %s",
156			    w->id, w->name);
157		}
158	}
159}
160
161void
162control_notify_attached_session_changed(struct client *c)
163{
164	struct session	*s;
165
166	if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
167		return;
168	s = c->session;
169
170	control_write(c, "%%session-changed $%u %s", s->id, s->name);
171}
172
173void
174control_notify_session_renamed(struct session *s)
175{
176	struct client	*c;
177	u_int		 i;
178
179	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
180		c = ARRAY_ITEM(&clients, i);
181		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
182			continue;
183
184		control_write(c, "%%session-renamed $%u %s", s->id, s->name);
185	}
186}
187
188void
189control_notify_session_created(unused struct session *s)
190{
191	struct client	*c;
192	u_int		 i;
193
194	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
195		c = ARRAY_ITEM(&clients, i);
196		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
197			continue;
198
199		control_write(c, "%%sessions-changed");
200	}
201}
202
203void
204control_notify_session_close(unused struct session *s)
205{
206	struct client	*c;
207	u_int		 i;
208
209	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
210		c = ARRAY_ITEM(&clients, i);
211		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
212			continue;
213
214		control_write(c, "%%sessions-changed");
215	}
216}
217