diff --git a/csi.c b/csi.c index e4a60eda..0200e6a3 100644 --- a/csi.c +++ b/csi.c @@ -380,6 +380,21 @@ csi_dispatch(struct terminal *term, uint8_t final) break; } + case 'r': { + int start = term->vt.params.idx > 0 ? term->vt.params.v[0].value : 1; + int end = term->vt.params.idx > 1 + ? term->vt.params.v[1].value : term->grid.rows; + + /* 1-based */ + term->grid.scrolling_region.start = start - 1; + term->grid.scrolling_region.end = end - 1; + + tll_free(term->grid.damage); + grid_damage_update(&term->grid, 0, term->grid.rows * term->grid.cols); + grid_cursor_to(&term->grid, 0, 0); + break; + } + case 't': /* * TODO: xterm's terminfo specifies *both* \e[?1049h *and* diff --git a/grid.c b/grid.c index 78fb9e40..7952e7de 100644 --- a/grid.c +++ b/grid.c @@ -87,8 +87,11 @@ grid_damage_erase(struct grid *grid, int start, int length) static void damage_adjust_after_scroll(struct grid *grid, enum damage_type damage_type, - int top_margin, int bottom_margin, int lines) + int lines) { + int top_margin = grid->scrolling_region.start; + int bottom_margin = grid->rows - grid->scrolling_region.end; + const int adjustment = lines * grid->cols * (damage_type == DAMAGE_SCROLL_REVERSE ? -1 : 1); top_margin *= grid->cols; @@ -131,8 +134,7 @@ damage_adjust_after_scroll(struct grid *grid, enum damage_type damage_type, } void -grid_damage_scroll(struct grid *grid, enum damage_type damage_type, - int top_margin, int bottom_margin, int lines) +grid_damage_scroll(struct grid *grid, enum damage_type damage_type, int lines) { if (tll_length(grid->damage) > 0 && tll_front(grid->damage).type == damage_type) @@ -140,33 +142,26 @@ grid_damage_scroll(struct grid *grid, enum damage_type damage_type, /* Merge with existing scroll damage */ struct damage *dmg = &tll_front(grid->damage); - - assert(dmg->scroll.top_margin == top_margin); - assert(dmg->scroll.bottom_margin == bottom_margin); - dmg->scroll.lines += lines; + const int scrolling_region = + grid->scrolling_region.end - grid->scrolling_region.start; + /* If we've scrolled away the entire screen, replace with an erase */ - if (dmg->scroll.lines >= (grid->rows - (dmg->scroll.top_margin + - dmg->scroll.bottom_margin))) { + if (dmg->scroll.lines >= scrolling_region) { dmg->type = DAMAGE_ERASE; - dmg->range.start = dmg->scroll.top_margin * grid->cols; - dmg->range.length = (grid->rows - top_margin - bottom_margin) * grid->cols; + dmg->range.start = grid->scrolling_region.start * grid->cols; + dmg->range.length = scrolling_region * grid->cols; } } else { struct damage dmg = { .type = damage_type, - .scroll = { - .top_margin = top_margin, - .bottom_margin = bottom_margin, - .lines = lines - }, + .scroll = {.lines = lines}, }; tll_push_front(grid->damage, dmg); } - damage_adjust_after_scroll( - grid, damage_type, top_margin, bottom_margin, lines); + damage_adjust_after_scroll(grid, damage_type, lines); } void @@ -243,15 +238,12 @@ grid_cursor_down(struct grid *grid, int count) void grid_scroll(struct grid *grid, int rows) { - const int top_margin = 0; - const int bottom_margin = 0; - const int grid_rows = grid->rows - top_margin - bottom_margin; + const int grid_rows = grid->scrolling_region.end - grid->scrolling_region.start; + const int top_margin = grid->scrolling_region.start; + const int bottom_margin = grid->rows - grid->scrolling_region.end; if (rows >= grid_rows) { assert(false && "untested"); - grid_erase(grid, - top_margin * grid->cols, - (grid->rows - bottom_margin) * grid->cols); return; } @@ -266,7 +258,7 @@ grid_scroll(struct grid *grid, int rows) &grid->cells[cell_dst], &grid->cells[cell_src], bytes); - grid_damage_scroll(grid, DAMAGE_SCROLL, top_margin, bottom_margin, rows); + grid_damage_scroll(grid, DAMAGE_SCROLL, rows); grid_erase( grid, (grid_rows - bottom_margin - rows) * grid->cols, @@ -276,9 +268,9 @@ grid_scroll(struct grid *grid, int rows) void grid_scroll_reverse(struct grid *grid, int rows) { - const int top_margin = 0; - const int bottom_margin = 0; - const int grid_rows = grid->rows - top_margin - bottom_margin; + const int grid_rows = grid->scrolling_region.end - grid->scrolling_region.start; + const int top_margin = grid->scrolling_region.start; + const int bottom_margin = grid->rows - grid->scrolling_region.end; if (rows >= grid_rows) { assert(false && "todo"); @@ -296,7 +288,7 @@ grid_scroll_reverse(struct grid *grid, int rows) &grid->cells[cell_dst], &grid->cells[cell_src], bytes); - grid_damage_scroll(grid, DAMAGE_SCROLL_REVERSE, top_margin, bottom_margin, rows); + grid_damage_scroll(grid, DAMAGE_SCROLL_REVERSE, rows); grid_erase( grid, top_margin * grid->cols, diff --git a/grid.h b/grid.h index 1951f54f..9a52b108 100644 --- a/grid.h +++ b/grid.h @@ -5,8 +5,7 @@ void grid_damage_update(struct grid *grid, int start, int length); void grid_damage_erase(struct grid *grid, int start, int length); void grid_damage_scroll( - struct grid *grid, enum damage_type damage_type, - int top_margin, int bottom_margin, int lines); + struct grid *grid, enum damage_type damage_type, int lines); void grid_erase(struct grid *grid, int start, int end); diff --git a/main.c b/main.c index b0395839..6bec90bc 100644 --- a/main.c +++ b/main.c @@ -256,20 +256,19 @@ grid_render_scroll(struct context *c, struct buffer *buf, const struct damage *dmg) { //int x = 0; - int dst_y = (dmg->scroll.top_margin + 0) * c->term.grid.cell_height; - int src_y = (dmg->scroll.top_margin + dmg->scroll.lines) * c->term.grid.cell_height; + const int scrolling_region + = c->term.grid.scrolling_region.end - c->term.grid.scrolling_region.start; + + int dst_y = (c->term.grid.scrolling_region.start + 0) * c->term.grid.cell_height; + int src_y = (c->term.grid.scrolling_region.start + dmg->scroll.lines) * c->term.grid.cell_height; int width = buf->width; - int height = (c->term.grid.rows - - dmg->scroll.top_margin - - dmg->scroll.bottom_margin - - dmg->scroll.lines) * c->term.grid.cell_height; + int height = (scrolling_region - dmg->scroll.lines) * c->term.grid.cell_height; const uint32_t stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); LOG_DBG("damage: SCROLL: %d-%d by %d lines (dst-y: %d, src-y: %d, " "height: %d, stride: %d, mmap-size: %zu)", - dmg->scroll.top_margin, - c->term.grid.rows - dmg->scroll.bottom_margin, + c->term.grid.scrolling_region.start, c->term.grid.scrolling_region.end, dmg->scroll.lines, dst_y, src_y, height, stride, buf->size); @@ -286,8 +285,7 @@ grid_render_scroll(struct context *c, struct buffer *buf, struct damage erase = { .type = DAMAGE_ERASE, .range = { - .start = (c->term.grid.rows - - dmg->scroll.bottom_margin - + .start = (c->term.grid.scrolling_region.end - dmg->scroll.lines) * cols, .length = dmg->scroll.lines * cols }, @@ -300,20 +298,19 @@ grid_render_scroll_reverse(struct context *c, struct buffer *buf, const struct damage *dmg) { //int x = 0; - int src_y = (dmg->scroll.top_margin + 0) * c->term.grid.cell_height; - int dst_y = (dmg->scroll.top_margin + dmg->scroll.lines) * c->term.grid.cell_height; + const int scrolling_region = + c->term.grid.scrolling_region.end - c->term.grid.scrolling_region.start; + + int src_y = (c->term.grid.scrolling_region.start + 0) * c->term.grid.cell_height; + int dst_y = (c->term.grid.scrolling_region.start + dmg->scroll.lines) * c->term.grid.cell_height; int width = buf->width; - int height = (c->term.grid.rows - - dmg->scroll.top_margin - - dmg->scroll.bottom_margin - - dmg->scroll.lines) * c->term.grid.cell_height; + int height = (scrolling_region - dmg->scroll.lines) * c->term.grid.cell_height; const uint32_t stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); LOG_DBG("damage: SCROLL REVERSE: %d-%d by %d lines (dst-y: %d, src-y: %d, " "height: %d, stride: %d, mmap-size: %zu)", - dmg->scroll.top_margin, - c->term.grid.rows - dmg->scroll.bottom_margin, + c->term.grid.scrolling_region.start, c->term.grid.scrolling_region.end, dmg->scroll.lines, dst_y, src_y, height, stride, buf->size); @@ -330,7 +327,7 @@ grid_render_scroll_reverse(struct context *c, struct buffer *buf, struct damage erase = { .type = DAMAGE_ERASE, .range = { - .start = dmg->scroll.top_margin * cols, + .start = c->term.grid.scrolling_region.start * cols, .length = dmg->scroll.lines * cols }, }; @@ -405,7 +402,9 @@ resize(struct context *c, int width, int height) c->width = width; c->height = height; - size_t old_cells_len = c->term.grid.cols * c->term.grid.rows; + const size_t old_rows = c->term.grid.rows; + const size_t old_cols = c->term.grid.cols; + const size_t old_cells_len = old_rows * old_cols; c->term.grid.cell_width = (int)ceil(c->fextents.max_x_advance); c->term.grid.cell_height = (int)ceil(c->fextents.height); @@ -455,6 +454,9 @@ resize(struct context *c, int width, int height) LOG_ERRNO("TIOCSWINSZ"); } + if (c->term.grid.scrolling_region.end == old_rows) + c->term.grid.scrolling_region.end = c->term.grid.rows; + tll_free(c->term.grid.damage); assert(tll_length(c->term.grid.damage) == 0); grid_damage_update(&c->term.grid, 0, c->term.grid.rows * c->term.grid.cols); diff --git a/terminal.h b/terminal.h index 08b441d9..ee866b83 100644 --- a/terminal.h +++ b/terminal.h @@ -40,8 +40,6 @@ struct damage { /* DAMAGE_SCROLL, DAMAGE_SCROLL_REVERSE */ struct { - int top_margin; - int bottom_margin; int lines; } scroll; }; @@ -53,6 +51,13 @@ struct grid { int cell_width; int cell_height; + /* Scrolling region - counted as lines excluded from scrolling, + * from top and from bottom */ + struct { + int start; + int end; + } scrolling_region; + int linear_cursor; struct { int row; diff --git a/vt.c b/vt.c index c7352b9b..df5f559a 100644 --- a/vt.c +++ b/vt.c @@ -574,12 +574,12 @@ esc_dispatch(struct terminal *term, uint8_t final) case '=': /* Other half of xterm's smkx */ - LOG_WARN("ignoring ESC with final %c", final); + LOG_WARN("unimplemented: keypad mode change"); break; case '>': /* Other half of xterm's rmkx */ - LOG_WARN("ignoring ESC with final %c", final); + LOG_WARN("unimplemented: keypad mode change"); break; default: