Annotation of embedaddon/tmux/alerts.c, revision 1.1.1.1
1.1 misho 1: /* $OpenBSD$ */
2:
3: /*
4: * Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
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: #include <stdlib.h>
23:
24: #include "tmux.h"
25:
26: static int alerts_fired;
27:
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:
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 *);
37: static void printflike(2, 3) alerts_set_message(struct session *, const char *,
38: ...);
39: static void alerts_ring_bell(struct session *);
40:
41: static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list);
42:
43: static void
44: alerts_timer(__unused int fd, __unused short events, void *arg)
45: {
46: struct window *w = arg;
47:
48: log_debug("@%u alerts timer expired", w->id);
49: alerts_reset(w);
50: alerts_queue(w, WINDOW_SILENCE);
51: }
52:
53: static void
54: alerts_callback(__unused int fd, __unused short events, __unused void *arg)
55: {
56: struct window *w, *w1;
57: int alerts;
58:
59: TAILQ_FOREACH_SAFE(w, &alerts_list, alerts_entry, w1) {
60: alerts = alerts_check_all(w);
61: log_debug("@%u alerts check, alerts %#x", w->id, alerts);
62:
63: w->alerts_queued = 0;
64: TAILQ_REMOVE(&alerts_list, w, alerts_entry);
65:
66: w->flags &= ~WINDOW_ALERTFLAGS;
67: window_remove_ref(w);
68: }
69: alerts_fired = 0;
70: }
71:
72: static int
73: alerts_check_all(struct window *w)
74: {
75: int alerts;
76:
77: alerts = alerts_check_bell(w);
78: alerts |= alerts_check_activity(w);
79: alerts |= alerts_check_silence(w);
80: return (alerts);
81: }
82:
83: void
84: alerts_check_session(struct session *s)
85: {
86: struct winlink *wl;
87:
88: RB_FOREACH(wl, winlinks, &s->windows)
89: alerts_check_all(wl->window);
90: }
91:
92: static int
93: alerts_enabled(struct window *w, int flags)
94: {
95: if (flags & WINDOW_BELL)
96: return (1);
97: if (flags & WINDOW_ACTIVITY) {
98: if (options_get_number(w->options, "monitor-activity"))
99: return (1);
100: }
101: if (flags & WINDOW_SILENCE) {
102: if (options_get_number(w->options, "monitor-silence") != 0)
103: return (1);
104: }
105: return (0);
106: }
107:
108: void
109: alerts_reset_all(void)
110: {
111: struct window *w;
112:
113: RB_FOREACH(w, windows, &windows)
114: alerts_reset(w);
115: }
116:
117: static void
118: alerts_reset(struct window *w)
119: {
120: struct timeval tv;
121:
122: w->flags &= ~WINDOW_SILENCE;
123: event_del(&w->alerts_timer);
124:
125: timerclear(&tv);
126: tv.tv_sec = options_get_number(w->options, "monitor-silence");
127:
128: log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec);
129: if (tv.tv_sec != 0)
130: event_add(&w->alerts_timer, &tv);
131: }
132:
133: void
134: alerts_queue(struct window *w, int flags)
135: {
136: if (w->flags & WINDOW_ACTIVITY)
137: alerts_reset(w);
138:
139: if (!event_initialized(&w->alerts_timer))
140: evtimer_set(&w->alerts_timer, alerts_timer, w);
141:
142: if ((w->flags & flags) != flags) {
143: w->flags |= flags;
144: log_debug("@%u alerts flags added %#x", w->id, flags);
145: }
146:
147: if (!w->alerts_queued) {
148: w->alerts_queued = 1;
149: TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
150: w->references++;
151: }
152:
153: if (!alerts_fired && alerts_enabled(w, flags)) {
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: }
158: }
159:
160: static int
161: alerts_check_bell(struct window *w)
162: {
163: struct window *ws;
164: struct winlink *wl;
165: struct session *s;
166: struct client *c;
167: int action, visual;
168:
169: if (~w->flags & WINDOW_BELL)
170: return (0);
171:
172: TAILQ_FOREACH(wl, &w->winlinks, wentry)
173: wl->session->flags &= ~SESSION_ALERTED;
174:
175: TAILQ_FOREACH(wl, &w->winlinks, wentry) {
176: if (wl->flags & WINLINK_BELL)
177: continue;
178: s = wl->session;
179: if (s->curw != wl) {
180: wl->flags |= WINLINK_BELL;
181: notify_winlink("alert-bell", s, wl);
182: }
183:
184: if (s->flags & SESSION_ALERTED)
185: continue;
186: s->flags |= SESSION_ALERTED;
187:
188: action = options_get_number(s->options, "bell-action");
189: if (action == BELL_NONE)
190: return (0);
191:
192: visual = options_get_number(s->options, "visual-bell");
193: TAILQ_FOREACH(c, &clients, entry) {
194: if (c->session != s || c->flags & CLIENT_CONTROL)
195: continue;
196: ws = c->session->curw->window;
197:
198: if (action == BELL_CURRENT && ws != w)
199: action = BELL_NONE;
200: if (action == BELL_OTHER && ws != w)
201: action = BELL_NONE;
202:
203: if (!visual) {
204: if (action != BELL_NONE)
205: tty_putcode(&c->tty, TTYC_BEL);
206: continue;
207: }
208: if (action == BELL_CURRENT)
209: status_message_set(c, "Bell in current window");
210: else if (action != BELL_NONE) {
211: status_message_set(c, "Bell in window %d",
212: wl->idx);
213: }
214: }
215: }
216:
217: return (WINDOW_BELL);
218: }
219:
220: static int
221: alerts_check_activity(struct window *w)
222: {
223: struct winlink *wl;
224: struct session *s;
225:
226: if (~w->flags & WINDOW_ACTIVITY)
227: return (0);
228: if (!options_get_number(w->options, "monitor-activity"))
229: return (0);
230:
231: TAILQ_FOREACH(wl, &w->winlinks, wentry)
232: wl->session->flags &= ~SESSION_ALERTED;
233:
234: TAILQ_FOREACH(wl, &w->winlinks, wentry) {
235: if (wl->flags & WINLINK_ACTIVITY)
236: continue;
237: s = wl->session;
238: if (s->curw == wl)
239: continue;
240:
241: wl->flags |= WINLINK_ACTIVITY;
242: notify_winlink("alert-activity", s, wl);
243:
244: if (s->flags & SESSION_ALERTED)
245: continue;
246: s->flags |= SESSION_ALERTED;
247:
248: if (options_get_number(s->options, "bell-on-alert"))
249: alerts_ring_bell(s);
250: if (options_get_number(s->options, "visual-activity"))
251: alerts_set_message(s, "Activity in window %d", wl->idx);
252: }
253:
254: return (WINDOW_ACTIVITY);
255: }
256:
257: static int
258: alerts_check_silence(struct window *w)
259: {
260: struct winlink *wl;
261: struct session *s;
262:
263: if (~w->flags & WINDOW_SILENCE)
264: return (0);
265: if (!options_get_number(w->options, "monitor-silence"))
266: return (0);
267:
268: TAILQ_FOREACH(wl, &w->winlinks, wentry)
269: wl->session->flags &= ~SESSION_ALERTED;
270:
271: TAILQ_FOREACH(wl, &w->winlinks, wentry) {
272: if (wl->flags & WINLINK_SILENCE)
273: continue;
274: s = wl->session;
275: if (s->curw == wl)
276: continue;
277: wl->flags |= WINLINK_SILENCE;
278: notify_winlink("alert-silence", s, wl);
279:
280: if (s->flags & SESSION_ALERTED)
281: continue;
282: s->flags |= SESSION_ALERTED;
283:
284: if (options_get_number(s->options, "bell-on-alert"))
285: alerts_ring_bell(s);
286:
287: if (!options_get_number(s->options, "visual-silence"))
288: alerts_set_message(s, "Silence in window %d", wl->idx);
289: }
290:
291: return (WINDOW_SILENCE);
292: }
293:
294: static void
295: alerts_set_message(struct session *s, const char *fmt, ...)
296: {
297: struct client *c;
298: va_list ap;
299: char *message;
300:
301: va_start(ap, fmt);
302: xvasprintf(&message, fmt, ap);
303: va_end(ap);
304:
305: TAILQ_FOREACH(c, &clients, entry) {
306: if (c->session == s)
307: status_message_set(c, "%s", message);
308: }
309:
310: free(message);
311: }
312:
313: static void
314: alerts_ring_bell(struct session *s)
315: {
316: struct client *c;
317:
318: TAILQ_FOREACH(c, &clients, entry) {
319: if (c->session == s && !(c->flags & CLIENT_CONTROL))
320: tty_putcode(&c->tty, TTYC_BEL);
321: }
322: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>