diff --git a/Makefile.am b/Makefile.am index 874e51a4..829a9ef9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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) diff --git a/configure.ac b/configure.ac index b09dfbbd..4d85624d 100644 --- a/configure.ac +++ b/configure.ac @@ -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( diff --git a/sixel.c b/image-sixel.c similarity index 98% rename from sixel.c rename to image-sixel.c index ad8f70df..f4492d95 100644 --- a/sixel.c +++ b/image-sixel.c @@ -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; diff --git a/image.c b/image.c index e8f274d0..7135c6a3 100644 --- a/image.c +++ b/image.c @@ -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 diff --git a/input.c b/input.c index e018c053..d32dfd67 100644 --- a/input.c +++ b/input.c @@ -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); } diff --git a/screen-redraw.c b/screen-redraw.c index 06ed8990..ce79b41f 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -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 } diff --git a/screen-write.c b/screen-write.c index 99e63ae9..91750d93 100644 --- a/screen-write.c +++ b/screen-write.c @@ -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 diff --git a/screen.c b/screen.c index 2ee86b0f..a51b17bd 100644 --- a/screen.c +++ b/screen.c @@ -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); } diff --git a/tmux.1 b/tmux.1 index 7bf2bc4d..5cd90d88 100644 --- a/tmux.1 +++ b/tmux.1 @@ -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 diff --git a/tmux.h b/tmux.h index f75e9edf..602bbd89 100644 --- a/tmux.h +++ b/tmux.h @@ -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); diff --git a/tty-keys.c b/tty-keys.c index 2801914f..25956c4d 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -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. diff --git a/tty.c b/tty.c index 4c5c43b3..a602a950 100644 --- a/tty.c +++ b/tty.c @@ -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)