Annotation of src/usr.bin/tmux/alerts.c, Revision 1.13
1.13 ! nicm 1: /* $OpenBSD: alerts.c,v 1.12 2016/10/03 22:52:11 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>
22:
23: #include "tmux.h"
24:
1.12 nicm 25: static int alerts_fired;
1.1 nicm 26:
1.12 nicm 27: static void alerts_timer(int, short, void *);
28: static int alerts_enabled(struct window *, int);
29: static void alerts_callback(int, short, void *);
30: static void alerts_reset(struct window *);
31:
32: static void alerts_run_hook(struct session *, struct winlink *, int);
33: static int alerts_check_all(struct session *, struct winlink *);
34: static int alerts_check_bell(struct session *, struct winlink *);
35: static int alerts_check_activity(struct session *, struct winlink *);
36: static int alerts_check_silence(struct session *, struct winlink *);
37: static void alerts_ring_bell(struct session *);
1.1 nicm 38:
1.12 nicm 39: static void
1.5 nicm 40: alerts_timer(__unused int fd, __unused short events, void *arg)
1.1 nicm 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:
1.12 nicm 49: static void
1.5 nicm 50: alerts_callback(__unused int fd, __unused short events, __unused void *arg)
1.1 nicm 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:
1.8 nicm 64: alerts = alerts_check_all(s, wl);
1.1 nicm 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:
1.12 nicm 75: static void
1.9 nicm 76: alerts_run_hook(struct session *s, struct winlink *wl, int flags)
77: {
78: if (flags & WINDOW_BELL)
1.13 ! nicm 79: notify_winlink("alert-bell", s, wl);
1.9 nicm 80: if (flags & WINDOW_SILENCE)
1.13 ! nicm 81: notify_winlink("alert-silence", s, wl);
1.9 nicm 82: if (flags & WINDOW_ACTIVITY)
1.13 ! nicm 83: notify_winlink("alert-activity", s, wl);
1.9 nicm 84: }
85:
1.12 nicm 86: static int
1.8 nicm 87: alerts_check_all(struct session *s, struct winlink *wl)
88: {
89: int alerts;
90:
91: alerts = alerts_check_bell(s, wl);
92: alerts |= alerts_check_activity(s, wl);
93: alerts |= alerts_check_silence(s, wl);
1.9 nicm 94: if (alerts != 0) {
95: alerts_run_hook(s, wl, alerts);
1.8 nicm 96: server_status_session(s);
1.9 nicm 97: }
1.8 nicm 98:
99: return (alerts);
100: }
101:
102: void
103: alerts_check_session(struct session *s)
104: {
105: struct winlink *wl;
106:
107: RB_FOREACH(wl, winlinks, &s->windows)
108: alerts_check_all(s, wl);
109: }
110:
1.12 nicm 111: static int
1.1 nicm 112: alerts_enabled(struct window *w, int flags)
113: {
1.7 nicm 114: if (flags & WINDOW_BELL)
115: return (1);
1.1 nicm 116: if (flags & WINDOW_ACTIVITY) {
1.4 nicm 117: if (options_get_number(w->options, "monitor-activity"))
1.1 nicm 118: return (1);
119: }
120: if (flags & WINDOW_SILENCE) {
1.4 nicm 121: if (options_get_number(w->options, "monitor-silence") != 0)
1.1 nicm 122: return (1);
123: }
124: return (0);
125: }
126:
127: void
128: alerts_reset_all(void)
129: {
130: struct window *w;
131:
132: RB_FOREACH(w, windows, &windows)
133: alerts_reset(w);
134: }
135:
1.12 nicm 136: static void
1.1 nicm 137: alerts_reset(struct window *w)
138: {
139: struct timeval tv;
140:
141: w->flags &= ~WINDOW_SILENCE;
142: event_del(&w->alerts_timer);
143:
144: timerclear(&tv);
1.4 nicm 145: tv.tv_sec = options_get_number(w->options, "monitor-silence");
1.1 nicm 146:
147: log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec);
148: if (tv.tv_sec != 0)
149: event_add(&w->alerts_timer, &tv);
150: }
151:
152: void
153: alerts_queue(struct window *w, int flags)
154: {
1.3 nicm 155: if (w->flags & WINDOW_ACTIVITY)
156: alerts_reset(w);
157:
1.1 nicm 158: if (!event_initialized(&w->alerts_timer))
159: evtimer_set(&w->alerts_timer, alerts_timer, w);
160:
1.11 nicm 161: if ((w->flags & flags) != flags) {
1.6 nicm 162: w->flags |= flags;
163: log_debug("@%u alerts flags added %#x", w->id, flags);
1.11 nicm 164: }
1.6 nicm 165:
1.11 nicm 166: if (!alerts_fired && alerts_enabled(w, flags)) {
167: log_debug("alerts check queued (by @%u)", w->id);
168: event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
169: alerts_fired = 1;
1.1 nicm 170: }
171: }
172:
1.12 nicm 173: static int
1.1 nicm 174: alerts_check_bell(struct session *s, struct winlink *wl)
175: {
176: struct client *c;
177: struct window *w = wl->window;
178: int action, visual;
179:
1.8 nicm 180: if (!(w->flags & WINDOW_BELL))
1.1 nicm 181: return (0);
1.8 nicm 182: if (s->curw != wl) {
1.1 nicm 183: wl->flags |= WINLINK_BELL;
1.8 nicm 184: w->flags &= ~WINDOW_BELL;
185: }
1.1 nicm 186: if (s->curw->window == w)
187: w->flags &= ~WINDOW_BELL;
188:
1.4 nicm 189: action = options_get_number(s->options, "bell-action");
1.1 nicm 190: if (action == BELL_NONE)
191: return (0);
192:
1.4 nicm 193: visual = options_get_number(s->options, "visual-bell");
1.1 nicm 194: TAILQ_FOREACH(c, &clients, entry) {
195: if (c->session != s || c->flags & CLIENT_CONTROL)
196: continue;
197: if (!visual) {
198: if ((action == BELL_CURRENT &&
199: c->session->curw->window == w) ||
200: (action == BELL_OTHER &&
201: c->session->curw->window != w) ||
202: action == BELL_ANY)
1.2 nicm 203: tty_putcode(&c->tty, TTYC_BEL);
1.1 nicm 204: continue;
205: }
206: if (action == BELL_CURRENT && c->session->curw->window == w)
207: status_message_set(c, "Bell in current window");
208: else if (action == BELL_ANY || (action == BELL_OTHER &&
209: c->session->curw->window != w))
210: status_message_set(c, "Bell in window %d", wl->idx);
211: }
212:
213: return (WINDOW_BELL);
214: }
215:
1.12 nicm 216: static int
1.1 nicm 217: alerts_check_activity(struct session *s, struct winlink *wl)
218: {
219: struct client *c;
220: struct window *w = wl->window;
221:
222: if (s->curw->window == w)
223: w->flags &= ~WINDOW_ACTIVITY;
224:
225: if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY)
226: return (0);
1.8 nicm 227: if (s->curw == wl)
1.1 nicm 228: return (0);
229:
1.4 nicm 230: if (!options_get_number(w->options, "monitor-activity"))
1.1 nicm 231: return (0);
232:
1.4 nicm 233: if (options_get_number(s->options, "bell-on-alert"))
1.1 nicm 234: alerts_ring_bell(s);
235: wl->flags |= WINLINK_ACTIVITY;
236:
1.4 nicm 237: if (options_get_number(s->options, "visual-activity")) {
1.1 nicm 238: TAILQ_FOREACH(c, &clients, entry) {
239: if (c->session != s)
240: continue;
241: status_message_set(c, "Activity in window %d", wl->idx);
242: }
243: }
244:
245: return (WINDOW_ACTIVITY);
246: }
247:
1.12 nicm 248: static int
1.1 nicm 249: alerts_check_silence(struct session *s, struct winlink *wl)
250: {
251: struct client *c;
252: struct window *w = wl->window;
253:
254: if (s->curw->window == w)
255: w->flags &= ~WINDOW_SILENCE;
256:
257: if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
258: return (0);
1.8 nicm 259: if (s->curw == wl)
1.1 nicm 260: return (0);
261:
1.4 nicm 262: if (options_get_number(w->options, "monitor-silence") == 0)
1.1 nicm 263: return (0);
264:
1.4 nicm 265: if (options_get_number(s->options, "bell-on-alert"))
1.1 nicm 266: alerts_ring_bell(s);
267: wl->flags |= WINLINK_SILENCE;
268:
1.4 nicm 269: if (options_get_number(s->options, "visual-silence")) {
1.1 nicm 270: TAILQ_FOREACH(c, &clients, entry) {
271: if (c->session != s)
272: continue;
273: status_message_set(c, "Silence in window %d", wl->idx);
274: }
275: }
276:
277: return (WINDOW_SILENCE);
278: }
279:
1.12 nicm 280: static void
1.1 nicm 281: alerts_ring_bell(struct session *s)
282: {
283: struct client *c;
284:
285: TAILQ_FOREACH(c, &clients, entry) {
286: if (c->session == s && !(c->flags & CLIENT_CONTROL))
1.2 nicm 287: tty_putcode(&c->tty, TTYC_BEL);
1.1 nicm 288: }
289: }