hi take a look at this please - tweaked style and naming somewhat, particularly we have never used focus for anything apart from the focus events before so no reason to start now
also used a new member of layout_cell otherwise it changes the layout string (this seems like another thing that should really be part of the layout code but there is already other stuff like that and your way is simpler. a revamp of layouts has been on the todo list for a while :-).) Index: tmux.h =================================================================== RCS file: /cvs/src/usr.bin/tmux/tmux.h,v retrieving revision 1.433 diff -u -p -r1.433 tmux.h --- tmux.h 9 Jan 2014 14:20:55 -0000 1.433 +++ tmux.h 22 Jan 2014 23:10:34 -0000 @@ -1028,6 +1028,8 @@ struct layout_cell { u_int yoff; struct window_pane *wp; + struct window_pane *lastwp; + struct layout_cells cells; TAILQ_ENTRY(layout_cell) entry; Index: window.c =================================================================== RCS file: /cvs/src/usr.bin/tmux/window.c,v retrieving revision 1.99 diff -u -p -r1.99 window.c --- window.c 10 Oct 2013 12:26:37 -0000 1.99 +++ window.c 22 Jan 2014 23:10:34 -0000 @@ -61,6 +61,10 @@ 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 *); + 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 *); @@ -386,6 +390,59 @@ window_resize(struct window *w, u_int sx 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. + */ + if (nextwp->layout_cell->parent != NULL) { + lastwp = nextwp->layout_cell->parent->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; + + /* Save the target pane in its parent. */ + nextwp->layout_cell->parent->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) { + lc2 = nextwp->layout_cell->parent; + for (; lc2 != NULL; lc2 = lc2->parent) { + if (lc == lc2) + return; + } + lc->lastwp = wp; + } +} + void window_set_active_pane(struct window *w, struct window_pane *wp) { @@ -393,6 +450,7 @@ window_set_active_pane(struct window *w, 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) @@ -707,6 +765,16 @@ window_pane_create(struct window *w, u_i 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)) @@ -1130,7 +1198,7 @@ window_pane_find_up(struct window_pane * if (wp2->yoff + wp2->sy + 1 != top) continue; if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx) - return (wp2); + return (window_pane_active_set(wp, wp2)); } return (NULL); } @@ -1156,7 +1224,7 @@ window_pane_find_down(struct window_pane if (wp2->yoff != bottom) continue; if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx) - return (wp2); + return (window_pane_active_set(wp, wp2)); } return (NULL); } @@ -1185,7 +1253,7 @@ window_pane_find_left(struct window_pane if (wp2->xoff + wp2->sx + 1 != left) continue; if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy) - return (wp2); + return (window_pane_active_set(wp, wp2)); } return (NULL); } @@ -1214,7 +1282,7 @@ window_pane_find_right(struct window_pan if (wp2->xoff != right) continue; if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy) - return (wp2); + return (window_pane_active_set(wp, wp2)); } return (NULL); } On Tue, Jan 14, 2014 at 10:10:00AM -0800, Suraj N. Kurapati wrote: > This patch makes non-window-pane layout cells remember which of their > descendant window panes previously had focus (or was "active" in tmux > parlance) so that the focus may be restored later on, when applicable. > > For example, consider the following scenario created by steps 1-5: > > 1 2 3 4 5 > > @@@@@@@@@ +---@@@@@ +---+---+ @@@@@---+ +---+---+ > @ @ | @ @ | | Y | @ @ Y | | | Y | > @ X @ | X @ Y @ | X @@@@@ @ X @---+ | X @@@@@ > @ @ | @ @ | @ Z @ @ @ Z | | @ Z @ > @@@@@@@@@ +---@@@@@ +---@@@@@ @@@@@---+ +---@@@@@ > > 1. We run `tmux new-window` to create pane X. > 2. We run `tmux split-window -h` to create and focus pane Y. > 3. We run `tmux split-window` to create and focus pane Z. > 4. We run `tmux select-pane -L` to focus pane X. > 5. We run `tmux select-pane -R` to focus pane Z, thanks to this patch. > Without this patch, this step would focus pane Y instead of pane Z. > > Although this example illustrates a rather simple scenario, note that > this patch can handle more complex (nested cell) layouts just as well. > --- > window.c | 70 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- > 1 file changed, 66 insertions(+), 4 deletions(-) > > diff --git a/window.c b/window.c > index 7678adc..adb67e0 100644 > --- a/window.c > +++ b/window.c > @@ -383,6 +383,34 @@ window_resize(struct window *w, u_int sx, u_int sy) > w->sy = sy; > } > > +/* > + * Commandeers the transfer of focus from `wp` to `wp2` in order to mark `wp` > + * so that window_pane_refocus is able to restore focus to it when necessary. > + */ > +static void > +window_pane_defocus(struct window_pane *wp, struct window_pane *wp2) > +{ > + struct layout_cell *lc, *lc2; > + > + /* remember the target pane's focus in its parent */ > + wp2->layout_cell->parent->wp = wp2; > + > + if (wp == NULL) > + return; > + > + /* remember the source pane's focus in all of its parents up to, but > + * not including, the common ancestor of itself and the target pane */ > + for(lc = wp->layout_cell->parent; lc != NULL; lc = lc->parent) { > + /* search for a common ancestor in the target's lineage */ > + for(lc2 = wp2->layout_cell->parent; lc2 != NULL; lc2 = > lc2->parent) > + if (lc == lc2) > + /* found a common ancestor so stop here */ > + return; > + /* remember the source pane's focus in its uncommon parent */ > + lc->wp = wp; > + } > +} > + > void > window_set_active_pane(struct window *w, struct window_pane *wp) > { > @@ -390,6 +418,7 @@ window_set_active_pane(struct window *w, struct > window_pane *wp) > return; > w->last = w->active; > w->active = wp; > + window_pane_defocus(w->last, wp); > while (!window_pane_visible(w->active)) { > w->active = TAILQ_PREV(w->active, window_panes, entry); > if (w->active == NULL) > @@ -704,6 +733,14 @@ window_pane_create(struct window *w, u_int sx, u_int sy, > u_int hlimit) > void > window_pane_destroy(struct window_pane *wp) > { > + /* forget removed pane's focus in all layout cells that remember it */ > + struct window_pane *wp2; > + RB_FOREACH(wp2, window_pane_tree, &all_window_panes) > + if (wp2->layout_cell != NULL && > + wp2->layout_cell->parent != NULL && > + wp2->layout_cell->parent->wp == wp) > + wp2->layout_cell->parent->wp = NULL; /* forget pane */ > + > window_pane_reset_mode(wp); > > if (event_initialized(&wp->changes_timer)) > @@ -1110,6 +1147,31 @@ window_pane_search(struct window_pane *wp, const char > *searchstr, u_int *lineno) > return (msg); > } > > +/* > + * Commandeers the transfer of focus from `wp` to `wp2` in order to restore > + * focus to a previously focused window pane marked by window_pane_defocus. > + * If this is not possible, the transfer proceeds as originally intended. > + */ > +static struct window_pane * > +window_pane_refocus(struct window_pane *wp, struct window_pane *wp2) > +{ > + struct layout_cell *lc; > + struct window_pane *fp; /* pane marked by window_pane_defocus */ > + > + /* 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 == wp2->layout_cell->parent) > + return (wp2); > + > + /* focused pane, if any, must not be the same as source pane */ > + lc = wp2->layout_cell->parent; > + fp = lc != NULL ? lc->wp : NULL; > + if (fp != NULL && fp != wp && window_pane_visible(fp)) > + return (fp); > + else > + return (wp2); > +} > + > /* Find the pane directly above another. */ > struct window_pane * > window_pane_find_up(struct window_pane *wp) > @@ -1131,7 +1193,7 @@ window_pane_find_up(struct window_pane *wp) > if (wp2->yoff + wp2->sy + 1 != top) > continue; > if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx) > - return (wp2); > + return window_pane_refocus(wp, wp2); > } > return (NULL); > } > @@ -1157,7 +1219,7 @@ window_pane_find_down(struct window_pane *wp) > if (wp2->yoff != bottom) > continue; > if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx) > - return (wp2); > + return window_pane_refocus(wp, wp2); > } > return (NULL); > } > @@ -1186,7 +1248,7 @@ window_pane_find_left(struct window_pane *wp) > if (wp2->xoff + wp2->sx + 1 != left) > continue; > if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy) > - return (wp2); > + return window_pane_refocus(wp, wp2); > } > return (NULL); > } > @@ -1215,7 +1277,7 @@ window_pane_find_right(struct window_pane *wp) > if (wp2->xoff != right) > continue; > if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy) > - return (wp2); > + return window_pane_refocus(wp, wp2); > } > return (NULL); > } > -- > 1.8.5.2 > ------------------------------------------------------------------------------ CenturyLink Cloud: The Leader in Enterprise Cloud Services. Learn Why More Businesses Are Choosing CenturyLink Cloud For Critical Workloads, Development Environments & Everything In Between. Get a Quote or Start a Free Trial Today. http://pubads.g.doubleclick.net/gampad/clk?id=119420431&iu=/4140/ostg.clktrk _______________________________________________ tmux-users mailing list tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users