Alerts are too slow, so rather than walking all sessions and windows,

add a link of winlinks to each window and a pointer to the session to
each winlink. Also rewrite the alerts processing to return to the old
behaviour (alert in any window sets the flag on any winlink).
This commit is contained in:
nicm 2016-10-19 09:22:07 +00:00
parent bc27451e15
commit 899e629bf0
5 changed files with 179 additions and 133 deletions

216
alerts.c
View File

@ -19,6 +19,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <event.h> #include <event.h>
#include <stdlib.h>
#include "tmux.h" #include "tmux.h"
@ -29,13 +30,16 @@ static int alerts_enabled(struct window *, int);
static void alerts_callback(int, short, void *); static void alerts_callback(int, short, void *);
static void alerts_reset(struct window *); static void alerts_reset(struct window *);
static void alerts_run_hook(struct session *, struct winlink *, int); static int alerts_check_all(struct window *);
static int alerts_check_all(struct session *, struct winlink *); static int alerts_check_bell(struct window *);
static int alerts_check_bell(struct session *, struct winlink *); static int alerts_check_activity(struct window *);
static int alerts_check_activity(struct session *, struct winlink *); static int alerts_check_silence(struct window *);
static int alerts_check_silence(struct session *, struct winlink *); static void printflike(2, 3) alerts_set_message(struct session *, const char *,
...);
static void alerts_ring_bell(struct session *); static void alerts_ring_bell(struct session *);
static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list);
static void static void
alerts_timer(__unused int fd, __unused short events, void *arg) alerts_timer(__unused int fd, __unused short events, void *arg)
{ {
@ -49,53 +53,28 @@ alerts_timer(__unused int fd, __unused short events, void *arg)
static void static void
alerts_callback(__unused int fd, __unused short events, __unused void *arg) alerts_callback(__unused int fd, __unused short events, __unused void *arg)
{ {
struct window *w; struct window *w, *w1;
struct session *s; int alerts;
struct winlink *wl;
int flags, alerts;
RB_FOREACH(w, windows, &windows) { TAILQ_FOREACH_SAFE(w, &alerts_list, alerts_entry, w1) {
RB_FOREACH(s, sessions, &sessions) { alerts = alerts_check_all(w);
RB_FOREACH(wl, winlinks, &s->windows) { log_debug("@%u alerts check, alerts %#x", w->id, alerts);
if (wl->window != w)
continue;
flags = w->flags;
alerts = alerts_check_all(s, wl); w->alerts_queued = 0;
TAILQ_REMOVE(&alerts_list, w, alerts_entry);
log_debug("%s:%d @%u alerts check, alerts %#x, " window_remove_ref(w);
"flags %#x", s->name, wl->idx, w->id,
alerts, flags);
}
}
} }
alerts_fired = 0; alerts_fired = 0;
} }
static void
alerts_run_hook(struct session *s, struct winlink *wl, int flags)
{
if (flags & WINDOW_BELL)
notify_winlink("alert-bell", s, wl);
if (flags & WINDOW_SILENCE)
notify_winlink("alert-silence", s, wl);
if (flags & WINDOW_ACTIVITY)
notify_winlink("alert-activity", s, wl);
}
static int static int
alerts_check_all(struct session *s, struct winlink *wl) alerts_check_all(struct window *w)
{ {
int alerts; int alerts;
alerts = alerts_check_bell(s, wl); alerts = alerts_check_bell(w);
alerts |= alerts_check_activity(s, wl); alerts |= alerts_check_activity(w);
alerts |= alerts_check_silence(s, wl); alerts |= alerts_check_silence(w);
if (alerts != 0) {
alerts_run_hook(s, wl, alerts);
server_status_session(s);
}
return (alerts); return (alerts);
} }
@ -105,7 +84,7 @@ alerts_check_session(struct session *s)
struct winlink *wl; struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows) RB_FOREACH(wl, winlinks, &s->windows)
alerts_check_all(s, wl); alerts_check_all(wl->window);
} }
static int static int
@ -163,6 +142,12 @@ alerts_queue(struct window *w, int flags)
log_debug("@%u alerts flags added %#x", w->id, flags); log_debug("@%u alerts flags added %#x", w->id, flags);
} }
if (!w->alerts_queued) {
w->alerts_queued = 1;
TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry);
w->references++;
}
if (!alerts_fired && alerts_enabled(w, flags)) { if (!alerts_fired && alerts_enabled(w, flags)) {
log_debug("alerts check queued (by @%u)", w->id); log_debug("alerts check queued (by @%u)", w->id);
event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL); event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
@ -171,20 +156,32 @@ alerts_queue(struct window *w, int flags)
} }
static int static int
alerts_check_bell(struct session *s, struct winlink *wl) alerts_check_bell(struct window *w)
{ {
struct window *ws;
struct winlink *wl;
struct session *s;
struct client *c; struct client *c;
struct window *w = wl->window;
int action, visual; int action, visual;
if (!(w->flags & WINDOW_BELL)) if (~w->flags & WINDOW_BELL)
return (0); return (0);
TAILQ_FOREACH(wl, &w->winlinks, wentry)
wl->session->flags &= ~SESSION_ALERTED;
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (wl->flags & WINLINK_BELL)
continue;
s = wl->session;
if (s->curw != wl) { if (s->curw != wl) {
wl->flags |= WINLINK_BELL; wl->flags |= WINLINK_BELL;
w->flags &= ~WINDOW_BELL; notify_winlink("alert-bell", s, wl);
} }
if (s->curw->window == w)
w->flags &= ~WINDOW_BELL; if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
action = options_get_number(s->options, "bell-action"); action = options_get_number(s->options, "bell-action");
if (action == BELL_NONE) if (action == BELL_NONE)
@ -194,89 +191,122 @@ alerts_check_bell(struct session *s, struct winlink *wl)
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (c->session != s || c->flags & CLIENT_CONTROL) if (c->session != s || c->flags & CLIENT_CONTROL)
continue; continue;
ws = c->session->curw->window;
if (action == BELL_CURRENT && ws != w)
action = BELL_NONE;
if (action == BELL_OTHER && ws != w)
action = BELL_NONE;
if (!visual) { if (!visual) {
if ((action == BELL_CURRENT && if (action != BELL_NONE)
c->session->curw->window == w) ||
(action == BELL_OTHER &&
c->session->curw->window != w) ||
action == BELL_ANY)
tty_putcode(&c->tty, TTYC_BEL); tty_putcode(&c->tty, TTYC_BEL);
continue; continue;
} }
if (action == BELL_CURRENT && c->session->curw->window == w) if (action == BELL_CURRENT)
status_message_set(c, "Bell in current window"); status_message_set(c, "Bell in current window");
else if (action == BELL_ANY || (action == BELL_OTHER && else if (action != BELL_NONE) {
c->session->curw->window != w)) status_message_set(c, "Bell in window %d",
status_message_set(c, "Bell in window %d", wl->idx); wl->idx);
}
}
} }
return (WINDOW_BELL); return (WINDOW_BELL);
} }
static int static int
alerts_check_activity(struct session *s, struct winlink *wl) alerts_check_activity(struct window *w)
{ {
struct client *c; struct winlink *wl;
struct window *w = wl->window; struct session *s;
if (s->curw->window == w) if (~w->flags & WINDOW_ACTIVITY)
w->flags &= ~WINDOW_ACTIVITY;
if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY)
return (0); return (0);
if (s->curw == wl)
return (0);
if (!options_get_number(w->options, "monitor-activity")) if (!options_get_number(w->options, "monitor-activity"))
return (0); return (0);
TAILQ_FOREACH(wl, &w->winlinks, wentry)
wl->session->flags &= ~SESSION_ALERTED;
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (wl->flags & WINLINK_ACTIVITY)
continue;
s = wl->session;
if (s->curw != wl) {
wl->flags |= WINLINK_ACTIVITY;
notify_winlink("alert-activity", s, wl);
}
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
if (options_get_number(s->options, "bell-on-alert")) if (options_get_number(s->options, "bell-on-alert"))
alerts_ring_bell(s); alerts_ring_bell(s);
wl->flags |= WINLINK_ACTIVITY; if (options_get_number(s->options, "visual-activity"))
alerts_set_message(s, "Activity in window %d", wl->idx);
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); return (WINDOW_ACTIVITY);
} }
static int static int
alerts_check_silence(struct session *s, struct winlink *wl) alerts_check_silence(struct window *w)
{ {
struct client *c; struct winlink *wl;
struct window *w = wl->window; struct session *s;
if (s->curw->window == w) if (~w->flags & WINDOW_SILENCE)
w->flags &= ~WINDOW_SILENCE;
if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
return (0); return (0);
if (s->curw == wl) if (!options_get_number(w->options, "monitor-silence"))
return (0); return (0);
if (options_get_number(w->options, "monitor-silence") == 0) TAILQ_FOREACH(wl, &w->winlinks, wentry)
return (0); wl->session->flags &= ~SESSION_ALERTED;
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (wl->flags & WINLINK_SILENCE)
continue;
s = wl->session;
if (s->curw != wl) {
wl->flags |= WINLINK_SILENCE;
notify_winlink("alert-silence", s, wl);
}
if (s->flags & SESSION_ALERTED)
continue;
s->flags |= SESSION_ALERTED;
if (options_get_number(s->options, "bell-on-alert")) if (options_get_number(s->options, "bell-on-alert"))
alerts_ring_bell(s); alerts_ring_bell(s);
wl->flags |= WINLINK_SILENCE;
if (options_get_number(s->options, "visual-silence")) { if (!options_get_number(s->options, "visual-silence"))
TAILQ_FOREACH(c, &clients, entry) { alerts_set_message(s, "Silence in window %d", wl->idx);
if (c->session != s)
continue;
status_message_set(c, "Silence in window %d", wl->idx);
}
} }
return (WINDOW_SILENCE); return (WINDOW_SILENCE);
} }
static void
alerts_set_message(struct session *s, const char *fmt, ...)
{
struct client *c;
va_list ap;
char *message;
va_start(ap, fmt);
xvasprintf(&message, fmt, ap);
va_end(ap);
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == s)
status_message_set(c, "%s", message);
}
free(message);
}
static void static void
alerts_ring_bell(struct session *s) alerts_ring_bell(struct session *s)
{ {

View File

@ -853,6 +853,7 @@ server_client_loop(void)
struct client *c; struct client *c;
struct window *w; struct window *w;
struct window_pane *wp; struct window_pane *wp;
int focus;
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
server_client_check_exit(c); server_client_check_exit(c);
@ -866,10 +867,12 @@ server_client_loop(void)
* Any windows will have been redrawn as part of clients, so clear * Any windows will have been redrawn as part of clients, so clear
* their flags now. Also check pane focus and resize. * their flags now. Also check pane focus and resize.
*/ */
focus = options_get_number(global_options, "focus-events");
RB_FOREACH(w, windows, &windows) { RB_FOREACH(w, windows, &windows) {
w->flags &= ~WINDOW_REDRAW; w->flags &= ~WINDOW_REDRAW;
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd != -1) { if (wp->fd != -1) {
if (focus)
server_client_check_focus(wp); server_client_check_focus(wp);
server_client_check_resize(wp); server_client_check_resize(wp);
} }
@ -937,10 +940,6 @@ server_client_check_focus(struct window_pane *wp)
struct client *c; struct client *c;
int push; int push;
/* Are focus events off? */
if (!options_get_number(global_options, "focus-events"))
return;
/* Do we need to push the focus state? */ /* Do we need to push the focus state? */
push = wp->flags & PANE_FOCUSPUSH; push = wp->flags & PANE_FOCUSPUSH;
wp->flags &= ~PANE_FOCUSPUSH; wp->flags &= ~PANE_FOCUSPUSH;

View File

@ -337,6 +337,7 @@ session_new(struct session *s, const char *name, int argc, char **argv,
xasprintf(cause, "index in use: %d", idx); xasprintf(cause, "index in use: %d", idx);
return (NULL); return (NULL);
} }
wl->session = s;
env = environ_create(); env = environ_create();
environ_copy(global_environ, env); environ_copy(global_environ, env);
@ -373,6 +374,7 @@ session_attach(struct session *s, struct window *w, int idx, char **cause)
xasprintf(cause, "index in use: %d", idx); xasprintf(cause, "index in use: %d", idx);
return (NULL); return (NULL);
} }
wl->session = s;
winlink_set_window(wl, w); winlink_set_window(wl, w);
notify_session_window("window-linked", s, w); notify_session_window("window-linked", s, w);
@ -409,8 +411,8 @@ session_has(struct session *s, struct window *w)
{ {
struct winlink *wl; struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows) { TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (wl->window == w) if (wl->session == s)
return (1); return (1);
} }
return (0); return (0);
@ -679,6 +681,7 @@ session_group_synchronize1(struct session *target, struct session *s)
/* Link all the windows from the target. */ /* Link all the windows from the target. */
RB_FOREACH(wl, winlinks, ww) { RB_FOREACH(wl, winlinks, ww) {
wl2 = winlink_add(&s->windows, wl->idx); wl2 = winlink_add(&s->windows, wl->idx);
wl2->session = s;
winlink_set_window(wl2, wl->window); winlink_set_window(wl2, wl->window);
notify_session_window("window-linked", s, wl2->window); notify_session_window("window-linked", s, wl2->window);
wl2->flags |= wl->flags & WINLINK_ALERTFLAGS; wl2->flags |= wl->flags & WINLINK_ALERTFLAGS;
@ -729,6 +732,7 @@ session_renumber_windows(struct session *s)
/* Go through the winlinks and assign new indexes. */ /* Go through the winlinks and assign new indexes. */
RB_FOREACH(wl, winlinks, &old_wins) { RB_FOREACH(wl, winlinks, &old_wins) {
wl_new = winlink_add(&s->windows, new_idx); wl_new = winlink_add(&s->windows, new_idx);
wl_new->session = s;
winlink_set_window(wl_new, wl->window); winlink_set_window(wl_new, wl->window);
wl_new->flags |= wl->flags & WINLINK_ALERTFLAGS; wl_new->flags |= wl->flags & WINLINK_ALERTFLAGS;

8
tmux.h
View File

@ -889,12 +889,16 @@ struct window {
#define WINDOW_STYLECHANGED 0x8000 #define WINDOW_STYLECHANGED 0x8000
#define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE) #define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE)
int alerts_queued;
TAILQ_ENTRY(window) alerts_entry;
struct options *options; struct options *options;
struct grid_cell style; struct grid_cell style;
struct grid_cell active_style; struct grid_cell active_style;
u_int references; u_int references;
TAILQ_HEAD(, winlink) winlinks;
RB_ENTRY(window) entry; RB_ENTRY(window) entry;
}; };
@ -903,6 +907,7 @@ RB_HEAD(windows, window);
/* Entry on local window list. */ /* Entry on local window list. */
struct winlink { struct winlink {
int idx; int idx;
struct session *session;
struct window *window; struct window *window;
size_t status_width; size_t status_width;
@ -916,6 +921,7 @@ struct winlink {
#define WINLINK_ALERTFLAGS (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_SILENCE) #define WINLINK_ALERTFLAGS (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_SILENCE)
RB_ENTRY(winlink) entry; RB_ENTRY(winlink) entry;
TAILQ_ENTRY(winlink) wentry;
TAILQ_ENTRY(winlink) sentry; TAILQ_ENTRY(winlink) sentry;
}; };
RB_HEAD(winlinks, winlink); RB_HEAD(winlinks, winlink);
@ -990,6 +996,7 @@ struct session {
#define SESSION_UNATTACHED 0x1 /* not attached to any clients */ #define SESSION_UNATTACHED 0x1 /* not attached to any clients */
#define SESSION_PASTING 0x2 #define SESSION_PASTING 0x2
#define SESSION_ALERTED 0x4
int flags; int flags;
u_int attached; u_int attached;
@ -2069,7 +2076,6 @@ struct window *window_create(u_int, u_int);
struct window *window_create_spawn(const char *, int, char **, const char *, struct window *window_create_spawn(const char *, int, char **, const char *,
const char *, const char *, struct environ *, const char *, const char *, struct environ *,
struct termios *, u_int, u_int, u_int, char **); struct termios *, u_int, u_int, u_int, char **);
void window_destroy(struct window *);
struct window_pane *window_get_active_at(struct window *, u_int, u_int); struct window_pane *window_get_active_at(struct window *, u_int, u_int);
struct window_pane *window_find_string(struct window *, const char *); struct window_pane *window_find_string(struct window *, const char *);
int window_has_pane(struct window *, struct window_pane *); int window_has_pane(struct window *, struct window_pane *);

View File

@ -60,6 +60,8 @@ static u_int next_window_pane_id;
static u_int next_window_id; static u_int next_window_id;
static u_int next_active_point; static u_int next_active_point;
static void window_destroy(struct window *);
static struct window_pane *window_pane_create(struct window *, u_int, u_int, static struct window_pane *window_pane_create(struct window *, u_int, u_int,
u_int); u_int);
static void window_pane_destroy(struct window_pane *); static void window_pane_destroy(struct window_pane *);
@ -184,6 +186,11 @@ winlink_add(struct winlinks *wwl, int idx)
void void
winlink_set_window(struct winlink *wl, struct window *w) winlink_set_window(struct winlink *wl, struct window *w)
{ {
if (wl->window != NULL) {
TAILQ_REMOVE(&wl->window->winlinks, wl, wentry);
window_remove_ref(w);
}
TAILQ_INSERT_TAIL(&w->winlinks, wl, wentry);
wl->window = w; wl->window = w;
w->references++; w->references++;
} }
@ -193,12 +200,14 @@ winlink_remove(struct winlinks *wwl, struct winlink *wl)
{ {
struct window *w = wl->window; struct window *w = wl->window;
if (w != NULL) {
TAILQ_REMOVE(&w->winlinks, wl, wentry);
window_remove_ref(w);
}
RB_REMOVE(winlinks, wwl, wl); RB_REMOVE(winlinks, wwl, wl);
free(wl->status_text); free(wl->status_text);
free(wl); free(wl);
if (w != NULL)
window_remove_ref(w);
} }
struct winlink * struct winlink *
@ -313,6 +322,7 @@ window_create(u_int sx, u_int sy)
w->options = options_create(global_w_options); w->options = options_create(global_w_options);
w->references = 0; w->references = 0;
TAILQ_INIT(&w->winlinks);
w->id = next_window_id++; w->id = next_window_id++;
RB_INSERT(windows, &windows, w); RB_INSERT(windows, &windows, w);
@ -350,9 +360,12 @@ window_create_spawn(const char *name, int argc, char **argv, const char *path,
return (w); return (w);
} }
void static void
window_destroy(struct window *w) window_destroy(struct window *w)
{ {
if (!TAILQ_EMPTY(&w->winlinks))
fatalx("window destroyed with winlinks");
RB_REMOVE(windows, &windows, w); RB_REMOVE(windows, &windows, w);
if (w->layout_root != NULL) if (w->layout_root != NULL)
@ -1421,19 +1434,13 @@ window_pane_find_right(struct window_pane *wp)
void void
winlink_clear_flags(struct winlink *wl) winlink_clear_flags(struct winlink *wl)
{ {
struct session *s; struct winlink *loop;
struct winlink *wl_loop;
RB_FOREACH(s, sessions, &sessions) { wl->window->flags &= ~WINDOW_ALERTFLAGS;
RB_FOREACH(wl_loop, winlinks, &s->windows) { TAILQ_FOREACH(loop, &wl->window->winlinks, wentry) {
if (wl_loop->window != wl->window) if ((loop->flags & WINLINK_ALERTFLAGS) != 0) {
continue; loop->flags &= ~WINLINK_ALERTFLAGS;
if ((wl_loop->flags & WINLINK_ALERTFLAGS) == 0) server_status_session(loop->session);
continue;
wl_loop->flags &= ~WINLINK_ALERTFLAGS;
wl_loop->window->flags &= ~WINDOW_ALERTFLAGS;
server_status_session(s);
} }
} }
} }