SIXEL draw bits.

This commit is contained in:
Nicholas Marriott
2026-10-14 11:40:55 +01:00
parent 464f404b85
commit 1e294b175f
4 changed files with 141 additions and 2 deletions

View File

@@ -88,6 +88,9 @@ struct image_backend {
const char *name; const char *name;
int flags; int flags;
int (*select)(struct tty *); 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 (*draw_rect)(struct tty *, struct image_rect *);
void (*start_draw)(struct tty *, u_int, u_int, u_int, u_int); void (*start_draw)(struct tty *, u_int, u_int, u_int, u_int);
void (*flush)(struct tty *); void (*flush)(struct tty *);
@@ -99,6 +102,7 @@ static struct image_backend image_backend_fallback = {
"fallback", "fallback",
IMAGE_BACKEND_SCROLLS, IMAGE_BACKEND_SCROLLS,
fallback_select, fallback_select,
fallback_map_cell,
NULL, NULL,
NULL, NULL,
NULL, NULL,
@@ -108,6 +112,7 @@ static struct image_backend image_backend_sixel = {
"sixel", "sixel",
IMAGE_BACKEND_GRAPHICAL, IMAGE_BACKEND_GRAPHICAL,
sixel_select, sixel_select,
NULL,
sixel_draw_rect, sixel_draw_rect,
sixel_start_draw, sixel_start_draw,
sixel_flush_pending, sixel_flush_pending,
@@ -142,6 +147,69 @@ image_tty_update(struct tty *tty)
return (1); 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. */ /* Clear old image pixels before redrawing a terminal area. */
void void
image_redraw_start(struct tty *tty, u_int x, u_int y, u_int w, u_int h) image_redraw_start(struct tty *tty, u_int x, u_int y, u_int w, u_int h)

View File

@@ -1525,6 +1525,12 @@ redraw_draw_span(struct redraw_draw_ctx *dctx, struct redraw_span *span,
case REDRAW_SPAN_PANE: case REDRAW_SPAN_PANE:
if (phase == REDRAW_TEXT) if (phase == REDRAW_TEXT)
redraw_draw_pane_span(dctx, span, span->x, y, width); 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; break;
case REDRAW_SPAN_BORDER: case REDRAW_SPAN_BORDER:
case REDRAW_SPAN_EMPTY: 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) if (bottom > (int)scene->sy)
bottom = 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. */ /* Draw each phase. */
for (phase = 0; phase < REDRAW_PHASE_COUNT; phase++) { for (phase = 0; phase < REDRAW_PHASE_COUNT; phase++) {
for (y = top; y < bottom; y++) { 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); 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 */ 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); tty_update_mode(tty, tty->mode & ~CURSOR_MODES, NULL);
if (wp != 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) if (sx == 0 || sy == 0)
return; 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. */ /* Draw each phase in the damaged spans. */
for (phase = 0; phase < REDRAW_PHASE_COUNT; phase++) { for (phase = 0; phase < REDRAW_PHASE_COUNT; phase++) {
for (yy = y; yy < y + sy; yy++) { 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. */ /* Draw prompts and pane status lines last. */

View File

@@ -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); void image_write(struct screen_write_ctx *, struct image *, u_int);
int image_grid_get_at(struct grid *, u_int, u_int, struct image **, int image_grid_get_at(struct grid *, u_int, u_int, struct image **,
u_int *, u_int *); 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_redraw_start(struct tty *, u_int, u_int, u_int, u_int);
void image_draw_flush(struct tty *); void image_draw_flush(struct tty *);
int image_tty_update(struct tty *); int image_tty_update(struct tty *);

View File

@@ -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 #ifdef ENABLE_IMAGES
/* Map an image cell if needed. */ /* 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); gd->hsize + py, gcp, &gc, &empty);
#endif #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 #ifdef ENABLE_IMAGES
/* Map an image cell if needed. */ /* 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); gd->hsize + py, gcp, &gc, NULL);
#endif #endif