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

View File

@ -449,6 +449,16 @@ if test "x$enable_cgroups" = xyes; then
fi fi
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. # Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well.
AC_MSG_CHECKING(for b64_ntop) AC_MSG_CHECKING(for b64_ntop)
AC_LINK_IFELSE([AC_LANG_PROGRAM( 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; const char *last;
char *endptr; char *endptr;
u_int d, x, y; u_int x, y;
last = cp; last = cp;
while (last != end) { while (last != end) {
@ -134,10 +134,10 @@ sixel_parse_attributes(struct sixel_image *si, const char *cp, const char *end)
break; break;
last++; last++;
} }
d = strtoul(cp, &endptr, 10); strtoul(cp, &endptr, 10);
if (endptr == last || *endptr != ';') if (endptr == last || *endptr != ';')
return (last); return (last);
d = strtoul(endptr + 1, &endptr, 10); strtoul(endptr + 1, &endptr, 10);
if (endptr == last || *endptr != ';') if (endptr == last || *endptr != ';')
return (NULL); return (NULL);
@ -442,7 +442,7 @@ sixel_print_repeat(char **buf, size_t *len, size_t *used, u_int count, char ch)
char * char *
sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size) 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; size_t len, used = 0, tmplen;
u_int *colours, ncolours, i, c, x, y, count; u_int *colours, ncolours, i, c, x, y, count;
struct sixel_line *sl; struct sixel_line *sl;

View File

@ -34,6 +34,8 @@ image_free(struct image *im)
all_images_count--; all_images_count--;
TAILQ_REMOVE(&s->images, im, entry); TAILQ_REMOVE(&s->images, im, entry);
sixel_free(im->data);
free(im->fallback);
free(im); free(im);
} }
@ -48,7 +50,7 @@ image_free_all(struct screen *s)
return (redraw); return (redraw);
} }
void struct image*
image_store(struct screen *s, struct sixel_image *si) image_store(struct screen *s, struct sixel_image *si)
{ {
struct image *im; struct image *im;
@ -61,11 +63,16 @@ image_store(struct screen *s, struct sixel_image *si)
im->py = s->cy; im->py = s->cy;
sixel_size_in_cells(si, &im->sx, &im->sy); 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(&s->images, im, entry);
TAILQ_INSERT_TAIL(&all_images, im, all_entry); TAILQ_INSERT_TAIL(&all_images, im, all_entry);
if (++all_images_count == 10/*XXX*/) if (++all_images_count == 10/*XXX*/)
image_free(TAILQ_FIRST(&all_images)); image_free(TAILQ_FIRST(&all_images));
return (im);
} }
int int

13
input.c
View File

