-/* $OpenBSD: window.c,v 1.108 2014/04/17 14:45:49 nicm Exp $ */
+/* $OpenBSD: window.c,v 1.109 2014/05/08 06:03:30 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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
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)
{
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)
if (w->active == wp)
return;
}
+ w->active->active_point = next_active_point++;
}
struct window_pane *
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))
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 */