mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 09:26:05 +00:00 
			
		
		
		
	Both the two previous ways of navigating panes by direction have
irritating flaws: a) The old way of always using the top or left if the choice is ambiguous is annoying when the layout is unbalanced. b) The new way of remembering the last used pane is annoying if the layout is balanced and the leftmost is obvious to the user (because clearly if we go right from the top-left in a tiled set of four we want to end up in top-right, even if we were last using the bottom-right). So instead, use a combination of both: if there is only one possible pane alongside the current pane, move to it, otherwise choose the most recently used of the choice.
This commit is contained in:
		
							
								
								
									
										1
									
								
								layout.c
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								layout.c
									
									
									
									
									
								
							@@ -53,7 +53,6 @@ layout_create_cell(struct layout_cell *lcparent)
 | 
			
		||||
	lc->yoff = UINT_MAX;
 | 
			
		||||
 | 
			
		||||
	lc->wp = NULL;
 | 
			
		||||
	lc->lastwp = NULL;
 | 
			
		||||
 | 
			
		||||
	return (lc);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								tmux.h
									
									
									
									
									
								
							@@ -892,6 +892,7 @@ struct window_choose_mode_item {
 | 
			
		||||
/* Child window structure. */
 | 
			
		||||
struct window_pane {
 | 
			
		||||
	u_int		 id;
 | 
			
		||||
	u_int		 active_point;
 | 
			
		||||
 | 
			
		||||
	struct window	*window;
 | 
			
		||||
 | 
			
		||||
@@ -948,6 +949,7 @@ struct window_pane {
 | 
			
		||||
};
 | 
			
		||||
TAILQ_HEAD(window_panes, window_pane);
 | 
			
		||||
RB_HEAD(window_pane_tree, window_pane);
 | 
			
		||||
ARRAY_DECL(window_pane_list, struct window_pane *);
 | 
			
		||||
 | 
			
		||||
/* Window structure. */
 | 
			
		||||
struct window {
 | 
			
		||||
@@ -1025,8 +1027,6 @@ struct layout_cell {
 | 
			
		||||
	u_int		 yoff;
 | 
			
		||||
 | 
			
		||||
	struct window_pane *wp;
 | 
			
		||||
	struct window_pane *lastwp;
 | 
			
		||||
 | 
			
		||||
	struct layout_cells cells;
 | 
			
		||||
 | 
			
		||||
	TAILQ_ENTRY(layout_cell) entry;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										267
									
								
								window.c
									
									
									
									
									
								
							
							
						
						
									
										267
									
								
								window.c
									
									
									
									
									
								
							@@ -56,15 +56,14 @@ struct windows windows;
 | 
			
		||||
struct window_pane_tree all_window_panes;
 | 
			
		||||
u_int	next_window_pane_id;
 | 
			
		||||
u_int	next_window_id;
 | 
			
		||||
 | 
			
		||||
struct window_pane *window_pane_active_set(struct window_pane *,
 | 
			
		||||
	    struct window_pane *);
 | 
			
		||||
void	window_pane_active_lost(struct window_pane *, struct window_pane *);
 | 
			
		||||
u_int	next_active_point;
 | 
			
		||||
 | 
			
		||||
void	window_pane_timer_callback(int, short, void *);
 | 
			
		||||
void	window_pane_read_callback(struct bufferevent *, void *);
 | 
			
		||||
void	window_pane_error_callback(struct bufferevent *, short, void *);
 | 
			
		||||
 | 
			
		||||
struct window_pane *window_pane_choose_best(struct window_pane_list *);
 | 
			
		||||
 | 
			
		||||
RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
@@ -387,64 +386,6 @@ window_resize(struct window *w, u_int sx, u_int sy)
 | 
			
		||||
	w->sy = sy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Restore previously active pane when changing from wp to nextwp. The intended
 | 
			
		||||
 * pane is in nextwp and it returns the previously focused pane.
 | 
			
		||||
 */
 | 
			
		||||
struct window_pane *
 | 
			
		||||
window_pane_active_set(struct window_pane *wp, struct window_pane *nextwp)
 | 
			
		||||
{
 | 
			
		||||
	struct layout_cell	*lc;
 | 
			
		||||
	struct window_pane	*lastwp;
 | 
			
		||||
 | 
			
		||||
	/* Target pane's parent must not be an ancestor of source pane. */
 | 
			
		||||
	for (lc = wp->layout_cell->parent; lc != NULL; lc = lc->parent) {
 | 
			
		||||
		if (lc == nextwp->layout_cell->parent)
 | 
			
		||||
			return (nextwp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Previously active pane, if any, must not be the same as the source
 | 
			
		||||
	 * pane.
 | 
			
		||||
	 */
 | 
			
		||||
	lc = nextwp->layout_cell->parent;
 | 
			
		||||
	if (lc != NULL && lc->lastwp != NULL) {
 | 
			
		||||
		lastwp = lc->lastwp;
 | 
			
		||||
		if (lastwp != wp && window_pane_visible(lastwp))
 | 
			
		||||
			return (lastwp);
 | 
			
		||||
	}
 | 
			
		||||
	return (nextwp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Remember previously active pane when changing from wp to nextwp. */
 | 
			
		||||
void
 | 
			
		||||
window_pane_active_lost(struct window_pane *wp, struct window_pane *nextwp)
 | 
			
		||||
{
 | 
			
		||||
	struct layout_cell	*lc, *lc2, *lcparent;
 | 
			
		||||
 | 
			
		||||
	/* Get the parent cell. */
 | 
			
		||||
	lcparent = nextwp->layout_cell->parent;
 | 
			
		||||
	if (lcparent == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* Save the target pane in its parent. */
 | 
			
		||||
	lcparent->lastwp = nextwp;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Save the source pane in all of its parents up to, but not including,
 | 
			
		||||
	 * the common ancestor of itself and the target panes.
 | 
			
		||||
	 */
 | 
			
		||||
	if (wp == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
	for (lc = wp->layout_cell->parent; lc != NULL; lc = lc->parent) {
 | 
			
		||||
		for (lc2 = lcparent; lc2 != NULL; lc2 = lc2->parent) {
 | 
			
		||||
			if (lc == lc2)
 | 
			
		||||
				return;
 | 
			
		||||
		}
 | 
			
		||||
		lc->lastwp = wp;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
window_set_active_pane(struct window *w, struct window_pane *wp)
 | 
			
		||||
{
 | 
			
		||||
@@ -452,7 +393,6 @@ window_set_active_pane(struct window *w, struct window_pane *wp)
 | 
			
		||||
		return;
 | 
			
		||||
	w->last = w->active;
 | 
			
		||||
	w->active = wp;
 | 
			
		||||
	window_pane_active_lost(w->last, wp);
 | 
			
		||||
	while (!window_pane_visible(w->active)) {
 | 
			
		||||
		w->active = TAILQ_PREV(w->active, window_panes, entry);
 | 
			
		||||
		if (w->active == NULL)
 | 
			
		||||
@@ -460,6 +400,7 @@ window_set_active_pane(struct window *w, struct window_pane *wp)
 | 
			
		||||
		if (w->active == wp)
 | 
			
		||||
			return;
 | 
			
		||||
	}
 | 
			
		||||
	w->active->active_point = next_active_point++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct window_pane *
 | 
			
		||||
@@ -771,16 +712,6 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
 | 
			
		||||
void
 | 
			
		||||
window_pane_destroy(struct window_pane *wp)
 | 
			
		||||
{
 | 
			
		||||
	struct window_pane	*wp2;
 | 
			
		||||
 | 
			
		||||
	/* Forget removed pane in all layout cells that remember it. */
 | 
			
		||||
	RB_FOREACH(wp2, window_pane_tree, &all_window_panes) {
 | 
			
		||||
		if (wp2->layout_cell != NULL &&
 | 
			
		||||
		    wp2->layout_cell->parent != NULL &&
 | 
			
		||||
		    wp2->layout_cell->parent->lastwp == wp)
 | 
			
		||||
			wp2->layout_cell->parent->lastwp = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	window_pane_reset_mode(wp);
 | 
			
		||||
 | 
			
		||||
	if (event_initialized(&wp->changes_timer))
 | 
			
		||||
@@ -1187,114 +1118,198 @@ window_pane_search(struct window_pane *wp, const char *searchstr,
 | 
			
		||||
	return (msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Find the pane directly above another. */
 | 
			
		||||
/* Get MRU pane from a list. */
 | 
			
		||||
struct window_pane *
 | 
			
		||||
window_pane_choose_best(struct window_pane_list *list)
 | 
			
		||||
{
 | 
			
		||||
	struct window_pane	*next, *best;
 | 
			
		||||
	u_int			 i;
 | 
			
		||||
 | 
			
		||||
	if (ARRAY_LENGTH(list) == 0)
 | 
			
		||||
		return (NULL);
 | 
			
		||||
 | 
			
		||||
	best = ARRAY_FIRST(list);
 | 
			
		||||
	for (i = 1; i < ARRAY_LENGTH(list); i++) {
 | 
			
		||||
		next = ARRAY_ITEM(list, i);
 | 
			
		||||
		if (next->active_point > best->active_point)
 | 
			
		||||
			best = next;
 | 
			
		||||
	}
 | 
			
		||||
	return (best);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Find the pane directly above another. We build a list of those adjacent to
 | 
			
		||||
 * top edge and then choose the best.
 | 
			
		||||
 */
 | 
			
		||||
struct window_pane *
 | 
			
		||||
window_pane_find_up(struct window_pane *wp)
 | 
			
		||||
{
 | 
			
		||||
	struct window_pane     *wp2;
 | 
			
		||||
	u_int			left, top;
 | 
			
		||||
	struct window_pane	*next, *best;
 | 
			
		||||
	u_int			 edge, left, right, end;
 | 
			
		||||
	struct window_pane_list	 list;
 | 
			
		||||
	int			 found;
 | 
			
		||||
 | 
			
		||||
	if (wp == NULL || !window_pane_visible(wp))
 | 
			
		||||
		return (NULL);
 | 
			
		||||
	ARRAY_INIT(&list);
 | 
			
		||||
 | 
			
		||||
	edge = wp->yoff;
 | 
			
		||||
	if (edge == 0)
 | 
			
		||||
		edge = wp->window->sy + 1;
 | 
			
		||||
 | 
			
		||||
	top = wp->yoff;
 | 
			
		||||
	if (top == 0)
 | 
			
		||||
		top = wp->window->sy + 1;
 | 
			
		||||
	left = wp->xoff;
 | 
			
		||||
	right = wp->xoff + wp->sx;
 | 
			
		||||
 | 
			
		||||
	TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
 | 
			
		||||
		if (!window_pane_visible(wp2))
 | 
			
		||||
	TAILQ_FOREACH(next, &wp->window->panes, entry) {
 | 
			
		||||
		if (next == wp || !window_pane_visible(next))
 | 
			
		||||
			continue;
 | 
			
		||||
		if (wp2->yoff + wp2->sy + 1 != top)
 | 
			
		||||
		if (next->yoff + next->sy + 1 != edge)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
 | 
			
		||||
			return (window_pane_active_set(wp, wp2));
 | 
			
		||||
		end = next->xoff + next->sx - 1;
 | 
			
		||||
 | 
			
		||||
		found = 0;
 | 
			
		||||
		if (next->xoff < left && end > right)
 | 
			
		||||
			found = 1;
 | 
			
		||||
		else if (next->xoff >= left && next->xoff <= right)
 | 
			
		||||
			found = 1;
 | 
			
		||||
		else if (end >= left && end <= right)
 | 
			
		||||
			found = 1;
 | 
			
		||||
		if (found)
 | 
			
		||||
			ARRAY_ADD(&list, next);
 | 
			
		||||
	}
 | 
			
		||||
	return (NULL);
 | 
			
		||||
 | 
			
		||||
	best = window_pane_choose_best(&list);
 | 
			
		||||
	ARRAY_FREE(&list);
 | 
			
		||||
	return (best);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Find the pane directly below another. */
 | 
			
		||||
struct window_pane *
 | 
			
		||||
window_pane_find_down(struct window_pane *wp)
 | 
			
		||||
{
 | 
			
		||||
	struct window_pane     *wp2;
 | 
			
		||||
	u_int			left, bottom;
 | 
			
		||||
	struct window_pane	*next, *best;
 | 
			
		||||
	u_int			 edge, left, right, end;
 | 
			
		||||
	struct window_pane_list	 list;
 | 
			
		||||
	int			 found;
 | 
			
		||||
 | 
			
		||||
	if (wp == NULL || !window_pane_visible(wp))
 | 
			
		||||
		return (NULL);
 | 
			
		||||
	ARRAY_INIT(&list);
 | 
			
		||||
 | 
			
		||||
	edge = wp->yoff + wp->sy + 1;
 | 
			
		||||
	if (edge >= wp->window->sy)
 | 
			
		||||
		edge = 0;
 | 
			
		||||
 | 
			
		||||
	bottom = wp->yoff + wp->sy + 1;
 | 
			
		||||
	if (bottom >= wp->window->sy)
 | 
			
		||||
		bottom = 0;
 | 
			
		||||
	left = wp->xoff;
 | 
			
		||||
	right = wp->xoff + wp->sx;
 | 
			
		||||
 | 
			
		||||
	TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
 | 
			
		||||
		if (!window_pane_visible(wp2))
 | 
			
		||||
	TAILQ_FOREACH(next, &wp->window->panes, entry) {
 | 
			
		||||
		if (next == wp || !window_pane_visible(next))
 | 
			
		||||
			continue;
 | 
			
		||||
		if (wp2->yoff != bottom)
 | 
			
		||||
		if (next->yoff != edge)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
 | 
			
		||||
			return (window_pane_active_set(wp, wp2));
 | 
			
		||||
		end = next->xoff + next->sx - 1;
 | 
			
		||||
 | 
			
		||||
		found = 0;
 | 
			
		||||
		if (next->xoff < left && end > right)
 | 
			
		||||
			found = 1;
 | 
			
		||||
		else if (next->xoff >= left && next->xoff <= right)
 | 
			
		||||
			found = 1;
 | 
			
		||||
		else if (end >= left && end <= right)
 | 
			
		||||
			found = 1;
 | 
			
		||||
		if (found)
 | 
			
		||||
			ARRAY_ADD(&list, next);
 | 
			
		||||
	}
 | 
			
		||||
	return (NULL);
 | 
			
		||||
 | 
			
		||||
	best = window_pane_choose_best(&list);
 | 
			
		||||
	ARRAY_FREE(&list);
 | 
			
		||||
	return (best);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Find the pane directly to the left of another, adjacent to the left side and
 | 
			
		||||
 * containing the top edge.
 | 
			
		||||
 */
 | 
			
		||||
/* Find the pane directly to the left of another. */
 | 
			
		||||
struct window_pane *
 | 
			
		||||
window_pane_find_left(struct window_pane *wp)
 | 
			
		||||
{
 | 
			
		||||
	struct window_pane     *wp2;
 | 
			
		||||
	u_int			left, top;
 | 
			
		||||
	struct window_pane	*next, *best;
 | 
			
		||||
	u_int			 edge, top, bottom, end;
 | 
			
		||||
	struct window_pane_list	 list;
 | 
			
		||||
	int			 found;
 | 
			
		||||
 | 
			
		||||
	if (wp == NULL || !window_pane_visible(wp))
 | 
			
		||||
		return (NULL);
 | 
			
		||||
	ARRAY_INIT(&list);
 | 
			
		||||
 | 
			
		||||
	edge = wp->xoff;
 | 
			
		||||
	if (edge == 0)
 | 
			
		||||
		edge = wp->window->sx + 1;
 | 
			
		||||
 | 
			
		||||
	left = wp->xoff;
 | 
			
		||||
	if (left == 0)
 | 
			
		||||
		left = wp->window->sx + 1;
 | 
			
		||||
	top = wp->yoff;
 | 
			
		||||
	bottom = wp->yoff + wp->sy;
 | 
			
		||||
 | 
			
		||||
	TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
 | 
			
		||||
		if (!window_pane_visible(wp2))
 | 
			
		||||
	TAILQ_FOREACH(next, &wp->window->panes, entry) {
 | 
			
		||||
		if (next == wp || !window_pane_visible(next))
 | 
			
		||||
			continue;
 | 
			
		||||
		if (wp2->xoff + wp2->sx + 1 != left)
 | 
			
		||||
		if (next->xoff + next->sx + 1 != edge)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
 | 
			
		||||
			return (window_pane_active_set(wp, wp2));
 | 
			
		||||
		end = next->yoff + next->sy - 1;
 | 
			
		||||
 | 
			
		||||
		found = 0;
 | 
			
		||||
		if (next->yoff < top && end > bottom)
 | 
			
		||||
			found = 1;
 | 
			
		||||
		else if (next->yoff >= top && next->yoff <= bottom)
 | 
			
		||||
			found = 1;
 | 
			
		||||
		else if (end >= top && end <= bottom)
 | 
			
		||||
			found = 1;
 | 
			
		||||
		if (found)
 | 
			
		||||
			ARRAY_ADD(&list, next);
 | 
			
		||||
	}
 | 
			
		||||
	return (NULL);
 | 
			
		||||
 | 
			
		||||
	best = window_pane_choose_best(&list);
 | 
			
		||||
	ARRAY_FREE(&list);
 | 
			
		||||
	return (best);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Find the pane directly to the right of another, that is adjacent to the
 | 
			
		||||
 * right edge and including the top edge.
 | 
			
		||||
 */
 | 
			
		||||
/* Find the pane directly to the right of another. */
 | 
			
		||||
struct window_pane *
 | 
			
		||||
window_pane_find_right(struct window_pane *wp)
 | 
			
		||||
{
 | 
			
		||||
	struct window_pane     *wp2;
 | 
			
		||||
	u_int			right, top;
 | 
			
		||||
	struct window_pane	*next, *best;
 | 
			
		||||
	u_int			 edge, top, bottom, end;
 | 
			
		||||
	struct window_pane_list	 list;
 | 
			
		||||
	int			 found;
 | 
			
		||||
 | 
			
		||||
	if (wp == NULL || !window_pane_visible(wp))
 | 
			
		||||
		return (NULL);
 | 
			
		||||
	ARRAY_INIT(&list);
 | 
			
		||||
 | 
			
		||||
	edge = wp->xoff + wp->sx + 1;
 | 
			
		||||
	if (edge >= wp->window->sx)
 | 
			
		||||
		edge = 0;
 | 
			
		||||
 | 
			
		||||
	right = wp->xoff + wp->sx + 1;
 | 
			
		||||
	if (right >= wp->window->sx)
 | 
			
		||||
		right = 0;
 | 
			
		||||
	top = wp->yoff;
 | 
			
		||||
	bottom = wp->yoff + wp->sy;
 | 
			
		||||
 | 
			
		||||
	TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
 | 
			
		||||
		if (!window_pane_visible(wp2))
 | 
			
		||||
	TAILQ_FOREACH(next, &wp->window->panes, entry) {
 | 
			
		||||
		if (next == wp || !window_pane_visible(next))
 | 
			
		||||
			continue;
 | 
			
		||||
		if (wp2->xoff != right)
 | 
			
		||||
		if (next->xoff != edge)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
 | 
			
		||||
			return (window_pane_active_set(wp, wp2));
 | 
			
		||||
		end = next->yoff + next->sy - 1;
 | 
			
		||||
 | 
			
		||||
		found = 0;
 | 
			
		||||
		if (next->yoff < top && end > bottom)
 | 
			
		||||
			found = 1;
 | 
			
		||||
		else if (next->yoff >= top && next->yoff <= bottom)
 | 
			
		||||
			found = 1;
 | 
			
		||||
		else if (end >= top && end <= bottom)
 | 
			
		||||
			found = 1;
 | 
			
		||||
		if (found)
 | 
			
		||||
			ARRAY_ADD(&list, next);
 | 
			
		||||
	}
 | 
			
		||||
	return (NULL);
 | 
			
		||||
 | 
			
		||||
	best = window_pane_choose_best(&list);
 | 
			
		||||
	ARRAY_FREE(&list);
 | 
			
		||||
	return (best);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Clear alert flags for a winlink */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user