alerts.c revision 1.9
1/* $OpenBSD: alerts.c,v 1.9 2016/01/16 00:36:53 nicm Exp $ */ 2 3/* 4 * Copyright (c) 2015 Nicholas Marriott <nicm@users.sourceforge.net> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/types.h> 20 21#include <event.h> 22 23#include "tmux.h" 24 25int alerts_fired; 26 27void alerts_timer(int, short, void *); 28int alerts_enabled(struct window *, int); 29void alerts_callback(int, short, void *); 30void alerts_reset(struct window *); 31 32void alerts_run_hook(struct session *, struct winlink *, int); 33int alerts_check_all(struct session *, struct winlink *); 34int alerts_check_bell(struct session *, struct winlink *); 35int alerts_check_activity(struct session *, struct winlink *); 36int alerts_check_silence(struct session *, struct winlink *); 37void alerts_ring_bell(struct session *); 38 39void 40alerts_timer(__unused int fd, __unused short events, void *arg) 41{ 42 struct window *w = arg; 43 44 log_debug("@%u alerts timer expired", w->id); 45 alerts_reset(w); 46 alerts_queue(w, WINDOW_SILENCE); 47} 48 49void 50alerts_callback(__unused int fd, __unused short events, __unused void *arg) 51{ 52 struct window *w; 53 struct session *s; 54 struct winlink *wl; 55 int flags, alerts; 56 57 RB_FOREACH(w, windows, &windows) { 58 RB_FOREACH(s, sessions, &sessions) { 59 RB_FOREACH(wl, winlinks, &s->windows) { 60 if (wl->window != w) 61 continue; 62 flags = w->flags; 63 64 alerts = alerts_check_all(s, wl); 65 66 log_debug("%s:%d @%u alerts check, alerts %#x, " 67 "flags %#x", s->name, wl->idx, w->id, 68 alerts, flags); 69 } 70 } 71 } 72 alerts_fired = 0; 73} 74 75void 76alerts_run_hook(struct session *s, struct winlink *wl, int flags) 77{ 78 struct cmd_find_state fs; 79 80 if (cmd_find_from_winlink(&fs, s, wl) != 0) 81 return; 82 83 if (flags & WINDOW_BELL) 84 hooks_run(s->hooks, NULL, &fs, "alert-bell"); 85 if (flags & WINDOW_SILENCE) 86 hooks_run(s->hooks, NULL, &fs, "alert-silence"); 87 if (flags & WINDOW_ACTIVITY) 88 hooks_run(s->hooks, NULL, &fs, "alert-activity"); 89} 90 91int 92alerts_check_all(struct session *s, struct winlink *wl) 93{ 94 int alerts; 95 96 alerts = alerts_check_bell(s, wl); 97 alerts |= alerts_check_activity(s, wl); 98 alerts |= alerts_check_silence(s, wl); 99 if (alerts != 0) { 100 alerts_run_hook(s, wl, alerts); 101 server_status_session(s); 102 } 103 104 return (alerts); 105} 106 107void 108alerts_check_session(struct session *s) 109{ 110 struct winlink *wl; 111 112 RB_FOREACH(wl, winlinks, &s->windows) 113 alerts_check_all(s, wl); 114} 115 116int 117alerts_enabled(struct window *w, int flags) 118{ 119 if (flags & WINDOW_BELL) 120 return (1); 121 if (flags & WINDOW_ACTIVITY) { 122 if (options_get_number(w->options, "monitor-activity")) 123 return (1); 124 } 125 if (flags & WINDOW_SILENCE) { 126 if (options_get_number(w->options, "monitor-silence") != 0) 127 return (1); 128 } 129 return (0); 130} 131 132void 133alerts_reset_all(void) 134{ 135 struct window *w; 136 137 RB_FOREACH(w, windows, &windows) 138 alerts_reset(w); 139} 140 141void 142alerts_reset(struct window *w) 143{ 144 struct timeval tv; 145 146 w->flags &= ~WINDOW_SILENCE; 147 event_del(&w->alerts_timer); 148 149 timerclear(&tv); 150 tv.tv_sec = options_get_number(w->options, "monitor-silence"); 151 152 log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec); 153 if (tv.tv_sec != 0) 154 event_add(&w->alerts_timer, &tv); 155} 156 157void 158alerts_queue(struct window *w, int flags) 159{ 160 if (w->flags & WINDOW_ACTIVITY) 161 alerts_reset(w); 162 163 if (!event_initialized(&w->alerts_timer)) 164 evtimer_set(&w->alerts_timer, alerts_timer, w); 165 166 if (!alerts_fired) { 167 w->flags |= flags; 168 log_debug("@%u alerts flags added %#x", w->id, flags); 169 170 if (alerts_enabled(w, flags)) { 171 log_debug("alerts check queued (by @%u)", w->id); 172 event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL); 173 alerts_fired = 1; 174 } 175 } 176} 177 178int 179alerts_check_bell(struct session *s, struct winlink *wl) 180{ 181 struct client *c; 182 struct window *w = wl->window; 183 int action, visual; 184 185 if (!(w->flags & WINDOW_BELL)) 186 return (0); 187 if (s->curw != wl) { 188 wl->flags |= WINLINK_BELL; 189 w->flags &= ~WINDOW_BELL; 190 } 191 if (s->curw->window == w) 192 w->flags &= ~WINDOW_BELL; 193 194 action = options_get_number(s->options, "bell-action"); 195 if (action == BELL_NONE) 196 return (0); 197 198 visual = options_get_number(s->options, "visual-bell"); 199 TAILQ_FOREACH(c, &clients, entry) { 200 if (c->session != s || c->flags & CLIENT_CONTROL) 201 continue; 202 if (!visual) { 203 if ((action == BELL_CURRENT && 204 c->session->curw->window == w) || 205 (action == BELL_OTHER && 206 c->session->curw->window != w) || 207 action == BELL_ANY) 208 tty_putcode(&c->tty, TTYC_BEL); 209 continue; 210 } 211 if (action == BELL_CURRENT && c->session->curw->window == w) 212 status_message_set(c, "Bell in current window"); 213 else if (action == BELL_ANY || (action == BELL_OTHER && 214 c->session->curw->window != w)) 215 status_message_set(c, "Bell in window %d", wl->idx); 216 } 217 218 return (WINDOW_BELL); 219} 220 221int 222alerts_check_activity(struct session *s, struct winlink *wl) 223{ 224 struct client *c; 225 struct window *w = wl->window; 226 227 if (s->curw->window == w) 228 w->flags &= ~WINDOW_ACTIVITY; 229 230 if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY) 231 return (0); 232 if (s->curw == wl) 233 return (0); 234 235 if (!options_get_number(w->options, "monitor-activity")) 236 return (0); 237 238 if (options_get_number(s->options, "bell-on-alert")) 239 alerts_ring_bell(s); 240 wl->flags |= WINLINK_ACTIVITY; 241 242 if (options_get_number(s->options, "visual-activity")) { 243 TAILQ_FOREACH(c, &clients, entry) { 244 if (c->session != s) 245 continue; 246 status_message_set(c, "Activity in window %d", wl->idx); 247 } 248 } 249 250 return (WINDOW_ACTIVITY); 251} 252 253int 254alerts_check_silence(struct session *s, struct winlink *wl) 255{ 256 struct client *c; 257 struct window *w = wl->window; 258 259 if (s->curw->window == w) 260 w->flags &= ~WINDOW_SILENCE; 261 262 if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE) 263 return (0); 264 if (s->curw == wl) 265 return (0); 266 267 if (options_get_number(w->options, "monitor-silence") == 0) 268 return (0); 269 270 if (options_get_number(s->options, "bell-on-alert")) 271 alerts_ring_bell(s); 272 wl->flags |= WINLINK_SILENCE; 273 274 if (options_get_number(s->options, "visual-silence")) { 275 TAILQ_FOREACH(c, &clients, entry) { 276 if (c->session != s) 277 continue; 278 status_message_set(c, "Silence in window %d", wl->idx); 279 } 280 } 281 282 return (WINDOW_SILENCE); 283} 284 285void 286alerts_ring_bell(struct session *s) 287{ 288 struct client *c; 289 290 TAILQ_FOREACH(c, &clients, entry) { 291 if (c->session == s && !(c->flags & CLIENT_CONTROL)) 292 tty_putcode(&c->tty, TTYC_BEL); 293 } 294} 295