control-notify.c revision 1.7
1/* $OpenBSD: control-notify.c,v 1.7 2013/03/25 11:40:54 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_winlink(ft, c->session, wl);
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		control_write(c, "%%window-close @%u", w->id);
112	}
113}
114
115void
116control_notify_window_linked(unused struct session *s, struct window *w)
117{
118	struct client	*c;
119	struct session	*cs;
120	u_int		 i;
121
122	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
123		c = ARRAY_ITEM(&clients, i);
124		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
125			continue;
126		cs = c->session;
127
128		if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
129			control_write(c, "%%window-add @%u", w->id);
130		else
131			control_write(c, "%%unlinked-window-add @%u", w->id);
132	}
133}
134
135void
136control_notify_window_renamed(struct window *w)
137{
138	struct client	*c;
139	struct session	*s;
140	u_int		 i;
141
142	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
143		c = ARRAY_ITEM(&clients, i);
144		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
145			continue;
146		s = c->session;
147
148		control_write(c, "%%window-renamed @%u %s", w->id, w->name);
149	}
150}
151
152void
153control_notify_attached_session_changed(struct client *c)
154{
155	struct session	*s;
156
157	if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
158		return;
159	s = c->session;
160
161	control_write(c, "%%session-changed $%u %s", s->id, s->name);
162}
163
164void
165control_notify_session_renamed(struct session *s)
166{
167	struct client	*c;
168	u_int		 i;
169
170	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
171		c = ARRAY_ITEM(&clients, i);
172		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
173			continue;
174
175		control_write(c, "%%session-renamed $%u %s", s->id, s->name);
176	}
177}
178
179void
180control_notify_session_created(unused struct session *s)
181{
182	struct client	*c;
183	u_int		 i;
184
185	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
186		c = ARRAY_ITEM(&clients, i);
187		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
188			continue;
189
190		control_write(c, "%%sessions-changed");
191	}
192}
193
194void
195control_notify_session_close(unused struct session *s)
196{
197	struct client	*c;
198	u_int		 i;
199
200	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
201		c = ARRAY_ITEM(&clients, i);
202		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
203			continue;
204
205		control_write(c, "%%sessions-changed");
206	}
207}
208