vt: wip: implement scrolling region

This is largely untested, but existing scrolling code has been
converted to using a terminal-global scrolling region that is defined
as start-end of the scrollable region.

This is compared to the old code where the scrolling region where
defined in terms of marginals, counted in lines from top and from
bottom.
This commit is contained in:
Daniel Eklöf 2019-06-23 18:02:49 +02:00
parent 7183b2f0fe
commit b0a2c54fe8
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
6 changed files with 68 additions and 55 deletions

15
csi.c
View file

@ -380,6 +380,21 @@ csi_dispatch(struct terminal *term, uint8_t final)
break; 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': case 't':
/* /*
* TODO: xterm's terminfo specifies *both* \e[?1049h *and* * TODO: xterm's terminfo specifies *both* \e[?1049h *and*

50
grid.c
View file

@ -87,8 +87,11 @@ grid_damage_erase(struct grid *grid, int start, int length)
static void static void
damage_adjust_after_scroll(struct grid *grid, enum damage_type damage_type, 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 const int adjustment
= lines * grid->cols * (damage_type == DAMAGE_SCROLL_REVERSE ? -1 : 1); = lines * grid->cols * (damage_type == DAMAGE_SCROLL_REVERSE ? -1 : 1);
top_margin *= grid->cols; top_margin *= grid->cols;
@ -131,8 +134,7 @@ damage_adjust_after_scroll(struct grid *grid, enum damage_type damage_type,
} }
void void
grid_damage_scroll(struct grid *grid, enum damage_type damage_type, grid_damage_scroll(struct grid *grid, enum damage_type damage_type, int lines)
int top_margin, int bottom_margin, int lines)
{ {
if (tll_length(grid->damage) > 0 && if (tll_length(grid->damage) > 0 &&
tll_front(grid->damage).type == damage_type) 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 */ /* Merge with existing scroll damage */
struct damage *dmg = &tll_front(grid->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; 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 we've scrolled away the entire screen, replace with an erase */
if (dmg->scroll.lines >= (grid->rows - (dmg->scroll.top_margin + if (dmg->scroll.lines >= scrolling_region) {
dmg->scroll.bottom_margin))) {
dmg->type = DAMAGE_ERASE; dmg->type = DAMAGE_ERASE;
dmg->range.start = dmg->scroll.top_margin * grid->cols; dmg->range.start = grid->scrolling_region.start * grid->cols;
dmg->range.length = (grid->rows - top_margin - bottom_margin) * grid->cols; dmg->range.length = scrolling_region * grid->cols;
} }
} else { } else {
struct damage dmg = { struct damage dmg = {
.type = damage_type, .type = damage_type,
.scroll = { .scroll = {.lines = lines},
.top_margin = top_margin,
.bottom_margin = bottom_margin,
.lines = lines
},
}; };
tll_push_front(grid->damage, dmg); tll_push_front(grid->damage, dmg);
} }
damage_adjust_after_scroll( damage_adjust_after_scroll(grid, damage_type, lines);
grid, damage_type, top_margin, bottom_margin, lines);
} }
void void
@ -243,15 +238,12 @@ grid_cursor_down(struct grid *grid, int count)
void void
grid_scroll(struct grid *grid, int rows) grid_scroll(struct grid *grid, int rows)
{ {
const int top_margin = 0; const int grid_rows = grid->scrolling_region.end - grid->scrolling_region.start;
const int bottom_margin = 0; const int top_margin = grid->scrolling_region.start;
const int grid_rows = grid->rows - top_margin - bottom_margin; const int bottom_margin = grid->rows - grid->scrolling_region.end;
if (rows >= grid_rows) { if (rows >= grid_rows) {
assert(false && "untested"); assert(false && "untested");
grid_erase(grid,
top_margin * grid->cols,
(grid->rows - bottom_margin) * grid->cols);
return; return;
} }
@ -266,7 +258,7 @@ grid_scroll(struct grid *grid, int rows)
&grid->cells[cell_dst], &grid->cells[cell_src], &grid->cells[cell_dst], &grid->cells[cell_src],
bytes); bytes);
grid_damage_scroll(grid, DAMAGE_SCROLL, top_margin, bottom_margin, rows); grid_damage_scroll(grid, DAMAGE_SCROLL, rows);
grid_erase( grid_erase(
grid, grid,
(grid_rows - bottom_margin - rows) * grid->cols, (grid_rows - bottom_margin - rows) * grid->cols,
@ -276,9 +268,9 @@ grid_scroll(struct grid *grid, int rows)
void void
grid_scroll_reverse(struct grid *grid, int rows) grid_scroll_reverse(struct grid *grid, int rows)
{ {
const int top_margin = 0; const int grid_rows = grid->scrolling_region.end - grid->scrolling_region.start;
const int bottom_margin = 0; const int top_margin = grid->scrolling_region.start;
const int grid_rows = grid->rows - top_margin - bottom_margin; const int bottom_margin = grid->rows - grid->scrolling_region.end;
if (rows >= grid_rows) { if (rows >= grid_rows) {
assert(false && "todo"); assert(false && "todo");
@ -296,7 +288,7 @@ grid_scroll_reverse(struct grid *grid, int rows)
&grid->cells[cell_dst], &grid->cells[cell_src], &grid->cells[cell_dst], &grid->cells[cell_src],
bytes); bytes);
grid_damage_scroll(grid, DAMAGE_SCROLL_REVERSE, top_margin, bottom_margin, rows); grid_damage_scroll(grid, DAMAGE_SCROLL_REVERSE, rows);
grid_erase( grid_erase(
grid, grid,
top_margin * grid->cols, top_margin * grid->cols,

3
grid.h
View file

@ -5,8 +5,7 @@
void grid_damage_update(struct grid *grid, int start, int length); 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_erase(struct grid *grid, int start, int length);
void grid_damage_scroll( void grid_damage_scroll(
struct grid *grid, enum damage_type damage_type, struct grid *grid, enum damage_type damage_type, int lines);
int top_margin, int bottom_margin, int lines);
void grid_erase(struct grid *grid, int start, int end); void grid_erase(struct grid *grid, int start, int end);

42
main.c
View file

@ -256,20 +256,19 @@ grid_render_scroll(struct context *c, struct buffer *buf,
const struct damage *dmg) const struct damage *dmg)
{ {
//int x = 0; //int x = 0;
int dst_y = (dmg->scroll.top_margin + 0) * c->term.grid.cell_height; const int scrolling_region
int src_y = (dmg->scroll.top_margin + dmg->scroll.lines) * c->term.grid.cell_height; = 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 width = buf->width;
int height = (c->term.grid.rows - int height = (scrolling_region - dmg->scroll.lines) * c->term.grid.cell_height;
dmg->scroll.top_margin -
dmg->scroll.bottom_margin -
dmg->scroll.lines) * c->term.grid.cell_height;
const uint32_t stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); 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, " LOG_DBG("damage: SCROLL: %d-%d by %d lines (dst-y: %d, src-y: %d, "
"height: %d, stride: %d, mmap-size: %zu)", "height: %d, stride: %d, mmap-size: %zu)",
dmg->scroll.top_margin, c->term.grid.scrolling_region.start, c->term.grid.scrolling_region.end,
c->term.grid.rows - dmg->scroll.bottom_margin,
dmg->scroll.lines, dmg->scroll.lines,
dst_y, src_y, height, stride, dst_y, src_y, height, stride,
buf->size); buf->size);
@ -286,8 +285,7 @@ grid_render_scroll(struct context *c, struct buffer *buf,
struct damage erase = { struct damage erase = {
.type = DAMAGE_ERASE, .type = DAMAGE_ERASE,
.range = { .range = {
.start = (c->term.grid.rows - .start = (c->term.grid.scrolling_region.end -
dmg->scroll.bottom_margin -
dmg->scroll.lines) * cols, dmg->scroll.lines) * cols,
.length = 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) const struct damage *dmg)
{ {
//int x = 0; //int x = 0;
int src_y = (dmg->scroll.top_margin + 0) * c->term.grid.cell_height; const int scrolling_region =
int dst_y = (dmg->scroll.top_margin + dmg->scroll.lines) * c->term.grid.cell_height; 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 width = buf->width;
int height = (c->term.grid.rows - int height = (scrolling_region - dmg->scroll.lines) * c->term.grid.cell_height;
dmg->scroll.top_margin -
dmg->scroll.bottom_margin -
dmg->scroll.lines) * c->term.grid.cell_height;
const uint32_t stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); 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, " LOG_DBG("damage: SCROLL REVERSE: %d-%d by %d lines (dst-y: %d, src-y: %d, "
"height: %d, stride: %d, mmap-size: %zu)", "height: %d, stride: %d, mmap-size: %zu)",
dmg->scroll.top_margin, c->term.grid.scrolling_region.start, c->term.grid.scrolling_region.end,
c->term.grid.rows - dmg->scroll.bottom_margin,
dmg->scroll.lines, dmg->scroll.lines,
dst_y, src_y, height, stride, dst_y, src_y, height, stride,
buf->size); buf->size);
@ -330,7 +327,7 @@ grid_render_scroll_reverse(struct context *c, struct buffer *buf,
struct damage erase = { struct damage erase = {
.type = DAMAGE_ERASE, .type = DAMAGE_ERASE,
.range = { .range = {
.start = dmg->scroll.top_margin * cols, .start = c->term.grid.scrolling_region.start * cols,
.length = dmg->scroll.lines * cols .length = dmg->scroll.lines * cols
}, },
}; };
@ -405,7 +402,9 @@ resize(struct context *c, int width, int height)
c->width = width; c->width = width;
c->height = height; 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_width = (int)ceil(c->fextents.max_x_advance);
c->term.grid.cell_height = (int)ceil(c->fextents.height); 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"); 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); tll_free(c->term.grid.damage);
assert(tll_length(c->term.grid.damage) == 0); assert(tll_length(c->term.grid.damage) == 0);
grid_damage_update(&c->term.grid, 0, c->term.grid.rows * c->term.grid.cols); grid_damage_update(&c->term.grid, 0, c->term.grid.rows * c->term.grid.cols);

View file

@ -40,8 +40,6 @@ struct damage {
/* DAMAGE_SCROLL, DAMAGE_SCROLL_REVERSE */ /* DAMAGE_SCROLL, DAMAGE_SCROLL_REVERSE */
struct { struct {
int top_margin;
int bottom_margin;
int lines; int lines;
} scroll; } scroll;
}; };
@ -53,6 +51,13 @@ struct grid {
int cell_width; int cell_width;
int cell_height; 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; int linear_cursor;
struct { struct {
int row; int row;

4
vt.c
View file

@ -574,12 +574,12 @@ esc_dispatch(struct terminal *term, uint8_t final)
case '=': case '=':
/* Other half of xterm's smkx */ /* Other half of xterm's smkx */
LOG_WARN("ignoring ESC with final %c", final); LOG_WARN("unimplemented: keypad mode change");
break; break;
case '>': case '>':
/* Other half of xterm's rmkx */ /* Other half of xterm's rmkx */
LOG_WARN("ignoring ESC with final %c", final); LOG_WARN("unimplemented: keypad mode change");
break; break;
default: default: