Merge branch 'master' into sixel

This commit is contained in:
Nicholas Marriott
2021-12-08 10:37:33 +00:00
39 changed files with 1218 additions and 433 deletions

260
tty.c
View File

@@ -38,7 +38,7 @@ static int tty_client_ready(struct client *);
static void tty_set_italics(struct tty *);
static int tty_try_colour(struct tty *, int, const char *);
static void tty_force_cursor_colour(struct tty *, const char *);
static void tty_force_cursor_colour(struct tty *, int);
static void tty_cursor_pane(struct tty *, const struct tty_ctx *, u_int,
u_int);
static void tty_cursor_pane_unless_wrap(struct tty *,
@@ -71,6 +71,8 @@ static void tty_draw_pane(struct tty *, const struct tty_ctx *, u_int);
static void tty_default_attributes(struct tty *, const struct grid_cell *,
struct colour_palette *, u_int);
static int tty_check_overlay(struct tty *, u_int, u_int);
static void tty_check_overlay_range(struct tty *, u_int, u_int, u_int,
struct overlay_ranges *);
#define tty_use_margin(tty) \
(tty->term->flags & TERM_DECSLRM)
@@ -103,7 +105,7 @@ tty_init(struct tty *tty, struct client *c)
tty->client = c;
tty->cstyle = SCREEN_CURSOR_DEFAULT;
tty->ccolour = xstrdup("");
tty->ccolour = -1;
if (tcgetattr(c->fd, &tty->tio) != 0)
return (-1);
@@ -305,7 +307,7 @@ tty_start_tty(struct tty *tty)
{
struct client *c = tty->client;
struct termios tio;
struct timeval tv = { .tv_sec = 1 };
struct timeval tv = { .tv_sec = 3 };
setblocking(c->fd, 0);
event_add(&tty->event_in, NULL);
@@ -344,8 +346,8 @@ tty_start_tty(struct tty *tty)
tty->flags |= TTY_STARTED;
tty_invalidate(tty);
if (*tty->ccolour != '\0')
tty_force_cursor_colour(tty, "");
if (tty->ccolour != -1)
tty_force_cursor_colour(tty, -1);
tty->mouse_drag_flag = 0;
tty->mouse_drag_update = NULL;
@@ -409,7 +411,7 @@ tty_stop_tty(struct tty *tty)
}
if (tty->mode & MODE_BRACKETPASTE)
tty_raw(tty, tty_term_string(tty->term, TTYC_DSBP));
if (*tty->ccolour != '\0')
if (tty->ccolour != -1)
tty_raw(tty, tty_term_string(tty->term, TTYC_CR));
tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM));
@@ -454,7 +456,6 @@ void
tty_free(struct tty *tty)
{
tty_close(tty);
free(tty->ccolour);
}
void
@@ -653,39 +654,66 @@ tty_set_title(struct tty *tty, const char *title)
}
static void
tty_force_cursor_colour(struct tty *tty, const char *ccolour)
tty_force_cursor_colour(struct tty *tty, int c)
{
if (*ccolour == '\0')
u_char r, g, b;
char s[13] = "";
if (c != -1)
c = colour_force_rgb(c);
if (c == tty->ccolour)
return;
if (c == -1)
tty_putcode(tty, TTYC_CR);
else
tty_putcode_ptr1(tty, TTYC_CS, ccolour);
free(tty->ccolour);
tty->ccolour = xstrdup(ccolour);
else {
colour_split_rgb(c, &r, &g, &b);
xsnprintf(s, sizeof s, "rgb:%02hhx/%02hhx/%02hhx", r, g, b);
tty_putcode_ptr1(tty, TTYC_CS, s);
}
tty->ccolour = c;
}
static void
tty_update_cursor(struct tty *tty, int mode, int changed, struct screen *s)
static int
tty_update_cursor(struct tty *tty, int mode, struct screen *s)
{
enum screen_cursor_style cstyle;
enum screen_cursor_style cstyle;
int ccolour, changed, cmode = mode;
/* Set cursor colour if changed. */
if (s != NULL && strcmp(s->ccolour, tty->ccolour) != 0)
tty_force_cursor_colour(tty, s->ccolour);
if (s != NULL) {
ccolour = s->ccolour;
if (s->ccolour == -1)
ccolour = s->default_ccolour;
tty_force_cursor_colour(tty, ccolour);
}
/* If cursor is off, set as invisible. */
if (~mode & MODE_CURSOR) {
if (changed & MODE_CURSOR)
if (~cmode & MODE_CURSOR) {
if (tty->mode & MODE_CURSOR)
tty_putcode(tty, TTYC_CIVIS);
return;
return (cmode);
}
/* Check if blinking or very visible flag changed or style changed. */
if (s == NULL)
cstyle = tty->cstyle;
else
else {
cstyle = s->cstyle;
if (cstyle == SCREEN_CURSOR_DEFAULT) {
if (~cmode & MODE_CURSOR_BLINKING_SET) {
if (s->default_mode & MODE_CURSOR_BLINKING)
cmode |= MODE_CURSOR_BLINKING;
else
cmode &= ~MODE_CURSOR_BLINKING;
}
cstyle = s->default_cstyle;
}
}
/* If nothing changed, do nothing. */
changed = cmode ^ tty->mode;
if ((changed & CURSOR_MODES) == 0 && cstyle == tty->cstyle)
return;
return (cmode);
/*
* Set cursor style. If an explicit style has been set with DECSCUSR,
@@ -703,49 +731,56 @@ tty_update_cursor(struct tty *tty, int mode, int changed, struct screen *s)
else
tty_putcode1(tty, TTYC_SS, 0);
}
if (mode & (MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE))
if (cmode & (MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE))
tty_putcode(tty, TTYC_CVVIS);
break;
case SCREEN_CURSOR_BLOCK:
if (tty_term_has(tty->term, TTYC_SS)) {
if (mode & MODE_CURSOR_BLINKING)
if (cmode & MODE_CURSOR_BLINKING)
tty_putcode1(tty, TTYC_SS, 1);
else
tty_putcode1(tty, TTYC_SS, 2);
} else if (mode & MODE_CURSOR_BLINKING)
} else if (cmode & MODE_CURSOR_BLINKING)
tty_putcode(tty, TTYC_CVVIS);
break;
case SCREEN_CURSOR_UNDERLINE:
if (tty_term_has(tty->term, TTYC_SS)) {
if (mode & MODE_CURSOR_BLINKING)
if (cmode & MODE_CURSOR_BLINKING)
tty_putcode1(tty, TTYC_SS, 3);
else
tty_putcode1(tty, TTYC_SS, 4);
} else if (mode & MODE_CURSOR_BLINKING)
} else if (cmode & MODE_CURSOR_BLINKING)
tty_putcode(tty, TTYC_CVVIS);
break;
case SCREEN_CURSOR_BAR:
if (tty_term_has(tty->term, TTYC_SS)) {
if (mode & MODE_CURSOR_BLINKING)
if (cmode & MODE_CURSOR_BLINKING)
tty_putcode1(tty, TTYC_SS, 5);
else
tty_putcode1(tty, TTYC_SS, 6);
} else if (mode & MODE_CURSOR_BLINKING)
} else if (cmode & MODE_CURSOR_BLINKING)
tty_putcode(tty, TTYC_CVVIS);
break;
}
tty->cstyle = cstyle;
return (cmode);
}
void
tty_update_mode(struct tty *tty, int mode, struct screen *s)
{
struct tty_term *term = tty->term;
struct client *c = tty->client;
int changed;
if (tty->flags & TTY_NOCURSOR)
mode &= ~MODE_CURSOR;
if (tty_update_cursor(tty, mode, s) & MODE_CURSOR_BLINKING)
mode |= MODE_CURSOR_BLINKING;
else
mode &= ~MODE_CURSOR_BLINKING;
changed = mode ^ tty->mode;
if (log_get_level() != 0 && changed != 0) {
log_debug("%s: current mode %s", c->name,
@@ -754,9 +789,7 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
screen_mode_to_string(mode));
}
tty_update_cursor(tty, mode, changed, s);
if ((changed & ALL_MOUSE_MODES) &&
tty_term_has(tty->term, TTYC_KMOUS)) {
if ((changed & ALL_MOUSE_MODES) && tty_term_has(term, TTYC_KMOUS)) {
/*
* If the mouse modes have changed, clear any that are set and
* apply again. There are differences in how terminals track
@@ -909,7 +942,9 @@ tty_update_window_offset(struct window *w)
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != NULL && c->session->curw->window == w)
if (c->session != NULL &&
c->session->curw != NULL &&
c->session->curw->window == w)
tty_update_client_offset(c);
}
}
@@ -1051,8 +1086,9 @@ static void
tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py,
u_int px, u_int nx, u_int bg)
{
struct client *c = tty->client;
u_int i;
struct client *c = tty->client;
struct overlay_ranges r;
u_int i;
log_debug("%s: %s, %u at %u,%u", __func__, c->name, nx, px, py);
@@ -1088,18 +1124,13 @@ tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py,
* Couldn't use an escape sequence, use spaces. Clear only the visible
* bit if there is an overlay.
*/
for (i = 0; i < nx; i++) {
if (!tty_check_overlay(tty, px + i, py))
break;
tty_check_overlay_range(tty, px, py, nx, &r);
for (i = 0; i < OVERLAY_MAX_RANGES; i++) {
if (r.nx[i] == 0)
continue;
tty_cursor(tty, r.px[i], py);
tty_repeat_space(tty, r.nx[i]);
}
tty_cursor(tty, px, py);
tty_repeat_space(tty, i);
for (; i < nx; i++) {
if (tty_check_overlay(tty, px + i, py))
break;
}
tty_cursor(tty, px + i, py);
tty_repeat_space(tty, nx - i);
}
/* Clear a line, adjusting to visible part of pane. */
@@ -1311,14 +1342,44 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
return (&new);
}
/*
* Check if a single character is obstructed by the overlay and return a
* boolean.
*/
static int
tty_check_overlay(struct tty *tty, u_int px, u_int py)
{
struct overlay_ranges r;
/*
* A unit width range will always return nx[2] == 0 from a check, even
* with multiple overlays, so it's sufficient to check just the first
* two entries.
*/
tty_check_overlay_range(tty, px, py, 1, &r);
if (r.nx[0] + r.nx[1] == 0)
return (0);
return (1);
}
/* Return parts of the input range which are visible. */
static void
tty_check_overlay_range(struct tty *tty, u_int px, u_int py, u_int nx,
struct overlay_ranges *r)
{
struct client *c = tty->client;
if (c->overlay_check == NULL)
return (1);
return (c->overlay_check(c, c->overlay_data, px, py));
if (c->overlay_check == NULL) {
r->px[0] = px;
r->nx[0] = nx;
r->px[1] = 0;
r->nx[1] = 0;
r->px[2] = 0;
r->nx[2] = 0;
return;
}
c->overlay_check(c, c->overlay_data, px, py, nx, r);
}
void
@@ -1331,11 +1392,12 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
const struct grid_cell *gcp;
struct grid_line *gl;
struct client *c = tty->client;
u_int i, j, ux, sx, width, hidden;
struct overlay_ranges r;
u_int i, j, ux, sx, width, hidden, eux, nxx;
u_int cellsize;
int flags, cleared = 0, wrapped = 0;
char buf[512];
size_t len;
u_int cellsize;
log_debug("%s: px=%u py=%u nx=%u atx=%u aty=%u", __func__,
px, py, nx, atx, aty);
@@ -1435,29 +1497,31 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
else
memcpy(&last, gcp, sizeof last);
tty_check_overlay_range(tty, atx + ux, aty, gcp->data.width,
&r);
hidden = 0;
for (j = 0; j < gcp->data.width; j++) {
if (!tty_check_overlay(tty, atx + ux + j, aty))
hidden++;
}
for (j = 0; j < OVERLAY_MAX_RANGES; j++)
hidden += r.nx[j];
hidden = gcp->data.width - hidden;
if (hidden != 0 && hidden == gcp->data.width) {
if (~gcp->flags & GRID_FLAG_PADDING)
ux += gcp->data.width;
} else if (hidden != 0 || ux + gcp->data.width > nx) {
if (~gcp->flags & GRID_FLAG_PADDING) {
tty_attributes(tty, &last, defaults, palette);
tty_cursor(tty, atx + ux, aty);
for (j = 0; j < gcp->data.width; j++) {
if (ux > nx)
break;
if (tty_check_overlay(tty, atx + ux,
aty))
tty_putc(tty, ' ');
else {
tty_cursor(tty, atx + ux + 1,
aty);
for (j = 0; j < OVERLAY_MAX_RANGES; j++) {
if (r.nx[j] == 0)
continue;
/* Effective width drawn so far. */
eux = r.px[j] - atx;
if (eux < nx) {
tty_cursor(tty, r.px[j], aty);
nxx = nx - eux;
if (r.nx[j] > nxx)
r.nx[j] = nxx;
tty_repeat_space(tty, r.nx[j]);
ux = eux + r.nx[j];
}
ux++;
}
}
} else if (gcp->attr & GRID_ATTR_CHARSET) {
@@ -1963,7 +2027,8 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
{
const struct grid_cell *gcp = ctx->cell;
struct screen *s = ctx->s;
u_int i, px, py;
struct overlay_ranges r;
u_int px, py, i, vis = 0;
px = ctx->xoff + ctx->ocx - ctx->wox;
py = ctx->yoff + ctx->ocy - ctx->woy;
@@ -1973,13 +2038,13 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
/* Handle partially obstructed wide characters. */
if (gcp->data.width > 1) {
for (i = 0; i < gcp->data.width; i++) {
if (!tty_check_overlay(tty, px + i, py)) {
tty_draw_line(tty, s, s->cx, s->cy,
gcp->data.width, px, py, &ctx->defaults,
ctx->palette);
return;
}
tty_check_overlay_range(tty, px, py, gcp->data.width, &r);
for (i = 0; i < OVERLAY_MAX_RANGES; i++)
vis += r.nx[i];
if (vis < gcp->data.width) {
tty_draw_line(tty, s, s->cx, s->cy, gcp->data.width,
px, py, &ctx->defaults, ctx->palette);
return;
}
}
@@ -1997,7 +2062,9 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
{
u_int i, hide = 0;
struct overlay_ranges r;
u_int i, px, py, cx;
char *cp = ctx->ptr;
if (!tty_is_visible(tty, ctx, ctx->ocx, ctx->ocy, ctx->num, 1))
return;
@@ -2020,20 +2087,21 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
tty_margin_off(tty);
tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy);
tty_attributes(tty, ctx->cell, &ctx->defaults, ctx->palette);
for (i = 0; i < ctx->num; i++) {
if (!tty_check_overlay(tty, tty->cx + i, tty->cy))
break;
/* Get tty position from pane position for overlay check. */
px = ctx->xoff + ctx->ocx - ctx->wox;
py = ctx->yoff + ctx->ocy - ctx->woy;
tty_check_overlay_range(tty, px, py, ctx->num, &r);
for (i = 0; i < OVERLAY_MAX_RANGES; i++) {
if (r.nx[i] == 0)
continue;
/* Convert back to pane position for printing. */
cx = r.px[i] - ctx->xoff + ctx->wox;
tty_cursor_pane_unless_wrap(tty, ctx, cx, ctx->ocy);
tty_putn(tty, cp + r.px[i] - px, r.nx[i], r.nx[i]);
}
tty_putn(tty, ctx->ptr, i, i);
for (; i < ctx->num; i++) {
if (tty_check_overlay(tty, tty->cx + hide, tty->cy))
break;
hide++;
}
tty_cursor(tty, tty->cx + hide, tty->cy);
tty_putn(tty, (char *)ctx->ptr + i, ctx->num - i, ctx->num - i);
}
void
@@ -2321,17 +2389,25 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy)
if (tty->flags & TTY_BLOCK)
return;
if (cx > tty->sx - 1)
cx = tty->sx - 1;
thisx = tty->cx;
thisy = tty->cy;
/*
* If in the automargin space, and want to be there, do not move.
* Otherwise, force the cursor to be in range (and complain).
*/
if (cx == thisx && cy == thisy && cx == tty->sx)
return;
if (cx > tty->sx - 1) {
log_debug("%s: x too big %u > %u", __func__, cx, tty->sx - 1);
cx = tty->sx - 1;
}
/* No change. */
if (cx == thisx && cy == thisy)
return;
/* Very end of the line, just use absolute movement. */
/* Currently at the very end of the line - use absolute movement. */
if (thisx > tty->sx - 1)
goto absolute;