mirror of
https://github.com/tmux/tmux.git
synced 2024-12-13 01:48:47 +00:00
Merge branch 'obsd-master'
This commit is contained in:
commit
f68a908c8a
@ -124,7 +124,7 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
|
||||
else
|
||||
size = (dst_wp->sx * percentage) / 100;
|
||||
}
|
||||
lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'));
|
||||
lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'), 0);
|
||||
if (lc == NULL) {
|
||||
cmdq_error(cmdq, "create pane failed: pane too small");
|
||||
return (CMD_RETURN_ERROR);
|
||||
|
@ -38,8 +38,8 @@ const struct cmd_entry cmd_split_window_entry = {
|
||||
.name = "split-window",
|
||||
.alias = "splitw",
|
||||
|
||||
.args = { "bc:dF:l:hp:Pt:v", 0, -1 },
|
||||
.usage = "[-bdhvP] [-c start-directory] [-F format] "
|
||||
.args = { "bc:dfF:l:hp:Pt:v", 0, -1 },
|
||||
.usage = "[-bdfhvP] [-c start-directory] [-F format] "
|
||||
"[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]",
|
||||
|
||||
.tflag = CMD_PANE,
|
||||
@ -130,7 +130,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||
if (*shell == '\0' || areshell(shell))
|
||||
shell = _PATH_BSHELL;
|
||||
|
||||
lc = layout_split_pane(wp, type, size, args_has(args, 'b'));
|
||||
lc = layout_split_pane(wp, type, size, args_has(args, 'b'),
|
||||
args_has(args, 'f'));
|
||||
if (lc == NULL) {
|
||||
cause = xstrdup("pane too small");
|
||||
goto error;
|
||||
|
275
layout.c
275
layout.c
@ -2,6 +2,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
* Copyright (c) 2016 Stephen Kent <smkent@smkent.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -39,6 +40,13 @@ static int layout_resize_pane_grow(struct window *, struct layout_cell *,
|
||||
static int layout_resize_pane_shrink(struct window *, struct layout_cell *,
|
||||
enum layout_type, int);
|
||||
static int layout_need_status(struct layout_cell *, int);
|
||||
static u_int layout_new_pane_size(struct window *, u_int,
|
||||
struct layout_cell *, enum layout_type, u_int, u_int,
|
||||
u_int);
|
||||
static int layout_set_size_check(struct window *, struct layout_cell *,
|
||||
enum layout_type, int);
|
||||
static void layout_resize_child_cells(struct window *,
|
||||
struct layout_cell *);
|
||||
|
||||
struct layout_cell *
|
||||
layout_create_cell(struct layout_cell *lcparent)
|
||||
@ -267,17 +275,17 @@ u_int
|
||||
layout_count_cells(struct layout_cell *lc)
|
||||
{
|
||||
struct layout_cell *lcchild;
|
||||
u_int n;
|
||||
u_int count;
|
||||
|
||||
switch (lc->type) {
|
||||
case LAYOUT_WINDOWPANE:
|
||||
return (1);
|
||||
case LAYOUT_LEFTRIGHT:
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
n = 0;
|
||||
count = 0;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry)
|
||||
n += layout_count_cells(lcchild);
|
||||
return (n);
|
||||
count += layout_count_cells(lcchild);
|
||||
return (count);
|
||||
default:
|
||||
fatalx("bad layout type");
|
||||
}
|
||||
@ -652,18 +660,166 @@ layout_assign_pane(struct layout_cell *lc, struct window_pane *wp)
|
||||
layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
|
||||
}
|
||||
|
||||
/* Calculate the new pane size for resized parent. */
|
||||
static u_int
|
||||
layout_new_pane_size(struct window *w, u_int previous, struct layout_cell *lc,
|
||||
enum layout_type type, u_int size, u_int count_left, u_int size_left)
|
||||
{
|
||||
u_int new_size, min, max, available;
|
||||
|
||||
/* If this is the last cell, it can take all of the remaining size. */
|
||||
if (count_left == 1)
|
||||
return (size_left);
|
||||
|
||||
/* How much is available in this parent? */
|
||||
available = layout_resize_check(w, lc, type);
|
||||
|
||||
/*
|
||||
* Work out the minimum size of this cell and the new size
|
||||
* proportionate to the previous size.
|
||||
*/
|
||||
min = (PANE_MINIMUM + 1) * (count_left - 1);
|
||||
if (type == LAYOUT_LEFTRIGHT) {
|
||||
if (lc->sx - available > min)
|
||||
min = lc->sx - available;
|
||||
new_size = (lc->sx * size) / previous;
|
||||
} else {
|
||||
if (lc->sy - available > min)
|
||||
min = lc->sy - available;
|
||||
new_size = (lc->sy * size) / previous;
|
||||
}
|
||||
|
||||
/* Check against the maximum and minimum size. */
|
||||
max = size_left - min;
|
||||
if (new_size > max)
|
||||
new_size = max;
|
||||
if (new_size < PANE_MINIMUM)
|
||||
new_size = PANE_MINIMUM;
|
||||
return (new_size);
|
||||
}
|
||||
|
||||
/* Check if the cell and all its children can be resized to a specific size. */
|
||||
static int
|
||||
layout_set_size_check(struct window *w, struct layout_cell *lc,
|
||||
enum layout_type type, int size)
|
||||
{
|
||||
struct layout_cell *lcchild;
|
||||
u_int new_size, available, previous, count, idx;
|
||||
|
||||
/* Cells with no children must just be bigger than minimum. */
|
||||
if (lc->type == LAYOUT_WINDOWPANE)
|
||||
return (size >= PANE_MINIMUM);
|
||||
available = size;
|
||||
|
||||
/* Count number of children. */
|
||||
count = 0;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry)
|
||||
count++;
|
||||
|
||||
/* Check new size will work for each child. */
|
||||
if (lc->type == type) {
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
previous = lc->sx;
|
||||
else
|
||||
previous = lc->sy;
|
||||
|
||||
idx = 0;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
new_size = layout_new_pane_size(w, previous, lcchild,
|
||||
type, size, count - idx, available);
|
||||
if (new_size > available)
|
||||
return (0);
|
||||
|
||||
available -= (new_size + 1);
|
||||
if (!layout_set_size_check(w, lcchild, type, new_size))
|
||||
return (0);
|
||||
|
||||
idx++;
|
||||
}
|
||||
} else {
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (lcchild->type == LAYOUT_WINDOWPANE)
|
||||
continue;
|
||||
if (!layout_set_size_check(w, lcchild, type, size))
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Resize all child cells to fit within the current cell. */
|
||||
static void
|
||||
layout_resize_child_cells(struct window *w, struct layout_cell *lc)
|
||||
{
|
||||
struct layout_cell *lcchild;
|
||||
u_int previous, available, count, idx;
|
||||
|
||||
if (lc->type == LAYOUT_WINDOWPANE)
|
||||
return;
|
||||
|
||||
/* What is the current size used? */
|
||||
count = 0;
|
||||
previous = 0;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
count++;
|
||||
if (lc->type == LAYOUT_LEFTRIGHT)
|
||||
previous += lcchild->sx;
|
||||
else if (lc->type == LAYOUT_TOPBOTTOM)
|
||||
previous += lcchild->sy;
|
||||
}
|
||||
previous += (count - 1);
|
||||
|
||||
/* And how much is available? */
|
||||
available = 0;
|
||||
if (lc->type == LAYOUT_LEFTRIGHT)
|
||||
available = lc->sx;
|
||||
else if (lc->type == LAYOUT_TOPBOTTOM)
|
||||
available = lc->sy;
|
||||
|
||||
/* Resize children into the new size. */
|
||||
idx = 0;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (lc->type == LAYOUT_TOPBOTTOM) {
|
||||
lcchild->sx = lc->sx;
|
||||
lcchild->xoff = lc->xoff;
|
||||
} else {
|
||||
lcchild->sx = layout_new_pane_size(w, previous, lcchild,
|
||||
lc->type, lc->sx, count - idx, available);
|
||||
available -= (lcchild->sx + 1);
|
||||
}
|
||||
if (lc->type == LAYOUT_LEFTRIGHT)
|
||||
lcchild->sy = lc->sy;
|
||||
else {
|
||||
lcchild->sy = layout_new_pane_size(w, previous, lcchild,
|
||||
lc->type, lc->sy, count - idx, available);
|
||||
available -= (lcchild->sy + 1);
|
||||
}
|
||||
layout_resize_child_cells(w, lcchild);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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!
|
||||
**/
|
||||
*/
|
||||
struct layout_cell *
|
||||
layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
int insert_before)
|
||||
int insert_before, int full_size)
|
||||
{
|
||||
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
|
||||
u_int sx, sy, xoff, yoff, size1, size2;
|
||||
u_int new_size, saved_size, resize_first = 0;
|
||||
|
||||
lc = wp->layout_cell;
|
||||
/*
|
||||
* If full_size is specified, add a new cell at the top of the window
|
||||
* layout. Otherwise, split the cell for the current pane.
|
||||
*/
|
||||
if (full_size)
|
||||
lc = wp->window->layout_root;
|
||||
else
|
||||
lc = wp->layout_cell;
|
||||
|
||||
/* Copy the old cell size. */
|
||||
sx = lc->sx;
|
||||
@ -685,19 +841,75 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
fatalx("bad layout type");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 (insert_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? */
|
||||
if (insert_before)
|
||||
new_size = size2;
|
||||
else
|
||||
new_size = size1;
|
||||
|
||||
/* Confirm there is enough space for full size pane. */
|
||||
if (full_size && !layout_set_size_check(wp->window, lc, type, new_size))
|
||||
return (NULL);
|
||||
|
||||
if (lc->parent != NULL && lc->parent->type == type) {
|
||||
/*
|
||||
* If the parent exists and is of the same type as the split,
|
||||
* create a new cell and insert it after this one.
|
||||
*/
|
||||
|
||||
/* Create the new child cell. */
|
||||
lcparent = lc->parent;
|
||||
lcnew = layout_create_cell(lcparent);
|
||||
if (insert_before)
|
||||
TAILQ_INSERT_BEFORE(lc, lcnew, entry);
|
||||
else
|
||||
TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry);
|
||||
} else if (full_size && lc->parent == NULL && lc->type == type) {
|
||||
/*
|
||||
* If the new full size pane is the same type as the root
|
||||
* split, insert the new pane under the existing root cell
|
||||
* instead of creating a new root cell. The existing layout
|
||||
* must be resized before inserting the new cell.
|
||||
*/
|
||||
if (lc->type == LAYOUT_LEFTRIGHT) {
|
||||
lc->sx = new_size;
|
||||
layout_resize_child_cells(wp->window, lc);
|
||||
lc->sx = saved_size;
|
||||
} else if (lc->type == LAYOUT_TOPBOTTOM) {
|
||||
lc->sy = new_size;
|
||||
layout_resize_child_cells(wp->window, lc);
|
||||
lc->sy = saved_size;
|
||||
}
|
||||
resize_first = 1;
|
||||
|
||||
/* Create the new cell. */
|
||||
lcnew = layout_create_cell(lc);
|
||||
if (lc->type == LAYOUT_LEFTRIGHT)
|
||||
layout_set_size(lcnew, new_size, sy, 0, 0);
|
||||
else if (lc->type == LAYOUT_TOPBOTTOM)
|
||||
layout_set_size(lcnew, sx, new_size, 0, 0);
|
||||
if (insert_before)
|
||||
TAILQ_INSERT_HEAD(&lc->cells, lcnew, entry);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
|
||||
} else {
|
||||
/*
|
||||
* Otherwise create a new parent and insert it.
|
||||
@ -731,46 +943,23 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
lc2 = lcnew;
|
||||
}
|
||||
|
||||
/* Set 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.
|
||||
/*
|
||||
* Set new cell sizes. size1 is the size of the top/left and size2 the
|
||||
* bottom/right.
|
||||
*/
|
||||
switch (type) {
|
||||
case LAYOUT_LEFTRIGHT:
|
||||
if (size < 0)
|
||||
size2 = ((sx + 1) / 2) - 1;
|
||||
else if (insert_before)
|
||||
size2 = sx - size - 1;
|
||||
else
|
||||
size2 = size;
|
||||
if (size2 < PANE_MINIMUM)
|
||||
size2 = PANE_MINIMUM;
|
||||
else if (size2 > sx - 2)
|
||||
size2 = sx - 2;
|
||||
size1 = sx - 1 - size2;
|
||||
if (!resize_first && type == LAYOUT_LEFTRIGHT) {
|
||||
layout_set_size(lc1, size1, sy, xoff, yoff);
|
||||
layout_set_size(lc2, size2, sy, xoff + lc1->sx + 1, yoff);
|
||||
break;
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
if (size < 0)
|
||||
size2 = ((sy + 1) / 2) - 1;
|
||||
else if (insert_before)
|
||||
size2 = sy - size - 1;
|
||||
else
|
||||
size2 = size;
|
||||
if (size2 < PANE_MINIMUM)
|
||||
size2 = PANE_MINIMUM;
|
||||
else if (size2 > sy - 2)
|
||||
size2 = sy - 2;
|
||||
size1 = sy - 1 - size2;
|
||||
} else if (!resize_first && type == LAYOUT_TOPBOTTOM) {
|
||||
layout_set_size(lc1, sx, size1, xoff, yoff);
|
||||
layout_set_size(lc2, sx, size2, xoff, yoff + lc1->sy + 1);
|
||||
break;
|
||||
default:
|
||||
fatalx("bad layout type");
|
||||
}
|
||||
|
||||
/* Assign the panes. */
|
||||
layout_make_leaf(lc, wp);
|
||||
if (full_size) {
|
||||
if (!resize_first)
|
||||
layout_resize_child_cells(wp->window, lc);
|
||||
layout_fix_offsets(wp->window->layout_root);
|
||||
} else
|
||||
layout_make_leaf(lc, wp);
|
||||
|
||||
return (lcnew);
|
||||
}
|
||||
|
7
tmux.1
7
tmux.1
@ -2015,6 +2015,13 @@ The
|
||||
.Fl b
|
||||
option causes the new pane to be created to the left of or above
|
||||
.Ar target-pane .
|
||||
The
|
||||
.Fl f
|
||||
option creates a new pane spanning the full window height (with
|
||||
.Fl h )
|
||||
or full window width (with
|
||||
.Fl v ) ,
|
||||
instead of splitting the active pane.
|
||||
All other options have the same meaning as for the
|
||||
.Ic new-window
|
||||
command.
|
||||
|
2
tmux.h
2
tmux.h
@ -2207,7 +2207,7 @@ void layout_resize_pane_to(struct window_pane *, enum layout_type,
|
||||
u_int);
|
||||
void layout_assign_pane(struct layout_cell *, struct window_pane *);
|
||||
struct layout_cell *layout_split_pane(struct window_pane *, enum layout_type,
|
||||
int, int);
|
||||
int, int, int);
|
||||
void layout_close_pane(struct window_pane *);
|
||||
|
||||
/* layout-custom.c */
|
||||
|
Loading…
Reference in New Issue
Block a user