mirror of
https://github.com/tmux/tmux.git
synced 2026-03-07 08:15:36 +00:00
Feedback from nicm
This commit is contained in:
@@ -469,9 +469,8 @@ AC_ARG_ENABLE(
|
|||||||
|
|
||||||
AC_ARG_ENABLE(
|
AC_ARG_ENABLE(
|
||||||
sixel,
|
sixel,
|
||||||
AS_HELP_STRING(--enable-sixel, deprecated; use --enable-sixel-images),
|
AS_HELP_STRING(--enable-sixel support),
|
||||||
[
|
[
|
||||||
AC_MSG_WARN([--enable-sixel is deprecated; use --enable-sixel-images])
|
|
||||||
enable_sixel_images="$enableval"
|
enable_sixel_images="$enableval"
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
11
format.c
11
format.c
@@ -2566,16 +2566,13 @@ format_cb_image_support(__unused struct format_tree *ft)
|
|||||||
{
|
{
|
||||||
#if defined(ENABLE_SIXEL_IMAGES) && defined(ENABLE_KITTY_IMAGES)
|
#if defined(ENABLE_SIXEL_IMAGES) && defined(ENABLE_KITTY_IMAGES)
|
||||||
return (xstrdup("kitty,sixel"));
|
return (xstrdup("kitty,sixel"));
|
||||||
#endif
|
#elif defined(ENABLE_SIXEL_IMAGES)
|
||||||
|
|
||||||
#ifdef ENABLE_SIXEL_IMAGES
|
|
||||||
return (xstrdup("sixel"));
|
return (xstrdup("sixel"));
|
||||||
#endif
|
#elif defined(ENABLE_KITTY_IMAGES)
|
||||||
|
|
||||||
#ifdef ENABLE_KITTY_IMAGES
|
|
||||||
return (xstrdup("kitty"));
|
return (xstrdup("kitty"));
|
||||||
#endif
|
#else
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Callback for active_window_index. */
|
/* Callback for active_window_index. */
|
||||||
|
|||||||
@@ -23,6 +23,41 @@
|
|||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kitty_image stores the raw decoded pixel data and metadata from a kitty
|
||||||
|
* graphics protocol APC sequence. It is used to re-emit the sequence to the
|
||||||
|
* outer terminal on redraw.
|
||||||
|
*/
|
||||||
|
struct kitty_image {
|
||||||
|
/* Control-data fields parsed from the APC sequence. */
|
||||||
|
char action; /* a=: 'T'=transmit+display, 't', 'p', 'd' */
|
||||||
|
u_int format; /* f=: 32=RGBA, 24=RGB, 100=PNG */
|
||||||
|
char medium; /* t=: 'd'=direct, 'f'=file, 't'=tmp, 's'=shm */
|
||||||
|
u_int pixel_w; /* s=: source image pixel width */
|
||||||
|
u_int pixel_h; /* v=: source image pixel height */
|
||||||
|
u_int cols; /* c=: display columns (0=auto) */
|
||||||
|
u_int rows; /* r=: display rows (0=auto) */
|
||||||
|
u_int image_id; /* i=: image id (0=unassigned) */
|
||||||
|
u_int image_num; /* I=: image number */
|
||||||
|
u_int placement_id; /* p=: placement id */
|
||||||
|
u_int more; /* m=: 1=more chunks coming, 0=last */
|
||||||
|
u_int quiet; /* q=: suppress responses */
|
||||||
|
int z_index; /* z=: z-index */
|
||||||
|
char compression; /* o=: 'z'=zlib, 0=none */
|
||||||
|
char delete_what; /* d=: delete target (used with a=d) */
|
||||||
|
|
||||||
|
/* Cell size at the time of parsing (from the owning window). */
|
||||||
|
u_int xpixel;
|
||||||
|
u_int ypixel;
|
||||||
|
|
||||||
|
/* Original base64-encoded payload (concatenated across all chunks). */
|
||||||
|
char *encoded;
|
||||||
|
size_t encodedlen;
|
||||||
|
|
||||||
|
char *ctrl;
|
||||||
|
size_t ctrllen;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse control-data key=value pairs from a kitty APC sequence.
|
* Parse control-data key=value pairs from a kitty APC sequence.
|
||||||
* Format: key=value,key=value,...
|
* Format: key=value,key=value,...
|
||||||
@@ -190,6 +225,52 @@ kitty_free(struct kitty_image *ki)
|
|||||||
free(ki);
|
free(ki);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the size in cells of a kitty image. If cols/rows are 0 (auto),
|
||||||
|
* calculate from pixel dimensions. Returns size via sx/sy pointers.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
kitty_size_in_cells(struct kitty_image *ki, u_int *sx, u_int *sy)
|
||||||
|
{
|
||||||
|
*sx = ki->cols;
|
||||||
|
*sy = ki->rows;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If cols/rows are 0, they mean "auto" - calculate from
|
||||||
|
* pixel dimensions.
|
||||||
|
*/
|
||||||
|
if (*sx == 0 && ki->pixel_w > 0 && ki->xpixel > 0) {
|
||||||
|
*sx = (ki->pixel_w + ki->xpixel - 1) / ki->xpixel;
|
||||||
|
}
|
||||||
|
if (*sy == 0 && ki->pixel_h > 0 && ki->ypixel > 0) {
|
||||||
|
*sy = (ki->pixel_h + ki->ypixel - 1) / ki->ypixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If still 0, use a reasonable default */
|
||||||
|
if (*sx == 0)
|
||||||
|
*sx = 10;
|
||||||
|
if (*sy == 0)
|
||||||
|
*sy = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
char
|
||||||
|
kitty_get_action(struct kitty_image *ki)
|
||||||
|
{
|
||||||
|
return (ki->action);
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int
|
||||||
|
kitty_get_image_id(struct kitty_image *ki)
|
||||||
|
{
|
||||||
|
return (ki->image_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int
|
||||||
|
kitty_get_rows(struct kitty_image *ki)
|
||||||
|
{
|
||||||
|
return (ki->rows);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Serialize a kitty_image back into an APC escape sequence for transmission
|
* Serialize a kitty_image back into an APC escape sequence for transmission
|
||||||
* to the terminal. This recreates the original command that was parsed.
|
* to the terminal. This recreates the original command that was parsed.
|
||||||
@@ -238,9 +319,7 @@ kitty_delete_all(size_t *outlen)
|
|||||||
{
|
{
|
||||||
char *out;
|
char *out;
|
||||||
|
|
||||||
*outlen = 3 + 7 + 2;
|
out = xstrdup("\033_Ga=d,d=a\033\\");
|
||||||
out = xmalloc(*outlen + 1);
|
*outlen = strlen(out);
|
||||||
memcpy(out, "\033_Ga=d,d=a\033\\", *outlen);
|
|
||||||
out[*outlen] = '\0';
|
|
||||||
return (out);
|
return (out);
|
||||||
}
|
}
|
||||||
|
|||||||
33
image.c
33
image.c
@@ -176,33 +176,7 @@ image_store(struct screen *s, enum image_type type, void *data)
|
|||||||
#ifdef ENABLE_KITTY_IMAGES
|
#ifdef ENABLE_KITTY_IMAGES
|
||||||
case IMAGE_KITTY:
|
case IMAGE_KITTY:
|
||||||
im->data.kitty = data;
|
im->data.kitty = data;
|
||||||
|
kitty_size_in_cells(im->data.kitty, &im->sx, &im->sy);
|
||||||
/* Kitty images have size info in the structure */
|
|
||||||
im->sx = im->data.kitty->cols;
|
|
||||||
im->sy = im->data.kitty->rows;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If cols/rows are 0, they mean "auto" - calculate from
|
|
||||||
* pixel dimensions. The terminal will figure out the actual
|
|
||||||
* size, but we need a reasonable estimate for our cache.
|
|
||||||
*/
|
|
||||||
if (im->sx == 0 && im->data.kitty->pixel_w > 0 &&
|
|
||||||
im->data.kitty->xpixel > 0) {
|
|
||||||
im->sx = (im->data.kitty->pixel_w +
|
|
||||||
im->data.kitty->xpixel - 1) /
|
|
||||||
im->data.kitty->xpixel;
|
|
||||||
}
|
|
||||||
if (im->sy == 0 && im->data.kitty->pixel_h > 0 &&
|
|
||||||
im->data.kitty->ypixel > 0) {
|
|
||||||
im->sy = (im->data.kitty->pixel_h +
|
|
||||||
im->data.kitty->ypixel - 1) / im->data.kitty->ypixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If still 0, use a reasonable default */
|
|
||||||
if (im->sx == 0)
|
|
||||||
im->sx = 10;
|
|
||||||
if (im->sy == 0)
|
|
||||||
im->sy = 10;
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
@@ -288,7 +262,7 @@ image_scroll_up(struct screen *s, u_int lines)
|
|||||||
case IMAGE_SIXEL:
|
case IMAGE_SIXEL:
|
||||||
sx = im->sx;
|
sx = im->sx;
|
||||||
sy = (im->py + im->sy) - lines;
|
sy = (im->py + im->sy) - lines;
|
||||||
image_log(im, __func__, "3 sixel, lines=%u, sy=%u",
|
image_log(im, __func__, "sixel, lines=%u, sy=%u",
|
||||||
lines, sy);
|
lines, sy);
|
||||||
|
|
||||||
new = sixel_scale(im->data.sixel, 0, 0, 0, im->sy - sy,
|
new = sixel_scale(im->data.sixel, 0, 0, 0, im->sy - sy,
|
||||||
@@ -311,10 +285,7 @@ image_scroll_up(struct screen *s, u_int lines)
|
|||||||
* owns the placement. Just adjust position and let
|
* owns the placement. Just adjust position and let
|
||||||
* the terminal handle clipping.
|
* the terminal handle clipping.
|
||||||
*/
|
*/
|
||||||
image_log(im, __func__,
|
|
||||||
"3 kitty, lines=%u (no rescale)", lines);
|
|
||||||
im->py = 0;
|
im->py = 0;
|
||||||
/* Height remains the same - terminal will clip */
|
|
||||||
redraw = 1;
|
redraw = 1;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
158
input.c
158
input.c
@@ -181,6 +181,7 @@ static void input_ground(struct input_ctx *);
|
|||||||
static void input_enter_dcs(struct input_ctx *);
|
static void input_enter_dcs(struct input_ctx *);
|
||||||
static void input_enter_osc(struct input_ctx *);
|
static void input_enter_osc(struct input_ctx *);
|
||||||
static void input_exit_osc(struct input_ctx *);
|
static void input_exit_osc(struct input_ctx *);
|
||||||
|
static int input_da1_has_sixel(struct input_ctx *);
|
||||||
static void input_enter_apc(struct input_ctx *);
|
static void input_enter_apc(struct input_ctx *);
|
||||||
static void input_exit_apc(struct input_ctx *);
|
static void input_exit_apc(struct input_ctx *);
|
||||||
static void input_enter_rename(struct input_ctx *);
|
static void input_enter_rename(struct input_ctx *);
|
||||||
@@ -1561,31 +1562,11 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
case -1:
|
case -1:
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
{
|
if (input_da1_has_sixel(ictx))
|
||||||
/*
|
|
||||||
* Report sixel support only if outer terminal supports it.
|
|
||||||
* This ensures applications choose the right protocol.
|
|
||||||
*/
|
|
||||||
int has_sixel = 0;
|
|
||||||
#ifdef ENABLE_SIXEL_IMAGES
|
|
||||||
if (ictx->wp != NULL) {
|
|
||||||
struct client *c;
|
|
||||||
TAILQ_FOREACH(c, &clients, entry) {
|
|
||||||
if (c->session != NULL &&
|
|
||||||
c->session->curw->window == ictx->wp->window &&
|
|
||||||
(c->tty.term->flags & TERM_SIXEL)) {
|
|
||||||
has_sixel = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (has_sixel)
|
|
||||||
input_reply(ictx, 1, "\033[?1;2;4c");
|
input_reply(ictx, 1, "\033[?1;2;4c");
|
||||||
else
|
else
|
||||||
input_reply(ictx, 1, "\033[?1;2c");
|
input_reply(ictx, 1, "\033[?1;2c");
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
@@ -2740,16 +2721,85 @@ input_enter_apc(struct input_ctx *ictx)
|
|||||||
ictx->flags &= ~INPUT_LAST;
|
ictx->flags &= ~INPUT_LAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if any client viewing this pane has an outer terminal that supports
|
||||||
|
* sixel, so we can report it in the DA1 response.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
input_da1_has_sixel(__unused struct input_ctx *ictx)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_SIXEL_IMAGES
|
||||||
|
struct window_pane *wp = ictx->wp;
|
||||||
|
struct client *c;
|
||||||
|
|
||||||
|
if (wp == NULL)
|
||||||
|
return (0);
|
||||||
|
TAILQ_FOREACH(c, &clients, entry) {
|
||||||
|
if (c->session == NULL)
|
||||||
|
continue;
|
||||||
|
if (c->session->curw->window != wp->window)
|
||||||
|
continue;
|
||||||
|
if (c->tty.term->flags & TERM_SIXEL)
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_KITTY_IMAGES
|
||||||
|
/* Handle a kitty graphics APC sequence. */
|
||||||
|
static void
|
||||||
|
input_apc_kitty_image(struct input_ctx *ictx)
|
||||||
|
{
|
||||||
|
struct screen_write_ctx *sctx = &ictx->ctx;
|
||||||
|
struct window_pane *wp = ictx->wp;
|
||||||
|
struct window *w;
|
||||||
|
struct kitty_image *ki;
|
||||||
|
|
||||||
|
if (wp == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
w = wp->window;
|
||||||
|
ki = kitty_parse(ictx->input_buf + 1, ictx->input_len - 1,
|
||||||
|
w->xpixel, w->ypixel);
|
||||||
|
if (ki == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Handle query commands. */
|
||||||
|
if (kitty_get_action(ki) == 'q') {
|
||||||
|
if (kitty_get_image_id(ki) != 0)
|
||||||
|
input_reply(ictx, 0, "\033_Gi=%u;OK\033\\",
|
||||||
|
kitty_get_image_id(ki));
|
||||||
|
else
|
||||||
|
input_reply(ictx, 0, "\033_Ga=q;OK\033\\");
|
||||||
|
kitty_free(ki);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store image placements and trigger a redraw. */
|
||||||
|
if (kitty_get_action(ki) == 'T' || kitty_get_action(ki) == 't' ||
|
||||||
|
kitty_get_action(ki) == 'p') {
|
||||||
|
screen_write_kittyimage(sctx, ki);
|
||||||
|
} else {
|
||||||
|
/* For other actions (delete, etc.), pass through. */
|
||||||
|
char *apc;
|
||||||
|
size_t apclen;
|
||||||
|
|
||||||
|
apclen = xasprintf(&apc, "\033_%s\033\\", ictx->input_buf);
|
||||||
|
tty_kitty_passthrough(wp, apc, apclen, sctx->s->cx,
|
||||||
|
sctx->s->cy);
|
||||||
|
free(apc);
|
||||||
|
kitty_free(ki);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* APC terminator (ST) received. */
|
/* APC terminator (ST) received. */
|
||||||
static void
|
static void
|
||||||
input_exit_apc(struct input_ctx *ictx)
|
input_exit_apc(struct input_ctx *ictx)
|
||||||
{
|
{
|
||||||
struct screen_write_ctx *sctx = &ictx->ctx;
|
struct screen_write_ctx *sctx = &ictx->ctx;
|
||||||
struct window_pane *wp = ictx->wp;
|
struct window_pane *wp = ictx->wp;
|
||||||
#ifdef ENABLE_KITTY_IMAGES
|
|
||||||
struct kitty_image *ki;
|
|
||||||
struct window *w;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ictx->flags & INPUT_DISCARD)
|
if (ictx->flags & INPUT_DISCARD)
|
||||||
return;
|
return;
|
||||||
@@ -2757,64 +2807,10 @@ input_exit_apc(struct input_ctx *ictx)
|
|||||||
|
|
||||||
#ifdef ENABLE_KITTY_IMAGES
|
#ifdef ENABLE_KITTY_IMAGES
|
||||||
if (ictx->input_len >= 1 && ictx->input_buf[0] == 'G') {
|
if (ictx->input_len >= 1 && ictx->input_buf[0] == 'G') {
|
||||||
if (wp == NULL)
|
input_apc_kitty_image(ictx);
|
||||||
return;
|
|
||||||
|
|
||||||
w = wp->window;
|
|
||||||
/*
|
|
||||||
* Intercept only a=q (query) to reply OK ourselves.
|
|
||||||
* Everything else — including a=T (transmit+display),
|
|
||||||
* a=d (delete), a=p (place), multi-chunk sequences —
|
|
||||||
* passes through verbatim to the outer terminal.
|
|
||||||
* The outer terminal manages all image placement and
|
|
||||||
* scrolling; tmux must not interfere.
|
|
||||||
*/
|
|
||||||
ki = kitty_parse(ictx->input_buf + 1,
|
|
||||||
ictx->input_len - 1, w->xpixel, w->ypixel);
|
|
||||||
if (ki == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Handle query commands */
|
|
||||||
if (ki->action == 'q') {
|
|
||||||
if (ki->image_id != 0)
|
|
||||||
input_reply(ictx, 0,
|
|
||||||
"\033_Gi=%u;OK\033\\",
|
|
||||||
ki->image_id);
|
|
||||||
else
|
|
||||||
input_reply(ictx, 0,
|
|
||||||
"\033_Ga=q;OK\033\\");
|
|
||||||
kitty_free(ki);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Store the image and trigger a redraw.
|
|
||||||
* Similar to sixel, we cache the image and let the
|
|
||||||
* redraw mechanism handle sending it to terminals.
|
|
||||||
*/
|
|
||||||
if (ki->action == 'T' || ki->action == 't' || ki->action == 'p') {
|
|
||||||
screen_write_kittyimage(sctx, ki);
|
|
||||||
} else {
|
|
||||||
/* For other actions (delete, etc.), pass through */
|
|
||||||
char *apc;
|
|
||||||
size_t apclen;
|
|
||||||
|
|
||||||
apclen = 2 + ictx->input_len + 2;
|
|
||||||
apc = xmalloc(apclen + 1);
|
|
||||||
apc[0] = '\033';
|
|
||||||
apc[1] = '_';
|
|
||||||
memcpy(apc + 2, ictx->input_buf, ictx->input_len);
|
|
||||||
apc[2 + ictx->input_len] = '\033';
|
|
||||||
apc[2 + ictx->input_len + 1] = '\\';
|
|
||||||
apc[apclen] = '\0';
|
|
||||||
tty_kitty_passthrough(wp, apc, apclen,
|
|
||||||
sctx->s->cx, sctx->s->cy);
|
|
||||||
free(apc);
|
|
||||||
kitty_free(ki);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif /* ENABLE_KITTY_IMAGES */
|
#endif
|
||||||
|
|
||||||
if (wp != NULL &&
|
if (wp != NULL &&
|
||||||
options_get_number(wp->options, "allow-set-title") &&
|
options_get_number(wp->options, "allow-set-title") &&
|
||||||
|
|||||||
@@ -2469,10 +2469,10 @@ screen_write_kittyimage(struct screen_write_ctx *ctx, struct kitty_image *ki)
|
|||||||
if (ki == NULL)
|
if (ki == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Store the image in the cache */
|
/* Store the image in the cache. */
|
||||||
im = image_store(s, IMAGE_KITTY, ki);
|
im = image_store(s, IMAGE_KITTY, ki);
|
||||||
|
|
||||||
/* Trigger a tty write to send to all terminals */
|
/* Trigger a tty write to send to all terminals. */
|
||||||
if (im != NULL && ctx->wp != NULL) {
|
if (im != NULL && ctx->wp != NULL) {
|
||||||
screen_write_collect_flush(ctx, 0, __func__);
|
screen_write_collect_flush(ctx, 0, __func__);
|
||||||
screen_write_initctx(ctx, &ttyctx, 0);
|
screen_write_initctx(ctx, &ttyctx, 0);
|
||||||
@@ -2484,9 +2484,9 @@ screen_write_kittyimage(struct screen_write_ctx *ctx, struct kitty_image *ki)
|
|||||||
tty_write(tty_cmd_kittyimage, &ttyctx);
|
tty_write(tty_cmd_kittyimage, &ttyctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move cursor past the image */
|
/* Move cursor past the image. */
|
||||||
if (ki->rows > 0)
|
if (kitty_get_rows(ki) > 0)
|
||||||
screen_write_cursormove(ctx, 0, s->cy + ki->rows, 0);
|
screen_write_cursormove(ctx, 0, s->cy + kitty_get_rows(ki), 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
45
tmux.h
45
tmux.h
@@ -623,7 +623,6 @@ enum tty_code_code {
|
|||||||
TTYC_SMULX,
|
TTYC_SMULX,
|
||||||
TTYC_SMXX,
|
TTYC_SMXX,
|
||||||
TTYC_SXL,
|
TTYC_SXL,
|
||||||
TTYC_KTY,
|
|
||||||
TTYC_SS,
|
TTYC_SS,
|
||||||
TTYC_SWD,
|
TTYC_SWD,
|
||||||
TTYC_SYNC,
|
TTYC_SYNC,
|
||||||
@@ -947,7 +946,9 @@ struct image {
|
|||||||
enum image_type type;
|
enum image_type type;
|
||||||
struct screen *s;
|
struct screen *s;
|
||||||
union {
|
union {
|
||||||
|
#ifdef ENABLE_SIXEL_IMAGES
|
||||||
struct sixel_image *sixel;
|
struct sixel_image *sixel;
|
||||||
|
#endif
|
||||||
#ifdef ENABLE_KITTY_IMAGES
|
#ifdef ENABLE_KITTY_IMAGES
|
||||||
struct kitty_image *kitty;
|
struct kitty_image *kitty;
|
||||||
#endif
|
#endif
|
||||||
@@ -965,44 +966,6 @@ struct image {
|
|||||||
TAILQ_HEAD(images, image);
|
TAILQ_HEAD(images, image);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_KITTY_IMAGES
|
|
||||||
/*
|
|
||||||
* kitty_image stores the raw decoded pixel data and metadata from a kitty
|
|
||||||
* graphics protocol APC sequence. It is used to re-emit the sequence to the
|
|
||||||
* outer terminal on redraw.
|
|
||||||
*/
|
|
||||||
struct kitty_image {
|
|
||||||
/* Control-data fields parsed from the APC sequence. */
|
|
||||||
char action; /* a=: 'T'=transmit+display, 't', 'p', 'd', ... */
|
|
||||||
u_int format; /* f=: 32=RGBA, 24=RGB, 100=PNG */
|
|
||||||
char medium; /* t=: 'd'=direct, 'f'=file, 't'=tmp, 's'=shm */
|
|
||||||
u_int pixel_w; /* s=: source image pixel width */
|
|
||||||
u_int pixel_h; /* v=: source image pixel height */
|
|
||||||
u_int cols; /* c=: display columns (0=auto) */
|
|
||||||
u_int rows; /* r=: display rows (0=auto) */
|
|
||||||
u_int image_id; /* i=: image id (0=unassigned) */
|
|
||||||
u_int image_num; /* I=: image number */
|
|
||||||
u_int placement_id; /* p=: placement id */
|
|
||||||
u_int more; /* m=: 1=more chunks coming, 0=last */
|
|
||||||
u_int quiet; /* q=: suppress responses */
|
|
||||||
int z_index; /* z=: z-index */
|
|
||||||
char compression; /* o=: 'z'=zlib, 0=none */
|
|
||||||
char delete_what; /* d=: delete target (used with a=d) */
|
|
||||||
|
|
||||||
/* Cell size at the time of parsing (from the owning window). */
|
|
||||||
u_int xpixel;
|
|
||||||
u_int ypixel;
|
|
||||||
|
|
||||||
/* Original base64-encoded payload (concatenated across all chunks). */
|
|
||||||
char *encoded;
|
|
||||||
size_t encodedlen;
|
|
||||||
|
|
||||||
char *ctrl;
|
|
||||||
size_t ctrllen;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Cursor style. */
|
/* Cursor style. */
|
||||||
enum screen_cursor_style {
|
enum screen_cursor_style {
|
||||||
SCREEN_CURSOR_DEFAULT,
|
SCREEN_CURSOR_DEFAULT,
|
||||||
@@ -3832,6 +3795,10 @@ struct screen *sixel_to_screen(struct sixel_image *);
|
|||||||
/* image-kitty.c */
|
/* image-kitty.c */
|
||||||
struct kitty_image *kitty_parse(const u_char *, size_t, u_int, u_int);
|
struct kitty_image *kitty_parse(const u_char *, size_t, u_int, u_int);
|
||||||
void kitty_free(struct kitty_image *);
|
void kitty_free(struct kitty_image *);
|
||||||
|
void kitty_size_in_cells(struct kitty_image *, u_int *, u_int *);
|
||||||
|
char kitty_get_action(struct kitty_image *);
|
||||||
|
u_int kitty_get_image_id(struct kitty_image *);
|
||||||
|
u_int kitty_get_rows(struct kitty_image *);
|
||||||
char *kitty_print(struct kitty_image *, size_t *);
|
char *kitty_print(struct kitty_image *, size_t *);
|
||||||
char *kitty_delete_all(size_t *);
|
char *kitty_delete_all(size_t *);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
BIN
tools/image.kitty
Normal file
BIN
tools/image.kitty
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 172 KiB |
17
tty-keys.c
17
tty-keys.c
@@ -1836,6 +1836,7 @@ tty_keys_kitty_graphics(struct tty *tty, const char *buf, size_t len,
|
|||||||
{
|
{
|
||||||
struct client *c = tty->client;
|
struct client *c = tty->client;
|
||||||
int *features = &c->term_features;
|
int *features = &c->term_features;
|
||||||
|
const char *semi;
|
||||||
size_t i;
|
size_t i;
|
||||||
char tmp[256];
|
char tmp[256];
|
||||||
|
|
||||||
@@ -1878,15 +1879,13 @@ tty_keys_kitty_graphics(struct tty *tty, const char *buf, size_t len,
|
|||||||
* Check if the message (after the semicolon) starts with "OK".
|
* Check if the message (after the semicolon) starts with "OK".
|
||||||
* The format is: i=31;OK or i=31;ENOSYS:...
|
* The format is: i=31;OK or i=31;ENOSYS:...
|
||||||
*/
|
*/
|
||||||
{
|
semi = strchr(tmp, ';');
|
||||||
const char *semi = strchr(tmp, ';');
|
if (semi != NULL && strncmp(semi + 1, "OK", 2) == 0) {
|
||||||
if (semi != NULL && strncmp(semi + 1, "OK", 2) == 0) {
|
log_debug("%s: kitty graphics supported", c->name);
|
||||||
log_debug("%s: kitty graphics supported", c->name);
|
tty_add_features(features, "kitty", ",");
|
||||||
tty_add_features(features, "kitty", ",");
|
tty_update_features(tty);
|
||||||
tty_update_features(tty);
|
} else {
|
||||||
} else {
|
log_debug("%s: kitty graphics not supported", c->name);
|
||||||
log_debug("%s: kitty graphics not supported", c->name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
|
|||||||
@@ -270,7 +270,6 @@ static const struct tty_term_code_entry tty_term_codes[] = {
|
|||||||
[TTYC_SETULC1] = { TTYCODE_STRING, "Setulc1" },
|
[TTYC_SETULC1] = { TTYCODE_STRING, "Setulc1" },
|
||||||
[TTYC_SE] = { TTYCODE_STRING, "Se" },
|
[TTYC_SE] = { TTYCODE_STRING, "Se" },
|
||||||
[TTYC_SXL] = { TTYCODE_FLAG, "Sxl" },
|
[TTYC_SXL] = { TTYCODE_FLAG, "Sxl" },
|
||||||
[TTYC_KTY] = { TTYCODE_FLAG, "Kty" },
|
|
||||||
[TTYC_SGR0] = { TTYCODE_STRING, "sgr0" },
|
[TTYC_SGR0] = { TTYCODE_STRING, "sgr0" },
|
||||||
[TTYC_SITM] = { TTYCODE_STRING, "sitm" },
|
[TTYC_SITM] = { TTYCODE_STRING, "sitm" },
|
||||||
[TTYC_SMACS] = { TTYCODE_STRING, "smacs" },
|
[TTYC_SMACS] = { TTYCODE_STRING, "smacs" },
|
||||||
|
|||||||
29
tty.c
29
tty.c
@@ -2180,48 +2180,35 @@ tty_cmd_sixelimage(struct tty *tty, const struct tty_ctx *ctx)
|
|||||||
static int
|
static int
|
||||||
tty_has_kitty(struct tty *tty)
|
tty_has_kitty(struct tty *tty)
|
||||||
{
|
{
|
||||||
return ((tty->term->flags & TERM_KITTY) ||
|
return (tty->term->flags & TERM_KITTY);
|
||||||
tty_term_has(tty->term, TTYC_KTY));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tty_cmd_kittyimage(struct tty *tty, const struct tty_ctx *ctx)
|
tty_cmd_kittyimage(struct tty *tty, const struct tty_ctx *ctx)
|
||||||
{
|
{
|
||||||
struct image *im = ctx->ptr;
|
struct image *im = ctx->ptr;
|
||||||
struct kitty_image *ki;
|
|
||||||
char *data;
|
char *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
u_int cx = ctx->ocx, cy = ctx->ocy;
|
u_int cx = ctx->ocx, cy = ctx->ocy;
|
||||||
int fallback = 0;
|
int fallback = 0;
|
||||||
|
|
||||||
log_debug("%s: called, im=%p", __func__, im);
|
if (im == NULL || im->data.kitty == NULL)
|
||||||
|
|
||||||
if (im == NULL) {
|
|
||||||
log_debug("%s: NULL image pointer", __func__);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
ki = im->data.kitty;
|
/* Check if this terminal supports kitty graphics. */
|
||||||
log_debug("%s: ki=%p, type=%d", __func__, ki, im->type);
|
|
||||||
|
|
||||||
if (ki == NULL) {
|
|
||||||
log_debug("%s: NULL kitty_image pointer", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if this terminal supports kitty graphics */
|
|
||||||
if (!tty_has_kitty(tty))
|
if (!tty_has_kitty(tty))
|
||||||
fallback = 1;
|
fallback = 1;
|
||||||
|
|
||||||
log_debug("%s: image at %u,%u (fallback=%d)", __func__, cx, cy, fallback);
|
log_debug("%s: image at %u,%u (fallback=%d)", __func__, cx, cy,
|
||||||
|
fallback);
|
||||||
|
|
||||||
if (fallback == 1) {
|
if (fallback == 1) {
|
||||||
/* Use text fallback for non-kitty terminals */
|
/* Use text fallback for non-kitty terminals. */
|
||||||
data = xstrdup(im->fallback);
|
data = xstrdup(im->fallback);
|
||||||
size = strlen(data);
|
size = strlen(data);
|
||||||
} else {
|
} else {
|
||||||
/* Re-serialize the kitty image command */
|
/* Re-serialize the kitty image command. */
|
||||||
data = kitty_print(ki, &size);
|
data = kitty_print(im->data.kitty, &size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
|
|||||||
Reference in New Issue
Block a user