Having a list of winlinks->alerts for each session is stupid, just store

the alert flags directly in the winlink itself.
This commit is contained in:
Nicholas Marriott 2010-06-21 01:27:46 +00:00
parent 447a07e9f8
commit e63f0546a1
8 changed files with 78 additions and 180 deletions

View File

@ -81,11 +81,11 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
idx++; idx++;
flag = ' '; flag = ' ';
if (session_alert_has(s, wm, WINDOW_ACTIVITY)) if (wm->flags & WINLINK_ACTIVITY)
flag = '#'; flag = '#';
else if (session_alert_has(s, wm, WINDOW_BELL)) else if (wm->flags & WINLINK_BELL)
flag = '!'; flag = '!';
else if (session_alert_has(s, wm, WINDOW_CONTENT)) else if (wm->flags & WINLINK_CONTENT)
flag = '+'; flag = '+';
else if (wm == s->curw) else if (wm == s->curw)
flag = '*'; flag = '*';

View File

@ -162,7 +162,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
* Can't use session_detach as it will destroy session if this * Can't use session_detach as it will destroy session if this
* makes it empty. * makes it empty.
*/ */
session_alert_cancel(s, wl); wl->flags &= ~WINLINK_ALERTFLAGS;
winlink_stack_remove(&s->lastw, wl); winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl); winlink_remove(&s->windows, wl);

View File

