xref: /openbsd-src/usr.bin/tmux/control-notify.c (revision 48950c12d106c85f315112191a0228d7b83b9510)
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 
27 void
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
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
99 control_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 
115 void
116 control_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 
135 void
136 control_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 
152 void
153 control_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 
164 void
165 control_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 
179 void
180 control_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 
194 void
195 control_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