File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / tty.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (6 years, 11 months ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

    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>