1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
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 <stdlib.h>
23 
24 #include "tmux.h"
25 
26 #define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
27 	((c) != NULL && ((c)->flags & CLIENT_CONTROL))
28 
29 void
control_notify_pane_mode_changed(int pane)30 control_notify_pane_mode_changed(int pane)
31 {
32 	struct client	*c;
33 
34 	TAILQ_FOREACH(c, &clients, entry) {
35 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
36 			continue;
37 
38 		control_write(c, "%%pane-mode-changed %%%u", pane);
39 	}
40 }
41 
42 void
control_notify_window_layout_changed(struct window * w)43 control_notify_window_layout_changed(struct window *w)
44 {
45 	struct client	*c;
46 	struct session	*s;
47 	struct winlink	*wl;
48 	const char	*template;
49 	char		*cp;
50 
51 	template = "%layout-change #{window_id} #{window_layout} "
52 	    "#{window_visible_layout} #{window_raw_flags}";
53 
54 	TAILQ_FOREACH(c, &clients, entry) {
55 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
56 			continue;
57 		s = c->session;
58 
59 		if (winlink_find_by_window_id(&s->windows, w->id) == NULL)
60 			continue;
61 
62 		/*
63 		 * When the last pane in a window is closed it won't have a
64 		 * layout root and we don't need to inform the client about the
65 		 * layout change because the whole window will go away soon.
66 		 */
67 		if (w->layout_root == NULL)
68 			continue;
69 
70 		wl = winlink_find_by_window(&s->windows, w);
71 		if (wl != NULL) {
72 			cp = format_single(NULL, template, c, NULL, wl, NULL);
73 			control_write(c, "%s", cp);
74 			free(cp);
75 		}
76 	}
77 }
78 
79 void
control_notify_window_pane_changed(struct window * w)80 control_notify_window_pane_changed(struct window *w)
81 {
82 	struct client	*c;
83 
84 	TAILQ_FOREACH(c, &clients, entry) {
85 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
86 			continue;
87 
88 		control_write(c, "%%window-pane-changed @%u %%%u", w->id,
89 		    w->active->id);
90 	}
91 }
92 
93 void
control_notify_window_unlinked(__unused struct session * s,struct window * w)94 control_notify_window_unlinked(__unused struct session *s, struct window *w)
95 {
96 	struct client	*c;
97 	struct session	*cs;
98 
99 	TAILQ_FOREACH(c, &clients, entry) {
100 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
101 			continue;
102 		cs = c->session;
103 
104 		if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
105 			control_write(c, "%%window-close @%u", w->id);
106 		else
107 			control_write(c, "%%unlinked-window-close @%u", w->id);
108 	}
109 }
110 
111 void
control_notify_window_linked(__unused struct session * s,struct window * w)112 control_notify_window_linked(__unused struct session *s, struct window *w)
113 {
114 	struct client	*c;
115 	struct session	*cs;
116 
117 	TAILQ_FOREACH(c, &clients, entry) {
118 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
119 			continue;
120 		cs = c->session;
121 
122 		if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
123 			control_write(c, "%%window-add @%u", w->id);
124 		else
125 			control_write(c, "%%unlinked-window-add @%u", w->id);
126 	}
127 }
128 
129 void
control_notify_window_renamed(struct window * w)130 control_notify_window_renamed(struct window *w)
131 {
132 	struct client	*c;
133 	struct session	*cs;
134 
135 	TAILQ_FOREACH(c, &clients, entry) {
136 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
137 			continue;
138 		cs = c->session;
139 
140 		if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) {
141 			control_write(c, "%%window-renamed @%u %s", w->id,
142 			    w->name);
143 		} else {
144 			control_write(c, "%%unlinked-window-renamed @%u %s",
145 			    w->id, w->name);
146 		}
147 	}
148 }
149 
150 void
control_notify_client_session_changed(struct client * cc)151 control_notify_client_session_changed(struct client *cc)
152 {
153 	struct client	*c;
154 	struct session	*s;
155 
156 	if (cc->session == NULL)
157 		return;
158 	s = cc->session;
159 
160 	TAILQ_FOREACH(c, &clients, entry) {
161 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
162 			continue;
163 
164 		if (cc == c) {
165 			control_write(c, "%%session-changed $%u %s", s->id,
166 			    s->name);
167 		} else {
168 			control_write(c, "%%client-session-changed %s $%u %s",
169 			    cc->name, s->id, s->name);
170 		}
171 	}
172 }
173 
174 void
control_notify_client_detached(struct client * cc)175 control_notify_client_detached(struct client *cc)
176 {
177 	struct client	*c;
178 
179 	TAILQ_FOREACH(c, &clients, entry) {
180 		if (CONTROL_SHOULD_NOTIFY_CLIENT(c))
181 			control_write(c, "%%client-detached %s", cc->name);
182 	}
183 }
184 
185 void
control_notify_session_renamed(struct session * s)186 control_notify_session_renamed(struct session *s)
187 {
188 	struct client	*c;
189 
190 	TAILQ_FOREACH(c, &clients, entry) {
191 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
192 			continue;
193 
194 		control_write(c, "%%session-renamed $%u %s", s->id, s->name);
195 	}
196 }
197 
198 void
control_notify_session_created(__unused struct session * s)199 control_notify_session_created(__unused struct session *s)
200 {
201 	struct client	*c;
202 
203 	TAILQ_FOREACH(c, &clients, entry) {
204 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
205 			continue;
206 
207 		control_write(c, "%%sessions-changed");
208 	}
209 }
210 
211 void
control_notify_session_closed(__unused struct session * s)212 control_notify_session_closed(__unused struct session *s)
213 {
214 	struct client	*c;
215 
216 	TAILQ_FOREACH(c, &clients, entry) {
217 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
218 			continue;
219 
220 		control_write(c, "%%sessions-changed");
221 	}
222 }
223 
224 void
control_notify_session_window_changed(struct session * s)225 control_notify_session_window_changed(struct session *s)
226 {
227 	struct client	*c;
228 
229 	TAILQ_FOREACH(c, &clients, entry) {
230 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
231 			continue;
232 
233 		control_write(c, "%%session-window-changed $%u @%u", s->id,
234 		    s->curw->window->id);
235 	}
236 }
237