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