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