diff --git a/csi.c b/csi.c index a737022f..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; @@ -338,25 +334,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 +362,6 @@ csi_dispatch(struct terminal *term, uint8_t final) abort(); break; } - - term_erase(term, start, end); break; } @@ -374,25 +369,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 +399,6 @@ csi_dispatch(struct terminal *term, uint8_t final) break; } - term_erase(term, start, end); break; } @@ -453,15 +449,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 +484,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 +643,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..8efade1a 100644 --- a/main.c +++ b/main.c @@ -10,8 +10,6 @@ #include #include -//#include - #include #include #include @@ -32,12 +30,15 @@ #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) { + 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 +108,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 +379,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); @@ -491,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); } @@ -579,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) @@ -589,6 +596,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 +612,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..d42a04ec 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)) @@ -27,227 +28,93 @@ struct glyph_sequence { int count; struct attributes attrs; - struct rgba foreground; + struct rgb foreground; }; static struct glyph_sequence gseq; static void -grid_render_update(struct terminal *term, struct buffer *buf, const struct damage *dmg) +render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, + int col, int row) { - 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); + /* Cursor here? */ + bool has_cursor + = (!term->hide_cursor && + (term->cursor.col == col && term->cursor.row == row)); - int start = dmg->range.start; - int length = dmg->range.length; + double width = term->cell_width; + double height = term->cell_height; + double x = col * width; + double y = row * height; - if (start < term->grid->offset) { - int end = start + length; - if (end >= term->grid->offset) { - start = term->grid->offset; - length = end - start; - } else - return; + const struct rgb *foreground = cell->attrs.have_foreground + ? &cell->attrs.foreground + : !term->reverse ? &term->foreground : &term->background; + const struct rgb *background = cell->attrs.have_background + ? &cell->attrs.background + : !term->reverse ? &term->background : &term->foreground; + + /* If *one* is set, we reverse */ + if (has_cursor ^ cell->attrs.reverse) { + const struct rgb *swap = foreground; + foreground = background; + background = swap; } - const int cols = term->cols; + /* Background */ + cairo_set_source_rgb(buf->cairo, background->r, background->g, background->b); + cairo_rectangle(buf->cairo, x, y, width, height); + cairo_fill(buf->cairo); - 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) + 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"); - assert(row >= 0); - assert(row < term->rows); - assert(col >= 0); - assert(col < term->cols); + cairo_set_scaled_font(buf->cairo, attrs_to_font(term, &gseq.attrs)); + cairo_set_source_rgb( + buf->cairo, gseq.foreground.r, gseq.foreground.g, + gseq.foreground.b); - int cell_idx = linear_cursor % term->grid->size; - if (cell_idx < 0) - cell_idx += term->grid->size; + cairo_show_glyphs(buf->cairo, gseq.glyphs, gseq.count); - 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])); + gseq.g = gseq.glyphs; + gseq.count = 0; + gseq.attrs = cell->attrs; + gseq.foreground = *foreground; } - 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); -} + int new_glyphs + = sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0]) - gseq.count; -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); + 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); - assert(dmg->range.start >= term->grid->offset); + if (status != CAIRO_STATUS_SUCCESS) + return; - 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); - } + gseq.g += new_glyphs; + gseq.count += new_glyphs; + assert(gseq.count <= sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0])); } static void @@ -277,19 +144,6 @@ grid_render_scroll(struct terminal *term, struct buffer *buf, wl_surface_damage_buffer(term->wl.surface, 0, dst_y, width, height); } - - 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); } static void @@ -319,18 +173,6 @@ grid_render_scroll_reverse(struct terminal *term, struct buffer *buf, wl_surface_damage_buffer(term->wl.surface, 0, dst_y, width, height); } - - 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); } static void frame_callback( @@ -345,13 +187,6 @@ grid_render(struct terminal *term) { static int last_cursor; - if (tll_length(term->grid->damage) == 0 && - tll_length(term->grid->scroll_damage) == 0 && - last_cursor == term->grid->offset + term->cursor.linear) - { - return; - } - assert(term->width > 0); assert(term->height > 0); @@ -369,9 +204,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); @@ -388,6 +223,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: @@ -397,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); @@ -410,57 +242,75 @@ grid_render(struct terminal *term) gseq.g = gseq.glyphs; gseq.count = 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; + for (int r = 0; r < term->rows; r++) { + struct row *row = grid_row(term->grid, r); - case DAMAGE_SCROLL: - case DAMAGE_SCROLL_REVERSE: - assert(false); - break; - } + if (!row->dirty) + continue; - tll_remove(term->grid->damage, it); + //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) { - struct damage prev_cursor = { - .type = DAMAGE_UPDATE, - .range = {.start = last_cursor, .length = 1}, - }; - grid_render_update(term, buf, &prev_cursor); + int cursor_as_linear + = (term->grid->offset + term->cursor.row) * term->cols + term->cursor.col; + + if (last_cursor != cursor_as_linear) { + 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; } - 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; + if (all_clean) { + buf->busy = false; + return; + } + + 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)); - cairo_set_source_rgba( + cairo_set_source_rgb( buf->cairo, gseq.foreground.r, gseq.foreground.g, - gseq.foreground.b, gseq.foreground.a); - cairo_set_operator(buf->cairo, CAIRO_OPERATOR_OVER); + gseq.foreground.b); cairo_show_glyphs(buf->cairo, gseq.glyphs, gseq.count); } - term->grid->offset %= term->grid->size; - if (term->grid->offset < 0) - term->grid->offset += term->grid->size; + assert(term->grid->offset >= 0 && term->grid->offset < term->grid->num_rows); - //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); - 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); } @@ -470,11 +320,32 @@ 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); } +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) @@ -485,44 +356,60 @@ render_resize(struct terminal *term, int width, int height) term->width = width; term->height = height; - 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; + 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; - term->cols = term->width / term->cell_width; - term->rows = term->height / term->cell_height; + 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; - 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}, - }; + /* 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; } - /* 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}, - }; + /* 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); + + 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); @@ -537,17 +424,19 @@ 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; term_cursor_to( term, min(term->cursor.row, term->rows - 1), 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.c b/terminal.c index 7c15ce87..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,131 +14,17 @@ #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) -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); -} - -void -term_damage_update(struct terminal *term, int start, int length) -{ - assert(start + length <= term->rows * term->cols); - term_damage_update_or_erase(term, DAMAGE_UPDATE, start, length); -} - -void -term_damage_erase(struct terminal *term, int start, int length) -{ - assert(start + length <= term->rows * term->cols); - term_damage_update_or_erase(term, DAMAGE_ERASE, start, length); -} - void term_damage_all(struct terminal *term) { - tll_free(term->grid->damage); - tll_free(term->grid->scroll_damage); - term_damage_update(term, 0, term->rows * term->cols); + for (int i = 0; i < term->rows; i++) + grid_row(term->grid, i)->dirty = true; } -#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) { - //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; - } - } - if (tll_length(term->grid->scroll_damage) > 0) { struct damage *dmg = &tll_back(term->grid->scroll_damage); @@ -155,43 +43,51 @@ term_damage_scroll(struct terminal *term, enum damage_type damage_type, tll_push_back(term->grid->scroll_damage, dmg); } -void -term_erase(struct terminal *term, int start, int end) +static inline void +erase_cell_range(struct terminal *term, struct row *row, int start, int end) { - LOG_DBG("erase: %d-%d", start, end); - assert(end >= start); - assert(end <= term->rows * term->cols); + assert(start < term->cols); + assert(end < 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; + 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; } - - term_damage_update(term, start, end - start); } else { - grid_memclear(term->grid, start, end - start); - term_damage_erase(term, start, end - start); + memset(&row->cells[start], 0, (end - start + 1) * sizeof(row->cells[0])); } + row->dirty = true; } -int -term_cursor_linear(const struct terminal *term, int row, int col) +static inline void +erase_line(struct terminal *term, struct row *row) { - return row * term->cols + col; + 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); } void @@ -200,28 +96,20 @@ 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 +117,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,58 +141,25 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows { LOG_DBG("scroll: %d rows", rows); - if (region.start > 0) { - /* TODO: check if it's worth memoving the scroll area instead, - * under certain circumstances */ + assert(rows < term->rows && "unimplemented"); - grid_memmove(term->grid, rows * term->cols, 0, region.start * term->cols); + /* Top non-scrolling region */ + for (int i = region.start - 1; i >= 0; i--) + grid_swap_row(term->grid, i, i + rows); - 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; - } - } - } - - if (region.end < term->rows) { - /* Copy scrolled-up bottom region to new bottom region */ - 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; - } - } - } + /* Bottom non-scrolling region */ + for (int i = term->rows - 1; i >= region.end; i--) + grid_swap_row(term->grid, i, i + rows); /* 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); + for (int r = max(region.end - rows, 0); r < region.end; r++) + erase_line(term, grid_row(term->grid, r)); term_damage_scroll(term, DAMAGE_SCROLL, region, rows); - - int len = term->cols; - term->grid->cur_line = grid_get_range( - term->grid, term->cursor.linear - term->cursor.col, &len); - - assert(len == term->cols); + term->grid->cur_row = grid_row(term->grid, term->cursor.row); } void @@ -317,56 +172,26 @@ void term_scroll_reverse_partial(struct terminal *term, struct scroll_region region, int rows) { - if (region.end < term->rows) { - grid_memmove( - term->grid, - (region.end - rows) * term->cols, - region.end * term->cols, - (term->rows - region.end) * term->cols); + assert(rows < term->rows && "unimplemented"); - tll_foreach(term->grid->damage, it) { - int start = it->item.range.start - term->grid->offset; - int end = start + it->item.range.length; + term->grid->offset += term->grid->num_rows - rows; + term->grid->offset %= term->grid->num_rows; - if (end > region.end * term->cols) { - assert(start >= region.end * term->cols); - it->item.range.start -= rows * term->cols; - } - } + /* 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); - if (region.start > 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; - } - } - } - - term->grid->offset -= rows * term->cols; - - grid_memclear(term->grid, region.start * term->cols, rows * term->cols); + 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); - - int len = term->cols; - term->grid->cur_line = grid_get_range( - term->grid, term->cursor.linear - term->cursor.col, &len); - - assert(len == term->cols); + term->grid->cur_row = grid_row(term->grid, term->cursor.row); } void @@ -375,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 ddc37410..a0ad718a 100644 --- a/terminal.h +++ b/terminal.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -34,9 +35,10 @@ struct wayland { struct xdg_wm_base *shell; struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; + bool have_argb8888; }; -struct rgba { double r, g, b, a; } __attribute__((packed)); +struct rgb { double r, g, b; } __attribute__((packed)); struct attributes { #if 0 @@ -60,8 +62,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 { @@ -74,36 +76,32 @@ 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}; +enum damage_type {DAMAGE_SCROLL, DAMAGE_SCROLL_REVERSE}; struct damage { enum damage_type type; - union { - /* DAMAGE_UPDATE, DAMAGE_ERASE */ - struct { - int start; - int length; - } range; + /* 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 { + struct cell *cells; + bool dirty; }; struct grid { - int size; + int num_rows; int offset; - struct cell *cells; - struct cell *cur_line; + struct row **rows; + struct row *cur_row; tll(struct damage) damage; tll(struct damage) scroll_damage; @@ -223,18 +221,18 @@ 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 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; @@ -244,17 +242,16 @@ 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); -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); void term_cursor_to(struct terminal *term, int row, int col); void term_cursor_left(struct terminal *term, int count); @@ -270,8 +267,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);