From 64ded18960f9baf546110c0ae6a7035fe8080b64 Mon Sep 17 00:00:00 2001 From: Dane Jensen Date: Tue, 9 Jun 2026 18:31:13 -0700 Subject: [PATCH] Updating tile-pane and float-pane to use new layout mechanics. --- cmd-tile-float-pane.c | 278 +++++----------------------------- layout.c | 339 ++++++++++++++++++++++++++++++++---------- tmux.1 | 63 ++++---- tmux.h | 23 ++- window.c | 10 ++ 5 files changed, 358 insertions(+), 355 deletions(-) diff --git a/cmd-tile-float-pane.c b/cmd-tile-float-pane.c index 19dfa4fc..1c33a148 100644 --- a/cmd-tile-float-pane.c +++ b/cmd-tile-float-pane.c @@ -38,10 +38,10 @@ static enum cmd_retval cmd_tile_pane_exec(struct cmd *, struct cmdq_item *); const struct cmd_entry cmd_float_pane_entry = { .name = "float-pane", - .alias = NULL, + .alias = "floatp", - .args = { "t:x:y:w:h:", 0, 0, NULL }, - .usage = "[-h height] [-w width] [-x x] [-y y] " + .args = { "dt:x:X:y:Y:", 0, 0, NULL }, + .usage = "[-x height] [-y width] [-X x-position] [-Y y-position] " CMD_TARGET_PANE_USAGE, .target = { 't', CMD_FIND_PANE, 0 }, @@ -52,9 +52,9 @@ const struct cmd_entry cmd_float_pane_entry = { const struct cmd_entry cmd_tile_pane_entry = { .name = "tile-pane", - .alias = NULL, + .alias = "tilep", - .args = { "t:", 0, 0, NULL }, + .args = { "dt:", 0, 0, NULL }, .usage = CMD_TARGET_PANE_USAGE, .target = { 't', CMD_FIND_PANE, 0 }, @@ -63,90 +63,6 @@ const struct cmd_entry cmd_tile_pane_entry = { .exec = cmd_tile_pane_exec }; -/* - * Parse geometry arguments for float-pane. - * Returns 0 on success, -1 on error (error message already set on item). - * x/y/sx/sy are set to parsed values or cascade defaults. - * last_x/last_y are the static cascade counters; pass the address of the - * caller's statics. - */ -static int -cmd_float_pane_parse_geometry(struct args *args, struct cmdq_item *item, - struct window *w, int *out_x, int *out_y, u_int *out_sx, u_int *out_sy, - int *last_x, int *last_y) -{ - char *cause = NULL; - int x, y; - u_int sx, sy; - - /* Default size: half the window. */ - sx = w->sx / 2; - sy = w->sy / 2; - - if (args_has(args, 'w')) { - sx = args_strtonum_and_expand(args, 'w', 1, USHRT_MAX, item, - &cause); - if (cause != NULL) { - cmdq_error(item, "width %s", cause); - free(cause); - return (-1); - } - } - if (args_has(args, 'h')) { - sy = args_strtonum_and_expand(args, 'h', 1, USHRT_MAX, item, - &cause); - if (cause != NULL) { - cmdq_error(item, "height %s", cause); - free(cause); - return (-1); - } - } - - /* Default position: cascade from (5,5), step +5, wrap at window edge. */ - if (args_has(args, 'x')) { - x = args_strtonum_and_expand(args, 'x', SHRT_MIN, SHRT_MAX, - item, &cause); - if (cause != NULL) { - cmdq_error(item, "x %s", cause); - free(cause); - return (-1); - } - } else { - if (*last_x == 0) { - x = 5; - } else { - x = (*last_x += 5); - if (*last_x > (int)w->sx) - x = *last_x = 5; - } - } - if (args_has(args, 'y')) { - y = args_strtonum_and_expand(args, 'y', SHRT_MIN, SHRT_MAX, - item, &cause); - if (cause != NULL) { - cmdq_error(item, "y %s", cause); - free(cause); - return (-1); - } - } else { - if (*last_y == 0) { - y = 5; - } else { - y = (*last_y += 5); - if (*last_y > (int)w->sy) - y = *last_y = 5; - } - } - - *last_x = x; - *last_y = y; - *out_x = x; - *out_y = y; - *out_sx = sx; - *out_sy = sy; - return (0); -} - static enum cmd_retval cmd_float_pane_exec(struct cmd *self, struct cmdq_item *item) { @@ -154,16 +70,16 @@ cmd_float_pane_exec(struct cmd *self, struct cmdq_item *item) struct cmd_find_state *target = cmdq_get_target(item); struct window *w = target->wl->window; struct window_pane *wp = target->wp; - static int last_x = 0, last_y = 0; - int x, y; - u_int sx, sy; - struct layout_cell *lc; + struct layout_cell *lc = wp->layout_cell; + u_int sx = lc->saved_sx, sy = lc->saved_sy; + int ox = lc->saved_xoff, oy = lc->saved_yoff; + char *cause = NULL; if (window_pane_is_floating(wp)) { cmdq_error(item, "pane is already floating"); return (CMD_RETURN_ERROR); } - if (wp->flags & PANE_HIDDEN) { + if (window_pane_is_hidden(wp)) { cmdq_error(item, "can't float a hidden pane"); return (CMD_RETURN_ERROR); } @@ -172,47 +88,22 @@ cmd_float_pane_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_ERROR); } - /* - * If no geometry was given explicitly and we have a saved floating - * position from a previous tile-pane, restore it. - */ - if ((wp->flags & PANE_SAVED_FLOAT) && - !args_has(args, 'x') && !args_has(args, 'y') && - !args_has(args, 'w') && !args_has(args, 'h')) { - x = wp->saved_float_xoff; - y = wp->saved_float_yoff; - sx = wp->saved_float_sx; - sy = wp->saved_float_sy; - } else { - if (cmd_float_pane_parse_geometry(args, item, w, &x, &y, &sx, - &sy, &last_x, &last_y) != 0) - return (CMD_RETURN_ERROR); + layout_cell_remove_tile(w, lc); + layout_cell_floating_args(item, args, w, &sx, &sy, &ox, &oy, &cause); + if (cause != NULL) { + cmdq_error(item, "failed to float pane: %s", cause); + free(cause); + return (CMD_RETURN_ERROR); } - - /* - * Remove the pane from the tiled layout tree so neighbours reclaim - * the space. layout_close_pane calls layout_destroy_cell which frees - * the tiled layout_cell and sets wp->layout_cell = NULL via - * layout_free_cell. It also calls layout_fix_offsets/fix_panes and - * notify_window, which is fine to do here before we set up the - * floating cell. - */ - layout_close_pane(wp); /* wp->layout_cell is NULL afterwards */ - - /* Create a detached floating cell with the requested geometry. */ - lc = layout_create_cell(NULL); - lc->xoff = x; - lc->yoff = y; - lc->sx = sx; - lc->sy = sy; - layout_make_leaf(lc, wp); /* sets wp->layout_cell = lc, lc->wp = wp */ + layout_set_size(lc, sx, sy, ox, oy); lc->flags |= LAYOUT_CELL_FLOATING; TAILQ_REMOVE(&w->z_index, wp, zentry); TAILQ_INSERT_HEAD(&w->z_index, wp, zentry); - if (w->layout_root != NULL) - layout_fix_offsets(w); + 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); @@ -223,138 +114,37 @@ cmd_float_pane_exec(struct cmd *self, struct cmdq_item *item) static enum cmd_retval cmd_tile_pane_exec(struct cmd *self, struct cmdq_item *item) { - __attribute((unused)) struct args *args = cmd_get_args(self); - struct cmd_find_state *target = cmdq_get_target(item); - struct window *w = target->wl->window; - struct window_pane *wp = target->wp; - struct window_pane *target_wp, *wpiter; - struct layout_cell *float_lc, *lc; - int was_hidden; + __unused struct args *args = cmd_get_args(self); + struct cmd_find_state *target = cmdq_get_target(item); + struct window *w = target->wl->window; + struct window_pane *wp = target->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 (window_pane_is_hidden(wp)) { + cmdq_error(item, "can't tile a hidden pane"); + 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); } - was_hidden = (wp->flags & PANE_HIDDEN) != 0; + layout_save_size(lc); + if (layout_cell_insert_tile(w, lc) == 0) + return (CMD_RETURN_ERROR); - /* - * Save the floating geometry so we can restore it next time this pane - * is floated without an explicit position/size. - */ - float_lc = wp->layout_cell; - wp->saved_float_xoff = float_lc->xoff; - wp->saved_float_yoff = float_lc->yoff; - wp->saved_float_sx = float_lc->sx; - wp->saved_float_sy = float_lc->sy; - wp->flags |= PANE_SAVED_FLOAT; - - /* - * If the pane is also hidden, clear saved_layout_cell before - * freeing the floating cell — otherwise the pointer would dangle. - */ - if (was_hidden) - wp->saved_layout_cell = NULL; - - /* - * Free the detached floating cell. Clear its wp pointer first so - * layout_free_cell's WINDOWPANE case does not corrupt wp->layout_cell. - */ - float_lc->wp = NULL; - layout_free_cell(float_lc); - wp->layout_cell = NULL; - - /* - * Find the best tiled pane to split after, prefer a visible (non- - * hidden) tiled pane. If all tiled panes are hidden, fall back - * to any tiled pane so the new pane enters the existing tree rather - * than becoming a disconnected root. - */ - target_wp = NULL; - if (w->active != NULL && !window_pane_is_floating(w->active) && - !(w->active->flags & PANE_HIDDEN)) - target_wp = w->active; - if (target_wp == NULL) { - TAILQ_FOREACH(wpiter, &w->last_panes, sentry) { - if (!(wpiter->flags & PANE_HIDDEN) && - !window_pane_is_floating(wpiter) && - window_pane_visible(wpiter)) { - target_wp = wpiter; - break; - } - } - } - if (target_wp == NULL) { - TAILQ_FOREACH(wpiter, &w->panes, entry) { - if (!(wpiter->flags & PANE_HIDDEN) && - !window_pane_is_floating(wpiter) && - window_pane_visible(wpiter)) { - target_wp = wpiter; - break; - } - } - } - /* Fall back to any tiled pane (even hidden) to stay in the tree. */ - if (target_wp == NULL) { - TAILQ_FOREACH(wpiter, &w->panes, entry) { - if (!window_pane_is_floating(wpiter)) { - target_wp = wpiter; - break; - } - } - } - if (target_wp != NULL) { - lc = layout_split_pane(target_wp, LAYOUT_TOPBOTTOM, -1, 0); - if (lc == NULL) - lc = layout_split_pane(target_wp, LAYOUT_LEFTRIGHT, - -1, 0); - if (lc == NULL) { - cmdq_error(item, "not enough space to tile pane"); - return (CMD_RETURN_ERROR); - } - layout_assign_pane(lc, wp, 0); - /* - * Redistribute space equally among all visible panes at this - * level, so the new pane gets an equal share rather than just - * half of the split target. - */ - if (wp->layout_cell != NULL && wp->layout_cell->parent != NULL) - layout_redistribute_cells(w, wp->layout_cell->parent, - wp->layout_cell->parent->type); - } else { - /* - * No tiled panes at all: make this pane the sole tiled pane - * (new layout root). - */ - lc = layout_create_cell(NULL); - lc->sx = w->sx; - lc->sy = w->sy; - lc->xoff = 0; - lc->yoff = 0; - w->layout_root = lc; - layout_make_leaf(lc, wp); - } - - /* - * If the pane was hidden while floating, record its new tiled cell - * as the saved cell so 'show' can restore it correctly. - */ - if (was_hidden) - wp->saved_layout_cell = wp->layout_cell; lc->flags &= ~LAYOUT_CELL_FLOATING; TAILQ_REMOVE(&w->z_index, wp, zentry); TAILQ_INSERT_TAIL(&w->z_index, wp, zentry); - if (!(wp->flags & PANE_HIDDEN)) + if (!args_has(args, 'd')) window_set_active_pane(w, wp, 1); - - if (w->layout_root != NULL) - layout_fix_offsets(w); + layout_fix_offsets(w); layout_fix_panes(w, NULL); notify_window("window-layout-changed", w); server_redraw_window(w); diff --git a/layout.c b/layout.c index d6935c42..e36f7e7a 100644 --- a/layout.c +++ b/layout.c @@ -66,6 +66,12 @@ layout_create_cell(struct layout_cell *lcparent) lc->xoff = INT_MAX; lc->yoff = INT_MAX; + lc->saved_sx = UINT_MAX; + lc->saved_sy = UINT_MAX; + + lc->saved_xoff = INT_MAX; + lc->saved_yoff = INT_MAX; + lc->wp = NULL; return (lc); @@ -190,6 +196,16 @@ layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, int xoff, int yoff) lc->yoff = yoff; } +void +layout_save_size(struct layout_cell *lc) +{ + lc->saved_sx = lc->sx; + lc->saved_sy = lc->sy; + + lc->saved_xoff = lc->xoff; + lc->saved_yoff = lc->yoff; +} + /* Make a cell a leaf cell. */ void layout_make_leaf(struct layout_cell *lc, struct window_pane *wp) @@ -290,13 +306,33 @@ layout_fix_offsets(struct window *w) /* * Not all cells are drawn within the tiled grid of a layout. This predicate - * isolates that logic. + * isolates that logic. Nodes are considered tiled. */ int layout_cell_is_tiled(struct layout_cell *lc) { - return ((~lc->flags & LAYOUT_CELL_HIDDEN) && - (~lc->flags & LAYOUT_CELL_FLOATING)); + int is_node, is_floating, is_hidden; + + is_node = lc->type != LAYOUT_WINDOWPANE; + is_floating = lc->flags & LAYOUT_CELL_FLOATING; + is_hidden = lc->flags & LAYOUT_CELL_HIDDEN; + + return is_node || (!is_floating && !is_hidden); +} + +static int +layout_cell_has_tiled_child(struct layout_cell *lc) +{ + struct layout_cell *lcchild; + + if (lc == NULL || lc->type == LAYOUT_WINDOWPANE) + return (0); + + TAILQ_FOREACH(lcchild, &lc->cells, entry) { + if (layout_cell_is_tiled(lcchild)) + return (1); + } + return (0); } static int @@ -532,6 +568,12 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc, return; } + /* + * If a container doesn't have any tiled cells, there is nothing to do. + */ + if (!layout_cell_has_tiled_child(lc)) + return; + /* * Child cell runs in the same direction. Adjust each child equally * until no further change is possible. @@ -555,6 +597,20 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc, } } +/* Resizes a cell to a specified size */ +void +layout_resize_set(struct window *w, struct layout_cell *lc, + enum layout_type type, u_int size) +{ + int change; + + if (type == LAYOUT_LEFTRIGHT) + change = size - lc->sx; + else + change = size - lc->sy; + layout_resize_adjust(w, lc, type, change); +} + /* * Redistribute space equally among all visible (non-hidden WINDOWPANE) * children of lcparent in the given direction. Hidden WINDOWPANE leaves @@ -1238,6 +1294,73 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc) } } +/* Checks if there is enough space for two new panes. */ +int +layout_split_check_space(struct window_pane *wp, struct layout_cell *lc, + enum layout_type type) +{ + struct style *sb_style = &wp->scrollbar_style; + u_int minimum, sx = lc->sx, sy = lc->sy; + int scrollbars, status; + + status = options_get_number(wp->window->options, "pane-border-status"); + scrollbars = options_get_number(wp->window->options, "pane-scrollbars"); + + switch (type) { + case LAYOUT_LEFTRIGHT: + if (scrollbars) { + minimum = PANE_MINIMUM * 2 + sb_style->width + + sb_style->pad; + } else + minimum = PANE_MINIMUM * 2 + 1; + if (sx < minimum) + return (0); + break; + case LAYOUT_TOPBOTTOM: + if (layout_add_horizontal_border(wp->window, lc, status)) + minimum = PANE_MINIMUM * 2 + 2; + else + minimum = PANE_MINIMUM * 2 + 1; + if (sy < minimum) + return (0); + break; + default: + fatalx("bad layout type"); + } + + return (1); +} + +/* Calculates the new cell sizes when splitting a pane. */ +void +layout_split_sizes(struct layout_cell *lc, int size, int flags, + enum layout_type type, u_int *size1, u_int *size2, u_int *saved_size) +{ + u_int s1, s2, ss; + u_int sx = lc->sx, sy = lc->sy; + + if (type == LAYOUT_LEFTRIGHT) + ss = sx; + else + ss = sy; + if (size < 0) + s2 = ((ss + 1) / 2) - 1; + else if (flags & SPAWN_BEFORE) + s2 = ss - size - 1; + else + s2 = size; + if (s2 < PANE_MINIMUM) + s2 = PANE_MINIMUM; + else if (s2 > sx - 2) + s2 = ss - 2; + s1 = ss - 1 - s2; + + *size1 = s1; + *size2 = s2; + *saved_size = ss; +} + + /* * Split a pane into two. size is a hint, or -1 for default half/half * split. This must be followed by layout_assign_pane before much else happens! @@ -1247,11 +1370,9 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size, int flags) { struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2; - struct style *sb_style = &wp->scrollbar_style; - u_int sx, sy, xoff, yoff, size1, size2, minimum; + u_int sx, sy, xoff, yoff, size1, size2; u_int new_size, saved_size, resize_first = 0; - int full_size = (flags & SPAWN_FULLSIZE), status; - int scrollbars; + int full_size = (flags & SPAWN_FULLSIZE); /* * If full_size is specified, add a new cell at the top of the window @@ -1261,8 +1382,6 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size, lc = wp->window->layout_root; else lc = wp->layout_cell; - status = window_get_pane_status(wp->window); - scrollbars = options_get_number(wp->window->options, "pane-scrollbars"); /* Copy the old cell size. */ sx = lc->sx; @@ -1271,47 +1390,14 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size, yoff = lc->yoff; /* Check there is enough space for the two new panes. */ - switch (type) { - case LAYOUT_LEFTRIGHT: - if (scrollbars) { - minimum = PANE_MINIMUM * 2 + sb_style->width + - sb_style->pad; - } else - minimum = PANE_MINIMUM * 2 + 1; - if (sx < minimum) - return (NULL); - break; - case LAYOUT_TOPBOTTOM: - if (layout_add_horizontal_border(wp->window, lc, status)) - minimum = PANE_MINIMUM * 2 + 2; - else - minimum = PANE_MINIMUM * 2 + 1; - if (sy < minimum) - return (NULL); - break; - default: - fatalx("bad layout type"); - } + if (!layout_split_check_space(wp, lc, type)) + return (NULL); /* * Calculate new cell sizes. size is the target size or -1 for middle * split, size1 is the size of the top/left and size2 the bottom/right. */ - if (type == LAYOUT_LEFTRIGHT) - saved_size = sx; - else - saved_size = sy; - if (size < 0) - size2 = ((saved_size + 1) / 2) - 1; - else if (flags & SPAWN_BEFORE) - size2 = saved_size - size - 1; - else - size2 = size; - if (size2 < PANE_MINIMUM) - size2 = PANE_MINIMUM; - else if (size2 > saved_size - 2) - size2 = saved_size - 2; - size1 = saved_size - 1 - size2; + layout_split_sizes(lc, size, flags, type, &size1, &size2, &saved_size); /* Which size are we using? */ if (flags & SPAWN_BEFORE) @@ -1619,51 +1705,41 @@ layout_get_tiled_cell(struct cmdq_item *item, struct args *args, return (lc); } -/* Get a new floating cell. */ -struct layout_cell * -layout_get_floating_cell(struct cmdq_item *item, struct args *args, - struct window *w, struct window_pane *wp, char **cause) +void +layout_cell_floating_args(struct cmdq_item *item, struct args *args, + struct window *w, u_int *sxp, u_int *syp, int *oxp, int *oyp, char **cause) { - struct layout_cell *lcnew; - u_int sx = w->sx / 2, sy = w->sy / 4; - int ox = INT_MAX, oy = INT_MAX; - char *error; + int sx, sy, ox, oy; + + sx = *sxp == UINT_MAX ? w->sx / 2 : *sxp; + sy = *syp == UINT_MAX ? w->sy / 4 : *syp; + ox = *oxp == INT_MAX ? INT_MAX : *oxp; + oy = *oyp == INT_MAX ? INT_MAX : *oyp; if (args_has(args, 'x')) { sx = args_percentage_and_expand(args, 'x', 0, w->sx - 1, w->sx, - item, &error); - if (error != NULL) { - xasprintf(cause, "position %s", error); - free(error); - return (NULL); - } + item, cause); + if (*cause != NULL) + return; } if (args_has(args, 'y')) { sy = args_percentage_and_expand(args, 'y', 0, w->sy - 1, w->sy, - item, &error); - if (error != NULL) { - xasprintf(cause, "position %s", error); - free(error); - return (NULL); - } + item, cause); + if (*cause != NULL) + return; } if (args_has(args, 'X')) { - ox = args_percentage_and_expand(args, 'X', -sx, w->sx, - w->sx, item, &error); - if (error != NULL) { - xasprintf(cause, "size %s", error); - free(error); - return (NULL); - } + ox = args_percentage_and_expand(args, 'X', -(int)w->sx, w->sx, + w->sx, item, cause); + if (*cause != NULL) + return; } if (args_has(args, 'Y')) { - oy = args_percentage_and_expand(args, 'Y', -sy, w->sy, - w->sy, item, &error); - if (error != NULL) { - xasprintf(cause, "size %s", error); - free(error); - return (NULL); - } + oy = args_percentage_and_expand(args, 'Y', -(int)w->sy, w->sy, + w->sy, item, cause); + if (*cause != NULL) + return; +>>>>>>> 5d81c9e4 (Updating tile-pane and float-pane to use new layout mechanics.) } if (ox == INT_MAX) { @@ -1686,6 +1762,25 @@ layout_get_floating_cell(struct cmdq_item *item, struct args *args, } w->last_new_pane_y = oy; } + *sxp = sx; + *syp = sy; + *oxp = ox; + *oyp = oy; +} + +/* Get a new floating cell. */ +struct layout_cell * +layout_get_floating_cell(struct cmdq_item *item, struct args *args, + struct window *w, struct window_pane *wp, char **cause) +{ + struct layout_cell *lcnew; + u_int sx, sy; + int ox, oy; + + layout_cell_floating_args(item, args, w, &sx, &sy, &ox, &oy, cause); + if (cause != NULL) { + return (NULL); + } if (sx < PANE_MINIMUM || sx > PANE_MAXIMUM) { *cause = xstrdup("invalid width"); @@ -1699,3 +1794,89 @@ layout_get_floating_cell(struct cmdq_item *item, struct args *args, lcnew = layout_floating_pane(w, wp, sx, sy, ox, oy); return (lcnew); } + +int +layout_cell_remove_tile(struct window *w, struct layout_cell *lc) +{ + struct layout_cell *lcother, *lcparent; + enum layout_type type; + int change; + + if (lc->flags & LAYOUT_CELL_FLOATING) + return (0); + + lcother = layout_cell_get_neighbour(lc); + if (lcother == NULL) { + layout_cell_remove_tile(w, lc->parent); + } else if ((lcparent = lcother->parent) != NULL) { + type = lcparent->type; + if (type == LAYOUT_TOPBOTTOM) + change = lcother->sy + 1; + else + change = lcother->sx + 1; + layout_resize_adjust(w, lcother, type, change); + } + + layout_set_size(lc, 0, 0, 0, 0); + return (1); +} + +int +layout_cell_insert_tile(struct window *w, struct layout_cell *lc) +{ + struct window_pane *wp; + struct layout_cell *lcother, *lcparent = lc->parent; + enum layout_type type; + u_int size1, size2, saved_size; + int flags = 0; + + if (lc == NULL) + return (0); + + if (lcparent == NULL) { + layout_set_size(lc, w->sx, w->sy, 0, 0); + return (1); + } + + type = lcparent->type; + lcother = layout_cell_get_neighbour(lc); + if (lcother == NULL) { + /* + * This is now the only revealed cell in the parent. Reveal the + * parent, then set the child's 'type' dimension. + */ + layout_cell_insert_tile(w, lcparent); + if (type == LAYOUT_LEFTRIGHT) + size1 = lcparent->sx; + else + size1 = lcparent->sy; + layout_resize_set(w, lc, type, size1); + } else { + if (lcother->wp == NULL) /* neighbour is a container */ + wp = TAILQ_FIRST(&lcother->cells)->wp; + else + wp = lcother->wp; + /* + * Failure point requires clearing concealed flag in many spots + */ + if (!layout_split_check_space(wp, lcother, type)) + return (0); + layout_split_sizes(lcother, -1, flags, type, &size1, &size2, + &saved_size); + layout_resize_set(w, lc, type, size1); + layout_resize_set(w, lcother, type, size2); + } + + /* Setting the opposite of 'type' dimension. */ + if (lcparent != NULL) { + if (lcparent->type == LAYOUT_LEFTRIGHT) { + size1 = lcparent->sy; + type = LAYOUT_TOPBOTTOM; + } else { + size1 = lcparent->sx; + type = LAYOUT_LEFTRIGHT; + } + layout_resize_set(w, lc, type, size1); + } + return (1); +} diff --git a/tmux.1 b/tmux.1 index d352a0a2..ffa87d9e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3119,37 +3119,42 @@ The command works only if at least one client is attached. .Tg floatp .It Xo Ic float\-pane -.Op Fl h Ar height -.Op Fl w Ar width -.Op Fl x Ar x -.Op Fl y Ar y +.Op Fl d +.Op Fl x Ar height +.Op Fl y Ar width +.Op Fl X Ar x\-position +.Op Fl y Ar y\-position .Op Fl t Ar target\-pane .Xc +.D1 Pq alias: Ic floatp Lift .Ar target\-pane out of the tiled layout and make it a floating pane. The -.Fl w -and -.Fl h -options set the width and height of the floating pane in columns and lines -respectively; the default is half the window width and height. -The .Fl x and .Fl y -options set the position of the upper-left corner of the pane; -if omitted, new floating panes are cascaded from the top-left of the window. -If +options set the width and height of the floating pane in columns and lines +respectively. +The default is half the window width and a quarter the window height. +The +.Fl X +and +.Fl Y +options set the position of the upper-left corner of the pane. +If omitted, new floating panes are cascaded from the top-left of the window. +.Pp +If the pane has previously been floating, the geometry is restored for +dimensions not specified by the provided arguments: .Fl x , .Fl y , -.Fl w , -and -.Fl h -are all omitted and the pane was previously returned to the tiled layout -with -.Ic tile\-pane , -its last floating position and size are restored. +.Fl X , +or +.Fl Y . +.Pp +If +.Fl d +is given, the active pane is not changed. The pane must not already be floating or hidden, and the window must not be zoomed. .Tg joinp @@ -4064,18 +4069,24 @@ is omitted and a marked pane is present (see the window containing the marked pane is used rather than the current window. .Tg tilep .It Xo Ic tile\-pane +.Op Fl d .Op Fl t Ar target\-pane .Xc -Insert a floating +.D1 Pq alias: Ic tilep +Return a floating .Ar target\-pane -back into the tiled layout. -The pane is placed by splitting the active tiled pane (or the most recently -active tiled pane, or any visible tiled pane if none is active). +back to the tiled layout. +The location in the layout is preserved. +The pane's takes half the relevant dimension from the nearest tiled pane in the +layout. The current floating position and size are saved so they can be restored by a subsequent .Ic float\-pane -command with no geometry options. -The pane must be floating and the window must not be zoomed. +comman. +The pane must be floating, not hidden, and the window must not be zoomed. +If +.Fl d +is given, the active pane is not changed. .Tg showp .It Xo Ic show\-pane .Op Fl t Ar target\-pane diff --git a/tmux.h b/tmux.h index ad10acf0..c4050f48 100644 --- a/tmux.h +++ b/tmux.h @@ -1290,7 +1290,6 @@ struct window_pane { #define PANE_UNSEENCHANGES 0x4000 #define PANE_REDRAWSCROLLBAR 0x8000 #define PANE_HIDDEN 0x20000 -#define PANE_SAVED_FLOAT 0x80000 /* saved_float_* fields are valid */ /* Last floating position/size, saved when the pane is tiled. */ int saved_float_xoff; @@ -1497,11 +1496,11 @@ struct layout_cell { struct layout_cell *parent; - u_int sx; - u_int sy; + u_int sx, saved_sx; + u_int sy, saved_sy; - int xoff; - int yoff; + int xoff, saved_xoff; + int yoff, saved_yoff; struct window_pane *wp; struct layout_cells cells; @@ -3535,6 +3534,7 @@ int window_get_pane_status(struct window *); struct style_range *window_pane_status_get_range(struct window_pane *, u_int, u_int); int window_pane_is_floating(struct window_pane *); +int window_pane_is_hidden(struct window_pane *); /* layout.c */ u_int layout_count_cells(struct layout_cell *); @@ -3551,14 +3551,16 @@ void layout_resize_layout(struct window *, struct layout_cell *, enum layout_type, int, int); struct layout_cell *layout_search_by_border(struct layout_cell *, u_int, u_int); void layout_set_size(struct layout_cell *, u_int, u_int, int, int); +void layout_save_size(struct layout_cell *); void layout_make_leaf(struct layout_cell *, struct window_pane *); void layout_make_node(struct layout_cell *, enum layout_type); void layout_fix_zindexes(struct window *, struct layout_cell *); void layout_fix_offsets(struct window *); -int layout_cell_is_tiled(struct layout_cell *); void layout_fix_panes(struct window *, struct window_pane *); void layout_resize_adjust(struct window *, struct layout_cell *, enum layout_type, int); +void layout_resize_set(struct window *, struct layout_cell *, + enum layout_type, u_int); struct layout_cell *layout_cell_get_neighbour(struct layout_cell *); void layout_init(struct window *, struct window_pane *); void layout_free(struct window *); @@ -3573,6 +3575,10 @@ void layout_resize_floating_pane_to(struct window_pane *, enum layout_type, u_int, char **); void layout_assign_pane(struct layout_cell *, struct window_pane *, int); +int layout_split_check_space(struct window_pane *, + struct layout_cell *, enum layout_type); +void layout_split_sizes(struct layout_cell *, int, int, + enum layout_type, u_int *, u_int *, u_int *); struct layout_cell *layout_split_pane(struct window_pane *, enum layout_type, int, int); struct layout_cell *layout_floating_pane(struct window *, struct window_pane *, @@ -3580,10 +3586,15 @@ struct layout_cell *layout_floating_pane(struct window *, struct window_pane *, void layout_close_pane(struct window_pane *); int layout_spread_cell(struct window *, struct layout_cell *); void layout_spread_out(struct window_pane *); +void layout_cell_floating_args(struct cmdq_item *, struct args *, + struct window *, u_int *, u_int *, int *, int *, char **); struct layout_cell *layout_get_floating_cell(struct cmdq_item *, struct args *, struct window *, struct window_pane *, char **); struct layout_cell *layout_get_tiled_cell(struct cmdq_item *, struct args *, struct window *, struct window_pane *, int, char **); +int layout_cell_is_tiled(struct layout_cell *); +int layout_cell_remove_tile(struct window *, struct layout_cell *); +int layout_cell_insert_tile(struct window *, struct layout_cell *); /* layout-custom.c */ char *layout_dump(struct window *, struct layout_cell *); diff --git a/window.c b/window.c index 80e37068..f02db4d1 100644 --- a/window.c +++ b/window.c @@ -2208,3 +2208,13 @@ window_pane_is_floating(struct window_pane *wp) return (0); return (1); } + +int +window_pane_is_hidden(struct window_pane *wp) +{ + struct layout_cell *lc = wp->layout_cell; + + if (lc == NULL || (lc->flags & LAYOUT_CELL_HIDDEN) == 0) + return (0); + return (1); +}