control-notify.c revision 1.19
1/* $OpenBSD: control-notify.c,v 1.19 2017/02/03 11:57:27 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_input(struct client *c, struct window_pane *wp, 31 struct evbuffer *input) 32{ 33 u_char *buf; 34 size_t len; 35 struct evbuffer *message; 36 u_int i; 37 38 if (c->session == NULL) 39 return; 40 41 buf = EVBUFFER_DATA(input); 42 len = EVBUFFER_LENGTH(input); 43 44 /* 45 * Only write input if the window pane is linked to a window belonging 46 * to the client's session. 47 */ 48 if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) { 49 message = evbuffer_new(); 50 evbuffer_add_printf(message, "%%output %%%u ", wp->id); 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 } 57 control_write_buffer(c, message); 58 evbuffer_free(message); 59 } 60} 61 62void 63control_notify_window_layout_changed(struct window *w) 64{ 65 struct client *c; 66 struct session *s; 67 struct format_tree *ft; 68 struct winlink *wl; 69 const char *template; 70 char *expanded; 71 72 template = "%layout-change #{window_id} #{window_layout} " 73 "#{window_visible_layout} #{window_flags}"; 74 75 TAILQ_FOREACH(c, &clients, entry) { 76 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 77 continue; 78 s = c->session; 79 80 if (winlink_find_by_window_id(&s->windows, w->id) == NULL) 81 continue; 82 83 /* 84 * When the last pane in a window is closed it won't have a 85 * layout root and we don't need to inform the client about the 86 * layout change because the whole window will go away soon. 87 */ 88 if (w->layout_root == NULL) 89 continue; 90 91 ft = format_create(NULL, FORMAT_NONE, 0); 92 wl = winlink_find_by_window(&s->windows, w); 93 if (wl != NULL) { 94 format_defaults(ft, c, NULL, wl, NULL); 95 expanded = format_expand(ft, template); 96 control_write(c, "%s", expanded); 97 free(expanded); 98 } 99 format_free(ft); 100 } 101} 102 103void 104control_notify_window_unlinked(__unused struct session *s, struct window *w) 105{ 106 struct client *c; 107 struct session *cs; 108 109 TAILQ_FOREACH(c, &clients, entry) { 110 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 111 continue; 112 cs = c->session; 113 114 if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) 115 control_write(c, "%%window-close @%u", w->id); 116 else 117 control_write(c, "%%unlinked-window-close @%u", w->id); 118 } 119} 120 121void 122control_notify_window_linked(__unused struct session *s, struct window *w) 123{ 124 struct client *c; 125 struct session *cs; 126 127 TAILQ_FOREACH(c, &clients, entry) { 128 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 129 continue; 130 cs = c->session; 131 132 if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) 133 control_write(c, "%%window-add @%u", w->id); 134 else 135 control_write(c, "%%unlinked-window-add @%u", w->id); 136 } 137} 138 139void 140control_notify_window_renamed(struct window *w) 141{ 142 struct client *c; 143 struct session *cs; 144 145 TAILQ_FOREACH(c, &clients, entry) { 146 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 147 continue; 148 cs = c->session; 149 150 if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) { 151 control_write(c, "%%window-renamed @%u %s", w->id, 152 w->name); 153 } else { 154 control_write(c, "%%unlinked-window-renamed @%u %s", 155 w->id, w->name); 156 } 157 } 158} 159 160void 161control_notify_client_session_changed(struct client *c) 162{ 163 struct session *s; 164 165 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 166 return; 167 s = c->session; 168 169 control_write(c, "%%session-changed $%u %s", s->id, s->name); 170} 171 172void 173control_notify_session_renamed(struct session *s) 174{ 175 struct client *c; 176 177 TAILQ_FOREACH(c, &clients, entry) { 178 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) 179 continue; 180 181 control_write(c, "%%session-renamed $%u %s", s->id, s->name); 182 } 183} 184 185void 186control_notify_session_created(__unused 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, "%%sessions-changed"); 195 } 196} 197 198void 199control_notify_session_closed(__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