1 /* $Id: cmd-new-window.c,v 1.1.1.1 2011/03/10 09:15:37 jmmv 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 <stdlib.h> 22 23 #include "tmux.h" 24 25 /* 26 * Create a new window. 27 */ 28 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); 34 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; 42 }; 43 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 53 }; 54 55 /* ARGSUSED */ 56 void 57 cmd_new_window_init(struct cmd *self, unused int arg) 58 { 59 struct cmd_new_window_data *data; 60 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; 68 } 69 70 int 71 cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause) 72 { 73 struct cmd_new_window_data *data; 74 int opt; 75 76 self->entry->init(self, KEYC_NONE); 77 data = self->data; 78 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; 100 } 101 } 102 argc -= optind; 103 argv += optind; 104 if (argc != 0 && argc != 1) 105 goto usage; 106 107 if (argc == 1) 108 data->cmd = xstrdup(argv[0]); 109 110 return (0); 111 112 usage: 113 xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); 114 115 self->entry->free(self); 116 return (-1); 117 } 118 119 int 120 cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) 121 { 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; 127 128 if (data == NULL) 129 return (0); 130 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; 135 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; 140 } 141 if (last == INT_MAX) { 142 ctx->error(ctx, "no free window indexes"); 143 return (-1); 144 } 145 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); 151 } 152 } else { 153 if ((idx = cmd_find_index(ctx, data->target, &s)) == -2) 154 return (-1); 155 } 156 157 wl = NULL; 158 if (idx != -1) 159 wl = winlink_find_by_index(&s->windows, idx); 160 if (wl != NULL && data->flag_kill) { 161 /* 162 * Can't use session_detach as it will destroy session if this 163 * makes it empty. 164 */ 165 wl->flags &= ~WINLINK_ALERTFLAGS; 166 winlink_stack_remove(&s->lastw, wl); 167 winlink_remove(&s->windows, wl); 168 169 /* Force select/redraw if current. */ 170 if (wl == s->curw) { 171 data->flag_detached = 0; 172 s->curw = NULL; 173 } 174 } 175 176 cmd = data->cmd; 177 if (cmd == NULL) 178 cmd = options_get_string(&s->options, "default-command"); 179 cwd = options_get_string(&s->options, "default-path"); 180 if (*cwd == '\0') { 181 if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) 182 cwd = ctx->cmdclient->cwd; 183 else 184 cwd = s->cwd; 185 } 186 187 if (idx == -1) 188 idx = -1 - options_get_number(&s->options, "base-index"); 189 wl = session_new(s, data->name, cmd, cwd, idx, &cause); 190 if (wl == NULL) { 191 ctx->error(ctx, "create window failed: %s", cause); 192 xfree(cause); 193 return (-1); 194 } 195 if (!data->flag_detached) { 196 session_select(s, wl->idx); 197 server_redraw_session_group(s); 198 } else 199 server_status_session_group(s); 200 201 return (0); 202 } 203 204 void 205 cmd_new_window_free(struct cmd *self) 206 { 207 struct cmd_new_window_data *data = self->data; 208 209 if (data->target != NULL) 210 xfree(data->target); 211 if (data->name != NULL) 212 xfree(data->name); 213 if (data->cmd != NULL) 214 xfree(data->cmd); 215 xfree(data); 216 } 217 218 size_t 219 cmd_new_window_print(struct cmd *self, char *buf, size_t len) 220 { 221 struct cmd_new_window_data *data = self->data; 222 size_t off = 0; 223 224 off += xsnprintf(buf, len, "%s", self->entry->name); 225 if (data == NULL) 226 return (off); 227 if (off < len && data->flag_detached) 228 off += xsnprintf(buf + off, len - off, " -d"); 229 if (off < len && data->target != NULL) 230 off += cmd_prarg(buf + off, len - off, " -t ", data->target); 231 if (off < len && data->name != NULL) 232 off += cmd_prarg(buf + off, len - off, " -n ", data->name); 233 if (off < len && data->cmd != NULL) 234 off += cmd_prarg(buf + off, len - off, " ", data->cmd); 235 return (off); 236 } 237