@ -1442,7 +1442,11 @@ input_csi_dispatch(struct input_ctx *ictx)
case -1: case -1:
break; break;
case 0: case 0:
#ifdef ENABLE_SIXEL
input_reply(ictx, "\033[?1;2;4c");
#else
input_reply(ictx, "\033[?1;2c"); input_reply(ictx, "\033[?1;2c");
#endif
break; break;
default: default:
log_debug("%s: unknown '%c'", __func__, ictx->ch); 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 window_pane *wp = ictx->wp;
struct screen_write_ctx *sctx = &ictx->ctx; struct screen_write_ctx *sctx = &ictx->ctx;
struct window *w = wp->window;
u_char *buf = ictx->input_buf; u_char *buf = ictx->input_buf;
size_t len = ictx->input_len; size_t len = ictx->input_len;
const char prefix[] = "tmux;"; const char prefix[] = "tmux;";
const u_int prefixlen = (sizeof prefix) - 1; const u_int prefixlen = (sizeof prefix) - 1;
struct sixel_image *si;
long long allow_passthrough = 0; long long allow_passthrough = 0;
#ifdef ENABLE_SIXEL
struct window *w = wp->window;
struct sixel_image *si;
#endif
if (wp == NULL) if (wp == NULL)
return (0); return (0);
if (ictx->flags & INPUT_DISCARD) if (ictx->flags & INPUT_DISCARD)
return (0); return (0);
#ifdef ENABLE_SIXEL
if (buf[0] == 'q') { if (buf[0] == 'q') {
si = sixel_parse(buf, len, w->xpixel, w->ypixel); si = sixel_parse(buf, len, w->xpixel, w->ypixel);
if (si != NULL) { if (si != NULL) {
@ -2257,6 +2264,7 @@ input_dcs_dispatch(struct input_ctx *ictx)
screen_write_sixelimage(sctx, si, ictx->cell.cell.bg); screen_write_sixelimage(sctx, si, ictx->cell.cell.bg);
} }
} }
#endif
allow_passthrough = options_get_number(wp->options, "allow-passthrough"); allow_passthrough = options_get_number(wp->options, "allow-passthrough");
if (!allow_passthrough) if (!allow_passthrough)
@ -2267,6 +2275,7 @@ input_dcs_dispatch(struct input_ctx *ictx)
screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen, screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen,
allow_passthrough == 2); allow_passthrough == 2);
} }
return (0); 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_default_colours(&defaults, wp);
tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette); 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); memcpy(&gc, &grid_default_cell, sizeof gc);
utf8_set(&gc.data, 'E'); utf8_set(&gc.data, 'E');
#ifdef ENABLE_SIXEL
if (image_free_all(s) && ctx->wp != NULL) if (image_free_all(s) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
for (yy = 0; yy < screen_size_y(s); yy++) { for (yy = 0; yy < screen_size_y(s); yy++) {
for (xx = 0; xx < screen_size_x(s); xx++) 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) if (s->cx > screen_size_x(s) - 1)
return; return;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL) if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.bg = bg; 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) if (s->cx > screen_size_x(s) - 1)
return; return;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL) if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.bg = bg; 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) if (s->cx > screen_size_x(s) - 1)
return; return;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL) if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.bg = bg; 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 screen *s = ctx->s;
struct grid *gd = s->grid; struct grid *gd = s->grid;
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
#ifdef ENABLE_SIXEL
u_int sy = screen_size_y(s); u_int sy = screen_size_y(s);
#endif
if (ny == 0) if (ny == 0)
ny = 1; ny = 1;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL) if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
if (s->cy < s->rupper || s->cy > s->rlower) { if (s->cy < s->rupper || s->cy > s->rlower) {
if (ny > screen_size_y(s) - s->cy) 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) if (ny == 0)
ny = 1; ny = 1;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL) if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
if (s->cy < s->rupper || s->cy > s->rlower) { if (s->cy < s->rupper || s->cy > s->rlower) {
if (ny > sy - s->cy) 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)) if (gl->cellsize == 0 && COLOUR_DEFAULT(bg))
return; return;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL) if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); 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))) if (s->cx > sx - 1 || (s->cx >= gl->cellsize && COLOUR_DEFAULT(bg)))
return; return;
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL) if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg); 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; return;
} }
#ifdef ENABLE_SIXEL
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL) if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
if (s->cx > sx - 1) if (s->cx > sx - 1)
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); 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 screen *s = ctx->s;
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
#ifdef ENABLE_SIXEL
if (image_free_all(s) && ctx->wp != NULL) if (image_free_all(s) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
if (s->cy == s->rupper) { if (s->cy == s->rupper) {
grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg); 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 screen *s = ctx->s;
struct grid *gd = s->grid; struct grid *gd = s->grid;
struct grid_line *gl; struct grid_line *gl;
int redraw; int redraw = 0;
u_int rupper = s->rupper, rlower = s->rlower; u_int rupper = s->rupper, rlower = s->rlower;
gl = grid_get_line(gd, gd->hsize + s->cy); 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) { if (s->cy == s->rlower) {
#ifdef ENABLE_SIXEL
if (rlower == screen_size_y(s) - 1) if (rlower == screen_size_y(s) - 1)
redraw = image_scroll_up(s, 1); redraw = image_scroll_up(s, 1);
else else
redraw = image_check_line(s, rupper, rlower - rupper); redraw = image_check_line(s, rupper, rlower - rupper);
#endif
if (redraw && ctx->wp != NULL) if (redraw && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); 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; ctx->bg = bg;
} }
#ifdef ENABLE_SIXEL
if (image_scroll_up(s, lines) && ctx->wp != NULL) if (image_scroll_up(s, lines) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
for (i = 0; i < lines; i++) { for (i = 0; i < lines; i++) {
grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); 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) else if (lines > s->rlower - s->rupper + 1)
lines = s->rlower - s->rupper + 1; lines = s->rlower - s->rupper + 1;
#ifdef ENABLE_SIXEL
if (image_free_all(s) && ctx->wp != NULL) if (image_free_all(s) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
for (i = 0; i < lines; i++) for (i = 0; i < lines; i++)
grid_view_scroll_region_down(gd, s->rupper, s->rlower, bg); 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; struct tty_ctx ttyctx;
u_int sx = screen_size_x(s), sy = screen_size_y(s); 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) if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
screen_write_initctx(ctx, &ttyctx, 1); screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg; ttyctx.bg = bg;
@ -1507,8 +1538,10 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
u_int sx = screen_size_x(s); u_int sx = screen_size_x(s);
#ifdef ENABLE_SIXEL
if (image_check_line(s, 0, s->cy - 1) && ctx->wp != NULL) if (image_check_line(s, 0, s->cy - 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
screen_write_initctx(ctx, &ttyctx, 1); screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg; ttyctx.bg = bg;
@ -1533,8 +1566,10 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
u_int sx = screen_size_x(s), sy = screen_size_y(s); u_int sx = screen_size_x(s), sy = screen_size_y(s);
#ifdef ENABLE_SIXEL
if (image_free_all(s) && ctx->wp != NULL) if (image_free_all(s) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
screen_write_initctx(ctx, &ttyctx, 1); screen_write_initctx(ctx, &ttyctx, 1);
ttyctx.bg = bg; 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) if (image_check_area(s, s->cx, s->cy, ci->used, 1) && ctx->wp != NULL)
ctx->wp->flags |= PANE_REDRAW; ctx->wp->flags |= PANE_REDRAW;
#endif
grid_view_set_cells(s->grid, s->cx, s->cy, &ci->gc, cl->data + ci->x, grid_view_set_cells(s->grid, s->cx, s->cy, &ci->gc, cl->data + ci->x,
ci->used); 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); tty_write(tty_cmd_rawstring, &ttyctx);
} }
#ifdef ENABLE_SIXEL
/* Write a SIXEL image. */ /* Write a SIXEL image. */
void void
screen_write_sixelimage(struct screen_write_ctx *ctx, struct sixel_image *si, 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__); screen_write_collect_flush(ctx, 0, __func__);
image_store(s, si);
screen_write_initctx(ctx, &ttyctx, 0); screen_write_initctx(ctx, &ttyctx, 0);
ttyctx.ptr = si; ttyctx.ptr = image_store(s, si);
tty_write(tty_cmd_sixelimage, &ttyctx); tty_write(tty_cmd_sixelimage, &ttyctx);
screen_write_cursormove(ctx, 0, cy + y, 0); screen_write_cursormove(ctx, 0, cy + y, 0);
} }
#endif
/* Turn alternate screen on. */ /* Turn alternate screen on. */
void 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->tabs = NULL;
s->sel = NULL; s->sel = NULL;
#ifdef ENABLE_SIXEL
TAILQ_INIT(&s->images); TAILQ_INIT(&s->images);
#endif
s->write_list = NULL; s->write_list = NULL;
s->hyperlinks = NULL; s->hyperlinks = NULL;
@ -120,7 +123,11 @@ screen_reinit(struct screen *s)
screen_clear_selection(s); screen_clear_selection(s);
screen_free_titles(s); screen_free_titles(s);
#ifdef ENABLE_SIXEL
image_free_all(s); image_free_all(s);
#endif
screen_reset_hyperlinks(s); screen_reset_hyperlinks(s);
} }
@ -153,7 +160,10 @@ screen_free(struct screen *s)
if (s->hyperlinks != NULL) if (s->hyperlinks != NULL)
hyperlinks_free(s->hyperlinks); hyperlinks_free(s->hyperlinks);
screen_free_titles(s); screen_free_titles(s);
#ifdef ENABLE_SIXEL
image_free_all(s); image_free_all(s);
#endif
} }
/* Reset tabs to default, eight spaces apart. */ /* 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); screen_resize_y(s, sy, eat_empty, &cy);
if (reflow) { if (reflow) {
#ifdef ENABLE_SIXEL
image_free_all(s); image_free_all(s);
#endif
screen_reflow(s, sx, &cx, &cy, cursor); screen_reflow(s, sx, &cx, &cy, cursor);
} }

2
tmux.1
View File

@ -21,7 +21,7 @@
.Nm tmux .Nm tmux
.Nd terminal multiplexer .Nd terminal multiplexer
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm tmux .Nm
.Bk -words .Bk -words
.Op Fl 2CDlNuVv .Op Fl 2CDlNuVv
.Op Fl c Ar shell-command .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_cline;
struct screen_write_ctx; struct screen_write_ctx;
struct session; struct session;
#ifdef ENABLE_SIXEL
struct sixel_image; struct sixel_image;
#endif
struct tty_ctx; struct tty_ctx;
struct tty_code; struct tty_code;
struct tty_key; struct tty_key;
@ -833,10 +837,12 @@ struct style {
enum style_default_type default_type; enum style_default_type default_type;
}; };
#ifdef ENABLE_SIXEL
/* Image. */ /* Image. */
struct image { struct image {
struct screen *s; struct screen *s;
struct sixel_image *data; struct sixel_image *data;
char *fallback;
u_int px; u_int px;
u_int py; u_int py;
@ -847,6 +853,7 @@ struct image {
TAILQ_ENTRY (image) entry; TAILQ_ENTRY (image) entry;
}; };
TAILQ_HEAD(images, image); TAILQ_HEAD(images, image);
#endif
/* Cursor style. */ /* Cursor style. */
enum screen_cursor_style { enum screen_cursor_style {
@ -888,7 +895,10 @@ struct screen {
bitstr_t *tabs; bitstr_t *tabs;
struct screen_sel *sel; struct screen_sel *sel;
#ifdef ENABLE_SIXEL
struct images images; struct images images;
#endif
struct screen_write_cline *write_list; struct screen_write_cline *write_list;
@ -1390,6 +1400,7 @@ struct tty {
u_int sx; u_int sx;
u_int sy; u_int sy;
/* Cell size in pixels. */
u_int xpixel; u_int xpixel;
u_int ypixel; u_int ypixel;
@ -1398,6 +1409,8 @@ struct tty {
enum screen_cursor_style cstyle; enum screen_cursor_style cstyle;
int ccolour; int ccolour;
/* Properties of the area being drawn on. */
/* When true, the drawing area is bigger than the terminal. */
int oflag; int oflag;
u_int oox; u_int oox;
u_int ooy; 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_update_mode(struct tty *, int, struct screen *);
void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int, 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 *); 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_start(struct tty *);
void tty_sync_end(struct tty *); void tty_sync_end(struct tty *);
int tty_open(struct tty *, char **); 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_reverseindex(struct tty *, const struct tty_ctx *);
void tty_cmd_setselection(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 *); void tty_cmd_rawstring(struct tty *, const struct tty_ctx *);
#ifdef ENABLE_SIXEL
void tty_cmd_sixelimage(struct tty *, const struct tty_ctx *); void tty_cmd_sixelimage(struct tty *, const struct tty_ctx *);
#endif
void tty_cmd_syncstart(struct tty *, const struct tty_ctx *); void tty_cmd_syncstart(struct tty *, const struct tty_ctx *);
void tty_default_colours(struct grid_cell *, struct window_pane *); 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); u_char *, u_int);
void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int, void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int,
int); int);
#ifdef ENABLE_SIXEL
void screen_write_sixelimage(struct screen_write_ctx *, void screen_write_sixelimage(struct screen_write_ctx *,
struct sixel_image *, u_int); struct sixel_image *, u_int);
#endif
void screen_write_alternateon(struct screen_write_ctx *, void screen_write_alternateon(struct screen_write_ctx *,
struct grid_cell *, int); struct grid_cell *, int);
void screen_write_alternateoff(struct screen_write_ctx *, void screen_write_alternateoff(struct screen_write_ctx *,
@ -3370,14 +3393,15 @@ struct window_pane *spawn_pane(struct spawn_context *, char **);
/* regsub.c */ /* regsub.c */
char *regsub(const char *, const char *, const char *, int); char *regsub(const char *, const char *, const char *, int);
#ifdef ENABLE_SIXEL
/* image.c */ /* image.c */
int image_free_all(struct screen *); 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_line(struct screen *, u_int, u_int);
int image_check_area(struct screen *, u_int, u_int, 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); 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); struct sixel_image *sixel_parse(const char *, size_t, u_int, u_int);
void sixel_free(struct sixel_image *); void sixel_free(struct sixel_image *);
void sixel_log(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 *, char *sixel_print(struct sixel_image *, struct sixel_image *,
size_t *); size_t *);
struct screen *sixel_to_screen(struct sixel_image *); struct screen *sixel_to_screen(struct sixel_image *);
#endif
/* server-acl.c */ /* server-acl.c */
void server_acl_init(void); 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); 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 * Handle primary device attributes input. Returns 0 for success, -1 for
* failure, 1 for partial. * 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, static void tty_check_overlay_range(struct tty *, u_int, u_int, u_int,
struct overlay_ranges *); 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) \ #define tty_use_margin(tty) \
(tty->term->flags & TERM_DECSLRM) (tty->term->flags & TERM_DECSLRM)
#define tty_full_width(tty, ctx) \ #define tty_full_width(tty, ctx) \
@ -483,6 +488,11 @@ tty_update_features(struct tty *tty)
if (tty->term->flags & TERM_VT100LIKE) if (tty->term->flags & TERM_VT100LIKE)
tty_puts(tty, "\033[?7727h"); 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); 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); tty_update_mode(tty, tty->mode, s);
} }
void #ifdef ENABLE_SIXEL
tty_draw_images(struct tty *tty, struct window_pane *wp, struct screen *s) /* 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 image *im;
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
TAILQ_FOREACH(im, &s->images, entry) { TAILQ_FOREACH(im, &s->images, entry) {
memset(&ttyctx, 0, sizeof ttyctx); memset(&ttyctx, 0, sizeof ttyctx);
/* Set the client independent properties. */
ttyctx.ocx = im->px; ttyctx.ocx = im->px;
ttyctx.ocy = im->py; ttyctx.ocy = im->py;
ttyctx.orlower = s->rlower; ttyctx.orlower = s->rlower;
ttyctx.orupper = s->rupper; ttyctx.orupper = s->rupper;
ttyctx.bigger = tty_window_offset(&c->tty, &ttyctx.ox, ttyctx.xoff = ttyctx.rxoff = wp->xoff;
&ttyctx.oy, &ttyctx.sx, &ttyctx.sy); ttyctx.sx = wp->sx;
ttyctx.sy = wp->sy;
ttyctx.xoff = wp->xoff; ttyctx.ptr = im;
ttyctx.yoff = wp->yoff; ttyctx.arg = wp;
ttyctx.set_client_cb = tty_set_client_cb;
if (status_at_line(c) == 0) ttyctx.allow_invisible_panes = 1;
ttyctx.yoff += status_line_size(c); tty_write_one(tty_cmd_sixelimage, c, &ttyctx);
ttyctx.ptr = im->data;
tty_cmd_sixelimage(tty, &ttyctx);
} }
#endif
} }
#endif
void void
tty_sync_start(struct tty *tty) 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 void
tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) 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); tty_invalidate(tty);
} }
#ifdef ENABLE_SIXEL
void void
tty_cmd_sixelimage(struct tty *tty, const struct tty_ctx *ctx) 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; struct sixel_image *new;
char *data; char *data;
size_t size; size_t size;
u_int cx = ctx->ocx, cy = ctx->ocy, sx, sy; u_int cx = ctx->ocx, cy = ctx->ocy, sx, sy;
u_int i, j, x, y, rx, ry; u_int i, j, x, y, rx, ry;
int fallback = 0;
if ((~tty->term->flags & TERM_SIXEL) && if ((~tty->term->flags & TERM_SIXEL) &&
!tty_term_has(tty->term, TTYC_SXL)) !tty_term_has(tty->term, TTYC_SXL))
return; fallback = 1;
if (tty->xpixel == 0 || tty->ypixel == 0) if (tty->xpixel == 0 || tty->ypixel == 0)
return; fallback = 1;
sixel_size_in_cells(si, &sx, &sy); sixel_size_in_cells(si, &sx, &sy);
log_debug("%s: image is %ux%u", __func__, 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; return;
log_debug("%s: clamping to %u,%u-%u,%u", __func__, i, j, rx, ry); 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 (fallback == 1) {
if (new == NULL) data = xstrdup(im->fallback);
return; 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) { if (data != NULL) {
log_debug("%s: %zu bytes: %s", __func__, size, data); log_debug("%s: %zu bytes: %s", __func__, size, data);
tty_region_off(tty); tty_region_off(tty);
@ -2220,8 +2271,11 @@ tty_cmd_sixelimage(struct tty *tty, const struct tty_ctx *ctx)
tty_invalidate(tty); tty_invalidate(tty);
free(data); free(data);
} }
sixel_free(new);
if (fallback == 0)
sixel_free(new);
} }
#endif
void void
tty_cmd_syncstart(struct tty *tty, const struct tty_ctx *ctx) tty_cmd_syncstart(struct tty *tty, const struct tty_ctx *ctx)