Annotation of src/usr.bin/tmux/control-notify.c, Revision 1.26
1.26 ! nicm 1: /* $OpenBSD: control-notify.c,v 1.25 2019/12/12 11:39:56 nicm Exp $ */
1.1 nicm 2:
3: /*
1.16 nicm 4: * Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1 nicm 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:
1.12 nicm 22: #include <stdlib.h>
23:
1.1 nicm 24: #include "tmux.h"
25:
26: #define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
27: ((c) != NULL && ((c)->flags & CLIENT_CONTROL))
1.2 nicm 28:
29: void
30: control_notify_input(struct client *c, struct window_pane *wp,
1.23 nicm 31: const u_char *buf, size_t len)
1.2 nicm 32: {
33: struct evbuffer *message;
34: u_int i;
35:
36: if (c->session == NULL)
37: return;
1.24 nicm 38:
39: if (c->flags & CLIENT_CONTROL_NOOUTPUT)
40: return;
1.2 nicm 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();
1.22 nicm 48: if (message == NULL)
49: fatalx("out of memory");
1.7 nicm 50: evbuffer_add_printf(message, "%%output %%%u ", wp->id);
1.6 nicm 51: for (i = 0; i < len; i++) {
52: if (buf[i] < ' ' || buf[i] == '\\')
53: evbuffer_add_printf(message, "\\%03o", buf[i]);
54: else
55: evbuffer_add_printf(message, "%c", buf[i]);
56: }
1.26 ! nicm 57: evbuffer_add(message, "", 1);
1.25 nicm 58: control_write(c, "%s", EVBUFFER_DATA(message));
1.2 nicm 59: evbuffer_free(message);
60: }
61: }
1.1 nicm 62:
63: void
1.21 nicm 64: control_notify_pane_mode_changed(int pane)
65: {
66: struct client *c;
67:
68: TAILQ_FOREACH(c, &clients, entry) {
69: if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
70: continue;
71:
72: control_write(c, "%%pane-mode-changed %%%u", pane);
73: }
74: }
75:
76: void
1.1 nicm 77: control_notify_window_layout_changed(struct window *w)
78: {
1.21 nicm 79: struct client *c;
80: struct session *s;
81: struct winlink *wl;
82: const char *template;
83: char *cp;
1.12 nicm 84:
85: template = "%layout-change #{window_id} #{window_layout} "
86: "#{window_visible_layout} #{window_flags}";
1.1 nicm 87:
1.11 nicm 88: TAILQ_FOREACH(c, &clients, entry) {
1.1 nicm 89: if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
90: continue;
91: s = c->session;
92:
93: if (winlink_find_by_window_id(&s->windows, w->id) == NULL)
94: continue;
95:
96: /*
97: * When the last pane in a window is closed it won't have a
98: * layout root and we don't need to inform the client about the
99: * layout change because the whole window will go away soon.
100: */
101: if (w->layout_root == NULL)
102: continue;
103:
104: wl = winlink_find_by_window(&s->windows, w);
105: if (wl != NULL) {
1.20 nicm 106: cp = format_single(NULL, template, c, NULL, wl, NULL);
107: control_write(c, "%s", cp);
108: free(cp);
1.1 nicm 109: }
110: }
111: }
112:
113: void
1.21 nicm 114: control_notify_window_pane_changed(struct window *w)
115: {
116: struct client *c;
117:
118: TAILQ_FOREACH(c, &clients, entry) {
119: if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
120: continue;
121:
122: control_write(c, "%%window-pane-changed @%u %%%u", w->id,
123: w->active->id);
124: }
125: }
126:
127: void
1.13 nicm 128: control_notify_window_unlinked(__unused struct session *s, struct window *w)
1.1 nicm 129: {
130: struct client *c;
1.9 nicm 131: struct session *cs;
1.1 nicm 132:
1.11 nicm 133: TAILQ_FOREACH(c, &clients, entry) {
1.1 nicm 134: if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
135: continue;
1.9 nicm 136: cs = c->session;
1.1 nicm 137:
1.9 nicm 138: if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
139: control_write(c, "%%window-close @%u", w->id);
140: else
141: control_write(c, "%%unlinked-window-close @%u", w->id);
1.1 nicm 142: }
143: }
144:
145: void
1.13 nicm 146: control_notify_window_linked(__unused struct session *s, struct window *w)
1.1 nicm 147: {
148: struct client *c;
149: struct session *cs;
150:
1.11 nicm 151: TAILQ_FOREACH(c, &clients, entry) {
1.1 nicm 152: if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
153: continue;
154: cs = c->session;
155:
156: if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
1.7 nicm 157: control_write(c, "%%window-add @%u", w->id);
1.1 nicm 158: else
1.7 nicm 159: control_write(c, "%%unlinked-window-add @%u", w->id);
1.1 nicm 160: }
161: }
162:
163: void
164: control_notify_window_renamed(struct window *w)
165: {
166: struct client *c;
1.9 nicm 167: struct session *cs;
1.1 nicm 168:
1.11 nicm 169: TAILQ_FOREACH(c, &clients, entry) {
1.1 nicm 170: if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
171: continue;
1.9 nicm 172: cs = c->session;
1.1 nicm 173:
1.9 nicm 174: if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) {
175: control_write(c, "%%window-renamed @%u %s", w->id,
176: w->name);
177: } else {
178: control_write(c, "%%unlinked-window-renamed @%u %s",
179: w->id, w->name);
180: }
1.1 nicm 181: }
182: }
183:
184: void
1.21 nicm 185: control_notify_client_session_changed(struct client *cc)
1.1 nicm 186: {
1.21 nicm 187: struct client *c;
1.1 nicm 188: struct session *s;
189:
1.21 nicm 190: if (cc->session == NULL)
1.1 nicm 191: return;
1.21 nicm 192: s = cc->session;
1.1 nicm 193:
1.21 nicm 194: TAILQ_FOREACH(c, &clients, entry) {
195: if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
196: continue;
197:
198: if (cc == c) {
199: control_write(c, "%%session-changed $%u %s", s->id,
200: s->name);
201: } else {
202: control_write(c, "%%client-session-changed %s $%u %s",
203: cc->name, s->id, s->name);
204: }
205: }
1.1 nicm 206: }
207:
208: void
209: control_notify_session_renamed(struct session *s)
210: {
211: struct client *c;
212:
1.11 nicm 213: TAILQ_FOREACH(c, &clients, entry) {
1.7 nicm 214: if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
1.1 nicm 215: continue;
216:
1.7 nicm 217: control_write(c, "%%session-renamed $%u %s", s->id, s->name);
1.1 nicm 218: }
219: }
220:
221: void
1.13 nicm 222: control_notify_session_created(__unused struct session *s)
1.1 nicm 223: {
224: struct client *c;
225:
1.11 nicm 226: TAILQ_FOREACH(c, &clients, entry) {
1.7 nicm 227: if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
1.1 nicm 228: continue;
229:
230: control_write(c, "%%sessions-changed");
231: }
232: }
233:
234: void
1.17 nicm 235: control_notify_session_closed(__unused struct session *s)
1.1 nicm 236: {
237: struct client *c;
238:
1.11 nicm 239: TAILQ_FOREACH(c, &clients, entry) {
1.7 nicm 240: if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
1.1 nicm 241: continue;
242:
243: control_write(c, "%%sessions-changed");
1.21 nicm 244: }
245: }
246:
247: void
248: control_notify_session_window_changed(struct session *s)
249: {
250: struct client *c;
251:
252: TAILQ_FOREACH(c, &clients, entry) {
253: if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
254: continue;
255:
256: control_write(c, "%%session-window-changed $%u @%u", s->id,
257: s->curw->window->id);
1.1 nicm 258: }
259: }