Merge topcat001/tmux/sixel.

topcat001 2023-06-17 17:53:01 -07:00
parent 6794facc82
commit 4c92acf6ff
12 changed files with 203 additions and 49 deletions

View File

@ -154,7 +154,6 @@ dist_tmux_SOURCES = \
hyperlinks.c \
input-keys.c \
input.c \
image.c \
job.c \
key-bindings.c \
key-string.c \
@ -181,7 +180,6 @@ dist_tmux_SOURCES = \
server-fn.c \
server.c \
session.c \
sixel.c \
spawn.c \
status.c \
style.c \
@ -220,6 +218,12 @@ if HAVE_UTF8PROC
nodist_tmux_SOURCES += compat/utf8proc.c
endif
# Enable sixel support.
if ENABLE_SIXEL
dist_tmux_SOURCES += image.c
dist_tmux_SOURCES += image-sixel.c
endif
if NEED_FUZZING
check_PROGRAMS = fuzz/input-fuzzer
fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS)

View File

@ -449,6 +449,16 @@ if test "x$enable_cgroups" = xyes; then
fi
fi
# Enable sixel support.
AC_ARG_ENABLE(
sixel,
AS_HELP_STRING(--enable-sixel, enable sixel images)
)
if test "x$enable_sixel" = xyes; then
AC_DEFINE(ENABLE_SIXEL)
fi
AM_CONDITIONAL(ENABLE_SIXEL, [test "x$enable_sixel" = xyes])
# Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well.
AC_MSG_CHECKING(for b64_ntop)
AC_LINK_IFELSE([AC_LANG_PROGRAM(

View File

@ -126,7 +126,7 @@ sixel_parse_attributes(struct sixel_image *si, const char *cp, const char *end)
{
const char *last;
char *endptr;
u_int d, x, y;
u_int x, y;
last = cp;
while (last != end) {
@ -134,10 +134,10 @@ sixel_parse_attributes(struct sixel_image *si, const char *cp, const char *end)
break;
last++;
}
d = strtoul(cp, &endptr, 10);
strtoul(cp, &endptr, 10);
if (endptr == last || *endptr != ';')
return (last);
d = strtoul(endptr + 1, &endptr, 10);
strtoul(endptr + 1, &endptr, 10);
if (endptr == last || *endptr != ';')
return (NULL);
@ -442,7 +442,7 @@ sixel_print_repeat(char **buf, size_t *len, size_t *used, u_int count, char ch)
char *
sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
{
char *buf, tmp[64], *contains, data, last;
char *buf, tmp[64], *contains, data, last = 0;
size_t len, used = 0, tmplen;
u_int *colours, ncolours, i, c, x, y, count;
struct sixel_line *sl;

View File

@ -34,6 +34,8 @@ image_free(struct image *im)
all_images_count--;
TAILQ_REMOVE(&s->images, im, entry);
sixel_free(im->data);
free(im->fallback);
free(im);
}
@ -48,7 +50,7 @@ image_free_all(struct screen *s)
return (redraw);
}
void
struct image*
image_store(struct screen *s, struct sixel_image *si)
{
struct image *im;
@ -61,11 +63,16 @@ image_store(struct screen *s, struct sixel_image *si)
im->py = s->cy;
sixel_size_in_cells(si, &im->sx, &im->sy);
/* XXX Fallback mode: This can be abstracted further. */
xasprintf(&im->fallback, "Sixel image (%ux%u)\n", im->sx, im->sy);
TAILQ_INSERT_TAIL(&s->images, im, entry);
TAILQ_INSERT_TAIL(&all_images, im, all_entry);
if (++all_images_count == 10/*XXX*/)
image_free(TAILQ_FIRST(&all_images));
return (im);
}
int

13
input.c
View File

@ -1442,7 +1442,11 @@ input_csi_dispatch(struct input_ctx *ictx)
case -1:
break;
case 0:
#ifdef ENABLE_SIXEL
input_reply(ictx, "\033[?1;2;4c");
#else
input_reply(ictx, "\033[?1;2c");
#endif
break;
default:
log_debug("%s: unknown '%c'", __func__, ictx->ch);
@ -2237,19 +2241,22 @@ input_dcs_dispatch(struct input_ctx *ictx)
{
struct window_pane *wp = ictx->wp;
struct screen_write_ctx *sctx = &ictx->ctx;
struct window *w = wp->window;
u_char *buf = ictx->input_buf;
size_t len = ictx->input_len;
const char prefix[] = "tmux;";
const u_int prefixlen = (sizeof prefix) - 1;
struct sixel_image *si;
long long allow_passthrough = 0;
#ifdef ENABLE_SIXEL
struct window *w = wp->window;
struct sixel_image *si;
#endif
if (wp == NULL)
return (0);
if (ictx->flags & INPUT_DISCARD)
return (0);
#ifdef ENABLE_SIXEL
if (buf[0] == 'q') {
si = sixel_parse(buf, len, w->xpixel, w->ypixel);
if (si != NULL) {
@ -2257,6 +2264,7 @@ input_dcs_dispatch(struct input_ctx *ictx)
screen_write_sixelimage(sctx, si, ictx->cell.cell.bg);
}
}
#endif
allow_passthrough = options_get_number(wp->options, "allow-passthrough");
if (!allow_passthrough)
@ -2267,6 +2275,7 @@ input_dcs_dispatch(struct input_ctx *ictx)
screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen,
allow_passthrough == 2);
}
return (0);
}

View File

@ -856,5 +856,8 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
tty_default_colours(&defaults, wp);
tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette);
}
tty_draw_images(tty, wp, s);
#ifdef ENABLE_SIXEL
tty_draw_images(c, wp, s);
#endif
}

