diff --git a/csi.c b/csi.c index a737022f..44d6f8bc 100644 --- a/csi.c +++ b/csi.c @@ -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; diff --git a/grid.c b/grid.c index c08a002e..b36c5e0b 100644 --- a/grid.c +++ b/grid.c @@ -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 diff --git a/grid.h b/grid.h index 11f38506..d6ddabee 100644 --- a/grid.h +++ b/grid.h @@ -3,6 +3,34 @@ #include #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 diff --git a/main.c b/main.c index 98fd5045..43507811 100644 --- a/main.c +++ b/main.c @@ -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) diff --git a/render.c b/render.c index 0b833376..1376c454 100644 --- a/render.c +++ b/render.c @@ -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); diff --git a/terminal.c b/terminal.c index 7c15ce87..7630c25e 100644 --- a/terminal.c +++ b/terminal.c @@ -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 diff --git a/terminal.h b/terminal.h index ddc37410..253163af 100644 --- a/terminal.h +++ b/terminal.h @@ -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, diff --git a/vt.c b/vt.c index 7bab63d1..7ce2ddcb 100644 --- a/vt.c +++ b/vt.c @@ -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);