Annotation of src/usr.bin/tmux/alerts.c, Revision 1.2
1.2 ! nicm 1: /* $OpenBSD: alerts.c,v 1.1 2015/08/29 08:30:54 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
38: alerts_timer(unused int fd, unused short events, void *arg)
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
48: alerts_callback(unused int fd, unused short events, unused void *arg)
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: {
80: struct session *s;
81:
82: if (flags & WINDOW_ACTIVITY) {
83: if (options_get_number(&w->options, "monitor-activity"))
84: return (1);
85: }
86: if (flags & WINDOW_SILENCE) {
87: if (options_get_number(&w->options, "monitor-silence") != 0)
88: return (1);
89: }
90: if (~flags & WINDOW_BELL)
91: return (0);
92: RB_FOREACH(s, sessions, &sessions) {
93: if (!session_has(s, w))
94: continue;
95: if (options_get_number(&s->options, "bell-action") != BELL_NONE)
96: return (1);
97: }
98: return (0);
99: }
100:
101: void
102: alerts_reset_all(void)
103: {
104: struct window *w;
105:
106: RB_FOREACH(w, windows, &windows)
107: alerts_reset(w);
108: }
109:
110: void
111: alerts_reset(struct window *w)
112: {
113: struct timeval tv;
114:
115: w->flags &= ~WINDOW_SILENCE;
116: event_del(&w->alerts_timer);
117:
118: timerclear(&tv);
119: tv.tv_sec = options_get_number(&w->options, "monitor-silence");
120:
121: log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec);
122: if (tv.tv_sec != 0)
123: event_add(&w->alerts_timer, &tv);
124: }
125:
126: void
127: alerts_queue(struct window *w, int flags)
128: {
129: if (!event_initialized(&w->alerts_timer))
130: evtimer_set(&w->alerts_timer, alerts_timer, w);
131:
132: if (w->flags & flags)
133: return;
134: w->flags |= flags;
135: log_debug("@%u alerts flags added %#x", w->id, flags);
136:
137: if (!alerts_fired && alerts_enabled(w, flags)) {
138: log_debug("alerts check queued (by @%u)", w->id);
139: event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
140: alerts_fired = 1;
141: }
142:
143: if (flags & WINDOW_ACTIVITY)
144: alerts_reset(w);
145: }
146:
147: int
148: alerts_check_bell(struct session *s, struct winlink *wl)
149: {
150: struct client *c;
151: struct window *w = wl->window;
152: int action, visual;
153:
154: if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL)
155: return (0);
156: if (s->curw != wl || s->flags & SESSION_UNATTACHED)
157: wl->flags |= WINLINK_BELL;
158: if (s->flags & SESSION_UNATTACHED)
159: return (0);
160: if (s->curw->window == w)
161: w->flags &= ~WINDOW_BELL;
162:
163: action = options_get_number(&s->options, "bell-action");
164: if (action == BELL_NONE)
165: return (0);
166:
167: visual = options_get_number(&s->options, "visual-bell");
168: TAILQ_FOREACH(c, &clients, entry) {
169: if (c->session != s || c->flags & CLIENT_CONTROL)
170: continue;
171: if (!visual) {
172: if ((action == BELL_CURRENT &&
173: c->session->curw->window == w) ||
174: (action == BELL_OTHER &&
175: c->session->curw->window != w) ||
176: action == BELL_ANY)
1.2 ! nicm 177: tty_putcode(&c->tty, TTYC_BEL);
1.1 nicm 178: continue;
179: }
180: if (action == BELL_CURRENT && c->session->curw->window == w)
181: status_message_set(c, "Bell in current window");
182: else if (action == BELL_ANY || (action == BELL_OTHER &&
183: c->session->curw->window != w))
184: status_message_set(c, "Bell in window %d", wl->idx);
185: }
186:
187: return (WINDOW_BELL);
188: }
189:
190: int
191: alerts_check_activity(struct session *s, struct winlink *wl)
192: {
193: struct client *c;
194: struct window *w = wl->window;
195:
196: if (s->curw->window == w)
197: w->flags &= ~WINDOW_ACTIVITY;
198:
199: if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY)
200: return (0);
201: if (s->curw == wl && !(s->flags & SESSION_UNATTACHED))
202: return (0);
203:
204: if (!options_get_number(&w->options, "monitor-activity"))
205: return (0);
206:
207: if (options_get_number(&s->options, "bell-on-alert"))
208: alerts_ring_bell(s);
209: wl->flags |= WINLINK_ACTIVITY;
210:
211: if (options_get_number(&s->options, "visual-activity")) {
212: TAILQ_FOREACH(c, &clients, entry) {
213: if (c->session != s)
214: continue;
215: status_message_set(c, "Activity in window %d", wl->idx);
216: }
217: }
218:
219: return (WINDOW_ACTIVITY);
220: }
221:
222: int
223: alerts_check_silence(struct session *s, struct winlink *wl)
224: {
225: struct client *c;
226: struct window *w = wl->window;
227:
228: if (s->curw->window == w)
229: w->flags &= ~WINDOW_SILENCE;
230:
231: if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
232: return (0);
233: if (s->curw == wl && !(s->flags & SESSION_UNATTACHED))
234: return (0);
235:
236: if (options_get_number(&w->options, "monitor-silence") == 0)
237: return (0);
238:
239: if (options_get_number(&s->options, "bell-on-alert"))
240: alerts_ring_bell(s);
241: wl->flags |= WINLINK_SILENCE;
242:
243: if (options_get_number(&s->options, "visual-silence")) {
244: TAILQ_FOREACH(c, &clients, entry) {
245: if (c->session != s)
246: continue;
247: status_message_set(c, "Silence in window %d", wl->idx);
248: }
249: }
250:
251: return (WINDOW_SILENCE);
252: }
253:
254: void
255: alerts_ring_bell(struct session *s)
256: {
257: struct client *c;
258:
259: TAILQ_FOREACH(c, &clients, entry) {
260: if (c->session == s && !(c->flags & CLIENT_CONTROL))
1.2 ! nicm 261: tty_putcode(&c->tty, TTYC_BEL);
1.1 nicm 262: }
263: }