From e26a351865a0d969b3f40ca3c14be7ff8d7533ad Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 6 Dec 2010 22:51:02 +0000 Subject: [PATCH] Add an option to alert (monitor) for silence (lack of activity) in a window. From Thomas Adam. --- cmd-choose-window.c | 2 ++ cmd-set-option.c | 2 ++ input.c | 2 ++ server-window.c | 53 ++++++++++++++++++++++++++++++++++++++++++++- status.c | 2 ++ tmux.1 | 17 +++++++++++++++ tmux.c | 2 ++ tmux.h | 6 ++++- window.c | 8 +++++++ 9 files changed, 92 insertions(+), 2 deletions(-) diff --git a/cmd-choose-window.c b/cmd-choose-window.c index e341dd41..b3e4b2b3 100644 --- a/cmd-choose-window.c +++ b/cmd-choose-window.c @@ -87,6 +87,8 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx) flag = '!'; else if (wm->flags & WINLINK_CONTENT) flag = '+'; + else if (wm->flags & WINLINK_SILENCE) + flag = '~'; else if (wm == s->curw) flag = '*'; else if (wm == TAILQ_FIRST(&s->lastw)) diff --git a/cmd-set-option.c b/cmd-set-option.c index 684f1b04..7856a52e 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -136,6 +136,7 @@ const struct set_option_entry set_session_option_table[] = { { "visual-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "visual-bell", SET_OPTION_FLAG, 0, 0, NULL }, { "visual-content", SET_OPTION_FLAG, 0, 0, NULL }, + { "visual-silence", SET_OPTION_FLAG, 0, 0, NULL }, { NULL, 0, 0, 0, NULL } }; @@ -157,6 +158,7 @@ const struct set_option_entry set_window_option_table[] = { { "mode-mouse", SET_OPTION_FLAG, 0, 0, NULL }, { "monitor-activity", SET_OPTION_FLAG, 0, 0, NULL }, { "monitor-content", SET_OPTION_STRING, 0, 0, NULL }, + { "monitor-silence",SET_OPTION_NUMBER, 0, INT_MAX, NULL}, { "remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, { "synchronize-panes", SET_OPTION_FLAG, 0, 0, NULL }, { "utf8", SET_OPTION_FLAG, 0, 0, NULL }, diff --git a/input.c b/input.c index f49591a7..4a964550 100644 --- a/input.c +++ b/input.c @@ -681,7 +681,9 @@ input_parse(struct window_pane *wp) if (EVBUFFER_LENGTH(evb) == 0) return; + wp->window->flags |= WINDOW_ACTIVITY; + wp->window->flags &= ~WINDOW_SILENCE; /* * Open the screen. Use NULL wp if there is a mode set as don't want to diff --git a/server-window.c b/server-window.c index 634a1b8a..abf82499 100644 --- a/server-window.c +++ b/server-window.c @@ -26,6 +26,7 @@ int server_window_backoff(struct window_pane *); int server_window_check_bell(struct session *, struct winlink *); int server_window_check_activity(struct session *, struct winlink *); +int server_window_check_silence(struct session *, struct winlink *); int server_window_check_content( struct session *, struct winlink *, struct window_pane *); @@ -53,7 +54,8 @@ server_window_loop(void) continue; if (server_window_check_bell(s, wl) || - server_window_check_activity(s, wl)) + server_window_check_activity(s, wl) || + server_window_check_silence(s, wl)) server_status_session(s); TAILQ_FOREACH(wp, &w->panes, entry) server_window_check_content(s, wl, wp); @@ -151,6 +153,55 @@ server_window_check_activity(struct session *s, struct winlink *wl) return (1); } +/* Check for silence in window. */ +int +server_window_check_silence(struct session *s, struct winlink *wl) +{ + struct client *c; + struct window *w = wl->window; + struct timeval timer; + u_int i; + int silence_interval, timer_difference; + + if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE) + return (0); + + if (s->curw == wl) { + /* + * Reset the timer for this window if we've focused it. We + * don't want the timer tripping as soon as we've switched away + * from this window. + */ + if (gettimeofday(&w->silence_timer, NULL) != 0) + fatal("gettimeofday failed."); + + return (0); + } + + silence_interval = options_get_number(&w->options, "monitor-silence"); + if (silence_interval == 0) + return (0); + + if (gettimeofday(&timer, NULL) != 0) + fatal("gettimeofday"); + timer_difference = timer.tv_sec - w->silence_timer.tv_sec; + if (timer_difference <= silence_interval) + return (0); + wl->flags |= WINLINK_SILENCE; + + if (options_get_number(&s->options, "visual-silence")) { + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session != s) + continue; + status_message_set(c, "Silence in window %u", + winlink_find_by_window(&s->windows, w)->idx); + } + } + + return (1); +} + /* Check for content change in window. */ int server_window_check_content( diff --git a/status.c b/status.c index b1d93c97..65a0afeb 100644 --- a/status.c +++ b/status.c @@ -395,6 +395,8 @@ status_replace1(struct client *c,struct winlink *wl, tmp[0] = '!'; else if (wl->flags & WINLINK_ACTIVITY) tmp[0] = '#'; + else if (wl->flags & WINLINK_SILENCE) + tmp[0] = '~'; else if (wl == s->curw) tmp[0] = '*'; else if (wl == TAILQ_FIRST(&s->lastw)) diff --git a/tmux.1 b/tmux.1 index de5144a5..8ce1cce9 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2053,6 +2053,12 @@ display a message when content is present in a window for which the .Ic monitor-content window option is enabled. +.It Xo Ic visual-silence +.Op Ic on | off +.Xc +If +.Ic monitor-silence +is enabled, prints a message after the interval has expired on a given window. .El .It Xo Ic set-window-option .Op Fl agu @@ -2175,6 +2181,16 @@ pattern .Ar match-string appears in the window, it is highlighted in the status line. .Pp +.It Xo Ic monitor-silence +.Op Ic interval +.Xc +Monitor for silence (no activity) in the window within +.Ic interval +seconds. +Windows that have been silent for the interval are highlighted in the +status line. +An interval of zero disables the monitoring. +.Pp .It Xo Ic remain-on-exit .Op Ic on | off .Xc @@ -2386,6 +2402,7 @@ The flag is one of the following symbols appended to the window name: .It Li "#" Ta "Window is monitored and activity has been detected." .It Li "!" Ta "A bell has occurred in the window." .It Li "+" Ta "Window is monitored for content and it has appeared." +.It Li "~" Ta "The window has been silent for the monitor-silence interval." .El .Pp The # symbol relates to the diff --git a/tmux.c b/tmux.c index c5793955..0ebeea28 100644 --- a/tmux.c +++ b/tmux.c @@ -379,6 +379,7 @@ main(int argc, char **argv) options_set_number(so, "visual-activity", 0); options_set_number(so, "visual-bell", 0); options_set_number(so, "visual-content", 0); + options_set_number(so, "visual-silence", 0); keylist = xmalloc(sizeof *keylist); ARRAY_INIT(keylist); @@ -402,6 +403,7 @@ main(int argc, char **argv) options_set_number(wo, "mode-mouse", 0); options_set_number(wo, "monitor-activity", 0); options_set_string(wo, "monitor-content", "%s", ""); + options_set_number(wo, "monitor-silence", 0); options_set_number(wo, "window-status-attr", 0); options_set_number(wo, "window-status-bg", 8); options_set_number(wo, "window-status-current-attr", 0); diff --git a/tmux.h b/tmux.h index e4323a5d..529b6439 100644 --- a/tmux.h +++ b/tmux.h @@ -830,6 +830,7 @@ TAILQ_HEAD(window_panes, window_pane); struct window { char *name; struct event name_timer; + struct timeval silence_timer; struct window_pane *active; struct window_pane *last; @@ -845,6 +846,7 @@ struct window { #define WINDOW_BELL 0x1 #define WINDOW_ACTIVITY 0x2 #define WINDOW_REDRAW 0x4 +#define WINDOW_SILENCE 0x8 struct options options; @@ -865,7 +867,9 @@ struct winlink { #define WINLINK_BELL 0x1 #define WINLINK_ACTIVITY 0x2 #define WINLINK_CONTENT 0x4 -#define WINLINK_ALERTFLAGS (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_CONTENT) +#define WINLINK_SILENCE 0x8 +#define WINLINK_ALERTFLAGS \ + (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_CONTENT|WINLINK_SILENCE) RB_ENTRY(winlink) entry; TAILQ_ENTRY(winlink) sentry; diff --git a/window.c b/window.c index a7a5c40e..95877cb5 100644 --- a/window.c +++ b/window.c @@ -639,6 +639,14 @@ window_pane_read_callback(unused struct bufferevent *bufev, void *data) input_parse(wp); wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); + + /* + * If we get here, we're not outputting anymore, so set the silence + * flag on the window. + */ + wp->window->flags |= WINDOW_SILENCE; + if (gettimeofday(&wp->window->silence_timer, NULL) != 0) + fatal("gettimeofday failed."); } /* ARGSUSED */