control-notify.c revision 1.29
1/* $OpenBSD: control-notify.c,v 1.29 2021/03/16 09:14:58 nicm Exp $ */
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
29void
30control_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
42void
43control_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
79void
80control_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
93void
94control_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
111void
112control_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
129void
130control_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
150void
151control_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
174void
175control_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
185void
186control_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
198void
199control_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
211void
212control_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
224void
225control_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