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