xref: /openbsd-src/usr.bin/tmux/cmd-new-window.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /* $OpenBSD: cmd-new-window.c,v 1.38 2013/11/23 09:18:29 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 enum cmd_retval	cmd_new_window_exec(struct cmd *, struct cmd_q *);
34 
35 const struct cmd_entry cmd_new_window_entry = {
36 	"new-window", "neww",
37 	"ac:dF:kn:Pt:", 0, 1,
38 	"[-adkP] [-c start-directory] [-F format] [-n window-name] "
39 	CMD_TARGET_WINDOW_USAGE " [command]",
40 	0,
41 	NULL,
42 	cmd_new_window_exec
43 };
44 
45 enum cmd_retval
46 cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
47 {
48 	struct args		*args = self->args;
49 	struct session		*s;
50 	struct winlink		*wl;
51 	struct client		*c;
52 	const char		*cmd, *template;
53 	char			*cause, *cp;
54 	int			 idx, last, detached, cwd, fd = -1;
55 	struct format_tree	*ft;
56 
57 	if (args_has(args, 'a')) {
58 		wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
59 		if (wl == NULL)
60 			return (CMD_RETURN_ERROR);
61 		idx = wl->idx + 1;
62 
63 		/* Find the next free index. */
64 		for (last = idx; last < INT_MAX; last++) {
65 			if (winlink_find_by_index(&s->windows, last) == NULL)
66 				break;
67 		}
68 		if (last == INT_MAX) {
69 			cmdq_error(cmdq, "no free window indexes");
70 			return (CMD_RETURN_ERROR);
71 		}
72 
73 		/* Move everything from last - 1 to idx up a bit. */
74 		for (; last > idx; last--) {
75 			wl = winlink_find_by_index(&s->windows, last - 1);
76 			server_link_window(s, wl, s, last, 0, 0, NULL);
77 			server_unlink_window(s, wl);
78 		}
79 	} else {
80 		if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &s)) == -2)
81 			return (CMD_RETURN_ERROR);
82 	}
83 	detached = args_has(args, 'd');
84 
85 	if (args->argc == 0)
86 		cmd = options_get_string(&s->options, "default-command");
87 	else
88 		cmd = args->argv[0];
89 
90 	if (args_has(args, 'c')) {
91 		ft = format_create();
92 		if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
93 			format_client(ft, c);
94 		format_session(ft, s);
95 		format_winlink(ft, s, s->curw);
96 		format_window_pane(ft, s->curw->window->active);
97 		cp = format_expand(ft, args_get(args, 'c'));
98 		format_free(ft);
99 
100 		if (cp != NULL && *cp != '\0') {
101 			fd = open(cp, O_RDONLY|O_DIRECTORY);
102 			free(cp);
103 			if (fd == -1) {
104 				cmdq_error(cmdq, "bad working directory: %s",
105 				    strerror(errno));
106 				return (CMD_RETURN_ERROR);
107 			}
108 		} else if (cp != NULL)
109 			free(cp);
110 		cwd = fd;
111 	} else if (cmdq->client != NULL && cmdq->client->session == NULL)
112 		cwd = cmdq->client->cwd;
113 	else
114 		cwd = s->cwd;
115 
116 	wl = NULL;
117 	if (idx != -1)
118 		wl = winlink_find_by_index(&s->windows, idx);
119 	if (wl != NULL && args_has(args, 'k')) {
120 		/*
121 		 * Can't use session_detach as it will destroy session if this
122 		 * makes it empty.
123 		 */
124 		notify_window_unlinked(s, wl->window);
125 		wl->flags &= ~WINLINK_ALERTFLAGS;
126 		winlink_stack_remove(&s->lastw, wl);
127 		winlink_remove(&s->windows, wl);
128 
129 		/* Force select/redraw if current. */
130 		if (wl == s->curw) {
131 			detached = 0;
132 			s->curw = NULL;
133 		}
134 	}
135 
136 	if (idx == -1)
137 		idx = -1 - options_get_number(&s->options, "base-index");
138 	wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause);
139 	if (wl == NULL) {
140 		cmdq_error(cmdq, "create window failed: %s", cause);
141 		free(cause);
142 		goto error;
143 	}
144 	if (!detached) {
145 		session_select(s, wl->idx);
146 		server_redraw_session_group(s);
147 	} else
148 		server_status_session_group(s);
149 
150 	if (args_has(args, 'P')) {
151 		if ((template = args_get(args, 'F')) == NULL)
152 			template = NEW_WINDOW_TEMPLATE;
153 
154 		ft = format_create();
155 		if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
156 			format_client(ft, c);
157 		format_session(ft, s);
158 		format_winlink(ft, s, wl);
159 		format_window_pane(ft, wl->window->active);
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