diff options
Diffstat (limited to 'tty.c')
-rw-r--r-- | tty.c | 482 |
1 files changed, 354 insertions, 128 deletions
@@ -34,8 +34,6 @@ static int tty_log_fd = -1; -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 *, int); @@ -69,11 +67,16 @@ 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 *); +#ifdef ENABLE_SIXEL +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) \ @@ -84,6 +87,7 @@ static void tty_check_overlay_range(struct tty *, u_int, u_int, u_int, #define TTY_BLOCK_STOP(tty) (1 + ((tty)->sx * (tty)->sy) / 8) #define TTY_QUERY_TIMEOUT 5 +#define TTY_REQUEST_LIMIT 30 void tty_create_log(void) @@ -108,6 +112,7 @@ tty_init(struct tty *tty, struct client *c) tty->cstyle = SCREEN_CURSOR_DEFAULT; tty->ccolour = -1; + tty->fg = tty->bg = -1; if (tcgetattr(c->fd, &tty->tio) != 0) return (-1); @@ -286,7 +291,6 @@ tty_open(struct tty *tty, char **cause) evtimer_set(&tty->timer, tty_timer_callback, tty); tty_start_tty(tty); - tty_keys_build(tty); return (0); @@ -299,9 +303,9 @@ tty_start_timer_callback(__unused int fd, __unused short events, void *data) struct client *c = tty->client; log_debug("%s: start timer fired", c->name); - if ((tty->flags & (TTY_HAVEDA|TTY_HAVEXDA)) == 0) + if ((tty->flags & (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA)) == 0) tty_update_features(tty); - tty->flags |= (TTY_HAVEDA|TTY_HAVEXDA); + tty->flags |= TTY_ALL_REQUEST_FLAGS; } void @@ -341,6 +345,8 @@ tty_start_tty(struct tty *tty) tty_puts(tty, "\033[?1000l\033[?1002l\033[?1003l"); tty_puts(tty, "\033[?1006l\033[?1005l"); } + if (tty_term_has(tty->term, TTYC_ENBP)) + tty_putcode(tty, TTYC_ENBP); evtimer_set(&tty->start_timer, tty_start_timer_callback, tty); evtimer_add(&tty->start_timer, &tv); @@ -363,12 +369,35 @@ tty_send_requests(struct tty *tty) return; if (tty->term->flags & TERM_VT100LIKE) { - if (~tty->flags & TTY_HAVEDA) + if (~tty->term->flags & TTY_HAVEDA) + tty_puts(tty, "\033[c"); + if (~tty->flags & TTY_HAVEDA2) tty_puts(tty, "\033[>c"); if (~tty->flags & TTY_HAVEXDA) tty_puts(tty, "\033[>q"); + tty_puts(tty, "\033]10;?\033\\"); + tty_puts(tty, "\033]11;?\033\\"); } else - tty->flags |= (TTY_HAVEDA|TTY_HAVEXDA); + tty->flags |= TTY_ALL_REQUEST_FLAGS; + tty->last_requests = time (NULL); +} + +void +tty_repeat_requests(struct tty *tty) +{ + time_t t = time (NULL); + + if (~tty->flags & TTY_STARTED) + return; + + if (t - tty->last_requests <= TTY_REQUEST_LIMIT) + return; + tty->last_requests = t; + + if (tty->term->flags & TERM_VT100LIKE) { + tty_puts(tty, "\033]10;?\033\\"); + tty_puts(tty, "\033]11;?\033\\"); + } } void @@ -399,7 +428,7 @@ tty_stop_tty(struct tty *tty) if (tcsetattr(c->fd, TCSANOW, &tty->tio) == -1) return; - tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); + tty_raw(tty, tty_term_string_ii(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); 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)); @@ -409,10 +438,8 @@ tty_stop_tty(struct tty *tty) if (tty_term_has(tty->term, TTYC_SE)) tty_raw(tty, tty_term_string(tty->term, TTYC_SE)); else if (tty_term_has(tty->term, TTYC_SS)) - tty_raw(tty, tty_term_string1(tty->term, TTYC_SS, 0)); + tty_raw(tty, tty_term_string_i(tty->term, TTYC_SS, 0)); } - if (tty->mode & MODE_BRACKETPASTE) - tty_raw(tty, tty_term_string(tty->term, TTYC_DSBP)); if (tty->ccolour != -1) tty_raw(tty, tty_term_string(tty->term, TTYC_CR)); @@ -421,6 +448,8 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, "\033[?1000l\033[?1002l\033[?1003l"); tty_raw(tty, "\033[?1006l\033[?1005l"); } + if (tty_term_has(tty->term, TTYC_DSBP)) + tty_raw(tty, tty_term_string(tty->term, TTYC_DSBP)); if (tty->term->flags & TERM_VT100LIKE) tty_raw(tty, "\033[?7727l"); @@ -476,6 +505,14 @@ tty_update_features(struct tty *tty) tty_puts(tty, tty_term_string(tty->term, TTYC_ENFCS)); if (tty->term->flags & TERM_VT100LIKE) tty_puts(tty, "\033[?7727h"); + + /* + * Features might have changed since the first draw during attach. For + * example, this happens when DA responses are received. + */ + server_redraw_client(c); + + tty_invalidate(tty); } void @@ -506,42 +543,42 @@ tty_putcode(struct tty *tty, enum tty_code_code code) } void -tty_putcode1(struct tty *tty, enum tty_code_code code, int a) +tty_putcode_i(struct tty *tty, enum tty_code_code code, int a) { if (a < 0) return; - tty_puts(tty, tty_term_string1(tty->term, code, a)); + tty_puts(tty, tty_term_string_i(tty->term, code, a)); } void -tty_putcode2(struct tty *tty, enum tty_code_code code, int a, int b) +tty_putcode_ii(struct tty *tty, enum tty_code_code code, int a, int b) { if (a < 0 || b < 0) return; - tty_puts(tty, tty_term_string2(tty->term, code, a, b)); + tty_puts(tty, tty_term_string_ii(tty->term, code, a, b)); } void -tty_putcode3(struct tty *tty, enum tty_code_code code, int a, int b, int c) +tty_putcode_iii(struct tty *tty, enum tty_code_code code, int a, int b, int c) { if (a < 0 || b < 0 || c < 0) return; - tty_puts(tty, tty_term_string3(tty->term, code, a, b, c)); + tty_puts(tty, tty_term_string_iii(tty->term, code, a, b, c)); } void -tty_putcode_ptr1(struct tty *tty, enum tty_code_code code, const void *a) +tty_putcode_s(struct tty *tty, enum tty_code_code code, const char *a) { if (a != NULL) - tty_puts(tty, tty_term_ptr1(tty->term, code, a)); + tty_puts(tty, tty_term_string_s(tty->term, code, a)); } void -tty_putcode_ptr2(struct tty *tty, enum tty_code_code code, const void *a, - const void *b) +tty_putcode_ss(struct tty *tty, enum tty_code_code code, const char *a, + const char *b) { if (a != NULL && b != NULL) - tty_puts(tty, tty_term_ptr2(tty->term, code, a, b)); + tty_puts(tty, tty_term_string_ss(tty->term, code, a, b)); } static void @@ -603,7 +640,7 @@ tty_putc(struct tty *tty, u_char ch) * it works on sensible terminals as well. */ if (tty->term->flags & TERM_NOAM) - tty_putcode2(tty, TTYC_CUP, tty->cy, tty->cx); + tty_putcode_ii(tty, TTYC_CUP, tty->cy, tty->cx); } else tty->cx++; } @@ -671,7 +708,7 @@ static void tty_force_cursor_colour(struct tty *tty, int c) { u_char r, g, b; - char s[13] = ""; + char s[13]; if (c != -1) c = colour_force_rgb(c); @@ -682,7 +719,7 @@ tty_force_cursor_colour(struct tty *tty, int c) 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_putcode_s(tty, TTYC_CS, s); } tty->ccolour = c; } @@ -743,7 +780,7 @@ tty_update_cursor(struct tty *tty, int mode, struct screen *s) if (tty_term_has(tty->term, TTYC_SE)) tty_putcode(tty, TTYC_SE); else - tty_putcode1(tty, TTYC_SS, 0); + tty_putcode_i(tty, TTYC_SS, 0); } if (cmode & (MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE)) tty_putcode(tty, TTYC_CVVIS); @@ -751,27 +788,27 @@ tty_update_cursor(struct tty *tty, int mode, struct screen *s) case SCREEN_CURSOR_BLOCK: if (tty_term_has(tty->term, TTYC_SS)) { if (cmode & MODE_CURSOR_BLINKING) - tty_putcode1(tty, TTYC_SS, 1); + tty_putcode_i(tty, TTYC_SS, 1); else - tty_putcode1(tty, TTYC_SS, 2); + tty_putcode_i(tty, TTYC_SS, 2); } 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 (cmode & MODE_CURSOR_BLINKING) - tty_putcode1(tty, TTYC_SS, 3); + tty_putcode_i(tty, TTYC_SS, 3); else - tty_putcode1(tty, TTYC_SS, 4); + tty_putcode_i(tty, TTYC_SS, 4); } 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 (cmode & MODE_CURSOR_BLINKING) - tty_putcode1(tty, TTYC_SS, 5); + tty_putcode_i(tty, TTYC_SS, 5); else - tty_putcode1(tty, TTYC_SS, 6); + tty_putcode_i(tty, TTYC_SS, 6); } else if (cmode & MODE_CURSOR_BLINKING) tty_putcode(tty, TTYC_CVVIS); break; @@ -819,12 +856,6 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s) else if (mode & MODE_MOUSE_STANDARD) tty_puts(tty, "\033[?1000h"); } - if (changed & MODE_BRACKETPASTE) { - if (mode & MODE_BRACKETPASTE) - tty_putcode(tty, TTYC_ENBP); - else - tty_putcode(tty, TTYC_DSBP); - } tty->mode = mode; } @@ -833,7 +864,7 @@ tty_emulate_repeat(struct tty *tty, enum tty_code_code code, enum tty_code_code code1, u_int n) { if (tty_term_has(tty->term, code)) - tty_putcode1(tty, code, n); + tty_putcode_i(tty, code, n); else { while (n-- > 0) tty_putcode(tty, code1); @@ -1122,7 +1153,7 @@ tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py, /* 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); + tty_putcode_i(tty, TTYC_ECH, nx); return; } } @@ -1263,7 +1294,7 @@ tty_clear_area(struct tty *tty, const struct grid_cell *defaults, u_int py, tty_term_has(tty->term, TTYC_INDN)) { tty_region(tty, py, py + ny - 1); tty_margin_off(tty); - tty_putcode1(tty, TTYC_INDN, ny); + tty_putcode_i(tty, TTYC_INDN, ny); return; } @@ -1278,7 +1309,7 @@ tty_clear_area(struct tty *tty, const struct grid_cell *defaults, u_int py, 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); + tty_putcode_i(tty, TTYC_INDN, ny); return; } } @@ -1455,7 +1486,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; @@ -1480,9 +1512,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, @@ -1515,7 +1549,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, 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_attributes(tty, &last, defaults, palette, + s->hyperlinks); for (j = 0; j < OVERLAY_MAX_RANGES; j++) { if (r.nx[j] == 0) continue; @@ -1532,7 +1567,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, } } } 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]); @@ -1544,7 +1580,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, @@ -1560,7 +1596,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); } @@ -1568,6 +1605,58 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, tty_update_mode(tty, tty->mode, s); } +#ifdef ENABLE_SIXEL +/* 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); + + /* Set the properties relevant to the current client. */ + ttyctx->bigger = tty_window_offset(&c->tty, &ttyctx->wox, &ttyctx->woy, + &ttyctx->wsx, &ttyctx->wsy); + + 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 screen *s) +{ + struct image *im; + struct tty_ctx ttyctx; + + TAILQ_FOREACH(im, &s->images, entry) { + memset(&ttyctx, 0, sizeof ttyctx); + + /* Set the client independent properties. */ + ttyctx.ocx = im->px; + ttyctx.ocy = im->py; + + ttyctx.orlower = s->rlower; + ttyctx.orupper = s->rupper; + + ttyctx.xoff = ttyctx.rxoff = wp->xoff; + ttyctx.sx = wp->sx; + ttyctx.sy = wp->sy; + + ttyctx.ptr = im; + ttyctx.arg = wp; + ttyctx.set_client_cb = tty_set_client_cb; + ttyctx.allow_invisible_panes = 1; + tty_write_one(tty_cmd_sixelimage, c, &ttyctx); + } +} +#endif + void tty_sync_start(struct tty *tty) { @@ -1579,7 +1668,7 @@ tty_sync_start(struct tty *tty) if (tty_term_has(tty->term, TTYC_SYNC)) { log_debug("%s sync start", tty->client->name); - tty_putcode1(tty, TTYC_SYNC, 1); + tty_putcode_i(tty, TTYC_SYNC, 1); } } @@ -1594,16 +1683,26 @@ tty_sync_end(struct tty *tty) if (tty_term_has(tty->term, TTYC_SYNC)) { log_debug("%s sync end", tty->client->name); - tty_putcode1(tty, TTYC_SYNC, 2); + tty_putcode_i(tty, TTYC_SYNC, 2); } } static int -tty_client_ready(struct client *c) +tty_client_ready(const struct tty_ctx *ctx, struct client *c) { if (c->session == NULL || c->tty.term == NULL) return (0); - if (c->flags & (CLIENT_REDRAWWINDOW|CLIENT_SUSPENDED)) + if (c->flags & CLIENT_SUSPENDED) + return (0); + + /* + * If invisible panes are allowed (used for passthrough), don't care if + * redrawing or frozen. + */ + if (ctx->allow_invisible_panes) + return (1); + + if (c->flags & CLIENT_REDRAWWINDOW) return (0); if (c->tty.flags & TTY_FREEZE) return (0); @@ -1620,17 +1719,30 @@ tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *), if (ctx->set_client_cb == NULL) return; TAILQ_FOREACH(c, &clients, entry) { - if (!tty_client_ready(c)) - continue; - state = ctx->set_client_cb(ctx, c); - if (state == -1) - break; - if (state == 0) - continue; - cmdfn(&c->tty, ctx); + if (tty_client_ready(ctx, c)) { + state = ctx->set_client_cb(ctx, c); + if (state == -1) + break; + if (state == 0) + continue; + cmdfn(&c->tty, ctx); + } } } +#ifdef ENABLE_SIXEL +/* 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) { @@ -1646,7 +1758,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); @@ -1668,7 +1781,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); @@ -1678,7 +1792,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); } @@ -1700,7 +1815,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); @@ -1727,7 +1843,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); @@ -1740,7 +1857,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); } @@ -1750,7 +1868,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); } @@ -1758,7 +1877,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); } @@ -1784,7 +1904,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); @@ -1793,7 +1914,7 @@ tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) if (tty_term_has(tty->term, TTYC_RI)) tty_putcode(tty, TTYC_RI); else - tty_putcode1(tty, TTYC_RIN, 1); + tty_putcode_i(tty, TTYC_RIN, 1); } void @@ -1815,7 +1936,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); @@ -1855,7 +1977,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); @@ -1872,7 +1995,7 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx) tty_cursor(tty, 0, 0); else tty_cursor(tty, 0, tty->cy); - tty_putcode1(tty, TTYC_INDN, ctx->num); + tty_putcode_i(tty, TTYC_INDN, ctx->num); } } @@ -1895,14 +2018,15 @@ 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); tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper); if (tty_term_has(tty->term, TTYC_RIN)) - tty_putcode1(tty, TTYC_RIN, ctx->num); + tty_putcode_i(tty, TTYC_RIN, ctx->num); else { for (i = 0; i < ctx->num; i++) tty_putcode(tty, TTYC_RI); @@ -1914,7 +2038,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); @@ -1938,7 +2063,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); @@ -1962,7 +2088,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); @@ -1985,7 +2112,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); @@ -2031,7 +2159,11 @@ 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); + + if (ctx->num == 1) + tty_invalidate(tty); } void @@ -2062,7 +2194,7 @@ 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); + tty_attributes(tty, ctx->cell, &ctx->defaults, ctx->palette, ctx->s->hyperlinks); /* Get tty position from pane position for overlay check. */ px = ctx->xoff + ctx->ocx - ctx->wox; @@ -2082,11 +2214,12 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx) 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; @@ -2101,7 +2234,7 @@ tty_set_selection(struct tty *tty, const char *buf, size_t len) b64_ntop(buf, len, encoded, size); tty->flags |= TTY_NOBLOCK; - tty_putcode_ptr2(tty, TTYC_MS, "", encoded); + tty_putcode_ss(tty, TTYC_MS, flags, encoded); free(encoded); } @@ -2114,6 +2247,58 @@ tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx) tty_invalidate(tty); } +#ifdef ENABLE_SIXEL +void +tty_cmd_sixelimage(struct tty *tty, const struct tty_ctx *ctx) +{ + struct image *im = ctx->ptr; + 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) { @@ -2135,7 +2320,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; @@ -2151,11 +2337,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); @@ -2172,6 +2358,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_ss(tty, TTYC_HLS, "", ""); if ((gc->attr & GRID_ATTR_CHARSET) && tty_acs_needed(tty)) tty_putcode(tty, TTYC_RMACS); tty_putcode(tty, TTYC_SGR0); @@ -2246,7 +2434,7 @@ tty_region(struct tty *tty, u_int rupper, u_int rlower) tty_cursor(tty, 0, tty->cy); } - tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower); + tty_putcode_ii(tty, TTYC_CSR, tty->rupper, tty->rlower); tty->cx = tty->cy = UINT_MAX; } @@ -2274,7 +2462,7 @@ tty_margin(struct tty *tty, u_int rleft, u_int rright) if (tty->rleft == rleft && tty->rright == rright) return; - tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower); + tty_putcode_ii(tty, TTYC_CSR, tty->rupper, tty->rlower); tty->rleft = rleft; tty->rright = rright; @@ -2282,7 +2470,7 @@ tty_margin(struct tty *tty, u_int rleft, u_int rright) if (rleft == 0 && rright == tty->sx - 1) tty_putcode(tty, TTYC_CLMG); else - tty_putcode2(tty, TTYC_CMG, rleft, rright); + tty_putcode_ii(tty, TTYC_CMG, rleft, rright); tty->cx = tty->cy = UINT_MAX; } @@ -2392,7 +2580,7 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) * the cursor with CUB/CUF. */ if ((u_int) abs(change) > cx && tty_term_has(term, TTYC_HPA)) { - tty_putcode1(tty, TTYC_HPA, cx); + tty_putcode_i(tty, TTYC_HPA, cx); goto out; } else if (change > 0 && tty_term_has(term, TTYC_CUB) && @@ -2402,12 +2590,12 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) tty_putcode(tty, TTYC_CUB1); goto out; } - tty_putcode1(tty, TTYC_CUB, change); + tty_putcode_i(tty, TTYC_CUB, change); goto out; } else if (change < 0 && tty_term_has(term, TTYC_CUF) && !tty_use_margin(tty)) { - tty_putcode1(tty, TTYC_CUF, -change); + tty_putcode_i(tty, TTYC_CUF, -change); goto out; } } else if (cx == thisx) { @@ -2440,30 +2628,50 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) (change < 0 && cy - change > tty->rlower) || (change > 0 && cy - change < tty->rupper)) { if (tty_term_has(term, TTYC_VPA)) { - tty_putcode1(tty, TTYC_VPA, cy); + tty_putcode_i(tty, TTYC_VPA, cy); goto out; } } else if (change > 0 && tty_term_has(term, TTYC_CUU)) { - tty_putcode1(tty, TTYC_CUU, change); + tty_putcode_i(tty, TTYC_CUU, change); goto out; } else if (change < 0 && tty_term_has(term, TTYC_CUD)) { - tty_putcode1(tty, TTYC_CUD, -change); + tty_putcode_i(tty, TTYC_CUD, -change); goto out; } } absolute: /* Absolute movement. */ - tty_putcode2(tty, TTYC_CUP, cy, cx); + tty_putcode_ii(tty, TTYC_CUP, cy, cx); out: tty->cx = cx; 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_ss(tty, TTYC_HLS, "", ""); + else + tty_putcode_ss(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; @@ -2481,7 +2689,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; /* @@ -2533,13 +2742,13 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc, !tty_term_has(tty->term, TTYC_SMULX)) tty_putcode(tty, TTYC_SMUL); else if (changed & GRID_ATTR_UNDERSCORE_2) - tty_putcode1(tty, TTYC_SMULX, 2); + tty_putcode_i(tty, TTYC_SMULX, 2); else if (changed & GRID_ATTR_UNDERSCORE_3) - tty_putcode1(tty, TTYC_SMULX, 3); + tty_putcode_i(tty, TTYC_SMULX, 3); else if (changed & GRID_ATTR_UNDERSCORE_4) - tty_putcode1(tty, TTYC_SMULX, 4); + tty_putcode_i(tty, TTYC_SMULX, 4); else if (changed & GRID_ATTR_UNDERSCORE_5) - tty_putcode1(tty, TTYC_SMULX, 5); + tty_putcode_i(tty, TTYC_SMULX, 5); } if (changed & GRID_ATTR_BLINK) tty_putcode(tty, TTYC_BLINK); @@ -2558,6 +2767,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); } @@ -2593,14 +2805,14 @@ tty_colours(struct tty *tty, const struct grid_cell *gc) if (have_ax) tty_puts(tty, "\033[39m"); else if (tc->fg != 7) - tty_putcode1(tty, TTYC_SETAF, 7); + tty_putcode_i(tty, TTYC_SETAF, 7); tc->fg = gc->fg; } if (COLOUR_DEFAULT(gc->bg) && !COLOUR_DEFAULT(tc->bg)) { if (have_ax) tty_puts(tty, "\033[49m"); else if (tc->bg != 0) - tty_putcode1(tty, TTYC_SETAB, 0); + tty_putcode_i(tty, TTYC_SETAB, 0); tc->bg = gc->bg; } } @@ -2632,12 +2844,14 @@ tty_check_fg(struct tty *tty, struct colour_palette *palette, /* * Perform substitution if this pane has a palette. If the bright - * attribute is set, use the bright entry in the palette by changing to - * the aixterm colour. + * attribute is set and Nobr is not present, use the bright entry in + * the palette by changing to the aixterm colour */ if (~gc->flags & GRID_FLAG_NOPALETTE) { c = gc->fg; - if (c < 8 && gc->attr & GRID_ATTR_BRIGHT) + if (c < 8 && + gc->attr & GRID_ATTR_BRIGHT && + !tty_term_has(tty->term, TTYC_NOBR)) c += 90; if ((c = colour_palette_get(palette, c)) != -1) gc->fg = c; @@ -2743,9 +2957,13 @@ tty_check_us(__unused struct tty *tty, struct colour_palette *palette, gc->us = c; } - /* Underscore colour is set as RGB so convert a 256 colour to RGB. */ - if (gc->us & COLOUR_FLAG_256) - gc->us = colour_256toRGB (gc->us); + /* Convert underscore colour if only RGB can be supported. */ + if (!tty_term_has(tty->term, TTYC_SETULC1)) { + if ((c = colour_force_rgb (gc->us)) == -1) + gc->us = 8; + else + gc->us = c; + } } static void @@ -2768,12 +2986,12 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc) xsnprintf(s, sizeof s, "\033[%dm", gc->fg); tty_puts(tty, s); } else - tty_putcode1(tty, TTYC_SETAF, gc->fg - 90 + 8); + tty_putcode_i(tty, TTYC_SETAF, gc->fg - 90 + 8); goto save; } /* Otherwise set the foreground colour. */ - tty_putcode1(tty, TTYC_SETAF, gc->fg); + tty_putcode_i(tty, TTYC_SETAF, gc->fg); save: /* Save the new values in the terminal current cell. */ @@ -2800,12 +3018,12 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc) xsnprintf(s, sizeof s, "\033[%dm", gc->bg + 10); tty_puts(tty, s); } else - tty_putcode1(tty, TTYC_SETAB, gc->bg - 90 + 8); + tty_putcode_i(tty, TTYC_SETAB, gc->bg - 90 + 8); goto save; } /* Otherwise set the background colour. */ - tty_putcode1(tty, TTYC_SETAB, gc->bg); + tty_putcode_i(tty, TTYC_SETAB, gc->bg); save: /* Save the new values in the terminal current cell. */ @@ -2820,14 +3038,22 @@ tty_colours_us(struct tty *tty, const struct grid_cell *gc) u_char r, g, b; /* Clear underline colour. */ - if (gc->us == 0) { + if (COLOUR_DEFAULT(gc->us)) { tty_putcode(tty, TTYC_OL); goto save; } - /* Must be an RGB colour - this should never happen. */ - if (~gc->us & COLOUR_FLAG_RGB) + /* + * If this is not an RGB colour, use Setulc1 if it exists, otherwise + * convert. + */ + if (~gc->us & COLOUR_FLAG_RGB) { + c = gc->us; + if ((~c & COLOUR_FLAG_256) && (c >= 90 && c <= 97)) + c -= 82; + tty_putcode_i(tty, TTYC_SETULC1, c & ~COLOUR_FLAG_256); return; + } /* * Setulc and setal follows the ncurses(3) one argument "direct colour" @@ -2841,10 +3067,10 @@ tty_colours_us(struct tty *tty, const struct grid_cell *gc) * non-RGB version may be wrong. */ if (tty_term_has(tty->term, TTYC_SETULC)) - tty_putcode1(tty, TTYC_SETULC, c); + tty_putcode_i(tty, TTYC_SETULC, c); else if (tty_term_has(tty->term, TTYC_SETAL) && tty_term_has(tty->term, TTYC_RGB)) - tty_putcode1(tty, TTYC_SETAL, c); + tty_putcode_i(tty, TTYC_SETAL, c); save: /* Save the new values in the terminal current cell. */ @@ -2858,18 +3084,18 @@ tty_try_colour(struct tty *tty, int colour, const char *type) if (colour & COLOUR_FLAG_256) { if (*type == '3' && tty_term_has(tty->term, TTYC_SETAF)) - tty_putcode1(tty, TTYC_SETAF, colour & 0xff); + tty_putcode_i(tty, TTYC_SETAF, colour & 0xff); else if (tty_term_has(tty->term, TTYC_SETAB)) - tty_putcode1(tty, TTYC_SETAB, colour & 0xff); + tty_putcode_i(tty, TTYC_SETAB, colour & 0xff); return (0); } if (colour & COLOUR_FLAG_RGB) { colour_split_rgb(colour & 0xffffff, &r, &g, &b); if (*type == '3' && tty_term_has(tty->term, TTYC_SETRGBF)) - tty_putcode3(tty, TTYC_SETRGBF, r, g, b); + tty_putcode_iii(tty, TTYC_SETRGBF, r, g, b); else if (tty_term_has(tty->term, TTYC_SETRGBB)) - tty_putcode3(tty, TTYC_SETRGBB, r, g, b); + tty_putcode_iii(tty, TTYC_SETRGBB, r, g, b); return (0); } @@ -2923,13 +3149,13 @@ 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 @@ -2953,7 +3179,7 @@ tty_clipboard_query(struct tty *tty) if ((~tty->flags & TTY_STARTED) || (tty->flags & TTY_OSC52QUERY)) return; - tty_putcode_ptr2(tty, TTYC_MS, "", "?"); + tty_putcode_ss(tty, TTYC_MS, "", "?"); tty->flags |= TTY_OSC52QUERY; evtimer_set(&tty->clipboard_timer, tty_clipboard_query_callback, tty); |