diff options
Diffstat (limited to 'tty.c')
-rw-r--r-- | tty.c | 325 |
1 files changed, 178 insertions, 147 deletions
@@ -71,8 +71,6 @@ static void tty_default_colours(struct grid_cell *, static void tty_default_attributes(struct tty *, const struct window_pane *, u_int); -#define tty_use_acs(tty) \ - (tty_term_has((tty)->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8)) #define tty_use_margin(tty) \ ((tty)->term_type == TTY_VT420) @@ -278,7 +276,8 @@ tty_open(struct tty *tty, char **cause) void tty_start_tty(struct tty *tty) { - struct termios tio; + struct client *c = tty->client; + struct termios tio; if (tty->fd != -1 && tcgetattr(tty->fd, &tty->tio) == 0) { setblocking(tty->fd, 0); @@ -299,10 +298,14 @@ tty_start_tty(struct tty *tty) tty_putcode(tty, TTYC_SMCUP); tty_putcode(tty, TTYC_SMKX); - if (tty_use_acs(tty)) - tty_putcode(tty, TTYC_ENACS); tty_putcode(tty, TTYC_CLEAR); + if (tty_acs_needed(tty)) { + log_debug("%s: using capabilities for ACS", c->name); + tty_putcode(tty, TTYC_ENACS); + } else + log_debug("%s: using UTF-8 for ACS", c->name); + tty_putcode(tty, TTYC_CNORM); if (tty_term_has(tty->term, TTYC_KMOUS)) tty_puts(tty, "\033[?1000l\033[?1002l\033[?1006l\033[?1005l"); @@ -351,7 +354,7 @@ tty_stop_tty(struct tty *tty) return; tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); - if (tty_use_acs(tty)) + if (tty_acs_needed(tty)) tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS)); tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0)); tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX)); @@ -754,6 +757,115 @@ tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx) } } +static void +tty_clear_line(struct tty *tty, const struct window_pane *wp, u_int py, + u_int px, u_int nx, u_int bg) +{ + log_debug("%s: %u at %u,%u", __func__, nx, px, py); + + /* Nothing to clear. */ + if (nx == 0) + return; + + /* If genuine BCE is available, can try escape sequences. */ + if (!tty_fake_bce(tty, wp, bg)) { + /* Off the end of the line, use EL if available. */ + if (px + nx >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { + tty_cursor(tty, px, py); + tty_putcode(tty, TTYC_EL); + return; + } + + /* At the start of the line. Use EL1. */ + if (px == 0 && tty_term_has(tty->term, TTYC_EL1)) { + tty_cursor(tty, px + nx - 1, py); + tty_putcode(tty, TTYC_EL1); + return; + } + + /* Section of line. Use ECH if possible. */ + if (tty_term_has(tty->term, TTYC_ECH)) { + tty_cursor(tty, px, py); + tty_putcode1(tty, TTYC_ECH, nx); + return; + } + } + + /* Couldn't use an escape sequence, use spaces. */ + tty_cursor(tty, px, py); + tty_repeat_space(tty, nx); +} + +static void +tty_clear_area(struct tty *tty, const struct window_pane *wp, u_int py, + u_int ny, u_int px, u_int nx, u_int bg) +{ + u_int yy; + char tmp[64]; + + log_debug("%s: %u,%u at %u,%u", __func__, nx, ny, px, py); + + /* Nothing to clear. */ + if (nx == 0 || ny == 0) + return; + + /* If genuine BCE is available, can try escape sequences. */ + if (!tty_fake_bce(tty, wp, bg)) { + /* Use ED if clearing off the bottom of the terminal. */ + if (px == 0 && + px + nx >= tty->sx && + py + ny >= tty->sy && + tty_term_has(tty->term, TTYC_ED)) { + tty_cursor(tty, 0, py); + tty_putcode(tty, TTYC_ED); + return; + } + + /* + * On VT420 compatible terminals we can use DECFRA if the + * background colour isn't default (because it doesn't work + * after SGR 0). + */ + if (tty->term_type == TTY_VT420 && bg != 8) { + xsnprintf(tmp, sizeof tmp, "\033[32;%u;%u;%u;%u$x", + py + 1, px + 1, py + ny, px + nx); + tty_puts(tty, tmp); + return; + } + + /* Full lines can be scrolled away to clear them. */ + if (px == 0 && + px + nx >= tty->sx && + ny > 2 && + tty_term_has(tty->term, TTYC_CSR) && + tty_term_has(tty->term, TTYC_INDN)) { + tty_region(tty, py, py + ny - 1); + tty_margin_off(tty); + tty_putcode1(tty, TTYC_INDN, ny); + return; + } + + /* + * If margins are supported, can just scroll the area off to + * clear it. + */ + if (nx > 2 && + ny > 2 && + tty_term_has(tty->term, TTYC_CSR) && + tty_use_margin(tty) && + tty_term_has(tty->term, TTYC_INDN)) { + tty_region(tty, py, py + ny - 1); + tty_margin(tty, px, px + nx - 1); + tty_putcode1(tty, TTYC_INDN, ny); + return; + } + } + + /* Couldn't use an escape sequence, loop over the lines. */ + for (yy = py; yy < py + ny; yy++) + tty_clear_line(tty, wp, yy, px, nx, bg); +} + void tty_draw_pane(struct tty *tty, const struct window_pane *wp, u_int py, u_int ox, u_int oy) @@ -766,7 +878,7 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp, struct screen *s, u_int py, u_int ox, u_int oy) { struct grid_cell gc, last; - u_int i, j, sx, width; + u_int i, j, sx, nx, width; int flags, cleared = 0; char buf[512]; size_t len; @@ -861,16 +973,10 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp, tty_putn(tty, buf, len, width); } - if (!cleared && sx < tty->sx) { + nx = screen_size_x(s) - sx; + if (!cleared && sx < tty->sx && nx != 0) { tty_default_attributes(tty, wp, 8); - tty_cursor(tty, ox + sx, oy + py); - if (sx != screen_size_x(s) && - ox + screen_size_x(s) >= tty->sx && - tty_term_has(tty->term, TTYC_EL) && - !tty_fake_bce(tty, wp, 8)) - tty_putcode(tty, TTYC_EL); - else - tty_repeat_space(tty, screen_size_x(s) - sx); + tty_clear_line(tty, wp, oy + py, ox + sx, nx, 8); } tty->flags = (tty->flags & ~TTY_NOCURSOR) | flags; @@ -1018,73 +1124,54 @@ void tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - u_int sx = screen_size_x(s); + u_int nx, py = ctx->yoff + ctx->ocy; tty_default_attributes(tty, wp, ctx->bg); - tty_cursor_pane(tty, ctx, 0, ctx->ocy); - - if (tty_pane_full_width(tty, ctx) && - !tty_fake_bce(tty, wp, ctx->bg) && - tty_term_has(tty->term, TTYC_EL)) - tty_putcode(tty, TTYC_EL); - else - tty_repeat_space(tty, sx); + nx = screen_size_x(wp->screen); + tty_clear_line(tty, wp, py, ctx->xoff, nx, ctx->bg); } void tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - u_int sx = screen_size_x(s); + u_int nx, py = ctx->yoff + ctx->ocy; tty_default_attributes(tty, wp, ctx->bg); - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - - if (tty_pane_full_width(tty, ctx) && - tty_term_has(tty->term, TTYC_EL) && - !tty_fake_bce(tty, wp, ctx->bg)) - tty_putcode(tty, TTYC_EL); - else - tty_repeat_space(tty, sx - ctx->ocx); + nx = screen_size_x(wp->screen) - ctx->ocx; + tty_clear_line(tty, wp, py, ctx->xoff + ctx->ocx, nx, ctx->bg); } void tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; + u_int py = ctx->yoff + ctx->ocy; tty_default_attributes(tty, wp, ctx->bg); - if (ctx->xoff == 0 && - tty_term_has(tty->term, TTYC_EL1) && - !tty_fake_bce(tty, ctx->wp, ctx->bg)) { - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - tty_putcode(tty, TTYC_EL1); - } else { - tty_cursor_pane(tty, ctx, 0, ctx->ocy); - tty_repeat_space(tty, ctx->ocx + 1); - } + tty_clear_line(tty, wp, py, ctx->xoff, ctx->ocx + 1, ctx->bg); } void tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) { + struct window_pane *wp = ctx->wp; + if (ctx->ocy != ctx->orupper) return; if (!tty_pane_full_width(tty, ctx) || - tty_fake_bce(tty, ctx->wp, 8) || + tty_fake_bce(tty, wp, 8) || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_RI)) { tty_redraw_region(tty, ctx); return; } - tty_attributes(tty, &grid_default_cell, ctx->wp); + tty_default_attributes(tty, wp, ctx->bg); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_margin_off(tty); @@ -1108,7 +1195,7 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_attributes(tty, &grid_default_cell, wp); + tty_default_attributes(tty, wp, ctx->bg); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_margin_pane(tty, ctx); @@ -1130,7 +1217,7 @@ void tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - u_int i, lines; + u_int i; if ((!tty_pane_full_width(tty, ctx) && !tty_use_margin(tty)) || tty_fake_bce(tty, wp, 8) || @@ -1139,142 +1226,86 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_attributes(tty, &grid_default_cell, wp); + tty_default_attributes(tty, wp, ctx->bg); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_margin_pane(tty, ctx); - /* - * Konsole has a bug where it will ignore SU if the parameter is more - * than the height of the scroll region. Clamping the parameter doesn't - * hurt in any case. - */ - lines = tty->rlower - tty->rupper; - if (lines > ctx->num) - lines = ctx->num; - - if (lines == 1 || !tty_term_has(tty->term, TTYC_INDN)) { + if (ctx->num == 1 || !tty_term_has(tty->term, TTYC_INDN)) { tty_cursor(tty, tty->rright, tty->rlower); - for (i = 0; i < lines; i++) + for (i = 0; i < ctx->num; i++) tty_putc(tty, '\n'); } else - tty_putcode1(tty, TTYC_INDN, lines); + tty_putcode1(tty, TTYC_INDN, ctx->num); } void tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - u_int i, j; - u_int sx = screen_size_x(s), sy = screen_size_y(s); + u_int px, py, nx, ny; tty_default_attributes(tty, wp, ctx->bg); - tty_region_pane(tty, ctx, 0, sy - 1); + tty_region_pane(tty, ctx, 0, screen_size_y(wp->screen) - 1); tty_margin_off(tty); - if (tty_pane_full_width(tty, ctx) && - ctx->yoff + wp->sy >= tty->sy - 1 && - status_at_line(tty->client) <= 0 && - tty_term_has(tty->term, TTYC_ED)) { - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - tty_putcode(tty, TTYC_ED); - } else if (tty_pane_full_width(tty, ctx) && - tty_term_has(tty->term, TTYC_EL) && - !tty_fake_bce(tty, wp, ctx->bg)) { - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - tty_putcode(tty, TTYC_EL); - if (ctx->ocy != sy - 1) { - tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); - for (i = ctx->ocy + 1; i < sy; i++) { - tty_putcode(tty, TTYC_EL); - if (i == sy - 1) - continue; - tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); - tty->cy++; - } - } - } else { - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - tty_repeat_space(tty, sx - ctx->ocx); - for (j = ctx->ocy + 1; j < sy; j++) { - tty_cursor_pane(tty, ctx, 0, j); - tty_repeat_space(tty, sx); - } - } + px = ctx->xoff; + nx = screen_size_x(wp->screen); + py = ctx->yoff + ctx->ocy + 1; + ny = screen_size_y(wp->screen) - ctx->ocy - 1; + + tty_clear_area(tty, wp, py, ny, px, nx, ctx->bg); + + px = ctx->xoff + ctx->ocx; + nx = screen_size_x(wp->screen) - ctx->ocx; + py = ctx->yoff + ctx->ocy; + + tty_clear_line(tty, wp, py, px, nx, ctx->bg); } void tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - u_int i, j; - u_int sx = screen_size_x(s), sy = screen_size_y(s); + u_int px, py, nx, ny; tty_default_attributes(tty, wp, ctx->bg); - tty_region_pane(tty, ctx, 0, sy - 1); + tty_region_pane(tty, ctx, 0, screen_size_y(wp->screen) - 1); tty_margin_off(tty); - if (tty_pane_full_width(tty, ctx) && - tty_term_has(tty->term, TTYC_EL) && - !tty_fake_bce(tty, wp, ctx->bg)) { - tty_cursor_pane(tty, ctx, 0, 0); - for (i = 0; i < ctx->ocy; i++) { - tty_putcode(tty, TTYC_EL); - tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); - tty->cy++; - } - } else { - tty_cursor_pane(tty, ctx, 0, 0); - for (j = 0; j < ctx->ocy; j++) { - tty_cursor_pane(tty, ctx, 0, j); - tty_repeat_space(tty, sx); - } - } - tty_cursor_pane(tty, ctx, 0, ctx->ocy); - tty_repeat_space(tty, ctx->ocx + 1); + px = ctx->xoff; + nx = screen_size_x(wp->screen); + py = ctx->yoff; + ny = ctx->ocy - 1; + + tty_clear_area(tty, wp, py, ny, px, nx, ctx->bg); + + px = ctx->xoff; + nx = ctx->ocx + 1; + py = ctx->yoff + ctx->ocy; + + tty_clear_line(tty, wp, py, px, nx, ctx->bg); } void tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - u_int i, j; - u_int sx = screen_size_x(s), sy = screen_size_y(s); + u_int px, py, nx, ny; tty_default_attributes(tty, wp, ctx->bg); - tty_region_pane(tty, ctx, 0, sy - 1); + tty_region_pane(tty, ctx, 0, screen_size_y(wp->screen) - 1); tty_margin_off(tty); - if (tty_pane_full_width(tty, ctx) && - ctx->yoff + wp->sy >= tty->sy - 1 && - status_at_line(tty->client) <= 0 && - tty_term_has(tty->term, TTYC_ED)) { - tty_cursor_pane(tty, ctx, 0, 0); - tty_putcode(tty, TTYC_ED); - } else if (tty_pane_full_width(tty, ctx) && - tty_term_has(tty->term, TTYC_EL) && - !tty_fake_bce(tty, wp, ctx->bg)) { - tty_cursor_pane(tty, ctx, 0, 0); - for (i = 0; i < sy; i++) { - tty_putcode(tty, TTYC_EL); - if (i != sy - 1) { - tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); - tty->cy++; - } - } - } else { - tty_cursor_pane(tty, ctx, 0, 0); - for (j = 0; j < sy; j++) { - tty_cursor_pane(tty, ctx, 0, j); - tty_repeat_space(tty, sx); - } - } + px = ctx->xoff; + nx = screen_size_x(wp->screen); + py = ctx->yoff; + ny = screen_size_y(wp->screen); + + tty_clear_area(tty, wp, py, ny, px, nx, ctx->bg); } void @@ -1389,7 +1420,7 @@ tty_reset(struct tty *tty) struct grid_cell *gc = &tty->cell; if (!grid_cells_equal(gc, &grid_default_cell)) { - if ((gc->attr & GRID_ATTR_CHARSET) && tty_use_acs(tty)) + if ((gc->attr & GRID_ATTR_CHARSET) && tty_acs_needed(tty)) tty_putcode(tty, TTYC_RMACS); tty_putcode(tty, TTYC_SGR0); memcpy(gc, &grid_default_cell, sizeof *gc); @@ -1739,7 +1770,7 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc, tty_putcode(tty, TTYC_INVIS); if (changed & GRID_ATTR_STRIKETHROUGH) tty_putcode(tty, TTYC_SMXX); - if ((changed & GRID_ATTR_CHARSET) && tty_use_acs(tty)) + if ((changed & GRID_ATTR_CHARSET) && tty_acs_needed(tty)) tty_putcode(tty, TTYC_SMACS); } |