File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / alerts.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (6 years, 11 months ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

    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>