View File

@ -990,8 +990,10 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
memcpy(&gc, &grid_default_cell, sizeof gc);
utf8_set(&gc.data, 'E');
#ifdef ENABLE_SIXEL
if (image_free_all(s) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
for (yy = 0; yy < screen_size_y(s); yy++) {
for (xx = 0; xx < screen_size_x(s); xx++)
@ -1027,8 +1029,10 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
if (s->cx > screen_size_x(s) - 1)
return;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.bg = bg;
@ -1058,8 +1062,10 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
if (s->cx > screen_size_x(s) - 1)
return;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.bg = bg;
@ -1089,8 +1095,10 @@ screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
if (s->cx > screen_size_x(s) - 1)
return;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.bg = bg;
@ -1109,13 +1117,18 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
struct screen *s = ctx->s;
struct grid *gd = s->grid;
struct tty_ctx ttyctx;
#ifdef ENABLE_SIXEL
u_int sy = screen_size_y(s);
#endif
if (ny == 0)
ny = 1;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
if (s->cy < s->rupper || s->cy > s->rlower) {
if (ny > screen_size_y(s) - s->cy)
@ -1165,8 +1178,10 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
if (ny == 0)
ny = 1;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
if (s->cy < s->rupper || s->cy > s->rlower) {
if (ny > sy - s->cy)
@ -1216,8 +1231,10 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
if (gl->cellsize == 0 && COLOUR_DEFAULT(bg))
return;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
@ -1248,8 +1265,10 @@ screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg)
if (s->cx > sx - 1 || (s->cx >= gl->cellsize && COLOUR_DEFAULT(bg)))
return;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg);
@ -1278,8 +1297,10 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg)
return;
}
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
if (s->cx > sx - 1)
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
@ -1328,8 +1349,10 @@ screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg)
struct screen *s = ctx->s;
struct tty_ctx ttyctx;
#ifdef ENABLE_SIXEL
if (image_free_all(s) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
if (s->cy == s->rupper) {
grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg);
@ -1374,7 +1397,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
struct screen *s = ctx->s;
struct grid *gd = s->grid;
struct grid_line *gl;
int redraw;
int redraw = 0;
u_int rupper = s->rupper, rlower = s->rlower;
gl = grid_get_line(gd, gd->hsize + s->cy);
@ -1390,10 +1413,12 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
}
if (s->cy == s->rlower) {
#ifdef ENABLE_SIXEL
if (rlower == screen_size_y(s) - 1)
redraw = image_scroll_up(s, 1);
else
redraw = image_check_line(s, rupper, rlower - rupper);
#endif
if (redraw && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg);
@ -1421,8 +1446,10 @@ screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines, u_int bg)
ctx->bg = bg;
}
#ifdef ENABLE_SIXEL
if (image_scroll_up(s, lines) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
for (i = 0; i < lines; i++) {
grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg);
@ -1448,8 +1475,10 @@ screen_write_scrolldown(struct screen_write_ctx *ctx, u_int lines, u_int bg)
else if (lines > s->rlower - s->rupper + 1)
lines = s->rlower - s->rupper + 1;
#ifdef ENABLE_SIXEL
if (image_free_all(s) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
for (i = 0; i < lines; i++)
grid_view_scroll_region_down(gd, s->rupper, s->rlower, bg);
@ -1475,8 +1504,10 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s), sy = screen_size_y(s);
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg;
@ -1507,8 +1538,10 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s);
#ifdef ENABLE_SIXEL
if (image_check_line(s, 0, s->cy - 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg;
@ -1533,8 +1566,10 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s), sy = screen_size_y(s);
#ifdef ENABLE_SIXEL
if (image_free_all(s) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg;
@ -1804,8 +1839,10 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
}
}
#ifdef ENABLE_SIXEL
if (image_check_area(s, s->cx, s->cy, ci->used, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW;
#endif
grid_view_set_cells(s->grid, s->cx, s->cy, &ci->gc, cl->data + ci->x,
ci->used);
@ -2194,6 +2231,7 @@ screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len,
tty_write(tty_cmd_rawstring, &ttyctx);
}
#ifdef ENABLE_SIXEL
/* Write a SIXEL image. */
void
screen_write_sixelimage(struct screen_write_ctx *ctx, struct sixel_image *si,
@ -2239,15 +2277,14 @@ screen_write_sixelimage(struct screen_write_ctx *ctx, struct sixel_image *si,
}
screen_write_collect_flush(ctx, 0, __func__);
image_store(s, si);
screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.ptr = si;
ttyctx.ptr = image_store(s, si);
tty_write(tty_cmd_sixelimage, &ttyctx);
screen_write_cursormove(ctx, 0, cy + y, 0);
}
#endif
/* Turn alternate screen on. */
void

View File

@ -88,7 +88,10 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
s->tabs = NULL;
s->sel = NULL;
#ifdef ENABLE_SIXEL
TAILQ_INIT(&s->images);
#endif
s->write_list = NULL;
s->hyperlinks = NULL;
@ -120,7 +123,11 @@ screen_reinit(struct screen *s)
screen_clear_selection(s);
screen_free_titles(s);
#ifdef ENABLE_SIXEL
image_free_all(s);
#endif
screen_reset_hyperlinks(s);
}
@ -153,7 +160,10 @@ screen_free(struct screen *s)
if (s->hyperlinks != NULL)
hyperlinks_free(s->hyperlinks);
screen_free_titles(s);
#ifdef ENABLE_SIXEL
image_free_all(s);
#endif
}
/* Reset tabs to default, eight spaces apart. */
@ -298,7 +308,9 @@ screen_resize_cursor(struct screen *s, u_int sx, u_int sy, int reflow,
screen_resize_y(s, sy, eat_empty, &cy);
if (reflow) {
#ifdef ENABLE_SIXEL
image_free_all(s);
#endif
screen_reflow(s, sx, &cx, &cy, cursor);
}

2
tmux.1
View File

@ -21,7 +21,7 @@
.Nm tmux
.Nd terminal multiplexer
.Sh SYNOPSIS
.Nm tmux
.Nm
.Bk -words
.Op Fl 2CDlNuVv
.Op Fl c Ar shell-command

31
tmux.h
View File

@ -64,7 +64,11 @@ struct screen_write_citem;
struct screen_write_cline;
struct screen_write_ctx;
struct session;
#ifdef ENABLE_SIXEL
struct sixel_image;
#endif
struct tty_ctx;
struct tty_code;
struct tty_key;
@ -833,10 +837,12 @@ struct style {
enum style_default_type default_type;
};
#ifdef ENABLE_SIXEL
/* Image. */
struct image {
struct screen *s;
struct sixel_image *data;
char *fallback;
u_int px;
u_int py;
@ -847,6 +853,7 @@ struct image {
TAILQ_ENTRY (image) entry;
};
TAILQ_HEAD(images, image);
#endif
/* Cursor style. */
enum screen_cursor_style {
@ -888,7 +895,10 @@ struct screen {
bitstr_t *tabs;
struct screen_sel *sel;
#ifdef ENABLE_SIXEL
struct images images;
#endif
struct screen_write_cline *write_list;
@ -1390,6 +1400,7 @@ struct tty {
u_int sx;
u_int sy;
/* Cell size in pixels. */
u_int xpixel;
u_int ypixel;
@ -1398,6 +1409,8 @@ struct tty {
enum screen_cursor_style cstyle;
int ccolour;
/* Properties of the area being drawn on. */
/* When true, the drawing area is bigger than the terminal. */
int oflag;
u_int oox;
u_int ooy;
@ -2341,7 +2354,11 @@ void tty_set_path(struct tty *, const char *);
void tty_update_mode(struct tty *, int, struct screen *);
void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int,
u_int, u_int, const struct grid_cell *, struct colour_palette *);
void tty_draw_images(struct tty *, struct window_pane *, struct screen *);
#ifdef ENABLE_SIXEL
void tty_draw_images(struct client *, struct window_pane *, struct screen *);
#endif
void tty_sync_start(struct tty *);
void tty_sync_end(struct tty *);
int tty_open(struct tty *, char **);
@ -2372,7 +2389,11 @@ void tty_cmd_scrolldown(struct tty *, const struct tty_ctx *);
void tty_cmd_reverseindex(struct tty *, const struct tty_ctx *);
void tty_cmd_setselection(struct tty *, const struct tty_ctx *);
void tty_cmd_rawstring(struct tty *, const struct tty_ctx *);
#ifdef ENABLE_SIXEL
void tty_cmd_sixelimage(struct tty *, const struct tty_ctx *);
#endif
void tty_cmd_syncstart(struct tty *, const struct tty_ctx *);
void tty_default_colours(struct grid_cell *, struct window_pane *);
@ -2955,8 +2976,10 @@ void screen_write_setselection(struct screen_write_ctx *, const char *,
u_char *, u_int);
void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int,
int);
#ifdef ENABLE_SIXEL
void screen_write_sixelimage(struct screen_write_ctx *,
struct sixel_image *, u_int);
#endif
void screen_write_alternateon(struct screen_write_ctx *,
struct grid_cell *, int);
void screen_write_alternateoff(struct screen_write_ctx *,
@ -3370,14 +3393,15 @@ struct window_pane *spawn_pane(struct spawn_context *, char **);
/* regsub.c */
char *regsub(const char *, const char *, const char *, int);
#ifdef ENABLE_SIXEL
/* image.c */
int image_free_all(struct screen *);
void image_store(struct screen *, struct sixel_image *);
struct image *image_store(struct screen *, struct sixel_image *);
int image_check_line(struct screen *, u_int, u_int);
int image_check_area(struct screen *, u_int, u_int, u_int, u_int);
int image_scroll_up(struct screen *, u_int);
/* sixel.c */
/* image-sixel.c */
struct sixel_image *sixel_parse(const char *, size_t, u_int, u_int);
void sixel_free(struct sixel_image *);
void sixel_log(struct sixel_image *);
@ -3387,6 +3411,7 @@ struct sixel_image *sixel_scale(struct sixel_image *, u_int, u_int, u_int,
char *sixel_print(struct sixel_image *, struct sixel_image *,
size_t *);
struct screen *sixel_to_screen(struct sixel_image *);
#endif
/* server-acl.c */
void server_acl_init(void);

View File

@ -1260,13 +1260,6 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
return (0);
}
//XXX primary DA
// for (i = 1; i < n; i++) {
// log_debug("%s: DA feature: %d", c->name, p[i]);
// if (p[i] == 4)
// flags |= TERM_SIXEL;
// }
/*
* Handle primary device attributes input. Returns 0 for success, -1 for
* failure, 1 for partial.

102
tty.c
View File

@ -72,6 +72,11 @@ static int tty_check_overlay(struct tty *, u_int, u_int);
static void tty_check_overlay_range(struct tty *, u_int, u_int, u_int,
struct overlay_ranges *);
#ifdef ENABLE_SIXEL
static void tty_write_one(void (*)(struct tty *, const struct tty_ctx *),
struct client *, struct tty_ctx *);
#endif
#define tty_use_margin(tty) \
(tty->term->flags & TERM_DECSLRM)
#define tty_full_width(tty, ctx) \
@ -483,6 +488,11 @@ tty_update_features(struct tty *tty)
if (tty->term->flags & TERM_VT100LIKE)
tty_puts(tty, "\033[?7727h");
/* tty features might have changed since the first draw during attach.
* For example, this happens when DA responses are received.
*/
c->flags |= CLIENT_REDRAWWINDOW;
tty_invalidate(tty);
}
@ -1576,37 +1586,57 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
tty_update_mode(tty, tty->mode, s);
}
void
tty_draw_images(struct tty *tty, struct window_pane *wp, struct screen *s)
#ifdef ENABLE_SIXEL
/* Update context for client. */
static int
tty_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
{
struct window_pane *wp = ttyctx->arg;
if (c->session->curw->window != wp->window)
return (0);
if (wp->layout_cell == NULL)
return (0);
/* Set the properties relevant to the current client. */
ttyctx->bigger = tty_window_offset(&c->tty, &ttyctx->wox, &ttyctx->woy,
&ttyctx->wsx, &ttyctx->wsy);
ttyctx->yoff = ttyctx->ryoff = wp->yoff;
if (status_at_line(c) == 0)
ttyctx->yoff += status_line_size(c);
return (1);
}
void
tty_draw_images(struct client *c, struct window_pane *wp, struct screen *s)
{
#if 0 /* XXX */
struct client *c = tty->client;
struct image *im;
struct tty_ctx ttyctx;
TAILQ_FOREACH(im, &s->images, entry) {
memset(&ttyctx, 0, sizeof ttyctx);
/* Set the client independent properties. */
ttyctx.ocx = im->px;
ttyctx.ocy = im->py;
ttyctx.orlower = s->rlower;
ttyctx.orupper = s->rupper;
ttyctx.bigger = tty_window_offset(&c->tty, &ttyctx.ox,
&ttyctx.oy, &ttyctx.sx, &ttyctx.sy);
ttyctx.xoff = ttyctx.rxoff = wp->xoff;
ttyctx.sx = wp->sx;
ttyctx.sy = wp->sy;
ttyctx.xoff = wp->xoff;
ttyctx.yoff = wp->yoff;
if (status_at_line(c) == 0)
ttyctx.yoff += status_line_size(c);
ttyctx.ptr = im->data;
tty_cmd_sixelimage(tty, &ttyctx);
ttyctx.ptr = im;
ttyctx.arg = wp;
ttyctx.set_client_cb = tty_set_client_cb;
ttyctx.allow_invisible_panes = 1;
tty_write_one(tty_cmd_sixelimage, c, &ttyctx);
}
#endif
}
#endif
void
tty_sync_start(struct tty *tty)
@ -1681,6 +1711,19 @@ tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *),
}
}
#ifdef ENABLE_SIXEL
/* Only write to the incoming tty instead of every client. */
static void
tty_write_one(void (*cmdfn)(struct tty *, const struct tty_ctx *),
struct client *c, struct tty_ctx *ctx)
{
if (ctx->set_client_cb == NULL)
return;
if ((ctx->set_client_cb(ctx, c)) == 1)
cmdfn(&c->tty, ctx);
}
#endif
void
tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx)
{
@ -2182,21 +2225,24 @@ tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx)
tty_invalidate(tty);
}
#ifdef ENABLE_SIXEL
void
tty_cmd_sixelimage(struct tty *tty, const struct tty_ctx *ctx)
{
struct sixel_image *si = ctx->ptr;
struct image *im = ctx->ptr;
struct sixel_image *si = im->data;
struct sixel_image *new;
char *data;
size_t size;
u_int cx = ctx->ocx, cy = ctx->ocy, sx, sy;
u_int i, j, x, y, rx, ry;
int fallback = 0;
if ((~tty->term->flags & TERM_SIXEL) &&
!tty_term_has(tty->term, TTYC_SXL))
return;
!tty_term_has(tty->term, TTYC_SXL))
fallback = 1;
if (tty->xpixel == 0 || tty->ypixel == 0)
return;
fallback = 1;
sixel_size_in_cells(si, &sx, &sy);
log_debug("%s: image is %ux%u", __func__, sx, sy);
@ -2204,11 +2250,16 @@ tty_cmd_sixelimage(struct tty *tty, const struct tty_ctx *ctx)
return;
log_debug("%s: clamping to %u,%u-%u,%u", __func__, i, j, rx, ry);
new = sixel_scale(si, tty->xpixel, tty->ypixel, i, j, rx, ry, 0);
if (new == NULL)
return;
if (fallback == 1) {
data = xstrdup(im->fallback);
size = strlen(data);
} else {
new = sixel_scale(si, tty->xpixel, tty->ypixel, i, j, rx, ry, 0);
if (new == NULL)
return;
data = sixel_print(new, si, &size);
data = sixel_print(new, si, &size);
}
if (data != NULL) {
log_debug("%s: %zu bytes: %s", __func__, size, data);
tty_region_off(tty);
@ -2220,8 +2271,11 @@ tty_cmd_sixelimage(struct tty *tty, const struct tty_ctx *ctx)
tty_invalidate(tty);
free(data);
}
sixel_free(new);
if (fallback == 0)
sixel_free(new);
}
#endif
void
tty_cmd_syncstart(struct tty *tty, const struct tty_ctx *ctx)