Annotation of embedaddon/tmux/tty.c, revision 1.1

1.1     ! misho       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 *, struct window_pane *);
        !            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 *, const struct window_pane *,
        !            49:                    struct grid_cell *);
        !            50: static void    tty_check_bg(struct tty *, const struct window_pane *,
        !            51:                    struct grid_cell *);
        !            52: static void    tty_colours_fg(struct tty *, const struct grid_cell *);
        !            53: static void    tty_colours_bg(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 window_pane *,
        !            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_cell(struct tty *, const struct grid_cell *,
        !            68:                    const struct window_pane *);
        !            69: static void    tty_default_colours(struct grid_cell *,
        !            70:                    const struct window_pane *);
        !            71: static void    tty_default_attributes(struct tty *, const struct window_pane *,
        !            72:                    u_int);
        !            73: 
        !            74: #define tty_use_acs(tty) \
        !            75:        (tty_term_has((tty)->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8))
        !            76: #define tty_use_margin(tty) \
        !            77:        ((tty)->term_type == TTY_VT420)
        !            78: 
        !            79: #define tty_pane_full_width(tty, ctx)                                  \
        !            80:        ((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx)
        !            81: 
        !            82: void
        !            83: tty_create_log(void)
        !            84: {
        !            85:        char    name[64];
        !            86: 
        !            87:        xsnprintf(name, sizeof name, "tmux-out-%ld.log", (long)getpid());
        !            88: 
        !            89:        tty_log_fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0644);
        !            90:        if (tty_log_fd != -1 && fcntl(tty_log_fd, F_SETFD, FD_CLOEXEC) == -1)
        !            91:                fatal("fcntl failed");
        !            92: }
        !            93: 
        !            94: int
        !            95: tty_init(struct tty *tty, struct client *c, int fd, char *term)
        !            96: {
        !            97:        if (!isatty(fd))
        !            98:                return (-1);
        !            99: 
        !           100:        memset(tty, 0, sizeof *tty);
        !           101: 
        !           102:        if (term == NULL || *term == '\0')
        !           103:                tty->term_name = xstrdup("unknown");
        !           104:        else
        !           105:                tty->term_name = xstrdup(term);
        !           106: 
        !           107:        tty->fd = fd;
        !           108:        tty->client = c;
        !           109: 
        !           110:        tty->cstyle = 0;
        !           111:        tty->ccolour = xstrdup("");
        !           112: 
        !           113:        tty->flags = 0;
        !           114: 
        !           115:        tty->term_flags = 0;
        !           116:        tty->term_type = TTY_UNKNOWN;
        !           117: 
        !           118:        return (0);
        !           119: }
        !           120: 
        !           121: int
        !           122: tty_resize(struct tty *tty)
        !           123: {
        !           124:        struct client   *c = tty->client;
        !           125:        struct winsize   ws;
        !           126:        u_int            sx, sy;
        !           127: 
        !           128:        if (ioctl(tty->fd, TIOCGWINSZ, &ws) != -1) {
        !           129:                sx = ws.ws_col;
        !           130:                if (sx == 0)
        !           131:                        sx = 80;
        !           132:                sy = ws.ws_row;
        !           133:                if (sy == 0)
        !           134:                        sy = 24;
        !           135:        } else {
        !           136:                sx = 80;
        !           137:                sy = 24;
        !           138:        }
        !           139:        log_debug("%s: %s now %ux%u", __func__, c->name, sx, sy);
        !           140: 
        !           141:        if (!tty_set_size(tty, sx, sy))
        !           142:                return (0);
        !           143:        tty_invalidate(tty);
        !           144:        return (1);
        !           145: }
        !           146: 
        !           147: int
        !           148: tty_set_size(struct tty *tty, u_int sx, u_int sy)
        !           149: {
        !           150:        if (sx == tty->sx && sy == tty->sy)
        !           151:                return (0);
        !           152:        tty->sx = sx;
        !           153:        tty->sy = sy;
        !           154:        return (1);
        !           155: }
        !           156: 
        !           157: static void
        !           158: tty_read_callback(__unused int fd, __unused short events, void *data)
        !           159: {
        !           160:        struct tty      *tty = data;
        !           161:        struct client   *c = tty->client;
        !           162:        size_t           size = EVBUFFER_LENGTH(tty->in);
        !           163:        int              nread;
        !           164: 
        !           165:        nread = evbuffer_read(tty->in, tty->fd, -1);
        !           166:        if (nread == -1)
        !           167:                return;
        !           168:        log_debug("%s: read %d bytes (already %zu)", c->name, nread, size);
        !           169: 
        !           170:        while (tty_keys_next(tty))
        !           171:                ;
        !           172: }
        !           173: 
        !           174: static void
        !           175: tty_write_callback(__unused int fd, __unused short events, void *data)
        !           176: {
        !           177:        struct tty      *tty = data;
        !           178:        struct client   *c = tty->client;
        !           179:        size_t           size = EVBUFFER_LENGTH(tty->out);
        !           180:        int              nwrite;
        !           181: 
        !           182:        nwrite = evbuffer_write(tty->out, tty->fd);
        !           183:        if (nwrite == -1)
        !           184:                return;
        !           185:        log_debug("%s: wrote %d bytes (of %zu)", c->name, nwrite, size);
        !           186: 
        !           187:        if (EVBUFFER_LENGTH(tty->out) != 0)
        !           188:                event_add(&tty->event_out, NULL);
        !           189: }
        !           190: 
        !           191: int
        !           192: tty_open(struct tty *tty, char **cause)
        !           193: {
        !           194:        tty->term = tty_term_find(tty->term_name, tty->fd, cause);
        !           195:        if (tty->term == NULL) {
        !           196:                tty_close(tty);
        !           197:                return (-1);
        !           198:        }
        !           199:        tty->flags |= TTY_OPENED;
        !           200: 
        !           201:        tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE);
        !           202: 
        !           203:        event_set(&tty->event_in, tty->fd, EV_PERSIST|EV_READ,
        !           204:            tty_read_callback, tty);
        !           205:        tty->in = evbuffer_new();
        !           206: 
        !           207:        event_set(&tty->event_out, tty->fd, EV_WRITE, tty_write_callback, tty);
        !           208:        tty->out = evbuffer_new();
        !           209: 
        !           210:        tty_start_tty(tty);
        !           211: 
        !           212:        tty_keys_build(tty);
        !           213: 
        !           214:        return (0);
        !           215: }
        !           216: 
        !           217: void
        !           218: tty_start_tty(struct tty *tty)
        !           219: {
        !           220:        struct termios  tio;
        !           221: 
        !           222:        if (tty->fd != -1 && tcgetattr(tty->fd, &tty->tio) == 0) {
        !           223:                setblocking(tty->fd, 0);
        !           224:                event_add(&tty->event_in, NULL);
        !           225: 
        !           226:                memcpy(&tio, &tty->tio, sizeof tio);
        !           227:                tio.c_iflag &= ~(IXON|IXOFF|ICRNL|INLCR|IGNCR|IMAXBEL|ISTRIP);
        !           228:                tio.c_iflag |= IGNBRK;
        !           229:                tio.c_oflag &= ~(OPOST|ONLCR|OCRNL|ONLRET);
        !           230:                tio.c_lflag &= ~(IEXTEN|ICANON|ECHO|ECHOE|ECHONL|ECHOCTL|
        !           231:                    ECHOPRT|ECHOKE|ISIG);
        !           232:                tio.c_cc[VMIN] = 1;
        !           233:                tio.c_cc[VTIME] = 0;
        !           234:                if (tcsetattr(tty->fd, TCSANOW, &tio) == 0)
        !           235:                        tcflush(tty->fd, TCIOFLUSH);
        !           236:        }
        !           237: 
        !           238:        tty_putcode(tty, TTYC_SMCUP);
        !           239: 
        !           240:        tty_putcode(tty, TTYC_SMKX);
        !           241:        if (tty_use_acs(tty))
        !           242:                tty_putcode(tty, TTYC_ENACS);
        !           243:        tty_putcode(tty, TTYC_CLEAR);
        !           244: 
        !           245:        tty_putcode(tty, TTYC_CNORM);
        !           246:        if (tty_term_has(tty->term, TTYC_KMOUS))
        !           247:                tty_puts(tty, "\033[?1000l\033[?1002l\033[?1006l\033[?1005l");
        !           248: 
        !           249:        if (tty_term_flag(tty->term, TTYC_XT)) {
        !           250:                if (options_get_number(global_options, "focus-events")) {
        !           251:                        tty->flags |= TTY_FOCUS;
        !           252:                        tty_puts(tty, "\033[?1004h");
        !           253:                }
        !           254:                tty_puts(tty, "\033[c");
        !           255:        }
        !           256: 
        !           257:        tty->flags |= TTY_STARTED;
        !           258:        tty_invalidate(tty);
        !           259: 
        !           260:        tty_force_cursor_colour(tty, "");
        !           261: 
        !           262:        tty->mouse_drag_flag = 0;
        !           263:        tty->mouse_drag_update = NULL;
        !           264:        tty->mouse_drag_release = NULL;
        !           265: }
        !           266: 
        !           267: void
        !           268: tty_stop_tty(struct tty *tty)
        !           269: {
        !           270:        struct winsize  ws;
        !           271: 
        !           272:        if (!(tty->flags & TTY_STARTED))
        !           273:                return;
        !           274:        tty->flags &= ~TTY_STARTED;
        !           275: 
        !           276:        event_del(&tty->event_in);
        !           277:        event_del(&tty->event_out);
        !           278: 
        !           279:        /*
        !           280:         * Be flexible about error handling and try not kill the server just
        !           281:         * because the fd is invalid. Things like ssh -t can easily leave us
        !           282:         * with a dead tty.
        !           283:         */
        !           284:        if (ioctl(tty->fd, TIOCGWINSZ, &ws) == -1)
        !           285:                return;
        !           286:        if (tcsetattr(tty->fd, TCSANOW, &tty->tio) == -1)
        !           287:                return;
        !           288: 
        !           289:        tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1));
        !           290:        if (tty_use_acs(tty))
        !           291:                tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS));
        !           292:        tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0));
        !           293:        tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX));
        !           294:        tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR));
        !           295:        if (tty_term_has(tty->term, TTYC_SS) && tty->cstyle != 0) {
        !           296:                if (tty_term_has(tty->term, TTYC_SE))
        !           297:                        tty_raw(tty, tty_term_string(tty->term, TTYC_SE));
        !           298:                else
        !           299:                        tty_raw(tty, tty_term_string1(tty->term, TTYC_SS, 0));
        !           300:        }
        !           301:        if (tty->mode & MODE_BRACKETPASTE)
        !           302:                tty_raw(tty, "\033[?2004l");
        !           303:        tty_raw(tty, tty_term_string(tty->term, TTYC_CR));
        !           304: 
        !           305:        tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM));
        !           306:        if (tty_term_has(tty->term, TTYC_KMOUS))
        !           307:                tty_raw(tty, "\033[?1000l\033[?1002l\033[?1006l\033[?1005l");
        !           308: 
        !           309:        if (tty_term_flag(tty->term, TTYC_XT)) {
        !           310:                if (tty->flags & TTY_FOCUS) {
        !           311:                        tty->flags &= ~TTY_FOCUS;
        !           312:                        tty_raw(tty, "\033[?1004l");
        !           313:                }
        !           314:        }
        !           315: 
        !           316:        if (tty_use_margin(tty))
        !           317:                tty_raw(tty, "\033[?69l"); /* DECLRMM */
        !           318:        tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
        !           319: 
        !           320:        setblocking(tty->fd, 1);
        !           321: }
        !           322: 
        !           323: void
        !           324: tty_close(struct tty *tty)
        !           325: {
        !           326:        if (event_initialized(&tty->key_timer))
        !           327:                evtimer_del(&tty->key_timer);
        !           328:        tty_stop_tty(tty);
        !           329: 
        !           330:        if (tty->flags & TTY_OPENED) {
        !           331:                evbuffer_free(tty->in);
        !           332:                event_del(&tty->event_in);
        !           333:                evbuffer_free(tty->out);
        !           334:                event_del(&tty->event_out);
        !           335: 
        !           336:                tty_term_free(tty->term);
        !           337:                tty_keys_free(tty);
        !           338: 
        !           339:                tty->flags &= ~TTY_OPENED;
        !           340:        }
        !           341: 
        !           342:        if (tty->fd != -1) {
        !           343:                close(tty->fd);
        !           344:                tty->fd = -1;
        !           345:        }
        !           346: }
        !           347: 
        !           348: void
        !           349: tty_free(struct tty *tty)
        !           350: {
        !           351:        tty_close(tty);
        !           352: 
        !           353:        free(tty->ccolour);
        !           354:        free(tty->term_name);
        !           355: }
        !           356: 
        !           357: void
        !           358: tty_set_type(struct tty *tty, int type)
        !           359: {
        !           360:        tty->term_type = type;
        !           361: 
        !           362:        if (tty_use_margin(tty))
        !           363:                tty_puts(tty, "\033[?69h"); /* DECLRMM */
        !           364: }
        !           365: 
        !           366: void
        !           367: tty_raw(struct tty *tty, const char *s)
        !           368: {
        !           369:        ssize_t n, slen;
        !           370:        u_int   i;
        !           371: 
        !           372:        slen = strlen(s);
        !           373:        for (i = 0; i < 5; i++) {
        !           374:                n = write(tty->fd, s, slen);
        !           375:                if (n >= 0) {
        !           376:                        s += n;
        !           377:                        slen -= n;
        !           378:                        if (slen == 0)
        !           379:                                break;
        !           380:                } else if (n == -1 && errno != EAGAIN)
        !           381:                        break;
        !           382:                usleep(100);
        !           383:        }
        !           384: }
        !           385: 
        !           386: void
        !           387: tty_putcode(struct tty *tty, enum tty_code_code code)
        !           388: {
        !           389:        tty_puts(tty, tty_term_string(tty->term, code));
        !           390: }
        !           391: 
        !           392: void
        !           393: tty_putcode1(struct tty *tty, enum tty_code_code code, int a)
        !           394: {
        !           395:        if (a < 0)
        !           396:                return;
        !           397:        tty_puts(tty, tty_term_string1(tty->term, code, a));
        !           398: }
        !           399: 
        !           400: void
        !           401: tty_putcode2(struct tty *tty, enum tty_code_code code, int a, int b)
        !           402: {
        !           403:        if (a < 0 || b < 0)
        !           404:                return;
        !           405:        tty_puts(tty, tty_term_string2(tty->term, code, a, b));
        !           406: }
        !           407: 
        !           408: void
        !           409: tty_putcode_ptr1(struct tty *tty, enum tty_code_code code, const void *a)
        !           410: {
        !           411:        if (a != NULL)
        !           412:                tty_puts(tty, tty_term_ptr1(tty->term, code, a));
        !           413: }
        !           414: 
        !           415: void
        !           416: tty_putcode_ptr2(struct tty *tty, enum tty_code_code code, const void *a,
        !           417:     const void *b)
        !           418: {
        !           419:        if (a != NULL && b != NULL)
        !           420:                tty_puts(tty, tty_term_ptr2(tty->term, code, a, b));
        !           421: }
        !           422: 
        !           423: static void
        !           424: tty_add(struct tty *tty, const char *buf, size_t len)
        !           425: {
        !           426:        struct client   *c = tty->client;
        !           427: 
        !           428:        evbuffer_add(tty->out, buf, len);
        !           429:        log_debug("%s: %.*s", c->name, (int)len, (const char *)buf);
        !           430:        tty->written += len;
        !           431: 
        !           432:        if (tty_log_fd != -1)
        !           433:                write(tty_log_fd, buf, len);
        !           434:        if (tty->flags & TTY_STARTED)
        !           435:                event_add(&tty->event_out, NULL);
        !           436: }
        !           437: 
        !           438: void
        !           439: tty_puts(struct tty *tty, const char *s)
        !           440: {
        !           441:        if (*s != '\0')
        !           442:                tty_add(tty, s, strlen(s));
        !           443: }
        !           444: 
        !           445: void
        !           446: tty_putc(struct tty *tty, u_char ch)
        !           447: {
        !           448:        const char      *acs;
        !           449: 
        !           450:        if (tty->cell.attr & GRID_ATTR_CHARSET) {
        !           451:                acs = tty_acs_get(tty, ch);
        !           452:                if (acs != NULL)
        !           453:                        tty_add(tty, acs, strlen(acs));
        !           454:                else
        !           455:                        tty_add(tty, &ch, 1);
        !           456:        } else
        !           457:                tty_add(tty, &ch, 1);
        !           458: 
        !           459:        if (ch >= 0x20 && ch != 0x7f) {
        !           460:                if (tty->cx >= tty->sx) {
        !           461:                        tty->cx = 1;
        !           462:                        if (tty->cy != tty->rlower)
        !           463:                                tty->cy++;
        !           464: 
        !           465:                        /*
        !           466:                         * On !xenl terminals, force the cursor position to
        !           467:                         * where we think it should be after a line wrap - this
        !           468:                         * means it works on sensible terminals as well.
        !           469:                         */
        !           470:                        if (tty->term->flags & TERM_EARLYWRAP)
        !           471:                                tty_putcode2(tty, TTYC_CUP, tty->cy, tty->cx);
        !           472:                } else
        !           473:                        tty->cx++;
        !           474:        }
        !           475: }
        !           476: 
        !           477: void
        !           478: tty_putn(struct tty *tty, const void *buf, size_t len, u_int width)
        !           479: {
        !           480:        tty_add(tty, buf, len);
        !           481:        if (tty->cx + width > tty->sx)
        !           482:                tty->cx = tty->cy = UINT_MAX;
        !           483:        else
        !           484:                tty->cx += width;
        !           485: }
        !           486: 
        !           487: static void
        !           488: tty_set_italics(struct tty *tty)
        !           489: {
        !           490:        const char      *s;
        !           491: 
        !           492:        if (tty_term_has(tty->term, TTYC_SITM)) {
        !           493:                s = options_get_string(global_options, "default-terminal");
        !           494:                if (strcmp(s, "screen") != 0 && strncmp(s, "screen-", 7) != 0) {
        !           495:                        tty_putcode(tty, TTYC_SITM);
        !           496:                        return;
        !           497:                }
        !           498:        }
        !           499:        tty_putcode(tty, TTYC_SMSO);
        !           500: }
        !           501: 
        !           502: void
        !           503: tty_set_title(struct tty *tty, const char *title)
        !           504: {
        !           505:        if (!tty_term_has(tty->term, TTYC_TSL) ||
        !           506:            !tty_term_has(tty->term, TTYC_FSL))
        !           507:                return;
        !           508: 
        !           509:        tty_putcode(tty, TTYC_TSL);
        !           510:        tty_puts(tty, title);
        !           511:        tty_putcode(tty, TTYC_FSL);
        !           512: }
        !           513: 
        !           514: static void
        !           515: tty_force_cursor_colour(struct tty *tty, const char *ccolour)
        !           516: {
        !           517:        if (*ccolour == '\0')
        !           518:                tty_putcode(tty, TTYC_CR);
        !           519:        else
        !           520:                tty_putcode_ptr1(tty, TTYC_CS, ccolour);
        !           521:        free(tty->ccolour);
        !           522:        tty->ccolour = xstrdup(ccolour);
        !           523: }
        !           524: 
        !           525: void
        !           526: tty_update_mode(struct tty *tty, int mode, struct screen *s)
        !           527: {
        !           528:        int     changed;
        !           529: 
        !           530:        if (s != NULL && strcmp(s->ccolour, tty->ccolour) != 0)
        !           531:                tty_force_cursor_colour(tty, s->ccolour);
        !           532: 
        !           533:        if (tty->flags & TTY_NOCURSOR)
        !           534:                mode &= ~MODE_CURSOR;
        !           535: 
        !           536:        changed = mode ^ tty->mode;
        !           537:        if (changed & MODE_BLINKING) {
        !           538:                if (tty_term_has(tty->term, TTYC_CVVIS))
        !           539:                        tty_putcode(tty, TTYC_CVVIS);
        !           540:                else
        !           541:                        tty_putcode(tty, TTYC_CNORM);
        !           542:                changed |= MODE_CURSOR;
        !           543:        }
        !           544:        if (changed & MODE_CURSOR) {
        !           545:                if (mode & MODE_CURSOR)
        !           546:                        tty_putcode(tty, TTYC_CNORM);
        !           547:                else
        !           548:                        tty_putcode(tty, TTYC_CIVIS);
        !           549:        }
        !           550:        if (s != NULL && tty->cstyle != s->cstyle) {
        !           551:                if (tty_term_has(tty->term, TTYC_SS)) {
        !           552:                        if (s->cstyle == 0 &&
        !           553:                            tty_term_has(tty->term, TTYC_SE))
        !           554:                                tty_putcode(tty, TTYC_SE);
        !           555:                        else
        !           556:                                tty_putcode1(tty, TTYC_SS, s->cstyle);
        !           557:                }
        !           558:                tty->cstyle = s->cstyle;
        !           559:        }
        !           560:        if (changed & ALL_MOUSE_MODES) {
        !           561:                if (mode & ALL_MOUSE_MODES) {
        !           562:                        /*
        !           563:                         * Enable the SGR (1006) extension unconditionally, as
        !           564:                         * it is safe from misinterpretation.
        !           565:                         */
        !           566:                        tty_puts(tty, "\033[?1006h");
        !           567:                        if (mode & MODE_MOUSE_ALL)
        !           568:                                tty_puts(tty, "\033[?1003h");
        !           569:                        else if (mode & MODE_MOUSE_BUTTON)
        !           570:                                tty_puts(tty, "\033[?1002h");
        !           571:                        else if (mode & MODE_MOUSE_STANDARD)
        !           572:                                tty_puts(tty, "\033[?1000h");
        !           573:                } else {
        !           574:                        if (tty->mode & MODE_MOUSE_ALL)
        !           575:                                tty_puts(tty, "\033[?1003l");
        !           576:                        else if (tty->mode & MODE_MOUSE_BUTTON)
        !           577:                                tty_puts(tty, "\033[?1002l");
        !           578:                        else if (tty->mode & MODE_MOUSE_STANDARD)
        !           579:                                tty_puts(tty, "\033[?1000l");
        !           580:                        tty_puts(tty, "\033[?1006l");
        !           581:                }
        !           582:        }
        !           583:        if (changed & MODE_BRACKETPASTE) {
        !           584:                if (mode & MODE_BRACKETPASTE)
        !           585:                        tty_puts(tty, "\033[?2004h");
        !           586:                else
        !           587:                        tty_puts(tty, "\033[?2004l");
        !           588:        }
        !           589:        tty->mode = mode;
        !           590: }
        !           591: 
        !           592: static void
        !           593: tty_emulate_repeat(struct tty *tty, enum tty_code_code code,
        !           594:     enum tty_code_code code1, u_int n)
        !           595: {
        !           596:        if (tty_term_has(tty->term, code))
        !           597:                tty_putcode1(tty, code, n);
        !           598:        else {
        !           599:                while (n-- > 0)
        !           600:                        tty_putcode(tty, code1);
        !           601:        }
        !           602: }
        !           603: 
        !           604: static void
        !           605: tty_repeat_space(struct tty *tty, u_int n)
        !           606: {
        !           607:        static char s[500];
        !           608: 
        !           609:        if (*s != ' ')
        !           610:                memset(s, ' ', sizeof s);
        !           611: 
        !           612:        while (n > sizeof s) {
        !           613:                tty_putn(tty, s, sizeof s, sizeof s);
        !           614:                n -= sizeof s;
        !           615:        }
        !           616:        if (n != 0)
        !           617:                tty_putn(tty, s, n, n);
        !           618: }
        !           619: 
        !           620: /*
        !           621:  * Is the region large enough to be worth redrawing once later rather than
        !           622:  * probably several times now? Currently yes if it is more than 50% of the
        !           623:  * pane.
        !           624:  */
        !           625: static int
        !           626: tty_large_region(__unused struct tty *tty, const struct tty_ctx *ctx)
        !           627: {
        !           628:        struct window_pane      *wp = ctx->wp;
        !           629: 
        !           630:        return (ctx->orlower - ctx->orupper >= screen_size_y(wp->screen) / 2);
        !           631: }
        !           632: 
        !           633: /*
        !           634:  * Return if BCE is needed but the terminal doesn't have it - it'll need to be
        !           635:  * emulated.
        !           636:  */
        !           637: static int
        !           638: tty_fake_bce(const struct tty *tty, const struct window_pane *wp, u_int bg)
        !           639: {
        !           640:        struct grid_cell        gc;
        !           641: 
        !           642:        if (tty_term_flag(tty->term, TTYC_BCE))
        !           643:                return (0);
        !           644: 
        !           645:        memcpy(&gc, &grid_default_cell, sizeof gc);
        !           646:        if (wp != NULL)
        !           647:                tty_default_colours(&gc, wp);
        !           648: 
        !           649:        if (bg != 8 || gc.bg != 8)
        !           650:                return (1);
        !           651:        return (0);
        !           652: }
        !           653: 
        !           654: /*
        !           655:  * Redraw scroll region using data from screen (already updated). Used when
        !           656:  * CSR not supported, or window is a pane that doesn't take up the full
        !           657:  * width of the terminal.
        !           658:  */
        !           659: static void
        !           660: tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx)
        !           661: {
        !           662:        struct window_pane      *wp = ctx->wp;
        !           663:        struct screen           *s = wp->screen;
        !           664:        u_int                    i;
        !           665: 
        !           666:        /*
        !           667:         * If region is large, schedule a window redraw. In most cases this is
        !           668:         * likely to be followed by some more scrolling.
        !           669:         */
        !           670:        if (tty_large_region(tty, ctx)) {
        !           671:                wp->flags |= PANE_REDRAW;
        !           672:                return;
        !           673:        }
        !           674: 
        !           675:        if (ctx->ocy < ctx->orupper || ctx->ocy > ctx->orlower) {
        !           676:                for (i = ctx->ocy; i < screen_size_y(s); i++)
        !           677:                        tty_draw_pane(tty, wp, i, ctx->xoff, ctx->yoff);
        !           678:        } else {
        !           679:                for (i = ctx->orupper; i <= ctx->orlower; i++)
        !           680:                        tty_draw_pane(tty, wp, i, ctx->xoff, ctx->yoff);
        !           681:        }
        !           682: }
        !           683: 
        !           684: void
        !           685: tty_draw_pane(struct tty *tty, const struct window_pane *wp, u_int py, u_int ox,
        !           686:     u_int oy)
        !           687: {
        !           688:        tty_draw_line(tty, wp, wp->screen, py, ox, oy);
        !           689: }
        !           690: 
        !           691: void
        !           692: tty_draw_line(struct tty *tty, const struct window_pane *wp,
        !           693:     struct screen *s, u_int py, u_int ox, u_int oy)
        !           694: {
        !           695:        struct grid_cell         gc, last;
        !           696:        u_int                    i, j, sx, width;
        !           697:        int                      flags, cleared = 0;
        !           698:        char                     buf[512];
        !           699:        size_t                   len;
        !           700: 
        !           701:        flags = (tty->flags & TTY_NOCURSOR);
        !           702:        tty->flags |= TTY_NOCURSOR;
        !           703:        tty_update_mode(tty, tty->mode, s);
        !           704: 
        !           705:        tty_region_off(tty);
        !           706:        tty_margin_off(tty);
        !           707: 
        !           708:        sx = screen_size_x(s);
        !           709:        if (sx > s->grid->linedata[s->grid->hsize + py].cellused)
        !           710:                sx = s->grid->linedata[s->grid->hsize + py].cellused;
        !           711:        if (sx > tty->sx)
        !           712:                sx = tty->sx;
        !           713: 
        !           714:        if (screen_size_x(s) < tty->sx &&
        !           715:            ox == 0 &&
        !           716:            sx != screen_size_x(s) &&
        !           717:            tty_term_has(tty->term, TTYC_EL1) &&
        !           718:            !tty_fake_bce(tty, wp, 8)) {
        !           719:                tty_default_attributes(tty, wp, 8);
        !           720:                tty_cursor(tty, screen_size_x(s) - 1, oy + py);
        !           721:                tty_putcode(tty, TTYC_EL1);
        !           722:                cleared = 1;
        !           723:        }
        !           724:        if (sx != 0)
        !           725:                tty_cursor(tty, ox, oy + py);
        !           726: 
        !           727:        memcpy(&last, &grid_default_cell, sizeof last);
        !           728:        len = 0;
        !           729:        width = 0;
        !           730: 
        !           731:        for (i = 0; i < sx; i++) {
        !           732:                grid_view_get_cell(s->grid, i, py, &gc);
        !           733:                if (len != 0 &&
        !           734:                    (((~tty->flags & TTY_UTF8) &&
        !           735:                    (gc.data.size != 1 ||
        !           736:                    *gc.data.data >= 0x7f ||
        !           737:                    gc.data.width != 1)) ||
        !           738:                    (gc.attr & GRID_ATTR_CHARSET) ||
        !           739:                    gc.flags != last.flags ||
        !           740:                    gc.attr != last.attr ||
        !           741:                    gc.fg != last.fg ||
        !           742:                    gc.bg != last.bg ||
        !           743:                    (sizeof buf) - len < gc.data.size)) {
        !           744:                        tty_attributes(tty, &last, wp);
        !           745:                        tty_putn(tty, buf, len, width);
        !           746: 
        !           747:                        len = 0;
        !           748:                        width = 0;
        !           749:                }
        !           750: 
        !           751:                if (gc.flags & GRID_FLAG_SELECTED)
        !           752:                        screen_select_cell(s, &last, &gc);
        !           753:                else
        !           754:                        memcpy(&last, &gc, sizeof last);
        !           755:                if (((~tty->flags & TTY_UTF8) &&
        !           756:                    (gc.data.size != 1 ||
        !           757:                    *gc.data.data >= 0x7f ||
        !           758:                    gc.data.width != 1)) ||
        !           759:                    (gc.attr & GRID_ATTR_CHARSET)) {
        !           760:                        tty_attributes(tty, &last, wp);
        !           761:                        if (~tty->flags & TTY_UTF8) {
        !           762:                                for (j = 0; j < gc.data.width; j++)
        !           763:                                        tty_putc(tty, '_');
        !           764:                        } else {
        !           765:                                for (j = 0; j < gc.data.size; j++)
        !           766:                                        tty_putc(tty, gc.data.data[j]);
        !           767:                        }
        !           768:                } else {
        !           769:                        memcpy(buf + len, gc.data.data, gc.data.size);
        !           770:                        len += gc.data.size;
        !           771:                        width += gc.data.width;
        !           772:                }
        !           773:        }
        !           774:        if (len != 0) {
        !           775:                tty_attributes(tty, &last, wp);
        !           776:                tty_putn(tty, buf, len, width);
        !           777:        }
        !           778: 
        !           779:        if (!cleared && sx < tty->sx) {
        !           780:                tty_default_attributes(tty, wp, 8);
        !           781:                tty_cursor(tty, ox + sx, oy + py);
        !           782:                if (sx != screen_size_x(s) &&
        !           783:                    ox + screen_size_x(s) >= tty->sx &&
        !           784:                    tty_term_has(tty->term, TTYC_EL) &&
        !           785:                    !tty_fake_bce(tty, wp, 8))
        !           786:                        tty_putcode(tty, TTYC_EL);
        !           787:                else
        !           788:                        tty_repeat_space(tty, screen_size_x(s) - sx);
        !           789:        }
        !           790: 
        !           791:        tty->flags = (tty->flags & ~TTY_NOCURSOR) | flags;
        !           792:        tty_update_mode(tty, tty->mode, s);
        !           793: }
        !           794: 
        !           795: static int
        !           796: tty_client_ready(struct client *c, struct window_pane *wp)
        !           797: {
        !           798:        if (c->session == NULL || c->tty.term == NULL)
        !           799:                return (0);
        !           800:        if (c->flags & (CLIENT_REDRAW|CLIENT_SUSPENDED))
        !           801:                return (0);
        !           802:        if (c->tty.flags & TTY_FREEZE)
        !           803:                return (0);
        !           804:        if (c->session->curw->window != wp->window)
        !           805:                return (0);
        !           806:        return (1);
        !           807: }
        !           808: 
        !           809: void
        !           810: tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *),
        !           811:     struct tty_ctx *ctx)
        !           812: {
        !           813:        struct window_pane      *wp = ctx->wp;
        !           814:        struct client           *c;
        !           815: 
        !           816:        /* wp can be NULL if updating the screen but not the terminal. */
        !           817:        if (wp == NULL)
        !           818:                return;
        !           819: 
        !           820:        if ((wp->flags & (PANE_REDRAW|PANE_DROP)) || !window_pane_visible(wp))
        !           821:                return;
        !           822: 
        !           823:        TAILQ_FOREACH(c, &clients, entry) {
        !           824:                if (!tty_client_ready(c, wp))
        !           825:                        continue;
        !           826: 
        !           827:                ctx->xoff = wp->xoff;
        !           828:                ctx->yoff = wp->yoff;
        !           829:                if (status_at_line(c) == 0)
        !           830:                        ctx->yoff++;
        !           831: 
        !           832:                cmdfn(&c->tty, ctx);
        !           833:        }
        !           834: }
        !           835: 
        !           836: void
        !           837: tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx)
        !           838: {
        !           839:        struct window_pane      *wp = ctx->wp;
        !           840: 
        !           841:        if (!tty_pane_full_width(tty, ctx) ||
        !           842:            tty_fake_bce(tty, wp, ctx->bg) ||
        !           843:            (!tty_term_has(tty->term, TTYC_ICH) &&
        !           844:            !tty_term_has(tty->term, TTYC_ICH1))) {
        !           845:                tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff);
        !           846:                return;
        !           847:        }
        !           848: 
        !           849:        tty_default_attributes(tty, wp, ctx->bg);
        !           850: 
        !           851:        tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
        !           852: 
        !           853:        tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num);
        !           854: }
        !           855: 
        !           856: void
        !           857: tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx)
        !           858: {
        !           859:        struct window_pane      *wp = ctx->wp;
        !           860: 
        !           861:        if (!tty_pane_full_width(tty, ctx) ||
        !           862:            tty_fake_bce(tty, wp, ctx->bg) ||
        !           863:            (!tty_term_has(tty->term, TTYC_DCH) &&
        !           864:            !tty_term_has(tty->term, TTYC_DCH1))) {
        !           865:                tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff);
        !           866:                return;
        !           867:        }
        !           868: 
        !           869:        tty_default_attributes(tty, wp, ctx->bg);
        !           870: 
        !           871:        tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
        !           872: 
        !           873:        tty_emulate_repeat(tty, TTYC_DCH, TTYC_DCH1, ctx->num);
        !           874: }
        !           875: 
        !           876: void
        !           877: tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx)
        !           878: {
        !           879:        tty_attributes(tty, &grid_default_cell, ctx->wp);
        !           880: 
        !           881:        tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
        !           882: 
        !           883:        if (tty_term_has(tty->term, TTYC_ECH) &&
        !           884:            !tty_fake_bce(tty, ctx->wp, 8))
        !           885:                tty_putcode1(tty, TTYC_ECH, ctx->num);
        !           886:        else
        !           887:                tty_repeat_space(tty, ctx->num);
        !           888: }
        !           889: 
        !           890: void
        !           891: tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx)
        !           892: {
        !           893:        if (!tty_pane_full_width(tty, ctx) ||
        !           894:            tty_fake_bce(tty, ctx->wp, ctx->bg) ||
        !           895:            !tty_term_has(tty->term, TTYC_CSR) ||
        !           896:            !tty_term_has(tty->term, TTYC_IL1)) {
        !           897:                tty_redraw_region(tty, ctx);
        !           898:                return;
        !           899:        }
        !           900: 
        !           901:        tty_default_attributes(tty, ctx->wp, ctx->bg);
        !           902: 
        !           903:        tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
        !           904:        tty_margin_off(tty);
        !           905:        tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
        !           906: 
        !           907:        tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ctx->num);
        !           908: }
        !           909: 
        !           910: void
        !           911: tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx)
        !           912: {
        !           913:        if (!tty_pane_full_width(tty, ctx) ||
        !           914:            tty_fake_bce(tty, ctx->wp, ctx->bg) ||
        !           915:            !tty_term_has(tty->term, TTYC_CSR) ||
        !           916:            !tty_term_has(tty->term, TTYC_DL1)) {
        !           917:                tty_redraw_region(tty, ctx);
        !           918:                return;
        !           919:        }
        !           920: 
        !           921:        tty_default_attributes(tty, ctx->wp, ctx->bg);
        !           922: 
        !           923:        tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
        !           924:        tty_margin_off(tty);
        !           925:        tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
        !           926: 
        !           927:        tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ctx->num);
        !           928: }
        !           929: 
        !           930: void
        !           931: tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx)
        !           932: {
        !           933:        struct window_pane      *wp = ctx->wp;
        !           934:        struct screen           *s = wp->screen;
        !           935:        u_int                    sx = screen_size_x(s);
        !           936: 
        !           937:        tty_default_attributes(tty, wp, ctx->bg);
        !           938: 
        !           939:        tty_cursor_pane(tty, ctx, 0, ctx->ocy);
        !           940: 
        !           941:        if (tty_pane_full_width(tty, ctx) &&
        !           942:            !tty_fake_bce(tty, wp, ctx->bg) &&
        !           943:            tty_term_has(tty->term, TTYC_EL))
        !           944:                tty_putcode(tty, TTYC_EL);
        !           945:        else
        !           946:                tty_repeat_space(tty, sx);
        !           947: }
        !           948: 
        !           949: void
        !           950: tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx)
        !           951: {
        !           952:        struct window_pane      *wp = ctx->wp;
        !           953:        struct screen           *s = wp->screen;
        !           954:        u_int                    sx = screen_size_x(s);
        !           955: 
        !           956:        tty_default_attributes(tty, wp, ctx->bg);
        !           957: 
        !           958:        tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
        !           959: 
        !           960:        if (tty_pane_full_width(tty, ctx) &&
        !           961:            tty_term_has(tty->term, TTYC_EL) &&
        !           962:            !tty_fake_bce(tty, wp, ctx->bg))
        !           963:                tty_putcode(tty, TTYC_EL);
        !           964:        else
        !           965:                tty_repeat_space(tty, sx - ctx->ocx);
        !           966: }
        !           967: 
        !           968: void
        !           969: tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx)
        !           970: {
        !           971:        struct window_pane      *wp = ctx->wp;
        !           972: 
        !           973:        tty_default_attributes(tty, wp, ctx->bg);
        !           974: 
        !           975:        if (ctx->xoff == 0 &&
        !           976:            tty_term_has(tty->term, TTYC_EL1) &&
        !           977:            !tty_fake_bce(tty, ctx->wp, ctx->bg)) {
        !           978:                tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
        !           979:                tty_putcode(tty, TTYC_EL1);
        !           980:        } else {
        !           981:                tty_cursor_pane(tty, ctx, 0, ctx->ocy);
        !           982:                tty_repeat_space(tty, ctx->ocx + 1);
        !           983:        }
        !           984: }
        !           985: 
        !           986: void
        !           987: tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx)
        !           988: {
        !           989:        if (ctx->ocy != ctx->orupper)
        !           990:                return;
        !           991: 
        !           992:        if (!tty_pane_full_width(tty, ctx) ||
        !           993:            tty_fake_bce(tty, ctx->wp, 8) ||
        !           994:            !tty_term_has(tty->term, TTYC_CSR) ||
        !           995:            !tty_term_has(tty->term, TTYC_RI)) {
        !           996:                tty_redraw_region(tty, ctx);
        !           997:                return;
        !           998:        }
        !           999: 
        !          1000:        tty_attributes(tty, &grid_default_cell, ctx->wp);
        !          1001: 
        !          1002:        tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
        !          1003:        tty_margin_off(tty);
        !          1004:        tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper);
        !          1005: 
        !          1006:        tty_putcode(tty, TTYC_RI);
        !          1007: }
        !          1008: 
        !          1009: void
        !          1010: tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
        !          1011: {
        !          1012:        struct window_pane      *wp = ctx->wp;
        !          1013: 
        !          1014:        if (ctx->ocy != ctx->orlower)
        !          1015:                return;
        !          1016: 
        !          1017:        if ((!tty_pane_full_width(tty, ctx) && !tty_use_margin(tty)) ||
        !          1018:            tty_fake_bce(tty, wp, 8) ||
        !          1019:            !tty_term_has(tty->term, TTYC_CSR)) {
        !          1020:                tty_redraw_region(tty, ctx);
        !          1021:                return;
        !          1022:        }
        !          1023: 
        !          1024:        tty_attributes(tty, &grid_default_cell, wp);
        !          1025: 
        !          1026:        tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
        !          1027:        tty_margin_pane(tty, ctx);
        !          1028: 
        !          1029:        /*
        !          1030:         * If we want to wrap a pane, the cursor needs to be exactly on the
        !          1031:         * right of the region. But if the pane isn't on the right, it may be
        !          1032:         * off the edge - if so, move the cursor back to the right.
        !          1033:         */
        !          1034:        if (ctx->xoff + ctx->ocx > tty->rright)
        !          1035:                tty_cursor(tty, tty->rright, ctx->yoff + ctx->ocy);
        !          1036:        else
        !          1037:                tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
        !          1038: 
        !          1039:        tty_putc(tty, '\n');
        !          1040: }
        !          1041: 
        !          1042: void
        !          1043: tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx)
        !          1044: {
        !          1045:        struct window_pane      *wp = ctx->wp;
        !          1046:        u_int                    i;
        !          1047: 
        !          1048:        if ((!tty_pane_full_width(tty, ctx) && !tty_use_margin(tty)) ||
        !          1049:            tty_fake_bce(tty, wp, 8) ||
        !          1050:            !tty_term_has(tty->term, TTYC_CSR)) {
        !          1051:                tty_redraw_region(tty, ctx);
        !          1052:                return;
        !          1053:        }
        !          1054: 
        !          1055:        tty_attributes(tty, &grid_default_cell, wp);
        !          1056: 
        !          1057:        tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
        !          1058:        tty_margin_pane(tty, ctx);
        !          1059: 
        !          1060:        if (ctx->num == 1 || !tty_term_has(tty->term, TTYC_INDN)) {
        !          1061:                tty_cursor(tty, tty->rright, tty->rlower);
        !          1062:                for (i = 0; i < ctx->num; i++)
        !          1063:                        tty_putc(tty, '\n');
        !          1064:        } else
        !          1065:                tty_putcode1(tty, TTYC_INDN, ctx->num);
        !          1066: }
        !          1067: 
        !          1068: void
        !          1069: tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx)
        !          1070: {
        !          1071:        struct window_pane      *wp = ctx->wp;
        !          1072:        struct screen           *s = wp->screen;
        !          1073:        u_int                    i, j;
        !          1074:        u_int                    sx = screen_size_x(s), sy = screen_size_y(s);
        !          1075: 
        !          1076:        tty_default_attributes(tty, wp, ctx->bg);
        !          1077: 
        !          1078:        tty_region_pane(tty, ctx, 0, sy - 1);
        !          1079:        tty_margin_off(tty);
        !          1080: 
        !          1081:        if (tty_pane_full_width(tty, ctx) &&
        !          1082:            ctx->yoff + wp->sy >= tty->sy - 1 &&
        !          1083:            status_at_line(tty->client) <= 0 &&
        !          1084:            tty_term_has(tty->term, TTYC_ED)) {
        !          1085:                tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
        !          1086:                tty_putcode(tty, TTYC_ED);
        !          1087:        } else if (tty_pane_full_width(tty, ctx) &&
        !          1088:            tty_term_has(tty->term, TTYC_EL) &&
        !          1089:            !tty_fake_bce(tty, wp, ctx->bg)) {
        !          1090:                tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
        !          1091:                tty_putcode(tty, TTYC_EL);
        !          1092:                if (ctx->ocy != sy - 1) {
        !          1093:                        tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1);
        !          1094:                        for (i = ctx->ocy + 1; i < sy; i++) {
        !          1095:                                tty_putcode(tty, TTYC_EL);
        !          1096:                                if (i == sy - 1)
        !          1097:                                        continue;
        !          1098:                                tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1);
        !          1099:                                tty->cy++;
        !          1100:                        }
        !          1101:                }
        !          1102:        } else {
        !          1103:                tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
        !          1104:                tty_repeat_space(tty, sx - ctx->ocx);
        !          1105:                for (j = ctx->ocy + 1; j < sy; j++) {
        !          1106:                        tty_cursor_pane(tty, ctx, 0, j);
        !          1107:                        tty_repeat_space(tty, sx);
        !          1108:                }
        !          1109:        }
        !          1110: }
        !          1111: 
        !          1112: void
        !          1113: tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx)
        !          1114: {
        !          1115:        struct window_pane      *wp = ctx->wp;
        !          1116:        struct screen           *s = wp->screen;
        !          1117:        u_int                    i, j;
        !          1118:        u_int                    sx = screen_size_x(s), sy = screen_size_y(s);
        !          1119: 
        !          1120:        tty_default_attributes(tty, wp, ctx->bg);
        !          1121: 
        !          1122:        tty_region_pane(tty, ctx, 0, sy - 1);
        !          1123:        tty_margin_off(tty);
        !          1124: 
        !          1125:        if (tty_pane_full_width(tty, ctx) &&
        !          1126:            tty_term_has(tty->term, TTYC_EL) &&
        !          1127:            !tty_fake_bce(tty, wp, ctx->bg)) {
        !          1128:                tty_cursor_pane(tty, ctx, 0, 0);
        !          1129:                for (i = 0; i < ctx->ocy; i++) {
        !          1130:                        tty_putcode(tty, TTYC_EL);
        !          1131:                        tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1);
        !          1132:                        tty->cy++;
        !          1133:                }
        !          1134:        } else {
        !          1135:                tty_cursor_pane(tty, ctx, 0, 0);
        !          1136:                for (j = 0; j < ctx->ocy; j++) {
        !          1137:                        tty_cursor_pane(tty, ctx, 0, j);
        !          1138:                        tty_repeat_space(tty, sx);
        !          1139:                }
        !          1140:        }
        !          1141:        tty_cursor_pane(tty, ctx, 0, ctx->ocy);
        !          1142:        tty_repeat_space(tty, ctx->ocx + 1);
        !          1143: }
        !          1144: 
        !          1145: void
        !          1146: tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx)
        !          1147: {
        !          1148:        struct window_pane      *wp = ctx->wp;
        !          1149:        struct screen           *s = wp->screen;
        !          1150:        u_int                    i, j;
        !          1151:        u_int                    sx = screen_size_x(s), sy = screen_size_y(s);
        !          1152: 
        !          1153:        tty_default_attributes(tty, wp, ctx->bg);
        !          1154: 
        !          1155:        tty_region_pane(tty, ctx, 0, sy - 1);
        !          1156:        tty_margin_off(tty);
        !          1157: 
        !          1158:        if (tty_pane_full_width(tty, ctx) &&
        !          1159:            status_at_line(tty->client) <= 0 &&
        !          1160:            tty_term_has(tty->term, TTYC_ED)) {
        !          1161:                tty_cursor_pane(tty, ctx, 0, 0);
        !          1162:                tty_putcode(tty, TTYC_ED);
        !          1163:        } else if (tty_pane_full_width(tty, ctx) &&
        !          1164:            tty_term_has(tty->term, TTYC_EL) &&
        !          1165:            !tty_fake_bce(tty, wp, ctx->bg)) {
        !          1166:                tty_cursor_pane(tty, ctx, 0, 0);
        !          1167:                for (i = 0; i < sy; i++) {
        !          1168:                        tty_putcode(tty, TTYC_EL);
        !          1169:                        if (i != sy - 1) {
        !          1170:                                tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1);
        !          1171:                                tty->cy++;
        !          1172:                        }
        !          1173:                }
        !          1174:        } else {
        !          1175:                tty_cursor_pane(tty, ctx, 0, 0);
        !          1176:                for (j = 0; j < sy; j++) {
        !          1177:                        tty_cursor_pane(tty, ctx, 0, j);
        !          1178:                        tty_repeat_space(tty, sx);
        !          1179:                }
        !          1180:        }
        !          1181: }
        !          1182: 
        !          1183: void
        !          1184: tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx)
        !          1185: {
        !          1186:        struct window_pane      *wp = ctx->wp;
        !          1187:        struct screen           *s = wp->screen;
        !          1188:        u_int                    i, j;
        !          1189: 
        !          1190:        tty_attributes(tty, &grid_default_cell, wp);
        !          1191: 
        !          1192:        tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1);
        !          1193:        tty_margin_off(tty);
        !          1194: 
        !          1195:        for (j = 0; j < screen_size_y(s); j++) {
        !          1196:                tty_cursor_pane(tty, ctx, 0, j);
        !          1197:                for (i = 0; i < screen_size_x(s); i++)
        !          1198:                        tty_putc(tty, 'E');
        !          1199:        }
        !          1200: }
        !          1201: 
        !          1202: void
        !          1203: tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
        !          1204: {
        !          1205:        if (ctx->xoff + ctx->ocx > tty->sx - 1 && ctx->ocy == ctx->orlower) {
        !          1206:                if (tty_pane_full_width(tty, ctx))
        !          1207:                        tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
        !          1208:                else
        !          1209:                        tty_margin_off(tty);
        !          1210:        }
        !          1211: 
        !          1212:        tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy);
        !          1213: 
        !          1214:        tty_cell(tty, ctx->cell, ctx->wp);
        !          1215: }
        !          1216: 
        !          1217: void
        !          1218: tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
        !          1219: {
        !          1220:        tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy);
        !          1221: 
        !          1222:        tty_attributes(tty, ctx->cell, ctx->wp);
        !          1223:        tty_putn(tty, ctx->ptr, ctx->num, ctx->num);
        !          1224: }
        !          1225: 
        !          1226: void
        !          1227: tty_cmd_setselection(struct tty *tty, const struct tty_ctx *ctx)
        !          1228: {
        !          1229:        char    *buf;
        !          1230:        size_t   off;
        !          1231: 
        !          1232:        if (!tty_term_has(tty->term, TTYC_MS))
        !          1233:                return;
        !          1234: 
        !          1235:        off = 4 * ((ctx->num + 2) / 3) + 1; /* storage for base64 */
        !          1236:        buf = xmalloc(off);
        !          1237: 
        !          1238:        b64_ntop(ctx->ptr, ctx->num, buf, off);
        !          1239:        tty_putcode_ptr2(tty, TTYC_MS, "", buf);
        !          1240: 
        !          1241:        free(buf);
        !          1242: }
        !          1243: 
        !          1244: void
        !          1245: tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx)
        !          1246: {
        !          1247:        tty_add(tty, ctx->ptr, ctx->num);
        !          1248:        tty_invalidate(tty);
        !          1249: }
        !          1250: 
        !          1251: static void
        !          1252: tty_cell(struct tty *tty, const struct grid_cell *gc,
        !          1253:     const struct window_pane *wp)
        !          1254: {
        !          1255:        u_int   i;
        !          1256: 
        !          1257:        /* Skip last character if terminal is stupid. */
        !          1258:        if ((tty->term->flags & TERM_EARLYWRAP) &&
        !          1259:            tty->cy == tty->sy - 1 &&
        !          1260:            tty->cx == tty->sx - 1)
        !          1261:                return;
        !          1262: 
        !          1263:        /* If this is a padding character, do nothing. */
        !          1264:        if (gc->flags & GRID_FLAG_PADDING)
        !          1265:                return;
        !          1266: 
        !          1267:        /* Set the attributes. */
        !          1268:        tty_attributes(tty, gc, wp);
        !          1269: 
        !          1270:        /* Get the cell and if ASCII write with putc to do ACS translation. */
        !          1271:        if (gc->data.size == 1) {
        !          1272:                if (*gc->data.data < 0x20 || *gc->data.data == 0x7f)
        !          1273:                        return;
        !          1274:                tty_putc(tty, *gc->data.data);
        !          1275:                return;
        !          1276:        }
        !          1277: 
        !          1278:        /* If not UTF-8, write _. */
        !          1279:        if (!(tty->flags & TTY_UTF8)) {
        !          1280:                for (i = 0; i < gc->data.width; i++)
        !          1281:                        tty_putc(tty, '_');
        !          1282:                return;
        !          1283:        }
        !          1284: 
        !          1285:        /* Write the data. */
        !          1286:        tty_putn(tty, gc->data.data, gc->data.size, gc->data.width);
        !          1287: }
        !          1288: 
        !          1289: void
        !          1290: tty_reset(struct tty *tty)
        !          1291: {
        !          1292:        struct grid_cell        *gc = &tty->cell;
        !          1293: 
        !          1294:        if (!grid_cells_equal(gc, &grid_default_cell)) {
        !          1295:                if ((gc->attr & GRID_ATTR_CHARSET) && tty_use_acs(tty))
        !          1296:                        tty_putcode(tty, TTYC_RMACS);
        !          1297:                tty_putcode(tty, TTYC_SGR0);
        !          1298:                memcpy(gc, &grid_default_cell, sizeof *gc);
        !          1299:        }
        !          1300: 
        !          1301:        memcpy(&tty->last_cell, &grid_default_cell, sizeof tty->last_cell);
        !          1302:        tty->last_wp = -1;
        !          1303: }
        !          1304: 
        !          1305: static void
        !          1306: tty_invalidate(struct tty *tty)
        !          1307: {
        !          1308:        memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell);
        !          1309: 
        !          1310:        memcpy(&tty->last_cell, &grid_default_cell, sizeof tty->last_cell);
        !          1311:        tty->last_wp = -1;
        !          1312: 
        !          1313:        tty->cx = tty->cy = UINT_MAX;
        !          1314: 
        !          1315:        tty->rupper = tty->rleft = UINT_MAX;
        !          1316:        tty->rlower = tty->rright = UINT_MAX;
        !          1317: 
        !          1318:        if (tty->flags & TTY_STARTED) {
        !          1319:                tty_putcode(tty, TTYC_SGR0);
        !          1320: 
        !          1321:                tty->mode = ALL_MODES;
        !          1322:                tty_update_mode(tty, MODE_CURSOR, NULL);
        !          1323: 
        !          1324:                tty_cursor(tty, 0, 0);
        !          1325:                tty_region_off(tty);
        !          1326:                tty_margin_off(tty);
        !          1327:        } else
        !          1328:                tty->mode = MODE_CURSOR;
        !          1329: }
        !          1330: 
        !          1331: /* Turn off margin. */
        !          1332: void
        !          1333: tty_region_off(struct tty *tty)
        !          1334: {
        !          1335:        tty_region(tty, 0, tty->sy - 1);
        !          1336: }
        !          1337: 
        !          1338: /* Set region inside pane. */
        !          1339: static void
        !          1340: tty_region_pane(struct tty *tty, const struct tty_ctx *ctx, u_int rupper,
        !          1341:     u_int rlower)
        !          1342: {
        !          1343:        tty_region(tty, ctx->yoff + rupper, ctx->yoff + rlower);
        !          1344: }
        !          1345: 
        !          1346: /* Set region at absolute position. */
        !          1347: static void
        !          1348: tty_region(struct tty *tty, u_int rupper, u_int rlower)
        !          1349: {
        !          1350:        if (tty->rlower == rlower && tty->rupper == rupper)
        !          1351:                return;
        !          1352:        if (!tty_term_has(tty->term, TTYC_CSR))
        !          1353:                return;
        !          1354: 
        !          1355:        tty->rupper = rupper;
        !          1356:        tty->rlower = rlower;
        !          1357: 
        !          1358:        /*
        !          1359:         * Some terminals (such as PuTTY) do not correctly reset the cursor to
        !          1360:         * 0,0 if it is beyond the last column (they do not reset their wrap
        !          1361:         * flag so further output causes a line feed). As a workaround, do an
        !          1362:         * explicit move to 0 first.
        !          1363:         */
        !          1364:        if (tty->cx >= tty->sx)
        !          1365:                tty_cursor(tty, 0, tty->cy);
        !          1366: 
        !          1367:        tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower);
        !          1368:        tty->cx = tty->cy = UINT_MAX;
        !          1369: }
        !          1370: 
        !          1371: /* Turn off margin. */
        !          1372: void
        !          1373: tty_margin_off(struct tty *tty)
        !          1374: {
        !          1375:        tty_margin(tty, 0, tty->sx - 1);
        !          1376: }
        !          1377: 
        !          1378: /* Set margin inside pane. */
        !          1379: static void
        !          1380: tty_margin_pane(struct tty *tty, const struct tty_ctx *ctx)
        !          1381: {
        !          1382:        tty_margin(tty, ctx->xoff, ctx->xoff + ctx->wp->sx - 1);
        !          1383: }
        !          1384: 
        !          1385: /* Set margin at absolute position. */
        !          1386: static void
        !          1387: tty_margin(struct tty *tty, u_int rleft, u_int rright)
        !          1388: {
        !          1389:        char s[64];
        !          1390: 
        !          1391:        if (!tty_use_margin(tty))
        !          1392:                return;
        !          1393:        if (tty->rleft == rleft && tty->rright == rright)
        !          1394:                return;
        !          1395: 
        !          1396:        tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower);
        !          1397: 
        !          1398:        tty->rleft = rleft;
        !          1399:        tty->rright = rright;
        !          1400: 
        !          1401:        if (rleft == 0 && rright == tty->sx - 1)
        !          1402:                snprintf(s, sizeof s, "\033[s");
        !          1403:        else
        !          1404:                snprintf(s, sizeof s, "\033[%u;%us", rleft + 1, rright + 1);
        !          1405:        tty_puts(tty, s);
        !          1406:        tty->cx = tty->cy = UINT_MAX;
        !          1407: }
        !          1408: 
        !          1409: /*
        !          1410:  * Move the cursor, unless it would wrap itself when the next character is
        !          1411:  * printed.
        !          1412:  */
        !          1413: static void
        !          1414: tty_cursor_pane_unless_wrap(struct tty *tty, const struct tty_ctx *ctx,
        !          1415:     u_int cx, u_int cy)
        !          1416: {
        !          1417:        if (!tty_pane_full_width(tty, ctx) ||
        !          1418:            (tty->term->flags & TERM_EARLYWRAP) ||
        !          1419:            ctx->xoff + cx != 0 ||
        !          1420:            ctx->yoff + cy != tty->cy + 1 ||
        !          1421:            tty->cx < tty->sx ||
        !          1422:            tty->cy == tty->rlower)
        !          1423:                tty_cursor_pane(tty, ctx, cx, cy);
        !          1424:        else
        !          1425:                log_debug("%s: will wrap at %u,%u", __func__, tty->cx, tty->cy);
        !          1426: }
        !          1427: 
        !          1428: /* Move cursor inside pane. */
        !          1429: static void
        !          1430: tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy)
        !          1431: {
        !          1432:        tty_cursor(tty, ctx->xoff + cx, ctx->yoff + cy);
        !          1433: }
        !          1434: 
        !          1435: /* Move cursor to absolute position. */
        !          1436: void
        !          1437: tty_cursor(struct tty *tty, u_int cx, u_int cy)
        !          1438: {
        !          1439:        struct tty_term *term = tty->term;
        !          1440:        u_int            thisx, thisy;
        !          1441:        int              change;
        !          1442: 
        !          1443:        if (cx > tty->sx - 1)
        !          1444:                cx = tty->sx - 1;
        !          1445: 
        !          1446:        thisx = tty->cx;
        !          1447:        thisy = tty->cy;
        !          1448: 
        !          1449:        /* No change. */
        !          1450:        if (cx == thisx && cy == thisy)
        !          1451:                return;
        !          1452: 
        !          1453:        /* Very end of the line, just use absolute movement. */
        !          1454:        if (thisx > tty->sx - 1)
        !          1455:                goto absolute;
        !          1456: 
        !          1457:        /* Move to home position (0, 0). */
        !          1458:        if (cx == 0 && cy == 0 && tty_term_has(term, TTYC_HOME)) {
        !          1459:                tty_putcode(tty, TTYC_HOME);
        !          1460:                goto out;
        !          1461:        }
        !          1462: 
        !          1463:        /* Zero on the next line. */
        !          1464:        if (cx == 0 && cy == thisy + 1 && thisy != tty->rlower) {
        !          1465:                tty_putc(tty, '\r');
        !          1466:                tty_putc(tty, '\n');
        !          1467:                goto out;
        !          1468:        }
        !          1469: 
        !          1470:        /* Moving column or row. */
        !          1471:        if (cy == thisy) {
        !          1472:                /*
        !          1473:                 * Moving column only, row staying the same.
        !          1474:                 */
        !          1475: 
        !          1476:                /* To left edge. */
        !          1477:                if (cx == 0) {
        !          1478:                        tty_putc(tty, '\r');
        !          1479:                        goto out;
        !          1480:                }
        !          1481: 
        !          1482:                /* One to the left. */
        !          1483:                if (cx == thisx - 1 && tty_term_has(term, TTYC_CUB1)) {
        !          1484:                        tty_putcode(tty, TTYC_CUB1);
        !          1485:                        goto out;
        !          1486:                }
        !          1487: 
        !          1488:                /* One to the right. */
        !          1489:                if (cx == thisx + 1 && tty_term_has(term, TTYC_CUF1)) {
        !          1490:                        tty_putcode(tty, TTYC_CUF1);
        !          1491:                        goto out;
        !          1492:                }
        !          1493: 
        !          1494:                /* Calculate difference. */
        !          1495:                change = thisx - cx;    /* +ve left, -ve right */
        !          1496: 
        !          1497:                /*
        !          1498:                 * Use HPA if change is larger than absolute, otherwise move
        !          1499:                 * the cursor with CUB/CUF.
        !          1500:                 */
        !          1501:                if ((u_int) abs(change) > cx && tty_term_has(term, TTYC_HPA)) {
        !          1502:                        tty_putcode1(tty, TTYC_HPA, cx);
        !          1503:                        goto out;
        !          1504:                } else if (change > 0 && tty_term_has(term, TTYC_CUB)) {
        !          1505:                        if (change == 2 && tty_term_has(term, TTYC_CUB1)) {
        !          1506:                                tty_putcode(tty, TTYC_CUB1);
        !          1507:                                tty_putcode(tty, TTYC_CUB1);
        !          1508:                                goto out;
        !          1509:                        }
        !          1510:                        tty_putcode1(tty, TTYC_CUB, change);
        !          1511:                        goto out;
        !          1512:                } else if (change < 0 && tty_term_has(term, TTYC_CUF)) {
        !          1513:                        tty_putcode1(tty, TTYC_CUF, -change);
        !          1514:                        goto out;
        !          1515:                }
        !          1516:        } else if (cx == thisx) {
        !          1517:                /*
        !          1518:                 * Moving row only, column staying the same.
        !          1519:                 */
        !          1520: 
        !          1521:                /* One above. */
        !          1522:                if (thisy != tty->rupper &&
        !          1523:                    cy == thisy - 1 && tty_term_has(term, TTYC_CUU1)) {
        !          1524:                        tty_putcode(tty, TTYC_CUU1);
        !          1525:                        goto out;
        !          1526:                }
        !          1527: 
        !          1528:                /* One below. */
        !          1529:                if (thisy != tty->rlower &&
        !          1530:                    cy == thisy + 1 && tty_term_has(term, TTYC_CUD1)) {
        !          1531:                        tty_putcode(tty, TTYC_CUD1);
        !          1532:                        goto out;
        !          1533:                }
        !          1534: 
        !          1535:                /* Calculate difference. */
        !          1536:                change = thisy - cy;    /* +ve up, -ve down */
        !          1537: 
        !          1538:                /*
        !          1539:                 * Try to use VPA if change is larger than absolute or if this
        !          1540:                 * change would cross the scroll region, otherwise use CUU/CUD.
        !          1541:                 */
        !          1542:                if ((u_int) abs(change) > cy ||
        !          1543:                    (change < 0 && cy - change > tty->rlower) ||
        !          1544:                    (change > 0 && cy - change < tty->rupper)) {
        !          1545:                            if (tty_term_has(term, TTYC_VPA)) {
        !          1546:                                    tty_putcode1(tty, TTYC_VPA, cy);
        !          1547:                                    goto out;
        !          1548:                            }
        !          1549:                } else if (change > 0 && tty_term_has(term, TTYC_CUU)) {
        !          1550:                        tty_putcode1(tty, TTYC_CUU, change);
        !          1551:                        goto out;
        !          1552:                } else if (change < 0 && tty_term_has(term, TTYC_CUD)) {
        !          1553:                        tty_putcode1(tty, TTYC_CUD, -change);
        !          1554:                        goto out;
        !          1555:                }
        !          1556:        }
        !          1557: 
        !          1558: absolute:
        !          1559:        /* Absolute movement. */
        !          1560:        tty_putcode2(tty, TTYC_CUP, cy, cx);
        !          1561: 
        !          1562: out:
        !          1563:        tty->cx = cx;
        !          1564:        tty->cy = cy;
        !          1565: }
        !          1566: 
        !          1567: void
        !          1568: tty_attributes(struct tty *tty, const struct grid_cell *gc,
        !          1569:     const struct window_pane *wp)
        !          1570: {
        !          1571:        struct grid_cell        *tc = &tty->cell, gc2;
        !          1572:        int                      changed;
        !          1573: 
        !          1574:        /* Ignore cell if it is the same as the last one. */
        !          1575:        if (wp != NULL &&
        !          1576:            (int)wp->id == tty->last_wp &&
        !          1577:            ~(wp->window->flags & WINDOW_STYLECHANGED) &&
        !          1578:            gc->attr == tty->last_cell.attr &&
        !          1579:            gc->fg == tty->last_cell.fg &&
        !          1580:            gc->bg == tty->last_cell.bg)
        !          1581:                return;
        !          1582:        tty->last_wp = (wp != NULL ? (int)wp->id : -1);
        !          1583:        memcpy(&tty->last_cell, gc, sizeof tty->last_cell);
        !          1584: 
        !          1585:        /* Copy cell and update default colours. */
        !          1586:        memcpy(&gc2, gc, sizeof gc2);
        !          1587:        if (wp != NULL)
        !          1588:                tty_default_colours(&gc2, wp);
        !          1589: 
        !          1590:        /*
        !          1591:         * If no setab, try to use the reverse attribute as a best-effort for a
        !          1592:         * non-default background. This is a bit of a hack but it doesn't do
        !          1593:         * any serious harm and makes a couple of applications happier.
        !          1594:         */
        !          1595:        if (!tty_term_has(tty->term, TTYC_SETAB)) {
        !          1596:                if (gc2.attr & GRID_ATTR_REVERSE) {
        !          1597:                        if (gc2.fg != 7 && gc2.fg != 8)
        !          1598:                                gc2.attr &= ~GRID_ATTR_REVERSE;
        !          1599:                } else {
        !          1600:                        if (gc2.bg != 0 && gc2.bg != 8)
        !          1601:                                gc2.attr |= GRID_ATTR_REVERSE;
        !          1602:                }
        !          1603:        }
        !          1604: 
        !          1605:        /* Fix up the colours if necessary. */
        !          1606:        tty_check_fg(tty, wp, &gc2);
        !          1607:        tty_check_bg(tty, wp, &gc2);
        !          1608: 
        !          1609:        /* If any bits are being cleared, reset everything. */
        !          1610:        if (tc->attr & ~gc2.attr)
        !          1611:                tty_reset(tty);
        !          1612: 
        !          1613:        /*
        !          1614:         * Set the colours. This may call tty_reset() (so it comes next) and
        !          1615:         * may add to (NOT remove) the desired attributes by changing new_attr.
        !          1616:         */
        !          1617:        tty_colours(tty, &gc2);
        !          1618: 
        !          1619:        /* Filter out attribute bits already set. */
        !          1620:        changed = gc2.attr & ~tc->attr;
        !          1621:        tc->attr = gc2.attr;
        !          1622: 
        !          1623:        /* Set the attributes. */
        !          1624:        if (changed & GRID_ATTR_BRIGHT)
        !          1625:                tty_putcode(tty, TTYC_BOLD);
        !          1626:        if (changed & GRID_ATTR_DIM)
        !          1627:                tty_putcode(tty, TTYC_DIM);
        !          1628:        if (changed & GRID_ATTR_ITALICS)
        !          1629:                tty_set_italics(tty);
        !          1630:        if (changed & GRID_ATTR_UNDERSCORE)
        !          1631:                tty_putcode(tty, TTYC_SMUL);
        !          1632:        if (changed & GRID_ATTR_BLINK)
        !          1633:                tty_putcode(tty, TTYC_BLINK);
        !          1634:        if (changed & GRID_ATTR_REVERSE) {
        !          1635:                if (tty_term_has(tty->term, TTYC_REV))
        !          1636:                        tty_putcode(tty, TTYC_REV);
        !          1637:                else if (tty_term_has(tty->term, TTYC_SMSO))
        !          1638:                        tty_putcode(tty, TTYC_SMSO);
        !          1639:        }
        !          1640:        if (changed & GRID_ATTR_HIDDEN)
        !          1641:                tty_putcode(tty, TTYC_INVIS);
        !          1642:        if (changed & GRID_ATTR_STRIKETHROUGH)
        !          1643:                tty_putcode(tty, TTYC_SMXX);
        !          1644:        if ((changed & GRID_ATTR_CHARSET) && tty_use_acs(tty))
        !          1645:                tty_putcode(tty, TTYC_SMACS);
        !          1646: }
        !          1647: 
        !          1648: static void
        !          1649: tty_colours(struct tty *tty, const struct grid_cell *gc)
        !          1650: {
        !          1651:        struct grid_cell        *tc = &tty->cell;
        !          1652:        int                      have_ax;
        !          1653: 
        !          1654:        /* No changes? Nothing is necessary. */
        !          1655:        if (gc->fg == tc->fg && gc->bg == tc->bg)
        !          1656:                return;
        !          1657: 
        !          1658:        /*
        !          1659:         * Is either the default colour? This is handled specially because the
        !          1660:         * best solution might be to reset both colours to default, in which
        !          1661:         * case if only one is default need to fall onward to set the other
        !          1662:         * colour.
        !          1663:         */
        !          1664:        if (gc->fg == 8 || gc->bg == 8) {
        !          1665:                /*
        !          1666:                 * If don't have AX but do have op, send sgr0 (op can't
        !          1667:                 * actually be used because it is sometimes the same as sgr0
        !          1668:                 * and sometimes isn't). This resets both colours to default.
        !          1669:                 *
        !          1670:                 * Otherwise, try to set the default colour only as needed.
        !          1671:                 */
        !          1672:                have_ax = tty_term_flag(tty->term, TTYC_AX);
        !          1673:                if (!have_ax && tty_term_has(tty->term, TTYC_OP))
        !          1674:                        tty_reset(tty);
        !          1675:                else {
        !          1676:                        if (gc->fg == 8 && tc->fg != 8) {
        !          1677:                                if (have_ax)
        !          1678:                                        tty_puts(tty, "\033[39m");
        !          1679:                                else if (tc->fg != 7)
        !          1680:                                        tty_putcode1(tty, TTYC_SETAF, 7);
        !          1681:                                tc->fg = 8;
        !          1682:                        }
        !          1683:                        if (gc->bg == 8 && tc->bg != 8) {
        !          1684:                                if (have_ax)
        !          1685:                                        tty_puts(tty, "\033[49m");
        !          1686:                                else if (tc->bg != 0)
        !          1687:                                        tty_putcode1(tty, TTYC_SETAB, 0);
        !          1688:                                tc->bg = 8;
        !          1689:                        }
        !          1690:                }
        !          1691:        }
        !          1692: 
        !          1693:        /* Set the foreground colour. */
        !          1694:        if (gc->fg != 8 && gc->fg != tc->fg)
        !          1695:                tty_colours_fg(tty, gc);
        !          1696: 
        !          1697:        /*
        !          1698:         * Set the background colour. This must come after the foreground as
        !          1699:         * tty_colour_fg() can call tty_reset().
        !          1700:         */
        !          1701:        if (gc->bg != 8 && gc->bg != tc->bg)
        !          1702:                tty_colours_bg(tty, gc);
        !          1703: }
        !          1704: 
        !          1705: static void
        !          1706: tty_check_fg(struct tty *tty, const struct window_pane *wp,
        !          1707:     struct grid_cell *gc)
        !          1708: {
        !          1709:        u_char  r, g, b;
        !          1710:        u_int   colours;
        !          1711:        int     c;
        !          1712: 
        !          1713:        /* Perform substitution if this pane has a palette */
        !          1714:        if ((~gc->flags & GRID_FLAG_NOPALETTE) &&
        !          1715:            (c = window_pane_get_palette(wp, gc->fg)) != -1)
        !          1716:                gc->fg = c;
        !          1717: 
        !          1718:        /* Is this a 24-bit colour? */
        !          1719:        if (gc->fg & COLOUR_FLAG_RGB) {
        !          1720:                /* Not a 24-bit terminal? Translate to 256-colour palette. */
        !          1721:                if (!tty_term_flag(tty->term, TTYC_TC)) {
        !          1722:                        colour_split_rgb(gc->fg, &r, &g, &b);
        !          1723:                        gc->fg = colour_find_rgb(r, g, b);
        !          1724:                } else
        !          1725:                        return;
        !          1726:        }
        !          1727: 
        !          1728:        /* How many colours does this terminal have? */
        !          1729:        if ((tty->term->flags|tty->term_flags) & TERM_256COLOURS)
        !          1730:                colours = 256;
        !          1731:        else
        !          1732:                colours = tty_term_number(tty->term, TTYC_COLORS);
        !          1733: 
        !          1734:        /* Is this a 256-colour colour? */
        !          1735:        if (gc->fg & COLOUR_FLAG_256) {
        !          1736:                /* And not a 256 colour mode? */
        !          1737:                if (colours != 256) {
        !          1738:                        gc->fg = colour_256to16(gc->fg);
        !          1739:                        if (gc->fg & 8) {
        !          1740:                                gc->fg &= 7;
        !          1741:                                if (colours >= 16)
        !          1742:                                        gc->fg += 90;
        !          1743:                                else
        !          1744:                                        gc->attr |= GRID_ATTR_BRIGHT;
        !          1745:                        } else
        !          1746:                                gc->attr &= ~GRID_ATTR_BRIGHT;
        !          1747:                }
        !          1748:                return;
        !          1749:        }
        !          1750: 
        !          1751:        /* Is this an aixterm colour? */
        !          1752:        if (gc->fg >= 90 && gc->fg <= 97 && colours < 16) {
        !          1753:                gc->fg -= 90;
        !          1754:                gc->attr |= GRID_ATTR_BRIGHT;
        !          1755:        }
        !          1756: }
        !          1757: 
        !          1758: static void
        !          1759: tty_check_bg(struct tty *tty, const struct window_pane *wp,
        !          1760:     struct grid_cell *gc)
        !          1761: {
        !          1762:        u_char  r, g, b;
        !          1763:        u_int   colours;
        !          1764:        int     c;
        !          1765: 
        !          1766:        /* Perform substitution if this pane has a palette */
        !          1767:        if ((~gc->flags & GRID_FLAG_NOPALETTE) &&
        !          1768:            (c = window_pane_get_palette(wp, gc->bg)) != -1)
        !          1769:                gc->bg = c;
        !          1770: 
        !          1771:        /* Is this a 24-bit colour? */
        !          1772:        if (gc->bg & COLOUR_FLAG_RGB) {
        !          1773:                /* Not a 24-bit terminal? Translate to 256-colour palette. */
        !          1774:                if (!tty_term_flag(tty->term, TTYC_TC)) {
        !          1775:                        colour_split_rgb(gc->bg, &r, &g, &b);
        !          1776:                        gc->bg = colour_find_rgb(r, g, b);
        !          1777:                } else
        !          1778:                        return;
        !          1779:        }
        !          1780: 
        !          1781:        /* How many colours does this terminal have? */
        !          1782:        if ((tty->term->flags|tty->term_flags) & TERM_256COLOURS)
        !          1783:                colours = 256;
        !          1784:        else
        !          1785:                colours = tty_term_number(tty->term, TTYC_COLORS);
        !          1786: 
        !          1787:        /* Is this a 256-colour colour? */
        !          1788:        if (gc->bg & COLOUR_FLAG_256) {
        !          1789:                /*
        !          1790:                 * And not a 256 colour mode? Translate to 16-colour
        !          1791:                 * palette. Bold background doesn't exist portably, so just
        !          1792:                 * discard the bold bit if set.
        !          1793:                 */
        !          1794:                if (colours != 256) {
        !          1795:                        gc->bg = colour_256to16(gc->bg);
        !          1796:                        if (gc->bg & 8) {
        !          1797:                                gc->bg &= 7;
        !          1798:                                if (colours >= 16)
        !          1799:                                        gc->fg += 90;
        !          1800:                        }
        !          1801:                }
        !          1802:                return;
        !          1803:        }
        !          1804: 
        !          1805:        /* Is this an aixterm colour? */
        !          1806:        if (gc->bg >= 90 && gc->bg <= 97 && colours < 16)
        !          1807:                gc->bg -= 90;
        !          1808: }
        !          1809: 
        !          1810: static void
        !          1811: tty_colours_fg(struct tty *tty, const struct grid_cell *gc)
        !          1812: {
        !          1813:        struct grid_cell        *tc = &tty->cell;
        !          1814:        char                     s[32];
        !          1815: 
        !          1816:        /* Is this a 24-bit or 256-colour colour? */
        !          1817:        if (gc->fg & COLOUR_FLAG_RGB ||
        !          1818:            gc->fg & COLOUR_FLAG_256) {
        !          1819:                if (tty_try_colour(tty, gc->fg, "38") == 0)
        !          1820:                        goto save_fg;
        !          1821:                /* Should not get here, already converted in tty_check_fg. */
        !          1822:                return;
        !          1823:        }
        !          1824: 
        !          1825:        /* Is this an aixterm bright colour? */
        !          1826:        if (gc->fg >= 90 && gc->fg <= 97) {
        !          1827:                xsnprintf(s, sizeof s, "\033[%dm", gc->fg);
        !          1828:                tty_puts(tty, s);
        !          1829:                goto save_fg;
        !          1830:        }
        !          1831: 
        !          1832:        /* Otherwise set the foreground colour. */
        !          1833:        tty_putcode1(tty, TTYC_SETAF, gc->fg);
        !          1834: 
        !          1835: save_fg:
        !          1836:        /* Save the new values in the terminal current cell. */
        !          1837:        tc->fg = gc->fg;
        !          1838: }
        !          1839: 
        !          1840: static void
        !          1841: tty_colours_bg(struct tty *tty, const struct grid_cell *gc)
        !          1842: {
        !          1843:        struct grid_cell        *tc = &tty->cell;
        !          1844:        char                     s[32];
        !          1845: 
        !          1846:        /* Is this a 24-bit or 256-colour colour? */
        !          1847:        if (gc->bg & COLOUR_FLAG_RGB ||
        !          1848:            gc->bg & COLOUR_FLAG_256) {
        !          1849:                if (tty_try_colour(tty, gc->bg, "48") == 0)
        !          1850:                        goto save_bg;
        !          1851:                /* Should not get here, already converted in tty_check_bg. */
        !          1852:                return;
        !          1853:        }
        !          1854: 
        !          1855:        /* Is this an aixterm bright colour? */
        !          1856:        if (gc->bg >= 90 && gc->bg <= 97) {
        !          1857:                xsnprintf(s, sizeof s, "\033[%dm", gc->bg + 10);
        !          1858:                tty_puts(tty, s);
        !          1859:                goto save_bg;
        !          1860:        }
        !          1861: 
        !          1862:        /* Otherwise set the background colour. */
        !          1863:        tty_putcode1(tty, TTYC_SETAB, gc->bg);
        !          1864: 
        !          1865: save_bg:
        !          1866:        /* Save the new values in the terminal current cell. */
        !          1867:        tc->bg = gc->bg;
        !          1868: }
        !          1869: 
        !          1870: static int
        !          1871: tty_try_colour(struct tty *tty, int colour, const char *type)
        !          1872: {
        !          1873:        u_char  r, g, b;
        !          1874:        char    s[32];
        !          1875: 
        !          1876:        if (colour & COLOUR_FLAG_256) {
        !          1877:                /*
        !          1878:                 * If the user has specified -2 to the client, setaf and setab
        !          1879:                 * may not work (or they may not want to use them), so send the
        !          1880:                 * usual sequence.
        !          1881:                 */
        !          1882:                if (tty->term_flags & TERM_256COLOURS)
        !          1883:                        goto fallback_256;
        !          1884: 
        !          1885:                /*
        !          1886:                 * If the terminfo entry has 256 colours and setaf and setab
        !          1887:                 * exist, assume that they work correctly.
        !          1888:                 */
        !          1889:                if (tty->term->flags & TERM_256COLOURS) {
        !          1890:                        if (*type == '3') {
        !          1891:                                if (!tty_term_has(tty->term, TTYC_SETAF))
        !          1892:                                        goto fallback_256;
        !          1893:                                tty_putcode1(tty, TTYC_SETAF, colour & 0xff);
        !          1894:                        } else {
        !          1895:                                if (!tty_term_has(tty->term, TTYC_SETAB))
        !          1896:                                        goto fallback_256;
        !          1897:                                tty_putcode1(tty, TTYC_SETAB, colour & 0xff);
        !          1898:                        }
        !          1899:                        return (0);
        !          1900:                }
        !          1901:                goto fallback_256;
        !          1902:        }
        !          1903: 
        !          1904:        if (colour & COLOUR_FLAG_RGB) {
        !          1905:                if (!tty_term_flag(tty->term, TTYC_TC))
        !          1906:                        return (-1);
        !          1907: 
        !          1908:                colour_split_rgb(colour & 0xffffff, &r, &g, &b);
        !          1909:                xsnprintf(s, sizeof s, "\033[%s;2;%hhu;%hhu;%hhum", type,
        !          1910:                    r, g, b);
        !          1911:                tty_puts(tty, s);
        !          1912:                return (0);
        !          1913:        }
        !          1914: 
        !          1915:        return (-1);
        !          1916: 
        !          1917: fallback_256:
        !          1918:        xsnprintf(s, sizeof s, "\033[%s;5;%dm", type, colour & 0xff);
        !          1919:        tty_puts(tty, s);
        !          1920:        return (0);
        !          1921: }
        !          1922: 
        !          1923: static void
        !          1924: tty_default_colours(struct grid_cell *gc, const struct window_pane *wp)
        !          1925: {
        !          1926:        struct window           *w = wp->window;
        !          1927:        struct options          *oo = w->options;
        !          1928:        const struct grid_cell  *agc, *pgc, *wgc;
        !          1929:        int                      c;
        !          1930: 
        !          1931:        if (w->flags & WINDOW_STYLECHANGED) {
        !          1932:                w->flags &= ~WINDOW_STYLECHANGED;
        !          1933:                agc = options_get_style(oo, "window-active-style");
        !          1934:                memcpy(&w->active_style, agc, sizeof w->active_style);
        !          1935:                wgc = options_get_style(oo, "window-style");
        !          1936:                memcpy(&w->style, wgc, sizeof w->style);
        !          1937:        } else {
        !          1938:                agc = &w->active_style;
        !          1939:                wgc = &w->style;
        !          1940:        }
        !          1941:        pgc = &wp->colgc;
        !          1942: 
        !          1943:        if (gc->fg == 8) {
        !          1944:                if (pgc->fg != 8)
        !          1945:                        gc->fg = pgc->fg;
        !          1946:                else if (wp == w->active && agc->fg != 8)
        !          1947:                        gc->fg = agc->fg;
        !          1948:                else
        !          1949:                        gc->fg = wgc->fg;
        !          1950: 
        !          1951:                if (gc->fg != 8 &&
        !          1952:                    (c = window_pane_get_palette(wp, gc->fg)) != -1)
        !          1953:                        gc->fg = c;
        !          1954:        }
        !          1955: 
        !          1956:        if (gc->bg == 8) {
        !          1957:                if (pgc->bg != 8)
        !          1958:                        gc->bg = pgc->bg;
        !          1959:                else if (wp == w->active && agc->bg != 8)
        !          1960:                        gc->bg = agc->bg;
        !          1961:                else
        !          1962:                        gc->bg = wgc->bg;
        !          1963: 
        !          1964:                if (gc->bg != 8 &&
        !          1965:                    (c = window_pane_get_palette(wp, gc->bg)) != -1)
        !          1966:                        gc->bg = c;
        !          1967:        }
        !          1968: }
        !          1969: 
        !          1970: static void
        !          1971: tty_default_attributes(struct tty *tty, const struct window_pane *wp, u_int bg)
        !          1972: {
        !          1973:        static struct grid_cell gc;
        !          1974: 
        !          1975:        memcpy(&gc, &grid_default_cell, sizeof gc);
        !          1976:        gc.bg = bg;
        !          1977:        tty_attributes(tty, &gc, wp);
        !          1978: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>