mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-25 09:05:47 -04:00
render: bug: previous cursor wasn't always redrawn correctly
The main problem is knowing: * The correct *cell* (to be able to render the *content* when erasing the old cursor) * Whether the cursor has moved (to determine whether to stop the rendering loop or not) * Where on the *screen* the cursor is/was (since the terminal may be partly scrolled back) This patch stores three static variables: * last_cursor is used to compare against current cursor to see if the cursor has moved or not * last_cursor_on_screen is the actual screen coordinates the cursor was rendered at (typically the same as last_cursor, but may be offset by the view) * last_cursor_cell is a pointer to the cell to render
This commit is contained in:
parent
bf4847d3e0
commit
10a7b94804
1 changed files with 56 additions and 39 deletions
95
render.c
95
render.c
|
|
@ -361,14 +361,42 @@ grid_render(struct terminal *term)
|
||||||
gettimeofday(&start_time, NULL);
|
gettimeofday(&start_time, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int last_cursor;
|
|
||||||
|
|
||||||
assert(term->width > 0);
|
assert(term->width > 0);
|
||||||
assert(term->height > 0);
|
assert(term->height > 0);
|
||||||
|
|
||||||
struct buffer *buf = shm_get_buffer(term->wl.shm, term->width, term->height);
|
struct buffer *buf = shm_get_buffer(term->wl.shm, term->width, term->height);
|
||||||
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_SOURCE);
|
cairo_set_operator(buf->cairo, CAIRO_OPERATOR_SOURCE);
|
||||||
|
|
||||||
|
gseq.g = gseq.glyphs;
|
||||||
|
gseq.count = 0;
|
||||||
|
|
||||||
|
static struct coord last_cursor = {0,0};
|
||||||
|
static struct coord last_cursor_on_screen = {0, 0};
|
||||||
|
static struct cell *last_cursor_cell = NULL;
|
||||||
|
|
||||||
|
bool all_clean = tll_length(term->grid->scroll_damage) == 0;
|
||||||
|
|
||||||
|
/* Erase old cursor (if we rendered a cursor last time) */
|
||||||
|
if (last_cursor_cell != NULL) {
|
||||||
|
render_cell(
|
||||||
|
term, buf, last_cursor_cell,
|
||||||
|
last_cursor_on_screen.col, last_cursor_on_screen.row, false);
|
||||||
|
|
||||||
|
wl_surface_damage_buffer(
|
||||||
|
term->wl.surface,
|
||||||
|
last_cursor_on_screen.col * term->cell_width,
|
||||||
|
last_cursor_on_screen.row * term->cell_height,
|
||||||
|
term->cell_width, term->cell_height);
|
||||||
|
last_cursor_cell = NULL;
|
||||||
|
|
||||||
|
if (last_cursor.col != term->cursor.col ||
|
||||||
|
last_cursor.row != term->cursor.row) {
|
||||||
|
/* Detect cursor movement - we don't dirty cells touched
|
||||||
|
* by the cursor, since only the final cell matters. */
|
||||||
|
all_clean = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (term->flash.active)
|
if (term->flash.active)
|
||||||
term_damage_view(term);
|
term_damage_view(term);
|
||||||
|
|
||||||
|
|
@ -405,8 +433,6 @@ grid_render(struct terminal *term)
|
||||||
last_flash = term->flash.active;
|
last_flash = term->flash.active;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool all_clean = tll_length(term->grid->scroll_damage) == 0;
|
|
||||||
|
|
||||||
tll_foreach(term->grid->scroll_damage, it) {
|
tll_foreach(term->grid->scroll_damage, it) {
|
||||||
switch (it->item.type) {
|
switch (it->item.type) {
|
||||||
case DAMAGE_SCROLL:
|
case DAMAGE_SCROLL:
|
||||||
|
|
@ -421,9 +447,6 @@ grid_render(struct terminal *term)
|
||||||
tll_remove(term->grid->scroll_damage, it);
|
tll_remove(term->grid->scroll_damage, it);
|
||||||
}
|
}
|
||||||
|
|
||||||
gseq.g = gseq.glyphs;
|
|
||||||
gseq.count = 0;
|
|
||||||
|
|
||||||
for (int r = 0; r < term->rows; r++) {
|
for (int r = 0; r < term->rows; r++) {
|
||||||
struct row *row = grid_row_in_view(term->grid, r);
|
struct row *row = grid_row_in_view(term->grid, r);
|
||||||
|
|
||||||
|
|
@ -473,34 +496,10 @@ grid_render(struct terminal *term)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: break out to function */
|
/*
|
||||||
/* Re-render last cursor cell and current cursor cell */
|
* Determine if we need to render a cursor or not. The cursor
|
||||||
/* Make sure previous cursor is refreshed (to avoid "ghost" cursors) */
|
* could be hidden. Or it could have been scrolled out of view.
|
||||||
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;
|
|
||||||
|
|
||||||
/* Last cursor cell may have scrolled off screen */
|
|
||||||
if (row >= 0 && row < term->rows) {
|
|
||||||
render_cell(term, buf, &grid_row_in_view(term->grid, row)->cells[col], col, row, false);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (all_clean) {
|
|
||||||
buf->busy = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Current cursor cell - may be invisible if we've scrolled back */
|
|
||||||
bool cursor_is_visible = false;
|
bool cursor_is_visible = false;
|
||||||
int view_end = (term->grid->view + term->rows - 1) % term->grid->num_rows;
|
int view_end = (term->grid->view + term->rows - 1) % term->grid->num_rows;
|
||||||
int cursor_row = (term->grid->offset + term->cursor.row) % term->grid->num_rows;
|
int cursor_row = (term->grid->offset + term->cursor.row) % term->grid->num_rows;
|
||||||
|
|
@ -515,10 +514,22 @@ grid_render(struct terminal *term)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor_is_visible && !term->hide_cursor) {
|
if (cursor_is_visible && !term->hide_cursor) {
|
||||||
render_cell(
|
/* Remember cursor coordinates so that we can erase it next
|
||||||
term, buf,
|
* time. Note that we need to re-align it against the view. */
|
||||||
&grid_row_in_view(term->grid, term->cursor.row)->cells[term->cursor.col],
|
last_cursor = term->cursor;
|
||||||
term->cursor.col, term->cursor.row, true);
|
last_cursor_on_screen = (struct coord) {
|
||||||
|
term->cursor.col,
|
||||||
|
(cursor_row - term->grid->view + term->grid->num_rows) % term->grid->num_rows,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct row *row = grid_row_in_view(
|
||||||
|
term->grid, last_cursor_on_screen.row);
|
||||||
|
|
||||||
|
last_cursor_cell = &row->cells[term->cursor.col];
|
||||||
|
render_cell(term, buf, last_cursor_cell,
|
||||||
|
term->cursor.col,
|
||||||
|
last_cursor_on_screen.row,
|
||||||
|
true);
|
||||||
|
|
||||||
wl_surface_damage_buffer(
|
wl_surface_damage_buffer(
|
||||||
term->wl.surface,
|
term->wl.surface,
|
||||||
|
|
@ -527,6 +538,12 @@ grid_render(struct terminal *term)
|
||||||
term->cell_width, term->cell_height);
|
term->cell_width, term->cell_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (all_clean) {
|
||||||
|
buf->busy = false;
|
||||||
|
gseq_flush(term, buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (gseq.count > 0)
|
if (gseq.count > 0)
|
||||||
gseq_flush(term, buf);
|
gseq_flush(term, buf);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue