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