summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd-break-pane.c3
-rw-r--r--cmd-choose-session.c16
-rw-r--r--cmd-choose-window.c4
-rw-r--r--cmd-kill-session.c4
-rw-r--r--cmd-link-window.c8
-rw-r--r--cmd-list-sessions.c23
-rw-r--r--cmd-move-window.c4
-rw-r--r--cmd-new-session.c38
-rw-r--r--cmd-new-window.c8
-rw-r--r--cmd-rename-window.c4
-rw-r--r--cmd-swap-window.c20
-rw-r--r--cmd-unlink-window.c20
-rw-r--r--server-fn.c75
-rw-r--r--server.c6
-rw-r--r--session.c191
-rw-r--r--status.c4
-rw-r--r--tmux.123
-rw-r--r--tmux.h28
-rw-r--r--window.c10
19 files changed, 411 insertions, 78 deletions
diff --git a/cmd-break-pane.c b/cmd-break-pane.c
index 63e4c6a9..e2e8768f 100644
--- a/cmd-break-pane.c
+++ b/cmd-break-pane.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-break-pane.c,v 1.8 2009-08-16 19:16:27 tcunha Exp $ */
+/* $Id: cmd-break-pane.c,v 1.9 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -78,6 +78,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
session_select(s, wl->idx);
server_redraw_session(s);
+ server_status_session_group(s);
return (0);
}
diff --git a/cmd-choose-session.c b/cmd-choose-session.c
index da15b9bb..27e03d19 100644
--- a/cmd-choose-session.c
+++ b/cmd-choose-session.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-choose-session.c,v 1.13 2009-09-07 23:59:19 tcunha Exp $ */
+/* $Id: cmd-choose-session.c,v 1.14 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -54,7 +54,9 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_choose_session_data *cdata;
struct winlink *wl;
struct session *s;
+ struct session_group *sg;
u_int i, idx, cur;
+ char tmp[64];
if (ctx->curclient == NULL) {
ctx->error(ctx, "must be run interactively");
@@ -76,10 +78,18 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
cur = idx;
idx++;
+ sg = session_group_find(s);
+ if (sg == NULL)
+ *tmp = '\0';
+ else {
+ idx = session_group_index(sg);
+ xsnprintf(tmp, sizeof tmp, " (group %u)", idx);
+ }
+
window_choose_add(wl->window->active, i,
- "%s: %u windows [%ux%u]%s", s->name,
+ "%s: %u windows [%ux%u]%s%s", s->name,
winlink_count(&s->windows), s->sx, s->sy,
- s->flags & SESSION_UNATTACHED ? "" : " (attached)");
+ tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)");
}
cdata = xmalloc(sizeof *cdata);
diff --git a/cmd-choose-window.c b/cmd-choose-window.c
index 04d77e73..8137c6eb 100644
--- a/cmd-choose-window.c
+++ b/cmd-choose-window.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-choose-window.c,v 1.17 2009-09-07 23:59:19 tcunha Exp $ */
+/* $Id: cmd-choose-window.c,v 1.18 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -89,7 +89,7 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
flag = '+';
else if (wm == s->curw)
flag = '*';
- else if (wm == SLIST_FIRST(&s->lastw))
+ else if (wm == TAILQ_FIRST(&s->lastw))
flag = '-';
title = w->active->screen->title;
diff --git a/cmd-kill-session.c b/cmd-kill-session.c
index cc1ff254..55e3ff6e 100644
--- a/cmd-kill-session.c
+++ b/cmd-kill-session.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-kill-session.c,v 1.14 2009-07-28 22:12:16 tcunha Exp $ */
+/* $Id: cmd-kill-session.c,v 1.15 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -53,7 +53,7 @@ cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
- if (c->session == s) {
+ if (c != NULL && c->session == s) {
c->session = NULL;
server_write_client(c, MSG_EXIT, NULL, 0);
}
diff --git a/cmd-link-window.c b/cmd-link-window.c
index 59a59109..0f55c82d 100644
--- a/cmd-link-window.c
+++ b/cmd-link-window.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-link-window.c,v 1.34 2009-09-20 22:17:03 tcunha Exp $ */
+/* $Id: cmd-link-window.c,v 1.35 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -43,19 +43,19 @@ int
cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_srcdst_data *data = self->data;
- struct session *dst;
+ struct session *src, *dst;
struct winlink *wl;
char *cause;
int idx, kflag, dflag;
- if ((wl = cmd_find_window(ctx, data->src, NULL)) == NULL)
+ if ((wl = cmd_find_window(ctx, data->src, &src)) == NULL)
return (-1);
if ((idx = cmd_find_index(ctx, data->dst, &dst)) == -2)
return (-1);
kflag = data->chflags & CMD_CHFLAG('k');
dflag = data->chflags & CMD_CHFLAG('d');
- if (server_link_window(wl, dst, idx, kflag, !dflag, &cause) != 0) {
+ if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
ctx->error(ctx, "can't link window: %s", cause);
xfree(cause);
return (-1);
diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c
index 74274e05..e6be3bbc 100644
--- a/cmd-list-sessions.c
+++ b/cmd-list-sessions.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-list-sessions.c,v 1.21 2009-07-28 22:12:16 tcunha Exp $ */
+/* $Id: cmd-list-sessions.c,v 1.22 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -42,23 +42,32 @@ const struct cmd_entry cmd_list_sessions_entry = {
int
cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx)
{
- struct session *s;
- char *tim;
- u_int i;
- time_t t;
+ struct session *s;
+ struct session_group *sg;
+ char *tim, tmp[64];
+ u_int i, idx;
+ time_t t;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
+ sg = session_group_find(s);
+ if (sg == NULL)
+ *tmp = '\0';
+ else {
+ idx = session_group_index(sg);
+ xsnprintf(tmp, sizeof tmp, " (group %u)", idx);
+ }
+
t = s->tv.tv_sec;
tim = ctime(&t);
*strchr(tim, '\n') = '\0';
- ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s",
+ ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s%s",
s->name, winlink_count(&s->windows), tim, s->sx, s->sy,
- s->flags & SESSION_UNATTACHED ? "" : " (attached)");
+ tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)");
}
return (0);
diff --git a/cmd-move-window.c b/cmd-move-window.c
index ae0595d2..6ac07c1c 100644
--- a/cmd-move-window.c
+++ b/cmd-move-window.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-move-window.c,v 1.11 2009-09-20 22:17:03 tcunha Exp $ */
+/* $Id: cmd-move-window.c,v 1.12 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -55,7 +55,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
kflag = data->chflags & CMD_CHFLAG('k');
dflag = data->chflags & CMD_CHFLAG('d');
- if (server_link_window(wl, dst, idx, kflag, !dflag, &cause) != 0) {
+ if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
ctx->error(ctx, "can't move window: %s", cause);
xfree(cause);
return (-1);
diff --git a/cmd-new-session.c b/cmd-new-session.c
index 8ee40eca..426fd4de 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-new-session.c,v 1.67 2009-09-22 14:06:40 tcunha Exp $ */
+/* $Id: cmd-new-session.c,v 1.68 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -35,6 +35,7 @@ void cmd_new_session_init(struct cmd *, int);
size_t cmd_new_session_print(struct cmd *, char *, size_t);
struct cmd_new_session_data {
+ char *target;
char *newname;
char *winname;
char *cmd;
@@ -43,7 +44,7 @@ struct cmd_new_session_data {
const struct cmd_entry cmd_new_session_entry = {
"new-session", "new",
- "[-d] [-n window-name] [-s session-name] [command]",
+ "[-d] [-n window-name] [-s session-name] [-t target-session] [command]",
CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, 0,
cmd_new_session_init,
cmd_new_session_parse,
@@ -59,6 +60,7 @@ cmd_new_session_init(struct cmd *self, unused int arg)
self->data = data = xmalloc(sizeof *data);
data->flag_detached = 0;
+ data->target = NULL;
data->newname = NULL;
data->winname = NULL;
data->cmd = NULL;
@@ -73,7 +75,7 @@ cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause)
self->entry->init(self, KEYC_NONE);
data = self->data;
- while ((opt = getopt(argc, argv, "ds:n:")) != -1) {
+ while ((opt = getopt(argc, argv, "ds:t:n:")) != -1) {
switch (opt) {
case 'd':
data->flag_detached = 1;
@@ -82,6 +84,10 @@ cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause)
if (data->newname == NULL)
data->newname = xstrdup(optarg);
break;
+ case 't':
+ if (data->target == NULL)
+ data->target = xstrdup(optarg);
+ break;
case 'n':
if (data->winname == NULL)
data->winname = xstrdup(optarg);
@@ -95,6 +101,9 @@ cmd_new_session_parse(struct cmd *self, int argc, char **argv, char **cause)
if (argc != 0 && argc != 1)
goto usage;
+ if (data->target != NULL && (argc == 1 || data->winname != NULL))
+ goto usage;
+
if (argc == 1)
data->cmd = xstrdup(argv[0]);
@@ -111,7 +120,7 @@ int
cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_new_session_data *data = self->data;
- struct session *s;
+ struct session *s, *groupwith;
struct window *w;
struct environ env;
struct termios tio, *tiop;
@@ -125,6 +134,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1);
}
+ groupwith = NULL;
+ if (data->target != NULL &&
+ (groupwith = cmd_find_session(ctx, data->target)) == NULL)
+ return (-1);
+
/*
* There are three cases:
*
@@ -205,7 +219,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
sy = 1;
/* Figure out the command for the new window. */
- if (data->cmd != NULL)
+ if (data->target != NULL)
+ cmd = NULL;
+ else if (data->cmd != NULL)
cmd = data->cmd;
else
cmd = options_get_string(&global_s_options, "default-command");
@@ -228,7 +244,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
environ_free(&env);
/* Set the initial window name if one given. */
- if (data->winname != NULL) {
+ if (cmd != NULL && data->winname != NULL) {
w = s->curw->window;
xfree(w->name);
@@ -238,6 +254,16 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
}
/*
+ * If a target session is given, this is to be part of a session group,
+ * so add it to the group and synchronize.
+ */
+ if (groupwith != NULL) {
+ session_group_add(groupwith, s);
+ session_group_synchronize_to(s);
+ session_select(s, RB_ROOT(&s->windows)->idx);
+ }
+
+ /*
* Set the client to the new session. If a command client exists, it is
* taking this session and needs to get MSG_READY and stay around.
*/
diff --git a/cmd-new-window.c b/cmd-new-window.c
index 4a258c41..779ca418 100644
--- a/cmd-new-window.c
+++ b/cmd-new-window.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-new-window.c,v 1.38 2009-09-22 14:06:40 tcunha Exp $ */
+/* $Id: cmd-new-window.c,v 1.39 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -164,9 +164,9 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
}
if (!data->flag_detached) {
session_select(s, wl->idx);
- server_redraw_session(s);
- } else
- server_status_session(s);
+ server_redraw_session_group(s);
+ } else
+ server_status_session_group(s);
return (0);
}
diff --git a/cmd-rename-window.c b/cmd-rename-window.c
index 518e013d..44242d5b 100644
--- a/cmd-rename-window.c
+++ b/cmd-rename-window.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-rename-window.c,v 1.29 2009-07-28 22:12:16 tcunha Exp $ */
+/* $Id: cmd-rename-window.c,v 1.30 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -53,7 +53,7 @@ cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx)
wl->window->name = xstrdup(data->arg);
options_set_number(&wl->window->options, "automatic-rename", 0);
- server_status_session(s);
+ server_status_window(wl->window);
return (0);
}
diff --git a/cmd-swap-window.c b/cmd-swap-window.c
index fdd25ce6..8d6e0b32 100644
--- a/cmd-swap-window.c
+++ b/cmd-swap-window.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-swap-window.c,v 1.17 2009-07-28 22:12:16 tcunha Exp $ */
+/* $Id: cmd-swap-window.c,v 1.18 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -44,6 +44,7 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_srcdst_data *data = self->data;
struct session *src, *dst;
+ struct session_group *sg_src, *sg_dst;
struct winlink *wl_src, *wl_dst;
struct window *w;
@@ -52,6 +53,14 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
if ((wl_dst = cmd_find_window(ctx, data->dst, &dst)) == NULL)
return (-1);
+ sg_src = session_group_find(src);
+ sg_dst = session_group_find(dst);
+ if (src != dst &&
+ sg_src != NULL && sg_dst != NULL && sg_src == sg_dst) {
+ ctx->error(ctx, "can't move window, sessions are grouped");
+ return (-1);
+ }
+
if (wl_dst->window == wl_src->window)
return (0);
@@ -64,9 +73,12 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
if (src != dst)
session_select(src, wl_src->idx);
}
- server_redraw_session(src);
- if (src != dst)
- server_redraw_session(dst);
+ session_group_synchronize_from(src);
+ server_redraw_session_group(src);
+ if (src != dst) {
+ session_group_synchronize_from(dst);
+ server_redraw_session_group(dst);
+ }
recalculate_sizes();
return (0);
diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c
index dea0a058..936a7e4f 100644
--- a/cmd-unlink-window.c
+++ b/cmd-unlink-window.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-unlink-window.c,v 1.18 2009-09-20 22:17:03 tcunha Exp $ */
+/* $Id: cmd-unlink-window.c,v 1.19 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -42,16 +42,28 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct winlink *wl;
- struct session *s;
+ struct window *w;
+ struct session *s, *s2;
+ struct session_group *sg;
+ u_int references;
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
return (-1);
+ w = wl->window;
- if (!(data->chflags & CMD_CHFLAG('k')) && wl->window->references == 1) {
+ sg = session_group_find(s);
+ if (sg != NULL) {
+ references = 0;
+ TAILQ_FOREACH(s2, &sg->sessions, gentry)
+ references++;
+ } else
+ references = 1;
+
+ if (!(data->chflags & CMD_CHFLAG('k')) && w->references == references) {
ctx->error(ctx, "window is only linked to one session");
return (-1);
}
-
+
server_unlink_window(s, wl);
recalculate_sizes();
diff --git a/server-fn.c b/server-fn.c
index 03c14c35..f34c8aec 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -1,4 +1,4 @@
-/* $Id: server-fn.c,v 1.92 2009-10-05 18:23:31 tcunha Exp $ */
+/* $Id: server-fn.c,v 1.93 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -105,6 +105,19 @@ server_redraw_session(struct session *s)
}
void
+server_redraw_session_group(struct session *s)
+{
+ struct session_group *sg;
+
+ if ((sg = session_group_find(s)) == NULL)
+ server_redraw_session(s);
+ else {
+ TAILQ_FOREACH(s, &sg->sessions, gentry)
+ server_redraw_session(s);
+ }
+}
+
+void
server_status_session(struct session *s)
{
struct client *c;
@@ -120,6 +133,19 @@ server_status_session(struct session *s)
}
void
+server_status_session_group(struct session *s)
+{
+ struct session_group *sg;
+
+ if ((sg = session_group_find(s)) == NULL)
+ server_status_session(s);
+ else {
+ TAILQ_FOREACH(s, &sg->sessions, gentry)
+ server_status_session(s);
+ }
+}
+
+void
server_redraw_window(struct window *w)
{
struct client *c;
@@ -220,18 +246,27 @@ server_kill_window(struct window *w)
continue;
if (session_detach(s, wl))
- server_destroy_session(s);
- else
+ server_destroy_session_group(s);
+ else {
server_redraw_session(s);
+ server_status_session_group(s);
+ }
}
}
int
-server_link_window(
- struct winlink *srcwl, struct session *dst, int dstidx,
- int killflag, int selectflag, char **cause)
+server_link_window(struct session *src, struct winlink *srcwl,
+ struct session *dst, int dstidx, int killflag, int selectflag, char **cause)
{
- struct winlink *dstwl;
+ struct winlink *dstwl;
+ struct session_group *srcsg, *dstsg;
+
+ srcsg = session_group_find(src);
+ dstsg = session_group_find(dst);
+ if (src != dst && srcsg != NULL && dstsg != NULL && srcsg == dstsg) {
+ xasprintf(cause, "sessions are grouped");
+ return (-1);
+ }
dstwl = NULL;
if (dstidx != -1)
@@ -260,12 +295,9 @@ server_link_window(
if (dstwl == NULL)
return (-1);
- if (!selectflag)
- server_status_session(dst);
- else {
+ if (selectflag)
session_select(dst, dstwl->idx);
- server_redraw_session(dst);
- }
+ server_redraw_session_group(dst);
return (0);
}
@@ -274,9 +306,24 @@ void
server_unlink_window(struct session *s, struct winlink *wl)
{
if (session_detach(s, wl))
- server_destroy_session(s);
+ server_destroy_session_group(s);
else
- server_redraw_session(s);
+ server_redraw_session_group(s);
+}
+
+void
+server_destroy_session_group(struct session *s)
+{
+ struct session_group *sg;
+
+ if ((sg = session_group_find(s)) == NULL)
+ server_destroy_session(s);
+ else {
+ TAILQ_FOREACH(s, &sg->sessions, gentry)
+ server_destroy_session(s);
+ TAILQ_REMOVE(&session_groups, sg, entry);
+ xfree(sg);
+ }
}
void
diff --git a/server.c b/server.c
index b6de3986..6a7e7a54 100644
--- a/server.c
+++ b/server.c
@@ -1,4 +1,4 @@
-/* $Id: server.c,v 1.197 2009-10-11 23:30:28 tcunha Exp $ */
+/* $Id: server.c,v 1.198 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -248,6 +248,7 @@ server_start(char *path)
ARRAY_INIT(&dead_clients);
ARRAY_INIT(&sessions);
ARRAY_INIT(&dead_sessions);
+ TAILQ_INIT(&session_groups);
mode_key_init_trees();
key_bindings_init();
utf8_build();
@@ -1246,10 +1247,11 @@ server_check_window(struct window *w)
if (wl->window != w)
continue;
if (session_detach(s, wl)) {
- server_destroy_session(s);
+ server_destroy_session_group(s);
break;
}
server_redraw_session(s);
+ server_status_session_group(s);
goto restart;
}
}
diff --git a/session.c b/session.c
index b6a23ad7..e4f5055c 100644
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
-/* $Id: session.c,v 1.68 2009-10-11 23:30:28 tcunha Exp $ */
+/* $Id: session.c,v 1.69 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -29,6 +29,7 @@
/* Global session list. */
struct sessions sessions;
struct sessions dead_sessions;
+struct session_groups session_groups;
struct winlink *session_next_activity(struct session *, struct winlink *);
struct winlink *session_previous_activity(struct session *, struct winlink *);
@@ -130,7 +131,7 @@ session_create(const char *name, const char *cmd, const char *cwd,
fatal("gettimeofday failed");
s->curw = NULL;
- SLIST_INIT(&s->lastw);
+ TAILQ_INIT(&s->lastw);
RB_INIT(&s->windows);
SLIST_INIT(&s->alerts);
@@ -163,11 +164,14 @@ session_create(const char *name, const char *cmd, const char *cwd,
s->name = xstrdup(name);
else
xasprintf(&s->name, "%u", i);
- if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) {
- session_destroy(s);
- return (NULL);
+
+ if (cmd != NULL) {
+ if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) {
+ session_destroy(s);
+ return (NULL);
+ }
+ session_select(s, RB_ROOT(&s->windows)->idx);
}
- session_select(s, RB_ROOT(&s->windows)->idx);
log_debug("session %s created", s->name);
@@ -191,13 +195,14 @@ session_destroy(struct session *s)
if (s->tio != NULL)
xfree(s->tio);
+ session_group_remove(s);
session_alert_cancel(s, NULL);
environ_free(&s->environ);
options_free(&s->options);
paste_free_stack(&s->buffers);
- while (!SLIST_EMPTY(&s->lastw))
- winlink_stack_remove(&s->lastw, SLIST_FIRST(&s->lastw));
+ while (!TAILQ_EMPTY(&s->lastw))
+ winlink_stack_remove(&s->lastw, TAILQ_FIRST(&s->lastw));
while (!RB_EMPTY(&s->windows))
winlink_remove(&s->windows, RB_ROOT(&s->windows));
@@ -267,6 +272,7 @@ session_attach(struct session *s, struct window *w, int idx, char **cause)
if ((wl = winlink_add(&s->windows, w, idx)) == NULL)
xasprintf(cause, "index in use: %d", idx);
+ session_group_synchronize_from(s);
return (wl);
}
@@ -281,6 +287,7 @@ session_detach(struct session *s, struct winlink *wl)
session_alert_cancel(s, wl);
winlink_stack_remove(&s->lastw, wl);
winlink_remove(&s->windows, wl);
+ session_group_synchronize_from(s);
if (RB_EMPTY(&s->windows)) {
session_destroy(s);
return (1);
@@ -407,7 +414,7 @@ session_last(struct session *s)
{
struct winlink *wl;
- wl = SLIST_FIRST(&s->lastw);
+ wl = TAILQ_FIRST(&s->lastw);
if (wl == NULL)
return (-1);
if (wl == s->curw)
@@ -419,3 +426,169 @@ session_last(struct session *s)
session_alert_cancel(s, wl);
return (0);
}
+
+/* Find the session group containing a session. */
+struct session_group *
+session_group_find(struct session *target)
+{
+ struct session_group *sg;
+ struct session *s;
+
+ TAILQ_FOREACH(sg, &session_groups, entry) {
+ TAILQ_FOREACH(s, &sg->sessions, gentry) {
+ if (s == target)
+ return (sg);
+ }
+ }
+ return (NULL);
+}
+
+/* Find session group index. */
+u_int
+session_group_index(struct session_group *sg)
+{
+ struct session_group *sg2;
+ u_int i;
+
+ i = 0;
+ TAILQ_FOREACH(sg2, &session_groups, entry) {
+ if (sg == sg2)
+ return (i);
+ i++;
+ }
+
+ fatalx("session group not found");
+}
+
+/*
+ * Add a session to the session group containing target, creating it if
+ * necessary.
+ */
+void
+session_group_add(struct session *target, struct session *s)
+{
+ struct session_group *sg;
+
+ if ((sg = session_group_find(target)) == NULL) {
+ sg = xmalloc(sizeof *sg);
+ TAILQ_INSERT_TAIL(&session_groups, sg, entry);
+ TAILQ_INIT(&sg->sessions);
+ TAILQ_INSERT_TAIL(&sg->sessions, target, gentry);
+ }
+ TAILQ_INSERT_TAIL(&sg->sessions, s, gentry);
+}
+
+/* Remove a session from its group and destroy the group if empty. */
+void
+session_group_remove(struct session *s)
+{
+ struct session_group *sg;
+
+ if ((sg = session_group_find(s)) == NULL)
+ return;
+ TAILQ_REMOVE(&sg->sessions, s, gentry);
+ if (TAILQ_NEXT(TAILQ_FIRST(&sg->sessions), gentry) == NULL)
+ TAILQ_REMOVE(&sg->sessions, TAILQ_FIRST(&sg->sessions), gentry);
+ if (TAILQ_EMPTY(&sg->sessions)) {
+ TAILQ_REMOVE(&session_groups, sg, entry);
+ xfree(sg);
+ }
+}
+
+/* Synchronize a session to its session group. */
+void
+session_group_synchronize_to(struct session *s)
+{
+ struct session_group *sg;
+ struct session *target;
+
+ if ((sg = session_group_find(s)) == NULL)
+ return;
+
+ target = NULL;
+ TAILQ_FOREACH(target, &sg->sessions, gentry) {
+ if (target != s)
+ break;
+ }
+ session_group_synchronize1(target, s);
+}
+
+/* Synchronize a session group to a session. */
+void
+session_group_synchronize_from(struct session *target)
+{
+ struct session_group *sg;
+ struct session *s;
+
+ if ((sg = session_group_find(target)) == NULL)
+ return;
+
+ TAILQ_FOREACH(s, &sg->sessions, gentry) {
+ if (s != target)
+ session_group_synchronize1(target, s);
+ }
+}
+
+/*
+ * Synchronize a session with a target session. This means destroying all
+ * winlinks then recreating them, then updating the current window, last window
+ * stack and alerts.
+ */
+void
+session_group_synchronize1(struct session *target, struct session *s)
+{
+ struct winlinks old_windows, *ww;
+ struct winlink_stack old_lastw;
+ struct winlink *wl, *wl2;
+ struct session_alert *sa;
+
+ /* Don't do anything if the session is empty (it'll be destroyed). */
+ ww = &target->windows;
+ if (RB_EMPTY(ww))
+ return;
+
+ /* If the current window has vanished, move to the next now. */
+ if (s->curw != NULL) {
+ while (winlink_find_by_index(ww, s->curw->idx) == NULL)
+ session_next(s, 0);
+ }
+
+ /* Save the old pointer and reset it. */
+ memcpy(&old_windows, &s->windows, sizeof old_windows);
+ RB_INIT(&s->windows);
+
+ /* Link all the windows from the target. */
+ RB_FOREACH(wl, winlinks, ww)
+ winlink_add(&s->windows, wl->window, wl->idx);
+
+ /* Fix up the current window. */
+ if (s->curw != NULL)
+ s->curw = winlink_find_by_index(&s->windows, s->curw->idx);
+ else
+ s->curw = winlink_find_by_index(&s->windows, target->curw->idx);
+
+ /* Fix up the last window stack. */
+ memcpy(&old_lastw, &s->lastw, sizeof old_lastw);
+ TAILQ_INIT(&s->lastw);
+ TAILQ_FOREACH(wl, &old_lastw, sentry) {
+ wl2 = winlink_find_by_index(&s->windows, wl->idx);
+ if (wl2 != NULL)
+ 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. */
+ while (!RB_EMPTY(&old_windows)) {
+ wl = RB_ROOT(&old_windows);
+ RB_REMOVE(winlinks, &old_windows, wl);
+ xfree(wl);
+ }
+}
diff --git a/status.c b/status.c
index 7f4f31e1..795f8efc 100644
--- a/status.c
+++ b/status.c
@@ -1,4 +1,4 @@
-/* $Id: status.c,v 1.121 2009-09-25 17:45:46 tcunha Exp $ */
+/* $Id: status.c,v 1.122 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -516,7 +516,7 @@ status_print(struct session *s, struct winlink *wl, struct grid_cell *gc)
gc->attr = attr;
flag = ' ';
- if (wl == SLIST_FIRST(&s->lastw))
+ if (wl == TAILQ_FIRST(&s->lastw))
flag = '-';
if (wl == s->curw) {
fg = options_get_number(oo, "window-status-current-fg");
diff --git a/tmux.1 b/tmux.1
index 328ec5d9..4600910d 100644
--- a/tmux.1
+++ b/tmux.1
@@ -1,4 +1,4 @@
-.\" $Id: tmux.1,v 1.182 2009-10-11 23:30:28 tcunha Exp $
+.\" $Id: tmux.1,v 1.183 2009-10-11 23:38:16 tcunha Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\"
@@ -409,6 +409,7 @@ Lock all clients attached to
.Op Fl d
.Op Fl n Ar window-name
.Op Fl s Ar session-name
+.Op Fl t Ar target-session
.Op Ar command
.Xc
.D1 (alias: Ic new )
@@ -425,6 +426,26 @@ are the name of and command to execute in the initial window.
If run from a terminal, any
.Xr termios 4
special characters are saved and used for new windows in the new session.
+.Pp
+If
+.Fl t
+is given, the new session is
+.Em grouped
+with
+.Ar target-session .
+This means they share the same set of windows - all windows from
+.Ar target-session
+are linked to the new session and any subsequent new windows or windows being
+closed are applied to both sessions.
+The current and previous window and any session options remain independent and
+either session may be killed without affecting the other.
+Giving
+.Fl n
+or
+.Ar command
+are invalid if
+.Fl t
+is used.
.It Ic refresh-client Op Fl t Ar target-client
.D1 (alias: Ic refresh )
Refresh the current client if bound to a key, or a single client if one is given
diff --git a/tmux.h b/tmux.h
index 63d05fc5..f53b3b42 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1,4 +1,4 @@
-/* $Id: tmux.h,v 1.461 2009-10-11 23:30:28 tcunha Exp $ */
+/* $Id: tmux.h,v 1.462 2009-10-11 23:38:16 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -737,10 +737,10 @@ struct winlink {
struct window *window;
RB_ENTRY(winlink) entry;
- SLIST_ENTRY(winlink) sentry;
+ TAILQ_ENTRY(winlink) sentry;
};
RB_HEAD(winlinks, winlink);
-SLIST_HEAD(winlink_stack, winlink);
+TAILQ_HEAD(winlink_stack, winlink);
/* Layout direction. */
enum layout_type {
@@ -795,6 +795,13 @@ struct session_alert {
SLIST_ENTRY(session_alert) entry;
};
+struct session_group {
+ TAILQ_HEAD(, session) sessions;
+
+ TAILQ_ENTRY(session_group) entry;
+};
+TAILQ_HEAD(session_groups, session_group);
+
struct session {
char *name;
struct timeval tv;
@@ -822,6 +829,8 @@ struct session {
struct environ environ;
int references;
+
+ TAILQ_ENTRY(session) gentry;
};
ARRAY_DECL(sessions, struct session *);
@@ -1454,7 +1463,9 @@ void server_write_session(
void server_redraw_client(struct client *);
void server_status_client(struct client *);
void server_redraw_session(struct session *);
+void server_redraw_session_group(struct session *);
void server_status_session(struct session *);
+void server_status_session_group(struct session *);
void server_redraw_window(struct window *);