Fix problems with window sizing seen by Raghavendra D Prabhu when
[tmux-openbsd.git] / cmd-new-window.c
blobcf32f29e1fc56baec41e05fbf9b9fd4b71c06279
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
21 #include <stdlib.h>
23 #include "tmux.h"
26 * Create a new window.
29 int cmd_new_window_parse(struct cmd *, int, char **, char **);
30 int cmd_new_window_exec(struct cmd *, struct cmd_ctx *);
31 void cmd_new_window_free(struct cmd *);
32 void cmd_new_window_init(struct cmd *, int);
33 size_t cmd_new_window_print(struct cmd *, char *, size_t);
35 struct cmd_new_window_data {
36 char *target;
37 char *name;
38 char *cmd;
39 int flag_insert_after;
40 int flag_detached;
41 int flag_kill;
44 const struct cmd_entry cmd_new_window_entry = {
45 "new-window", "neww",
46 "[-adk] [-n window-name] [-t target-window] [command]",
47 0, "",
48 cmd_new_window_init,
49 cmd_new_window_parse,
50 cmd_new_window_exec,
51 cmd_new_window_free,
52 cmd_new_window_print
55 /* ARGSUSED */
56 void
57 cmd_new_window_init(struct cmd *self, unused int arg)
59 struct cmd_new_window_data *data;
61 self->data = data = xmalloc(sizeof *data);
62 data->target = NULL;
63 data->name = NULL;
64 data->cmd = NULL;
65 data->flag_insert_after = 0;
66 data->flag_detached = 0;
67 data->flag_kill = 0;
70 int
71 cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause)
73 struct cmd_new_window_data *data;
74 int opt;
76 self->entry->init(self, KEYC_NONE);
77 data = self->data;
79 while ((opt = getopt(argc, argv, "adkt:n:")) != -1) {
80 switch (opt) {
81 case 'a':
82 data->flag_insert_after = 1;
83 break;
84 case 'd':
85 data->flag_detached = 1;
86 break;
87 case 'k':
88 data->flag_kill = 1;
89 break;
90 case 't':
91 if (data->target == NULL)
92 data->target = xstrdup(optarg);
93 break;
94 case 'n':
95 if (data->name == NULL)
96 data->name = xstrdup(optarg);
97 break;
98 default:
99 goto usage;
102 argc -= optind;
103 argv += optind;
104 if (argc != 0 && argc != 1)
105 goto usage;
107 if (argc == 1)
108 data->cmd = xstrdup(argv[0]);
110 return (0);
112 usage:
113 xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
115 self->entry->free(self);
116 return (-1);
120 cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
122 struct cmd_new_window_data *data = self->data;
123 struct session *s;
124 struct winlink *wl;
125 char *cmd, *cwd, *cause;
126 int idx, last;
128 if (data == NULL)
129 return (0);
131 if (data->flag_insert_after) {
132 if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
133 return (-1);
134 idx = wl->idx + 1;
136 /* Find the next free index. */
137 for (last = idx; last < INT_MAX; last++) {
138 if (winlink_find_by_index(&s->windows, last) == NULL)
139 break;
141 if (last == INT_MAX) {
142 ctx->error(ctx, "no free window indexes");
143 return (-1);
146 /* Move everything from last - 1 to idx up a bit. */
147 for (; last > idx; last--) {
148 wl = winlink_find_by_index(&s->windows, last - 1);
149 server_link_window(s, wl, s, last, 0, 0, NULL);
150 server_unlink_window(s, wl);
152 } else {
153 if ((idx = cmd_find_index(ctx, data->target, &s)) == -2)
154 return (-1);
157 wl = NULL;
158 if (idx != -1)
159 wl = winlink_find_by_index(&s->windows, idx);
160 if (wl != NULL && data->flag_kill) {
162 * Can't use session_detach as it will destroy session if this
163 * makes it empty.
165 session_alert_cancel(s, wl);
166 winlink_stack_remove(&s->lastw, wl);
167 winlink_remove(&s->windows, wl);
169 /* Force select/redraw if current. */
170 if (wl == s->curw) {
171 data->flag_detached = 0;
172 s->curw = NULL;
176 cmd = data->cmd;
177 if (cmd == NULL)
178 cmd = options_get_string(&s->options, "default-command");
179 if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL)
180 cwd = options_get_string(&s->options, "default-path");
181 else
182 cwd = ctx->cmdclient->cwd;
184 if (idx == -1)
185 idx = -1 - options_get_number(&s->options, "base-index");
186 wl = session_new(s, data->name, cmd, cwd, idx, &cause);
187 if (wl == NULL) {
188 ctx->error(ctx, "create window failed: %s", cause);
189 xfree(cause);
190 return (-1);
192 if (!data->flag_detached) {
193 session_select(s, wl->idx);
194 server_redraw_session_group(s);
195 } else
196 server_status_session_group(s);
198 return (0);
201 void
202 cmd_new_window_free(struct cmd *self)
204 struct cmd_new_window_data *data = self->data;
206 if (data->target != NULL)
207 xfree(data->target);
208 if (data->name != NULL)
209 xfree(data->name);
210 if (data->cmd != NULL)
211 xfree(data->cmd);
212 xfree(data);
215 size_t
216 cmd_new_window_print(struct cmd *self, char *buf, size_t len)
218 struct cmd_new_window_data *data = self->data;
219 size_t off = 0;
221 off += xsnprintf(buf, len, "%s", self->entry->name);
222 if (data == NULL)
223 return (off);
224 if (off < len && data->flag_detached)
225 off += xsnprintf(buf + off, len - off, " -d");
226 if (off < len && data->target != NULL)
227 off += cmd_prarg(buf + off, len - off, " -t ", data->target);
228 if (off < len && data->name != NULL)
229 off += cmd_prarg(buf + off, len - off, " -n ", data->name);
230 if (off < len && data->cmd != NULL)
231 off += cmd_prarg(buf + off, len - off, " ", data->cmd);
232 return (off);