wip: grid is now represented as a grid, not a linear array

The grid is now represented with an array of row *pointers*. Each row
contains an array of cells (the row's columns).

The main point of having row pointers is we can now move rows around
almost for free.

This is useful when scrolling with scroll margins for example, where
we previously had to copy the lines in the margins. Now it's just a
matter of swapping two pointers.
This commit is contained in:
Daniel Eklöf 2019-07-08 13:57:31 +02:00
parent 98db7f58cb
commit 4e25019ba6
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
8 changed files with 457 additions and 81 deletions

65
csi.c
View file

@ -338,25 +338,26 @@ csi_dispatch(struct terminal *term, uint8_t final)
/* Erase screen */
int param = param_get(term, 0, 0);
int start = -1;
int end = -1;
switch (param) {
case 0:
/* From cursor to end of screen */
start = term->cursor.linear;
end = term->cols * term->rows;
term_erase(
term,
&term->cursor,
&(struct coord){term->cols - 1, term->rows - 1});
break;
case 1:
/* From start of screen to cursor */
start = 0;
end = term->cursor.linear;
term_erase(term, &(struct coord){0, 0}, &term->cursor);
break;
case 2:
/* Erase entire screen */
start = 0;
end = term->cols * term->rows;
term_erase(
term,
&(struct coord){0, 0},
&(struct coord){term->cols - 1, term->rows - 1});
break;
default:
@ -365,8 +366,6 @@ csi_dispatch(struct terminal *term, uint8_t final)
abort();
break;
}
term_erase(term, start, end);
break;
}
@ -374,25 +373,27 @@ csi_dispatch(struct terminal *term, uint8_t final)
/* Erase line */
int param = param_get(term, 0, 0);
int start = -1;
int end = -1;
switch (param) {
case 0:
/* From cursor to end of line */
start = term->cursor.linear;
end = term_cursor_linear(term, term->cursor.row, term->cols);
term_erase(
term,
&term->cursor,
&(struct coord){term->cols - 1, term->cursor.row});
break;
case 1:
/* From start of line to cursor */
start = term_cursor_linear(term, term->cursor.row, 0);
end = term->cursor.linear;
term_erase(
term, &(struct coord){0, term->cursor.row}, &term->cursor);
break;
case 2:
/* Entire line */
start = term_cursor_linear(term, term->cursor.row, 0);
end = term_cursor_linear(term, term->cursor.row, term->cols);
term_erase(
term,
&(struct coord){0, term->cursor.row},
&(struct coord){term->cols - 1, term->cursor.row});
break;
default:
@ -402,7 +403,6 @@ csi_dispatch(struct terminal *term, uint8_t final)
break;
}
term_erase(term, start, end);
break;
}
@ -453,15 +453,25 @@ csi_dispatch(struct terminal *term, uint8_t final)
int remaining = term->cols - (term->cursor.col + count);
/* 'Delete' characters by moving the remaining ones */
memmove(&term->grid->cur_line[term->cursor.col],
&term->grid->cur_line[term->cursor.col + count],
remaining * sizeof(term->grid->cur_line[0]));
memmove(&term->grid->cur_row->cells[term->cursor.col],
&term->grid->cur_row->cells[term->cursor.col + count],
remaining * sizeof(term->grid->cur_row->cells[0]));
#if 0
term_damage_update(term, term->cursor.linear, remaining);
#else
term->grid->cur_row->dirty = true;
#endif
/* Erase the remainder of the line */
term_erase(
term,
&(struct coord){term->cursor.col + remaining, term->cursor.row},
&(struct coord){term->cols - 1, term->cursor.row});
#if 0
term_erase(
term, term->cursor.linear + remaining,
term->cursor.linear + remaining + count);
#endif
break;
}
@ -478,9 +488,16 @@ csi_dispatch(struct terminal *term, uint8_t final)
int count = min(
param_get(term, 0, 1), term->cols - term->cursor.col);
term_erase(
term,
&term->cursor,
&(struct coord){term->cursor.col + count, term->cursor.row});
#if 0
memset(&term->grid->cur_line[term->cursor.col],
0, count * sizeof(term->grid->cur_line[0]));
term_damage_erase(term, term->cursor.linear, count);
#endif
break;
}
@ -630,8 +647,8 @@ csi_dispatch(struct terminal *term, uint8_t final)
tll_free(term->alt.damage);
tll_free(term->alt.scroll_damage);
grid_memclear(term->grid, 0, term->rows * term->cols);
term_damage_erase(term, 0, term->rows * term->cols);
//grid_memclear(term->grid, 0, term->rows * term->cols);
//term_damage_erase(term, 0, term->rows * term->cols);
}
break;

