mirror of
				https://github.com/tmux/tmux.git
				synced 2025-10-26 12:27:15 +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:
		
							
								
								
									
										1
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
									
									
									
									
								
							| @@ -104,6 +104,7 @@ SRCS=	alerts.c \ | |||||||
| 	server-fn.c \ | 	server-fn.c \ | ||||||
| 	server.c \ | 	server.c \ | ||||||
| 	session.c \ | 	session.c \ | ||||||
|  | 	spawn.c \ | ||||||
| 	status.c \ | 	status.c \ | ||||||
| 	style.c \ | 	style.c \ | ||||||
| 	tmux.c \ | 	tmux.c \ | ||||||
|   | |||||||
| @@ -87,7 +87,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, | |||||||
|  |  | ||||||
| 	if (wl != NULL) { | 	if (wl != NULL) { | ||||||
| 		if (wp != NULL) | 		if (wp != NULL) | ||||||
| 			window_set_active_pane(wp->window, wp); | 			window_set_active_pane(wp->window, wp, 1); | ||||||
| 		session_set_current(s, wl); | 		session_set_current(s, wl); | ||||||
| 		if (wp != NULL) | 		if (wp != NULL) | ||||||
| 			cmd_find_from_winlink_pane(current, wl, wp, 0); | 			cmd_find_from_winlink_pane(current, wl, wp, 0); | ||||||
|   | |||||||
| @@ -72,7 +72,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) | |||||||
| 	int			 size, percentage, dst_idx; | 	int			 size, percentage, dst_idx; | ||||||
| 	enum layout_type	 type; | 	enum layout_type	 type; | ||||||
| 	struct layout_cell	*lc; | 	struct layout_cell	*lc; | ||||||
| 	int			 not_same_window; | 	int			 not_same_window, flags; | ||||||
|  |  | ||||||
| 	if (self->entry == &cmd_join_pane_entry) | 	if (self->entry == &cmd_join_pane_entry) | ||||||
| 		not_same_window = 1; | 		not_same_window = 1; | ||||||
| @@ -124,7 +124,11 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) | |||||||
| 		else | 		else | ||||||
| 			size = (dst_wp->sx * percentage) / 100; | 			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) { | 	if (lc == NULL) { | ||||||
| 		cmdq_error(item, "create pane failed: pane too small"); | 		cmdq_error(item, "create pane failed: pane too small"); | ||||||
| 		return (CMD_RETURN_ERROR); | 		return (CMD_RETURN_ERROR); | ||||||
| @@ -145,7 +149,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) | |||||||
| 	server_redraw_window(dst_w); | 	server_redraw_window(dst_w); | ||||||
|  |  | ||||||
| 	if (!args_has(args, 'd')) { | 	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); | 		session_select(dst_s, dst_idx); | ||||||
| 		cmd_find_from_session(current, dst_s, 0); | 		cmd_find_from_session(current, dst_s, 0); | ||||||
| 		server_redraw_session(dst_s); | 		server_redraw_session(dst_s); | ||||||
|   | |||||||
| @@ -61,12 +61,12 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item) | |||||||
| 		RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) { | 		RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) { | ||||||
| 			if (sloop != s) { | 			if (sloop != s) { | ||||||
| 				server_destroy_session(sloop); | 				server_destroy_session(sloop); | ||||||
| 				session_destroy(sloop, __func__); | 				session_destroy(sloop, 1, __func__); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		server_destroy_session(s); | 		server_destroy_session(s); | ||||||
| 		session_destroy(s, __func__); | 		session_destroy(s, 1, __func__); | ||||||
| 	} | 	} | ||||||
| 	return (CMD_RETURN_NORMAL); | 	return (CMD_RETURN_NORMAL); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -69,20 +69,17 @@ 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, *groupwith; | 	struct session		*s, *as, *groupwith; | ||||||
| 	struct window		*w; |  | ||||||
| 	struct environ		*env; | 	struct environ		*env; | ||||||
| 	struct options		*oo; | 	struct options		*oo; | ||||||
| 	struct termios		 tio, *tiop; | 	struct termios		 tio, *tiop; | ||||||
| 	struct session_group	*sg; | 	struct session_group	*sg; | ||||||
| 	const char		*errstr, *template, *group, *prefix; | 	const char		*errstr, *template, *group, *prefix, *tmp; | ||||||
| 	const char		*path, *cmd, *tmp, *value; | 	char			*cause, *cwd = NULL, *cp, *newname = NULL; | ||||||
| 	char		       **argv, *cause, *cp, *newname, *cwd = NULL; | 	int			 detached, already_attached, is_control = 0; | ||||||
| 	int			 detached, already_attached, idx, argc; | 	u_int			 sx, sy, dsx, dsy; | ||||||
| 	int			 is_control = 0; | 	struct spawn_context	 sc; | ||||||
| 	u_int			 sx, sy, dsx = 80, dsy = 24; |  | ||||||
| 	struct environ_entry	*envent; |  | ||||||
| 	struct cmd_find_state	 fs; |  | ||||||
| 	enum cmd_retval		 retval; | 	enum cmd_retval		 retval; | ||||||
|  | 	struct cmd_find_state    fs; | ||||||
|  |  | ||||||
| 	if (self->entry == &cmd_has_session_entry) { | 	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); | 		return (CMD_RETURN_ERROR); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	newname = NULL; |  | ||||||
| 	if (args_has(args, 's')) { | 	if (args_has(args, 's')) { | ||||||
| 		newname = format_single(item, args_get(args, 's'), c, NULL, | 		newname = format_single(item, args_get(args, 's'), c, NULL, | ||||||
| 		    NULL, NULL); | 		    NULL, NULL); | ||||||
| 		if (!session_check_name(newname)) { | 		if (!session_check_name(newname)) { | ||||||
| 			cmdq_error(item, "bad session name: %s", newname); | 			cmdq_error(item, "bad session name: %s", newname); | ||||||
| 			goto error; | 			goto fail; | ||||||
| 		} | 		} | ||||||
| 		if ((as = session_find(newname)) != NULL) { | 		if ((as = session_find(newname)) != NULL) { | ||||||
| 			if (args_has(args, 'A')) { | 			if (args_has(args, 'A')) { | ||||||
| @@ -114,7 +110,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) | |||||||
| 				return (retval); | 				return (retval); | ||||||
| 			} | 			} | ||||||
| 			cmdq_error(item, "duplicate session: %s", newname); | 			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 (groupwith == NULL) { | ||||||
| 			if (!session_check_name(group)) { | 			if (!session_check_name(group)) { | ||||||
| 				cmdq_error(item, "bad group name: %s", group); | 				cmdq_error(item, "bad group name: %s", group); | ||||||
| 				goto error; | 				goto fail; | ||||||
| 			} | 			} | ||||||
| 			sg = session_group_find(group); | 			sg = session_group_find(group); | ||||||
| 		} else | 		} else | ||||||
| @@ -173,7 +169,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) | |||||||
| 		if (server_client_check_nested(item->client)) { | 		if (server_client_check_nested(item->client)) { | ||||||
| 			cmdq_error(item, "sessions should be nested with care, " | 			cmdq_error(item, "sessions should be nested with care, " | ||||||
| 			    "unset $TMUX to force"); | 			    "unset $TMUX to force"); | ||||||
| 			return (CMD_RETURN_ERROR); | 			goto fail; | ||||||
| 		} | 		} | ||||||
| 		if (tcgetattr(c->tty.fd, &tio) != 0) | 		if (tcgetattr(c->tty.fd, &tio) != 0) | ||||||
| 			fatal("tcgetattr failed"); | 			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) { | 		if (server_client_open(c, &cause) != 0) { | ||||||
| 			cmdq_error(item, "open terminal failed: %s", cause); | 			cmdq_error(item, "open terminal failed: %s", cause); | ||||||
| 			free(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); | 			dsx = strtonum(tmp, 1, USHRT_MAX, &errstr); | ||||||
| 			if (errstr != NULL) { | 			if (errstr != NULL) { | ||||||
| 				cmdq_error(item, "width %s", errstr); | 				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); | 			dsy = strtonum(tmp, 1, USHRT_MAX, &errstr); | ||||||
| 			if (errstr != NULL) { | 			if (errstr != NULL) { | ||||||
| 				cmdq_error(item, "height %s", errstr); | 				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")) | 		if (sy > 0 && options_get_number(global_s_options, "status")) | ||||||
| 			sy--; | 			sy--; | ||||||
| 	} else { | 	} else { | ||||||
| 		value = options_get_string(global_s_options, "default-size"); | 		tmp = options_get_string(global_s_options, "default-size"); | ||||||
| 		if (sscanf(value, "%ux%u", &sx, &sy) != 2) { | 		if (sscanf(tmp, "%ux%u", &sx, &sy) != 2) { | ||||||
| 			sx = 80; | 			sx = 80; | ||||||
| 			sy = 24; | 			sy = 24; | ||||||
| 		} | 		} | ||||||
| @@ -240,59 +236,34 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) | |||||||
| 	if (sy == 0) | 	if (sy == 0) | ||||||
| 		sy = 1; | 		sy = 1; | ||||||
|  |  | ||||||
| 	/* Figure out the command for the new window. */ | 	/* Create the new session. */ | ||||||
| 	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. */ |  | ||||||
| 	env = environ_create(); |  | ||||||
| 	if (c != NULL && !args_has(args, 'E')) |  | ||||||
| 		environ_update(global_s_options, c->environ, env); |  | ||||||
|  |  | ||||||
| 	/* Set up the options. */ |  | ||||||
| 	oo = options_create(global_s_options); | 	oo = options_create(global_s_options); | ||||||
| 	if (args_has(args, 'x') || args_has(args, 'y')) | 	if (args_has(args, 'x') || args_has(args, 'y')) | ||||||
| 		options_set_string(oo, "default-size", 0, "%ux%u", dsx, dsy); | 		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); | ||||||
|  |  | ||||||
| 	/* Create the new session. */ | 	/* Spawn the initial window. */ | ||||||
| 	idx = -1 - options_get_number(global_s_options, "base-index"); | 	memset(&sc, 0, sizeof sc); | ||||||
| 	s = session_create(prefix, newname, argc, argv, path, cwd, env, oo, | 	sc.item = item; | ||||||
| 	    tiop, idx, &cause); | 	sc.s = s; | ||||||
| 	environ_free(env); |  | ||||||
| 	if (s == NULL) { | 	sc.name = args_get(args, 'n'); | ||||||
| 		cmdq_error(item, "create session failed: %s", cause); | 	sc.argc = args->argc; | ||||||
|  | 	sc.argv = args->argv; | ||||||
|  |  | ||||||
|  | 	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); | 		free(cause); | ||||||
| 		goto error; | 		goto fail; | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* 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); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
| @@ -364,7 +335,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) | |||||||
| 	free(newname); | 	free(newname); | ||||||
| 	return (CMD_RETURN_NORMAL); | 	return (CMD_RETURN_NORMAL); | ||||||
|  |  | ||||||
| error: | fail: | ||||||
| 	free(cwd); | 	free(cwd); | ||||||
| 	free(newname); | 	free(newname); | ||||||
| 	return (CMD_RETURN_ERROR); | 	return (CMD_RETURN_ERROR); | ||||||
|   | |||||||
							
								
								
									
										103
									
								
								cmd-new-window.c
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								cmd-new-window.c
									
									
									
									
									
								
							| @@ -53,87 +53,45 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) | |||||||
| { | { | ||||||
| 	struct args		*args = self->args; | 	struct args		*args = self->args; | ||||||
| 	struct cmd_find_state	*current = &item->shared->current; | 	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 session		*s = item->target.s; | ||||||
| 	struct winlink		*wl = item->target.wl; | 	struct winlink		*wl = item->target.wl; | ||||||
| 	struct client		*c = cmd_find_client(item, NULL, 1); |  | ||||||
| 	int			 idx = item->target.idx; | 	int			 idx = item->target.idx; | ||||||
| 	const char		*cmd, *path, *template, *tmp; | 	struct winlink		*new_wl; | ||||||
| 	char		       **argv, *cause, *cp, *cwd, *name; | 	char			*cause = NULL, *cp; | ||||||
| 	int			 argc, detached; | 	const char		*template; | ||||||
| 	struct environ_entry	*envent; |  | ||||||
| 	struct cmd_find_state	 fs; | 	struct cmd_find_state	 fs; | ||||||
|  |  | ||||||
| 	if (args_has(args, 'a') && wl != NULL) { | 	if (args_has(args, 'a') && (idx = winlink_shuffle_up(s, wl)) == -1) { | ||||||
| 		if ((idx = winlink_shuffle_up(s, wl)) == -1) { | 		cmdq_error(item, "couldn't get a window index"); | ||||||
| 			cmdq_error(item, "no free window indexes"); | 		return (CMD_RETURN_ERROR); | ||||||
| 			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; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	path = NULL; | 	memset(&sc, 0, sizeof sc); | ||||||
| 	if (item->client != NULL && item->client->session == NULL) | 	sc.item = item; | ||||||
| 		envent = environ_find(item->client->environ, "PATH"); | 	sc.s = s; | ||||||
| 	else |  | ||||||
| 		envent = environ_find(s->environ, "PATH"); |  | ||||||
| 	if (envent != NULL) |  | ||||||
| 		path = envent->value; |  | ||||||
|  |  | ||||||
| 	if ((tmp = args_get(args, 'c')) != NULL) | 	sc.name = args_get(args, 'n'); | ||||||
| 		cwd = format_single(item, tmp, c, s, NULL, NULL); | 	sc.argc = args->argc; | ||||||
| 	else | 	sc.argv = args->argv; | ||||||
| 		cwd = xstrdup(server_client_get_cwd(item->client, s)); |  | ||||||
|  |  | ||||||
| 	if ((tmp = args_get(args, 'n')) != NULL) | 	sc.idx = idx; | ||||||
| 		name = format_single(item, tmp, c, s, NULL, NULL); | 	sc.cwd = args_get(args, 'c'); | ||||||
| 	else |  | ||||||
| 		name = NULL; |  | ||||||
|  |  | ||||||
| 	if (idx != -1) | 	sc.flags = 0; | ||||||
| 		wl = winlink_find_by_index(&s->windows, idx); | 	if (args_has(args, 'd')) | ||||||
| 	if (wl != NULL && args_has(args, 'k')) { | 		sc.flags |= SPAWN_DETACHED; | ||||||
| 		/* | 	if (args_has(args, 'k')) | ||||||
| 		 * Can't use session_detach as it will destroy session if this | 		sc.flags |= SPAWN_KILL; | ||||||
| 		 * 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 ((new_wl = spawn_window(&sc, &cause)) == NULL) { | ||||||
| 		if (wl == s->curw) { |  | ||||||
| 			detached = 0; |  | ||||||
| 			s->curw = NULL; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	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) { |  | ||||||
| 		cmdq_error(item, "create window failed: %s", cause); | 		cmdq_error(item, "create window failed: %s", cause); | ||||||
| 		free(cause); | 		free(cause); | ||||||
| 		goto error; | 		return (CMD_RETURN_ERROR); | ||||||
| 	} | 	} | ||||||
| 	if (!detached) { | 	if (!args_has(args, 'd') || new_wl == s->curw) { | ||||||
| 		session_select(s, wl->idx); | 		cmd_find_from_winlink(current, new_wl, 0); | ||||||
| 		cmd_find_from_winlink(current, wl, 0); |  | ||||||
| 		server_redraw_session_group(s); | 		server_redraw_session_group(s); | ||||||
| 	} else | 	} else | ||||||
| 		server_status_session_group(s); | 		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 (args_has(args, 'P')) { | ||||||
| 		if ((template = args_get(args, 'F')) == NULL) | 		if ((template = args_get(args, 'F')) == NULL) | ||||||
| 			template = NEW_WINDOW_TEMPLATE; | 			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); | 		cmdq_print(item, "%s", cp); | ||||||
| 		free(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"); | 	hooks_insert(s->hooks, item, &fs, "after-new-window"); | ||||||
|  |  | ||||||
| 	free(name); |  | ||||||
| 	free(cwd); |  | ||||||
| 	return (CMD_RETURN_NORMAL); | 	return (CMD_RETURN_NORMAL); | ||||||
|  |  | ||||||
| error: |  | ||||||
| 	free(name); |  | ||||||
| 	free(cwd); |  | ||||||
| 	return (CMD_RETURN_ERROR); |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -111,7 +111,7 @@ cmdq_remove(struct cmdq_item *item) | |||||||
| 	if (item->client != NULL) | 	if (item->client != NULL) | ||||||
| 		server_client_unref(item->client); | 		server_client_unref(item->client); | ||||||
|  |  | ||||||
| 	if (item->type == CMDQ_COMMAND) | 	if (item->cmdlist != NULL) | ||||||
| 		cmd_list_free(item->cmdlist); | 		cmd_list_free(item->cmdlist); | ||||||
|  |  | ||||||
| 	TAILQ_REMOVE(item->queue, item, entry); | 	TAILQ_REMOVE(item->queue, item, entry); | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ | |||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
|  |  | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <unistd.h> | #include <string.h> | ||||||
|  |  | ||||||
| #include "tmux.h" | #include "tmux.h" | ||||||
|  |  | ||||||
| @@ -36,7 +36,7 @@ const struct cmd_entry cmd_respawn_pane_entry = { | |||||||
|  |  | ||||||
| 	.args = { "c:kt:", 0, -1 }, | 	.args = { "c:kt:", 0, -1 }, | ||||||
| 	.usage = "[-c start-directory] [-k] " CMD_TARGET_PANE_USAGE | 	.usage = "[-c start-directory] [-k] " CMD_TARGET_PANE_USAGE | ||||||
| 	         " [command]", | 		 " [command]", | ||||||
|  |  | ||||||
| 	.target = { 't', CMD_FIND_PANE, 0 }, | 	.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) | cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item) | ||||||
| { | { | ||||||
| 	struct args		*args = self->args; | 	struct args		*args = self->args; | ||||||
| 	struct winlink		*wl = item->target.wl; | 	struct spawn_context	 sc; | ||||||
| 	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 session		*s = item->target.s; | ||||||
| 	struct environ		*env; | 	struct winlink		*wl = item->target.wl; | ||||||
| 	const char		*path = NULL, *cp; | 	struct window_pane	*wp = item->target.wp; | ||||||
| 	char			*cause, *cwd = NULL; | 	char			*cause = NULL; | ||||||
| 	u_int			 idx; |  | ||||||
| 	struct environ_entry	*envent; |  | ||||||
|  |  | ||||||
| 	if (!args_has(self->args, 'k') && wp->fd != -1) { | 	memset(&sc, 0, sizeof sc); | ||||||
| 		if (window_pane_index(wp, &idx) != 0) | 	sc.item = item; | ||||||
| 			fatalx("index not found"); | 	sc.s = s; | ||||||
| 		cmdq_error(item, "pane still active: %s:%d.%u", | 	sc.wl = wl; | ||||||
| 		    s->name, wl->idx, idx); |  | ||||||
| 		return (CMD_RETURN_ERROR); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	window_pane_reset_mode_all(wp); | 	sc.wp0 = wp; | ||||||
| 	screen_reinit(&wp->base); | 	sc.lc = NULL; | ||||||
| 	input_init(wp); |  | ||||||
|  |  | ||||||
| 	if (item->client != NULL && item->client->session == NULL) | 	sc.name = NULL; | ||||||
| 		envent = environ_find(item->client->environ, "PATH"); | 	sc.argc = args->argc; | ||||||
| 	else | 	sc.argv = args->argv; | ||||||
| 		envent = environ_find(s->environ, "PATH"); |  | ||||||
| 	if (envent != NULL) |  | ||||||
| 		path = envent->value; |  | ||||||
|  |  | ||||||
| 	if ((cp = args_get(args, 'c')) != NULL) | 	sc.idx = -1; | ||||||
| 		cwd = format_single(item, cp, c, s, NULL, NULL); | 	sc.cwd = args_get(args, 'c'); | ||||||
|  |  | ||||||
| 	env = environ_for_session(s, 0); | 	sc.flags = SPAWN_RESPAWN; | ||||||
| 	if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, cwd, env, | 	if (args_has(args, 'k')) | ||||||
| 	    s->tio, &cause) != 0) { | 		sc.flags |= SPAWN_KILL; | ||||||
|  |  | ||||||
|  | 	if (spawn_pane(&sc, &cause) == NULL) { | ||||||
| 		cmdq_error(item, "respawn pane failed: %s", cause); | 		cmdq_error(item, "respawn pane failed: %s", cause); | ||||||
| 		free(cause); | 		free(cause); | ||||||
| 		environ_free(env); |  | ||||||
| 		free(cwd); |  | ||||||
| 		return (CMD_RETURN_ERROR); | 		return (CMD_RETURN_ERROR); | ||||||
| 	} | 	} | ||||||
| 	environ_free(env); |  | ||||||
| 	free(cwd); |  | ||||||
|  |  | ||||||
| 	wp->flags |= PANE_REDRAW; | 	wp->flags |= PANE_REDRAW; | ||||||
| 	server_status_window(w); | 	server_status_window(wp->window); | ||||||
|  |  | ||||||
| 	return (CMD_RETURN_NORMAL); | 	return (CMD_RETURN_NORMAL); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ | |||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
|  |  | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <unistd.h> | #include <string.h> | ||||||
|  |  | ||||||
| #include "tmux.h" | #include "tmux.h" | ||||||
|  |  | ||||||
| @@ -48,64 +48,34 @@ static enum cmd_retval | |||||||
| cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item) | cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item) | ||||||
| { | { | ||||||
| 	struct args		*args = self->args; | 	struct args		*args = self->args; | ||||||
|  | 	struct spawn_context	 sc; | ||||||
| 	struct session		*s = item->target.s; | 	struct session		*s = item->target.s; | ||||||
| 	struct winlink		*wl = item->target.wl; | 	struct winlink		*wl = item->target.wl; | ||||||
| 	struct window		*w = wl->window; | 	char			*cause = NULL; | ||||||
| 	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')) { | 	memset(&sc, 0, sizeof sc); | ||||||
| 		TAILQ_FOREACH(wp, &w->panes, entry) { | 	sc.item = item; | ||||||
| 			if (wp->fd == -1) | 	sc.s = s; | ||||||
| 				continue; | 	sc.wl = wl; | ||||||
| 			cmdq_error(item, "window still active: %s:%d", s->name, |  | ||||||
| 			    wl->idx); |  | ||||||
| 			return (CMD_RETURN_ERROR); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	wp = TAILQ_FIRST(&w->panes); | 	sc.name = NULL; | ||||||
| 	TAILQ_REMOVE(&w->panes, wp, entry); | 	sc.argc = args->argc; | ||||||
| 	layout_free(w); | 	sc.argv = args->argv; | ||||||
| 	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) | 	sc.idx = -1; | ||||||
| 		envent = environ_find(item->client->environ, "PATH"); | 	sc.cwd = args_get(args, 'c'); | ||||||
| 	else |  | ||||||
| 		envent = environ_find(s->environ, "PATH"); |  | ||||||
| 	if (envent != NULL) |  | ||||||
| 		path = envent->value; |  | ||||||
|  |  | ||||||
| 	if ((cp = args_get(args, 'c')) != NULL) | 	sc.flags = SPAWN_RESPAWN; | ||||||
| 		cwd = format_single(item, cp, c, s, NULL, NULL); | 	if (args_has(args, 'k')) | ||||||
|  | 		sc.flags |= SPAWN_KILL; | ||||||
|  |  | ||||||
| 	env = environ_for_session(s, 0); | 	if (spawn_window(&sc, &cause) == NULL) { | ||||||
| 	if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, cwd, env, |  | ||||||
| 	    s->tio, &cause) != 0) { |  | ||||||
| 		cmdq_error(item, "respawn window failed: %s", cause); | 		cmdq_error(item, "respawn window failed: %s", cause); | ||||||
| 		free(cause); | 		free(cause); | ||||||
| 		environ_free(env); |  | ||||||
| 		free(cwd); |  | ||||||
| 		server_destroy_pane(wp, 0); |  | ||||||
| 		return (CMD_RETURN_ERROR); | 		return (CMD_RETURN_ERROR); | ||||||
| 	} | 	} | ||||||
| 	environ_free(env); |  | ||||||
| 	free(cwd); |  | ||||||
|  |  | ||||||
| 	layout_init(w, wp); | 	server_redraw_window(wl->window); | ||||||
| 	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); |  | ||||||
|  |  | ||||||
| 	return (CMD_RETURN_NORMAL); | 	return (CMD_RETURN_NORMAL); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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) | 		if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL) | ||||||
| 			wp = TAILQ_LAST(&w->panes, window_panes); | 			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); | 		cmd_find_from_winlink_pane(current, wl, wp, 0); | ||||||
| 		server_redraw_window(w); | 		server_redraw_window(w); | ||||||
| 	} else { | 	} else { | ||||||
| @@ -105,7 +105,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item) | |||||||
|  |  | ||||||
| 		if ((wp = TAILQ_NEXT(w->active, entry)) == NULL) | 		if ((wp = TAILQ_NEXT(w->active, entry)) == NULL) | ||||||
| 			wp = TAILQ_FIRST(&w->panes); | 			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); | 		cmd_find_from_winlink_pane(current, wl, wp, 0); | ||||||
| 		server_redraw_window(w); | 		server_redraw_window(w); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -112,7 +112,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) | |||||||
| 		else { | 		else { | ||||||
| 			server_unzoom_window(w); | 			server_unzoom_window(w); | ||||||
| 			window_redraw_active_switch(w, lastwp); | 			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_find_from_winlink(current, wl, 0); | ||||||
| 				cmd_select_pane_redraw(w); | 				cmd_select_pane_redraw(w); | ||||||
| 			} | 			} | ||||||
| @@ -194,7 +194,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) | |||||||
| 		return (CMD_RETURN_NORMAL); | 		return (CMD_RETURN_NORMAL); | ||||||
| 	server_unzoom_window(wp->window); | 	server_unzoom_window(wp->window); | ||||||
| 	window_redraw_active_switch(w, wp); | 	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); | 		cmd_find_from_winlink_pane(current, wl, wp, 0); | ||||||
| 		hooks_insert(s->hooks, item, current, "after-select-pane"); | 		hooks_insert(s->hooks, item, current, "after-select-pane"); | ||||||
| 		cmd_select_pane_redraw(w); | 		cmd_select_pane_redraw(w); | ||||||
|   | |||||||
| @@ -53,111 +53,87 @@ const struct cmd_entry cmd_split_window_entry = { | |||||||
| static enum cmd_retval | static enum cmd_retval | ||||||
| cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) | 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 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 client		*c = cmd_find_client(item, NULL, 1); | ||||||
| 	struct session		*s = item->target.s; | 	struct session		*s = item->target.s; | ||||||
| 	struct winlink		*wl = item->target.wl; | 	struct winlink		*wl = item->target.wl; | ||||||
| 	struct window		*w = wl->window; | 	struct window_pane	*wp = item->target.wp, *new_wp; | ||||||
| 	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; |  | ||||||
| 	enum layout_type	 type; | 	enum layout_type	 type; | ||||||
| 	struct layout_cell	*lc; | 	struct layout_cell	*lc; | ||||||
| 	struct environ_entry	*envent; | 	struct cmd_find_state	 fs; | ||||||
| 	struct cmd_find_state    fs; | 	int			 size, percentage, flags; | ||||||
|  | 	const char		*template; | ||||||
|  | 	char			*cause, *cp; | ||||||
|  |  | ||||||
| 	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)); |  | ||||||
|  |  | ||||||
| 	type = LAYOUT_TOPBOTTOM; |  | ||||||
| 	if (args_has(args, 'h')) | 	if (args_has(args, 'h')) | ||||||
| 		type = LAYOUT_LEFTRIGHT; | 		type = LAYOUT_LEFTRIGHT; | ||||||
| 	before = args_has(args, 'b'); | 	else | ||||||
|  | 		type = LAYOUT_TOPBOTTOM; | ||||||
| 	size = -1; |  | ||||||
| 	if (args_has(args, 'l')) { | 	if (args_has(args, 'l')) { | ||||||
| 		size = args_strtonum(args, 'l', 0, INT_MAX, &cause); | 		size = args_strtonum(args, 'l', 0, INT_MAX, &cause); | ||||||
| 		if (cause != NULL) { | 		if (cause != NULL) { | ||||||
| 			xasprintf(&new_cause, "size %s", cause); | 			cmdq_error(item, "create pane failed: -l %s", cause); | ||||||
| 			free(cause); | 			free(cause); | ||||||
| 			cause = new_cause; | 			return (CMD_RETURN_ERROR); | ||||||
| 			goto error; |  | ||||||
| 		} | 		} | ||||||
| 	} else if (args_has(args, 'p')) { | 	} else if (args_has(args, 'p')) { | ||||||
| 		percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause); | 		percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause); | ||||||
| 		if (cause != NULL) { | 		if (cause != NULL) { | ||||||
| 			xasprintf(&new_cause, "percentage %s", cause); | 			cmdq_error(item, "create pane failed: -p %s", cause); | ||||||
| 			free(cause); | 			free(cause); | ||||||
| 			cause = new_cause; | 			return (CMD_RETURN_ERROR); | ||||||
| 			goto error; |  | ||||||
| 		} | 		} | ||||||
| 		if (type == LAYOUT_TOPBOTTOM) | 		if (type == LAYOUT_TOPBOTTOM) | ||||||
| 			size = (wp->sy * percentage) / 100; | 			size = (wp->sy * percentage) / 100; | ||||||
| 		else | 		else | ||||||
| 			size = (wp->sx * percentage) / 100; | 			size = (wp->sx * percentage) / 100; | ||||||
| 	} |  | ||||||
| 	hlimit = options_get_number(s->options, "history-limit"); |  | ||||||
|  |  | ||||||
| 	shell = options_get_string(s->options, "default-shell"); |  | ||||||
| 	if (*shell == '\0' || areshell(shell)) |  | ||||||
| 		shell = _PATH_BSHELL; |  | ||||||
|  |  | ||||||
| 	lc = layout_split_pane(wp, type, size, before, args_has(args, 'f')); |  | ||||||
| 	if (lc == NULL) { |  | ||||||
| 		cause = xstrdup("pane too small"); |  | ||||||
| 		goto 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); |  | ||||||
|  |  | ||||||
| 	layout_fix_panes(w); |  | ||||||
| 	server_redraw_window(w); |  | ||||||
|  |  | ||||||
| 	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 | 	} else | ||||||
| 		server_status_session(s); | 		size = -1; | ||||||
|  |  | ||||||
|  | 	server_unzoom_window(wp->window); | ||||||
|  |  | ||||||
|  | 	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, flags); | ||||||
|  | 	if (lc == NULL) { | ||||||
|  | 		cmdq_error(item, "no space for new pane"); | ||||||
|  | 		return (CMD_RETURN_ERROR); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	memset(&sc, 0, sizeof sc); | ||||||
|  | 	sc.item = item; | ||||||
|  | 	sc.s = s; | ||||||
|  | 	sc.wl = wl; | ||||||
|  |  | ||||||
|  | 	sc.wp0 = wp; | ||||||
|  | 	sc.lc = lc; | ||||||
|  |  | ||||||
|  | 	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 (args_has(args, 'P')) { | ||||||
| 		if ((template = args_get(args, 'F')) == NULL) | 		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); | 		cmdq_print(item, "%s", cp); | ||||||
| 		free(cp); | 		free(cp); | ||||||
| 	} | 	} | ||||||
| 	notify_window("window-layout-changed", w); |  | ||||||
|  |  | ||||||
| 	cmd_find_from_winlink_pane(&fs, wl, new_wp, 0); | 	cmd_find_from_winlink_pane(&fs, wl, new_wp, 0); | ||||||
| 	hooks_insert(s->hooks, item, &fs, "after-split-window"); | 	hooks_insert(s->hooks, item, &fs, "after-split-window"); | ||||||
|  |  | ||||||
| 	free(cwd); |  | ||||||
| 	return (CMD_RETURN_NORMAL); | 	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); |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -101,17 +101,17 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item) | |||||||
|  |  | ||||||
| 	if (!args_has(self->args, 'd')) { | 	if (!args_has(self->args, 'd')) { | ||||||
| 		if (src_w != dst_w) { | 		if (src_w != dst_w) { | ||||||
| 			window_set_active_pane(src_w, dst_wp); | 			window_set_active_pane(src_w, dst_wp, 1); | ||||||
| 			window_set_active_pane(dst_w, src_wp); | 			window_set_active_pane(dst_w, src_wp, 1); | ||||||
| 		} else { | 		} else { | ||||||
| 			tmp_wp = dst_wp; | 			tmp_wp = dst_wp; | ||||||
| 			window_set_active_pane(src_w, tmp_wp); | 			window_set_active_pane(src_w, tmp_wp, 1); | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		if (src_w->active == src_wp) | 		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) | 		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 != dst_w) { | ||||||
| 		if (src_w->last == src_wp) | 		if (src_w->last == src_wp) | ||||||
|   | |||||||
| @@ -116,7 +116,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) | |||||||
| 			server_unzoom_window(wl->window); | 			server_unzoom_window(wl->window); | ||||||
| 			if (wp != NULL) { | 			if (wp != NULL) { | ||||||
| 				window_redraw_active_switch(wp->window, wp); | 				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); | 			session_set_current(s, wl); | ||||||
| 			cmd_find_from_session(&item->shared->current, s, 0); | 			cmd_find_from_session(&item->shared->current, s, 0); | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								layout.c
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								layout.c
									
									
									
									
									
								
							| @@ -831,11 +831,12 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc) | |||||||
|  */ |  */ | ||||||
| struct layout_cell * | struct layout_cell * | ||||||
| layout_split_pane(struct window_pane *wp, enum layout_type type, int size, | 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; | 	struct layout_cell     *lc, *lcparent, *lcnew, *lc1, *lc2; | ||||||
| 	u_int			sx, sy, xoff, yoff, size1, size2; | 	u_int			sx, sy, xoff, yoff, size1, size2; | ||||||
| 	u_int			new_size, saved_size, resize_first = 0; | 	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 | 	 * 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; | 		saved_size = sy; | ||||||
| 	if (size < 0) | 	if (size < 0) | ||||||
| 		size2 = ((saved_size + 1) / 2) - 1; | 		size2 = ((saved_size + 1) / 2) - 1; | ||||||
| 	else if (insert_before) | 	else if (flags & SPAWN_BEFORE) | ||||||
| 		size2 = saved_size - size - 1; | 		size2 = saved_size - size - 1; | ||||||
| 	else | 	else | ||||||
| 		size2 = size; | 		size2 = size; | ||||||
| @@ -887,7 +888,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size, | |||||||
| 	size1 = saved_size - 1 - size2; | 	size1 = saved_size - 1 - size2; | ||||||
|  |  | ||||||
| 	/* Which size are we using? */ | 	/* Which size are we using? */ | ||||||
| 	if (insert_before) | 	if (flags & SPAWN_BEFORE) | ||||||
| 		new_size = size2; | 		new_size = size2; | ||||||
| 	else | 	else | ||||||
| 		new_size = size1; | 		new_size = size1; | ||||||
| @@ -903,7 +904,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size, | |||||||
| 		 */ | 		 */ | ||||||
| 		lcparent = lc->parent; | 		lcparent = lc->parent; | ||||||
| 		lcnew = layout_create_cell(lcparent); | 		lcnew = layout_create_cell(lcparent); | ||||||
| 		if (insert_before) | 		if (flags & SPAWN_BEFORE) | ||||||
| 			TAILQ_INSERT_BEFORE(lc, lcnew, entry); | 			TAILQ_INSERT_BEFORE(lc, lcnew, entry); | ||||||
| 		else | 		else | ||||||
| 			TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry); | 			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); | 			layout_set_size(lcnew, size, sy, 0, 0); | ||||||
| 		else if (lc->type == LAYOUT_TOPBOTTOM) | 		else if (lc->type == LAYOUT_TOPBOTTOM) | ||||||
| 			layout_set_size(lcnew, sx, size, 0, 0); | 			layout_set_size(lcnew, sx, size, 0, 0); | ||||||
| 		if (insert_before) | 		if (flags & SPAWN_BEFORE) | ||||||
| 			TAILQ_INSERT_HEAD(&lc->cells, lcnew, entry); | 			TAILQ_INSERT_HEAD(&lc->cells, lcnew, entry); | ||||||
| 		else | 		else | ||||||
| 			TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry); | 			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. */ | 		/* Create the new child cell. */ | ||||||
| 		lcnew = layout_create_cell(lcparent); | 		lcnew = layout_create_cell(lcparent); | ||||||
| 		if (insert_before) | 		if (flags & SPAWN_BEFORE) | ||||||
| 			TAILQ_INSERT_HEAD(&lcparent->cells, lcnew, entry); | 			TAILQ_INSERT_HEAD(&lcparent->cells, lcnew, entry); | ||||||
| 		else | 		else | ||||||
| 			TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry); | 			TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry); | ||||||
| 	} | 	} | ||||||
| 	if (insert_before) { | 	if (flags & SPAWN_BEFORE) { | ||||||
| 		lc1 = lcnew; | 		lc1 = lcnew; | ||||||
| 		lc2 = lc; | 		lc2 = lc; | ||||||
| 	} else { | 	} else { | ||||||
|   | |||||||
| @@ -368,7 +368,7 @@ server_destroy_session_group(struct session *s) | |||||||
| 	else { | 	else { | ||||||
| 		TAILQ_FOREACH_SAFE(s, &sg->sessions, gentry, s1) { | 		TAILQ_FOREACH_SAFE(s, &sg->sessions, gentry, s1) { | ||||||
| 			server_destroy_session(s); | 			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) | 		if (s->attached != 0) | ||||||
| 			continue; | 			continue; | ||||||
| 		if (options_get_number (s->options, "destroy-unattached")) | 		if (options_get_number (s->options, "destroy-unattached")) | ||||||
| 			session_destroy(s, __func__); | 			session_destroy(s, 1, __func__); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								server.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								server.c
									
									
									
									
									
								
							| @@ -297,7 +297,7 @@ server_send_exit(void) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	RB_FOREACH_SAFE(s, sessions, &sessions, s1) | 	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. */ | /* Update socket execute permissions based on whether sessions are attached. */ | ||||||
|   | |||||||
							
								
								
									
										68
									
								
								session.c
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								session.c
									
									
									
									
									
								
							| @@ -112,12 +112,10 @@ session_find_by_id(u_int id) | |||||||
|  |  | ||||||
| /* Create a new session. */ | /* Create a new session. */ | ||||||
| struct session * | struct session * | ||||||
| session_create(const char *prefix, const char *name, int argc, char **argv, | session_create(const char *prefix, const char *name, const char *cwd, | ||||||
|     const char *path, const char *cwd, struct environ *env, struct options *oo, |     struct environ *env, struct options *oo, struct termios *tio) | ||||||
|     struct termios *tio, int idx, char **cause) |  | ||||||
| { | { | ||||||
| 	struct session	*s; | 	struct session	*s; | ||||||
| 	struct winlink	*wl; |  | ||||||
|  |  | ||||||
| 	s = xcalloc(1, sizeof *s); | 	s = xcalloc(1, sizeof *s); | ||||||
| 	s->references = 1; | 	s->references = 1; | ||||||
| @@ -129,10 +127,7 @@ session_create(const char *prefix, const char *name, int argc, char **argv, | |||||||
| 	TAILQ_INIT(&s->lastw); | 	TAILQ_INIT(&s->lastw); | ||||||
| 	RB_INIT(&s->windows); | 	RB_INIT(&s->windows); | ||||||
|  |  | ||||||
| 	s->environ = environ_create(); | 	s->environ = env; | ||||||
| 	if (env != NULL) |  | ||||||
| 		environ_copy(env, s->environ); |  | ||||||
|  |  | ||||||
| 	s->options = oo; | 	s->options = oo; | ||||||
| 	s->hooks = hooks_create(global_hooks); | 	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"); | 		fatal("gettimeofday failed"); | ||||||
| 	session_update_activity(s, &s->creation_time); | 	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); | 	return (s); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -220,7 +204,7 @@ session_free(__unused int fd, __unused short events, void *arg) | |||||||
|  |  | ||||||
| /* Destroy a session. */ | /* Destroy a session. */ | ||||||
| void | void | ||||||
| session_destroy(struct session *s, const char *from) | session_destroy(struct session *s, int notify, const char *from) | ||||||
| { | { | ||||||
| 	struct winlink	*wl; | 	struct winlink	*wl; | ||||||
|  |  | ||||||
| @@ -228,7 +212,8 @@ session_destroy(struct session *s, const char *from) | |||||||
| 	s->curw = NULL; | 	s->curw = NULL; | ||||||
|  |  | ||||||
| 	RB_REMOVE(sessions, &sessions, s); | 	RB_REMOVE(sessions, &sessions, s); | ||||||
| 	notify_session("session-closed", s); | 	if (notify) | ||||||
|  | 		notify_session("session-closed", s); | ||||||
|  |  | ||||||
| 	free(s->tio); | 	free(s->tio); | ||||||
|  |  | ||||||
| @@ -338,45 +323,6 @@ session_previous_session(struct session *s) | |||||||
| 	return (s2); | 	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. */ | /* Attach a window to a session. */ | ||||||
| struct winlink * | struct winlink * | ||||||
| session_attach(struct session *s, struct window *w, int idx, char **cause) | 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); | 	session_group_synchronize_from(s); | ||||||
|  |  | ||||||
| 	if (RB_EMPTY(&s->windows)) { | 	if (RB_EMPTY(&s->windows)) { | ||||||
| 		session_destroy(s, __func__); | 		session_destroy(s, 1, __func__); | ||||||
| 		return (1); | 		return (1); | ||||||
| 	} | 	} | ||||||
| 	return (0); | 	return (0); | ||||||
|   | |||||||
							
								
								
									
										434
									
								
								spawn.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										434
									
								
								spawn.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,434 @@ | |||||||
|  | /* $OpenBSD$ */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * 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); | ||||||
|  | } | ||||||
							
								
								
									
										58
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								tmux.h
									
									
									
									
									
								
							| @@ -233,8 +233,8 @@ enum { | |||||||
|  |  | ||||||
| /* Termcap codes. */ | /* Termcap codes. */ | ||||||
| enum tty_code_code { | enum tty_code_code { | ||||||
| 	TTYC_AX = 0, |  | ||||||
| 	TTYC_ACSC, | 	TTYC_ACSC, | ||||||
|  | 	TTYC_AX, | ||||||
| 	TTYC_BCE, | 	TTYC_BCE, | ||||||
| 	TTYC_BEL, | 	TTYC_BEL, | ||||||
| 	TTYC_BLINK, | 	TTYC_BLINK, | ||||||
| @@ -814,7 +814,7 @@ struct window_pane { | |||||||
| 	int		 argc; | 	int		 argc; | ||||||
| 	char	       **argv; | 	char	       **argv; | ||||||
| 	char		*shell; | 	char		*shell; | ||||||
| 	const char	*cwd; | 	char		*cwd; | ||||||
|  |  | ||||||
| 	pid_t		 pid; | 	pid_t		 pid; | ||||||
| 	char		 tty[TTY_NAME_MAX]; | 	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_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]" | ||||||
| #define CMD_BUFFER_USAGE "[-b buffer-name]" | #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 */ | /* tmux.c */ | ||||||
| extern struct hooks	*global_hooks; | extern struct hooks	*global_hooks; | ||||||
| extern struct options	*global_options; | 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); | struct window	*window_find_by_id(u_int); | ||||||
| void		 window_update_activity(struct window *); | void		 window_update_activity(struct window *); | ||||||
| struct window	*window_create(u_int, u_int); | struct window	*window_create(u_int, u_int); | ||||||
| struct window	*window_create_spawn(const char *, int, char **, const char *, | void		 window_destroy(struct window *); | ||||||
| 		     const char *, const char *, struct environ *, | void		 window_pane_set_event(struct window_pane *); | ||||||
| 		     struct termios *, u_int, u_int, u_int, char **); |  | ||||||
| struct window_pane *window_get_active_at(struct window *, u_int, u_int); | struct window_pane *window_get_active_at(struct window *, u_int, u_int); | ||||||
| struct window_pane *window_find_string(struct window *, const char *); | struct window_pane *window_find_string(struct window *, const char *); | ||||||
| int		 window_has_pane(struct window *, struct window_pane *); | 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 *, | void		 window_redraw_active_switch(struct window *, | ||||||
| 		     struct window_pane *); | 		     struct window_pane *); | ||||||
| struct window_pane *window_add_pane(struct window *, struct window_pane *, int, | struct window_pane *window_add_pane(struct window *, struct window_pane *, | ||||||
| 		     int, u_int); | 		     u_int, int); | ||||||
| void		 window_resize(struct window *, u_int, u_int); | void		 window_resize(struct window *, u_int, u_int); | ||||||
| int		 window_zoom(struct window_pane *); | int		 window_zoom(struct window_pane *); | ||||||
| int		 window_unzoom(struct window *); | 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_str(const char *); | ||||||
| struct window_pane *window_pane_find_by_id(u_int); | struct window_pane *window_pane_find_by_id(u_int); | ||||||
| int		 window_pane_destroy_ready(struct window_pane *); | 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_resize(struct window_pane *, u_int, u_int); | ||||||
| void		 window_pane_alternate_on(struct window_pane *, | void		 window_pane_alternate_on(struct window_pane *, | ||||||
| 		     struct grid_cell *, int); | 		     struct grid_cell *, int); | ||||||
| @@ -2319,7 +2342,7 @@ void		 layout_resize_pane_to(struct window_pane *, enum layout_type, | |||||||
| 		     u_int); | 		     u_int); | ||||||
| void		 layout_assign_pane(struct layout_cell *, struct window_pane *); | void		 layout_assign_pane(struct layout_cell *, struct window_pane *); | ||||||
| struct layout_cell *layout_split_pane(struct window_pane *, enum layout_type, | struct layout_cell *layout_split_pane(struct window_pane *, enum layout_type, | ||||||
| 		     int, int, int); | 		     int, int); | ||||||
| void		 layout_close_pane(struct window_pane *); | void		 layout_close_pane(struct window_pane *); | ||||||
| int		 layout_spread_cell(struct window *, struct layout_cell *); | int		 layout_spread_cell(struct window *, struct layout_cell *); | ||||||
| void		 layout_spread_out(struct window_pane *); | 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(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 *, const char *, int, char **, | struct session	*session_create(const char *, const char *, const char *, | ||||||
| 		     const char *, const char *, struct environ *, | 		     struct environ *, struct options *, struct termios *); | ||||||
| 		     struct options *, struct termios *, int, char **); | void		 session_destroy(struct session *, int,  const char *); | ||||||
| void		 session_destroy(struct session *, const char *); |  | ||||||
| void		 session_add_ref(struct session *, const char *); | void		 session_add_ref(struct session *, const char *); | ||||||
| void		 session_remove_ref(struct session *, const char *); | void		 session_remove_ref(struct session *, const char *); | ||||||
| int		 session_check_name(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 *); | void		 style_copy(struct style *, struct style *); | ||||||
| int		 style_is_default(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 */ | #endif /* TMUX_H */ | ||||||
|   | |||||||
| @@ -1006,7 +1006,7 @@ window_tree_kill_each(__unused void* modedata, void* itemdata, | |||||||
| 	case WINDOW_TREE_SESSION: | 	case WINDOW_TREE_SESSION: | ||||||
| 		if (s != NULL) { | 		if (s != NULL) { | ||||||
| 			server_destroy_session(s); | 			server_destroy_session(s); | ||||||
| 			session_destroy(s, __func__); | 			session_destroy(s, 1, __func__); | ||||||
| 		} | 		} | ||||||
| 		break; | 		break; | ||||||
| 	case WINDOW_TREE_WINDOW: | 	case WINDOW_TREE_WINDOW: | ||||||
|   | |||||||
							
								
								
									
										215
									
								
								window.c
									
									
									
									
									
								
							
							
						
						
									
										215
									
								
								window.c
									
									
									
									
									
								
							| @@ -26,7 +26,6 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <termios.h> |  | ||||||
| #include <time.h> | #include <time.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <util.h> | #include <util.h> | ||||||
| @@ -73,20 +72,10 @@ const struct window_mode *all_window_modes[] = { | |||||||
| 	NULL | 	NULL | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static void	window_destroy(struct window *); |  | ||||||
|  |  | ||||||
| static struct window_pane *window_pane_create(struct window *, u_int, u_int, | static struct window_pane *window_pane_create(struct window *, u_int, u_int, | ||||||
| 		    u_int); | 		    u_int); | ||||||
| static void	window_pane_destroy(struct window_pane *); | 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(windows, window, entry, window_cmp); | ||||||
| RB_GENERATE(winlinks, winlink, entry, winlink_cmp); | RB_GENERATE(winlinks, winlink, entry, winlink_cmp); | ||||||
| RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_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); | 	return (w); | ||||||
| } | } | ||||||
|  |  | ||||||
| struct window * | void | ||||||
| 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 |  | ||||||
| window_destroy(struct window *w) | window_destroy(struct window *w) | ||||||
| { | { | ||||||
| 	log_debug("window @%u destroyed (%d references)", w->id, w->references); | 	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 | 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) | 	if (wp == w->active) | ||||||
| 		return (0); | 		return (0); | ||||||
| 	w->last = w->active; | 	w->last = w->active; | ||||||
|  |  | ||||||
| 	w->active = wp; | 	w->active = wp; | ||||||
| 	w->active->active_point = next_active_point++; | 	w->active->active_point = next_active_point++; | ||||||
| 	w->active->flags |= PANE_CHANGED; | 	w->active->flags |= PANE_CHANGED; | ||||||
|  |  | ||||||
| 	tty_update_window_offset(w); | 	tty_update_window_offset(w); | ||||||
| 	notify_window("window-pane-changed", w); |  | ||||||
|  | 	if (notify) | ||||||
|  | 		notify_window("window-pane-changed", w); | ||||||
| 	return (1); | 	return (1); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -571,7 +535,7 @@ window_zoom(struct window_pane *wp) | |||||||
| 		return (-1); | 		return (-1); | ||||||
|  |  | ||||||
| 	if (w->active != wp) | 	if (w->active != wp) | ||||||
| 		window_set_active_pane(w, wp); | 		window_set_active_pane(w, wp, 1); | ||||||
|  |  | ||||||
| 	TAILQ_FOREACH(wp1, &w->panes, entry) { | 	TAILQ_FOREACH(wp1, &w->panes, entry) { | ||||||
| 		wp1->saved_layout_cell = wp1->layout_cell; | 		wp1->saved_layout_cell = wp1->layout_cell; | ||||||
| @@ -610,8 +574,8 @@ window_unzoom(struct window *w) | |||||||
| } | } | ||||||
|  |  | ||||||
| struct window_pane * | struct window_pane * | ||||||
| window_add_pane(struct window *w, struct window_pane *other, int before, | window_add_pane(struct window *w, struct window_pane *other, u_int hlimit, | ||||||
|     int full_size, u_int hlimit) |     int flags) | ||||||
| { | { | ||||||
| 	struct window_pane	*wp; | 	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)) { | 	if (TAILQ_EMPTY(&w->panes)) { | ||||||
| 		log_debug("%s: @%u at start", __func__, w->id); | 		log_debug("%s: @%u at start", __func__, w->id); | ||||||
| 		TAILQ_INSERT_HEAD(&w->panes, wp, entry); | 		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); | 		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); | 			TAILQ_INSERT_HEAD(&w->panes, wp, entry); | ||||||
| 		else | 		else | ||||||
| 			TAILQ_INSERT_BEFORE(other, wp, entry); | 			TAILQ_INSERT_BEFORE(other, wp, entry); | ||||||
| 	} else { | 	} else { | ||||||
| 		log_debug("%s: @%u after %%%u", __func__, w->id, wp->id); | 		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); | 			TAILQ_INSERT_TAIL(&w->panes, wp, entry); | ||||||
| 		else | 		else | ||||||
| 			TAILQ_INSERT_AFTER(&w->panes, other, wp, entry); | 			TAILQ_INSERT_AFTER(&w->panes, other, wp, entry); | ||||||
| @@ -887,141 +851,6 @@ window_pane_destroy(struct window_pane *wp) | |||||||
| 	free(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 | static void | ||||||
| window_pane_read_callback(__unused struct bufferevent *bufev, void *data) | 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); | 		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 | void | ||||||
| window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) | 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; | 	int	 idx, last; | ||||||
|  |  | ||||||
|  | 	if (wl == NULL) | ||||||
|  | 		return (-1); | ||||||
| 	idx = wl->idx + 1; | 	idx = wl->idx + 1; | ||||||
|  |  | ||||||
| 	/* Find the next free index. */ | 	/* Find the next free index. */ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 nicm
					nicm