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
|
else
|
||||||
size = (dst_wp->sx * percentage) / 100;
|
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) {
|
if (lc == NULL) {
|
||||||
cmdq_error(cmdq, "create pane failed: pane too small");
|
cmdq_error(cmdq, "create pane failed: pane too small");
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
|
@ -38,8 +38,8 @@ const struct cmd_entry cmd_split_window_entry = {
|
|||||||
.name = "split-window",
|
.name = "split-window",
|
||||||
.alias = "splitw",
|
.alias = "splitw",
|
||||||
|
|
||||||
.args = { "bc:dF:l:hp:Pt:v", 0, -1 },
|
.args = { "bc:dfF:l:hp:Pt:v", 0, -1 },
|
||||||
.usage = "[-bdhvP] [-c start-directory] [-F format] "
|
.usage = "[-bdfhvP] [-c start-directory] [-F format] "
|
||||||
"[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]",
|
"[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]",
|
||||||
|
|
||||||
.tflag = CMD_PANE,
|
.tflag = CMD_PANE,
|
||||||
@ -130,7 +130,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
if (*shell == '\0' || areshell(shell))
|
if (*shell == '\0' || areshell(shell))
|
||||||
shell = _PATH_BSHELL;
|
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) {
|
if (lc == NULL) {
|
||||||
cause = xstrdup("pane too small");
|
cause = xstrdup("pane too small");
|
||||||
goto error;
|
goto error;
|
||||||
|
275
layout.c
275
layout.c
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* 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
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* 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 *,
|
static int layout_resize_pane_shrink(struct window *, struct layout_cell *,
|
||||||
enum layout_type, int);
|
enum layout_type, int);
|
||||||
static int layout_need_status(struct layout_cell *, 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 *
|
struct layout_cell *
|
||||||
layout_create_cell(struct layout_cell *lcparent)
|
layout_create_cell(struct layout_cell *lcparent)
|
||||||
@ -267,17 +275,17 @@ u_int
|
|||||||
layout_count_cells(struct layout_cell *lc)
|
layout_count_cells(struct layout_cell *lc)
|
||||||
{
|
{
|
||||||
struct layout_cell *lcchild;
|
struct layout_cell *lcchild;
|
||||||
u_int n;
|
u_int count;
|
||||||
|
|
||||||
switch (lc->type) {
|
switch (lc->type) {
|
||||||
case LAYOUT_WINDOWPANE:
|
case LAYOUT_WINDOWPANE:
|
||||||
return (1);
|
return (1);
|
||||||
case LAYOUT_LEFTRIGHT:
|
case LAYOUT_LEFTRIGHT:
|
||||||
case LAYOUT_TOPBOTTOM:
|
case LAYOUT_TOPBOTTOM:
|
||||||
n = 0;
|
count = 0;
|
||||||
TAILQ_FOREACH(lcchild, &lc->cells, entry)
|
TAILQ_FOREACH(lcchild, &lc->cells, entry)
|
||||||
n += layout_count_cells(lcchild);
|
count += layout_count_cells(lcchild);
|
||||||
return (n);
|
return (count);
|
||||||
default:
|
default:
|
||||||
fatalx("bad layout type");
|
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);
|
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 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!
|
||||||
**/
|
*/
|
||||||
struct layout_cell *
|
struct layout_cell *
|
||||||
layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
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;
|
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
|
||||||
u_int sx, sy, xoff, yoff, size1, size2;
|
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. */
|
/* Copy the old cell size. */
|
||||||
sx = lc->sx;
|
sx = lc->sx;
|
||||||
@ -685,19 +841,75 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
|||||||
fatalx("bad layout type");
|
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 (lc->parent != NULL && lc->parent->type == type) {
|
||||||
/*
|
/*
|
||||||
* If the parent exists and is of the same type as the split,
|
* If the parent exists and is of the same type as the split,
|
||||||
* create a new cell and insert it after this one.
|
* create a new cell and insert it after this one.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Create the new child cell. */
|
|
||||||
lcparent = lc->parent;
|
lcparent = lc->parent;
|
||||||
lcnew = layout_create_cell(lcparent);
|
lcnew = layout_create_cell(lcparent);
|
||||||
if (insert_before)
|
if (insert_before)
|
||||||
TAILQ_INSERT_BEFORE(lc, lcnew, entry);
|
TAILQ_INSERT_BEFORE(lc, lcnew, entry);
|
||||||
else
|
else
|
||||||
TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry);
|
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 {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Otherwise create a new parent and insert it.
|
* 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;
|
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) {
|
if (!resize_first && type == LAYOUT_LEFTRIGHT) {
|
||||||
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;
|
|
||||||
layout_set_size(lc1, size1, sy, xoff, yoff);
|
layout_set_size(lc1, size1, sy, xoff, yoff);
|
||||||
layout_set_size(lc2, size2, sy, xoff + lc1->sx + 1, yoff);
|
layout_set_size(lc2, size2, sy, xoff + lc1->sx + 1, yoff);
|
||||||
break;
|
} else if (!resize_first && type == LAYOUT_TOPBOTTOM) {
|
||||||
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;
|
|
||||||
layout_set_size(lc1, sx, size1, xoff, yoff);
|
layout_set_size(lc1, sx, size1, xoff, yoff);
|
||||||
layout_set_size(lc2, sx, size2, xoff, yoff + lc1->sy + 1);
|
layout_set_size(lc2, sx, size2, xoff, yoff + lc1->sy + 1);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fatalx("bad layout type");
|
|
||||||
}
|
}
|
||||||
|
if (full_size) {
|
||||||
/* Assign the panes. */
|
if (!resize_first)
|
||||||
layout_make_leaf(lc, wp);
|
layout_resize_child_cells(wp->window, lc);
|
||||||
|
layout_fix_offsets(wp->window->layout_root);
|
||||||
|
} else
|
||||||
|
layout_make_leaf(lc, wp);
|
||||||
|
|
||||||
return (lcnew);
|
return (lcnew);
|
||||||
}
|
}
|
||||||
|
7
tmux.1
7
tmux.1
@ -2015,6 +2015,13 @@ The
|
|||||||
.Fl b
|
.Fl b
|
||||||
option causes the new pane to be created to the left of or above
|
option causes the new pane to be created to the left of or above
|
||||||
.Ar target-pane .
|
.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
|
All other options have the same meaning as for the
|
||||||
.Ic new-window
|
.Ic new-window
|
||||||
command.
|
command.
|
||||||
|
2
tmux.h
2
tmux.h
@ -2207,7 +2207,7 @@ void layout_resize_pane_to(struct window_pane *, enum layout_type,
|
|||||||
u_int);
|
u_int);
|
||||||
void layout_assign_pane(struct layout_cell *, struct window_pane *);
|
void layout_assign_pane(struct layout_cell *, struct window_pane *);
|
||||||
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, int);
|
||||||
void layout_close_pane(struct window_pane *);
|
void layout_close_pane(struct window_pane *);
|
||||||
|
|
||||||
/* layout-custom.c */
|
/* layout-custom.c */
|
||||||
|
Loading…
Reference in New Issue
Block a user