mirror of
https://github.com/tmux/tmux.git
synced 2026-10-14 06:44:28 +00:00
Merge master into 4902-image-support
This commit is contained in:
@@ -211,6 +211,7 @@ dist_tmux_SOURCES = \
|
|||||||
style.c \
|
style.c \
|
||||||
tmux-protocol.h \
|
tmux-protocol.h \
|
||||||
tmux.c \
|
tmux.c \
|
||||||
|
tmux-image.h \
|
||||||
tmux.h \
|
tmux.h \
|
||||||
tty-acs.c \
|
tty-acs.c \
|
||||||
tty-draw.c \
|
tty-draw.c \
|
||||||
@@ -252,7 +253,12 @@ endif
|
|||||||
|
|
||||||
# Enable image support.
|
# Enable image support.
|
||||||
if ENABLE_IMAGES
|
if ENABLE_IMAGES
|
||||||
dist_tmux_SOURCES += image.c image-sixel.c image-kitty.c image-fallback.c
|
dist_tmux_SOURCES += \
|
||||||
|
image.c \
|
||||||
|
image-grid.c \
|
||||||
|
image-sixel.c \
|
||||||
|
image-kitty.c \
|
||||||
|
image-fallback.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Add bits for fuzzing if enabled.
|
# Add bits for fuzzing if enabled.
|
||||||
|
|||||||
16
format.c
16
format.c
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: format.c,v 1.427 2026/10/12 12:22:42 nicm Exp $ */
|
/* $OpenBSD: format.c,v 1.428 2026/10/13 10:21:58 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -2354,6 +2354,17 @@ format_cb_pane_last_prompt_time(struct format_tree *ft)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Callback for pane_command_line. */
|
||||||
|
static void *
|
||||||
|
format_cb_pane_command_line(struct format_tree *ft)
|
||||||
|
{
|
||||||
|
struct window_pane *wp = ft->wp;
|
||||||
|
|
||||||
|
if (wp != NULL && wp->cmd_line != NULL)
|
||||||
|
return (xstrdup(wp->cmd_line));
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Callback for pane_command_start_time. */
|
/* Callback for pane_command_start_time. */
|
||||||
static void *
|
static void *
|
||||||
format_cb_pane_command_start_time(struct format_tree *ft)
|
format_cb_pane_command_start_time(struct format_tree *ft)
|
||||||
@@ -3843,6 +3854,9 @@ static const struct format_table_entry format_table[] = {
|
|||||||
{ "pane_command_end_time", FORMAT_TABLE_TIME,
|
{ "pane_command_end_time", FORMAT_TABLE_TIME,
|
||||||
format_cb_pane_command_end_time
|
format_cb_pane_command_end_time
|
||||||
},
|
},
|
||||||
|
{ "pane_command_line", FORMAT_TABLE_STRING,
|
||||||
|
format_cb_pane_command_line
|
||||||
|
},
|
||||||
{ "pane_command_running", FORMAT_TABLE_STRING,
|
{ "pane_command_running", FORMAT_TABLE_STRING,
|
||||||
format_cb_pane_command_running
|
format_cb_pane_command_running
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ grid_view_clear_history(struct grid *gd, u_int bg)
|
|||||||
gl = grid_get_line(gd, grid_view_y(gd, yy));
|
gl = grid_get_line(gd, grid_view_y(gd, yy));
|
||||||
if (gl->cellused != 0)
|
if (gl->cellused != 0)
|
||||||
last = yy + 1;
|
last = yy + 1;
|
||||||
|
#ifdef ENABLE_IMAGES
|
||||||
|
else if (image_grid_line_has_images(gl))
|
||||||
|
last = yy + 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (last == 0) {
|
if (last == 0) {
|
||||||
grid_view_clear(gd, 0, 0, gd->sx, gd->sy, bg);
|
grid_view_clear(gd, 0, 0, gd->sx, gd->sy, bg);
|
||||||
|
|||||||
13
grid.c
13
grid.c
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: grid.c,v 1.160 2026/10/12 08:08:37 nicm Exp $ */
|
/* $OpenBSD: grid.c,v 1.161 2026/10/12 15:40:17 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -701,6 +701,9 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg)
|
|||||||
return;
|
return;
|
||||||
if (grid_check_y(gd, __func__, py + ny - 1) != 0)
|
if (grid_check_y(gd, __func__, py + ny - 1) != 0)
|
||||||
return;
|
return;
|
||||||
|
#ifdef ENABLE_IMAGES
|
||||||
|
image_grid_remove(gd, px, py, nx, ny);
|
||||||
|
#endif
|
||||||
|
|
||||||
for (yy = py; yy < py + ny; yy++) {
|
for (yy = py; yy < py + ny; yy++) {
|
||||||
gl = &gd->linedata[yy];
|
gl = &gd->linedata[yy];
|
||||||
@@ -1262,17 +1265,13 @@ grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy,
|
|||||||
struct grid_line *dstl, *srcl;
|
struct grid_line *dstl, *srcl;
|
||||||
u_int yy;
|
u_int yy;
|
||||||
#ifdef ENABLE_IMAGES
|
#ifdef ENABLE_IMAGES
|
||||||
u_int original_dy, original_sy;
|
u_int ody = dy, osy = sy;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (dy + ny > dst->hsize + dst->sy)
|
if (dy + ny > dst->hsize + dst->sy)
|
||||||
ny = dst->hsize + dst->sy - dy;
|
ny = dst->hsize + dst->sy - dy;
|
||||||
if (sy + ny > src->hsize + src->sy)
|
if (sy + ny > src->hsize + src->sy)
|
||||||
ny = src->hsize + src->sy - sy;
|
ny = src->hsize + src->sy - sy;
|
||||||
#ifdef ENABLE_IMAGES
|
|
||||||
original_dy = dy;
|
|
||||||
original_sy = sy;
|
|
||||||
#endif
|
|
||||||
grid_free_lines(dst, dy, ny);
|
grid_free_lines(dst, dy, ny);
|
||||||
|
|
||||||
for (yy = 0; yy < ny; yy++) {
|
for (yy = 0; yy < ny; yy++) {
|
||||||
@@ -1303,7 +1302,7 @@ grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy,
|
|||||||
dy++;
|
dy++;
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_IMAGES
|
#ifdef ENABLE_IMAGES
|
||||||
image_grid_duplicate_lines(dst, original_dy, src, original_sy, ny);
|
image_grid_duplicate_lines(dst, ody, src, osy, ny);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -252,27 +252,31 @@ fallback_block_key(enum image_glyph_detail detail, u_int mask)
|
|||||||
static u_char *
|
static u_char *
|
||||||
fallback_make_shades(struct image *im, u_int levels)
|
fallback_make_shades(struct image *im, u_int levels)
|
||||||
{
|
{
|
||||||
struct image_glyph_data *data = im->fallback_data;
|
struct image_glyph_data *data = image_get_fallback_data(im);
|
||||||
const struct image_cell *cell;
|
const struct image_cell *cell;
|
||||||
int *values, value, represented, error;
|
int *values, value, represented, error;
|
||||||
size_t cells, index;
|
size_t cells, index;
|
||||||
u_int x, y, scan, level, minimum = 255, maximum = 0;
|
u_int x, y, scan, level, minimum = 255, maximum = 0;
|
||||||
|
u_int sx, sy;
|
||||||
int reverse;
|
int reverse;
|
||||||
u_char *result;
|
u_char *result;
|
||||||
|
|
||||||
if (data == NULL)
|
if (data == NULL) {
|
||||||
data = im->fallback_data = xcalloc(1, sizeof *data);
|
data = xcalloc(1, sizeof *data);
|
||||||
|
image_set_fallback_data(im, data);
|
||||||
|
}
|
||||||
|
image_get_size_in_cells(im, &sx, &sy);
|
||||||
result = (levels == 5 ? data->shade5 : data->shade8);
|
result = (levels == 5 ? data->shade5 : data->shade8);
|
||||||
if (result != NULL)
|
if (result != NULL)
|
||||||
return (result);
|
return (result);
|
||||||
|
|
||||||
/* Collect cell brightness and the range used by this image. */
|
/* Collect cell brightness and the range used by this image. */
|
||||||
cells = (size_t)im->sx * im->sy;
|
cells = (size_t)sx * sy;
|
||||||
values = xcalloc(cells, sizeof *values);
|
values = xcalloc(cells, sizeof *values);
|
||||||
result = xcalloc(cells, 1);
|
result = xcalloc(cells, 1);
|
||||||
for (y = 0; y < im->sy; y++) {
|
for (y = 0; y < sy; y++) {
|
||||||
for (x = 0; x < im->sx; x++) {
|
for (x = 0; x < sx; x++) {
|
||||||
index = (size_t)y * im->sx + x;
|
index = (size_t)y * sx + x;
|
||||||
cell = image_get_cell(im, x, y);
|
cell = image_get_cell(im, x, y);
|
||||||
value = cell->whole.brightness;
|
value = cell->whole.brightness;
|
||||||
if ((u_int)value < minimum)
|
if ((u_int)value < minimum)
|
||||||
@@ -291,11 +295,11 @@ fallback_make_shades(struct image *im, u_int levels)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Dither each row, alternating direction to distribute the error. */
|
/* Dither each row, alternating direction to distribute the error. */
|
||||||
for (y = 0; y < im->sy; y++) {
|
for (y = 0; y < sy; y++) {
|
||||||
reverse = (y & 1);
|
reverse = (y & 1);
|
||||||
for (scan = 0; scan < im->sx; scan++) {
|
for (scan = 0; scan < sx; scan++) {
|
||||||
x = (reverse ? im->sx - scan - 1 : scan);
|
x = (reverse ? sx - scan - 1 : scan);
|
||||||
index = (size_t)y * im->sx + x;
|
index = (size_t)y * sx + x;
|
||||||
value = values[index];
|
value = values[index];
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
value = 0;
|
value = 0;
|
||||||
@@ -305,21 +309,21 @@ fallback_make_shades(struct image *im, u_int levels)
|
|||||||
result[index] = level;
|
result[index] = level;
|
||||||
represented = level * 255 / (levels - 1);
|
represented = level * 255 / (levels - 1);
|
||||||
error = value - represented;
|
error = value - represented;
|
||||||
if (!reverse && x + 1 < im->sx)
|
if (!reverse && x + 1 < sx)
|
||||||
values[index + 1] += error * 7 / 16;
|
values[index + 1] += error * 7 / 16;
|
||||||
if (reverse && x != 0)
|
if (reverse && x != 0)
|
||||||
values[index - 1] += error * 7 / 16;
|
values[index - 1] += error * 7 / 16;
|
||||||
if (y + 1 == im->sy)
|
if (y + 1 == sy)
|
||||||
continue;
|
continue;
|
||||||
if (!reverse && x != 0)
|
if (!reverse && x != 0)
|
||||||
values[index + im->sx - 1] += error * 3 / 16;
|
values[index + sx - 1] += error * 3 / 16;
|
||||||
if (reverse && x + 1 < im->sx)
|
if (reverse && x + 1 < sx)
|
||||||
values[index + im->sx + 1] += error * 3 / 16;
|
values[index + sx + 1] += error * 3 / 16;
|
||||||
values[index + im->sx] += error * 5 / 16;
|
values[index + sx] += error * 5 / 16;
|
||||||
if (!reverse && x + 1 < im->sx)
|
if (!reverse && x + 1 < sx)
|
||||||
values[index + im->sx + 1] += error / 16;
|
values[index + sx + 1] += error / 16;
|
||||||
if (reverse && x != 0)
|
if (reverse && x != 0)
|
||||||
values[index + im->sx - 1] += error / 16;
|
values[index + sx - 1] += error / 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(values);
|
free(values);
|
||||||
@@ -447,7 +451,7 @@ fallback_get_cell(struct tty *tty, struct image *im, u_int x, u_int y,
|
|||||||
enum image_glyph_palette palette;
|
enum image_glyph_palette palette;
|
||||||
enum image_glyph_detail detail;
|
enum image_glyph_detail detail;
|
||||||
u_char *levels, key;
|
u_char *levels, key;
|
||||||
u_int level = 0, nlevels;
|
u_int level = 0, nlevels, sx, sy;
|
||||||
|
|
||||||
memcpy(out, gc, sizeof *out);
|
memcpy(out, gc, sizeof *out);
|
||||||
cell = image_get_cell(im, x, y);
|
cell = image_get_cell(im, x, y);
|
||||||
@@ -469,7 +473,8 @@ fallback_get_cell(struct tty *tty, struct image *im, u_int x, u_int y,
|
|||||||
if (detail == IMAGE_GLYPH_SHADE5)
|
if (detail == IMAGE_GLYPH_SHADE5)
|
||||||
nlevels = 5;
|
nlevels = 5;
|
||||||
levels = fallback_make_shades(im, nlevels);
|
levels = fallback_make_shades(im, nlevels);
|
||||||
level = levels[(size_t)y * im->sx + x];
|
image_get_size_in_cells(im, &sx, &sy);
|
||||||
|
level = levels[(size_t)y * sx + x];
|
||||||
key = (detail == IMAGE_GLYPH_SHADE5 ? shades[level] :
|
key = (detail == IMAGE_GLYPH_SHADE5 ? shades[level] :
|
||||||
bold_shades[level]);
|
bold_shades[level]);
|
||||||
if (key == 0)
|
if (key == 0)
|
||||||
@@ -492,7 +497,7 @@ fallback_get_cell(struct tty *tty, struct image *im, u_int x, u_int y,
|
|||||||
void
|
void
|
||||||
fallback_free(struct image *im)
|
fallback_free(struct image *im)
|
||||||
{
|
{
|
||||||
struct image_glyph_data *data = im->fallback_data;
|
struct image_glyph_data *data = image_get_fallback_data(im);
|
||||||
|
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
return;
|
return;
|
||||||
|
|||||||
1491
image-grid.c
Normal file
1491
image-grid.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -595,7 +595,7 @@ kitty_upload(struct tty *tty, struct image *im)
|
|||||||
} while (id == 0);
|
} while (id == 0);
|
||||||
entry->server_id = image_get_id(im);
|
entry->server_id = image_get_id(im);
|
||||||
entry->kitty_id = id;
|
entry->kitty_id = id;
|
||||||
entry->order_id = im->order_id;
|
entry->order_id = image_get_order_id(im);
|
||||||
entry->xpixel = tty->xpixel;
|
entry->xpixel = tty->xpixel;
|
||||||
entry->ypixel = tty->ypixel;
|
entry->ypixel = tty->ypixel;
|
||||||
entry->next_placement = 0;
|
entry->next_placement = 0;
|
||||||
@@ -843,7 +843,7 @@ kitty_placements_free(struct kitty_source *source)
|
|||||||
for (placement = source->placements; placement != NULL;
|
for (placement = source->placements; placement != NULL;
|
||||||
placement = next) {
|
placement = next) {
|
||||||
next = placement->next;
|
next = placement->next;
|
||||||
image_free(placement->server_id);
|
image_free(image_find(placement->server_id));
|
||||||
free(placement);
|
free(placement);
|
||||||
}
|
}
|
||||||
source->placements = NULL;
|
source->placements = NULL;
|
||||||
@@ -854,7 +854,7 @@ static void
|
|||||||
kitty_source_free(struct kitty_source *source)
|
kitty_source_free(struct kitty_source *source)
|
||||||
{
|
{
|
||||||
kitty_placements_free(source);
|
kitty_placements_free(source);
|
||||||
image_free(source->server_id);
|
image_free(image_find(source->server_id));
|
||||||
free(source);
|
free(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -908,11 +908,11 @@ kitty_source_set(struct kitty_context *kc, u_int id, struct image *im)
|
|||||||
old_id = source->server_id;
|
old_id = source->server_id;
|
||||||
old = image_find(old_id);
|
old = image_find(old_id);
|
||||||
if (old != NULL)
|
if (old != NULL)
|
||||||
im->order_id = old->order_id;
|
image_set_order_id(im, image_get_order_id(old));
|
||||||
kitty_placements_free(source);
|
kitty_placements_free(source);
|
||||||
image_free(source->server_id);
|
image_free(image_find(source->server_id));
|
||||||
}
|
}
|
||||||
image_ref(image_get_id(im));
|
image_ref(im);
|
||||||
source->server_id = image_get_id(im);
|
source->server_id = image_get_id(im);
|
||||||
return (old_id);
|
return (old_id);
|
||||||
}
|
}
|
||||||
@@ -945,10 +945,10 @@ kitty_placement_set(struct kitty_context *kc, const struct kitty_state *ks,
|
|||||||
old_id = placement->server_id;
|
old_id = placement->server_id;
|
||||||
placement->z = ks->z;
|
placement->z = ks->z;
|
||||||
placement->virtual = ks->virtual;
|
placement->virtual = ks->virtual;
|
||||||
image_ref(image_get_id(im));
|
image_ref(im);
|
||||||
placement->server_id = image_get_id(im);
|
placement->server_id = image_get_id(im);
|
||||||
if (old_id != 0)
|
if (old_id != 0)
|
||||||
image_free(old_id);
|
image_free(image_find(old_id));
|
||||||
return (old_id);
|
return (old_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -964,7 +964,7 @@ kitty_source_get(struct kitty_context *kc, u_int id)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
im = image_find(source->server_id);
|
im = image_find(source->server_id);
|
||||||
if (im != NULL)
|
if (im != NULL)
|
||||||
image_ref(image_get_id(im));
|
image_ref(im);
|
||||||
return (im);
|
return (im);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -981,7 +981,7 @@ kitty_prune_placements(struct kitty_source *source, struct grid *gd)
|
|||||||
if (image_grid_has_image(gd, placement->server_id))
|
if (image_grid_has_image(gd, placement->server_id))
|
||||||
goto keep;
|
goto keep;
|
||||||
*pp = placement->next;
|
*pp = placement->next;
|
||||||
image_free(placement->server_id);
|
image_free(image_find(placement->server_id));
|
||||||
free(placement);
|
free(placement);
|
||||||
removed++;
|
removed++;
|
||||||
continue;
|
continue;
|
||||||
@@ -1040,7 +1040,7 @@ kitty_delete_images(void *state, struct screen_write_ctx *ctx,
|
|||||||
goto keep_placement;
|
goto keep_placement;
|
||||||
}
|
}
|
||||||
*pp = placement->next;
|
*pp = placement->next;
|
||||||
image_free(placement->server_id);
|
image_free(image_find(placement->server_id));
|
||||||
free(placement);
|
free(placement);
|
||||||
removed++;
|
removed++;
|
||||||
continue;
|
continue;
|
||||||
@@ -1272,20 +1272,20 @@ kitty_place_image(struct image *source, struct kitty_state *ks, u_int xpixel,
|
|||||||
view.scaled_height = floor(view.height * height_scale * units);
|
view.scaled_height = floor(view.height * height_scale * units);
|
||||||
if (view.scaled_height < view.height)
|
if (view.scaled_height < view.height)
|
||||||
view.scaled_height = view.height;
|
view.scaled_height = view.height;
|
||||||
view.x_offset = floor(x_offset * units);
|
view.canvas_xoff = floor(x_offset * units);
|
||||||
view.y_offset = floor(y_offset * units);
|
view.canvas_yoff = floor(y_offset * units);
|
||||||
if (view.x_offset > view.canvas_width ||
|
if (view.canvas_xoff > view.canvas_width ||
|
||||||
view.scaled_width > view.canvas_width - view.x_offset ||
|
view.scaled_width > view.canvas_width - view.canvas_xoff ||
|
||||||
view.y_offset > view.canvas_height ||
|
view.canvas_yoff > view.canvas_height ||
|
||||||
view.scaled_height > view.canvas_height - view.y_offset) {
|
view.scaled_height > view.canvas_height - view.canvas_yoff) {
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Centre Unicode-placeholder images within their rectangle. */
|
/* Centre Unicode-placeholder images within their rectangle. */
|
||||||
if (ks->virtual && ks->columns != 0 && ks->rows != 0) {
|
if (ks->virtual && ks->columns != 0 && ks->rows != 0) {
|
||||||
view.x_offset += (view.canvas_width - view.x_offset -
|
view.canvas_xoff += (view.canvas_width - view.canvas_xoff -
|
||||||
view.scaled_width) / 2;
|
view.scaled_width) / 2;
|
||||||
view.y_offset += (view.canvas_height - view.y_offset -
|
view.canvas_yoff += (view.canvas_height - view.canvas_yoff -
|
||||||
view.scaled_height) / 2;
|
view.scaled_height) / 2;
|
||||||
}
|
}
|
||||||
/* Let the output terminal scale unpadded rectangular placements. */
|
/* Let the output terminal scale unpadded rectangular placements. */
|
||||||
@@ -1297,8 +1297,8 @@ kitty_place_image(struct image *source, struct kitty_state *ks, u_int xpixel,
|
|||||||
view.scaled_width = view.width;
|
view.scaled_width = view.width;
|
||||||
view.canvas_height = view.height;
|
view.canvas_height = view.height;
|
||||||
view.scaled_height = view.height;
|
view.scaled_height = view.height;
|
||||||
view.x_offset = 0;
|
view.canvas_xoff = 0;
|
||||||
view.y_offset = 0;
|
view.canvas_yoff = 0;
|
||||||
}
|
}
|
||||||
im = image_create_view(source, &view);
|
im = image_create_view(source, &view);
|
||||||
if (im != NULL && ks->no_cursor)
|
if (im != NULL && ks->no_cursor)
|
||||||
@@ -1401,17 +1401,17 @@ kitty_parse_image(void **state, const u_char *buf, size_t len, u_int xpixel,
|
|||||||
im = NULL;
|
im = NULL;
|
||||||
} else if (ks->virtual) {
|
} else if (ks->virtual) {
|
||||||
im = kitty_place_image(source, ks, xpixel, ypixel);
|
im = kitty_place_image(source, ks, xpixel, ypixel);
|
||||||
image_free(image_get_id(source));
|
image_free(source);
|
||||||
if (im != NULL) {
|
if (im != NULL) {
|
||||||
(void)kitty_placement_set(kc, ks, im);
|
(void)kitty_placement_set(kc, ks, im);
|
||||||
image_free(image_get_id(im));
|
image_free(im);
|
||||||
im = NULL;
|
im = NULL;
|
||||||
result->action = 'u';
|
result->action = 'u';
|
||||||
result->status = KITTY_PARSE_OK;
|
result->status = KITTY_PARSE_OK;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
im = kitty_place_image(source, ks, xpixel, ypixel);
|
im = kitty_place_image(source, ks, xpixel, ypixel);
|
||||||
image_free(image_get_id(source));
|
image_free(source);
|
||||||
if (im != NULL) {
|
if (im != NULL) {
|
||||||
result->replace_id =
|
result->replace_id =
|
||||||
kitty_placement_set(kc, ks, im);
|
kitty_placement_set(kc, ks, im);
|
||||||
@@ -1524,14 +1524,14 @@ kitty_parse_image(void **state, const u_char *buf, size_t len, u_int xpixel,
|
|||||||
result->status = KITTY_PARSE_ERROR;
|
result->status = KITTY_PARSE_ERROR;
|
||||||
else {
|
else {
|
||||||
(void)kitty_placement_set(kc, ks, im);
|
(void)kitty_placement_set(kc, ks, im);
|
||||||
image_free(image_get_id(im));
|
image_free(im);
|
||||||
im = NULL;
|
im = NULL;
|
||||||
result->action = 'u';
|
result->action = 'u';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
im = NULL;
|
im = NULL;
|
||||||
}
|
}
|
||||||
image_free(image_get_id(source));
|
image_free(source);
|
||||||
}
|
}
|
||||||
kitty_state_free(ks);
|
kitty_state_free(ks);
|
||||||
return (im);
|
return (im);
|
||||||
|
|||||||
@@ -1695,3 +1695,18 @@ sixel_redraw_start(struct tty *tty, u_int x, u_int y, u_int sx, u_int sy)
|
|||||||
tty_repeat_space(tty, sx);
|
tty_repeat_space(tty, sx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Write a SIXEL image and release the parsed data. */
|
||||||
|
void
|
||||||
|
sixel_write(struct screen_write_ctx *ctx, struct sixel_image *si, u_int bg)
|
||||||
|
{
|
||||||
|
struct image *im;
|
||||||
|
|
||||||
|
im = sixel_to_image(si);
|
||||||
|
if (im == NULL) {
|
||||||
|
sixel_free(si);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
image_write_sixel(ctx, im, bg);
|
||||||
|
image_free(im);
|
||||||
|
}
|
||||||
|
|||||||
65
input.c
65
input.c
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: input.c,v 1.273 2026/10/08 07:50:05 nicm Exp $ */
|
/* $OpenBSD: input.c,v 1.276 2026/10/13 10:21:58 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -2032,6 +2032,7 @@ static void
|
|||||||
input_csi_dispatch_sm_private(struct input_ctx *ictx)
|
input_csi_dispatch_sm_private(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 grid_cell *gc = &ictx->cell.cell;
|
struct grid_cell *gc = &ictx->cell.cell;
|
||||||
u_int i;
|
u_int i;
|
||||||
|
|
||||||
@@ -2093,13 +2094,13 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
|
|||||||
break;
|
break;
|
||||||
case 2031:
|
case 2031:
|
||||||
screen_write_mode_set(sctx, MODE_THEME_UPDATES);
|
screen_write_mode_set(sctx, MODE_THEME_UPDATES);
|
||||||
if (ictx->wp != NULL) {
|
if (wp != NULL) {
|
||||||
ictx->wp->last_theme = window_pane_get_theme(ictx->wp);
|
wp->last_theme = window_pane_get_theme(wp);
|
||||||
ictx->wp->flags &= ~PANE_THEMECHANGED;
|
wp->flags &= ~PANE_THEMECHANGED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2026:
|
case 2026:
|
||||||
screen_write_start_sync(ictx->wp);
|
screen_write_start_sync(wp);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
@@ -2666,7 +2667,7 @@ input_dcs_dispatch(struct input_ctx *ictx)
|
|||||||
p2 = 0;
|
p2 = 0;
|
||||||
si = sixel_parse(buf, len, p1, p2, w->xpixel, w->ypixel);
|
si = sixel_parse(buf, len, p1, p2, w->xpixel, w->ypixel);
|
||||||
if (si != NULL)
|
if (si != NULL)
|
||||||
screen_write_sixelimage(sctx, si, ictx->cell.cell.bg);
|
sixel_write(sctx, si, ictx->cell.cell.bg);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -2867,7 +2868,7 @@ input_handle_kitty(struct input_ctx *ictx, const u_char *buf, size_t len)
|
|||||||
} else if (im != NULL) {
|
} else if (im != NULL) {
|
||||||
image_write_kitty(sctx, im, ictx->cell.cell.bg,
|
image_write_kitty(sctx, im, ictx->cell.cell.bg,
|
||||||
result.image_id, result.placement_id, result.z);
|
result.image_id, result.placement_id, result.z);
|
||||||
image_free(image_get_id(im));
|
image_free(im);
|
||||||
}
|
}
|
||||||
if (result.action != 'd')
|
if (result.action != 'd')
|
||||||
input_reply_kitty(ictx, &result, "OK");
|
input_reply_kitty(ictx, &result, "OK");
|
||||||
@@ -3336,6 +3337,52 @@ input_osc_133_exit_status(const char *p)
|
|||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse and clean the URL-encoded command line from OSC 133 C. */
|
||||||
|
static char *
|
||||||
|
input_osc_133_command_line(const char *p)
|
||||||
|
{
|
||||||
|
const char *end;
|
||||||
|
char line[16385], h[3] = { 0 };
|
||||||
|
size_t size = 0;
|
||||||
|
u_char ch;
|
||||||
|
|
||||||
|
if (p[1] != ';')
|
||||||
|
return (NULL);
|
||||||
|
p += 2;
|
||||||
|
for (;;) {
|
||||||
|
end = strchr(p, ';');
|
||||||
|
if (end == NULL)
|
||||||
|
end = p + strlen(p);
|
||||||
|
if (end - p >= 12 && strncmp(p, "cmdline_url=", 12) == 0)
|
||||||
|
break;
|
||||||
|
if (*end == '\0')
|
||||||
|
return (NULL);
|
||||||
|
p = end + 1;
|
||||||
|
}
|
||||||
|
p += 12;
|
||||||
|
while (p < end) {
|
||||||
|
if (size == sizeof line - 1)
|
||||||
|
return (NULL);
|
||||||
|
ch = *p++;
|
||||||
|
if (ch == '%') {
|
||||||
|
if (end - p < 2 ||
|
||||||
|
!isxdigit((u_char)p[0]) ||
|
||||||
|
!isxdigit((u_char)p[1]))
|
||||||
|
return (NULL);
|
||||||
|
h[0] = p[0];
|
||||||
|
h[1] = p[1];
|
||||||
|
|
||||||
|
ch = strtoul(h, NULL, 16);
|
||||||
|
if (ch == '\0')
|
||||||
|
return (NULL);
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
line[size++] = ch;
|
||||||
|
}
|
||||||
|
line[size] = '\0';
|
||||||
|
return (clean_name(line, 1));
|
||||||
|
}
|
||||||
|
|
||||||
/* Fire an OSC 133 command event. */
|
/* Fire an OSC 133 command event. */
|
||||||
static void
|
static void
|
||||||
input_fire_command_event(struct window_pane *wp, const char *name)
|
input_fire_command_event(struct window_pane *wp, const char *name)
|
||||||
@@ -3355,6 +3402,8 @@ input_fire_command_event(struct window_pane *wp, const char *name)
|
|||||||
event_payload_set_window(ep, "window", wp->window);
|
event_payload_set_window(ep, "window", wp->window);
|
||||||
event_payload_set_pane(ep, "pane", wp);
|
event_payload_set_pane(ep, "pane", wp);
|
||||||
|
|
||||||
|
if (wp->cmd_line != NULL)
|
||||||
|
event_payload_set_string(ep, "command_line", "%s", wp->cmd_line);
|
||||||
if (wp->cmd_status != -1)
|
if (wp->cmd_status != -1)
|
||||||
event_payload_set_int(ep, "command_status", wp->cmd_status);
|
event_payload_set_int(ep, "command_status", wp->cmd_status);
|
||||||
if (tstart != 0)
|
if (tstart != 0)
|
||||||
@@ -3426,6 +3475,8 @@ input_osc_133(struct input_ctx *ictx, const char *p)
|
|||||||
gl->osc133_data.out_start_col = s->cx;
|
gl->osc133_data.out_start_col = s->cx;
|
||||||
}
|
}
|
||||||
if (wp != NULL) {
|
if (wp != NULL) {
|
||||||
|
free(wp->cmd_line);
|
||||||
|
wp->cmd_line = input_osc_133_command_line(p);
|
||||||
wp->cmd_start_time = time(NULL);
|
wp->cmd_start_time = time(NULL);
|
||||||
wp->cmd_end_time = 0;
|
wp->cmd_end_time = 0;
|
||||||
wp->flags |= PANE_CMDRUNNING;
|
wp->flags |= PANE_CMDRUNNING;
|
||||||
|
|||||||
35
mode-tree.c
35
mode-tree.c
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: mode-tree.c,v 1.103 2026/09/24 18:59:00 nicm Exp $ */
|
/* $OpenBSD: mode-tree.c,v 1.104 2026/10/12 18:23:25 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -701,8 +701,17 @@ mode_tree_build(struct mode_tree_data *mtd)
|
|||||||
static void
|
static void
|
||||||
mode_tree_remove_ref(struct mode_tree_data *mtd)
|
mode_tree_remove_ref(struct mode_tree_data *mtd)
|
||||||
{
|
{
|
||||||
if (--mtd->references == 0)
|
if (--mtd->references != 0)
|
||||||
free(mtd);
|
return;
|
||||||
|
|
||||||
|
mode_tree_clear_prompt(mtd);
|
||||||
|
mode_tree_free_items(&mtd->children);
|
||||||
|
mode_tree_clear_lines(mtd);
|
||||||
|
screen_free(&mtd->screen);
|
||||||
|
|
||||||
|
free(mtd->search);
|
||||||
|
free(mtd->filter);
|
||||||
|
free(mtd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -713,14 +722,6 @@ mode_tree_free(struct mode_tree_data *mtd)
|
|||||||
if (mtd->zoomed == 0)
|
if (mtd->zoomed == 0)
|
||||||
server_unzoom_window(wp->window);
|
server_unzoom_window(wp->window);
|
||||||
|
|
||||||
mode_tree_clear_prompt(mtd);
|
|
||||||
mode_tree_free_items(&mtd->children);
|
|
||||||
mode_tree_clear_lines(mtd);
|
|
||||||
screen_free(&mtd->screen);
|
|
||||||
|
|
||||||
free(mtd->search);
|
|
||||||
free(mtd->filter);
|
|
||||||
|
|
||||||
mtd->dead = 1;
|
mtd->dead = 1;
|
||||||
mode_tree_remove_ref(mtd);
|
mode_tree_remove_ref(mtd);
|
||||||
}
|
}
|
||||||
@@ -1095,7 +1096,7 @@ mode_tree_prompt_accept(struct cmdq_item *item, void *data)
|
|||||||
struct client *c = cmdq_get_client(item);
|
struct client *c = cmdq_get_client(item);
|
||||||
key_code key = 'y';
|
key_code key = 'y';
|
||||||
|
|
||||||
if (mtd->prompt != NULL && c != NULL)
|
if (!mtd->dead && mtd->prompt != NULL && c != NULL)
|
||||||
mode_tree_key(mtd, c, &key, NULL, NULL, NULL);
|
mode_tree_key(mtd, c, &key, NULL, NULL, NULL);
|
||||||
|
|
||||||
mode_tree_remove_ref(mtd);
|
mode_tree_remove_ref(mtd);
|
||||||
@@ -1122,7 +1123,6 @@ mode_tree_prompt_free_callback(void *data)
|
|||||||
mtp->mtd->prompt_data = NULL;
|
mtp->mtd->prompt_data = NULL;
|
||||||
if (mtp->freecb != NULL)
|
if (mtp->freecb != NULL)
|
||||||
mtp->freecb(mtp->data);
|
mtp->freecb(mtp->data);
|
||||||
mode_tree_remove_ref(mtp->mtd);
|
|
||||||
free(mtp);
|
free(mtp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1152,8 +1152,6 @@ mode_tree_set_prompt(struct mode_tree_data *mtd, struct client *c,
|
|||||||
mtp->inputcb = inputcb;
|
mtp->inputcb = inputcb;
|
||||||
mtp->freecb = freecb;
|
mtp->freecb = freecb;
|
||||||
mtp->data = data;
|
mtp->data = data;
|
||||||
|
|
||||||
mtd->references++;
|
|
||||||
mtd->prompt_top = options_get_number(oo, "status-position") == 0;
|
mtd->prompt_top = options_get_number(oo, "status-position") == 0;
|
||||||
|
|
||||||
memset(&pd, 0, sizeof pd);
|
memset(&pd, 0, sizeof pd);
|
||||||
@@ -1524,6 +1522,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
|||||||
if (mtd->prompt != NULL) {
|
if (mtd->prompt != NULL) {
|
||||||
redraw = 0;
|
redraw = 0;
|
||||||
prompt = mtd->prompt;
|
prompt = mtd->prompt;
|
||||||
|
mtd->references++;
|
||||||
|
|
||||||
mtp = mtd->prompt_data;
|
mtp = mtd->prompt_data;
|
||||||
if (mtp != NULL)
|
if (mtp != NULL)
|
||||||
@@ -1548,6 +1547,11 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
|||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
result = prompt_key(prompt, *key, &redraw);
|
result = prompt_key(prompt, *key, &redraw);
|
||||||
|
if (mtd->dead) {
|
||||||
|
mode_tree_remove_ref(mtd);
|
||||||
|
*key = KEYC_NONE;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
if (mtd->prompt_data == mtp && mtp != NULL)
|
if (mtd->prompt_data == mtp && mtp != NULL)
|
||||||
mtp->c = NULL;
|
mtp->c = NULL;
|
||||||
|
|
||||||
@@ -1563,6 +1567,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
|||||||
mode_tree_draw(mtd);
|
mode_tree_draw(mtd);
|
||||||
mtd->wp->flags |= PANE_REDRAW;
|
mtd->wp->flags |= PANE_REDRAW;
|
||||||
}
|
}
|
||||||
|
mode_tree_remove_ref(mtd);
|
||||||
if (result != PROMPT_KEY_NOT_HANDLED) {
|
if (result != PROMPT_KEY_NOT_HANDLED) {
|
||||||
*key = KEYC_NONE;
|
*key = KEYC_NONE;
|
||||||
return (0);
|
return (0);
|
||||||
|
|||||||
42
prompt.c
42
prompt.c
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: prompt.c,v 1.7 2026/09/09 07:53:03 nicm Exp $ */
|
/* $OpenBSD: prompt.c,v 1.8 2026/10/13 07:56:00 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -1555,14 +1555,25 @@ prompt_complete_add(char ***list, u_int *size, const char *s)
|
|||||||
|
|
||||||
/* Build completion list. */
|
/* Build completion list. */
|
||||||
static char **
|
static char **
|
||||||
prompt_complete_commands(u_int *size, const char *s)
|
prompt_complete_commands(u_int *size, const char *s, int at_start)
|
||||||
{
|
{
|
||||||
char **list = NULL, *tmp;
|
char **list = NULL, *tmp;
|
||||||
const char *value, *cp;
|
const char **layout, *value, *cp;
|
||||||
const struct cmd_entry **cmdent;
|
const struct cmd_entry **cmdent;
|
||||||
size_t slen = strlen(s), valuelen;
|
const struct options_table_entry *oe;
|
||||||
struct options_entry *o;
|
size_t slen = strlen(s), valuelen;
|
||||||
struct options_array_item *a;
|
struct options_entry *o;
|
||||||
|
struct options_array_item *a;
|
||||||
|
const char *layouts[] = {
|
||||||
|
"even-horizontal",
|
||||||
|
"even-vertical",
|
||||||
|
"main-horizontal",
|
||||||
|
"main-horizontal-mirrored",
|
||||||
|
"main-vertical",
|
||||||
|
"main-vertical-mirrored",
|
||||||
|
"tiled",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
*size = 0;
|
*size = 0;
|
||||||
for (cmdent = cmd_table; *cmdent != NULL; cmdent++) {
|
for (cmdent = cmd_table; *cmdent != NULL; cmdent++) {
|
||||||
@@ -1588,6 +1599,16 @@ prompt_complete_commands(u_int *size, const char *s)
|
|||||||
a = options_array_next(a);
|
a = options_array_next(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (at_start)
|
||||||
|
return (list);
|
||||||
|
for (oe = options_table; oe->name != NULL; oe++) {
|
||||||
|
if (strncmp(oe->name, s, slen) == 0)
|
||||||
|
prompt_complete_add(&list, size, oe->name);
|
||||||
|
}
|
||||||
|
for (layout = layouts; *layout != NULL; layout++) {
|
||||||
|
if (strncmp(*layout, s, slen) == 0)
|
||||||
|
prompt_complete_add(&list, size, *layout);
|
||||||
|
}
|
||||||
return (list);
|
return (list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1671,11 +1692,10 @@ prompt_complete(struct prompt *pr, const char *word, u_int offset)
|
|||||||
char **list = NULL, *out = NULL;
|
char **list = NULL, *out = NULL;
|
||||||
u_int size = 0, i;
|
u_int size = 0, i;
|
||||||
|
|
||||||
if (pr->type != PROMPT_TYPE_COMMAND || offset != 0 ||
|
if (pr->type != PROMPT_TYPE_COMMAND || *word == '\0')
|
||||||
*word == '\0')
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
list = prompt_complete_commands(&size, word);
|
list = prompt_complete_commands(&size, word, offset == 0);
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
free(list);
|
free(list);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|||||||
@@ -378,4 +378,23 @@ done
|
|||||||
[ "$i" -lt 50 ] || fail "tagged windows were not killed"
|
[ "$i" -lt 50 ] || fail "tagged windows were not killed"
|
||||||
exit_mode q
|
exit_mode q
|
||||||
|
|
||||||
|
# --- killing the mode's own session -----------------------------------------
|
||||||
|
# Killing the attached session also destroys the pane hosting the tree. The
|
||||||
|
# confirmation callback must finish without redrawing the destroyed mode.
|
||||||
|
$TMUX set-option -g detach-on-destroy off || exit 1
|
||||||
|
$TMUX choose-tree -s -t aaa:0 -F 'G7' -O name || exit 1
|
||||||
|
wait_count ': G7' 2
|
||||||
|
$TMUX send-keys -t aaa:0 g x || fail "send-keys session kill failed"
|
||||||
|
wait_for 'Kill session aaa'
|
||||||
|
$TMUX send-keys -t aaa:0 y || fail "session kill confirmation failed"
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt 50 ]; do
|
||||||
|
sessions=$($TMUX list-sessions -F '#{session_name}' 2>/dev/null)
|
||||||
|
client_session=$($TMUX list-clients -F '#{client_session}' 2>/dev/null)
|
||||||
|
[ "$sessions" = 'zzz' ] && [ "$client_session" = 'zzz' ] && break
|
||||||
|
sleep 0.2
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
[ "$i" -lt 50 ] || fail "killing the tree session killed the server"
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -59,7 +59,13 @@ os.kill(client, signal.SIGTERM)
|
|||||||
size(master, 23, 61, 0, 0)
|
size(master, 23, 61, 0, 0)
|
||||||
os.kill(client, signal.SIGWINCH)
|
os.kill(client, signal.SIGWINCH)
|
||||||
os.kill(client, signal.SIGCONT)
|
os.kill(client, signal.SIGCONT)
|
||||||
|
# macOS drains the controlling terminal when its session leader exits.
|
||||||
|
# Keep reading output so the client can finish exiting.
|
||||||
for i in range(200):
|
for i in range(200):
|
||||||
|
try:
|
||||||
|
os.read(master, 65536)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
if os.waitpid(client, os.WNOHANG)[0] != 0:
|
if os.waitpid(client, os.WNOHANG)[0] != 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.05)
|
time.sleep(0.05)
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ pane_bg
|
|||||||
pane_bottom
|
pane_bottom
|
||||||
pane_command_duration
|
pane_command_duration
|
||||||
pane_command_end_time
|
pane_command_end_time
|
||||||
|
pane_command_line
|
||||||
pane_command_running
|
pane_command_running
|
||||||
pane_command_start_time
|
pane_command_start_time
|
||||||
pane_command_status
|
pane_command_status
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
. ./input-common.inc
|
|
||||||
|
|
||||||
# Exercise expansion by VS16, a skin tone modifier and a regional indicator.
|
|
||||||
for kind in variation modifier flag; do
|
|
||||||
case "$kind" in
|
|
||||||
variation)
|
|
||||||
combine_seq='\342\234\224\357\270\217'
|
|
||||||
text='✔️'
|
|
||||||
;;
|
|
||||||
modifier)
|
|
||||||
combine_seq='\342\230\235\360\237\217\273'
|
|
||||||
text='☝🏻'
|
|
||||||
;;
|
|
||||||
flag)
|
|
||||||
combine_seq='\360\237\207\254\360\237\207\247'
|
|
||||||
text='🇬🇧'
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
start_pane "$kind-overwrite" 10 3 "A\347\225\214BC\r${combine_seq}X"
|
|
||||||
check_capture "$kind-overwrite" "${text}XBC"
|
|
||||||
check_cursor "$kind-overwrite" '3,0'
|
|
||||||
check_raw_matches "$kind-overwrite" \
|
|
||||||
"C 0,0 data=\(2,[0-9]+,$text\) flags=NONE\[0\]" \
|
|
||||||
'C 0,1 .*flags=PADDING\[[0-9a-f]+\]' \
|
|
||||||
'C 0,2 data=\(1,1,X\) flags=NONE\[0\]'
|
|
||||||
|
|
||||||
start_pane "$kind-edge" 5 3 "abcd${combine_seq}X"
|
|
||||||
check_capture "$kind-edge" "abcd
|
|
||||||
${text}X"
|
|
||||||
check_cursor "$kind-edge" '3,1'
|
|
||||||
check_raw_matches "$kind-edge" \
|
|
||||||
'L 0 \(0\) flags=.*WRAPPED' \
|
|
||||||
'C 0,4 data=\(1,1, \)' \
|
|
||||||
"C 1,0 data=\(2,[0-9]+,$text\) flags=NONE\[0\]" \
|
|
||||||
'C 1,1 .*flags=PADDING\[[0-9a-f]+\]' \
|
|
||||||
'C 1,2 data=\(1,1,X\) flags=NONE\[0\]'
|
|
||||||
|
|
||||||
start_pane "$kind-fit" 5 3 "abc${combine_seq}X"
|
|
||||||
check_capture "$kind-fit" "abc${text}
|
|
||||||
X"
|
|
||||||
check_cursor "$kind-fit" '1,1'
|
|
||||||
|
|
||||||
start_pane "$kind-scroll" 5 2 "11111\r\nabcd${combine_seq}X"
|
|
||||||
check_capture "$kind-scroll" "abcd
|
|
||||||
${text}X"
|
|
||||||
check_cursor "$kind-scroll" '3,1'
|
|
||||||
|
|
||||||
start_pane "$kind-region" 5 4 \
|
|
||||||
"top\033[2;1Hold\033[4;1Hend\033[2;3r\033[3;1Habcd${combine_seq}X"
|
|
||||||
check_capture "$kind-region" "top
|
|
||||||
abcd
|
|
||||||
${text}X
|
|
||||||
end"
|
|
||||||
check_cursor "$kind-region" '3,2'
|
|
||||||
|
|
||||||
start_pane "$kind-insert" 10 3 "ABCDE\r\033[4h${combine_seq}X"
|
|
||||||
check_capture "$kind-insert" "${text}XABCDE"
|
|
||||||
check_cursor "$kind-insert" '3,0'
|
|
||||||
|
|
||||||
start_pane "$kind-insert-edge" 5 3 \
|
|
||||||
"\033[2;1HABCDE\033[1;1Habcd\033[4h${combine_seq}X"
|
|
||||||
check_capture "$kind-insert-edge" "abcd
|
|
||||||
${text}XAB"
|
|
||||||
check_cursor "$kind-insert-edge" '3,1'
|
|
||||||
|
|
||||||
start_pane "$kind-nowrap" 5 3 "\033[?7labc${combine_seq}"
|
|
||||||
check_capture "$kind-nowrap" "abc${text}"
|
|
||||||
check_cursor "$kind-nowrap" '4,0'
|
|
||||||
check_raw_matches "$kind-nowrap" \
|
|
||||||
"C 0,3 data=\(2,[0-9]+,$text\) flags=NONE\[0\]" \
|
|
||||||
'C 0,4 .*flags=PADDING\[[0-9a-f]+\]'
|
|
||||||
done
|
|
||||||
|
|
||||||
# A two-column cluster cannot fit in a one-column pane. Keep its narrow base.
|
|
||||||
start_pane one-column 1 3 '\342\234\224\357\270\217'
|
|
||||||
check_capture one-column '✔'
|
|
||||||
check_cursor one-column '1,0'
|
|
||||||
check_raw_no_matches one-column 'data=\(2,'
|
|
||||||
|
|
||||||
# Without wrapping, even a wide cell filling the pane leaves the cursor inside.
|
|
||||||
start_pane two-columns-nowrap 2 3 '\033[?7l\342\234\224\357\270\217'
|
|
||||||
check_capture two-columns-nowrap '✔️'
|
|
||||||
check_cursor two-columns-nowrap '1,0'
|
|
||||||
|
|
||||||
exit $exit_status
|
|
||||||
142
regress/input-osc133.sh
Normal file
142
regress/input-osc133.sh
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
LC_ALL=C.UTF-8
|
||||||
|
export TERM LC_ALL
|
||||||
|
|
||||||
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||||
|
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||||
|
trap '$TMUX kill-server 2>/dev/null' 0
|
||||||
|
trap 'exit 1' 1 2 15
|
||||||
|
|
||||||
|
check()
|
||||||
|
{
|
||||||
|
format=$1
|
||||||
|
expected=$2
|
||||||
|
actual=$($TMUX -u display-message -p -t "$pane" "$format") || exit 1
|
||||||
|
if [ "$actual" != "$expected" ]; then
|
||||||
|
printf 'format: %s\nexpected: %s\nactual: %s\n' \
|
||||||
|
"$format" "$expected" "$actual"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
emit()
|
||||||
|
{
|
||||||
|
printf '\033]133;%s\033\\' "$1" |
|
||||||
|
$TMUX display-message -I -t "$pane" || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
check_command()
|
||||||
|
{
|
||||||
|
emit "C;$1"
|
||||||
|
check '#{pane_command_line}' "$2"
|
||||||
|
check '#{@started}' "$2"
|
||||||
|
check '#{pane_command_running}:#{pane_command_status}' '1:'
|
||||||
|
emit 'D;7'
|
||||||
|
check '#{pane_command_line}' "$2"
|
||||||
|
check '#{@finished}' "$2"
|
||||||
|
check '#{pane_command_running}:#{pane_command_status}' '0:7'
|
||||||
|
}
|
||||||
|
|
||||||
|
$TMUX new-session -d -s test 'sleep 1000' || exit 1
|
||||||
|
pane=$($TMUX new-window -d -P -F '#{pane_id}' '') || exit 1
|
||||||
|
other=$($TMUX new-window -d -P -F '#{pane_id}' '') || exit 1
|
||||||
|
$TMUX set-hook -g pane-command-started \
|
||||||
|
'set -gF @started "#{hook_command_line}"' || exit 1
|
||||||
|
$TMUX set-hook -g pane-command-finished \
|
||||||
|
'set -gF @finished "#{hook_command_line}"' || exit 1
|
||||||
|
|
||||||
|
check '#{pane_command_line}:#{pane_command_running}' ':0'
|
||||||
|
check_command 'cmdline_url=sleep%201' 'sleep 1'
|
||||||
|
|
||||||
|
# Prompt markers leave the most recent command available.
|
||||||
|
emit A
|
||||||
|
emit B
|
||||||
|
check '#{pane_command_line}' 'sleep 1'
|
||||||
|
$TMUX display-message -p -t "$other" '#{pane_command_line}' |
|
||||||
|
grep -qx '' || exit 1
|
||||||
|
|
||||||
|
# Unknown fields are ignored and decoded semicolons belong to the value.
|
||||||
|
check_command 'other=1;cmdline_url=echo%20one%3B%20echo%20two;other=2' \
|
||||||
|
'echo one; echo two'
|
||||||
|
check_command 'cmdline_url=echo%20a+b%2Bc%25%3d%3D' 'echo a+b+c%=='
|
||||||
|
check_command 'cmdline_url=echo%20%C3%A9%E4%B8%AD' 'echo é中'
|
||||||
|
check_command 'cmdline_url=echo%20%2520' 'echo %20'
|
||||||
|
|
||||||
|
# Use the same cleanup as titles for control characters and format jobs.
|
||||||
|
check_command 'cmdline_url=echo%20%23%28date%29' 'echo _(date)'
|
||||||
|
check_command 'cmdline_url=echo%20%5C' 'echo \\'
|
||||||
|
|
||||||
|
# Multiline commands retain tabs and newlines as visible escapes, including
|
||||||
|
# in the event payloads used by hooks.
|
||||||
|
check_command 'cmdline_url=sleep%201%0Aecho%20done' 'sleep 1\necho done'
|
||||||
|
check_command 'cmdline_url=echo%09hello%0Aworld' 'echo\thello\nworld'
|
||||||
|
|
||||||
|
# The name validator also permits these bytes before clean_name escapes them.
|
||||||
|
name=$(printf 'tab\tnewline\nname')
|
||||||
|
$TMUX rename-window -t "$other" "$name" || exit 1
|
||||||
|
actual=$($TMUX -u display-message -p -t "$other" '#{window_name}') || exit 1
|
||||||
|
[ "$actual" = 'tab\tnewline\nname' ] || exit 1
|
||||||
|
$TMUX select-pane -t "$pane" -T "$name" || exit 1
|
||||||
|
check '#{pane_title}' 'tab\tnewline\nname'
|
||||||
|
|
||||||
|
# Every new start clears old metadata if it is missing or invalid.
|
||||||
|
emit C
|
||||||
|
check '#{pane_command_line}:#{@started}' ':'
|
||||||
|
for metadata in \
|
||||||
|
'cmdline_url=' \
|
||||||
|
'other=cmdline_url=stale' \
|
||||||
|
'xcmdline_url=stale' \
|
||||||
|
'cmdline_url=bad%' \
|
||||||
|
'cmdline_url=bad%2' \
|
||||||
|
'cmdline_url=bad%GG' \
|
||||||
|
'cmdline_url=bad%00tail' \
|
||||||
|
'cmdline_url=bad%0Dtail' \
|
||||||
|
'cmdline_url=bad%1Btail' \
|
||||||
|
'cmdline_url=bad%07tail' \
|
||||||
|
'cmdline_url=bad%08tail' \
|
||||||
|
'cmdline_url=bad%0Btail' \
|
||||||
|
'cmdline_url=bad%0Ctail' \
|
||||||
|
'cmdline_url=bad%7Ftail' \
|
||||||
|
'cmdline_url=bad%FF' \
|
||||||
|
'cmdline_url=bad%C3' \
|
||||||
|
'cmdline_url=bad%C0%AF'
|
||||||
|
do
|
||||||
|
check_command 'cmdline_url=previous' previous
|
||||||
|
check_command "$metadata" ''
|
||||||
|
done
|
||||||
|
|
||||||
|
# The limit applies to decoded bytes, not the size of the OSC string.
|
||||||
|
decoded=$(printf '%5000s' '' | tr ' ' x)
|
||||||
|
check_command "cmdline_url=$decoded" "$decoded"
|
||||||
|
encoded=$(awk 'BEGIN { for (i = 0; i < 16384; i++) printf "%%78" }')
|
||||||
|
decoded=$(printf '%16384s' '' | tr ' ' x)
|
||||||
|
check_command "cmdline_url=$encoded" "$decoded"
|
||||||
|
check_command "cmdline_url=${encoded}%78" ''
|
||||||
|
|
||||||
|
# Complete UTF-8 characters may reach the limit, but overlong lines are
|
||||||
|
# rejected in full rather than truncated, even through a character.
|
||||||
|
check_boundary()
|
||||||
|
{
|
||||||
|
prefix=$(printf "%${1}s" '' | tr ' ' x)
|
||||||
|
check_command "cmdline_url=$prefix$2" "$prefix$3"
|
||||||
|
check_command "cmdline_url=${prefix}x$2" ''
|
||||||
|
}
|
||||||
|
check_boundary 16382 '%C3%A9' 'é'
|
||||||
|
check_boundary 16381 '%E4%B8%AD' '中'
|
||||||
|
check_boundary 16380 '%F0%9F%98%80' '😀'
|
||||||
|
|
||||||
|
# Each hook gets a snapshot, even if multiple commands arrive in one read.
|
||||||
|
$TMUX set -g @log '' || exit 1
|
||||||
|
$TMUX set-hook -g pane-command-started \
|
||||||
|
'set -gF @log "#{@log}|start:#{hook_command_line}"' || exit 1
|
||||||
|
$TMUX set-hook -g pane-command-finished \
|
||||||
|
'set -gF @log "#{@log}|end:#{hook_command_line}:#{hook_command_status}"' || exit 1
|
||||||
|
printf '\033]133;C;cmdline_url=first\007\033]133;D;0\007\033]133;C;cmdline_url=second\007\033]133;D;1\007\033]133;C\007\033]133;D;2\007' |
|
||||||
|
$TMUX display-message -I -t "$pane" || exit 1
|
||||||
|
check '#{@log}' '|start:first|end:first:0|start:second|end:second:1|start:|end::2'
|
||||||
|
check '#{pane_command_line}' ''
|
||||||
|
|
||||||
|
exit 0
|
||||||
176
screen-write.c
176
screen-write.c
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: screen-write.c,v 1.299 2026/10/05 08:41:23 nicm Exp $ */
|
/* $OpenBSD: screen-write.c,v 1.300 2026/10/12 18:47:52 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -34,10 +34,6 @@ static void screen_write_collect_clear(struct screen_write_ctx *, u_int,
|
|||||||
static void screen_write_collect_scroll(struct screen_write_ctx *, u_int);
|
static void screen_write_collect_scroll(struct screen_write_ctx *, u_int);
|
||||||
static void screen_write_collect_flush(struct screen_write_ctx *, int,
|
static void screen_write_collect_flush(struct screen_write_ctx *, int,
|
||||||
const char *);
|
const char *);
|
||||||
#ifdef ENABLE_IMAGES
|
|
||||||
static void screen_write_image_damage(struct screen_write_ctx *, u_int,
|
|
||||||
u_int, u_int, u_int);
|
|
||||||
#endif
|
|
||||||
static int screen_write_overwrite(struct screen_write_ctx *,
|
static int screen_write_overwrite(struct screen_write_ctx *,
|
||||||
struct grid_cell *, u_int);
|
struct grid_cell *, u_int);
|
||||||
static int screen_write_combine(struct screen_write_ctx *,
|
static int screen_write_combine(struct screen_write_ctx *,
|
||||||
@@ -396,20 +392,6 @@ screen_write_init(struct screen_write_ctx *ctx, struct screen *s)
|
|||||||
ctx->bg = 8;
|
ctx->bg = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
|
||||||
/* Damage temporal images when application input writes text cells. */
|
|
||||||
static void
|
|
||||||
screen_write_image_damage(struct screen_write_ctx *ctx, u_int x, u_int y,
|
|
||||||
u_int sx, u_int sy)
|
|
||||||
{
|
|
||||||
image_redraw_area(ctx, x, y, sx, sy);
|
|
||||||
if (ctx->flags & SCREEN_WRITE_INPUT) {
|
|
||||||
image_grid_remove_overwritten_spans(ctx->s->grid, x,
|
|
||||||
ctx->s->grid->hsize + y, sx, sy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Initialize writing with a pane. */
|
/* Initialize writing with a pane. */
|
||||||
void
|
void
|
||||||
screen_write_start_pane(struct screen_write_ctx *ctx, struct window_pane *wp,
|
screen_write_start_pane(struct screen_write_ctx *ctx, struct window_pane *wp,
|
||||||
@@ -1491,11 +1473,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
|
|||||||
utf8_set(&gc.data, 'E');
|
utf8_set(&gc.data, 'E');
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
#ifdef ENABLE_IMAGES
|
||||||
image_redraw_all(ctx);
|
image_damage_screen(ctx, 0, 0, screen_size_x(s), screen_size_y(s));
|
||||||
if (ctx->flags & SCREEN_WRITE_INPUT) {
|
|
||||||
image_grid_remove_overwritten_spans(s->grid, 0, s->grid->hsize,
|
|
||||||
screen_size_x(s), screen_size_y(s));
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (yy = 0; yy < screen_size_y(s); yy++) {
|
for (yy = 0; yy < screen_size_y(s); yy++) {
|
||||||
@@ -1540,13 +1518,13 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
|
|||||||
if (s->cx > screen_size_x(s) - 1)
|
if (s->cx > screen_size_x(s) - 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
screen_write_initctx(ctx, &ttyctx, 0, 1);
|
||||||
|
ttyctx.bg = bg;
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
#ifdef ENABLE_IMAGES
|
||||||
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), 1);
|
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
screen_write_initctx(ctx, &ttyctx, 0, 1);
|
|
||||||
ttyctx.bg = bg;
|
|
||||||
|
|
||||||
grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg);
|
grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg);
|
||||||
|
|
||||||
screen_write_collect_flush(ctx, 0, __func__);
|
screen_write_collect_flush(ctx, 0, __func__);
|
||||||
@@ -1580,13 +1558,13 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
|
|||||||
if (s->cx > screen_size_x(s) - 1)
|
if (s->cx > screen_size_x(s) - 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
screen_write_initctx(ctx, &ttyctx, 0, 1);
|
||||||
|
ttyctx.bg = bg;
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
#ifdef ENABLE_IMAGES
|
||||||
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), 1);
|
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
screen_write_initctx(ctx, &ttyctx, 0, 1);
|
|
||||||
ttyctx.bg = bg;
|
|
||||||
|
|
||||||
grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg);
|
grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg);
|
||||||
|
|
||||||
screen_write_collect_flush(ctx, 0, __func__);
|
screen_write_collect_flush(ctx, 0, __func__);
|
||||||
@@ -1620,13 +1598,13 @@ screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
|
|||||||
if (s->cx > screen_size_x(s) - 1)
|
if (s->cx > screen_size_x(s) - 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
|
||||||
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
screen_write_initctx(ctx, &ttyctx, 0, 1);
|
screen_write_initctx(ctx, &ttyctx, 0, 1);
|
||||||
ttyctx.bg = bg;
|
ttyctx.bg = bg;
|
||||||
|
|
||||||
|
#ifdef ENABLE_IMAGES
|
||||||
|
image_redraw_area(ctx, s->cx, s->cy, nx, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
grid_view_clear(s->grid, s->cx, s->cy, nx, 1, bg);
|
grid_view_clear(s->grid, s->cx, s->cy, nx, 1, bg);
|
||||||
|
|
||||||
screen_write_collect_flush(ctx, 0, __func__);
|
screen_write_collect_flush(ctx, 0, __func__);
|
||||||
@@ -1654,10 +1632,6 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
|
|||||||
if (ny == 0)
|
if (ny == 0)
|
||||||
ny = 1;
|
ny = 1;
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
|
||||||
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), sy - s->cy);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (s->cy < s->rupper || s->cy > s->rlower) {
|
if (s->cy < s->rupper || s->cy > s->rlower) {
|
||||||
if (ny > sy - s->cy)
|
if (ny > sy - s->cy)
|
||||||
ny = sy - s->cy;
|
ny = sy - s->cy;
|
||||||
@@ -1667,6 +1641,10 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
|
|||||||
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
||||||
ttyctx.bg = bg;
|
ttyctx.bg = bg;
|
||||||
|
|
||||||
|
#ifdef ENABLE_IMAGES
|
||||||
|
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), sy - s->cy);
|
||||||
|
#endif
|
||||||
|
|
||||||
grid_view_insert_lines(gd, s->cy, ny, bg);
|
grid_view_insert_lines(gd, s->cy, ny, bg);
|
||||||
|
|
||||||
screen_write_collect_flush(ctx, 0, __func__);
|
screen_write_collect_flush(ctx, 0, __func__);
|
||||||
@@ -1691,6 +1669,11 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
|
|||||||
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
||||||
ttyctx.bg = bg;
|
ttyctx.bg = bg;
|
||||||
|
|
||||||
|
#ifdef ENABLE_IMAGES
|
||||||
|
image_redraw_area(ctx, 0, s->cy, screen_size_x(s),
|
||||||
|
s->rlower + 1 - s->cy);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (s->cy < s->rupper || s->cy > s->rlower)
|
if (s->cy < s->rupper || s->cy > s->rlower)
|
||||||
grid_view_insert_lines(gd, s->cy, ny, bg);
|
grid_view_insert_lines(gd, s->cy, ny, bg);
|
||||||
else
|
else
|
||||||
@@ -1721,10 +1704,6 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
|
|||||||
if (ny == 0)
|
if (ny == 0)
|
||||||
ny = 1;
|
ny = 1;
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
|
||||||
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), sy - s->cy);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (s->cy < s->rupper || s->cy > s->rlower) {
|
if (s->cy < s->rupper || s->cy > s->rlower) {
|
||||||
if (ny > sy - s->cy)
|
if (ny > sy - s->cy)
|
||||||
ny = sy - s->cy;
|
ny = sy - s->cy;
|
||||||
@@ -1734,6 +1713,10 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
|
|||||||
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
||||||
ttyctx.bg = bg;
|
ttyctx.bg = bg;
|
||||||
|
|
||||||
|
#ifdef ENABLE_IMAGES
|
||||||
|
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), sy - s->cy);
|
||||||
|
#endif
|
||||||
|
|
||||||
grid_view_delete_lines(gd, s->cy, ny, bg);
|
grid_view_delete_lines(gd, s->cy, ny, bg);
|
||||||
|
|
||||||
screen_write_collect_flush(ctx, 0, __func__);
|
screen_write_collect_flush(ctx, 0, __func__);
|
||||||
@@ -1760,6 +1743,10 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
|
|||||||
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
||||||
ttyctx.bg = bg;
|
ttyctx.bg = bg;
|
||||||
|
|
||||||
|
#ifdef ENABLE_IMAGES
|
||||||
|
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), ry);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (s->cy < s->rupper || s->cy > s->rlower)
|
if (s->cy < s->rupper || s->cy > s->rlower)
|
||||||
grid_view_delete_lines(gd, s->cy, ny, bg);
|
grid_view_delete_lines(gd, s->cy, ny, bg);
|
||||||
else
|
else
|
||||||
@@ -1790,11 +1777,17 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
|
|||||||
u_int flags;
|
u_int flags;
|
||||||
|
|
||||||
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
|
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
|
||||||
if (gl->cellsize == 0 && COLOUR_DEFAULT(bg))
|
if (gl->cellsize == 0 && COLOUR_DEFAULT(bg)) {
|
||||||
|
#ifdef ENABLE_IMAGES
|
||||||
|
if (!image_grid_line_has_images(gl))
|
||||||
|
return;
|
||||||
|
#else
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
#ifdef ENABLE_IMAGES
|
||||||
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), 1);
|
image_redraw_area(ctx, 0, s->cy, sx, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
flags = gl->flags & GRID_LINE_OSC133_FLAGS;
|
flags = gl->flags & GRID_LINE_OSC133_FLAGS;
|
||||||
@@ -1828,11 +1821,20 @@ screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
|
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
|
||||||
if (s->cx > sx - 1 || (s->cx >= gl->cellsize && COLOUR_DEFAULT(bg)))
|
if (s->cx > sx - 1)
|
||||||
return;
|
return;
|
||||||
|
if (s->cx >= gl->cellsize && COLOUR_DEFAULT(bg)) {
|
||||||
|
#ifdef ENABLE_IMAGES
|
||||||
|
if (!image_grid_area_has_images(s->grid, s->cx,
|
||||||
|
s->grid->hsize + s->cy, sx - s->cx, 1))
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
#ifdef ENABLE_IMAGES
|
||||||
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), 1);
|
image_redraw_area(ctx, s->cx, s->cy, sx - s->cx, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg);
|
grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg);
|
||||||
@@ -1858,7 +1860,7 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
#ifdef ENABLE_IMAGES
|
||||||
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), 1);
|
image_redraw_area(ctx, 0, s->cy, s->cx + 1, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (s->cx > sx - 1)
|
if (s->cx > sx - 1)
|
||||||
@@ -1982,11 +1984,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
#ifdef ENABLE_IMAGES
|
||||||
if (rlower == screen_size_y(s) - 1)
|
image_redraw_scroll(ctx);
|
||||||
image_redraw_scroll(ctx);
|
|
||||||
else
|
|
||||||
image_redraw_area(ctx, 0, rupper, screen_size_x(s),
|
|
||||||
rlower - rupper);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg);
|
grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg);
|
||||||
@@ -2080,13 +2078,15 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
|
|||||||
struct visible_ranges *r;
|
struct visible_ranges *r;
|
||||||
struct visible_range *ri;
|
struct visible_range *ri;
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
|
||||||
image_redraw_area(ctx, 0, s->cy, screen_size_x(s), sy - s->cy);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
||||||
ttyctx.bg = bg;
|
ttyctx.bg = bg;
|
||||||
|
|
||||||
|
#ifdef ENABLE_IMAGES
|
||||||
|
if (s->cx < sx)
|
||||||
|
image_redraw_area(ctx, s->cx, s->cy, sx - s->cx, 1);
|
||||||
|
image_redraw_area(ctx, 0, s->cy + 1, sx, sy - (s->cy + 1));
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Scroll into history if it is enabled and clearing entire screen. */
|
/* Scroll into history if it is enabled and clearing entire screen. */
|
||||||
if (s->cx == 0 &&
|
if (s->cx == 0 &&
|
||||||
s->cy == 0 &&
|
s->cy == 0 &&
|
||||||
@@ -2160,13 +2160,14 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
|
|||||||
struct visible_ranges *r;
|
struct visible_ranges *r;
|
||||||
struct visible_range *ri;
|
struct visible_range *ri;
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
|
||||||
image_redraw_area(ctx, 0, 0, screen_size_x(s), s->cy + 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
||||||
ttyctx.bg = bg;
|
ttyctx.bg = bg;
|
||||||
|
|
||||||
|
#ifdef ENABLE_IMAGES
|
||||||
|
image_redraw_area(ctx, 0, 0, sx, s->cy);
|
||||||
|
image_redraw_area(ctx, 0, s->cy, s->cx + 1, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (s->cy > 0)
|
if (s->cy > 0)
|
||||||
grid_view_clear(s->grid, 0, 0, sx, s->cy, bg);
|
grid_view_clear(s->grid, 0, 0, sx, s->cy, bg);
|
||||||
if (s->cx > sx - 1)
|
if (s->cx > sx - 1)
|
||||||
@@ -2232,13 +2233,13 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
|
|||||||
struct visible_ranges *r;
|
struct visible_ranges *r;
|
||||||
struct visible_range *ri;
|
struct visible_range *ri;
|
||||||
|
|
||||||
|
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
||||||
|
ttyctx.bg = bg;
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
#ifdef ENABLE_IMAGES
|
||||||
image_redraw_all(ctx);
|
image_redraw_all(ctx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
|
||||||
ttyctx.bg = bg;
|
|
||||||
|
|
||||||
/* Scroll into history if it is enabled. */
|
/* Scroll into history if it is enabled. */
|
||||||
if ((s->grid->flags & GRID_HISTORY) &&
|
if ((s->grid->flags & GRID_HISTORY) &&
|
||||||
ctx->wp != NULL &&
|
ctx->wp != NULL &&
|
||||||
@@ -2662,14 +2663,19 @@ screen_write_collect_insert_clear(struct screen_write_ctx *ctx, u_int px,
|
|||||||
* background so the columns it covered do not lose their colour.
|
* background so the columns it covered do not lose their colour.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
screen_write_clear_cell(struct grid *gd, u_int px, u_int py)
|
screen_write_clear_cell(struct screen_write_ctx *ctx, u_int px, u_int py)
|
||||||
{
|
{
|
||||||
|
struct grid *gd = ctx->s->grid;
|
||||||
struct grid_cell gc;
|
struct grid_cell gc;
|
||||||
int bg;
|
int bg;
|
||||||
|
|
||||||
grid_view_get_cell(gd, px, py, &gc);
|
grid_view_get_cell(gd, px, py, &gc);
|
||||||
bg = gc.bg;
|
bg = gc.bg;
|
||||||
|
|
||||||
|
#ifdef ENABLE_IMAGES
|
||||||
|
image_damage_screen(ctx, px, py, 1, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||||
gc.bg = bg;
|
gc.bg = bg;
|
||||||
grid_view_set_cell(gd, px, py, &gc);
|
grid_view_set_cell(gd, px, py, &gc);
|
||||||
@@ -2728,7 +2734,7 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
|
|||||||
grid_view_get_cell(s->grid, xx, s->cy, &gc);
|
grid_view_get_cell(s->grid, xx, s->cy, &gc);
|
||||||
if (~gc.flags & GRID_FLAG_PADDING)
|
if (~gc.flags & GRID_FLAG_PADDING)
|
||||||
break;
|
break;
|
||||||
screen_write_clear_cell(s->grid, xx, s->cy);
|
screen_write_clear_cell(ctx, xx, s->cy);
|
||||||
log_debug("%s: padding erased (before) at %u (cx %u)",
|
log_debug("%s: padding erased (before) at %u (cx %u)",
|
||||||
__func__, xx, s->cx);
|
__func__, xx, s->cx);
|
||||||
}
|
}
|
||||||
@@ -2737,7 +2743,7 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
|
|||||||
grid_view_get_cell(s->grid, 0, s->cy, &gc);
|
grid_view_get_cell(s->grid, 0, s->cy, &gc);
|
||||||
if (gc.data.width > 1 ||
|
if (gc.data.width > 1 ||
|
||||||
(gc.flags & GRID_FLAG_PADDING)) {
|
(gc.flags & GRID_FLAG_PADDING)) {
|
||||||
screen_write_clear_cell(s->grid, xx, s->cy);
|
screen_write_clear_cell(ctx, xx, s->cy);
|
||||||
log_debug("%s: padding erased (before) at %u "
|
log_debug("%s: padding erased (before) at %u "
|
||||||
"(cx %u)", __func__, xx, s->cx);
|
"(cx %u)", __func__, xx, s->cx);
|
||||||
}
|
}
|
||||||
@@ -2747,7 +2753,7 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
#ifdef ENABLE_IMAGES
|
||||||
screen_write_image_damage(ctx, s->cx, s->cy, ci->used, 1);
|
image_damage_screen(ctx, s->cx, s->cy, ci->used, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
grid_view_set_cells(s->grid, s->cx, s->cy, &ci->gc, cl->data + ci->x,
|
grid_view_set_cells(s->grid, s->cx, s->cy, &ci->gc, cl->data + ci->x,
|
||||||
@@ -2760,7 +2766,7 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
|
|||||||
grid_view_get_cell(s->grid, xx, s->cy, &gc);
|
grid_view_get_cell(s->grid, xx, s->cy, &gc);
|
||||||
if (~gc.flags & GRID_FLAG_PADDING)
|
if (~gc.flags & GRID_FLAG_PADDING)
|
||||||
break;
|
break;
|
||||||
screen_write_clear_cell(s->grid, xx, s->cy);
|
screen_write_clear_cell(ctx, xx, s->cy);
|
||||||
log_debug("%s: padding erased (after) at %u (cx %u)", __func__,
|
log_debug("%s: padding erased (after) at %u (cx %u)", __func__,
|
||||||
xx, s->cx);
|
xx, s->cx);
|
||||||
}
|
}
|
||||||
@@ -2883,8 +2889,8 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
|
|||||||
screen_write_initctx(ctx, &ttyctx, 0, 0);
|
screen_write_initctx(ctx, &ttyctx, 0, 0);
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
#ifdef ENABLE_IMAGES
|
||||||
/* Input semantics decide which image layers this text damages. */
|
/* Mark images as damaged. */
|
||||||
screen_write_image_damage(ctx, s->cx, s->cy, width, 1);
|
image_damage_screen(ctx, s->cx, s->cy, width, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Handle overwriting of UTF-8 characters. */
|
/* Handle overwriting of UTF-8 characters. */
|
||||||
@@ -3118,10 +3124,12 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc)
|
|||||||
} else
|
} else
|
||||||
force_wide = 0;
|
force_wide = 0;
|
||||||
|
|
||||||
/* Set the new cell. */
|
|
||||||
#ifdef ENABLE_IMAGES
|
#ifdef ENABLE_IMAGES
|
||||||
screen_write_image_damage(ctx, cx - n, cy, n, 1);
|
/* Mark images as damaged. */
|
||||||
|
image_damage_screen(ctx, cx - n, cy, n, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Set the new cell. */
|
||||||
grid_view_set_cell(gd, cx - n, cy, &last);
|
grid_view_set_cell(gd, cx - n, cy, &last);
|
||||||
if (force_wide)
|
if (force_wide)
|
||||||
grid_view_set_padding(gd, cx - 1, cy, last.bg);
|
grid_view_set_padding(gd, cx - 1, cy, last.bg);
|
||||||
@@ -3195,12 +3203,12 @@ screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
|
|||||||
if (~tmp_gc.flags & GRID_FLAG_PADDING)
|
if (~tmp_gc.flags & GRID_FLAG_PADDING)
|
||||||
break;
|
break;
|
||||||
log_debug("%s: padding at %u,%u", __func__, xx, s->cy);
|
log_debug("%s: padding at %u,%u", __func__, xx, s->cy);
|
||||||
screen_write_clear_cell(gd, xx, s->cy);
|
screen_write_clear_cell(ctx, xx, s->cy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Overwrite the character at the start of this padding. */
|
/* Overwrite the character at the start of this padding. */
|
||||||
log_debug("%s: character at %u,%u", __func__, xx, s->cy);
|
log_debug("%s: character at %u,%u", __func__, xx, s->cy);
|
||||||
screen_write_clear_cell(gd, xx, s->cy);
|
screen_write_clear_cell(ctx, xx, s->cy);
|
||||||
done = 1;
|
done = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3218,7 +3226,7 @@ screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
|
|||||||
break;
|
break;
|
||||||
log_debug("%s: overwrite at %u,%u", __func__, xx,
|
log_debug("%s: overwrite at %u,%u", __func__, xx,
|
||||||
s->cy);
|
s->cy);
|
||||||
screen_write_clear_cell(gd, xx, s->cy);
|
screen_write_clear_cell(ctx, xx, s->cy);
|
||||||
done = 1;
|
done = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3257,24 +3265,6 @@ screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len,
|
|||||||
tty_write(tty_cmd_rawstring, &ttyctx);
|
tty_write(tty_cmd_rawstring, &ttyctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
|
||||||
/* Write a SIXEL image. */
|
|
||||||
void
|
|
||||||
screen_write_sixelimage(struct screen_write_ctx *ctx, struct sixel_image *si,
|
|
||||||
u_int bg)
|
|
||||||
{
|
|
||||||
struct image *im;
|
|
||||||
|
|
||||||
im = sixel_to_image(si);
|
|
||||||
if (im == NULL) {
|
|
||||||
sixel_free(si);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
image_write_sixel(ctx, im, bg);
|
|
||||||
image_free(image_get_id(im));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Turn alternate screen on. */
|
/* Turn alternate screen on. */
|
||||||
void
|
void
|
||||||
screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc,
|
screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc,
|
||||||
|
|||||||
254
tmux-image.h
Normal file
254
tmux-image.h
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
/* $OpenBSD$ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
|
* Copyright (c) 2026 Michael Grant <mgrant@grant.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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TMUX_IMAGE_H
|
||||||
|
#define TMUX_IMAGE_H
|
||||||
|
|
||||||
|
#ifdef ENABLE_IMAGES
|
||||||
|
|
||||||
|
struct grid;
|
||||||
|
struct grid_line;
|
||||||
|
struct image;
|
||||||
|
struct image_line;
|
||||||
|
struct image_store;
|
||||||
|
struct screen;
|
||||||
|
struct screen_write_ctx;
|
||||||
|
struct sixel_image;
|
||||||
|
struct tty;
|
||||||
|
struct grid_cell;
|
||||||
|
struct image_rect;
|
||||||
|
struct image_backend;
|
||||||
|
|
||||||
|
#define IMAGE_SIZE_LIMIT (64 * 1024 * 1024)
|
||||||
|
#define IMAGE_BACKEND_GRAPHICAL 0x1
|
||||||
|
#define IMAGE_BACKEND_SCROLLS 0x2
|
||||||
|
#define IMAGE_BACKEND_CLIPPED 0x4
|
||||||
|
|
||||||
|
/* Private ACS keys used by the text image backend. */
|
||||||
|
#define TTY_ACS_IMAGE_SHADE_LIGHT 0x80
|
||||||
|
#define TTY_ACS_IMAGE_SHADE_MEDIUM 0x81
|
||||||
|
#define TTY_ACS_IMAGE_SHADE_DARK 0x82
|
||||||
|
#define TTY_ACS_IMAGE_BLOCK 0x83
|
||||||
|
#define TTY_ACS_IMAGE_HALF_UPPER 0x84
|
||||||
|
#define TTY_ACS_IMAGE_HALF_LOWER 0x85
|
||||||
|
#define TTY_ACS_IMAGE_HALF_LEFT 0x86
|
||||||
|
#define TTY_ACS_IMAGE_HALF_RIGHT 0x87
|
||||||
|
#define TTY_ACS_IMAGE_QUADRANT_LOWER_LEFT 0x88
|
||||||
|
#define TTY_ACS_IMAGE_QUADRANT_LOWER_RIGHT 0x89
|
||||||
|
#define TTY_ACS_IMAGE_QUADRANT_UPPER_LEFT 0x8a
|
||||||
|
#define TTY_ACS_IMAGE_QUADRANT_UPPER_LEFT_LOWER_LEFT_LOWER_RIGHT 0x8b
|
||||||
|
#define TTY_ACS_IMAGE_QUADRANT_UPPER_LEFT_LOWER_RIGHT 0x8c
|
||||||
|
#define TTY_ACS_IMAGE_QUADRANT_UPPER_LEFT_UPPER_RIGHT_LOWER_LEFT 0x8d
|
||||||
|
#define TTY_ACS_IMAGE_QUADRANT_UPPER_LEFT_UPPER_RIGHT_LOWER_RIGHT 0x8e
|
||||||
|
#define TTY_ACS_IMAGE_QUADRANT_UPPER_RIGHT 0x8f
|
||||||
|
#define TTY_ACS_IMAGE_QUADRANT_UPPER_RIGHT_LOWER_LEFT 0x90
|
||||||
|
#define TTY_ACS_IMAGE_QUADRANT_UPPER_RIGHT_LOWER_LEFT_LOWER_RIGHT 0x91
|
||||||
|
#define TTY_ACS_IMAGE_SEXTANT_FIRST 0x92
|
||||||
|
#define TTY_ACS_IMAGE_SEXTANT_LAST 0xcd
|
||||||
|
|
||||||
|
/* Averaged RGBA colour and brightness used by the text image backend. */
|
||||||
|
struct image_sample {
|
||||||
|
u_char red;
|
||||||
|
u_char green;
|
||||||
|
u_char blue;
|
||||||
|
u_char alpha;
|
||||||
|
u_char brightness;
|
||||||
|
};
|
||||||
|
#define IMAGE_SAMPLE_COLUMNS 2
|
||||||
|
#define IMAGE_SAMPLE_ROWS 6
|
||||||
|
|
||||||
|
/* Whole-cell and subcell samples generated lazily for one image cell. */
|
||||||
|
struct image_cell {
|
||||||
|
struct image_sample whole;
|
||||||
|
struct image_sample samples[IMAGE_SAMPLE_ROWS][IMAGE_SAMPLE_COLUMNS];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum kitty_parse_status {
|
||||||
|
KITTY_PARSE_ERROR = -1,
|
||||||
|
KITTY_PARSE_OK,
|
||||||
|
KITTY_PARSE_MORE,
|
||||||
|
KITTY_PARSE_MISSING,
|
||||||
|
KITTY_PARSE_UNSUPPORTED
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Reply fields and placement actions returned by one Kitty command. */
|
||||||
|
struct kitty_parse_result {
|
||||||
|
u_int image_id;
|
||||||
|
u_int image_number;
|
||||||
|
u_int replace_id;
|
||||||
|
u_int placement_id;
|
||||||
|
u_int quiet;
|
||||||
|
u_int x;
|
||||||
|
u_int y;
|
||||||
|
int32_t z;
|
||||||
|
char action;
|
||||||
|
char delete;
|
||||||
|
enum kitty_parse_status status;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Resolved source cell and application IDs of one Unicode placeholder. */
|
||||||
|
struct kitty_placeholder {
|
||||||
|
struct image *image;
|
||||||
|
u_int source_x;
|
||||||
|
u_int source_y;
|
||||||
|
u_int image_id;
|
||||||
|
u_int placement_id;
|
||||||
|
int32_t z;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* View of all or part of an image. */
|
||||||
|
struct image_view {
|
||||||
|
/* Position and size in the image, in pixels. */
|
||||||
|
u_int x;
|
||||||
|
u_int y;
|
||||||
|
u_int width;
|
||||||
|
u_int height;
|
||||||
|
|
||||||
|
/* Size after scaling, in pixels. */
|
||||||
|
u_int scaled_width;
|
||||||
|
u_int scaled_height;
|
||||||
|
|
||||||
|
/* Destination canvas size and offset in pixels. */
|
||||||
|
u_int canvas_width;
|
||||||
|
u_int canvas_height;
|
||||||
|
u_int canvas_xoff;
|
||||||
|
u_int canvas_yoff;
|
||||||
|
|
||||||
|
/* Destination size in terminal cells. */
|
||||||
|
u_int sx;
|
||||||
|
u_int sy;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* image.c */
|
||||||
|
struct image *image_create(u_int, u_int, u_int, u_int, u_int, u_int,
|
||||||
|
u_char *);
|
||||||
|
struct image *image_create_view(struct image *, struct image_view *);
|
||||||
|
struct image *image_find(u_int);
|
||||||
|
u_int image_get_id(struct image *);
|
||||||
|
void image_ref(struct image *);
|
||||||
|
void image_free(struct image *);
|
||||||
|
void image_get_size(struct image *, u_int *, u_int *);
|
||||||
|
void image_get_canvas_size(struct image *, u_int *, u_int *);
|
||||||
|
void image_get_size_in_cells(struct image *, u_int *, u_int *);
|
||||||
|
const u_char *image_get_pixels(struct image *, size_t *, size_t *);
|
||||||
|
void image_size_in_cells(u_int, u_int, u_int, u_int, u_int *,
|
||||||
|
u_int *);
|
||||||
|
void image_set_no_cursor(struct image *);
|
||||||
|
int image_has_no_cursor(struct image *);
|
||||||
|
struct sixel_image *image_get_sixel(struct image *);
|
||||||
|
void image_set_sixel(struct image *, struct sixel_image *);
|
||||||
|
u_int image_get_source_id(struct image *);
|
||||||
|
u_int image_get_order_id(struct image *);
|
||||||
|
void image_set_order_id(struct image *, u_int);
|
||||||
|
void *image_get_fallback_data(struct image *);
|
||||||
|
void image_set_fallback_data(struct image *, void *);
|
||||||
|
const struct image_cell *image_get_cell(struct image *, u_int, u_int);
|
||||||
|
void image_get_pixel_rect(struct image *, u_int, u_int, u_int,
|
||||||
|
u_int, u_int *, u_int *, u_int *, u_int *);
|
||||||
|
u_char *image_base64_decode(const char *, size_t, size_t, size_t *);
|
||||||
|
u_char *image_png_decode(const u_char *, size_t, size_t, u_int *,
|
||||||
|
u_int *);
|
||||||
|
|
||||||
|
/* image-grid.c */
|
||||||
|
void image_grid_add(struct grid *, struct image *, u_int, u_int,
|
||||||
|
u_int, u_int, u_int, u_int);
|
||||||
|
void image_grid_remove(struct grid *, u_int, u_int, u_int, u_int);
|
||||||
|
void image_grid_remove_overwritten_spans(struct grid *, u_int, u_int,
|
||||||
|
u_int, u_int);
|
||||||
|
void image_grid_free_line(struct grid *, struct grid_line *);
|
||||||
|
void image_grid_free(struct grid *);
|
||||||
|
void image_grid_move_cells(struct grid *, u_int, u_int, u_int,
|
||||||
|
u_int);
|
||||||
|
void image_grid_duplicate_lines(struct grid *, u_int, struct grid *,
|
||||||
|
u_int, u_int);
|
||||||
|
int image_grid_line_has_images(struct grid_line *);
|
||||||
|
int image_grid_area_has_images(struct grid *, u_int, u_int, u_int,
|
||||||
|
u_int);
|
||||||
|
void image_redraw_area(struct screen_write_ctx *, u_int, u_int,
|
||||||
|
u_int, u_int);
|
||||||
|
void image_redraw_all(struct screen_write_ctx *);
|
||||||
|
void image_redraw_scroll(struct screen_write_ctx *);
|
||||||
|
void image_damage_screen(struct screen_write_ctx *, u_int, u_int,
|
||||||
|
u_int, u_int);
|
||||||
|
void image_grid_copy_area(struct grid *, u_int, u_int, struct grid *,
|
||||||
|
u_int, u_int, u_int, u_int);
|
||||||
|
void image_grid_resize_width(struct grid *, u_int);
|
||||||
|
int image_grid_has_image(struct grid *, u_int);
|
||||||
|
int image_grid_get_placeholder(struct grid *, u_int, u_int,
|
||||||
|
struct kitty_placeholder *);
|
||||||
|
void image_place_cell_kitty(struct screen_write_ctx *, struct image *,
|
||||||
|
u_int, u_int, u_int, u_int, u_int, u_int, int32_t);
|
||||||
|
void image_write_sixel(struct screen_write_ctx *, struct image *, u_int);
|
||||||
|
void image_write_kitty(struct screen_write_ctx *, struct image *, u_int,
|
||||||
|
u_int, u_int, int32_t);
|
||||||
|
void image_clear(struct screen_write_ctx *, u_int);
|
||||||
|
void image_clear_kitty(struct screen_write_ctx *,
|
||||||
|
const struct kitty_parse_result *);
|
||||||
|
int image_get_fallback_at(struct tty *, struct screen *, u_int, u_int,
|
||||||
|
const struct grid_cell *, struct grid_cell *);
|
||||||
|
struct image *image_rect_get_image(const struct image_rect *);
|
||||||
|
void image_rect_get_coords(const struct image_rect *, u_int *, u_int *,
|
||||||
|
u_int *, u_int *, u_int *, u_int *);
|
||||||
|
int64_t image_rect_get_z(const struct image_rect *);
|
||||||
|
void image_draw_line(struct tty *, struct screen *, u_int, u_int, u_int,
|
||||||
|
u_int, u_int, int);
|
||||||
|
void image_redraw_start(struct tty *, u_int, u_int, u_int, u_int);
|
||||||
|
void image_redraw_finish(struct tty *);
|
||||||
|
void image_draw_flush(struct tty *);
|
||||||
|
int image_backend_flags(struct tty *);
|
||||||
|
int image_tty_update(struct tty *);
|
||||||
|
void image_tty_geometry_changed(struct tty *);
|
||||||
|
void image_tty_free(struct tty *, int);
|
||||||
|
|
||||||
|
/* image-fallback.c */
|
||||||
|
void fallback_get_cell(struct tty *, struct image *, u_int, u_int,
|
||||||
|
const struct grid_cell *, struct grid_cell *);
|
||||||
|
void fallback_free(struct image *);
|
||||||
|
|
||||||
|
/* image-kitty.c */
|
||||||
|
struct image *kitty_parse_image(void **, const u_char *, size_t, u_int,
|
||||||
|
u_int, struct kitty_parse_result *);
|
||||||
|
int kitty_placeholder_to_image(void *, struct grid *,
|
||||||
|
struct grid_cell *, u_int, u_int, struct kitty_placeholder *);
|
||||||
|
int kitty_cell_is_placeholder(const struct grid_cell *);
|
||||||
|
void kitty_delete_images(void *, struct screen_write_ctx *,
|
||||||
|
const struct kitty_parse_result *);
|
||||||
|
void kitty_free_state(void *);
|
||||||
|
void kitty_draw_rect(struct tty *, const struct image_rect *);
|
||||||
|
void kitty_redraw_start(struct tty *, u_int, u_int, u_int, u_int);
|
||||||
|
void kitty_redraw_finish(struct tty *);
|
||||||
|
void kitty_free_output_state(struct tty *, int);
|
||||||
|
|
||||||
|
/* image-sixel.c */
|
||||||
|
#define SIXEL_COLOUR_REGISTERS 1024
|
||||||
|
struct sixel_image *sixel_parse(const char *, size_t, u_int, u_int, u_int,
|
||||||
|
u_int);
|
||||||
|
void sixel_write(struct screen_write_ctx *, struct sixel_image *,
|
||||||
|
u_int);
|
||||||
|
void sixel_draw_rect(struct tty *, const struct image_rect *);
|
||||||
|
void sixel_redraw_start(struct tty *, u_int, u_int, u_int, u_int);
|
||||||
|
void sixel_free_output(struct tty *, int);
|
||||||
|
void sixel_flush_output(struct tty *);
|
||||||
|
struct image *sixel_to_image(struct sixel_image *);
|
||||||
|
void sixel_free(struct sixel_image *);
|
||||||
|
void sixel_log(struct sixel_image *);
|
||||||
|
|
||||||
|
#endif /* ENABLE_IMAGES */
|
||||||
|
|
||||||
|
#endif /* TMUX_IMAGE_H */
|
||||||
6
tmux.1
6
tmux.1
@@ -1,4 +1,4 @@
|
|||||||
.\" $OpenBSD: tmux.1,v 1.1184 2026/10/12 12:35:03 nicm Exp $
|
.\" $OpenBSD: tmux.1,v 1.1185 2026/10/13 10:21:58 nicm Exp $
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
.\"
|
.\"
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
.\"
|
.\"
|
||||||
.Dd $Mdocdate: October 12 2026 $
|
.Dd $Mdocdate: October 13 2026 $
|
||||||
.Dt TMUX 1
|
.Dt TMUX 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -7463,6 +7463,7 @@ The following variables are available, where appropriate:
|
|||||||
.It Li "history_size" Ta "" Ta "Size of history in lines"
|
.It Li "history_size" Ta "" Ta "Size of history in lines"
|
||||||
.It Li "hook" Ta "" Ta "Name of running hook, if any"
|
.It Li "hook" Ta "" Ta "Name of running hook, if any"
|
||||||
.It Li "hook_client" Ta "" Ta "Name of client where hook was run, if any"
|
.It Li "hook_client" Ta "" Ta "Name of client where hook was run, if any"
|
||||||
|
.It Li "hook_command_line" Ta "" Ta "Command line reported for an OSC 133 command hook, if any"
|
||||||
.It Li "hook_fire_count" Ta "" Ta "Number of times hook has fired"
|
.It Li "hook_fire_count" Ta "" Ta "Number of times hook has fired"
|
||||||
.It Li "hook_fire_time" Ta "" Ta "Time hook last fired"
|
.It Li "hook_fire_time" Ta "" Ta "Time hook last fired"
|
||||||
.It Li "hook_last" Ta "" Ta "Previous value for a monitor hook"
|
.It Li "hook_last" Ta "" Ta "Previous value for a monitor hook"
|
||||||
@@ -7531,6 +7532,7 @@ The following variables are available, where appropriate:
|
|||||||
.It Li "pane_bottom" Ta "" Ta "Bottom of pane"
|
.It Li "pane_bottom" Ta "" Ta "Bottom of pane"
|
||||||
.It Li "pane_command_duration" Ta "" Ta "Current or most recent OSC 133 command duration in seconds"
|
.It Li "pane_command_duration" Ta "" Ta "Current or most recent OSC 133 command duration in seconds"
|
||||||
.It Li "pane_command_end_time" Ta "" Ta "Time most recent OSC 133 command ended"
|
.It Li "pane_command_end_time" Ta "" Ta "Time most recent OSC 133 command ended"
|
||||||
|
.It Li "pane_command_line" Ta "" Ta "Current or most recent OSC 133 command line, if reported"
|
||||||
.It Li "pane_command_running" Ta "" Ta "1 if an OSC 133 command is running"
|
.It Li "pane_command_running" Ta "" Ta "1 if an OSC 133 command is running"
|
||||||
.It Li "pane_command_start_time" Ta "" Ta "Time current or most recent OSC 133 command started"
|
.It Li "pane_command_start_time" Ta "" Ta "Time current or most recent OSC 133 command started"
|
||||||
.It Li "pane_command_status" Ta "" Ta "Exit status from most recent OSC 133 command"
|
.It Li "pane_command_status" Ta "" Ta "Exit status from most recent OSC 133 command"
|
||||||
|
|||||||
245
tmux.h
245
tmux.h
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: tmux.h,v 1.1457 2026/10/12 12:35:03 nicm Exp $ */
|
/* $OpenBSD: tmux.h,v 1.1459 2026/10/13 10:21:58 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -19,11 +19,13 @@
|
|||||||
#ifndef TMUX_H
|
#ifndef TMUX_H
|
||||||
#define TMUX_H
|
#define TMUX_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
@@ -33,6 +35,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
#include "tmux-image.h"
|
||||||
#include "tmux-protocol.h"
|
#include "tmux-protocol.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
|
||||||
@@ -77,15 +80,6 @@ struct screen_write_cline;
|
|||||||
struct screen_write_ctx;
|
struct screen_write_ctx;
|
||||||
struct session;
|
struct session;
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
|
||||||
struct image;
|
|
||||||
struct image_backend;
|
|
||||||
struct image_rect;
|
|
||||||
struct image_line;
|
|
||||||
struct image_store;
|
|
||||||
struct sixel_image;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct tty_ctx;
|
struct tty_ctx;
|
||||||
struct tty_code;
|
struct tty_code;
|
||||||
struct tty_key;
|
struct tty_key;
|
||||||
@@ -1048,123 +1042,6 @@ struct style {
|
|||||||
u_int link;
|
u_int link;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
|
||||||
/* Private ACS keys used by the text image backend. */
|
|
||||||
#define TTY_ACS_IMAGE_SHADE_LIGHT 0x80
|
|
||||||
#define TTY_ACS_IMAGE_SHADE_MEDIUM 0x81
|
|
||||||
#define TTY_ACS_IMAGE_SHADE_DARK 0x82
|
|
||||||
#define TTY_ACS_IMAGE_BLOCK 0x83
|
|
||||||
#define TTY_ACS_IMAGE_HALF_UPPER 0x84
|
|
||||||
#define TTY_ACS_IMAGE_HALF_LOWER 0x85
|
|
||||||
#define TTY_ACS_IMAGE_HALF_LEFT 0x86
|
|
||||||
#define TTY_ACS_IMAGE_HALF_RIGHT 0x87
|
|
||||||
#define TTY_ACS_IMAGE_QUADRANT_LOWER_LEFT 0x88
|
|
||||||
#define TTY_ACS_IMAGE_QUADRANT_LOWER_RIGHT 0x89
|
|
||||||
#define TTY_ACS_IMAGE_QUADRANT_UPPER_LEFT 0x8a
|
|
||||||
#define TTY_ACS_IMAGE_QUADRANT_UPPER_LEFT_LOWER_LEFT_LOWER_RIGHT 0x8b
|
|
||||||
#define TTY_ACS_IMAGE_QUADRANT_UPPER_LEFT_LOWER_RIGHT 0x8c
|
|
||||||
#define TTY_ACS_IMAGE_QUADRANT_UPPER_LEFT_UPPER_RIGHT_LOWER_LEFT 0x8d
|
|
||||||
#define TTY_ACS_IMAGE_QUADRANT_UPPER_LEFT_UPPER_RIGHT_LOWER_RIGHT 0x8e
|
|
||||||
#define TTY_ACS_IMAGE_QUADRANT_UPPER_RIGHT 0x8f
|
|
||||||
#define TTY_ACS_IMAGE_QUADRANT_UPPER_RIGHT_LOWER_LEFT 0x90
|
|
||||||
#define TTY_ACS_IMAGE_QUADRANT_UPPER_RIGHT_LOWER_LEFT_LOWER_RIGHT 0x91
|
|
||||||
#define TTY_ACS_IMAGE_SEXTANT_FIRST 0x92
|
|
||||||
#define TTY_ACS_IMAGE_SEXTANT_LAST 0xcd
|
|
||||||
|
|
||||||
/* Averaged RGBA colour and brightness used by the text image backend. */
|
|
||||||
struct image_sample {
|
|
||||||
u_char red;
|
|
||||||
u_char green;
|
|
||||||
u_char blue;
|
|
||||||
u_char alpha;
|
|
||||||
u_char brightness;
|
|
||||||
};
|
|
||||||
#define IMAGE_SAMPLE_COLUMNS 2
|
|
||||||
#define IMAGE_SAMPLE_ROWS 6
|
|
||||||
/* Whole-cell and subcell samples generated lazily for one image cell. */
|
|
||||||
struct image_cell {
|
|
||||||
struct image_sample whole;
|
|
||||||
struct image_sample samples[IMAGE_SAMPLE_ROWS][IMAGE_SAMPLE_COLUMNS];
|
|
||||||
};
|
|
||||||
/* Immutable pixels and derived output data shared by image placements. */
|
|
||||||
struct image {
|
|
||||||
u_int id;
|
|
||||||
u_int references;
|
|
||||||
u_int flags;
|
|
||||||
/* Retained parent (zero for sources) and original source IDs. */
|
|
||||||
u_int parent_id;
|
|
||||||
u_int source_id;
|
|
||||||
u_int order_id; /* Original creation order. */
|
|
||||||
/* Pixel dimensions, including the logical transparent canvas. */
|
|
||||||
u_int width;
|
|
||||||
u_int height;
|
|
||||||
u_int canvas_width;
|
|
||||||
u_int canvas_height;
|
|
||||||
/* Grid dimensions and pixel buffer lengths in bytes. */
|
|
||||||
u_int sx;
|
|
||||||
u_int sy;
|
|
||||||
size_t stride;
|
|
||||||
size_t size;
|
|
||||||
u_char *pixels;
|
|
||||||
struct sixel_image *sixel;
|
|
||||||
struct image_cell *cells;
|
|
||||||
void *fallback_data;
|
|
||||||
|
|
||||||
RB_ENTRY(image) entry;
|
|
||||||
};
|
|
||||||
RB_HEAD(images, image);
|
|
||||||
#define IMAGE_SIZE_LIMIT (64 * 1024 * 1024)
|
|
||||||
|
|
||||||
/* Source crop and padded destination canvas for creating an image view. */
|
|
||||||
struct image_view {
|
|
||||||
u_int x; /* Crop origin in source pixels. */
|
|
||||||
u_int y;
|
|
||||||
u_int width; /* Crop size in source pixels. */
|
|
||||||
u_int height;
|
|
||||||
u_int scaled_width; /* Resampled crop size in pixels. */
|
|
||||||
u_int scaled_height;
|
|
||||||
u_int canvas_width; /* Padded canvas size in pixels. */
|
|
||||||
u_int canvas_height;
|
|
||||||
u_int sx; /* Placement size in cells. */
|
|
||||||
u_int sy;
|
|
||||||
u_int x_offset; /* Crop origin in canvas pixels. */
|
|
||||||
u_int y_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum kitty_parse_status {
|
|
||||||
KITTY_PARSE_ERROR = -1,
|
|
||||||
KITTY_PARSE_OK,
|
|
||||||
KITTY_PARSE_MORE,
|
|
||||||
KITTY_PARSE_MISSING,
|
|
||||||
KITTY_PARSE_UNSUPPORTED
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Reply fields and placement actions returned by one Kitty command. */
|
|
||||||
struct kitty_parse_result {
|
|
||||||
u_int image_id;
|
|
||||||
u_int image_number;
|
|
||||||
u_int replace_id; /* Old server ID, or zero. */
|
|
||||||
u_int placement_id;
|
|
||||||
u_int quiet;
|
|
||||||
u_int x; /* Deletion coordinates. */
|
|
||||||
u_int y;
|
|
||||||
int32_t z;
|
|
||||||
char action;
|
|
||||||
char delete;
|
|
||||||
enum kitty_parse_status status;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Resolved source cell and application IDs of one Unicode placeholder. */
|
|
||||||
struct kitty_placeholder {
|
|
||||||
struct image *image;
|
|
||||||
u_int source_x; /* Origin in image cells. */
|
|
||||||
u_int source_y;
|
|
||||||
u_int image_id;
|
|
||||||
u_int placement_id;
|
|
||||||
int32_t z;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Cursor style. */
|
/* Cursor style. */
|
||||||
enum screen_cursor_style {
|
enum screen_cursor_style {
|
||||||
SCREEN_CURSOR_DEFAULT,
|
SCREEN_CURSOR_DEFAULT,
|
||||||
@@ -1493,6 +1370,7 @@ struct window_pane {
|
|||||||
time_t cmd_start_time;
|
time_t cmd_start_time;
|
||||||
time_t cmd_end_time;
|
time_t cmd_end_time;
|
||||||
int cmd_status;
|
int cmd_status;
|
||||||
|
char *cmd_line;
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
struct bufferevent *event;
|
struct bufferevent *event;
|
||||||
@@ -3764,10 +3642,6 @@ void screen_write_setselection(struct screen_write_ctx *, const char *,
|
|||||||
u_char *, u_int);
|
u_char *, u_int);
|
||||||
void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int,
|
void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int,
|
||||||
int);
|
int);
|
||||||
#ifdef ENABLE_IMAGES
|
|
||||||
void screen_write_sixelimage(struct screen_write_ctx *,
|
|
||||||
struct sixel_image *, u_int);
|
|
||||||
#endif
|
|
||||||
void screen_write_alternateon(struct screen_write_ctx *,
|
void screen_write_alternateon(struct screen_write_ctx *,
|
||||||
struct grid_cell *, int);
|
struct grid_cell *, int);
|
||||||
void screen_write_alternateoff(struct screen_write_ctx *,
|
void screen_write_alternateoff(struct screen_write_ctx *,
|
||||||
@@ -4357,115 +4231,6 @@ void spawn_editor_finish(struct window_pane *);
|
|||||||
/* regsub.c */
|
/* regsub.c */
|
||||||
char *regsub(const char *, const char *, const char *, int);
|
char *regsub(const char *, const char *, const char *, int);
|
||||||
|
|
||||||
#ifdef ENABLE_IMAGES
|
|
||||||
/* image.c */
|
|
||||||
#define IMAGE_BACKEND_GRAPHICAL 0x1
|
|
||||||
#define IMAGE_BACKEND_SCROLLS 0x2
|
|
||||||
#define IMAGE_BACKEND_CLIPPED 0x4
|
|
||||||
|
|
||||||
struct image *image_create(u_int, u_int, u_int, u_int, u_int, u_int,
|
|
||||||
u_char *);
|
|
||||||
struct image *image_create_view(struct image *, const struct image_view *);
|
|
||||||
struct image *image_find(u_int);
|
|
||||||
u_int image_get_id(const struct image *);
|
|
||||||
void image_get_size(const struct image *, u_int *, u_int *);
|
|
||||||
void image_get_canvas_size(const struct image *, u_int *, u_int *);
|
|
||||||
void image_get_size_in_cells(const struct image *, u_int *, u_int *);
|
|
||||||
const u_char *image_get_pixels(const struct image *, size_t *, size_t *);
|
|
||||||
void image_set_no_cursor(struct image *);
|
|
||||||
struct sixel_image *image_get_sixel(const struct image *);
|
|
||||||
void image_set_sixel(struct image *, struct sixel_image *);
|
|
||||||
void image_ref(u_int);
|
|
||||||
void image_free(u_int);
|
|
||||||
void image_write_sixel(struct screen_write_ctx *, struct image *,
|
|
||||||
u_int);
|
|
||||||
void image_write_kitty(struct screen_write_ctx *, struct image *,
|
|
||||||
u_int, u_int, u_int, int32_t);
|
|
||||||
void image_get_pixel_rect(const struct image *, u_int, u_int,
|
|
||||||
u_int, u_int, u_int *, u_int *, u_int *, u_int *);
|
|
||||||
void image_size_in_cells(u_int, u_int, u_int, u_int, u_int *,
|
|
||||||
u_int *);
|
|
||||||
u_char *image_base64_decode(const char *, size_t, size_t, size_t *);
|
|
||||||
u_char *image_png_decode(const u_char *, size_t, size_t, u_int *,
|
|
||||||
u_int *);
|
|
||||||
void image_redraw_area(struct screen_write_ctx *, u_int, u_int,
|
|
||||||
u_int, u_int);
|
|
||||||
void image_redraw_all(struct screen_write_ctx *);
|
|
||||||
void image_redraw_scroll(struct screen_write_ctx *);
|
|
||||||
void image_redraw_start(struct tty *, u_int, u_int, u_int, u_int);
|
|
||||||
void image_redraw_finish(struct tty *);
|
|
||||||
void image_draw_flush(struct tty *);
|
|
||||||
int image_backend_flags(struct tty *);
|
|
||||||
int image_tty_update(struct tty *);
|
|
||||||
void image_tty_geometry_changed(struct tty *);
|
|
||||||
void image_tty_free(struct tty *, int);
|
|
||||||
void image_draw_line(struct tty *, struct screen *, u_int, u_int,
|
|
||||||
u_int, u_int, u_int, int);
|
|
||||||
const struct image_cell *image_get_cell(struct image *, u_int, u_int);
|
|
||||||
int image_get_fallback_at(struct tty *, struct screen *, u_int,
|
|
||||||
u_int, const struct grid_cell *, struct grid_cell *);
|
|
||||||
struct image *image_rect_get_image(const struct image_rect *);
|
|
||||||
void image_rect_get_coords(const struct image_rect *,
|
|
||||||
u_int *, u_int *, u_int *, u_int *, u_int *, u_int *);
|
|
||||||
int64_t image_rect_get_z(const struct image_rect *);
|
|
||||||
void image_clear(struct screen_write_ctx *, u_int);
|
|
||||||
void image_clear_kitty(struct screen_write_ctx *,
|
|
||||||
const struct kitty_parse_result *);
|
|
||||||
int image_grid_has_image(struct grid *, u_int);
|
|
||||||
void image_grid_remove_overwritten_spans(struct grid *, u_int,
|
|
||||||
u_int, u_int, u_int);
|
|
||||||
void image_grid_free_line(struct grid *, struct grid_line *);
|
|
||||||
void image_grid_free(struct grid *);
|
|
||||||
void image_grid_move_cells(struct grid *, u_int, u_int, u_int,
|
|
||||||
u_int);
|
|
||||||
void image_grid_duplicate_lines(struct grid *, u_int, struct grid *,
|
|
||||||
u_int, u_int);
|
|
||||||
void image_grid_copy_area(struct grid *, u_int, u_int, struct grid *,
|
|
||||||
u_int, u_int, u_int, u_int);
|
|
||||||
void image_grid_resize_width(struct grid *, u_int);
|
|
||||||
int image_grid_line_has_images(const struct grid_line *);
|
|
||||||
int image_grid_area_has_images(struct grid *, u_int, u_int, u_int,
|
|
||||||
u_int);
|
|
||||||
int image_grid_get_placeholder(struct grid *, u_int, u_int,
|
|
||||||
struct kitty_placeholder *);
|
|
||||||
void image_place_cell_kitty(struct screen_write_ctx *, struct image *,
|
|
||||||
u_int, u_int, u_int, u_int, u_int, u_int, int32_t);
|
|
||||||
|
|
||||||
/* image-fallback.c */
|
|
||||||
void fallback_get_cell(struct tty *, struct image *, u_int,
|
|
||||||
u_int, const struct grid_cell *, struct grid_cell *);
|
|
||||||
void fallback_free(struct image *);
|
|
||||||
|
|
||||||
/* image-kitty.c */
|
|
||||||
struct image *kitty_parse_image(void **, const u_char *, size_t, u_int,
|
|
||||||
u_int, struct kitty_parse_result *);
|
|
||||||
int kitty_placeholder_to_image(void *, struct grid *,
|
|
||||||
struct grid_cell *, u_int, u_int,
|
|
||||||
struct kitty_placeholder *);
|
|
||||||
int kitty_cell_is_placeholder(const struct grid_cell *);
|
|
||||||
void kitty_delete_images(void *, struct screen_write_ctx *,
|
|
||||||
const struct kitty_parse_result *);
|
|
||||||
void kitty_free_state(void *);
|
|
||||||
void kitty_draw_rect(struct tty *,
|
|
||||||
const struct image_rect *);
|
|
||||||
void kitty_redraw_start(struct tty *, u_int, u_int, u_int, u_int);
|
|
||||||
void kitty_redraw_finish(struct tty *);
|
|
||||||
void kitty_free_output_state(struct tty *, int);
|
|
||||||
|
|
||||||
/* image-sixel.c */
|
|
||||||
#define SIXEL_COLOUR_REGISTERS 1024
|
|
||||||
void sixel_draw_rect(struct tty *,
|
|
||||||
const struct image_rect *);
|
|
||||||
void sixel_redraw_start(struct tty *, u_int, u_int, u_int, u_int);
|
|
||||||
void sixel_free_output(struct tty *, int);
|
|
||||||
void sixel_flush_output(struct tty *);
|
|
||||||
struct sixel_image *sixel_parse(const char *, size_t, u_int, u_int, u_int,
|
|
||||||
u_int);
|
|
||||||
void sixel_free(struct sixel_image *);
|
|
||||||
void sixel_log(struct sixel_image *);
|
|
||||||
struct image *sixel_to_image(struct sixel_image *);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* server-acl.c */
|
/* server-acl.c */
|
||||||
#define SERVER_ACL_READONLY 0x1
|
#define SERVER_ACL_READONLY 0x1
|
||||||
#define SERVER_ACL_IS_GROUP 0x2
|
#define SERVER_ACL_IS_GROUP 0x2
|
||||||
|
|||||||
1
tty.c
1
tty.c
@@ -1487,7 +1487,6 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
|
|||||||
return (&new);
|
return (&new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
tty_sync_start(struct tty *tty)
|
tty_sync_start(struct tty *tty)
|
||||||
{
|
{
|
||||||
|
|||||||
4
utf8.c
4
utf8.c
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: utf8.c,v 1.74 2026/10/05 08:32:24 nicm Exp $ */
|
/* $OpenBSD: utf8.c,v 1.75 2026/10/13 10:21:58 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -835,7 +835,7 @@ utf8_isvalid(const char *s)
|
|||||||
continue;
|
continue;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
if (*s < 0x20 || *s > 0x7e)
|
if (*s != '\t' && *s != '\n' && (*s < 0x20 || *s > 0x7e))
|
||||||
return (0);
|
return (0);
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: window-tree.c,v 1.96 2026/08/25 07:23:30 nicm Exp $ */
|
/* $OpenBSD: window-tree.c,v 1.97 2026/10/12 18:23:25 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -1344,12 +1344,10 @@ window_tree_kill_current_callback(struct client *c, void *modedata,
|
|||||||
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
|
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
|
||||||
return (PROMPT_CLOSE);
|
return (PROMPT_CLOSE);
|
||||||
|
|
||||||
|
data->references++;
|
||||||
window_tree_kill_each(data, mode_tree_get_current(mtd), c, KEYC_NONE);
|
window_tree_kill_each(data, mode_tree_get_current(mtd), c, KEYC_NONE);
|
||||||
server_renumber_all();
|
server_renumber_all();
|
||||||
|
|
||||||
data->references++;
|
|
||||||
cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
|
cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
|
||||||
|
|
||||||
return (PROMPT_CLOSE);
|
return (PROMPT_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1365,12 +1363,10 @@ window_tree_kill_tagged_callback(struct client *c, void *modedata,
|
|||||||
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
|
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
|
||||||
return (PROMPT_CLOSE);
|
return (PROMPT_CLOSE);
|
||||||
|
|
||||||
|
data->references++;
|
||||||
mode_tree_each_tagged(mtd, window_tree_kill_each, c, KEYC_NONE, 1);
|
mode_tree_each_tagged(mtd, window_tree_kill_each, c, KEYC_NONE, 1);
|
||||||
server_renumber_all();
|
server_renumber_all();
|
||||||
|
|
||||||
data->references++;
|
|
||||||
cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
|
cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
|
||||||
|
|
||||||
return (PROMPT_CLOSE);
|
return (PROMPT_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1453,6 +1449,8 @@ window_tree_key(struct window_mode_entry *wme, struct client *c,
|
|||||||
|
|
||||||
item = mode_tree_get_current(data->data);
|
item = mode_tree_get_current(data->data);
|
||||||
finished = mode_tree_key(data->data, c, &key, m, &x, &y);
|
finished = mode_tree_key(data->data, c, &key, m, &x, &y);
|
||||||
|
if (data->dead)
|
||||||
|
return;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
if (item != (new_item = mode_tree_get_current(data->data))) {
|
if (item != (new_item = mode_tree_get_current(data->data))) {
|
||||||
|
|||||||
3
window.c
3
window.c
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: window.c,v 1.385 2026/10/08 07:06:26 nicm Exp $ */
|
/* $OpenBSD: window.c,v 1.386 2026/10/13 10:21:58 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -1670,6 +1670,7 @@ window_pane_free(struct window_pane *wp)
|
|||||||
log_debug("pane %%%u freed (%d references)", wp->id, wp->references);
|
log_debug("pane %%%u freed (%d references)", wp->id, wp->references);
|
||||||
|
|
||||||
free(wp->searchstr);
|
free(wp->searchstr);
|
||||||
|
free(wp->cmd_line);
|
||||||
screen_free(&wp->status_screen);
|
screen_free(&wp->status_screen);
|
||||||
screen_free(&wp->base);
|
screen_free(&wp->base);
|
||||||
free(wp->r.ranges);
|
free(wp->r.ranges);
|
||||||
|
|||||||
Reference in New Issue
Block a user