diff --git a/image-kitty.c b/image-kitty.c index 313cb5042..af3133804 100644 --- a/image-kitty.c +++ b/image-kitty.c @@ -131,6 +131,7 @@ struct kitty_placement_cache { u_int y; u_int width; u_int height; + int pending_delete; struct kitty_placement_cache *next; }; @@ -177,13 +178,49 @@ kitty_free_placements(struct kitty_image_cache *entry) entry->placements = NULL; } -/* Delete Kitty placements intersecting a redraw area. */ +/* + * Mark Kitty placements intersecting a redraw area as stale, without + * deleting them yet - see kitty_redraw_finish(). Deleting immediately here + * would, for an image whose only placements are in this area, leave it + * with none at all until the replacement is placed - some Kitty + * implementations free an image's pixel data once it has no placements + * left, which would leave the replacement referencing already-discarded + * data and render as nothing. + */ void kitty_redraw_start(struct tty *tty, u_int x, u_int y, u_int width, u_int height) { - struct kitty_output *ko = tty->image_data; - struct kitty_image_cache *entry; + struct kitty_output *ko = tty->image_data; + struct kitty_image_cache *entry; + struct kitty_placement_cache *placement; + + if (ko == NULL) + return; + for (entry = ko->images; entry != NULL; entry = entry->next) { + for (placement = entry->placements; placement != NULL; + placement = placement->next) { + if (placement->x >= x + width || + placement->x + placement->width <= x || + placement->y >= y + height || + placement->y + placement->height <= y) + continue; + placement->pending_delete = 1; + } + } +} + +/* + * Delete placements marked stale by kitty_redraw_start() - called once any + * replacement placements have already been created, so an image already + * placed elsewhere in the same redraw is never left with none at all in + * between the two. + */ +void +kitty_redraw_finish(struct tty *tty) +{ + struct kitty_output *ko = tty->image_data; + struct kitty_image_cache *entry; struct kitty_placement_cache **pp, *placement; char s[64]; @@ -191,15 +228,12 @@ kitty_redraw_start(struct tty *tty, u_int x, u_int y, u_int width, return; for (entry = ko->images; entry != NULL; entry = entry->next) { for (pp = &entry->placements; (placement = *pp) != NULL; ) { - if (placement->x >= x + width || - placement->x + placement->width <= x || - placement->y >= y + height || - placement->y + placement->height <= y) { + if (!placement->pending_delete) { pp = &placement->next; continue; - } - xsnprintf(s, sizeof s, - "\033_Ga=d,d=i,i=%u,p=%u,q=2\033\\", entry->kitty_id, + } + xsnprintf(s, sizeof s, + "\033_Ga=d,d=i,i=%u,p=%u,q=2\033\\", entry->kitty_id, placement->id); tty_puts(tty, s); *pp = placement->next; diff --git a/image.c b/image.c index 10bbaa5bc..ec15767f7 100644 --- a/image.c +++ b/image.c @@ -156,6 +156,20 @@ image_redraw_start(struct tty *tty, u_int x, u_int y, u_int width, sixel_redraw_start(tty, x, y, width, height); } +/* + * Delete placements marked stale by image_redraw_start() - called once any + * replacement placements a redraw is making have already been created. Only + * meaningful for Kitty (see kitty_redraw_finish()) - SIXEL has no separate + * placement/data distinction for sixel_redraw_start()'s plain erase to + * leave dangling. + */ +void +image_redraw_finish(struct tty *tty) +{ + if (tty->image_backend == &image_backend_kitty) + kitty_redraw_finish(tty); +} + /* Write out any image output the backend is still holding back. */ void image_draw_flush(struct tty *tty) diff --git a/screen-redraw.c b/screen-redraw.c index f79f0ab9c..4829d13ff 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1806,6 +1806,10 @@ redraw_draw_pane_lines(struct redraw_draw_ctx *dctx, struct window_pane *wp, image_draw_flush(&scene->c->tty); #endif } +#ifdef ENABLE_IMAGES + if (flags & REDRAW_PANE) + image_redraw_finish(&scene->c->tty); +#endif } /* Draw lines. */ @@ -2139,8 +2143,13 @@ redraw_draw(struct client *c, struct window_pane *wp, int flags) if (wp != NULL) redraw_draw_pane_lines(&dctx, wp, flags); - else + else { redraw_draw_lines(&dctx, flags); +#ifdef ENABLE_IMAGES + if (flags & REDRAW_PANE) + image_redraw_finish(tty); +#endif + } #ifdef ENABLE_IMAGES if ((flags & REDRAW_PANE) && (image_backend_flags(tty) & @@ -2541,6 +2550,10 @@ redraw_draw_damage_rect(struct redraw_draw_ctx *dctx, u_int x, u_int y, image_draw_flush(&scene->c->tty); #endif } +#ifdef ENABLE_IMAGES + if (!skip_images) + image_redraw_finish(&scene->c->tty); +#endif /* SIXEL image output may disturb status cells; compose them last. */ for (yy = y; yy < y + sy; yy++) { diff --git a/tmux.h b/tmux.h index 057927d84..40737450c 100644 --- a/tmux.h +++ b/tmux.h @@ -4341,6 +4341,7 @@ void image_redraw_area(struct screen_write_ctx *, u_int, u_int, void image_redraw_all(struct screen_write_ctx *); void image_redraw_scroll(struct screen_write_ctx *, u_int); void image_redraw_start(struct tty *, u_int, u_int, u_int, u_int); +void image_redraw_finish(struct tty *); void image_draw_flush(struct tty *); int image_backend_flags(struct tty *); int image_tty_update(struct tty *); @@ -4398,6 +4399,7 @@ void kitty_free_state(void *); void kitty_draw_rect(struct tty *, const struct image_rect *, const struct tty_style_ctx *); void kitty_redraw_start(struct tty *, u_int, u_int, u_int, u_int); +void kitty_redraw_finish(struct tty *); void kitty_free_output_state(struct tty *, int); #endif