3
grid.c
View file

@ -6,7 +6,7 @@
#define LOG_MODULE "grid"
#define LOG_ENABLE_DBG 0
#include "log.h"
#if 0
struct cell *
grid_get_range(struct grid *grid, int start, int *length)
{
@ -89,3 +89,4 @@ grid_memmove(struct grid *grid, int dst, int src, int length)
copy_idx += count;
}
}
#endif

28
grid.h
View file

@ -3,6 +3,34 @@
#include <stddef.h>
#include "terminal.h"
static inline struct row *
grid_row(struct grid *grid, int row)
{
assert(grid->offset >= 0);
return grid->rows[(grid->offset + row + grid->num_rows) % grid->num_rows];
}
static inline void
grid_swap_row(struct grid *grid, int row_a, int row_b)
{
assert(grid->offset >= 0);
assert(row_a != row_b);
assert(row_a >= 0);
assert(row_b >= 0);
int real_a = (grid->offset + row_a + grid->num_rows) % grid->num_rows;
int real_b = (grid->offset + row_b + grid->num_rows) % grid->num_rows;
struct row *tmp = grid->rows[real_a];
grid->rows[real_a] = grid->rows[real_b];
grid->rows[real_b] = tmp;
grid->rows[real_a]->dirty = true;
grid->rows[real_b]->dirty = true;
}
#if 0
struct cell *grid_get_range(struct grid *grid, int start, int *length);
void grid_memclear(struct grid *grid, int start, int length);
void grid_memmove(struct grid *grid, int dst, int src, int length);
#endif

22
main.c
View file

