alerts.c revision 1.7
1/* $OpenBSD: alerts.c,v 1.7 2015/11/20 16:33:46 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 32int alerts_check_bell(struct session *, struct winlink *); 33int alerts_check_activity(struct session *, struct winlink *); 34int alerts_check_silence(struct session *, struct winlink *); 35void alerts_ring_bell(struct session *); 36 37void 38alerts_timer(__unused int fd, __unused short events, void *arg) 39{ 40 struct window *w = arg; 41 42 log_debug("@%u alerts timer expired", w->id); 43 alerts_reset(w); 44 alerts_queue(w, WINDOW_SILENCE); 45} 46 47void 48alerts_callback(__unused int fd, __unused short events, __unused void *arg) 49{ 50 struct window *w; 51 struct session *s; 52 struct winlink *wl; 53 int flags, alerts; 54 55 RB_FOREACH(w, windows, &windows) { 56 RB_FOREACH(s, sessions, &sessions) { 57 RB_FOREACH(wl, winlinks, &s->windows) { 58 if (wl->window != w) 59 continue; 60 flags = w->flags; 61 62 alerts = alerts_check_bell(s, wl); 63 alerts |= alerts_check_activity(s, wl); 64 alerts |= alerts_check_silence(s, wl); 65 if (alerts != 0) 66 server_status_session(s); 67 68 log_debug("%s:%d @%u alerts check, alerts %#x, " 69 "flags %#x", s->name, wl->idx, w->id, 70 alerts, flags); 71 } 72 } 73 } 74 alerts_fired = 0; 75} 76 77int 78alerts_enabled(struct window *w, int flags) 79{ 80 if (flags & WINDOW_BELL) 81 return (1); 82 if (flags & WINDOW_ACTIVITY) { 83 if (options_get_number(w->options, "monitor-activity")) 84 return (1); 85 } 86 if (flags & WINDOW_SILENCE) { 87 if (options_get_number(w->options, "monitor-silence") != 0) 88 return (1); 89 } 90 return (0); 91} 92 93void 94alerts_reset_all(void) 95{ 96 struct window *w; 97 98 RB_FOREACH(w, windows, &windows) 99 alerts_reset(w); 100} 101 102void 103alerts_reset(struct window *w) 104{ 105 struct timeval tv; 106 107 w->flags &= ~WINDOW_SILENCE; 108 event_del(&w->alerts_timer); 109 110 timerclear(&tv); 111 tv.tv_sec = options_get_number(w->options, "monitor-silence"); 112 113 log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec); 114 if (tv.tv_sec != 0) 115 event_add(&w->alerts_timer, &tv); 116} 117 118void 119alerts_queue(struct window *w, int flags) 120{ 121 if (w->flags & WINDOW_ACTIVITY) 122 alerts_reset(w); 123 124 if (!event_initialized(&w->alerts_timer)) 125 evtimer_set(&w->alerts_timer, alerts_timer, w); 126 127 if (!alerts_fired) { 128 w->flags |= flags; 129 log_debug("@%u alerts flags added %#x", w->id, flags); 130 131 if (alerts_enabled(w, flags)) { 132 log_debug("alerts check queued (by @%u)", w->id); 133 event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL); 134 alerts_fired = 1; 135 } 136 } 137} 138 139int 140alerts_check_bell(struct session *s, struct winlink *wl) 141{ 142 struct client *c; 143 struct window *w = wl->window; 144 int action, visual; 145 146 if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL) 147 return (0); 148 if (s->curw != wl || s->flags & SESSION_UNATTACHED) 149 wl->flags |= WINLINK_BELL; 150 if (s->flags & SESSION_UNATTACHED) 151 return (0); 152 if (s->curw->window == w) 153 w->flags &= ~WINDOW_BELL; 154 155 action = options_get_number(s->options, "bell-action"); 156 if (action == BELL_NONE) 157 return (0); 158 159 visual = options_get_number(s->options, "visual-bell"); 160 TAILQ_FOREACH(c, &clients, entry) { 161 if (c->session != s || c->flags & CLIENT_CONTROL) 162 continue; 163 if (!visual) { 164 if ((action == BELL_CURRENT && 165 c->session->curw->window == w) || 166 (action == BELL_OTHER && 167 c->session->curw->window != w) || 168 action == BELL_ANY) 169 tty_putcode(&c->tty, TTYC_BEL); 170 continue; 171 } 172 if (action == BELL_CURRENT && c->session->curw->window == w) 173 status_message_set(c, "Bell in current window"); 174 else if (action == BELL_ANY || (action == BELL_OTHER && 175 c->session->curw->window != w)) 176 status_message_set(c, "Bell in window %d", wl->idx); 177 } 178 179 return (WINDOW_BELL); 180} 181 182int 183alerts_check_activity(struct session *s, struct winlink *wl) 184{ 185 struct client *c; 186 struct window *w = wl->window; 187 188 if (s->curw->window == w) 189 w->flags &= ~WINDOW_ACTIVITY; 190 191 if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY) 192 return (0); 193 if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) 194 return (0); 195 196 if (!options_get_number(w->options, "monitor-activity")) 197 return (0); 198 199 if (options_get_number(s->options, "bell-on-alert")) 200 alerts_ring_bell(s); 201 wl->flags |= WINLINK_ACTIVITY; 202 203 if (options_get_number(s->options, "visual-activity")) { 204 TAILQ_FOREACH(c, &clients, entry) { 205 if (c->session != s) 206 continue; 207 status_message_set(c, "Activity in window %d", wl->idx); 208 } 209 } 210 211 return (WINDOW_ACTIVITY); 212} 213 214int 215alerts_check_silence(struct session *s, struct winlink *wl) 216{ 217 struct client *c; 218 struct window *w = wl->window; 219 220 if (s->curw->window == w) 221 w->flags &= ~WINDOW_SILENCE; 222 223 if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE) 224 return (0); 225 if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) 226 return (0); 227 228 if (options_get_number(w->options, "monitor-silence") == 0) 229 return (0); 230 231 if (options_get_number(s->options, "bell-on-alert")) 232 alerts_ring_bell(s); 233 wl->flags |= WINLINK_SILENCE; 234 235 if (options_get_number(s->options, "visual-silence")) { 236 TAILQ_FOREACH(c, &clients, entry) { 237 if (c->session != s) 238 continue; 239 status_message_set(c, "Silence in window %d", wl->idx); 240 } 241 } 242 243 return (WINDOW_SILENCE); 244} 245 246void 247alerts_ring_bell(struct session *s) 248{ 249 struct client *c; 250 251 TAILQ_FOREACH(c, &clients, entry) { 252 if (c->session == s && !(c->flags & CLIENT_CONTROL)) 253 tty_putcode(&c->tty, TTYC_BEL); 254 } 255} 256