mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-10 04:27:45 -05:00
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.
This commit is contained in:
parent
62a5805d4b
commit
d482bf0a30
7 changed files with 69 additions and 42 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
8
csi.c
8
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);
|
||||
|
|
|
|||
35
grid.c
35
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;
|
||||
}
|
||||
|
|
|
|||
5
render.c
5
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
21
sixel.c
21
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
|
||||
|
|
|
|||
19
terminal.c
19
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;
|
||||
|
|
|
|||
22
terminal.h
22
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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue