|  | /* $Id: cmd-swap-pane.c,v 1.11 2009-07-28 22:12:16 tcunha Exp $ */ | 
|  |  | 
|  | /* | 
|  | * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> | 
|  | * | 
|  | * Permission to use, copy, modify, and distribute this software for any | 
|  | * purpose with or without fee is hereby granted, provided that the above | 
|  | * copyright notice and this permission notice appear in all copies. | 
|  | * | 
|  | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 
|  | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 
|  | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 
|  | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 
|  | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER | 
|  | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | 
|  | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 
|  | */ | 
|  |  | 
|  | #include <sys/types.h> | 
|  |  | 
|  | #include <stdlib.h> | 
|  |  | 
|  | #include "tmux.h" | 
|  |  | 
|  | /* | 
|  | * Swap two panes. | 
|  | */ | 
|  |  | 
|  | int	cmd_swap_pane_parse(struct cmd *, int, char **, char **); | 
|  | int	cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *); | 
|  | void	cmd_swap_pane_free(struct cmd *); | 
|  | void	cmd_swap_pane_init(struct cmd *, int); | 
|  | size_t	cmd_swap_pane_print(struct cmd *, char *, size_t); | 
|  |  | 
|  | struct cmd_swap_pane_data { | 
|  | char	*target; | 
|  | int	 src; | 
|  | int	 dst; | 
|  | int	 flag_detached; | 
|  | int	 flag_up; | 
|  | int	 flag_down; | 
|  | }; | 
|  |  | 
|  | const struct cmd_entry cmd_swap_pane_entry = { | 
|  | "swap-pane", "swapp", | 
|  | "[-dDU] [-t target-window] [-p src-index] [-q dst-index]", | 
|  | 0, 0, | 
|  | cmd_swap_pane_init, | 
|  | cmd_swap_pane_parse, | 
|  | cmd_swap_pane_exec, | 
|  | cmd_swap_pane_free, | 
|  | cmd_swap_pane_print | 
|  | }; | 
|  |  | 
|  | void | 
|  | cmd_swap_pane_init(struct cmd *self, int key) | 
|  | { | 
|  | struct cmd_swap_pane_data	 *data; | 
|  |  | 
|  | self->data = data = xmalloc(sizeof *data); | 
|  | data->target = NULL; | 
|  | data->src = -1; | 
|  | data->dst = -1; | 
|  | data->flag_detached = 0; | 
|  | data->flag_up = 0; | 
|  | data->flag_down = 0; | 
|  |  | 
|  | switch (key) { | 
|  | case '{': | 
|  | data->flag_up = 1; | 
|  | break; | 
|  | case '}': | 
|  | data->flag_down = 1; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | int | 
|  | cmd_swap_pane_parse(struct cmd *self, int argc, char **argv, char **cause) | 
|  | { | 
|  | struct cmd_swap_pane_data	*data; | 
|  | int				 opt, n; | 
|  | const char			*errstr; | 
|  |  | 
|  | self->entry->init(self, 0); | 
|  | data = self->data; | 
|  |  | 
|  | while ((opt = getopt(argc, argv, "dDt:p:q:U")) != -1) { | 
|  | switch (opt) { | 
|  | case 'd': | 
|  | data->flag_detached = 1; | 
|  | break; | 
|  | case 'D': | 
|  | data->flag_up = 0; | 
|  | data->flag_down = 1; | 
|  | data->dst = -1; | 
|  | break; | 
|  | case 't': | 
|  | if (data->target == NULL) | 
|  | data->target = xstrdup(optarg); | 
|  | break; | 
|  | case 'p': | 
|  | if (data->src == -1) { | 
|  | n = strtonum(optarg, 0, INT_MAX, &errstr); | 
|  | if (errstr != NULL) { | 
|  | xasprintf(cause, "src %s", errstr); | 
|  | goto error; | 
|  | } | 
|  | data->src = n; | 
|  | } | 
|  | break; | 
|  | case 'q': | 
|  | if (data->dst == -1) { | 
|  | n = strtonum(optarg, 0, INT_MAX, &errstr); | 
|  | if (errstr != NULL) { | 
|  | xasprintf(cause, "dst %s", errstr); | 
|  | goto error; | 
|  | } | 
|  | data->dst = n; | 
|  | } | 
|  | data->flag_up = 0; | 
|  | data->flag_down = 0; | 
|  | break; | 
|  | case 'U': | 
|  | data->flag_up = 1; | 
|  | data->flag_down = 0; | 
|  | data->dst = -1; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | goto usage; | 
|  | } | 
|  | } | 
|  | argc -= optind; | 
|  | argv += optind; | 
|  | if (argc != 0) | 
|  | goto usage; | 
|  |  | 
|  | return (0); | 
|  |  | 
|  | usage: | 
|  | xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); | 
|  |  | 
|  | error: | 
|  | self->entry->free(self); | 
|  | return (-1); | 
|  | } | 
|  |  | 
|  | int | 
|  | cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) | 
|  | { | 
|  | struct cmd_swap_pane_data	*data = self->data; | 
|  | struct winlink			*wl; | 
|  | struct window			*w; | 
|  | struct window_pane		*tmp_wp, *src_wp, *dst_wp; | 
|  | struct layout_cell		*lc; | 
|  | u_int				 sx, sy, xoff, yoff; | 
|  |  | 
|  | if (data == NULL) | 
|  | return (0); | 
|  |  | 
|  | if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL) | 
|  | return (-1); | 
|  | w = wl->window; | 
|  |  | 
|  | if (data->src == -1) | 
|  | src_wp = w->active; | 
|  | else { | 
|  | src_wp = window_pane_at_index(w, data->src); | 
|  | if (src_wp == NULL) { | 
|  | ctx->error(ctx, "no pane: %d", data->src); | 
|  | return (-1); | 
|  | } | 
|  | } | 
|  | if (data->dst == -1) | 
|  | dst_wp = w->active; | 
|  | else { | 
|  | dst_wp = window_pane_at_index(w, data->dst); | 
|  | if (dst_wp == NULL) { | 
|  | ctx->error(ctx, "no pane: %d", data->dst); | 
|  | return (-1); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (data->dst == -1 && data->flag_up) { | 
|  | if ((dst_wp = TAILQ_PREV(src_wp, window_panes, entry)) == NULL) | 
|  | dst_wp = TAILQ_LAST(&w->panes, window_panes); | 
|  | } | 
|  | if (data->dst == -1 && data->flag_down) { | 
|  | if ((dst_wp = TAILQ_NEXT(src_wp, entry)) == NULL) | 
|  | dst_wp = TAILQ_FIRST(&w->panes); | 
|  | } | 
|  |  | 
|  | if (src_wp == dst_wp) | 
|  | return (0); | 
|  |  | 
|  | tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry); | 
|  | TAILQ_REMOVE(&w->panes, dst_wp, entry); | 
|  | TAILQ_REPLACE(&w->panes, src_wp, dst_wp, entry); | 
|  | if (tmp_wp == src_wp) | 
|  | tmp_wp = dst_wp; | 
|  | if (tmp_wp == NULL) | 
|  | TAILQ_INSERT_HEAD(&w->panes, src_wp, entry); | 
|  | else | 
|  | TAILQ_INSERT_AFTER(&w->panes, tmp_wp, src_wp, entry); | 
|  |  | 
|  | lc = src_wp->layout_cell; | 
|  | src_wp->layout_cell = dst_wp->layout_cell; | 
|  | if (src_wp->layout_cell != NULL) | 
|  | src_wp->layout_cell->wp = src_wp; | 
|  | dst_wp->layout_cell = lc; | 
|  | if (dst_wp->layout_cell != NULL) | 
|  | dst_wp->layout_cell->wp = dst_wp; | 
|  |  | 
|  | sx = src_wp->sx; sy = src_wp->sy; | 
|  | xoff = src_wp->xoff; yoff = src_wp->yoff; | 
|  | src_wp->xoff = dst_wp->xoff; src_wp->yoff = dst_wp->yoff; | 
|  | window_pane_resize(src_wp, dst_wp->sx, dst_wp->sy); | 
|  | dst_wp->xoff = xoff; dst_wp->yoff = yoff; | 
|  | window_pane_resize(dst_wp, sx, sy); | 
|  |  | 
|  | if (!data->flag_detached) { | 
|  | tmp_wp = dst_wp; | 
|  | if (!window_pane_visible(tmp_wp)) | 
|  | tmp_wp = src_wp; | 
|  | window_set_active_pane(w, tmp_wp); | 
|  | } | 
|  | server_redraw_window(w); | 
|  |  | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | void | 
|  | cmd_swap_pane_free(struct cmd *self) | 
|  | { | 
|  | struct cmd_swap_pane_data	*data = self->data; | 
|  |  | 
|  | if (data->target != NULL) | 
|  | xfree(data->target); | 
|  | xfree(data); | 
|  | } | 
|  |  | 
|  | size_t | 
|  | cmd_swap_pane_print(struct cmd *self, char *buf, size_t len) | 
|  | { | 
|  | struct cmd_swap_pane_data	*data = self->data; | 
|  | size_t				 off = 0; | 
|  |  | 
|  | off += xsnprintf(buf, len, "%s", self->entry->name); | 
|  | if (data == NULL) | 
|  | return (off); | 
|  | if (off < len && | 
|  | (data->flag_down || data->flag_up || data->flag_detached)) { | 
|  | off += xsnprintf(buf + off, len - off, " -"); | 
|  | if (off < len && data->flag_detached) | 
|  | off += xsnprintf(buf + off, len - off, "d"); | 
|  | if (off < len && data->flag_up) | 
|  | off += xsnprintf(buf + off, len - off, "D"); | 
|  | if (off < len && data->flag_down) | 
|  | off += xsnprintf(buf + off, len - off, "U"); | 
|  | } | 
|  | if (off < len && data->target != NULL) | 
|  | off += cmd_prarg(buf + off, len - off, " -t ", data->target); | 
|  | if (off < len && data->src != -1) | 
|  | off += xsnprintf(buf + off, len - off, " -p %d", data->src); | 
|  | if (off < len && data->dst != -1) | 
|  | off += xsnprintf(buf + off, len - off, " -q %d", data->dst); | 
|  | return (off); | 
|  | } |