Annotation of src/usr.bin/tmux/alerts.c, Revision 1.19
1.19 ! nicm 1: /* $OpenBSD: alerts.c,v 1.18 2017/04/28 19:10:48 nicm Exp $ */
1.1 nicm 2:
3: /*
1.10 nicm 4: * Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1 nicm 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>
1.14 nicm 22: #include <stdlib.h>
1.1 nicm 23:
24: #include "tmux.h"
25:
1.12 nicm 26: static int alerts_fired;
1.1 nicm 27:
1.12 nicm 28: static void alerts_timer(int, short, void *);
29: static int alerts_enabled(struct window *, int);
30: static void alerts_callback(int, short, void *);
31: static void alerts_reset(struct window *);
32:
1.14 nicm 33: static int alerts_check_all(struct window *);
34: static int alerts_check_bell(struct window *);
35: static int alerts_check_activity(struct window *);
36: static int alerts_check_silence(struct window *);
37: static void printflike(2, 3) alerts_set_message(struct session *, const char *,
38: ...);
1.12 nicm 39: static void alerts_ring_bell(struct session *);
1.1 nicm 40:
1.14 nicm 41: static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list);
42:
1.12 nicm 43: static void
1.5 nicm 44: alerts_timer(__unused int fd, __unused short events, void *arg)
1.1 nicm 45: {
46: struct window *w = arg;
47:
48: log_debug("@%u alerts timer expired", w->id);
49: alerts_reset(w);
50: alerts_queue(w, WINDOW_SILENCE);
51: }
52:
1.12 nicm 53: static void
1.5 nicm 54: alerts_callback(__unused int fd, __unused short events, __unused void *arg)
1.1 nicm 55: {
1.14 nicm 56: struct window *w, *w1;
57: int alerts;
1.1 nicm 58:
1.14 nicm 59: TAILQ_FOREACH_SAFE(w, &alerts_list, alerts_entry, w1) {
60: alerts = alerts_check_all(w);
61: log_debug("@%u alerts check, alerts %#x", w->id, alerts);
62:
63: w->alerts_queued = 0;
64: TAILQ_REMOVE(&alerts_list, w, alerts_entry);
1.16 nicm 65:
66: w->flags &= ~WINDOW_ALERTFLAGS;
1.19 ! nicm 67: window_remove_ref(w, __func__);
1.1 nicm 68: }
69: alerts_fired = 0;
70: }
71:
1.12 nicm 72: static int
1.14 nicm 73: alerts_check_all(struct window *w)
1.8 nicm 74: {
75: int alerts;
76:
1.14 nicm 77: alerts = alerts_check_bell(w);
78: alerts |= alerts_check_activity(w);
79: alerts |= alerts_check_silence(w);
1.8 nicm 80: return (alerts);
81: }
82:
83: void
84: alerts_check_session(struct session *s)
85: {
86: struct winlink *wl;
87:
88: RB_FOREACH(wl, winlinks, &s->windows)
1.14 nicm 89: alerts_check_all(wl->window);
1.8 nicm 90: }
91:
1.12 nicm 92: static int
1.1 nicm 93: alerts_enabled(struct window *w, int flags)
94: {
1.7 nicm 95: if (flags & WINDOW_BELL)
96: return (1);
1.1 nicm 97: if (flags & WINDOW_ACTIVITY) {
1.4 nicm 98: if (options_get_number(w->options, "monitor-activity"))
1.1 nicm 99: return (1);
100: }
101: if (flags & WINDOW_SILENCE) {
1.4 nicm 102: if (options_get_number(w->options, "monitor-silence") != 0)
1.1 nicm 103: return (1);
104: }
105: return (0);
106: }
107:
108: void
109: alerts_reset_all(void)
110: {
111: struct window *w;
112:
113: RB_FOREACH(w, windows, &windows)
114: alerts_reset(w);
115: }
116:
1.12 nicm 117: static void
1.1 nicm 118: alerts_reset(struct window *w)
119: {
120: struct timeval tv;
121:
122: w->flags &= ~WINDOW_SILENCE;
123: event_del(&w->alerts_timer);
124:
125: timerclear(&tv);
1.4 nicm 126: tv.tv_sec = options_get_number(w->options, "monitor-silence");
1.1 nicm 127:
128: log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec);
129: if (tv.tv_sec != 0)
130: event_add(&w->alerts_timer, &tv);
131: }
132:
133: void
134: alerts_queue(struct window *w, int flags)
135: {
1.3 nicm 136: if (w->flags & WINDOW_ACTIVITY)
137: alerts_reset(w);
138:
1.1 nicm 139: if (!event_initialized(&w->alerts_timer))
140: evtimer_set(&w->alerts_timer, alerts_timer, w);
141:
1.11 nicm 142: if ((w->flags & flags) != flags) {
1.6 nicm 143: w->flags |= flags;
144: log_debug("@%u alerts flags added %#x", w->id, flags);
1.11 nicm 145: }
1.6 nicm 146:
1.18 nicm 147: if (alerts_enabled(w, flags)) {
148: if (!w->alerts_queued) {
149: w->alerts_queued = 1;
150: TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
1.19 ! nicm 151: window_add_ref(w, __func__);
1.18 nicm 152: }
153:
154: if (!alerts_fired) {
155: log_debug("alerts check queued (by @%u)", w->id);
156: event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
157: alerts_fired = 1;
158: }
1.1 nicm 159: }
160: }
161:
1.12 nicm 162: static int
1.14 nicm 163: alerts_check_bell(struct window *w)
1.1 nicm 164: {
1.14 nicm 165: struct window *ws;
166: struct winlink *wl;
167: struct session *s;
1.1 nicm 168: struct client *c;
169: int action, visual;
170:
1.14 nicm 171: if (~w->flags & WINDOW_BELL)
1.1 nicm 172: return (0);
173:
1.14 nicm 174: TAILQ_FOREACH(wl, &w->winlinks, wentry)
175: wl->session->flags &= ~SESSION_ALERTED;
1.1 nicm 176:
1.14 nicm 177: TAILQ_FOREACH(wl, &w->winlinks, wentry) {
178: if (wl->flags & WINLINK_BELL)
1.1 nicm 179: continue;
1.14 nicm 180: s = wl->session;
181: if (s->curw != wl) {
182: wl->flags |= WINLINK_BELL;
1.17 nicm 183: notify_winlink("alert-bell", wl);
1.14 nicm 184: }
185:
186: if (s->flags & SESSION_ALERTED)
1.1 nicm 187: continue;
1.14 nicm 188: s->flags |= SESSION_ALERTED;
189:
190: action = options_get_number(s->options, "bell-action");
191: if (action == BELL_NONE)
192: return (0);
193:
194: visual = options_get_number(s->options, "visual-bell");
195: TAILQ_FOREACH(c, &clients, entry) {
196: if (c->session != s || c->flags & CLIENT_CONTROL)
197: continue;
198: ws = c->session->curw->window;
199:
200: if (action == BELL_CURRENT && ws != w)
201: action = BELL_NONE;
202: if (action == BELL_OTHER && ws != w)
203: action = BELL_NONE;
204:
205: if (!visual) {
206: if (action != BELL_NONE)
207: tty_putcode(&c->tty, TTYC_BEL);
208: continue;
209: }
210: if (action == BELL_CURRENT)
211: status_message_set(c, "Bell in current window");
212: else if (action != BELL_NONE) {
213: status_message_set(c, "Bell in window %d",
214: wl->idx);
215: }
1.1 nicm 216: }
217: }
218:
219: return (WINDOW_BELL);
220: }
221:
1.12 nicm 222: static int
1.14 nicm 223: alerts_check_activity(struct window *w)
1.1 nicm 224: {
1.14 nicm 225: struct winlink *wl;
226: struct session *s;
1.1 nicm 227:
1.14 nicm 228: if (~w->flags & WINDOW_ACTIVITY)
1.1 nicm 229: return (0);
1.4 nicm 230: if (!options_get_number(w->options, "monitor-activity"))
1.1 nicm 231: return (0);
232:
1.14 nicm 233: TAILQ_FOREACH(wl, &w->winlinks, wentry)
234: wl->session->flags &= ~SESSION_ALERTED;
1.1 nicm 235:
1.14 nicm 236: TAILQ_FOREACH(wl, &w->winlinks, wentry) {
237: if (wl->flags & WINLINK_ACTIVITY)
238: continue;
239: s = wl->session;
1.15 nicm 240: if (s->curw == wl)
241: continue;
242:
243: wl->flags |= WINLINK_ACTIVITY;
1.17 nicm 244: notify_winlink("alert-activity", wl);
1.14 nicm 245:
246: if (s->flags & SESSION_ALERTED)
247: continue;
248: s->flags |= SESSION_ALERTED;
249:
250: if (options_get_number(s->options, "bell-on-alert"))
251: alerts_ring_bell(s);
252: if (options_get_number(s->options, "visual-activity"))
253: alerts_set_message(s, "Activity in window %d", wl->idx);
1.1 nicm 254: }
255:
256: return (WINDOW_ACTIVITY);
257: }
258:
1.12 nicm 259: static int
1.14 nicm 260: alerts_check_silence(struct window *w)
1.1 nicm 261: {
1.14 nicm 262: struct winlink *wl;
263: struct session *s;
1.1 nicm 264:
1.14 nicm 265: if (~w->flags & WINDOW_SILENCE)
1.1 nicm 266: return (0);
1.14 nicm 267: if (!options_get_number(w->options, "monitor-silence"))
1.1 nicm 268: return (0);
269:
1.14 nicm 270: TAILQ_FOREACH(wl, &w->winlinks, wentry)
271: wl->session->flags &= ~SESSION_ALERTED;
272:
273: TAILQ_FOREACH(wl, &w->winlinks, wentry) {
274: if (wl->flags & WINLINK_SILENCE)
275: continue;
276: s = wl->session;
1.15 nicm 277: if (s->curw == wl)
278: continue;
279: wl->flags |= WINLINK_SILENCE;
1.17 nicm 280: notify_winlink("alert-silence", wl);
1.14 nicm 281:
282: if (s->flags & SESSION_ALERTED)
283: continue;
284: s->flags |= SESSION_ALERTED;
1.1 nicm 285:
1.14 nicm 286: if (options_get_number(s->options, "bell-on-alert"))
287: alerts_ring_bell(s);
1.1 nicm 288:
1.14 nicm 289: if (!options_get_number(s->options, "visual-silence"))
290: alerts_set_message(s, "Silence in window %d", wl->idx);
1.1 nicm 291: }
292:
293: return (WINDOW_SILENCE);
1.14 nicm 294: }
295:
296: static void
297: alerts_set_message(struct session *s, const char *fmt, ...)
298: {
299: struct client *c;
300: va_list ap;
301: char *message;
302:
303: va_start(ap, fmt);
304: xvasprintf(&message, fmt, ap);
305: va_end(ap);
306:
307: TAILQ_FOREACH(c, &clients, entry) {
308: if (c->session == s)
309: status_message_set(c, "%s", message);
310: }
311:
312: free(message);
1.1 nicm 313: }
314:
1.12 nicm 315: static void
1.1 nicm 316: alerts_ring_bell(struct session *s)
317: {
318: struct client *c;
319:
320: TAILQ_FOREACH(c, &clients, entry) {
321: if (c->session == s && !(c->flags & CLIENT_CONTROL))
1.2 nicm 322: tty_putcode(&c->tty, TTYC_BEL);
1.1 nicm 323: }
324: }