xref: /openbsd-src/usr.bin/tmux/control-notify.c (revision 6f05df2d9be0954bec42d51d943d77bd250fb664)
1 /* $OpenBSD: control-notify.c,v 1.9 2014/04/23 10:14:29 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 		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 
118 void
119 control_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 
138 void
139 control_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 
161 void
162 control_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 
173 void
174 control_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 
188 void
189 control_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 
203 void
204 control_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