Coverage Report

Created: 2026-07-09 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/cmd-swap-pane.c
Line
Count
Source
1
/* $OpenBSD$ */
2
3
/*
4
 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
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
 * Swap two panes.
27
 */
28
29
static enum cmd_retval  cmd_swap_pane_exec(struct cmd *, struct cmdq_item *);
30
31
const struct cmd_entry cmd_swap_pane_entry = {
32
  .name = "swap-pane",
33
  .alias = "swapp",
34
35
  .args = { "dDs:t:UZ", 0, 0, NULL },
36
  .usage = "[-dDUZ] " CMD_SRCDST_PANE_USAGE,
37
38
  .source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
39
  .target = { 't', CMD_FIND_PANE, 0 },
40
41
  .flags = 0,
42
  .exec = cmd_swap_pane_exec
43
};
44
45
static struct window_pane *
46
cmd_swap_pane_next_tiled_pane(struct window_pane *wp)
47
0
{
48
0
  while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell))
49
0
    wp = TAILQ_NEXT(wp, entry);
50
0
  return (wp);
51
0
}
52
53
static struct window_pane *
54
cmd_swap_pane_prev_tiled_pane(struct window_pane *wp)
55
0
{
56
0
  while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell))
57
0
    wp = TAILQ_PREV(wp, window_panes, entry);
58
0
  return (wp);
59
0
}
60
61
static enum cmd_retval
62
cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
63
0
{
64
0
  struct args   *args = cmd_get_args(self);
65
0
  struct cmd_find_state *source = cmdq_get_source(item);
66
0
  struct cmd_find_state *target = cmdq_get_target(item);
67
0
  struct window   *src_w, *dst_w;
68
0
  struct window_pane  *tmp_wp, *src_wp, *dst_wp;
69
0
  struct layout_cell  *src_lc, *dst_lc;
70
0
  u_int      sx, sy, xoff, yoff;
71
72
0
  dst_w = target->wl->window;
73
0
  dst_wp = target->wp;
74
0
  src_w = source->wl->window;
75
0
  src_wp = source->wp;
76
77
0
  if (window_push_zoom(dst_w, 0, args_has(args, 'Z')))
78
0
    server_redraw_window(dst_w);
79
80
0
  if (args_has(args, 'D')) {
81
0
    if (window_pane_is_floating(dst_wp)) {
82
0
      cmdq_error(item, "cannot swap down on floating pane");
83
0
      return (CMD_RETURN_ERROR);
84
0
    }
85
0
    src_w = dst_w;
86
0
    src_wp = TAILQ_NEXT(dst_wp, entry);
87
0
    src_wp = cmd_swap_pane_next_tiled_pane(src_wp);
88
0
    if (src_wp == NULL) {
89
0
      src_wp = TAILQ_FIRST(&dst_w->panes);
90
0
      src_wp = cmd_swap_pane_next_tiled_pane(src_wp);
91
0
    }
92
0
  } else if (args_has(args, 'U')) {
93
0
    if (window_pane_is_floating(dst_wp)) {
94
0
      cmdq_error(item, "cannot swap up on floating pane");
95
0
      return (CMD_RETURN_ERROR);
96
0
    }
97
0
    src_w = dst_w;
98
0
    src_wp = TAILQ_PREV(dst_wp, window_panes, entry);
99
0
    src_wp = cmd_swap_pane_prev_tiled_pane(src_wp);
100
0
    if (src_wp == NULL) {
101
0
      src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
102
0
      src_wp = cmd_swap_pane_prev_tiled_pane(src_wp);
103
0
    }
104
0
  }
105
106
0
  if (src_w != dst_w && window_push_zoom(src_w, 0, args_has(args, 'Z')))
107
0
    server_redraw_window(src_w);
108
109
0
  if (src_wp == dst_wp)
110
0
    goto out;
111
112
0
  server_client_remove_pane(src_wp);
113
0
  server_client_remove_pane(dst_wp);
114
115
0
  tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry);
116
0
  TAILQ_REMOVE(&dst_w->panes, dst_wp, entry);
117
0
  TAILQ_REPLACE(&src_w->panes, src_wp, dst_wp, entry);
