diff options
Diffstat (limited to 'screen.c')
-rw-r--r-- | screen.c | 186 |
1 files changed, 149 insertions, 37 deletions
@@ -47,9 +47,8 @@ struct screen_title_entry { }; TAILQ_HEAD(screen_titles, screen_title_entry); -static void screen_resize_y(struct screen *, u_int); - -static void screen_reflow(struct screen *, u_int); +static void screen_resize_y(struct screen *, u_int, int, u_int *); +static void screen_reflow(struct screen *, u_int, u_int *, u_int *); /* Free titles stack. */ static void @@ -75,6 +74,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; @@ -83,6 +84,8 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit) s->tabs = NULL; s->sel = NULL; + s->write_list = NULL; + screen_reinit(s); } @@ -98,6 +101,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 +123,11 @@ screen_free(struct screen *s) free(s->title); free(s->ccolour); + if (s->write_list != NULL) + screen_write_free_list(s); + + if (s->saved_grid != NULL) + grid_destroy(s->saved_grid); grid_destroy(s->grid); screen_free_titles(s); @@ -206,10 +219,28 @@ screen_pop_title(struct screen *s) } } -/* Resize screen. */ +/* Resize screen and return cursor position. */ void -screen_resize(struct screen *s, u_int sx, u_int sy, int reflow) +screen_resize_cursor(struct screen *s, u_int sx, u_int sy, int reflow, + int eat_empty, u_int *cx, u_int *cy) { + u_int tcx, tcy; + + if (s->write_list != NULL) + screen_write_free_list(s); + + if (cx == NULL) + cx = &tcx; + *cx = s->cx; + + if (cy == NULL) + cy = т + *cy = s->grid->hsize + s->cy; + + log_debug("%s: new size %ux%u, now %ux%u (cursor %u,%u = %u,%u)", + __func__, sx, sy, screen_size_x(s), screen_size_y(s), s->cx, s->cy, + *cx, *cy); + if (sx < 1) sx = 1; if (sy < 1) @@ -222,14 +253,34 @@ screen_resize(struct screen *s, u_int sx, u_int sy, int reflow) reflow = 0; if (sy != screen_size_y(s)) - screen_resize_y(s, sy); + screen_resize_y(s, sy, eat_empty, cy); if (reflow) - screen_reflow(s, sx); + screen_reflow(s, sx, cx, cy); + + if (*cy >= s->grid->hsize) { + s->cx = *cx; + s->cy = (*cy) - s->grid->hsize; + } else { + s->cx = 0; + s->cy = 0; + } + log_debug("%s: cursor finished at %u,%u = %u,%u", __func__, s->cx, + s->cy, *cx, *cy); + + if (s->write_list != NULL) + screen_write_make_list(s); +} + +/* Resize screen. */ +void +screen_resize(struct screen *s, u_int sx, u_int sy, int reflow) +{ + screen_resize_cursor(s, sx, sy, reflow, 1, NULL, NULL); } static void -screen_resize_y(struct screen *s, u_int sy) +screen_resize_y(struct screen *s, u_int sy, int eat_empty, u_int *cy) { struct grid *gd = s->grid; u_int needed, available, oldy, i; @@ -254,14 +305,16 @@ screen_resize_y(struct screen *s, u_int sy) needed = oldy - sy; /* Delete as many lines as possible from the bottom. */ - available = oldy - 1 - s->cy; - if (available > 0) { - if (available > needed) - available = needed; - grid_view_delete_lines(gd, oldy - available, available, - 8); + if (eat_empty) { + available = oldy - 1 - s->cy; + if (available > 0) { + if (available > needed) + available = needed; + grid_view_delete_lines(gd, oldy - available, + available, 8); + } + needed -= available; } - needed -= available; /* * Now just increase the history size, if possible, to take @@ -276,8 +329,8 @@ screen_resize_y(struct screen *s, u_int sy) if (available > needed) available = needed; grid_view_delete_lines(gd, 0, available, 8); + (*cy) -= available; } - s->cy -= needed; } /* Resize line array. */ @@ -297,14 +350,13 @@ screen_resize_y(struct screen *s, u_int sy) available = needed; gd->hscrolled -= available; gd->hsize -= available; - s->cy += available; } else available = 0; needed -= available; /* Then fill the rest in with blanks. */ for (i = gd->hsize + sy - needed; i < gd->hsize + sy; i++) - memset(grid_get_line(gd, i), 0, sizeof(struct grid_line)); + grid_empty_line(gd, i, 8); } /* Set the new size, and reset the scroll region. */ @@ -472,32 +524,92 @@ screen_select_cell(struct screen *s, struct grid_cell *dst, /* Reflow wrapped lines. */ static void -screen_reflow(struct screen *s, u_int new_x) +screen_reflow(struct screen *s, u_int new_x, u_int *cx, u_int *cy) { - u_int cx = s->cx, cy = s->grid->hsize + s->cy, wx, wy; - struct timeval start, tv; - - gettimeofday(&start, NULL); + u_int wx, wy; - grid_wrap_position(s->grid, cx, cy, &wx, &wy); - log_debug("%s: cursor %u,%u is %u,%u", __func__, cx, cy, wx, wy); + grid_wrap_position(s->grid, *cx, *cy, &wx, &wy); + log_debug("%s: cursor %u,%u is %u,%u", __func__, *cx, *cy, wx, wy); grid_reflow(s->grid, new_x); - grid_unwrap_position(s->grid, &cx, &cy, wx, wy); - log_debug("%s: new cursor is %u,%u", __func__, cx, cy); + grid_unwrap_position(s->grid, cx, cy, wx, wy); + log_debug("%s: new cursor is %u,%u", __func__, *cx,* cy); +} - if (cy >= s->grid->hsize) { - s->cx = cx; - s->cy = cy - s->grid->hsize; - } else { - s->cx = 0; - s->cy = 0; +/* + * 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->saved_flags = s->grid->flags; + 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); } - gettimeofday(&tv, NULL); - timersub(&tv, &start, &tv); + 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. + */ + if (s->saved_flags & GRID_HISTORY) + s->grid->flags |= GRID_HISTORY; + if (sy > s->saved_grid->sy || sx != s->saved_grid->sx) + screen_resize(s, sx, sy, 1); - log_debug("%s: reflow took %llu.%06u seconds", __func__, - (unsigned long long)tv.tv_sec, (u_int)tv.tv_usec); + grid_destroy(s->saved_grid); + s->saved_grid = NULL; } |