Annotation of src/usr.bin/tmux/alerts.c, Revision 1.1
1.1 ! nicm 1: /* $OpenBSD: server-window.c,v 1.39 2015/08/29 00:29:15 nicm Exp $ */
! 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)
! 177: tty_bell(&c->tty);
! 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))
! 261: tty_bell(&c->tty);
! 262: }
! 263: }