C=1 is parsed and stored as an image-placement flag, suppressing cursor movement and scrolling as required by the Kitty protocol.

This commit is contained in:
Michael Grant
2026-08-05 11:54:22 +01:00
parent e602dfa771
commit 52e2e2b0c0
4 changed files with 53 additions and 11 deletions

View File

@@ -82,6 +82,7 @@ struct kitty_state {
u_int rows;
u_int image_id;
u_int quiet;
int no_cursor;
u_int data_size;
int more;
@@ -441,6 +442,7 @@ kitty_control(struct kitty_state *ks, const u_char *buf, size_t len)
case 'q':
case 'm':
case 'S':
case 'C':
if (kitty_number((const char *)value, valuelen,
&number) != 0)
return (-1);
@@ -458,6 +460,7 @@ kitty_control(struct kitty_state *ks, const u_char *buf, size_t len)
case 'q': ks->quiet = number; break;
case 'm': ks->more = (number != 0); break;
case 'S': ks->data_size = number; break;
case 'C': ks->no_cursor = (number != 0); break;
}
break;
}
@@ -622,6 +625,7 @@ kitty_place_image(struct image *source, struct kitty_state *ks, u_int xpixel,
uint64_t numerator, denominator, value;
u_int x, y, width, height, sx, sy, canvas_width;
u_int canvas_height, cell_width, cell_height;
struct image *im;
x = ks->source_x;
y = ks->source_y;
@@ -688,8 +692,11 @@ kitty_place_image(struct image *source, struct kitty_state *ks, u_int xpixel,
canvas_width = value;
}
return (image_create_view(source, x, y, width, height, canvas_width,
canvas_height, sx, sy));
im = image_create_view(source, x, y, width, height, canvas_width,
canvas_height, sx, sy);
if (im != NULL && ks->no_cursor)
im->flags |= IMAGE_FLAG_NO_CURSOR;
return (im);
}
/*

22
image.c
View File

@@ -580,34 +580,38 @@ image_write(struct screen_write_ctx *ctx, struct image *im, u_int bg)
struct grid *gd = s->grid;
struct grid_cell gc;
u_int cx = s->cx, cy = s->cy;
u_int x, y, sx, sy, lines;
u_int x, y, sx, sy, lines, origin_y = 0;
sx = im->sx;
if (sx > screen_size_x(s) - cx)
sx = screen_size_x(s) - cx;
sy = im->sy;
if (sy > screen_size_y(s) - 1)
sy = screen_size_y(s) - 1;
if (sx == 0 || sy == 0)
if (sx == 0)
return;
if (screen_size_y(s) - cy <= sy) {
if (im->flags & IMAGE_FLAG_NO_CURSOR) {
if (sy > screen_size_y(s) - cy)
sy = screen_size_y(s) - cy;
} else if (screen_size_y(s) - cy <= sy) {
lines = sy - (screen_size_y(s) - cy) + 1;
screen_write_scrollup(ctx, lines, bg);
if (lines > cy)
if (lines > cy) {
origin_y = lines - cy;
screen_write_cursormove(ctx, -1, 0, 0);
else
} else
screen_write_cursormove(ctx, -1, cy - lines, 0);
cy = s->cy;
sy -= origin_y;
}
for (y = 0; y < sy; y++) {
for (x = 0; x < sx; x++) {
image_set_cell(&gc, im, x, y);
image_set_cell(&gc, im, x, origin_y + y);
gc.bg = bg;
grid_view_set_cell(gd, cx + x, cy + y, &gc);
}
}
image_redraw_area(ctx, cx, cy, sx, sy);
screen_write_cursormove(ctx, 0, cy + sy, 0);
if (!(im->flags & IMAGE_FLAG_NO_CURSOR))
screen_write_cursormove(ctx, 0, cy + sy, 0);
}

View File

@@ -114,4 +114,33 @@ $TMUX capture-pane -pS0 -E1 >$TMP || exit 1
[ "$(sed -n 1p $TMP)" = "*" ] || exit 1
[ "$(sed -n 2p $TMP)" = "@" ] || exit 1
# C=1 places the image without moving the cursor or scrolling. The four-row
# image is clipped at the bottom of this four-row pane, leaving its white last
# row off screen.
$TMUX2 new-window -d "
printf '\033[2;3H'
printf '\033_Ga=T,q=2,C=1,f=32,s=1,v=4,c=1,r=4;AAAA/1VVVf+qqqr//////w==\033\\'
sleep 10" || exit 1
$TMUX2 select-window -t:1 || exit 1
sleep 1
[ "$($TMUX2 display-message -p '#{cursor_x},#{cursor_y}')" = "2,1" ] || exit 1
$TMUX capture-pane -pS0 -E3 >$TMP || exit 1
[ "$(sed -n 3p $TMP)" = " :" ] || exit 1
[ "$(sed -n 4p $TMP)" = " *" ] || exit 1
# With normal cursor movement, scrolling is calculated from the full image
# height. Rows which scrolled above the pane are then cropped from the top, so
# the bottom three source rows remain visible and the cursor is on the last row.
$TMUX2 new-window -d "
printf '\033[3;1H'
printf '\033_Ga=T,q=2,f=32,s=1,v=4,c=1,r=4;AAAA/1VVVf+qqqr//////w==\033\\'
sleep 10" || exit 1
$TMUX2 select-window -t:2 || exit 1
sleep 1
[ "$($TMUX2 display-message -p '#{cursor_y}')" = 3 ] || exit 1
$TMUX capture-pane -pS0 -E3 >$TMP || exit 1
[ "$(sed -n 1p $TMP)" = ":" ] || exit 1
[ "$(sed -n 2p $TMP)" = "*" ] || exit 1
[ "$(sed -n 3p $TMP)" = "@" ] || exit 1
exit 0

2
tmux.h
View File

@@ -1051,6 +1051,7 @@ struct image_sample {
/* Half blocks, quadrants and sextants all divide evenly into a 2 by 6 grid. */
#define IMAGE_SAMPLE_COLUMNS 2
#define IMAGE_SAMPLE_ROWS 6
#define IMAGE_FLAG_NO_CURSOR 0x1
struct image_cell {
struct image_sample whole;
struct image_sample samples[IMAGE_SAMPLE_ROWS][IMAGE_SAMPLE_COLUMNS];
@@ -1060,6 +1061,7 @@ struct image_cell {
struct image {
u_int id;
u_int references;
u_int flags;
u_int parent_id;
u_int source_id;
u_int width;