From b5aaefc727f303276a681d74f091f52a7e859d36 Mon Sep 17 00:00:00 2001 From: nicm Date: Sat, 29 Aug 2015 08:30:54 +0000 Subject: Move alerts onto events rather than checking every loop. --- Makefile | 4 +- alerts.c | 263 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ cmd-set-option.c | 2 + input.c | 9 +- server-window.c | 191 ---------------------------------------- server.c | 5 +- session.c | 1 + tmux.h | 11 ++- window.c | 23 ++--- 9 files changed, 293 insertions(+), 216 deletions(-) create mode 100644 alerts.c delete mode 100644 server-window.c diff --git a/Makefile b/Makefile index ac7e6e54..ad893d4b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ # $OpenBSD$ PROG= tmux -SRCS= arguments.c \ +SRCS= alerts.c \ + arguments.c \ attributes.c \ cfg.c \ client.c \ @@ -101,7 +102,6 @@ SRCS= arguments.c \ screen.c \ server-client.c \ server-fn.c \ - server-window.c \ server.c \ session.c \ signal.c \ diff --git a/alerts.c b/alerts.c new file mode 100644 index 00000000..cfdd30e3 --- /dev/null +++ b/alerts.c @@ -0,0 +1,263 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2015 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 "tmux.h" + +int alerts_fired; + +void alerts_timer(int, short, void *); +int alerts_enabled(struct window *, int); +void alerts_callback(int, short, void *); +void alerts_reset(struct window *); + +int alerts_check_bell(struct session *, struct winlink *); +int alerts_check_activity(struct session *, struct winlink *); +int alerts_check_silence(struct session *, struct winlink *); +void alerts_ring_bell(struct session *); + +void +alerts_timer(unused int fd, unused short events, void *arg) +{ + struct window *w = arg; + + log_debug("@%u alerts timer expired", w->id); + alerts_reset(w); + alerts_queue(w, WINDOW_SILENCE); +} + +void +alerts_callback(unused int fd, unused short events, unused void *arg) +{ + struct window *w; + struct session *s; + struct winlink *wl; + int flags, alerts; + + RB_FOREACH(w, windows, &windows) { + RB_FOREACH(s, sessions, &sessions) { + RB_FOREACH(wl, winlinks, &s->windows) { + if (wl->window != w) + continue; + flags = w->flags; + + alerts = alerts_check_bell(s, wl); + alerts |= alerts_check_activity(s, wl); + alerts |= alerts_check_silence(s, wl); + if (alerts != 0) + server_status_session(s); + + log_debug("%s:%d @%u alerts check, alerts %#x, " + "flags %#x", s->name, wl->idx, w->id, + alerts, flags); + } + } + } + alerts_fired = 0; +} + +int +alerts_enabled(struct window *w, int flags) +{ + struct session *s; + + if (flags & WINDOW_ACTIVITY) { + if (options_get_number(&w->options, "monitor-activity")) + return (1); + } + if (flags & WINDOW_SILENCE) { + if (options_get_number(&w->options, "monitor-silence") != 0) + return (1); + } + if (~flags & WINDOW_BELL) + return (0); + RB_FOREACH(s, sessions, &sessions) { + if (!session_has(s, w)) + continue; + if (options_get_number(&s->options, "bell-action") != BELL_NONE) + return (1); + } + return (0); +} + +void +alerts_reset_all(void) +{ + struct window *w; + + RB_FOREACH(w, windows, &windows) + alerts_reset(w); +} + +void +alerts_reset(struct window *w) +{ + struct timeval tv; + + w->flags &= ~WINDOW_SILENCE; + event_del(&w->alerts_timer); + + timerclear(&tv); + tv.tv_sec = options_get_number(&w->options, "monitor-silence"); + + log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec); + if (tv.tv_sec != 0) + event_add(&w->alerts_timer, &tv); +} + +void +alerts_queue(struct window *w, int flags) +{ + if (!event_initialized(&w->alerts_timer)) + evtimer_set(&w->alerts_timer, alerts_timer, w); + + if (w->flags & flags) + return; + w->flags |= flags; + log_debug("@%u alerts flags added %#x", w->id, flags); + + if (!alerts_fired && alerts_enabled(w, flags)) { + log_debug("alerts check queued (by @%u)", w->id); + event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL); + alerts_fired = 1; + } + + if (flags & WINDOW_ACTIVITY) + alerts_reset(w); +} + +int +alerts_check_bell(struct session *s, struct winlink *wl) +{ + struct client *c; + struct window *w = wl->window; + 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; + + action = options_get_number(&s->options, "bell-action"); + if (action == BELL_NONE) + return (0); + + visual = options_get_number(&s->options, "visual-bell"); + TAILQ_FOREACH(c, &clients, entry) { + if (c->session != s || c->flags & CLIENT_CONTROL) + continue; + if (!visual) { + if ((action == BELL_CURRENT && + c->session->curw->window == w) || + (action == BELL_OTHER && + c->session->curw->window != w) || + action == BELL_ANY) + tty_bell(&c->tty); + continue; + } + if (action == BELL_CURRENT && c->session->curw->window == w) + status_message_set(c, "Bell in current window"); + else if (action == BELL_ANY || (action == BELL_OTHER && + c->session->curw->window != w)) + status_message_set(c, "Bell in window %d", wl->idx); + } + + return (WINDOW_BELL); +} + +int +alerts_check_activity(struct session *s, struct winlink *wl) +{ + struct client *c; + struct window *w = wl->window; + + 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")) + alerts_ring_bell(s); + wl->flags |= WINLINK_ACTIVITY; + + if (options_get_number(&s->options, "visual-activity")) { + TAILQ_FOREACH(c, &clients, entry) { + if (c->session != s) + continue; + status_message_set(c, "Activity in window %d", wl->idx); + } + } + + return (WINDOW_ACTIVITY); +} + +int +alerts_check_silence(struct session *s, struct winlink *wl) +{ + struct client *c; + struct window *w = wl->window; + + if (s->curw->window == w) + w->flags &= ~WINDOW_SILENCE; + + if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE) + return (0); + if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) + return (0); + + if (options_get_number(&w->options, "monitor-silence") == 0) + return (0); + + if (options_get_number(&s->options, "bell-on-alert")) + alerts_ring_bell(s); + wl->flags |= WINLINK_SILENCE; + + if (options_get_number(&s->options, "visual-silence")) { + TAILQ_FOREACH(c, &clients, entry) { + if (c->session != s) + continue; + status_message_set(c, "Silence in window %d", wl->idx); + } + } + + return (WINDOW_SILENCE); +} + +void +alerts_ring_bell(struct session *s) +{ + struct client *c; + + TAILQ_FOREACH(c, &clients, entry) { + if (c->session == s && !(c->flags & CLIENT_CONTROL)) + tty_bell(&c->tty); + } +} diff --git a/cmd-set-option.c b/cmd-set-option.c index 631a4d0e..98ab2513 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -186,6 +186,8 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq) if (strcmp(oe->name, "status") == 0 || strcmp(oe->name, "status-interval") == 0) status_timer_start_all(); + if (strcmp(oe->name, "monitor-silence") == 0) + alerts_reset_all(); /* Update sizes and redraw. May not need it but meh. */ recalculate_sizes(); diff --git a/input.c b/input.c index 7ec35c88..cfe6b4af 100644 --- a/input.c +++ b/input.c @@ -844,14 +844,9 @@ input_parse(struct window_pane *wp) if (EVBUFFER_LENGTH(evb) == 0) return; + window_update_activity(wp->window); wp->flags |= PANE_CHANGED; - wp->window->flags |= WINDOW_ACTIVITY; - wp->window->flags &= ~WINDOW_SILENCE; - - if (gettimeofday(&wp->window->activity_time, NULL) != 0) - fatal("gettimeofday failed"); - /* * Open the screen. Use NULL wp if there is a mode set as don't want to * update the tty. @@ -1081,7 +1076,7 @@ input_c0_dispatch(struct input_ctx *ictx) case '\000': /* NUL */ break; case '\007': /* BEL */ - wp->window->flags |= WINDOW_BELL; + alerts_queue(wp->window, WINDOW_BELL); break; case '\010': /* BS */ screen_write_backspace(sctx); diff --git a/server-window.c b/server-window.c deleted file mode 100644 index be1dde2a..00000000 --- a/server-window.c +++ /dev/null @@ -1,191 +0,0 @@ -/* $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 *); -void ring_bell(struct session *); - -/* Window functions that need to happen every loop. */ -void -server_window_loop(void) -{ - struct window *w; - struct session *s; - struct winlink *wl; - - RB_FOREACH(w, windows, &windows) { - RB_FOREACH(s, sessions, &sessions) { - RB_FOREACH(wl, winlinks, &s->windows) { - if (wl->window != w) - continue; - - if (server_window_check_bell(s, wl) || - server_window_check_activity(s, wl) || - server_window_check_silence(s, wl)) - server_status_session(s); - } - } - check_window_name(w); - } -} - -/* Check for bell in window. */ -int -server_window_check_bell(struct session *s, struct winlink *wl) -{ - struct client *c; - struct window *w = wl->window; - 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); - TAILQ_FOREACH(c, &clients, entry) { - if (c->session != s || c->flags & CLIENT_CONTROL) - continue; - if (!visual) { - if ((action == BELL_CURRENT && - c->session->curw->window == w) || - (action == BELL_OTHER && - c->session->curw->window != w) || - action == BELL_ANY) - tty_bell(&c->tty); - continue; - } - if (action == BELL_CURRENT && c->session->curw->window == w) - status_message_set(c, "Bell in current window"); - else if (action == BELL_ANY || (action == BELL_OTHER && - c->session->curw->window != w)) - status_message_set(c, "Bell in window %d", 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; - - 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")) { - TAILQ_FOREACH(c, &clients, entry) { - if (c->session != s) - continue; - status_message_set(c, "Activity in window %d", 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; - 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")) { - TAILQ_FOREACH(c, &clients, entry) { - if (c->session != s) - continue; - status_message_set(c, "Silence in window %d", wl->idx); - } - } - - return (1); -} - -/* Ring terminal bell. */ -void -ring_bell(struct session *s) -{ - struct client *c; - - TAILQ_FOREACH(c, &clients, entry) { - if (c->session == s && !(c->flags & CLIENT_CONTROL)) - tty_bell(&c->tty); - } -} diff --git a/server.c b/server.c index d36dda12..d21acbe9 100644 --- a/server.c +++ b/server.c @@ -249,10 +249,13 @@ server_start(int lockfd, char *lockfile) void server_loop(void) { + struct window *w; + while (!server_should_shutdown()) { event_loop(EVLOOP_ONCE); - server_window_loop(); + RB_FOREACH(w, windows, &windows) + check_window_name(w); server_client_loop(); } } diff --git a/session.c b/session.c index c4e64e27..56986497 100644 --- a/session.c +++ b/session.c @@ -519,6 +519,7 @@ session_set_current(struct session *s, struct winlink *wl) winlink_stack_push(&s->lastw, s->curw); s->curw = wl; winlink_clear_flags(wl); + window_update_activity(wl->window); return (0); } diff --git a/tmux.h b/tmux.h index 5ae7225f..ae305a64 100644 --- a/tmux.h +++ b/tmux.h @@ -874,7 +874,8 @@ struct window { struct event name_event; struct timeval name_time; - struct timeval silence_timer; + struct event alerts_timer; + struct timeval activity_time; struct window_pane *active; @@ -1829,6 +1830,10 @@ void key_bindings_dispatch(struct key_binding *, struct client *, int key_string_lookup_string(const char *); const char *key_string_lookup_key(int); +/* alerts.c */ +void alerts_reset_all(void); +void alerts_queue(struct window *, int); + /* server.c */ extern struct clients clients; extern struct clients dead_clients; @@ -1856,9 +1861,6 @@ void server_client_callback(int, short, void *); void server_client_status_timer(void); void server_client_loop(void); -/* server-window.c */ -void server_window_loop(void); - /* server-fn.c */ void server_fill_environ(struct session *, struct environ *); void server_write_ready(struct client *); @@ -2084,6 +2086,7 @@ void winlink_stack_push(struct winlink_stack *, struct winlink *); void winlink_stack_remove(struct winlink_stack *, struct winlink *); struct window *window_find_by_id_str(const char *); struct window *window_find_by_id(u_int); +void window_update_activity(struct window *); struct window *window_create1(u_int, u_int); struct window *window_create(const char *, int, char **, const char *, const char *, int, struct environ *, struct termios *, diff --git a/window.c b/window.c index c172b68e..d8506774 100644 --- a/window.c +++ b/window.c @@ -277,6 +277,13 @@ window_find_by_id(u_int id) return (RB_FIND(windows, &windows, &w)); } +void +window_update_activity(struct window *w) +{ + gettimeofday(&w->activity_time, NULL); + alerts_queue(w, WINDOW_ACTIVITY); +} + struct window * window_create1(u_int sx, u_int sy) { @@ -295,9 +302,6 @@ window_create1(u_int sx, u_int sy) w->sx = sx; w->sy = sy; - if (gettimeofday(&w->activity_time, NULL) != 0) - fatal("gettimeofday failed"); - options_init(&w->options, &global_w_options); w->references = 0; @@ -305,6 +309,8 @@ window_create1(u_int sx, u_int sy) w->id = next_window_id++; RB_INSERT(windows, &windows, w); + window_update_activity(w); + return (w); } @@ -350,6 +356,9 @@ window_destroy(struct window *w) if (event_initialized(&w->name_event)) evtimer_del(&w->name_event); + if (event_initialized(&w->alerts_timer)) + evtimer_del(&w->alerts_timer); + options_free(&w->options); window_destroy_panes(w); @@ -929,14 +938,6 @@ window_pane_read_callback(unused struct bufferevent *bufev, void *data) input_parse(wp); wp->pipe_off = EVBUFFER_LENGTH(evb); - - /* - * 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"); return; start_timer: -- cgit v1.2.3