xref: /openbsd-src/usr.bin/tmux/cmd-new-window.c (revision 9b9d2a55a62c8e82206c25f94fcc7f4e2765250e)
1 /* $OpenBSD: cmd-new-window.c,v 1.46 2015/06/17 16:50:28 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #include "tmux.h"
28 
29 /*
30  * Create a new window.
31  */
32 
33 #define NEW_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
34 
35 enum cmd_retval	cmd_new_window_exec(struct cmd *, struct cmd_q *);
36 
37 const struct cmd_entry cmd_new_window_entry = {
38 	"new-window", "neww",
39 	"ac:dF:kn:Pt:", 0, -1,
40 	"[-adkP] [-c start-directory] [-F format] [-n window-name] "
41 	CMD_TARGET_WINDOW_USAGE " [command]",
42 	0,
43 	cmd_new_window_exec
44 };
45 
46 enum cmd_retval
47 cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
48 {
49 	struct args		*args = self->args;
50 	struct session		*s;
51 	struct winlink		*wl;
52 	const char		*cmd, *path, *template;
53 	char		       **argv, *cause, *cp;
54 	int			 argc, idx, detached, cwd, fd = -1;
55 	struct format_tree	*ft;
56 	struct environ_entry	*envent;
57 
58 	if (args_has(args, 'a')) {
59 		wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
60 		if (wl == NULL)
61 			return (CMD_RETURN_ERROR);
62 		if ((idx = winlink_shuffle_up(s, wl)) == -1) {
63 			cmdq_error(cmdq, "no free window indexes");
64 			return (CMD_RETURN_ERROR);
65 		}
66 	} else {
67 		idx = cmd_find_index(cmdq, args_get(args, 't'), &s);
68 		if (idx == -2)
69 			return (CMD_RETURN_ERROR);
70 	}
71 	detached = args_has(args, 'd');
72 
73 	if (args->argc == 0) {
74 		cmd = options_get_string(&s->options, "default-command");
75 		if (cmd != NULL && *cmd != '\0') {
76 			argc = 1;
77 			argv = (char **)&cmd;
78 		} else {
79 			argc = 0;
80 			argv = NULL;
81 		}
82 	} else {
83 		argc = args->argc;
84 		argv = args->argv;
85 	}
86 
87 	path = NULL;
88 	if (cmdq->client != NULL && cmdq->client->session == NULL)
89 		envent = environ_find(&cmdq->client->environ, "PATH");
90 	else
91 		envent = environ_find(&s->environ, "PATH");
92 	if (envent != NULL)
93 		path = envent->value;
94 
95 	if (args_has(args, 'c')) {
96 		ft = format_create();
97 		format_defaults(ft, cmd_find_client(cmdq, NULL, 1), s, NULL,
98 		    NULL);
99 		cp = format_expand(ft, args_get(args, 'c'));
100 		format_free(ft);
101 
102 		if (cp != NULL && *cp != '\0') {
103 			fd = open(cp, O_RDONLY|O_DIRECTORY);
104 			free(cp);
105 			if (fd == -1) {
106 				cmdq_error(cmdq, "bad working directory: %s",
107 				    strerror(errno));
108 				return (CMD_RETURN_ERROR);
109 			}
110 		} else if (cp != NULL)
111 			free(cp);
112 		cwd = fd;
113 	} else if (cmdq->client != NULL && cmdq->client->session == NULL)
114 		cwd = cmdq->client->cwd;
115 	else
116 		cwd = s->cwd;
117 
118 	wl = NULL;
119 	if (idx != -1)
120 		wl = winlink_find_by_index(&s->windows, idx);
121 	if (wl != NULL && args_has(args, 'k')) {
122 		/*
123 		 * Can't use session_detach as it will destroy session if this
124 		 * makes it empty.
125 		 */
126 		notify_window_unlinked(s, wl->window);
127 		wl->flags &= ~WINLINK_ALERTFLAGS;
128 		winlink_stack_remove(&s->lastw, wl);
129 		winlink_remove(&s->windows, wl);
130 
131 		/* Force select/redraw if current. */
132 		if (wl == s->curw) {
133 			detached = 0;
134 			s->curw = NULL;
135 		}
136 	}
137 
138 	if (idx == -1)
139 		idx = -1 - options_get_number(&s->options, "base-index");
140 	wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx,
141 		&cause);
142 	if (wl == NULL) {
143 		cmdq_error(cmdq, "create window failed: %s", cause);
144 		free(cause);
145 		goto error;
146 	}
147 	if (!detached) {
148 		session_select(s, wl->idx);
149 		server_redraw_session_group(s);
150 	} else
151 		server_status_session_group(s);
152 
153 	if (args_has(args, 'P')) {
154 		if ((template = args_get(args, 'F')) == NULL)
155 			template = NEW_WINDOW_TEMPLATE;
156 
157 		ft = format_create();
158 		format_defaults(ft, cmd_find_client(cmdq, NULL, 1), s, wl,
159 		    NULL);
160 
161 		cp = format_expand(ft, template);
162 		cmdq_print(cmdq, "%s", cp);
163 		free(cp);
164 
165 		format_free(ft);
166 	}
167 
168 	if (fd != -1)
169 		close(fd);
170 	return (CMD_RETURN_NORMAL);
171 
172 error:
173 	if (fd != -1)
174 		close(fd);
175 	return (CMD_RETURN_ERROR);
176 }
177