summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2019-04-17 14:37:49 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2019-04-17 14:37:49 +0000
commitddd9feaf012765cc8a535fff0ceda103da7f7610 (patch)
tree6965433e13502baf0b5d11d30c4c06f9cb48034e /usr.bin
parent4d0445e68e521952f9d36dbe08966b4996118c8a (diff)
Break new window and pane creation common code from various commands and
window.c into a separate file spawn.c.
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/tmux/Makefile3
-rw-r--r--usr.bin/tmux/cmd-attach-session.c4
-rw-r--r--usr.bin/tmux/cmd-join-pane.c12
-rw-r--r--usr.bin/tmux/cmd-kill-session.c6
-rw-r--r--usr.bin/tmux/cmd-new-session.c107
-rw-r--r--usr.bin/tmux/cmd-new-window.c111
-rw-r--r--usr.bin/tmux/cmd-queue.c4
-rw-r--r--usr.bin/tmux/cmd-respawn-pane.c62
-rw-r--r--usr.bin/tmux/cmd-respawn-window.c74
-rw-r--r--usr.bin/tmux/cmd-rotate-window.c6
-rw-r--r--usr.bin/tmux/cmd-select-pane.c6
-rw-r--r--usr.bin/tmux/cmd-split-window.c141
-rw-r--r--usr.bin/tmux/cmd-swap-pane.c12
-rw-r--r--usr.bin/tmux/cmd-switch-client.c4
-rw-r--r--usr.bin/tmux/layout.c17
-rw-r--r--usr.bin/tmux/server-fn.c6
-rw-r--r--usr.bin/tmux/server.c4
-rw-r--r--usr.bin/tmux/session.c70
-rw-r--r--usr.bin/tmux/spawn.c434
-rw-r--r--usr.bin/tmux/tmux.h60
-rw-r--r--usr.bin/tmux/window-tree.c4
-rw-r--r--usr.bin/tmux/window.c217
22 files changed, 730 insertions, 634 deletions
diff --git a/usr.bin/tmux/Makefile b/usr.bin/tmux/Makefile
index 9038b6db0af..b0e5708dcf8 100644
--- a/usr.bin/tmux/Makefile
+++ b/usr.bin/tmux/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.93 2019/03/18 20:53:33 nicm Exp $
+# $OpenBSD: Makefile,v 1.94 2019/04/17 14:37:48 nicm Exp $
PROG= tmux
SRCS= alerts.c \
@@ -104,6 +104,7 @@ SRCS= alerts.c \
server-fn.c \
server.c \
session.c \
+ spawn.c \
status.c \
style.c \
tmux.c \
diff --git a/usr.bin/tmux/cmd-attach-session.c b/usr.bin/tmux/cmd-attach-session.c
index 450b60e6553..7950ab9f5db 100644
--- a/usr.bin/tmux/cmd-attach-session.c
+++ b/usr.bin/tmux/cmd-attach-session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-attach-session.c,v 1.76 2018/10/18 08:38:01 nicm Exp $ */
+/* $OpenBSD: cmd-attach-session.c,v 1.77 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -87,7 +87,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (wl != NULL) {
if (wp != NULL)
- window_set_active_pane(wp->window, wp);
+ window_set_active_pane(wp->window, wp, 1);
session_set_current(s, wl);
if (wp != NULL)
cmd_find_from_winlink_pane(current, wl, wp, 0);
diff --git a/usr.bin/tmux/cmd-join-pane.c b/usr.bin/tmux/cmd-join-pane.c
index aae9919f9ea..34c306f7f8c 100644
--- a/usr.bin/tmux/cmd-join-pane.c
+++ b/usr.bin/tmux/cmd-join-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-join-pane.c,v 1.33 2017/08/30 10:33:57 nicm Exp $ */
+/* $OpenBSD: cmd-join-pane.c,v 1.34 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2011 George Nachman <tmux@georgester.com>
@@ -72,7 +72,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
int size, percentage, dst_idx;
enum layout_type type;
struct layout_cell *lc;
- int not_same_window;
+ int not_same_window, flags;
if (self->entry == &cmd_join_pane_entry)
not_same_window = 1;
@@ -124,7 +124,11 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
else
size = (dst_wp->sx * percentage) / 100;
}
- lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'), 0);
+ if (args_has(args, 'b'))
+ flags = SPAWN_BEFORE;
+ else
+ flags = 0;
+ lc = layout_split_pane(dst_wp, type, size, flags);
if (lc == NULL) {
cmdq_error(item, "create pane failed: pane too small");
return (CMD_RETURN_ERROR);
@@ -145,7 +149,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
server_redraw_window(dst_w);
if (!args_has(args, 'd')) {
- window_set_active_pane(dst_w, src_wp);
+ window_set_active_pane(dst_w, src_wp, 1);
session_select(dst_s, dst_idx);
cmd_find_from_session(current, dst_s, 0);
server_redraw_session(dst_s);
diff --git a/usr.bin/tmux/cmd-kill-session.c b/usr.bin/tmux/cmd-kill-session.c
index 9dbf7fe992e..e3bec65de1a 100644
--- a/usr.bin/tmux/cmd-kill-session.c
+++ b/usr.bin/tmux/cmd-kill-session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-kill-session.c,v 1.24 2017/07/09 22:33:09 nicm Exp $ */
+/* $OpenBSD: cmd-kill-session.c,v 1.25 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -61,12 +61,12 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) {
if (sloop != s) {
server_destroy_session(sloop);
- session_destroy(sloop, __func__);
+ session_destroy(sloop, 1, __func__);
}
}
} else {
server_destroy_session(s);
- session_destroy(s, __func__);
+ session_destroy(s, 1, __func__);
}
return (CMD_RETURN_NORMAL);
}
diff --git a/usr.bin/tmux/cmd-new-session.c b/usr.bin/tmux/cmd-new-session.c
index a3fa8c87783..d5c63e40bd0 100644
--- a/usr.bin/tmux/cmd-new-session.c
+++ b/usr.bin/tmux/cmd-new-session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-new-session.c,v 1.115 2019/03/12 13:56:30 nicm Exp $ */
+/* $OpenBSD: cmd-new-session.c,v 1.116 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -69,20 +69,17 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = self->args;
struct client *c = item->client;
struct session *s, *as, *groupwith;
- struct window *w;
struct environ *env;
struct options *oo;
struct termios tio, *tiop;
struct session_group *sg;
- const char *errstr, *template, *group, *prefix;
- const char *path, *cmd, *tmp, *value;
- char **argv, *cause, *cp, *newname, *cwd = NULL;
- int detached, already_attached, idx, argc;
- int is_control = 0;
- u_int sx, sy, dsx = 80, dsy = 24;
- struct environ_entry *envent;
- struct cmd_find_state fs;
+ const char *errstr, *template, *group, *prefix, *tmp;
+ char *cause, *cwd = NULL, *cp, *newname = NULL;
+ int detached, already_attached, is_control = 0;
+ u_int sx, sy, dsx, dsy;
+ struct spawn_context sc;
enum cmd_retval retval;
+ struct cmd_find_state fs;
if (self->entry == &cmd_has_session_entry) {
/*
@@ -97,13 +94,12 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
- newname = NULL;
if (args_has(args, 's')) {
newname = format_single(item, args_get(args, 's'), c, NULL,
NULL, NULL);
if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname);
- goto error;
+ goto fail;
}
if ((as = session_find(newname)) != NULL) {
if (args_has(args, 'A')) {
@@ -114,7 +110,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
return (retval);
}
cmdq_error(item, "duplicate session: %s", newname);
- goto error;
+ goto fail;
}
}
@@ -125,7 +121,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (groupwith == NULL) {
if (!session_check_name(group)) {
cmdq_error(item, "bad group name: %s", group);
- goto error;
+ goto fail;
}
sg = session_group_find(group);
} else
@@ -173,7 +169,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (server_client_check_nested(item->client)) {
cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force");
- return (CMD_RETURN_ERROR);
+ goto fail;
}
if (tcgetattr(c->tty.fd, &tio) != 0)
fatal("tcgetattr failed");
@@ -186,7 +182,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (server_client_open(c, &cause) != 0) {
cmdq_error(item, "open terminal failed: %s", cause);
free(cause);
- goto error;
+ goto fail;
}
}
@@ -200,7 +196,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
dsx = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
- goto error;
+ goto fail;
}
}
}
@@ -213,7 +209,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
dsy = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
- goto error;
+ goto fail;
}
}
}
@@ -225,8 +221,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (sy > 0 && options_get_number(global_s_options, "status"))
sy--;
} else {
- value = options_get_string(global_s_options, "default-size");
- if (sscanf(value, "%ux%u", &sx, &sy) != 2) {
+ tmp = options_get_string(global_s_options, "default-size");
+ if (sscanf(tmp, "%ux%u", &sx, &sy) != 2) {
sx = 80;
sy = 24;
}
@@ -240,59 +236,34 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (sy == 0)
sy = 1;
- /* Figure out the command for the new window. */
- argc = -1;
- argv = NULL;
- if (!args_has(args, 't') && args->argc != 0) {
- argc = args->argc;
- argv = args->argv;
- } else if (sg == NULL && groupwith == NULL) {
- cmd = options_get_string(global_s_options, "default-command");
- if (cmd != NULL && *cmd != '\0') {
- argc = 1;
- argv = (char **)&cmd;
- } else {
- argc = 0;
- argv = NULL;
- }
- }
-
- path = NULL;
- if (c != NULL && c->session == NULL)
- envent = environ_find(c->environ, "PATH");
- else
- envent = environ_find(global_environ, "PATH");
- if (envent != NULL)
- path = envent->value;
-
- /* Construct the environment. */
+ /* Create the new session. */
+ oo = options_create(global_s_options);
+ if (args_has(args, 'x') || args_has(args, 'y'))
+ options_set_string(oo, "default-size", 0, "%ux%u", dsx, dsy);
env = environ_create();
if (c != NULL && !args_has(args, 'E'))
environ_update(global_s_options, c->environ, env);
+ s = session_create(prefix, newname, cwd, env, oo, tiop);
- /* Set up the options. */
- oo = options_create(global_s_options);
- if (args_has(args, 'x') || args_has(args, 'y'))
- options_set_string(oo, "default-size", 0, "%ux%u", dsx, dsy);
+ /* Spawn the initial window. */
+ memset(&sc, 0, sizeof sc);
+ sc.item = item;
+ sc.s = s;
- /* Create the new session. */
- idx = -1 - options_get_number(global_s_options, "base-index");
- s = session_create(prefix, newname, argc, argv, path, cwd, env, oo,
- tiop, idx, &cause);
- environ_free(env);
- if (s == NULL) {
- cmdq_error(item, "create session failed: %s", cause);
- free(cause);
- goto error;
- }
+ sc.name = args_get(args, 'n');
+ sc.argc = args->argc;
+ sc.argv = args->argv;
- /* Set the initial window name if one given. */
- if (argc >= 0 && (tmp = args_get(args, 'n')) != NULL) {
- cp = format_single(item, tmp, c, s, NULL, NULL);
- w = s->curw->window;
- window_set_name(w, cp);
- options_set_number(w->options, "automatic-rename", 0);
- free(cp);
+ sc.idx = -1;
+ sc.cwd = args_get(args, 'c');
+
+ sc.flags = 0;
+
+ if (spawn_window(&sc, &cause) == NULL) {
+ session_destroy(s, 0, __func__);
+ cmdq_error(item, "create window failed: %s", cause);
+ free(cause);
+ goto fail;
}
/*
@@ -364,7 +335,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
free(newname);
return (CMD_RETURN_NORMAL);
-error:
+fail:
free(cwd);
free(newname);
return (CMD_RETURN_ERROR);
diff --git a/usr.bin/tmux/cmd-new-window.c b/usr.bin/tmux/cmd-new-window.c
index 5ce3e771a12..0383b53b444 100644
--- a/usr.bin/tmux/cmd-new-window.c
+++ b/usr.bin/tmux/cmd-new-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-new-window.c,v 1.76 2018/07/15 06:57:13 nicm Exp $ */
+/* $OpenBSD: cmd-new-window.c,v 1.77 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -53,87 +53,45 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
+ struct spawn_context sc;
+ struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
- struct client *c = cmd_find_client(item, NULL, 1);
int idx = item->target.idx;
- const char *cmd, *path, *template, *tmp;
- char **argv, *cause, *cp, *cwd, *name;
- int argc, detached;
- struct environ_entry *envent;
+ struct winlink *new_wl;
+ char *cause = NULL, *cp;
+ const char *template;
struct cmd_find_state fs;
- if (args_has(args, 'a') && wl != NULL) {
- if ((idx = winlink_shuffle_up(s, wl)) == -1) {
- cmdq_error(item, "no free window indexes");
- return (CMD_RETURN_ERROR);
- }
- }
- detached = args_has(args, 'd');
-
- if (args->argc == 0) {
- cmd = options_get_string(s->options, "default-command");
- if (cmd != NULL && *cmd != '\0') {
- argc = 1;
- argv = (char **)&cmd;
- } else {
- argc = 0;
- argv = NULL;
- }
- } else {
- argc = args->argc;
- argv = args->argv;
+ if (args_has(args, 'a') && (idx = winlink_shuffle_up(s, wl)) == -1) {
+ cmdq_error(item, "couldn't get a window index");
+ return (CMD_RETURN_ERROR);
}
- path = NULL;
- if (item->client != NULL && item->client->session == NULL)
- envent = environ_find(item->client->environ, "PATH");
- else
- envent = environ_find(s->environ, "PATH");
- if (envent != NULL)
- path = envent->value;
-
- if ((tmp = args_get(args, 'c')) != NULL)
- cwd = format_single(item, tmp, c, s, NULL, NULL);
- else
- cwd = xstrdup(server_client_get_cwd(item->client, s));
-
- if ((tmp = args_get(args, 'n')) != NULL)
- name = format_single(item, tmp, c, s, NULL, NULL);
- else
- name = NULL;
-
- if (idx != -1)
- wl = winlink_find_by_index(&s->windows, idx);
- if (wl != NULL && args_has(args, 'k')) {
- /*
- * Can't use session_detach as it will destroy session if this
- * makes it empty.
- */
- notify_session_window("window-unlinked", s, wl->window);
- wl->flags &= ~WINLINK_ALERTFLAGS;
- winlink_stack_remove(&s->lastw, wl);
- winlink_remove(&s->windows, wl);
-
- /* Force select/redraw if current. */
- if (wl == s->curw) {
- detached = 0;
- s->curw = NULL;
- }
- }
+ memset(&sc, 0, sizeof sc);
+ sc.item = item;
+ sc.s = s;
- if (idx == -1)
- idx = -1 - options_get_number(s->options, "base-index");
- wl = session_new(s, name, argc, argv, path, cwd, idx,
- &cause);
- if (wl == NULL) {
+ sc.name = args_get(args, 'n');
+ sc.argc = args->argc;
+ sc.argv = args->argv;
+
+ sc.idx = idx;
+ sc.cwd = args_get(args, 'c');
+
+ sc.flags = 0;
+ if (args_has(args, 'd'))
+ sc.flags |= SPAWN_DETACHED;
+ if (args_has(args, 'k'))
+ sc.flags |= SPAWN_KILL;
+
+ if ((new_wl = spawn_window(&sc, &cause)) == NULL) {
cmdq_error(item, "create window failed: %s", cause);
free(cause);
- goto error;
+ return (CMD_RETURN_ERROR);
}
- if (!detached) {
- session_select(s, wl->idx);
- cmd_find_from_winlink(current, wl, 0);
+ if (!args_has(args, 'd') || new_wl == s->curw) {
+ cmd_find_from_winlink(current, new_wl, 0);
server_redraw_session_group(s);
} else
server_status_session_group(s);
@@ -141,20 +99,13 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = NEW_WINDOW_TEMPLATE;
- cp = format_single(item, template, c, s, wl, NULL);
+ cp = format_single(item, template, c, s, new_wl, NULL);
cmdq_print(item, "%s", cp);
free(cp);
}
- cmd_find_from_winlink(&fs, wl, 0);
+ cmd_find_from_winlink(&fs, new_wl, 0);
hooks_insert(s->hooks, item, &fs, "after-new-window");
- free(name);
- free(cwd);
return (CMD_RETURN_NORMAL);
-
-error:
- free(name);
- free(cwd);
- return (CMD_RETURN_ERROR);
}
diff --git a/usr.bin/tmux/cmd-queue.c b/usr.bin/tmux/cmd-queue.c
index 84c25b311da..95b78ef3402 100644
--- a/usr.bin/tmux/cmd-queue.c
+++ b/usr.bin/tmux/cmd-queue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-queue.c,v 1.61 2019/03/12 11:16:50 nicm Exp $ */
+/* $OpenBSD: cmd-queue.c,v 1.62 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -111,7 +111,7 @@ cmdq_remove(struct cmdq_item *item)
if (item->client != NULL)
server_client_unref(item->client);
- if (item->type == CMDQ_COMMAND)
+ if (item->cmdlist != NULL)
cmd_list_free(item->cmdlist);
TAILQ_REMOVE(item->queue, item, entry);
diff --git a/usr.bin/tmux/cmd-respawn-pane.c b/usr.bin/tmux/cmd-respawn-pane.c
index 8a70fb4dc0b..31492f10dec 100644
--- a/usr.bin/tmux/cmd-respawn-pane.c
+++ b/usr.bin/tmux/cmd-respawn-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-respawn-pane.c,v 1.27 2019/03/12 11:16:50 nicm Exp $ */
+/* $OpenBSD: cmd-respawn-pane.c,v 1.28 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -20,7 +20,7 @@
#include <sys/types.h>
#include <stdlib.h>
-#include <unistd.h>
+#include <string.h>
#include "tmux.h"
@@ -36,7 +36,7 @@ const struct cmd_entry cmd_respawn_pane_entry = {
.args = { "c:kt:", 0, -1 },
.usage = "[-c start-directory] [-k] " CMD_TARGET_PANE_USAGE
- " [command]",
+ " [command]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -48,53 +48,39 @@ static enum cmd_retval
cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
+ struct spawn_context sc;
+ struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
- struct window *w = wl->window;
struct window_pane *wp = item->target.wp;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct session *s = item->target.s;
- struct environ *env;
- const char *path = NULL, *cp;
- char *cause, *cwd = NULL;
- u_int idx;
- struct environ_entry *envent;
-
- if (!args_has(self->args, 'k') && wp->fd != -1) {
- if (window_pane_index(wp, &idx) != 0)
- fatalx("index not found");
- cmdq_error(item, "pane still active: %s:%d.%u",
- s->name, wl->idx, idx);
- return (CMD_RETURN_ERROR);
- }
+ char *cause = NULL;
+
+ memset(&sc, 0, sizeof sc);
+ sc.item = item;
+ sc.s = s;
+ sc.wl = wl;
+
+ sc.wp0 = wp;
+ sc.lc = NULL;
- window_pane_reset_mode_all(wp);
- screen_reinit(&wp->base);
- input_init(wp);
+ sc.name = NULL;
+ sc.argc = args->argc;
+ sc.argv = args->argv;
- if (item->client != NULL && item->client->session == NULL)
- envent = environ_find(item->client->environ, "PATH");
- else
- envent = environ_find(s->environ, "PATH");
- if (envent != NULL)
- path = envent->value;
+ sc.idx = -1;
+ sc.cwd = args_get(args, 'c');
- if ((cp = args_get(args, 'c')) != NULL)
- cwd = format_single(item, cp, c, s, NULL, NULL);
+ sc.flags = SPAWN_RESPAWN;
+ if (args_has(args, 'k'))
+ sc.flags |= SPAWN_KILL;
- env = environ_for_session(s, 0);
- if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, cwd, env,
- s->tio, &cause) != 0) {
+ if (spawn_pane(&sc, &cause) == NULL) {
cmdq_error(item, "respawn pane failed: %s", cause);
free(cause);
- environ_free(env);
- free(cwd);
return (CMD_RETURN_ERROR);
}
- environ_free(env);
- free(cwd);
wp->flags |= PANE_REDRAW;
- server_status_window(w);
+ server_status_window(wp->window);
return (CMD_RETURN_NORMAL);
}
diff --git a/usr.bin/tmux/cmd-respawn-window.c b/usr.bin/tmux/cmd-respawn-window.c
index 0c5e3453c72..fc9b3214683 100644
--- a/usr.bin/tmux/cmd-respawn-window.c
+++ b/usr.bin/tmux/cmd-respawn-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-respawn-window.c,v 1.37 2019/03/12 11:16:50 nicm Exp $ */
+/* $OpenBSD: cmd-respawn-window.c,v 1.38 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -19,7 +19,7 @@
#include <sys/types.h>
#include <stdlib.h>
-#include <unistd.h>
+#include <string.h>
#include "tmux.h"
@@ -48,64 +48,34 @@ static enum cmd_retval
cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
+ struct spawn_context sc;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
- struct window *w = wl->window;
- struct window_pane *wp;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct environ *env;
- const char *path = NULL, *cp;
- char *cause, *cwd = NULL;
- struct environ_entry *envent;
-
- if (!args_has(self->args, 'k')) {
- TAILQ_FOREACH(wp, &w->panes, entry) {
- if (wp->fd == -1)
- continue;
- cmdq_error(item, "window still active: %s:%d", s->name,
- wl->idx);
- return (CMD_RETURN_ERROR);
- }
- }
+ char *cause = NULL;
+
+ memset(&sc, 0, sizeof sc);
+ sc.item = item;
+ sc.s = s;
+ sc.wl = wl;
+
+ sc.name = NULL;
+ sc.argc = args->argc;
+ sc.argv = args->argv;
- wp = TAILQ_FIRST(&w->panes);
- TAILQ_REMOVE(&w->panes, wp, entry);
- layout_free(w);
- window_destroy_panes(w);
- TAILQ_INSERT_HEAD(&w->panes, wp, entry);
- window_pane_resize(wp, w->sx, w->sy);
-
- if (item->client != NULL && item->client->session == NULL)
- envent = environ_find(item->client->environ, "PATH");
- else
- envent = environ_find(s->environ, "PATH");
- if (envent != NULL)
- path = envent->value;
-
- if ((cp = args_get(args, 'c')) != NULL)
- cwd = format_single(item, cp, c, s, NULL, NULL);
-
- env = environ_for_session(s, 0);
- if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, cwd, env,
- s->tio, &cause) != 0) {
+ sc.idx = -1;
+ sc.cwd = args_get(args, 'c');
+
+ sc.flags = SPAWN_RESPAWN;
+ if (args_has(args, 'k'))
+ sc.flags |= SPAWN_KILL;
+
+ if (spawn_window(&sc, &cause) == NULL) {
cmdq_error(item, "respawn window failed: %s", cause);
free(cause);
- environ_free(env);
- free(cwd);
- server_destroy_pane(wp, 0);
return (CMD_RETURN_ERROR);
}
- environ_free(env);
- free(cwd);
-
- layout_init(w, wp);
- window_pane_reset_mode_all(wp);
- screen_reinit(&wp->base);
- input_init(wp);
- window_set_active_pane(w, wp);
- recalculate_sizes();
- server_redraw_window(w);
+ server_redraw_window(wl->window);
return (CMD_RETURN_NORMAL);
}
diff --git a/usr.bin/tmux/cmd-rotate-window.c b/usr.bin/tmux/cmd-rotate-window.c
index 6a35cf29408..433605a1622 100644
--- a/usr.bin/tmux/cmd-rotate-window.c
+++ b/usr.bin/tmux/cmd-rotate-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-rotate-window.c,v 1.25 2017/08/30 10:33:57 nicm Exp $ */
+/* $OpenBSD: cmd-rotate-window.c,v 1.26 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -77,7 +77,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL)
wp = TAILQ_LAST(&w->panes, window_panes);
- window_set_active_pane(w, wp);
+ window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
} else {
@@ -105,7 +105,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_NEXT(w->active, entry)) == NULL)
wp = TAILQ_FIRST(&w->panes);
- window_set_active_pane(w, wp);
+ window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
}
diff --git a/usr.bin/tmux/cmd-select-pane.c b/usr.bin/tmux/cmd-select-pane.c
index 9f4ff5bb721..9fce50d4fcf 100644
--- a/usr.bin/tmux/cmd-select-pane.c
+++ b/usr.bin/tmux/cmd-select-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-select-pane.c,v 1.47 2019/03/14 09:53:52 nicm Exp $ */
+/* $OpenBSD: cmd-select-pane.c,v 1.48 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -112,7 +112,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
else {
server_unzoom_window(w);
window_redraw_active_switch(w, lastwp);
- if (window_set_active_pane(w, lastwp)) {
+ if (window_set_active_pane(w, lastwp, 1)) {
cmd_find_from_winlink(current, wl, 0);
cmd_select_pane_redraw(w);
}
@@ -194,7 +194,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
server_unzoom_window(wp->window);
window_redraw_active_switch(w, wp);
- if (window_set_active_pane(w, wp)) {
+ if (window_set_active_pane(w, wp, 1)) {
cmd_find_from_winlink_pane(current, wl, wp, 0);
hooks_insert(s->hooks, item, current, "after-select-pane");
cmd_select_pane_redraw(w);
diff --git a/usr.bin/tmux/cmd-split-window.c b/usr.bin/tmux/cmd-split-window.c
index e9a21b85d4f..8010ca46bbf 100644
--- a/usr.bin/tmux/cmd-split-window.c
+++ b/usr.bin/tmux/cmd-split-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-split-window.c,v 1.91 2018/10/18 08:38:01 nicm Exp $ */
+/* $OpenBSD: cmd-split-window.c,v 1.92 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -53,111 +53,87 @@ const struct cmd_entry cmd_split_window_entry = {
static enum cmd_retval
cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
{
- struct cmd_find_state *current = &item->shared->current;
struct args *args = self->args;
+ struct cmd_find_state *current = &item->shared->current;
+ struct spawn_context sc;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
- struct window *w = wl->window;
- struct window_pane *wp = item->target.wp, *new_wp = NULL;
- struct environ *env;
- const char *cmd, *path, *shell, *template, *tmp;
- char **argv, *cause, *new_cause, *cp, *cwd;
- u_int hlimit;
- int argc, size, percentage, before;
+ struct window_pane *wp = item->target.wp, *new_wp;
enum layout_type type;
struct layout_cell *lc;
- struct environ_entry *envent;
- struct cmd_find_state fs;
-
- server_unzoom_window(w);
-
- if (args->argc == 0) {
- cmd = options_get_string(s->options, "default-command");
- if (cmd != NULL && *cmd != '\0') {
- argc = 1;
- argv = (char **)&cmd;
- } else {
- argc = 0;
- argv = NULL;
- }
- } else {
- argc = args->argc;
- argv = args->argv;
- }
-
- if ((tmp = args_get(args, 'c')) != NULL)
- cwd = format_single(item, tmp, c, s, NULL, NULL);
- else
- cwd = xstrdup(server_client_get_cwd(item->client, s));
+ struct cmd_find_state fs;
+ int size, percentage, flags;
+ const char *template;
+ char *cause, *cp;
- type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
- before = args_has(args, 'b');
-
- size = -1;
+ else
+ type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
- xasprintf(&new_cause, "size %s", cause);
+ cmdq_error(item, "create pane failed: -l %s", cause);
free(cause);
- cause = new_cause;
- goto error;
+ return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
if (cause != NULL) {
- xasprintf(&new_cause, "percentage %s", cause);
+ cmdq_error(item, "create pane failed: -p %s", cause);
free(cause);
- cause = new_cause;
- goto error;
+ return (CMD_RETURN_ERROR);
}
if (type == LAYOUT_TOPBOTTOM)
size = (wp->sy * percentage) / 100;
else
size = (wp->sx * percentage) / 100;
- }
- hlimit = options_get_number(s->options, "history-limit");
+ } else
+ size = -1;
+
+ server_unzoom_window(wp->window);
- shell = options_get_string(s->options, "default-shell");
- if (*shell == '\0' || areshell(shell))
- shell = _PATH_BSHELL;
+ flags = 0;
+ if (args_has(args, 'b'))
+ flags |= SPAWN_BEFORE;
+ if (args_has(args, 'f'))
+ flags |= SPAWN_FULLSIZE;
- lc = layout_split_pane(wp, type, size, before, args_has(args, 'f'));
+ lc = layout_split_pane(wp, type, size, flags);
if (lc == NULL) {
- cause = xstrdup("pane too small");
- goto error;
+ cmdq_error(item, "no space for new pane");
+ return (CMD_RETURN_ERROR);
}
- new_wp = window_add_pane(w, wp, before, args_has(args, 'f'), hlimit);
- layout_make_leaf(lc, new_wp);
- path = NULL;
- if (item->client != NULL && item->client->session == NULL)
- envent = environ_find(item->client->environ, "PATH");
- else
- envent = environ_find(s->environ, "PATH");
- if (envent != NULL)
- path = envent->value;
-
- env = environ_for_session(s, 0);
- if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, env,
- s->tio, &cause) != 0) {
- environ_free(env);
- goto error;
- }
- environ_free(env);
+ memset(&sc, 0, sizeof sc);
+ sc.item = item;
+ sc.s = s;
+ sc.wl = wl;
- layout_fix_panes(w);
- server_redraw_window(w);
+ sc.wp0 = wp;
+ sc.lc = lc;
- if (!args_has(args, 'd')) {
- window_set_active_pane(w, new_wp);
- session_select(s, wl->idx);
- cmd_find_from_session(current, s, 0);
- server_redraw_session(s);
- } else
- server_status_session(s);
+ sc.name = NULL;
+ sc.argc = args->argc;
+ sc.argv = args->argv;
+
+ sc.idx = -1;
+ sc.cwd = args_get(args, 'c');
+
+ sc.flags = flags;
+ if (args_has(args, 'd'))
+ sc.flags |= SPAWN_DETACHED;
+
+ if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
+ cmdq_error(item, "create pane failed: %s", cause);
+ free(cause);
+ return (CMD_RETURN_ERROR);
+ }
+ if (!args_has(args, 'd'))
+ cmd_find_from_winlink_pane(current, wl, new_wp, 0);
+ server_redraw_window(wp->window);
+ server_status_session(s);
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
@@ -166,22 +142,9 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
cmdq_print(item, "%s", cp);
free(cp);
}
- notify_window("window-layout-changed", w);
cmd_find_from_winlink_pane(&fs, wl, new_wp, 0);
hooks_insert(s->hooks, item, &fs, "after-split-window");
- free(cwd);
return (CMD_RETURN_NORMAL);
-
-error:
- if (new_wp != NULL) {
- layout_close_pane(new_wp);
- window_remove_pane(w, new_wp);
- }
- cmdq_error(item, "create pane failed: %s", cause);
- free(cause);
-
- free(cwd);
- return (CMD_RETURN_ERROR);
}
diff --git a/usr.bin/tmux/cmd-swap-pane.c b/usr.bin/tmux/cmd-swap-pane.c
index 59e2dce1f22..99cb7d4dfd5 100644
--- a/usr.bin/tmux/cmd-swap-pane.c
+++ b/usr.bin/tmux/cmd-swap-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-swap-pane.c,v 1.32 2018/10/18 08:38:01 nicm Exp $ */
+/* $OpenBSD: cmd-swap-pane.c,v 1.33 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -101,17 +101,17 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(self->args, 'd')) {
if (src_w != dst_w) {
- window_set_active_pane(src_w, dst_wp);
- window_set_active_pane(dst_w, src_wp);
+ window_set_active_pane(src_w, dst_wp, 1);
+ window_set_active_pane(dst_w, src_wp, 1);
} else {
tmp_wp = dst_wp;
- window_set_active_pane(src_w, tmp_wp);
+ window_set_active_pane(src_w, tmp_wp, 1);
}
} else {
if (src_w->active == src_wp)
- window_set_active_pane(src_w, dst_wp);
+ window_set_active_pane(src_w, dst_wp, 1);
if (dst_w->active == dst_wp)
- window_set_active_pane(dst_w, src_wp);
+ window_set_active_pane(dst_w, src_wp, 1);
}
if (src_w != dst_w) {
if (src_w->last == src_wp)
diff --git a/usr.bin/tmux/cmd-switch-client.c b/usr.bin/tmux/cmd-switch-client.c
index 654ab4dc05f..ee233720b3c 100644
--- a/usr.bin/tmux/cmd-switch-client.c
+++ b/usr.bin/tmux/cmd-switch-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-switch-client.c,v 1.55 2018/11/06 15:13:13 nicm Exp $ */
+/* $OpenBSD: cmd-switch-client.c,v 1.56 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -116,7 +116,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
server_unzoom_window(wl->window);
if (wp != NULL) {
window_redraw_active_switch(wp->window, wp);
- window_set_active_pane(wp->window, wp);
+ window_set_active_pane(wp->window, wp, 1);
}
session_set_current(s, wl);
cmd_find_from_session(&item->shared->current, s, 0);
diff --git a/usr.bin/tmux/layout.c b/usr.bin/tmux/layout.c
index 8670861fc80..2cf22b4e937 100644
--- a/usr.bin/tmux/layout.c
+++ b/usr.bin/tmux/layout.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: layout.c,v 1.39 2019/04/04 10:25:35 nicm Exp $ */
+/* $OpenBSD: layout.c,v 1.40 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -831,11 +831,12 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc)
*/
struct layout_cell *
layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
- int insert_before, int full_size)
+ int flags)
{
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
u_int sx, sy, xoff, yoff, size1, size2;
u_int new_size, saved_size, resize_first = 0;
+ int full_size = (flags & SPAWN_FULLSIZE);
/*
* If full_size is specified, add a new cell at the top of the window
@@ -876,7 +877,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
saved_size = sy;
if (size < 0)
size2 = ((saved_size + 1) / 2) - 1;
- else if (insert_before)
+ else if (flags & SPAWN_BEFORE)
size2 = saved_size - size - 1;
else
size2 = size;
@@ -887,7 +888,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
size1 = saved_size - 1 - size2;
/* Which size are we using? */
- if (insert_before)
+ if (flags & SPAWN_BEFORE)
new_size = size2;
else
new_size = size1;
@@ -903,7 +904,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
*/
lcparent = lc->parent;
lcnew = layout_create_cell(lcparent);
- if (insert_before)
+ if (flags & SPAWN_BEFORE)
TAILQ_INSERT_BEFORE(lc, lcnew, entry);
else
TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry);
@@ -932,7 +933,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
layout_set_size(lcnew, size, sy, 0, 0);
else if (lc->type == LAYOUT_TOPBOTTOM)
layout_set_size(lcnew, sx, size, 0, 0);
- if (insert_before)
+ if (flags & SPAWN_BEFORE)
TAILQ_INSERT_HEAD(&lc->cells, lcnew, entry);
else
TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
@@ -956,12 +957,12 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
/* Create the new child cell. */
lcnew = layout_create_cell(lcparent);
- if (insert_before)
+ if (flags & SPAWN_BEFORE)
TAILQ_INSERT_HEAD(&lcparent->cells, lcnew, entry);
else
TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry);
}
- if (insert_before) {
+ if (flags & SPAWN_BEFORE) {
lc1 = lcnew;
lc2 = lc;
} else {
diff --git a/usr.bin/tmux/server-fn.c b/usr.bin/tmux/server-fn.c
index d33c26d0ebd..f22e0419ed4 100644
--- a/usr.bin/tmux/server-fn.c
+++ b/usr.bin/tmux/server-fn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-fn.c,v 1.119 2019/03/12 20:02:47 nicm Exp $ */
+/* $OpenBSD: server-fn.c,v 1.120 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -368,7 +368,7 @@ server_destroy_session_group(struct session *s)
else {
TAILQ_FOREACH_SAFE(s, &sg->sessions, gentry, s1) {
server_destroy_session(s);
- session_destroy(s, __func__);
+ session_destroy(s, 1, __func__);
}
}
}
@@ -435,7 +435,7 @@ server_check_unattached(void)
if (s->attached != 0)
continue;
if (options_get_number (s->options, "destroy-unattached"))
- session_destroy(s, __func__);
+ session_destroy(s, 1, __func__);
}
}
diff --git a/usr.bin/tmux/server.c b/usr.bin/tmux/server.c
index d4756e5e49d..96d248e4d6b 100644
--- a/usr.bin/tmux/server.c
+++ b/usr.bin/tmux/server.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server.c,v 1.183 2018/08/23 15:45:05 nicm Exp $ */
+/* $OpenBSD: server.c,v 1.184 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -297,7 +297,7 @@ server_send_exit(void)
}
RB_FOREACH_SAFE(s, sessions, &sessions, s1)
- session_destroy(s, __func__);
+ session_destroy(s, 1, __func__);
}
/* Update socket execute permissions based on whether sessions are attached. */
diff --git a/usr.bin/tmux/session.c b/usr.bin/tmux/session.c
index 37868f95544..347f91b6699 100644
--- a/usr.bin/tmux/session.c
+++ b/usr.bin/tmux/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.83 2019/03/16 17:14:07 nicm Exp $ */
+/* $OpenBSD: session.c,v 1.84 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -112,12 +112,10 @@ session_find_by_id(u_int id)
/* Create a new session. */
struct session *
-session_create(const char *prefix, const char *name, int argc, char **argv,
- const char *path, const char *cwd, struct environ *env, struct options *oo,
- struct termios *tio, int idx, char **cause)
+session_create(const char *prefix, const char *name, const char *cwd,
+ struct environ *env, struct options *oo, struct termios *tio)
{
struct session *s;
- struct winlink *wl;
s = xcalloc(1, sizeof *s);
s->references = 1;
@@ -129,10 +127,7 @@ session_create(const char *prefix, const char *name, int argc, char **argv,
TAILQ_INIT(&s->lastw);
RB_INIT(&s->windows);
- s->environ = environ_create();
- if (env != NULL)
- environ_copy(env, s->environ);
-
+ s->environ = env;
s->options = oo;
s->hooks = hooks_create(global_hooks);
@@ -166,17 +161,6 @@ session_create(const char *prefix, const char *name, int argc, char **argv,
fatal("gettimeofday failed");
session_update_activity(s, &s->creation_time);
- if (argc >= 0) {
- wl = session_new(s, NULL, argc, argv, path, cwd, idx, cause);
- if (wl == NULL) {
- session_destroy(s, __func__);
- return (NULL);
- }
- session_select(s, RB_ROOT(&s->windows)->idx);
- }
-
- log_debug("session %s created", s->name);
-
return (s);
}
@@ -220,7 +204,7 @@ session_free(__unused int fd, __unused short events, void *arg)
/* Destroy a session. */
void
-session_destroy(struct session *s, const char *from)
+session_destroy(struct session *s, int notify, const char *from)
{
struct winlink *wl;
@@ -228,7 +212,8 @@ session_destroy(struct session *s, const char *from)
s->curw = NULL;
RB_REMOVE(sessions, &sessions, s);
- notify_session("session-closed", s);
+ if (notify)
+ notify_session("session-closed", s);
free(s->tio);
@@ -338,45 +323,6 @@ session_previous_session(struct session *s)
return (s2);
}
-/* Create a new window on a session. */
-struct winlink *
-session_new(struct session *s, const char *name, int argc, char **argv,
- const char *path, const char *cwd, int idx, char **cause)
-{
- struct window *w;
- struct winlink *wl;
- struct environ *env;
- const char *shell;
- u_int hlimit, sx, sy;
-
- if ((wl = winlink_add(&s->windows, idx)) == NULL) {
- xasprintf(cause, "index in use: %d", idx);
- return (NULL);
- }
- wl->session = s;
-
- shell = options_get_string(s->options, "default-shell");
- if (*shell == '\0' || areshell(shell))
- shell = _PATH_BSHELL;
-
- default_window_size(s, NULL, &sx, &sy, -1);
- hlimit = options_get_number(s->options, "history-limit");
- env = environ_for_session(s, 0);
- w = window_create_spawn(name, argc, argv, path, shell, cwd, env, s->tio,
- sx, sy, hlimit, cause);
- if (w == NULL) {
- winlink_remove(&s->windows, wl);
- environ_free(env);
- return (NULL);
- }
- winlink_set_window(wl, w);
- environ_free(env);
- notify_session_window("window-linked", s, w);
-
- session_group_synchronize_from(s);
- return (wl);
-}
-
/* Attach a window to a session. */
struct winlink *
session_attach(struct session *s, struct window *w, int idx, char **cause)
@@ -412,7 +358,7 @@ session_detach(struct session *s, struct winlink *wl)
session_group_synchronize_from(s);
if (RB_EMPTY(&s->windows)) {
- session_destroy(s, __func__);
+ session_destroy(s, 1, __func__);
return (1);
}
return (0);
diff --git a/usr.bin/tmux/spawn.c b/usr.bin/tmux/spawn.c
new file mode 100644
index 00000000000..5109c432311
--- /dev/null
+++ b/usr.bin/tmux/spawn.c
@@ -0,0 +1,434 @@
+/* $OpenBSD: spawn.c,v 1.1 2019/04/17 14:37:48 nicm Exp $ */
+
+/*
+ * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+
+#include "tmux.h"
+
+/*
+ * Set up the environment and create a new window and pane or a new pane.
+ *
+ * We need to set up the following items:
+ *
+ * - history limit, comes from the session;
+ *
+ * - base index, comes from the session;
+ *
+ * - current working directory, may be specified - if it isn't it comes from
+ * either the client or the session;
+ *
+ * - PATH variable, comes from the client if any, otherwise from the session
+ * environment;
+ *
+ * - shell, comes from default-shell;
+ *
+ * - termios, comes from the session;
+ *
+ * - remaining environment, comes from the session.
+ */
+
+static void
+spawn_log(const char *from, struct spawn_context *sc)
+{
+ struct session *s = sc->s;
+ struct winlink *wl = sc->wl;
+ struct window_pane *wp0 = sc->wp0;
+ char tmp[128];
+ const char *name;
+
+ log_debug("%s: %s, flags=%#x", from, sc->item->name, sc->flags);
+
+ if (wl != NULL && wp0 != NULL)
+ xsnprintf(tmp, sizeof tmp, "wl=%d wp0=%%%u", wl->idx, wp0->id);
+ else if (wl != NULL)
+ xsnprintf(tmp, sizeof tmp, "wl=%d wp0=none", wl->idx);
+ else if (wp0 != NULL)
+ xsnprintf(tmp, sizeof tmp, "wl=none wp0=%%%u", wp0->id);
+ else
+ xsnprintf(tmp, sizeof tmp, "wl=none wp0=none");
+ log_debug("%s: s=$%u %s idx=%d", from, s->id, tmp, sc->idx);
+
+ name = sc->name;
+ if (name == NULL)
+ name = "none";
+ log_debug("%s: name=%s", from, name);
+}
+
+struct winlink *
+spawn_window(struct spawn_context *sc, char **cause)
+{
+ struct session *s = sc->s;
+ struct window *w;
+ struct window_pane *wp;
+ struct winlink *wl;
+ int idx = sc->idx;
+ u_int sx, sy;
+
+ spawn_log(__func__, sc);
+
+ /*
+ * If the window already exists, we are respawning, so destroy all the
+ * panes except one.
+ */
+ if (sc->flags & SPAWN_RESPAWN) {
+ w = sc->wl->window;
+ if (~sc->flags & SPAWN_KILL) {
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ if (wp->fd != -1)
+ break;
+ }
+ if (wp != NULL) {
+ xasprintf(cause, "window %s:%d still active",
+ s->name, sc->wl->idx);
+ return (NULL);
+ }
+ }
+
+ sc->wp0 = TAILQ_FIRST(&w->panes);
+ TAILQ_REMOVE(&w->panes, sc->wp0, entry);
+
+ layout_free(w);
+ window_destroy_panes(w);
+
+ TAILQ_INSERT_HEAD(&w->panes, sc->wp0, entry);
+ window_pane_resize(sc->wp0, w->sx, w->sy);
+
+ layout_init(w, sc->wp0);
+ window_set_active_pane(w, sc->wp0, 0);
+ }
+
+ /*
+ * Otherwise we have no window so we will need to create one. First
+ * check if the given index already exists and destroy it if so.
+ */
+ if ((~sc->flags & SPAWN_RESPAWN) && idx != -1) {
+ wl = winlink_find_by_index(&s->windows, idx);
+ if (wl != NULL && (~sc->flags & SPAWN_KILL)) {
+ xasprintf(cause, "index %d in use", idx);
+ return (NULL);
+ }
+ if (wl != NULL) {
+ /*
+ * Can't use session_detach as it will destroy session
+ * if this makes it empty.
+ */
+ wl->flags &= ~WINLINK_ALERTFLAGS;
+ notify_session_window("window-unlinked", s, wl->window);
+ winlink_stack_remove(&s->lastw, wl);
+ winlink_remove(&s->windows, wl);
+
+ if (s->curw == wl) {
+ s->curw = NULL;
+ sc->flags &= ~SPAWN_DETACHED;
+ }
+ }
+ }
+
+ /* Then create a window if needed. */
+ if (~sc->flags & SPAWN_RESPAWN) {
+ if (idx == -1)
+ idx = -1 - options_get_number(s->options, "base-index");
+ if ((sc->wl = winlink_add(&s->windows, idx)) == NULL) {
+ xasprintf(cause, "couldn't add window %d", idx);
+ return (NULL);
+ }
+ default_window_size(s, NULL, &sx, &sy, -1);
+ if ((w = window_create(sx, sy)) == NULL) {
+ winlink_remove(&s->windows, sc->wl);
+ xasprintf(cause, "couldn't create window %d", idx);
+ return (NULL);
+ }
+ sc->wl->session = s;
+ winlink_set_window(sc->wl, w);
+ } else
+ w = NULL;
+ sc->flags |= SPAWN_NONOTIFY;
+
+ /* Spawn the pane. */
+ wp = spawn_pane(sc, cause);
+ if (wp == NULL) {
+ if (~sc->flags & SPAWN_RESPAWN) {
+ window_destroy(w);
+ winlink_remove(&s->windows, sc->wl);
+ }
+ return (NULL);
+ }
+
+ /* Set the name of the new window. */
+ if (~sc->flags & SPAWN_RESPAWN) {
+ if (sc->name != NULL) {
+ w->name = xstrdup(sc->name);
+ options_set_number(w->options, "automatic-rename", 0);
+ } else
+ w->name = xstrdup(default_window_name(w));
+ }
+
+ /* Switch to the new window if required. */
+ if (~sc->flags & SPAWN_DETACHED)
+ session_select(s, sc->wl->idx);
+
+ /* Fire notification if new window. */
+ if (~sc->flags & SPAWN_RESPAWN)
+ notify_session_window("window-linked", s, w);
+
+ session_group_synchronize_from(s);
+ return (sc->wl);
+}
+
+struct window_pane *
+spawn_pane(struct spawn_context *sc, char **cause)
+{
+ struct cmdq_item *item = sc->item;
+ struct client *c = item->client;
+ struct session *s = sc->s;
+ struct window *w = sc->wl->window;
+ struct window_pane *new_wp;
+ struct environ *child;
+ struct environ_entry *ee;
+ char **argv, *cp, **argvp, *argv0, *cwd;
+ const char *cmd, *tmp;
+ int argc;
+ u_int idx;
+ struct termios now;
+ u_int hlimit;
+ struct winsize ws;
+ sigset_t set, oldset;
+
+ spawn_log(__func__, sc);
+
+ /*
+ * If we are respawning then get rid of the old process. Otherwise
+ * either create a new cell or assign to the one we are given.
+ */
+ hlimit = options_get_number(s->options, "history-limit");
+ if (sc->flags & SPAWN_RESPAWN) {
+ if (sc->wp0->fd != -1 && (~sc->flags & SPAWN_KILL)) {
+ window_pane_index(sc->wp0, &idx);
+ xasprintf(cause, "pane %s:%d.%u still active",
+ s->name, sc->wl->idx, idx);
+ return (NULL);
+ }
+ if (sc->wp0->fd != -1) {
+ bufferevent_free(sc->wp0->event);
+ close(sc->wp0->fd);
+ }
+ window_pane_reset_mode_all(sc->wp0);
+ screen_reinit(&sc->wp0->base);
+ input_init(sc->wp0);
+ new_wp = sc->wp0;
+ new_wp->flags &= ~(PANE_STATUSREADY|PANE_STATUSDRAWN);
+ } else if (sc->lc == NULL) {
+ new_wp = window_add_pane(w, NULL, hlimit, sc->flags);
+ layout_init(w, new_wp);
+ } else {
+ new_wp = window_add_pane(w, sc->wp0, hlimit, sc->flags);
+ layout_assign_pane(sc->lc, new_wp);
+ }
+
+ /*
+ * Now we have a pane with nothing running in it ready for the new
+ * process. Work out the command and arguments.
+ */
+ if (sc->argc == 0) {
+ cmd = options_get_string(s->options, "default-command");
+ if (cmd != NULL && *cmd != '\0') {
+ argc = 1;
+ argv = (char **)&cmd;
+ } else {
+ argc = 0;
+ argv = NULL;
+ }
+ } else {
+ argc = sc->argc;
+ argv = sc->argv;
+ }
+
+ /*
+ * Replace the stored arguments if there are new ones. If not, the
+ * existing ones will be used (they will only exist for respawn).
+ */
+ if (argc > 0) {
+ cmd_free_argv(new_wp->argc, new_wp->argv);
+ new_wp->argc = argc;
+ new_wp->argv = cmd_copy_argv(argc, argv);
+ }
+
+ /*
+ * Work out the current working directory. If respawning, use
+ * the pane's stored one unless specified.
+ */
+ if (sc->cwd != NULL)
+ cwd = format_single(item, sc->cwd, c, s, NULL, NULL);
+ else if (~sc->flags & SPAWN_RESPAWN)
+ cwd = xstrdup(server_client_get_cwd(c, s));
+ else
+ cwd = NULL;
+ if (cwd != NULL) {
+ free(new_wp->cwd);
+ new_wp->cwd = cwd;
+ }
+
+ /* Create an environment for this pane. */
+ child = environ_for_session(s, 0);
+ environ_set(child, "TMUX_PANE", "%%%u", new_wp->id);
+
+ /*
+ * Then the PATH environment variable. The session one is replaced from
+ * the client if there is one because otherwise running "tmux new
+ * myprogram" wouldn't work if myprogram isn't in the session's path.
+ */
+ if (c != NULL && c->session == NULL) { /* only unattached clients */
+ ee = environ_find(c->environ, "PATH");
+ if (ee != NULL)
+ environ_set(child, "PATH", "%s", ee->value);
+ }
+ if (environ_find(child, "PATH") == NULL)
+ environ_set(child, "%s", _PATH_DEFPATH);
+
+ /* Then the shell. If respawning, use the old one. */
+ if (~sc->flags & SPAWN_RESPAWN) {
+ tmp = options_get_string(s->options, "default-shell");
+ if (*tmp == '\0' || areshell(tmp))
+ tmp = _PATH_BSHELL;
+ free(new_wp->shell);
+ new_wp->shell = xstrdup(tmp);
+ }
+ environ_set(child, "SHELL", "%s", new_wp->shell);
+
+ /* Log the arguments we are going to use. */
+ log_debug("%s: shell=%s", __func__, new_wp->shell);
+ if (new_wp->argc != 0) {
+ cp = cmd_stringify_argv(new_wp->argc, new_wp->argv);
+ log_debug("%s: cmd=%s", __func__, cp);
+ free(cp);
+ }
+ if (cwd != NULL)
+ log_debug("%s: cwd=%s", __func__, cwd);
+ cmd_log_argv(new_wp->argc, new_wp->argv, __func__);
+ environ_log(child, "%s: environment ", __func__);
+
+ /* Initialize the window size. */
+ memset(&ws, 0, sizeof ws);
+ ws.ws_col = screen_size_x(&new_wp->base);
+ ws.ws_row = screen_size_y(&new_wp->base);
+
+ /* Block signals until fork has completed. */
+ sigfillset(&set);
+ sigprocmask(SIG_BLOCK, &set, &oldset);
+
+ /* Fork the new process. */
+ new_wp->pid = fdforkpty(ptm_fd, &new_wp->fd, new_wp->tty, NULL, &ws);
+ if (new_wp->pid == -1) {
+ xasprintf(cause, "fork failed: %s", strerror(errno));
+ new_wp->fd = -1;
+ if (~sc->flags & SPAWN_RESPAWN) {
+ layout_close_pane(new_wp);
+ window_remove_pane(w, new_wp);
+ }
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ return (NULL);
+ }
+
+ /* In the parent process, everything is done now. */
+ if (new_wp->pid != 0) {
+ new_wp->pipe_off = 0;
+ new_wp->flags &= ~PANE_EXITED;
+
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ window_pane_set_event(new_wp);
+
+ if (sc->flags & SPAWN_RESPAWN)
+ return (new_wp);
+ if ((~sc->flags & SPAWN_DETACHED) || w->active == NULL) {
+ if (sc->flags & SPAWN_NONOTIFY)
+ window_set_active_pane(w, new_wp, 0);
+ else
+ window_set_active_pane(w, new_wp, 1);
+ }
+ if (~sc->flags & SPAWN_NONOTIFY)
+ notify_window("window-layout-changed", w);
+ return (new_wp);
+ }
+
+ /*
+ * Child process. Change to the working directory or home if that
+ * fails.
+ */
+ if (chdir(new_wp->cwd) != 0) {
+ if ((tmp = find_home()) == NULL || chdir(tmp) != 0)
+ chdir("/");
+ }
+
+ /*
+ * Update terminal escape characters from the session if available and
+ * force VERASE to tmux's \177.
+ */
+ if (tcgetattr(STDIN_FILENO, &now) != 0)
+ _exit(1);
+ if (s->tio != NULL)
+ memcpy(now.c_cc, s->tio->c_cc, sizeof now.c_cc);
+ now.c_cc[VERASE] = '\177';
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &now) != 0)
+ _exit(1);
+
+ /* Clean up file descriptors and signals and update the environment. */
+ closefrom(STDERR_FILENO + 1);
+ proc_clear_signals(server_proc, 1);
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ log_close();
+ environ_push(child);
+
+ /*
+ * If given multiple arguments, use execvp(). Copy the arguments to
+ * ensure they end in a NULL.
+ */
+ if (new_wp->argc != 0 && new_wp->argc != 1) {
+ argvp = cmd_copy_argv(new_wp->argc, new_wp->argv);
+ execvp(argvp[0], argvp);
+ _exit(1);
+ }
+
+ /*
+ * If one argument, pass it to $SHELL -c. Otherwise create a login
+ * shell.
+ */
+ cp = strrchr(new_wp->shell, '/');
+ if (new_wp->argc == 1) {
+ tmp = new_wp->argv[0];
+ if (cp != NULL && cp[1] != '\0')
+ xasprintf(&argv0, "%s", cp + 1);
+ else
+ xasprintf(&argv0, "%s", new_wp->shell);
+ execl(new_wp->shell, argv0, "-c", tmp, (char *)NULL);
+ _exit(1);
+ }
+ if (cp != NULL && cp[1] != '\0')
+ xasprintf(&argv0, "-%s", cp + 1);
+ else
+ xasprintf(&argv0, "-%s", new_wp->shell);
+ execl(new_wp->shell, argv0, (char *)NULL);
+ _exit(1);
+}
diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h
index cafd3e752e2..9c95a9885c3 100644
--- a/usr.bin/tmux/tmux.h
+++ b/usr.bin/tmux/tmux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.879 2019/04/02 09:03:39 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.880 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -233,8 +233,8 @@ enum {
/* Termcap codes. */
enum tty_code_code {
- TTYC_AX = 0,
TTYC_ACSC,
+ TTYC_AX,
TTYC_BCE,
TTYC_BEL,
TTYC_BLINK,
@@ -814,7 +814,7 @@ struct window_pane {
int argc;
char **argv;
char *shell;
- const char *cwd;
+ char *cwd;
pid_t pid;
char tty[TTY_NAME_MAX];
@@ -1561,6 +1561,32 @@ struct options_table_entry {
#define CMD_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]"
#define CMD_BUFFER_USAGE "[-b buffer-name]"
+/* Spawn common context. */
+struct spawn_context {
+ struct cmdq_item *item;
+
+ struct session *s;
+ struct winlink *wl;
+
+ struct window_pane *wp0;
+ struct layout_cell *lc;
+
+ const char *name;
+ char **argv;
+ int argc;
+
+ int idx;
+ const char *cwd;
+
+ int flags;
+#define SPAWN_KILL 0x1
+#define SPAWN_DETACHED 0x2
+#define SPAWN_RESPAWN 0x4
+#define SPAWN_BEFORE 0x8
+#define SPAWN_NONOTIFY 0x10
+#define SPAWN_FULLSIZE 0x20
+};
+
/* tmux.c */
extern struct hooks *global_hooks;
extern struct options *global_options;
@@ -2232,17 +2258,17 @@ struct window *window_find_by_id_str(const char *);
struct window *window_find_by_id(u_int);
void window_update_activity(struct window *);
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 *);
+void window_pane_set_event(struct window_pane *);
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 *);
-int window_set_active_pane(struct window *, struct window_pane *);
+int window_set_active_pane(struct window *, struct window_pane *,
+ int);
void window_redraw_active_switch(struct window *,
struct window_pane *);
-struct window_pane *window_add_pane(struct window *, struct window_pane *, int,
- int, u_int);
+struct window_pane *window_add_pane(struct window *, struct window_pane *,
+ u_int, int);
void window_resize(struct window *, u_int, u_int);
int window_zoom(struct window_pane *);
int window_unzoom(struct window *);
@@ -2259,9 +2285,6 @@ void window_destroy_panes(struct window *);
struct window_pane *window_pane_find_by_id_str(const char *);
struct window_pane *window_pane_find_by_id(u_int);
int window_pane_destroy_ready(struct window_pane *);
-int window_pane_spawn(struct window_pane *, int, char **,
- const char *, const char *, const char *, struct environ *,
- struct termios *, char **);
void window_pane_resize(struct window_pane *, u_int, u_int);
void window_pane_alternate_on(struct window_pane *,
struct grid_cell *, int);
@@ -2319,7 +2342,7 @@ void layout_resize_pane_to(struct window_pane *, enum layout_type,
u_int);
void layout_assign_pane(struct layout_cell *, struct window_pane *);
struct layout_cell *layout_split_pane(struct window_pane *, enum layout_type,
- int, int, int);
+ int, int);
void layout_close_pane(struct window_pane *);
int layout_spread_cell(struct window *, struct layout_cell *);
void layout_spread_out(struct window_pane *);
@@ -2418,10 +2441,9 @@ int session_alive(struct session *);
struct session *session_find(const char *);
struct session *session_find_by_id_str(const char *);
struct session *session_find_by_id(u_int);
-struct session *session_create(const char *, const char *, int, char **,
- const char *, const char *, struct environ *,
- struct options *, struct termios *, int, char **);
-void session_destroy(struct session *, const char *);
+struct session *session_create(const char *, const char *, const char *,
+ struct environ *, struct options *, struct termios *);
+void session_destroy(struct session *, int, const char *);
void session_add_ref(struct session *, const char *);
void session_remove_ref(struct session *, const char *);
int session_check_name(const char *);
@@ -2493,4 +2515,8 @@ void style_set(struct style *, const struct grid_cell *);
void style_copy(struct style *, struct style *);
int style_is_default(struct style *);
+/* spawn.c */
+struct winlink *spawn_window(struct spawn_context *, char **);
+struct window_pane *spawn_pane(struct spawn_context *, char **);
+
#endif /* TMUX_H */
diff --git a/usr.bin/tmux/window-tree.c b/usr.bin/tmux/window-tree.c
index 5784a6ac2d1..4d1f603dfbc 100644
--- a/usr.bin/tmux/window-tree.c
+++ b/usr.bin/tmux/window-tree.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-tree.c,v 1.35 2019/03/18 14:10:25 nicm Exp $ */
+/* $OpenBSD: window-tree.c,v 1.36 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1006,7 +1006,7 @@ window_tree_kill_each(__unused void* modedata, void* itemdata,
case WINDOW_TREE_SESSION:
if (s != NULL) {
server_destroy_session(s);
- session_destroy(s, __func__);
+ session_destroy(s, 1, __func__);
}
break;
case WINDOW_TREE_WINDOW:
diff --git a/usr.bin/tmux/window.c b/usr.bin/tmux/window.c
index 42b36e8240c..0eff1d8c649 100644
--- a/usr.bin/tmux/window.c
+++ b/usr.bin/tmux/window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: window.c,v 1.225 2019/03/18 21:55:04 nicm Exp $ */
+/* $OpenBSD: window.c,v 1.226 2019/04/17 14:37:48 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -26,7 +26,6 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include <termios.h>
#include <time.h>
#include <unistd.h>
#include <util.h>
@@ -73,20 +72,10 @@ const struct window_mode *all_window_modes[] = {
NULL
};
-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 *);
-static void window_pane_read_callback(struct bufferevent *, void *);
-static void window_pane_error_callback(struct bufferevent *, short, void *);
-
-static int winlink_next_index(struct winlinks *, int);
-
-static struct window_pane *window_pane_choose_best(struct window_pane **,
- u_int);
-
RB_GENERATE(windows, window, entry, window_cmp);
RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp);
@@ -342,37 +331,7 @@ window_create(u_int sx, u_int sy)
return (w);
}
-struct window *
-window_create_spawn(const char *name, int argc, char **argv, const char *path,
- const char *shell, const char *cwd, struct environ *env,
- struct termios *tio, u_int sx, u_int sy, u_int hlimit, char **cause)
-{
- struct window *w;
- struct window_pane *wp;
-
- w = window_create(sx, sy);
- wp = window_add_pane(w, NULL, 0, 0, hlimit);
- layout_init(w, wp);
-
- if (window_pane_spawn(wp, argc, argv, path, shell, cwd,
- env, tio, cause) != 0) {
- window_destroy(w);
- return (NULL);
- }
-
- w->active = TAILQ_FIRST(&w->panes);
- if (name != NULL) {
- w->name = xstrdup(name);
- options_set_number(w->options, "automatic-rename", 0);
- } else
- w->name = default_window_name(w);
-
- notify_window("window-pane-changed", w);
-
- return (w);
-}
-
-static void
+void
window_destroy(struct window *w)
{
log_debug("window @%u destroyed (%d references)", w->id, w->references);
@@ -463,17 +422,22 @@ window_has_pane(struct window *w, struct window_pane *wp)
}
int
-window_set_active_pane(struct window *w, struct window_pane *wp)
+window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
{
- log_debug("%s: pane %%%u (was %%%u)", __func__, wp->id, w->active->id);
+ log_debug("%s: pane %%%u", __func__, wp->id);
+
if (wp == w->active)
return (0);
w->last = w->active;
+
w->active = wp;
w->active->active_point = next_active_point++;
w->active->flags |= PANE_CHANGED;
+
tty_update_window_offset(w);
- notify_window("window-pane-changed", w);
+
+ if (notify)
+ notify_window("window-pane-changed", w);
return (1);
}
@@ -571,7 +535,7 @@ window_zoom(struct window_pane *wp)
return (-1);
if (w->active != wp)
- window_set_active_pane(w, wp);
+ window_set_active_pane(w, wp, 1);
TAILQ_FOREACH(wp1, &w->panes, entry) {
wp1->saved_layout_cell = wp1->layout_cell;
@@ -610,8 +574,8 @@ window_unzoom(struct window *w)
}
struct window_pane *
-window_add_pane(struct window *w, struct window_pane *other, int before,
- int full_size, u_int hlimit)
+window_add_pane(struct window *w, struct window_pane *other, u_int hlimit,
+ int flags)
{
struct window_pane *wp;
@@ -622,15 +586,15 @@ window_add_pane(struct window *w, struct window_pane *other, int before,
if (TAILQ_EMPTY(&w->panes)) {
log_debug("%s: @%u at start", __func__, w->id);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
- } else if (before) {
+ } else if (flags & SPAWN_BEFORE) {
log_debug("%s: @%u before %%%u", __func__, w->id, wp->id);
- if (full_size)
+ if (flags & SPAWN_FULLSIZE)
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
else
TAILQ_INSERT_BEFORE(other, wp, entry);
} else {
log_debug("%s: @%u after %%%u", __func__, w->id, wp->id);
- if (full_size)
+ if (flags & SPAWN_FULLSIZE)
TAILQ_INSERT_TAIL(&w->panes, wp, entry);
else
TAILQ_INSERT_AFTER(&w->panes, other, wp, entry);
@@ -887,141 +851,6 @@ window_pane_destroy(struct window_pane *wp)
free(wp);
}
-int
-window_pane_spawn(struct window_pane *wp, int argc, char **argv,
- const char *path, const char *shell, const char *cwd, struct environ *env,
- struct termios *tio, char **cause)
-{
- struct winsize ws;
- char *argv0, *cmd, **argvp;
- const char *ptr, *first, *home;
- struct termios tio2;
- sigset_t set, oldset;
-
- if (wp->fd != -1) {
- bufferevent_free(wp->event);
- close(wp->fd);
- }
- if (argc > 0) {
- cmd_free_argv(wp->argc, wp->argv);
- wp->argc = argc;
- wp->argv = cmd_copy_argv(argc, argv);
- }
- if (shell != NULL) {
- free(wp->shell);
- wp->shell = xstrdup(shell);
- }
- if (cwd != NULL) {
- free((void *)wp->cwd);
- wp->cwd = xstrdup(cwd);
- }
- wp->flags &= ~(PANE_STATUSREADY|PANE_STATUSDRAWN);
-
- cmd = cmd_stringify_argv(wp->argc, wp->argv);
- log_debug("%s: shell=%s", __func__, wp->shell);
- log_debug("%s: cmd=%s", __func__, cmd);
- log_debug("%s: cwd=%s", __func__, cwd);
- cmd_log_argv(wp->argc, wp->argv, __func__);
- environ_log(env, "%s: environment ", __func__);
-
- memset(&ws, 0, sizeof ws);
- ws.ws_col = screen_size_x(&wp->base);
- ws.ws_row = screen_size_y(&wp->base);
-
- sigfillset(&set);
- sigprocmask(SIG_BLOCK, &set, &oldset);
- switch (wp->pid = fdforkpty(ptm_fd, &wp->fd, wp->tty, NULL, &ws)) {
- case -1:
- wp->event = NULL;
- wp->fd = -1;
-
- xasprintf(cause, "%s: %s", cmd, strerror(errno));
- free(cmd);
-
- sigprocmask(SIG_SETMASK, &oldset, NULL);
- return (-1);
- case 0:
- proc_clear_signals(server_proc, 1);
- sigprocmask(SIG_SETMASK, &oldset, NULL);
-
- cwd = NULL;
- if (chdir(wp->cwd) == 0)
- cwd = wp->cwd;
- else if ((home = find_home()) != NULL && chdir(home) == 0)
- cwd = home;
- else
- chdir("/");
-
- if (tcgetattr(STDIN_FILENO, &tio2) != 0)
- fatal("tcgetattr failed");
- if (tio != NULL)
- memcpy(tio2.c_cc, tio->c_cc, sizeof tio2.c_cc);
- tio2.c_cc[VERASE] = '\177';
- if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0)
- fatal("tcgetattr failed");
-
- log_close();
- closefrom(STDERR_FILENO + 1);
-
- if (path != NULL)
- environ_set(env, "PATH", "%s", path);
- if (cwd != NULL)
- environ_set(env, "PWD", "%s", cwd);
- environ_set(env, "TMUX_PANE", "%%%u", wp->id);
- environ_push(env);
-
- setenv("SHELL", wp->shell, 1);
- ptr = strrchr(wp->shell, '/');
-
- /*
- * If given one argument, assume it should be passed to sh -c;
- * with more than one argument, use execvp(). If there is no
- * arguments, create a login shell.
- */
- if (wp->argc > 0) {
- if (wp->argc != 1) {
- /* Copy to ensure argv ends in NULL. */
- argvp = cmd_copy_argv(wp->argc, wp->argv);
- execvp(argvp[0], argvp);
- fatal("execvp failed");
- }
- first = wp->argv[0];
-
- if (ptr != NULL && *(ptr + 1) != '\0')
- xasprintf(&argv0, "%s", ptr + 1);
- else
- xasprintf(&argv0, "%s", wp->shell);
- execl(wp->shell, argv0, "-c", first, (char *)NULL);
- fatal("execl failed");
- }
- if (ptr != NULL && *(ptr + 1) != '\0')
- xasprintf(&argv0, "-%s", ptr + 1);
- else
- xasprintf(&argv0, "-%s", wp->shell);
- execl(wp->shell, argv0, (char *)NULL);
- fatal("execl failed");
- }
- log_debug("%s: master=%s", __func__, ttyname(wp->fd));
- log_debug("%s: slave=%s", __func__, wp->tty);
-
- sigprocmask(SIG_SETMASK, &oldset, NULL);
- setblocking(wp->fd, 0);
-
- wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL,
- window_pane_error_callback, wp);
- if (wp->event == NULL)
- fatalx("out of memory");
-
- wp->pipe_off = 0;
- wp->flags &= ~PANE_EXITED;
-
- bufferevent_setwatermark(wp->event, EV_READ, 0, READ_SIZE);
- bufferevent_enable(wp->event, EV_READ|EV_WRITE);
-
- free(cmd);
- return (0);
-}
-
static void
window_pane_read_callback(__unused struct bufferevent *bufev, void *data)
{
@@ -1057,6 +886,18 @@ window_pane_error_callback(__unused struct bufferevent *bufev,
}
void
+window_pane_set_event(struct window_pane *wp)
+{
+ setblocking(wp->fd, 0);
+
+ wp->event = bufferevent_new(wp->fd, window_pane_read_callback,
+ NULL, window_pane_error_callback, wp);
+
+ bufferevent_setwatermark(wp->event, EV_READ, 0, READ_SIZE);
+ bufferevent_enable(wp->event, EV_READ|EV_WRITE);
+}
+
+void
window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
{
struct window_mode_entry *wme;
@@ -1604,6 +1445,8 @@ winlink_shuffle_up(struct session *s, struct winlink *wl)
{
int idx, last;
+ if (wl == NULL)
+ return (-1);
idx = wl->idx + 1;
/* Find the next free index. */