@ -105,7 +105,7 @@ recalculate_sizes(void)
if (flag) if (flag)
has = s->curw->window == w; has = s->curw->window == w;
else else
has = session_has(s, w); has = session_has(s, w) != NULL;
if (has) { if (has) {
if (s->sx < ssx) if (s->sx < ssx)
ssx = s->sx; ssx = s->sx;

View File

@ -184,7 +184,7 @@ server_status_window(struct window *w)
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i); s = ARRAY_ITEM(&sessions, i);
if (s != NULL && session_has(s, w)) if (s != NULL && session_has(s, w) != NULL)
server_status_session(s); server_status_session(s);
} }
} }
@ -249,7 +249,7 @@ server_kill_window(struct window *w)
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i); s = ARRAY_ITEM(&sessions, i);
if (s == NULL || !session_has(s, w)) if (s == NULL || session_has(s, w) == NULL)
continue; continue;
while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) { while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) {
if (session_detach(s, wl)) { if (session_detach(s, wl)) {
@ -286,7 +286,7 @@ server_link_window(struct session *src, struct winlink *srcwl,
* Can't use session_detach as it will destroy session * Can't use session_detach as it will destroy session
* if this makes it empty. * if this makes it empty.
*/ */
session_alert_cancel(dst, dstwl); dstwl->flags &= ~WINLINK_ALERTFLAGS;
winlink_stack_remove(&dst->lastw, dstwl); winlink_stack_remove(&dst->lastw, dstwl);
winlink_remove(&dst->windows, dstwl); winlink_remove(&dst->windows, dstwl);

View File

@ -24,10 +24,10 @@
#include "tmux.h" #include "tmux.h"
int server_window_backoff(struct window_pane *); int server_window_backoff(struct window_pane *);
int server_window_check_bell(struct session *, struct window *); int server_window_check_bell(struct session *, struct winlink *);
int server_window_check_activity(struct session *, struct window *); int server_window_check_activity(struct session *, struct winlink *);
int server_window_check_content( int server_window_check_content(
struct session *, struct window *, struct window_pane *); struct session *, struct winlink *, struct window_pane *);
/* Check if this window should suspend reading. */ /* Check if this window should suspend reading. */
int int
@ -59,6 +59,7 @@ void
server_window_loop(void) server_window_loop(void)
{ {
struct window *w; struct window *w;
struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
struct session *s; struct session *s;
u_int i, j; u_int i, j;
@ -81,33 +82,37 @@ server_window_loop(void)
for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { for (j = 0; j < ARRAY_LENGTH(&sessions); j++) {
s = ARRAY_ITEM(&sessions, j); s = ARRAY_ITEM(&sessions, j);
if (s == NULL || !session_has(s, w)) if (s == NULL)
continue;
wl = session_has(s, w);
if (wl == NULL)
continue; continue;
if (server_window_check_bell(s, w) || if (server_window_check_bell(s, wl) ||
server_window_check_activity(s, w)) server_window_check_activity(s, wl))
server_status_session(s); server_status_session(s);
TAILQ_FOREACH(wp, &w->panes, entry) TAILQ_FOREACH(wp, &w->panes, entry)
server_window_check_content(s, w, wp); server_window_check_content(s, wl, wp);
} }
w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT); w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY);
} }
} }
/* Check for bell in window. */ /* Check for bell in window. */
int int
server_window_check_bell(struct session *s, struct window *w) server_window_check_bell(struct session *s, struct winlink *wl)
{ {
struct client *c; struct client *c;
struct window *w = wl->window;
u_int i; u_int i;
int action, visual; int action, visual;
if (!(w->flags & WINDOW_BELL)) if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL)
return (0);
if (s->curw == wl)
return (0); return (0);
if (session_alert_has_window(s, w, WINDOW_BELL)) wl->flags |= WINLINK_BELL;
return (0);
session_alert_add(s, w, WINDOW_BELL);
action = options_get_number(&s->options, "bell-action"); action = options_get_number(&s->options, "bell-action");
switch (action) { switch (action) {
@ -155,25 +160,22 @@ server_window_check_bell(struct session *s, struct window *w)
/* Check for activity in window. */ /* Check for activity in window. */
int int
server_window_check_activity(struct session *s, struct window *w) server_window_check_activity(struct session *s, struct winlink *wl)
{ {
struct client *c; struct client *c;
struct window *w = wl->window;
u_int i; u_int i;
if (!(w->flags & WINDOW_ACTIVITY)) if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY)
return (0); return (0);
if (s->curw->window == w) if (s->curw == wl)
return (0); return (0);
if (!options_get_number(&w->options, "monitor-activity")) if (!options_get_number(&w->options, "monitor-activity"))
return (0); return (0);
if (session_alert_has_window(s, w, WINDOW_ACTIVITY)) wl->flags |= WINLINK_ACTIVITY;
return (0);
session_alert_add(s, w, WINDOW_ACTIVITY);
if (s->flags & SESSION_UNATTACHED)
return (0);
if (options_get_number(&s->options, "visual-activity")) { if (options_get_number(&s->options, "visual-activity")) {
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
@ -190,31 +192,28 @@ server_window_check_activity(struct session *s, struct window *w)
/* Check for content change in window. */ /* Check for content change in window. */
int int
server_window_check_content( server_window_check_content(
struct session *s, struct window *w, struct window_pane *wp) struct session *s, struct winlink *wl, struct window_pane *wp)
{ {
struct client *c; struct client *c;
struct window *w = wl->window;
u_int i; u_int i;
char *found, *ptr; char *found, *ptr;
if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */ /* Activity flag must be set for new content. */
if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_CONTENT)
return (0); return (0);
if (s->curw->window == w) if (s->curw == wl)
return (0); return (0);
ptr = options_get_string(&w->options, "monitor-content"); ptr = options_get_string(&w->options, "monitor-content");
if (ptr == NULL || *ptr == '\0') if (ptr == NULL || *ptr == '\0')
return (0); return (0);
if (session_alert_has_window(s, w, WINDOW_CONTENT))
return (0);
if ((found = window_pane_search(wp, ptr, NULL)) == NULL) if ((found = window_pane_search(wp, ptr, NULL)) == NULL)
return (0); return (0);
xfree(found); xfree(found);
session_alert_add(s, w, WINDOW_CONTENT); wl->flags |= WINLINK_CONTENT;
if (s->flags & SESSION_UNATTACHED)
return (0);
if (options_get_number(&s->options, "visual-content")) { if (options_get_number(&s->options, "visual-content")) {
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);

125
session.c
View File

@ -32,71 +32,8 @@ struct sessions sessions;
struct sessions dead_sessions; struct sessions dead_sessions;
struct session_groups session_groups; struct session_groups session_groups;
struct winlink *session_next_alert(struct session *, struct winlink *); struct winlink *session_next_alert(struct winlink *);
struct winlink *session_previous_alert(struct session *, struct winlink *); struct winlink *session_previous_alert(struct winlink *);
void
session_alert_cancel(struct session *s, struct winlink *wl)
{
struct session_alert *sa, *sb;
sa = SLIST_FIRST(&s->alerts);
while (sa != NULL) {
sb = sa;
sa = SLIST_NEXT(sa, entry);
if (wl == NULL || sb->wl == wl) {
SLIST_REMOVE(&s->alerts, sb, session_alert, entry);
xfree(sb);
}
}
}
void
session_alert_add(struct session *s, struct window *w, int type)
{
struct session_alert *sa;
struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows) {
if (wl == s->curw)
continue;
if (wl->window == w &&
!session_alert_has(s, wl, type)) {
sa = xmalloc(sizeof *sa);
sa->wl = wl;
sa->type = type;
SLIST_INSERT_HEAD(&s->alerts, sa, entry);
}
}
}
int
session_alert_has(struct session *s, struct winlink *wl, int type)
{
struct session_alert *sa;
SLIST_FOREACH(sa, &s->alerts, entry) {
if (sa->wl == wl && sa->type == type)
return (1);
}
return (0);
}
int
session_alert_has_window(struct session *s, struct window *w, int type)
{
struct session_alert *sa;
SLIST_FOREACH(sa, &s->alerts, entry) {
if (sa->wl->window == w && sa->type == type)
return (1);
}
return (0);
}
/* Find session by name. */ /* Find session by name. */
struct session * struct session *
@ -134,7 +71,6 @@ session_create(const char *name, const char *cmd, const char *cwd,
s->curw = NULL; s->curw = NULL;
TAILQ_INIT(&s->lastw); TAILQ_INIT(&s->lastw);
RB_INIT(&s->windows); RB_INIT(&s->windows);
SLIST_INIT(&s->alerts);
paste_init_stack(&s->buffers); paste_init_stack(&s->buffers);
@ -197,7 +133,6 @@ session_destroy(struct session *s)
xfree(s->tio); xfree(s->tio);
session_group_remove(s); session_group_remove(s);
session_alert_cancel(s, NULL);
environ_free(&s->environ); environ_free(&s->environ);
options_free(&s->options); options_free(&s->options);
paste_free_stack(&s->buffers); paste_free_stack(&s->buffers);
@ -285,7 +220,7 @@ session_detach(struct session *s, struct winlink *wl)
session_last(s) != 0 && session_previous(s, 0) != 0) session_last(s) != 0 && session_previous(s, 0) != 0)
session_next(s, 0); session_next(s, 0);
session_alert_cancel(s, wl); wl->flags &= ~WINLINK_ALERTFLAGS;
winlink_stack_remove(&s->lastw, wl); winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl); winlink_remove(&s->windows, wl);
session_group_synchronize_from(s); session_group_synchronize_from(s);
@ -297,27 +232,23 @@ session_detach(struct session *s, struct winlink *wl)
} }
/* Return if session has window. */ /* Return if session has window. */
int struct winlink *
session_has(struct session *s, struct window *w) session_has(struct session *s, struct window *w)
{ {
struct winlink *wl; struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
if (wl->window == w) if (wl->window == w)
return (1); return (wl);
} }
return (0); return (NULL);
} }
struct winlink * struct winlink *
session_next_alert(struct session *s, struct winlink *wl) session_next_alert(struct winlink *wl)
{ {
while (wl != NULL) { while (wl != NULL) {
if (session_alert_has(s, wl, WINDOW_BELL)) if (wl->flags & WINLINK_ALERTFLAGS)
break;
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
break;
if (session_alert_has(s, wl, WINDOW_CONTENT))
break; break;
wl = winlink_next(wl); wl = winlink_next(wl);
} }
@ -335,10 +266,10 @@ session_next(struct session *s, int alert)
wl = winlink_next(s->curw); wl = winlink_next(s->curw);
if (alert) if (alert)
wl = session_next_alert(s, wl); wl = session_next_alert(wl);
if (wl == NULL) { if (wl == NULL) {
wl = RB_MIN(winlinks, &s->windows); wl = RB_MIN(winlinks, &s->windows);
if (alert && ((wl = session_next_alert(s, wl)) == NULL)) if (alert && ((wl = session_next_alert(wl)) == NULL))
return (-1); return (-1);
} }
if (wl == s->curw) if (wl == s->curw)
@ -346,19 +277,15 @@ session_next(struct session *s, int alert)
winlink_stack_remove(&s->lastw, wl); winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw); winlink_stack_push(&s->lastw, s->curw);
s->curw = wl; s->curw = wl;
session_alert_cancel(s, wl); wl->flags &= ~WINLINK_ALERTFLAGS;
return (0); return (0);
} }
struct winlink * struct winlink *
session_previous_alert(struct session *s, struct winlink *wl) session_previous_alert(struct winlink *wl)
{ {
while (wl != NULL) { while (wl != NULL) {
if (session_alert_has(s, wl, WINDOW_BELL)) if (wl->flags & WINLINK_ALERTFLAGS)
break;
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
break;
if (session_alert_has(s, wl, WINDOW_CONTENT))
break; break;
wl = winlink_previous(wl); wl = winlink_previous(wl);
} }
@ -376,10 +303,10 @@ session_previous(struct session *s, int alert)
wl = winlink_previous(s->curw); wl = winlink_previous(s->curw);
if (alert) if (alert)
wl = session_previous_alert(s, wl); wl = session_previous_alert(wl);
if (wl == NULL) { if (wl == NULL) {
wl = RB_MAX(winlinks, &s->windows); wl = RB_MAX(winlinks, &s->windows);
if (alert && (wl = session_previous_alert(s, wl)) == NULL) if (alert && (wl = session_previous_alert(wl)) == NULL)
return (-1); return (-1);
} }
if (wl == s->curw) if (wl == s->curw)
@ -387,7 +314,7 @@ session_previous(struct session *s, int alert)
winlink_stack_remove(&s->lastw, wl); winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw); winlink_stack_push(&s->lastw, s->curw);
s->curw = wl; s->curw = wl;
session_alert_cancel(s, wl); wl->flags &= ~WINLINK_ALERTFLAGS;
return (0); return (0);
} }
@ -405,7 +332,7 @@ session_select(struct session *s, int idx)
winlink_stack_remove(&s->lastw, wl); winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw); winlink_stack_push(&s->lastw, s->curw);
s->curw = wl; s->curw = wl;
session_alert_cancel(s, wl); wl->flags &= ~WINLINK_ALERTFLAGS;
return (0); return (0);
} }
@ -424,7 +351,7 @@ session_last(struct session *s)
winlink_stack_remove(&s->lastw, wl); winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw); winlink_stack_push(&s->lastw, s->curw);
s->curw = wl; s->curw = wl;
session_alert_cancel(s, wl); wl->flags &= ~WINLINK_ALERTFLAGS;
return (0); return (0);
} }
@ -541,7 +468,6 @@ session_group_synchronize1(struct session *target, struct session *s)
struct winlinks old_windows, *ww; struct winlinks old_windows, *ww;
struct winlink_stack old_lastw; struct winlink_stack old_lastw;
struct winlink *wl, *wl2; struct winlink *wl, *wl2;
struct session_alert *sa;
/* Don't do anything if the session is empty (it'll be destroyed). */ /* Don't do anything if the session is empty (it'll be destroyed). */
ww = &target->windows; ww = &target->windows;
@ -559,8 +485,10 @@ session_group_synchronize1(struct session *target, struct session *s)
RB_INIT(&s->windows); RB_INIT(&s->windows);
/* Link all the windows from the target. */ /* Link all the windows from the target. */
RB_FOREACH(wl, winlinks, ww) RB_FOREACH(wl, winlinks, ww) {
winlink_add(&s->windows, wl->window, wl->idx); wl2 = winlink_add(&s->windows, wl->window, wl->idx);
wl2->flags |= wl->flags & WINLINK_ALERTFLAGS;
}
/* Fix up the current window. */ /* Fix up the current window. */
if (s->curw != NULL) if (s->curw != NULL)
@ -577,15 +505,6 @@ session_group_synchronize1(struct session *target, struct session *s)
TAILQ_INSERT_TAIL(&s->lastw, wl2, sentry); TAILQ_INSERT_TAIL(&s->lastw, wl2, sentry);
} }
/* And update the alerts list. */
SLIST_FOREACH(sa, &s->alerts, entry) {
wl = winlink_find_by_index(&s->windows, sa->wl->idx);
if (wl == NULL)
session_alert_cancel(s, sa->wl);
else
sa->wl = wl;
}
/* Then free the old winlinks list. */ /* Then free the old winlinks list. */
while (!RB_EMPTY(&old_windows)) { while (!RB_EMPTY(&old_windows)) {
wl = RB_ROOT(&old_windows); wl = RB_ROOT(&old_windows);

View File

@ -248,25 +248,15 @@ status_redraw(struct client *c)
*/ */
offset = 0; offset = 0;
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
if (larrow == 1 && offset < wlstart) { if (wl->flags & WINLINK_ALERTFLAGS &&
if (session_alert_has(s, wl, WINDOW_ACTIVITY)) larrow == 1 && offset < wlstart)
larrow = -1; larrow = -1;
else if (session_alert_has(s, wl, WINDOW_BELL))
larrow = -1;
else if (session_alert_has(s, wl, WINDOW_CONTENT))
larrow = -1;
}
offset += wl->status_width; offset += wl->status_width;
if (rarrow == 1 && offset > wlstart + wlwidth) { if (wl->flags & WINLINK_ALERTFLAGS &&
if (session_alert_has(s, wl, WINDOW_ACTIVITY)) rarrow == 1 && offset > wlstart + wlwidth)
rarrow = -1; rarrow = -1;
else if (session_alert_has(s, wl, WINDOW_BELL))
rarrow = -1;
else if (session_alert_has(s, wl, WINDOW_CONTENT))
rarrow = -1;
}
} }
draw: draw:
@ -399,11 +389,11 @@ status_replace1(struct client *c,struct winlink *wl,
goto do_replace; goto do_replace;
case 'F': case 'F':
tmp[0] = ' '; tmp[0] = ' ';
if (session_alert_has(s, wl, WINDOW_CONTENT)) if (wl->flags & WINLINK_CONTENT)
tmp[0] = '+'; tmp[0] = '+';
else if (session_alert_has(s, wl, WINDOW_BELL)) else if (wl->flags & WINLINK_BELL)
tmp[0] = '!'; tmp[0] = '!';
else if (session_alert_has(s, wl, WINDOW_ACTIVITY)) else if (wl->flags & WINLINK_ACTIVITY)
tmp[0] = '#'; tmp[0] = '#';
else if (wl == s->curw) else if (wl == s->curw)
tmp[0] = '*'; tmp[0] = '*';
@ -593,9 +583,7 @@ status_print(
fmt = options_get_string(oo, "window-status-current-format"); fmt = options_get_string(oo, "window-status-current-format");
} }
if (session_alert_has(s, wl, WINDOW_ACTIVITY) || if (wl->flags & WINLINK_ALERTFLAGS) {
session_alert_has(s, wl, WINDOW_BELL) ||
session_alert_has(s, wl, WINDOW_CONTENT)) {
fg = options_get_number(oo, "window-status-alert-fg"); fg = options_get_number(oo, "window-status-alert-fg");
if (fg != 8) if (fg != 8)
colour_set_fg(gc, fg); colour_set_fg(gc, fg);

24
tmux.h
View File

@ -843,8 +843,7 @@ struct window {
#define WINDOW_BELL 0x1 #define WINDOW_BELL 0x1
#define WINDOW_HIDDEN 0x2 #define WINDOW_HIDDEN 0x2
#define WINDOW_ACTIVITY 0x4 #define WINDOW_ACTIVITY 0x4
#define WINDOW_CONTENT 0x8 #define WINDOW_REDRAW 0x8
#define WINDOW_REDRAW 0x10
struct options options; struct options options;
@ -861,6 +860,12 @@ struct winlink {
struct grid_cell status_cell; struct grid_cell status_cell;
char *status_text; char *status_text;
int flags;
#define WINLINK_BELL 0x1
#define WINLINK_ACTIVITY 0x2
#define WINLINK_CONTENT 0x4
#define WINLINK_ALERTFLAGS (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_CONTENT)
RB_ENTRY(winlink) entry; RB_ENTRY(winlink) entry;
TAILQ_ENTRY(winlink) sentry; TAILQ_ENTRY(winlink) sentry;
}; };
@ -912,13 +917,6 @@ struct environ_entry {
RB_HEAD(environ, environ_entry); RB_HEAD(environ, environ_entry);
/* Client session. */ /* Client session. */
struct session_alert {
struct winlink *wl;
int type;
SLIST_ENTRY(session_alert) entry;
};
struct session_group { struct session_group {
TAILQ_HEAD(, session) sessions; TAILQ_HEAD(, session) sessions;
@ -943,8 +941,6 @@ struct session {
struct paste_stack buffers; struct paste_stack buffers;
SLIST_HEAD(, session_alert) alerts;
#define SESSION_UNATTACHED 0x1 /* not attached to any clients */ #define SESSION_UNATTACHED 0x1 /* not attached to any clients */
#define SESSION_DEAD 0x2 #define SESSION_DEAD 0x2
int flags; int flags;
@ -1911,10 +1907,6 @@ void clear_signals(void);
extern struct sessions sessions; extern struct sessions sessions;
extern struct sessions dead_sessions; extern struct sessions dead_sessions;
extern struct session_groups session_groups; extern struct session_groups session_groups;
void session_alert_add(struct session *, struct window *, int);
void session_alert_cancel(struct session *, struct winlink *);
int session_alert_has(struct session *, struct winlink *, int);
int session_alert_has_window(struct session *, struct window *, int);
struct session *session_find(const char *); struct session *session_find(const char *);
struct session *session_create(const char *, const char *, const char *, struct session *session_create(const char *, const char *, const char *,
struct environ *, struct termios *, int, u_int, u_int, struct environ *, struct termios *, int, u_int, u_int,
@ -1926,7 +1918,7 @@ struct winlink *session_new(struct session *,
struct winlink *session_attach( struct winlink *session_attach(
struct session *, struct window *, int, char **); struct session *, struct window *, int, char **);
int session_detach(struct session *, struct winlink *); int session_detach(struct session *, struct winlink *);
int session_has(struct session *, struct window *); struct winlink* session_has(struct session *, struct window *);
int session_next(struct session *, int); int session_next(struct session *, int);
int session_previous(struct session *, int); int session_previous(struct session *, int);
int session_select(struct session *, int); int session_select(struct session *, int);