diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 2c8dd920..ad6755ba 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -118,7 +118,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item, sx = screen_size_x(&wp->base); if (args_has(args, 'a')) { - gd = wp->saved_grid; + gd = wp->base.saved_grid; if (gd == NULL) { if (!args_has(args, 'q')) { cmdq_error(item, "no alternate screen"); diff --git a/format.c b/format.c index c3fc3cad..79917faf 100644 --- a/format.c +++ b/format.c @@ -2745,9 +2745,11 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "scroll_region_upper", "%u", wp->base.rupper); format_add(ft, "scroll_region_lower", "%u", wp->base.rlower); - format_add(ft, "alternate_on", "%d", wp->saved_grid ? 1 : 0); - format_add(ft, "alternate_saved_x", "%u", wp->saved_cx); - format_add(ft, "alternate_saved_y", "%u", wp->saved_cy); + format_add(ft, "alternate_on", "%d", wp->base.saved_grid != NULL); + if (wp->base.saved_cx != UINT_MAX) + format_add(ft, "alternate_saved_x", "%u", wp->base.saved_cx); + if (wp->base.saved_cy != UINT_MAX) + format_add(ft, "alternate_saved_y", "%u", wp->base.saved_cy); format_add(ft, "cursor_flag", "%d", !!(wp->base.mode & MODE_CURSOR)); diff --git a/input.c b/input.c index c7d67b82..4901e886 100644 --- a/input.c +++ b/input.c @@ -75,6 +75,7 @@ struct input_param { /* Input parser context. */ struct input_ctx { struct window_pane *wp; + struct bufferevent *event; struct screen_write_ctx ctx; struct input_cell cell; @@ -788,12 +789,13 @@ input_restore_state(struct input_ctx *ictx) /* Initialise input parser. */ struct input_ctx * -input_init(struct window_pane *wp) +input_init(struct window_pane *wp, struct bufferevent *bev) { struct input_ctx *ictx; ictx = xcalloc(1, sizeof *ictx); ictx->wp = wp; + ictx->event = bev; ictx->input_space = INPUT_BUF_START; ictx->input_buf = xmalloc(INPUT_BUF_START); @@ -1058,18 +1060,15 @@ input_get(struct input_ctx *ictx, u_int validx, int minval, int defval) static void input_reply(struct input_ctx *ictx, const char *fmt, ...) { - struct window_pane *wp = ictx->wp; + struct bufferevent *bev = ictx->event; va_list ap; char *reply; - if (wp == NULL) - return; - va_start(ap, fmt); xvasprintf(&reply, fmt, ap); va_end(ap); - bufferevent_write(wp->event, reply, strlen(reply)); + bufferevent_write(bev, reply, strlen(reply)); free(reply); } @@ -1680,10 +1679,14 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx) case 1047: if (wp != NULL) window_pane_alternate_off(wp, gc, 0); + else + screen_alternate_off(sctx->s, gc, 0); break; case 1049: if (wp != NULL) window_pane_alternate_off(wp, gc, 1); + else + screen_alternate_off(sctx->s, gc, 1); break; case 2004: screen_write_mode_clear(sctx, MODE_BRACKETPASTE); @@ -1781,10 +1784,14 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx) case 1047: if (wp != NULL) window_pane_alternate_on(wp, gc, 0); + else + screen_alternate_on(sctx->s, gc, 0); break; case 1049: if (wp != NULL) window_pane_alternate_on(wp, gc, 1); + else + screen_alternate_on(sctx->s, gc, 1); break; case 2004: screen_write_mode_set(sctx, MODE_BRACKETPASTE); @@ -1801,7 +1808,9 @@ static void input_csi_dispatch_winops(struct input_ctx *ictx) { struct screen_write_ctx *sctx = &ictx->ctx; + struct screen *s = sctx->s; struct window_pane *wp = ictx->wp; + u_int x = screen_size_x(s), y = screen_size_y(s); int n, m; m = 0; @@ -1858,10 +1867,7 @@ input_csi_dispatch_winops(struct input_ctx *ictx) } break; case 18: - if (wp != NULL) { - input_reply(ictx, "\033[8;%u;%ut", wp->sy, - wp->sx); - } + input_reply(ictx, "\033[8;%u;%ut", x, y); break; default: log_debug("%s: unknown '%c'", __func__, ictx->ch); @@ -2565,13 +2571,13 @@ input_osc_52(struct input_ctx *ictx, const char *p) outlen = 0; out = NULL; } - bufferevent_write(wp->event, "\033]52;;", 6); + bufferevent_write(ictx->event, "\033]52;;", 6); if (outlen != 0) - bufferevent_write(wp->event, out, outlen); + bufferevent_write(ictx->event, out, outlen); if (ictx->input_end == INPUT_END_BEL) - bufferevent_write(wp->event, "\007", 1); + bufferevent_write(ictx->event, "\007", 1); else - bufferevent_write(wp->event, "\033\\", 2); + bufferevent_write(ictx->event, "\033\\", 2); free(out); return; } diff --git a/popup.c b/popup.c index 7eff7c14..05ff1b4c 100644 --- a/popup.c +++ b/popup.c @@ -443,8 +443,6 @@ popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx, popup_write_screen(c, pd); if (shellcmd != NULL) { - pd->ictx = input_init(NULL); - if (fs != NULL) s = fs->s; else @@ -455,6 +453,7 @@ popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx, pd->job = job_run(shellcmd, s, cwd, popup_job_update_cb, popup_job_complete_cb, NULL, pd, jobflags, pd->sx - 2, pd->sy - 2); + pd->ictx = input_init(NULL, job_get_event(pd->job)); } server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb, diff --git a/screen.c b/screen.c index fafb3456..a3cd5501 100644 --- a/screen.c +++ b/screen.c @@ -75,6 +75,8 @@ void screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit) { s->grid = grid_create(sx, sy, hlimit); + s->saved_grid = NULL; + s->title = xstrdup(""); s->titles = NULL; @@ -98,6 +100,11 @@ screen_reinit(struct screen *s) s->mode = MODE_CURSOR | MODE_WRAP; + if (s->saved_grid != NULL) + screen_alternate_off(s, NULL, 0); + s->saved_cx = UINT_MAX; + s->saved_cy = UINT_MAX; + screen_reset_tabs(s); grid_clear_lines(s->grid, s->grid->hsize, s->grid->sy, 8); @@ -115,6 +122,8 @@ screen_free(struct screen *s) free(s->title); free(s->ccolour); + if (s->saved_grid != NULL) + grid_destroy(s->saved_grid); grid_destroy(s->grid); screen_free_titles(s); @@ -501,3 +510,78 @@ screen_reflow(struct screen *s, u_int new_x) log_debug("%s: reflow took %llu.%06u seconds", __func__, (unsigned long long)tv.tv_sec, (u_int)tv.tv_usec); } + +/* + * Enter alternative screen mode. A copy of the visible screen is saved and the + * history is not updated. + */ +void +screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor) +{ + u_int sx, sy; + + if (s->saved_grid != NULL) + return; + sx = screen_size_x(s); + sy = screen_size_y(s); + + s->saved_grid = grid_create(sx, sy, 0); + grid_duplicate_lines(s->saved_grid, 0, s->grid, screen_hsize(s), sy); + if (cursor) { + s->saved_cx = s->cx; + s->saved_cy = s->cy; + } + memcpy(&s->saved_cell, gc, sizeof s->saved_cell); + + grid_view_clear(s->grid, 0, 0, sx, sy, 8); + + s->grid->flags &= ~GRID_HISTORY; +} + +/* Exit alternate screen mode and restore the copied grid. */ +void +screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor) +{ + u_int sx, sy; + + /* + * Restore the cursor position and cell. This happens even if not + * currently in the alternate screen. + */ + if (cursor && s->saved_cx != UINT_MAX && s->saved_cy != UINT_MAX) { + s->cx = s->saved_cx; + if (s->cx > screen_size_x(s) - 1) + s->cx = screen_size_x(s) - 1; + s->cy = s->saved_cy; + if (s->cy > screen_size_y(s) - 1) + s->cy = screen_size_y(s) - 1; + if (gc != NULL) + memcpy(gc, &s->saved_cell, sizeof *gc); + } + + if (s->saved_grid == NULL) + return; + sx = screen_size_x(s); + sy = screen_size_y(s); + + /* + * If the current size is bigger, temporarily resize to the old size + * before copying back. + */ + if (sy > s->saved_grid->sy) + screen_resize(s, sx, s->saved_grid->sy, 1); + + /* Restore the saved grid. */ + grid_duplicate_lines(s->grid, screen_hsize(s), s->saved_grid, 0, sy); + + /* + * Turn history back on (so resize can use it) and then resize back to + * the current size. + */ + s->grid->flags |= GRID_HISTORY; + if (sy > s->saved_grid->sy || sx != s->saved_grid->sx) + screen_resize(s, sx, sy, 1); + + grid_destroy(s->saved_grid); + s->saved_grid = NULL; +} diff --git a/server-client.c b/server-client.c index 5a9626c5..6df792cf 100644 --- a/server-client.c +++ b/server-client.c @@ -1398,7 +1398,7 @@ server_client_resize_event(__unused int fd, __unused short events, void *data) log_debug("%s: %%%u timer fired (was%s resized)", __func__, wp->id, (wp->flags & PANE_RESIZED) ? "" : " not"); - if (wp->saved_grid == NULL && (wp->flags & PANE_RESIZED)) { + if (wp->base.saved_grid == NULL && (wp->flags & PANE_RESIZED)) { log_debug("%s: %%%u deferring timer", __func__, wp->id); server_client_start_resize_timer(wp); } else if (!server_client_resize_force(wp)) { diff --git a/spawn.c b/spawn.c index 08bcfe87..aaabe0ab 100644 --- a/spawn.c +++ b/spawn.c @@ -254,7 +254,7 @@ spawn_pane(struct spawn_context *sc, char **cause) window_pane_reset_mode_all(sc->wp0); screen_reinit(&sc->wp0->base); input_free(sc->wp0->ictx); - sc->wp0->ictx = input_init(sc->wp0); + sc->wp0->ictx = NULL; new_wp = sc->wp0; new_wp->flags &= ~(PANE_STATUSREADY|PANE_STATUSDRAWN); } else if (sc->lc == NULL) { diff --git a/tmux.h b/tmux.h index 5ab51173..8756a774 100644 --- a/tmux.h +++ b/tmux.h @@ -756,8 +756,12 @@ struct screen { int mode; - bitstr_t *tabs; + u_int saved_cx; + u_int saved_cy; + struct grid *saved_grid; + struct grid_cell saved_cell; + bitstr_t *tabs; struct screen_sel *sel; }; @@ -919,12 +923,6 @@ struct window_pane { struct screen status_screen; size_t status_size; - /* Saved in alternative screen mode. */ - u_int saved_cx; - u_int saved_cy; - struct grid *saved_grid; - struct grid_cell saved_cell; - TAILQ_HEAD (, window_mode_entry) modes; struct event modetimer; time_t modelast; @@ -2298,7 +2296,7 @@ void recalculate_size(struct window *); void recalculate_sizes(void); /* input.c */ -struct input_ctx *input_init(struct window_pane *); +struct input_ctx *input_init(struct window_pane *, struct bufferevent *); void input_free(struct input_ctx *); void input_reset(struct input_ctx *, int); struct evbuffer *input_pending(struct input_ctx *); @@ -2336,6 +2334,7 @@ struct grid *grid_create(u_int, u_int, u_int); void grid_destroy(struct grid *); int grid_compare(struct grid *, struct grid *); void grid_collect_history(struct grid *); +void grid_remove_history(struct grid *, u_int ); void grid_scroll_history(struct grid *, u_int); void grid_scroll_history_region(struct grid *, u_int, u_int, u_int); void grid_clear_history(struct grid *); @@ -2460,6 +2459,9 @@ void screen_hide_selection(struct screen *); int screen_check_selection(struct screen *, u_int, u_int); void screen_select_cell(struct screen *, struct grid_cell *, const struct grid_cell *); +void screen_alternate_on(struct screen *, struct grid_cell *, int); +void screen_alternate_off(struct screen *, struct grid_cell *, int); + /* window.c */ extern struct windows windows; diff --git a/window.c b/window.c index 72a58e45..3b248618 100644 --- a/window.c +++ b/window.c @@ -886,10 +886,6 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->pipe_off = 0; wp->pipe_event = NULL; - wp->saved_grid = NULL; - wp->saved_cx = UINT_MAX; - wp->saved_cy = UINT_MAX; - screen_init(&wp->base, sx, sy, hlimit); wp->screen = &wp->base; @@ -898,8 +894,6 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) if (gethostname(host, sizeof host) == 0) screen_set_title(&wp->base, host); - wp->ictx = input_init(wp); - return (wp); } @@ -916,14 +910,12 @@ window_pane_destroy(struct window_pane *wp) bufferevent_free(wp->event); close(wp->fd); } - - input_free(wp->ictx); + if (wp->ictx != NULL) + input_free(wp->ictx); screen_free(&wp->status_screen); screen_free(&wp->base); - if (wp->saved_grid != NULL) - grid_destroy(wp->saved_grid); if (wp->pipe_fd != -1) { bufferevent_free(wp->pipe_event); @@ -984,6 +976,7 @@ window_pane_set_event(struct window_pane *wp) wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL, window_pane_error_callback, wp); + wp->ictx = input_init(wp, wp->event); bufferevent_setwatermark(wp->event, EV_READ, 0, READ_SIZE); bufferevent_enable(wp->event, EV_READ|EV_WRITE); @@ -1000,7 +993,7 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) wp->sy = sy; log_debug("%s: %%%u resize %ux%u", __func__, wp->id, sx, sy); - screen_resize(&wp->base, sx, sy, wp->saved_grid == NULL); + screen_resize(&wp->base, sx, sy, wp->base.saved_grid == NULL); wme = TAILQ_FIRST(&wp->modes); if (wme != NULL && wme->mode->resize != NULL) @@ -1009,90 +1002,23 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) wp->flags |= (PANE_RESIZE|PANE_RESIZED); } -/* - * Enter alternative screen mode. A copy of the visible screen is saved and the - * history is not updated - */ void window_pane_alternate_on(struct window_pane *wp, struct grid_cell *gc, int cursor) { - struct screen *s = &wp->base; - u_int sx, sy; - - if (wp->saved_grid != NULL) - return; if (!options_get_number(wp->options, "alternate-screen")) return; - sx = screen_size_x(s); - sy = screen_size_y(s); - - wp->saved_grid = grid_create(sx, sy, 0); - grid_duplicate_lines(wp->saved_grid, 0, s->grid, screen_hsize(s), sy); - if (cursor) { - wp->saved_cx = s->cx; - wp->saved_cy = s->cy; - } - memcpy(&wp->saved_cell, gc, sizeof wp->saved_cell); - - grid_view_clear(s->grid, 0, 0, sx, sy, 8); - - wp->base.grid->flags &= ~GRID_HISTORY; - + screen_alternate_on(&wp->base, gc, cursor); wp->flags |= PANE_REDRAW; } -/* Exit alternate screen mode and restore the copied grid. */ void window_pane_alternate_off(struct window_pane *wp, struct grid_cell *gc, int cursor) { - struct screen *s = &wp->base; - u_int sx, sy; - if (!options_get_number(wp->options, "alternate-screen")) return; - - /* - * Restore the cursor position and cell. This happens even if not - * currently in the alternate screen. - */ - if (cursor && wp->saved_cx != UINT_MAX && wp->saved_cy != UINT_MAX) { - s->cx = wp->saved_cx; - if (s->cx > screen_size_x(s) - 1) - s->cx = screen_size_x(s) - 1; - s->cy = wp->saved_cy; - if (s->cy > screen_size_y(s) - 1) - s->cy = screen_size_y(s) - 1; - memcpy(gc, &wp->saved_cell, sizeof *gc); - } - - if (wp->saved_grid == NULL) - return; - sx = screen_size_x(s); - sy = screen_size_y(s); - - /* - * If the current size is bigger, temporarily resize to the old size - * before copying back. - */ - if (sy > wp->saved_grid->sy) - screen_resize(s, sx, wp->saved_grid->sy, 1); - - /* Restore the saved grid. */ - grid_duplicate_lines(s->grid, screen_hsize(s), wp->saved_grid, 0, sy); - - /* - * Turn history back on (so resize can use it) and then resize back to - * the current size. - */ - wp->base.grid->flags |= GRID_HISTORY; - if (sy > wp->saved_grid->sy || sx != wp->saved_grid->sx) - screen_resize(s, sx, sy, 1); - - grid_destroy(wp->saved_grid); - wp->saved_grid = NULL; - + screen_alternate_off(&wp->base, gc, cursor); wp->flags |= PANE_REDRAW; }