118
0
  if (tmp_wp == src_wp)
119
0
    tmp_wp = dst_wp;
120
0
  if (tmp_wp == NULL)
121
0
    TAILQ_INSERT_HEAD(&dst_w->panes, src_wp, entry);
122
0
  else
123
0
    TAILQ_INSERT_AFTER(&dst_w->panes, tmp_wp, src_wp, entry);
124
125
0
  tmp_wp = TAILQ_PREV(dst_wp, window_panes, zentry);
126
0
  TAILQ_REMOVE(&dst_w->z_index, dst_wp, zentry);
127
0
  TAILQ_REPLACE(&src_w->z_index, src_wp, dst_wp, zentry);
128
0
  if (tmp_wp == src_wp)
129
0
    tmp_wp = dst_wp;
130
0
  if (tmp_wp == NULL)
131
0
    TAILQ_INSERT_HEAD(&dst_w->z_index, src_wp, zentry);
132
0
  else
133
0
    TAILQ_INSERT_AFTER(&dst_w->z_index, tmp_wp, src_wp, zentry);
134
135
0
  src_lc = src_wp->layout_cell;
136
0
  dst_lc = dst_wp->layout_cell;
137
0
  src_lc->wp = dst_wp;
138
0
  dst_wp->layout_cell = src_lc;
139
0
  dst_lc->wp = src_wp;
140
0
  src_wp->layout_cell = dst_lc;
141
142
0
  src_wp->window = dst_w;
143
0
  options_set_parent(src_wp->options, dst_w->options);
144
0
  src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
145
0
  dst_wp->window = src_w;
146
0
  options_set_parent(dst_wp->options, src_w->options);
147
0
  dst_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
148
149
0
  sx = src_wp->sx; sy = src_wp->sy;
150
0
  xoff = src_wp->xoff; yoff = src_wp->yoff;
151
0
  src_wp->xoff = dst_wp->xoff; src_wp->yoff = dst_wp->yoff;
152
0
  window_pane_resize(src_wp, dst_wp->sx, dst_wp->sy);
153
0
  dst_wp->xoff = xoff; dst_wp->yoff = yoff;
154
0
  window_pane_resize(dst_wp, sx, sy);
155
156
0
  if (!args_has(args, 'd')) {
157
0
    if (src_w != dst_w) {
158
0
      window_set_active_pane(src_w, dst_wp, 1);
159
0
      window_set_active_pane(dst_w, src_wp, 1);
160
0
    } else {
161
0
      tmp_wp = dst_wp;
162
0
      window_set_active_pane(src_w, tmp_wp, 1);
163
0
    }
164
0
  } else {
165
0
    if (src_w->active == src_wp)
166
0
      window_set_active_pane(src_w, dst_wp, 1);
167
0
    if (dst_w->active == dst_wp)
168
0
      window_set_active_pane(dst_w, src_wp, 1);
169
0
  }
170
0
  if (src_w != dst_w) {
171
0
    window_pane_stack_remove(&src_w->last_panes, src_wp);
172
0
    window_pane_stack_remove(&dst_w->last_panes, dst_wp);
173
0
    colour_palette_from_option(&src_wp->palette, src_wp->options);
174
0
    colour_palette_from_option(&dst_wp->palette, dst_wp->options);
175
0
    layout_fix_panes(src_w, NULL);
176
0
    redraw_invalidate_scene(src_w);
177
0
    server_redraw_window(src_w);
178
0
  }
179
0
  layout_fix_panes(dst_w, NULL);
180
0
  redraw_invalidate_scene(dst_w);
181
0
  server_redraw_window(dst_w);
182
183
0
  notify_window("window-layout-changed", src_w);
184
0
  if (src_w != dst_w)
185
0
    notify_window("window-layout-changed", dst_w);
186
187
0
out:
188
0
  if (window_pop_zoom(src_w))
189
0
    server_redraw_window(src_w);
190
0
  if (src_w != dst_w && window_pop_zoom(dst_w))
191
0
    server_redraw_window(dst_w);
192
0
  return (CMD_RETURN_NORMAL);
193
0
}