1/* $OpenBSD: tty.c,v 1.436 2024/05/14 10:11:09 nicm Exp $ */
2
3/*
4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/ioctl.h>
21
22#include <netinet/in.h>
23
24#include <curses.h>
25#include <errno.h>
26#include <fcntl.h>
27#include <resolv.h>
28#include <stdlib.h>
29#include <string.h>
30#include <termios.h>
31#include <time.h>
32#include <unistd.h>
33
34#include "tmux.h"
35
36static int	tty_log_fd = -1;
37
38static void	tty_set_italics(struct tty *);
39static int	tty_try_colour(struct tty *, int, const char *);
40static void	tty_force_cursor_colour(struct tty *, int);
41static void	tty_cursor_pane(struct tty *, const struct tty_ctx *, u_int,
42		    u_int);
43static void	tty_cursor_pane_unless_wrap(struct tty *,
44		    const struct tty_ctx *, u_int, u_int);
45static void	tty_invalidate(struct tty *);
46static void	tty_colours(struct tty *, const struct grid_cell *);
47static void	tty_check_fg(struct tty *, struct colour_palette *,
48    		    struct grid_cell *);
49static void	tty_check_bg(struct tty *, struct colour_palette *,
50    		    struct grid_cell *);
51static void	tty_check_us(struct tty *, struct colour_palette *,
52    		    struct grid_cell *);
53static void	tty_colours_fg(struct tty *, const struct grid_cell *);
54static void	tty_colours_bg(struct tty *, const struct grid_cell *);
55static void	tty_colours_us(struct tty *, const struct grid_cell *);
56
57static void	tty_region_pane(struct tty *, const struct tty_ctx *, u_int,
58		    u_int);
59static void	tty_region(struct tty *, u_int, u_int);
60static void	tty_margin_pane(struct tty *, const struct tty_ctx *);
61static void	tty_margin(struct tty *, u_int, u_int);
62static int	tty_large_region(struct tty *, const struct tty_ctx *);
63static int	tty_fake_bce(const struct tty *, const struct grid_cell *,
64		    u_int);
65static void	tty_redraw_region(struct tty *, const struct tty_ctx *);
66static void	tty_emulate_repeat(struct tty *, enum tty_code_code,
67		    enum tty_code_code, u_int);
68static void	tty_repeat_space(struct tty *, u_int);
69static void	tty_draw_pane(struct tty *, const struct tty_ctx *, u_int);
70static void	tty_default_attributes(struct tty *, const struct grid_cell *,
71		    struct colour_palette *, u_int, struct hyperlinks *);
72static int	tty_check_overlay(struct tty *, u_int, u_int);
73static void	tty_check_overlay_range(struct tty *, u_int, u_int, u_int,
74		    struct overlay_ranges *);
75
76#define tty_use_margin(tty) \
77	(tty->term->flags & TERM_DECSLRM)
78#define tty_full_width(tty, ctx) \
79	((ctx)->xoff == 0 && (ctx)->sx >= (tty)->sx)
80
81#define TTY_BLOCK_INTERVAL (100000 /* 100 milliseconds */)
82#define TTY_BLOCK_START(tty) (1 + ((tty)->sx * (tty)->sy) * 8)
83#define TTY_BLOCK_STOP(tty) (1 + ((tty)->sx * (tty)->sy) / 8)
84
85#define TTY_QUERY_TIMEOUT 5
86#define TTY_REQUEST_LIMIT 30
87
88void
89tty_create_log(void)
90{
91	char	name[64];
92
93	xsnprintf(name, sizeof name, "tmux-out-%ld.log", (long)getpid());
94
95	tty_log_fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0644);
96	if (tty_log_fd != -1 && fcntl(tty_log_fd, F_SETFD, FD_CLOEXEC) == -1)
97		fatal("fcntl failed");
98}
99
100int
101tty_init(struct tty *tty, struct client *c)
102{
103	if (!isatty(c->fd))
104		return (-1);
105
106	memset(tty, 0, sizeof *tty);
107	tty->client = c;
108
109	tty->cstyle = SCREEN_CURSOR_DEFAULT;
110	tty->ccolour = -1;
111	tty->fg = tty->bg = -1;
112
113	if (tcgetattr(c->fd, &tty->tio) != 0)
114		return (-1);
115	return (0);
116}
117
118void
119tty_resize(struct tty *tty)
120{
121	struct client	*c = tty->client;
122	struct winsize	 ws;
123	u_int		 sx, sy, xpixel, ypixel;
124
125	if (ioctl(c->fd, TIOCGWINSZ, &ws) != -1) {
126		sx = ws.ws_col;
127		if (sx == 0) {
128			sx = 80;
129			xpixel = 0;
130		} else
131			xpixel = ws.ws_xpixel / sx;
132		sy = ws.ws_row;
133		if (sy == 0) {
134			sy = 24;
135			ypixel = 0;
136		} else
137			ypixel = ws.ws_ypixel / sy;
138	} else {
139		sx = 80;
140		sy = 24;
141		xpixel = 0;
142		ypixel = 0;
143	}
144	log_debug("%s: %s now %ux%u (%ux%u)", __func__, c->name, sx, sy,
145	    xpixel, ypixel);
146	tty_set_size(tty, sx, sy, xpixel, ypixel);
147	tty_invalidate(tty);
148}
149
150void
151tty_set_size(struct tty *tty, u_int sx, u_int sy, u_int xpixel, u_int ypixel)
152{
153	tty->sx = sx;
154	tty->sy = sy;
155	tty->xpixel = xpixel;
156	tty->ypixel = ypixel;
157}
158
159static void
160tty_read_callback(__unused int fd, __unused short events, void *data)
161{
162	struct tty	*tty = data;
163	struct client	*c = tty->client;
164	const char	*name = c->name;
165	size_t		 size = EVBUFFER_LENGTH(tty->in);
166	int		 nread;
167
168	nread = evbuffer_read(tty->in, c->fd, -1);
169	if (nread == 0 || nread == -1) {
170		if (nread == 0)
171			log_debug("%s: read closed", name);
172		else
173			log_debug("%s: read error: %s", name, strerror(errno));
174		event_del(&tty->event_in);
175		server_client_lost(tty->client);
176		return;
177	}
178	log_debug("%s: read %d bytes (already %zu)", name, nread, size);
179
180	while (tty_keys_next(tty))
181		;
182}
183
184static void
185tty_timer_callback(__unused int fd, __unused short events, void *data)
186{
187	struct tty	*tty = data;
188	struct client	*c = tty->client;
189	struct timeval	 tv = { .tv_usec = TTY_BLOCK_INTERVAL };
190
191	log_debug("%s: %zu discarded", c->name, tty->discarded);
192
193	c->flags |= CLIENT_ALLREDRAWFLAGS;
194	c->discarded += tty->discarded;
195
196	if (tty->discarded < TTY_BLOCK_STOP(tty)) {
197		tty->flags &= ~TTY_BLOCK;
198		tty_invalidate(tty);
199		return;
200	}
201	tty->discarded = 0;
202	evtimer_add(&tty->timer, &tv);
203}
204
205static int
206tty_block_maybe(struct tty *tty)
207{
208	struct client	*c = tty->client;
209	size_t		 size = EVBUFFER_LENGTH(tty->out);
210	struct timeval	 tv = { .tv_usec = TTY_BLOCK_INTERVAL };
211
212	if (size == 0)
213		tty->flags &= ~TTY_NOBLOCK;
214	else if (tty->flags & TTY_NOBLOCK)
215		return (0);
216
217	if (size < TTY_BLOCK_START(tty))
218		return (0);
219
220	if (tty->flags & TTY_BLOCK)
221		return (1);
222	tty->flags |= TTY_BLOCK;
223
224	log_debug("%s: can't keep up, %zu discarded", c->name, size);
225
226	evbuffer_drain(tty->out, size);
227	c->discarded += size;
228
229	tty->discarded = 0;
230	evtimer_add(&tty->timer, &tv);
231	return (1);
232}
233
234static void
235tty_write_callback(__unused int fd, __unused short events, void *data)
236{
237	struct tty	*tty = data;
238	struct client	*c = tty->client;
239	size_t		 size = EVBUFFER_LENGTH(tty->out);
240	int		 nwrite;
241
242	nwrite = evbuffer_write(tty->out, c->fd);
243	if (nwrite == -1)
244		return;
245	log_debug("%s: wrote %d bytes (of %zu)", c->name, nwrite, size);
246
247	if (c->redraw > 0) {
248		if ((size_t)nwrite >= c->redraw)
249			c->redraw = 0;
250		else
251			c->redraw -= nwrite;
252		log_debug("%s: waiting for redraw, %zu bytes left", c->name,
253		    c->redraw);
254	} else if (tty_block_maybe(tty))
255		return;
256
257	if (EVBUFFER_LENGTH(tty->out) != 0)
258		event_add(&tty->event_out, NULL);
259}
260
261int
262tty_open(struct tty *tty, char **cause)
263{
264	struct client	*c = tty->client;
265
266	tty->term = tty_term_create(tty, c->term_name, c->term_caps,
267	    c->term_ncaps, &c->term_features, cause);
268	if (tty->term == NULL) {
269		tty_close(tty);
270		return (-1);
271	}
272	tty->flags |= TTY_OPENED;
273
274	tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE|TTY_BLOCK|TTY_TIMER);
275
276	event_set(&tty->event_in, c->fd, EV_PERSIST|EV_READ,
277	    tty_read_callback, tty);
278	tty->in = evbuffer_new();
279	if (tty->in == NULL)
280		fatal("out of memory");
281
282	event_set(&tty->event_out, c->fd, EV_WRITE, tty_write_callback, tty);
283	tty->out = evbuffer_new();
284	if (tty->out == NULL)
285		fatal("out of memory");
286
287	evtimer_set(&tty->timer, tty_timer_callback, tty);
288
289	tty_start_tty(tty);
290	tty_keys_build(tty);
291
292	return (0);
293}
294
295static void
296tty_start_timer_callback(__unused int fd, __unused short events, void *data)
297{
298	struct tty	*tty = data;
299	struct client	*c = tty->client;
300
301	log_debug("%s: start timer fired", c->name);
302	if ((tty->flags & (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA)) == 0)
303		tty_update_features(tty);
304	tty->flags |= TTY_ALL_REQUEST_FLAGS;
305}
306
307void
308tty_start_tty(struct tty *tty)
309{
310	struct client	*c = tty->client;
311	struct termios	 tio;
312	struct timeval	 tv = { .tv_sec = TTY_QUERY_TIMEOUT };
313
314	setblocking(c->fd, 0);
315	event_add(&tty->event_in, NULL);
316
317	memcpy(&tio, &tty->tio, sizeof tio);
318	tio.c_iflag &= ~(IXON|IXOFF|ICRNL|INLCR|IGNCR|IMAXBEL|ISTRIP);
319	tio.c_iflag |= IGNBRK;
320	tio.c_oflag &= ~(OPOST|ONLCR|OCRNL|ONLRET);
321	tio.c_lflag &= ~(IEXTEN|ICANON|ECHO|ECHOE|ECHONL|ECHOCTL|ECHOPRT|
322	    ECHOKE|ISIG);
323	tio.c_cc[VMIN] = 1;
324	tio.c_cc[VTIME] = 0;
325	if (tcsetattr(c->fd, TCSANOW, &tio) == 0)
326		tcflush(c->fd, TCOFLUSH);
327
328	tty_putcode(tty, TTYC_SMCUP);
329
330	tty_putcode(tty, TTYC_SMKX);
331	tty_putcode(tty, TTYC_CLEAR);
332
333	if (tty_acs_needed(tty)) {
334		log_debug("%s: using capabilities for ACS", c->name);
335		tty_putcode(tty, TTYC_ENACS);
336	} else
337		log_debug("%s: using UTF-8 for ACS", c->name);
338
339	tty_putcode(tty, TTYC_CNORM);
340	if (tty_term_has(tty->term, TTYC_KMOUS)) {
341		tty_puts(tty, "\033[?1000l\033[?1002l\033[?1003l");
342		tty_puts(tty, "\033[?1006l\033[?1005l");
343	}
344	if (tty_term_has(tty->term, TTYC_ENBP))
345		tty_putcode(tty, TTYC_ENBP);
346
347	evtimer_set(&tty->start_timer, tty_start_timer_callback, tty);
348	evtimer_add(&tty->start_timer, &tv);
349
350	tty->flags |= TTY_STARTED;
351	tty_invalidate(tty);
352
353	if (tty->ccolour != -1)
354		tty_force_cursor_colour(tty, -1);
355
356	tty->mouse_drag_flag = 0;
357	tty->mouse_drag_update = NULL;
358	tty->mouse_drag_release = NULL;
359}
360
361void
362tty_send_requests(struct tty *tty)
363{
364	if (~tty->flags & TTY_STARTED)
365		return;
366
367	if (tty->term->flags & TERM_VT100LIKE) {
368		if (~tty->term->flags & TTY_HAVEDA)
369			tty_puts(tty, "\033[c");
370		if (~tty->flags & TTY_HAVEDA2)
371			tty_puts(tty, "\033[>c");
372		if (~tty->flags & TTY_HAVEXDA)
373			tty_puts(tty, "\033[>q");
374		tty_puts(tty, "\033]10;?\033\\");
375		tty_puts(tty, "\033]11;?\033\\");
376	} else
377		tty->flags |= TTY_ALL_REQUEST_FLAGS;
378	tty->last_requests = time(NULL);
379}
380
381void
382tty_repeat_requests(struct tty *tty)
383{
384	time_t	t = time(NULL);
385
386	if (~tty->flags & TTY_STARTED)
387		return;
388
389	if (t - tty->last_requests <= TTY_REQUEST_LIMIT)
390		return;
391	tty->last_requests = t;
392
393	if (tty->term->flags & TERM_VT100LIKE) {
394		tty_puts(tty, "\033]10;?\033\\");
395		tty_puts(tty, "\033]11;?\033\\");
396	}
397}
398
399void
400tty_stop_tty(struct tty *tty)
401{
402	struct client	*c = tty->client;
403	struct winsize	 ws;
404
405	if (!(tty->flags & TTY_STARTED))
406		return;
407	tty->flags &= ~TTY_STARTED;
408
409	evtimer_del(&tty->start_timer);
410
411	event_del(&tty->timer);
412	tty->flags &= ~TTY_BLOCK;
413
414	event_del(&tty->event_in);
415	event_del(&tty->event_out);
416
417	/*
418	 * Be flexible about error handling and try not kill the server just
419	 * because the fd is invalid. Things like ssh -t can easily leave us
420	 * with a dead tty.
421	 */
422	if (ioctl(c->fd, TIOCGWINSZ, &ws) == -1)
423		return;
424	if (tcsetattr(c->fd, TCSANOW, &tty->tio) == -1)
425		return;
426
427	tty_raw(tty, tty_term_string_ii(tty->term, TTYC_CSR, 0, ws.ws_row - 1));
428	if (tty_acs_needed(tty))
429		tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS));
430	tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0));
431	tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX));
432	tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR));
433	if (tty->cstyle != SCREEN_CURSOR_DEFAULT) {
434		if (tty_term_has(tty->term, TTYC_SE))
435			tty_raw(tty, tty_term_string(tty->term, TTYC_SE));
436		else if (tty_term_has(tty->term, TTYC_SS))
437			tty_raw(tty, tty_term_string_i(tty->term, TTYC_SS, 0));
438	}
439	if (tty->ccolour != -1)
440		tty_raw(tty, tty_term_string(tty->term, TTYC_CR));
441
442	tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM));
443	if (tty_term_has(tty->term, TTYC_KMOUS)) {
444		tty_raw(tty, "\033[?1000l\033[?1002l\033[?1003l");
445		tty_raw(tty, "\033[?1006l\033[?1005l");
446	}
447	if (tty_term_has(tty->term, TTYC_DSBP))
448		tty_raw(tty, tty_term_string(tty->term, TTYC_DSBP));
449
450	if (tty->term->flags & TERM_VT100LIKE)
451		tty_raw(tty, "\033[?7727l");
452	tty_raw(tty, tty_term_string(tty->term, TTYC_DSFCS));
453	tty_raw(tty, tty_term_string(tty->term, TTYC_DSEKS));
454
455	if (tty_use_margin(tty))
456		tty_raw(tty, tty_term_string(tty->term, TTYC_DSMG));
457	tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
458
459	setblocking(c->fd, 1);
460}
461
462void
463tty_close(struct tty *tty)
464{
465	if (event_initialized(&tty->key_timer))
466		evtimer_del(&tty->key_timer);
467	tty_stop_tty(tty);
468
469	if (tty->flags & TTY_OPENED) {
470		evbuffer_free(tty->in);
471		event_del(&tty->event_in);
472		evbuffer_free(tty->out);
473		event_del(&tty->event_out);
474
475		tty_term_free(tty->term);
476		tty_keys_free(tty);
477
478		tty->flags &= ~TTY_OPENED;
479	}
480}
481
482void
483tty_free(struct tty *tty)
484{
485	tty_close(tty);
486}
487
488void
489tty_update_features(struct tty *tty)
490{
491	struct client	*c = tty->client;
492
493	if (tty_apply_features(tty->term, c->term_features))
494		tty_term_apply_overrides(tty->term);
495
496	if (tty_use_margin(tty))
497		tty_putcode(tty, TTYC_ENMG);
498	if (options_get_number(global_options, "extended-keys"))
499		tty_puts(tty, tty_term_string(tty->term, TTYC_ENEKS));
500	if (options_get_number(global_options, "focus-events"))
501		tty_puts(tty, tty_term_string(tty->term, TTYC_ENFCS));
502	if (tty->term->flags & TERM_VT100LIKE)
503		tty_puts(tty, "\033[?7727h");
504
505	/*
506	 * Features might have changed since the first draw during attach. For
507	 * example, this happens when DA responses are received.
508	 */
509	server_redraw_client(c);
510
511	tty_invalidate(tty);
512}
513
514void
515tty_raw(struct tty *tty, const char *s)
516{
517	struct client	*c = tty->client;
518	ssize_t		 n, slen;
519	u_int		 i;
520
521	slen = strlen(s);
522	for (i = 0; i < 5; i++) {
523		n = write(c->fd, s, slen);
524		if (n >= 0) {
525			s += n;
526			slen -= n;
527			if (slen == 0)
528				break;
529		} else if (n == -1 && errno != EAGAIN)
530			break;
531		usleep(100);
532	}
533}
534
535void
536tty_putcode(struct tty *tty, enum tty_code_code code)
537{
538	tty_puts(tty, tty_term_string(tty->term, code));
539}
540
541void
542tty_putcode_i(struct tty *tty, enum tty_code_code code, int a)
543{
544	if (a < 0)
545		return;
546	tty_puts(tty, tty_term_string_i(tty->term, code, a));
547}
548
549void
550tty_putcode_ii(struct tty *tty, enum tty_code_code code, int a, int b)
551{
552	if (a < 0 || b < 0)
553		return;
554	tty_puts(tty, tty_term_string_ii(tty->term, code, a, b));
555}
556
557void
558tty_putcode_iii(struct tty *tty, enum tty_code_code code, int a, int b, int c)
559{
560	if (a < 0 || b < 0 || c < 0)
561		return;
562	tty_puts(tty, tty_term_string_iii(tty->term, code, a, b, c));
563}
564
565void
566tty_putcode_s(struct tty *tty, enum tty_code_code code, const char *a)
567{
568	if (a != NULL)
569		tty_puts(tty, tty_term_string_s(tty->term, code, a));
570}
571
572void
573tty_putcode_ss(struct tty *tty, enum tty_code_code code, const char *a,
574    const char *b)
575{
576	if (a != NULL && b != NULL)
577		tty_puts(tty, tty_term_string_ss(tty->term, code, a, b));
578}
579
580static void
581tty_add(struct tty *tty, const char *buf, size_t len)
582{
583	struct client	*c = tty->client;
584
585	if (tty->flags & TTY_BLOCK) {
586		tty->discarded += len;
587		return;
588	}
589
590	evbuffer_add(tty->out, buf, len);
591	log_debug("%s: %.*s", c->name, (int)len, buf);
592	c->written += len;
593
594	if (tty_log_fd != -1)
595		write(tty_log_fd, buf, len);
596	if (tty->flags & TTY_STARTED)
597		event_add(&tty->event_out, NULL);
598}
599
600void
601tty_puts(struct tty *tty, const char *s)
602{
603	if (*s != '\0')
604		tty_add(tty, s, strlen(s));
605}
606
607void
608tty_putc(struct tty *tty, u_char ch)
609{
610	const char	*acs;
611
612	if ((tty->term->flags & TERM_NOAM) &&
613	    ch >= 0x20 && ch != 0x7f &&
614	    tty->cy == tty->sy - 1 &&
615	    tty->cx + 1 >= tty->sx)
616		return;
617
618	if (tty->cell.attr & GRID_ATTR_CHARSET) {
619		acs = tty_acs_get(tty, ch);
620		if (acs != NULL)
621			tty_add(tty, acs, strlen(acs));
622		else
623			tty_add(tty, &ch, 1);
624	} else
625		tty_add(tty, &ch, 1);
626
627	if (ch >= 0x20 && ch != 0x7f) {
628		if (tty->cx >= tty->sx) {
629			tty->cx = 1;
630			if (tty->cy != tty->rlower)
631				tty->cy++;
632
633			/*
634			 * On !am terminals, force the cursor position to where
635			 * we think it should be after a line wrap - this means
636			 * it works on sensible terminals as well.
637			 */
638			if (tty->term->flags & TERM_NOAM)
639				tty_putcode_ii(tty, TTYC_CUP, tty->cy, tty->cx);
640		} else
641			tty->cx++;
642	}
643}
644
645void
646tty_putn(struct tty *tty, const void *buf, size_t len, u_int width)
647{
648	if ((tty->term->flags & TERM_NOAM) &&
649	    tty->cy == tty->sy - 1 &&
650	    tty->cx + len >= tty->sx)
651		len = tty->sx - tty->cx - 1;
652
653	tty_add(tty, buf, len);
654	if (tty->cx + width > tty->sx) {
655		tty->cx = (tty->cx + width) - tty->sx;
656		if (tty->cx <= tty->sx)
657			tty->cy++;
658		else
659			tty->cx = tty->cy = UINT_MAX;
660	} else
661		tty->cx += width;
662}
663
664static void
665tty_set_italics(struct tty *tty)
666{
667	const char	*s;
668
669	if (tty_term_has(tty->term, TTYC_SITM)) {
670		s = options_get_string(global_options, "default-terminal");
671		if (strcmp(s, "screen") != 0 && strncmp(s, "screen-", 7) != 0) {
672			tty_putcode(tty, TTYC_SITM);
673			return;
674		}
675	}
676	tty_putcode(tty, TTYC_SMSO);
677}
678
679void
680tty_set_title(struct tty *tty, const char *title)
681{
682	if (!tty_term_has(tty->term, TTYC_TSL) ||
683	    !tty_term_has(tty->term, TTYC_FSL))
684		return;
685
686	tty_putcode(tty, TTYC_TSL);
687	tty_puts(tty, title);
688	tty_putcode(tty, TTYC_FSL);
689}
690
691void
692tty_set_path(struct tty *tty, const char *title)
693{
694	if (!tty_term_has(tty->term, TTYC_SWD) ||
695	    !tty_term_has(tty->term, TTYC_FSL))
696		return;
697
698	tty_putcode(tty, TTYC_SWD);
699	tty_puts(tty, title);
700	tty_putcode(tty, TTYC_FSL);
701}
702
703static void
704tty_force_cursor_colour(struct tty *tty, int c)
705{
706	u_char	r, g, b;
707	char	s[13];
708
709	if (c != -1)
710		c = colour_force_rgb(c);
711	if (c == tty->ccolour)
712		return;
713	if (c == -1)
714		tty_putcode(tty, TTYC_CR);
715	else {
716		colour_split_rgb(c, &r, &g, &b);
717		xsnprintf(s, sizeof s, "rgb:%02hhx/%02hhx/%02hhx", r, g, b);
718		tty_putcode_s(tty, TTYC_CS, s);
719	}
720	tty->ccolour = c;
721}
722
723static int
724tty_update_cursor(struct tty *tty, int mode, struct screen *s)
725{
726	enum screen_cursor_style	cstyle;
727	int				ccolour, changed, cmode = mode;
728
729	/* Set cursor colour if changed. */
730	if (s != NULL) {
731		ccolour = s->ccolour;
732		if (s->ccolour == -1)
733			ccolour = s->default_ccolour;
734		tty_force_cursor_colour(tty, ccolour);
735	}
736
737	/* If cursor is off, set as invisible. */
738	if (~cmode & MODE_CURSOR) {
739		if (tty->mode & MODE_CURSOR)
740			tty_putcode(tty, TTYC_CIVIS);
741		return (cmode);
742	}
743
744	/* Check if blinking or very visible flag changed or style changed. */
745	if (s == NULL)
746		cstyle = tty->cstyle;
747	else {
748		cstyle = s->cstyle;
749		if (cstyle == SCREEN_CURSOR_DEFAULT) {
750			if (~cmode & MODE_CURSOR_BLINKING_SET) {
751				if (s->default_mode & MODE_CURSOR_BLINKING)
752					cmode |= MODE_CURSOR_BLINKING;
753				else
754					cmode &= ~MODE_CURSOR_BLINKING;
755			}
756			cstyle = s->default_cstyle;
757		}
758	}
759
760	/* If nothing changed, do nothing. */
761	changed = cmode ^ tty->mode;
762	if ((changed & CURSOR_MODES) == 0 && cstyle == tty->cstyle)
763		return (cmode);
764
765	/*
766	 * Set cursor style. If an explicit style has been set with DECSCUSR,
767	 * set it if supported, otherwise send cvvis for blinking styles.
768	 *
769	 * If no style, has been set (SCREEN_CURSOR_DEFAULT), then send cvvis
770	 * if either the blinking or very visible flags are set.
771	 */
772	tty_putcode(tty, TTYC_CNORM);
773	switch (cstyle) {
774	case SCREEN_CURSOR_DEFAULT:
775		if (tty->cstyle != SCREEN_CURSOR_DEFAULT) {
776			if (tty_term_has(tty->term, TTYC_SE))
777				tty_putcode(tty, TTYC_SE);
778			else
779				tty_putcode_i(tty, TTYC_SS, 0);
780		}
781		if (cmode & (MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE))
782			tty_putcode(tty, TTYC_CVVIS);
783		break;
784	case SCREEN_CURSOR_BLOCK:
785		if (tty_term_has(tty->term, TTYC_SS)) {
786			if (cmode & MODE_CURSOR_BLINKING)
787				tty_putcode_i(tty, TTYC_SS, 1);
788			else
789				tty_putcode_i(tty, TTYC_SS, 2);
790		} else if (cmode & MODE_CURSOR_BLINKING)
791			tty_putcode(tty, TTYC_CVVIS);
792		break;
793	case SCREEN_CURSOR_UNDERLINE:
794		if (tty_term_has(tty->term, TTYC_SS)) {
795			if (cmode & MODE_CURSOR_BLINKING)
796				tty_putcode_i(tty, TTYC_SS, 3);
797			else
798				tty_putcode_i(tty, TTYC_SS, 4);
799		} else if (cmode & MODE_CURSOR_BLINKING)
800			tty_putcode(tty, TTYC_CVVIS);
801		break;
802	case SCREEN_CURSOR_BAR:
803		if (tty_term_has(tty->term, TTYC_SS)) {
804			if (cmode & MODE_CURSOR_BLINKING)
805				tty_putcode_i(tty, TTYC_SS, 5);
806			else
807				tty_putcode_i(tty, TTYC_SS, 6);
808		} else if (cmode & MODE_CURSOR_BLINKING)
809			tty_putcode(tty, TTYC_CVVIS);
810		break;
811	}
812	tty->cstyle = cstyle;
813	return (cmode);
814 }
815
816void
817tty_update_mode(struct tty *tty, int mode, struct screen *s)
818{
819	struct tty_term	*term = tty->term;
820	struct client	*c = tty->client;
821	int		 changed;
822
823	if (tty->flags & TTY_NOCURSOR)
824		mode &= ~MODE_CURSOR;
825
826	if (tty_update_cursor(tty, mode, s) & MODE_CURSOR_BLINKING)
827		mode |= MODE_CURSOR_BLINKING;
828	else
829		mode &= ~MODE_CURSOR_BLINKING;
830
831	changed = mode ^ tty->mode;
832	if (log_get_level() != 0 && changed != 0) {
833		log_debug("%s: current mode %s", c->name,
834		    screen_mode_to_string(tty->mode));
835		log_debug("%s: setting mode %s", c->name,
836		    screen_mode_to_string(mode));
837	}
838
839	if ((changed & ALL_MOUSE_MODES) && tty_term_has(term, TTYC_KMOUS)) {
840		/*
841		 * If the mouse modes have changed, clear then all and apply
842		 * again. There are differences in how terminals track the
843		 * various bits.
844		 */
845		tty_puts(tty, "\033[?1006l\033[?1000l\033[?1002l\033[?1003l");
846		if (mode & ALL_MOUSE_MODES)
847			tty_puts(tty, "\033[?1006h");
848		if (mode & MODE_MOUSE_ALL)
849			tty_puts(tty, "\033[?1000h\033[?1002h\033[?1003h");
850		else if (mode & MODE_MOUSE_BUTTON)
851			tty_puts(tty, "\033[?1000h\033[?1002h");
852		else if (mode & MODE_MOUSE_STANDARD)
853			tty_puts(tty, "\033[?1000h");
854	}
855	tty->mode = mode;
856}
857
858static void
859tty_emulate_repeat(struct tty *tty, enum tty_code_code code,
860    enum tty_code_code code1, u_int n)
861{
862	if (tty_term_has(tty->term, code))
863		tty_putcode_i(tty, code, n);
864	else {
865		while (n-- > 0)
866			tty_putcode(tty, code1);
867	}
868}
869
870static void
871tty_repeat_space(struct tty *tty, u_int n)
872{
873	static char s[500];
874
875	if (*s != ' ')
876		memset(s, ' ', sizeof s);
877
878	while (n > sizeof s) {
879		tty_putn(tty, s, sizeof s, sizeof s);
880		n -= sizeof s;
881	}
882	if (n != 0)
883		tty_putn(tty, s, n, n);
884}
885
886/* Is this window bigger than the terminal? */
887int
888tty_window_bigger(struct tty *tty)
889{
890	struct client	*c = tty->client;
891	struct window	*w = c->session->curw->window;
892
893	return (tty->sx < w->sx || tty->sy - status_line_size(c) < w->sy);
894}
895
896/* What offset should this window be drawn at? */
897int
898tty_window_offset(struct tty *tty, u_int *ox, u_int *oy, u_int *sx, u_int *sy)
899{
900	*ox = tty->oox;
901	*oy = tty->ooy;
902	*sx = tty->osx;
903	*sy = tty->osy;
904
905	return (tty->oflag);
906}
907
908/* What offset should this window be drawn at? */
909static int
910tty_window_offset1(struct tty *tty, u_int *ox, u_int *oy, u_int *sx, u_int *sy)
911{
912	struct client		*c = tty->client;
913	struct window		*w = c->session->curw->window;
914	struct window_pane	*wp = server_client_get_pane(c);
915	u_int			 cx, cy, lines;
916
917	lines = status_line_size(c);
918
919	if (tty->sx >= w->sx && tty->sy - lines >= w->sy) {
920		*ox = 0;
921		*oy = 0;
922		*sx = w->sx;
923		*sy = w->sy;
924
925		c->pan_window = NULL;
926		return (0);
927	}
928
929	*sx = tty->sx;
930	*sy = tty->sy - lines;
931
932	if (c->pan_window == w) {
933		if (*sx >= w->sx)
934			c->pan_ox = 0;
935		else if (c->pan_ox + *sx > w->sx)
936			c->pan_ox = w->sx - *sx;
937		*ox = c->pan_ox;
938		if (*sy >= w->sy)
939			c->pan_oy = 0;
940		else if (c->pan_oy + *sy > w->sy)
941			c->pan_oy = w->sy - *sy;
942		*oy = c->pan_oy;
943		return (1);
944	}
945
946	if (~wp->screen->mode & MODE_CURSOR) {
947		*ox = 0;
948		*oy = 0;
949	} else {
950		cx = wp->xoff + wp->screen->cx;
951		cy = wp->yoff + wp->screen->cy;
952
953		if (cx < *sx)
954			*ox = 0;
955		else if (cx > w->sx - *sx)
956			*ox = w->sx - *sx;
957		else
958			*ox = cx - *sx / 2;
959
960		if (cy < *sy)
961			*oy = 0;
962		else if (cy > w->sy - *sy)
963			*oy = w->sy - *sy;
964		else
965			*oy = cy - *sy / 2;
966	}
967
968	c->pan_window = NULL;
969	return (1);
970}
971
972/* Update stored offsets for a window and redraw if necessary. */
973void
974tty_update_window_offset(struct window *w)
975{
976	struct client	*c;
977
978	TAILQ_FOREACH(c, &clients, entry) {
979		if (c->session != NULL &&
980		    c->session->curw != NULL &&
981		    c->session->curw->window == w)
982			tty_update_client_offset(c);
983	}
984}
985
986/* Update stored offsets for a client and redraw if necessary. */
987void
988tty_update_client_offset(struct client *c)
989{
990	u_int	ox, oy, sx, sy;
991
992	if (~c->flags & CLIENT_TERMINAL)
993		return;
994
995	c->tty.oflag = tty_window_offset1(&c->tty, &ox, &oy, &sx, &sy);
996	if (ox == c->tty.oox &&
997	    oy == c->tty.ooy &&
998	    sx == c->tty.osx &&
999	    sy == c->tty.osy)
1000		return;
1001
1002	log_debug ("%s: %s offset has changed (%u,%u %ux%u -> %u,%u %ux%u)",
1003	    __func__, c->name, c->tty.oox, c->tty.ooy, c->tty.osx, c->tty.osy,
1004	    ox, oy, sx, sy);
1005
1006	c->tty.oox = ox;
1007	c->tty.ooy = oy;
1008	c->tty.osx = sx;
1009	c->tty.osy = sy;
1010
1011	c->flags |= (CLIENT_REDRAWWINDOW|CLIENT_REDRAWSTATUS);
1012}
1013
1014/*
1015 * Is the region large enough to be worth redrawing once later rather than
1016 * probably several times now? Currently yes if it is more than 50% of the
1017 * pane.
1018 */
1019static int
1020tty_large_region(__unused struct tty *tty, const struct tty_ctx *ctx)
1021{
1022	return (ctx->orlower - ctx->orupper >= ctx->sy / 2);
1023}
1024
1025/*
1026 * Return if BCE is needed but the terminal doesn't have it - it'll need to be
1027 * emulated.
1028 */
1029static int
1030tty_fake_bce(const struct tty *tty, const struct grid_cell *gc, u_int bg)
1031{
1032	if (tty_term_flag(tty->term, TTYC_BCE))
1033		return (0);
1034	if (!COLOUR_DEFAULT(bg) || !COLOUR_DEFAULT(gc->bg))
1035		return (1);
1036	return (0);
1037}
1038
1039/*
1040 * Redraw scroll region using data from screen (already updated). Used when
1041 * CSR not supported, or window is a pane that doesn't take up the full
1042 * width of the terminal.
1043 */
1044static void
1045tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx)
1046{
1047	struct client		*c = tty->client;
1048	u_int			 i;
1049
1050	/*
1051	 * If region is large, schedule a redraw. In most cases this is likely
1052	 * to be followed by some more scrolling.
1053	 */
1054	if (tty_large_region(tty, ctx)) {
1055		log_debug("%s: %s large redraw", __func__, c->name);
1056		ctx->redraw_cb(ctx);
1057		return;
1058	}
1059
1060	for (i = ctx->orupper; i <= ctx->orlower; i++)
1061		tty_draw_pane(tty, ctx, i);
1062}
1063
1064/* Is this position visible in the pane? */
1065static int
1066tty_is_visible(__unused struct tty *tty, const struct tty_ctx *ctx, u_int px,
1067    u_int py, u_int nx, u_int ny)
1068{
1069	u_int	xoff = ctx->rxoff + px, yoff = ctx->ryoff + py;
1070
1071	if (!ctx->bigger)
1072		return (1);
1073
1074	if (xoff + nx <= ctx->wox || xoff >= ctx->wox + ctx->wsx ||
1075	    yoff + ny <= ctx->woy || yoff >= ctx->woy + ctx->wsy)
1076		return (0);
1077	return (1);
1078}
1079
1080/* Clamp line position to visible part of pane. */
1081static int
1082tty_clamp_line(struct tty *tty, const struct tty_ctx *ctx, u_int px, u_int py,
1083    u_int nx, u_int *i, u_int *x, u_int *rx, u_int *ry)
1084{
1085	u_int	xoff = ctx->rxoff + px;
1086
1087	if (!tty_is_visible(tty, ctx, px, py, nx, 1))
1088		return (0);
1089	*ry = ctx->yoff + py - ctx->woy;
1090
1091	if (xoff >= ctx->wox && xoff + nx <= ctx->wox + ctx->wsx) {
1092		/* All visible. */
1093		*i = 0;
1094		*x = ctx->xoff + px - ctx->wox;
1095		*rx = nx;
1096	} else if (xoff < ctx->wox && xoff + nx > ctx->wox + ctx->wsx) {
1097		/* Both left and right not visible. */
1098		*i = ctx->wox;
1099		*x = 0;
1100		*rx = ctx->wsx;
1101	} else if (xoff < ctx->wox) {
1102		/* Left not visible. */
1103		*i = ctx->wox - (ctx->xoff + px);
1104		*x = 0;
1105		*rx = nx - *i;
1106	} else {
1107		/* Right not visible. */
1108		*i = 0;
1109		*x = (ctx->xoff + px) - ctx->wox;
1110		*rx = ctx->wsx - *x;
1111	}
1112	if (*rx > nx)
1113		fatalx("%s: x too big, %u > %u", __func__, *rx, nx);
1114
1115	return (1);
1116}
1117
1118/* Clear a line. */
1119static void
1120tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py,
1121    u_int px, u_int nx, u_int bg)
1122{
1123	struct client		*c = tty->client;
1124	struct overlay_ranges	 r;
1125	u_int			 i;
1126
1127	log_debug("%s: %s, %u at %u,%u", __func__, c->name, nx, px, py);
1128
1129	/* Nothing to clear. */
1130	if (nx == 0)
1131		return;
1132
1133	/* If genuine BCE is available, can try escape sequences. */
1134	if (c->overlay_check == NULL && !tty_fake_bce(tty, defaults, bg)) {
1135		/* Off the end of the line, use EL if available. */
1136		if (px + nx >= tty->sx && tty_term_has(tty->term, TTYC_EL)) {
1137			tty_cursor(tty, px, py);
1138			tty_putcode(tty, TTYC_EL);
1139			return;
1140		}
1141
1142		/* At the start of the line. Use EL1. */
1143		if (px == 0 && tty_term_has(tty->term, TTYC_EL1)) {
1144			tty_cursor(tty, px + nx - 1, py);
1145			tty_putcode(tty, TTYC_EL1);
1146			return;
1147		}
1148
1149		/* Section of line. Use ECH if possible. */
1150		if (tty_term_has(tty->term, TTYC_ECH)) {
1151			tty_cursor(tty, px, py);
1152			tty_putcode_i(tty, TTYC_ECH, nx);
1153			return;
1154		}
1155	}
1156
1157	/*
1158	 * Couldn't use an escape sequence, use spaces. Clear only the visible
1159	 * bit if there is an overlay.
1160	 */
1161	tty_check_overlay_range(tty, px, py, nx, &r);
1162	for (i = 0; i < OVERLAY_MAX_RANGES; i++) {
1163		if (r.nx[i] == 0)
1164			continue;
1165		tty_cursor(tty, r.px[i], py);
1166		tty_repeat_space(tty, r.nx[i]);
1167	}
1168}
1169
1170/* Clear a line, adjusting to visible part of pane. */
1171static void
1172tty_clear_pane_line(struct tty *tty, const struct tty_ctx *ctx, u_int py,
1173    u_int px, u_int nx, u_int bg)
1174{
1175	struct client	*c = tty->client;
1176	u_int		 i, x, rx, ry;
1177
1178	log_debug("%s: %s, %u at %u,%u", __func__, c->name, nx, px, py);
1179
1180	if (tty_clamp_line(tty, ctx, px, py, nx, &i, &x, &rx, &ry))
1181		tty_clear_line(tty, &ctx->defaults, ry, x, rx, bg);
1182}
1183
1184/* Clamp area position to visible part of pane. */
1185static int
1186tty_clamp_area(struct tty *tty, const struct tty_ctx *ctx, u_int px, u_int py,
1187    u_int nx, u_int ny, u_int *i, u_int *j, u_int *x, u_int *y, u_int *rx,
1188    u_int *ry)
1189{
1190	u_int	xoff = ctx->rxoff + px, yoff = ctx->ryoff + py;
1191
1192	if (!tty_is_visible(tty, ctx, px, py, nx, ny))
1193		return (0);
1194
1195	if (xoff >= ctx->wox && xoff + nx <= ctx->wox + ctx->wsx) {
1196		/* All visible. */
1197		*i = 0;
1198		*x = ctx->xoff + px - ctx->wox;
1199		*rx = nx;
1200	} else if (xoff < ctx->wox && xoff + nx > ctx->wox + ctx->wsx) {
1201		/* Both left and right not visible. */
1202		*i = ctx->wox;
1203		*x = 0;
1204		*rx = ctx->wsx;
1205	} else if (xoff < ctx->wox) {
1206		/* Left not visible. */
1207		*i = ctx->wox - (ctx->xoff + px);
1208		*x = 0;
1209		*rx = nx - *i;
1210	} else {
1211		/* Right not visible. */
1212		*i = 0;
1213		*x = (ctx->xoff + px) - ctx->wox;
1214		*rx = ctx->wsx - *x;
1215	}
1216	if (*rx > nx)
1217		fatalx("%s: x too big, %u > %u", __func__, *rx, nx);
1218
1219	if (yoff >= ctx->woy && yoff + ny <= ctx->woy + ctx->wsy) {
1220		/* All visible. */
1221		*j = 0;
1222		*y = ctx->yoff + py - ctx->woy;
1223		*ry = ny;
1224	} else if (yoff < ctx->woy && yoff + ny > ctx->woy + ctx->wsy) {
1225		/* Both top and bottom not visible. */
1226		*j = ctx->woy;
1227		*y = 0;
1228		*ry = ctx->wsy;
1229	} else if (yoff < ctx->woy) {
1230		/* Top not visible. */
1231		*j = ctx->woy - (ctx->yoff + py);
1232		*y = 0;
1233		*ry = ny - *j;
1234	} else {
1235		/* Bottom not visible. */
1236		*j = 0;
1237		*y = (ctx->yoff + py) - ctx->woy;
1238		*ry = ctx->wsy - *y;
1239	}
1240	if (*ry > ny)
1241		fatalx("%s: y too big, %u > %u", __func__, *ry, ny);
1242
1243	return (1);
1244}
1245
1246/* Clear an area, adjusting to visible part of pane. */
1247static void
1248tty_clear_area(struct tty *tty, const struct grid_cell *defaults, u_int py,
1249    u_int ny, u_int px, u_int nx, u_int bg)
1250{
1251	struct client	*c = tty->client;
1252	u_int		 yy;
1253	char		 tmp[64];
1254
1255	log_debug("%s: %s, %u,%u at %u,%u", __func__, c->name, nx, ny, px, py);
1256
1257	/* Nothing to clear. */
1258	if (nx == 0 || ny == 0)
1259		return;
1260
1261	/* If genuine BCE is available, can try escape sequences. */
1262	if (c->overlay_check == NULL && !tty_fake_bce(tty, defaults, bg)) {
1263		/* Use ED if clearing off the bottom of the terminal. */
1264		if (px == 0 &&
1265		    px + nx >= tty->sx &&
1266		    py + ny >= tty->sy &&
1267		    tty_term_has(tty->term, TTYC_ED)) {
1268			tty_cursor(tty, 0, py);
1269			tty_putcode(tty, TTYC_ED);
1270			return;
1271		}
1272
1273		/*
1274		 * On VT420 compatible terminals we can use DECFRA if the
1275		 * background colour isn't default (because it doesn't work
1276		 * after SGR 0).
1277		 */
1278		if ((tty->term->flags & TERM_DECFRA) && !COLOUR_DEFAULT(bg)) {
1279			xsnprintf(tmp, sizeof tmp, "\033[32;%u;%u;%u;%u$x",
1280			    py + 1, px + 1, py + ny, px + nx);
1281			tty_puts(tty, tmp);
1282			return;
1283		}
1284
1285		/* Full lines can be scrolled away to clear them. */
1286		if (px == 0 &&
1287		    px + nx >= tty->sx &&
1288		    ny > 2 &&
1289		    tty_term_has(tty->term, TTYC_CSR) &&
1290		    tty_term_has(tty->term, TTYC_INDN)) {
1291			tty_region(tty, py, py + ny - 1);
1292			tty_margin_off(tty);
1293			tty_putcode_i(tty, TTYC_INDN, ny);
1294			return;
1295		}
1296
1297		/*
1298		 * If margins are supported, can just scroll the area off to
1299		 * clear it.
1300		 */
1301		if (nx > 2 &&
1302		    ny > 2 &&
1303		    tty_term_has(tty->term, TTYC_CSR) &&
1304		    tty_use_margin(tty) &&
1305		    tty_term_has(tty->term, TTYC_INDN)) {
1306			tty_region(tty, py, py + ny - 1);
1307			tty_margin(tty, px, px + nx - 1);
1308			tty_putcode_i(tty, TTYC_INDN, ny);
1309			return;
1310		}
1311	}
1312
1313	/* Couldn't use an escape sequence, loop over the lines. */
1314	for (yy = py; yy < py + ny; yy++)
1315		tty_clear_line(tty, defaults, yy, px, nx, bg);
1316}
1317
1318/* Clear an area in a pane. */
1319static void
1320tty_clear_pane_area(struct tty *tty, const struct tty_ctx *ctx, u_int py,
1321    u_int ny, u_int px, u_int nx, u_int bg)
1322{
1323	u_int	i, j, x, y, rx, ry;
1324
1325	if (tty_clamp_area(tty, ctx, px, py, nx, ny, &i, &j, &x, &y, &rx, &ry))
1326		tty_clear_area(tty, &ctx->defaults, y, ry, x, rx, bg);
1327}
1328
1329static void
1330tty_draw_pane(struct tty *tty, const struct tty_ctx *ctx, u_int py)
1331{
1332	struct screen	*s = ctx->s;
1333	u_int		 nx = ctx->sx, i, x, rx, ry;
1334
1335	log_debug("%s: %s %u %d", __func__, tty->client->name, py, ctx->bigger);
1336
1337	if (!ctx->bigger) {
1338		tty_draw_line(tty, s, 0, py, nx, ctx->xoff, ctx->yoff + py,
1339		    &ctx->defaults, ctx->palette);
1340		return;
1341	}
1342	if (tty_clamp_line(tty, ctx, 0, py, nx, &i, &x, &rx, &ry)) {
1343		tty_draw_line(tty, s, i, py, rx, x, ry, &ctx->defaults,
1344		    ctx->palette);
1345	}
1346}
1347
1348static const struct grid_cell *
1349tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
1350{
1351	static struct grid_cell	new;
1352	int			c;
1353
1354	/* Characters less than 0x7f are always fine, no matter what. */
1355	if (gc->data.size == 1 && *gc->data.data < 0x7f)
1356		return (gc);
1357
1358	/* UTF-8 terminal and a UTF-8 character - fine. */
1359	if (tty->client->flags & CLIENT_UTF8)
1360		return (gc);
1361	memcpy(&new, gc, sizeof new);
1362
1363	/* See if this can be mapped to an ACS character. */
1364	c = tty_acs_reverse_get(tty, gc->data.data, gc->data.size);
1365	if (c != -1) {
1366		utf8_set(&new.data, c);
1367		new.attr |= GRID_ATTR_CHARSET;
1368		return (&new);
1369	}
1370
1371	/* Replace by the right number of underscores. */
1372	new.data.size = gc->data.width;
1373	if (new.data.size > UTF8_SIZE)
1374		new.data.size = UTF8_SIZE;
1375	memset(new.data.data, '_', new.data.size);
1376	return (&new);
1377}
1378
1379/*
1380 * Check if a single character is obstructed by the overlay and return a
1381 * boolean.
1382 */
1383static int
1384tty_check_overlay(struct tty *tty, u_int px, u_int py)
1385{
1386	struct overlay_ranges	r;
1387
1388	/*
1389	 * A unit width range will always return nx[2] == 0 from a check, even
1390	 * with multiple overlays, so it's sufficient to check just the first
1391	 * two entries.
1392	 */
1393	tty_check_overlay_range(tty, px, py, 1, &r);
1394	if (r.nx[0] + r.nx[1] == 0)
1395		return (0);
1396	return (1);
1397}
1398
1399/* Return parts of the input range which are visible. */
1400static void
1401tty_check_overlay_range(struct tty *tty, u_int px, u_int py, u_int nx,
1402    struct overlay_ranges *r)
1403{
1404	struct client	*c = tty->client;
1405
1406	if (c->overlay_check == NULL) {
1407		r->px[0] = px;
1408		r->nx[0] = nx;
1409		r->px[1] = 0;
1410		r->nx[1] = 0;
1411		r->px[2] = 0;
1412		r->nx[2] = 0;
1413		return;
1414	}
1415
1416	c->overlay_check(c, c->overlay_data, px, py, nx, r);
1417}
1418
1419void
1420tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
1421    u_int atx, u_int aty, const struct grid_cell *defaults,
1422    struct colour_palette *palette)
1423{
1424	struct grid		*gd = s->grid;
1425	struct grid_cell	 gc, last;
1426	const struct grid_cell	*gcp;
1427	struct grid_line	*gl;
1428	struct client		*c = tty->client;
1429	struct overlay_ranges	 r;
1430	u_int			 i, j, ux, sx, width, hidden, eux, nxx;
1431	u_int			 cellsize;
1432	int			 flags, cleared = 0, wrapped = 0;
1433	char			 buf[512];
1434	size_t			 len;
1435
1436	log_debug("%s: px=%u py=%u nx=%u atx=%u aty=%u", __func__,
1437	    px, py, nx, atx, aty);
1438	log_debug("%s: defaults: fg=%d, bg=%d", __func__, defaults->fg,
1439	    defaults->bg);
1440
1441	/*
1442	 * py is the line in the screen to draw.
1443	 * px is the start x and nx is the width to draw.
1444	 * atx,aty is the line on the terminal to draw it.
1445	 */
1446
1447	flags = (tty->flags & TTY_NOCURSOR);
1448	tty->flags |= TTY_NOCURSOR;
1449	tty_update_mode(tty, tty->mode, s);
1450
1451	tty_region_off(tty);
1452	tty_margin_off(tty);
1453
1454	/*
1455	 * Clamp the width to cellsize - note this is not cellused, because
1456	 * there may be empty background cells after it (from BCE).
1457	 */
1458	sx = screen_size_x(s);
1459	if (nx > sx)
1460		nx = sx;
1461	cellsize = grid_get_line(gd, gd->hsize + py)->cellsize;
1462	if (sx > cellsize)
1463		sx = cellsize;
1464	if (sx > tty->sx)
1465		sx = tty->sx;
1466	if (sx > nx)
1467		sx = nx;
1468	ux = 0;
1469
1470	if (py == 0)
1471		gl = NULL;
1472	else
1473		gl = grid_get_line(gd, gd->hsize + py - 1);
1474	if (gl == NULL ||
1475	    (~gl->flags & GRID_LINE_WRAPPED) ||
1476	    atx != 0 ||
1477	    tty->cx < tty->sx ||
1478	    nx < tty->sx) {
1479		if (nx < tty->sx &&
1480		    atx == 0 &&
1481		    px + sx != nx &&
1482		    tty_term_has(tty->term, TTYC_EL1) &&
1483		    !tty_fake_bce(tty, defaults, 8) &&
1484		    c->overlay_check == NULL) {
1485			tty_default_attributes(tty, defaults, palette, 8,
1486			    s->hyperlinks);
1487			tty_cursor(tty, nx - 1, aty);
1488			tty_putcode(tty, TTYC_EL1);
1489			cleared = 1;
1490		}
1491	} else {
1492		log_debug("%s: wrapped line %u", __func__, aty);
1493		wrapped = 1;
1494	}
1495
1496	memcpy(&last, &grid_default_cell, sizeof last);
1497	len = 0;
1498	width = 0;
1499
1500	for (i = 0; i < sx; i++) {
1501		grid_view_get_cell(gd, px + i, py, &gc);
1502		gcp = tty_check_codeset(tty, &gc);
1503		if (len != 0 &&
1504		    (!tty_check_overlay(tty, atx + ux + width, aty) ||
1505		    (gcp->attr & GRID_ATTR_CHARSET) ||
1506		    gcp->flags != last.flags ||
1507		    gcp->attr != last.attr ||
1508		    gcp->fg != last.fg ||
1509		    gcp->bg != last.bg ||
1510		    gcp->us != last.us ||
1511		    gcp->link != last.link ||
1512		    ux + width + gcp->data.width > nx ||
1513		    (sizeof buf) - len < gcp->data.size)) {
1514			tty_attributes(tty, &last, defaults, palette,
1515			    s->hyperlinks);
1516			if (last.flags & GRID_FLAG_CLEARED) {
1517				log_debug("%s: %zu cleared", __func__, len);
1518				tty_clear_line(tty, defaults, aty, atx + ux,
1519				    width, last.bg);
1520			} else {
1521				if (!wrapped || atx != 0 || ux != 0)
1522					tty_cursor(tty, atx + ux, aty);
1523				tty_putn(tty, buf, len, width);
1524			}
1525			ux += width;
1526
1527			len = 0;
1528			width = 0;
1529			wrapped = 0;
1530		}
1531
1532		if (gcp->flags & GRID_FLAG_SELECTED)
1533			screen_select_cell(s, &last, gcp);
1534		else
1535			memcpy(&last, gcp, sizeof last);
1536
1537		tty_check_overlay_range(tty, atx + ux, aty, gcp->data.width,
1538		    &r);
1539		hidden = 0;
1540		for (j = 0; j < OVERLAY_MAX_RANGES; j++)
1541			hidden += r.nx[j];
1542		hidden = gcp->data.width - hidden;
1543		if (hidden != 0 && hidden == gcp->data.width) {
1544			if (~gcp->flags & GRID_FLAG_PADDING)
1545				ux += gcp->data.width;
1546		} else if (hidden != 0 || ux + gcp->data.width > nx) {
1547			if (~gcp->flags & GRID_FLAG_PADDING) {
1548				tty_attributes(tty, &last, defaults, palette,
1549				    s->hyperlinks);
1550				for (j = 0; j < OVERLAY_MAX_RANGES; j++) {
1551					if (r.nx[j] == 0)
1552						continue;
1553					/* Effective width drawn so far. */
1554					eux = r.px[j] - atx;
1555					if (eux < nx) {
1556						tty_cursor(tty, r.px[j], aty);
1557						nxx = nx - eux;
1558						if (r.nx[j] > nxx)
1559							r.nx[j] = nxx;
1560						tty_repeat_space(tty, r.nx[j]);
1561						ux = eux + r.nx[j];
1562					}
1563				}
1564			}
1565		} else if (gcp->attr & GRID_ATTR_CHARSET) {
1566			tty_attributes(tty, &last, defaults, palette,
1567			    s->hyperlinks);
1568			tty_cursor(tty, atx + ux, aty);
1569			for (j = 0; j < gcp->data.size; j++)
1570				tty_putc(tty, gcp->data.data[j]);
1571			ux += gcp->data.width;
1572		} else if (~gcp->flags & GRID_FLAG_PADDING) {
1573			memcpy(buf + len, gcp->data.data, gcp->data.size);
1574			len += gcp->data.size;
1575			width += gcp->data.width;
1576		}
1577	}
1578	if (len != 0 && ((~last.flags & GRID_FLAG_CLEARED) || last.bg != 8)) {
1579		tty_attributes(tty, &last, defaults, palette, s->hyperlinks);
1580		if (last.flags & GRID_FLAG_CLEARED) {
1581			log_debug("%s: %zu cleared (end)", __func__, len);
1582			tty_clear_line(tty, defaults, aty, atx + ux, width,
1583			    last.bg);
1584		} else {
1585			if (!wrapped || atx != 0 || ux != 0)
1586				tty_cursor(tty, atx + ux, aty);
1587			tty_putn(tty, buf, len, width);
1588		}
1589		ux += width;
1590	}
1591
1592	if (!cleared && ux < nx) {
1593		log_debug("%s: %u to end of line (%zu cleared)", __func__,
1594		    nx - ux, len);
1595		tty_default_attributes(tty, defaults, palette, 8,
1596		    s->hyperlinks);
1597		tty_clear_line(tty, defaults, aty, atx + ux, nx - ux, 8);
1598	}
1599
1600	tty->flags = (tty->flags & ~TTY_NOCURSOR) | flags;
1601	tty_update_mode(tty, tty->mode, s);
1602}
1603
1604void
1605tty_sync_start(struct tty *tty)
1606{
1607	if (tty->flags & TTY_BLOCK)
1608		return;
1609	if (tty->flags & TTY_SYNCING)
1610		return;
1611	tty->flags |= TTY_SYNCING;
1612
1613	if (tty_term_has(tty->term, TTYC_SYNC)) {
1614		log_debug("%s sync start", tty->client->name);
1615		tty_putcode_i(tty, TTYC_SYNC, 1);
1616	}
1617}
1618
1619void
1620tty_sync_end(struct tty *tty)
1621{
1622	if (tty->flags & TTY_BLOCK)
1623		return;
1624	if (~tty->flags & TTY_SYNCING)
1625		return;
1626	tty->flags &= ~TTY_SYNCING;
1627
1628	if (tty_term_has(tty->term, TTYC_SYNC)) {
1629 		log_debug("%s sync end", tty->client->name);
1630		tty_putcode_i(tty, TTYC_SYNC, 2);
1631	}
1632}
1633
1634static int
1635tty_client_ready(const struct tty_ctx *ctx, struct client *c)
1636{
1637	if (c->session == NULL || c->tty.term == NULL)
1638		return (0);
1639	if (c->flags & CLIENT_SUSPENDED)
1640		return (0);
1641
1642	/*
1643	 * If invisible panes are allowed (used for passthrough), don't care if
1644	 * redrawing or frozen.
1645	 */
1646	if (ctx->allow_invisible_panes)
1647		return (1);
1648
1649	if (c->flags & CLIENT_REDRAWWINDOW)
1650		return (0);
1651	if (c->tty.flags & TTY_FREEZE)
1652		return (0);
1653	return (1);
1654}
1655
1656void
1657tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *),
1658    struct tty_ctx *ctx)
1659{
1660	struct client	*c;
1661	int		 state;
1662
1663	if (ctx->set_client_cb == NULL)
1664		return;
1665	TAILQ_FOREACH(c, &clients, entry) {
1666		if (tty_client_ready(ctx, c)) {
1667			state = ctx->set_client_cb(ctx, c);
1668			if (state == -1)
1669				break;
1670			if (state == 0)
1671				continue;
1672			cmdfn(&c->tty, ctx);
1673		}
1674	}
1675}
1676
1677void
1678tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx)
1679{
1680	struct client	*c = tty->client;
1681
1682	if (ctx->bigger ||
1683	    !tty_full_width(tty, ctx) ||
1684	    tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
1685	    (!tty_term_has(tty->term, TTYC_ICH) &&
1686	    !tty_term_has(tty->term, TTYC_ICH1)) ||
1687	    c->overlay_check != NULL) {
1688		tty_draw_pane(tty, ctx, ctx->ocy);
1689		return;
1690	}
1691
1692	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1693	    ctx->s->hyperlinks);
1694
1695	tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
1696
1697	tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num);
1698}
1699
1700void
1701tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx)
1702{
1703	struct client	*c = tty->client;
1704
1705	if (ctx->bigger ||
1706	    !tty_full_width(tty, ctx) ||
1707	    tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
1708	    (!tty_term_has(tty->term, TTYC_DCH) &&
1709	    !tty_term_has(tty->term, TTYC_DCH1)) ||
1710	    c->overlay_check != NULL) {
1711		tty_draw_pane(tty, ctx, ctx->ocy);
1712		return;
1713	}
1714
1715	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1716	    ctx->s->hyperlinks);
1717
1718	tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
1719
1720	tty_emulate_repeat(tty, TTYC_DCH, TTYC_DCH1, ctx->num);
1721}
1722
1723void
1724tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx)
1725{
1726	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1727	    ctx->s->hyperlinks);
1728
1729	tty_clear_pane_line(tty, ctx, ctx->ocy, ctx->ocx, ctx->num, ctx->bg);
1730}
1731
1732void
1733tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx)
1734{
1735	struct client	*c = tty->client;
1736
1737	if (ctx->bigger ||
1738	    !tty_full_width(tty, ctx) ||
1739	    tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
1740	    !tty_term_has(tty->term, TTYC_CSR) ||
1741	    !tty_term_has(tty->term, TTYC_IL1) ||
1742	    ctx->sx == 1 ||
1743	    ctx->sy == 1 ||
1744	    c->overlay_check != NULL) {
1745		tty_redraw_region(tty, ctx);
1746		return;
1747	}
1748
1749	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1750	    ctx->s->hyperlinks);
1751
1752	tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
1753	tty_margin_off(tty);
1754	tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
1755
1756	tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ctx->num);
1757	tty->cx = tty->cy = UINT_MAX;
1758}
1759
1760void
1761tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx)
1762{
1763	struct client	*c = tty->client;
1764
1765	if (ctx->bigger ||
1766	    !tty_full_width(tty, ctx) ||
1767	    tty_fake_bce(tty, &ctx->defaults, ctx->bg) ||
1768	    !tty_term_has(tty->term, TTYC_CSR) ||
1769	    !tty_term_has(tty->term, TTYC_DL1) ||
1770	    ctx->sx == 1 ||
1771	    ctx->sy == 1 ||
1772	    c->overlay_check != NULL) {
1773		tty_redraw_region(tty, ctx);
1774		return;
1775	}
1776
1777	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1778	    ctx->s->hyperlinks);
1779
1780	tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
1781	tty_margin_off(tty);
1782	tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
1783
1784	tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ctx->num);
1785	tty->cx = tty->cy = UINT_MAX;
1786}
1787
1788void
1789tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx)
1790{
1791	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1792	    ctx->s->hyperlinks);
1793
1794	tty_clear_pane_line(tty, ctx, ctx->ocy, 0, ctx->sx, ctx->bg);
1795}
1796
1797void
1798tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx)
1799{
1800	u_int	nx = ctx->sx - ctx->ocx;
1801
1802	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1803	    ctx->s->hyperlinks);
1804
1805	tty_clear_pane_line(tty, ctx, ctx->ocy, ctx->ocx, nx, ctx->bg);
1806}
1807
1808void
1809tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx)
1810{
1811	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1812	    ctx->s->hyperlinks);
1813
1814	tty_clear_pane_line(tty, ctx, ctx->ocy, 0, ctx->ocx + 1, ctx->bg);
1815}
1816
1817void
1818tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx)
1819{
1820	struct client	*c = tty->client;
1821
1822	if (ctx->ocy != ctx->orupper)
1823		return;
1824
1825	if (ctx->bigger ||
1826	    (!tty_full_width(tty, ctx) && !tty_use_margin(tty)) ||
1827	    tty_fake_bce(tty, &ctx->defaults, 8) ||
1828	    !tty_term_has(tty->term, TTYC_CSR) ||
1829	    (!tty_term_has(tty->term, TTYC_RI) &&
1830	    !tty_term_has(tty->term, TTYC_RIN)) ||
1831	    ctx->sx == 1 ||
1832	    ctx->sy == 1 ||
1833	    c->overlay_check != NULL) {
1834		tty_redraw_region(tty, ctx);
1835		return;
1836	}
1837
1838	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1839	    ctx->s->hyperlinks);
1840
1841	tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
1842	tty_margin_pane(tty, ctx);
1843	tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper);
1844
1845	if (tty_term_has(tty->term, TTYC_RI))
1846		tty_putcode(tty, TTYC_RI);
1847	else
1848		tty_putcode_i(tty, TTYC_RIN, 1);
1849}
1850
1851void
1852tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
1853{
1854	struct client	*c = tty->client;
1855
1856	if (ctx->ocy != ctx->orlower)
1857		return;
1858
1859	if (ctx->bigger ||
1860	    (!tty_full_width(tty, ctx) && !tty_use_margin(tty)) ||
1861	    tty_fake_bce(tty, &ctx->defaults, 8) ||
1862	    !tty_term_has(tty->term, TTYC_CSR) ||
1863	    ctx->sx == 1 ||
1864	    ctx->sy == 1 ||
1865	    c->overlay_check != NULL) {
1866		tty_redraw_region(tty, ctx);
1867		return;
1868	}
1869
1870	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1871	    ctx->s->hyperlinks);
1872
1873	tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
1874	tty_margin_pane(tty, ctx);
1875
1876	/*
1877	 * If we want to wrap a pane while using margins, the cursor needs to
1878	 * be exactly on the right of the region. If the cursor is entirely off
1879	 * the edge - move it back to the right. Some terminals are funny about
1880	 * this and insert extra spaces, so only use the right if margins are
1881	 * enabled.
1882	 */
1883	if (ctx->xoff + ctx->ocx > tty->rright) {
1884		if (!tty_use_margin(tty))
1885			tty_cursor(tty, 0, ctx->yoff + ctx->ocy);
1886		else
1887			tty_cursor(tty, tty->rright, ctx->yoff + ctx->ocy);
1888	} else
1889		tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
1890
1891	tty_putc(tty, '\n');
1892}
1893
1894void
1895tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx)
1896{
1897	struct client	*c = tty->client;
1898	u_int		 i;
1899
1900	if (ctx->bigger ||
1901	    (!tty_full_width(tty, ctx) && !tty_use_margin(tty)) ||
1902	    tty_fake_bce(tty, &ctx->defaults, 8) ||
1903	    !tty_term_has(tty->term, TTYC_CSR) ||
1904	    ctx->sx == 1 ||
1905	    ctx->sy == 1 ||
1906	    c->overlay_check != NULL) {
1907		tty_redraw_region(tty, ctx);
1908		return;
1909	}
1910
1911	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1912	    ctx->s->hyperlinks);
1913
1914	tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
1915	tty_margin_pane(tty, ctx);
1916
1917	if (ctx->num == 1 || !tty_term_has(tty->term, TTYC_INDN)) {
1918		if (!tty_use_margin(tty))
1919			tty_cursor(tty, 0, tty->rlower);
1920		else
1921			tty_cursor(tty, tty->rright, tty->rlower);
1922		for (i = 0; i < ctx->num; i++)
1923			tty_putc(tty, '\n');
1924	} else {
1925		if (tty->cy == UINT_MAX)
1926			tty_cursor(tty, 0, 0);
1927		else
1928			tty_cursor(tty, 0, tty->cy);
1929		tty_putcode_i(tty, TTYC_INDN, ctx->num);
1930	}
1931}
1932
1933void
1934tty_cmd_scrolldown(struct tty *tty, const struct tty_ctx *ctx)
1935{
1936	u_int		 i;
1937	struct client	*c = tty->client;
1938
1939	if (ctx->bigger ||
1940	    (!tty_full_width(tty, ctx) && !tty_use_margin(tty)) ||
1941	    tty_fake_bce(tty, &ctx->defaults, 8) ||
1942	    !tty_term_has(tty->term, TTYC_CSR) ||
1943	    (!tty_term_has(tty->term, TTYC_RI) &&
1944	    !tty_term_has(tty->term, TTYC_RIN)) ||
1945	    ctx->sx == 1 ||
1946	    ctx->sy == 1 ||
1947	    c->overlay_check != NULL) {
1948		tty_redraw_region(tty, ctx);
1949		return;
1950	}
1951
1952	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1953	    ctx->s->hyperlinks);
1954
1955	tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
1956	tty_margin_pane(tty, ctx);
1957	tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper);
1958
1959	if (tty_term_has(tty->term, TTYC_RIN))
1960		tty_putcode_i(tty, TTYC_RIN, ctx->num);
1961	else {
1962		for (i = 0; i < ctx->num; i++)
1963			tty_putcode(tty, TTYC_RI);
1964	}
1965}
1966
1967void
1968tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx)
1969{
1970	u_int	px, py, nx, ny;
1971
1972	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1973	    ctx->s->hyperlinks);
1974
1975	tty_region_pane(tty, ctx, 0, ctx->sy - 1);
1976	tty_margin_off(tty);
1977
1978	px = 0;
1979	nx = ctx->sx;
1980	py = ctx->ocy + 1;
1981	ny = ctx->sy - ctx->ocy - 1;
1982
1983	tty_clear_pane_area(tty, ctx, py, ny, px, nx, ctx->bg);
1984
1985	px = ctx->ocx;
1986	nx = ctx->sx - ctx->ocx;
1987	py = ctx->ocy;
1988
1989	tty_clear_pane_line(tty, ctx, py, px, nx, ctx->bg);
1990}
1991
1992void
1993tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx)
1994{
1995	u_int	px, py, nx, ny;
1996
1997	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
1998	    ctx->s->hyperlinks);
1999
2000	tty_region_pane(tty, ctx, 0, ctx->sy - 1);
2001	tty_margin_off(tty);
2002
2003	px = 0;
2004	nx = ctx->sx;
2005	py = 0;
2006	ny = ctx->ocy;
2007
2008	tty_clear_pane_area(tty, ctx, py, ny, px, nx, ctx->bg);
2009
2010	px = 0;
2011	nx = ctx->ocx + 1;
2012	py = ctx->ocy;
2013
2014	tty_clear_pane_line(tty, ctx, py, px, nx, ctx->bg);
2015}
2016
2017void
2018tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx)
2019{
2020	u_int	px, py, nx, ny;
2021
2022	tty_default_attributes(tty, &ctx->defaults, ctx->palette, ctx->bg,
2023	    ctx->s->hyperlinks);
2024
2025	tty_region_pane(tty, ctx, 0, ctx->sy - 1);
2026	tty_margin_off(tty);
2027
2028	px = 0;
2029	nx = ctx->sx;
2030	py = 0;
2031	ny = ctx->sy;
2032
2033	tty_clear_pane_area(tty, ctx, py, ny, px, nx, ctx->bg);
2034}
2035
2036void
2037tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx)
2038{
2039	u_int	i, j;
2040
2041	if (ctx->bigger) {
2042		ctx->redraw_cb(ctx);
2043		return;
2044	}
2045
2046	tty_attributes(tty, &grid_default_cell, &ctx->defaults, ctx->palette,
2047	    ctx->s->hyperlinks);
2048
2049	tty_region_pane(tty, ctx, 0, ctx->sy - 1);
2050	tty_margin_off(tty);
2051
2052	for (j = 0; j < ctx->sy; j++) {
2053		tty_cursor_pane(tty, ctx, 0, j);
2054		for (i = 0; i < ctx->sx; i++)
2055			tty_putc(tty, 'E');
2056	}
2057}
2058
2059void
2060tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
2061{
2062	const struct grid_cell	*gcp = ctx->cell;
2063	struct screen		*s = ctx->s;
2064	struct overlay_ranges	 r;
2065	u_int			 px, py, i, vis = 0;
2066
2067	px = ctx->xoff + ctx->ocx - ctx->wox;
2068	py = ctx->yoff + ctx->ocy - ctx->woy;
2069	if (!tty_is_visible(tty, ctx, ctx->ocx, ctx->ocy, 1, 1) ||
2070	    (gcp->data.width == 1 && !tty_check_overlay(tty, px, py)))
2071		return;
2072
2073	/* Handle partially obstructed wide characters. */
2074	if (gcp->data.width > 1) {
2075		tty_check_overlay_range(tty, px, py, gcp->data.width, &r);
2076		for (i = 0; i < OVERLAY_MAX_RANGES; i++)
2077			vis += r.nx[i];
2078		if (vis < gcp->data.width) {
2079			tty_draw_line(tty, s, s->cx, s->cy, gcp->data.width,
2080			    px, py, &ctx->defaults, ctx->palette);
2081			return;
2082		}
2083	}
2084
2085	if (ctx->xoff + ctx->ocx - ctx->wox > tty->sx - 1 &&
2086	    ctx->ocy == ctx->orlower &&
2087	    tty_full_width(tty, ctx))
2088		tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
2089
2090	tty_margin_off(tty);
2091	tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy);
2092
2093	tty_cell(tty, ctx->cell, &ctx->defaults, ctx->palette,
2094	    ctx->s->hyperlinks);
2095
2096	if (ctx->num == 1)
2097		tty_invalidate(tty);
2098}
2099
2100void
2101tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
2102{
2103	struct overlay_ranges	 r;
2104	u_int			 i, px, py, cx;
2105	char			*cp = ctx->ptr;
2106
2107	if (!tty_is_visible(tty, ctx, ctx->ocx, ctx->ocy, ctx->num, 1))
2108		return;
2109
2110	if (ctx->bigger &&
2111	    (ctx->xoff + ctx->ocx < ctx->wox ||
2112	    ctx->xoff + ctx->ocx + ctx->num > ctx->wox + ctx->wsx)) {
2113		if (!ctx->wrapped ||
2114		    !tty_full_width(tty, ctx) ||
2115		    (tty->term->flags & TERM_NOAM) ||
2116		    ctx->xoff + ctx->ocx != 0 ||
2117		    ctx->yoff + ctx->ocy != tty->cy + 1 ||
2118		    tty->cx < tty->sx ||
2119		    tty->cy == tty->rlower)
2120			tty_draw_pane(tty, ctx, ctx->ocy);
2121		else
2122			ctx->redraw_cb(ctx);
2123		return;
2124	}
2125
2126	tty_margin_off(tty);
2127	tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy);
2128	tty_attributes(tty, ctx->cell, &ctx->defaults, ctx->palette, ctx->s->hyperlinks);
2129
2130	/* Get tty position from pane position for overlay check. */
2131	px = ctx->xoff + ctx->ocx - ctx->wox;
2132	py = ctx->yoff + ctx->ocy - ctx->woy;
2133
2134	tty_check_overlay_range(tty, px, py, ctx->num, &r);
2135	for (i = 0; i < OVERLAY_MAX_RANGES; i++) {
2136		if (r.nx[i] == 0)
2137			continue;
2138		/* Convert back to pane position for printing. */
2139		cx = r.px[i] - ctx->xoff + ctx->wox;
2140		tty_cursor_pane_unless_wrap(tty, ctx, cx, ctx->ocy);
2141		tty_putn(tty, cp + r.px[i] - px, r.nx[i], r.nx[i]);
2142	}
2143}
2144
2145void
2146tty_cmd_setselection(struct tty *tty, const struct tty_ctx *ctx)
2147{
2148	tty_set_selection(tty, ctx->ptr2, ctx->ptr, ctx->num);
2149}
2150
2151void
2152tty_set_selection(struct tty *tty, const char *flags, const char *buf,
2153    size_t len)
2154{
2155	char	*encoded;
2156	size_t	 size;
2157
2158	if (~tty->flags & TTY_STARTED)
2159		return;
2160	if (!tty_term_has(tty->term, TTYC_MS))
2161		return;
2162
2163	size = 4 * ((len + 2) / 3) + 1; /* storage for base64 */
2164	encoded = xmalloc(size);
2165
2166	b64_ntop(buf, len, encoded, size);
2167	tty->flags |= TTY_NOBLOCK;
2168	tty_putcode_ss(tty, TTYC_MS, flags, encoded);
2169
2170	free(encoded);
2171}
2172
2173void
2174tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx)
2175{
2176	tty->flags |= TTY_NOBLOCK;
2177	tty_add(tty, ctx->ptr, ctx->num);
2178	tty_invalidate(tty);
2179}
2180
2181void
2182tty_cmd_syncstart(struct tty *tty, const struct tty_ctx *ctx)
2183{
2184	if (ctx->num == 0x11) {
2185		/*
2186		 * This is an overlay and a command that moves the cursor so
2187		 * start synchronized updates.
2188		 */
2189		tty_sync_start(tty);
2190	} else if (~ctx->num & 0x10) {
2191		/*
2192		 * This is a pane. If there is an overlay, always start;
2193		 * otherwise, only if requested.
2194		 */
2195		if (ctx->num || tty->client->overlay_draw != NULL)
2196			tty_sync_start(tty);
2197	}
2198}
2199
2200void
2201tty_cell(struct tty *tty, const struct grid_cell *gc,
2202    const struct grid_cell *defaults, struct colour_palette *palette,
2203    struct hyperlinks *hl)
2204{
2205	const struct grid_cell	*gcp;
2206
2207	/* Skip last character if terminal is stupid. */
2208	if ((tty->term->flags & TERM_NOAM) &&
2209	    tty->cy == tty->sy - 1 &&
2210	    tty->cx == tty->sx - 1)
2211		return;
2212
2213	/* If this is a padding character, do nothing. */
2214	if (gc->flags & GRID_FLAG_PADDING)
2215		return;
2216
2217	/* Check the output codeset and apply attributes. */
2218	gcp = tty_check_codeset(tty, gc);
2219	tty_attributes(tty, gcp, defaults, palette, hl);
2220
2221	/* If it is a single character, write with putc to handle ACS. */
2222	if (gcp->data.size == 1) {
2223		tty_attributes(tty, gcp, defaults, palette, hl);
2224		if (*gcp->data.data < 0x20 || *gcp->data.data == 0x7f)
2225			return;
2226		tty_putc(tty, *gcp->data.data);
2227		return;
2228	}
2229
2230	/* Write the data. */
2231	tty_putn(tty, gcp->data.data, gcp->data.size, gcp->data.width);
2232}
2233
2234void
2235tty_reset(struct tty *tty)
2236{
2237	struct grid_cell	*gc = &tty->cell;
2238
2239	if (!grid_cells_equal(gc, &grid_default_cell)) {
2240		if (gc->link != 0)
2241			tty_putcode_ss(tty, TTYC_HLS, "", "");
2242		if ((gc->attr & GRID_ATTR_CHARSET) && tty_acs_needed(tty))
2243			tty_putcode(tty, TTYC_RMACS);
2244		tty_putcode(tty, TTYC_SGR0);
2245		memcpy(gc, &grid_default_cell, sizeof *gc);
2246	}
2247	memcpy(&tty->last_cell, &grid_default_cell, sizeof tty->last_cell);
2248}
2249
2250static void
2251tty_invalidate(struct tty *tty)
2252{
2253	memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell);
2254	memcpy(&tty->last_cell, &grid_default_cell, sizeof tty->last_cell);
2255
2256	tty->cx = tty->cy = UINT_MAX;
2257	tty->rupper = tty->rleft = UINT_MAX;
2258	tty->rlower = tty->rright = UINT_MAX;
2259
2260	if (tty->flags & TTY_STARTED) {
2261		if (tty_use_margin(tty))
2262			tty_putcode(tty, TTYC_ENMG);
2263		tty_putcode(tty, TTYC_SGR0);
2264
2265		tty->mode = ALL_MODES;
2266		tty_update_mode(tty, MODE_CURSOR, NULL);
2267
2268		tty_cursor(tty, 0, 0);
2269		tty_region_off(tty);
2270		tty_margin_off(tty);
2271	} else
2272		tty->mode = MODE_CURSOR;
2273}
2274
2275/* Turn off margin. */
2276void
2277tty_region_off(struct tty *tty)
2278{
2279	tty_region(tty, 0, tty->sy - 1);
2280}
2281
2282/* Set region inside pane. */
2283static void
2284tty_region_pane(struct tty *tty, const struct tty_ctx *ctx, u_int rupper,
2285    u_int rlower)
2286{
2287	tty_region(tty, ctx->yoff + rupper - ctx->woy,
2288	    ctx->yoff + rlower - ctx->woy);
2289}
2290
2291/* Set region at absolute position. */
2292static void
2293tty_region(struct tty *tty, u_int rupper, u_int rlower)
2294{
2295	if (tty->rlower == rlower && tty->rupper == rupper)
2296		return;
2297	if (!tty_term_has(tty->term, TTYC_CSR))
2298		return;
2299
2300	tty->rupper = rupper;
2301	tty->rlower = rlower;
2302
2303	/*
2304	 * Some terminals (such as PuTTY) do not correctly reset the cursor to
2305	 * 0,0 if it is beyond the last column (they do not reset their wrap
2306	 * flag so further output causes a line feed). As a workaround, do an
2307	 * explicit move to 0 first.
2308	 */
2309	if (tty->cx >= tty->sx) {
2310		if (tty->cy == UINT_MAX)
2311			tty_cursor(tty, 0, 0);
2312		else
2313			tty_cursor(tty, 0, tty->cy);
2314	}
2315
2316	tty_putcode_ii(tty, TTYC_CSR, tty->rupper, tty->rlower);
2317	tty->cx = tty->cy = UINT_MAX;
2318}
2319
2320/* Turn off margin. */
2321void
2322tty_margin_off(struct tty *tty)
2323{
2324	tty_margin(tty, 0, tty->sx - 1);
2325}
2326
2327/* Set margin inside pane. */
2328static void
2329tty_margin_pane(struct tty *tty, const struct tty_ctx *ctx)
2330{
2331	tty_margin(tty, ctx->xoff - ctx->wox,
2332	    ctx->xoff + ctx->sx - 1 - ctx->wox);
2333}
2334
2335/* Set margin at absolute position. */
2336static void
2337tty_margin(struct tty *tty, u_int rleft, u_int rright)
2338{
2339	if (!tty_use_margin(tty))
2340		return;
2341	if (tty->rleft == rleft && tty->rright == rright)
2342		return;
2343
2344	tty_putcode_ii(tty, TTYC_CSR, tty->rupper, tty->rlower);
2345
2346	tty->rleft = rleft;
2347	tty->rright = rright;
2348
2349	if (rleft == 0 && rright == tty->sx - 1)
2350		tty_putcode(tty, TTYC_CLMG);
2351	else
2352		tty_putcode_ii(tty, TTYC_CMG, rleft, rright);
2353	tty->cx = tty->cy = UINT_MAX;
2354}
2355
2356/*
2357 * Move the cursor, unless it would wrap itself when the next character is
2358 * printed.
2359 */
2360static void
2361tty_cursor_pane_unless_wrap(struct tty *tty, const struct tty_ctx *ctx,
2362    u_int cx, u_int cy)
2363{
2364	if (!ctx->wrapped ||
2365	    !tty_full_width(tty, ctx) ||
2366	    (tty->term->flags & TERM_NOAM) ||
2367	    ctx->xoff + cx != 0 ||
2368	    ctx->yoff + cy != tty->cy + 1 ||
2369	    tty->cx < tty->sx ||
2370	    tty->cy == tty->rlower)
2371		tty_cursor_pane(tty, ctx, cx, cy);
2372	else
2373		log_debug("%s: will wrap at %u,%u", __func__, tty->cx, tty->cy);
2374}
2375
2376/* Move cursor inside pane. */
2377static void
2378tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy)
2379{
2380	tty_cursor(tty, ctx->xoff + cx - ctx->wox, ctx->yoff + cy - ctx->woy);
2381}
2382
2383/* Move cursor to absolute position. */
2384void
2385tty_cursor(struct tty *tty, u_int cx, u_int cy)
2386{
2387	struct tty_term	*term = tty->term;
2388	u_int		 thisx, thisy;
2389	int		 change;
2390
2391	if (tty->flags & TTY_BLOCK)
2392		return;
2393
2394	thisx = tty->cx;
2395	thisy = tty->cy;
2396
2397	/*
2398	 * If in the automargin space, and want to be there, do not move.
2399	 * Otherwise, force the cursor to be in range (and complain).
2400	 */
2401	if (cx == thisx && cy == thisy && cx == tty->sx)
2402		return;
2403	if (cx > tty->sx - 1) {
2404		log_debug("%s: x too big %u > %u", __func__, cx, tty->sx - 1);
2405		cx = tty->sx - 1;
2406	}
2407
2408	/* No change. */
2409	if (cx == thisx && cy == thisy)
2410		return;
2411
2412	/* Currently at the very end of the line - use absolute movement. */
2413	if (thisx > tty->sx - 1)
2414		goto absolute;
2415
2416	/* Move to home position (0, 0). */
2417	if (cx == 0 && cy == 0 && tty_term_has(term, TTYC_HOME)) {
2418		tty_putcode(tty, TTYC_HOME);
2419		goto out;
2420	}
2421
2422	/* Zero on the next line. */
2423	if (cx == 0 && cy == thisy + 1 && thisy != tty->rlower &&
2424	    (!tty_use_margin(tty) || tty->rleft == 0)) {
2425		tty_putc(tty, '\r');
2426		tty_putc(tty, '\n');
2427		goto out;
2428	}
2429
2430	/* Moving column or row. */
2431	if (cy == thisy) {
2432		/*
2433		 * Moving column only, row staying the same.
2434		 */
2435
2436		/* To left edge. */
2437		if (cx == 0 && (!tty_use_margin(tty) || tty->rleft == 0)) {
2438			tty_putc(tty, '\r');
2439			goto out;
2440		}
2441
2442		/* One to the left. */
2443		if (cx == thisx - 1 && tty_term_has(term, TTYC_CUB1)) {
2444			tty_putcode(tty, TTYC_CUB1);
2445			goto out;
2446		}
2447
2448		/* One to the right. */
2449		if (cx == thisx + 1 && tty_term_has(term, TTYC_CUF1)) {
2450			tty_putcode(tty, TTYC_CUF1);
2451			goto out;
2452		}
2453
2454		/* Calculate difference. */
2455		change = thisx - cx;	/* +ve left, -ve right */
2456
2457		/*
2458		 * Use HPA if change is larger than absolute, otherwise move
2459		 * the cursor with CUB/CUF.
2460		 */
2461		if ((u_int) abs(change) > cx && tty_term_has(term, TTYC_HPA)) {
2462			tty_putcode_i(tty, TTYC_HPA, cx);
2463			goto out;
2464		} else if (change > 0 &&
2465		    tty_term_has(term, TTYC_CUB) &&
2466		    !tty_use_margin(tty)) {
2467			if (change == 2 && tty_term_has(term, TTYC_CUB1)) {
2468				tty_putcode(tty, TTYC_CUB1);
2469				tty_putcode(tty, TTYC_CUB1);
2470				goto out;
2471			}
2472			tty_putcode_i(tty, TTYC_CUB, change);
2473			goto out;
2474		} else if (change < 0 &&
2475		    tty_term_has(term, TTYC_CUF) &&
2476		    !tty_use_margin(tty)) {
2477			tty_putcode_i(tty, TTYC_CUF, -change);
2478			goto out;
2479		}
2480	} else if (cx == thisx) {
2481		/*
2482		 * Moving row only, column staying the same.
2483		 */
2484
2485		/* One above. */
2486		if (thisy != tty->rupper &&
2487		    cy == thisy - 1 && tty_term_has(term, TTYC_CUU1)) {
2488			tty_putcode(tty, TTYC_CUU1);
2489			goto out;
2490		}
2491
2492		/* One below. */
2493		if (thisy != tty->rlower &&
2494		    cy == thisy + 1 && tty_term_has(term, TTYC_CUD1)) {
2495			tty_putcode(tty, TTYC_CUD1);
2496			goto out;
2497		}
2498
2499		/* Calculate difference. */
2500		change = thisy - cy;	/* +ve up, -ve down */
2501
2502		/*
2503		 * Try to use VPA if change is larger than absolute or if this
2504		 * change would cross the scroll region, otherwise use CUU/CUD.
2505		 */
2506		if ((u_int) abs(change) > cy ||
2507		    (change < 0 && cy - change > tty->rlower) ||
2508		    (change > 0 && cy - change < tty->rupper)) {
2509			    if (tty_term_has(term, TTYC_VPA)) {
2510				    tty_putcode_i(tty, TTYC_VPA, cy);
2511				    goto out;
2512			    }
2513		} else if (change > 0 && tty_term_has(term, TTYC_CUU)) {
2514			tty_putcode_i(tty, TTYC_CUU, change);
2515			goto out;
2516		} else if (change < 0 && tty_term_has(term, TTYC_CUD)) {
2517			tty_putcode_i(tty, TTYC_CUD, -change);
2518			goto out;
2519		}
2520	}
2521
2522absolute:
2523	/* Absolute movement. */
2524	tty_putcode_ii(tty, TTYC_CUP, cy, cx);
2525
2526out:
2527	tty->cx = cx;
2528	tty->cy = cy;
2529}
2530
2531static void
2532tty_hyperlink(struct tty *tty, const struct grid_cell *gc,
2533    struct hyperlinks *hl)
2534{
2535	const char	*uri, *id;
2536
2537	if (gc->link == tty->cell.link)
2538		return;
2539	tty->cell.link = gc->link;
2540
2541	if (hl == NULL)
2542		return;
2543
2544	if (gc->link == 0 || !hyperlinks_get(hl, gc->link, &uri, NULL, &id))
2545		tty_putcode_ss(tty, TTYC_HLS, "", "");
2546	else
2547		tty_putcode_ss(tty, TTYC_HLS, id, uri);
2548}
2549
2550void
2551tty_attributes(struct tty *tty, const struct grid_cell *gc,
2552    const struct grid_cell *defaults, struct colour_palette *palette,
2553    struct hyperlinks *hl)
2554{
2555	struct grid_cell	*tc = &tty->cell, gc2;
2556	int			 changed;
2557
2558	/* Copy cell and update default colours. */
2559	memcpy(&gc2, gc, sizeof gc2);
2560	if (~gc->flags & GRID_FLAG_NOPALETTE) {
2561		if (gc2.fg == 8)
2562			gc2.fg = defaults->fg;
2563		if (gc2.bg == 8)
2564			gc2.bg = defaults->bg;
2565	}
2566
2567	/* Ignore cell if it is the same as the last one. */
2568	if (gc2.attr == tty->last_cell.attr &&
2569	    gc2.fg == tty->last_cell.fg &&
2570	    gc2.bg == tty->last_cell.bg &&
2571	    gc2.us == tty->last_cell.us &&
2572		gc2.link == tty->last_cell.link)
2573		return;
2574
2575	/*
2576	 * If no setab, try to use the reverse attribute as a best-effort for a
2577	 * non-default background. This is a bit of a hack but it doesn't do
2578	 * any serious harm and makes a couple of applications happier.
2579	 */
2580	if (!tty_term_has(tty->term, TTYC_SETAB)) {
2581		if (gc2.attr & GRID_ATTR_REVERSE) {
2582			if (gc2.fg != 7 && !COLOUR_DEFAULT(gc2.fg))
2583				gc2.attr &= ~GRID_ATTR_REVERSE;
2584		} else {
2585			if (gc2.bg != 0 && !COLOUR_DEFAULT(gc2.bg))
2586				gc2.attr |= GRID_ATTR_REVERSE;
2587		}
2588	}
2589
2590	/* Fix up the colours if necessary. */
2591	tty_check_fg(tty, palette, &gc2);
2592	tty_check_bg(tty, palette, &gc2);
2593	tty_check_us(tty, palette, &gc2);
2594
2595	/*
2596	 * If any bits are being cleared or the underline colour is now default,
2597	 * reset everything.
2598	 */
2599	if ((tc->attr & ~gc2.attr) || (tc->us != gc2.us && gc2.us == 0))
2600		tty_reset(tty);
2601
2602	/*
2603	 * Set the colours. This may call tty_reset() (so it comes next) and
2604	 * may add to (NOT remove) the desired attributes.
2605	 */
2606	tty_colours(tty, &gc2);
2607
2608	/* Filter out attribute bits already set. */
2609	changed = gc2.attr & ~tc->attr;
2610	tc->attr = gc2.attr;
2611
2612	/* Set the attributes. */
2613	if (changed & GRID_ATTR_BRIGHT)
2614		tty_putcode(tty, TTYC_BOLD);
2615	if (changed & GRID_ATTR_DIM)
2616		tty_putcode(tty, TTYC_DIM);
2617	if (changed & GRID_ATTR_ITALICS)
2618		tty_set_italics(tty);
2619	if (changed & GRID_ATTR_ALL_UNDERSCORE) {
2620		if ((changed & GRID_ATTR_UNDERSCORE) ||
2621		    !tty_term_has(tty->term, TTYC_SMULX))
2622			tty_putcode(tty, TTYC_SMUL);
2623		else if (changed & GRID_ATTR_UNDERSCORE_2)
2624			tty_putcode_i(tty, TTYC_SMULX, 2);
2625		else if (changed & GRID_ATTR_UNDERSCORE_3)
2626			tty_putcode_i(tty, TTYC_SMULX, 3);
2627		else if (changed & GRID_ATTR_UNDERSCORE_4)
2628			tty_putcode_i(tty, TTYC_SMULX, 4);
2629		else if (changed & GRID_ATTR_UNDERSCORE_5)
2630			tty_putcode_i(tty, TTYC_SMULX, 5);
2631	}
2632	if (changed & GRID_ATTR_BLINK)
2633		tty_putcode(tty, TTYC_BLINK);
2634	if (changed & GRID_ATTR_REVERSE) {
2635		if (tty_term_has(tty->term, TTYC_REV))
2636			tty_putcode(tty, TTYC_REV);
2637		else if (tty_term_has(tty->term, TTYC_SMSO))
2638			tty_putcode(tty, TTYC_SMSO);
2639	}
2640	if (changed & GRID_ATTR_HIDDEN)
2641		tty_putcode(tty, TTYC_INVIS);
2642	if (changed & GRID_ATTR_STRIKETHROUGH)
2643		tty_putcode(tty, TTYC_SMXX);
2644	if (changed & GRID_ATTR_OVERLINE)
2645		tty_putcode(tty, TTYC_SMOL);
2646	if ((changed & GRID_ATTR_CHARSET) && tty_acs_needed(tty))
2647		tty_putcode(tty, TTYC_SMACS);
2648
2649	/* Set hyperlink if any. */
2650	tty_hyperlink(tty, gc, hl);
2651
2652	memcpy(&tty->last_cell, &gc2, sizeof tty->last_cell);
2653}
2654
2655static void
2656tty_colours(struct tty *tty, const struct grid_cell *gc)
2657{
2658	struct grid_cell	*tc = &tty->cell;
2659	int			 have_ax;
2660
2661	/* No changes? Nothing is necessary. */
2662	if (gc->fg == tc->fg && gc->bg == tc->bg && gc->us == tc->us)
2663		return;
2664
2665	/*
2666	 * Is either the default colour? This is handled specially because the
2667	 * best solution might be to reset both colours to default, in which
2668	 * case if only one is default need to fall onward to set the other
2669	 * colour.
2670	 */
2671	if (COLOUR_DEFAULT(gc->fg) || COLOUR_DEFAULT(gc->bg)) {
2672		/*
2673		 * If don't have AX but do have op, send sgr0 (op can't
2674		 * actually be used because it is sometimes the same as sgr0
2675		 * and sometimes isn't). This resets both colours to default.
2676		 *
2677		 * Otherwise, try to set the default colour only as needed.
2678		 */
2679		have_ax = tty_term_flag(tty->term, TTYC_AX);
2680		if (!have_ax && tty_term_has(tty->term, TTYC_OP))
2681			tty_reset(tty);
2682		else {
2683			if (COLOUR_DEFAULT(gc->fg) && !COLOUR_DEFAULT(tc->fg)) {
2684				if (have_ax)
2685					tty_puts(tty, "\033[39m");
2686				else if (tc->fg != 7)
2687					tty_putcode_i(tty, TTYC_SETAF, 7);
2688				tc->fg = gc->fg;
2689			}
2690			if (COLOUR_DEFAULT(gc->bg) && !COLOUR_DEFAULT(tc->bg)) {
2691				if (have_ax)
2692					tty_puts(tty, "\033[49m");
2693				else if (tc->bg != 0)
2694					tty_putcode_i(tty, TTYC_SETAB, 0);
2695				tc->bg = gc->bg;
2696			}
2697		}
2698	}
2699
2700	/* Set the foreground colour. */
2701	if (!COLOUR_DEFAULT(gc->fg) && gc->fg != tc->fg)
2702		tty_colours_fg(tty, gc);
2703
2704	/*
2705	 * Set the background colour. This must come after the foreground as
2706	 * tty_colour_fg() can call tty_reset().
2707	 */
2708	if (!COLOUR_DEFAULT(gc->bg) && gc->bg != tc->bg)
2709		tty_colours_bg(tty, gc);
2710
2711	/* Set the underscore colour. */
2712	if (gc->us != tc->us)
2713		tty_colours_us(tty, gc);
2714}
2715
2716static void
2717tty_check_fg(struct tty *tty, struct colour_palette *palette,
2718    struct grid_cell *gc)
2719{
2720	u_char	r, g, b;
2721	u_int	colours;
2722	int	c;
2723
2724	/*
2725	 * Perform substitution if this pane has a palette. If the bright
2726	 * attribute is set and Nobr is not present, use the bright entry in
2727	 * the palette by changing to the aixterm colour
2728	 */
2729	if (~gc->flags & GRID_FLAG_NOPALETTE) {
2730		c = gc->fg;
2731		if (c < 8 &&
2732		    gc->attr & GRID_ATTR_BRIGHT &&
2733		    !tty_term_has(tty->term, TTYC_NOBR))
2734			c += 90;
2735		if ((c = colour_palette_get(palette, c)) != -1)
2736			gc->fg = c;
2737	}
2738
2739	/* Is this a 24-bit colour? */
2740	if (gc->fg & COLOUR_FLAG_RGB) {
2741		/* Not a 24-bit terminal? Translate to 256-colour palette. */
2742		if (tty->term->flags & TERM_RGBCOLOURS)
2743			return;
2744		colour_split_rgb(gc->fg, &r, &g, &b);
2745		gc->fg = colour_find_rgb(r, g, b);
2746	}
2747
2748	/* How many colours does this terminal have? */
2749	if (tty->term->flags & TERM_256COLOURS)
2750		colours = 256;
2751	else
2752		colours = tty_term_number(tty->term, TTYC_COLORS);
2753
2754	/* Is this a 256-colour colour? */
2755	if (gc->fg & COLOUR_FLAG_256) {
2756		/* And not a 256 colour mode? */
2757		if (colours < 256) {
2758			gc->fg = colour_256to16(gc->fg);
2759			if (gc->fg & 8) {
2760				gc->fg &= 7;
2761				if (colours >= 16)
2762					gc->fg += 90;
2763			}
2764		}
2765		return;
2766	}
2767
2768	/* Is this an aixterm colour? */
2769	if (gc->fg >= 90 && gc->fg <= 97 && colours < 16) {
2770		gc->fg -= 90;
2771		gc->attr |= GRID_ATTR_BRIGHT;
2772	}
2773}
2774
2775static void
2776tty_check_bg(struct tty *tty, struct colour_palette *palette,
2777    struct grid_cell *gc)
2778{
2779	u_char	r, g, b;
2780	u_int	colours;
2781	int	c;
2782
2783	/* Perform substitution if this pane has a palette. */
2784	if (~gc->flags & GRID_FLAG_NOPALETTE) {
2785		if ((c = colour_palette_get(palette, gc->bg)) != -1)
2786			gc->bg = c;
2787	}
2788
2789	/* Is this a 24-bit colour? */
2790	if (gc->bg & COLOUR_FLAG_RGB) {
2791		/* Not a 24-bit terminal? Translate to 256-colour palette. */
2792		if (tty->term->flags & TERM_RGBCOLOURS)
2793			return;
2794		colour_split_rgb(gc->bg, &r, &g, &b);
2795		gc->bg = colour_find_rgb(r, g, b);
2796	}
2797
2798	/* How many colours does this terminal have? */
2799	if (tty->term->flags & TERM_256COLOURS)
2800		colours = 256;
2801	else
2802		colours = tty_term_number(tty->term, TTYC_COLORS);
2803
2804	/* Is this a 256-colour colour? */
2805	if (gc->bg & COLOUR_FLAG_256) {
2806		/*
2807		 * And not a 256 colour mode? Translate to 16-colour
2808		 * palette. Bold background doesn't exist portably, so just
2809		 * discard the bold bit if set.
2810		 */
2811		if (colours < 256) {
2812			gc->bg = colour_256to16(gc->bg);
2813			if (gc->bg & 8) {
2814				gc->bg &= 7;
2815				if (colours >= 16)
2816					gc->bg += 90;
2817			}
2818		}
2819		return;
2820	}
2821
2822	/* Is this an aixterm colour? */
2823	if (gc->bg >= 90 && gc->bg <= 97 && colours < 16)
2824		gc->bg -= 90;
2825}
2826
2827static void
2828tty_check_us(__unused struct tty *tty, struct colour_palette *palette,
2829    struct grid_cell *gc)
2830{
2831	int	c;
2832
2833	/* Perform substitution if this pane has a palette. */
2834	if (~gc->flags & GRID_FLAG_NOPALETTE) {
2835		if ((c = colour_palette_get(palette, gc->us)) != -1)
2836			gc->us = c;
2837	}
2838
2839	/* Convert underscore colour if only RGB can be supported. */
2840	if (!tty_term_has(tty->term, TTYC_SETULC1)) {
2841		    if ((c = colour_force_rgb (gc->us)) == -1)
2842			    gc->us = 8;
2843		    else
2844			    gc->us = c;
2845	}
2846}
2847
2848static void
2849tty_colours_fg(struct tty *tty, const struct grid_cell *gc)
2850{
2851	struct grid_cell	*tc = &tty->cell;
2852	char			 s[32];
2853
2854	/* Is this a 24-bit or 256-colour colour? */
2855	if (gc->fg & COLOUR_FLAG_RGB || gc->fg & COLOUR_FLAG_256) {
2856		if (tty_try_colour(tty, gc->fg, "38") == 0)
2857			goto save;
2858		/* Should not get here, already converted in tty_check_fg. */
2859		return;
2860	}
2861
2862	/* Is this an aixterm bright colour? */
2863	if (gc->fg >= 90 && gc->fg <= 97) {
2864		if (tty->term->flags & TERM_256COLOURS) {
2865			xsnprintf(s, sizeof s, "\033[%dm", gc->fg);
2866			tty_puts(tty, s);
2867		} else
2868			tty_putcode_i(tty, TTYC_SETAF, gc->fg - 90 + 8);
2869		goto save;
2870	}
2871
2872	/* Otherwise set the foreground colour. */
2873	tty_putcode_i(tty, TTYC_SETAF, gc->fg);
2874
2875save:
2876	/* Save the new values in the terminal current cell. */
2877	tc->fg = gc->fg;
2878}
2879
2880static void
2881tty_colours_bg(struct tty *tty, const struct grid_cell *gc)
2882{
2883	struct grid_cell	*tc = &tty->cell;
2884	char			 s[32];
2885
2886	/* Is this a 24-bit or 256-colour colour? */
2887	if (gc->bg & COLOUR_FLAG_RGB || gc->bg & COLOUR_FLAG_256) {
2888		if (tty_try_colour(tty, gc->bg, "48") == 0)
2889			goto save;
2890		/* Should not get here, already converted in tty_check_bg. */
2891		return;
2892	}
2893
2894	/* Is this an aixterm bright colour? */
2895	if (gc->bg >= 90 && gc->bg <= 97) {
2896		if (tty->term->flags & TERM_256COLOURS) {
2897			xsnprintf(s, sizeof s, "\033[%dm", gc->bg + 10);
2898			tty_puts(tty, s);
2899		} else
2900			tty_putcode_i(tty, TTYC_SETAB, gc->bg - 90 + 8);
2901		goto save;
2902	}
2903
2904	/* Otherwise set the background colour. */
2905	tty_putcode_i(tty, TTYC_SETAB, gc->bg);
2906
2907save:
2908	/* Save the new values in the terminal current cell. */
2909	tc->bg = gc->bg;
2910}
2911
2912static void
2913tty_colours_us(struct tty *tty, const struct grid_cell *gc)
2914{
2915	struct grid_cell	*tc = &tty->cell;
2916	u_int			 c;
2917	u_char			 r, g, b;
2918
2919	/* Clear underline colour. */
2920	if (COLOUR_DEFAULT(gc->us)) {
2921		tty_putcode(tty, TTYC_OL);
2922		goto save;
2923	}
2924
2925	/*
2926	 * If this is not an RGB colour, use Setulc1 if it exists, otherwise
2927	 * convert.
2928	 */
2929	if (~gc->us & COLOUR_FLAG_RGB) {
2930		c = gc->us;
2931		if ((~c & COLOUR_FLAG_256) && (c >= 90 && c <= 97))
2932			c -= 82;
2933		tty_putcode_i(tty, TTYC_SETULC1, c & ~COLOUR_FLAG_256);
2934		return;
2935	}
2936
2937	/*
2938	 * Setulc and setal follows the ncurses(3) one argument "direct colour"
2939	 * capability format. Calculate the colour value.
2940	 */
2941	colour_split_rgb(gc->us, &r, &g, &b);
2942	c = (65536 * r) + (256 * g) + b;
2943
2944	/*
2945	 * Write the colour. Only use setal if the RGB flag is set because the
2946	 * non-RGB version may be wrong.
2947	 */
2948	if (tty_term_has(tty->term, TTYC_SETULC))
2949		tty_putcode_i(tty, TTYC_SETULC, c);
2950	else if (tty_term_has(tty->term, TTYC_SETAL) &&
2951	    tty_term_has(tty->term, TTYC_RGB))
2952		tty_putcode_i(tty, TTYC_SETAL, c);
2953
2954save:
2955	/* Save the new values in the terminal current cell. */
2956	tc->us = gc->us;
2957}
2958
2959static int
2960tty_try_colour(struct tty *tty, int colour, const char *type)
2961{
2962	u_char	r, g, b;
2963
2964	if (colour & COLOUR_FLAG_256) {
2965		if (*type == '3' && tty_term_has(tty->term, TTYC_SETAF))
2966			tty_putcode_i(tty, TTYC_SETAF, colour & 0xff);
2967		else if (tty_term_has(tty->term, TTYC_SETAB))
2968			tty_putcode_i(tty, TTYC_SETAB, colour & 0xff);
2969		return (0);
2970	}
2971
2972	if (colour & COLOUR_FLAG_RGB) {
2973		colour_split_rgb(colour & 0xffffff, &r, &g, &b);
2974		if (*type == '3' && tty_term_has(tty->term, TTYC_SETRGBF))
2975			tty_putcode_iii(tty, TTYC_SETRGBF, r, g, b);
2976		else if (tty_term_has(tty->term, TTYC_SETRGBB))
2977			tty_putcode_iii(tty, TTYC_SETRGBB, r, g, b);
2978		return (0);
2979	}
2980
2981	return (-1);
2982}
2983
2984static void
2985tty_window_default_style(struct grid_cell *gc, struct window_pane *wp)
2986{
2987	memcpy(gc, &grid_default_cell, sizeof *gc);
2988	gc->fg = wp->palette.fg;
2989	gc->bg = wp->palette.bg;
2990}
2991
2992void
2993tty_default_colours(struct grid_cell *gc, struct window_pane *wp)
2994{
2995	struct options		*oo = wp->options;
2996	struct format_tree	*ft;
2997
2998	memcpy(gc, &grid_default_cell, sizeof *gc);
2999
3000	if (wp->flags & PANE_STYLECHANGED) {
3001		log_debug("%%%u: style changed", wp->id);
3002		wp->flags &= ~PANE_STYLECHANGED;
3003
3004		ft = format_create(NULL, NULL, FORMAT_PANE|wp->id,
3005		    FORMAT_NOJOBS);
3006		format_defaults(ft, NULL, NULL, NULL, wp);
3007		tty_window_default_style(&wp->cached_active_gc, wp);
3008		style_add(&wp->cached_active_gc, oo, "window-active-style", ft);
3009		tty_window_default_style(&wp->cached_gc, wp);
3010		style_add(&wp->cached_gc, oo, "window-style", ft);
3011		format_free(ft);
3012	}
3013
3014	if (gc->fg == 8) {
3015		if (wp == wp->window->active && wp->cached_active_gc.fg != 8)
3016			gc->fg = wp->cached_active_gc.fg;
3017		else
3018			gc->fg = wp->cached_gc.fg;
3019	}
3020
3021	if (gc->bg == 8) {
3022		if (wp == wp->window->active && wp->cached_active_gc.bg != 8)
3023			gc->bg = wp->cached_active_gc.bg;
3024		else
3025			gc->bg = wp->cached_gc.bg;
3026	}
3027}
3028
3029static void
3030tty_default_attributes(struct tty *tty, const struct grid_cell *defaults,
3031    struct colour_palette *palette, u_int bg, struct hyperlinks *hl)
3032{
3033	struct grid_cell	gc;
3034
3035	memcpy(&gc, &grid_default_cell, sizeof gc);
3036	gc.bg = bg;
3037	tty_attributes(tty, &gc, defaults, palette, hl);
3038}
3039
3040static void
3041tty_clipboard_query_callback(__unused int fd, __unused short events, void *data)
3042{
3043	struct tty	*tty = data;
3044	struct client	*c = tty->client;
3045
3046	c->flags &= ~CLIENT_CLIPBOARDBUFFER;
3047	free(c->clipboard_panes);
3048	c->clipboard_panes = NULL;
3049	c->clipboard_npanes = 0;
3050
3051	tty->flags &= ~TTY_OSC52QUERY;
3052}
3053
3054void
3055tty_clipboard_query(struct tty *tty)
3056{
3057	struct timeval	 tv = { .tv_sec = TTY_QUERY_TIMEOUT };
3058
3059	if ((~tty->flags & TTY_STARTED) || (tty->flags & TTY_OSC52QUERY))
3060		return;
3061	tty_putcode_ss(tty, TTYC_MS, "", "?");
3062
3063	tty->flags |= TTY_OSC52QUERY;
3064	evtimer_set(&tty->clipboard_timer, tty_clipboard_query_callback, tty);
3065	evtimer_add(&tty->clipboard_timer, &tv);
3066}
3067