diff --git a/image-grid.c b/image-grid.c index 51350b8e5..e5afe730a 100644 --- a/image-grid.c +++ b/image-grid.c @@ -88,6 +88,9 @@ struct image_backend { const char *name; int flags; int (*select)(struct tty *); + const struct grid_cell *(*map_cell)(struct tty *, struct grid *, u_int, + u_int, const struct grid_cell *, struct grid_cell *, + int *); void (*draw_rect)(struct tty *, struct image_rect *); void (*start_draw)(struct tty *, u_int, u_int, u_int, u_int); void (*flush)(struct tty *); @@ -99,6 +102,7 @@ static struct image_backend image_backend_fallback = { "fallback", IMAGE_BACKEND_SCROLLS, fallback_select, + fallback_map_cell, NULL, NULL, NULL, @@ -108,6 +112,7 @@ static struct image_backend image_backend_sixel = { "sixel", IMAGE_BACKEND_GRAPHICAL, sixel_select, + NULL, sixel_draw_rect, sixel_start_draw, sixel_flush_pending, @@ -142,6 +147,69 @@ image_tty_update(struct tty *tty) return (1); } +/* Map an image grid cell to text for the selected backend. */ +const struct grid_cell * +image_map_cell(struct tty *tty, struct grid *gd, u_int x, u_int y, + const struct grid_cell *gc, struct grid_cell *out, int *empty) +{ + image_tty_update(tty); + if (tty->image_backend->map_cell == NULL) + return (gc); + return (tty->image_backend->map_cell(tty, gd, x, y, gc, out, empty)); +} + +/* Draw a clipped part of one image span. */ +static void +image_draw_span(struct image_backend *backend, struct tty *tty, + struct image_span *span, u_int start, u_int end, u_int px, u_int atx, + u_int aty) +{ + struct image_rect rect; + + rect.image = span->placement->image; + rect.src_x = span->source_x + start - span->x; + rect.src_y = span->source_y; + rect.sx = end - start; + rect.sy = 1; + rect.dst_x = atx + start - px; + rect.dst_y = aty; + backend->draw_rect(tty, &rect); +} + +/* Draw images in the visible part of one screen line. */ +void +image_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, + u_int nx, u_int atx, u_int aty) +{ + struct image_backend *backend; + struct image_line *line; + struct image_span *span; + u_int start, end, span_end; + + image_tty_update(tty); + backend = tty->image_backend; + if (backend->draw_rect == NULL) + return; + if (py >= s->grid->sy) + return; + line = s->grid->linedata[s->grid->hsize + py].images; + if (line == NULL) + return; + end = px + nx; + TAILQ_FOREACH(span, &line->spans, line_entry) { + span_end = span->x + span->sx; + start = span->x; + if (start < px) + start = px; + if (start >= end || span_end <= px) + continue; + if (span_end > end) + span_end = end; + image_draw_span(backend, tty, span, start, span_end, px, atx, + aty); + } +} + /* Clear old image pixels before redrawing a terminal area. */ void image_redraw_start(struct tty *tty, u_int x, u_int y, u_int w, u_int h) diff --git a/screen-redraw.c b/screen-redraw.c index ca4a4c3f3..2bc69a471 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1525,6 +1525,12 @@ redraw_draw_span(struct redraw_draw_ctx *dctx, struct redraw_span *span, case REDRAW_SPAN_PANE: if (phase == REDRAW_TEXT) redraw_draw_pane_span(dctx, span, span->x, y, width); +#ifdef ENABLE_IMAGES + else { + image_draw_line(&dctx->scene->c->tty, data->p.wp->screen, + data->p.px, data->p.py, width, span->x, y); + } +#endif break; case REDRAW_SPAN_BORDER: case REDRAW_SPAN_EMPTY: @@ -1565,6 +1571,26 @@ redraw_draw_pane_lines(struct redraw_draw_ctx *dctx, struct window_pane *wp, if (bottom > (int)scene->sy) bottom = scene->sy; +#ifdef ENABLE_IMAGES + /* Erase only pane-owned spans so overlapping panes remain intact. */ + if (flags & REDRAW_PANE) { + for (y = top; y < bottom; y++) { + line = &scene->lines[y]; + if (dctx->flags & REDRAW_STATUS_TOP) + cy = dctx->status_lines + y; + else + cy = y; + spans = &line->spans[REDRAW_SPAN_PANE]; + TAILQ_FOREACH(span, spans, entry) { + if (span->data.p.wp == wp) { + image_redraw_start(&scene->c->tty, + span->x, cy, span->width, 1); + } + } + } + } +#endif + /* Draw each phase. */ for (phase = 0; phase < REDRAW_PHASE_COUNT; phase++) { for (y = top; y < bottom; y++) { @@ -1591,6 +1617,9 @@ redraw_draw_pane_lines(struct redraw_draw_ctx *dctx, struct window_pane *wp, } } } +#ifdef ENABLE_IMAGES + image_draw_flush(&scene->c->tty); +#endif } } @@ -1651,6 +1680,9 @@ redraw_draw_lines(struct redraw_draw_ctx *dctx, int flags) redraw_draw_span(dctx, span, cy, phase); } } +#ifdef ENABLE_IMAGES + image_draw_flush(&scene->c->tty); +#endif } } @@ -1906,6 +1938,14 @@ redraw_draw(struct client *c, struct window_pane *wp, int flags) } } tty_sync_start(tty); /* end in server_client_reset_state */ +#ifdef ENABLE_IMAGES + if (wp == NULL && (flags & REDRAW_PANE)) { + y = 0; + if (dctx.flags & REDRAW_STATUS_TOP) + y = dctx.status_lines; + image_redraw_start(tty, 0, y, scene->sx, scene->sy); + } +#endif tty_update_mode(tty, tty->mode & ~CURSOR_MODES, NULL); if (wp != NULL) @@ -2084,6 +2124,30 @@ redraw_draw_damage_rectangle(struct redraw_draw_ctx *dctx, u_int x, u_int y, if (sx == 0 || sy == 0) return; +#ifdef ENABLE_IMAGES + /* Clear old image pixels on all damaged spans. */ + for (yy = y; yy < y + sy; yy++) { + line = &scene->lines[yy]; + if (dctx->flags & REDRAW_STATUS_TOP) + cy = dctx->status_lines + yy; + else + cy = yy; + for (type = 0; type < REDRAW_SPAN_TYPES; type++) { + if (type == REDRAW_SPAN_STATUS) + continue; + spans = &line->spans[type]; + TAILQ_FOREACH(span, spans, entry) { + if (span->x >= x + sx) + continue; + if (span->x + span->width <= x) + continue; + image_redraw_start(&scene->c->tty, + span->x, cy, span->width, 1); + } + } + } +#endif + /* Draw each phase in the damaged spans. */ for (phase = 0; phase < REDRAW_PHASE_COUNT; phase++) { for (yy = y; yy < y + sy; yy++) { @@ -2108,6 +2172,9 @@ redraw_draw_damage_rectangle(struct redraw_draw_ctx *dctx, u_int x, u_int y, } } } +#ifdef ENABLE_IMAGES + image_draw_flush(&scene->c->tty); +#endif } /* Draw prompts and pane status lines last. */ diff --git a/tmux-image.h b/tmux-image.h index 9616e739b..1b1d26885 100644 --- a/tmux-image.h +++ b/tmux-image.h @@ -126,6 +126,10 @@ void image_damage_screen(struct screen_write_ctx *, u_int, u_int, void image_write(struct screen_write_ctx *, struct image *, u_int); int image_grid_get_at(struct grid *, u_int, u_int, struct image **, u_int *, u_int *); +const struct grid_cell *image_map_cell(struct tty *, struct grid *, u_int, + u_int, const struct grid_cell *, struct grid_cell *, int *); +void image_draw_line(struct tty *, struct screen *, u_int, u_int, + u_int, u_int, u_int); void image_redraw_start(struct tty *, u_int, u_int, u_int, u_int); void image_draw_flush(struct tty *); int image_tty_update(struct tty *); diff --git a/tty-draw.c b/tty-draw.c index 041625524..a9b0243fb 100644 --- a/tty-draw.c +++ b/tty-draw.c @@ -264,7 +264,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, #ifdef ENABLE_IMAGES /* Map an image cell if needed. */ - gcp = fallback_map_cell(tty, gd, px + i, + gcp = image_map_cell(tty, gd, px + i, gd->hsize + py, gcp, &gc, &empty); #endif @@ -278,7 +278,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, #ifdef ENABLE_IMAGES /* Map an image cell if needed. */ - gcp = fallback_map_cell(tty, gd, px + i, + gcp = image_map_cell(tty, gd, px + i, gd->hsize + py, gcp, &gc, NULL); #endif