mirror of
https://github.com/tmux/tmux.git
synced 2025-09-07 03:48:20 +00:00
Merge branch 'obsd-master'
Conflicts: server.c
This commit is contained in:
@@ -68,12 +68,12 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
{
|
{
|
||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
struct client *c = item->client;
|
struct client *c = item->client;
|
||||||
struct session *s, *as;
|
struct session *s, *as, *groupwith;
|
||||||
struct session *groupwith = item->state.tflag.s;
|
|
||||||
struct window *w;
|
struct window *w;
|
||||||
struct environ *env;
|
struct environ *env;
|
||||||
struct termios tio, *tiop;
|
struct termios tio, *tiop;
|
||||||
const char *newname, *target, *errstr, *template;
|
struct session_group *sg;
|
||||||
|
const char *newname, *errstr, *template, *group, *prefix;
|
||||||
const char *path, *cmd, *cwd, *to_free = NULL;
|
const char *path, *cmd, *cwd, *to_free = NULL;
|
||||||
char **argv, *cause, *cp;
|
char **argv, *cause, *cp;
|
||||||
int detached, already_attached, idx, argc;
|
int detached, already_attached, idx, argc;
|
||||||
@@ -119,13 +119,29 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((target = args_get(args, 't')) != NULL) {
|
/* Is this going to be part of a session group? */
|
||||||
|
group = args_get(args, 't');
|
||||||
|
if (group != NULL) {
|
||||||
|
groupwith = item->state.tflag.s;
|
||||||
if (groupwith == NULL) {
|
if (groupwith == NULL) {
|
||||||
cmdq_error(item, "no such session: %s", target);
|
if (!session_check_name(group)) {
|
||||||
goto error;
|
cmdq_error(item, "bad group name: %s", group);
|
||||||
}
|
goto error;
|
||||||
} else
|
}
|
||||||
|
sg = session_group_find(group);
|
||||||
|
} else
|
||||||
|
sg = session_group_contains(groupwith);
|
||||||
|
if (sg != NULL)
|
||||||
|
prefix = sg->name;
|
||||||
|
else if (groupwith != NULL)
|
||||||
|
prefix = groupwith->name;
|
||||||
|
else
|
||||||
|
prefix = group;
|
||||||
|
} else {
|
||||||
groupwith = NULL;
|
groupwith = NULL;
|
||||||
|
sg = NULL;
|
||||||
|
prefix = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set -d if no client. */
|
/* Set -d if no client. */
|
||||||
detached = args_has(args, 'd');
|
detached = args_has(args, 'd');
|
||||||
@@ -213,7 +229,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (!args_has(args, 't') && args->argc != 0) {
|
if (!args_has(args, 't') && args->argc != 0) {
|
||||||
argc = args->argc;
|
argc = args->argc;
|
||||||
argv = args->argv;
|
argv = args->argv;
|
||||||
} else if (groupwith == NULL) {
|
} else if (sg == NULL && groupwith == NULL) {
|
||||||
cmd = options_get_string(global_s_options, "default-command");
|
cmd = options_get_string(global_s_options, "default-command");
|
||||||
if (cmd != NULL && *cmd != '\0') {
|
if (cmd != NULL && *cmd != '\0') {
|
||||||
argc = 1;
|
argc = 1;
|
||||||
@@ -239,8 +255,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
/* Create the new session. */
|
/* Create the new session. */
|
||||||
idx = -1 - options_get_number(global_s_options, "base-index");
|
idx = -1 - options_get_number(global_s_options, "base-index");
|
||||||
s = session_create(newname, argc, argv, path, cwd, env, tiop, idx, sx,
|
s = session_create(prefix, newname, argc, argv, path, cwd, env, tiop,
|
||||||
sy, &cause);
|
idx, sx, sy, &cause);
|
||||||
environ_free(env);
|
environ_free(env);
|
||||||
if (s == NULL) {
|
if (s == NULL) {
|
||||||
cmdq_error(item, "create session failed: %s", cause);
|
cmdq_error(item, "create session failed: %s", cause);
|
||||||
@@ -259,8 +275,15 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
* If a target session is given, this is to be part of a session group,
|
* If a target session is given, this is to be part of a session group,
|
||||||
* so add it to the group and synchronize.
|
* so add it to the group and synchronize.
|
||||||
*/
|
*/
|
||||||
if (groupwith != NULL) {
|
if (group != NULL) {
|
||||||
session_group_add(groupwith, s);
|
if (sg == NULL) {
|
||||||
|
if (groupwith != NULL) {
|
||||||
|
sg = session_group_new(groupwith->name);
|
||||||
|
session_group_add(sg, groupwith);
|
||||||
|
} else
|
||||||
|
sg = session_group_new(group);
|
||||||
|
}
|
||||||
|
session_group_add(sg, s);
|
||||||
session_group_synchronize_to(s);
|
session_group_synchronize_to(s);
|
||||||
session_select(s, RB_MIN(winlinks, &s->windows)->idx);
|
session_select(s, RB_MIN(winlinks, &s->windows)->idx);
|
||||||
}
|
}
|
||||||
|
@@ -52,11 +52,11 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
wl_src = item->state.sflag.wl;
|
wl_src = item->state.sflag.wl;
|
||||||
src = item->state.sflag.s;
|
src = item->state.sflag.s;
|
||||||
sg_src = session_group_find(src);
|
sg_src = session_group_contains(src);
|
||||||
|
|
||||||
wl_dst = item->state.tflag.wl;
|
wl_dst = item->state.tflag.wl;
|
||||||
dst = item->state.tflag.s;
|
dst = item->state.tflag.s;
|
||||||
sg_dst = session_group_find(dst);
|
sg_dst = session_group_contains(dst);
|
||||||
|
|
||||||
if (src != dst && sg_src != NULL && sg_dst != NULL &&
|
if (src != dst && sg_src != NULL && sg_dst != NULL &&
|
||||||
sg_src == sg_dst) {
|
sg_src == sg_dst) {
|
||||||
|
4
format.c
4
format.c
@@ -1117,10 +1117,10 @@ format_defaults_session(struct format_tree *ft, struct session *s)
|
|||||||
format_add(ft, "session_height", "%u", s->sy);
|
format_add(ft, "session_height", "%u", s->sy);
|
||||||
format_add(ft, "session_id", "$%u", s->id);
|
format_add(ft, "session_id", "$%u", s->id);
|
||||||
|
|
||||||
sg = session_group_find(s);
|
sg = session_group_contains(s);
|
||||||
format_add(ft, "session_grouped", "%d", sg != NULL);
|
format_add(ft, "session_grouped", "%d", sg != NULL);
|
||||||
if (sg != NULL)
|
if (sg != NULL)
|
||||||
format_add(ft, "session_group", "%u", session_group_index(sg));
|
format_add(ft, "session_group", "%s", sg->name);
|
||||||
|
|
||||||
format_add_tv(ft, "session_created", &s->creation_time);
|
format_add_tv(ft, "session_created", &s->creation_time);
|
||||||
format_add_tv(ft, "session_last_attached", &s->last_attached_time);
|
format_add_tv(ft, "session_last_attached", &s->last_attached_time);
|
||||||
|
29
grid.c
29
grid.c
@@ -78,6 +78,20 @@ grid_store_cell(struct grid_cell_entry *gce, const struct grid_cell *gc,
|
|||||||
gce->data.data = c;
|
gce->data.data = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if a cell should be extended. */
|
||||||
|
static int
|
||||||
|
grid_need_extended_cell(const struct grid_cell_entry *gce,
|
||||||
|
const struct grid_cell *gc)
|
||||||
|
{
|
||||||
|
if (gce->flags & GRID_FLAG_EXTENDED)
|
||||||
|
return (1);
|
||||||
|
if (gc->data.size != 1 || gc->data.width != 1)
|
||||||
|
return (1);
|
||||||
|
if ((gc->fg & COLOUR_FLAG_RGB) ||(gc->bg & COLOUR_FLAG_RGB))
|
||||||
|
return (1);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Set cell as extended. */
|
/* Set cell as extended. */
|
||||||
static struct grid_cell *
|
static struct grid_cell *
|
||||||
grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
|
grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
|
||||||
@@ -382,7 +396,6 @@ grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
|
|||||||
{
|
{
|
||||||
struct grid_line *gl;
|
struct grid_line *gl;
|
||||||
struct grid_cell_entry *gce;
|
struct grid_cell_entry *gce;
|
||||||
int extended;
|
|
||||||
|
|
||||||
if (grid_check_y(gd, py) != 0)
|
if (grid_check_y(gd, py) != 0)
|
||||||
return;
|
return;
|
||||||
@@ -394,14 +407,7 @@ grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
|
|||||||
gl->cellused = px + 1;
|
gl->cellused = px + 1;
|
||||||
|
|
||||||
gce = &gl->celldata[px];
|
gce = &gl->celldata[px];
|
||||||
extended = (gce->flags & GRID_FLAG_EXTENDED);
|
if (grid_need_extended_cell(gce, gc))
|
||||||
if (!extended && (gc->data.size != 1 || gc->data.width != 1))
|
|
||||||
extended = 1;
|
|
||||||
if (!extended && (gc->fg & COLOUR_FLAG_RGB))
|
|
||||||
extended = 1;
|
|
||||||
if (!extended && (gc->bg & COLOUR_FLAG_RGB))
|
|
||||||
extended = 1;
|
|
||||||
if (extended)
|
|
||||||
grid_extended_cell(gl, gce, gc);
|
grid_extended_cell(gl, gce, gc);
|
||||||
else
|
else
|
||||||
grid_store_cell(gce, gc, gc->data.data[0]);
|
grid_store_cell(gce, gc, gc->data.data[0]);
|
||||||
@@ -428,9 +434,8 @@ grid_set_cells(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc,
|
|||||||
|
|
||||||
for (i = 0; i < slen; i++) {
|
for (i = 0; i < slen; i++) {
|
||||||
gce = &gl->celldata[px + i];
|
gce = &gl->celldata[px + i];
|
||||||
if (gce->flags & GRID_FLAG_EXTENDED) {
|
if (grid_need_extended_cell(gce, gc)) {
|
||||||
gcp = &gl->extddata[gce->offset];
|
gcp = grid_extended_cell(gl, gce, gc);
|
||||||
memcpy(gcp, gc, sizeof *gcp);
|
|
||||||
utf8_set(&gcp->data, s[i]);
|
utf8_set(&gcp->data, s[i]);
|
||||||
} else
|
} else
|
||||||
grid_store_cell(gce, gc, s[i]);
|
grid_store_cell(gce, gc, s[i]);
|
||||||
|
12
server-fn.c
12
server-fn.c
@@ -76,7 +76,7 @@ server_redraw_session_group(struct session *s)
|
|||||||
{
|
{
|
||||||
struct session_group *sg;
|
struct session_group *sg;
|
||||||
|
|
||||||
if ((sg = session_group_find(s)) == NULL)
|
if ((sg = session_group_contains(s)) == NULL)
|
||||||
server_redraw_session(s);
|
server_redraw_session(s);
|
||||||
else {
|
else {
|
||||||
TAILQ_FOREACH(s, &sg->sessions, gentry)
|
TAILQ_FOREACH(s, &sg->sessions, gentry)
|
||||||
@@ -100,7 +100,7 @@ server_status_session_group(struct session *s)
|
|||||||
{
|
{
|
||||||
struct session_group *sg;
|
struct session_group *sg;
|
||||||
|
|
||||||
if ((sg = session_group_find(s)) == NULL)
|
if ((sg = session_group_contains(s)) == NULL)
|
||||||
server_status_session(s);
|
server_status_session(s);
|
||||||
else {
|
else {
|
||||||
TAILQ_FOREACH(s, &sg->sessions, gentry)
|
TAILQ_FOREACH(s, &sg->sessions, gentry)
|
||||||
@@ -218,7 +218,7 @@ server_kill_window(struct window *w)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options_get_number(s->options, "renumber-windows")) {
|
if (options_get_number(s->options, "renumber-windows")) {
|
||||||
if ((sg = session_group_find(s)) != NULL) {
|
if ((sg = session_group_contains(s)) != NULL) {
|
||||||
TAILQ_FOREACH(target_s, &sg->sessions, gentry)
|
TAILQ_FOREACH(target_s, &sg->sessions, gentry)
|
||||||
session_renumber_windows(target_s);
|
session_renumber_windows(target_s);
|
||||||
} else
|
} else
|
||||||
@@ -236,8 +236,8 @@ server_link_window(struct session *src, struct winlink *srcwl,
|
|||||||
struct winlink *dstwl;
|
struct winlink *dstwl;
|
||||||
struct session_group *srcsg, *dstsg;
|
struct session_group *srcsg, *dstsg;
|
||||||
|
|
||||||
srcsg = session_group_find(src);
|
srcsg = session_group_contains(src);
|
||||||
dstsg = session_group_find(dst);
|
dstsg = session_group_contains(dst);
|
||||||
if (src != dst && srcsg != NULL && dstsg != NULL && srcsg == dstsg) {
|
if (src != dst && srcsg != NULL && dstsg != NULL && srcsg == dstsg) {
|
||||||
xasprintf(cause, "sessions are grouped");
|
xasprintf(cause, "sessions are grouped");
|
||||||
return (-1);
|
return (-1);
|
||||||
@@ -349,7 +349,7 @@ server_destroy_session_group(struct session *s)
|
|||||||
struct session_group *sg;
|
struct session_group *sg;
|
||||||
struct session *s1;
|
struct session *s1;
|
||||||
|
|
||||||
if ((sg = session_group_find(s)) == NULL)
|
if ((sg = session_group_contains(s)) == NULL)
|
||||||
server_destroy_session(s);
|
server_destroy_session(s);
|
||||||
else {
|
else {
|
||||||
TAILQ_FOREACH_SAFE(s, &sg->sessions, gentry, s1) {
|
TAILQ_FOREACH_SAFE(s, &sg->sessions, gentry, s1) {
|
||||||
|
2
server.c
2
server.c
@@ -155,7 +155,7 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
|
|||||||
RB_INIT(&all_window_panes);
|
RB_INIT(&all_window_panes);
|
||||||
TAILQ_INIT(&clients);
|
TAILQ_INIT(&clients);
|
||||||
RB_INIT(&sessions);
|
RB_INIT(&sessions);
|
||||||
TAILQ_INIT(&session_groups);
|
RB_INIT(&session_groups);
|
||||||
key_bindings_init();
|
key_bindings_init();
|
||||||
|
|
||||||
gettimeofday(&start_time, NULL);
|
gettimeofday(&start_time, NULL);
|
||||||
|
93
session.c
93
session.c
@@ -41,6 +41,9 @@ static void session_group_remove(struct session *);
|
|||||||
static u_int session_group_count(struct session_group *);
|
static u_int session_group_count(struct session_group *);
|
||||||
static void session_group_synchronize1(struct session *, struct session *);
|
static void session_group_synchronize1(struct session *, struct session *);
|
||||||
|
|
||||||
|
static u_int session_group_count(struct session_group *);
|
||||||
|
static void session_group_synchronize1(struct session *, struct session *);
|
||||||
|
|
||||||
RB_GENERATE(sessions, session, entry, session_cmp);
|
RB_GENERATE(sessions, session, entry, session_cmp);
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -49,6 +52,14 @@ session_cmp(struct session *s1, struct session *s2)
|
|||||||
return (strcmp(s1->name, s2->name));
|
return (strcmp(s1->name, s2->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RB_GENERATE(session_groups, session_group, entry, session_group_cmp);
|
||||||
|
|
||||||
|
int
|
||||||
|
session_group_cmp(struct session_group *s1, struct session_group *s2)
|
||||||
|
{
|
||||||
|
return (strcmp(s1->name, s2->name));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find if session is still alive. This is true if it is still on the global
|
* Find if session is still alive. This is true if it is still on the global
|
||||||
* sessions list.
|
* sessions list.
|
||||||
@@ -106,9 +117,9 @@ session_find_by_id(u_int id)
|
|||||||
|
|
||||||
/* Create a new session. */
|
/* Create a new session. */
|
||||||
struct session *
|
struct session *
|
||||||
session_create(const char *name, int argc, char **argv, const char *path,
|
session_create(const char *prefix, const char *name, int argc, char **argv,
|
||||||
const char *cwd, struct environ *env, struct termios *tio, int idx,
|
const char *path, const char *cwd, struct environ *env, struct termios *tio,
|
||||||
u_int sx, u_int sy, char **cause)
|
int idx, u_int sx, u_int sy, char **cause)
|
||||||
{
|
{
|
||||||
struct session *s;
|
struct session *s;
|
||||||
struct winlink *wl;
|
struct winlink *wl;
|
||||||
@@ -149,7 +160,10 @@ session_create(const char *name, int argc, char **argv, const char *path,
|
|||||||
do {
|
do {
|
||||||
s->id = next_session_id++;
|
s->id = next_session_id++;
|
||||||
free(s->name);
|
free(s->name);
|
||||||
xasprintf(&s->name, "%u", s->id);
|
if (prefix != NULL)
|
||||||
|
xasprintf(&s->name, "%s-%u", prefix, s->id);
|
||||||
|
else
|
||||||
|
xasprintf(&s->name, "%u", s->id);
|
||||||
} while (RB_FIND(sessions, &sessions, s) != NULL);
|
} while (RB_FIND(sessions, &sessions, s) != NULL);
|
||||||
}
|
}
|
||||||
RB_INSERT(sessions, &sessions, s);
|
RB_INSERT(sessions, &sessions, s);
|
||||||
@@ -428,7 +442,7 @@ session_is_linked(struct session *s, struct window *w)
|
|||||||
{
|
{
|
||||||
struct session_group *sg;
|
struct session_group *sg;
|
||||||
|
|
||||||
if ((sg = session_group_find(s)) != NULL)
|
if ((sg = session_group_contains(s)) != NULL)
|
||||||
return (w->references != session_group_count(sg));
|
return (w->references != session_group_count(sg));
|
||||||
return (w->references != 1);
|
return (w->references != 1);
|
||||||
}
|
}
|
||||||
@@ -539,12 +553,12 @@ session_set_current(struct session *s, struct winlink *wl)
|
|||||||
|
|
||||||
/* Find the session group containing a session. */
|
/* Find the session group containing a session. */
|
||||||
struct session_group *
|
struct session_group *
|
||||||
session_group_find(struct session *target)
|
session_group_contains(struct session *target)
|
||||||
{
|
{
|
||||||
struct session_group *sg;
|
struct session_group *sg;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
|
|
||||||
TAILQ_FOREACH(sg, &session_groups, entry) {
|
RB_FOREACH(sg, session_groups, &session_groups) {
|
||||||
TAILQ_FOREACH(s, &sg->sessions, gentry) {
|
TAILQ_FOREACH(s, &sg->sessions, gentry) {
|
||||||
if (s == target)
|
if (s == target)
|
||||||
return (sg);
|
return (sg);
|
||||||
@@ -553,39 +567,39 @@ session_group_find(struct session *target)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find session group index. */
|
/* Find session group by name. */
|
||||||
u_int
|
struct session_group *
|
||||||
session_group_index(struct session_group *sg)
|
session_group_find(const char *name)
|
||||||
{
|
{
|
||||||
struct session_group *sg2;
|
struct session_group sg;
|
||||||
u_int i;
|
|
||||||
|
|
||||||
i = 0;
|
sg.name = name;
|
||||||
TAILQ_FOREACH(sg2, &session_groups, entry) {
|
return (RB_FIND(session_groups, &session_groups, &sg));
|
||||||
if (sg == sg2)
|
|
||||||
return (i);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fatalx("session group not found");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Create a new session group. */
|
||||||
* Add a session to the session group containing target, creating it if
|
struct session_group *
|
||||||
* necessary.
|
session_group_new(const char *name)
|
||||||
*/
|
|
||||||
void
|
|
||||||
session_group_add(struct session *target, struct session *s)
|
|
||||||
{
|
{
|
||||||
struct session_group *sg;
|
struct session_group *sg;
|
||||||
|
|
||||||
if ((sg = session_group_find(target)) == NULL) {
|
if ((sg = session_group_find(name)) != NULL)
|
||||||
sg = xmalloc(sizeof *sg);
|
return (sg);
|
||||||
TAILQ_INSERT_TAIL(&session_groups, sg, entry);
|
|
||||||
TAILQ_INIT(&sg->sessions);
|
sg = xcalloc(1, sizeof *sg);
|
||||||
TAILQ_INSERT_TAIL(&sg->sessions, target, gentry);
|
sg->name = xstrdup(name);
|
||||||
}
|
TAILQ_INIT(&sg->sessions);
|
||||||
TAILQ_INSERT_TAIL(&sg->sessions, s, gentry);
|
|
||||||
|
RB_INSERT(session_groups, &session_groups, sg);
|
||||||
|
return (sg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a session to a session group. */
|
||||||
|
void
|
||||||
|
session_group_add(struct session_group *sg, struct session *s)
|
||||||
|
{
|
||||||
|
if (session_group_contains(s) == NULL)
|
||||||
|
TAILQ_INSERT_TAIL(&sg->sessions, s, gentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove a session from its group and destroy the group if empty. */
|
/* Remove a session from its group and destroy the group if empty. */
|
||||||
@@ -594,13 +608,11 @@ session_group_remove(struct session *s)
|
|||||||
{
|
{
|
||||||
struct session_group *sg;
|
struct session_group *sg;
|
||||||
|
|
||||||
if ((sg = session_group_find(s)) == NULL)
|
if ((sg = session_group_contains(s)) == NULL)
|
||||||
return;
|
return;
|
||||||
TAILQ_REMOVE(&sg->sessions, s, gentry);
|
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)) {
|
if (TAILQ_EMPTY(&sg->sessions)) {
|
||||||
TAILQ_REMOVE(&session_groups, sg, entry);
|
RB_REMOVE(session_groups, &session_groups, sg);
|
||||||
free(sg);
|
free(sg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -625,7 +637,7 @@ session_group_synchronize_to(struct session *s)
|
|||||||
struct session_group *sg;
|
struct session_group *sg;
|
||||||
struct session *target;
|
struct session *target;
|
||||||
|
|
||||||
if ((sg = session_group_find(s)) == NULL)
|
if ((sg = session_group_contains(s)) == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
target = NULL;
|
target = NULL;
|
||||||
@@ -633,7 +645,8 @@ session_group_synchronize_to(struct session *s)
|
|||||||
if (target != s)
|
if (target != s)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
session_group_synchronize1(target, s);
|
if (target != NULL)
|
||||||
|
session_group_synchronize1(target, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Synchronize a session group to a session. */
|
/* Synchronize a session group to a session. */
|
||||||
@@ -643,7 +656,7 @@ session_group_synchronize_from(struct session *target)
|
|||||||
struct session_group *sg;
|
struct session_group *sg;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
|
|
||||||
if ((sg = session_group_find(target)) == NULL)
|
if ((sg = session_group_contains(target)) == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TAILQ_FOREACH(s, &sg->sessions, gentry) {
|
TAILQ_FOREACH(s, &sg->sessions, gentry) {
|
||||||
|
42
tmux.1
42
tmux.1
@@ -816,7 +816,7 @@ Lock all clients attached to
|
|||||||
.Op Fl F Ar format
|
.Op Fl F Ar format
|
||||||
.Op Fl n Ar window-name
|
.Op Fl n Ar window-name
|
||||||
.Op Fl s Ar session-name
|
.Op Fl s Ar session-name
|
||||||
.Op Fl t Ar target-session
|
.Op Fl t Ar group-name
|
||||||
.Op Fl x Ar width
|
.Op Fl x Ar width
|
||||||
.Op Fl y Ar height
|
.Op Fl y Ar height
|
||||||
.Op Ar shell-command
|
.Op Ar shell-command
|
||||||
@@ -861,16 +861,27 @@ to
|
|||||||
.Pp
|
.Pp
|
||||||
If
|
If
|
||||||
.Fl t
|
.Fl t
|
||||||
is given, the new session is
|
is given, it specifies a
|
||||||
.Em grouped
|
.Ic session group .
|
||||||
with
|
Sessions in the same group share the same set of windows - new windows are
|
||||||
.Ar target-session .
|
linked to all sessions in the group and any windows closed removed from all
|
||||||
This means they share the same set of windows - all windows from
|
sessions.
|
||||||
.Ar target-session
|
|
||||||
are linked to the new session, any new windows are linked to both sessions and
|
|
||||||
any windows closed removed from both sessions.
|
|
||||||
The current and previous window and any session options remain independent and
|
The current and previous window and any session options remain independent and
|
||||||
either session may be killed without affecting the other.
|
any session in a group may be killed without affecting the others.
|
||||||
|
The
|
||||||
|
.Ar group-name
|
||||||
|
argument may be:
|
||||||
|
.Bl -enum -width Ds
|
||||||
|
.It
|
||||||
|
the name of an existing group, in which case the new session is added to that
|
||||||
|
group;
|
||||||
|
.It
|
||||||
|
the name of an existing session - the new session is added to the same group
|
||||||
|
as that session, creating a new group if necessary;
|
||||||
|
.It
|
||||||
|
the name for a new group containing only the new session.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
.Fl n
|
.Fl n
|
||||||
and
|
and
|
||||||
.Ar shell-command
|
.Ar shell-command
|
||||||
@@ -892,6 +903,7 @@ is used, the
|
|||||||
.Ic update-environment
|
.Ic update-environment
|
||||||
option will not be applied.
|
option will not be applied.
|
||||||
.It Xo Ic refresh-client
|
.It Xo Ic refresh-client
|
||||||
|
.Op Fl C Ar width,height
|
||||||
.Op Fl S
|
.Op Fl S
|
||||||
.Op Fl t Ar target-client
|
.Op Fl t Ar target-client
|
||||||
.Xc
|
.Xc
|
||||||
@@ -902,6 +914,9 @@ with
|
|||||||
If
|
If
|
||||||
.Fl S
|
.Fl S
|
||||||
is specified, only update the client's status bar.
|
is specified, only update the client's status bar.
|
||||||
|
.Pp
|
||||||
|
.Fl C
|
||||||
|
sets the width and height of a control client.
|
||||||
.It Xo Ic rename-session
|
.It Xo Ic rename-session
|
||||||
.Op Fl t Ar target-session
|
.Op Fl t Ar target-session
|
||||||
.Ar new-name
|
.Ar new-name
|
||||||
@@ -3563,7 +3578,7 @@ The following variables are available, where appropriate:
|
|||||||
.It Li "session_activity" Ta "" Ta "Integer time of session last activity"
|
.It Li "session_activity" Ta "" Ta "Integer time of session last activity"
|
||||||
.It Li "session_created" Ta "" Ta "Integer time session created"
|
.It Li "session_created" Ta "" Ta "Integer time session created"
|
||||||
.It Li "session_last_attached" Ta "" Ta "Integer time session last attached"
|
.It Li "session_last_attached" Ta "" Ta "Integer time session last attached"
|
||||||
.It Li "session_group" Ta "" Ta "Number of session group"
|
.It Li "session_group" Ta "" Ta "Name of session group"
|
||||||
.It Li "session_grouped" Ta "" Ta "1 if session in a group"
|
.It Li "session_grouped" Ta "" Ta "1 if session in a group"
|
||||||
.It Li "session_height" Ta "" Ta "Height of session"
|
.It Li "session_height" Ta "" Ta "Height of session"
|
||||||
.It Li "session_id" Ta "" Ta "Unique session ID"
|
.It Li "session_id" Ta "" Ta "Unique session ID"
|
||||||
@@ -4203,6 +4218,11 @@ For example:
|
|||||||
%end 1363006971 2
|
%end 1363006971 2
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
|
The
|
||||||
|
.Ic refresh-client
|
||||||
|
.Fl C
|
||||||
|
command may be used to set the size of a client in control mode.
|
||||||
|
.Pp
|
||||||
In control mode,
|
In control mode,
|
||||||
.Nm
|
.Nm
|
||||||
outputs notifications.
|
outputs notifications.
|
||||||
|
27
tmux.h
27
tmux.h
@@ -903,11 +903,12 @@ struct environ_entry {
|
|||||||
|
|
||||||
/* Client session. */
|
/* Client session. */
|
||||||
struct session_group {
|
struct session_group {
|
||||||
TAILQ_HEAD(, session) sessions;
|
const char *name;
|
||||||
|
TAILQ_HEAD(, session) sessions;
|
||||||
|
|
||||||
TAILQ_ENTRY(session_group) entry;
|
RB_ENTRY(session_group) entry;
|
||||||
};
|
};
|
||||||
TAILQ_HEAD(session_groups, session_group);
|
RB_HEAD(session_groups, session_group);
|
||||||
|
|
||||||
struct session {
|
struct session {
|
||||||
u_int id;
|
u_int id;
|
||||||
@@ -1042,7 +1043,10 @@ struct tty {
|
|||||||
u_int rright;
|
u_int rright;
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
struct bufferevent *event;
|
struct event event_in;
|
||||||
|
struct evbuffer *in;
|
||||||
|
struct event event_out;
|
||||||
|
struct evbuffer *out;
|
||||||
|
|
||||||
struct termios tio;
|
struct termios tio;
|
||||||
|
|
||||||
@@ -2212,13 +2216,15 @@ extern struct sessions sessions;
|
|||||||
extern struct session_groups session_groups;
|
extern struct session_groups session_groups;
|
||||||
int session_cmp(struct session *, struct session *);
|
int session_cmp(struct session *, struct session *);
|
||||||
RB_PROTOTYPE(sessions, session, entry, session_cmp);
|
RB_PROTOTYPE(sessions, session, entry, session_cmp);
|
||||||
|
int session_group_cmp(struct session_group *, struct session_group *);
|
||||||
|
RB_PROTOTYPE(session_groups, session_group, entry, session_group_cmp);
|
||||||
int session_alive(struct session *);
|
int session_alive(struct session *);
|
||||||
struct session *session_find(const char *);
|
struct session *session_find(const char *);
|
||||||
struct session *session_find_by_id_str(const char *);
|
struct session *session_find_by_id_str(const char *);
|
||||||
struct session *session_find_by_id(u_int);
|
struct session *session_find_by_id(u_int);
|
||||||
struct session *session_create(const char *, int, char **, const char *,
|
struct session *session_create(const char *, const char *, int, char **,
|
||||||
const char *, struct environ *, struct termios *, int,
|
const char *, const char *, struct environ *,
|
||||||
u_int, u_int, char **);
|
struct termios *, int, u_int, u_int, char **);
|
||||||
void session_destroy(struct session *);
|
void session_destroy(struct session *);
|
||||||
void session_unref(struct session *);
|
void session_unref(struct session *);
|
||||||
int session_check_name(const char *);
|
int session_check_name(const char *);
|
||||||
@@ -2237,9 +2243,10 @@ int session_previous(struct session *, int);
|
|||||||
int session_select(struct session *, int);
|
int session_select(struct session *, int);
|
||||||
int session_last(struct session *);
|
int session_last(struct session *);
|
||||||
int session_set_current(struct session *, struct winlink *);
|
int session_set_current(struct session *, struct winlink *);
|
||||||
struct session_group *session_group_find(struct session *);
|
struct session_group *session_group_contains(struct session *);
|
||||||
u_int session_group_index(struct session_group *);
|
struct session_group *session_group_find(const char *);
|
||||||
void session_group_add(struct session *, struct session *);
|
struct session_group *session_group_new(const char *);
|
||||||
|
void session_group_add(struct session_group *, struct session *);
|
||||||
void session_group_synchronize_to(struct session *);
|
void session_group_synchronize_to(struct session *);
|
||||||
void session_group_synchronize_from(struct session *);
|
void session_group_synchronize_from(struct session *);
|
||||||
void session_renumber_windows(struct session *);
|
void session_renumber_windows(struct session *);
|
||||||
|
@@ -532,8 +532,8 @@ tty_keys_next(struct tty *tty)
|
|||||||
key_code key;
|
key_code key;
|
||||||
|
|
||||||
/* Get key buffer. */
|
/* Get key buffer. */
|
||||||
buf = EVBUFFER_DATA(tty->event->input);
|
buf = EVBUFFER_DATA(tty->in);
|
||||||
len = EVBUFFER_LENGTH(tty->event->input);
|
len = EVBUFFER_LENGTH(tty->in);
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return (0);
|
return (0);
|
||||||
@@ -645,7 +645,7 @@ complete_key:
|
|||||||
key = (key & KEYC_MASK_MOD) | KEYC_BSPACE;
|
key = (key & KEYC_MASK_MOD) | KEYC_BSPACE;
|
||||||
|
|
||||||
/* Remove data from buffer. */
|
/* Remove data from buffer. */
|
||||||
evbuffer_drain(tty->event->input, size);
|
evbuffer_drain(tty->in, size);
|
||||||
|
|
||||||
/* Remove key timer. */
|
/* Remove key timer. */
|
||||||
if (event_initialized(&tty->key_timer))
|
if (event_initialized(&tty->key_timer))
|
||||||
@@ -671,7 +671,7 @@ discard_key:
|
|||||||
log_debug("discard key %.*s %#llx", (int)size, buf, key);
|
log_debug("discard key %.*s %#llx", (int)size, buf, key);
|
||||||
|
|
||||||
/* Remove data from buffer. */
|
/* Remove data from buffer. */
|
||||||
evbuffer_drain(tty->event->input, size);
|
evbuffer_drain(tty->in, size);
|
||||||
|
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
121
tty.c
121
tty.c
@@ -34,11 +34,6 @@
|
|||||||
|
|
||||||
static int tty_log_fd = -1;
|
static int tty_log_fd = -1;
|
||||||
|
|
||||||
static void tty_init_termios(int, struct termios *, struct bufferevent *);
|
|
||||||
|
|
||||||
static void tty_read_callback(struct bufferevent *, void *);
|
|
||||||
static void tty_error_callback(struct bufferevent *, short, void *);
|
|
||||||
|
|
||||||
static int tty_client_ready(struct client *, struct window_pane *);
|
static int tty_client_ready(struct client *, struct window_pane *);
|
||||||
|
|
||||||
static void tty_set_italics(struct tty *);
|
static void tty_set_italics(struct tty *);
|
||||||
@@ -159,6 +154,38 @@ tty_set_size(struct tty *tty, u_int sx, u_int sy)
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tty_read_callback(__unused int fd, __unused short events, void *data)
|
||||||
|
{
|
||||||
|
struct tty *tty = data;
|
||||||
|
size_t size = EVBUFFER_LENGTH(tty->in);
|
||||||
|
int nread;
|
||||||
|
|
||||||
|
nread = evbuffer_read(tty->in, tty->fd, -1);
|
||||||
|
if (nread == -1)
|
||||||
|
return;
|
||||||
|
log_debug("%s: read %d bytes (already %zu)", tty->path, nread, size);
|
||||||
|
|
||||||
|
while (tty_keys_next(tty))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tty_write_callback(__unused int fd, __unused short events, void *data)
|
||||||
|
{
|
||||||
|
struct tty *tty = data;
|
||||||
|
size_t size = EVBUFFER_LENGTH(tty->out);
|
||||||
|
int nwrite;
|
||||||
|
|
||||||
|
nwrite = evbuffer_write(tty->out, tty->fd);
|
||||||
|
if (nwrite == -1)
|
||||||
|
return;
|
||||||
|
log_debug("%s: wrote %d bytes (of %zu)", tty->path, nwrite, size);
|
||||||
|
|
||||||
|
if (EVBUFFER_LENGTH(tty->out) != 0)
|
||||||
|
event_add(&tty->event_out, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
tty_open(struct tty *tty, char **cause)
|
tty_open(struct tty *tty, char **cause)
|
||||||
{
|
{
|
||||||
@@ -169,10 +196,14 @@ tty_open(struct tty *tty, char **cause)
|
|||||||
}
|
}
|
||||||
tty->flags |= TTY_OPENED;
|
tty->flags |= TTY_OPENED;
|
||||||
|
|
||||||
tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE|TTY_TIMER);
|
tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE);
|
||||||
|
|
||||||
tty->event = bufferevent_new(tty->fd, tty_read_callback, NULL,
|
event_set(&tty->event_in, tty->fd, EV_PERSIST|EV_READ,
|
||||||
tty_error_callback, tty);
|
tty_read_callback, tty);
|
||||||
|
tty->in = evbuffer_new();
|
||||||
|
|
||||||
|
event_set(&tty->event_out, tty->fd, EV_WRITE, tty_write_callback, tty);
|
||||||
|
tty->out = evbuffer_new();
|
||||||
|
|
||||||
tty_start_tty(tty);
|
tty_start_tty(tty);
|
||||||
|
|
||||||
@@ -181,50 +212,26 @@ tty_open(struct tty *tty, char **cause)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
tty_read_callback(__unused struct bufferevent *bufev, void *data)
|
|
||||||
{
|
|
||||||
struct tty *tty = data;
|
|
||||||
|
|
||||||
while (tty_keys_next(tty))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
tty_error_callback(__unused struct bufferevent *bufev, __unused short what,
|
|
||||||
__unused void *data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
tty_init_termios(int fd, struct termios *orig_tio, struct bufferevent *bufev)
|
|
||||||
{
|
|
||||||
struct termios tio;
|
|
||||||
|
|
||||||
if (fd == -1 || tcgetattr(fd, orig_tio) != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
setblocking(fd, 0);
|
|
||||||
|
|
||||||
if (bufev != NULL)
|
|
||||||
bufferevent_enable(bufev, EV_READ|EV_WRITE);
|
|
||||||
|
|
||||||
memcpy(&tio, orig_tio, sizeof tio);
|
|
||||||
tio.c_iflag &= ~(IXON|IXOFF|ICRNL|INLCR|IGNCR|IMAXBEL|ISTRIP);
|
|
||||||
tio.c_iflag |= IGNBRK;
|
|
||||||
tio.c_oflag &= ~(OPOST|ONLCR|OCRNL|ONLRET);
|
|
||||||
tio.c_lflag &= ~(IEXTEN|ICANON|ECHO|ECHOE|ECHONL|ECHOCTL|
|
|
||||||
ECHOPRT|ECHOKE|ISIG);
|
|
||||||
tio.c_cc[VMIN] = 1;
|
|
||||||
tio.c_cc[VTIME] = 0;
|
|
||||||
if (tcsetattr(fd, TCSANOW, &tio) == 0)
|
|
||||||
tcflush(fd, TCIOFLUSH);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
tty_start_tty(struct tty *tty)
|
tty_start_tty(struct tty *tty)
|
||||||
{
|
{
|
||||||
tty_init_termios(tty->fd, &tty->tio, tty->event);
|
struct termios tio;
|
||||||
|
|
||||||
|
if (tty->fd != -1 && tcgetattr(tty->fd, &tty->tio) == 0) {
|
||||||
|
setblocking(tty->fd, 0);
|
||||||
|
event_add(&tty->event_in, NULL);
|
||||||
|
|
||||||
|
memcpy(&tio, &tty->tio, sizeof tio);
|
||||||
|
tio.c_iflag &= ~(IXON|IXOFF|ICRNL|INLCR|IGNCR|IMAXBEL|ISTRIP);
|
||||||
|
tio.c_iflag |= IGNBRK;
|
||||||
|
tio.c_oflag &= ~(OPOST|ONLCR|OCRNL|ONLRET);
|
||||||
|
tio.c_lflag &= ~(IEXTEN|ICANON|ECHO|ECHOE|ECHONL|ECHOCTL|
|
||||||
|
ECHOPRT|ECHOKE|ISIG);
|
||||||
|
tio.c_cc[VMIN] = 1;
|
||||||
|
tio.c_cc[VTIME] = 0;
|
||||||
|
if (tcsetattr(tty->fd, TCSANOW, &tio) == 0)
|
||||||
|
tcflush(tty->fd, TCIOFLUSH);
|
||||||
|
}
|
||||||
|
|
||||||
tty_putcode(tty, TTYC_SMCUP);
|
tty_putcode(tty, TTYC_SMCUP);
|
||||||
|
|
||||||
@@ -264,7 +271,8 @@ tty_stop_tty(struct tty *tty)
|
|||||||
return;
|
return;
|
||||||
tty->flags &= ~TTY_STARTED;
|
tty->flags &= ~TTY_STARTED;
|
||||||
|
|
||||||
bufferevent_disable(tty->event, EV_READ|EV_WRITE);
|
event_del(&tty->event_in);
|
||||||
|
event_del(&tty->event_out);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Be flexible about error handling and try not kill the server just
|
* Be flexible about error handling and try not kill the server just
|
||||||
@@ -318,7 +326,10 @@ tty_close(struct tty *tty)
|
|||||||
tty_stop_tty(tty);
|
tty_stop_tty(tty);
|
||||||
|
|
||||||
if (tty->flags & TTY_OPENED) {
|
if (tty->flags & TTY_OPENED) {
|
||||||
bufferevent_free(tty->event);
|
evbuffer_free(tty->in);
|
||||||
|
event_del(&tty->event_in);
|
||||||
|
evbuffer_free(tty->out);
|
||||||
|
event_del(&tty->event_out);
|
||||||
|
|
||||||
tty_term_free(tty->term);
|
tty_term_free(tty->term);
|
||||||
tty_keys_free(tty);
|
tty_keys_free(tty);
|
||||||
@@ -411,11 +422,13 @@ tty_putcode_ptr2(struct tty *tty, enum tty_code_code code, const void *a,
|
|||||||
static void
|
static void
|
||||||
tty_add(struct tty *tty, const char *buf, size_t len)
|
tty_add(struct tty *tty, const char *buf, size_t len)
|
||||||
{
|
{
|
||||||
bufferevent_write(tty->event, buf, len);
|
evbuffer_add(tty->out, buf, len);
|
||||||
log_debug("%s: %.*s", tty->path, (int)len, buf);
|
log_debug("%s: %.*s", tty->path, (int)len, (const char *)buf);
|
||||||
|
|
||||||
if (tty_log_fd != -1)
|
if (tty_log_fd != -1)
|
||||||
write(tty_log_fd, buf, len);
|
write(tty_log_fd, buf, len);
|
||||||
|
if (tty->flags & TTY_STARTED)
|
||||||
|
event_add(&tty->event_out, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -730,7 +743,7 @@ tty_client_ready(struct client *c, struct window_pane *wp)
|
|||||||
{
|
{
|
||||||
if (c->session == NULL || c->tty.term == NULL)
|
if (c->session == NULL || c->tty.term == NULL)
|
||||||
return (0);
|
return (0);
|
||||||
if (c->flags & CLIENT_SUSPENDED)
|
if (c->flags & (CLIENT_REDRAW|CLIENT_SUSPENDED))
|
||||||
return (0);
|
return (0);
|
||||||
if (c->tty.flags & TTY_FREEZE)
|
if (c->tty.flags & TTY_FREEZE)
|
||||||
return (0);
|
return (0);
|
||||||
|
Reference in New Issue
Block a user