mirror of
https://github.com/tmux/tmux.git
synced 2026-06-21 09:45:41 +00:00
tile-pane and float-pane now use the new layout mechanics
The layout position of every cell is kept throughout the state changing actions, and can therefore be restored.
This commit is contained in:
@@ -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 = {
|
const struct cmd_entry cmd_float_pane_entry = {
|
||||||
.name = "float-pane",
|
.name = "float-pane",
|
||||||
.alias = NULL,
|
.alias = "floatp",
|
||||||
|
|
||||||
.args = { "t:x:y:w:h:", 0, 0, NULL },
|
.args = { "dt:x:X:y:Y:", 0, 0, NULL },
|
||||||
.usage = "[-h height] [-w width] [-x x] [-y y] "
|
.usage = "[-x height] [-y width] [-X x-position] [-Y y-position] "
|
||||||
CMD_TARGET_PANE_USAGE,
|
CMD_TARGET_PANE_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.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 = {
|
const struct cmd_entry cmd_tile_pane_entry = {
|
||||||
.name = "tile-pane",
|
.name = "tile-pane",
|
||||||
.alias = NULL,
|
.alias = "tilep",
|
||||||
|
|
||||||
.args = { "t:", 0, 0, NULL },
|
.args = { "dt:", 0, 0, NULL },
|
||||||
.usage = CMD_TARGET_PANE_USAGE,
|
.usage = CMD_TARGET_PANE_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
@@ -63,90 +63,6 @@ const struct cmd_entry cmd_tile_pane_entry = {
|
|||||||
.exec = cmd_tile_pane_exec
|
.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
|
static enum cmd_retval
|
||||||
cmd_float_pane_exec(struct cmd *self, struct cmdq_item *item)
|
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 cmd_find_state *target = cmdq_get_target(item);
|
||||||
struct window *w = target->wl->window;
|
struct window *w = target->wl->window;
|
||||||
struct window_pane *wp = target->wp;
|
struct window_pane *wp = target->wp;
|
||||||
static int last_x = 0, last_y = 0;
|
struct layout_cell *lc = wp->layout_cell;
|
||||||
int x, y;
|
u_int sx = lc->saved_sx, sy = lc->saved_sy;
|
||||||
u_int sx, sy;
|
int ox = lc->saved_xoff, oy = lc->saved_yoff;
|
||||||
struct layout_cell *lc;
|
char *cause = NULL;
|
||||||
|
|
||||||
if (window_pane_is_floating(wp)) {
|
if (window_pane_is_floating(wp)) {
|
||||||
cmdq_error(item, "pane is already floating");
|
cmdq_error(item, "pane is already floating");
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
if (wp->flags & PANE_HIDDEN) {
|
if (window_pane_is_hidden(wp)) {
|
||||||
cmdq_error(item, "can't float a hidden pane");
|
cmdq_error(item, "can't float a hidden pane");
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
@@ -172,47 +88,22 @@ cmd_float_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
layout_remove_tile(w, lc);
|
||||||
* If no geometry was given explicitly and we have a saved floating
|
layout_cell_floating_args_parse(item, args, w, &sx, &sy, &ox, &oy, &cause);
|
||||||
* position from a previous tile-pane, restore it.
|
if (cause != NULL) {
|
||||||
*/
|
cmdq_error(item, "failed to float pane: %s", cause);
|
||||||
if ((wp->flags & PANE_SAVED_FLOAT) &&
|
free(cause);
|
||||||
!args_has(args, 'x') && !args_has(args, 'y') &&
|
return (CMD_RETURN_ERROR);
|
||||||
!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_set_size(lc, sx, sy, ox, oy);
|
||||||
/*
|
|
||||||
* 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 */
|
|
||||||
|
|
||||||
lc->flags |= LAYOUT_CELL_FLOATING;
|
lc->flags |= LAYOUT_CELL_FLOATING;
|
||||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||||
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
||||||
|
|
||||||
if (w->layout_root != NULL)
|
if (!args_has(args, 'd'))
|
||||||
layout_fix_offsets(w);
|
window_set_active_pane(w, wp, 1);
|
||||||
|
layout_fix_offsets(w);
|
||||||
layout_fix_panes(w, NULL);
|
layout_fix_panes(w, NULL);
|
||||||
notify_window("window-layout-changed", w);
|
notify_window("window-layout-changed", w);
|
||||||
server_redraw_window(w);
|
server_redraw_window(w);
|
||||||
@@ -223,138 +114,38 @@ cmd_float_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
cmd_tile_pane_exec(struct cmd *self, struct cmdq_item *item)
|
cmd_tile_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||||
{
|
{
|
||||||
__attribute((unused)) struct args *args = cmd_get_args(self);
|
__unused struct args *args = cmd_get_args(self);
|
||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
struct window *w = target->wl->window;
|
struct window *w = target->wl->window;
|
||||||
struct window_pane *wp = target->wp;
|
struct window_pane *wp = target->wp;
|
||||||
struct window_pane *target_wp, *wpiter;
|
struct layout_cell *lc = wp->layout_cell;
|
||||||
struct layout_cell *float_lc, *lc;
|
|
||||||
int was_hidden;
|
|
||||||
|
|
||||||
if (!window_pane_is_floating(wp)) {
|
if (!window_pane_is_floating(wp)) {
|
||||||
cmdq_error(item, "pane is not floating");
|
cmdq_error(item, "pane is not floating");
|
||||||
return (CMD_RETURN_ERROR);
|
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) {
|
if (w->flags & WINDOW_ZOOMED) {
|
||||||
cmdq_error(item, "can't tile a pane while window is zoomed");
|
cmdq_error(item, "can't tile a pane while window is zoomed");
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
was_hidden = (wp->flags & PANE_HIDDEN) != 0;
|
layout_save_size(lc);
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
lc->flags &= ~LAYOUT_CELL_FLOATING;
|
||||||
|
if (layout_insert_tile(w, lc) == 0) {
|
||||||
|
cmdq_error(item, "can't tile a pane that is already tiled");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||||
TAILQ_INSERT_TAIL(&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);
|
window_set_active_pane(w, wp, 1);
|
||||||
|
layout_fix_offsets(w);
|
||||||
if (w->layout_root != NULL)
|
|
||||||
layout_fix_offsets(w);
|
|
||||||
layout_fix_panes(w, NULL);
|
layout_fix_panes(w, NULL);
|
||||||
notify_window("window-layout-changed", w);
|
notify_window("window-layout-changed", w);
|
||||||
server_redraw_window(w);
|
server_redraw_window(w);
|
||||||
|
|||||||
437
layout.c
437
layout.c
@@ -26,11 +26,18 @@
|
|||||||
/*
|
/*
|
||||||
* The window layout is a tree of cells each of which can be one of: a
|
* The window layout is a tree of cells each of which can be one of: a
|
||||||
* left-right container for a list of cells, a top-bottom container for a list
|
* left-right container for a list of cells, a top-bottom container for a list
|
||||||
* of cells, or a container for a window pane.
|
* of cells, or a container for a window pane. 'Node' will be used to refer to
|
||||||
|
* a cell which contains a list of cells, and 'leaf' to refer to a cell that
|
||||||
|
* contains a window pane. A leaf is considered to be tiled if it is to be drawn
|
||||||
|
* as a part of the tiled layout. A 'neighbour' is a sibling that is also tiled.
|
||||||
|
* A cell's 'split' size refers to the side that is shortened when splitting it,
|
||||||
|
* determined by the parent's type.
|
||||||
*
|
*
|
||||||
* Each window has a pointer to the root of its layout tree (containing its
|
* Each window has a pointer to the root of its layout tree (containing its
|
||||||
* panes), every pane has a pointer back to the cell containing it, and each
|
* panes), every pane has a pointer back to the cell containing it, and each
|
||||||
* cell a pointer to its parent cell.
|
* cell a pointer to its parent cell. Every cell has a position in the root
|
||||||
|
* layout tree. This position is retained through cell state changes such as
|
||||||
|
* floating or hiding.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static u_int layout_resize_check(struct window *, struct layout_cell *,
|
static u_int layout_resize_check(struct window *, struct layout_cell *,
|
||||||
@@ -44,6 +51,7 @@ static u_int layout_new_pane_size(struct window *, u_int,
|
|||||||
u_int);
|
u_int);
|
||||||
static int layout_set_size_check(struct window *, struct layout_cell *,
|
static int layout_set_size_check(struct window *, struct layout_cell *,
|
||||||
enum layout_type, int);
|
enum layout_type, int);
|
||||||
|
static int layout_cell_has_tiled_child(struct layout_cell *);
|
||||||
static void layout_resize_child_cells(struct window *,
|
static void layout_resize_child_cells(struct window *,
|
||||||
struct layout_cell *);
|
struct layout_cell *);
|
||||||
|
|
||||||
@@ -66,6 +74,12 @@ layout_create_cell(struct layout_cell *lcparent)
|
|||||||
lc->xoff = INT_MAX;
|
lc->xoff = INT_MAX;
|
||||||
lc->yoff = 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;
|
lc->wp = NULL;
|
||||||
|
|
||||||
return (lc);
|
return (lc);
|
||||||
@@ -190,6 +204,16 @@ layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, int xoff, int yoff)
|
|||||||
lc->yoff = 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. */
|
/* Make a cell a leaf cell. */
|
||||||
void
|
void
|
||||||
layout_make_leaf(struct layout_cell *lc, struct window_pane *wp)
|
layout_make_leaf(struct layout_cell *lc, struct window_pane *wp)
|
||||||
@@ -250,7 +274,8 @@ layout_fix_offsets1(struct layout_cell *lc)
|
|||||||
if (lc->type == LAYOUT_LEFTRIGHT) {
|
if (lc->type == LAYOUT_LEFTRIGHT) {
|
||||||
xoff = lc->xoff;
|
xoff = lc->xoff;
|
||||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
if (!layout_cell_is_tiled(lcchild))
|
if (!layout_cell_is_tiled(lcchild) &&
|
||||||
|
!layout_cell_has_tiled_child(lcchild))
|
||||||
continue;
|
continue;
|
||||||
lcchild->xoff = xoff;
|
lcchild->xoff = xoff;
|
||||||
lcchild->yoff = lc->yoff;
|
lcchild->yoff = lc->yoff;
|
||||||
@@ -261,7 +286,8 @@ layout_fix_offsets1(struct layout_cell *lc)
|
|||||||
} else {
|
} else {
|
||||||
yoff = lc->yoff;
|
yoff = lc->yoff;
|
||||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
if (!layout_cell_is_tiled(lcchild))
|
if (!layout_cell_is_tiled(lcchild) &&
|
||||||
|
!layout_cell_has_tiled_child(lcchild))
|
||||||
continue;
|
continue;
|
||||||
lcchild->xoff = lc->xoff;
|
lcchild->xoff = lc->xoff;
|
||||||
lcchild->yoff = yoff;
|
lcchild->yoff = yoff;
|
||||||
@@ -290,13 +316,34 @@ layout_fix_offsets(struct window *w)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Not all cells are drawn within the tiled grid of a layout. This predicate
|
* Not all cells are drawn within the tiled grid of a layout. This predicate
|
||||||
* isolates that logic.
|
* isolates that logic. Nodes are not considered tiled.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
layout_cell_is_tiled(struct layout_cell *lc)
|
layout_cell_is_tiled(struct layout_cell *lc)
|
||||||
{
|
{
|
||||||
return ((~lc->flags & LAYOUT_CELL_HIDDEN) &&
|
int is_leaf, is_floating, is_hidden;
|
||||||
(~lc->flags & LAYOUT_CELL_FLOATING));
|
|
||||||
|
is_leaf = lc->type == LAYOUT_WINDOWPANE;
|
||||||
|
is_floating = lc->flags & LAYOUT_CELL_FLOATING;
|
||||||
|
is_hidden = lc->flags & LAYOUT_CELL_HIDDEN;
|
||||||
|
|
||||||
|
return is_leaf && !(is_floating || is_hidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
layout_cell_has_tiled_child(struct layout_cell *lc)
|
||||||
|
{
|
||||||
|
struct layout_cell *lcchild;
|
||||||
|
|
||||||
|
if (lc->type == LAYOUT_WINDOWPANE)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
|
if (layout_cell_is_tiled(lcchild) ||
|
||||||
|
layout_cell_has_tiled_child(lcchild))
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -308,7 +355,8 @@ layout_cell_is_first_tiled(struct layout_cell *lc)
|
|||||||
return (layout_cell_is_tiled(lc));
|
return (layout_cell_is_tiled(lc));
|
||||||
|
|
||||||
TAILQ_FOREACH(lcchild, &lcparent->cells, entry) {
|
TAILQ_FOREACH(lcchild, &lcparent->cells, entry) {
|
||||||
if (layout_cell_is_tiled(lcchild))
|
if (layout_cell_is_tiled(lcchild) ||
|
||||||
|
layout_cell_has_tiled_child(lcchild))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,7 +367,7 @@ layout_cell_is_first_tiled(struct layout_cell *lc)
|
|||||||
static int
|
static int
|
||||||
layout_cell_is_top(struct window *w, struct layout_cell *lc)
|
layout_cell_is_top(struct window *w, struct layout_cell *lc)
|
||||||
{
|
{
|
||||||
struct layout_cell *next, *edge;
|
struct layout_cell *next;
|
||||||
|
|
||||||
while (lc != w->layout_root) {
|
while (lc != w->layout_root) {
|
||||||
next = lc->parent;
|
next = lc->parent;
|
||||||
@@ -525,13 +573,20 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
|
|||||||
/* Child cell runs in a different direction. */
|
/* Child cell runs in a different direction. */
|
||||||
if (lc->type != type) {
|
if (lc->type != type) {
|
||||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
if (!layout_cell_is_tiled(lcchild))
|
if (!layout_cell_is_tiled(lcchild) &&
|
||||||
|
!layout_cell_has_tiled_child(lcchild))
|
||||||
continue;
|
continue;
|
||||||
layout_resize_adjust(w, lcchild, type, change);
|
layout_resize_adjust(w, lcchild, type, change);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a node doesn't contain 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
|
* Child cell runs in the same direction. Adjust each child equally
|
||||||
* until no further change is possible.
|
* until no further change is possible.
|
||||||
@@ -540,7 +595,8 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
|
|||||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
if (change == 0)
|
if (change == 0)
|
||||||
break;
|
break;
|
||||||
if (!layout_cell_is_tiled(lcchild))
|
if (!layout_cell_is_tiled(lcchild) &&
|
||||||
|
!layout_cell_has_tiled_child(lcchild))
|
||||||
continue;
|
continue;
|
||||||
if (change > 0) {
|
if (change > 0) {
|
||||||
layout_resize_adjust(w, lcchild, type, 1);
|
layout_resize_adjust(w, lcchild, type, 1);
|
||||||
@@ -555,6 +611,20 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Resizes a cell to a specified size */
|
||||||
|
void
|
||||||
|
layout_resize_set_size(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)
|
* Redistribute space equally among all visible (non-hidden WINDOWPANE)
|
||||||
* children of lcparent in the given direction. Hidden WINDOWPANE leaves
|
* children of lcparent in the given direction. Hidden WINDOWPANE leaves
|
||||||
@@ -611,40 +681,41 @@ layout_redistribute_cells(struct window *w, struct layout_cell *lcparent,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper function for layout_cell_get_neighbour. */
|
/* Find and return the nearest neighbour to a cell in a specific direction. */
|
||||||
static struct layout_cell *
|
static struct layout_cell *
|
||||||
layout_cell_get_neighbour_direction(struct layout_cell *lc, int direction)
|
layout_cell_get_neighbour_direction(struct layout_cell *lc, int direction)
|
||||||
{
|
{
|
||||||
struct layout_cell *lcother = lc;
|
struct layout_cell *lcneighbour = lc;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (direction)
|
if (direction)
|
||||||
lcother = TAILQ_NEXT(lcother, entry);
|
lcneighbour = TAILQ_NEXT(lcneighbour, entry);
|
||||||
else
|
else
|
||||||
lcother = TAILQ_PREV(lcother, layout_cells, entry);
|
lcneighbour = TAILQ_PREV(lcneighbour, layout_cells,
|
||||||
|
entry);
|
||||||
|
|
||||||
if (lcother == NULL || layout_cell_is_tiled(lcother))
|
if (lcneighbour == NULL || layout_cell_is_tiled(lcneighbour) ||
|
||||||
return (lcother);
|
layout_cell_has_tiled_child(lcneighbour))
|
||||||
|
return (lcneighbour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finds the nearest visible neighbour. A neighbour is a sibling cell drawn
|
* Find and return the nearest neighbour. Prefers cells "after" the specified
|
||||||
* within the tiled layout. Prefers cells "before" the specified cell.
|
* cell. This behavior defines how cell dimensions are redistributed when a cell
|
||||||
* This behavior defines how cell dimensions are redistributed when a cell is
|
* is hidden/shown and floated/tiled.
|
||||||
* hidden/shown and floated/tiled.
|
|
||||||
*/
|
*/
|
||||||
struct layout_cell *
|
struct layout_cell *
|
||||||
layout_cell_get_neighbour(struct layout_cell *lc)
|
layout_cell_get_neighbour(struct layout_cell *lc)
|
||||||
{
|
{
|
||||||
struct layout_cell *lcother, *lcparent = lc->parent;
|
struct layout_cell *lcother, *lcparent = lc->parent;
|
||||||
int direction = 0;
|
int direction = 1;
|
||||||
|
|
||||||
if (lcparent == NULL)
|
if (lcparent == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
if (lc == TAILQ_FIRST(&lcparent->cells))
|
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
|
||||||
direction = 1;
|
direction = !direction;
|
||||||
|
|
||||||
lcother = layout_cell_get_neighbour_direction(lc, direction);
|
lcother = layout_cell_get_neighbour_direction(lc, direction);
|
||||||
if (lcother == NULL)
|
if (lcother == NULL)
|
||||||
@@ -653,8 +724,10 @@ layout_cell_get_neighbour(struct layout_cell *lc)
|
|||||||
return lcother;
|
return lcother;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/* Destroy a cell and redistribute the space if the cell was tiled. */
|
* Destroy a cell and redistribute the space if the cell was tiled. Assumes
|
||||||
|
* to be called on a leaf cell.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
layout_destroy_cell(struct window *w, struct layout_cell *lc,
|
layout_destroy_cell(struct window *w, struct layout_cell *lc,
|
||||||
struct layout_cell **lcroot)
|
struct layout_cell **lcroot)
|
||||||
@@ -689,7 +762,7 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc,
|
|||||||
val = lc->sy + 1;
|
val = lc->sy + 1;
|
||||||
layout_resize_adjust(w, lcother, lcparent->type, val);
|
layout_resize_adjust(w, lcother, lcparent->type, val);
|
||||||
} else
|
} else
|
||||||
layout_hide_cell(w, lcparent);
|
layout_remove_tile(w, lcparent);
|
||||||
|
|
||||||
/* Remove this from the parent's list. */
|
/* Remove this from the parent's list. */
|
||||||
TAILQ_REMOVE(&lcparent->cells, lc, entry);
|
TAILQ_REMOVE(&lcparent->cells, lc, entry);
|
||||||
@@ -705,6 +778,7 @@ out:
|
|||||||
TAILQ_REMOVE(&lcparent->cells, lc, entry);
|
TAILQ_REMOVE(&lcparent->cells, lc, entry);
|
||||||
|
|
||||||
lc->parent = lcparent->parent;
|
lc->parent = lcparent->parent;
|
||||||
|
|
||||||
if (lc->parent == NULL) {
|
if (lc->parent == NULL) {
|
||||||
if (layout_cell_is_tiled(lc))
|
if (layout_cell_is_tiled(lc))
|
||||||
layout_set_size(lc, w->sx, w->sy, 0, 0);
|
layout_set_size(lc, w->sx, w->sy, 0, 0);
|
||||||
@@ -820,7 +894,7 @@ layout_resize(struct window *w, u_int sx, u_int sy)
|
|||||||
* out proportionately - this should leave the layout fitting the new
|
* out proportionately - this should leave the layout fitting the new
|
||||||
* window size.
|
* window size.
|
||||||
*/
|
*/
|
||||||
if (lc->type == LAYOUT_WINDOWPANE && !layout_cell_is_tiled(lc))
|
if (!layout_cell_is_tiled(lc))
|
||||||
return;
|
return;
|
||||||
xchange = sx - lc->sx;
|
xchange = sx - lc->sx;
|
||||||
xlimit = layout_resize_check(w, lc, LAYOUT_LEFTRIGHT);
|
xlimit = layout_resize_check(w, lc, LAYOUT_LEFTRIGHT);
|
||||||
@@ -1195,7 +1269,8 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc)
|
|||||||
count = 0;
|
count = 0;
|
||||||
previous = 0;
|
previous = 0;
|
||||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
if (!layout_cell_is_tiled(lcchild))
|
if (!layout_cell_is_tiled(lcchild) &&
|
||||||
|
!layout_cell_has_tiled_child(lcchild))
|
||||||
continue;
|
continue;
|
||||||
count++;
|
count++;
|
||||||
if (lc->type == LAYOUT_LEFTRIGHT)
|
if (lc->type == LAYOUT_LEFTRIGHT)
|
||||||
@@ -1215,7 +1290,8 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc)
|
|||||||
/* Resize children into the new size. */
|
/* Resize children into the new size. */
|
||||||
idx = 0;
|
idx = 0;
|
||||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
if (!layout_cell_is_tiled(lcchild))
|
if (!layout_cell_is_tiled(lcchild) &&
|
||||||
|
!layout_cell_has_tiled_child(lcchild))
|
||||||
continue;
|
continue;
|
||||||
if (lc->type == LAYOUT_TOPBOTTOM) {
|
if (lc->type == LAYOUT_TOPBOTTOM) {
|
||||||
lcchild->sx = lc->sx;
|
lcchild->sx = lc->sx;
|
||||||
@@ -1238,6 +1314,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 before,
|
||||||
|
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 (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 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!
|
* split. This must be followed by layout_assign_pane before much else happens!
|
||||||
@@ -1247,11 +1390,10 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
|||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
|
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
|
||||||
struct style *sb_style = &wp->scrollbar_style;
|
u_int sx, sy, xoff, yoff, size1, size2;
|
||||||
u_int sx, sy, xoff, yoff, size1, size2, minimum;
|
|
||||||
u_int new_size, saved_size, resize_first = 0;
|
u_int new_size, saved_size, resize_first = 0;
|
||||||
int full_size = (flags & SPAWN_FULLSIZE), status;
|
int full_size = (flags & SPAWN_FULLSIZE);
|
||||||
int scrollbars;
|
int before = (flags & SPAWN_BEFORE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If full_size is specified, add a new cell at the top of the window
|
* If full_size is specified, add a new cell at the top of the window
|
||||||
@@ -1261,8 +1403,6 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
|||||||
lc = wp->window->layout_root;
|
lc = wp->window->layout_root;
|
||||||
else
|
else
|
||||||
lc = wp->layout_cell;
|
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. */
|
/* Copy the old cell size. */
|
||||||
sx = lc->sx;
|
sx = lc->sx;
|
||||||
@@ -1271,47 +1411,14 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
|||||||
yoff = lc->yoff;
|
yoff = lc->yoff;
|
||||||
|
|
||||||
/* Check there is enough space for the two new panes. */
|
/* Check there is enough space for the two new panes. */
|
||||||
switch (type) {
|
if (!layout_split_check_space(wp, lc, type))
|
||||||
case LAYOUT_LEFTRIGHT:
|
return (NULL);
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate new cell sizes. size is the target size or -1 for middle
|
* 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.
|
* split, size1 is the size of the top/left and size2 the bottom/right.
|
||||||
*/
|
*/
|
||||||
if (type == LAYOUT_LEFTRIGHT)
|
layout_split_sizes(lc, size, before, type, &size1, &size2, &saved_size);
|
||||||
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;
|
|
||||||
|
|
||||||
/* Which size are we using? */
|
/* Which size are we using? */
|
||||||
if (flags & SPAWN_BEFORE)
|
if (flags & SPAWN_BEFORE)
|
||||||
@@ -1433,8 +1540,8 @@ layout_floating_pane(struct window *w, struct window_pane *wp, u_int sx,
|
|||||||
|
|
||||||
if (lcparent == NULL) {
|
if (lcparent == NULL) {
|
||||||
/*
|
/*
|
||||||
* Adding a pane to a root that doesn't have a container. Must
|
* Adding a pane to a root that isn't node. Must create and
|
||||||
* create and insert a new root.
|
* insert a new root.
|
||||||
*/
|
*/
|
||||||
lcparent = layout_create_cell(NULL);
|
lcparent = layout_create_cell(NULL);
|
||||||
layout_make_node(lcparent, LAYOUT_TOPBOTTOM);
|
layout_make_node(lcparent, LAYOUT_TOPBOTTOM);
|
||||||
@@ -1619,51 +1726,40 @@ layout_get_tiled_cell(struct cmdq_item *item, struct args *args,
|
|||||||
return (lc);
|
return (lc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get a new floating cell. */
|
void
|
||||||
struct layout_cell *
|
layout_cell_floating_args_parse(struct cmdq_item *item, struct args *args,
|
||||||
layout_get_floating_cell(struct cmdq_item *item, struct args *args,
|
struct window *w, u_int *sxp, u_int *syp, int *oxp, int *oyp, char **cause)
|
||||||
struct window *w, struct window_pane *wp, char **cause)
|
|
||||||
{
|
{
|
||||||
struct layout_cell *lcnew;
|
int sx, sy, ox, oy;
|
||||||
u_int sx = w->sx / 2, sy = w->sy / 4;
|
|
||||||
int ox = INT_MAX, oy = INT_MAX;
|
sx = *sxp == UINT_MAX ? w->sx / 2 : *sxp;
|
||||||
char *error;
|
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')) {
|
if (args_has(args, 'x')) {
|
||||||
sx = args_percentage_and_expand(args, 'x', 0, w->sx - 1, w->sx,
|
sx = args_percentage_and_expand(args, 'x', 0, w->sx - 1, w->sx,
|
||||||
item, &error);
|
item, cause);
|
||||||
if (error != NULL) {
|
if (*cause != NULL)
|
||||||
xasprintf(cause, "position %s", error);
|
return;
|
||||||
free(error);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (args_has(args, 'y')) {
|
if (args_has(args, 'y')) {
|
||||||
sy = args_percentage_and_expand(args, 'y', 0, w->sy - 1, w->sy,
|
sy = args_percentage_and_expand(args, 'y', 0, w->sy - 1, w->sy,
|
||||||
item, &error);
|
item, cause);
|
||||||
if (error != NULL) {
|
if (*cause != NULL)
|
||||||
xasprintf(cause, "position %s", error);
|
return;
|
||||||
free(error);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (args_has(args, 'X')) {
|
if (args_has(args, 'X')) {
|
||||||
ox = args_percentage_and_expand(args, 'X', -sx, w->sx,
|
ox = args_percentage_and_expand(args, 'X', -(int)w->sx, w->sx,
|
||||||
w->sx, item, &error);
|
w->sx, item, cause);
|
||||||
if (error != NULL) {
|
if (*cause != NULL)
|
||||||
xasprintf(cause, "size %s", error);
|
return;
|
||||||
free(error);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (args_has(args, 'Y')) {
|
if (args_has(args, 'Y')) {
|
||||||
oy = args_percentage_and_expand(args, 'Y', -sy, w->sy,
|
oy = args_percentage_and_expand(args, 'Y', -(int)w->sy, w->sy,
|
||||||
w->sy, item, &error);
|
w->sy, item, cause);
|
||||||
if (error != NULL) {
|
if (*cause != NULL)
|
||||||
xasprintf(cause, "size %s", error);
|
return;
|
||||||
free(error);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ox == INT_MAX) {
|
if (ox == INT_MAX) {
|
||||||
@@ -1686,6 +1782,25 @@ layout_get_floating_cell(struct cmdq_item *item, struct args *args,
|
|||||||
}
|
}
|
||||||
w->last_new_pane_y = oy;
|
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_parse(item, args, w, &sx, &sy, &ox, &oy, cause);
|
||||||
|
if (cause != NULL) {
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (sx < PANE_MINIMUM || sx > PANE_MAXIMUM) {
|
if (sx < PANE_MINIMUM || sx > PANE_MAXIMUM) {
|
||||||
*cause = xstrdup("invalid width");
|
*cause = xstrdup("invalid width");
|
||||||
@@ -1699,3 +1814,109 @@ layout_get_floating_cell(struct cmdq_item *item, struct args *args,
|
|||||||
lcnew = layout_floating_pane(w, wp, sx, sy, ox, oy);
|
lcnew = layout_floating_pane(w, wp, sx, sy, ox, oy);
|
||||||
return (lcnew);
|
return (lcnew);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removes a cell from the tiled layout by giving half the cells space to the
|
||||||
|
* nearest neighbour.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
layout_remove_tile(struct window *w, struct layout_cell *lc)
|
||||||
|
{
|
||||||
|
struct layout_cell *lcneighbour, *lcparent;
|
||||||
|
enum layout_type type;
|
||||||
|
int change;
|
||||||
|
|
||||||
|
if (lc->flags & LAYOUT_CELL_FLOATING)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
lcneighbour = layout_cell_get_neighbour(lc);
|
||||||
|
if (lcneighbour == NULL) {
|
||||||
|
if (lc->parent != NULL)
|
||||||
|
layout_remove_tile(w, lc->parent);
|
||||||
|
} else if ((lcparent = lcneighbour->parent) != NULL) {
|
||||||
|
type = lcparent->type;
|
||||||
|
/*
|
||||||
|
* Adding the size of the layout cell plus its border to the
|
||||||
|
* neighbour.
|
||||||
|
*/
|
||||||
|
if (type == LAYOUT_TOPBOTTOM)
|
||||||
|
change = lc->sy + 1;
|
||||||
|
else
|
||||||
|
change = lc->sx + 1;
|
||||||
|
layout_resize_adjust(w, lcneighbour, type, change);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zeroing out the cell geometry until the cell is retiled. */
|
||||||
|
layout_set_size(lc, 0, 0, 0, 0);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inserts a cell back into the tiled layout by taking half the space from its
|
||||||
|
* nearest neighbour.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
layout_insert_tile(struct window *w, struct layout_cell *lc)
|
||||||
|
{
|
||||||
|
struct window_pane *wp;
|
||||||
|
struct layout_cell *lcneighbour, *lcparent = lc->parent;
|
||||||
|
enum layout_type type;
|
||||||
|
u_int size1, size2, saved_size;
|
||||||
|
|
||||||
|
if (lc == NULL)
|
||||||
|
fatalx("layout cell cannot be null when tiling");
|
||||||
|
|
||||||
|
if (lcparent == NULL) {
|
||||||
|
/* Only pane in the layout. */
|
||||||
|
layout_set_size(lc, w->sx, w->sy, 0, 0);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
type = lcparent->type;
|
||||||
|
lcneighbour = layout_cell_get_neighbour(lc);
|
||||||
|
if (lcneighbour == NULL) {
|
||||||
|
/*
|
||||||
|
* This will become the only visible cell in the parent.
|
||||||
|
* Tile the parent, then set the child's 'split' size.
|
||||||
|
*/
|
||||||
|
layout_insert_tile(w, lcparent);
|
||||||
|
if (type == LAYOUT_LEFTRIGHT)
|
||||||
|
size1 = lcparent->sx;
|
||||||
|
else
|
||||||
|
size1 = lcparent->sy;
|
||||||
|
layout_resize_set_size(w, lc, type, size1);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* In order to determine if there is enough space to retile the
|
||||||
|
* pane, information is needed from window and window pane
|
||||||
|
* options. First get a neightbour window pane...
|
||||||
|
*/
|
||||||
|
if (~lcneighbour->type & LAYOUT_WINDOWPANE)
|
||||||
|
wp = TAILQ_FIRST(&lcneighbour->cells)->wp;
|
||||||
|
else
|
||||||
|
wp = lcneighbour->wp;
|
||||||
|
/*
|
||||||
|
* ...and then check if there is enough room to tile.
|
||||||
|
*/
|
||||||
|
if (!layout_split_check_space(wp, lcneighbour, type))
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
layout_split_sizes(lcneighbour, -1, 0, type, &size1, &size2,
|
||||||
|
&saved_size);
|
||||||
|
layout_resize_set_size(w, lc, type, size1);
|
||||||
|
layout_resize_set_size(w, lcneighbour, type, size2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setting opposite of the 'split' size to that of the parent. */
|
||||||
|
if (lcparent != NULL) {
|
||||||
|
if (lcparent->type == LAYOUT_LEFTRIGHT) {
|
||||||
|
size1 = lcparent->sy;
|
||||||
|
type = LAYOUT_TOPBOTTOM;
|
||||||
|
} else {
|
||||||
|
size1 = lcparent->sx;
|
||||||
|
type = LAYOUT_LEFTRIGHT;
|
||||||
|
}
|
||||||
|
layout_resize_set_size(w, lc, type, size1);
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|||||||
69
tmux.1
69
tmux.1
@@ -3119,37 +3119,43 @@ The
|
|||||||
command works only if at least one client is attached.
|
command works only if at least one client is attached.
|
||||||
.Tg floatp
|
.Tg floatp
|
||||||
.It Xo Ic float\-pane
|
.It Xo Ic float\-pane
|
||||||
.Op Fl h Ar height
|
.Op Fl d
|
||||||
.Op Fl w Ar width
|
.Op Fl x Ar width
|
||||||
.Op Fl x Ar x
|
.Op Fl y Ar height
|
||||||
.Op Fl y Ar y
|
.Op Fl X Ar x\-position
|
||||||
|
.Op Fl y Ar y\-position
|
||||||
.Op Fl t Ar target\-pane
|
.Op Fl t Ar target\-pane
|
||||||
.Xc
|
.Xc
|
||||||
|
.D1 Pq alias: Ic floatp
|
||||||
Lift
|
Lift
|
||||||
.Ar target\-pane
|
.Ar target\-pane
|
||||||
out of the tiled layout and make it a floating pane.
|
out of the tiled layout and make it floating.
|
||||||
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
|
The
|
||||||
.Fl x
|
.Fl x
|
||||||
and
|
and
|
||||||
.Fl y
|
.Fl y
|
||||||
options set the position of the upper-left corner of the pane;
|
options set the width and height of the floating pane in columns and lines
|
||||||
if omitted, new floating panes are cascaded from the top-left of the window.
|
respectively.
|
||||||
If
|
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 had previously been floating, the position and sizes are restored
|
||||||
|
from the saved values not specified by the
|
||||||
.Fl x ,
|
.Fl x ,
|
||||||
.Fl y ,
|
.Fl y ,
|
||||||
.Fl w ,
|
.Fl X ,
|
||||||
and
|
and
|
||||||
.Fl h
|
.Fl Y
|
||||||
are all omitted and the pane was previously returned to the tiled layout
|
options.
|
||||||
with
|
.Pp
|
||||||
.Ic tile\-pane ,
|
If
|
||||||
its last floating position and size are restored.
|
.Fl d
|
||||||
|
is given, the active pane is not changed.
|
||||||
The pane must not already be floating or hidden, and the window must not
|
The pane must not already be floating or hidden, and the window must not
|
||||||
be zoomed.
|
be zoomed.
|
||||||
.Tg joinp
|
.Tg joinp
|
||||||
@@ -4064,18 +4070,23 @@ is omitted and a marked pane is present (see
|
|||||||
the window containing the marked pane is used rather than the current window.
|
the window containing the marked pane is used rather than the current window.
|
||||||
.Tg tilep
|
.Tg tilep
|
||||||
.It Xo Ic tile\-pane
|
.It Xo Ic tile\-pane
|
||||||
|
.Op Fl d
|
||||||
.Op Fl t Ar target\-pane
|
.Op Fl t Ar target\-pane
|
||||||
.Xc
|
.Xc
|
||||||
Insert a floating
|
.D1 Pq alias: Ic tilep
|
||||||
|
Return a floating
|
||||||
.Ar target\-pane
|
.Ar target\-pane
|
||||||
back into the tiled layout.
|
back to the tiled layout.
|
||||||
The pane is placed by splitting the active tiled pane (or the most recently
|
The location in the layout is preserved.
|
||||||
active tiled pane, or any visible tiled pane if none is active).
|
Half the space from the nearest tiled pane in the layout is given to
|
||||||
The current floating position and size are saved so they can be restored by
|
.Ar target\-pane .
|
||||||
a subsequent
|
The floating position and sizes are saved so they can be restored by future
|
||||||
.Ic float\-pane
|
calls to
|
||||||
command with no geometry options.
|
.Ic float\-pane .
|
||||||
The pane must be floating and the window must not be zoomed.
|
If
|
||||||
|
.Fl d
|
||||||
|
is given, the active pane is not changed.
|
||||||
|
The pane must be floating, not hidden, and the window must not be zoomed.
|
||||||
.Tg showp
|
.Tg showp
|
||||||
.It Xo Ic show\-pane
|
.It Xo Ic show\-pane
|
||||||
.Op Fl t Ar target\-pane
|
.Op Fl t Ar target\-pane
|
||||||
|
|||||||
23
tmux.h
23
tmux.h
@@ -1290,7 +1290,6 @@ struct window_pane {
|
|||||||
#define PANE_UNSEENCHANGES 0x4000
|
#define PANE_UNSEENCHANGES 0x4000
|
||||||
#define PANE_REDRAWSCROLLBAR 0x8000
|
#define PANE_REDRAWSCROLLBAR 0x8000
|
||||||
#define PANE_HIDDEN 0x20000
|
#define PANE_HIDDEN 0x20000
|
||||||
#define PANE_SAVED_FLOAT 0x80000 /* saved_float_* fields are valid */
|
|
||||||
|
|
||||||
/* Last floating position/size, saved when the pane is tiled. */
|
/* Last floating position/size, saved when the pane is tiled. */
|
||||||
int saved_float_xoff;
|
int saved_float_xoff;
|
||||||
@@ -1497,11 +1496,11 @@ struct layout_cell {
|
|||||||
|
|
||||||
struct layout_cell *parent;
|
struct layout_cell *parent;
|
||||||
|
|
||||||
u_int sx;
|
u_int sx, saved_sx;
|
||||||
u_int sy;
|
u_int sy, saved_sy;
|
||||||
|
|
||||||
int xoff;
|
int xoff, saved_xoff;
|
||||||
int yoff;
|
int yoff, saved_yoff;
|
||||||
|
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
struct layout_cells cells;
|
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,
|
struct style_range *window_pane_status_get_range(struct window_pane *, u_int,
|
||||||
u_int);
|
u_int);
|
||||||
int window_pane_is_floating(struct window_pane *);
|
int window_pane_is_floating(struct window_pane *);
|
||||||
|
int window_pane_is_hidden(struct window_pane *);
|
||||||
|
|
||||||
/* layout.c */
|
/* layout.c */
|
||||||
u_int layout_count_cells(struct layout_cell *);
|
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);
|
enum layout_type, int, int);
|
||||||
struct layout_cell *layout_search_by_border(struct layout_cell *, u_int, u_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_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_leaf(struct layout_cell *, struct window_pane *);
|
||||||
void layout_make_node(struct layout_cell *, enum layout_type);
|
void layout_make_node(struct layout_cell *, enum layout_type);
|
||||||
void layout_fix_zindexes(struct window *, struct layout_cell *);
|
void layout_fix_zindexes(struct window *, struct layout_cell *);
|
||||||
void layout_fix_offsets(struct window *);
|
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_fix_panes(struct window *, struct window_pane *);
|
||||||
void layout_resize_adjust(struct window *, struct layout_cell *,
|
void layout_resize_adjust(struct window *, struct layout_cell *,
|
||||||
enum layout_type, int);
|
enum layout_type, int);
|
||||||
|
void layout_resize_set_size(struct window *, struct layout_cell *,
|
||||||
|
enum layout_type, u_int);
|
||||||
struct layout_cell *layout_cell_get_neighbour(struct layout_cell *);
|
struct layout_cell *layout_cell_get_neighbour(struct layout_cell *);
|
||||||
void layout_init(struct window *, struct window_pane *);
|
void layout_init(struct window *, struct window_pane *);
|
||||||
void layout_free(struct window *);
|
void layout_free(struct window *);
|
||||||
@@ -3573,6 +3575,10 @@ void layout_resize_floating_pane_to(struct window_pane *,
|
|||||||
enum layout_type, u_int, char **);
|
enum layout_type, u_int, char **);
|
||||||
void layout_assign_pane(struct layout_cell *, struct window_pane *,
|
void layout_assign_pane(struct layout_cell *, struct window_pane *,
|
||||||
int);
|
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,
|
struct layout_cell *layout_split_pane(struct window_pane *, enum layout_type,
|
||||||
int, int);
|
int, int);
|
||||||
struct layout_cell *layout_floating_pane(struct window *, struct window_pane *,
|
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 *);
|
void layout_close_pane(struct window_pane *);
|
||||||
int layout_spread_cell(struct window *, struct layout_cell *);
|
int layout_spread_cell(struct window *, struct layout_cell *);
|
||||||
void layout_spread_out(struct window_pane *);
|
void layout_spread_out(struct window_pane *);
|
||||||
|
void layout_cell_floating_args_parse(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 layout_cell *layout_get_floating_cell(struct cmdq_item *, struct args *,
|
||||||
struct window *, struct window_pane *, char **);
|
struct window *, struct window_pane *, char **);
|
||||||
struct layout_cell *layout_get_tiled_cell(struct cmdq_item *, struct args *,
|
struct layout_cell *layout_get_tiled_cell(struct cmdq_item *, struct args *,
|
||||||
struct window *, struct window_pane *, int, char **);
|
struct window *, struct window_pane *, int, char **);
|
||||||
|
int layout_cell_is_tiled(struct layout_cell *);
|
||||||
|
int layout_remove_tile(struct window *, struct layout_cell *);
|
||||||
|
int layout_insert_tile(struct window *, struct layout_cell *);
|
||||||
|
|
||||||
/* layout-custom.c */
|
/* layout-custom.c */
|
||||||
char *layout_dump(struct window *, struct layout_cell *);
|
char *layout_dump(struct window *, struct layout_cell *);
|
||||||
|
|||||||
10
window.c
10
window.c
@@ -2208,3 +2208,13 @@ window_pane_is_floating(struct window_pane *wp)
|
|||||||
return (0);
|
return (0);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
window_pane_is_hidden(struct window_pane *wp)
|
||||||
|
{
|
||||||
|
struct layout_cell *lc = wp->layout_cell;
|
||||||
|
|
||||||
|
if ((lc->flags & LAYOUT_CELL_HIDDEN) == 0)
|
||||||
|
return (0);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user