Updating tile-pane and float-pane to use new layout mechanics.

This commit is contained in:
Dane Jensen
2026-06-09 18:31:13 -07:00
parent 4dd496790a
commit 64ded18960
5 changed files with 358 additions and 355 deletions

View File

@@ -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);

339
layout.c
View File

@@ -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);
}

63
tmux.1
View File

@@ -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

23
tmux.h
View File

@@ -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 *);

View File

@@ -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);
}