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