@ -589,6 +589,10 @@ out:
wl_pointer_destroy(term.wl.pointer.pointer);
if (term.wl.pointer.surface != NULL)
wl_surface_destroy(term.wl.pointer.surface);
if (term.wl.keyboard != NULL)
wl_keyboard_destroy(term.wl.keyboard);
if (term.wl.seat != NULL)
wl_seat_destroy(term.wl.seat);
if (term.wl.surface != NULL)
wl_surface_destroy(term.wl.surface);
if (term.wl.shell != NULL)
@ -601,9 +605,23 @@ out:
wl_registry_destroy(term.wl.registry);
if (term.wl.display != NULL)
wl_display_disconnect(term.wl.display);
if (term.kbd.xkb_keymap != NULL)
xkb_keymap_unref(term.kbd.xkb_keymap);
if (term.kbd.xkb_state != NULL)
xkb_state_unref(term.kbd.xkb_state);
if (term.kbd.xkb != NULL)
xkb_context_unref(term.kbd.xkb);
free(term.normal.cells);
free(term.alt.cells);
for (int row = 0; row < term.normal.num_rows; row++) {
free(term.normal.rows[row]->cells);
free(term.normal.rows[row]);
}
free(term.normal.rows);
for (int row = 0; row < term.alt.num_rows; row++) {
free(term.alt.rows[row]->cells);
free(term.alt.rows[row]);
}
free(term.alt.rows);
for (size_t i = 0; i < sizeof(term.fonts) / sizeof(term.fonts[0]); i++) {
if (term.fonts[i] != NULL)

213
render.c
View file

@ -10,6 +10,7 @@
#define LOG_ENABLE_DBG 0
#include "log.h"
#include "shm.h"
#include "grid.h"
#define min(x, y) ((x) < (y) ? (x) : (y))
#define max(x, y) ((x) > (y) ? (x) : (y))
@ -32,6 +33,97 @@ struct glyph_sequence {
static struct glyph_sequence gseq;
static void
render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell,
int col, int row)
{
/* Cursor here? */
bool has_cursor
= (!term->hide_cursor &&
(term->cursor.col == col && term->cursor.row == row));
int width = term->cell_width;
int height = term->cell_height;
int x = col * width;
int y = row * height;
struct rgba foreground = cell->attrs.have_foreground
? cell->attrs.foreground
: !term->reverse ? term->foreground : term->background;
struct rgba background = cell->attrs.have_background
? cell->attrs.background
: !term->reverse ? term->background : term->foreground;
if (has_cursor) {
struct rgba swap = foreground;
foreground = background;
background = swap;
}
if (cell->attrs.reverse) {
struct rgba swap = foreground;
foreground = background;
background = swap;
}
/* Background */
cairo_set_source_rgba(
buf->cairo, background.r, background.g, background.b, background.a);
cairo_rectangle(buf->cairo, x, y, width, height);
cairo_fill(buf->cairo);
if (cell->c[0] == '\0' || cell->c[0] == ' ')
return;
if (cell->attrs.conceal)
return;
/*
* cairo_show_glyphs() apparently works *much* faster when
* called once with a large array of glyphs, compared to
* multiple calls with a single glyph.
*
* So, collect glyphs until cell attributes change, then we
* 'flush' (render) the glyphs.
*/
if (memcmp(&cell->attrs, &gseq.attrs, sizeof(cell->attrs)) != 0 ||
gseq.count >= sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0]) - 10 ||
memcmp(&gseq.foreground, &foreground, sizeof(foreground)) != 0)
{
if (gseq.count >= sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0]) - 10)
LOG_WARN("hit glyph limit");
cairo_set_scaled_font(buf->cairo, attrs_to_font(term, &gseq.attrs));
cairo_set_source_rgba(
buf->cairo, gseq.foreground.r, gseq.foreground.g,
gseq.foreground.b, gseq.foreground.a);
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_OVER);
cairo_show_glyphs(buf->cairo, gseq.glyphs, gseq.count);
gseq.g = gseq.glyphs;
gseq.count = 0;
gseq.attrs = cell->attrs;
gseq.foreground = foreground;
}
int new_glyphs
= sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0]) - gseq.count;
cairo_status_t status = cairo_scaled_font_text_to_glyphs(
attrs_to_font(term, &cell->attrs), x, y + term->fextents.ascent,
cell->c, strlen(cell->c), &gseq.g, &new_glyphs,
NULL, NULL, NULL);
if (status != CAIRO_STATUS_SUCCESS)
return;
gseq.g += new_glyphs;
gseq.count += new_glyphs;
assert(gseq.count <= sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0]));
}
#if 0
static void
grid_render_update(struct terminal *term, struct buffer *buf, const struct damage *dmg)
{
@ -249,6 +341,7 @@ grid_render_erase(struct terminal *term, struct buffer *buf, const struct damage
wl_surface_damage_buffer(term->wl.surface, x, y, width, height);
}
}
#endif
static void
grid_render_scroll(struct terminal *term, struct buffer *buf,
@ -278,6 +371,7 @@ grid_render_scroll(struct terminal *term, struct buffer *buf,
wl_surface_damage_buffer(term->wl.surface, 0, dst_y, width, height);
}
#if 0
const int cols = term->cols;
struct damage erase = {
@ -290,6 +384,7 @@ grid_render_scroll(struct terminal *term, struct buffer *buf,
},
};
grid_render_erase(term, buf, &erase);
#endif
}
static void
@ -320,6 +415,7 @@ grid_render_scroll_reverse(struct terminal *term, struct buffer *buf,
wl_surface_damage_buffer(term->wl.surface, 0, dst_y, width, height);
}
#if 0
const int cols = term->cols;
struct damage erase = {
@ -331,6 +427,7 @@ grid_render_scroll_reverse(struct terminal *term, struct buffer *buf,
},
};
grid_render_erase(term, buf, &erase);
#endif
}
static void frame_callback(
@ -345,16 +442,19 @@ grid_render(struct terminal *term)
{
static int last_cursor;
#if 0
if (tll_length(term->grid->damage) == 0 &&
tll_length(term->grid->scroll_damage) == 0 &&
last_cursor == term->grid->offset + term->cursor.linear)
{
return;
}
#endif
assert(term->width > 0);
assert(term->height > 0);
//LOG_WARN("RENDER");
struct buffer *buf = shm_get_buffer(term->wl.shm, term->width, term->height);
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_SOURCE);
@ -388,6 +488,8 @@ grid_render(struct terminal *term)
last_buf = buf;
}
bool all_clean = tll_length(term->grid->scroll_damage) == 0;
tll_foreach(term->grid->scroll_damage, it) {
switch (it->item.type) {
case DAMAGE_SCROLL:
@ -409,7 +511,7 @@ grid_render(struct terminal *term)
gseq.g = gseq.glyphs;
gseq.count = 0;
#if 0
tll_foreach(term->grid->damage, it) {
switch (it->item.type) {
case DAMAGE_ERASE: grid_render_erase(term, buf, &it->item); break;
@ -423,24 +525,77 @@ grid_render(struct terminal *term)
tll_remove(term->grid->damage, it);
}
#endif
for (int r = 0; r < term->rows; r++) {
struct row *row = grid_row(term->grid, r);
if (!row->dirty)
continue;
//LOG_WARN("rendering line: %d", r);
for (int col = 0; col < term->cols; col++)
render_cell(term, buf, &row->cells[col], col, r);
row->dirty = false;
all_clean = false;
wl_surface_damage_buffer(term->wl.surface, 0, r * term->cell_height, term->width, term->cell_height);
}
/* TODO: break out to function */
/* Re-render last cursor cell and current cursor cell */
/* Make sure previous cursor is refreshed (to avoid "ghost" cursors) */
if (last_cursor != term->cursor.linear) {
int cursor_as_linear
= (term->grid->offset + term->cursor.row) * term->cols + term->cursor.col;
if (last_cursor != cursor_as_linear) {
#if 0
struct damage prev_cursor = {
.type = DAMAGE_UPDATE,
.range = {.start = last_cursor, .length = 1},
};
grid_render_update(term, buf, &prev_cursor);
#endif
#if 1
int row = last_cursor / term->cols - term->grid->offset;
int col = last_cursor % term->cols;
if (row >= 0 && row < term->rows) {
render_cell(term, buf, &grid_row(term->grid, row)->cells[col], col, row);
all_clean = false;
wl_surface_damage_buffer(
term->wl.surface, col * term->cell_width, row * term->cell_height,
term->cell_width, term->cell_height);
}
last_cursor = cursor_as_linear;
#endif
}
if (all_clean) {
buf->busy = false;
return;
}
#if 0
struct damage cursor = {
.type = DAMAGE_UPDATE,
.range = {.start = term->grid->offset + term->cursor.linear, .length = 1},
};
grid_render_update(term, buf, &cursor);
last_cursor = term->grid->offset + term->cursor.linear;
#endif
render_cell(
term, buf,
&grid_row(term->grid, term->cursor.row)->cells[term->cursor.col],
term->cursor.col, term->cursor.row);
wl_surface_damage_buffer(
term->wl.surface,
term->cursor.col * term->cell_width,
term->cursor.row * term->cell_height,
term->cell_width, term->cell_height);
if (gseq.count > 0) {
cairo_set_scaled_font(buf->cairo, attrs_to_font(term, &gseq.attrs));
@ -451,9 +606,11 @@ grid_render(struct terminal *term)
cairo_show_glyphs(buf->cairo, gseq.glyphs, gseq.count);
}
#if 0
term->grid->offset %= term->grid->size;
if (term->grid->offset < 0)
term->grid->offset += term->grid->size;
#endif
//cairo_surface_flush(buf->cairo_surface);
wl_surface_attach(term->wl.surface, buf->wl_buf, 0, 0);
@ -485,6 +642,7 @@ render_resize(struct terminal *term, int width, int height)
term->width = width;
term->height = height;
#if 0
const size_t old_rows = term->rows;
const size_t normal_old_size = term->normal.size;
const size_t alt_old_size = term->alt.size;
@ -522,6 +680,49 @@ render_resize(struct terminal *term, int width, int height)
.background = term->background},
};
}
#endif
//const int old_cols = term->cols;
const int old_rows = term->rows;
const int new_cols = term->width / term->cell_width;
const int new_rows = term->height / term->cell_height;
for (int r = 0; r < term->normal.num_rows; r++) {
free(term->normal.rows[r]->cells);
free(term->normal.rows[r]);
}
free(term->normal.rows);
for (int r = 0; r < term->alt.num_rows; r++) {
free(term->alt.rows[r]->cells);
free(term->alt.rows[r]);
}
free(term->alt.rows);
/* TODO: reflow old content */
term->normal.num_rows = new_rows;
term->normal.offset = 0;
term->alt.num_rows = new_rows;
term->alt.offset = 0;
term->normal.rows = malloc(
term->normal.num_rows * sizeof(term->normal.rows[0]));
for (int r = 0; r < term->normal.num_rows; r++) {
struct row *row = malloc(sizeof(*row));
row->cells = calloc(new_cols, sizeof(row->cells[0]));
row->dirty = true;
term->normal.rows[r] = row;
}
term->alt.rows = malloc(term->alt.num_rows * sizeof(term->alt.rows[0]));
for (int r = 0; r < term->alt.num_rows; r++) {
struct row *row = malloc(sizeof(*row));
row->cells = calloc(new_cols, sizeof(row->cells[0]));
row->dirty = true;
term->alt.rows[r] = row;
}
term->cols = new_cols;
term->rows = new_rows;
LOG_INFO("resize: %dx%d, grid: cols=%d, rows=%d",
term->width, term->height, term->cols, term->rows);
@ -540,10 +741,14 @@ render_resize(struct terminal *term, int width, int height)
if (term->scroll_region.end == old_rows)
term->scroll_region.end = term->rows;
#if 0
term_cursor_to(
term,
min(term->cursor.row, term->rows - 1),
min(term->cursor.col, term->cols - 1));
#endif
term->cursor.row = term->cursor.col = 0;
term->grid->cur_row = grid_row(term->grid, 0);
term_damage_all(term);

View file

@ -12,6 +12,7 @@
#define min(x, y) ((x) < (y) ? (x) : (y))
#define max(x, y) ((x) > (y) ? (x) : (y))
#if 0
static bool
damage_merge_range(struct terminal *term, const struct damage *dmg)
{
@ -66,27 +67,36 @@ term_damage_update_or_erase(struct terminal *term, enum damage_type damage_type,
tll_push_back(term->grid->damage, dmg);
}
#endif
void
term_damage_update(struct terminal *term, int start, int length)
{
#if 0
assert(start + length <= term->rows * term->cols);
term_damage_update_or_erase(term, DAMAGE_UPDATE, start, length);
#endif
}
void
term_damage_erase(struct terminal *term, int start, int length)
{
#if 0
assert(start + length <= term->rows * term->cols);
term_damage_update_or_erase(term, DAMAGE_ERASE, start, length);
#endif
}
void
term_damage_all(struct terminal *term)
{
#if 0
tll_free(term->grid->damage);
tll_free(term->grid->scroll_damage);
term_damage_update(term, 0, term->rows * term->cols);
#else
for (int i = 0; i < term->rows; i++)
grid_row(term->grid, i)->dirty = true;
#endif
}
#if 0
@ -119,6 +129,7 @@ void
term_damage_scroll(struct terminal *term, enum damage_type damage_type,
struct scroll_region region, int lines)
{
#if 0
//damage_adjust_after_scroll(term, damage_type, region, lines);
if (damage_type == DAMAGE_SCROLL) {
tll_foreach(term->grid->damage, it) {
@ -136,7 +147,7 @@ term_damage_scroll(struct terminal *term, enum damage_type damage_type,
break;
}
}
#endif
if (tll_length(term->grid->scroll_damage) > 0) {
struct damage *dmg = &tll_back(term->grid->scroll_damage);
@ -155,6 +166,7 @@ term_damage_scroll(struct terminal *term, enum damage_type damage_type,
tll_push_back(term->grid->scroll_damage, dmg);
}
#if 0
void
term_erase(struct terminal *term, int start, int end)
{
@ -187,41 +199,75 @@ term_erase(struct terminal *term, int start, int end)
term_damage_erase(term, start, end - start);
}
}
int
term_cursor_linear(const struct terminal *term, int row, int col)
#else
static inline void
erase_cell_range(struct terminal *term, struct row *row, int start, int end)
{
return row * term->cols + col;
assert(start < term->cols);
assert(end < term->cols);
if (unlikely(term->vt.attrs.have_background)) {
for (int col = start; col <= end; col++) {
row->cells[col].c[0] = '\0';
row->cells[col].attrs.have_background = true;
row->cells[col].attrs.background = term->vt.attrs.background;
}
} else {
memset(&row->cells[start], 0, (end - start + 1) * sizeof(row->cells[0]));
}
row->dirty = true;
}
static inline void
erase_line(struct terminal *term, struct row *row)
{
erase_cell_range(term, row, 0, term->cols - 1);
}
void
term_erase(struct terminal *term, const struct coord *start, const struct coord *end)
{
assert(start->row <= end->row);
assert(start->col <= end->col || start->row < end->row);
if (start->row == end->row) {
struct row *row = grid_row(term->grid, start->row);
erase_cell_range(term, row, start->col, end->col);
return;
}
assert(end->row > start->row);
erase_cell_range(
term, grid_row(term->grid, start->row), start->col, term->cols - 1);
for (int r = start->row + 1; r < end->row; r++)
erase_line(term, grid_row(term->grid, r));
erase_cell_range(term, grid_row(term->grid, end->row), 0, end->col);
}
#endif
void
term_cursor_to(struct terminal *term, int row, int col)
{
assert(row < term->rows);
assert(col < term->cols);
int new_linear = row * term->cols + col;
assert(new_linear < term->rows * term->cols);
term->print_needs_wrap = false;
term->cursor.linear = new_linear;
term->cursor.col = col;
term->cursor.row = row;
int len = term->cols;
term->grid->cur_line = grid_get_range(
term->grid, term->cursor.linear - col, &len);
assert(len == term->cols);
term->grid->cur_row = grid_row(term->grid, row);
}
void
term_cursor_left(struct terminal *term, int count)
{
int move_amount = min(term->cursor.col, count);
term->cursor.linear -= move_amount;
term->cursor.col -= move_amount;
assert(term->cursor.col >= 0);
term->print_needs_wrap = false;
}
@ -229,8 +275,8 @@ void
term_cursor_right(struct terminal *term, int count)
{
int move_amount = min(term->cols - term->cursor.col - 1, count);
term->cursor.linear += move_amount;
term->cursor.col += move_amount;
assert(term->cursor.col < term->cols);
term->print_needs_wrap = false;
}
@ -253,12 +299,13 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows
{
LOG_DBG("scroll: %d rows", rows);
assert(rows < term->rows && "unimplemented");
for (int i = region.start - 1; i >= 0; i--)
grid_swap_row(term->grid, i, i + rows);
if (region.start > 0) {
/* TODO: check if it's worth memoving the scroll area instead,
* under certain circumstances */
grid_memmove(term->grid, rows * term->cols, 0, region.start * term->cols);
#if 0
tll_foreach(term->grid->damage, it) {
int start = it->item.range.start - term->grid->offset;
int end __attribute__((unused)) = start + it->item.range.length;
@ -268,16 +315,22 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows
it->item.range.start += rows * term->cols;
}
}
#endif
}
for (int i = term->rows - 1; i >= region.end; i--)
grid_swap_row(term->grid, i, i + rows);
if (region.end < term->rows) {
/* Copy scrolled-up bottom region to new bottom region */
#if 0
grid_memmove(
term->grid,
(region.end + rows) * term->cols,
region.end * term->cols,
(term->rows - region.end) * term->cols);
#endif
#if 0
tll_foreach(term->grid->damage, it) {
int start = it->item.range.start - term->grid->offset;
int end = start + it->item.range.length;
@ -287,24 +340,33 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows
it->item.range.start += rows * term->cols;
}
}
#endif
}
/* Offset grid origin */
term->grid->offset += rows * term->cols;
term->grid->offset += rows;
term->grid->offset %= term->grid->num_rows;
/* Clear scrolled-in lines */
grid_memclear(
term->grid,
max(0, region.end - rows) * term->cols,
min(rows, term->rows) * term->cols);
#if 0
term_erase(
term,
&(struct coord){0, max(region.end - rows, 0)},
&(struct coord){term->cols - 1, region.end - 1});
#else
for (int r = max(region.end - rows, 0); r < region.end; r++)
erase_line(term, grid_row(term->grid, r));
#endif
term_damage_scroll(term, DAMAGE_SCROLL, region, rows);
term->grid->cur_row = grid_row(term->grid, term->cursor.row);
#if 0
int len = term->cols;
term->grid->cur_line = grid_get_range(
term->grid, term->cursor.linear - term->cursor.col, &len);
assert(len == term->cols);
#endif
}
void
@ -317,7 +379,11 @@ void
term_scroll_reverse_partial(struct terminal *term,
struct scroll_region region, int rows)
{
assert(rows < term->rows && "unimplemented");
if (region.end < term->rows) {
//assert(false);
#if 0
grid_memmove(
term->grid,
(region.end - rows) * term->cols,
@ -333,10 +399,12 @@ term_scroll_reverse_partial(struct terminal *term,
it->item.range.start -= rows * term->cols;
}
}
#endif
}
if (region.start > 0) {
//assert(false);
#if 0
grid_memmove(
term->grid, -rows * term->cols, 0, region.start * term->cols);
@ -354,19 +422,31 @@ term_scroll_reverse_partial(struct terminal *term,
it->item.range.start -= rows * term->cols;
}
}
#endif
}
term->grid->offset -= rows * term->cols;
term->grid->offset += term->grid->num_rows - rows;
term->grid->offset %= term->grid->num_rows;
grid_memclear(term->grid, region.start * term->cols, rows * term->cols);
for (int i = region.end + rows; i < term->rows + rows; i++)
grid_swap_row(term->grid, i, i - rows);
for (int i = 0 + rows; i < region.start + rows; i++)
grid_swap_row(term->grid, i, i - rows);
term_erase(
term,
&(struct coord){0, region.start},
&(struct coord){term->cols - 1, min(region.start + rows, region.end) - 1});
term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows);
term->grid->cur_row = grid_row(term->grid, term->cursor.row);
#if 0
int len = term->cols;
term->grid->cur_line = grid_get_range(
term->grid, term->cursor.linear - term->cursor.col, &len);
assert(len == term->cols);
#endif
}
void

