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