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