1 /* $OpenBSD: control-notify.c,v 1.11 2015/04/24 23:17:11 nicm Exp $ */ 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 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 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 const char *template; 68 69 TAILQ_FOREACH(c, &clients, entry) { 70 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 71 continue; 72 s = c->session; 73 74 if (winlink_find_by_window_id(&s->windows, w->id) == NULL) 75 continue; 76 77 /* 78 * When the last pane in a window is closed it won't have a 79 * layout root and we don't need to inform the client about the 80 * layout change because the whole window will go away soon. 81 */ 82 if (w->layout_root == NULL) 83 continue; 84 template = "%layout-change #{window_id} #{window_layout}"; 85 86 ft = format_create(); 87 wl = winlink_find_by_window(&s->windows, w); 88 if (wl != NULL) { 89 format_defaults(ft, c, NULL, wl, NULL); 90 control_write(c, "%s", format_expand(ft, template)); 91 } 92 format_free(ft); 93 } 94 } 95 96 void 97 control_notify_window_unlinked(unused struct session *s, struct window *w) 98 { 99 struct client *c; 100 struct session *cs; 101 102 TAILQ_FOREACH(c, &clients, entry) { 103 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 104 continue; 105 cs = c->session; 106 107 if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) 108 control_write(c, "%%window-close @%u", w->id); 109 else 110 control_write(c, "%%unlinked-window-close @%u", w->id); 111 } 112 } 113 114 void 115 control_notify_window_linked(unused struct session *s, struct window *w) 116 { 117 struct client *c; 118 struct session *cs; 119 120 TAILQ_FOREACH(c, &clients, entry) { 121 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 122 continue; 123 cs = c->session; 124 125 if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) 126 control_write(c, "%%window-add @%u", w->id); 127 else 128 control_write(c, "%%unlinked-window-add @%u", w->id); 129 } 130 } 131 132 void 133 control_notify_window_renamed(struct window *w) 134 { 135 struct client *c; 136 struct session *cs; 137 138 TAILQ_FOREACH(c, &clients, entry) { 139 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 140 continue; 141 cs = c->session; 142 143 if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) { 144 control_write(c, "%%window-renamed @%u %s", w->id, 145 w->name); 146 } else { 147 control_write(c, "%%unlinked-window-renamed @%u %s", 148 w->id, w->name); 149 } 150 } 151 } 152 153 void 154 control_notify_attached_session_changed(struct client *c) 155 { 156 struct session *s; 157 158 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 159 return; 160 s = c->session; 161 162 control_write(c, "%%session-changed $%u %s", s->id, s->name); 163 } 164 165 void 166 control_notify_session_renamed(struct session *s) 167 { 168 struct client *c; 169 170 TAILQ_FOREACH(c, &clients, entry) { 171 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) 172 continue; 173 174 control_write(c, "%%session-renamed $%u %s", s->id, s->name); 175 } 176 } 177 178 void 179 control_notify_session_created(unused struct session *s) 180 { 181 struct client *c; 182 183 TAILQ_FOREACH(c, &clients, entry) { 184 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) 185 continue; 186 187 control_write(c, "%%sessions-changed"); 188 } 189 } 190 191 void 192 control_notify_session_close(unused struct session *s) 193 { 194 struct client *c; 195 196 TAILQ_FOREACH(c, &clients, entry) { 197 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) 198 continue; 199 200 control_write(c, "%%sessions-changed"); 201 } 202 } 203