/* $OpenBSD$ */ /* * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include "tmux.h" 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 *); void ring_bell(struct session *); /* Window functions that need to happen every loop. */ void server_window_loop(void) { struct window *w; struct winlink *wl; struct window_pane *wp; struct session *s; u_int i; for (i = 0; i < ARRAY_LENGTH(&windows); i++) { w = ARRAY_ITEM(&windows, i); if (w == NULL) continue; RB_FOREACH(s, sessions, &sessions) { wl = session_has(s, w); if (wl == NULL) continue; if (server_window_check_bell(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); } } } /* Check for bell in window. */ int server_window_check_bell(struct session *s, struct winlink *wl) { struct client *c; struct window *w = wl->window; u_int i; int action, visual; if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL) return (0); if (s->curw != wl || s->flags & SESSION_UNATTACHED) wl->flags |= WINLINK_BELL; if (s->flags & SESSION_UNATTACHED) return (0); if (s->curw->window == w) w->flags &= ~WINDOW_BELL; visual = options_get_number(&s->options, "visual-bell"); action = options_get_number(&s->options, "bell-action"); if (action == BELL_NONE) return (0); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s || c->flags & CLIENT_CONTROL) continue; if (!visual) { if (c->session->curw->window == w || action == BELL_ANY) tty_bell(&c->tty); continue; } if (c->session->curw->window == w) status_message_set(c, "Bell in current window"); else if (action == BELL_ANY) status_message_set(c, "Bell in window %u", wl->idx); } return (1); } /* Check for activity in window. */ int server_window_check_activity(struct session *s, struct winlink *wl) { struct client *c; struct window *w = wl->window; u_int i; if (s->curw->window == w) w->flags &= ~WINDOW_ACTIVITY; if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY) return (0); if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) return (0); if (!options_get_number(&w->options, "monitor-activity")) return (0); if (options_get_number(&s->options, "bell-on-alert")) ring_bell(s); wl->flags |= WINLINK_ACTIVITY; if (options_get_number(&s->options, "visual-activity")) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) continue; status_message_set(c, "Activity in window %u", wl->idx); } } 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 && !(s->flags & SESSION_UNATTACHED)) { /* * 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); if (options_get_number(&s->options, "bell-on-alert")) ring_bell(s); 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", wl->idx); } } return (1); } /* Check for content change in window. */ int server_window_check_content( struct session *s, struct winlink *wl, struct window_pane *wp) { struct client *c; struct window *w = wl->window; u_int i; char *found, *ptr; /* Activity flag must be set for new content. */ if (s->curw->window == w) w->flags &= ~WINDOW_ACTIVITY; if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_CONTENT) return (0); if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) return (0); ptr = options_get_string(&w->options, "monitor-content"); if (ptr == NULL || *ptr == '\0') return (0); if ((found = window_pane_search(wp, ptr, NULL)) == NULL) return (0); free(found); if (options_get_number(&s->options, "bell-on-alert")) ring_bell(s); wl->flags |= WINLINK_CONTENT; if (options_get_number(&s->options, "visual-content")) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) continue; status_message_set(c, "Content in window %u", wl->idx); } } return (1); } /* Ring terminal bell. */ void ring_bell(struct session *s) { struct client *c; u_int i; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c != NULL && c->session == s && !(c->flags & CLIENT_CONTROL)) tty_bell(&c->tty); } }