mirror of
https://github.com/tmux/tmux.git
synced 2026-10-14 23:34:22 +00:00
Some of SIXEL output path.
This commit is contained in:
@@ -34,7 +34,14 @@ static const struct utf8_data fallback_half_lower = {
|
||||
"\342\226\204", 3, 3, 1
|
||||
};
|
||||
|
||||
/* Return the average colour and brightness of an area. */
|
||||
/* Fallback output is available on every terminal. */
|
||||
int
|
||||
fallback_select(__unused struct tty *tty)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Get the average colour and brightness of an area. */
|
||||
static int
|
||||
fallback_sample(struct image *im, uint64_t px, uint64_t py, uint64_t pw,
|
||||
uint64_t ph, u_char *brightness)
|
||||
@@ -142,7 +149,7 @@ fallback_get_cell(struct tty *tty, struct image *im, u_int x, u_int y,
|
||||
out->attr |= GRID_ATTR_BRIGHT;
|
||||
}
|
||||
|
||||
/* Return a text cell for an image grid cell, if there is one. */
|
||||
/* Get a text cell for an image grid cell, if there is one. */
|
||||
const struct grid_cell *
|
||||
fallback_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)
|
||||
|
||||
106
image-grid.c
106
image-grid.c
@@ -83,6 +83,105 @@ struct image_recover_row {
|
||||
u_int source_y;
|
||||
};
|
||||
|
||||
/* A backend to draw an image. */
|
||||
struct image_backend {
|
||||
const char *name;
|
||||
int flags;
|
||||
int (*select)(struct tty *);
|
||||
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 *);
|
||||
void (*free)(struct tty *);
|
||||
};
|
||||
|
||||
/* Backend definitions. */
|
||||
static struct image_backend image_backend_fallback = {
|
||||
"fallback",
|
||||
IMAGE_BACKEND_SCROLLS,
|
||||
fallback_select,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
static struct image_backend image_backend_sixel = {
|
||||
"sixel",
|
||||
IMAGE_BACKEND_GRAPHICAL,
|
||||
sixel_select,
|
||||
sixel_draw_rect,
|
||||
sixel_start_draw,
|
||||
sixel_flush_pending,
|
||||
sixel_free_pending
|
||||
};
|
||||
|
||||
/* Backends in order of preference. */
|
||||
static struct image_backend *image_backends[] = {
|
||||
&image_backend_sixel,
|
||||
&image_backend_fallback
|
||||
};
|
||||
|
||||
/* Update the image backend. */
|
||||
int
|
||||
image_tty_update(struct tty *tty)
|
||||
{
|
||||
struct image_backend *backend;
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < nitems(image_backends); i++) {
|
||||
backend = image_backends[i];
|
||||
if (backend->select(tty))
|
||||
break;
|
||||
}
|
||||
if (tty->image_backend == backend)
|
||||
return (0);
|
||||
|
||||
if (tty->image_backend != NULL && tty->image_backend->free != NULL)
|
||||
tty->image_backend->free(tty);
|
||||
tty->image_data = NULL;
|
||||
tty->image_backend = backend;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
image_tty_update(tty);
|
||||
if (tty->image_backend->start_draw != NULL)
|
||||
tty->image_backend->start_draw(tty, x, y, w, h);
|
||||
}
|
||||
|
||||
/* Write pending image output to the terminal. */
|
||||
void
|
||||
image_draw_flush(struct tty *tty)
|
||||
{
|
||||
image_tty_update(tty);
|
||||
if (tty->image_backend->flush != NULL)
|
||||
tty->image_backend->flush(tty);
|
||||
}
|
||||
|
||||
/* Discard image backend state after a terminal size change. */
|
||||
void
|
||||
image_tty_size_changed(struct tty *tty)
|
||||
{
|
||||
if (!image_tty_update(tty)) {
|
||||
if (tty->image_backend->free != NULL)
|
||||
tty->image_backend->free(tty);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free image backend state for a terminal. */
|
||||
void
|
||||
image_tty_free(struct tty *tty)
|
||||
{
|
||||
if (tty->image_backend != NULL) {
|
||||
if (tty->image_backend->free != NULL)
|
||||
tty->image_backend->free(tty);
|
||||
tty->image_backend = NULL;
|
||||
tty->image_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the placement store for a grid. */
|
||||
static struct image_store *
|
||||
image_store_get(struct grid *gd)
|
||||
@@ -401,6 +500,7 @@ image_grid_copy_area(struct grid *dst, u_int dx, u_int dy, struct grid *src,
|
||||
struct image_copy_map *maps = NULL;
|
||||
struct image_placement *plmt;
|
||||
struct image_line *src_line, *dst_line;
|
||||
struct grid_line *gl;
|
||||
struct image_span *span;
|
||||
u_int nmaps = 0, row, start, end, span_end;
|
||||
|
||||
@@ -428,8 +528,10 @@ image_grid_copy_area(struct grid *dst, u_int dx, u_int dy, struct grid *src,
|
||||
continue;
|
||||
if (span_end > end)
|
||||
span_end = end;
|
||||
if (dst_line == NULL)
|
||||
dst_line = image_line_get(&dst->linedata[dy + row]);
|
||||
if (dst_line == NULL) {
|
||||
gl = &dst->linedata[dy + row];
|
||||
dst_line = image_line_get(gl);
|
||||
}
|
||||
plmt = image_copy_placement(dst, span->placement, &maps,
|
||||
&nmaps);
|
||||
plmt->recover_from = 0;
|
||||
|
||||
129
image-sixel.c
129
image-sixel.c
@@ -100,6 +100,23 @@ struct sixel_plane {
|
||||
char *stream;
|
||||
};
|
||||
|
||||
/* Adjacent placement rows buffered for one SIXEL output sequence. */
|
||||
struct sixel_pending {
|
||||
struct image *image;
|
||||
|
||||
/* Source in image in cells. */
|
||||
u_int src_x;
|
||||
u_int src_y;
|
||||
|
||||
/* Size in cells. */
|
||||
u_int w;
|
||||
u_int h;
|
||||
|
||||
/* Destination on terminal in cells. */
|
||||
u_int dst_x;
|
||||
u_int dst_y;
|
||||
};
|
||||
|
||||
/* RGB histogram entry. */
|
||||
struct sixel_hgram {
|
||||
u_int count;
|
||||
@@ -1272,3 +1289,115 @@ sixel_from_image(struct image *im, u_int x, u_int y, u_int sx, u_int sy,
|
||||
sixel_free(si);
|
||||
return (data);
|
||||
}
|
||||
|
||||
/* Return whether the terminal supports SIXEL. */
|
||||
int
|
||||
sixel_select(struct tty *tty)
|
||||
{
|
||||
if (tty->term != NULL &&
|
||||
(tty->term->flags & TERM_SIXEL) &&
|
||||
tty->xpixel != 0 &&
|
||||
tty->ypixel != 0)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Get pending SIXEL rows for a terminal. */
|
||||
static struct sixel_pending *
|
||||
sixel_get_pending(struct tty *tty)
|
||||
{
|
||||
struct sixel_pending *sp = tty->image_data;
|
||||
|
||||
if (sp == NULL) {
|
||||
sp = xcalloc(1, sizeof *sp);
|
||||
tty->image_data = sp;
|
||||
}
|
||||
return (sp);
|
||||
}
|
||||
|
||||
/* Free pending SIXEL rows for a terminal. */
|
||||
void
|
||||
sixel_free_pending(struct tty *tty)
|
||||
{
|
||||
struct sixel_pending *sp = tty->image_data;
|
||||
|
||||
if (sp == NULL)
|
||||
return;
|
||||
if (sp->image != NULL)
|
||||
image_free(sp->image);
|
||||
free(sp);
|
||||
tty->image_data = NULL;
|
||||
}
|
||||
|
||||
/* Write the rows held in the pending run as a single SIXEL. */
|
||||
void
|
||||
sixel_flush_pending(struct tty *tty)
|
||||
{
|
||||
struct sixel_pending *sp = tty->image_data;
|
||||
struct image *im;
|
||||
char *data;
|
||||
size_t size;
|
||||
|
||||
if (sp == NULL || sp->image == NULL)
|
||||
return;
|
||||
im = sp->image;
|
||||
sp->image = NULL;
|
||||
|
||||
data = sixel_from_image(im, sp->src_x, sp->src_y, sp->w, sp->h,
|
||||
tty->xpixel, tty->ypixel, &size);
|
||||
if (data != NULL) {
|
||||
tty_region_off(tty);
|
||||
tty_margin_off(tty);
|
||||
tty_cursor(tty, sp->dst_x, sp->dst_y);
|
||||
|
||||
tty->flags |= TTY_NOBLOCK;
|
||||
tty_putn(tty, data, size, 0);
|
||||
tty->cx = tty->cy = UINT_MAX;
|
||||
|
||||
free(data);
|
||||
}
|
||||
image_free(im);
|
||||
}
|
||||
|
||||
/* Queue adjacent placement rows for one SIXEL output sequence. */
|
||||
void
|
||||
sixel_draw_rect(struct tty *tty, struct image_rect *rect)
|
||||
{
|
||||
struct sixel_pending *sp = sixel_get_pending(tty);
|
||||
|
||||
if (sp->image == rect->image &&
|
||||
sp->src_x == rect->src_x &&
|
||||
sp->w == rect->sx &&
|
||||
sp->dst_x == rect->dst_x &&
|
||||
sp->src_y + sp->h == rect->src_y &&
|
||||
sp->dst_y + sp->h == rect->dst_y) {
|
||||
sp->h += rect->sy;
|
||||
return;
|
||||
}
|
||||
|
||||
image_ref(rect->image);
|
||||
sixel_flush_pending(tty);
|
||||
|
||||
sp->image = rect->image;
|
||||
sp->src_x = rect->src_x;
|
||||
sp->src_y = rect->src_y;
|
||||
sp->w = rect->sx;
|
||||
sp->h = rect->sy;
|
||||
sp->dst_x = rect->dst_x;
|
||||
sp->dst_y = rect->dst_y;
|
||||
}
|
||||
|
||||
/* Remove old SIXEL pixels before drawing an image area. */
|
||||
void
|
||||
sixel_start_draw(struct tty *tty, u_int x, u_int y, u_int sx, u_int sy)
|
||||
{
|
||||
u_int yy;
|
||||
|
||||
for (yy = y; yy < y + sy; yy++) {
|
||||
tty_cursor(tty, x, yy);
|
||||
if (tty_term_has(tty->term, TTYC_ECH))
|
||||
tty_putcode_i(tty, TTYC_ECH, sx);
|
||||
else
|
||||
tty_repeat_space(tty, sx);
|
||||
}
|
||||
}
|
||||
|
||||
37
tmux-image.h
37
tmux-image.h
@@ -21,12 +21,13 @@
|
||||
#define TMUX_IMAGE_H
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
#error image support is not ready yet
|
||||
//#error image support is not ready yet
|
||||
|
||||
struct grid;
|
||||
struct grid_cell;
|
||||
struct grid_line;
|
||||
struct image;
|
||||
struct image_backend;
|
||||
struct image_line;
|
||||
struct image_store;
|
||||
struct screen;
|
||||
@@ -37,6 +38,12 @@ struct tty;
|
||||
/* Maximum image size in bytes. */
|
||||
#define IMAGE_SIZE_LIMIT (64 * 1024 * 1024)
|
||||
|
||||
/* Backend draws images as graphics. */
|
||||
#define IMAGE_BACKEND_GRAPHICAL 0x1
|
||||
|
||||
/* Backend images move with terminal scrolling. */
|
||||
#define IMAGE_BACKEND_SCROLLS 0x2
|
||||
|
||||
/* View of all or part of an image. */
|
||||
struct image_view {
|
||||
/* Position and size in the image, in pixels. */
|
||||
@@ -60,6 +67,23 @@ struct image_view {
|
||||
u_int sy;
|
||||
};
|
||||
|
||||
/* A part of an image to draw. */
|
||||
struct image_rect {
|
||||
struct image *image;
|
||||
|
||||
/* Size in cells. */
|
||||
u_int sx;
|
||||
u_int sy;
|
||||
|
||||
/* Source in image in cells. */
|
||||
u_int src_x;
|
||||
u_int src_y;
|
||||
|
||||
/* Destination on terminal in cells. */
|
||||
u_int dst_x;
|
||||
u_int dst_y;
|
||||
};
|
||||
|
||||
/* image.c */
|
||||
struct image *image_create(u_int, u_int, u_int, u_int, u_int, u_int,
|
||||
u_char *);
|
||||
@@ -102,13 +126,20 @@ 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 *);
|
||||
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 *);
|
||||
void image_tty_size_changed(struct tty *);
|
||||
void image_tty_free(struct tty *);
|
||||
|
||||
/* image-fallback.c */
|
||||
int fallback_select(struct tty *);
|
||||
const struct grid_cell *fallback_map_cell(struct tty *, struct grid *, u_int,
|
||||
u_int, const struct grid_cell *, struct grid_cell *, int *);
|
||||
|
||||
/* image-sixel.c */
|
||||
#define SIXEL_COLOUR_REGISTERS 1024
|
||||
int sixel_select(struct tty *);
|
||||
struct sixel_image *sixel_parse(const char *, size_t, u_int, u_int, u_int,
|
||||
u_int);
|
||||
void sixel_free(struct sixel_image *);
|
||||
@@ -118,6 +149,10 @@ void sixel_write(struct screen_write_ctx *, struct sixel_image *,
|
||||
u_int);
|
||||
char *sixel_from_image(struct image *, u_int, u_int, u_int, u_int,
|
||||
u_int, u_int, size_t *);
|
||||
void sixel_draw_rect(struct tty *, struct image_rect *);
|
||||
void sixel_start_draw(struct tty *, u_int, u_int, u_int, u_int);
|
||||
void sixel_free_pending(struct tty *);
|
||||
void sixel_flush_pending(struct tty *);
|
||||
|
||||
#endif /* ENABLE_IMAGES */
|
||||
|
||||
|
||||
7
tmux.h
7
tmux.h
@@ -1852,6 +1852,11 @@ struct tty {
|
||||
|
||||
struct event key_timer;
|
||||
struct tty_key *key_tree;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
struct image_backend *image_backend;
|
||||
void *image_data;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Terminal command context. */
|
||||
@@ -2941,7 +2946,7 @@ void tty_cell(struct tty *, const struct grid_cell *,
|
||||
const struct tty_style_ctx *);
|
||||
int tty_init(struct tty *, struct client *);
|
||||
void tty_resize(struct tty *);
|
||||
void tty_set_size(struct tty *, u_int, u_int, u_int, u_int);
|
||||
int tty_set_size(struct tty *, u_int, u_int, u_int, u_int);
|
||||
void tty_invalidate(struct tty *);
|
||||
void tty_start_tty(struct tty *);
|
||||
void tty_send_requests(struct tty *);
|
||||
|
||||
@@ -1914,7 +1914,8 @@ tty_keys_winsz(struct tty *tty, const char *buf, size_t len, size_t *size,
|
||||
return (0);
|
||||
|
||||
/* Window size in characters. */
|
||||
tty_set_size(tty, sx, sy, tty->xpixel, tty->ypixel);
|
||||
if (tty_set_size(tty, sx, sy, tty->xpixel, tty->ypixel))
|
||||
server_redraw_client(c);
|
||||
return (0);
|
||||
} else if (sscanf(tmp, "4;%u;%u", &ypixel, &xpixel) == 2) {
|
||||
*size = end + 1;
|
||||
@@ -1924,7 +1925,8 @@ tty_keys_winsz(struct tty *tty, const char *buf, size_t len, size_t *size,
|
||||
/* Window size in pixels. */
|
||||
char_x = (xpixel && tty->sx) ? xpixel / tty->sx : 0;
|
||||
char_y = (ypixel && tty->sy) ? ypixel / tty->sy : 0;
|
||||
tty_set_size(tty, tty->sx, tty->sy, char_x, char_y);
|
||||
if (tty_set_size(tty, tty->sx, tty->sy, char_x, char_y))
|
||||
server_redraw_client(c);
|
||||
tty_invalidate(tty);
|
||||
|
||||
tty->flags &= ~TTY_WINSIZEQUERY;
|
||||
|
||||
20
tty.c
20
tty.c
@@ -155,13 +155,22 @@ tty_resize(struct tty *tty)
|
||||
tty_invalidate(tty);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
tty_set_size(struct tty *tty, u_int sx, u_int sy, u_int xpixel, u_int ypixel)
|
||||
{
|
||||
if (tty->sx == sx &&
|
||||
tty->sy == sy &&
|
||||
tty->xpixel == xpixel &&
|
||||
tty->ypixel == ypixel)
|
||||
return (0);
|
||||
tty->sx = sx;
|
||||
tty->sy = sy;
|
||||
tty->xpixel = xpixel;
|
||||
tty->ypixel = ypixel;
|
||||
#ifdef ENABLE_IMAGES
|
||||
image_tty_size_changed(tty);
|
||||
#endif
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -523,6 +532,9 @@ tty_close(struct tty *tty)
|
||||
tty_stop_tty(tty);
|
||||
|
||||
if (tty->flags & TTY_OPENED) {
|
||||
#ifdef ENABLE_IMAGES
|
||||
image_tty_free(tty);
|
||||
#endif
|
||||
evbuffer_free(tty->in);
|
||||
event_del(&tty->event_in);
|
||||
evbuffer_free(tty->out);
|
||||
@@ -539,6 +551,9 @@ void
|
||||
tty_free(struct tty *tty)
|
||||
{
|
||||
tty_close(tty);
|
||||
#ifdef ENABLE_IMAGES
|
||||
image_tty_free(tty);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@@ -548,6 +563,9 @@ tty_update_features(struct tty *tty)
|
||||
|
||||
if (tty_apply_features(tty->term))
|
||||
tty_term_apply_overrides(tty->term);
|
||||
#ifdef ENABLE_IMAGES
|
||||
image_tty_update(tty);
|
||||
#endif
|
||||
|
||||
if (tty_use_margin(tty))
|
||||
tty_putcode(tty, TTYC_ENMG);
|
||||
|
||||
Reference in New Issue
Block a user