"Fossies" - the Fresh Open Source Software Archive

Member "tmux-3.2a/tty.c" (10 Jun 2021, 66680 Bytes) of package /linux/misc/tmux-3.2a.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tty.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.2_vs_3.2a.

    1 /* $OpenBSD$ */
    2 
    3 /*
    4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
   15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
   16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 #include <sys/types.h>
   20 #include <sys/ioctl.h>
   21 
   22 #include <netinet/in.h>
   23 
   24 #include <curses.h>
   25 #include <errno.h>
   26 #include <fcntl.h>
   27 #include <resolv.h>
   28 #include <stdlib.h>
   29 #include <string.h>
   30 #include <termios.h>
   31 #include <unistd.h>
   32 
   33 #include "tmux.h"
   34 
   35 static int  tty_log_fd = -1;
   36 
   37 static int  tty_client_ready(struct client *);
   38 
   39 static void tty_set_italics(struct tty *);
   40 static int  tty_try_colour(struct tty *, int, const char *);
   41 static void tty_force_cursor_colour(struct tty *, const char *);
   42 static void tty_cursor_pane(struct tty *, const struct tty_ctx *, u_int,
   43             u_int);
   44 static void tty_cursor_pane_unless_wrap(struct tty *,
   45             const struct tty_ctx *, u_int, u_int);
   46 static void tty_invalidate(struct tty *);
   47 static void tty_colours(struct tty *, const struct grid_cell *);
   48 static void tty_check_fg(struct tty *, int *, struct grid_cell *);
   49 static void tty_check_bg(struct tty *, int *, struct grid_cell *);
   50 static void tty_check_us(struct tty *, int *, struct grid_cell *);
   51 static void tty_colours_fg(struct tty *, const struct grid_cell *);
   52 static void tty_colours_bg(struct tty *, const struct grid_cell *);
   53 static void tty_colours_us(struct tty *, const struct grid_cell *);
   54 
   55 static void tty_region_pane(struct tty *, const struct tty_ctx *, u_int,
   56             u_int);
   57 static void tty_region(struct tty *, u_int, u_int);
   58 static void tty_margin_pane(struct tty *, const struct tty_ctx *);
   59 static void tty_margin(struct tty *, u_int, u_int);
   60 static int  tty_large_region(struct tty *, const struct tty_ctx *);
   61 static int  tty_fake_bce(const struct tty *, const struct grid_cell *,
   62             u_int);
   63 static void tty_redraw_region(struct tty *, const struct tty_ctx *);
   64 static void tty_emulate_repeat(struct tty *, enum tty_code_code,
   65             enum tty_code_code, u_int);
   66 static void tty_repeat_space(struct tty *, u_int);
   67 static void tty_draw_pane(struct tty *, const struct tty_ctx *, u_int);
   68 static void tty_default_attributes(struct tty *, const struct grid_cell *,
   69             int *, u_int);
   70 
   71 #define tty_use_margin(tty) \
   72     (tty->term->flags & TERM_DECSLRM)
   73 #define tty_full_width(tty, ctx) \
   74     ((ctx)->xoff == 0 && (ctx)->sx >= (tty)->sx)
   75 
   76 #define TTY_BLOCK_INTERVAL (100000 /* 100 milliseconds */)
   77 #define TTY_BLOCK_START(tty) (1 + ((tty)->sx * (tty)->sy) * 8)
   78 #define TTY_BLOCK_STOP(tty) (1 + ((tty)->sx * (tty)->sy) / 8)
   79 
   80 void
   81 tty_create_log(void)
   82 {
   83     char    name[64];
   84 
   85     xsnprintf(name, sizeof name, "tmux-out-%ld.log", (long)getpid());
   86 
   87     tty_log_fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0644);
   88     if (tty_log_fd != -1 && fcntl(tty_log_fd, F_SETFD, FD_CLOEXEC) == -1)
   89         fatal("fcntl failed");
   90 }
   91 
   92 int
   93 tty_init(struct tty *tty, struct client *c)
   94 {
   95     if (!isatty(c->fd))
   96         return (-1);
   97 
   98     memset(tty, 0, sizeof *tty);
   99     tty->client = c;
  100 
  101     tty->cstyle = 0;
  102     tty->ccolour = xstrdup("");
  103 
  104     if (tcgetattr(c->fd, &tty->tio) != 0)
  105         return (-1);
  106     return (0);
  107 }
  108 
  109 void
  110 tty_resize(struct tty *tty)
  111 {
  112     struct client   *c = tty->client;
  113     struct winsize   ws;
  114     u_int        sx, sy, xpixel, ypixel;
  115 
  116     if (ioctl(c->fd, TIOCGWINSZ, &ws) != -1) {
  117         sx = ws.ws_col;
  118         if (sx == 0) {
  119             sx = 80;
  120             xpixel = 0;
  121         } else
  122             xpixel = ws.ws_xpixel / sx;
  123         sy = ws.ws_row;
  124         if (sy == 0) {
  125             sy = 24;
  126             ypixel = 0;
  127         } else
  128             ypixel = ws.ws_ypixel / sy;
  129     } else {
  130         sx = 80;
  131         sy = 24;
  132         xpixel = 0;
  133         ypixel = 0;
  134     }
  135     log_debug("%s: %s now %ux%u (%ux%u)", __func__, c->name, sx, sy,
  136         xpixel, ypixel);
  137     tty_set_size(tty, sx, sy, xpixel, ypixel);
  138     tty_invalidate(tty);
  139 }
  140 
  141 void
  142 tty_set_size(struct tty *tty, u_int sx, u_int sy, u_int xpixel, u_int ypixel)
  143 {
  144     tty->sx = sx;
  145     tty->sy = sy;
  146     tty->xpixel = xpixel;
  147     tty->ypixel = ypixel;
  148 }
  149 
  150 static void
  151 tty_read_callback(__unused int fd, __unused short events, void *data)
  152 {
  153     struct tty  *tty = data;
  154     struct client   *c = tty->client;
  155     const char  *name = c->name;
  156     size_t       size = EVBUFFER_LENGTH(tty->in);
  157     int      nread;
  158 
  159     nread = evbuffer_read(tty->in, c->fd, -1);
  160     if (nread == 0 || nread == -1) {
  161         if (nread == 0)
  162             log_debug("%s: read closed", name);
  163         else
  164             log_debug("%s: read error: %s", name, strerror(errno));
  165         event_del(&tty->event_in);
  166         server_client_lost(tty->client);
  167         return;
  168     }
  169     log_debug("%s: read %d bytes (already %zu)", name, nread, size);
  170 
  171     while (tty_keys_next(tty))
  172         ;
  173 }
  174 
  175 static void
  176 tty_timer_callback(__unused int fd, __unused short events, void *data)
  177 {
  178     struct tty  *tty = data;
  179     struct client   *c = tty->client;
  180     struct timeval   tv = { .tv_usec = TTY_BLOCK_INTERVAL };
  181 
  182     log_debug("%s: %zu discarded", c->name, tty->discarded);
  183 
  184     c->flags |= CLIENT_ALLREDRAWFLAGS;
  185     c->discarded += tty->discarded;
  186 
  187     if (tty->discarded < TTY_BLOCK_STOP(tty)) {
  188         tty->flags &= ~TTY_BLOCK;
  189         tty_invalidate(tty);
  190         return;
  191     }
  192     tty->discarded = 0;
  193     evtimer_add(&tty->timer, &tv);
  194 }
  195 
  196 static int
  197 tty_block_maybe(struct tty *tty)
  198 {
  199     struct client   *c = tty->client;
  200     size_t       size = EVBUFFER_LENGTH(tty->out);
  201     struct timeval   tv = { .tv_usec = TTY_BLOCK_INTERVAL };
  202 
  203     if (size < TTY_BLOCK_START(tty))
  204         return (0);
  205 
  206     if (tty->flags & TTY_BLOCK)
  207         return (1);
  208     tty->flags |= TTY_BLOCK;
  209 
  210     log_debug("%s: can't keep up, %zu discarded", c->name, size);
  211 
  212     evbuffer_drain(tty->out, size);
  213     c->discarded += size;
  214 
  215     tty->discarded = 0;
  216     evtimer_add(&tty->timer, &tv);
  217     return (1);
  218 }
  219 
  220 static void
  221 tty_write_callback(__unused int fd, __unused short events, void *data)
  222 {
  223     struct tty  *tty = data;
  224     struct client   *c = tty->client;
  225     size_t       size = EVBUFFER_LENGTH(tty->out);
  226     int      nwrite;
  227 
  228     nwrite = evbuffer_write(tty->out, c->fd);
  229     if (nwrite == -1)
  230         return;
  231     log_debug("%s: wrote %d bytes (of %zu)", c->name, nwrite, size);
  232 
  233     if (c->redraw > 0) {
  234         if ((size_t)nwrite >= c->redraw)
  235             c->redraw = 0;
  236         else
  237             c->redraw -= nwrite;
  238         log_debug("%s: waiting for redraw, %zu bytes left", c->name,
  239             c->redraw);
  240     } else if (tty_block_maybe(tty))
  241         return;
  242 
  243     if (EVBUFFER_LENGTH(tty->out) != 0)
  244         event_add(&tty->event_out, NULL);
  245 }
  246 
  247 int
  248 tty_open(struct tty *tty, char **cause)
  249 {
  250     struct client   *c = tty->client;
  251 
  252     tty->term = tty_term_create(tty, c->term_name, c->term_caps,
  253         c->term_ncaps, &c->term_features, cause);
  254     if (tty->term == NULL) {
  255         tty_close(tty);
  256         return (-1);
  257     }
  258     tty->flags |= TTY_OPENED;
  259 
  260     tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE|TTY_BLOCK|TTY_TIMER);
  261 
  262     event_set(&tty->event_in, c->fd, EV_PERSIST|EV_READ,
  263         tty_read_callback, tty);
  264     tty->in = evbuffer_new();
  265     if (tty->in == NULL)
  266         fatal("out of memory");
  267 
  268     event_set(&tty->event_out, c->fd, EV_WRITE, tty_write_callback, tty);
  269     tty->out = evbuffer_new();
  270     if (tty->out == NULL)
  271         fatal("out of memory");
  272 
  273     evtimer_set(&tty->timer, tty_timer_callback, tty);
  274 
  275     tty_start_tty(tty);
  276 
  277     tty_keys_build(tty);
  278 
  279     return (0);
  280 }
  281 
  282 static void
  283 tty_start_timer_callback(__unused int fd, __unused short events, void *data)
  284 {
  285     struct tty  *tty = data;
  286     struct client   *c = tty->client;
  287 
  288     log_debug("%s: start timer fired", c->name);
  289     if ((tty->flags & (TTY_HAVEDA|TTY_HAVEXDA)) == 0)
  290         tty_update_features(tty);
  291     tty->flags |= (TTY_HAVEDA|TTY_HAVEXDA);
  292 }
  293 
  294 void
  295 tty_start_tty(struct tty *tty)
  296 {
  297     struct client   *c = tty->client;
  298     struct termios   tio;
  299     struct timeval   tv = { .tv_sec = 1 };
  300 
  301     setblocking(c->fd, 0);
  302     event_add(&tty->event_in, NULL);
  303 
  304     memcpy(&tio, &tty->tio, sizeof tio);
  305     tio.c_iflag &= ~(IXON|IXOFF|ICRNL|INLCR|IGNCR|IMAXBEL|ISTRIP);
  306     tio.c_iflag |= IGNBRK;
  307     tio.c_oflag &= ~(OPOST|ONLCR|OCRNL|ONLRET);
  308     tio.c_lflag &= ~(IEXTEN|ICANON|ECHO|ECHOE|ECHONL|ECHOCTL|ECHOPRT|
  309         ECHOKE|ISIG);
  310     tio.c_cc[VMIN] = 1;
  311     tio.c_cc[VTIME] = 0;
  312     if (tcsetattr(c->fd, TCSANOW, &tio) == 0)
  313         tcflush(c->fd, TCIOFLUSH);
  314 
  315     tty_putcode(tty, TTYC_SMCUP);
  316 
  317     tty_putcode(tty, TTYC_SMKX);
  318     tty_putcode(tty, TTYC_CLEAR);
  319 
  320     if (tty_acs_needed(tty)) {
  321         log_debug("%s: using capabilities for ACS", c->name);
  322         tty_putcode(tty, TTYC_ENACS);
  323     } else
  324         log_debug("%s: using UTF-8 for ACS", c->name);
  325 
  326     tty_putcode(tty, TTYC_CNORM);
  327     if (tty_term_has(tty->term, TTYC_KMOUS)) {
  328         tty_puts(tty, "\033[?1000l\033[?1002l\033[?1003l");
  329         tty_puts(tty, "\033[?1006l\033[?1005l");
  330     }
  331 
  332     evtimer_set(&tty->start_timer, tty_start_timer_callback, tty);
  333     evtimer_add(&tty->start_timer, &tv);
  334 
  335     tty->flags |= TTY_STARTED;
  336     tty_invalidate(tty);
  337 
  338     if (*tty->ccolour != '\0')
  339         tty_force_cursor_colour(tty, "");
  340 
  341     tty->mouse_drag_flag = 0;
  342     tty->mouse_drag_update = NULL;
  343     tty->mouse_drag_release = NULL;
  344 }
  345 
  346 void
  347 tty_send_requests(struct tty *tty)
  348 {
  349     if (~tty->flags & TTY_STARTED)
  350         return;
  351 
  352     if (tty->term->flags & TERM_VT100LIKE) {
  353         if (~tty->flags & TTY_HAVEDA)
  354             tty_puts(tty, "\033[>c");
  355         if (~tty->flags & TTY_HAVEXDA)
  356             tty_puts(tty, "\033[>q");
  357     } else
  358         tty->flags |= (TTY_HAVEDA|TTY_HAVEXDA);
  359 }
  360 
  361 void
  362 tty_stop_tty(struct tty *tty)
  363 {
  364     struct client   *c = tty->client;
  365     struct winsize   ws;
  366 
  367     if (!(tty->flags & TTY_STARTED))
  368         return;
  369     tty->flags &= ~TTY_STARTED;
  370 
  371     evtimer_del(&tty->start_timer);
  372 
  373     event_del(&tty->timer);
  374     tty->flags &= ~TTY_BLOCK;
  375 
  376     event_del(&tty->event_in);
  377     event_del(&tty->event_out);
  378 
  379     /*
  380      * Be flexible about error handling and try not kill the server just
  381      * because the fd is invalid. Things like ssh -t can easily leave us
  382      * with a dead tty.
  383      */
  384     if (ioctl(c->fd, TIOCGWINSZ, &ws) == -1)
  385         return;
  386     if (tcsetattr(c->fd, TCSANOW, &tty->tio) == -1)
  387         return;
  388 
  389     tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1));
  390     if (tty_acs_needed(tty))
  391         tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS));
  392     tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0));
  393     tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX));
  394     tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR));
  395     if (tty_term_has(tty->term, TTYC_SS) && tty->cstyle != 0) {
  396         if (tty_term_has(tty->term, TTYC_SE))
  397             tty_raw(tty, tty_term_string(tty->term, TTYC_SE));
  398         else
  399             tty_raw(tty, tty_term_string1(tty->term, TTYC_SS, 0));
  400     }
  401     if (tty->mode & MODE_BRACKETPASTE)
  402         tty_raw(tty, tty_term_string(tty->term, TTYC_DSBP));
  403     if (*tty->ccolour != '\0')
  404         tty_raw(tty, tty_term_string(tty->term, TTYC_CR));
  405 
  406     tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM));
  407     if (tty_term_has(tty->term, TTYC_KMOUS)) {
  408         tty_raw(tty, "\033[?1000l\033[?1002l\033[?1003l");
  409         tty_raw(tty, "\033[?1006l\033[?1005l");
  410     }
  411 
  412     if (tty->term->flags & TERM_VT100LIKE)
  413         tty_raw(tty, "\033[?7727l");
  414     tty_raw(tty, tty_term_string(tty->term, TTYC_DSFCS));
  415     tty_raw(tty, tty_term_string(tty->term, TTYC_DSEKS));
  416 
  417     if (tty_use_margin(tty))
  418         tty_raw(tty, tty_term_string(tty->term, TTYC_DSMG));
  419     tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
  420 
  421     setblocking(c->fd, 1);
  422 }
  423 
  424 void
  425 tty_close(struct tty *tty)
  426 {
  427     if (event_initialized(&tty->key_timer))
  428         evtimer_del(&tty->key_timer);
  429     tty_stop_tty(tty);
  430 
  431     if (tty->flags & TTY_OPENED) {
  432         evbuffer_free(tty->in);
  433         event_del(&tty->event_in);
  434         evbuffer_free(tty->out);
  435         event_del(&tty->event_out);
  436 
  437         tty_term_free(tty->term);
  438         tty_keys_free(tty);
  439 
  440         tty->flags &= ~TTY_OPENED;
  441     }
  442 }
  443 
  444 void
  445 tty_free(struct tty *tty)
  446 {
  447     tty_close(tty);
  448     free(tty->ccolour);
  449 }
  450 
  451 void
  452 tty_update_features(struct tty *tty)
  453 {
  454     struct client   *c = tty->client;
  455 
  456     if (tty_apply_features(tty->term, c->term_features))
  457         tty_term_apply_overrides(tty->term);
  458 
  459     if (tty_use_margin(tty))
  460         tty_putcode(tty, TTYC_ENMG);
  461     if (options_get_number(global_options, "extended-keys"))
  462         tty_puts(tty, tty_term_string(tty->term, TTYC_ENEKS));
  463     if (options_get_number(global_options, "focus-events"))
  464         tty_puts(tty, tty_term_string(tty->term, TTYC_ENFCS));
  465     if (tty->term->flags & TERM_VT100LIKE)
  466         tty_puts(tty, "\033[?7727h");
  467 }
  468 
  469 void
  470 tty_raw(struct tty *tty, const char *s)
  471 {
  472     struct client   *c = tty->client;
  473     ssize_t      n, slen;
  474     u_int        i;
  475 
  476     slen = strlen(s);
  477     for (i = 0; i < 5; i++) {
  478         n = write(c->fd, s, slen);
  479         if (n >= 0) {
  480             s += n;
  481             slen -= n;
  482             if (slen == 0)
  483                 break;
  484         } else if (n == -1 && errno != EAGAIN)
  485             break;
  486         usleep(100);
  487     }
  488 }
  489 
  490 void
  491 tty_putcode(struct tty *tty, enum tty_code_code code)
  492 {
  493     tty_puts(tty, tty_term_string(tty->term, code));
  494 }
  495 
  496 void
  497 tty_putcode1(struct tty *tty, enum tty_code_code code, int a)
  498 {
  499     if (a < 0)
  500         return;
  501     tty_puts(tty, tty_term_string1(tty->term, code, a));
  502 }
  503 
  504 void
  505 tty_putcode2(struct tty *tty, enum tty_code_code code, int a, int b)
  506 {
  507     if (a < 0 || b < 0)
  508         return;
  509     tty_puts(tty, tty_term_string2(tty->term, code, a, b));
  510 }
  511 
  512 void
  513 tty_putcode3(struct tty *tty, enum tty_code_code code, int a, int b, int c)
  514 {
  515     if (a < 0 || b < 0 || c < 0)
  516         return;
  517     tty_puts(tty, tty_term_string3(tty->term, code, a, b, c));
  518 }
  519 
  520 void
  521 tty_putcode_ptr1(struct tty *tty, enum tty_code_code code, const void *a)
  522 {
  523     if (a != NULL)
  524         tty_puts(tty, tty_term_ptr1(tty->term, code, a));
  525 }
  526 
  527 void
  528 tty_putcode_ptr2(struct tty *tty, enum tty_code_code code, const void *a,
  529     const void *b)
  530 {
  531     if (a != NULL && b != NULL)
  532         tty_puts(tty, tty_term_ptr2(tty->term, code, a, b));
  533 }
  534 
  535 static void
  536 tty_add(struct tty *tty, const char *buf, size_t len)
  537 {
  538     struct client   *c = tty->client;
  539 
  540     if (tty->flags & TTY_BLOCK) {
  541         tty->discarded += len;
  542         return;
  543     }
  544 
  545     evbuffer_add(tty->out, buf, len);
  546     log_debug("%s: %.*s", c->name, (int)len, buf);
  547     c->written += len;
  548 
  549     if (tty_log_fd != -1)
  550         write(tty_log_fd, buf, len);
  551     if (tty->flags & TTY_STARTED)
  552         event_add(&tty->event_out, NULL);
  553 }
  554 
  555 void
  556 tty_puts(struct tty *tty, const char *s)
  557 {
  558     if (*s != '\0')
  559         tty_add(tty, s, strlen(s));
  560 }
  561 
  562 void
  563 tty_putc(struct tty *tty, u_char ch)
  564 {
  565     const char  *acs;
  566 
  567     if ((tty->term->flags & TERM_NOAM) &&
  568         ch >= 0x20 && ch != 0x7f &&
  569         tty->cy == tty->sy - 1 &&
  570         tty->cx + 1 >= tty->sx)
  571         return;
  572 
  573     if (tty->cell.attr & GRID_ATTR_CHARSET) {
  574         acs = tty_acs_get(tty, ch);
  575         if (acs != NULL)
  576             tty_add(tty, acs, strlen(acs));
  577         else
  578             tty_add(tty, &ch, 1);
  579     } else
  580         tty_add(tty, &ch, 1);
  581 
  582     if (ch >= 0x20 && ch != 0x7f) {
  583         if (tty->cx >= tty->sx) {
  584             tty->cx = 1;
  585             if (tty->cy != tty->rlower)
  586                 tty->cy++;
  587 
  588             /*
  589              * On !am terminals, force the cursor position to where
  590              * we think it should be after a line wrap - this means
  591              * it works on sensible terminals as well.
  592              */
  593             if (tty->term->flags & TERM_NOAM)
  594                 tty_putcode2(tty, TTYC_CUP, tty->cy, tty->cx);
  595         } else
  596             tty->cx++;
  597     }
  598 }
  599 
  600 void
  601 tty_putn(struct tty *tty, const void *buf, size_t len, u_int width)
  602 {
  603     if ((tty->term->flags & TERM_NOAM) &&
  604         tty->cy == tty->sy - 1 &&
  605         tty->cx + len >= tty->sx)
  606         len = tty->sx - tty->cx - 1;
  607 
  608     tty_add(tty, buf, len);
  609     if (tty->cx + width > tty->sx) {
  610         tty->cx = (tty->cx + width) - tty->sx;
  611         if (tty->cx <= tty->sx)
  612             tty->cy++;
  613         else
  614             tty->cx = tty->cy = UINT_MAX;
  615     } else
  616         tty->cx += width;
  617 }
  618 
  619 static void
  620 tty_set_italics(struct tty *tty)
  621 {
  622     const char  *s;
  623 
  624     if (tty_term_has(tty->term, TTYC_SITM)) {
  625         s = options_get_string(global_options, "default-terminal");
  626         if (strcmp(s, "screen") != 0 && strncmp(s, "screen-", 7) != 0) {
  627             tty_putcode(tty, TTYC_SITM);
  628             return;
  629         }
  630     }
  631     tty_putcode(tty, TTYC_SMSO);
  632 }
  633 
  634 void
  635 tty_set_title(struct tty *tty, const char *title)
  636 {
  637     if (!tty_term_has(tty->term, TTYC_TSL) ||
  638         !tty_term_has(tty->term, TTYC_FSL))
  639         return;
  640 
  641     tty_putcode(tty, TTYC_TSL);
  642     tty_puts(tty, title);
  643     tty_putcode(tty, TTYC_FSL);
  644 }
  645 
  646 static void
  647 tty_force_cursor_colour(struct tty *tty, const char *ccolour)
  648 {
  649     if (*ccolour == '\0')
  650         tty_putcode(tty, TTYC_CR);
  651     else
  652         tty_putcode_ptr1(tty, TTYC_CS, ccolour);
  653     free(tty->ccolour);
  654     tty->ccolour = xstrdup(ccolour);
  655 }
  656 
  657 void
  658 tty_update_mode(struct tty *tty, int mode, struct screen *s)
  659 {
  660     struct client   *c = tty->client;
  661     int      changed;
  662 
  663     if (s != NULL && strcmp(s->ccolour, tty->ccolour) != 0)
  664         tty_force_cursor_colour(tty, s->ccolour);
  665 
  666     if (tty->flags & TTY_NOCURSOR)
  667         mode &= ~MODE_CURSOR;
  668 
  669     changed = mode ^ tty->mode;
  670     if (changed != 0)
  671         log_debug("%s: update mode %x to %x", c->name, tty->mode, mode);
  672 
  673     /*
  674      * The cursor blinking flag can be reset by setting the cursor style, so
  675      * set the style first.
  676      */
  677     if (s != NULL && tty->cstyle != s->cstyle) {
  678         if (tty_term_has(tty->term, TTYC_SS)) {
  679             if (s->cstyle == 0 && tty_term_has(tty->term, TTYC_SE))
  680                 tty_putcode(tty, TTYC_SE);
  681             else
  682                 tty_putcode1(tty, TTYC_SS, s->cstyle);
  683         }
  684         tty->cstyle = s->cstyle;
  685         changed |= (MODE_CURSOR|MODE_BLINKING);
  686     }
  687 
  688     /*
  689      * Cursor invisible (RM ?25) overrides cursor blinking (SM ?12 or RM
  690      * 34), and we need to be careful not send cnorm after cvvis since it
  691      * can undo it.
  692      */
  693     if (changed & (MODE_CURSOR|MODE_BLINKING)) {
  694         log_debug("%s: cursor %s, %sblinking", __func__,
  695             (mode & MODE_CURSOR) ? "on" : "off",
  696             (mode & MODE_BLINKING) ? "" : "not ");
  697         if (~mode & MODE_CURSOR)
  698             tty_putcode(tty, TTYC_CIVIS);
  699         else if (mode & MODE_BLINKING) {
  700             tty_putcode(tty, TTYC_CNORM);
  701             if (tty_term_has(tty->term, TTYC_CVVIS))
  702                 tty_putcode(tty, TTYC_CVVIS);
  703         } else
  704             tty_putcode(tty, TTYC_CNORM);
  705     }
  706 
  707     if ((changed & ALL_MOUSE_MODES) &&
  708         tty_term_has(tty->term, TTYC_KMOUS)) {
  709         /*
  710          * If the mouse modes have changed, clear any that are set and
  711          * apply again. There are differences in how terminals track
  712          * the various bits.
  713          */
  714         if (tty->mode & MODE_MOUSE_SGR)
  715             tty_puts(tty, "\033[?1006l");
  716         if (tty->mode & MODE_MOUSE_STANDARD)
  717             tty_puts(tty, "\033[?1000l");
  718         if (tty->mode & MODE_MOUSE_BUTTON)
  719             tty_puts(tty, "\033[?1002l");
  720         if (tty->mode & MODE_MOUSE_ALL)
  721             tty_puts(tty, "\033[?1003l");
  722         if (mode & ALL_MOUSE_MODES)
  723             tty_puts(tty, "\033[?1006h");
  724         if (mode & MODE_MOUSE_STANDARD)
  725             tty_puts(tty, "\033[?1000h");
  726         if (mode & MODE_MOUSE_BUTTON)
  727             tty_puts(tty, "\033[?1002h");
  728         if (mode & MODE_MOUSE_ALL)
  729             tty_puts(tty, "\033[?1003h");
  730     }
  731     if (changed & MODE_BRACKETPASTE) {
  732         if (mode & MODE_BRACKETPASTE)
  733             tty_putcode(tty, TTYC_ENBP);
  734         else
  735             tty_putcode(tty, TTYC_DSBP);
  736     }
  737     tty->mode = mode;
  738 }
  739 
  740 static void
  741 tty_emulate_repeat(struct tty *tty, enum tty_code_code code,
  742     enum tty_code_code code1, u_int n)
  743 {
  744     if (tty_term_has(tty->term, code))
  745         tty_putcode1(tty, code, n);
  746     else {
  747         while (n-- > 0)
  748             tty_putcode(tty, code1);
  749     }
  750 }
  751 
  752 static void
  753 tty_repeat_space(struct tty *tty, u_int n)
  754 {
  755     static char s[500];
  756 
  757     if (*s != ' ')
  758         memset(s, ' ', sizeof s);
  759 
  760     while (n > sizeof s) {
  761         tty_putn(tty, s, sizeof s, sizeof s);
  762         n -= sizeof s;
  763     }
  764     if (n != 0)
  765         tty_putn(tty, s, n, n);
  766 }
  767 
  768 /* Is this window bigger than the terminal? */
  769 int
  770 tty_window_bigger(struct tty *tty)
  771 {
  772     struct client   *c = tty->client;
  773     struct window   *w = c->session->curw->window;
  774 
  775     return (tty->sx < w->sx || tty->sy - status_line_size(c) < w->sy);
  776 }
  777 
  778 /* What offset should this window be drawn at? */
  779 int
  780 tty_window_offset(struct tty *tty, u_int *ox, u_int *oy, u_int *sx, u_int *sy)
  781 {
  782     *ox = tty->oox;
  783     *oy = tty->ooy;
  784     *sx = tty->osx;
  785     *sy = tty->osy;
  786 
  787     return (tty->oflag);
  788 }
  789 
  790 /* What offset should this window be drawn at? */
  791 static int
  792 tty_window_offset1(struct tty *tty, u_int *ox, u_int *oy, u_int *sx, u_int *sy)
  793 {
  794     struct client       *c = tty->client;
  795     struct window       *w = c->session->curw->window;
  796     struct window_pane  *wp = server_client_get_pane(c);
  797     u_int            cx, cy, lines;
  798 
  799     lines = status_line_size(c);
  800 
  801     if (tty->sx >= w->sx && tty->sy - lines >= w->sy) {
  802         *ox = 0;
  803         *oy = 0;
  804         *sx = w->sx;
  805         *sy = w->sy;
  806 
  807         c->pan_window = NULL;
  808         return (0);
  809     }
  810 
  811     *sx = tty->sx;
  812     *sy = tty->sy - lines;
  813 
  814     if (c->pan_window == w) {
  815         if (*sx >= w->sx)
  816             c->pan_ox = 0;
  817         else if (c->pan_ox + *sx > w->sx)
  818             c->pan_ox = w->sx - *sx;
  819         *ox = c->pan_ox;
  820         if (*sy >= w->sy)
  821             c->pan_oy = 0;
  822         else if (c->pan_oy + *sy > w->sy)
  823             c->pan_oy = w->sy - *sy;
  824         *oy = c->pan_oy;
  825         return (1);
  826     }
  827 
  828     if (~wp->screen->mode & MODE_CURSOR) {
  829         *ox = 0;
  830         *oy = 0;
  831     } else {
  832         cx = wp->xoff + wp->screen->cx;
  833         cy = wp->yoff + wp->screen->cy;
  834 
  835         if (cx < *sx)
  836             *ox = 0;
  837         else if (cx > w->sx - *sx)
  838             *ox = w->sx - *sx;
  839         else
  840             *ox = cx - *sx / 2;
  841 
  842         if (cy < *sy)
  843             *oy = 0;
  844         else if (cy > w->sy - *sy)
  845             *oy = w->sy - *sy;
  846         else
  847             *oy = cy - *sy / 2;
  848     }
  849 
  850     c->pan_window = NULL;
  851     return (1);
  852 }
  853 
  854 /* Update stored offsets for a window and redraw if necessary. */
  855 void
  856 tty_update_window_offset(struct window *w)
  857 {
  858     struct client   *c;
  859 
  860     TAILQ_FOREACH(c, &clients, entry) {
  861         if (c->session != NULL && c->session->curw->window == w)
  862             tty_update_client_offset(c);
  863     }
  864 }
  865 
  866 /* Update stored offsets for a client and redraw if necessary. */
  867 void
  868 tty_update_client_offset(struct client *c)
  869 {
  870     u_int   ox, oy, sx, sy;
  871 
  872     if (~c->flags & CLIENT_TERMINAL)
  873         return;
  874 
  875     c->tty.oflag = tty_window_offset1(&c->tty, &ox, &oy, &sx, &sy);
  876     if (ox == c->tty.oox &&
  877         oy == c->tty.ooy &&
  878         sx == c->tty.osx &&
  879         sy == c->tty.osy)
  880         return;
  881 
  882     log_debug ("%s: %s offset has changed (%u,%u %ux%u -> %u,%u %ux%u)",
  883         __func__, c->name, c->tty.oox, c->tty.ooy, c->tty.osx, c->tty.osy,
  884         ox, oy, sx, sy);
  885 
  886     c->tty.oox = ox;
  887     c->tty.ooy = oy;
  888     c->tty.osx = sx;
  889     c->tty.osy = sy;
  890 
  891     c->flags |= (CLIENT_REDRAWWINDOW|CLIENT_REDRAWSTATUS);
  892 }
  893 
  894 /* Get a palette entry. */
  895 static int
  896 tty_get_palette(int *palette, int c)
  897 {
  898     int new;
  899 
  900     if (palette == NULL)
  901         return (-1);
  902 
  903     new = -1;
  904     if (c < 8)
  905         new = palette[c];
  906     else if (c >= 90 && c <= 97)
  907         new = palette[8 + c - 90];
  908     else if (c & COLOUR_FLAG_256)
  909         new = palette[c & ~COLOUR_FLAG_256];
  910     if (new == 0)
  911         return (-1);
  912     return (new);
  913 }
  914 
  915 /*
  916  * Is the region large enough to be worth redrawing once later rather than
  917  * probably several times now? Currently yes if it is more than 50% of the
  918  * pane.
  919  */
  920 static int
  921 tty_large_region(__unused struct tty *tty, const struct tty_ctx *ctx)
  922 {
  923     return (ctx->orlower - ctx->orupper >= ctx->sy / 2);
  924 }
  925 
  926 /*
  927  * Return if BCE is needed but the terminal doesn't have it - it'll need to be
  928  * emulated.
  929  */
  930 static int
  931 tty_fake_bce(const struct tty *tty, const struct grid_cell *gc, u_int bg)
  932 {
  933     if (tty_term_flag(tty->term, TTYC_BCE))
  934         return (0);
  935     if (!COLOUR_DEFAULT(bg) || !COLOUR_DEFAULT(gc->bg))
  936         return (1);
  937     return (0);
  938 }
  939 
  940 /*
  941  * Redraw scroll region using data from screen (already updated). Used when
  942  * CSR not supported, or window is a pane that doesn't take up the full
  943  * width of the terminal.
  944  */
  945 static void
  946 tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx)
  947 {
  948     struct client       *c = tty->client;
  949     u_int            i;
  950 
  951     /*
  952      * If region is large, schedule a redraw. In most cases this is likely
  953      * to be followed by some more scrolling.
  954      */
  955     if (tty_large_region(tty, ctx)) {
  956         log_debug("%s: %s large redraw", __func__, c->name);
  957         ctx->redraw_cb(ctx);
  958         return;
  959     }
  960 
  961     for (i = ctx->orupper; i <= ctx->orlower; i++)
  962         tty_draw_pane(tty, ctx, i);
  963 }
  964 
  965 /* Is this position visible in the pane? */
  966 static int
  967 tty_is_visible(__unused struct tty *tty, const struct tty_ctx *ctx, u_int px,
  968     u_int py, u_int nx, u_int ny)
  969 {
  970     u_int   xoff = ctx->rxoff + px, yoff = ctx->ryoff + py;
  971 
  972     if (!ctx->bigger)
  973         return (1);
  974 
  975     if (xoff + nx <= ctx->wox || xoff >= ctx->wox + ctx->wsx ||
  976         yoff + ny <= ctx->woy || yoff >= ctx->woy + ctx->wsy)
  977         return (0);
  978     return (1);
  979 }
  980 
  981 /* Clamp line position to visible part of pane. */
  982 static int
  983 tty_clamp_line(struct tty *tty, const struct tty_ctx *ctx, u_int px, u_int py,
  984     u_int nx, u_int *i, u_int *x, u_int *rx, u_int *ry)
  985 {
  986     u_int   xoff = ctx->rxoff + px;
  987 
  988     if (!tty_is_visible(tty, ctx, px, py, nx, 1))
  989         return (0);
  990     *ry = ctx->yoff + py - ctx->woy;
  991 
  992     if (xoff >= ctx->wox && xoff + nx <= ctx->wox + ctx->wsx) {
  993         /* All visible. */
  994         *i = 0;
  995         *x = ctx->xoff + px - ctx->wox;
  996         *rx = nx;
  997     } else if (xoff < ctx->wox && xoff + nx > ctx->wox + ctx->wsx) {
  998         /* Both left and right not visible. */
  999         *i = ctx->wox;
 1000         *x = 0;
 1001         *rx = ctx->wsx;
 1002     } else if (xoff < ctx->wox) {
 1003         /* Left not visible. */
 1004         *i = ctx->wox - (ctx->xoff + px);
 1005         *x = 0;
 1006         *rx = nx - *i;
 1007     } else {
 1008         /* Right not visible. */
 1009         *i = 0;
 1010         *x = (ctx->xoff + px) - ctx->wox;
 1011         *rx = ctx->wsx - *x;
 1012     }
 1013     if (*rx > nx)
 1014         fatalx("%s: x too big, %u > %u", __func__, *rx, nx);
 1015 
 1016     return (1);
 1017 }
 1018 
 1019 /* Clear a line. */
 1020 static void
 1021 tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py,
 1022     u_int px, u_int nx, u_int bg)
 1023 {
 1024     struct client   *c = tty->client;
 1025 
 1026     log_debug("%s: %s, %u at %u,%u", __func__, c->name, nx, px, py);
 1027 
 1028     /* Nothing to clear. */
 1029     if (nx == 0)
 1030         return;
 1031 
 1032     /* If genuine BCE is available, can try escape sequences. */
 1033     if (!tty_fake_bce(tty, defaults, bg)) {
 1034         /* Off the end of the line, use EL if available. */
 1035         if (px + nx >= tty->sx && tty_term_has(tty->term, TTYC_EL)) {
 1036             tty_cursor(tty, px, py);
 1037             tty_putcode(tty, TTYC_EL);
 1038             return;
 1039         }
 1040 
 1041         /* At the start of the line. Use EL1. */
 1042         if (px == 0 && tty_term_has(tty->term, TTYC_EL1)) {
 1043             tty_cursor(tty, px + nx - 1, py);
 1044             tty_putcode(tty, TTYC_EL1);
 1045             return;
 1046         }
 1047 
 1048         /* Section of line. Use ECH if possible. */
 1049         if (tty_term_has(tty->term, TTYC_ECH)) {
 1050             tty_cursor(tty, px, py);
 1051             tty_putcode1(tty, TTYC_ECH, nx);
 1052             return;
 1053         }
 1054     }
 1055 
 1056     /* Couldn't use an escape sequence, use spaces. */
 1057     tty_cursor(tty, px, py);
 1058     tty_repeat_space(tty, nx);
 1059 }
 1060 
 1061 /* Clear a line, adjusting to visible part of pane. */
 1062 static void
 1063 tty_clear_pane_line(struct tty *tty, const struct tty_ctx *ctx, u_int py,
 1064     u_int px, u_int nx, u_int bg)
 1065 {
 1066     struct client   *c = tty->client;
 1067     u_int        i, x, rx, ry;
 1068 
 1069     log_debug("%s: %s, %u at %u,%u", __func__, c->name, nx, px, py);
 1070 
 1071     if (tty_clamp_line(tty, ctx, px, py, nx, &i, &x, &rx, &ry))
 1072         tty_clear_line(tty, &ctx->defaults, ry, x, rx, bg);
 1073 }
 1074 
 1075 /* Clamp area position to visible part of pane. */
 1076 static int
 1077 tty_clamp_area(struct tty *tty, const struct tty_ctx *ctx, u_int px, u_int py,
 1078     u_int nx, u_int ny, u_int *i, u_int *j, u_int *x, u_int *y, u_int *rx,
 1079     u_int *ry)
 1080 {
 1081     u_int   xoff = ctx->rxoff + px, yoff = ctx->ryoff + py;
 1082 
 1083     if (!tty_is_visible(tty, ctx, px, py, nx, ny))
 1084         return (0);
 1085 
 1086     if (xoff >= ctx->wox && xoff + nx <= ctx->wox + ctx->wsx) {
 1087         /* All visible. */
 1088         *i = 0;
 1089         *x = ctx->xoff + px - ctx->wox;
 1090         *rx = nx;
 1091     } else if (xoff < ctx->wox && xoff + nx > ctx->wox + ctx->wsx) {
 1092         /* Both left and right not visible. */
 1093         *i = ctx->wox;
 1094         *x = 0;
 1095         *rx = ctx->wsx;
 1096     } else if (xoff < ctx->wox) {
 1097         /* Left not visible. */
 1098         *i = ctx->wox - (ctx->xoff + px);
 1099         *x = 0;
 1100         *rx = nx - *i;
 1101     } else {
 1102         /* Right not visible. */
 1103         *i = 0;
 1104         *x = (ctx->xoff + px) - ctx->wox;
 1105         *rx = ctx->wsx - *x;
 1106     }
 1107     if (*rx > nx)
 1108         fatalx("%s: x too big, %u > %u", __func__, *rx, nx);
 1109 
 1110     if (yoff >= ctx->woy && yoff + ny <= ctx->woy + ctx->wsy) {
 1111         /* All visible. */
 1112         *j = 0;
 1113         *y = ctx->yoff + py - ctx->woy;
 1114         *ry = ny;
 1115     } else if (yoff < ctx->woy && yoff + ny > ctx->woy + ctx->wsy) {
 1116         /* Both top and bottom not visible. */
 1117         *j = ctx->woy;
 1118         *y = 0;
 1119         *ry = ctx->wsy;
 1120     } else if (yoff < ctx->woy) {
 1121         /* Top not visible. */
 1122         *j = ctx->woy - (ctx->yoff + py);
 1123         *y = 0;
 1124         *ry = ny - *j;
 1125     } else {
 1126         /* Bottom not visible. */
 1127         *j = 0;
 1128         *y = (ctx->yoff + py) - ctx->woy;
 1129         *ry = ctx->wsy - *y;
 1130     }
 1131     if (*ry > ny)
 1132         fatalx("%s: y too big, %u > %u", __func__, *ry, ny);
 1133 
 1134     return (1);
 1135 }
 1136 
 1137 /* Clear an area, adjusting to visible part of pane. */
 1138 static void
 1139 tty_clear_area(struct tty *tty, const struct grid_cell *defaults, u_int py,
 1140     u_int ny, u_int px, u_int nx, u_int bg)
 1141 {
 1142     struct client   *c = tty->client;
 1143     u_int        yy;
 1144     char         tmp[64];
 1145 
 1146     log_debug("%s: %s, %u,%u at %u,%u", __func__, c->name, nx, ny, px, py);
 1147 
 1148     /* Nothing to clear. */
 1149     if (nx == 0 || ny == 0)
 1150         return;
 1151 
 1152     /* If genuine BCE is available, can try escape sequences. */
 1153     if (!tty_fake_bce(tty, defaults, bg)) {
 1154         /* Use ED if clearing off the bottom of the terminal. */
 1155         if (px == 0 &&
 1156             px + nx >= tty->sx &&
 1157             py + ny >= tty->sy &&
 1158             tty_term_has(tty->term, TTYC_ED)) {
 1159             tty_cursor(tty, 0, py);
 1160             tty_putcode(tty, TTYC_ED);
 1161             return;
 1162         }
 1163 
 1164         /*
 1165          * On VT420 compatible terminals we can use DECFRA if the
 1166          * background colour isn't default (because it doesn't work
 1167          * after SGR 0).
 1168          */
 1169         if ((tty->term->flags & TERM_DECFRA) && !COLOUR_DEFAULT(bg)) {
 1170             xsnprintf(tmp, sizeof tmp, "\033[32;%u;%u;%u;%u$x",
 1171                 py + 1, px + 1, py + ny, px + nx);
 1172             tty_puts(tty, tmp);
 1173             return;
 1174         }
 1175 
 1176         /* Full lines can be scrolled away to clear them. */
 1177         if (px == 0 &&
 1178             px + nx >= tty->sx &&
 1179             ny > 2 &&
 1180             tty_term_has(tty->term, TTYC_CSR) &&
 1181             tty_term_has(tty->term, TTYC_INDN)) {
 1182             tty_region(tty, py, py + ny - 1);
 1183             tty_margin_off(tty);
 1184             tty_putcode1(tty, TTYC_INDN, ny);
 1185             return;
 1186         }
 1187 
 1188         /*
 1189          * If margins are supported, can just scroll the area off to
 1190          * clear it.
 1191          */
 1192         if (nx > 2 &&
 1193             ny > 2 &&
 1194             tty_term_has(tty->term, TTYC_CSR) &&
 1195             tty_use_margin(tty) &&
 1196             tty_term_has(tty->term, TTYC_INDN)) {
 1197             tty_region(tty, py, py + ny - 1);
 1198             tty_margin(tty, px, px + nx - 1);
 1199             tty_putcode1(tty, TTYC_INDN, ny);
 1200             return;
 1201         }
 1202     }
 1203 
 1204     /* Couldn't use an escape sequence, loop over the lines. */
 1205     for (yy = py; yy < py + ny; yy++)
 1206         tty_clear_line(tty, defaults, yy, px, nx, bg);
 1207 }
 1208 
 1209 /* Clear an area in a pane. */
 1210 static void
 1211 tty_clear_pane_area(struct tty *tty, const struct tty_ctx *ctx, u_int py,
 1212     u_int ny, u_int px, u_int nx, u_int bg)
 1213 {
 1214     u_int   i, j, x, y, rx, ry;
 1215 
 1216     if (tty_clamp_area(tty, ctx, px, py, nx, ny, &i, &j, &x, &y, &rx, &ry))
 1217         tty_clear_area(tty, &ctx->defaults, y, ry, x, rx, bg);
 1218 }
 1219 
 1220 static void
 1221 tty_draw_pane(struct tty *tty, const struct tty_ctx *ctx, u_int py)
 1222 {
 1223     struct screen   *s = ctx->s;
 1224     u_int        nx = ctx->sx, i, x, rx, ry;
 1225 
 1226     log_debug("%s: %s %u %d", __func__, tty->client->name, py, ctx->bigger);
 1227 
 1228     if (!ctx->bigger) {
 1229         tty_draw_line(tty, s, 0, py, nx, ctx->xoff, ctx->yoff + py,
 1230             &ctx->defaults, ctx->palette);
 1231         return;
 1232     }
 1233     if (tty_clamp_line(tty, ctx, 0, py, nx, &i, &x, &rx, &ry)) {
 1234         tty_draw_line(tty, s, i, py, rx, x, ry, &ctx->defaults,
 1235             ctx->palette);
 1236     }
 1237 }
 1238 
 1239 static const struct grid_cell *
 1240 tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
 1241 {
 1242     static struct grid_cell new;
 1243     int         c;
 1244 
 1245     /* Characters less than 0x7f are always fine, no matter what. */
 1246     if (gc->data.size == 1 && *gc->data.data < 0x7f)
 1247         return (gc);
 1248 
 1249     /* UTF-8 terminal and a UTF-8 character - fine. */
 1250     if (tty->client->flags & CLIENT_UTF8)
 1251         return (gc);
 1252     memcpy(&new, gc, sizeof new);
 1253 
 1254     /* See if this can be mapped to an ACS character. */
 1255     c = tty_acs_reverse_get(tty, gc->data.data, gc->data.size);
 1256     if (c != -1) {
 1257         utf8_set(&new.data, c);
 1258         new.attr |= GRID_ATTR_CHARSET;
 1259         return (&new);
 1260     }
 1261 
 1262     /* Replace by the right number of underscores. */
 1263     new.data.size = gc->data.width;
 1264     if (new.data.size > UTF8_SIZE)
 1265         new.data.size = UTF8_SIZE;
 1266     memset(new.data.data, '_', new.data.size);
 1267     return (&new);
 1268 }
 1269 
 1270 static int
 1271 tty_check_overlay(struct tty *tty, u_int px, u_int py)
 1272 {
 1273     struct client   *c = tty->client;
 1274 
 1275     if (c->overlay_check == NULL)
 1276         return (1);
 1277     return (c->overlay_check(c, px, py));
 1278 }
 1279 
 1280 void
 1281 tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
 1282     u_int atx, u_int aty, const struct grid_cell *defaults, int *palette)
 1283 {
 1284     struct grid     *gd = s->grid;
 1285     struct grid_cell     gc, last;
 1286     const struct grid_cell  *gcp;
 1287     struct grid_line    *gl;
 1288     u_int            i, j, ux, sx, width;
 1289     int          flags, cleared = 0, wrapped = 0;
 1290     char             buf[512];
 1291     size_t           len;
 1292     u_int            cellsize;
 1293 
 1294     log_debug("%s: px=%u py=%u nx=%u atx=%u aty=%u", __func__,
 1295         px, py, nx, atx, aty);
 1296 
 1297     /*
 1298      * py is the line in the screen to draw.
 1299      * px is the start x and nx is the width to draw.
 1300      * atx,aty is the line on the terminal to draw it.
 1301      */
 1302 
 1303     flags = (tty->flags & TTY_NOCURSOR);
 1304     tty->flags |= TTY_NOCURSOR;
 1305     tty_update_mode(tty, tty->mode, s);
 1306 
 1307     tty_region_off(tty);
 1308     tty_margin_off(tty);
 1309 
 1310     /*
 1311      * Clamp the width to cellsize - note this is not cellused, because
 1312      * there may be empty background cells after it (from BCE).
 1313      */
 1314     sx = screen_size_x(s);
 1315     if (nx > sx)
 1316         nx = sx;
 1317     cellsize = grid_get_line(gd, gd->hsize + py)->cellsize;
 1318     if (sx > cellsize)
 1319         sx = cellsize;
 1320     if (sx > tty->sx)
 1321         sx = tty->sx;
 1322     if (sx > nx)
 1323         sx = nx;
 1324     ux = 0;
 1325 
 1326     if (py == 0)
 1327         gl = NULL;
 1328     else
 1329         gl = grid_get_line(gd, gd->hsize + py - 1);
 1330     if (gl == NULL ||
 1331         (~gl->flags & GRID_LINE_WRAPPED) ||
 1332         atx != 0 ||
 1333         tty->cx < tty->sx ||
 1334         nx < tty->sx) {
 1335         if (nx < tty->sx &&
 1336             atx == 0 &&
 1337             px + sx != nx &&
 1338             tty_term_has(tty->term, TTYC_EL1) &&
 1339             !tty_fake_bce(tty, defaults, 8)) {
 1340             tty_default_attributes(tty, defaults, palette, 8);
 1341             tty_cursor(tty, nx - 1, aty);
 1342             tty_putcode(tty, TTYC_EL1);
 1343             cleared = 1;
 1344         }
 1345     } else {
 1346         log_debug("%s: wrapped line %u", __func__, aty);
 1347         wrapped = 1;
 1348     }
 1349 
 1350     memcpy(&last, &grid_default_cell, sizeof last);
 1351     len = 0;
 1352     width = 0;
 1353 
 1354     for (i = 0; i < sx; i++) {
 1355         grid_view_get_cell(gd, px + i, py, &gc);
 1356         gcp = tty_check_codeset(tty, &gc);
 1357         if (len != 0 &&
 1358             (!tty_check_overlay(tty, atx + ux + width, aty) ||
 1359             (gcp->attr & GRID_ATTR_CHARSET) ||
 1360             gcp->flags != last.flags ||
 1361             gcp->attr != last.attr ||
 1362             gcp->fg != last.fg ||
 1363             gcp->bg != last.bg ||
 1364             gcp->us != last.us ||
 1365             ux + width + gcp->data.width > nx ||
 1366             (sizeof buf) - len < gcp->data.size)) {
 1367             tty_attributes(tty, &last, defaults, palette);
 1368             if (last.flags & GRID_FLAG_CLEARED) {
 1369                 log_debug("%s: %zu cleared", __func__, len);
 1370                 tty_clear_line(tty, defaults, aty, atx + ux,
 1371                     width, last.bg);
 1372             } else {
 1373                 if (!wrapped || atx != 0 || ux != 0)
 1374                     tty_cursor(tty, atx + ux, aty);
 1375                 tty_putn(tty, buf, len, width);
 1376             }
 1377             ux += width;
 1378 
 1379             len = 0;
 1380             width = 0;
 1381             wrapped = 0;
 1382         }
 1383 
 1384         if (gcp->flags & GRID_FLAG_SELECTED)
 1385             screen_select_cell(s, &last, gcp);
 1386         else
 1387             memcpy(&last, gcp, sizeof last);
 1388         if (!tty_check_overlay(tty, atx + ux, aty)) {
 1389             if (~gcp->flags & GRID_FLAG_PADDING)
 1390                 ux += gcp->data.width;
 1391         } else if (ux + gcp->data.width > nx) {
 1392             tty_attributes(tty, &last, defaults, palette);
 1393             tty_cursor(tty, atx + ux, aty);
 1394             for (j = 0; j < gcp->data.width; j++) {
 1395                 if (ux + j > nx)
 1396                     break;
 1397                 tty_putc(tty, ' ');
 1398                 ux++;
 1399             }
 1400         } else if (gcp->attr & GRID_ATTR_CHARSET) {
 1401             tty_attributes(tty, &last, defaults, palette);
 1402             tty_cursor(tty, atx + ux, aty);
 1403             for (j = 0; j < gcp->data.size; j++)
 1404                 tty_putc(tty, gcp->data.data[j]);
 1405             ux += gcp->data.width;
 1406         } else if (~gcp->flags & GRID_FLAG_PADDING) {
 1407             memcpy(buf + len, gcp->data.data, gcp->data.size);
 1408             len += gcp->data.size;
 1409             width += gcp->data.width;
 1410         }
 1411     }
 1412     if (len != 0 && ((~last.flags & GRID_FLAG_CLEARED) || last.bg != 8)) {
 1413         tty_attributes(tty, &last, defaults, palette);
 1414         if (last.flags & GRID_FLAG_CLEARED) {
 1415             log_debug("%s: %zu cleared (end)", __func__, len);
 1416             tty_clear_line(tty, defaults, aty, atx + ux, width,
 1417                 last.bg);
 1418         } else {
 1419             if (!wrapped || atx != 0 || ux != 0)
 1420                 tty_cursor(tty, atx + ux, aty);
 1421             tty_putn(tty, buf, len, width);
 1422         }
 1423         ux += width;
 1424     }
 1425 
 1426     if (!cleared && ux < nx) {
 1427         log_debug("%s: %u to end of line (%zu cleared)", __func__,
 1428             nx - ux, len);
 1429         tty_default_attributes(tty, defaults, palette, 8);
 1430         tty_clear_line(tty, defaults, aty, atx + ux, nx - ux, 8);
 1431     }
 1432 
 1433     tty->flags = (tty->flags & ~TTY_NOCURSOR) | flags;
 1434     tty_update_mode(tty, tty->mode, s);
 1435 }
 1436 
 1437 void
 1438 tty_sync_start(struct tty *tty)
 1439 {
 1440     if (tty->flags & TTY_BLOCK)
 1441         return;
 1442     if (tty->flags & TTY_SYNCING)
 1443         return;
 1444     tty->flags |= TTY_SYNCING;
 1445 
 1446     if (tty_term_has(tty->term, TTYC_SYNC)) {
 1447         log_debug("%s sync start", tty->client->name);
 1448         tty_putcode1(tty, TTYC_SYNC, 1);
 1449     }
 1450 }
 1451 
 1452 void
 1453 tty_sync_end(struct tty *tty)
 1454 {
 1455     if (tty->flags & TTY_BLOCK)
 1456         return;
 1457     if (~tty->flags & TTY_SYNCING)
 1458         return;
 1459     tty->flags &= ~TTY_SYNCING;
 1460 
 1461     if (tty_term_has(tty->term, TTYC_SYNC)) {
 1462         log_debug("%s sync end", tty->client->name);
 1463         tty_putcode1(tty, TTYC_SYNC, 2);
 1464     }
 1465 }
 1466 
 1467 static int
 1468 tty_client_ready(struct client *c)
 1469 {
 1470     if (c->session == NULL || c->tty.term == NULL)
 1471         return (0);
 1472     if (c->flags & (CLIENT_REDRAWWINDOW|CLIENT_SUSPENDED))
 1473         return (0);
 1474     if (c->tty.flags & TTY_FREEZE)
 1475         return (0);
 1476     return (1);
 1477 }
 1478 
 1479 void
 1480 tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *),
 1481     struct tty_ctx *ctx)
 1482 {
 1483     struct client   *c;
 1484     int      state;
 1485 
 1486     if (ctx->set_client_cb == NULL)
 1487         return;
 1488     TAILQ_FOREACH(c, &clients, entry) {
 1489         if (!tty_client_ready(c))
 1490             continue;
 1491         state = ctx->set_client_cb(ctx, c);
 1492         if (state == -1)
 1493             break;
 1494         if (state == 0)
 1495             continue;
 1496         cmdfn(&c->tty, ctx);
 1497     }
 1498 }
 1499 
 1500 void
 1501 tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx)
 1502 {
 1503     if (ctx->bigger ||
 1504         !tty_full_width(tty, ctx) ||
 1505         tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
 1506         (!tty_term_has(tty->term, TTYC_ICH) &&
 1507         !tty_term_has(tty->term, TTYC_ICH1))) {
 1508         tty_draw_pane(tty, ctx, ctx->ocy);
 1509         return;
 1510     }
 1511 
 1512     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1513 
 1514     tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
 1515 
 1516     tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num);
 1517 }
 1518 
 1519 void
 1520 tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx)
 1521 {
 1522     if (ctx->bigger ||
 1523         !tty_full_width(tty, ctx) ||
 1524         tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
 1525         (!tty_term_has(tty->term, TTYC_DCH) &&
 1526         !tty_term_has(tty->term, TTYC_DCH1))) {
 1527         tty_draw_pane(tty, ctx, ctx->ocy);
 1528         return;
 1529     }
 1530 
 1531     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1532 
 1533     tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
 1534 
 1535     tty_emulate_repeat(tty, TTYC_DCH, TTYC_DCH1, ctx->num);
 1536 }
 1537 
 1538 void
 1539 tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx)
 1540 {
 1541     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1542 
 1543     tty_clear_pane_line(tty, ctx, ctx->ocy, ctx->ocx, ctx->num, ctx->bg);
 1544 }
 1545 
 1546 void
 1547 tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx)
 1548 {
 1549     if (ctx->bigger ||
 1550         !tty_full_width(tty, ctx) ||
 1551         tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
 1552         !tty_term_has(tty->term, TTYC_CSR) ||
 1553         !tty_term_has(tty->term, TTYC_IL1) ||
 1554         ctx->sx == 1 ||
 1555         ctx->sy == 1) {
 1556         tty_redraw_region(tty, ctx);
 1557         return;
 1558     }
 1559 
 1560     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1561 
 1562     tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
 1563     tty_margin_off(tty);
 1564     tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
 1565 
 1566     tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ctx->num);
 1567     tty->cx = tty->cy = UINT_MAX;
 1568 }
 1569 
 1570 void
 1571 tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx)
 1572 {
 1573     if (ctx->bigger ||
 1574         !tty_full_width(tty, ctx) ||
 1575         tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
 1576         !tty_term_has(tty->term, TTYC_CSR) ||
 1577         !tty_term_has(tty->term, TTYC_DL1) ||
 1578         ctx->sx == 1 ||
 1579         ctx->sy == 1) {
 1580         tty_redraw_region(tty, ctx);
 1581         return;
 1582     }
 1583 
 1584     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1585 
 1586     tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
 1587     tty_margin_off(tty);
 1588     tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
 1589 
 1590     tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ctx->num);
 1591     tty->cx = tty->cy = UINT_MAX;
 1592 }
 1593 
 1594 void
 1595 tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx)
 1596 {
 1597     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1598 
 1599     tty_clear_pane_line(tty, ctx, ctx->ocy, 0, ctx->sx, ctx->bg);
 1600 }
 1601 
 1602 void
 1603 tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx)
 1604 {
 1605     u_int   nx = ctx->sx - ctx->ocx;
 1606 
 1607     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1608 
 1609     tty_clear_pane_line(tty, ctx, ctx->ocy, ctx->ocx, nx, ctx->bg);
 1610 }
 1611 
 1612 void
 1613 tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx)
 1614 {
 1615     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1616 
 1617     tty_clear_pane_line(tty, ctx, ctx->ocy, 0, ctx->ocx + 1, ctx->bg);
 1618 }
 1619 
 1620 void
 1621 tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx)
 1622 {
 1623     if (ctx->ocy != ctx->orupper)
 1624         return;
 1625 
 1626     if (ctx->bigger ||
 1627         (!tty_full_width(tty, ctx) && !tty_use_margin(tty)) ||
 1628         tty_fake_bce(tty, &ctx->defaults, 8) ||
 1629         !tty_term_has(tty->term, TTYC_CSR) ||
 1630         (!tty_term_has(tty->term, TTYC_RI) &&
 1631         !tty_term_has(tty->term, TTYC_RIN)) ||
 1632         ctx->sx == 1 ||
 1633         ctx->sy == 1) {
 1634         tty_redraw_region(tty, ctx);
 1635         return;
 1636     }
 1637 
 1638     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1639 
 1640     tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
 1641     tty_margin_pane(tty, ctx);
 1642     tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper);
 1643 
 1644     if (tty_term_has(tty->term, TTYC_RI))
 1645         tty_putcode(tty, TTYC_RI);
 1646     else
 1647         tty_putcode1(tty, TTYC_RIN, 1);
 1648 }
 1649 
 1650 void
 1651 tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
 1652 {
 1653     if (ctx->ocy != ctx->orlower)
 1654         return;
 1655 
 1656     if (ctx->bigger ||
 1657         (!tty_full_width(tty, ctx) && !tty_use_margin(tty)) ||
 1658         tty_fake_bce(tty, &ctx->defaults, 8) ||
 1659         !tty_term_has(tty->term, TTYC_CSR) ||
 1660         ctx->sx == 1 ||
 1661         ctx->sy == 1) {
 1662         tty_redraw_region(tty, ctx);
 1663         return;
 1664     }
 1665 
 1666     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1667 
 1668     tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
 1669     tty_margin_pane(tty, ctx);
 1670 
 1671     /*
 1672      * If we want to wrap a pane while using margins, the cursor needs to
 1673      * be exactly on the right of the region. If the cursor is entirely off
 1674      * the edge - move it back to the right. Some terminals are funny about
 1675      * this and insert extra spaces, so only use the right if margins are
 1676      * enabled.
 1677      */
 1678     if (ctx->xoff + ctx->ocx > tty->rright) {
 1679         if (!tty_use_margin(tty))
 1680             tty_cursor(tty, 0, ctx->yoff + ctx->ocy);
 1681         else
 1682             tty_cursor(tty, tty->rright, ctx->yoff + ctx->ocy);
 1683     } else
 1684         tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
 1685 
 1686     tty_putc(tty, '\n');
 1687 }
 1688 
 1689 void
 1690 tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx)
 1691 {
 1692     u_int   i;
 1693 
 1694     if (ctx->bigger ||
 1695         (!tty_full_width(tty, ctx) && !tty_use_margin(tty)) ||
 1696         tty_fake_bce(tty, &ctx->defaults, 8) ||
 1697         !tty_term_has(tty->term, TTYC_CSR) ||
 1698         ctx->sx == 1 ||
 1699         ctx->sy == 1) {
 1700         tty_redraw_region(tty, ctx);
 1701         return;
 1702     }
 1703 
 1704     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1705 
 1706     tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
 1707     tty_margin_pane(tty, ctx);
 1708 
 1709     if (ctx->num == 1 || !tty_term_has(tty->term, TTYC_INDN)) {
 1710         if (!tty_use_margin(tty))
 1711             tty_cursor(tty, 0, tty->rlower);
 1712         else
 1713             tty_cursor(tty, tty->rright, tty->rlower);
 1714         for (i = 0; i < ctx->num; i++)
 1715             tty_putc(tty, '\n');
 1716     } else {
 1717         if (tty->cy == UINT_MAX)
 1718             tty_cursor(tty, 0, 0);
 1719         else
 1720             tty_cursor(tty, 0, tty->cy);
 1721         tty_putcode1(tty, TTYC_INDN, ctx->num);
 1722     }
 1723 }
 1724 
 1725 void
 1726 tty_cmd_scrolldown(struct tty *tty, const struct tty_ctx *ctx)
 1727 {
 1728     u_int   i;
 1729 
 1730     if (ctx->bigger ||
 1731         (!tty_full_width(tty, ctx) && !tty_use_margin(tty)) ||
 1732         tty_fake_bce(tty, &ctx->defaults, 8) ||
 1733         !tty_term_has(tty->term, TTYC_CSR) ||
 1734         (!tty_term_has(tty->term, TTYC_RI) &&
 1735         !tty_term_has(tty->term, TTYC_RIN)) ||
 1736         ctx->sx == 1 ||
 1737         ctx->sy == 1) {
 1738         tty_redraw_region(tty, ctx);
 1739         return;
 1740     }
 1741 
 1742     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1743 
 1744     tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
 1745     tty_margin_pane(tty, ctx);
 1746     tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper);
 1747 
 1748     if (tty_term_has(tty->term, TTYC_RIN))
 1749         tty_putcode1(tty, TTYC_RIN, ctx->num);
 1750     else {
 1751         for (i = 0; i < ctx->num; i++)
 1752             tty_putcode(tty, TTYC_RI);
 1753     }
 1754 }
 1755 
 1756 void
 1757 tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx)
 1758 {
 1759     u_int   px, py, nx, ny;
 1760 
 1761     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1762 
 1763     tty_region_pane(tty, ctx, 0, ctx->sy - 1);
 1764     tty_margin_off(tty);
 1765 
 1766     px = 0;
 1767     nx = ctx->sx;
 1768     py = ctx->ocy + 1;
 1769     ny = ctx->sy - ctx->ocy - 1;
 1770 
 1771     tty_clear_pane_area(tty, ctx, py, ny, px, nx, ctx->bg);
 1772 
 1773     px = ctx->ocx;
 1774     nx = ctx->sx - ctx->ocx;
 1775     py = ctx->ocy;
 1776 
 1777     tty_clear_pane_line(tty, ctx, py, px, nx, ctx->bg);
 1778 }
 1779 
 1780 void
 1781 tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx)
 1782 {
 1783     u_int   px, py, nx, ny;
 1784 
 1785     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1786 
 1787     tty_region_pane(tty, ctx, 0, ctx->sy - 1);
 1788     tty_margin_off(tty);
 1789 
 1790     px = 0;
 1791     nx = ctx->sx;
 1792     py = 0;
 1793     ny = ctx->ocy;
 1794 
 1795     tty_clear_pane_area(tty, ctx, py, ny, px, nx, ctx->bg);
 1796 
 1797     px = 0;
 1798     nx = ctx->ocx + 1;
 1799     py = ctx->ocy;
 1800 
 1801     tty_clear_pane_line(tty, ctx, py, px, nx, ctx->bg);
 1802 }
 1803 
 1804 void
 1805 tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx)
 1806 {
 1807     u_int   px, py, nx, ny;
 1808 
 1809     tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg);
 1810 
 1811     tty_region_pane(tty, ctx, 0, ctx->sy - 1);
 1812     tty_margin_off(tty);
 1813 
 1814     px = 0;
 1815     nx = ctx->sx;
 1816     py = 0;
 1817     ny = ctx->sy;
 1818 
 1819     tty_clear_pane_area(tty, ctx, py, ny, px, nx, ctx->bg);
 1820 }
 1821 
 1822 void
 1823 tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx)
 1824 {
 1825     u_int   i, j;
 1826 
 1827     if (ctx->bigger) {
 1828         ctx->redraw_cb(ctx);
 1829         return;
 1830     }
 1831 
 1832     tty_attributes(tty, &grid_default_cell, &ctx->defaults, ctx->palette);
 1833 
 1834     tty_region_pane(tty, ctx, 0, ctx->sy - 1);
 1835     tty_margin_off(tty);
 1836 
 1837     for (j = 0; j < ctx->sy; j++) {
 1838         tty_cursor_pane(tty, ctx, 0, j);
 1839         for (i = 0; i < ctx->sx; i++)
 1840             tty_putc(tty, 'E');
 1841     }
 1842 }
 1843 
 1844 void
 1845 tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
 1846 {
 1847     if (!tty_is_visible(tty, ctx, ctx->ocx, ctx->ocy, 1, 1))
 1848         return;
 1849 
 1850     if (ctx->xoff + ctx->ocx - ctx->wox > tty->sx - 1 &&
 1851         ctx->ocy == ctx->orlower &&
 1852         tty_full_width(tty, ctx))
 1853         tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
 1854 
 1855     tty_margin_off(tty);
 1856     tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy);
 1857 
 1858     tty_cell(tty, ctx->cell, &ctx->defaults, ctx->palette);
 1859 }
 1860 
 1861 void
 1862 tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
 1863 {
 1864     if (!tty_is_visible(tty, ctx, ctx->ocx, ctx->ocy, ctx->num, 1))
 1865         return;
 1866 
 1867     if (ctx->bigger &&
 1868         (ctx->xoff + ctx->ocx < ctx->wox ||
 1869         ctx->xoff + ctx->ocx + ctx->num > ctx->wox + ctx->wsx)) {
 1870         if (!ctx->wrapped ||
 1871             !tty_full_width(tty, ctx) ||
 1872             (tty->term->flags & TERM_NOAM) ||
 1873             ctx->xoff + ctx->ocx != 0 ||
 1874             ctx->yoff + ctx->ocy != tty->cy + 1 ||
 1875             tty->cx < tty->sx ||
 1876             tty->cy == tty->rlower)
 1877             tty_draw_pane(tty, ctx, ctx->ocy);
 1878         else
 1879             ctx->redraw_cb(ctx);
 1880         return;
 1881     }
 1882 
 1883     tty_margin_off(tty);
 1884     tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy);
 1885 
 1886     tty_attributes(tty, ctx->cell, &ctx->defaults, ctx->palette);
 1887     tty_putn(tty, ctx->ptr, ctx->num, ctx->num);
 1888 }
 1889 
 1890 void
 1891 tty_cmd_setselection(struct tty *tty, const struct tty_ctx *ctx)
 1892 {
 1893     tty_set_selection(tty, ctx->ptr, ctx->num);
 1894 }
 1895 
 1896 void
 1897 tty_set_selection(struct tty *tty, const char *buf, size_t len)
 1898 {
 1899     char    *encoded;
 1900     size_t   size;
 1901 
 1902     if (~tty->flags & TTY_STARTED)
 1903         return;
 1904     if (!tty_term_has(tty->term, TTYC_MS))
 1905         return;
 1906 
 1907     size = 4 * ((len + 2) / 3) + 1; /* storage for base64 */
 1908     encoded = xmalloc(size);
 1909 
 1910     b64_ntop(buf, len, encoded, size);
 1911     tty_putcode_ptr2(tty, TTYC_MS, "", encoded);
 1912 
 1913     free(encoded);
 1914 }
 1915 
 1916 void
 1917 tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx)
 1918 {
 1919     tty_add(tty, ctx->ptr, ctx->num);
 1920     tty_invalidate(tty);
 1921 }
 1922 
 1923 void
 1924 tty_cmd_syncstart(struct tty *tty, __unused const struct tty_ctx *ctx)
 1925 {
 1926     tty_sync_start(tty);
 1927 }
 1928 
 1929 void
 1930 tty_cell(struct tty *tty, const struct grid_cell *gc,
 1931     const struct grid_cell *defaults, int *palette)
 1932 {
 1933     const struct grid_cell  *gcp;
 1934 
 1935     /* Skip last character if terminal is stupid. */
 1936     if ((tty->term->flags & TERM_NOAM) &&
 1937         tty->cy == tty->sy - 1 &&
 1938         tty->cx == tty->sx - 1)
 1939         return;
 1940 
 1941     /* If this is a padding character, do nothing. */
 1942     if (gc->flags & GRID_FLAG_PADDING)
 1943         return;
 1944 
 1945     /* Check the output codeset and apply attributes. */
 1946     gcp = tty_check_codeset(tty, gc);
 1947     tty_attributes(tty, gcp, defaults, palette);
 1948 
 1949     /* If it is a single character, write with putc to handle ACS. */
 1950     if (gcp->data.size == 1) {
 1951         tty_attributes(tty, gcp, defaults, palette);
 1952         if (*gcp->data.data < 0x20 || *gcp->data.data == 0x7f)
 1953             return;
 1954         tty_putc(tty, *gcp->data.data);
 1955         return;
 1956     }
 1957 
 1958     /* Write the data. */
 1959     tty_putn(tty, gcp->data.data, gcp->data.size, gcp->data.width);
 1960 }
 1961 
 1962 void
 1963 tty_reset(struct tty *tty)
 1964 {
 1965     struct grid_cell    *gc = &tty->cell;
 1966 
 1967     if (!grid_cells_equal(gc, &grid_default_cell)) {
 1968         if ((gc->attr & GRID_ATTR_CHARSET) && tty_acs_needed(tty))
 1969             tty_putcode(tty, TTYC_RMACS);
 1970         tty_putcode(tty, TTYC_SGR0);
 1971         memcpy(gc, &grid_default_cell, sizeof *gc);
 1972     }
 1973     memcpy(&tty->last_cell, &grid_default_cell, sizeof tty->last_cell);
 1974 }
 1975 
 1976 static void
 1977 tty_invalidate(struct tty *tty)
 1978 {
 1979     memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell);
 1980     memcpy(&tty->last_cell, &grid_default_cell, sizeof tty->last_cell);
 1981 
 1982     tty->cx = tty->cy = UINT_MAX;
 1983     tty->rupper = tty->rleft = UINT_MAX;
 1984     tty->rlower = tty->rright = UINT_MAX;
 1985 
 1986     if (tty->flags & TTY_STARTED) {
 1987         if (tty_use_margin(tty))
 1988             tty_putcode(tty, TTYC_ENMG);
 1989         tty_putcode(tty, TTYC_SGR0);
 1990 
 1991         tty->mode = ALL_MODES;
 1992         tty_update_mode(tty, MODE_CURSOR, NULL);
 1993 
 1994         tty_cursor(tty, 0, 0);
 1995         tty_region_off(tty);
 1996         tty_margin_off(tty);
 1997     } else
 1998         tty->mode = MODE_CURSOR;
 1999 }
 2000 
 2001 /* Turn off margin. */
 2002 void
 2003 tty_region_off(struct tty *tty)
 2004 {
 2005     tty_region(tty, 0, tty->sy - 1);
 2006 }
 2007 
 2008 /* Set region inside pane. */
 2009 static void
 2010 tty_region_pane(struct tty *tty, const struct tty_ctx *ctx, u_int rupper,
 2011     u_int rlower)
 2012 {
 2013     tty_region(tty, ctx->yoff + rupper - ctx->woy,
 2014         ctx->yoff + rlower - ctx->woy);
 2015 }
 2016 
 2017 /* Set region at absolute position. */
 2018 static void
 2019 tty_region(struct tty *tty, u_int rupper, u_int rlower)
 2020 {
 2021     if (tty->rlower == rlower && tty->rupper == rupper)
 2022         return;
 2023     if (!tty_term_has(tty->term, TTYC_CSR))
 2024         return;
 2025 
 2026     tty->rupper = rupper;
 2027     tty->rlower = rlower;
 2028 
 2029     /*
 2030      * Some terminals (such as PuTTY) do not correctly reset the cursor to
 2031      * 0,0 if it is beyond the last column (they do not reset their wrap
 2032      * flag so further output causes a line feed). As a workaround, do an
 2033      * explicit move to 0 first.
 2034      */
 2035     if (tty->cx >= tty->sx) {
 2036         if (tty->cy == UINT_MAX)
 2037             tty_cursor(tty, 0, 0);
 2038         else
 2039             tty_cursor(tty, 0, tty->cy);
 2040     }
 2041 
 2042     tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower);
 2043     tty->cx = tty->cy = UINT_MAX;
 2044 }
 2045 
 2046 /* Turn off margin. */
 2047 void
 2048 tty_margin_off(struct tty *tty)
 2049 {
 2050     tty_margin(tty, 0, tty->sx - 1);
 2051 }
 2052 
 2053 /* Set margin inside pane. */
 2054 static void
 2055 tty_margin_pane(struct tty *tty, const struct tty_ctx *ctx)
 2056 {
 2057     tty_margin(tty, ctx->xoff - ctx->wox,
 2058         ctx->xoff + ctx->sx - 1 - ctx->wox);
 2059 }
 2060 
 2061 /* Set margin at absolute position. */
 2062 static void
 2063 tty_margin(struct tty *tty, u_int rleft, u_int rright)
 2064 {
 2065     if (!tty_use_margin(tty))
 2066         return;
 2067     if (tty->rleft == rleft && tty->rright == rright)
 2068         return;
 2069 
 2070     tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower);
 2071 
 2072     tty->rleft = rleft;
 2073     tty->rright = rright;
 2074 
 2075     if (rleft == 0 && rright == tty->sx - 1)
 2076         tty_putcode(tty, TTYC_CLMG);
 2077     else
 2078         tty_putcode2(tty, TTYC_CMG, rleft, rright);
 2079     tty->cx = tty->cy = UINT_MAX;
 2080 }
 2081 
 2082 /*
 2083  * Move the cursor, unless it would wrap itself when the next character is
 2084  * printed.
 2085  */
 2086 static void
 2087 tty_cursor_pane_unless_wrap(struct tty *tty, const struct tty_ctx *ctx,
 2088     u_int cx, u_int cy)
 2089 {
 2090     if (!ctx->wrapped ||
 2091         !tty_full_width(tty, ctx) ||
 2092         (tty->term->flags & TERM_NOAM) ||
 2093         ctx->xoff + cx != 0 ||
 2094         ctx->yoff + cy != tty->cy + 1 ||
 2095         tty->cx < tty->sx ||
 2096         tty->cy == tty->rlower)
 2097         tty_cursor_pane(tty, ctx, cx, cy);
 2098     else
 2099         log_debug("%s: will wrap at %u,%u", __func__, tty->cx, tty->cy);
 2100 }
 2101 
 2102 /* Move cursor inside pane. */
 2103 static void
 2104 tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy)
 2105 {
 2106     tty_cursor(tty, ctx->xoff + cx - ctx->wox, ctx->yoff + cy - ctx->woy);
 2107 }
 2108 
 2109 /* Move cursor to absolute position. */
 2110 void
 2111 tty_cursor(struct tty *tty, u_int cx, u_int cy)
 2112 {
 2113     struct tty_term *term = tty->term;
 2114     u_int        thisx, thisy;
 2115     int      change;
 2116 
 2117     if (tty->flags & TTY_BLOCK)
 2118         return;
 2119 
 2120     if (cx > tty->sx - 1)
 2121         cx = tty->sx - 1;
 2122 
 2123     thisx = tty->cx;
 2124     thisy = tty->cy;
 2125 
 2126     /* No change. */
 2127     if (cx == thisx && cy == thisy)
 2128         return;
 2129 
 2130     /* Very end of the line, just use absolute movement. */
 2131     if (thisx > tty->sx - 1)
 2132         goto absolute;
 2133 
 2134     /* Move to home position (0, 0). */
 2135     if (cx == 0 && cy == 0 && tty_term_has(term, TTYC_HOME)) {
 2136         tty_putcode(tty, TTYC_HOME);
 2137         goto out;
 2138     }
 2139 
 2140     /* Zero on the next line. */
 2141     if (cx == 0 && cy == thisy + 1 && thisy != tty->rlower &&
 2142         (!tty_use_margin(tty) || tty->rleft == 0)) {
 2143         tty_putc(tty, '\r');
 2144         tty_putc(tty, '\n');
 2145         goto out;
 2146     }
 2147 
 2148     /* Moving column or row. */
 2149     if (cy == thisy) {
 2150         /*
 2151          * Moving column only, row staying the same.
 2152          */
 2153 
 2154         /* To left edge. */
 2155         if (cx == 0 && (!tty_use_margin(tty) || tty->rleft == 0)) {
 2156             tty_putc(tty, '\r');
 2157             goto out;
 2158         }
 2159 
 2160         /* One to the left. */
 2161         if (cx == thisx - 1 && tty_term_has(term, TTYC_CUB1)) {
 2162             tty_putcode(tty, TTYC_CUB1);
 2163             goto out;
 2164         }
 2165 
 2166         /* One to the right. */
 2167         if (cx == thisx + 1 && tty_term_has(term, TTYC_CUF1)) {
 2168             tty_putcode(tty, TTYC_CUF1);
 2169             goto out;
 2170         }
 2171 
 2172         /* Calculate difference. */
 2173         change = thisx - cx;    /* +ve left, -ve right */
 2174 
 2175         /*
 2176          * Use HPA if change is larger than absolute, otherwise move
 2177          * the cursor with CUB/CUF.
 2178          */
 2179         if ((u_int) abs(change) > cx && tty_term_has(term, TTYC_HPA)) {
 2180             tty_putcode1(tty, TTYC_HPA, cx);
 2181             goto out;
 2182         } else if (change > 0 &&
 2183             tty_term_has(term, TTYC_CUB) &&
 2184             !tty_use_margin(tty)) {
 2185             if (change == 2 && tty_term_has(term, TTYC_CUB1)) {
 2186                 tty_putcode(tty, TTYC_CUB1);
 2187                 tty_putcode(tty, TTYC_CUB1);
 2188                 goto out;
 2189             }
 2190             tty_putcode1(tty, TTYC_CUB, change);
 2191             goto out;
 2192         } else if (change < 0 &&
 2193             tty_term_has(term, TTYC_CUF) &&
 2194             !tty_use_margin(tty)) {
 2195             tty_putcode1(tty, TTYC_CUF, -change);
 2196             goto out;
 2197         }
 2198     } else if (cx == thisx) {
 2199         /*
 2200          * Moving row only, column staying the same.
 2201          */
 2202 
 2203         /* One above. */
 2204         if (thisy != tty->rupper &&
 2205             cy == thisy - 1 && tty_term_has(term, TTYC_CUU1)) {
 2206             tty_putcode(tty, TTYC_CUU1);
 2207             goto out;
 2208         }
 2209 
 2210         /* One below. */
 2211         if (thisy != tty->rlower &&
 2212             cy == thisy + 1 && tty_term_has(term, TTYC_CUD1)) {
 2213             tty_putcode(tty, TTYC_CUD1);
 2214             goto out;
 2215         }
 2216 
 2217         /* Calculate difference. */
 2218         change = thisy - cy;    /* +ve up, -ve down */
 2219 
 2220         /*
 2221          * Try to use VPA if change is larger than absolute or if this
 2222          * change would cross the scroll region, otherwise use CUU/CUD.
 2223          */
 2224         if ((u_int) abs(change) > cy ||
 2225             (change < 0 && cy - change > tty->rlower) ||
 2226             (change > 0 && cy - change < tty->rupper)) {
 2227                 if (tty_term_has(term, TTYC_VPA)) {
 2228                     tty_putcode1(tty, TTYC_VPA, cy);
 2229                     goto out;
 2230                 }
 2231         } else if (change > 0 && tty_term_has(term, TTYC_CUU)) {
 2232             tty_putcode1(tty, TTYC_CUU, change);
 2233             goto out;
 2234         } else if (change < 0 && tty_term_has(term, TTYC_CUD)) {
 2235             tty_putcode1(tty, TTYC_CUD, -change);
 2236             goto out;
 2237         }
 2238     }
 2239 
 2240 absolute:
 2241     /* Absolute movement. */
 2242     tty_putcode2(tty, TTYC_CUP, cy, cx);
 2243 
 2244 out:
 2245     tty->cx = cx;
 2246     tty->cy = cy;
 2247 }
 2248 
 2249 void
 2250 tty_attributes(struct tty *tty, const struct grid_cell *gc,
 2251     const struct grid_cell *defaults, int *palette)
 2252 {
 2253     struct grid_cell    *tc = &tty->cell, gc2;
 2254     int          changed;
 2255 
 2256     /* Copy cell and update default colours. */
 2257     memcpy(&gc2, gc, sizeof gc2);
 2258     if (gc2.fg == 8)
 2259         gc2.fg = defaults->fg;
 2260     if (gc2.bg == 8)
 2261         gc2.bg = defaults->bg;
 2262 
 2263     /* Ignore cell if it is the same as the last one. */
 2264     if (gc2.attr == tty->last_cell.attr &&
 2265         gc2.fg == tty->last_cell.fg &&
 2266         gc2.bg == tty->last_cell.bg &&
 2267         gc2.us == tty->last_cell.us)
 2268         return;
 2269 
 2270     /*
 2271      * If no setab, try to use the reverse attribute as a best-effort for a
 2272      * non-default background. This is a bit of a hack but it doesn't do
 2273      * any serious harm and makes a couple of applications happier.
 2274      */
 2275     if (!tty_term_has(tty->term, TTYC_SETAB)) {
 2276         if (gc2.attr & GRID_ATTR_REVERSE) {
 2277             if (gc2.fg != 7 && !COLOUR_DEFAULT(gc2.fg))
 2278                 gc2.attr &= ~GRID_ATTR_REVERSE;
 2279         } else {
 2280             if (gc2.bg != 0 && !COLOUR_DEFAULT(gc2.bg))
 2281                 gc2.attr |= GRID_ATTR_REVERSE;
 2282         }
 2283     }
 2284 
 2285     /* Fix up the colours if necessary. */
 2286     tty_check_fg(tty, palette, &gc2);
 2287     tty_check_bg(tty, palette, &gc2);
 2288     tty_check_us(tty, palette, &gc2);
 2289 
 2290     /*
 2291      * If any bits are being cleared or the underline colour is now default,
 2292      * reset everything.
 2293      */
 2294     if ((tc->attr & ~gc2.attr) || (tc->us != gc2.us && gc2.us == 0))
 2295         tty_reset(tty);
 2296 
 2297     /*
 2298      * Set the colours. This may call tty_reset() (so it comes next) and
 2299      * may add to (NOT remove) the desired attributes.
 2300      */
 2301     tty_colours(tty, &gc2);
 2302 
 2303     /* Filter out attribute bits already set. */
 2304     changed = gc2.attr & ~tc->attr;
 2305     tc->attr = gc2.attr;
 2306 
 2307     /* Set the attributes. */
 2308     if (changed & GRID_ATTR_BRIGHT)
 2309         tty_putcode(tty, TTYC_BOLD);
 2310     if (changed & GRID_ATTR_DIM)
 2311         tty_putcode(tty, TTYC_DIM);
 2312     if (changed & GRID_ATTR_ITALICS)
 2313         tty_set_italics(tty);
 2314     if (changed & GRID_ATTR_ALL_UNDERSCORE) {
 2315         if ((changed & GRID_ATTR_UNDERSCORE) ||
 2316             !tty_term_has(tty->term, TTYC_SMULX))
 2317             tty_putcode(tty, TTYC_SMUL);
 2318         else if (changed & GRID_ATTR_UNDERSCORE_2)
 2319             tty_putcode1(tty, TTYC_SMULX, 2);
 2320         else if (changed & GRID_ATTR_UNDERSCORE_3)
 2321             tty_putcode1(tty, TTYC_SMULX, 3);
 2322         else if (changed & GRID_ATTR_UNDERSCORE_4)
 2323             tty_putcode1(tty, TTYC_SMULX, 4);
 2324         else if (changed & GRID_ATTR_UNDERSCORE_5)
 2325             tty_putcode1(tty, TTYC_SMULX, 5);
 2326     }
 2327     if (changed & GRID_ATTR_BLINK)
 2328         tty_putcode(tty, TTYC_BLINK);
 2329     if (changed & GRID_ATTR_REVERSE) {
 2330         if (tty_term_has(tty->term, TTYC_REV))
 2331             tty_putcode(tty, TTYC_REV);
 2332         else if (tty_term_has(tty->term, TTYC_SMSO))
 2333             tty_putcode(tty, TTYC_SMSO);
 2334     }
 2335     if (changed & GRID_ATTR_HIDDEN)
 2336         tty_putcode(tty, TTYC_INVIS);
 2337     if (changed & GRID_ATTR_STRIKETHROUGH)
 2338         tty_putcode(tty, TTYC_SMXX);
 2339     if (changed & GRID_ATTR_OVERLINE)
 2340         tty_putcode(tty, TTYC_SMOL);
 2341     if ((changed & GRID_ATTR_CHARSET) && tty_acs_needed(tty))
 2342         tty_putcode(tty, TTYC_SMACS);
 2343 
 2344     memcpy(&tty->last_cell, &gc2, sizeof tty->last_cell);
 2345 }
 2346 
 2347 static void
 2348 tty_colours(struct tty *tty, const struct grid_cell *gc)
 2349 {
 2350     struct grid_cell    *tc = &tty->cell;
 2351     int          have_ax;
 2352 
 2353     /* No changes? Nothing is necessary. */
 2354     if (gc->fg == tc->fg && gc->bg == tc->bg && gc->us == tc->us)
 2355         return;
 2356 
 2357     /*
 2358      * Is either the default colour? This is handled specially because the
 2359      * best solution might be to reset both colours to default, in which
 2360      * case if only one is default need to fall onward to set the other
 2361      * colour.
 2362      */
 2363     if (COLOUR_DEFAULT(gc->fg) || COLOUR_DEFAULT(gc->bg)) {
 2364         /*
 2365          * If don't have AX but do have op, send sgr0 (op can't
 2366          * actually be used because it is sometimes the same as sgr0
 2367          * and sometimes isn't). This resets both colours to default.
 2368          *
 2369          * Otherwise, try to set the default colour only as needed.
 2370          */
 2371         have_ax = tty_term_flag(tty->term, TTYC_AX);
 2372         if (!have_ax && tty_term_has(tty->term, TTYC_OP))
 2373             tty_reset(tty);
 2374         else {
 2375             if (COLOUR_DEFAULT(gc->fg) && !COLOUR_DEFAULT(tc->fg)) {
 2376                 if (have_ax)
 2377                     tty_puts(tty, "\033[39m");
 2378                 else if (tc->fg != 7)
 2379                     tty_putcode1(tty, TTYC_SETAF, 7);
 2380                 tc->fg = gc->fg;
 2381             }
 2382             if (COLOUR_DEFAULT(gc->bg) && !COLOUR_DEFAULT(tc->bg)) {
 2383                 if (have_ax)
 2384                     tty_puts(tty, "\033[49m");
 2385                 else if (tc->bg != 0)
 2386                     tty_putcode1(tty, TTYC_SETAB, 0);
 2387                 tc->bg = gc->bg;
 2388             }
 2389         }
 2390     }
 2391 
 2392     /* Set the foreground colour. */
 2393     if (!COLOUR_DEFAULT(gc->fg) && gc->fg != tc->fg)
 2394         tty_colours_fg(tty, gc);
 2395 
 2396     /*
 2397      * Set the background colour. This must come after the foreground as
 2398      * tty_colour_fg() can call tty_reset().
 2399      */
 2400     if (!COLOUR_DEFAULT(gc->bg) && gc->bg != tc->bg)
 2401         tty_colours_bg(tty, gc);
 2402 
 2403     /* Set the underscore color. */
 2404     if (gc->us != tc->us)
 2405         tty_colours_us(tty, gc);
 2406 }
 2407 
 2408 static void
 2409 tty_check_fg(struct tty *tty, int *palette, struct grid_cell *gc)
 2410 {
 2411     u_char  r, g, b;
 2412     u_int   colours;
 2413     int c;
 2414 
 2415     /*
 2416      * Perform substitution if this pane has a palette. If the bright
 2417      * attribute is set, use the bright entry in the palette by changing to
 2418      * the aixterm colour.
 2419      */
 2420     if (~gc->flags & GRID_FLAG_NOPALETTE) {
 2421         c = gc->fg;
 2422         if (c < 8 && gc->attr & GRID_ATTR_BRIGHT)
 2423             c += 90;
 2424         if ((c = tty_get_palette(palette, c)) != -1)
 2425             gc->fg = c;
 2426     }
 2427 
 2428     /* Is this a 24-bit colour? */
 2429     if (gc->fg & COLOUR_FLAG_RGB) {
 2430         /* Not a 24-bit terminal? Translate to 256-colour palette. */
 2431         if (tty->term->flags & TERM_RGBCOLOURS)
 2432             return;
 2433         colour_split_rgb(gc->fg, &r, &g, &b);
 2434         gc->fg = colour_find_rgb(r, g, b);
 2435     }
 2436 
 2437     /* How many colours does this terminal have? */
 2438     if (tty->term->flags & TERM_256COLOURS)
 2439         colours = 256;
 2440     else
 2441         colours = tty_term_number(tty->term, TTYC_COLORS);
 2442 
 2443     /* Is this a 256-colour colour? */
 2444     if (gc->fg & COLOUR_FLAG_256) {
 2445         /* And not a 256 colour mode? */
 2446         if (colours < 256) {
 2447             gc->fg = colour_256to16(gc->fg);
 2448             if (gc->fg & 8) {
 2449                 gc->fg &= 7;
 2450                 if (colours >= 16)
 2451                     gc->fg += 90;
 2452             }
 2453         }
 2454         return;
 2455     }
 2456 
 2457     /* Is this an aixterm colour? */
 2458     if (gc->fg >= 90 && gc->fg <= 97 && colours < 16) {
 2459         gc->fg -= 90;
 2460         gc->attr |= GRID_ATTR_BRIGHT;
 2461     }
 2462 }
 2463 
 2464 static void
 2465 tty_check_bg(struct tty *tty, int *palette, struct grid_cell *gc)
 2466 {
 2467     u_char  r, g, b;
 2468     u_int   colours;
 2469     int c;
 2470 
 2471     /* Perform substitution if this pane has a palette. */
 2472     if (~gc->flags & GRID_FLAG_NOPALETTE) {
 2473         if ((c = tty_get_palette(palette, gc->bg)) != -1)
 2474             gc->bg = c;
 2475     }
 2476 
 2477     /* Is this a 24-bit colour? */
 2478     if (gc->bg & COLOUR_FLAG_RGB) {
 2479         /* Not a 24-bit terminal? Translate to 256-colour palette. */
 2480         if (tty->term->flags & TERM_RGBCOLOURS)
 2481             return;
 2482         colour_split_rgb(gc->bg, &r, &g, &b);
 2483         gc->bg = colour_find_rgb(r, g, b);
 2484     }
 2485 
 2486     /* How many colours does this terminal have? */
 2487     if (tty->term->flags & TERM_256COLOURS)
 2488         colours = 256;
 2489     else
 2490         colours = tty_term_number(tty->term, TTYC_COLORS);
 2491 
 2492     /* Is this a 256-colour colour? */
 2493     if (gc->bg & COLOUR_FLAG_256) {
 2494         /*
 2495          * And not a 256 colour mode? Translate to 16-colour
 2496          * palette. Bold background doesn't exist portably, so just
 2497          * discard the bold bit if set.
 2498          */
 2499         if (colours < 256) {
 2500             gc->bg = colour_256to16(gc->bg);
 2501             if (gc->bg & 8) {
 2502                 gc->bg &= 7;
 2503                 if (colours >= 16)
 2504                     gc->bg += 90;
 2505             }
 2506         }
 2507         return;
 2508     }
 2509 
 2510     /* Is this an aixterm colour? */
 2511     if (gc->bg >= 90 && gc->bg <= 97 && colours < 16)
 2512         gc->bg -= 90;
 2513 }
 2514 
 2515 static void
 2516 tty_check_us(__unused struct tty *tty, int *palette, struct grid_cell *gc)
 2517 {
 2518     int c;
 2519 
 2520     /* Perform substitution if this pane has a palette. */
 2521     if (~gc->flags & GRID_FLAG_NOPALETTE) {
 2522         if ((c = tty_get_palette(palette, gc->us)) != -1)
 2523             gc->us = c;
 2524     }
 2525 
 2526     /* Underscore colour is set as RGB so convert a 256 colour to RGB. */
 2527     if (gc->us & COLOUR_FLAG_256)
 2528         gc->us = colour_256toRGB (gc->us);
 2529 }
 2530 
 2531 static void
 2532 tty_colours_fg(struct tty *tty, const struct grid_cell *gc)
 2533 {
 2534     struct grid_cell    *tc = &tty->cell;
 2535     char             s[32];
 2536 
 2537     /* Is this a 24-bit or 256-colour colour? */
 2538     if (gc->fg & COLOUR_FLAG_RGB || gc->fg & COLOUR_FLAG_256) {
 2539         if (tty_try_colour(tty, gc->fg, "38") == 0)
 2540             goto save;
 2541         /* Should not get here, already converted in tty_check_fg. */
 2542         return;
 2543     }
 2544 
 2545     /* Is this an aixterm bright colour? */
 2546     if (gc->fg >= 90 && gc->fg <= 97) {
 2547         if (tty->term->flags & TERM_256COLOURS) {
 2548             xsnprintf(s, sizeof s, "\033[%dm", gc->fg);
 2549             tty_puts(tty, s);
 2550         } else
 2551             tty_putcode1(tty, TTYC_SETAF, gc->fg - 90 + 8);
 2552         goto save;
 2553     }
 2554 
 2555     /* Otherwise set the foreground colour. */
 2556     tty_putcode1(tty, TTYC_SETAF, gc->fg);
 2557 
 2558 save:
 2559     /* Save the new values in the terminal current cell. */
 2560     tc->fg = gc->fg;
 2561 }
 2562 
 2563 static void
 2564 tty_colours_bg(struct tty *tty, const struct grid_cell *gc)
 2565 {
 2566     struct grid_cell    *tc = &tty->cell;
 2567     char             s[32];
 2568 
 2569     /* Is this a 24-bit or 256-colour colour? */
 2570     if (gc->bg & COLOUR_FLAG_RGB || gc->bg & COLOUR_FLAG_256) {
 2571         if (tty_try_colour(tty, gc->bg, "48") == 0)
 2572             goto save;
 2573         /* Should not get here, already converted in tty_check_bg. */
 2574         return;
 2575     }
 2576 
 2577     /* Is this an aixterm bright colour? */
 2578     if (gc->bg >= 90 && gc->bg <= 97) {
 2579         if (tty->term->flags & TERM_256COLOURS) {
 2580             xsnprintf(s, sizeof s, "\033[%dm", gc->bg + 10);
 2581             tty_puts(tty, s);
 2582         } else
 2583             tty_putcode1(tty, TTYC_SETAB, gc->bg - 90 + 8);
 2584         goto save;
 2585     }
 2586 
 2587     /* Otherwise set the background colour. */
 2588     tty_putcode1(tty, TTYC_SETAB, gc->bg);
 2589 
 2590 save:
 2591     /* Save the new values in the terminal current cell. */
 2592     tc->bg = gc->bg;
 2593 }
 2594 
 2595 static void
 2596 tty_colours_us(struct tty *tty, const struct grid_cell *gc)
 2597 {
 2598     struct grid_cell    *tc = &tty->cell;
 2599     u_int            c;
 2600     u_char           r, g, b;
 2601 
 2602     /* Clear underline colour. */
 2603     if (gc->us == 0) {
 2604         tty_putcode(tty, TTYC_OL);
 2605         goto save;
 2606     }
 2607 
 2608     /* Must be an RGB colour - this should never happen. */
 2609     if (~gc->us & COLOUR_FLAG_RGB)
 2610         return;
 2611 
 2612     /*
 2613      * Setulc and setal follows the ncurses(3) one argument "direct colour"
 2614      * capability format. Calculate the colour value.
 2615      */
 2616     colour_split_rgb(gc->us, &r, &g, &b);
 2617     c = (65536 * r) + (256 * g) + b;
 2618 
 2619     /*
 2620      * Write the colour. Only use setal if the RGB flag is set because the
 2621      * non-RGB version may be wrong.
 2622      */
 2623     if (tty_term_has(tty->term, TTYC_SETULC))
 2624         tty_putcode1(tty, TTYC_SETULC, c);
 2625     else if (tty_term_has(tty->term, TTYC_SETAL) &&
 2626         tty_term_has(tty->term, TTYC_RGB))
 2627         tty_putcode1(tty, TTYC_SETAL, c);
 2628 
 2629 save:
 2630     /* Save the new values in the terminal current cell. */
 2631     tc->us = gc->us;
 2632 }
 2633 
 2634 static int
 2635 tty_try_colour(struct tty *tty, int colour, const char *type)
 2636 {
 2637     u_char  r, g, b;
 2638 
 2639     if (colour & COLOUR_FLAG_256) {
 2640         if (*type == '3' && tty_term_has(tty->term, TTYC_SETAF))
 2641             tty_putcode1(tty, TTYC_SETAF, colour & 0xff);
 2642         else if (tty_term_has(tty->term, TTYC_SETAB))
 2643             tty_putcode1(tty, TTYC_SETAB, colour & 0xff);
 2644         return (0);
 2645     }
 2646 
 2647     if (colour & COLOUR_FLAG_RGB) {
 2648         colour_split_rgb(colour & 0xffffff, &r, &g, &b);
 2649         if (*type == '3' && tty_term_has(tty->term, TTYC_SETRGBF))
 2650             tty_putcode3(tty, TTYC_SETRGBF, r, g, b);
 2651         else if (tty_term_has(tty->term, TTYC_SETRGBB))
 2652             tty_putcode3(tty, TTYC_SETRGBB, r, g, b);
 2653         return (0);
 2654     }
 2655 
 2656     return (-1);
 2657 }
 2658 
 2659 static void
 2660 tty_window_default_style(struct grid_cell *gc, struct window_pane *wp)
 2661 {
 2662     memcpy(gc, &grid_default_cell, sizeof *gc);
 2663     gc->fg = wp->fg;
 2664     gc->bg = wp->bg;
 2665 }
 2666 
 2667 void
 2668 tty_default_colours(struct grid_cell *gc, struct window_pane *wp)
 2669 {
 2670     struct options  *oo = wp->options;
 2671 
 2672     memcpy(gc, &grid_default_cell, sizeof *gc);
 2673 
 2674     if (wp->flags & PANE_STYLECHANGED) {
 2675         wp->flags &= ~PANE_STYLECHANGED;
 2676 
 2677         tty_window_default_style(&wp->cached_active_gc, wp);
 2678         style_add(&wp->cached_active_gc, oo, "window-active-style",
 2679             NULL);
 2680         tty_window_default_style(&wp->cached_gc, wp);
 2681         style_add(&wp->cached_gc, oo, "window-style", NULL);
 2682     }
 2683 
 2684     if (gc->fg == 8) {
 2685         if (wp == wp->window->active && wp->cached_active_gc.fg != 8)
 2686             gc->fg = wp->cached_active_gc.fg;
 2687         else
 2688             gc->fg = wp->cached_gc.fg;
 2689     }
 2690 
 2691     if (gc->bg == 8) {
 2692         if (wp == wp->window->active && wp->cached_active_gc.bg != 8)
 2693             gc->bg = wp->cached_active_gc.bg;
 2694         else
 2695             gc->bg = wp->cached_gc.bg;
 2696     }
 2697 }
 2698 
 2699 static void
 2700 tty_default_attributes(struct tty *tty, const struct grid_cell *defaults,
 2701     int *palette, u_int bg)
 2702 {
 2703     struct grid_cell    gc;
 2704 
 2705     memcpy(&gc, &grid_default_cell, sizeof gc);
 2706     gc.bg = bg;
 2707     tty_attributes(tty, &gc, defaults, palette);
 2708 }