Annotation of src/usr.bin/tmux/alerts.c, Revision 1.7
1.7 ! nicm 1: /* $OpenBSD: alerts.c,v 1.6 2015/11/19 14:55:25 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2015 Nicholas Marriott <nicm@users.sourceforge.net>
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:
32: int alerts_check_bell(struct session *, struct winlink *);
33: int alerts_check_activity(struct session *, struct winlink *);
34: int alerts_check_silence(struct session *, struct winlink *);
35: void alerts_ring_bell(struct session *);
36:
37: void
1.5 nicm 38: alerts_timer(__unused int fd, __unused short events, void *arg)
1.1 nicm 39: {
40: struct window *w = arg;
41:
42: log_debug("@%u alerts timer expired", w->id);
43: alerts_reset(w);
44: alerts_queue(w, WINDOW_SILENCE);
45: }
46:
47: void
1.5 nicm 48: alerts_callback(__unused int fd, __unused short events, __unused void *arg)
1.1 nicm 49: {
50: struct window *w;
51: struct session *s;
52: struct winlink *wl;
53: int flags, alerts;
54:
55: RB_FOREACH(w, windows, &windows) {
56: RB_FOREACH(s, sessions, &sessions) {
57: RB_FOREACH(wl, winlinks, &s->windows) {
58: if (wl->window != w)
59: continue;
60: flags = w->flags;
61:
62: alerts = alerts_check_bell(s, wl);
63: alerts |= alerts_check_activity(s, wl);
64: alerts |= alerts_check_silence(s, wl);
65: if (alerts != 0)
66: server_status_session(s);
67:
68: log_debug("%s:%d @%u alerts check, alerts %#x, "
69: "flags %#x", s->name, wl->idx, w->id,
70: alerts, flags);
71: }
72: }
73: }
74: alerts_fired = 0;
75: }
76:
77: int
78: alerts_enabled(struct window *w, int flags)
79: {
1.7 ! nicm 80: if (flags & WINDOW_BELL)
! 81: return (1);
1.1 nicm 82: if (flags & WINDOW_ACTIVITY) {
1.4 nicm 83: if (options_get_number(w->options, "monitor-activity"))
1.1 nicm 84: return (1);
85: }
86: if (flags & WINDOW_SILENCE) {
1.4 nicm 87: if (options_get_number(w->options, "monitor-silence") != 0)
1.1 nicm 88: return (1);
89: }
90: return (0);
91: }
92:
93: void
94: alerts_reset_all(void)
95: {
96: struct window *w;
97:
98: RB_FOREACH(w, windows, &windows)
99: alerts_reset(w);
100: }
101:
102: void
103: alerts_reset(struct window *w)
104: {
105: struct timeval tv;
106:
107: w->flags &= ~WINDOW_SILENCE;
108: event_del(&w->alerts_timer);
109:
110: timerclear(&tv);
1.4 nicm 111: tv.tv_sec = options_get_number(w->options, "monitor-silence");
1.1 nicm 112:
113: log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec);
114: if (tv.tv_sec != 0)
115: event_add(&w->alerts_timer, &tv);
116: }
117:
118: void
119: alerts_queue(struct window *w, int flags)
120: {
1.3 nicm 121: if (w->flags & WINDOW_ACTIVITY)
122: alerts_reset(w);
123:
1.1 nicm 124: if (!event_initialized(&w->alerts_timer))
125: evtimer_set(&w->alerts_timer, alerts_timer, w);
126:
1.6 nicm 127: if (!alerts_fired) {
128: w->flags |= flags;
129: log_debug("@%u alerts flags added %#x", w->id, flags);
130:
131: if (alerts_enabled(w, flags)) {
132: log_debug("alerts check queued (by @%u)", w->id);
133: event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
134: alerts_fired = 1;
135: }
1.1 nicm 136: }
137: }
138:
139: int
140: alerts_check_bell(struct session *s, struct winlink *wl)
141: {
142: struct client *c;
143: struct window *w = wl->window;
144: int action, visual;
145:
146: if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL)
147: return (0);
148: if (s->curw != wl || s->flags & SESSION_UNATTACHED)
149: wl->flags |= WINLINK_BELL;
150: if (s->flags & SESSION_UNATTACHED)
151: return (0);
152: if (s->curw->window == w)
153: w->flags &= ~WINDOW_BELL;
154:
1.4 nicm 155: action = options_get_number(s->options, "bell-action");
1.1 nicm 156: if (action == BELL_NONE)
157: return (0);
158:
1.4 nicm 159: visual = options_get_number(s->options, "visual-bell");
1.1 nicm 160: TAILQ_FOREACH(c, &clients, entry) {
161: if (c->session != s || c->flags & CLIENT_CONTROL)
162: continue;
163: if (!visual) {
164: if ((action == BELL_CURRENT &&
165: c->session->curw->window == w) ||
166: (action == BELL_OTHER &&
167: c->session->curw->window != w) ||
168: action == BELL_ANY)
1.2 nicm 169: tty_putcode(&c->tty, TTYC_BEL);
1.1 nicm 170: continue;
171: }
172: if (action == BELL_CURRENT && c->session->curw->window == w)
173: status_message_set(c, "Bell in current window");
174: else if (action == BELL_ANY || (action == BELL_OTHER &&
175: c->session->curw->window != w))
176: status_message_set(c, "Bell in window %d", wl->idx);
177: }
178:
179: return (WINDOW_BELL);
180: }
181:
182: int
183: alerts_check_activity(struct session *s, struct winlink *wl)
184: {
185: struct client *c;
186: struct window *w = wl->window;
187:
188: if (s->curw->window == w)
189: w->flags &= ~WINDOW_ACTIVITY;
190:
191: if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY)
192: return (0);
193: if (s->curw == wl && !(s->flags & SESSION_UNATTACHED))
194: return (0);
195:
1.4 nicm 196: if (!options_get_number(w->options, "monitor-activity"))
1.1 nicm 197: return (0);
198:
1.4 nicm 199: if (options_get_number(s->options, "bell-on-alert"))
1.1 nicm 200: alerts_ring_bell(s);
201: wl->flags |= WINLINK_ACTIVITY;
202:
1.4 nicm 203: if (options_get_number(s->options, "visual-activity")) {
1.1 nicm 204: TAILQ_FOREACH(c, &clients, entry) {
205: if (c->session != s)
206: continue;
207: status_message_set(c, "Activity in window %d", wl->idx);
208: }
209: }
210:
211: return (WINDOW_ACTIVITY);
212: }
213:
214: int
215: alerts_check_silence(struct session *s, struct winlink *wl)
216: {
217: struct client *c;
218: struct window *w = wl->window;
219:
220: if (s->curw->window == w)
221: w->flags &= ~WINDOW_SILENCE;
222:
223: if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
224: return (0);
225: if (s->curw == wl && !(s->flags & SESSION_UNATTACHED))
226: return (0);
227:
1.4 nicm 228: if (options_get_number(w->options, "monitor-silence") == 0)
1.1 nicm 229: return (0);
230:
1.4 nicm 231: if (options_get_number(s->options, "bell-on-alert"))
1.1 nicm 232: alerts_ring_bell(s);
233: wl->flags |= WINLINK_SILENCE;
234:
1.4 nicm 235: if (options_get_number(s->options, "visual-silence")) {
1.1 nicm 236: TAILQ_FOREACH(c, &clients, entry) {
237: if (c->session != s)
238: continue;
239: status_message_set(c, "Silence in window %d", wl->idx);
240: }
241: }
242:
243: return (WINDOW_SILENCE);
244: }
245:
246: void
247: alerts_ring_bell(struct session *s)
248: {
249: struct client *c;
250:
251: TAILQ_FOREACH(c, &clients, entry) {
252: if (c->session == s && !(c->flags & CLIENT_CONTROL))
1.2 nicm 253: tty_putcode(&c->tty, TTYC_BEL);
1.1 nicm 254: }
255: }