mirror of
https://github.com/tmux/tmux.git
synced 2025-11-09 20:15:06 +00:00
Merge branch 'master' into sixel
This commit is contained in:
260
tty.c
260
tty.c
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user