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