mirror of
https://github.com/tmux/tmux.git
synced 2026-10-14 15:04:50 +00:00
Merge branch 'image_merge'
This commit is contained in:
@@ -210,6 +210,7 @@ dist_tmux_SOURCES = \
|
||||
style.c \
|
||||
tmux-protocol.h \
|
||||
tmux.c \
|
||||
tmux-image.h \
|
||||
tmux.h \
|
||||
tty-acs.c \
|
||||
tty-draw.c \
|
||||
@@ -251,7 +252,7 @@ endif
|
||||
|
||||
# Enable image support.
|
||||
if ENABLE_IMAGES
|
||||
dist_tmux_SOURCES += image.c image-sixel.c
|
||||
dist_tmux_SOURCES += image.c image-grid.c image-sixel.c
|
||||
endif
|
||||
|
||||
# Add bits for fuzzing if enabled.
|
||||
|
||||
33
grid.c
33
grid.c
@@ -308,6 +308,9 @@ grid_free_line(struct grid *gd, u_int py)
|
||||
{
|
||||
struct grid_line *gl = &gd->linedata[py];
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
image_grid_free_line(gd, gl);
|
||||
#endif
|
||||
free(gl->celldata);
|
||||
free(gl->extddata);
|
||||
memset(gl, 0, sizeof *gl);
|
||||
@@ -347,6 +350,9 @@ void
|
||||
grid_destroy(struct grid *gd)
|
||||
{
|
||||
grid_free_lines(gd, 0, gd->hsize + gd->sy);
|
||||
#ifdef ENABLE_IMAGES
|
||||
image_grid_free(gd);
|
||||
#endif
|
||||
free(gd->linedata);
|
||||
free(gd);
|
||||
}
|
||||
@@ -692,6 +698,9 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg)
|
||||
return;
|
||||
if (grid_check_y(gd, __func__, py + ny - 1) != 0)
|
||||
return;
|
||||
#ifdef ENABLE_IMAGES
|
||||
image_grid_remove(gd, px, py, nx, ny);
|
||||
#endif
|
||||
|
||||
for (yy = py; yy < py + ny; yy++) {
|
||||
gl = &gd->linedata[yy];
|
||||
@@ -794,6 +803,9 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx,
|
||||
|
||||
grid_expand_line(gd, py, px + nx, 8);
|
||||
grid_expand_line(gd, py, dx + nx, 8);
|
||||
#ifdef ENABLE_IMAGES
|
||||
image_grid_move_cells(gd, dx, px, py, nx);
|
||||
#endif
|
||||
memmove(&gl->celldata[dx], &gl->celldata[px],
|
||||
nx * sizeof *gl->celldata);
|
||||
if (dx + nx > gl->cellused)
|
||||
@@ -1233,6 +1245,9 @@ grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy,
|
||||
{
|
||||
struct grid_line *dstl, *srcl;
|
||||
u_int yy;
|
||||
#ifdef ENABLE_IMAGES
|
||||
u_int ody = dy, osy = sy;
|
||||
#endif
|
||||
|
||||
if (dy + ny > dst->hsize + dst->sy)
|
||||
ny = dst->hsize + dst->sy - dy;
|
||||
@@ -1245,6 +1260,9 @@ grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy,
|
||||
dstl = &dst->linedata[dy];
|
||||
|
||||
memcpy(dstl, srcl, sizeof *dstl);
|
||||
#ifdef ENABLE_IMAGES
|
||||
dstl->images = NULL;
|
||||
#endif
|
||||
if (srcl->cellsize != 0) {
|
||||
dstl->celldata = xreallocarray(NULL,
|
||||
srcl->cellsize, sizeof *dstl->celldata);
|
||||
@@ -1264,6 +1282,9 @@ grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy,
|
||||
sy++;
|
||||
dy++;
|
||||
}
|
||||
#ifdef ENABLE_IMAGES
|
||||
image_grid_duplicate_lines(dst, ody, src, osy, ny);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Mark line as dead. */
|
||||
@@ -1384,6 +1405,11 @@ grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
|
||||
break;
|
||||
line = yy + 1 + lines;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_grid_line_has_images(&gd->linedata[line]))
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* Consume empty lines, including any markers. */
|
||||
if (~gd->linedata[line].flags & GRID_LINE_WRAPPED)
|
||||
wrapped = 0;
|
||||
@@ -1561,6 +1587,13 @@ grid_reflow(struct grid *gd, u_int sx)
|
||||
if (gl->flags & GRID_LINE_DEAD)
|
||||
continue;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_grid_line_has_images(gl)) {
|
||||
grid_reflow_move(target, gl);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Work out the width of this line. at is the point at which
|
||||
* the available width is hit, and width is the full line
|
||||
|
||||
382
image-grid.c
Normal file
382
image-grid.c
Normal file
@@ -0,0 +1,382 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* A run of cells on one grid line. */
|
||||
struct image_span {
|
||||
u_int x;
|
||||
u_int sx;
|
||||
u_int source_x;
|
||||
u_int source_y;
|
||||
|
||||
struct image_line *line;
|
||||
struct image_placement *placement;
|
||||
|
||||
TAILQ_ENTRY(image_span) line_entry;
|
||||
TAILQ_ENTRY(image_span) placement_entry;
|
||||
};
|
||||
TAILQ_HEAD(image_spans, image_span);
|
||||
|
||||
/* Spans on one grid line. */
|
||||
struct image_line {
|
||||
struct image_spans spans;
|
||||
};
|
||||
|
||||
/* A placement of an image, may be across multiple lines */
|
||||
struct image_placement {
|
||||
struct image_store *store;
|
||||
struct image *image;
|
||||
struct image_spans spans;
|
||||
|
||||
TAILQ_ENTRY(image_placement) entry;
|
||||
};
|
||||
TAILQ_HEAD(image_placements, image_placement);
|
||||
|
||||
/* Placements owned by one grid. */
|
||||
struct image_store {
|
||||
struct image_placements placements;
|
||||
};
|
||||
|
||||
/* A shared placements copied when duplicating lines. */
|
||||
struct image_copy_map {
|
||||
struct image_placement *source;
|
||||
struct image_placement *destination;
|
||||
};
|
||||
|
||||
/* Part of a span waiting to be moved. */
|
||||
struct image_move {
|
||||
struct image_placement *placement;
|
||||
u_int x;
|
||||
u_int sx;
|
||||
u_int source_x;
|
||||
u_int source_y;
|
||||
};
|
||||
|
||||
/* Get the placement store for a grid. */
|
||||
static struct image_store *
|
||||
image_store_get(struct grid *gd)
|
||||
{
|
||||
if (gd->images == NULL) {
|
||||
gd->images = xcalloc(1, sizeof *gd->images);
|
||||
TAILQ_INIT(&gd->images->placements);
|
||||
}
|
||||
return (gd->images);
|
||||
}
|
||||
|
||||
/* Get the spans for a grid line. */
|
||||
static struct image_line *
|
||||
image_line_get(struct grid_line *gl)
|
||||
{
|
||||
if (gl->images == NULL) {
|
||||
gl->images = xcalloc(1, sizeof *gl->images);
|
||||
TAILQ_INIT(&gl->images->spans);
|
||||
}
|
||||
return (gl->images);
|
||||
}
|
||||
|
||||
/* Create a placement. Takes a reference to the image. */
|
||||
static struct image_placement *
|
||||
image_placement_create(struct grid *gd, struct image *im)
|
||||
{
|
||||
struct image_store *store = image_store_get(gd);
|
||||
struct image_placement *plmt;
|
||||
|
||||
plmt = xcalloc(1, sizeof *plmt);
|
||||
plmt->store = store;
|
||||
plmt->image = im;
|
||||
TAILQ_INIT(&plmt->spans);
|
||||
TAILQ_INSERT_TAIL(&store->placements, plmt, entry);
|
||||
image_ref(im);
|
||||
return (plmt);
|
||||
}
|
||||
|
||||
/* Free a placement after all its spans have gone. */
|
||||
static void
|
||||
image_placement_free(struct image_placement *plmt)
|
||||
{
|
||||
TAILQ_REMOVE(&plmt->store->placements, plmt, entry);
|
||||
image_free(plmt->image);
|
||||
free(plmt);
|
||||
}
|
||||
|
||||
/* Attach a span to both its grid line and its placement. */
|
||||
static void
|
||||
image_span_add(struct image_line *line, struct image_placement *plmt, u_int x,
|
||||
u_int sx, u_int src_x, u_int src_y)
|
||||
{
|
||||
struct image_span *span;
|
||||
|
||||
if (sx == 0)
|
||||
return;
|
||||
|
||||
span = xcalloc(1, sizeof *span);
|
||||
span->x = x;
|
||||
span->sx = sx;
|
||||
span->source_x = src_x;
|
||||
span->source_y = src_y;
|
||||
span->line = line;
|
||||
span->placement = plmt;
|
||||
TAILQ_INSERT_TAIL(&line->spans, span, line_entry);
|
||||
TAILQ_INSERT_TAIL(&plmt->spans, span, placement_entry);
|
||||
}
|
||||
|
||||
/* Detach and free one span. */
|
||||
static void
|
||||
image_span_free(struct image_span *span)
|
||||
{
|
||||
TAILQ_REMOVE(&span->line->spans, span, line_entry);
|
||||
TAILQ_REMOVE(&span->placement->spans, span, placement_entry);
|
||||
free(span);
|
||||
}
|
||||
|
||||
/* Free placements with no remaining spans. */
|
||||
static void
|
||||
image_store_prune(struct image_store *store)
|
||||
{
|
||||
struct image_placement *plmt, *next;
|
||||
|
||||
if (store == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH_SAFE(plmt, &store->placements, entry, next) {
|
||||
if (TAILQ_EMPTY(&plmt->spans))
|
||||
image_placement_free(plmt);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a source rectangle at absolute grid coordinates. */
|
||||
void
|
||||
image_grid_add(struct grid *gd, struct image *im, u_int x, u_int y,
|
||||
u_int src_x, u_int src_y, u_int sx, u_int sy)
|
||||
{
|
||||
struct image_placement *plmt;
|
||||
struct image_line *line;
|
||||
u_int rows = gd->hsize + gd->sy, row;
|
||||
u_int image_sx, image_sy;
|
||||
|
||||
if (sx == 0 || sy == 0 || x >= gd->sx || y >= rows)
|
||||
return;
|
||||
image_get_size_in_cells(im, &image_sx, &image_sy);
|
||||
if (src_x >= image_sx || src_y >= image_sy)
|
||||
return;
|
||||
|
||||
if (sx > gd->sx - x)
|
||||
sx = gd->sx - x;
|
||||
if (sx > image_sx - src_x)
|
||||
sx = image_sx - src_x;
|
||||
if (sy > rows - y)
|
||||
sy = rows - y;
|
||||
if (sy > image_sy - src_y)
|
||||
sy = image_sy - src_y;
|
||||
|
||||
plmt = image_placement_create(gd, im);
|
||||
for (row = 0; row < sy; row++) {
|
||||
line = image_line_get(&gd->linedata[y + row]);
|
||||
image_span_add(line, plmt, x, sx, src_x, src_y + row);
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove the covered part of each span, retaining either side. */
|
||||
static void
|
||||
image_line_remove(struct image_line *line, u_int x, u_int w)
|
||||
{
|
||||
struct image_span *span, *next;
|
||||
u_int end, span_end, right;
|
||||
|
||||
if (line == NULL || w == 0)
|
||||
return;
|
||||
end = x + w;
|
||||
if (end < x)
|
||||
end = UINT_MAX;
|
||||
TAILQ_FOREACH_SAFE(span, &line->spans, line_entry, next) {
|
||||
span_end = span->x + span->sx;
|
||||
if (span_end <= x || span->x >= end)
|
||||
continue;
|
||||
if (span->x < x && span_end > end) {
|
||||
right = span_end - end;
|
||||
span->sx = x - span->x;
|
||||
image_span_add(line, span->placement, end, right,
|
||||
span->source_x + end - span->x, span->source_y);
|
||||
continue;
|
||||
}
|
||||
if (span->x < x) {
|
||||
span->sx = x - span->x;
|
||||
continue;
|
||||
}
|
||||
if (span_end > end) {
|
||||
span->source_x += end - span->x;
|
||||
span->sx = span_end - end;
|
||||
span->x = end;
|
||||
continue;
|
||||
}
|
||||
image_span_free(span);
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove a rectangle of image spans from a grid. */
|
||||
void
|
||||
image_grid_remove(struct grid *gd, u_int x, u_int y, u_int sx, u_int sy)
|
||||
{
|
||||
u_int rows = gd->hsize + gd->sy;
|
||||
u_int row;
|
||||
|
||||
if (gd->images == NULL || sx == 0 || sy == 0 || y >= rows)
|
||||
return;
|
||||
if (sy > rows - y)
|
||||
sy = rows - y;
|
||||
for (row = y; row < y + sy; row++)
|
||||
image_line_remove(gd->linedata[row].images, x, sx);
|
||||
image_store_prune(gd->images);
|
||||
}
|
||||
|
||||
/* Free all spans on a grid line. */
|
||||
void
|
||||
image_grid_free_line(struct grid *gd, struct grid_line *gl)
|
||||
{
|
||||
struct image_line *line = gl->images;
|
||||
struct image_span *span, *next;
|
||||
|
||||
if (line == NULL)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH_SAFE(span, &line->spans, line_entry, next)
|
||||
image_span_free(span);
|
||||
free(line);
|
||||
|
||||
gl->images = NULL;
|
||||
image_store_prune(gd->images);
|
||||
}
|
||||
|
||||
/* Free a grid's empty placement store. */
|
||||
void
|
||||
image_grid_free(struct grid *gd)
|
||||
{
|
||||
if (gd->images != NULL) {
|
||||
image_store_prune(gd->images);
|
||||
free(gd->images);
|
||||
gd->images = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move the image spans belonging to a range of text cells. */
|
||||
void
|
||||
image_grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx)
|
||||
{
|
||||
struct image_line *line;
|
||||
struct image_span *span;
|
||||
struct image_move *moves = NULL;
|
||||
size_t n = 0, i;
|
||||
u_int start, end, span_end;
|
||||
|
||||
if (gd->images == NULL ||
|
||||
nx == 0 ||
|
||||
px == dx ||
|
||||
py >= gd->hsize + gd->sy)
|
||||
return;
|
||||
line = gd->linedata[py].images;
|
||||
if (line == NULL)
|
||||
return;
|
||||
|
||||
end = px + nx;
|
||||
TAILQ_FOREACH(span, &line->spans, line_entry) {
|
||||
span_end = span->x + span->sx;
|
||||
start = (span->x > px ? span->x : px);
|
||||
if (start >= end || span_end <= px)
|
||||
continue;
|
||||
if (span_end > end)
|
||||
span_end = end;
|
||||
|
||||
moves = xreallocarray(moves, n + 1, sizeof *moves);
|
||||
moves[n].placement = span->placement;
|
||||
moves[n].x = dx + start - px;
|
||||
moves[n].sx = span_end - start;
|
||||
moves[n].source_x = span->source_x + start - span->x;
|
||||
moves[n].source_y = span->source_y;
|
||||
n++;
|
||||
}
|
||||
image_line_remove(line, px, nx);
|
||||
image_line_remove(line, dx, nx);
|
||||
for (i = 0; i < n; i++) {
|
||||
image_span_add(line, moves[i].placement, moves[i].x,
|
||||
moves[i].sx, moves[i].source_x, moves[i].source_y);
|
||||
}
|
||||
free(moves);
|
||||
image_store_prune(gd->images);
|
||||
}
|
||||
|
||||
/* Map one source placement to one destination placement during a copy. */
|
||||
static struct image_placement *
|
||||
image_copy_placement(struct grid *dst, struct image_placement *src,
|
||||
struct image_copy_map **maps, u_int *nmaps)
|
||||
{
|
||||
struct image_placement *plmt;
|
||||
struct image_copy_map *map = *maps;
|
||||
u_int i, n = *nmaps;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (map[i].source == src)
|
||||
return (map[i].destination);
|
||||
}
|
||||
plmt = image_placement_create(dst, src->image);
|
||||
|
||||
map = xreallocarray(map, n + 1, sizeof *map);
|
||||
map[n].source = src;
|
||||
map[n].destination = plmt;
|
||||
|
||||
*maps = map;
|
||||
*nmaps = n + 1;
|
||||
return (plmt);
|
||||
}
|
||||
|
||||
/* Duplicate image spans and their placements between grid lines. */
|
||||
void
|
||||
image_grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src,
|
||||
u_int sy, u_int ny)
|
||||
{
|
||||
struct image_copy_map *maps = NULL;
|
||||
struct image_line *src_line, *dst_line;
|
||||
struct image_span *span;
|
||||
struct image_placement *plmt;
|
||||
u_int nmaps = 0, row;
|
||||
|
||||
for (row = 0; row < ny; row++) {
|
||||
src_line = src->linedata[sy + row].images;
|
||||
if (src_line == NULL)
|
||||
continue;
|
||||
dst_line = image_line_get(&dst->linedata[dy + row]);
|
||||
TAILQ_FOREACH(span, &src_line->spans, line_entry) {
|
||||
plmt = image_copy_placement(dst, span->placement, &maps,
|
||||
&nmaps);
|
||||
image_span_add(dst_line, plmt, span->x, span->sx,
|
||||
span->source_x, span->source_y);
|
||||
}
|
||||
}
|
||||
free(maps);
|
||||
}
|
||||
|
||||
/* Check whether a grid line has any image spans. */
|
||||
int
|
||||
image_grid_line_has_images(struct grid_line *gl)
|
||||
{
|
||||
return (gl->images != NULL && !TAILQ_EMPTY(&gl->images->spans));
|
||||
}
|
||||
422
image.c
422
image.c
@@ -2,6 +2,7 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -18,210 +19,289 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
static struct images all_images = TAILQ_HEAD_INITIALIZER(all_images);
|
||||
static u_int all_images_count;
|
||||
#define MAX_IMAGE_COUNT 20
|
||||
/* Maximum image size in bytes. */
|
||||
#define IMAGE_SIZE_LIMIT (64 * 1024 * 1024)
|
||||
|
||||
static void printflike(3, 4)
|
||||
image_log(struct image *im, const char* from, const char* fmt, ...)
|
||||
/* An image. */
|
||||
struct image {
|
||||
u_int id;
|
||||
u_int references;
|
||||
u_int flags;
|
||||
#define IMAGE_FLAG_OWN_PIXELS 0x1
|
||||
|
||||
struct image *parent;
|
||||
u_int source_id;
|
||||
u_int order_id;
|
||||
|
||||
/* Size in cells. */
|
||||
u_int sx;
|
||||
u_int sy;
|
||||
|
||||
/* Size in pixels. */
|
||||
u_int width;
|
||||
u_int height;
|
||||
|
||||
/* Canvas size in pixels. */
|
||||
u_int canvas_width;
|
||||
u_int canvas_height;
|
||||
|
||||
/*
|
||||
* RGBA pixels use four bytes each. Stride is the number of bytes
|
||||
* between the start of each row. Size is the number of bytes
|
||||
* containing all of this image's pixels - it may include pixels that
|
||||
* are part of the parent image but not part of this image.
|
||||
*/
|
||||
size_t stride;
|
||||
size_t size;
|
||||
u_char *pixels;
|
||||
|
||||
RB_ENTRY(image) entry;
|
||||
};
|
||||
RB_HEAD(images, image);
|
||||
static struct images images = RB_INITIALIZER(&images);
|
||||
static u_int image_next_id;
|
||||
|
||||
/* Compare images by IDs. */
|
||||
static int
|
||||
image_cmp(struct image *a, struct image *b)
|
||||
{
|
||||
va_list ap;
|
||||
char s[128];
|
||||
if (a->id < b->id)
|
||||
return (-1);
|
||||
if (a->id > b->id)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
RB_GENERATE_STATIC(images, image, entry, image_cmp);
|
||||
|
||||
if (log_get_level() == 0)
|
||||
return;
|
||||
/* Find an image by its ID. */
|
||||
struct image *
|
||||
image_find(u_int id)
|
||||
{
|
||||
struct image find;
|
||||
|
||||
if (fmt == NULL) {
|
||||
log_debug("%s: %p (%ux%u %u,%u)", from, im, im->sx, im->sy,
|
||||
im->px, im->py);
|
||||
return;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(s, sizeof s, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
log_debug("%s: %p (%ux%u %u,%u): %s", from, im, im->sx, im->sy,
|
||||
im->px, im->py, s);
|
||||
find.id = id;
|
||||
return (RB_FIND(images, &images, &find));
|
||||
}
|
||||
|
||||
static void
|
||||
image_free(struct image *im)
|
||||
/* Return the ID of an image. */
|
||||
u_int
|
||||
image_get_id(struct image *im)
|
||||
{
|
||||
image_log(im, __func__, NULL);
|
||||
|
||||
TAILQ_REMOVE(&all_images, im, all_entry);
|
||||
all_images_count--;
|
||||
|
||||
TAILQ_REMOVE(im->list, im, entry);
|
||||
sixel_free(im->data);
|
||||
free(im->fallback);
|
||||
free(im);
|
||||
return (im->id);
|
||||
}
|
||||
|
||||
int
|
||||
image_free_all(struct screen *s)
|
||||
{
|
||||
struct image *im, *im1;
|
||||
int redraw = !TAILQ_EMPTY(&s->images);
|
||||
|
||||
if (redraw)
|
||||
log_debug ("%s", __func__);
|
||||
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1)
|
||||
image_free(im);
|
||||
return (redraw);
|
||||
}
|
||||
|
||||
/* Create text placeholder for an image. */
|
||||
static void
|
||||
image_fallback(char **ret, u_int sx, u_int sy)
|
||||
{
|
||||
char *buf, *label;
|
||||
u_int py, size, lsize;
|
||||
|
||||
if (sy == 0) {
|
||||
*ret = xstrdup("");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocate first line. */
|
||||
lsize = xasprintf(&label, "SIXEL IMAGE (%ux%u)\r\n", sx, sy) + 1;
|
||||
if (sx < lsize - 3)
|
||||
size = lsize - 1;
|
||||
else
|
||||
size = sx + 2;
|
||||
|
||||
/* Remaining lines. Every placeholder line has \r\n at the end. */
|
||||
size += (sx + 2) * (sy - 1) + 1;
|
||||
*ret = buf = xmalloc(size);
|
||||
|
||||
/* Render first line. */
|
||||
if (sx < lsize - 3) {
|
||||
memcpy(buf, label, lsize);
|
||||
buf += lsize - 1;
|
||||
} else {
|
||||
memcpy(buf, label, lsize - 3);
|
||||
buf += lsize - 3;
|
||||
memset(buf, '+', sx - lsize + 3);
|
||||
buf += sx - lsize + 3;
|
||||
snprintf(buf, 3, "\r\n");
|
||||
buf += 2;
|
||||
}
|
||||
|
||||
/* Remaining lines. */
|
||||
for (py = 1; py < sy; py++) {
|
||||
memset(buf, '+', sx);
|
||||
buf += sx;
|
||||
snprintf(buf, 3, "\r\n");
|
||||
buf += 2;
|
||||
}
|
||||
|
||||
free(label);
|
||||
}
|
||||
|
||||
struct image*
|
||||
image_store(struct screen *s, struct sixel_image *si)
|
||||
/* Allocate an image and assign a unique ID. */
|
||||
static struct image *
|
||||
image_alloc(u_int w, u_int h, u_int cw, u_int ch, u_int sx, u_int sy,
|
||||
size_t stride, u_char *pixels)
|
||||
{
|
||||
struct image *im;
|
||||
u_int id;
|
||||
|
||||
do {
|
||||
if (++image_next_id == 0)
|
||||
image_next_id++;
|
||||
id = image_next_id;
|
||||
} while (image_find(id) != NULL);
|
||||
|
||||
im = xcalloc(1, sizeof *im);
|
||||
im->s = s;
|
||||
im->data = si;
|
||||
|
||||
im->px = s->cx;
|
||||
im->py = s->cy;
|
||||
sixel_size_in_cells(si, &im->sx, &im->sy);
|
||||
|
||||
image_fallback(&im->fallback, im->sx, im->sy);
|
||||
|
||||
image_log(im, __func__, NULL);
|
||||
im->list = &s->images;
|
||||
TAILQ_INSERT_TAIL(im->list, im, entry);
|
||||
|
||||
TAILQ_INSERT_TAIL(&all_images, im, all_entry);
|
||||
if (++all_images_count == MAX_IMAGE_COUNT)
|
||||
image_free(TAILQ_FIRST(&all_images));
|
||||
|
||||
im->id = id;
|
||||
im->references = 1;
|
||||
im->source_id = im->order_id = id;
|
||||
im->width = w;
|
||||
im->height = h;
|
||||
im->canvas_width = cw;
|
||||
im->canvas_height = ch;
|
||||
im->sx = sx;
|
||||
im->sy = sy;
|
||||
im->stride = stride;
|
||||
im->size = (h - 1) * stride + w * 4;
|
||||
im->pixels = pixels;
|
||||
RB_INSERT(images, &images, im);
|
||||
return (im);
|
||||
}
|
||||
|
||||
int
|
||||
image_check_line(struct screen *s, u_int py, u_int ny)
|
||||
/* Create an image with the provided pixels. */
|
||||
struct image *
|
||||
image_create(u_int w, u_int h, u_int cw, u_int ch, u_int sx, u_int sy,
|
||||
u_char *pixels)
|
||||
{
|
||||
struct image *im, *im1;
|
||||
int redraw = 0, in;
|
||||
struct image *im;
|
||||
|
||||
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) {
|
||||
in = (py + ny > im->py && py < im->py + im->sy);
|
||||
image_log(im, __func__, "py=%u, ny=%u, in=%d", py, ny, in);
|
||||
if (in) {
|
||||
image_free(im);
|
||||
redraw = 1;
|
||||
}
|
||||
}
|
||||
return (redraw);
|
||||
if (w == 0 || h == 0 || cw < w || ch < h)
|
||||
return (NULL);
|
||||
if (sx == 0 || sy == 0 || pixels == NULL)
|
||||
return (NULL);
|
||||
if ((uint64_t)w * h > IMAGE_SIZE_LIMIT / 4)
|
||||
return (NULL);
|
||||
if (sx > USHRT_MAX || sy > USHRT_MAX)
|
||||
return (NULL);
|
||||
if (sx * sy > IMAGE_SIZE_LIMIT)
|
||||
return (NULL);
|
||||
|
||||
im = image_alloc(w, h, cw, ch, sx, sy, w * 4, pixels);
|
||||
im->flags |= IMAGE_FLAG_OWN_PIXELS;
|
||||
return (im);
|
||||
}
|
||||
|
||||
int
|
||||
image_check_area(struct screen *s, u_int px, u_int py, u_int nx, u_int ny)
|
||||
/* Resample the crop into transparent, padded RGBA pixels. */
|
||||
static u_char *
|
||||
image_view_resample(struct image *src, struct image_view *view, u_int w,
|
||||
u_int h)
|
||||
{
|
||||
struct image *im, *im1;
|
||||
int redraw = 0, in;
|
||||
u_char *pixels, *row, *src_row;
|
||||
u_int src_x, src_y;
|
||||
uint64_t x, y, off;
|
||||
|
||||
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) {
|
||||
in = (py < im->py + im->sy &&
|
||||
py + ny > im->py &&
|
||||
px < im->px + im->sx &&
|
||||
px + nx > im->px);
|
||||
image_log(im, __func__, "py=%u, ny=%u, in=%d", py, ny, in);
|
||||
if (in) {
|
||||
image_free(im);
|
||||
redraw = 1;
|
||||
pixels = xcalloc(w * h, 4);
|
||||
for (y = 0; y < view->scaled_height; y++) {
|
||||
src_y = view->y + y * view->height / view->scaled_height;
|
||||
src_row = src->pixels + src_y * src->stride + view->x * 4;
|
||||
|
||||
off = ((y + view->canvas_yoff) * w + view->canvas_xoff) * 4;
|
||||
row = pixels + off;
|
||||
|
||||
if (view->scaled_width == view->width)
|
||||
memcpy(row, src_row, view->width * 4);
|
||||
else {
|
||||
for (x = 0; x < view->scaled_width; x++) {
|
||||
src_x = x * view->width / view->scaled_width;
|
||||
memcpy(row + x * 4, src_row + src_x * 4, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (redraw);
|
||||
return (pixels);
|
||||
}
|
||||
|
||||
int
|
||||
image_scroll_up(struct screen *s, u_int lines)
|
||||
/* Crop and resample an image. The view takes a reference to the image. */
|
||||
struct image *
|
||||
image_create_view(struct image *src, struct image_view *view)
|
||||
{
|
||||
struct image *im, *im1;
|
||||
int redraw = 0;
|
||||
u_int sx, sy;
|
||||
struct sixel_image *new;
|
||||
struct image *im;
|
||||
u_char *pixels;
|
||||
u_int w, h;
|
||||
|
||||
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) {
|
||||
if (im->py >= lines) {
|
||||
image_log(im, __func__, "1, lines=%u", lines);
|
||||
im->py -= lines;
|
||||
redraw = 1;
|
||||
continue;
|
||||
}
|
||||
if (im->py + im->sy <= lines) {
|
||||
image_log(im, __func__, "2, lines=%u", lines);
|
||||
image_free(im);
|
||||
redraw = 1;
|
||||
continue;
|
||||
}
|
||||
sx = im->sx;
|
||||
sy = (im->py + im->sy) - lines;
|
||||
image_log(im, __func__, "3, lines=%u, sy=%u", lines, sy);
|
||||
if (src == NULL ||
|
||||
view == NULL ||
|
||||
view->x >= src->width ||
|
||||
view->y >= src->height ||
|
||||
view->width == 0 ||
|
||||
view->height == 0 ||
|
||||
view->scaled_width == 0 ||
|
||||
view->scaled_height == 0 ||
|
||||
view->sx == 0 ||
|
||||
view->sy == 0 ||
|
||||
view->width > src->width - view->x ||
|
||||
view->height > src->height - view->y ||
|
||||
view->sx > USHRT_MAX ||
|
||||
view->sy > USHRT_MAX ||
|
||||
view->sx * view->sy > IMAGE_SIZE_LIMIT ||
|
||||
view->canvas_xoff > view->canvas_width ||
|
||||
view->scaled_width > view->canvas_width - view->canvas_xoff ||
|
||||
view->canvas_yoff > view->canvas_height ||
|
||||
view->scaled_height > view->canvas_height - view->canvas_yoff)
|
||||
return (NULL);
|
||||
|
||||
new = sixel_scale(im->data, 0, 0, 0, im->sy - sy, sx, sy, 1);
|
||||
sixel_free(im->data);
|
||||
im->data = new;
|
||||
|
||||
im->py = 0;
|
||||
sixel_size_in_cells(im->data, &im->sx, &im->sy);
|
||||
|
||||
free(im->fallback);
|
||||
image_fallback(&im->fallback, im->sx, im->sy);
|
||||
redraw = 1;
|
||||
if (view->scaled_width == view->width &&
|
||||
view->scaled_height == view->height &&
|
||||
view->canvas_xoff == 0 &&
|
||||
view->canvas_yoff == 0) {
|
||||
pixels = src->pixels + view->y * src->stride + view->x * 4;
|
||||
im = image_alloc(view->width, view->height, view->canvas_width,
|
||||
view->canvas_height, view->sx, view->sy, src->stride,
|
||||
pixels);
|
||||
} else {
|
||||
w = view->canvas_xoff + view->scaled_width;
|
||||
h = view->canvas_yoff + view->scaled_height;
|
||||
if ((uint64_t)w * h > IMAGE_SIZE_LIMIT / 4)
|
||||
return (NULL);
|
||||
pixels = image_view_resample(src, view, w, h);
|
||||
im = image_alloc(w, h, view->canvas_width, view->canvas_height,
|
||||
view->sx, view->sy, w * 4, pixels);
|
||||
im->flags |= IMAGE_FLAG_OWN_PIXELS;
|
||||
}
|
||||
return (redraw);
|
||||
im->parent = src;
|
||||
im->source_id = src->source_id;
|
||||
im->order_id = src->order_id;
|
||||
image_ref(src);
|
||||
return (im);
|
||||
}
|
||||
|
||||
/* Add a reference to an image. */
|
||||
void
|
||||
image_ref(struct image *im)
|
||||
{
|
||||
if (im->references == UINT_MAX)
|
||||
fatalx("invalid image reference %u", im->id);
|
||||
im->references++;
|
||||
}
|
||||
|
||||
/* Free an image. */
|
||||
void
|
||||
image_free(struct image *im)
|
||||
{
|
||||
if (im->references == 0)
|
||||
fatalx("invalid image reference %u", im->id);
|
||||
if (--im->references == 0) {
|
||||
RB_REMOVE(images, &images, im);
|
||||
if (im->flags & IMAGE_FLAG_OWN_PIXELS)
|
||||
free(im->pixels);
|
||||
if (im->parent != NULL)
|
||||
image_free(im->parent);
|
||||
free(im);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return image size in pixels. */
|
||||
void
|
||||
image_get_size(struct image *im, u_int *w, u_int *h)
|
||||
{
|
||||
*w = im->width;
|
||||
*h = im->height;
|
||||
}
|
||||
|
||||
/* Return canvas size in pixels. */
|
||||
void
|
||||
image_get_canvas_size(struct image *im, u_int *w, u_int *h)
|
||||
{
|
||||
*w = im->canvas_width;
|
||||
*h = im->canvas_height;
|
||||
}
|
||||
|
||||
/* Return image size in cells. */
|
||||
void
|
||||
image_get_size_in_cells(struct image *im, u_int *sx, u_int *sy)
|
||||
{
|
||||
*sx = im->sx;
|
||||
*sy = im->sy;
|
||||
}
|
||||
|
||||
/* Return image pixels. */
|
||||
const u_char *
|
||||
image_get_pixels(struct image *im, size_t *stride, size_t *size)
|
||||
{
|
||||
if (stride != NULL)
|
||||
*stride = im->stride;
|
||||
if (size != NULL)
|
||||
*size = im->size;
|
||||
return (im->pixels);
|
||||
}
|
||||
|
||||
/* Calculate the cell size. */
|
||||
void
|
||||
image_size_in_cells(u_int w, u_int h, u_int xpixel, u_int ypixel, u_int *sx,
|
||||
u_int *sy)
|
||||
{
|
||||
if (xpixel == 0)
|
||||
xpixel = 8;
|
||||
if (ypixel == 0)
|
||||
ypixel = 16;
|
||||
*sx = w / xpixel + (w % xpixel != 0);
|
||||
*sy = h / ypixel + (h % ypixel != 0);
|
||||
}
|
||||
|
||||
19
input.c
19
input.c
@@ -2629,11 +2629,6 @@ input_dcs_dispatch(struct input_ctx *ictx)
|
||||
const char prefix[] = "tmux;";
|
||||
const u_int prefixlen = (sizeof prefix) - 1;
|
||||
long long allow_passthrough = 0;
|
||||
#ifdef ENABLE_IMAGES
|
||||
struct window *w;
|
||||
struct sixel_image *si;
|
||||
int p2;
|
||||
#endif
|
||||
|
||||
if (wp == NULL)
|
||||
oo = global_w_options;
|
||||
@@ -2645,20 +2640,6 @@ input_dcs_dispatch(struct input_ctx *ictx)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (wp != NULL && buf[0] == 'q' && ictx->interm_len == 0) {
|
||||
w = wp->window;
|
||||
if (input_split(ictx) != 0)
|
||||
return (0);
|
||||
p2 = input_get(ictx, 1, 0, 0);
|
||||
if (p2 == -1)
|
||||
p2 = 0;
|
||||
si = sixel_parse(buf, len, p2, w->xpixel, w->ypixel);
|
||||
if (si != NULL)
|
||||
screen_write_sixelimage(sctx, si, ictx->cell.cell.bg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* DCS sequences with intermediate byte '$' (includes DECRQSS). */
|
||||
if (ictx->interm_len == 1 && ictx->interm_buf[0] == '$') {
|
||||
/* DECRQSS is DCS $ q Pt ST. */
|
||||
|
||||
@@ -1921,15 +1921,6 @@ redraw_draw(struct client *c, struct window_pane *wp, int flags)
|
||||
|
||||
tty_reset(tty);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (wp != NULL)
|
||||
tty_draw_images(c, wp);
|
||||
else {
|
||||
TAILQ_FOREACH(loop, &scene->w->panes, entry)
|
||||
tty_draw_images(c, loop);
|
||||
}
|
||||
#endif
|
||||
|
||||
log_debug("%s: finished @%u redraw", c->name, scene->w->id);
|
||||
}
|
||||
|
||||
|
||||
152
screen-write.c
152
screen-write.c
@@ -1471,11 +1471,6 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
utf8_set(&gc.data, 'E');
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_free_all(s) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
for (yy = 0; yy < screen_size_y(s); yy++) {
|
||||
for (xx = 0; xx < screen_size_x(s); xx++)
|
||||
grid_view_set_cell(s->grid, xx, yy, &gc);
|
||||
@@ -1518,11 +1513,6 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
|
||||
if (s->cx > screen_size_x(s) - 1)
|
||||
return;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
screen_write_initctx(ctx, &ttyctx, 0, 1);
|
||||
ttyctx.bg = bg;
|
||||
|
||||
@@ -1559,11 +1549,6 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
|
||||
if (s->cx > screen_size_x(s) - 1)
|
||||
return;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
screen_write_initctx(ctx, &ttyctx, 0, 1);
|
||||
ttyctx.bg = bg;
|
||||
|
||||
@@ -1600,11 +1585,6 @@ screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
|
||||
if (s->cx > screen_size_x(s) - 1)
|
||||
return;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
screen_write_initctx(ctx, &ttyctx, 0, 1);
|
||||
ttyctx.bg = bg;
|
||||
|
||||
@@ -1635,11 +1615,6 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
|
||||
if (ny == 0)
|
||||
ny = 1;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
if (s->cy < s->rupper || s->cy > s->rlower) {
|
||||
if (ny > sy - s->cy)
|
||||
ny = sy - s->cy;
|
||||
@@ -1703,11 +1678,6 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
|
||||
if (ny == 0)
|
||||
ny = 1;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
if (s->cy < s->rupper || s->cy > s->rlower) {
|
||||
if (ny > sy - s->cy)
|
||||
ny = sy - s->cy;
|
||||
@@ -1776,11 +1746,6 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
|
||||
if (gl->cellsize == 0 && COLOUR_DEFAULT(bg))
|
||||
return;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
flags = gl->flags & GRID_LINE_OSC133_FLAGS;
|
||||
memcpy(&od, &gl->osc133_data, sizeof od);
|
||||
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
|
||||
@@ -1815,11 +1780,6 @@ screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg)
|
||||
if (s->cx > sx - 1 || (s->cx >= gl->cellsize && COLOUR_DEFAULT(bg)))
|
||||
return;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg);
|
||||
|
||||
ci->x = s->cx;
|
||||
@@ -1842,11 +1802,6 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_check_line(s, s->cy, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
if (s->cx > sx - 1)
|
||||
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
|
||||
else
|
||||
@@ -1896,11 +1851,6 @@ screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_free_all(s) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg);
|
||||
screen_write_collect_flush(ctx, 0, __func__);
|
||||
|
||||
@@ -1948,9 +1898,6 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
|
||||
struct screen *s = ctx->s;
|
||||
struct grid *gd = s->grid;
|
||||
struct grid_line *gl;
|
||||
#ifdef ENABLE_IMAGES
|
||||
int redraw = 0;
|
||||
#endif
|
||||
u_int rupper = s->rupper, rlower = s->rlower;
|
||||
|
||||
gl = grid_get_line(gd, gd->hsize + s->cy);
|
||||
@@ -1971,15 +1918,6 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (rlower == screen_size_y(s) - 1)
|
||||
redraw = image_scroll_up(s, 1);
|
||||
else
|
||||
redraw = image_check_line(s, rupper, rlower - rupper);
|
||||
if (redraw && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg);
|
||||
screen_write_collect_scroll(ctx, bg);
|
||||
ctx->scrolled++;
|
||||
@@ -2003,11 +1941,6 @@ screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines, u_int bg)
|
||||
ctx->bg = bg;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_scroll_up(s, lines) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < lines; i++) {
|
||||
grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg);
|
||||
screen_write_collect_scroll(ctx, bg);
|
||||
@@ -2032,11 +1965,6 @@ screen_write_scrolldown(struct screen_write_ctx *ctx, u_int lines, u_int bg)
|
||||
else if (lines > s->rlower - s->rupper + 1)
|
||||
lines = s->rlower - s->rupper + 1;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_free_all(s) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < lines; i++)
|
||||
grid_view_scroll_region_down(gd, s->rupper, s->rlower, bg);
|
||||
|
||||
@@ -2073,11 +2001,6 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
|
||||
struct visible_ranges *r;
|
||||
struct visible_range *ri;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_check_line(s, s->cy, sy - s->cy) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
||||
ttyctx.bg = bg;
|
||||
|
||||
@@ -2154,11 +2077,6 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
|
||||
struct visible_ranges *r;
|
||||
struct visible_range *ri;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_check_line(s, 0, s->cy - 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
||||
ttyctx.bg = bg;
|
||||
|
||||
@@ -2227,11 +2145,6 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
|
||||
struct visible_ranges *r;
|
||||
struct visible_range *ri;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_free_all(s) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
screen_write_initctx(ctx, &ttyctx, 1, 1);
|
||||
ttyctx.bg = bg;
|
||||
|
||||
@@ -2736,11 +2649,6 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
if (image_check_area(s, s->cx, s->cy, ci->used, 1) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
grid_view_set_cells(s->grid, s->cx, s->cy, &ci->gc, cl->data + ci->x,
|
||||
ci->used);
|
||||
if (bnx != 0)
|
||||
@@ -3240,66 +3148,6 @@ screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len,
|
||||
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 screen *s = ctx->s;
|
||||
struct grid *gd = s->grid;
|
||||
struct tty_ctx ttyctx;
|
||||
u_int x, y, sx, sy, cx = s->cx, cy = s->cy, i, lines;
|
||||
struct sixel_image *new;
|
||||
|
||||
if (screen_size_y(s) == 1)
|
||||
return;
|
||||
|
||||
sixel_size_in_cells(si, &x, &y);
|
||||
if (x > screen_size_x(s) || y > screen_size_y(s) - 1) {
|
||||
if (x > screen_size_x(s) - cx)
|
||||
sx = screen_size_x(s) - cx;
|
||||
else
|
||||
sx = x;
|
||||
if (y > screen_size_y(s) - 1)
|
||||
sy = screen_size_y(s) - 1;
|
||||
else
|
||||
sy = y;
|
||||
new = sixel_scale(si, 0, 0, 0, y - sy, sx, sy, 1);
|
||||
sixel_free(si);
|
||||
if (new == NULL)
|
||||
return;
|
||||
sixel_size_in_cells(new, &x, &y);
|
||||
si = new;
|
||||
}
|
||||
|
||||
sy = screen_size_y(s) - cy;
|
||||
if (sy <= y) {
|
||||
lines = y - sy + 1;
|
||||
if (image_scroll_up(s, lines) && ctx->wp != NULL)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
for (i = 0; i < lines; i++) {
|
||||
grid_view_scroll_region_up(gd, 0, screen_size_y(s) - 1,
|
||||
bg);
|
||||
screen_write_collect_scroll(ctx, bg);
|
||||
}
|
||||
ctx->scrolled += lines;
|
||||
if (lines > cy)
|
||||
screen_write_cursormove(ctx, -1, 0, 0);
|
||||
else
|
||||
screen_write_cursormove(ctx, -1, cy - lines, 0);
|
||||
}
|
||||
screen_write_collect_flush(ctx, 0, __func__);
|
||||
|
||||
screen_write_initctx(ctx, &ttyctx, 0, 0);
|
||||
ttyctx.image = image_store(s, si);
|
||||
|
||||
tty_write(tty_cmd_sixelimage, &ttyctx);
|
||||
|
||||
screen_write_cursormove(ctx, 0, cy + y, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Turn alternate screen on. */
|
||||
void
|
||||
screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc,
|
||||
|
||||
50
screen.c
50
screen.c
@@ -93,11 +93,6 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
|
||||
s->tabs = NULL;
|
||||
s->sel = NULL;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
TAILQ_INIT(&s->images);
|
||||
TAILQ_INIT(&s->saved_images);
|
||||
#endif
|
||||
|
||||
s->write_list = NULL;
|
||||
s->hyperlinks = NULL;
|
||||
|
||||
@@ -129,11 +124,6 @@ screen_reinit(struct screen *s)
|
||||
|
||||
screen_clear_selection(s);
|
||||
screen_free_titles(s);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
image_free_all(s);
|
||||
#endif
|
||||
|
||||
screen_set_progress_bar(s, PROGRESS_BAR_HIDDEN, 0);
|
||||
screen_reset_hyperlinks(s);
|
||||
}
|
||||
@@ -152,10 +142,6 @@ screen_reset_hyperlinks(struct screen *s)
|
||||
void
|
||||
screen_free(struct screen *s)
|
||||
{
|
||||
#ifdef ENABLE_IMAGES
|
||||
struct image *im;
|
||||
#endif
|
||||
|
||||
free(s->sel);
|
||||
free(s->tabs);
|
||||
free(s->path);
|
||||
@@ -172,17 +158,6 @@ screen_free(struct screen *s)
|
||||
hyperlinks_free(s->hyperlinks);
|
||||
screen_free_titles(s);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
/*
|
||||
* Images saved when entering the alternate screen stay linked in the
|
||||
* global list; move them back so they are freed and unlinked here, or
|
||||
* a later eviction would write through this freed screen.
|
||||
*/
|
||||
TAILQ_CONCAT(&s->images, &s->saved_images, entry);
|
||||
TAILQ_FOREACH(im, &s->images, entry)
|
||||
im->list = &s->images;
|
||||
image_free_all(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Reset tabs to default, eight spaces apart. */
|
||||
@@ -375,10 +350,6 @@ screen_resize_cursor(struct screen *s, u_int sx, u_int sy, int reflow,
|
||||
if (sy != screen_size_y(s))
|
||||
screen_resize_y(s, sy, eat_empty, &cy);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
image_free_all(s);
|
||||
#endif
|
||||
|
||||
if (reflow)
|
||||
screen_reflow(s, sx, &cx, &cy, cursor);
|
||||
|
||||
@@ -690,10 +661,6 @@ int
|
||||
screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor)
|
||||
{
|
||||
u_int sx, sy;
|
||||
#ifdef ENABLE_IMAGES
|
||||
struct image *im;
|
||||
#endif
|
||||
|
||||
if (SCREEN_IS_ALTERNATE(s))
|
||||
return 0;
|
||||
sx = screen_size_x(s);
|
||||
@@ -707,12 +674,6 @@ screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor)
|
||||
}
|
||||
memcpy(&s->saved_cell, gc, sizeof s->saved_cell);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
TAILQ_CONCAT(&s->saved_images, &s->images, entry);
|
||||
TAILQ_FOREACH(im, &s->saved_images, entry)
|
||||
im->list = &s->saved_images;
|
||||
#endif
|
||||
|
||||
grid_view_clear(s->grid, 0, 0, sx, sy, 8);
|
||||
|
||||
s->saved_flags = s->grid->flags;
|
||||
@@ -726,10 +687,6 @@ int
|
||||
screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
|
||||
{
|
||||
u_int sx = screen_size_x(s), sy = screen_size_y(s);
|
||||
#ifdef ENABLE_IMAGES
|
||||
struct image *im;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the current size is different, temporarily resize to the old size
|
||||
* before copying back.
|
||||
@@ -776,13 +733,6 @@ screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
|
||||
grid_destroy(s->saved_grid);
|
||||
s->saved_grid = NULL;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
image_free_all(s);
|
||||
TAILQ_CONCAT(&s->images, &s->saved_images, entry);
|
||||
TAILQ_FOREACH(im, &s->images, entry)
|
||||
im->list = &s->images;
|
||||
#endif
|
||||
|
||||
if (s->cx > screen_size_x(s) - 1)
|
||||
s->cx = screen_size_x(s) - 1;
|
||||
if (s->cy > screen_size_y(s) - 1)
|
||||
|
||||
99
tmux-image.h
Normal file
99
tmux-image.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/* $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
|
||||
#error image support is not ready yet
|
||||
|
||||
struct grid;
|
||||
struct grid_line;
|
||||
struct image;
|
||||
struct image_line;
|
||||
struct image_store;
|
||||
struct screen;
|
||||
struct screen_write_ctx;
|
||||
struct sixel_image;
|
||||
|
||||
/* 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 *);
|
||||
|
||||
/* 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_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 *);
|
||||
|
||||
/* image-sixel.c */
|
||||
#define SIXEL_COLOUR_REGISTERS 1024
|
||||
struct sixel_image *sixel_parse(const char *, size_t, u_int, u_int, u_int);
|
||||
void sixel_free(struct sixel_image *);
|
||||
void sixel_log(struct sixel_image *);
|
||||
void sixel_size_in_cells(struct sixel_image *, u_int *, u_int *);
|
||||
struct sixel_image *sixel_scale(struct sixel_image *, u_int, u_int, u_int,
|
||||
u_int, u_int, u_int, int);
|
||||
char *sixel_print(struct sixel_image *, struct sixel_image *,
|
||||
size_t *);
|
||||
struct screen *sixel_to_screen(struct sixel_image *);
|
||||
|
||||
#endif /* ENABLE_IMAGES */
|
||||
|
||||
#endif /* TMUX_IMAGE_H */
|
||||
70
tmux.h
70
tmux.h
@@ -19,11 +19,13 @@
|
||||
#ifndef TMUX_H
|
||||
#define TMUX_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
#include <wchar.h>
|
||||
@@ -33,6 +35,7 @@
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "tmux-image.h"
|
||||
#include "tmux-protocol.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
@@ -77,10 +80,6 @@ struct screen_write_cline;
|
||||
struct screen_write_ctx;
|
||||
struct session;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
struct sixel_image;
|
||||
#endif
|
||||
|
||||
struct tty_ctx;
|
||||
struct tty_code;
|
||||
struct tty_key;
|
||||
@@ -927,6 +926,9 @@ struct grid_line {
|
||||
u_int time;
|
||||
struct osc133_data osc133_data;
|
||||
u_short flags;
|
||||
#ifdef ENABLE_IMAGES
|
||||
struct image_line *images;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Entire grid of cells. */
|
||||
@@ -946,6 +948,9 @@ struct grid {
|
||||
u_int scroll_generation;
|
||||
|
||||
struct grid_line *linedata;
|
||||
#ifdef ENABLE_IMAGES
|
||||
struct image_store *images;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Virtual cursor in a grid. */
|
||||
@@ -1037,26 +1042,6 @@ struct style {
|
||||
u_int link;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
/* Image. */
|
||||
struct image {
|
||||
struct screen *s;
|
||||
struct sixel_image *data;
|
||||
char *fallback;
|
||||
|
||||
u_int px;
|
||||
u_int py;
|
||||
u_int sx;
|
||||
u_int sy;
|
||||
|
||||
struct images *list;
|
||||
TAILQ_ENTRY (image) entry;
|
||||
|
||||
TAILQ_ENTRY (image) all_entry;
|
||||
};
|
||||
TAILQ_HEAD(images, image);
|
||||
#endif
|
||||
|
||||
/* Cursor style. */
|
||||
enum screen_cursor_style {
|
||||
SCREEN_CURSOR_DEFAULT,
|
||||
@@ -1113,11 +1098,6 @@ struct screen {
|
||||
bitstr_t *tabs;
|
||||
struct screen_sel *sel;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
struct images images;
|
||||
struct images saved_images;
|
||||
#endif
|
||||
|
||||
struct screen_write_cline *write_list;
|
||||
|
||||
struct hyperlinks *hyperlinks;
|
||||
@@ -1907,9 +1887,6 @@ struct tty_ctx {
|
||||
size_t size;
|
||||
} sel;
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
struct image *image;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3008,10 +2985,6 @@ void tty_cmd_scrolldown(struct tty *, const struct tty_ctx *);
|
||||
void tty_cmd_reverseindex(struct tty *, const struct tty_ctx *);
|
||||
void tty_cmd_setselection(struct tty *, const struct tty_ctx *);
|
||||
void tty_cmd_rawstring(struct tty *, const struct tty_ctx *);
|
||||
#ifdef ENABLE_IMAGES
|
||||
void tty_cmd_sixelimage(struct tty *, const struct tty_ctx *);
|
||||
void tty_draw_images(struct client *, struct window_pane *);
|
||||
#endif
|
||||
void tty_cmd_syncstart(struct tty *, const struct tty_ctx *);
|
||||
void tty_default_colours(struct grid_cell *, struct window_pane *, u_int *);
|
||||
|
||||
@@ -3652,10 +3625,6 @@ void screen_write_setselection(struct screen_write_ctx *, const char *,
|
||||
u_char *, u_int);
|
||||
void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int,
|
||||
int);
|
||||
#ifdef ENABLE_IMAGES
|
||||
void screen_write_sixelimage(struct screen_write_ctx *,
|
||||
struct sixel_image *, u_int);
|
||||
#endif
|
||||
void screen_write_alternateon(struct screen_write_ctx *,
|
||||
struct grid_cell *, int);
|
||||
void screen_write_alternateoff(struct screen_write_ctx *,
|
||||
@@ -4240,27 +4209,6 @@ void spawn_editor_finish(struct window_pane *);
|
||||
/* regsub.c */
|
||||
char *regsub(const char *, const char *, const char *, int);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
/* image.c */
|
||||
int image_free_all(struct screen *);
|
||||
struct image *image_store(struct screen *, struct sixel_image *);
|
||||
int image_check_line(struct screen *, u_int, u_int);
|
||||
int image_check_area(struct screen *, u_int, u_int, u_int, u_int);
|
||||
int image_scroll_up(struct screen *, u_int);
|
||||
|
||||
/* image-sixel.c */
|
||||
#define SIXEL_COLOUR_REGISTERS 1024
|
||||
struct sixel_image *sixel_parse(const char *, size_t, u_int, u_int, u_int);
|
||||
void sixel_free(struct sixel_image *);
|
||||
void sixel_log(struct sixel_image *);
|
||||
void sixel_size_in_cells(struct sixel_image *, u_int *, u_int *);
|
||||
struct sixel_image *sixel_scale(struct sixel_image *, u_int, u_int, u_int,
|
||||
u_int, u_int, u_int, int);
|
||||
char *sixel_print(struct sixel_image *, struct sixel_image *,
|
||||
size_t *);
|
||||
struct screen *sixel_to_screen(struct sixel_image *);
|
||||
#endif
|
||||
|
||||
/* server-acl.c */
|
||||
#define SERVER_ACL_READONLY 0x1
|
||||
#define SERVER_ACL_IS_GROUP 0x2
|
||||
|
||||
124
tty.c
124
tty.c
@@ -68,11 +68,6 @@ static void tty_emulate_repeat(struct tty *, enum tty_code_code,
|
||||
enum tty_code_code, u_int);
|
||||
static void tty_draw_pane(struct tty *, const struct tty_ctx *, u_int);
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
static void tty_write_one(void (*)(struct tty *, const struct tty_ctx *),
|
||||
struct client *, struct tty_ctx *);
|
||||
#endif
|
||||
|
||||
#define tty_use_margin(tty) \
|
||||
(tty->term->flags & TERM_DECSLRM)
|
||||
#define tty_full_width(tty, ctx) \
|
||||
@@ -1460,60 +1455,6 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
|
||||
return (&new);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
/* Update context for client. */
|
||||
static int
|
||||
tty_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
|
||||
{
|
||||
struct window_pane *wp = ttyctx->arg;
|
||||
|
||||
if (c->session->curw->window != wp->window)
|
||||
return (0);
|
||||
if (wp->layout_cell == NULL)
|
||||
return (0);
|
||||
|
||||
if (tty_window_offset(&c->tty, &ttyctx->wox, &ttyctx->woy, &ttyctx->wsx,
|
||||
&ttyctx->wsy))
|
||||
ttyctx->flags |= TTY_CTX_WINDOW_BIGGER;
|
||||
else
|
||||
ttyctx->flags &= ~TTY_CTX_WINDOW_BIGGER;
|
||||
|
||||
ttyctx->yoff = ttyctx->ryoff = wp->yoff;
|
||||
if (status_at_line(c) == 0)
|
||||
ttyctx->yoff += status_line_size(c);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
tty_draw_images(struct client *c, struct window_pane *wp)
|
||||
{
|
||||
struct image *im;
|
||||
struct tty_ctx ttyctx;
|
||||
|
||||
TAILQ_FOREACH(im, &wp->screen->images, entry) {
|
||||
memset(&ttyctx, 0, sizeof ttyctx);
|
||||
|
||||
/* Set the client independent properties. */
|
||||
ttyctx.ocx = im->px;
|
||||
ttyctx.ocy = im->py;
|
||||
|
||||
ttyctx.orlower = wp->screen->rlower;
|
||||
ttyctx.orupper = wp->screen->rupper;
|
||||
|
||||
ttyctx.xoff = ttyctx.rxoff = wp->xoff;
|
||||
ttyctx.sx = wp->sx;
|
||||
ttyctx.sy = wp->sy;
|
||||
|
||||
ttyctx.image = im;
|
||||
ttyctx.arg = wp;
|
||||
ttyctx.set_client_cb = tty_set_client_cb;
|
||||
ttyctx.flags |= TTY_CTX_INVISIBLE_PANES;
|
||||
tty_write_one(tty_cmd_sixelimage, c, &ttyctx);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
tty_sync_start(struct tty *tty)
|
||||
{
|
||||
@@ -1588,19 +1529,6 @@ tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *),
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
/* Only write to the incoming tty instead of every client. */
|
||||
static void
|
||||
tty_write_one(void (*cmdfn)(struct tty *, const struct tty_ctx *),
|
||||
struct client *c, struct tty_ctx *ctx)
|
||||
{
|
||||
if (ctx->set_client_cb == NULL)
|
||||
return;
|
||||
if ((ctx->set_client_cb(ctx, c)) == 1)
|
||||
cmdfn(&c->tty, ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
@@ -2034,58 +1962,6 @@ tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx)
|
||||
tty_invalidate(tty);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IMAGES
|
||||
void
|
||||
tty_cmd_sixelimage(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
struct image *im = ctx->image;
|
||||
struct sixel_image *si = im->data;
|
||||
struct sixel_image *new;
|
||||
char *data;
|
||||
size_t size;
|
||||
u_int cx = ctx->ocx, cy = ctx->ocy, sx, sy;
|
||||
u_int i, j, x, y, rx, ry;
|
||||
int fallback = 0;
|
||||
|
||||
if ((~tty->term->flags & TERM_SIXEL) &&
|
||||
!tty_term_has(tty->term, TTYC_SXL))
|
||||
fallback = 1;
|
||||
if (tty->xpixel == 0 || tty->ypixel == 0)
|
||||
fallback = 1;
|
||||
|
||||
sixel_size_in_cells(si, &sx, &sy);
|
||||
log_debug("%s: image is %ux%u", __func__, sx, sy);
|
||||
if (!tty_clamp_area(tty, ctx, cx, cy, sx, sy, &i, &j, &x, &y, &rx, &ry))
|
||||
return;
|
||||
log_debug("%s: clamping to %u,%u-%u,%u", __func__, i, j, rx, ry);
|
||||
|
||||
if (fallback == 1) {
|
||||
data = xstrdup(im->fallback);
|
||||
size = strlen(data);
|
||||
} else {
|
||||
new = sixel_scale(si, tty->xpixel, tty->ypixel, i, j, rx, ry, 0);
|
||||
if (new == NULL)
|
||||
return;
|
||||
|
||||
data = sixel_print(new, si, &size);
|
||||
}
|
||||
if (data != NULL) {
|
||||
log_debug("%s: %zu bytes: %s", __func__, size, data);
|
||||
tty_region_off(tty);
|
||||
tty_margin_off(tty);
|
||||
tty_cursor(tty, x, y);
|
||||
|
||||
tty->flags |= TTY_NOBLOCK;
|
||||
tty_add(tty, data, size);
|
||||
tty_invalidate(tty);
|
||||
free(data);
|
||||
}
|
||||
|
||||
if (fallback == 0)
|
||||
sixel_free(new);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
tty_cmd_syncstart(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user