mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-03 16:46:18 +00:00 
			
		
		
		
	Merge branch 'obsd-master'
This commit is contained in:
		@@ -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 */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user