/src/tmux/cmd-join-pane.c
Line | Count | Source |
1 | | /* $OpenBSD: cmd-join-pane.c,v 1.72 2026/07/15 13:02:33 nicm Exp $ */ |
2 | | |
3 | | /* |
4 | | * Copyright (c) 2011 George Nachman <tmux@georgester.com> |
5 | | * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com> |
6 | | * |
7 | | * Permission to use, copy, modify, and distribute this software for any |
8 | | * purpose with or without fee is hereby granted, provided that the above |
9 | | * copyright notice and this permission notice appear in all copies. |
10 | | * |
11 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER |
16 | | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
17 | | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | | */ |
19 | | |
20 | | #include <sys/types.h> |
21 | | |
22 | | #include <stdlib.h> |
23 | | #include <string.h> |
24 | | #include <unistd.h> |
25 | | |
26 | | #include "tmux.h" |
27 | | |
28 | | /* |
29 | | * Join or move a pane into another (like split/swap/kill). |
30 | | */ |
31 | | |
32 | | static enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmdq_item *); |
33 | | static enum cmd_retval cmd_join_pane_mouse_update(struct cmdq_item *); |
34 | | static void cmd_join_pane_mouse_move(struct client *, |
35 | | struct mouse_event *); |
36 | | |
37 | | const struct cmd_entry cmd_join_pane_entry = { |
38 | | .name = "join-pane", |
39 | | .alias = "joinp", |
40 | | |
41 | | .args = { "bdfhvp:l:s:t:", 0, 0, NULL }, |
42 | | .usage = "[-bdfhv] [-l size] " CMD_SRCDST_PANE_USAGE, |
43 | | |
44 | | .source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED }, |
45 | | .target = { 't', CMD_FIND_PANE, 0 }, |
46 | | |
47 | | .flags = 0, |
48 | | .exec = cmd_join_pane_exec |
49 | | }; |
50 | | |
51 | | const struct cmd_entry cmd_move_pane_entry = { |
52 | | .name = "move-pane", |
53 | | .alias = "movep", |
54 | | |
55 | | .args = { "bdD::fhMvl:L::P:R::s:t:U::X:Y:z:", 0, 0, NULL }, |
56 | | .usage = "[-bdfhMv] [-D lines] [-l size] [-L columns] [-P position] " |
57 | | "[-R columns] " CMD_SRCDST_PANE_USAGE " [-U lines] " |
58 | | "[-X x-position] [-Y y-position] [-z z-index]", |
59 | | |
60 | | .source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED }, |
61 | | .target = { 't', CMD_FIND_PANE, 0 }, |
62 | | |
63 | | .flags = 0, |
64 | | .exec = cmd_join_pane_exec |
65 | | }; |
66 | | |
67 | | static enum cmd_retval |
68 | | cmd_join_pane_place(struct cmdq_item *item, struct winlink *wl, |
69 | | struct window_pane *wp, const char *position) |
70 | 0 | { |
71 | 0 | struct window *w = wl->window; |
72 | 0 | struct layout_cell *lc = wp->layout_cell; |
73 | 0 | struct window_pane *owp; |
74 | 0 | int wx = w->sx, wy = w->sy; |
75 | 0 | int px = lc->g.sx, py = lc->g.sy; |
76 | 0 | int xoff = lc->g.xoff, yoff = lc->g.yoff; |
77 | 0 | int border = 1; |
78 | |
|
79 | 0 | if (window_pane_get_pane_lines(wp) == PANE_LINES_NONE) |
80 | 0 | border = 0; |
81 | |
|
82 | 0 | if (strcmp(position, "top-left") == 0) { |
83 | 0 | xoff = border; |
84 | 0 | yoff = border; |
85 | 0 | } else if (strcmp(position, "top-centre") == 0 || |
86 | 0 | strcmp(position, "top-center") == 0) { |
87 | 0 | xoff = (wx - px) / 2; |
88 | 0 | yoff = border; |
89 | 0 | } else if (strcmp(position, "top-right") == 0) { |
90 | 0 | xoff = wx - px - border; |
91 | 0 | yoff = border; |
92 | 0 | } else if (strcmp(position, "centre-left") == 0 || |
93 | 0 | strcmp(position, "center-left") == 0) { |
94 | 0 | xoff = border; |
95 | 0 | yoff = (wy - py) / 2; |
96 | 0 | } else if (strcmp(position, "centre") == 0 || |
97 | 0 | strcmp(position, "center") == 0) { |
98 | 0 | xoff = (wx - px) / 2; |
99 | 0 | yoff = (wy - py) / 2; |
100 | 0 | } else if (strcmp(position, "centre-right") == 0 || |
101 | 0 | strcmp(position, "center-right") == 0) { |
102 | 0 | xoff = wx - px - border; |
103 | 0 | yoff = (wy - py) / 2; |
104 | 0 | } else if (strcmp(position, "bottom-left") == 0) { |
105 | 0 | xoff = border; |
106 | 0 | yoff = wy - py - border; |
107 | 0 | } else if (strcmp(position, "bottom-centre") == 0 || |
108 | 0 | strcmp(position, "bottom-center") == 0) { |
109 | 0 | xoff = (wx - px) / 2; |
110 | 0 | yoff = wy - py - border; |
111 | 0 | } else if (strcmp(position, "bottom-right") == 0) { |
112 | 0 | xoff = wx - px - border; |
113 | 0 | yoff = wy - py - border; |
114 | 0 | } else if (strcmp(position, "top-left-centre") == 0 || |
115 | 0 | strcmp(position, "top-left-center") == 0) { |
116 | 0 | xoff = wx / 4 - px / 2; |
117 | 0 | yoff = wy / 4 - py / 2; |
118 | 0 | } else if (strcmp(position, "top-right-centre") == 0 || |
119 | 0 | strcmp(position, "top-right-center") == 0) { |
120 | 0 | xoff = (3 * wx) / 4 - px / 2; |
121 | 0 | yoff = wy / 4 - py / 2; |
122 | 0 | } else if (strcmp(position, "bottom-left-centre") == 0 || |
123 | 0 | strcmp(position, "bottom-left-center") == 0) { |
124 | 0 | xoff = wx / 4 - px / 2; |
125 | 0 | yoff = (3 * wy) / 4 - py / 2; |
126 | 0 | } else if (strcmp(position, "bottom-right-centre") == 0 || |
127 | 0 | strcmp(position, "bottom-right-center") == 0) { |
128 | 0 | xoff = (3 * wx) / 4 - px / 2; |
129 | 0 | yoff = (3 * wy) / 4 - py / 2; |
130 | 0 | } else if (strcmp(position, "front") == 0) { |
131 | 0 | TAILQ_REMOVE(&w->z_index, wp, zentry); |
132 | 0 | TAILQ_INSERT_HEAD(&w->z_index, wp, zentry); |
133 | 0 | } else if (strcmp(position, "back") == 0) { |
134 | 0 | TAILQ_REMOVE(&w->z_index, wp, zentry); |
135 | 0 | TAILQ_FOREACH(owp, &w->z_index, zentry) { |
136 | 0 | if (!window_pane_is_floating(owp)) |
137 | 0 | break; |
138 | 0 | } |
139 | 0 | if (owp != NULL) |
140 | 0 | TAILQ_INSERT_BEFORE(owp, wp, zentry); |
141 | 0 | else |
142 | 0 | TAILQ_INSERT_TAIL(&w->z_index, wp, zentry); |
143 | 0 | } else if (strcmp(position, "forward") == 0) { |
144 | 0 | owp = TAILQ_PREV(wp, window_panes_zindex, zentry); |
145 | 0 | if (owp != NULL) { |
146 | 0 | TAILQ_REMOVE(&w->z_index, wp, zentry); |
147 | 0 | TAILQ_INSERT_BEFORE(owp, wp, zentry); |
148 | 0 | } |
149 | 0 | } else if (strcmp(position, "backward") == 0) { |
150 | 0 | owp = TAILQ_NEXT(wp, zentry); |
151 | 0 | if (owp != NULL && window_pane_is_floating(owp)) { |
152 | 0 | TAILQ_REMOVE(&w->z_index, wp, zentry); |
153 | 0 | TAILQ_INSERT_AFTER(&w->z_index, owp, wp, zentry); |
154 | 0 | } |
155 | 0 | } else if (strcmp(position, "forward-loop") == 0) { |
156 | 0 | owp = TAILQ_PREV(wp, window_panes_zindex, zentry); |
157 | 0 | TAILQ_REMOVE(&w->z_index, wp, zentry); |
158 | 0 | if (owp != NULL) |
159 | 0 | TAILQ_INSERT_BEFORE(owp, wp, zentry); |
160 | 0 | else { |
161 | 0 | TAILQ_FOREACH(owp, &w->z_index, zentry) { |
162 | 0 | if (!window_pane_is_floating(owp)) |
163 | 0 | break; |
164 | 0 | } |
165 | 0 | if (owp != NULL) |
166 | 0 | TAILQ_INSERT_BEFORE(owp, wp, zentry); |
167 | 0 | else |
168 | 0 | TAILQ_INSERT_TAIL(&w->z_index, wp, zentry); |
169 | 0 | } |
170 | 0 | } else if (strcmp(position, "backward-loop") == 0) { |
171 | 0 | owp = TAILQ_NEXT(wp, zentry); |
172 | 0 | if (owp != NULL && window_pane_is_floating(owp)) { |
173 | 0 | TAILQ_REMOVE(&w->z_index, wp, zentry); |
174 | 0 | TAILQ_INSERT_AFTER(&w->z_index, owp, wp, zentry); |
175 | 0 | } else { |
176 | 0 | TAILQ_REMOVE(&w->z_index, wp, zentry); |
177 | 0 | TAILQ_INSERT_HEAD(&w->z_index, wp, zentry); |
178 | 0 | } |
179 | 0 | } else { |
180 | 0 | cmdq_error(item, "unknown position: %s", position); |
181 | 0 | return (CMD_RETURN_ERROR); |
182 | 0 | } |
183 | | |
184 | 0 | if (xoff != lc->g.xoff || yoff != lc->g.yoff) { |
185 | 0 | lc->g.xoff = xoff; |
186 | 0 | lc->g.yoff = yoff; |
187 | 0 | layout_fix_panes(w, NULL); |
188 | 0 | } |
189 | 0 | events_fire_window("window-layout-changed", w); |
190 | 0 | server_redraw_window(w); |
191 | |
|
192 | 0 | return (CMD_RETURN_NORMAL); |
193 | 0 | } |
194 | | |
195 | | static enum cmd_retval |
196 | | cmd_join_pane_move(struct cmdq_item *item, struct args *args, |
197 | | struct winlink *wl, struct window_pane *wp) |
198 | 0 | { |
199 | 0 | struct window *w = wl->window; |
200 | 0 | struct layout_cell *lc = wp->layout_cell; |
201 | 0 | const char *errstr, *argval; |
202 | 0 | const char flags[] = { 'U', 'D', 'L', 'R' }; |
203 | 0 | char *cause = NULL, flag; |
204 | 0 | int xoff = lc->g.xoff, yoff = lc->g.yoff, adjust; |
205 | 0 | u_int i; |
206 | 0 | enum pane_lines lines = window_pane_get_pane_lines(wp); |
207 | |
|
208 | 0 | if (args_has(args, 'X')) { |
209 | 0 | xoff = args_percentage_and_expand(args, 'X', -(int)w->sx, |
210 | 0 | w->sx, w->sx, item, &cause); |
211 | 0 | if (cause != NULL) { |
212 | 0 | cmdq_error(item, "position %s", cause); |
213 | 0 | free(cause); |
214 | 0 | return (CMD_RETURN_ERROR); |
215 | 0 | } |
216 | 0 | if (lines != PANE_LINES_NONE) |
217 | 0 | xoff += 1; |
218 | 0 | } |
219 | 0 | if (args_has(args, 'Y')) { |
220 | 0 | yoff = args_percentage_and_expand(args, 'Y', -(int)w->sy, |
221 | 0 | w->sy, w->sy, item, &cause); |
222 | 0 | if (cause != NULL) { |
223 | 0 | cmdq_error(item, "position %s", cause); |
224 | 0 | free(cause); |
225 | 0 | return (CMD_RETURN_ERROR); |
226 | 0 | } |
227 | 0 | if (lines != PANE_LINES_NONE) |
228 | 0 | yoff += 1; |
229 | 0 | } |
230 | | |
231 | 0 | for (i = 0; i < nitems(flags); i++) { |
232 | 0 | flag = flags[i]; |
233 | 0 | if (!args_has(args, flag)) |
234 | 0 | continue; |
235 | | |
236 | 0 | argval = args_get(args, flag); |
237 | 0 | if (argval == NULL) |
238 | 0 | argval = "1"; |
239 | 0 | adjust = strtonum(argval, INT_MIN, INT_MAX, &errstr); |
240 | 0 | if (errstr != NULL) { |
241 | 0 | cmdq_error(item, "offset %s", errstr); |
242 | 0 | return (CMD_RETURN_ERROR); |
243 | 0 | } |
244 | | |
245 | 0 | if (flag == 'U') |
246 | 0 | yoff -= adjust; |
247 | 0 | else if (flag == 'D') |
248 | 0 | yoff += adjust; |
249 | 0 | else if (flag == 'L') |
250 | 0 | xoff -= adjust; |
251 | 0 | else |
252 | 0 | xoff += adjust; |
253 | 0 | } |
254 | | |
255 | 0 | if (xoff != lc->g.xoff || yoff != lc->g.yoff) { |
256 | 0 | lc->g.xoff = xoff; |
257 | 0 | lc->g.yoff = yoff; |
258 | 0 | layout_fix_panes(w, NULL); |
259 | 0 | events_fire_window("window-layout-changed", w); |
260 | 0 | server_redraw_window(w); |
261 | 0 | } |
262 | |
|
263 | 0 | return (CMD_RETURN_NORMAL); |
264 | 0 | } |
265 | | |
266 | | static enum cmd_retval |
267 | | cmd_join_pane_mouse_update(struct cmdq_item *item) |
268 | 0 | { |
269 | 0 | struct cmd_find_state *target = cmdq_get_target(item); |
270 | 0 | struct key_event *event = cmdq_get_event(item); |
271 | 0 | struct client *c = cmdq_get_client(item); |
272 | 0 | struct session *s = target->s; |
273 | 0 | struct winlink *wl; |
274 | 0 | struct window *w; |
275 | 0 | struct window_pane *wp; |
276 | |
|
277 | 0 | if (!event->m.valid) |
278 | 0 | return (CMD_RETURN_NORMAL); |
279 | 0 | wp = cmd_mouse_pane(&event->m, &s, &wl); |
280 | 0 | if (wp == NULL || c == NULL || c->session != s) |
281 | 0 | return (CMD_RETURN_NORMAL); |
282 | 0 | if (!window_pane_is_floating(wp)) |
283 | 0 | return (CMD_RETURN_NORMAL); |
284 | | |
285 | 0 | w = wl->window; |
286 | 0 | window_redraw_active_switch(w, wp); |
287 | 0 | window_set_active_pane(w, wp, 1); |
288 | |
|
289 | 0 | c->tty.mouse_drag_update = cmd_join_pane_mouse_move; |
290 | 0 | cmd_join_pane_mouse_move(c, &event->m); |
291 | 0 | return (CMD_RETURN_NORMAL); |
292 | 0 | } |
293 | | |
294 | | static void |
295 | | cmd_join_pane_mouse_move(struct client *c, struct mouse_event *m) |
296 | 0 | { |
297 | 0 | struct winlink *wl; |
298 | 0 | struct window *w; |
299 | 0 | struct window_pane *wp; |
300 | 0 | struct layout_cell *lc; |
301 | 0 | int y, ly, x, lx; |
302 | |
|
303 | 0 | wp = cmd_mouse_pane(m, NULL, &wl); |
304 | 0 | if (wp == NULL) { |
305 | 0 | c->tty.mouse_drag_update = NULL; |
306 | 0 | return; |
307 | 0 | } |
308 | 0 | w = wl->window; |
309 | 0 | lc = wp->layout_cell; |
310 | |
|
311 | 0 | y = m->y + m->oy; x = m->x + m->ox; |
312 | 0 | if (m->statusat == 0 && y >= (int)m->statuslines) |
313 | 0 | y -= m->statuslines; |
314 | 0 | else if (m->statusat > 0 && y >= m->statusat) |
315 | 0 | y = m->statusat - 1; |
316 | 0 | ly = m->ly + m->oy; lx = m->lx + m->ox; |
317 | 0 | if (m->statusat == 0 && ly >= (int)m->statuslines) |
318 | 0 | ly -= m->statuslines; |
319 | 0 | else if (m->statusat > 0 && ly >= m->statusat) |
320 | 0 | ly = m->statusat - 1; |
321 | |
|
322 | 0 | if (x != lx || y != ly) { |
323 | 0 | lc->g.xoff += x - lx; |
324 | 0 | lc->g.yoff += y - ly; |
325 | 0 | layout_fix_panes(w, NULL); |
326 | 0 | server_redraw_window(w); |
327 | 0 | server_redraw_window_borders(w); |
328 | 0 | } |
329 | 0 | } |
330 | | |
331 | | static enum cmd_retval |
332 | | cmd_join_pane_zindex(struct cmdq_item *item, struct winlink *wl, |
333 | | struct window_pane *wp, const char *s) |
334 | 0 | { |
335 | 0 | struct window *w = wl->window; |
336 | 0 | struct window_pane *owp; |
337 | 0 | const char *errstr; |
338 | 0 | u_int n, z; |
339 | |
|
340 | 0 | z = strtonum(s, 0, UINT_MAX, &errstr); |
341 | 0 | if (errstr != NULL) { |
342 | 0 | cmdq_error(item, "z-index %s", errstr); |
343 | 0 | return (CMD_RETURN_ERROR); |
344 | 0 | } |
345 | 0 | TAILQ_REMOVE(&w->z_index, wp, zentry); |
346 | |
|
347 | 0 | n = 0; |
348 | 0 | TAILQ_FOREACH(owp, &w->z_index, zentry) { |
349 | 0 | if (!window_pane_is_floating(owp)) |
350 | 0 | break; |
351 | 0 | if (n >= z) |
352 | 0 | break; |
353 | 0 | n++; |
354 | 0 | } |
355 | |
|
356 | 0 | if (owp != NULL) |
357 | 0 | TAILQ_INSERT_BEFORE(owp, wp, zentry); |
358 | 0 | else |
359 | 0 | TAILQ_INSERT_TAIL(&w->z_index, wp, zentry); |
360 | |
|
361 | 0 | events_fire_window("window-layout-changed", w); |
362 | 0 | server_redraw_window(w); |
363 | |
|
364 | 0 | return (CMD_RETURN_NORMAL); |
365 | 0 | } |
366 | | |
367 | | static enum cmd_retval |
368 | | cmd_join_pane_tile(struct cmdq_item *item, struct args *args, struct window *w, |
369 | | struct window_pane *wp) |
370 | 0 | { |
371 | 0 | struct layout_cell *lc = wp->layout_cell; |
372 | |
|
373 | 0 | if (!window_pane_is_floating(wp)) { |
374 | 0 | cmdq_error(item, "pane is not floating"); |
375 | 0 | return (CMD_RETURN_ERROR); |
376 | 0 | } |
377 | 0 | if (w->flags & WINDOW_ZOOMED) { |
378 | 0 | cmdq_error(item, "can't tile a pane while window is zoomed"); |
379 | 0 | return (CMD_RETURN_ERROR); |
380 | 0 | } |
381 | | |
382 | 0 | lc->fg.sx = lc->g.sx; |
383 | 0 | lc->fg.sy = lc->g.sy; |
384 | 0 | lc->fg.xoff = lc->g.xoff; |
385 | 0 | lc->fg.yoff = lc->g.yoff; |
386 | |
|
387 | 0 | if (layout_insert_tile(w, lc) != 0) { |
388 | 0 | cmdq_error(item, "no space for a new pane"); |
389 | 0 | return (CMD_RETURN_ERROR); |
390 | 0 | } |
391 | 0 | lc->flags &= ~LAYOUT_CELL_FLOATING; |
392 | |
|
393 | 0 | TAILQ_REMOVE(&w->z_index, wp, zentry); |
394 | 0 | TAILQ_INSERT_TAIL(&w->z_index, wp, zentry); |
395 | |
|
396 | 0 | if (!args_has(args, 'd')) |
397 | 0 | window_set_active_pane(w, wp, 1); |
398 | 0 | layout_fix_offsets(w); |
399 | 0 | layout_fix_panes(w, NULL); |
400 | 0 | events_fire_window("window-layout-changed", w); |
401 | 0 | server_redraw_window(w); |
402 | |
|
403 | 0 | return (CMD_RETURN_NORMAL); |
404 | 0 | } |
405 | | |
406 | | static enum cmd_retval |
407 | | cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) |
408 | 0 | { |
409 | 0 | struct args *args = cmd_get_args(self); |
410 | 0 | struct cmd_find_state *current = cmdq_get_current(item); |
411 | 0 | struct cmd_find_state *target = cmdq_get_target(item); |
412 | 0 | struct cmd_find_state *source = cmdq_get_source(item); |
413 | 0 | struct session *dst_s; |
414 | 0 | struct winlink *src_wl, *dst_wl; |
415 | 0 | struct window *src_w, *dst_w; |
416 | 0 | struct window_pane *src_wp, *dst_wp; |
417 | 0 | const char *s; |
418 | 0 | char *cause = NULL; |
419 | 0 | int flags = 0, dst_idx; |
420 | 0 | struct layout_cell *lc; |
421 | |
|
422 | 0 | dst_s = target->s; |
423 | 0 | dst_wl = target->wl; |
424 | 0 | dst_wp = target->wp; |
425 | 0 | dst_w = dst_wl->window; |
426 | 0 | dst_idx = dst_wl->idx; |
427 | |
|
428 | 0 | if (cmd_get_entry(self) == &cmd_move_pane_entry) { |
429 | 0 | if (args_has(args, 'M')) |
430 | 0 | return (cmd_join_pane_mouse_update(item)); |
431 | 0 | if (!window_pane_is_floating(dst_wp)) { |
432 | 0 | cmdq_error(item, "pane is not floating"); |
433 | 0 | return (CMD_RETURN_ERROR); |
434 | 0 | } |
435 | 0 | if ((s = args_get(args, 'P')) != NULL) { |
436 | 0 | server_unzoom_window(dst_w); |
437 | 0 | return (cmd_join_pane_place(item, dst_wl, dst_wp, s)); |
438 | 0 | } |
439 | 0 | if ((s = args_get(args, 'z')) != NULL) { |
440 | 0 | server_unzoom_window(dst_w); |
441 | 0 | return (cmd_join_pane_zindex(item, dst_wl, dst_wp, s)); |
442 | 0 | } |
443 | 0 | if (args_has(args, 'X') || |
444 | 0 | args_has(args, 'Y') || |
445 | 0 | args_has(args, 'U') || |
446 | 0 | args_has(args, 'D') || |
447 | 0 | args_has(args, 'L') || |
448 | 0 | args_has(args, 'R')) { |
449 | 0 | server_unzoom_window(dst_w); |
450 | 0 | return (cmd_join_pane_move(item, args, dst_wl, dst_wp)); |
451 | 0 | } |
452 | 0 | } |
453 | | |
454 | 0 | src_wl = source->wl; |
455 | 0 | src_wp = source->wp; |
456 | 0 | src_w = src_wl->window; |
457 | |
|
458 | 0 | if (src_wp == src_w->modal || dst_wp == dst_w->modal) { |
459 | 0 | cmdq_error(item, "pane is modal"); |
460 | 0 | return (CMD_RETURN_ERROR); |
461 | 0 | } |
462 | | |
463 | 0 | server_unzoom_window(dst_w); |
464 | 0 | server_unzoom_window(src_w); |
465 | |
|
466 | 0 | if (src_wp == dst_wp) { |
467 | 0 | if (window_pane_is_floating(src_wp)) |
468 | 0 | return (cmd_join_pane_tile(item, args, src_w, src_wp)); |
469 | 0 | cmdq_error(item, "source and target panes must be different"); |
470 | 0 | return (CMD_RETURN_ERROR); |
471 | 0 | } |
472 | | |
473 | 0 | if (args_has(args, 'h')) |
474 | 0 | flags |= SPAWN_HORIZONTAL; |
475 | 0 | if (args_has(args, 'b')) |
476 | 0 | flags |= SPAWN_BEFORE; |
477 | 0 | if (args_has(args, 'f')) |
478 | 0 | flags |= SPAWN_FULLSIZE; |
479 | |
|
480 | 0 | lc = layout_get_tiled_cell(item, args, dst_w, dst_wp, flags, &cause); |
481 | 0 | if (cause != NULL) { |
482 | 0 | cmdq_error(item, "size or position %s", cause); |
483 | 0 | free(cause); |
484 | 0 | return (CMD_RETURN_ERROR); |
485 | 0 | } |
486 | | |
487 | 0 | layout_close_pane(src_wp); |
488 | |
|
489 | 0 | server_client_remove_pane(src_wp); |
490 | 0 | window_lost_pane(src_w, src_wp); |
491 | 0 | TAILQ_REMOVE(&src_w->panes, src_wp, entry); |
492 | 0 | TAILQ_REMOVE(&src_w->z_index, src_wp, zentry); |
493 | |
|
494 | 0 | src_wp->window = dst_w; |
495 | 0 | options_set_parent(src_wp->options, dst_w->options); |
496 | 0 | src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED); |
497 | 0 | if (flags & SPAWN_BEFORE) { |
498 | 0 | TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry); |
499 | 0 | TAILQ_INSERT_BEFORE(dst_wp, src_wp, zentry); |
500 | 0 | } else { |
501 | 0 | TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry); |
502 | 0 | TAILQ_INSERT_AFTER(&dst_w->z_index, dst_wp, src_wp, zentry); |
503 | 0 | } |
504 | 0 | layout_assign_pane(lc, src_wp, 0); |
505 | 0 | colour_palette_from_option(&src_wp->palette, src_wp->options); |
506 | |
|
507 | 0 | recalculate_sizes(); |
508 | |
|
509 | 0 | server_redraw_window(src_w); |
510 | 0 | server_redraw_window(dst_w); |
511 | |
|
512 | 0 | if (!args_has(args, 'd')) { |
513 | 0 | window_set_active_pane(dst_w, src_wp, 1); |
514 | 0 | session_select(dst_s, dst_idx); |
515 | 0 | cmd_find_from_session(current, dst_s, 0); |
516 | 0 | server_redraw_session(dst_s); |
517 | 0 | } else |
518 | 0 | server_status_session(dst_s); |
519 | |
|
520 | 0 | window_fire_pane_moved(src_wp, src_w, src_wl->idx, dst_w, dst_idx); |
521 | 0 | if (window_count_panes(src_w, 1) == 0) |
522 | 0 | server_kill_window(src_w, 1); |
523 | 0 | else |
524 | 0 | events_fire_window("window-layout-changed", src_w); |
525 | 0 | events_fire_window("window-layout-changed", dst_w); |
526 | |
|
527 | 0 | return (CMD_RETURN_NORMAL); |
528 | 0 | } |