Annotation of src/usr.bin/tmux/alerts.c, Revision 1.22
1.22 ! nicm 1: /* $OpenBSD: alerts.c,v 1.21 2017/07/26 16:14:08 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 *);
1.21 nicm 37: static void alerts_set_message(struct session *, struct window *,
38: struct winlink *, const char *, int, int);
1.1 nicm 39:
1.14 nicm 40: static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list);
41:
1.12 nicm 42: static void
1.5 nicm 43: alerts_timer(__unused int fd, __unused short events, void *arg)
1.1 nicm 44: {
45: struct window *w = arg;
46:
47: log_debug("@%u alerts timer expired", w->id);
48: alerts_queue(w, WINDOW_SILENCE);
49: }
50:
1.12 nicm 51: static void
1.5 nicm 52: alerts_callback(__unused int fd, __unused short events, __unused void *arg)
1.1 nicm 53: {
1.14 nicm 54: struct window *w, *w1;
55: int alerts;
1.1 nicm 56:
1.14 nicm 57: TAILQ_FOREACH_SAFE(w, &alerts_list, alerts_entry, w1) {
58: alerts = alerts_check_all(w);
59: log_debug("@%u alerts check, alerts %#x", w->id, alerts);
60:
61: w->alerts_queued = 0;
62: TAILQ_REMOVE(&alerts_list, w, alerts_entry);
1.16 nicm 63:
64: w->flags &= ~WINDOW_ALERTFLAGS;
1.19 nicm 65: window_remove_ref(w, __func__);
1.1 nicm 66: }
67: alerts_fired = 0;
68: }
69:
1.12 nicm 70: static int
1.14 nicm 71: alerts_check_all(struct window *w)
1.8 nicm 72: {
73: int alerts;
74:
1.14 nicm 75: alerts = alerts_check_bell(w);
76: alerts |= alerts_check_activity(w);
77: alerts |= alerts_check_silence(w);
1.8 nicm 78: return (alerts);
79: }
80:
81: void
82: alerts_check_session(struct session *s)
83: {
84: struct winlink *wl;
85:
86: RB_FOREACH(wl, winlinks, &s->windows)
1.14 nicm 87: alerts_check_all(wl->window);
1.8 nicm 88: }
89:
1.12 nicm 90: static int
1.1 nicm 91: alerts_enabled(struct window *w, int flags)
92: {
1.7 nicm 93: if (flags & WINDOW_BELL)
94: return (1);
1.1 nicm 95: if (flags & WINDOW_ACTIVITY) {
1.4 nicm 96: if (options_get_number(w->options, "monitor-activity"))
1.1 nicm 97: return (1);
98: }
99: if (flags & WINDOW_SILENCE) {
1.4 nicm 100: if (options_get_number(w->options, "monitor-silence") != 0)
1.1 nicm 101: return (1);
102: }
103: return (0);
104: }
105:
106: void
107: alerts_reset_all(void)
108: {
109: struct window *w;
110:
111: RB_FOREACH(w, windows, &windows)
112: alerts_reset(w);
113: }
114:
1.12 nicm 115: static void
1.1 nicm 116: alerts_reset(struct window *w)
117: {
118: struct timeval tv;
119:
120: w->flags &= ~WINDOW_SILENCE;
121: event_del(&w->alerts_timer);
122:
123: timerclear(&tv);
1.4 nicm 124: tv.tv_sec = options_get_number(w->options, "monitor-silence");
1.1 nicm 125:
126: log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec);
127: if (tv.tv_sec != 0)
128: event_add(&w->alerts_timer, &tv);
129: }
130:
131: void
132: alerts_queue(struct window *w, int flags)
133: {
1.22 ! nicm 134: alerts_reset(w);
1.3 nicm 135:
1.1 nicm 136: if (!event_initialized(&w->alerts_timer))
137: evtimer_set(&w->alerts_timer, alerts_timer, w);
138:
1.11 nicm 139: if ((w->flags & flags) != flags) {
1.6 nicm 140: w->flags |= flags;
141: log_debug("@%u alerts flags added %#x", w->id, flags);
1.11 nicm 142: }
1.6 nicm 143:
1.18 nicm 144: if (alerts_enabled(w, flags)) {
145: if (!w->alerts_queued) {
146: w->alerts_queued = 1;
147: TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
1.19 nicm 148: window_add_ref(w, __func__);
1.18 nicm 149: }
150:
151: if (!alerts_fired) {
152: log_debug("alerts check queued (by @%u)", w->id);
153: event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
154: alerts_fired = 1;
155: }
1.1 nicm 156: }
157: }
158:
1.12 nicm 159: static int
1.14 nicm 160: alerts_check_bell(struct window *w)
1.1 nicm 161: {
1.14 nicm 162: struct winlink *wl;
163: struct session *s;
1.1 nicm 164:
1.14 nicm 165: if (~w->flags & WINDOW_BELL)
1.1 nicm 166: return (0);
167:
1.14 nicm 168: TAILQ_FOREACH(wl, &w->winlinks, wentry)
169: wl->session->flags &= ~SESSION_ALERTED;
1.1 nicm 170:
1.14 nicm 171: TAILQ_FOREACH(wl, &w->winlinks, wentry) {
172: if (wl->flags & WINLINK_BELL)
1.1 nicm 173: continue;
1.14 nicm 174: s = wl->session;
175: if (s->curw != wl) {
176: wl->flags |= WINLINK_BELL;
1.17 nicm 177: notify_winlink("alert-bell", wl);
1.14 nicm 178: }
179:
180: if (s->flags & SESSION_ALERTED)
1.1 nicm 181: continue;
1.14 nicm 182: s->flags |= SESSION_ALERTED;
183:
1.21 nicm 184: alerts_set_message(s, w, wl, "Bell",
185: options_get_number(s->options, "bell-action"),
186: options_get_number(s->options, "visual-bell"));
1.1 nicm 187: }
188:
189: return (WINDOW_BELL);
190: }
191:
1.12 nicm 192: static int
1.14 nicm 193: alerts_check_activity(struct window *w)
1.1 nicm 194: {
1.14 nicm 195: struct winlink *wl;
196: struct session *s;
1.1 nicm 197:
1.14 nicm 198: if (~w->flags & WINDOW_ACTIVITY)
1.1 nicm 199: return (0);
1.4 nicm 200: if (!options_get_number(w->options, "monitor-activity"))
1.1 nicm 201: return (0);
202:
1.14 nicm 203: TAILQ_FOREACH(wl, &w->winlinks, wentry)
204: wl->session->flags &= ~SESSION_ALERTED;
1.1 nicm 205:
1.14 nicm 206: TAILQ_FOREACH(wl, &w->winlinks, wentry) {
207: if (wl->flags & WINLINK_ACTIVITY)
208: continue;
209: s = wl->session;
1.21 nicm 210: if (s->curw != wl) {
211: wl->flags |= WINLINK_ACTIVITY;
212: notify_winlink("alert-activity", wl);
213: }
1.14 nicm 214:
215: if (s->flags & SESSION_ALERTED)
216: continue;
217: s->flags |= SESSION_ALERTED;
218:
1.21 nicm 219: alerts_set_message(s, w, wl, "Activity",
220: options_get_number(s->options, "activity-action"),
221: options_get_number(s->options, "visual-activity"));
1.1 nicm 222: }
223:
224: return (WINDOW_ACTIVITY);
225: }
226:
1.12 nicm 227: static int
1.14 nicm 228: alerts_check_silence(struct window *w)
1.1 nicm 229: {
1.14 nicm 230: struct winlink *wl;
231: struct session *s;
1.1 nicm 232:
1.14 nicm 233: if (~w->flags & WINDOW_SILENCE)
1.1 nicm 234: return (0);
1.21 nicm 235: if (options_get_number(w->options, "monitor-silence") == 0)
1.1 nicm 236: return (0);
237:
1.14 nicm 238: TAILQ_FOREACH(wl, &w->winlinks, wentry)
239: wl->session->flags &= ~SESSION_ALERTED;
240:
241: TAILQ_FOREACH(wl, &w->winlinks, wentry) {
242: if (wl->flags & WINLINK_SILENCE)
243: continue;
244: s = wl->session;
1.21 nicm 245: if (s->curw != wl) {
246: wl->flags |= WINLINK_SILENCE;
247: notify_winlink("alert-silence", wl);
248: }
1.14 nicm 249:
250: if (s->flags & SESSION_ALERTED)
251: continue;
252: s->flags |= SESSION_ALERTED;
1.1 nicm 253:
1.21 nicm 254: alerts_set_message(s, w, wl, "Silence",
255: options_get_number(s->options, "silence-action"),
256: options_get_number(s->options, "visual-silence"));
1.1 nicm 257: }
258:
259: return (WINDOW_SILENCE);
1.14 nicm 260: }
261:
262: static void
1.21 nicm 263: alerts_set_message(struct session *s, struct window *w, struct winlink *wl,
264: const char *type, int action, int visual)
1.14 nicm 265: {
266: struct client *c;
1.21 nicm 267: int flag;
1.14 nicm 268:
1.21 nicm 269: /*
270: * We have found an alert (bell, activity or silence), so we need
271: * to notify the user. For each client attached to this session,
272: * decide whether a bell (or visual message) is needed.
273: *
274: * {bell,activity,silence}-action determines when we notify: none means
275: * nothing happens, current means we only do something for the current
276: * window and other means only for windows other than the current.
277: *
278: * If visual-{bell,activity,silence} is on, then a message is
279: * substituted for a bell; if it is off, a bell is sent as normal; both
280: * mean both a bell and visual message is sent.
281: */
1.14 nicm 282:
1.21 nicm 283: if (action == BELL_NONE)
284: return;
1.14 nicm 285: TAILQ_FOREACH(c, &clients, entry) {
1.21 nicm 286: if (c->session != s || c->flags & CLIENT_CONTROL)
287: continue;
288: flag = 0;
289: if (action == BELL_ANY)
290: flag = 1;
291: else if (action == BELL_CURRENT)
292: flag = (c->session->curw->window == w);
293: else if (action == BELL_OTHER)
294: flag = (c->session->curw->window != w);
295: if (!flag)
296: continue;
1.1 nicm 297:
1.21 nicm 298: if (visual == VISUAL_OFF || visual == VISUAL_BOTH)
1.2 nicm 299: tty_putcode(&c->tty, TTYC_BEL);
1.21 nicm 300: if (visual == VISUAL_OFF)
301: continue;
302: if (c->session->curw->window == w)
303: status_message_set(c, "%s in current window", type);
304: else
305: status_message_set(c, "%s in window %d", type, wl->idx);
1.1 nicm 306: }
307: }