diff options
Diffstat (limited to 'tty.c')
-rw-r--r-- | tty.c | 454 |
1 files changed, 311 insertions, 143 deletions
@@ -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 *, @@ -69,8 +69,10 @@ static void tty_emulate_repeat(struct tty *, enum tty_code_code, static void tty_repeat_space(struct tty *, u_int); 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); + struct colour_palette *, u_int, struct hyperlinks *); 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) @@ -81,6 +83,8 @@ static int tty_check_overlay(struct tty *, u_int, u_int); #define TTY_BLOCK_START(tty) (1 + ((tty)->sx * (tty)->sy) * 8) #define TTY_BLOCK_STOP(tty) (1 + ((tty)->sx * (tty)->sy) / 8) +#define TTY_QUERY_TIMEOUT 5 + void tty_create_log(void) { @@ -103,7 +107,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); @@ -204,6 +208,11 @@ tty_block_maybe(struct tty *tty) size_t size = EVBUFFER_LENGTH(tty->out); struct timeval tv = { .tv_usec = TTY_BLOCK_INTERVAL }; + if (size == 0) + tty->flags &= ~TTY_NOBLOCK; + else if (tty->flags & TTY_NOBLOCK) + return (0); + if (size < TTY_BLOCK_START(tty)) return (0); @@ -300,7 +309,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 = TTY_QUERY_TIMEOUT }; setblocking(c->fd, 0); event_add(&tty->event_in, NULL); @@ -339,8 +348,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; @@ -404,7 +413,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)); @@ -449,7 +458,6 @@ void tty_free(struct tty *tty) { tty_close(tty); - free(tty->ccolour); } void @@ -647,40 +655,79 @@ tty_set_title(struct tty *tty, const char *title) tty_putcode(tty, TTYC_FSL); } +void +tty_set_path(struct tty *tty, const char *title) +{ + if (!tty_term_has(tty->term, TTYC_SWD) || + !tty_term_has(tty->term, TTYC_FSL)) + return; + + tty_putcode(tty, TTYC_SWD); + tty_puts(tty, title); + tty_putcode(tty, TTYC_FSL); +} + 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, @@ -698,49 +745,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, @@ -749,30 +803,21 @@ 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 - * the various bits. + * If the mouse modes have changed, clear then all and apply + * again. There are differences in how terminals track the + * various bits. */ - if (tty->mode & MODE_MOUSE_SGR) - tty_puts(tty, "\033[?1006l"); - if (tty->mode & MODE_MOUSE_STANDARD) - tty_puts(tty, "\033[?1000l"); - if (tty->mode & MODE_MOUSE_BUTTON) - tty_puts(tty, "\033[?1002l"); - if (tty->mode & MODE_MOUSE_ALL) - tty_puts(tty, "\033[?1003l"); + tty_puts(tty, "\033[?1006l\033[?1000l\033[?1002l\033[?1003l"); if (mode & ALL_MOUSE_MODES) tty_puts(tty, "\033[?1006h"); - if (mode & MODE_MOUSE_STANDARD) - tty_puts(tty, "\033[?1000h"); - if (mode & MODE_MOUSE_BUTTON) - tty_puts(tty, "\033[?1002h"); if (mode & MODE_MOUSE_ALL) - tty_puts(tty, "\033[?1003h"); + tty_puts(tty, "\033[?1000h\033[?1002h\033[?1003h"); + else if (mode & MODE_MOUSE_BUTTON) + tty_puts(tty, "\033[?1000h\033[?1002h"); + else if (mode & MODE_MOUSE_STANDARD) + tty_puts(tty, "\033[?1000h"); } if (changed & MODE_BRACKETPASTE) { if (mode & MODE_BRACKETPASTE) @@ -904,7 +949,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); } } @@ -1046,8 +1093,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); @@ -1083,18 +1131,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_cursor(tty, px, py); - tty_repeat_space(tty, i); - for (; 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 + i, py); - tty_repeat_space(tty, nx - i); } /* Clear a line, adjusting to visible part of pane. */ @@ -1306,14 +1349,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 @@ -1326,11 +1399,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); @@ -1381,7 +1455,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, tty_term_has(tty->term, TTYC_EL1) && !tty_fake_bce(tty, defaults, 8) && c->overlay_check == NULL) { - tty_default_attributes(tty, defaults, palette, 8); + tty_default_attributes(tty, defaults, palette, 8, + s->hyperlinks); tty_cursor(tty, nx - 1, aty); tty_putcode(tty, TTYC_EL1); cleared = 1; @@ -1406,9 +1481,11 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, gcp->fg != last.fg || gcp->bg != last.bg || gcp->us != last.us || + gcp->link != last.link || ux + width + gcp->data.width > nx || (sizeof buf) - len < gcp->data.size)) { - tty_attributes(tty, &last, defaults, palette); + tty_attributes(tty, &last, defaults, palette, + s->hyperlinks); if (last.flags & GRID_FLAG_CLEARED) { log_debug("%s: %zu cleared", __func__, len); tty_clear_line(tty, defaults, aty, atx + ux, @@ -1430,33 +1507,37 @@ 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); + tty_attributes(tty, &last, defaults, palette, + s->hyperlinks); + 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) { - tty_attributes(tty, &last, defaults, palette); + tty_attributes(tty, &last, defaults, palette, + s->hyperlinks); tty_cursor(tty, atx + ux, aty); for (j = 0; j < gcp->data.size; j++) tty_putc(tty, gcp->data.data[j]); @@ -1468,7 +1549,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, } } if (len != 0 && ((~last.flags & GRID_FLAG_CLEARED) || last.bg != 8)) { - tty_attributes(tty, &last, defaults, palette); + tty_attributes(tty, &last, defaults, palette, s->hyperlinks); if (last.flags & GRID_FLAG_CLEARED) { log_debug("%s: %zu cleared (end)", __func__, len); tty_clear_line(tty, defaults, aty, atx + ux, width, @@ -1484,7 +1565,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, if (!cleared && ux < nx) { log_debug("%s: %u to end of line (%zu cleared)", __func__, nx - ux, len); - tty_default_attributes(tty, defaults, palette, 8); + tty_default_attributes(tty, defaults, palette, 8, + s->hyperlinks); tty_clear_line(tty, defaults, aty, atx + ux, nx - ux, 8); } @@ -1570,7 +1652,8 @@ tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); @@ -1592,7 +1675,8 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); @@ -1602,7 +1686,8 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx) { - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_clear_pane_line(tty, ctx, ctx->ocy, ctx->ocx, ctx->num, ctx->bg); } @@ -1624,7 +1709,8 @@ tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_margin_off(tty); @@ -1651,7 +1737,8 @@ tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_margin_off(tty); @@ -1664,7 +1751,8 @@ tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx) { - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_clear_pane_line(tty, ctx, ctx->ocy, 0, ctx->sx, ctx->bg); } @@ -1674,7 +1762,8 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) { u_int nx = ctx->sx - ctx->ocx; - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_clear_pane_line(tty, ctx, ctx->ocy, ctx->ocx, nx, ctx->bg); } @@ -1682,7 +1771,8 @@ tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) { - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_clear_pane_line(tty, ctx, ctx->ocy, 0, ctx->ocx + 1, ctx->bg); } @@ -1708,7 +1798,8 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_margin_pane(tty, ctx); @@ -1739,7 +1830,8 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_margin_pane(tty, ctx); @@ -1779,7 +1871,8 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_margin_pane(tty, ctx); @@ -1819,7 +1912,8 @@ tty_cmd_scrolldown(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_margin_pane(tty, ctx); @@ -1838,7 +1932,8 @@ tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) { u_int px, py, nx, ny; - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_region_pane(tty, ctx, 0, ctx->sy - 1); tty_margin_off(tty); @@ -1862,7 +1957,8 @@ tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) { u_int px, py, nx, ny; - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_region_pane(tty, ctx, 0, ctx->sy - 1); tty_margin_off(tty); @@ -1886,7 +1982,8 @@ tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) { u_int px, py, nx, ny; - tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg); + tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg, + ctx->s->hyperlinks); tty_region_pane(tty, ctx, 0, ctx->sy - 1); tty_margin_off(tty); @@ -1909,7 +2006,8 @@ tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_attributes(tty, &grid_default_cell, &ctx->defaults, ctx->palette); + tty_attributes(tty, &grid_default_cell, &ctx->defaults, ctx->palette, + ctx->s->hyperlinks); tty_region_pane(tty, ctx, 0, ctx->sy - 1); tty_margin_off(tty); @@ -1926,7 +2024,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; @@ -1936,13 +2035,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; } } @@ -1954,13 +2053,16 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) tty_margin_off(tty); tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy); - tty_cell(tty, ctx->cell, &ctx->defaults, ctx->palette); + tty_cell(tty, ctx->cell, &ctx->defaults, ctx->palette, + ctx->s->hyperlinks); } 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; @@ -1983,30 +2085,32 @@ 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, ctx->s->hyperlinks); - 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; - } - tty_putn(tty, ctx->ptr, i, i); - for (; i < ctx->num; i++) { - if (tty_check_overlay(tty, tty->cx + hide, tty->cy)) - break; - hide++; + /* 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_cursor(tty, tty->cx + hide, tty->cy); - tty_putn(tty, (char *)ctx->ptr + i, ctx->num - i, ctx->num - i); } void tty_cmd_setselection(struct tty *tty, const struct tty_ctx *ctx) { - tty_set_selection(tty, ctx->ptr, ctx->num); + tty_set_selection(tty, ctx->ptr2, ctx->ptr, ctx->num); } void -tty_set_selection(struct tty *tty, const char *buf, size_t len) +tty_set_selection(struct tty *tty, const char *flags, const char *buf, + size_t len) { char *encoded; size_t size; @@ -2020,8 +2124,8 @@ tty_set_selection(struct tty *tty, const char *buf, size_t len) encoded = xmalloc(size); b64_ntop(buf, len, encoded, size); - tty_putcode_ptr2(tty, TTYC_MS, "", encoded); - tty->client->redraw = EVBUFFER_LENGTH(tty->out); + tty->flags |= TTY_NOBLOCK; + tty_putcode_ptr2(tty, TTYC_MS, flags, encoded); free(encoded); } @@ -2029,6 +2133,7 @@ tty_set_selection(struct tty *tty, const char *buf, size_t len) void tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx) { + tty->flags |= TTY_NOBLOCK; tty_add(tty, ctx->ptr, ctx->num); tty_invalidate(tty); } @@ -2054,7 +2159,8 @@ tty_cmd_syncstart(struct tty *tty, const struct tty_ctx *ctx) void tty_cell(struct tty *tty, const struct grid_cell *gc, - const struct grid_cell *defaults, struct colour_palette *palette) + const struct grid_cell *defaults, struct colour_palette *palette, + struct hyperlinks *hl) { const struct grid_cell *gcp; @@ -2070,11 +2176,11 @@ tty_cell(struct tty *tty, const struct grid_cell *gc, /* Check the output codeset and apply attributes. */ gcp = tty_check_codeset(tty, gc); - tty_attributes(tty, gcp, defaults, palette); + tty_attributes(tty, gcp, defaults, palette, hl); /* If it is a single character, write with putc to handle ACS. */ if (gcp->data.size == 1) { - tty_attributes(tty, gcp, defaults, palette); + tty_attributes(tty, gcp, defaults, palette, hl); if (*gcp->data.data < 0x20 || *gcp->data.data == 0x7f) return; tty_putc(tty, *gcp->data.data); @@ -2091,6 +2197,8 @@ tty_reset(struct tty *tty) struct grid_cell *gc = &tty->cell; if (!grid_cells_equal(gc, &grid_default_cell)) { + if (gc->link != 0) + tty_putcode_ptr2(tty, TTYC_HLS, "", ""); if ((gc->attr & GRID_ATTR_CHARSET) && tty_acs_needed(tty)) tty_putcode(tty, TTYC_RMACS); tty_putcode(tty, TTYC_SGR0); @@ -2243,17 +2351,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; @@ -2372,9 +2488,29 @@ out: tty->cy = cy; } +static void +tty_hyperlink(struct tty *tty, const struct grid_cell *gc, + struct hyperlinks *hl) +{ + const char *uri, *id; + + if (gc->link == tty->cell.link) + return; + tty->cell.link = gc->link; + + if (hl == NULL) + return; + + if (gc->link == 0 || !hyperlinks_get(hl, gc->link, &uri, NULL, &id)) + tty_putcode_ptr2(tty, TTYC_HLS, "", ""); + else + tty_putcode_ptr2(tty, TTYC_HLS, id, uri); +} + void tty_attributes(struct tty *tty, const struct grid_cell *gc, - const struct grid_cell *defaults, struct colour_palette *palette) + const struct grid_cell *defaults, struct colour_palette *palette, + struct hyperlinks *hl) { struct grid_cell *tc = &tty->cell, gc2; int changed; @@ -2392,7 +2528,8 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc, if (gc2.attr == tty->last_cell.attr && gc2.fg == tty->last_cell.fg && gc2.bg == tty->last_cell.bg && - gc2.us == tty->last_cell.us) + gc2.us == tty->last_cell.us && + gc2.link == tty->last_cell.link) return; /* @@ -2469,6 +2606,9 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc, if ((changed & GRID_ATTR_CHARSET) && tty_acs_needed(tty)) tty_putcode(tty, TTYC_SMACS); + /* Set hyperlink if any. */ + tty_hyperlink(tty, gc, hl); + memcpy(&tty->last_cell, &gc2, sizeof tty->last_cell); } @@ -2834,11 +2974,39 @@ tty_default_colours(struct grid_cell *gc, struct window_pane *wp) static void tty_default_attributes(struct tty *tty, const struct grid_cell *defaults, - struct colour_palette *palette, u_int bg) + struct colour_palette *palette, u_int bg, struct hyperlinks *hl) { struct grid_cell gc; memcpy(&gc, &grid_default_cell, sizeof gc); gc.bg = bg; - tty_attributes(tty, &gc, defaults, palette); + tty_attributes(tty, &gc, defaults, palette, hl); +} + +static void +tty_clipboard_query_callback(__unused int fd, __unused short events, void *data) +{ + struct tty *tty = data; + struct client *c = tty->client; + + c->flags &= ~CLIENT_CLIPBOARDBUFFER; + free(c->clipboard_panes); + c->clipboard_panes = NULL; + c->clipboard_npanes = 0; + + tty->flags &= ~TTY_OSC52QUERY; +} + +void +tty_clipboard_query(struct tty *tty) +{ + struct timeval tv = { .tv_sec = TTY_QUERY_TIMEOUT }; + + if ((~tty->flags & TTY_STARTED) || (tty->flags & TTY_OSC52QUERY)) + return; + tty_putcode_ptr2(tty, TTYC_MS, "", "?"); + + tty->flags |= TTY_OSC52QUERY; + evtimer_set(&tty->clipboard_timer, tty_clipboard_query_callback, tty); + evtimer_add(&tty->clipboard_timer, &tv); } |