aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--alerts.c244
-rw-r--r--server-client.c9
-rw-r--r--session.c8
-rw-r--r--tmux.h8
-rw-r--r--window.c39
5 files changed, 177 insertions, 131 deletions
diff --git a/alerts.c b/alerts.c
index ef869ae8..e0b2bf01 100644
--- a/alerts.c
+++ b/alerts.c
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <event.h>
+#include <stdlib.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_reset(struct window *);
-static void alerts_run_hook(struct session *, struct winlink *, int);
-static int alerts_check_all(struct session *, struct winlink *);
-static int alerts_check_bell(struct session *, struct winlink *);
-static int alerts_check_activity(struct session *, struct winlink *);
-static int alerts_check_silence(struct session *, struct winlink *);
+static int alerts_check_all(struct window *);
+static int alerts_check_bell(struct window *);
+static int alerts_check_activity(struct window *);
+static int alerts_check_silence(struct window *);
+static void printflike(2, 3) alerts_set_message(struct session *, const char *,
+ ...);
static void alerts_ring_bell(struct session *);
+static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list);
+
static void
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
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;
+ struct window *w, *w1;
+ int alerts;
- alerts = alerts_check_all(s, wl);
+ TAILQ_FOREACH_SAFE(w, &alerts_list, alerts_entry, w1) {
+ alerts = alerts_check_all(w);
+ log_debug("@%u alerts check, alerts %#x", w->id, alerts);
- log_debug("%s:%d @%u alerts check, alerts %#x, "
- "flags %#x", s->name, wl->idx, w->id,
- alerts, flags);
- }
- }
+ w->alerts_queued = 0;
+ TAILQ_REMOVE(&alerts_list, w, alerts_entry);
+ window_remove_ref(w);
}
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
-alerts_check_all(struct session *s, struct winlink *wl)
+alerts_check_all(struct window *w)
{
int alerts;
- alerts = alerts_check_bell(s, wl);
- alerts |= alerts_check_activity(s, wl);
- alerts |= alerts_check_silence(s, wl);
- if (alerts != 0) {
- alerts_run_hook(s, wl, alerts);
- server_status_session(s);
- }
-
+ alerts = alerts_check_bell(w);
+ alerts |= alerts_check_activity(w);
+ alerts |= alerts_check_silence(w);
return (alerts);
}
@@ -105,7 +84,7 @@ alerts_check_session(struct session *s)
struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows)
- alerts_check_all(s, wl);
+ alerts_check_all(wl->window);
}
static int
@@ -163,6 +142,12 @@ alerts_queue(struct window *w, int 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)) {
log_debug("alerts check queued (by @%u)", w->id);
event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
@@ -171,113 +156,158 @@ alerts_queue(struct window *w, int flags)
}
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 window *w = wl->window;
int action, visual;
- if (!(w->flags & WINDOW_BELL))
+ if (~w->flags & WINDOW_BELL)
return (0);
- if (s->curw != wl) {
- wl->flags |= WINLINK_BELL;
- w->flags &= ~WINDOW_BELL;
- }
- if (s->curw->window == w)
- w->flags &= ~WINDOW_BELL;
- action = options_get_number(s->options, "bell-action");
- if (action == BELL_NONE)
- return (0);
+ TAILQ_FOREACH(wl, &w->winlinks, wentry)
+ wl->session->flags &= ~SESSION_ALERTED;
- visual = options_get_number(s->options, "visual-bell");
- TAILQ_FOREACH(c, &clients, entry) {
- if (c->session != s || c->flags & CLIENT_CONTROL)
+ TAILQ_FOREACH(wl, &w->winlinks, wentry) {
+ if (wl->flags & WINLINK_BELL)
continue;
- if (!visual) {
- if ((action == BELL_CURRENT &&
- c->session->curw->window == w) ||
- (action == BELL_OTHER &&
- c->session->curw->window != w) ||
- action == BELL_ANY)
- tty_putcode(&c->tty, TTYC_BEL);
+ s = wl->session;
+ if (s->curw != wl) {
+ wl->flags |= WINLINK_BELL;
+ notify_winlink("alert-bell", s, wl);
+ }
+
+ if (s->flags & SESSION_ALERTED)
continue;
+ s->flags |= SESSION_ALERTED;
+
+ 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;
+ 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 (action != BELL_NONE)
+ tty_putcode(&c->tty, TTYC_BEL);
+ continue;
+ }
+ if (action == BELL_CURRENT)
+ status_message_set(c, "Bell in current window");
+ else if (action != BELL_NONE) {
+ status_message_set(c, "Bell in window %d",
+ wl->idx);
+ }
}
- 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);
}
static int
-alerts_check_activity(struct session *s, struct winlink *wl)
+alerts_check_activity(struct window *w)
{
- struct client *c;
- struct window *w = wl->window;
-
- if (s->curw->window == w)
- w->flags &= ~WINDOW_ACTIVITY;
+ struct winlink *wl;
+ struct session *s;
- if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY)
- return (0);
- if (s->curw == wl)
+ if (~w->flags & WINDOW_ACTIVITY)
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;
+ TAILQ_FOREACH(wl, &w->winlinks, wentry)
+ wl->session->flags &= ~SESSION_ALERTED;
- 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);
+ 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"))
+ alerts_ring_bell(s);
+ if (options_get_number(s->options, "visual-activity"))
+ alerts_set_message(s, "Activity in window %d", wl->idx);
}
return (WINDOW_ACTIVITY);
}
static int
-alerts_check_silence(struct session *s, struct winlink *wl)
+alerts_check_silence(struct window *w)
{
- struct client *c;
- struct window *w = wl->window;
-
- if (s->curw->window == w)
- w->flags &= ~WINDOW_SILENCE;
+ struct winlink *wl;
+ struct session *s;
- if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
- return (0);
- if (s->curw == wl)
+ if (~w->flags & WINDOW_SILENCE)
return (0);
-
- if (options_get_number(w->options, "monitor-silence") == 0)
+ if (!options_get_number(w->options, "monitor-silence"))
return (0);
- if (options_get_number(s->options, "bell-on-alert"))
- alerts_ring_bell(s);
- wl->flags |= WINLINK_SILENCE;
+ TAILQ_FOREACH(wl, &w->winlinks, wentry)
+ wl->session->flags &= ~SESSION_ALERTED;
- 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);
+ 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"))
+ alerts_ring_bell(s);
+
+ if (!options_get_number(s->options, "visual-silence"))
+ alerts_set_message(s, "Silence in window %d", wl->idx);
}
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
alerts_ring_bell(struct session *s)
{
struct client *c;
diff --git a/server-client.c b/server-client.c
index 98a28738..b92bada5 100644
--- a/server-client.c
+++ b/server-client.c
@@ -853,6 +853,7 @@ server_client_loop(void)
struct client *c;
struct window *w;
struct window_pane *wp;
+ int focus;
TAILQ_FOREACH(c, &clients, entry) {
server_client_check_exit(c);
@@ -866,11 +867,13 @@ server_client_loop(void)
* Any windows will have been redrawn as part of clients, so clear
* their flags now. Also check pane focus and resize.
*/
+ focus = options_get_number(global_options, "focus-events");
RB_FOREACH(w, windows, &windows) {
w->flags &= ~WINDOW_REDRAW;
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd != -1) {
- server_client_check_focus(wp);
+ if (focus)
+ server_client_check_focus(wp);
server_client_check_resize(wp);
}
wp->flags &= ~PANE_REDRAW;
@@ -937,10 +940,6 @@ server_client_check_focus(struct window_pane *wp)
struct client *c;
int push;
- /* Are focus events off? */
- if (!options_get_number(global_options, "focus-events"))
- return;
-
/* Do we need to push the focus state? */
push = wp->flags & PANE_FOCUSPUSH;
wp->flags &= ~PANE_FOCUSPUSH;
diff --git a/session.c b/session.c
index fa43a74e..19a6f139 100644
--- a/session.c
+++ b/session.c
@@ -337,6 +337,7 @@ session_new(struct session *s, const char *name, int argc, char **argv,
xasprintf(cause, "index in use: %d", idx);
return (NULL);
}
+ wl->session = s;
env = environ_create();
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);
return (NULL);
}
+ wl->session = s;
winlink_set_window(wl, w);
notify_session_window("window-linked", s, w);
@@ -409,8 +411,8 @@ session_has(struct session *s, struct window *w)
{
struct winlink *wl;
- RB_FOREACH(wl, winlinks, &s->windows) {
- if (wl->window == w)
+ TAILQ_FOREACH(wl, &w->winlinks, wentry) {
+ if (wl->session == s)
return (1);
}
return (0);
@@ -679,6 +681,7 @@ session_group_synchronize1(struct session *target, struct session *s)
/* Link all the windows from the target. */
RB_FOREACH(wl, winlinks, ww) {
wl2 = winlink_add(&s->windows, wl->idx);
+ wl2->session = s;
winlink_set_window(wl2, wl->window);
notify_session_window("window-linked", s, wl2->window);
wl2->flags |= wl->flags & WINLINK_ALERTFLAGS;
@@ -729,6 +732,7 @@ session_renumber_windows(struct session *s)
/* Go through the winlinks and assign new indexes. */
RB_FOREACH(wl, winlinks, &old_wins) {
wl_new = winlink_add(&s->windows, new_idx);
+ wl_new->session = s;
winlink_set_window(wl_new, wl->window);
wl_new->flags |= wl->flags & WINLINK_ALERTFLAGS;
diff --git a/tmux.h b/tmux.h
index ae4b75dd..1ec2d3ca 100644
--- a/tmux.h
+++ b/tmux.h
@@ -889,12 +889,16 @@ struct window {
#define WINDOW_STYLECHANGED 0x8000
#define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE)
+ int alerts_queued;
+ TAILQ_ENTRY(window) alerts_entry;
+
struct options *options;
struct grid_cell style;
struct grid_cell active_style;
u_int references;
+ TAILQ_HEAD(, winlink) winlinks;
RB_ENTRY(window) entry;
};
@@ -903,6 +907,7 @@ RB_HEAD(windows, window);
/* Entry on local window list. */
struct winlink {
int idx;
+ struct session *session;
struct window *window;
size_t status_width;
@@ -916,6 +921,7 @@ struct winlink {
#define WINLINK_ALERTFLAGS (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_SILENCE)
RB_ENTRY(winlink) entry;
+ TAILQ_ENTRY(winlink) wentry;
TAILQ_ENTRY(winlink) sentry;
};
RB_HEAD(winlinks, winlink);
@@ -990,6 +996,7 @@ struct session {
#define SESSION_UNATTACHED 0x1 /* not attached to any clients */
#define SESSION_PASTING 0x2
+#define SESSION_ALERTED 0x4
int flags;
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 *,
const char *, const char *, struct environ *,
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_find_string(struct window *, const char *);
int window_has_pane(struct window *, struct window_pane *);
diff --git a/window.c b/window.c
index 8ef54084..56878a19 100644
--- a/window.c
+++ b/window.c
@@ -60,6 +60,8 @@ static u_int next_window_pane_id;
static u_int next_window_id;
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,
u_int);
static void window_pane_destroy(struct window_pane *);
@@ -184,6 +186,11 @@ winlink_add(struct winlinks *wwl, int idx)
void
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;
w->references++;
}
@@ -193,12 +200,14 @@ winlink_remove(struct winlinks *wwl, struct winlink *wl)
{
struct window *w = wl->window;
+ if (w != NULL) {
+ TAILQ_REMOVE(&w->winlinks, wl, wentry);
+ window_remove_ref(w);
+ }
+
RB_REMOVE(winlinks, wwl, wl);
free(wl->status_text);
free(wl);
-
- if (w != NULL)
- window_remove_ref(w);
}
struct winlink *
@@ -313,6 +322,7 @@ window_create(u_int sx, u_int sy)
w->options = options_create(global_w_options);
w->references = 0;
+ TAILQ_INIT(&w->winlinks);
w->id = next_window_id++;
RB_INSERT(windows, &windows, w);
@@ -350,9 +360,12 @@ window_create_spawn(const char *name, int argc, char **argv, const char *path,
return (w);
}
-void
+static void
window_destroy(struct window *w)
{
+ if (!TAILQ_EMPTY(&w->winlinks))
+ fatalx("window destroyed with winlinks");
+
RB_REMOVE(windows, &windows, w);
if (w->layout_root != NULL)
@@ -1421,19 +1434,13 @@ window_pane_find_right(struct window_pane *wp)
void
winlink_clear_flags(struct winlink *wl)
{
- struct session *s;
- struct winlink *wl_loop;
-
- RB_FOREACH(s, sessions, &sessions) {
- RB_FOREACH(wl_loop, winlinks, &s->windows) {
- if (wl_loop->window != wl->window)
- continue;
- if ((wl_loop->flags & WINLINK_ALERTFLAGS) == 0)
- continue;
+ struct winlink *loop;
- wl_loop->flags &= ~WINLINK_ALERTFLAGS;
- wl_loop->window->flags &= ~WINDOW_ALERTFLAGS;
- server_status_session(s);
+ wl->window->flags &= ~WINDOW_ALERTFLAGS;
+ TAILQ_FOREACH(loop, &wl->window->winlinks, wentry) {
+ if ((loop->flags & WINLINK_ALERTFLAGS) != 0) {
+ loop->flags &= ~WINLINK_ALERTFLAGS;
+ server_status_session(loop->session);
}
}
}