xref: /openbsd-src/usr.bin/tmux/control-notify.c (revision 99acee14adedf06a250aaae2661fad6eb8f61e88)
1*99acee14Snicm /* $OpenBSD: control-notify.c,v 1.31 2022/10/28 13:00:02 nicm Exp $ */
2d5dd2023Snicm 
3d5dd2023Snicm /*
498ca8272Snicm  * Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
5d5dd2023Snicm  * Copyright (c) 2012 George Nachman <tmux@georgester.com>
6d5dd2023Snicm  *
7d5dd2023Snicm  * Permission to use, copy, modify, and distribute this software for any
8d5dd2023Snicm  * purpose with or without fee is hereby granted, provided that the above
9d5dd2023Snicm  * copyright notice and this permission notice appear in all copies.
10d5dd2023Snicm  *
11d5dd2023Snicm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12d5dd2023Snicm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13d5dd2023Snicm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14d5dd2023Snicm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15d5dd2023Snicm  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16d5dd2023Snicm  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17d5dd2023Snicm  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18d5dd2023Snicm  */
19d5dd2023Snicm 
20d5dd2023Snicm #include <sys/types.h>
21d5dd2023Snicm 
2278f99b37Snicm #include <stdlib.h>
2378f99b37Snicm 
24d5dd2023Snicm #include "tmux.h"
25d5dd2023Snicm 
26d5dd2023Snicm #define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
27d5dd2023Snicm 	((c) != NULL && ((c)->flags & CLIENT_CONTROL))
28d5dd2023Snicm 
29d5dd2023Snicm void
control_notify_pane_mode_changed(int pane)303c14ce20Snicm control_notify_pane_mode_changed(int pane)
313c14ce20Snicm {
323c14ce20Snicm 	struct client	*c;
333c14ce20Snicm 
343c14ce20Snicm 	TAILQ_FOREACH(c, &clients, entry) {
353c14ce20Snicm 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
363c14ce20Snicm 			continue;
373c14ce20Snicm 
383c14ce20Snicm 		control_write(c, "%%pane-mode-changed %%%u", pane);
393c14ce20Snicm 	}
403c14ce20Snicm }
413c14ce20Snicm 
423c14ce20Snicm void
control_notify_window_layout_changed(struct window * w)43d5dd2023Snicm control_notify_window_layout_changed(struct window *w)
44d5dd2023Snicm {
45d5dd2023Snicm 	struct client	*c;
46d5dd2023Snicm 	struct session	*s;
47d5dd2023Snicm 	struct winlink	*wl;
48d5dd2023Snicm 	const char	*template;
49e35be1bbSnicm 	char		*cp;
5078f99b37Snicm 
5178f99b37Snicm 	template = "%layout-change #{window_id} #{window_layout} "
52b1a38154Snicm 	    "#{window_visible_layout} #{window_raw_flags}";
53d5dd2023Snicm 
5482873134Snicm 	TAILQ_FOREACH(c, &clients, entry) {
55d5dd2023Snicm 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
56d5dd2023Snicm 			continue;
57d5dd2023Snicm 		s = c->session;
58d5dd2023Snicm 
59d5dd2023Snicm 		if (winlink_find_by_window_id(&s->windows, w->id) == NULL)
60d5dd2023Snicm 			continue;
61d5dd2023Snicm 
62d5dd2023Snicm 		/*
63d5dd2023Snicm 		 * When the last pane in a window is closed it won't have a
64d5dd2023Snicm 		 * layout root and we don't need to inform the client about the
65d5dd2023Snicm 		 * layout change because the whole window will go away soon.
66d5dd2023Snicm 		 */
67d5dd2023Snicm 		if (w->layout_root == NULL)
68d5dd2023Snicm 			continue;
69d5dd2023Snicm 
70d5dd2023Snicm 		wl = winlink_find_by_window(&s->windows, w);
71d5dd2023Snicm 		if (wl != NULL) {
72e35be1bbSnicm 			cp = format_single(NULL, template, c, NULL, wl, NULL);
73e35be1bbSnicm 			control_write(c, "%s", cp);
74e35be1bbSnicm 			free(cp);
75d5dd2023Snicm 		}
76d5dd2023Snicm 	}
77d5dd2023Snicm }
78d5dd2023Snicm 
79d5dd2023Snicm void
control_notify_window_pane_changed(struct window * w)803c14ce20Snicm control_notify_window_pane_changed(struct window *w)
813c14ce20Snicm {
823c14ce20Snicm 	struct client	*c;
833c14ce20Snicm 
843c14ce20Snicm 	TAILQ_FOREACH(c, &clients, entry) {
853c14ce20Snicm 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
863c14ce20Snicm 			continue;
873c14ce20Snicm 
883c14ce20Snicm 		control_write(c, "%%window-pane-changed @%u %%%u", w->id,
893c14ce20Snicm 		    w->active->id);
903c14ce20Snicm 	}
913c14ce20Snicm }
923c14ce20Snicm 
933c14ce20Snicm void
control_notify_window_unlinked(__unused struct session * s,struct window * w)94d0e2e7f1Snicm control_notify_window_unlinked(__unused struct session *s, struct window *w)
95d5dd2023Snicm {
96d5dd2023Snicm 	struct client	*c;
973e8f9303Snicm 	struct session	*cs;
98d5dd2023Snicm 
9982873134Snicm 	TAILQ_FOREACH(c, &clients, entry) {
100d5dd2023Snicm 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
101d5dd2023Snicm 			continue;
1023e8f9303Snicm 		cs = c->session;
103d5dd2023Snicm 
1043e8f9303Snicm 		if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
1059eac9144Snicm 			control_write(c, "%%window-close @%u", w->id);
1063e8f9303Snicm 		else
1073e8f9303Snicm 			control_write(c, "%%unlinked-window-close @%u", w->id);
108d5dd2023Snicm 	}
109d5dd2023Snicm }
110d5dd2023Snicm 
111d5dd2023Snicm void
control_notify_window_linked(__unused struct session * s,struct window * w)112d0e2e7f1Snicm control_notify_window_linked(__unused struct session *s, struct window *w)
113d5dd2023Snicm {
114d5dd2023Snicm 	struct client	*c;
115d5dd2023Snicm 	struct session	*cs;
116d5dd2023Snicm 
11782873134Snicm 	TAILQ_FOREACH(c, &clients, entry) {
118d5dd2023Snicm 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
119d5dd2023Snicm 			continue;
120d5dd2023Snicm 		cs = c->session;
121d5dd2023Snicm 
122d5dd2023Snicm 		if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
1239eac9144Snicm 			control_write(c, "%%window-add @%u", w->id);
124d5dd2023Snicm 		else
1259eac9144Snicm 			control_write(c, "%%unlinked-window-add @%u", w->id);
126d5dd2023Snicm 	}
127d5dd2023Snicm }
128d5dd2023Snicm 
129d5dd2023Snicm void
control_notify_window_renamed(struct window * w)130d5dd2023Snicm control_notify_window_renamed(struct window *w)
131d5dd2023Snicm {
132d5dd2023Snicm 	struct client	*c;
1333e8f9303Snicm 	struct session	*cs;
134d5dd2023Snicm 
13582873134Snicm 	TAILQ_FOREACH(c, &clients, entry) {
136d5dd2023Snicm 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
137d5dd2023Snicm 			continue;
1383e8f9303Snicm 		cs = c->session;
139d5dd2023Snicm 
1403e8f9303Snicm 		if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) {
1413e8f9303Snicm 			control_write(c, "%%window-renamed @%u %s", w->id,
1423e8f9303Snicm 			    w->name);
1433e8f9303Snicm 		} else {
1443e8f9303Snicm 			control_write(c, "%%unlinked-window-renamed @%u %s",
1453e8f9303Snicm 			    w->id, w->name);
1463e8f9303Snicm 		}
147d5dd2023Snicm 	}
148d5dd2023Snicm }
149d5dd2023Snicm 
150d5dd2023Snicm void
control_notify_client_session_changed(struct client * cc)1513c14ce20Snicm control_notify_client_session_changed(struct client *cc)
152d5dd2023Snicm {
1533c14ce20Snicm 	struct client	*c;
154d5dd2023Snicm 	struct session	*s;
155d5dd2023Snicm 
1563c14ce20Snicm 	if (cc->session == NULL)
157d5dd2023Snicm 		return;
1583c14ce20Snicm 	s = cc->session;
159d5dd2023Snicm 
1603c14ce20Snicm 	TAILQ_FOREACH(c, &clients, entry) {
1613c14ce20Snicm 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
1623c14ce20Snicm 			continue;
1633c14ce20Snicm 
1643c14ce20Snicm 		if (cc == c) {
1653c14ce20Snicm 			control_write(c, "%%session-changed $%u %s", s->id,
1663c14ce20Snicm 			    s->name);
1673c14ce20Snicm 		} else {
1683c14ce20Snicm 			control_write(c, "%%client-session-changed %s $%u %s",
1693c14ce20Snicm 			    cc->name, s->id, s->name);
1703c14ce20Snicm 		}
1713c14ce20Snicm 	}
172d5dd2023Snicm }
173d5dd2023Snicm 
174d5dd2023Snicm void
control_notify_client_detached(struct client * cc)1752b1e50bbSnicm control_notify_client_detached(struct client *cc)
1762b1e50bbSnicm {
1772b1e50bbSnicm 	struct client	*c;
1782b1e50bbSnicm 
1792b1e50bbSnicm 	TAILQ_FOREACH(c, &clients, entry) {
1802b1e50bbSnicm 		if (CONTROL_SHOULD_NOTIFY_CLIENT(c))
1812b1e50bbSnicm 			control_write(c, "%%client-detached %s", cc->name);
1822b1e50bbSnicm 	}
1832b1e50bbSnicm }
1842b1e50bbSnicm 
1852b1e50bbSnicm void
control_notify_session_renamed(struct session * s)186d5dd2023Snicm control_notify_session_renamed(struct session *s)
187d5dd2023Snicm {
188d5dd2023Snicm 	struct client	*c;
189d5dd2023Snicm 
19082873134Snicm 	TAILQ_FOREACH(c, &clients, entry) {
1919eac9144Snicm 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
192d5dd2023Snicm 			continue;
193d5dd2023Snicm 
1949eac9144Snicm 		control_write(c, "%%session-renamed $%u %s", s->id, s->name);
195d5dd2023Snicm 	}
196d5dd2023Snicm }
197d5dd2023Snicm 
198d5dd2023Snicm void
control_notify_session_created(__unused struct session * s)199d0e2e7f1Snicm control_notify_session_created(__unused struct session *s)
200d5dd2023Snicm {
201d5dd2023Snicm 	struct client	*c;
202d5dd2023Snicm 
20382873134Snicm 	TAILQ_FOREACH(c, &clients, entry) {
2049eac9144Snicm 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
205d5dd2023Snicm 			continue;
206d5dd2023Snicm 
207d5dd2023Snicm 		control_write(c, "%%sessions-changed");
208d5dd2023Snicm 	}
209d5dd2023Snicm }
210d5dd2023Snicm 
211d5dd2023Snicm void
control_notify_session_closed(__unused struct session * s)21283f26c8fSnicm control_notify_session_closed(__unused struct session *s)
213d5dd2023Snicm {
214d5dd2023Snicm 	struct client	*c;
215d5dd2023Snicm 
21682873134Snicm 	TAILQ_FOREACH(c, &clients, entry) {
2179eac9144Snicm 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
218d5dd2023Snicm 			continue;
219d5dd2023Snicm 
220d5dd2023Snicm 		control_write(c, "%%sessions-changed");
221d5dd2023Snicm 	}
222d5dd2023Snicm }
2233c14ce20Snicm 
2243c14ce20Snicm void
control_notify_session_window_changed(struct session * s)2253c14ce20Snicm control_notify_session_window_changed(struct session *s)
2263c14ce20Snicm {
2273c14ce20Snicm 	struct client	*c;
2283c14ce20Snicm 
2293c14ce20Snicm 	TAILQ_FOREACH(c, &clients, entry) {
2303c14ce20Snicm 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
2313c14ce20Snicm 			continue;
2323c14ce20Snicm 
2333c14ce20Snicm 		control_write(c, "%%session-window-changed $%u @%u", s->id,
2343c14ce20Snicm 		    s->curw->window->id);
2353c14ce20Snicm 	}
2363c14ce20Snicm }
237d79e52f9Snicm 
238d79e52f9Snicm void
control_notify_paste_buffer_changed(const char * name)239d79e52f9Snicm control_notify_paste_buffer_changed(const char *name)
240d79e52f9Snicm {
241d79e52f9Snicm 	struct client	*c;
242d79e52f9Snicm 
243d79e52f9Snicm 	TAILQ_FOREACH(c, &clients, entry) {
244d79e52f9Snicm 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
245d79e52f9Snicm 			continue;
246d79e52f9Snicm 
247*99acee14Snicm 		control_write(c, "%%paste-buffer-changed %s", name);
248*99acee14Snicm 	}
249*99acee14Snicm }
250*99acee14Snicm 
251*99acee14Snicm void
control_notify_paste_buffer_deleted(const char * name)252*99acee14Snicm control_notify_paste_buffer_deleted(const char *name)
253*99acee14Snicm {
254*99acee14Snicm 	struct client	*c;
255*99acee14Snicm 
256*99acee14Snicm 	TAILQ_FOREACH(c, &clients, entry) {
257*99acee14Snicm 		if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
258*99acee14Snicm 			continue;
259*99acee14Snicm 
260*99acee14Snicm 		control_write(c, "%%paste-buffer-deleted %s", name);
261d79e52f9Snicm 	}
262d79e52f9Snicm }
263