mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 09:26:05 +00:00 
			
		
		
		
	Break new window and pane creation common code from various commands and
window.c into a separate file spawn.c.
This commit is contained in:
		
							
								
								
									
										215
									
								
								window.c
									
									
									
									
									
								
							
							
						
						
									
										215
									
								
								window.c
									
									
									
									
									
								
							@@ -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)
 | 
			
		||||
{
 | 
			
		||||
@@ -1056,6 +885,18 @@ window_pane_error_callback(__unused struct bufferevent *bufev,
 | 
			
		||||
		server_destroy_pane(wp, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
@@ -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. */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user