Merge branch 'no-more-linear'

This commit is contained in:
Daniel Eklöf 2019-07-09 09:24:26 +02:00
commit 8cf7d7f7ab
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
8 changed files with 446 additions and 653 deletions

115
csi.c
View file

@ -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;

3
grid.c
View file

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

28
grid.h
View file

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

41
main.c
View file

@ -10,8 +10,6 @@
#include <poll.h>
#include <errno.h>
//#include <termios.h>
#include <wayland-client.h>
#include <wayland-cursor.h>
#include <xdg-shell.h>
@ -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)

505
render.c
View file

@ -10,6 +10,7 @@
#define LOG_ENABLE_DBG 0
#include "log.h"
#include "shm.h"
#include "grid.h"
#define min(x, y) ((x) < (y) ? (x) : (y))
#define max(x, y) ((x) > (y) ? (x) : (y))
@ -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);
}

View file

@ -4,6 +4,8 @@
#include <unistd.h>
#include <assert.h>
#include <linux/input-event-codes.h>
#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 <linux/input-event-codes.h>
static int
linux_mouse_button_to_x(int button)
{

View file

@ -7,6 +7,7 @@
#include <threads.h>
#include <cairo.h>
#include <wayland-client.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-keysyms.h>
@ -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,

27
vt.c
View file

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