1 /* $OpenBSD: control-notify.c,v 1.29 2021/03/16 09:14:58 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 29 void 30 control_notify_pane_mode_changed(int pane) 31 { 32 struct client *c; 33 34 TAILQ_FOREACH(c, &clients, entry) { 35 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) 36 continue; 37 38 control_write(c, "%%pane-mode-changed %%%u", pane); 39 } 40 } 41 42 void 43 control_notify_window_layout_changed(struct window *w) 44 { 45 struct client *c; 46 struct session *s; 47 struct winlink *wl; 48 const char *template; 49 char *cp; 50 51 template = "%layout-change #{window_id} #{window_layout} " 52 "#{window_visible_layout} #{window_raw_flags}"; 53 54 TAILQ_FOREACH(c, &clients, entry) { 55 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 56 continue; 57 s = c->session; 58 59 if (winlink_find_by_window_id(&s->windows, w->id) == NULL) 60 continue; 61 62 /* 63 * When the last pane in a window is closed it won't have a 64 * layout root and we don't need to inform the client about the 65 * layout change because the whole window will go away soon. 66 */ 67 if (w->layout_root == NULL) 68 continue; 69 70 wl = winlink_find_by_window(&s->windows, w); 71 if (wl != NULL) { 72 cp = format_single(NULL, template, c, NULL, wl, NULL); 73 control_write(c, "%s", cp); 74 free(cp); 75 } 76 } 77 } 78 79 void 80 control_notify_window_pane_changed(struct window *w) 81 { 82 struct client *c; 83 84 TAILQ_FOREACH(c, &clients, entry) { 85 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) 86 continue; 87 88 control_write(c, "%%window-pane-changed @%u %%%u", w->id, 89 w->active->id); 90 } 91 } 92 93 void 94 control_notify_window_unlinked(__unused struct session *s, struct window *w) 95 { 96 struct client *c; 97 struct session *cs; 98 99 TAILQ_FOREACH(c, &clients, entry) { 100 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 101 continue; 102 cs = c->session; 103 104 if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) 105 control_write(c, "%%window-close @%u", w->id); 106 else 107 control_write(c, "%%unlinked-window-close @%u", w->id); 108 } 109 } 110 111 void 112 control_notify_window_linked(__unused struct session *s, struct window *w) 113 { 114 struct client *c; 115 struct session *cs; 116 117 TAILQ_FOREACH(c, &clients, entry) { 118 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 119 continue; 120 cs = c->session; 121 122 if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) 123 control_write(c, "%%window-add @%u", w->id); 124 else 125 control_write(c, "%%unlinked-window-add @%u", w->id); 126 } 127 } 128 129 void 130 control_notify_window_renamed(struct window *w) 131 { 132 struct client *c; 133 struct session *cs; 134 135 TAILQ_FOREACH(c, &clients, entry) { 136 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 137 continue; 138 cs = c->session; 139 140 if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) { 141 control_write(c, "%%window-renamed @%u %s", w->id, 142 w->name); 143 } else { 144 control_write(c, "%%unlinked-window-renamed @%u %s", 145 w->id, w->name); 146 } 147 } 148 } 149 150 void 151 control_notify_client_session_changed(struct client *cc) 152 { 153 struct client *c; 154 struct session *s; 155 156 if (cc->session == NULL) 157 return; 158 s = cc->session; 159 160 TAILQ_FOREACH(c, &clients, entry) { 161 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) 162 continue; 163 164 if (cc == c) { 165 control_write(c, "%%session-changed $%u %s", s->id, 166 s->name); 167 } else { 168 control_write(c, "%%client-session-changed %s $%u %s", 169 cc->name, s->id, s->name); 170 } 171 } 172 } 173 174 void 175 control_notify_client_detached(struct client *cc) 176 { 177 struct client *c; 178 179 TAILQ_FOREACH(c, &clients, entry) { 180 if (CONTROL_SHOULD_NOTIFY_CLIENT(c)) 181 control_write(c, "%%client-detached %s", cc->name); 182 } 183 } 184 185 void 186 control_notify_session_renamed(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, "%%session-renamed $%u %s", s->id, s->name); 195 } 196 } 197 198 void 199 control_notify_session_created(__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 211 void 212 control_notify_session_closed(__unused struct session *s) 213 { 214 struct client *c; 215 216 TAILQ_FOREACH(c, &clients, entry) { 217 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) 218 continue; 219 220 control_write(c, "%%sessions-changed"); 221 } 222 } 223 224 void 225 control_notify_session_window_changed(struct session *s) 226 { 227 struct client *c; 228 229 TAILQ_FOREACH(c, &clients, entry) { 230 if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) 231 continue; 232 233 control_write(c, "%%session-window-changed $%u @%u", s->id, 234 s->curw->window->id); 235 } 236 } 237