View file

@ -74,10 +74,9 @@ struct scroll_region {
int end;
};
struct cursor {
int row;
struct coord {
int col;
int linear;
int row;
};
enum damage_type {DAMAGE_UPDATE, DAMAGE_ERASE, DAMAGE_SCROLL, DAMAGE_SCROLL_REVERSE};
@ -85,10 +84,12 @@ struct damage {
enum damage_type type;
union {
/* DAMAGE_UPDATE, DAMAGE_ERASE */
#if 0
struct {
int start;
int length;
} range;
#endif
/* DAMAGE_SCROLL, DAMAGE_SCROLL_REVERSE */
struct {
@ -98,12 +99,19 @@ struct damage {
};
};
struct row {
struct cell *cells;
bool dirty;
};
struct grid {
int size;
int num_rows;
int offset;
struct cell *cells;
struct cell *cur_line;
//struct cell *cells;
//struct cell *cur_line;
struct row **rows;
struct row *cur_row;
tll(struct damage) damage;
tll(struct damage) scroll_damage;
@ -227,14 +235,14 @@ struct terminal {
struct rgba background;
struct {
int row;
int col;
int row;
int button;
} mouse;
struct cursor cursor;
struct cursor saved_cursor;
struct cursor alt_saved_cursor;
struct coord cursor;
struct coord saved_cursor;
struct coord alt_saved_cursor;
struct grid normal;
struct grid alt;
@ -254,7 +262,9 @@ void term_damage_scroll(
struct terminal *term, enum damage_type damage_type,
struct scroll_region region, int lines);
void term_erase(struct terminal *term, int start, int end);
//void term_erase(struct terminal *term, int start, int end);
void term_erase(
struct terminal *term, const struct coord *start, const struct coord *end);
void term_cursor_to(struct terminal *term, int row, int col);
void term_cursor_left(struct terminal *term, int count);
@ -270,8 +280,6 @@ void term_scroll_partial(
void term_scroll_reverse_partial(
struct terminal *term, struct scroll_region region, int rows);
int term_cursor_linear(const struct terminal *term, int row, int col);
void term_mouse_down(struct terminal *term, int button, int row, int col,
bool shift, bool alt, bool ctrl);
void term_mouse_up(struct terminal *term, int button, int row, int col,

27
vt.c
View file

@ -658,6 +658,7 @@ pre_print(struct terminal *term)
static inline void
post_print(struct terminal *term)
{
term->grid->cur_row->dirty = true;
if (term->cursor.col < term->cols - 1)
term_cursor_right(term, 1);
else
@ -669,11 +670,19 @@ print_insert(struct terminal *term)
{
if (unlikely(term->insert_mode)) {
assert(false && "untested");
grid_memmove(
term->grid, term->cursor.linear + 1, term->cursor.linear,
struct row *row = term->grid->cur_row;
memmove(
&row[term->cursor.col + 1],
&row[term->cursor.col],
term->cols - term->cursor.col - 1);
#if 0
term_damage_update(
term, term->cursor.linear + 1, term->cols - term->cursor.col - 1);
#else
row->dirty = true;
#endif
}
}
@ -682,8 +691,13 @@ action_print_utf8(struct terminal *term)
{
pre_print(term);
struct cell *cell = &term->grid->cur_line[term->cursor.col];
struct row *row = term->grid->cur_row;
struct cell *cell = &row->cells[term->cursor.col];
#if 0
term_damage_update(term, term->cursor.linear, 1);
#else
row->dirty = true;
#endif
print_insert(term);
@ -701,8 +715,13 @@ action_print(struct terminal *term, uint8_t c)
{
pre_print(term);
struct cell *cell = &term->grid->cur_line[term->cursor.col];
struct row *row = term->grid->cur_row;
struct cell *cell = &row->cells[term->cursor.col];
#if 0
term_damage_update(term, term->cursor.linear, 1);
#else
row->dirty = true;
#endif
print_insert(term);