From d482bf0a304b8224499bf9de9e0781518106ec7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 13 Mar 2020 18:44:23 +0100 Subject: [PATCH] sixel: improve handling of images when reflowing the grids Update the sixels' 'row' attribute when re-flowing a grid, to ensure it is rendered at the correct place. This should work in most cases, but will break when the cell size has changed (e.g. font size increase/decrease, or a DPI change). This patch also moves the sixel image list from the terminal struct into the grid struct. The sixels are per-grid after all. --- CHANGELOG.md | 1 + csi.c | 8 +++----- grid.c | 35 +++++++++++++++++++++++++++++++++++ render.c | 5 +---- sixel.c | 21 +++++++-------------- terminal.c | 19 ++++++++++++------- terminal.h | 22 ++++++++++------------ 7 files changed, 69 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2f64473..41d18a56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ ### Fixed * Window size doubling when moving window between outputs with different scaling factors (https://codeberg.org/dnkl/foot/issues/3). +* Sixel images moved or deleted on window resize. ### Security diff --git a/csi.c b/csi.c index 9b00c3ef..6147f27b 100644 --- a/csi.c +++ b/csi.c @@ -1143,11 +1143,9 @@ csi_dispatch(struct terminal *term, uint8_t final) tll_free(term->alt.scroll_damage); /* Delete all sixel images on the alt screen */ - tll_foreach(term->sixel_images, it) { - if (it->item.grid == &term->alt) { - sixel_destroy(&it->item); - tll_remove(term->sixel_images, it); - } + tll_foreach(term->alt.sixel_images, it) { + sixel_destroy(&it->item); + tll_remove(term->alt.sixel_images, it); } term_damage_all(term); diff --git a/grid.c b/grid.c index d538edc9..056dd791 100644 --- a/grid.c +++ b/grid.c @@ -6,6 +6,7 @@ #define LOG_MODULE "grid" #define LOG_ENABLE_DBG 0 #include "log.h" +#include "sixel.h" #define max(x, y) ((x) > (y) ? (x) : (y)) @@ -76,6 +77,8 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, * at the output that is *oldest* */ int offset = grid->offset + old_screen_rows; + tll(struct sixel) new_sixels = tll_init(); + /* * Walk the old grid */ @@ -86,6 +89,28 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, if (old_row == NULL) continue; + /* + * Update 'row' in all sixels that *begin* at current row + * + * Since we might end up pushing the sixel down, we can't + * simply update the row inline - we'd then end up pushing the + * sixel down again, when we reach the next 'old' + * row. Instead, copy the sixel (with 'row' updated), to a + * temporary list and remove the original sixel. + * + * After we've reflowed the grid we'll move the sixels back to + * the "real" sixel list. + */ + tll_foreach(grid->sixel_images, it) { + if (it->item.pos.row == ((offset + r) & (old_rows - 1))) { + struct sixel six = it->item; + six.pos.row = new_row_idx; + + tll_push_back(new_sixels, six); + tll_remove(grid->sixel_images, it); + } + } + /* * Keep track of empty cells. If the old line ends with a * string of empty cells, we don't need to, nor do we want to, @@ -191,5 +216,15 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, grid->num_rows = new_rows; grid->num_cols = new_cols; + /* Destroy any non-moved sixels */ + tll_foreach(grid->sixel_images, it) + sixel_destroy(&it->item); + tll_free(grid->sixel_images); + + /* Move updated sixels back */ + tll_foreach(new_sixels, it) + tll_push_back(grid->sixel_images, it->item); + tll_free(new_sixels); + return new_row_idx; } diff --git a/render.c b/render.c index fdb156ea..2c00a513 100644 --- a/render.c +++ b/render.c @@ -531,9 +531,6 @@ static void render_sixel(struct terminal *term, pixman_image_t *pix, const struct sixel *sixel) { - if (sixel->grid != term->grid) - return; - int view_end = (term->grid->view + term->rows - 1) & (term->grid->num_rows - 1); int first_visible_row = -1; @@ -599,7 +596,7 @@ render_sixel(struct terminal *term, pixman_image_t *pix, static void render_sixel_images(struct terminal *term, pixman_image_t *pix) { - tll_foreach(term->sixel_images, it) + tll_foreach(term->grid->sixel_images, it) render_sixel(term, pix, &it->item); } diff --git a/sixel.c b/sixel.c index 90d886fe..98a82deb 100644 --- a/sixel.c +++ b/sixel.c @@ -76,22 +76,19 @@ sixel_erase(struct terminal *term, struct sixel *sixel) void sixel_delete_at_row(struct terminal *term, int _row) { - if (likely(tll_length(term->sixel_images) == 0)) + if (likely(tll_length(term->grid->sixel_images) == 0)) return; - tll_foreach(term->sixel_images, it) { + tll_foreach(term->grid->sixel_images, it) { struct sixel *six = &it->item; - if (six->grid != term->grid) - continue; - const int row = (term->grid->offset + _row) & (term->grid->num_rows - 1); const int six_start = six->pos.row; const int six_end = six_start + six->rows - 1; if (row >= six_start && row <= six_end) { sixel_erase(term, six); - tll_remove(term->sixel_images, it); + tll_remove(term->grid->sixel_images, it); } } } @@ -101,18 +98,15 @@ sixel_delete_in_range(struct terminal *term, int _start, int _end) { assert(_end >= _start); - if (likely(tll_length(term->sixel_images) == 0)) + if (likely(tll_length(term->grid->sixel_images) == 0)) return; if (_start == _end) return sixel_delete_at_row(term, _start); - tll_foreach(term->sixel_images, it) { + tll_foreach(term->grid->sixel_images, it) { struct sixel *six = &it->item; - if (six->grid != term->grid) - continue; - const int start = (term->grid->offset + _start) & (term->grid->num_rows - 1); const int end = start + (_end - _start); const int six_start = six->pos.row; @@ -123,7 +117,7 @@ sixel_delete_in_range(struct terminal *term, int _start, int _end) (start >= six_start && end <= six_end)) /* Fully within sixel range */ { sixel_erase(term, six); - tll_remove(term->sixel_images, it); + tll_remove(term->grid->sixel_images, it); } } } @@ -147,7 +141,6 @@ sixel_unhook(struct terminal *term) .width = term->sixel.image.width, .height = term->sixel.image.height, .rows = (term->sixel.image.height + term->cell_height - 1) / term->cell_height, - .grid = term->grid, .pos = (struct coord){ term->cursor.point.col, (term->grid->offset + term->cursor.point.row) & (term->grid->num_rows - 1)}, @@ -172,7 +165,7 @@ sixel_unhook(struct terminal *term) term_formfeed(term); render_refresh(term); - tll_push_back(term->sixel_images, image); + tll_push_back(term->grid->sixel_images, image); } static unsigned diff --git a/terminal.c b/terminal.c index 2a742268..35e145a7 100644 --- a/terminal.c +++ b/terminal.c @@ -721,8 +721,8 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, .start = {-1, -1}, .end = {-1, -1}, }, - .normal = {.damage = tll_init(), .scroll_damage = tll_init()}, - .alt = {.damage = tll_init(), .scroll_damage = tll_init()}, + .normal = {.damage = tll_init(), .scroll_damage = tll_init(), .sixel_images = tll_init()}, + .alt = {.damage = tll_init(), .scroll_damage = tll_init(), .sixel_images = tll_init()}, .grid = &term->normal, .meta = { .esc_prefix = true, @@ -747,7 +747,6 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, .sixel = { .palette_size = SIXEL_MAX_COLORS, }, - .sixel_images = tll_init(), .hold_at_exit = conf->hold_at_exit, .shutdown_cb = shutdown_cb, .shutdown_data = shutdown_data, @@ -978,9 +977,12 @@ term_destroy(struct terminal *term) tll_free(term->ptmx_buffer); tll_free(term->tab_stops); - tll_foreach(term->sixel_images, it) + tll_foreach(term->normal.sixel_images, it) sixel_destroy(&it->item); - tll_free(term->sixel_images); + tll_free(term->normal.sixel_images); + tll_foreach(term->alt.sixel_images, it) + sixel_destroy(&it->item); + tll_free(term->alt.sixel_images); free(term->foot_exe); free(term->cwd); @@ -1104,9 +1106,12 @@ term_reset(struct terminal *term, bool hard) term->meta.esc_prefix = true; term->meta.eight_bit = true; - tll_foreach(term->sixel_images, it) + tll_foreach(term->normal.sixel_images, it) sixel_destroy(&it->item); - tll_free(term->sixel_images); + tll_free(term->normal.sixel_images); + tll_foreach(term->alt.sixel_images, it) + sixel_destroy(&it->item); + tll_free(term->alt.sixel_images); if (!hard) return; diff --git a/terminal.h b/terminal.h index 92082d8c..90379ba1 100644 --- a/terminal.h +++ b/terminal.h @@ -86,6 +86,15 @@ struct row { bool linebreak; }; +struct sixel { + void *data; + pixman_image_t *pix; + int width; + int height; + int rows; + struct coord pos; +}; + struct grid { int num_rows; int num_cols; @@ -97,6 +106,7 @@ struct grid { tll(struct damage) damage; tll(struct damage) scroll_damage; + tll(struct sixel) sixel_images; }; struct vt_subparams { @@ -175,16 +185,6 @@ struct ptmx_buffer { size_t idx; }; -struct sixel { - void *data; - pixman_image_t *pix; - int width; - int height; - int rows; - const struct grid *grid; - struct coord pos; -}; - enum term_surface { TERM_SURF_NONE, TERM_SURF_GRID, @@ -417,8 +417,6 @@ struct terminal { unsigned max_height; /* Maximum image height, in pixels */ } sixel; - tll(struct sixel) sixel_images; - bool hold_at_exit; bool is_shutting_down; void (*shutdown_cb)(void *data, int exit_code);