xref: /minix/external/bsd/tmux/dist/control-notify.c (revision 0a6a1f1d)
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