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