1 /* $OpenBSD: cmd-join-pane.c,v 1.3 2010/04/17 23:14:17 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2009 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 <paths.h> 22 #include <stdlib.h> 23 #include <unistd.h> 24 25 #include "tmux.h" 26 27 /* 28 * Join a pane into another (like split/swap/kill). 29 */ 30 31 int cmd_join_pane_parse(struct cmd *, int, char **, char **); 32 int cmd_join_pane_exec(struct cmd *, struct cmd_ctx *); 33 void cmd_join_pane_free(struct cmd *); 34 void cmd_join_pane_init(struct cmd *, int); 35 size_t cmd_join_pane_print(struct cmd *, char *, size_t); 36 37 struct cmd_join_pane_data { 38 char *src; 39 char *dst; 40 int flag_detached; 41 int flag_horizontal; 42 int percentage; 43 int size; 44 }; 45 46 const struct cmd_entry cmd_join_pane_entry = { 47 "join-pane", "joinp", 48 "[-dhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane] [command]", 49 0, "", 50 cmd_join_pane_init, 51 cmd_join_pane_parse, 52 cmd_join_pane_exec, 53 cmd_join_pane_free, 54 cmd_join_pane_print 55 }; 56 57 void 58 cmd_join_pane_init(struct cmd *self, int key) 59 { 60 struct cmd_join_pane_data *data; 61 62 self->data = data = xmalloc(sizeof *data); 63 data->src = NULL; 64 data->dst = NULL; 65 data->flag_detached = 0; 66 data->flag_horizontal = 0; 67 data->percentage = -1; 68 data->size = -1; 69 70 switch (key) { 71 case '%': 72 data->flag_horizontal = 1; 73 break; 74 case '"': 75 data->flag_horizontal = 0; 76 break; 77 } 78 } 79 80 int 81 cmd_join_pane_parse(struct cmd *self, int argc, char **argv, char **cause) 82 { 83 struct cmd_join_pane_data *data; 84 int opt; 85 const char *errstr; 86 87 self->entry->init(self, KEYC_NONE); 88 data = self->data; 89 90 while ((opt = getopt(argc, argv, "dhl:p:s:t:v")) != -1) { 91 switch (opt) { 92 case 'd': 93 data->flag_detached = 1; 94 break; 95 case 'h': 96 data->flag_horizontal = 1; 97 break; 98 case 's': 99 if (data->src == NULL) 100 data->src = xstrdup(optarg); 101 break; 102 case 't': 103 if (data->dst == NULL) 104 data->dst = xstrdup(optarg); 105 break; 106 case 'l': 107 if (data->percentage != -1 || data->size != -1) 108 break; 109 data->size = strtonum(optarg, 1, INT_MAX, &errstr); 110 if (errstr != NULL) { 111 xasprintf(cause, "size %s", errstr); 112 goto error; 113 } 114 break; 115 case 'p': 116 if (data->size != -1 || data->percentage != -1) 117 break; 118 data->percentage = strtonum(optarg, 1, 100, &errstr); 119 if (errstr != NULL) { 120 xasprintf(cause, "percentage %s", errstr); 121 goto error; 122 } 123 break; 124 case 'v': 125 data->flag_horizontal = 0; 126 break; 127 default: 128 goto usage; 129 } 130 } 131 argc -= optind; 132 argv += optind; 133 if (argc != 0) 134 goto usage; 135 136 return (0); 137 138 usage: 139 xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); 140 141 error: 142 self->entry->free(self); 143 return (-1); 144 } 145 146 int 147 cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) 148 { 149 struct cmd_join_pane_data *data = self->data; 150 struct session *dst_s; 151 struct winlink *src_wl, *dst_wl; 152 struct window *src_w, *dst_w; 153 struct window_pane *src_wp, *dst_wp; 154 int size, dst_idx; 155 enum layout_type type; 156 struct layout_cell *lc; 157 158 if ((dst_wl = cmd_find_pane(ctx, data->dst, &dst_s, &dst_wp)) == NULL) 159 return (-1); 160 dst_w = dst_wl->window; 161 dst_idx = dst_wl->idx; 162 163 if ((src_wl = cmd_find_pane(ctx, data->src, NULL, &src_wp)) == NULL) 164 return (-1); 165 src_w = src_wl->window; 166 167 if (src_w == dst_w) { 168 ctx->error(ctx, "can't join a pane to its own window"); 169 return (-1); 170 } 171 172 type = LAYOUT_TOPBOTTOM; 173 if (data->flag_horizontal) 174 type = LAYOUT_LEFTRIGHT; 175 176 size = -1; 177 if (data->size != -1) 178 size = data->size; 179 else if (data->percentage != -1) { 180 if (type == LAYOUT_TOPBOTTOM) 181 size = (dst_wp->sy * data->percentage) / 100; 182 else 183 size = (dst_wp->sx * data->percentage) / 100; 184 } 185 186 if ((lc = layout_split_pane(dst_wp, type, size)) == NULL) { 187 ctx->error(ctx, "create pane failed: pane too small"); 188 return (-1); 189 } 190 191 layout_close_pane(src_wp); 192 193 if (src_w->active == src_wp) { 194 src_w->active = TAILQ_PREV(src_wp, window_panes, entry); 195 if (src_w->active == NULL) 196 src_w->active = TAILQ_NEXT(src_wp, entry); 197 } 198 TAILQ_REMOVE(&src_w->panes, src_wp, entry); 199 200 if (window_count_panes(src_w) == 0) 201 server_kill_window(src_w); 202 203 src_wp->window = dst_w; 204 TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry); 205 layout_assign_pane(lc, src_wp); 206 207 recalculate_sizes(); 208 209 server_redraw_window(src_w); 210 server_redraw_window(dst_w); 211 212 if (!data->flag_detached) { 213 window_set_active_pane(dst_w, src_wp); 214 session_select(dst_s, dst_idx); 215 server_redraw_session(dst_s); 216 } else 217 server_status_session(dst_s); 218 219 return (0); 220 } 221 222 void 223 cmd_join_pane_free(struct cmd *self) 224 { 225 struct cmd_join_pane_data *data = self->data; 226 227 if (data->src != NULL) 228 xfree(data->src); 229 if (data->dst != NULL) 230 xfree(data->dst); 231 xfree(data); 232 } 233 234 size_t 235 cmd_join_pane_print(struct cmd *self, char *buf, size_t len) 236 { 237 struct cmd_join_pane_data *data = self->data; 238 size_t off = 0; 239 240 off += xsnprintf(buf, len, "%s", self->entry->name); 241 if (data == NULL) 242 return (off); 243 if (off < len && data->flag_detached) 244 off += xsnprintf(buf + off, len - off, " -d"); 245 if (off < len && data->flag_horizontal) 246 off += xsnprintf(buf + off, len - off, " -h"); 247 if (off < len && data->size > 0) 248 off += xsnprintf(buf + off, len - off, " -l %d", data->size); 249 if (off < len && data->percentage > 0) { 250 off += xsnprintf( 251 buf + off, len - off, " -p %d", data->percentage); 252 } 253 if (off < len && data->src != NULL) 254 off += cmd_prarg(buf + off, len - off, " -s ", data->src); 255 if (off < len && data->dst != NULL) 256 off += cmd_prarg(buf + off, len - off, " -t ", data->dst); 257 return (off); 258 } 259