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