From fa2c9f45513b11e9b3e3b5ca98fff915e303b170 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 3 Jul 2026 10:47:32 +0000 Subject: [PATCH] Allow join-pane to tile floating panes, from Dane Jensen. --- cmd-join-pane.c | 40 ++++++++++++++++++++++++++++++++++++++++ layout.c | 16 ++++++++-------- tmux.1 | 9 +++++++++ 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 6cb37d7eb..9e67f1187 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -364,6 +364,44 @@ cmd_join_pane_zindex(struct cmdq_item *item, struct winlink *wl, return (CMD_RETURN_NORMAL); } +static enum cmd_retval +cmd_join_pane_tile(struct cmdq_item *item, struct args *args, struct window *w, + struct window_pane *wp) +{ + struct layout_cell *lc = wp->layout_cell; + + if (!window_pane_is_floating(wp)) { + cmdq_error(item, "pane is not floating"); + return (CMD_RETURN_ERROR); + } + if (w->flags & WINDOW_ZOOMED) { + cmdq_error(item, "can't tile a pane while window is zoomed"); + return (CMD_RETURN_ERROR); + } + + lc->saved_sx = lc->sx; + lc->saved_sy = lc->sy; + lc->saved_xoff = lc->xoff; + lc->saved_yoff = lc->yoff; + if (layout_insert_tile(w, lc) != 0) { + cmdq_error(item, "no space for a new pane"); + return (CMD_RETURN_ERROR); + } + lc->flags &= ~LAYOUT_CELL_FLOATING; + + TAILQ_REMOVE(&w->z_index, wp, zentry); + TAILQ_INSERT_TAIL(&w->z_index, wp, zentry); + + if (!args_has(args, 'd')) + window_set_active_pane(w, wp, 1); + layout_fix_offsets(w); + layout_fix_panes(w, NULL); + notify_window("window-layout-changed", w); + server_redraw_window(w); + + return (CMD_RETURN_NORMAL); +} + static enum cmd_retval cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) { @@ -413,6 +451,8 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) server_unzoom_window(src_w); if (src_wp == dst_wp) { + if (window_pane_is_floating(src_wp)) + return (cmd_join_pane_tile(item, args, src_w, src_wp)); cmdq_error(item, "source and target panes must be different"); return (CMD_RETURN_ERROR); } diff --git a/layout.c b/layout.c index 2a605d6cc..11c292bba 100644 --- a/layout.c +++ b/layout.c @@ -1774,7 +1774,7 @@ layout_remove_tile(struct window *w, struct layout_cell *lc) int change; if (lc->flags & LAYOUT_CELL_FLOATING) - return (0); + return (-1); lcneighbour = layout_cell_get_neighbour(lc); if (lcneighbour == NULL) { @@ -1799,7 +1799,7 @@ layout_remove_tile(struct window *w, struct layout_cell *lc) */ if (lc->parent != NULL) layout_set_size(lc, 0, 0, 0, 0); - return (1); + return (0); } /* @@ -1816,14 +1816,14 @@ layout_insert_tile(struct window *w, struct layout_cell *lc) if (lc == NULL) fatalx("layout cell cannot be null when tiling"); - lcparent = lc->parent; - if (lc->flags & LAYOUT_CELL_FLOATING) - return (1); + if (layout_cell_is_tiled(lc)) + return (-1); + lcparent = lc->parent; if (lcparent == NULL) { /* Only pane in the layout. */ layout_set_size(lc, w->sx, w->sy, 0, 0); - return (1); + return (0); } type = lcparent->type; @@ -1846,7 +1846,7 @@ layout_insert_tile(struct window *w, struct layout_cell *lc) */ lctiled = layout_cell_get_first_tiled(lcneighbour); if (!layout_split_check_space(lctiled->wp, lcneighbour, type)) - return (0); + return (-1); layout_split_sizes(lcneighbour, -1, 0, type, &size1, &size2, &saved_size); layout_resize_set_size(w, lc, type, size1); @@ -1863,5 +1863,5 @@ layout_insert_tile(struct window *w, struct layout_cell *lc) } layout_resize_set_size(w, lc, type, size1); - return (1); + return (0); } diff --git a/tmux.1 b/tmux.1 index 9e891ac23..6061fe9a0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3247,6 +3247,15 @@ is omitted and a marked pane is present (see .Ic select\-pane .Fl m ) , the marked pane is used rather than the current pane. +.Pp +If +.Ar src\-pane +is floating and +.Ar dst\-pane +is either unspecified or equal to +.Ar src\-pane, +.Ar src\-pane +is returned to its previous position in the layout. .Tg killp .It Xo Ic kill\-pane .Op Fl a