Annotation of embedaddon/tmux/alerts.c, revision 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>