mirror of
https://github.com/tmux/tmux.git
synced 2026-03-12 03:25:45 +00:00
Compare commits
12 Commits
ta/kitty-i
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04b4952f0e | ||
|
|
0d77555c97 | ||
|
|
67141fb4bb | ||
|
|
2efa762c2b | ||
|
|
6c2dd193cf | ||
|
|
881bec958e | ||
|
|
8899c751e5 | ||
|
|
d0caf0a322 | ||
|
|
91b5108eae | ||
|
|
2c7f73f9c4 | ||
|
|
5310592967 | ||
|
|
41bddae907 |
12
Makefile.am
12
Makefile.am
@@ -232,18 +232,8 @@ nodist_tmux_SOURCES += compat/utf8proc.c
|
||||
endif
|
||||
|
||||
# Enable sixel support.
|
||||
if ENABLE_SIXEL_IMAGES
|
||||
if ENABLE_SIXEL
|
||||
dist_tmux_SOURCES += image.c image-sixel.c
|
||||
else
|
||||
# If not sixel, still need image.c for kitty.
|
||||
if ENABLE_KITTY_IMAGES
|
||||
dist_tmux_SOURCES += image.c
|
||||
endif
|
||||
endif
|
||||
|
||||
# Enable kitty graphics protocol support.
|
||||
if ENABLE_KITTY_IMAGES
|
||||
dist_tmux_SOURCES += image-kitty.c
|
||||
endif
|
||||
|
||||
if NEED_FUZZING
|
||||
|
||||
@@ -370,7 +370,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
||||
flags |= MENU_NOMOUSE;
|
||||
if (menu_display(menu, flags, starting_choice, item, px, py, tc, lines,
|
||||
style, selected_style, border_style, target, NULL, NULL) != 0)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
goto out;
|
||||
return (CMD_RETURN_WAIT);
|
||||
|
||||
out:
|
||||
|
||||
@@ -195,10 +195,6 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
sort_crit.reversed = args_has(args, 'r');
|
||||
|
||||
prefix = cmd_list_keys_get_prefix(args);
|
||||
single = args_has(args, '1');
|
||||
notes_only = args_has(args, 'N');
|
||||
|
||||
if ((tablename = args_get(args, 'T')) != NULL) {
|
||||
table = key_bindings_get_table(tablename, 0);
|
||||
if (table == NULL) {
|
||||
@@ -207,6 +203,10 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
}
|
||||
|
||||
prefix = cmd_list_keys_get_prefix(args);
|
||||
single = args_has(args, '1');
|
||||
notes_only = args_has(args, 'N');
|
||||
|
||||
if ((template = args_get(args, 'F')) == NULL)
|
||||
template = LIST_KEYS_TEMPLATE;
|
||||
|
||||
|
||||
@@ -1604,7 +1604,9 @@ yylex_token_tilde(char **buf, size_t *len)
|
||||
|
||||
if (*name == '\0') {
|
||||
envent = environ_find(global_environ, "HOME");
|
||||
if (envent != NULL && *envent->value != '\0')
|
||||
if (envent != NULL &&
|
||||
envent->value != NULL &&
|
||||
*envent->value != '\0')
|
||||
home = envent->value;
|
||||
else if ((pw = getpwuid(getuid())) != NULL)
|
||||
home = pw->pw_dir;
|
||||
|
||||
27
configure.ac
27
configure.ac
@@ -462,33 +462,14 @@ if test "x$enable_cgroups" = xyes; then
|
||||
fi
|
||||
|
||||
# Enable sixel support.
|
||||
AC_ARG_ENABLE(
|
||||
sixel-images,
|
||||
AS_HELP_STRING(--enable-sixel-images, enable sixel images)
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
sixel,
|
||||
AS_HELP_STRING(--enable-sixel support),
|
||||
[
|
||||
enable_sixel_images="$enableval"
|
||||
]
|
||||
AS_HELP_STRING(--enable-sixel, enable sixel images)
|
||||
)
|
||||
|
||||
if test "x$enable_sixel_images" = xyes; then
|
||||
AC_DEFINE(ENABLE_SIXEL_IMAGES)
|
||||
if test "x$enable_sixel" = xyes; then
|
||||
AC_DEFINE(ENABLE_SIXEL)
|
||||
fi
|
||||
AM_CONDITIONAL(ENABLE_SIXEL_IMAGES, [test "x$enable_sixel_images" = xyes])
|
||||
|
||||
# Enable kitty graphics protocol support.
|
||||
AC_ARG_ENABLE(
|
||||
kitty-images,
|
||||
AS_HELP_STRING(--enable-kitty-images, enable kitty terminal graphics)
|
||||
)
|
||||
if test "x$enable_kitty_images" = xyes; then
|
||||
AC_DEFINE(ENABLE_KITTY_IMAGES)
|
||||
fi
|
||||
AM_CONDITIONAL(ENABLE_KITTY_IMAGES, [test "x$enable_kitty_images" = xyes])
|
||||
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)
|
||||
|
||||
@@ -1045,6 +1045,9 @@ control_check_subs_timer(__unused int fd, __unused short events, void *data)
|
||||
log_debug("%s: timer fired", __func__);
|
||||
evtimer_add(&cs->subs_timer, &tv);
|
||||
|
||||
if (s == NULL)
|
||||
return;
|
||||
|
||||
/* Find which subscription types are present. */
|
||||
RB_FOREACH(csub, control_subs, &cs->subs) {
|
||||
switch (csub->type) {
|
||||
|
||||
60
format.c
60
format.c
@@ -2562,16 +2562,12 @@ format_cb_version(__unused struct format_tree *ft)
|
||||
|
||||
/* Callback for sixel_support. */
|
||||
static void *
|
||||
format_cb_image_support(__unused struct format_tree *ft)
|
||||
format_cb_sixel_support(__unused struct format_tree *ft)
|
||||
{
|
||||
#if defined(ENABLE_SIXEL_IMAGES) && defined(ENABLE_KITTY_IMAGES)
|
||||
return (xstrdup("kitty,sixel"));
|
||||
#elif defined(ENABLE_SIXEL_IMAGES)
|
||||
return (xstrdup("sixel"));
|
||||
#elif defined(ENABLE_KITTY_IMAGES)
|
||||
return (xstrdup("kitty"));
|
||||
#ifdef ENABLE_SIXEL
|
||||
return (xstrdup("1"));
|
||||
#else
|
||||
return (NULL);
|
||||
return (xstrdup("0"));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3194,9 +3190,6 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "host_short", FORMAT_TABLE_STRING,
|
||||
format_cb_host_short
|
||||
},
|
||||
{ "image_support", FORMAT_TABLE_STRING,
|
||||
format_cb_image_support
|
||||
},
|
||||
{ "insert_flag", FORMAT_TABLE_STRING,
|
||||
format_cb_insert_flag
|
||||
},
|
||||
@@ -3473,6 +3466,9 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "session_windows", FORMAT_TABLE_STRING,
|
||||
format_cb_session_windows
|
||||
},
|
||||
{ "sixel_support", FORMAT_TABLE_STRING,
|
||||
format_cb_sixel_support
|
||||
},
|
||||
{ "socket_path", FORMAT_TABLE_STRING,
|
||||
format_cb_socket_path
|
||||
},
|
||||
@@ -4495,6 +4491,37 @@ format_window_name(struct format_expand_state *es, const char *fmt)
|
||||
return (xstrdup("0"));
|
||||
}
|
||||
|
||||
/* Add neighbor window variables to the format tree. */
|
||||
static void
|
||||
format_add_window_neighbor(struct format_tree *nft, struct winlink *wl,
|
||||
struct session *s, const char *prefix)
|
||||
{
|
||||
struct options_entry *o;
|
||||
const char *oname;
|
||||
char *key, *prefixed, *oval;
|
||||
|
||||
xasprintf(&key, "%s_window_index", prefix);
|
||||
format_add(nft, key, "%u", wl->idx);
|
||||
free(key);
|
||||
|
||||
xasprintf(&key, "%s_window_active", prefix);
|
||||
format_add(nft, key, "%d", wl == s->curw);
|
||||
free(key);
|
||||
|
||||
o = options_first(wl->window->options);
|
||||
while (o != NULL) {
|
||||
oname = options_name(o);
|
||||
if (*oname == '@') {
|
||||
xasprintf(&prefixed, "%s_%s", prefix, oname);
|
||||
oval = options_to_string(o, -1, 1);
|
||||
format_add(nft, prefixed, "%s", oval);
|
||||
free(oval);
|
||||
free(prefixed);
|
||||
}
|
||||
o = options_next(o);
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop over windows. */
|
||||
static char *
|
||||
format_loop_windows(struct format_expand_state *es, const char *fmt)
|
||||
@@ -4538,6 +4565,17 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
|
||||
nft = format_create(c, item, FORMAT_WINDOW|w->id,
|
||||
ft->flags|last);
|
||||
format_defaults(nft, ft->c, ft->s, wl, NULL);
|
||||
|
||||
/* Add neighbor window data to the format tree. */
|
||||
format_add(nft, "window_after_active", "%d",
|
||||
i > 0 && l[i - 1] == ft->s->curw);
|
||||
format_add(nft, "window_before_active", "%d",
|
||||
i + 1 < n && l[i + 1] == ft->s->curw);
|
||||
if (i + 1 < n)
|
||||
format_add_window_neighbor(nft, l[i + 1], ft->s, "next");
|
||||
if (i > 0)
|
||||
format_add_window_neighbor(nft, l[i - 1], ft->s, "prev");
|
||||
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
expanded = format_expand1(&next, use);
|
||||
|
||||
11
grid.c
11
grid.c
@@ -495,7 +495,7 @@ static void
|
||||
grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg)
|
||||
{
|
||||
struct grid_line *gl;
|
||||
u_int xx, old_cellsize;
|
||||
u_int xx;
|
||||
|
||||
gl = &gd->linedata[py];
|
||||
if (sx <= gl->cellsize)
|
||||
@@ -508,10 +508,13 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg)
|
||||
else if (gd->sx > sx)
|
||||
sx = gd->sx;
|
||||
|
||||
old_cellsize = gl->cellsize;
|
||||
gl->celldata = xrecallocarray(gl->celldata, old_cellsize, sx,
|
||||
gl->celldata = xreallocarray(gl->celldata, sx,
|
||||
sizeof *gl->celldata);
|
||||
for (xx = old_cellsize; xx < sx; xx++)
|
||||
if (gl->cellsize < sx) {
|
||||
memset(gl->celldata + gl->cellsize, 0,
|
||||
(sx - gl->cellsize) * sizeof *gl->celldata);
|
||||
}
|
||||
for (xx = gl->cellsize; xx < sx; xx++)
|
||||
grid_clear_cell(gd, xx, py, bg);
|
||||
gl->cellsize = sx;
|
||||
}
|
||||
|
||||
325
image-kitty.c
325
image-kitty.c
@@ -1,325 +0,0 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Thomas Adam <thomas@xteddy.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.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.
|
||||
* Format: key=value,key=value,...
|
||||
*/
|
||||
static int
|
||||
kitty_parse_control(const char *ctrl, size_t ctrllen, struct kitty_image *ki)
|
||||
{
|
||||
const char *p = ctrl, *end = ctrl + ctrllen, *errstr;
|
||||
char key[4], val[32];
|
||||
size_t klen, vlen;
|
||||
|
||||
while (p < end) {
|
||||
klen = 0;
|
||||
while (p < end && *p != '=' && klen < sizeof(key) - 1)
|
||||
key[klen++] = *p++;
|
||||
key[klen] = '\0';
|
||||
if (p >= end || *p != '=')
|
||||
return (-1);
|
||||
p++;
|
||||
|
||||
vlen = 0;
|
||||
while (p < end && *p != ',' && vlen < sizeof(val) - 1)
|
||||
val[vlen++] = *p++;
|
||||
val[vlen] = '\0';
|
||||
if (p < end && *p == ',')
|
||||
p++;
|
||||
|
||||
if (klen != 1)
|
||||
continue;
|
||||
|
||||
switch (key[0]) {
|
||||
case 'a':
|
||||
ki->action = val[0];
|
||||
break;
|
||||
case 'f':
|
||||
ki->format = strtonum(val, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return (-1);
|
||||
break;
|
||||
case 't':
|
||||
ki->medium = val[0];
|
||||
break;
|
||||
case 's':
|
||||
ki->pixel_w = strtonum(val, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return (-1);
|
||||
break;
|
||||
case 'v':
|
||||
ki->pixel_h = strtonum(val, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return (-1);
|
||||
break;
|
||||
case 'c':
|
||||
ki->cols = strtonum(val, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return (-1);
|
||||
break;
|
||||
case 'r':
|
||||
ki->rows = strtonum(val, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return (-1);
|
||||
break;
|
||||
case 'i':
|
||||
ki->image_id = strtonum(val, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return (-1);
|
||||
break;
|
||||
case 'I':
|
||||
ki->image_num = strtonum(val, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return (-1);
|
||||
break;
|
||||
case 'p':
|
||||
ki->placement_id = strtonum(val, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return (-1);
|
||||
break;
|
||||
case 'm':
|
||||
ki->more = strtonum(val, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return (-1);
|
||||
break;
|
||||
case 'q':
|
||||
ki->quiet = strtonum(val, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return (-1);
|
||||
break;
|
||||
case 'z':
|
||||
ki->z_index = strtonum(val, INT_MIN, INT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return (-1);
|
||||
break;
|
||||
case 'o':
|
||||
ki->compression = val[0];
|
||||
break;
|
||||
case 'd':
|
||||
ki->delete_what = val[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a kitty APC body (after the leading 'G').
|
||||
* Stores the original control string and base64 payload verbatim for
|
||||
* pass-through re-emission to the outer terminal.
|
||||
*/
|
||||
struct kitty_image *
|
||||
kitty_parse(const u_char *buf, size_t len, u_int xpixel, u_int ypixel)
|
||||
{
|
||||
struct kitty_image *ki;
|
||||
const u_char *semi;
|
||||
const char *ctrl;
|
||||
size_t ctrllen, paylen;
|
||||
|
||||
if (len == 0)
|
||||
return (NULL);
|
||||
|
||||
semi = memchr(buf, ';', len);
|
||||
if (semi != NULL) {
|
||||
ctrl = (const char *)buf;
|
||||
ctrllen = semi - buf;
|
||||
paylen = len - ctrllen - 1;
|
||||
} else {
|
||||
ctrl = (const char *)buf;
|
||||
ctrllen = len;
|
||||
paylen = 0;
|
||||
}
|
||||
|
||||
ki = xcalloc(1, sizeof *ki);
|
||||
ki->xpixel = xpixel;
|
||||
ki->ypixel = ypixel;
|
||||
ki->action = 'T';
|
||||
ki->format = 32;
|
||||
ki->medium = 'd';
|
||||
|
||||
if (kitty_parse_control(ctrl, ctrllen, ki) != 0) {
|
||||
free(ki);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (paylen > 0) {
|
||||
ki->encoded = xmalloc(paylen + 1);
|
||||
memcpy(ki->encoded, semi + 1, paylen);
|
||||
ki->encoded[paylen] = '\0';
|
||||
ki->encodedlen = paylen;
|
||||
}
|
||||
|
||||
ki->ctrl = xmalloc(ctrllen + 1);
|
||||
memcpy(ki->ctrl, ctrl, ctrllen);
|
||||
ki->ctrl[ctrllen] = '\0';
|
||||
ki->ctrllen = ctrllen;
|
||||
|
||||
return (ki);
|
||||
}
|
||||
|
||||
void
|
||||
kitty_free(struct kitty_image *ki)
|
||||
{
|
||||
if (ki == NULL)
|
||||
return;
|
||||
free(ki->encoded);
|
||||
free(ki->ctrl);
|
||||
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
|
||||
* to the terminal. This recreates the original command that was parsed.
|
||||
*/
|
||||
char *
|
||||
kitty_print(struct kitty_image *ki, size_t *outlen)
|
||||
{
|
||||
char *out;
|
||||
size_t total, pos;
|
||||
|
||||
if (ki == NULL || ki->ctrl == NULL)
|
||||
return (NULL);
|
||||
|
||||
/* Calculate total length: ESC _ G + ctrl + ; + encoded + ESC \ */
|
||||
total = 3 + ki->ctrllen; /* \033_G + ctrl */
|
||||
if (ki->encoded != NULL && ki->encodedlen > 0) {
|
||||
total += 1 + ki->encodedlen; /* ; + encoded */
|
||||
}
|
||||
total += 2; /* \033\\ */
|
||||
|
||||
out = xmalloc(total + 1);
|
||||
*outlen = total;
|
||||
|
||||
/* Build the sequence */
|
||||
pos = 0;
|
||||
memcpy(out + pos, "\033_G", 3);
|
||||
pos += 3;
|
||||
memcpy(out + pos, ki->ctrl, ki->ctrllen);
|
||||
pos += ki->ctrllen;
|
||||
|
||||
if (ki->encoded != NULL && ki->encodedlen > 0) {
|
||||
out[pos++] = ';';
|
||||
memcpy(out + pos, ki->encoded, ki->encodedlen);
|
||||
pos += ki->encodedlen;
|
||||
}
|
||||
|
||||
memcpy(out + pos, "\033\\", 2);
|
||||
pos += 2;
|
||||
out[pos] = '\0';
|
||||
|
||||
return (out);
|
||||
}
|
||||
|
||||
char *
|
||||
kitty_delete_all(size_t *outlen)
|
||||
{
|
||||
char *out;
|
||||
|
||||
out = xstrdup("\033_Ga=d,d=a\033\\");
|
||||
*outlen = strlen(out);
|
||||
return (out);
|
||||
}
|
||||
@@ -357,7 +357,7 @@ sixel_parse(const char *buf, size_t len, u_int p2, u_int xpixel, u_int ypixel)
|
||||
return (si);
|
||||
|
||||
bad:
|
||||
free(si);
|
||||
sixel_free(si);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
112
image.c
112
image.c
@@ -61,22 +61,7 @@ image_free(struct image *im)
|
||||
all_images_count--;
|
||||
|
||||
TAILQ_REMOVE(&s->images, im, entry);
|
||||
|
||||
switch (im->type) {
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
case IMAGE_SIXEL:
|
||||
sixel_free(im->data.sixel);
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
case IMAGE_KITTY:
|
||||
kitty_free(im->data.kitty);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
sixel_free(im->data);
|
||||
free(im->fallback);
|
||||
free(im);
|
||||
}
|
||||
@@ -96,30 +81,13 @@ image_free_all(struct screen *s)
|
||||
|
||||
/* Create text placeholder for an image. */
|
||||
static void
|
||||
image_fallback(char **ret, enum image_type type, u_int sx, u_int sy)
|
||||
image_fallback(char **ret, u_int sx, u_int sy)
|
||||
{
|
||||
char *buf, *label;
|
||||
u_int py, size, lsize;
|
||||
const char *type_name;
|
||||
|
||||
switch (type) {
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
case IMAGE_SIXEL:
|
||||
type_name = "SIXEL";
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
case IMAGE_KITTY:
|
||||
type_name = "KITTY";
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
type_name = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
|
||||
/* Allocate first line. */
|
||||
lsize = xasprintf(&label, "%s IMAGE (%ux%u)\r\n", type_name, sx, sy) + 1;
|
||||
lsize = xasprintf(&label, "SIXEL IMAGE (%ux%u)\r\n", sx, sy) + 1;
|
||||
if (sx < lsize - 3)
|
||||
size = lsize - 1;
|
||||
else
|
||||
@@ -154,36 +122,19 @@ image_fallback(char **ret, enum image_type type, u_int sx, u_int sy)
|
||||
}
|
||||
|
||||
struct image*
|
||||
image_store(struct screen *s, enum image_type type, void *data)
|
||||
image_store(struct screen *s, struct sixel_image *si)
|
||||
{
|
||||
struct image *im;
|
||||
|
||||
im = xcalloc(1, sizeof *im);
|
||||
|
||||
im->type = type;
|
||||
im->s = s;
|
||||
im->data = si;
|
||||
|
||||
im->px = s->cx;
|
||||
im->py = s->cy;
|
||||
sixel_size_in_cells(si, &im->sx, &im->sy);
|
||||
|
||||
switch (type) {
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
case IMAGE_SIXEL:
|
||||
im->data.sixel = data;
|
||||
sixel_size_in_cells(im->data.sixel, &im->sx, &im->sy);
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
case IMAGE_KITTY:
|
||||
im->data.kitty = data;
|
||||
kitty_size_in_cells(im->data.kitty, &im->sx, &im->sy);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
image_fallback(&im->fallback, type, im->sx, im->sy);
|
||||
image_fallback(&im->fallback, im->sx, im->sy);
|
||||
|
||||
image_log(im, __func__, NULL);
|
||||
TAILQ_INSERT_TAIL(&s->images, im, entry);
|
||||
@@ -237,10 +188,8 @@ image_scroll_up(struct screen *s, u_int lines)
|
||||
{
|
||||
struct image *im, *im1;
|
||||
int redraw = 0;
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
struct sixel_image *new;
|
||||
u_int sx, sy;
|
||||
#endif
|
||||
struct sixel_image *new;
|
||||
|
||||
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) {
|
||||
if (im->py >= lines) {
|
||||
@@ -255,43 +204,20 @@ image_scroll_up(struct screen *s, u_int lines)
|
||||
redraw = 1;
|
||||
continue;
|
||||
}
|
||||
sx = im->sx;
|
||||
sy = (im->py + im->sy) - lines;
|
||||
image_log(im, __func__, "3, lines=%u, sy=%u", lines, sy);
|
||||
|
||||
/* Image is partially scrolled off - need to crop it */
|
||||
switch (im->type) {
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
case IMAGE_SIXEL:
|
||||
sx = im->sx;
|
||||
sy = (im->py + im->sy) - lines;
|
||||
image_log(im, __func__, "sixel, lines=%u, sy=%u",
|
||||
lines, sy);
|
||||
new = sixel_scale(im->data, 0, 0, 0, im->sy - sy, sx, sy, 1);
|
||||
sixel_free(im->data);
|
||||
im->data = new;
|
||||
|
||||
new = sixel_scale(im->data.sixel, 0, 0, 0, im->sy - sy,
|
||||
sx, sy, 1);
|
||||
sixel_free(im->data.sixel);
|
||||
im->data.sixel = new;
|
||||
im->py = 0;
|
||||
sixel_size_in_cells(im->data, &im->sx, &im->sy);
|
||||
|
||||
im->py = 0;
|
||||
sixel_size_in_cells(im->data.sixel, &im->sx, &im->sy);
|
||||
|
||||
free(im->fallback);
|
||||
image_fallback(&im->fallback, im->type, im->sx, im->sy);
|
||||
redraw = 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
case IMAGE_KITTY:
|
||||
/*
|
||||
* For kitty images, we can't rescale - the terminal
|
||||
* owns the placement. Just adjust position and let
|
||||
* the terminal handle clipping.
|
||||
*/
|
||||
im->py = 0;
|
||||
redraw = 1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(im->fallback);
|
||||
image_fallback(&im->fallback, im->sx, im->sy);
|
||||
redraw = 1;
|
||||
}
|
||||
return (redraw);
|
||||
}
|
||||
|
||||
101
input.c
101
input.c
@@ -145,7 +145,6 @@ struct input_ctx {
|
||||
*/
|
||||
struct evbuffer *since_ground;
|
||||
struct event ground_timer;
|
||||
|
||||
};
|
||||
|
||||
/* Helper functions. */
|
||||
@@ -181,7 +180,6 @@ static void input_ground(struct input_ctx *);
|
||||
static void input_enter_dcs(struct input_ctx *);
|
||||
static void input_enter_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_exit_apc(struct input_ctx *);
|
||||
static void input_enter_rename(struct input_ctx *);
|
||||
@@ -1383,10 +1381,6 @@ input_esc_dispatch(struct input_ctx *ictx)
|
||||
input_reset_cell(ictx);
|
||||
screen_write_reset(sctx);
|
||||
screen_write_fullredraw(sctx);
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
if (ictx->wp != NULL)
|
||||
tty_kitty_delete_all_pane(ictx->wp);
|
||||
#endif
|
||||
break;
|
||||
case INPUT_ESC_IND:
|
||||
screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
|
||||
@@ -1562,10 +1556,11 @@ input_csi_dispatch(struct input_ctx *ictx)
|
||||
case -1:
|
||||
break;
|
||||
case 0:
|
||||
if (input_da1_has_sixel(ictx))
|
||||
input_reply(ictx, 1, "\033[?1;2;4c");
|
||||
else
|
||||
input_reply(ictx, 1, "\033[?1;2c");
|
||||
#ifdef ENABLE_SIXEL
|
||||
input_reply(ictx, 1, "\033[?1;2;4c");
|
||||
#else
|
||||
input_reply(ictx, 1, "\033[?1;2c");
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
||||
@@ -2035,7 +2030,7 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
|
||||
static void
|
||||
input_csi_dispatch_sm_graphics(__unused struct input_ctx *ictx)
|
||||
{
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
int n, m, o;
|
||||
|
||||
if (ictx->param_list_len > 3)
|
||||
@@ -2560,7 +2555,7 @@ input_dcs_dispatch(struct input_ctx *ictx)
|
||||
const char prefix[] = "tmux;";
|
||||
const u_int prefixlen = (sizeof prefix) - 1;
|
||||
long long allow_passthrough = 0;
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
struct window *w;
|
||||
struct sixel_image *si;
|
||||
int p2;
|
||||
@@ -2575,7 +2570,7 @@ input_dcs_dispatch(struct input_ctx *ictx)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
w = wp->window;
|
||||
if (buf[0] == 'q' && ictx->interm_len == 0) {
|
||||
if (input_split(ictx) != 0)
|
||||
@@ -2721,79 +2716,6 @@ input_enter_apc(struct input_ctx *ictx)
|
||||
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. */
|
||||
static void
|
||||
input_exit_apc(struct input_ctx *ictx)
|
||||
@@ -2805,13 +2727,6 @@ input_exit_apc(struct input_ctx *ictx)
|
||||
return;
|
||||
log_debug("%s: \"%s\"", __func__, ictx->input_buf);
|
||||
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
if (ictx->input_len >= 1 && ictx->input_buf[0] == 'G') {
|
||||
input_apc_kitty_image(ictx);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wp != NULL &&
|
||||
options_get_number(wp->options, "allow-set-title") &&
|
||||
screen_set_title(sctx->s, ictx->input_buf)) {
|
||||
|
||||
@@ -141,7 +141,7 @@ static const char *options_table_allow_passthrough_list[] = {
|
||||
"#{T:window-status-format}" \
|
||||
"#[pop-default]" \
|
||||
"#[norange default]" \
|
||||
"#{?loop_last_flag,,#{window-status-separator}}" \
|
||||
"#{?loop_last_flag,,#{E:window-status-separator}}" \
|
||||
"," \
|
||||
"#[range=window|#{window_index} list=focus " \
|
||||
"#{?#{!=:#{E:window-status-current-style},default}," \
|
||||
@@ -168,7 +168,7 @@ static const char *options_table_allow_passthrough_list[] = {
|
||||
"#{T:window-status-current-format}" \
|
||||
"#[pop-default]" \
|
||||
"#[norange list=on default]" \
|
||||
"#{?loop_last_flag,,#{window-status-separator}}" \
|
||||
"#{?loop_last_flag,,#{E:window-status-separator}}" \
|
||||
"}" \
|
||||
"#[nolist align=right range=right #{E:status-right-style}]" \
|
||||
"#[push-default]" \
|
||||
|
||||
@@ -667,16 +667,6 @@ screen_redraw_screen(struct client *c)
|
||||
}
|
||||
if (flags & CLIENT_REDRAWWINDOW) {
|
||||
log_debug("%s: redrawing panes", c->name);
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
/*
|
||||
* Delete all kitty image placements before redrawing panes.
|
||||
* This must happen unconditionally — even when the new window
|
||||
* has no images — so that images from the previous window
|
||||
* (or from a `reset` in the shell) are cleared from the outer
|
||||
* terminal before new content is drawn over them.
|
||||
*/
|
||||
tty_kitty_delete_all(&c->tty);
|
||||
#endif
|
||||
screen_redraw_draw_panes(&ctx);
|
||||
screen_redraw_draw_pane_scrollbars(&ctx);
|
||||
}
|
||||
@@ -707,12 +697,8 @@ screen_redraw_pane(struct client *c, struct window_pane *wp,
|
||||
tty_sync_start(&c->tty);
|
||||
tty_update_mode(&c->tty, c->tty.mode, NULL);
|
||||
|
||||
if (!redraw_scrollbar_only) {
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
tty_kitty_delete_all(&c->tty);
|
||||
#endif
|
||||
if (!redraw_scrollbar_only)
|
||||
screen_redraw_draw_pane(&ctx, wp);
|
||||
}
|
||||
|
||||
if (window_pane_show_scrollbar(wp, ctx.pane_scrollbars))
|
||||
screen_redraw_draw_pane_scrollbar(&ctx, wp);
|
||||
@@ -1016,7 +1002,7 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
tty_draw_images(c, wp, s);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1072,7 +1072,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
utf8_set(&gc.data, 'E');
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_free_all(s) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1111,7 +1111,7 @@ 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_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1144,7 +1144,7 @@ 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_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1177,7 +1177,7 @@ 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_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1200,14 +1200,14 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
|
||||
struct grid *gd = s->grid;
|
||||
struct tty_ctx ttyctx;
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
u_int sy = screen_size_y(s);
|
||||
#endif
|
||||
|
||||
if (ny == 0)
|
||||
ny = 1;
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1260,7 +1260,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
|
||||
if (ny == 0)
|
||||
ny = 1;
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1313,7 +1313,7 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
|
||||
if (gl->cellsize == 0 && COLOUR_DEFAULT(bg))
|
||||
return;
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1347,7 +1347,7 @@ 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_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1374,7 +1374,7 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1422,7 +1422,7 @@ screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg)
|
||||
struct tty_ctx ttyctx;
|
||||
|
||||
if (s->cy == s->rupper) {
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_free_all(s) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1469,7 +1469,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;
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
int redraw = 0;
|
||||
#endif
|
||||
u_int rupper = s->rupper, rlower = s->rlower;
|
||||
@@ -1487,7 +1487,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
|
||||
}
|
||||
|
||||
if (s->cy == s->rlower) {
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (rlower == screen_size_y(s) - 1)
|
||||
redraw = image_scroll_up(s, 1);
|
||||
else
|
||||
@@ -1520,7 +1520,7 @@ screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines, u_int bg)
|
||||
ctx->bg = bg;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_scroll_up(s, lines) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1549,7 +1549,7 @@ 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_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_free_all(s) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1578,7 +1578,7 @@ 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_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1612,7 +1612,7 @@ 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_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_check_line(s, 0, s->cy - 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1640,7 +1640,7 @@ 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_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_free_all(s) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -1957,7 +1957,7 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
if (image_check_area(s, s->cx, s->cy, ci->used, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
@@ -2398,7 +2398,7 @@ screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len,
|
||||
tty_write(tty_cmd_rawstring, &ttyctx);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
/* Write a SIXEL image. */
|
||||
void
|
||||
screen_write_sixelimage(struct screen_write_ctx *ctx, struct sixel_image *si,
|
||||
@@ -2450,7 +2450,7 @@ screen_write_sixelimage(struct screen_write_ctx *ctx, struct sixel_image *si,
|
||||
screen_write_collect_flush(ctx, 0, __func__);
|
||||
|
||||
screen_write_initctx(ctx, &ttyctx, 0);
|
||||
ttyctx.ptr = image_store(s, IMAGE_SIXEL, si);
|
||||
ttyctx.ptr = image_store(s, si);
|
||||
|
||||
tty_write(tty_cmd_sixelimage, &ttyctx);
|
||||
|
||||
@@ -2458,38 +2458,6 @@ screen_write_sixelimage(struct screen_write_ctx *ctx, struct sixel_image *si,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
void
|
||||
screen_write_kittyimage(struct screen_write_ctx *ctx, struct kitty_image *ki)
|
||||
{
|
||||
struct screen *s = ctx->s;
|
||||
struct tty_ctx ttyctx;
|
||||
struct image *im;
|
||||
|
||||
if (ki == NULL)
|
||||
return;
|
||||
|
||||
/* Store the image in the cache. */
|
||||
im = image_store(s, IMAGE_KITTY, ki);
|
||||
|
||||
/* Trigger a tty write to send to all terminals. */
|
||||
if (im != NULL && ctx->wp != NULL) {
|
||||
screen_write_collect_flush(ctx, 0, __func__);
|
||||
screen_write_initctx(ctx, &ttyctx, 0);
|
||||
ttyctx.ptr = im;
|
||||
ttyctx.arg = ctx->wp;
|
||||
ttyctx.ocx = s->cx;
|
||||
ttyctx.ocy = s->cy;
|
||||
ttyctx.set_client_cb = tty_set_client_cb;
|
||||
tty_write(tty_cmd_kittyimage, &ttyctx);
|
||||
}
|
||||
|
||||
/* Move cursor past the image. */
|
||||
if (kitty_get_rows(ki) > 0)
|
||||
screen_write_cursormove(ctx, 0, s->cy + kitty_get_rows(ki), 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Turn alternate screen on. */
|
||||
void
|
||||
screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc,
|
||||
|
||||
12
screen.c
12
screen.c
@@ -89,7 +89,7 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
|
||||
s->tabs = NULL;
|
||||
s->sel = NULL;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
TAILQ_INIT(&s->images);
|
||||
TAILQ_INIT(&s->saved_images);
|
||||
#endif
|
||||
@@ -127,7 +127,7 @@ screen_reinit(struct screen *s)
|
||||
screen_clear_selection(s);
|
||||
screen_free_titles(s);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
image_free_all(s);
|
||||
#endif
|
||||
|
||||
@@ -164,7 +164,7 @@ screen_free(struct screen *s)
|
||||
hyperlinks_free(s->hyperlinks);
|
||||
screen_free_titles(s);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
image_free_all(s);
|
||||
#endif
|
||||
}
|
||||
@@ -324,7 +324,7 @@ screen_resize_cursor(struct screen *s, u_int sx, u_int sy, int reflow,
|
||||
if (sy != screen_size_y(s))
|
||||
screen_resize_y(s, sy, eat_empty, &cy);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
image_free_all(s);
|
||||
#endif
|
||||
|
||||
@@ -649,7 +649,7 @@ screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor)
|
||||
}
|
||||
memcpy(&s->saved_cell, gc, sizeof s->saved_cell);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
TAILQ_CONCAT(&s->saved_images, &s->images, entry);
|
||||
#endif
|
||||
|
||||
@@ -707,7 +707,7 @@ screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
|
||||
grid_destroy(s->saved_grid);
|
||||
s->saved_grid = NULL;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
image_free_all(s);
|
||||
TAILQ_CONCAT(&s->images, &s->saved_images, entry);
|
||||
#endif
|
||||
|
||||
@@ -3708,7 +3708,7 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
|
||||
c->term_name = xstrdup("unknown");
|
||||
}
|
||||
|
||||
if (c->ttyname == NULL || *c->ttyname != '\0')
|
||||
if (c->ttyname != NULL && *c->ttyname != '\0')
|
||||
name = xstrdup(c->ttyname);
|
||||
else
|
||||
xasprintf(&name, "client-%ld", (long)c->pid);
|
||||
|
||||
21
tmux.1
21
tmux.1
@@ -6127,6 +6127,21 @@ For example, to get a list of windows formatted like the status line:
|
||||
#{W:#{E:window-status-format} ,#{E:window-status-current-format} }
|
||||
.Ed
|
||||
.Pp
|
||||
Within the
|
||||
.Ql W:\&
|
||||
loop, user options
|
||||
.Po
|
||||
.Ql @name
|
||||
.Pc
|
||||
from neighboring windows are available with a
|
||||
.Ql next_
|
||||
or
|
||||
.Ql prev_
|
||||
prefix, for example a user option
|
||||
.Ql @color
|
||||
on the next window is available as
|
||||
.Ql next_@color .
|
||||
.Pp
|
||||
.Ql N:\&
|
||||
checks if a window (without any suffix or with the
|
||||
.Ql w
|
||||
@@ -6266,7 +6281,6 @@ The following variables are available, where appropriate:
|
||||
.It Li "hook_window_name" Ta "" Ta "Name of window where hook was run, if any"
|
||||
.It Li "host" Ta "#H" Ta "Hostname of local host"
|
||||
.It Li "host_short" Ta "#h" Ta "Hostname of local host (no domain name)"
|
||||
.It Li "image_support" Ta "" Ta "Returns the string of the support image (sixel, kitty)"
|
||||
.It Li "insert_flag" Ta "" Ta "Pane insert flag"
|
||||
.It Li "key_string" Ta "" Ta "String representation of the key binding"
|
||||
.It Li "key_repeat" Ta "" Ta "1 if key binding is repeatable"
|
||||
@@ -6296,6 +6310,8 @@ The following variables are available, where appropriate:
|
||||
.It Li "mouse_x" Ta "" Ta "Mouse X position, if any"
|
||||
.It Li "mouse_y" Ta "" Ta "Mouse Y position, if any"
|
||||
.It Li "next_session_id" Ta "" Ta "Unique session ID for next new session"
|
||||
.It Li "next_window_active" Ta "" Ta "1 if next window in W: loop is active"
|
||||
.It Li "next_window_index" Ta "" Ta "Index of next window in W: loop"
|
||||
.It Li "origin_flag" Ta "" Ta "Pane origin flag"
|
||||
.It Li "pane_active" Ta "" Ta "1 if active pane"
|
||||
.It Li "pane_at_bottom" Ta "" Ta "1 if pane is at the bottom of window"
|
||||
@@ -6339,6 +6355,8 @@ The following variables are available, where appropriate:
|
||||
.It Li "pane_unseen_changes" Ta "" Ta "1 if there were changes in pane while in mode"
|
||||
.It Li "pane_width" Ta "" Ta "Width of pane"
|
||||
.It Li "pid" Ta "" Ta "Server PID"
|
||||
.It Li "prev_window_active" Ta "" Ta "1 if previous window in W: loop is active"
|
||||
.It Li "prev_window_index" Ta "" Ta "Index of previous window in W: loop"
|
||||
.It Li "rectangle_toggle" Ta "" Ta "1 if rectangle selection is activated"
|
||||
.It Li "scroll_position" Ta "" Ta "Scroll position in copy mode"
|
||||
.It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane"
|
||||
@@ -6381,6 +6399,7 @@ The following variables are available, where appropriate:
|
||||
.It Li "session_stack" Ta "" Ta "Window indexes in most recent order"
|
||||
.It Li "session_windows" Ta "" Ta "Number of windows in session"
|
||||
.It Li "socket_path" Ta "" Ta "Server socket path"
|
||||
.It Li "sixel_support" Ta "" Ta "1 if server has support for SIXEL"
|
||||
.It Li "start_time" Ta "" Ta "Server start time"
|
||||
.It Li "synchronized_output_flag" Ta "" Ta "1 if pane has synchronized output enabled"
|
||||
.It Li "uid" Ta "" Ta "Server UID"
|
||||
|
||||
73
tmux.h
73
tmux.h
@@ -68,19 +68,10 @@ struct screen_write_cline;
|
||||
struct screen_write_ctx;
|
||||
struct session;
|
||||
|
||||
/* Convenience macro: defined if any image protocol is compiled in. */
|
||||
#if defined(ENABLE_SIXEL_IMAGES) || defined(ENABLE_KITTY_IMAGES)
|
||||
#define ENABLE_IMAGES
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
struct sixel_image;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
struct kitty_image;
|
||||
#endif
|
||||
|
||||
struct tty_ctx;
|
||||
struct tty_code;
|
||||
struct tty_key;
|
||||
@@ -934,25 +925,11 @@ struct style {
|
||||
enum style_default_type default_type;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
/* Image types. */
|
||||
enum image_type {
|
||||
IMAGE_SIXEL,
|
||||
IMAGE_KITTY
|
||||
};
|
||||
|
||||
#ifdef ENABLE_SIXEL
|
||||
/* Image. */
|
||||
struct image {
|
||||
enum image_type type;
|
||||
struct screen *s;
|
||||
union {
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
struct sixel_image *sixel;
|
||||
#endif
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
struct kitty_image *kitty;
|
||||
#endif
|
||||
} data;
|
||||
struct sixel_image *data;
|
||||
char *fallback;
|
||||
|
||||
u_int px;
|
||||
@@ -1007,7 +984,7 @@ struct screen {
|
||||
bitstr_t *tabs;
|
||||
struct screen_sel *sel;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
struct images images;
|
||||
struct images saved_images;
|
||||
#endif
|
||||
@@ -1589,7 +1566,6 @@ struct tty_term {
|
||||
#define TERM_RGBCOLOURS 0x10
|
||||
#define TERM_VT100LIKE 0x20
|
||||
#define TERM_SIXEL 0x40
|
||||
#define TERM_KITTY 0x80
|
||||
int flags;
|
||||
|
||||
LIST_ENTRY(tty_term) entry;
|
||||
@@ -2644,7 +2620,7 @@ struct visible_ranges *tty_check_overlay_range(struct tty *, 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 *);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
void tty_draw_images(struct client *, struct window_pane *, struct screen *);
|
||||
#endif
|
||||
|
||||
@@ -2678,22 +2654,10 @@ 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_IMAGES
|
||||
int tty_set_client_cb(struct tty_ctx *, struct client *);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
void tty_cmd_sixelimage(struct tty *, const struct tty_ctx *);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
void tty_cmd_kittyimage(struct tty *, const struct tty_ctx *);
|
||||
void tty_kitty_delete_all(struct tty *);
|
||||
void tty_kitty_delete_all_pane(struct window_pane *);
|
||||
void tty_kitty_passthrough(struct window_pane *, const char *, size_t,
|
||||
u_int, u_int);
|
||||
#endif
|
||||
|
||||
void tty_cmd_syncstart(struct tty *, const struct tty_ctx *);
|
||||
void tty_default_colours(struct grid_cell *, struct window_pane *);
|
||||
|
||||
@@ -3296,15 +3260,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_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
void screen_write_sixelimage(struct screen_write_ctx *,
|
||||
struct sixel_image *, u_int);
|
||||
#endif
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
void screen_write_kittyimage(struct screen_write_ctx *,
|
||||
struct kitty_image *);
|
||||
#endif
|
||||
|
||||
void screen_write_alternateon(struct screen_write_ctx *,
|
||||
struct grid_cell *, int);
|
||||
void screen_write_alternateoff(struct screen_write_ctx *,
|
||||
@@ -3768,16 +3727,14 @@ struct window_pane *spawn_pane(struct spawn_context *, char **);
|
||||
/* regsub.c */
|
||||
char *regsub(const char *, const char *, const char *, int);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
/* image.c */
|
||||
int image_free_all(struct screen *);
|
||||
struct image *image_store(struct screen *, enum image_type, void *);
|
||||
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);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
/* image-sixel.c */
|
||||
#define SIXEL_COLOUR_REGISTERS 1024
|
||||
struct sixel_image *sixel_parse(const char *, size_t, u_int, u_int, u_int);
|
||||
@@ -3791,18 +3748,6 @@ char *sixel_print(struct sixel_image *, struct sixel_image *,
|
||||
struct screen *sixel_to_screen(struct sixel_image *);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
/* image-kitty.c */
|
||||
struct kitty_image *kitty_parse(const u_char *, size_t, u_int, u_int);
|
||||
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_delete_all(size_t *);
|
||||
#endif
|
||||
|
||||
/* server-acl.c */
|
||||
void server_acl_init(void);
|
||||
struct server_acl_user *server_acl_user_find(uid_t);
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 172 KiB |
@@ -357,17 +357,6 @@ static const struct tty_feature tty_feature_sixel = {
|
||||
TERM_SIXEL
|
||||
};
|
||||
|
||||
/* Terminal has kitty graphics protocol capability. */
|
||||
static const char *const tty_feature_kitty_capabilities[] = {
|
||||
"Kty",
|
||||
NULL
|
||||
};
|
||||
static const struct tty_feature tty_feature_kitty = {
|
||||
"kitty",
|
||||
tty_feature_kitty_capabilities,
|
||||
TERM_KITTY
|
||||
};
|
||||
|
||||
/* Available terminal features. */
|
||||
static const struct tty_feature *const tty_features[] = {
|
||||
&tty_feature_256,
|
||||
@@ -379,7 +368,6 @@ static const struct tty_feature *const tty_features[] = {
|
||||
&tty_feature_extkeys,
|
||||
&tty_feature_focus,
|
||||
&tty_feature_ignorefkeys,
|
||||
&tty_feature_kitty,
|
||||
&tty_feature_margins,
|
||||
&tty_feature_mouse,
|
||||
&tty_feature_osc7,
|
||||
@@ -512,19 +500,7 @@ tty_default_features(int *feat, const char *name, u_int version)
|
||||
*/
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM
|
||||
",ccolour,cstyle,extkeys,focus"
|
||||
},
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
{ .name = "kitty",
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM
|
||||
",ccolour,cstyle,extkeys,focus,sync,hyperlinks"
|
||||
",kitty"
|
||||
},
|
||||
{ .name = "ghostty",
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM
|
||||
",ccolour,cstyle,extkeys,focus,sync,hyperlinks"
|
||||
",kitty"
|
||||
},
|
||||
#endif
|
||||
}
|
||||
};
|
||||
u_int i;
|
||||
|
||||
|
||||
96
tty-keys.c
96
tty-keys.c
@@ -60,10 +60,6 @@ static int tty_keys_device_attributes2(struct tty *, const char *, size_t,
|
||||
static int tty_keys_extended_device_attributes(struct tty *, const char *,
|
||||
size_t, size_t *);
|
||||
static int tty_keys_palette(struct tty *, const char *, size_t, size_t *);
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
static int tty_keys_kitty_graphics(struct tty *, const char *, size_t,
|
||||
size_t *);
|
||||
#endif
|
||||
|
||||
/* A key tree entry. */
|
||||
struct tty_key {
|
||||
@@ -763,19 +759,6 @@ tty_keys_next(struct tty *tty)
|
||||
goto partial_key;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
/* Is this a kitty graphics protocol response? ESC _ G ... ESC \ */
|
||||
switch (tty_keys_kitty_graphics(tty, buf, len, &size)) {
|
||||
case 0: /* yes */
|
||||
key = KEYC_UNKNOWN;
|
||||
goto complete_key;
|
||||
case -1: /* no, or not valid */
|
||||
break;
|
||||
case 1: /* partial */
|
||||
goto partial_key;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Is this a primary device attributes response? */
|
||||
switch (tty_keys_device_attributes(tty, buf, len, &size)) {
|
||||
case 0: /* yes */
|
||||
@@ -1657,14 +1640,6 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
|
||||
tty_default_features(features, "mintty", 0);
|
||||
else if (strncmp(tmp, "foot(", 5) == 0)
|
||||
tty_default_features(features, "foot", 0);
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
else if (strncmp(tmp, "kitty ", 6) == 0 ||
|
||||
strcmp(tmp, "kitty") == 0)
|
||||
tty_default_features(features, "kitty", 0);
|
||||
else if (strncmp(tmp, "ghostty ", 8) == 0 ||
|
||||
strcmp(tmp, "ghostty") == 0)
|
||||
tty_default_features(features, "ghostty", 0);
|
||||
#endif
|
||||
log_debug("%s: received extended DA %.*s", c->name, (int)*size, buf);
|
||||
|
||||
free(c->term_type);
|
||||
@@ -1820,74 +1795,3 @@ tty_keys_palette(struct tty *tty, const char *buf, size_t len, size_t *size)
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
/*
|
||||
* Handle kitty graphics protocol response from outer terminal.
|
||||
* Format: ESC _ G <key=value,...> ; <message> ESC \
|
||||
* The response to our capability probe (a=q) is:
|
||||
* ESC _ G i=31;OK ESC \ (supported)
|
||||
* ESC _ G i=31;ENOSYS:... (not supported)
|
||||
* Returns 0 for success, -1 for not a kitty response, 1 for partial.
|
||||
*/
|
||||
static int
|
||||
tty_keys_kitty_graphics(struct tty *tty, const char *buf, size_t len,
|
||||
size_t *size)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
int *features = &c->term_features;
|
||||
const char *semi;
|
||||
size_t i;
|
||||
char tmp[256];
|
||||
|
||||
*size = 0;
|
||||
|
||||
/*
|
||||
* Kitty APC response starts with ESC _ G (3 bytes).
|
||||
* The 8-bit C1 equivalent 0x9f could also be used but is rare.
|
||||
*/
|
||||
if (buf[0] != '\033')
|
||||
return (-1);
|
||||
if (len == 1)
|
||||
return (1);
|
||||
if (buf[1] != '_')
|
||||
return (-1);
|
||||
if (len == 2)
|
||||
return (1);
|
||||
if (buf[2] != 'G')
|
||||
return (-1);
|
||||
if (len == 3)
|
||||
return (1);
|
||||
|
||||
/* Collect body up to ESC \ (ST). */
|
||||
for (i = 0; i < sizeof(tmp) - 1; i++) {
|
||||
if (3 + i + 1 >= len)
|
||||
return (1); /* partial */
|
||||
if (buf[3 + i] == '\033' && buf[3 + i + 1] == '\\') {
|
||||
tmp[i] = '\0';
|
||||
*size = 3 + i + 2;
|
||||
break;
|
||||
}
|
||||
tmp[i] = buf[3 + i];
|
||||
}
|
||||
if (i == sizeof(tmp) - 1)
|
||||
return (-1); /* too long, not a valid response */
|
||||
|
||||
log_debug("%s: kitty graphics response: %s", c->name, tmp);
|
||||
|
||||
/*
|
||||
* Check if the message (after the semicolon) starts with "OK".
|
||||
* The format is: i=31;OK or i=31;ENOSYS:...
|
||||
*/
|
||||
semi = strchr(tmp, ';');
|
||||
if (semi != NULL && strncmp(semi + 1, "OK", 2) == 0) {
|
||||
log_debug("%s: kitty graphics supported", c->name);
|
||||
tty_add_features(features, "kitty", ",");
|
||||
tty_update_features(tty);
|
||||
} else {
|
||||
log_debug("%s: kitty graphics not supported", c->name);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -461,9 +461,6 @@ tty_term_apply_overrides(struct tty_term *term)
|
||||
/* Log the SIXEL flag. */
|
||||
log_debug("SIXEL flag is %d", !!(term->flags & TERM_SIXEL));
|
||||
|
||||
/* Log the KITTY flag. */
|
||||
log_debug("KITTY flag is %d", !!(term->flags & TERM_KITTY));
|
||||
|
||||
/* Update the RGB flag if the terminal has RGB colours. */
|
||||
if (tty_term_has(term, TTYC_SETRGBF) &&
|
||||
tty_term_has(term, TTYC_SETRGBB))
|
||||
|
||||
182
tty.c
182
tty.c
@@ -67,7 +67,7 @@ static void tty_emulate_repeat(struct tty *, enum tty_code_code,
|
||||
static void tty_draw_pane(struct tty *, const struct tty_ctx *, u_int);
|
||||
static int tty_check_overlay(struct tty *, u_int, u_int);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
static void tty_write_one(void (*)(struct tty *, const struct tty_ctx *),
|
||||
struct client *, struct tty_ctx *);
|
||||
#endif
|
||||
@@ -391,23 +391,6 @@ tty_send_requests(struct tty *tty)
|
||||
return;
|
||||
|
||||
if (tty->term->flags & TERM_VT100LIKE) {
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
/*
|
||||
* Send the kitty graphics capability probe BEFORE the DA1
|
||||
* request. Per the kitty spec, a supporting terminal sends
|
||||
* its APC response before processing any subsequent requests.
|
||||
* So the reply ordering will be:
|
||||
* 1. ESC _ G i=31;OK ESC \ (kitty response, if supported)
|
||||
* 2. ESC [ ? ... c (DA1 response)
|
||||
* 3. ESC [ > ... c (DA2 response)
|
||||
* 4. ESC P > | ... ESC \ (XDA response)
|
||||
* which is exactly what our parsers expect.
|
||||
* Only probe if the kitty feature isn't already enabled.
|
||||
*/
|
||||
if (~tty->term->flags & TERM_KITTY)
|
||||
tty_puts(tty,
|
||||
"\033_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\033\\");
|
||||
#endif
|
||||
if (~tty->flags & TTY_HAVEDA)
|
||||
tty_puts(tty, "\033[c");
|
||||
if (~tty->flags & TTY_HAVEDA2)
|
||||
@@ -1459,9 +1442,9 @@ tty_check_overlay_range(struct tty *tty, u_int px, u_int py, u_int nx)
|
||||
return (c->overlay_check(c, c->overlay_data, px, py, nx));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
/* Update context for client. */
|
||||
int
|
||||
static int
|
||||
tty_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
|
||||
{
|
||||
struct window_pane *wp = ttyctx->arg;
|
||||
@@ -1506,22 +1489,7 @@ tty_draw_images(struct client *c, struct window_pane *wp, struct screen *s)
|
||||
ttyctx.arg = wp;
|
||||
ttyctx.set_client_cb = tty_set_client_cb;
|
||||
ttyctx.allow_invisible_panes = 1;
|
||||
|
||||
/* Call the appropriate rendering function based on image type */
|
||||
switch (im->type) {
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
case IMAGE_SIXEL:
|
||||
tty_write_one(tty_cmd_sixelimage, c, &ttyctx);
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
case IMAGE_KITTY:
|
||||
tty_write_one(tty_cmd_kittyimage, c, &ttyctx);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
tty_write_one(tty_cmd_sixelimage, c, &ttyctx);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1599,7 +1567,7 @@ tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *),
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
#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 *),
|
||||
@@ -2124,12 +2092,12 @@ tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx)
|
||||
tty_invalidate(tty);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SIXEL_IMAGES
|
||||
#ifdef ENABLE_SIXEL
|
||||
void
|
||||
tty_cmd_sixelimage(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
struct image *im = ctx->ptr;
|
||||
struct sixel_image *si = im->data.sixel;
|
||||
struct sixel_image *si = im->data;
|
||||
struct sixel_image *new;
|
||||
char *data;
|
||||
size_t size;
|
||||
@@ -2176,142 +2144,6 @@ tty_cmd_sixelimage(struct tty *tty, const struct tty_ctx *ctx)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_KITTY_IMAGES
|
||||
static int
|
||||
tty_has_kitty(struct tty *tty)
|
||||
{
|
||||
return (tty->term->flags & TERM_KITTY);
|
||||
}
|
||||
|
||||
void
|
||||
tty_cmd_kittyimage(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
struct image *im = ctx->ptr;
|
||||
char *data;
|
||||
size_t size;
|
||||
u_int cx = ctx->ocx, cy = ctx->ocy;
|
||||
int fallback = 0;
|
||||
|
||||
if (im == NULL || im->data.kitty == NULL)
|
||||
return;
|
||||
|
||||
/* Check if this terminal supports kitty graphics. */
|
||||
if (!tty_has_kitty(tty))
|
||||
fallback = 1;
|
||||
|
||||
log_debug("%s: image at %u,%u (fallback=%d)", __func__, cx, cy,
|
||||
fallback);
|
||||
|
||||
if (fallback == 1) {
|
||||
/* Use text fallback for non-kitty terminals. */
|
||||
data = xstrdup(im->fallback);
|
||||
size = strlen(data);
|
||||
} else {
|
||||
/* Re-serialize the kitty image command. */
|
||||
data = kitty_print(im->data.kitty, &size);
|
||||
}
|
||||
|
||||
if (data != NULL) {
|
||||
log_debug("%s: %zu bytes", __func__, size);
|
||||
tty_region_off(tty);
|
||||
tty_margin_off(tty);
|
||||
tty_cursor(tty, cx + ctx->xoff, cy + ctx->yoff);
|
||||
|
||||
tty->flags |= TTY_NOBLOCK;
|
||||
tty_add(tty, data, size);
|
||||
tty_invalidate(tty);
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass a kitty APC sequence directly to all attached kitty-capable clients
|
||||
* showing the given pane. The outer terminal's cursor is first moved to
|
||||
* the pane-relative position (cx, cy) so that images placed at "current
|
||||
* cursor" land in the right spot. Pass cx=cy=UINT_MAX to skip cursor
|
||||
* positioning (e.g. for delete commands that don't depend on position).
|
||||
*/
|
||||
void
|
||||
tty_kitty_passthrough(struct window_pane *wp, const char *data, size_t len,
|
||||
u_int cx, u_int cy)
|
||||
{
|
||||
struct client *c;
|
||||
struct tty *tty;
|
||||
u_int x, y;
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c->session == NULL || c->tty.term == NULL)
|
||||
continue;
|
||||
if (c->flags & CLIENT_SUSPENDED)
|
||||
continue;
|
||||
if (c->tty.flags & TTY_FREEZE)
|
||||
continue;
|
||||
tty = &c->tty;
|
||||
if (!tty_has_kitty(tty))
|
||||
continue;
|
||||
if (c->session->curw->window != wp->window)
|
||||
continue;
|
||||
if (!window_pane_visible(wp))
|
||||
continue;
|
||||
|
||||
/* Position cursor at the correct screen location. */
|
||||
if (cx != UINT_MAX && cy != UINT_MAX) {
|
||||
x = wp->xoff + cx;
|
||||
y = wp->yoff + cy;
|
||||
if (status_at_line(c) == 0)
|
||||
y += status_line_size(c);
|
||||
tty_region_off(tty);
|
||||
tty_margin_off(tty);
|
||||
tty_cursor(tty, x, y);
|
||||
}
|
||||
|
||||
tty->flags |= TTY_NOBLOCK;
|
||||
tty_add(tty, data, len);
|
||||
tty_invalidate(tty);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete all kitty image placements from the outer terminal unconditionally.
|
||||
* Called directly (not via tty_write) so it fires on every full window
|
||||
* redraw regardless of whether the current window has any stored images.
|
||||
*/
|
||||
void
|
||||
tty_kitty_delete_all(struct tty *tty)
|
||||
{
|
||||
char *data;
|
||||
size_t size;
|
||||
|
||||
if (!tty_has_kitty(tty))
|
||||
return;
|
||||
|
||||
if ((data = kitty_delete_all(&size)) == NULL)
|
||||
return;
|
||||
|
||||
tty->flags |= TTY_NOBLOCK;
|
||||
tty_add(tty, data, size);
|
||||
tty_invalidate(tty);
|
||||
free(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete all kitty image placements via passthrough for a specific pane.
|
||||
* Used on terminal reset (RIS) so images are cleared from the outer terminal.
|
||||
*/
|
||||
void
|
||||
tty_kitty_delete_all_pane(struct window_pane *wp)
|
||||
{
|
||||
char *data;
|
||||
size_t size;
|
||||
|
||||
if ((data = kitty_delete_all(&size)) == NULL)
|
||||
return;
|
||||
|
||||
tty_kitty_passthrough(wp, data, size, UINT_MAX, UINT_MAX);
|
||||
free(data);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
tty_cmd_syncstart(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user