From 4e25019ba6bd1bd07925ccafc2936416ef3f7cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 8 Jul 2019 13:57:31 +0200 Subject: [PATCH 01/10] 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. --- csi.c | 65 ++++++++++------ grid.c | 3 +- grid.h | 28 +++++++ main.c | 22 +++++- render.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++- terminal.c | 146 +++++++++++++++++++++++++++--------- terminal.h | 34 +++++---- vt.c | 27 ++++++- 8 files changed, 457 insertions(+), 81 deletions(-) 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); From 587a9c6ffe45ca2babbcdf06b3a6522acaaf2761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 8 Jul 2019 15:27:44 +0200 Subject: [PATCH 02/10] render: use pointers to rgba foreground/background colors This is faster, since we don't have to copy several large doubles when swapping the colors. --- render.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/render.c b/render.c index 1376c454..9a290a97 100644 --- a/render.c +++ b/render.c @@ -47,28 +47,28 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, 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; + const struct rgba *foreground = cell->attrs.have_foreground + ? &cell->attrs.foreground + : !term->reverse ? &term->foreground : &term->background; + const struct rgba *background = cell->attrs.have_background + ? &cell->attrs.background + : !term->reverse ? &term->background : &term->foreground; if (has_cursor) { - struct rgba swap = foreground; + const struct rgba *swap = foreground; foreground = background; background = swap; } if (cell->attrs.reverse) { - struct rgba swap = foreground; + const struct rgba *swap = foreground; foreground = background; background = swap; } /* Background */ cairo_set_source_rgba( - buf->cairo, background.r, background.g, background.b, background.a); + buf->cairo, background->r, background->g, background->b, background->a); cairo_rectangle(buf->cairo, x, y, width, height); cairo_fill(buf->cairo); @@ -89,10 +89,11 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, 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) + 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, @@ -104,7 +105,7 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, gseq.g = gseq.glyphs; gseq.count = 0; gseq.attrs = cell->attrs; - gseq.foreground = foreground; + gseq.foreground = *foreground; } int new_glyphs @@ -606,6 +607,7 @@ grid_render(struct terminal *term) cairo_show_glyphs(buf->cairo, gseq.glyphs, gseq.count); } + assert(term->grid->offset >= 0 && term->grid->offset < term->grid->num_rows); #if 0 term->grid->offset %= term->grid->size; if (term->grid->offset < 0) From f1fa5a4a372a7cd6aa4a0daa8886738f19dbce95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 8 Jul 2019 15:28:33 +0200 Subject: [PATCH 03/10] render: use doubles instead of ints --- render.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/render.c b/render.c index 9a290a97..4b307e7f 100644 --- a/render.c +++ b/render.c @@ -42,10 +42,10 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, = (!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; + double width = term->cell_width; + double height = term->cell_height; + double x = col * width; + double y = row * height; const struct rgba *foreground = cell->attrs.have_foreground ? &cell->attrs.foreground From 69e7744e5dba66df6d779570ffa17033a7e89a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 8 Jul 2019 15:51:44 +0200 Subject: [PATCH 04/10] render: use CAIRO_OPERATER_SOURCE to draw glyphs This is *much* faster. --- render.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/render.c b/render.c index 4b307e7f..09f95ff2 100644 --- a/render.c +++ b/render.c @@ -99,7 +99,6 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, 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; @@ -603,7 +602,6 @@ grid_render(struct terminal *term) 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); } From 1e2a7e77f041f2b6bff2c7f7babd19fe7096609e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 8 Jul 2019 15:56:15 +0200 Subject: [PATCH 05/10] rgba: drop alpha channel support --- csi.c | 50 +++++++++++++++++++++++--------------------------- main.c | 4 ++-- render.c | 32 +++++++++++++------------------- terminal.h | 10 +++++----- 4 files changed, 43 insertions(+), 53 deletions(-) diff --git a/csi.c b/csi.c index 44d6f8bc..a57b1a7f 100644 --- a/csi.c +++ b/csi.c @@ -16,29 +16,29 @@ #define min(x, y) ((x) < (y) ? (x) : (y)) -static const struct rgba colors_regular[] = { - {0.000000, 0.000000, 0.000000, 1.000000}, /* 0x000000ff */ - {0.800000, 0.576471, 0.576471, 1.000000}, /* 0xcc9393ff */ - {0.498039, 0.623529, 0.498039, 1.000000}, /* 0x7f9f7fff */ - {0.815686, 0.749020, 0.560784, 1.000000}, /* 0xd0bf8fff */ - {0.423529, 0.627451, 0.639216, 1.000000}, /* 0x6ca0a3ff */ - {0.862745, 0.549020, 0.764706, 1.000000}, /* 0xdc8cc3ff */ - {0.576471, 0.878431, 0.890196, 1.000000}, /* 0x93e0e3ff */ - {0.862745, 0.862745, 0.800000, 1.000000}, /* 0xdcdcccff */ +static const struct rgb colors_regular[] = { + {0.000000, 0.000000, 0.000000}, /* 0x000000 */ + {0.800000, 0.576471, 0.576471}, /* 0xcc9393 */ + {0.498039, 0.623529, 0.498039}, /* 0x7f9f7f */ + {0.815686, 0.749020, 0.560784}, /* 0xd0bf8f */ + {0.423529, 0.627451, 0.639216}, /* 0x6ca0a3 */ + {0.862745, 0.549020, 0.764706}, /* 0xdc8cc3 */ + {0.576471, 0.878431, 0.890196}, /* 0x93e0e3 */ + {0.862745, 0.862745, 0.800000}, /* 0xdcdccc */ }; -static const struct rgba colors_bright[] = { - {0.000000, 0.000000, 0.000000, 1.000000}, /* 0x000000ff */ - {0.862745, 0.639216, 0.639216, 1.000000}, /* 0xdca3a3ff */ - {0.749020, 0.921569, 0.749020, 1.000000}, /* 0xbfebbfff */ - {0.941176, 0.874510, 0.686275, 1.000000}, /* 0xf0dfafff */ - {0.549020, 0.815686, 0.827451, 1.000000}, /* 0x8cd0d3ff */ - {0.862745, 0.549020, 0.764706, 1.000000}, /* 0xdc8cc3ff */ - {0.576471, 0.878431, 0.890196, 1.000000}, /* 0x93e0e3ff */ - {1.000000, 1.000000, 1.000000, 1.000000}, /* 0xffffffff */ +static const struct rgb colors_bright[] = { + {0.000000, 0.000000, 0.000000}, /* 0x000000 */ + {0.862745, 0.639216, 0.639216}, /* 0xdca3a3 */ + {0.749020, 0.921569, 0.749020}, /* 0xbfebbf */ + {0.941176, 0.874510, 0.686275}, /* 0xf0dfaf */ + {0.549020, 0.815686, 0.827451}, /* 0x8cd0d3 */ + {0.862745, 0.549020, 0.764706}, /* 0xdc8cc3 */ + {0.576471, 0.878431, 0.890196}, /* 0x93e0e3 */ + {1.000000, 1.000000, 1.000000}, /* 0xffffff */ }; -static struct rgba colors256[256]; +static struct rgb colors256[256]; static void __attribute__((constructor)) initialize_colors256(void) @@ -51,22 +51,20 @@ initialize_colors256(void) for (size_t r = 0; r < 6; r++) { for (size_t g = 0; g < 6; g++) { for (size_t b = 0; b < 6; b++) { - colors256[16 + r * 6 * 6 + g * 6 + b] = (struct rgba) { + colors256[16 + r * 6 * 6 + g * 6 + b] = (struct rgb) { r * 51 / 255.0, g * 51 / 255.0, b * 51 / 255.0, - 1.0, }; } } } for (size_t i = 0; i < 24; i++){ - colors256[232 + i] = (struct rgba) { + colors256[232 + i] = (struct rgb) { i * 11 / 255.0, i * 11 / 255.0, i * 11 / 255.0, - 1.0 }; } } @@ -152,11 +150,10 @@ csi_sgr(struct terminal *term) uint8_t r = term->vt.params.v[i + 2].value; uint8_t g = term->vt.params.v[i + 3].value; uint8_t b = term->vt.params.v[i + 4].value; - term->vt.attrs.foreground = (struct rgba) { + term->vt.attrs.foreground = (struct rgb) { r / 255.0, g / 255.0, b / 255.0, - 1.0, }; term->vt.attrs.have_foreground = true; i += 4; @@ -199,11 +196,10 @@ csi_sgr(struct terminal *term) uint8_t r = term->vt.params.v[i + 2].value; uint8_t g = term->vt.params.v[i + 3].value; uint8_t b = term->vt.params.v[i + 4].value; - term->vt.attrs.background = (struct rgba) { + term->vt.attrs.background = (struct rgb) { r / 255.0, g / 255.0, b / 255.0, - 1.0 }; term->vt.attrs.have_background = true; i += 4; diff --git a/main.c b/main.c index 43507811..5ce9c623 100644 --- a/main.c +++ b/main.c @@ -32,8 +32,8 @@ #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) -static const struct rgba default_foreground = {0.86, 0.86, 0.86, 1.0}; -static const struct rgba default_background = {0.067, 0.067, 0.067, 1.0}; +static const struct rgb default_foreground = {0.86, 0.86, 0.86}; +static const struct rgb default_background = {0.067, 0.067, 0.067}; static void shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) diff --git a/render.c b/render.c index 09f95ff2..2e53cb7d 100644 --- a/render.c +++ b/render.c @@ -28,7 +28,7 @@ struct glyph_sequence { int count; struct attributes attrs; - struct rgba foreground; + struct rgb foreground; }; static struct glyph_sequence gseq; @@ -47,28 +47,22 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, double x = col * width; double y = row * height; - const struct rgba *foreground = cell->attrs.have_foreground + const struct rgb *foreground = cell->attrs.have_foreground ? &cell->attrs.foreground : !term->reverse ? &term->foreground : &term->background; - const struct rgba *background = cell->attrs.have_background + const struct rgb *background = cell->attrs.have_background ? &cell->attrs.background : !term->reverse ? &term->background : &term->foreground; - if (has_cursor) { - const struct rgba *swap = foreground; - foreground = background; - background = swap; - } - - if (cell->attrs.reverse) { - const struct rgba *swap = foreground; + /* If *one* is set, we reverse */ + if (has_cursor != cell->attrs.reverse) { + const struct rgb *swap = foreground; foreground = background; background = swap; } /* Background */ - cairo_set_source_rgba( - buf->cairo, background->r, background->g, background->b, background->a); + cairo_set_source_rgb(buf->cairo, background->r, background->g, background->b); cairo_rectangle(buf->cairo, x, y, width, height); cairo_fill(buf->cairo); @@ -95,9 +89,9 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, LOG_WARN("hit glyph limit"); cairo_set_scaled_font(buf->cairo, attrs_to_font(term, &gseq.attrs)); - cairo_set_source_rgba( + cairo_set_source_rgb( buf->cairo, gseq.foreground.r, gseq.foreground.g, - gseq.foreground.b, gseq.foreground.a); + gseq.foreground.b); cairo_show_glyphs(buf->cairo, gseq.glyphs, gseq.count); @@ -469,9 +463,9 @@ grid_render(struct terminal *term) int rmargin_width = term->width - rmargin; int bmargin_height = term->height - bmargin; - const struct rgba *bg = !term->reverse ? + const struct rgb *bg = !term->reverse ? &term->background : &term->foreground; - cairo_set_source_rgba(buf->cairo, bg->r, bg->g, bg->b, bg->a); + cairo_set_source_rgb(buf->cairo, bg->r, bg->g, bg->b); cairo_rectangle(buf->cairo, rmargin, 0, rmargin_width, term->height); cairo_rectangle(buf->cairo, 0, bmargin, term->width, bmargin_height); @@ -599,9 +593,9 @@ grid_render(struct terminal *term) if (gseq.count > 0) { cairo_set_scaled_font(buf->cairo, attrs_to_font(term, &gseq.attrs)); - cairo_set_source_rgba( + cairo_set_source_rgb( buf->cairo, gseq.foreground.r, gseq.foreground.g, - gseq.foreground.b, gseq.foreground.a); + gseq.foreground.b); cairo_show_glyphs(buf->cairo, gseq.glyphs, gseq.count); } diff --git a/terminal.h b/terminal.h index 253163af..d897b10a 100644 --- a/terminal.h +++ b/terminal.h @@ -36,7 +36,7 @@ struct wayland { struct xdg_toplevel *xdg_toplevel; }; -struct rgba { double r, g, b, a; } __attribute__((packed)); +struct rgb { double r, g, b; } __attribute__((packed)); struct attributes { #if 0 @@ -60,8 +60,8 @@ struct attributes { uint8_t have_foreground:1; uint8_t have_background:1; #endif - struct rgba foreground; /* Only valid when have_foreground == true */ - struct rgba background; /* Only valid when have_background == true */ + struct rgb foreground; /* Only valid when have_foreground == true */ + struct rgb background; /* Only valid when have_background == true */ } __attribute__((packed)); struct cell { @@ -231,8 +231,8 @@ struct terminal { bool print_needs_wrap; struct scroll_region scroll_region; - struct rgba foreground; - struct rgba background; + struct rgb foreground; + struct rgb background; struct { int col; From 729974492d1580ea6c4988cd2f36d5e517daacca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 8 Jul 2019 16:12:02 +0200 Subject: [PATCH 06/10] main: verify compositor has WL_SHM_FORMAT_ARGB8888 --- main.c | 9 ++++++++- terminal.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index 5ce9c623..247d153d 100644 --- a/main.c +++ b/main.c @@ -38,6 +38,9 @@ static const struct rgb default_background = {0.067, 0.067, 0.067}; static void shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) { + struct terminal *term = data; + if (format == WL_SHM_FORMAT_ARGB8888) + term->wl.have_argb8888 = true; } static const struct wl_shm_listener shm_listener = { @@ -107,7 +110,7 @@ handle_global(void *data, struct wl_registry *registry, else if (strcmp(interface, wl_shm_interface.name) == 0) { term->wl.shm = wl_registry_bind( term->wl.registry, name, &wl_shm_interface, 1); - wl_shm_add_listener(term->wl.shm, &shm_listener, NULL); + wl_shm_add_listener(term->wl.shm, &shm_listener, term); wl_display_roundtrip(term->wl.display); } @@ -378,6 +381,10 @@ main(int argc, char *const *argv) LOG_ERR("no XDG shell interface"); goto out; } + if (!term.wl.have_argb8888) { + LOG_ERR("compositor does not support ARGB surfaces"); + goto out; + } /* Cursor */ term.wl.pointer.surface = wl_compositor_create_surface(term.wl.compositor); diff --git a/terminal.h b/terminal.h index d897b10a..0ffcf01c 100644 --- a/terminal.h +++ b/terminal.h @@ -34,6 +34,7 @@ struct wayland { struct xdg_wm_base *shell; struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; + bool have_argb8888; }; struct rgb { double r, g, b; } __attribute__((packed)); From 6d48f0f2a565dd1a452bcf491f9da30fc144d982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 8 Jul 2019 20:25:41 +0200 Subject: [PATCH 07/10] render: hackerman --- render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/render.c b/render.c index 2e53cb7d..89358e34 100644 --- a/render.c +++ b/render.c @@ -55,7 +55,7 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, : !term->reverse ? &term->background : &term->foreground; /* If *one* is set, we reverse */ - if (has_cursor != cell->attrs.reverse) { + if (has_cursor ^ cell->attrs.reverse) { const struct rgb *swap = foreground; foreground = background; background = swap; From 0f14b5298ec4fc1d1945824c1a9dc17d88eb9159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 9 Jul 2019 09:12:41 +0200 Subject: [PATCH 08/10] render: copy old contents to new grids when resizing Eventually, we'll add text reflow here as well. --- render.c | 128 +++++++++++++++++++++++++------------------------------ 1 file changed, 59 insertions(+), 69 deletions(-) diff --git a/render.c b/render.c index 89358e34..5f5b3ff0 100644 --- a/render.c +++ b/render.c @@ -626,6 +626,26 @@ frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_da grid_render(term); } +static void +reflow(struct row **new_grid, int new_cols, int new_rows, + struct row *const *old_grid, int old_cols, int old_rows) +{ + /* TODO: actually reflow */ + for (int r = 0; r < min(new_rows, old_rows); r++) { + size_t copy_cols = min(new_cols, old_cols); + size_t clear_cols = new_cols - copy_cols; + + struct cell *new_cells = new_grid[r]->cells; + const struct cell *old_cells = old_grid[r]->cells; + + memcpy(new_cells, old_cells, copy_cols * sizeof(new_cells[0])); + memset(&new_cells[copy_cols], 0, clear_cols * sizeof(new_cells[0])); + } + + for (int r = min(new_rows, old_rows); r < new_rows; r++) + memset(new_grid[r]->cells, 0, new_cols * sizeof(new_grid[r]->cells[0])); +} + /* Move to terminal.c? */ void render_resize(struct terminal *term, int width, int height) @@ -636,88 +656,60 @@ 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; - - term->cols = term->width / term->cell_width; - term->rows = term->height / term->cell_height; - - term->normal.size = term->cols * term->rows; - term->alt.size = term->cols * term->rows; - - term->normal.cells = realloc( - term->normal.cells, - term->normal.size * sizeof(term->normal.cells[0])); - term->alt.cells = realloc( - term->alt.cells, - term->alt.size * sizeof(term->alt.cells[0])); - - term->normal.offset - = (term->normal.offset + term->cols - 1) / term->cols * term->cols; - term->alt.offset - = (term->alt.offset + term->cols - 1) / term->cols * term->cols; - - /* TODO: memset */ - for (size_t i = normal_old_size; i < term->normal.size; i++) { - term->normal.cells[i] = (struct cell){ - .attrs = {.foreground = term->foreground, - .background = term->background}, - }; - } - - /* TODO: memset */ - for (size_t i = alt_old_size; i < term->alt.size; i++) { - term->alt.cells[i] = (struct cell){ - .attrs = {.foreground = term->foreground, - .background = term->background}, - }; - } -#endif - //const int old_cols = term->cols; + const int old_cols = term->cols; const int old_rows = term->rows; + const int old_normal_grid_rows = term->normal.num_rows; + const int old_alt_grid_rows = term->alt.num_rows; + const int new_cols = term->width / term->cell_width; const int new_rows = term->height / term->cell_height; + const int new_normal_grid_rows = new_rows; + const int new_alt_grid_rows = new_rows; + /* Allocate new 'normal' grid */ + struct row **normal = malloc(new_normal_grid_rows * sizeof(normal[0])); + for (int r = 0; r < new_normal_grid_rows; r++) { + struct row *row = malloc(sizeof(*row)); + row->cells = malloc(new_cols * sizeof(row->cells[0])); + normal[r] = row; + } + + /* Allocate new 'alt' grid */ + struct row **alt = malloc(new_alt_grid_rows * sizeof(alt[0])); + for (int r = 0; r < new_alt_grid_rows; r++) { + struct row *row = malloc(sizeof(*row)); + row->cells = malloc(new_cols * sizeof(row->cells[0])); + alt[r] = row; + } + + /* Reflow content */ + reflow(normal, new_cols, new_normal_grid_rows, + term->normal.rows, old_cols, old_normal_grid_rows); + reflow(alt, new_cols, new_alt_grid_rows, + term->alt.rows, old_cols, old_alt_grid_rows); + + /* Free old 'normal' grid */ 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); + /* Free old 'alt' grid */ 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; + term->normal.rows = normal; + term->normal.num_rows = new_normal_grid_rows; + term->alt.rows = alt; + term->alt.num_rows = new_alt_grid_rows; + LOG_INFO("resize: %dx%d, grid: cols=%d, rows=%d", term->width, term->height, term->cols, term->rows); @@ -732,18 +724,16 @@ render_resize(struct terminal *term, int width, int height) LOG_ERRNO("TIOCSWINSZ"); } - if (term->scroll_region.end == old_rows) + if (term->scroll_region.start >= term->rows) + term->scroll_region.start = 0; + + 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); if (!term->frame_is_scheduled) From d7bb83022db76a620f626c452dc6be3d5b186d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 9 Jul 2019 09:17:24 +0200 Subject: [PATCH 09/10] cleanup --- main.c | 2 - render.c | 303 +---------------------------------------------------- terminal.c | 271 ++--------------------------------------------- terminal.h | 27 ++--- 4 files changed, 14 insertions(+), 589 deletions(-) diff --git a/main.c b/main.c index 247d153d..74a28c1c 100644 --- a/main.c +++ b/main.c @@ -10,8 +10,6 @@ #include #include -//#include - #include #include #include diff --git a/render.c b/render.c index 5f5b3ff0..ea40b3fb 100644 --- a/render.c +++ b/render.c @@ -117,226 +117,6 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, 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) -{ - LOG_DBG("damage: UPDATE: %d -> %d (offset = %d)", - (dmg->range.start - term->grid->offset) % term->grid->size, - (dmg->range.start - term->grid->offset) % term->grid->size + dmg->range.length, - term->grid->offset); - - int start = dmg->range.start; - int length = dmg->range.length; - - if (start < term->grid->offset) { - int end = start + length; - if (end >= term->grid->offset) { - start = term->grid->offset; - length = end - start; - } else - return; - } - - const int cols = term->cols; - - for (int linear_cursor = start, - row = ((start - term->grid->offset) % term->grid->size) / cols, - col = ((start - term->grid->offset) % term->grid->size) % cols; - linear_cursor < start + length; - linear_cursor++, - col = col + 1 >= term->cols ? 0 : col + 1, - row += col == 0 ? 1 : 0) - { - - assert(row >= 0); - assert(row < term->rows); - assert(col >= 0); - assert(col < term->cols); - - int cell_idx = linear_cursor % term->grid->size; - if (cell_idx < 0) - cell_idx += term->grid->size; - - assert(cell_idx >= 0); - assert(cell_idx < term->rows * term->cols); - - const struct cell *cell = &term->grid->cells[cell_idx]; - - /* Cursor here? */ - bool has_cursor - = (!term->hide_cursor && - (term->cursor.linear == linear_cursor - term->grid->offset)); - - int x = col * term->cell_width; - int y = row * term->cell_height; - int width = term->cell_width; - int height = term->cell_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] == ' ') - continue; - - if (cell->attrs.conceal) - continue; - - /* - * 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) - continue; - - gseq.g += new_glyphs; - gseq.count += new_glyphs; - assert(gseq.count <= sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0])); - } - - wl_surface_damage_buffer( - term->wl.surface, - 0, ((dmg->range.start - term->grid->offset) / cols) * term->cell_height, - buf->width, (dmg->range.length + cols - 1) / cols * term->cell_height); -} - -static void -grid_render_erase(struct terminal *term, struct buffer *buf, const struct damage *dmg) -{ - LOG_DBG("damage: ERASE: %d -> %d (offset = %d)", - (dmg->range.start - term->grid->offset) % term->grid->size, - (dmg->range.start - term->grid->offset) % term->grid->size + dmg->range.length, - term->grid->offset); - - assert(dmg->range.start >= term->grid->offset); - - const struct rgba *bg = !term->reverse ? - &term->background : &term->foreground; - - cairo_set_source_rgba(buf->cairo, bg->r, bg->g, bg->b, bg->a); - - const int cols = term->cols; - - int start = (dmg->range.start - term->grid->offset) % term->grid->size; - int left = dmg->range.length; - - int row = start / cols; - int col = start % cols; - - /* Partial initial line */ - if (col != 0) { - int cell_count = min(left, cols - col); - - int x = col * term->cell_width; - int y = row * term->cell_height; - int width = cell_count * term->cell_width; - int height = term->cell_height; - - cairo_rectangle(buf->cairo, x, y, width, height); - cairo_fill(buf->cairo); - wl_surface_damage_buffer(term->wl.surface, x, y, width, height); - - start += cell_count; - left -= cell_count; - - row = start / cols; - col = start % cols; - } - - assert(left == 0 || col == 0); - - /* One or more full lines left */ - if (left >= cols) { - int line_count = left / cols; - - int x = 0; - int y = row * term->cell_height; - int width = buf->width; - int height = line_count * term->cell_height; - - cairo_rectangle(buf->cairo, x, y, width, height); - cairo_fill(buf->cairo); - wl_surface_damage_buffer(term->wl.surface, x, y, width, height); - - start += line_count * cols; - left -= line_count * cols; - - row += line_count; - col = 0; - } - - assert(left == 0 || col == 0); - assert(left < cols); - - /* Partial last line */ - if (left > 0) { - int x = 0; - int y = row * term->cell_height; - int width = left * term->cell_width; - int height = term->cell_height; - - cairo_rectangle(buf->cairo, x, y, width, height); - cairo_fill(buf->cairo); - wl_surface_damage_buffer(term->wl.surface, x, y, width, height); - } -} -#endif - static void grid_render_scroll(struct terminal *term, struct buffer *buf, const struct damage *dmg) @@ -364,21 +144,6 @@ 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 = { - .type = DAMAGE_ERASE, - .range = { - .start = term->grid->offset + max(dmg->scroll.region.end - dmg->scroll.lines, - dmg->scroll.region.start) * cols, - .length = min(dmg->scroll.region.end - dmg->scroll.region.start, - dmg->scroll.lines) * cols, - }, - }; - grid_render_erase(term, buf, &erase); -#endif } static void @@ -408,20 +173,6 @@ 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 = { - .type = DAMAGE_ERASE, - .range = { - .start = term->grid->offset + dmg->scroll.region.start * cols, - .length = min(dmg->scroll.region.end - dmg->scroll.region.start, - dmg->scroll.lines) * cols, - }, - }; - grid_render_erase(term, buf, &erase); -#endif } static void frame_callback( @@ -436,19 +187,9 @@ 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); @@ -493,11 +234,6 @@ grid_render(struct terminal *term) case DAMAGE_SCROLL_REVERSE: grid_render_scroll_reverse(term, buf, &it->item); break; - - case DAMAGE_UPDATE: - case DAMAGE_ERASE: - assert(false); - break; } tll_remove(term->grid->scroll_damage, it); @@ -505,21 +241,6 @@ 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; - case DAMAGE_UPDATE: grid_render_update(term, buf, &it->item); break; - - case DAMAGE_SCROLL: - case DAMAGE_SCROLL_REVERSE: - assert(false); - break; - } - - tll_remove(term->grid->damage, it); - } -#endif for (int r = 0; r < term->rows; r++) { struct row *row = grid_row(term->grid, r); @@ -545,14 +266,6 @@ grid_render(struct terminal *term) = (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) { @@ -564,7 +277,6 @@ grid_render(struct terminal *term) term->cell_width, term->cell_height); } last_cursor = cursor_as_linear; -#endif } if (all_clean) { @@ -572,14 +284,6 @@ grid_render(struct terminal *term) 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); -#endif - render_cell( term, buf, &grid_row(term->grid, term->cursor.row)->cells[term->cursor.col], @@ -600,13 +304,8 @@ grid_render(struct terminal *term) } assert(term->grid->offset >= 0 && term->grid->offset < term->grid->num_rows); -#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); + cairo_surface_flush(buf->cairo_surface); wl_surface_attach(term->wl.surface, buf->wl_buf, 0, 0); struct wl_callback *cb = wl_surface_frame(term->wl.surface); diff --git a/terminal.c b/terminal.c index 7630c25e..1cf15cfb 100644 --- a/terminal.c +++ b/terminal.c @@ -4,6 +4,8 @@ #include #include +#include + #define LOG_MODULE "terminal" #define LOG_ENABLE_DBG 0 #include "log.h" @@ -12,142 +14,17 @@ #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) -{ - if (tll_length(term->grid->damage) == 0) - return false; - - struct damage *old = &tll_back(term->grid->damage); - if (old->type != dmg->type) - return false; - - const int start = dmg->range.start; - const int end = start + dmg->range.length; - - const int prev_start = old->range.start; - const int prev_end = prev_start + old->range.length; - - if ((start >= prev_start && start <= prev_end) || - (end >= prev_start && end <= prev_end) || - (start <= prev_start && end >= prev_end)) - { - /* The two damage ranges intersect */ - int new_start = min(start, prev_start); - int new_end = max(end, prev_end); - - old->range.start = new_start; - old->range.length = new_end - new_start; - - return true; - } - - return false; -} - -static void -term_damage_update_or_erase(struct terminal *term, enum damage_type damage_type, - int start, int length) -{ -#if 1 - if (tll_length(term->grid->damage) > 1024) { - term_damage_all(term); - return; - } -#endif - - struct damage dmg = { - .type = damage_type, - .range = {.start = term->grid->offset + start, .length = length}, - }; - - if (damage_merge_range(term, &dmg)) - return; - - 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 -static void -damage_adjust_after_scroll(struct terminal *term, enum damage_type damage_type, - struct scroll_region region, int lines) -{ - tll_foreach(term->grid->damage, it) { -#if 0 - if (it->item.range.start < term->grid->offset) { - int end = it->item.range.start + it->item.range.length; - if (end >= term->grid->offset) { - it->item.range.start = term->grid->offset; - it->item.range.length = end - it->item.range.start; - } else { - tll_remove(term->grid->damage, it); - } - } -#endif - - int start = it->item.range.start; - int end = start + it->item.range.length; - - if (start - - } -} -#endif - 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) { - int start = it->item.range.start; - int length = it->item.range.length; - - if (start < term->grid->offset) { - int end = start + length; - if (end >= term->grid->offset) { - it->item.range.start = term->grid->offset; - it->item.range.length = end - it->item.range.start; - } else - tll_remove(term->grid->damage, it); - } else - break; - } - } -#endif if (tll_length(term->grid->scroll_damage) > 0) { struct damage *dmg = &tll_back(term->grid->scroll_damage); @@ -166,40 +43,6 @@ 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) -{ - LOG_DBG("erase: %d-%d", start, end); - assert(end >= start); - assert(end <= term->rows * term->cols); - - if (term->vt.attrs.have_background) { - int erase_start = start; - int left = end - erase_start; - - while (left > 0) { - int len = left; - struct cell *cells = grid_get_range(term->grid, erase_start, &len); - - memset(cells, 0, len * sizeof(cells[0])); - - for (int i = 0; i < len; i++) { - cells[i].attrs.background = term->vt.attrs.background; - cells[i].attrs.have_background = true; - } - - erase_start += len; - left -= len; - } - - term_damage_update(term, start, end - start); - } else { - grid_memclear(term->grid, start, end - start); - term_damage_erase(term, start, end - start); - } -} -#else static inline void erase_cell_range(struct terminal *term, struct row *row, int start, int end) { @@ -246,7 +89,6 @@ term_erase(struct terminal *term, const struct coord *start, const struct coord 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) @@ -301,72 +143,23 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows assert(rows < term->rows && "unimplemented"); + /* Top non-scrolling region */ for (int i = region.start - 1; i >= 0; i--) grid_swap_row(term->grid, i, i + rows); - if (region.start > 0) { -#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; - - if (start < region.start * term->cols) { - assert(end <= region.start * term->cols); - it->item.range.start += rows * term->cols; - } - } -#endif - } - + /* Bottom non-scrolling region */ for (int i = term->rows - 1; i >= region.end; i--) grid_swap_row(term->grid, i, i + rows); - if (region.end < term->rows) { -#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; - - if (end > region.end * term->cols) { - assert(start >= region.end * term->cols); - it->item.range.start += rows * term->cols; - } - } -#endif - } - /* Offset grid origin */ term->grid->offset += rows; term->grid->offset %= term->grid->num_rows; -#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 @@ -381,55 +174,14 @@ term_scroll_reverse_partial(struct terminal *term, { assert(rows < term->rows && "unimplemented"); - if (region.end < term->rows) { - //assert(false); -#if 0 - grid_memmove( - term->grid, - (region.end - rows) * term->cols, - region.end * term->cols, - (term->rows - region.end) * term->cols); - - tll_foreach(term->grid->damage, it) { - int start = it->item.range.start - term->grid->offset; - int end = start + it->item.range.length; - - if (end > region.end * term->cols) { - assert(start >= region.end * term->cols); - 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); - - tll_foreach(term->grid->damage, it) { - int start = it->item.range.start - term->grid->offset; - int end __attribute__((unused)) = start + it->item.range.length; - - if (start < region.start * term->cols) { - if (end > region.start * term->cols) { - LOG_ERR("region.start = %d, rows = %d, damage.start = %d, damage.end = %d (%s)", - region.start, rows, start, end, it->item.type == DAMAGE_UPDATE ? "UPDATE" : "ERASE"); - abort(); - } - assert(end <= region.start * term->cols); - it->item.range.start -= rows * term->cols; - } - } -#endif - } - term->grid->offset += term->grid->num_rows - rows; term->grid->offset %= term->grid->num_rows; + /* Bottom non-scrolling region */ for (int i = region.end + rows; i < term->rows + rows; i++) grid_swap_row(term->grid, i, i - rows); + + /* Top non-scrolling region */ for (int i = 0 + rows; i < region.start + rows; i++) grid_swap_row(term->grid, i, i - rows); @@ -440,13 +192,6 @@ term_scroll_reverse_partial(struct terminal *term, 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 @@ -455,8 +200,6 @@ term_scroll_reverse(struct terminal *term, int rows) term_scroll_reverse_partial(term, term->scroll_region, rows); } -#include - static int linux_mouse_button_to_x(int button) { diff --git a/terminal.h b/terminal.h index 0ffcf01c..09b4a54a 100644 --- a/terminal.h +++ b/terminal.h @@ -80,24 +80,14 @@ struct coord { int row; }; -enum damage_type {DAMAGE_UPDATE, DAMAGE_ERASE, DAMAGE_SCROLL, DAMAGE_SCROLL_REVERSE}; +enum damage_type {DAMAGE_SCROLL, DAMAGE_SCROLL_REVERSE}; 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 { - struct scroll_region region; - int lines; - } scroll; - }; + /* DAMAGE_SCROLL, DAMAGE_SCROLL_REVERSE */ + struct { + struct scroll_region region; + int lines; + } scroll; }; struct row { @@ -109,8 +99,6 @@ struct grid { int num_rows; int offset; - //struct cell *cells; - //struct cell *cur_line; struct row **rows; struct row *cur_row; @@ -257,13 +245,10 @@ struct terminal { }; void term_damage_all(struct terminal *term); -void term_damage_update(struct terminal *term, int start, int length); -void term_damage_erase(struct terminal *term, int start, int length); 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, const struct coord *start, const struct coord *end); From 0d24fcafd0f12908b40b82986bc26db2762daf6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 9 Jul 2019 09:23:32 +0200 Subject: [PATCH 10/10] render: store frame callback pointer in terminal struct This allows us to free it when exiting --- main.c | 4 +++- render.c | 11 ++++++----- terminal.h | 3 ++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/main.c b/main.c index 74a28c1c..8efade1a 100644 --- a/main.c +++ b/main.c @@ -496,7 +496,7 @@ main(int argc, char *const *argv) if (ret == 0 || !(timeout_ms != -1 && fds[1].revents & POLLIN)) { /* Delayed rendering */ - if (!term.frame_is_scheduled) + if (term.frame_callback == NULL) grid_render(&term); } @@ -584,6 +584,8 @@ out: mtx_unlock(&term.kbd.repeat.mutex); shm_fini(); + if (term.frame_callback != NULL) + wl_callback_destroy(term.frame_callback); if (term.wl.xdg_toplevel != NULL) xdg_toplevel_destroy(term.wl.xdg_toplevel); if (term.wl.xdg_surface != NULL) diff --git a/render.c b/render.c index ea40b3fb..d42a04ec 100644 --- a/render.c +++ b/render.c @@ -308,9 +308,9 @@ grid_render(struct terminal *term) cairo_surface_flush(buf->cairo_surface); wl_surface_attach(term->wl.surface, buf->wl_buf, 0, 0); - struct wl_callback *cb = wl_surface_frame(term->wl.surface); - wl_callback_add_listener(cb, &frame_listener, term); - term->frame_is_scheduled = true; + assert(term->frame_callback == NULL); + term->frame_callback = wl_surface_frame(term->wl.surface); + wl_callback_add_listener(term->frame_callback, &frame_listener, term); wl_surface_commit(term->wl.surface); } @@ -320,8 +320,9 @@ frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_da { struct terminal *term = data; - term->frame_is_scheduled = false; + assert(term->frame_callback == wl_callback); wl_callback_destroy(wl_callback); + term->frame_callback = NULL; grid_render(term); } @@ -435,7 +436,7 @@ render_resize(struct terminal *term, int width, int height) min(term->cursor.col, term->cols - 1)); term_damage_all(term); - if (!term->frame_is_scheduled) + if (term->frame_callback == NULL) grid_render(term); } diff --git a/terminal.h b/terminal.h index 09b4a54a..a0ad718a 100644 --- a/terminal.h +++ b/terminal.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -241,7 +242,7 @@ struct terminal { cairo_font_extents_t fextents; struct wayland wl; - bool frame_is_scheduled; + struct wl_callback *frame_callback; }; void term_damage_all(struct terminal *term);