Allow multiple modes to be open in a pane. A stack of open modes is kept

and the previous restored when the top is exited. If a mode that is
already on the stack is entered, the existing instance is moved to the
top as the active mode rather than being opened new.
This commit is contained in:
nicm
2019-03-12 11:16:49 +00:00
parent ff4c80d53d
commit 3f6bfbaf2b
15 changed files with 182 additions and 116 deletions

View File

@ -810,7 +810,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp->fd = -1;
wp->event = NULL;
wp->mode = NULL;
TAILQ_INIT(&wp->modes);
wp->layout_cell = NULL;
@ -844,7 +844,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
static void
window_pane_destroy(struct window_pane *wp)
{
window_pane_reset_mode(wp);
window_pane_reset_mode_all(wp);
free(wp->searchstr);
if (wp->fd != -1) {
@ -1047,14 +1047,18 @@ window_pane_error_callback(__unused struct bufferevent *bufev,
void
window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
{
struct window_mode_entry *wme;
if (sx == wp->sx && sy == wp->sy)
return;
wp->sx = sx;
wp->sy = sy;
screen_resize(&wp->base, sx, sy, wp->saved_grid == NULL);
if (wp->mode != NULL && wp->mode->mode->resize != NULL)
wp->mode->mode->resize(wp->mode, sx, sy);
wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL && wme->mode->resize != NULL)
wme->mode->resize(wme, sx, sy);
wp->flags |= PANE_RESIZE;
}
@ -1208,7 +1212,7 @@ window_pane_mode_timer(__unused int fd, __unused short events, void *arg)
if (wp->modelast < time(NULL) - WINDOW_MODE_TIMEOUT) {
if (ioctl(wp->fd, FIONREAD, &n) == -1 || n > 0)
window_pane_reset_mode(wp);
window_pane_reset_mode_all(wp);
}
}
@ -1216,59 +1220,90 @@ int
window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode,
struct cmd_find_state *fs, struct args *args)
{
struct screen *s;
struct timeval tv = { .tv_sec = 10 };
struct timeval tv = { .tv_sec = 10 };
struct window_mode_entry *wme;
if (wp->mode != NULL)
if (!TAILQ_EMPTY(&wp->modes) && TAILQ_FIRST(&wp->modes)->mode == mode)
return (1);
wp->mode = xcalloc(1, sizeof *wp->mode);
wp->mode->wp = wp;
wp->mode->mode = mode;
wp->mode->prefix = 1;
wp->modelast = time(NULL);
evtimer_set(&wp->modetimer, window_pane_mode_timer, wp);
evtimer_add(&wp->modetimer, &tv);
if (TAILQ_EMPTY(&wp->modes)) {
evtimer_set(&wp->modetimer, window_pane_mode_timer, wp);
evtimer_add(&wp->modetimer, &tv);
}
if ((s = wp->mode->mode->init(wp->mode, fs, args)) != NULL)
wp->screen = s;
TAILQ_FOREACH(wme, &wp->modes, entry) {
if (wme->mode == mode)
break;
}
if (wme != NULL)
TAILQ_REMOVE(&wp->modes, wme, entry);
else {
wme = xcalloc(1, sizeof *wme);
wme->wp = wp;
wme->mode = mode;
wme->prefix = 1;
wme->screen = wme->mode->init(wme, fs, args);
}
TAILQ_INSERT_HEAD(&wp->modes, wme, entry);
wp->screen = wme->screen;
wp->flags |= (PANE_REDRAW|PANE_CHANGED);
server_status_window(wp->window);
notify_pane("pane-mode-changed", wp);
return (0);
}
void
window_pane_reset_mode(struct window_pane *wp)
{
if (wp->mode == NULL)
struct window_mode_entry *wme, *next;
if (TAILQ_EMPTY(&wp->modes))
return;
evtimer_del(&wp->modetimer);
wme = TAILQ_FIRST(&wp->modes);
TAILQ_REMOVE(&wp->modes, wme, entry);
wme->mode->free(wme);
free(wme);
wp->mode->mode->free(wp->mode);
free(wp->mode);
wp->mode = NULL;
wp->screen = &wp->base;
next = TAILQ_FIRST(&wp->modes);
if (next == NULL) {
log_debug("%s: no next mode", __func__);
evtimer_del(&wp->modetimer);
wp->screen = &wp->base;
} else {
log_debug("%s: next mode is %s", __func__, next->mode->name);
wp->screen = next->screen;
if (next != NULL && next->mode->resize != NULL)
next->mode->resize(next, wp->sx, wp->sy);
}
wp->flags |= (PANE_REDRAW|PANE_CHANGED);
server_status_window(wp->window);
notify_pane("pane-mode-changed", wp);
}
void
window_pane_reset_mode_all(struct window_pane *wp)
{
while (!TAILQ_EMPTY(&wp->modes))
window_pane_reset_mode(wp);
}
void
window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
struct winlink *wl, key_code key, struct mouse_event *m)
{
struct window_mode_entry *wme = wp->mode;
struct window_mode_entry *wme;
struct window_pane *wp2;
if (KEYC_IS_MOUSE(key) && m == NULL)
return;
wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL) {
wp->modelast = time(NULL);
if (wme->mode->key != NULL)
@ -1286,7 +1321,7 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
if (options_get_number(wp->window->options, "synchronize-panes")) {
TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
if (wp2 != wp &&
wp2->mode == NULL &&
TAILQ_EMPTY(&wp2->modes) &&
wp2->fd != -1 &&
(~wp2->flags & PANE_INPUTOFF) &&
window_pane_visible(wp2))