Annotation of src/usr.bin/tmux/tty.c, Revision 1.187
1.187 ! nicm 1: /* $OpenBSD: tty.c,v 1.186 2015/09/02 17:37:54 nicm Exp $ */
1.1 nicm 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:
1.106 nicm 22: #include <netinet/in.h>
23:
1.1 nicm 24: #include <errno.h>
25: #include <fcntl.h>
1.106 nicm 26: #include <resolv.h>
1.42 nicm 27: #include <stdlib.h>
1.1 nicm 28: #include <string.h>
29: #include <termios.h>
30: #include <unistd.h>
31:
32: #include "tmux.h"
33:
1.67 nicm 34: void tty_read_callback(struct bufferevent *, void *);
1.66 nicm 35: void tty_error_callback(struct bufferevent *, short, void *);
36:
1.180 nicm 37: void tty_set_italics(struct tty *);
1.1 nicm 38: int tty_try_256(struct tty *, u_char, const char *);
39:
1.85 nicm 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 *);
1.73 nicm 44: void tty_colours_bg(struct tty *, const struct grid_cell *);
1.1 nicm 45:
1.120 nicm 46: int tty_large_region(struct tty *, const struct tty_ctx *);
1.176 nicm 47: int tty_fake_bce(const struct tty *, const struct window_pane *);
1.24 nicm 48: void tty_redraw_region(struct tty *, const struct tty_ctx *);
1.13 nicm 49: void tty_emulate_repeat(
50: struct tty *, enum tty_code_code, enum tty_code_code, u_int);
1.133 nicm 51: void tty_repeat_space(struct tty *, u_int);
1.176 nicm 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 *);
1.1 nicm 55:
1.90 nicm 56: #define tty_use_acs(tty) \
1.131 nicm 57: (tty_term_has((tty)->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8))
1.90 nicm 58:
1.132 nicm 59: #define tty_pane_full_width(tty, ctx) \
60: ((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx)
61:
1.185 nicm 62: int
1.136 nicm 63: tty_init(struct tty *tty, struct client *c, int fd, char *term)
1.1 nicm 64: {
1.30 nicm 65: char *path;
66:
1.185 nicm 67: if (!isatty(fd))
68: return (-1);
69:
1.30 nicm 70: memset(tty, 0, sizeof *tty);
1.23 nicm 71: tty->log_fd = -1;
1.22 nicm 72:
1.9 nicm 73: if (term == NULL || *term == '\0')
1.1 nicm 74: tty->termname = xstrdup("unknown");
75: else
76: tty->termname = xstrdup(term);
1.30 nicm 77: tty->fd = fd;
1.136 nicm 78: tty->client = c;
1.30 nicm 79:
80: if ((path = ttyname(fd)) == NULL)
1.185 nicm 81: return (-1);
1.30 nicm 82: tty->path = xstrdup(path);
1.108 nicm 83: tty->cstyle = 0;
1.107 nicm 84: tty->ccolour = xstrdup("");
1.30 nicm 85:
1.1 nicm 86: tty->flags = 0;
87: tty->term_flags = 0;
1.185 nicm 88:
89: return (0);
1.31 nicm 90: }
91:
1.88 nicm 92: int
1.31 nicm 93: tty_resize(struct tty *tty)
94: {
95: struct winsize ws;
1.88 nicm 96: u_int sx, sy;
1.31 nicm 97:
98: if (ioctl(tty->fd, TIOCGWINSZ, &ws) != -1) {
1.88 nicm 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;
1.31 nicm 108: }
1.114 nicm 109: if (!tty_set_size(tty, sx, sy))
1.88 nicm 110: return (0);
1.31 nicm 111:
112: tty->cx = UINT_MAX;
113: tty->cy = UINT_MAX;
114:
115: tty->rupper = UINT_MAX;
116: tty->rlower = UINT_MAX;
1.88 nicm 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:
1.114 nicm 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;
1.88 nicm 136: return (1);
1.1 nicm 137: }
138:
139: int
1.166 nicm 140: tty_open(struct tty *tty, char **cause)
1.1 nicm 141: {
1.88 nicm 142: char out[64];
1.30 nicm 143: int fd;
1.1 nicm 144:
1.30 nicm 145: if (debug_level > 3) {
1.88 nicm 146: xsnprintf(out, sizeof out, "tmux-out-%ld.log", (long) getpid());
147: fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644);
1.30 nicm 148: if (fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
149: fatal("fcntl failed");
150: tty->log_fd = fd;
1.1 nicm 151: }
152:
1.166 nicm 153: tty->term = tty_term_find(tty->termname, tty->fd, cause);
1.21 nicm 154: if (tty->term == NULL) {
155: tty_close(tty);
156: return (-1);
157: }
158: tty->flags |= TTY_OPENED;
1.1 nicm 159:
1.149 nicm 160: tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE|TTY_TIMER);
1.1 nicm 161:
1.66 nicm 162: tty->event = bufferevent_new(
1.67 nicm 163: tty->fd, tty_read_callback, NULL, tty_error_callback, tty);
1.1 nicm 164:
165: tty_start_tty(tty);
166:
1.148 nicm 167: tty_keys_build(tty);
1.1 nicm 168:
169: return (0);
170: }
171:
172: void
1.67 nicm 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
1.66 nicm 182: tty_error_callback(
183: unused struct bufferevent *bufev, unused short what, unused void *data)
184: {
185: }
186:
187: void
1.127 nicm 188: tty_init_termios(int fd, struct termios *orig_tio, struct bufferevent *bufev)
1.1 nicm 189: {
1.128 nicm 190: struct termios tio;
1.33 nicm 191:
1.127 nicm 192: if (fd == -1 || tcgetattr(fd, orig_tio) != 0)
1.33 nicm 193: return;
1.1 nicm 194:
1.127 nicm 195: setblocking(fd, 0);
1.34 nicm 196:
1.127 nicm 197: if (bufev != NULL)
198: bufferevent_enable(bufev, EV_READ|EV_WRITE);
1.66 nicm 199:
1.127 nicm 200: memcpy(&tio, orig_tio, sizeof tio);
1.1 nicm 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|
1.169 jsg 205: ECHOPRT|ECHOKE|ISIG);
1.1 nicm 206: tio.c_cc[VMIN] = 1;
1.60 deraadt 207: tio.c_cc[VTIME] = 0;
1.127 nicm 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);
1.1 nicm 216:
1.10 nicm 217: tty_putcode(tty, TTYC_SMCUP);
1.1 nicm 218:
1.25 nicm 219: tty_putcode(tty, TTYC_SGR0);
220: memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell);
221:
1.76 nicm 222: tty_putcode(tty, TTYC_RMKX);
1.90 nicm 223: if (tty_use_acs(tty))
224: tty_putcode(tty, TTYC_ENACS);
1.1 nicm 225: tty_putcode(tty, TTYC_CLEAR);
226:
227: tty_putcode(tty, TTYC_CNORM);
228: if (tty_term_has(tty->term, TTYC_KMOUS))
1.179 nicm 229: tty_puts(tty, "\033[?1000l\033[?1002l\033[?1006l\033[?1005l");
1.121 nicm 230:
1.162 nicm 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: }
1.1 nicm 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;
1.20 nicm 245:
246: tty->flags |= TTY_STARTED;
1.107 nicm 247:
248: tty_force_cursor_colour(tty, "");
1.177 nicm 249:
250: tty->mouse_drag_flag = 0;
251: tty->mouse_drag_update = NULL;
252: tty->mouse_drag_release = NULL;
1.128 nicm 253: }
254:
255: void
1.1 nicm 256: tty_stop_tty(struct tty *tty)
257: {
258: struct winsize ws;
259:
1.20 nicm 260: if (!(tty->flags & TTY_STARTED))
261: return;
262: tty->flags &= ~TTY_STARTED;
263:
1.66 nicm 264: bufferevent_disable(tty->event, EV_READ|EV_WRITE);
265:
1.1 nicm 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));
1.90 nicm 277: if (tty_use_acs(tty))
278: tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS));
1.1 nicm 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));
1.160 nicm 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));
1.109 nicm 285: else
1.160 nicm 286: tty_raw(tty, tty_term_string1(tty->term, TTYC_SS, 0));
1.108 nicm 287: }
1.173 nicm 288: if (tty->mode & MODE_BRACKETPASTE)
289: tty_raw(tty, "\033[?2004l");
1.107 nicm 290: tty_raw(tty, tty_term_string(tty->term, TTYC_CR));
1.1 nicm 291:
292: tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM));
293: if (tty_term_has(tty->term, TTYC_KMOUS))
1.179 nicm 294: tty_raw(tty, "\033[?1000l\033[?1002l\033[?1006l\033[?1005l");
1.151 nicm 295:
1.162 nicm 296: if (tty_term_has(tty->term, TTYC_XT)) {
297: if (tty->flags & TTY_FOCUS) {
298: tty->flags &= ~TTY_FOCUS;
1.172 nicm 299: tty_raw(tty, "\033[?1004l");
1.162 nicm 300: }
301: }
1.10 nicm 302:
303: tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
1.150 nicm 304:
305: setblocking(tty->fd, 1);
1.1 nicm 306: }
307:
308: void
1.20 nicm 309: tty_close(struct tty *tty)
1.1 nicm 310: {
311: if (tty->log_fd != -1) {
312: close(tty->log_fd);
313: tty->log_fd = -1;
314: }
315:
1.123 nicm 316: if (event_initialized(&tty->key_timer))
317: evtimer_del(&tty->key_timer);
1.20 nicm 318: tty_stop_tty(tty);
1.1 nicm 319:
1.21 nicm 320: if (tty->flags & TTY_OPENED) {
1.66 nicm 321: bufferevent_free(tty->event);
322:
1.21 nicm 323: tty_term_free(tty->term);
324: tty_keys_free(tty);
325:
326: tty->flags &= ~TTY_OPENED;
327: }
1.1 nicm 328:
1.21 nicm 329: if (tty->fd != -1) {
330: close(tty->fd);
331: tty->fd = -1;
332: }
1.1 nicm 333: }
334:
335: void
1.20 nicm 336: tty_free(struct tty *tty)
1.1 nicm 337: {
1.20 nicm 338: tty_close(tty);
1.1 nicm 339:
1.138 nicm 340: free(tty->ccolour);
1.1 nicm 341: if (tty->path != NULL)
1.138 nicm 342: free(tty->path);
1.1 nicm 343: if (tty->termname != NULL)
1.138 nicm 344: free(tty->termname);
1.1 nicm 345: }
346:
347: void
348: tty_raw(struct tty *tty, const char *s)
349: {
1.150 nicm 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: }
1.1 nicm 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
1.107 nicm 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
1.167 nicm 397: tty_putcode_ptr2(struct tty *tty, enum tty_code_code code, const void *a,
398: const void *b)
1.106 nicm 399: {
400: if (a != NULL && b != NULL)
401: tty_puts(tty, tty_term_ptr2(tty->term, code, a, b));
402: }
403:
404: void
1.1 nicm 405: tty_puts(struct tty *tty, const char *s)
406: {
407: if (*s == '\0')
408: return;
1.66 nicm 409: bufferevent_write(tty->event, s, strlen(s));
1.1 nicm 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: {
1.90 nicm 418: const char *acs;
419: u_int sx;
1.1 nicm 420:
1.90 nicm 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);
1.1 nicm 429:
430: if (ch >= 0x20 && ch != 0x7f) {
431: sx = tty->sx;
432: if (tty->term->flags & TERM_EARLYWRAP)
433: sx--;
434:
1.46 nicm 435: if (tty->cx >= sx) {
436: tty->cx = 1;
437: if (tty->cy != tty->rlower)
438: tty->cy++;
1.1 nicm 439: } else
440: tty->cx++;
441: }
442:
443: if (tty->log_fd != -1)
444: write(tty->log_fd, &ch, 1);
445: }
446:
447: void
1.147 nicm 448: tty_putn(struct tty *tty, const void *buf, size_t len, u_int width)
1.5 nicm 449: {
1.147 nicm 450: bufferevent_write(tty->event, buf, len);
1.71 nicm 451: if (tty->log_fd != -1)
1.147 nicm 452: write(tty->log_fd, buf, len);
453: tty->cx += width;
1.5 nicm 454: }
455:
456: void
1.180 nicm 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
1.1 nicm 472: tty_set_title(struct tty *tty, const char *title)
473: {
1.105 nicm 474: if (!tty_term_has(tty->term, TTYC_TSL) ||
475: !tty_term_has(tty->term, TTYC_FSL))
1.1 nicm 476: return;
477:
1.105 nicm 478: tty_putcode(tty, TTYC_TSL);
1.1 nicm 479: tty_puts(tty, title);
1.105 nicm 480: tty_putcode(tty, TTYC_FSL);
1.1 nicm 481: }
482:
483: void
1.107 nicm 484: tty_force_cursor_colour(struct tty *tty, const char *ccolour)
485: {
486: if (*ccolour == '\0')
487: tty_putcode(tty, TTYC_CR);
488: else
1.160 nicm 489: tty_putcode_ptr1(tty, TTYC_CS, ccolour);
1.138 nicm 490: free(tty->ccolour);
1.107 nicm 491: tty->ccolour = xstrdup(ccolour);
492: }
493:
494: void
495: tty_update_mode(struct tty *tty, int mode, struct screen *s)
1.1 nicm 496: {
497: int changed;
498:
1.181 nicm 499: if (s != NULL && strcmp(s->ccolour, tty->ccolour))
1.107 nicm 500: tty_force_cursor_colour(tty, s->ccolour);
501:
1.1 nicm 502: if (tty->flags & TTY_NOCURSOR)
503: mode &= ~MODE_CURSOR;
504:
505: changed = mode ^ tty->mode;
1.183 nicm 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
1.1 nicm 517: tty_putcode(tty, TTYC_CIVIS);
1.108 nicm 518: }
1.181 nicm 519: if (s != NULL && tty->cstyle != s->cstyle) {
1.160 nicm 520: if (tty_term_has(tty->term, TTYC_SS)) {
1.108 nicm 521: if (s->cstyle == 0 &&
1.160 nicm 522: tty_term_has(tty->term, TTYC_SE))
523: tty_putcode(tty, TTYC_SE);
1.108 nicm 524: else
1.160 nicm 525: tty_putcode1(tty, TTYC_SS, s->cstyle);
1.108 nicm 526: }
527: tty->cstyle = s->cstyle;
1.1 nicm 528: }
1.154 nicm 529: if (changed & (ALL_MOUSE_MODES|MODE_MOUSE_UTF8)) {
1.94 nicm 530: if (mode & ALL_MOUSE_MODES) {
1.153 nicm 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: */
1.95 nicm 538: if (mode & MODE_MOUSE_UTF8)
539: tty_puts(tty, "\033[?1005h");
1.154 nicm 540: else
541: tty_puts(tty, "\033[?1005l");
1.153 nicm 542: tty_puts(tty, "\033[?1006h");
543:
1.170 nicm 544: if (mode & MODE_MOUSE_BUTTON)
1.94 nicm 545: tty_puts(tty, "\033[?1002h");
1.98 nicm 546: else if (mode & MODE_MOUSE_STANDARD)
547: tty_puts(tty, "\033[?1000h");
1.86 nicm 548: } else {
1.170 nicm 549: if (tty->mode & MODE_MOUSE_BUTTON)
1.94 nicm 550: tty_puts(tty, "\033[?1002l");
1.98 nicm 551: else if (tty->mode & MODE_MOUSE_STANDARD)
552: tty_puts(tty, "\033[?1000l");
1.153 nicm 553:
554: tty_puts(tty, "\033[?1006l");
1.95 nicm 555: if (tty->mode & MODE_MOUSE_UTF8)
556: tty_puts(tty, "\033[?1005l");
1.86 nicm 557: }
1.76 nicm 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);
1.115 nicm 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");
1.1 nicm 570: }
571: tty->mode = mode;
572: }
573:
574: void
1.168 nicm 575: tty_emulate_repeat(struct tty *tty, enum tty_code_code code,
576: enum tty_code_code code1, u_int n)
1.1 nicm 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:
1.133 nicm 586: void
587: tty_repeat_space(struct tty *tty, u_int n)
588: {
589: while (n-- > 0)
590: tty_putc(tty, ' ');
591: }
592:
1.1 nicm 593: /*
1.119 nicm 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: /*
1.176 nicm 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: /*
1.1 nicm 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
1.24 nicm 629: tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 630: {
1.14 nicm 631: struct window_pane *wp = ctx->wp;
632: struct screen *s = wp->screen;
633: u_int i;
1.1 nicm 634:
635: /*
1.119 nicm 636: * If region is large, schedule a window redraw. In most cases this is
637: * likely to be followed by some more scrolling.
1.1 nicm 638: */
1.119 nicm 639: if (tty_large_region(tty, ctx)) {
1.1 nicm 640: wp->flags |= PANE_REDRAW;
641: return;
642: }
643:
1.14 nicm 644: if (ctx->ocy < ctx->orupper || ctx->ocy > ctx->orlower) {
645: for (i = ctx->ocy; i < screen_size_y(s); i++)
1.176 nicm 646: tty_draw_pane(tty, wp, i, ctx->xoff, ctx->yoff);
1.1 nicm 647: } else {
1.14 nicm 648: for (i = ctx->orupper; i <= ctx->orlower; i++)
1.176 nicm 649: tty_draw_pane(tty, wp, i, ctx->xoff, ctx->yoff);
1.1 nicm 650: }
651: }
652:
653: void
1.176 nicm 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)
1.1 nicm 663: {
664: const struct grid_cell *gc;
1.46 nicm 665: struct grid_line *gl;
1.16 nicm 666: struct grid_cell tmpgc;
1.147 nicm 667: struct utf8_data ud;
1.1 nicm 668: u_int i, sx;
1.181 nicm 669: int flags;
1.1 nicm 670:
1.181 nicm 671: flags = tty->flags & TTY_NOCURSOR;
672: tty->flags |= TTY_NOCURSOR;
673: tty_update_mode(tty, tty->mode, s);
1.35 nicm 674:
1.1 nicm 675: sx = screen_size_x(s);
1.19 nicm 676: if (sx > s->grid->linedata[s->grid->hsize + py].cellsize)
677: sx = s->grid->linedata[s->grid->hsize + py].cellsize;
1.1 nicm 678: if (sx > tty->sx)
679: sx = tty->sx;
680:
1.46 nicm 681: /*
1.174 nicm 682: * Don't move the cursor to the start position if it will wrap there
1.50 nicm 683: * itself.
1.46 nicm 684: */
685: gl = NULL;
686: if (py != 0)
687: gl = &s->grid->linedata[s->grid->hsize + py - 1];
1.83 nicm 688: if (oy + py == 0 || gl == NULL || !(gl->flags & GRID_LINE_WRAPPED) ||
1.47 nicm 689: tty->cx < tty->sx || ox != 0 ||
690: (oy + py != tty->cy + 1 && tty->cy != s->rlower + oy))
1.46 nicm 691: tty_cursor(tty, ox, oy + py);
692:
1.1 nicm 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)) {
1.16 nicm 696: memcpy(&tmpgc, &s->sel.cell, sizeof tmpgc);
1.147 nicm 697: grid_cell_get(gc, &ud);
698: grid_cell_set(&tmpgc, &ud);
1.77 nicm 699: tmpgc.flags = gc->flags &
1.38 nicm 700: ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
701: tmpgc.flags |= s->sel.cell.flags &
702: (GRID_FLAG_FG256|GRID_FLAG_BG256);
1.176 nicm 703: tty_cell(tty, &tmpgc, wp);
1.1 nicm 704: } else
1.176 nicm 705: tty_cell(tty, gc, wp);
1.1 nicm 706: }
707:
1.181 nicm 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);
1.35 nicm 719: }
1.1 nicm 720:
1.181 nicm 721: tty->flags = (tty->flags & ~TTY_NOCURSOR) | flags;
1.107 nicm 722: tty_update_mode(tty, tty->mode, s);
1.15 nicm 723: }
724:
1.182 nicm 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:
1.15 nicm 739: void
1.182 nicm 740: tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *),
741: struct tty_ctx *ctx)
1.15 nicm 742: {
743: struct window_pane *wp = ctx->wp;
744: struct client *c;
745:
1.75 nicm 746: /* wp can be NULL if updating the screen but not the terminal. */
1.15 nicm 747: if (wp == NULL)
748: return;
749:
750: if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW)
751: return;
1.129 nicm 752: if (!window_pane_visible(wp) || wp->flags & PANE_DROP)
1.15 nicm 753: return;
754:
1.178 nicm 755: TAILQ_FOREACH(c, &clients, entry) {
1.182 nicm 756: if (!tty_client_ready(c, wp))
1.15 nicm 757: continue;
758:
1.139 nicm 759: ctx->xoff = wp->xoff;
760: ctx->yoff = wp->yoff;
761: if (status_at_line(c) == 0)
762: ctx->yoff++;
1.113 nicm 763:
1.139 nicm 764: cmdfn(&c->tty, ctx);
1.1 nicm 765: }
766: }
767:
768: void
1.24 nicm 769: tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 770: {
1.77 nicm 771: struct window_pane *wp = ctx->wp;
1.1 nicm 772:
1.135 nicm 773: if (!tty_pane_full_width(tty, ctx)) {
1.176 nicm 774: tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff);
1.1 nicm 775: return;
776: }
777:
1.176 nicm 778: tty_attributes(tty, &grid_default_cell, wp);
1.1 nicm 779:
1.77 nicm 780: tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
1.41 nicm 781:
1.176 nicm 782: if (!tty_fake_bce(tty, wp) && (tty_term_has(tty->term, TTYC_ICH) ||
783: tty_term_has(tty->term, TTYC_ICH1)))
1.12 nicm 784: tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num);
1.134 nicm 785: else
1.176 nicm 786: tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff);
1.1 nicm 787: }
788:
789: void
1.24 nicm 790: tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 791: {
1.77 nicm 792: struct window_pane *wp = ctx->wp;
1.1 nicm 793:
1.176 nicm 794: if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, wp) ||
1.26 nicm 795: (!tty_term_has(tty->term, TTYC_DCH) &&
796: !tty_term_has(tty->term, TTYC_DCH1))) {
1.176 nicm 797: tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff);
1.1 nicm 798: return;
799: }
800:
1.176 nicm 801: tty_attributes(tty, &grid_default_cell, wp);
1.1 nicm 802:
1.77 nicm 803: tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
1.41 nicm 804:
1.26 nicm 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);
1.146 nicm 808: }
809:
810: void
811: tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx)
812: {
813: u_int i;
814:
1.176 nicm 815: tty_attributes(tty, &grid_default_cell, ctx->wp);
1.146 nicm 816:
817: tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
818:
1.176 nicm 819: if (tty_term_has(tty->term, TTYC_ECH) && !tty_fake_bce(tty, ctx->wp))
1.146 nicm 820: tty_putcode1(tty, TTYC_ECH, ctx->num);
821: else {
822: for (i = 0; i < ctx->num; i++)
823: tty_putc(tty, ' ');
824: }
1.1 nicm 825: }
826:
827: void
1.24 nicm 828: tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 829: {
1.176 nicm 830: if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, ctx->wp) ||
1.77 nicm 831: !tty_term_has(tty->term, TTYC_CSR) ||
1.72 nicm 832: !tty_term_has(tty->term, TTYC_IL1)) {
1.14 nicm 833: tty_redraw_region(tty, ctx);
1.1 nicm 834: return;
835: }
836:
1.176 nicm 837: tty_attributes(tty, &grid_default_cell, ctx->wp);
1.1 nicm 838:
1.77 nicm 839: tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
840: tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
1.1 nicm 841:
1.12 nicm 842: tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ctx->num);
1.1 nicm 843: }
844:
845: void
1.24 nicm 846: tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 847: {
1.176 nicm 848: if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, ctx->wp) ||
1.72 nicm 849: !tty_term_has(tty->term, TTYC_CSR) ||
850: !tty_term_has(tty->term, TTYC_DL1)) {
1.14 nicm 851: tty_redraw_region(tty, ctx);
1.1 nicm 852: return;
853: }
854:
1.176 nicm 855: tty_attributes(tty, &grid_default_cell, ctx->wp);
1.1 nicm 856:
1.77 nicm 857: tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
858: tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
1.1 nicm 859:
1.12 nicm 860: tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ctx->num);
1.1 nicm 861: }
862:
863: void
1.24 nicm 864: tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 865: {
1.77 nicm 866: struct window_pane *wp = ctx->wp;
1.12 nicm 867: struct screen *s = wp->screen;
1.1 nicm 868:
1.176 nicm 869: tty_attributes(tty, &grid_default_cell, wp);
1.1 nicm 870:
1.77 nicm 871: tty_cursor_pane(tty, ctx, 0, ctx->ocy);
1.41 nicm 872:
1.176 nicm 873: if (tty_pane_full_width(tty, ctx) && !tty_fake_bce(tty, wp) &&
874: tty_term_has(tty->term, TTYC_EL))
1.1 nicm 875: tty_putcode(tty, TTYC_EL);
1.133 nicm 876: else
877: tty_repeat_space(tty, screen_size_x(s));
1.1 nicm 878: }
879:
880: void
1.24 nicm 881: tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 882: {
1.77 nicm 883: struct window_pane *wp = ctx->wp;
1.12 nicm 884: struct screen *s = wp->screen;
1.1 nicm 885:
1.176 nicm 886: tty_attributes(tty, &grid_default_cell, wp);
1.1 nicm 887:
1.41 nicm 888: tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
889:
1.176 nicm 890: if (tty_pane_full_width(tty, ctx) &&
891: tty_term_has(tty->term, TTYC_EL) && !tty_fake_bce(tty, wp))
1.1 nicm 892: tty_putcode(tty, TTYC_EL);
1.133 nicm 893: else
894: tty_repeat_space(tty, screen_size_x(s) - ctx->ocx);
1.1 nicm 895: }
896:
897: void
1.24 nicm 898: tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 899: {
1.176 nicm 900: tty_attributes(tty, &grid_default_cell, ctx->wp);
1.1 nicm 901:
1.176 nicm 902: if (ctx->xoff == 0 && tty_term_has(tty->term, TTYC_EL1) &&
903: !tty_fake_bce(tty, ctx->wp)) {
1.41 nicm 904: tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
1.1 nicm 905: tty_putcode(tty, TTYC_EL1);
906: } else {
1.41 nicm 907: tty_cursor_pane(tty, ctx, 0, ctx->ocy);
1.133 nicm 908: tty_repeat_space(tty, ctx->ocx + 1);
1.1 nicm 909: }
910: }
911:
912: void
1.24 nicm 913: tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 914: {
1.56 nicm 915: if (ctx->ocy != ctx->orupper)
916: return;
917:
1.176 nicm 918: if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, ctx->wp) ||
1.70 nicm 919: !tty_term_has(tty->term, TTYC_CSR) ||
920: !tty_term_has(tty->term, TTYC_RI)) {
1.14 nicm 921: tty_redraw_region(tty, ctx);
1.1 nicm 922: return;
923: }
924:
1.176 nicm 925: tty_attributes(tty, &grid_default_cell, ctx->wp);
1.77 nicm 926:
1.56 nicm 927: tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
928: tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper);
1.77 nicm 929:
1.56 nicm 930: tty_putcode(tty, TTYC_RI);
1.1 nicm 931: }
932:
933: void
1.24 nicm 934: tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 935: {
1.77 nicm 936: struct window_pane *wp = ctx->wp;
1.1 nicm 937:
1.56 nicm 938: if (ctx->ocy != ctx->orlower)
939: return;
940:
1.176 nicm 941: if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, wp) ||
1.1 nicm 942: !tty_term_has(tty->term, TTYC_CSR)) {
1.128 nicm 943: if (tty_large_region(tty, ctx))
944: wp->flags |= PANE_REDRAW;
1.140 nicm 945: else
1.128 nicm 946: tty_redraw_region(tty, ctx);
1.1 nicm 947: return;
948: }
1.52 nicm 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;
1.1 nicm 957:
1.176 nicm 958: tty_attributes(tty, &grid_default_cell, wp);
1.77 nicm 959:
1.56 nicm 960: tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
961: tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
1.77 nicm 962:
1.56 nicm 963: tty_putc(tty, '\n');
1.1 nicm 964: }
965:
966: void
1.24 nicm 967: tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 968: {
1.77 nicm 969: struct window_pane *wp = ctx->wp;
1.12 nicm 970: struct screen *s = wp->screen;
971: u_int i, j;
1.1 nicm 972:
1.176 nicm 973: tty_attributes(tty, &grid_default_cell, wp);
1.1 nicm 974:
1.39 nicm 975: tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1);
1.41 nicm 976: tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
1.39 nicm 977:
1.176 nicm 978: if (tty_pane_full_width(tty, ctx) &&
979: tty_term_has(tty->term, TTYC_EL) && !tty_fake_bce(tty, wp)) {
1.1 nicm 980: tty_putcode(tty, TTYC_EL);
1.14 nicm 981: if (ctx->ocy != screen_size_y(s) - 1) {
1.41 nicm 982: tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1);
1.14 nicm 983: for (i = ctx->ocy + 1; i < screen_size_y(s); i++) {
1.1 nicm 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 {
1.133 nicm 992: tty_repeat_space(tty, screen_size_x(s) - ctx->ocx);
1.68 nicm 993: for (j = ctx->ocy + 1; j < screen_size_y(s); j++) {
1.41 nicm 994: tty_cursor_pane(tty, ctx, 0, j);
1.133 nicm 995: tty_repeat_space(tty, screen_size_x(s));
1.1 nicm 996: }
997: }
998: }
999:
1000: void
1.24 nicm 1001: tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 1002: {
1.77 nicm 1003: struct window_pane *wp = ctx->wp;
1.12 nicm 1004: struct screen *s = wp->screen;
1005: u_int i, j;
1.1 nicm 1006:
1.176 nicm 1007: tty_attributes(tty, &grid_default_cell, wp);
1.1 nicm 1008:
1.39 nicm 1009: tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1);
1.41 nicm 1010: tty_cursor_pane(tty, ctx, 0, 0);
1.39 nicm 1011:
1.176 nicm 1012: if (tty_pane_full_width(tty, ctx) &&
1013: tty_term_has(tty->term, TTYC_EL) && !tty_fake_bce(tty, wp)) {
1.14 nicm 1014: for (i = 0; i < ctx->ocy; i++) {
1.1 nicm 1015: tty_putcode(tty, TTYC_EL);
1016: tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1);
1017: tty->cy++;
1018: }
1019: } else {
1.14 nicm 1020: for (j = 0; j < ctx->ocy; j++) {
1.41 nicm 1021: tty_cursor_pane(tty, ctx, 0, j);
1.133 nicm 1022: tty_repeat_space(tty, screen_size_x(s));
1.1 nicm 1023: }
1024: }
1.133 nicm 1025: tty_repeat_space(tty, ctx->ocx + 1);
1.1 nicm 1026: }
1027:
1028: void
1.24 nicm 1029: tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 1030: {
1.77 nicm 1031: struct window_pane *wp = ctx->wp;
1.12 nicm 1032: struct screen *s = wp->screen;
1033: u_int i, j;
1.1 nicm 1034:
1.176 nicm 1035: tty_attributes(tty, &grid_default_cell, wp);
1.1 nicm 1036:
1.39 nicm 1037: tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1);
1.41 nicm 1038: tty_cursor_pane(tty, ctx, 0, 0);
1.39 nicm 1039:
1.176 nicm 1040: if (tty_pane_full_width(tty, ctx) &&
1041: tty_term_has(tty->term, TTYC_EL) && !tty_fake_bce(tty, wp)) {
1.1 nicm 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++) {
1.41 nicm 1051: tty_cursor_pane(tty, ctx, 0, j);
1.133 nicm 1052: tty_repeat_space(tty, screen_size_x(s));
1.1 nicm 1053: }
1.4 nicm 1054: }
1055: }
1056:
1057: void
1.24 nicm 1058: tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx)
1.4 nicm 1059: {
1.12 nicm 1060: struct window_pane *wp = ctx->wp;
1061: struct screen *s = wp->screen;
1062: u_int i, j;
1.4 nicm 1063:
1.176 nicm 1064: tty_attributes(tty, &grid_default_cell, wp);
1.4 nicm 1065:
1.39 nicm 1066: tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1);
1.4 nicm 1067:
1068: for (j = 0; j < screen_size_y(s); j++) {
1.41 nicm 1069: tty_cursor_pane(tty, ctx, 0, j);
1.4 nicm 1070: for (i = 0; i < screen_size_x(s); i++)
1071: tty_putc(tty, 'E');
1.1 nicm 1072: }
1073: }
1074:
1075: void
1.24 nicm 1076: tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 1077: {
1.46 nicm 1078: struct window_pane *wp = ctx->wp;
1079: struct screen *s = wp->screen;
1.58 nicm 1080: u_int cx;
1.102 nicm 1081: u_int width;
1.46 nicm 1082:
1083: tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower);
1084:
1.57 nicm 1085: /* Is the cursor in the very last position? */
1.147 nicm 1086: width = grid_cell_width(ctx->cell);
1.102 nicm 1087: if (ctx->ocx > wp->sx - width) {
1.113 nicm 1088: if (ctx->xoff != 0 || wp->sx != tty->sx) {
1.57 nicm 1089: /*
1090: * The pane doesn't fill the entire line, the linefeed
1091: * will already have happened, so just move the cursor.
1092: */
1.125 nicm 1093: if (ctx->ocy != wp->yoff + wp->screen->rlower)
1.122 nicm 1094: tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1);
1095: else
1096: tty_cursor_pane(tty, ctx, 0, ctx->ocy);
1.57 nicm 1097: } else if (tty->cx < tty->sx) {
1098: /*
1099: * The cursor isn't in the last position already, so
1.102 nicm 1100: * move as far left as possible and redraw the last
1.57 nicm 1101: * cell to move into the last position.
1102: */
1.147 nicm 1103: cx = screen_size_x(s) - grid_cell_width(&ctx->last_cell);
1.50 nicm 1104: tty_cursor_pane(tty, ctx, cx, ctx->ocy);
1.176 nicm 1105: tty_cell(tty, &ctx->last_cell, wp);
1.50 nicm 1106: }
1107: } else
1.46 nicm 1108: tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy);
1.1 nicm 1109:
1.176 nicm 1110: tty_cell(tty, ctx->cell, wp);
1.1 nicm 1111: }
1112:
1113: void
1.24 nicm 1114: tty_cmd_utf8character(struct tty *tty, const struct tty_ctx *ctx)
1.1 nicm 1115: {
1.53 nicm 1116: struct window_pane *wp = ctx->wp;
1.1 nicm 1117:
1.53 nicm 1118: /*
1119: * Cannot rely on not being a partial character, so just redraw the
1120: * whole line.
1121: */
1.176 nicm 1122: tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff);
1.106 nicm 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:
1.138 nicm 1140: free(buf);
1.100 nicm 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]);
1.141 nicm 1151:
1152: tty->cx = tty->cy = UINT_MAX;
1153: tty->rupper = tty->rlower = UINT_MAX;
1154:
1.176 nicm 1155: tty_attributes(tty, &grid_default_cell, ctx->wp);
1.141 nicm 1156: tty_cursor(tty, 0, 0);
1.1 nicm 1157: }
1158:
1159: void
1.176 nicm 1160: tty_cell(struct tty *tty, const struct grid_cell *gc,
1161: const struct window_pane *wp)
1.1 nicm 1162: {
1.147 nicm 1163: struct utf8_data ud;
1164: u_int i;
1.1 nicm 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. */
1.176 nicm 1176: tty_attributes(tty, gc, wp);
1.1 nicm 1177:
1.147 nicm 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)
1.1 nicm 1182: return;
1.147 nicm 1183: tty_putc(tty, *ud.data);
1.1 nicm 1184: return;
1185: }
1186:
1.147 nicm 1187: /* If not UTF-8, write _. */
1.1 nicm 1188: if (!(tty->flags & TTY_UTF8)) {
1.147 nicm 1189: for (i = 0; i < ud.width; i++)
1.1 nicm 1190: tty_putc(tty, '_');
1191: return;
1192: }
1193:
1.147 nicm 1194: /* Write the data. */
1195: tty_putn(tty, ud.data, ud.size, ud.width);
1.1 nicm 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:
1.90 nicm 1206: if ((gc->attr & GRID_ATTR_CHARSET) && tty_use_acs(tty))
1.1 nicm 1207: tty_putcode(tty, TTYC_RMACS);
1208: tty_putcode(tty, TTYC_SGR0);
1209: memcpy(gc, &grid_default_cell, sizeof *gc);
1210: }
1211:
1.40 nicm 1212: /* Set region inside pane. */
1.1 nicm 1213: void
1.39 nicm 1214: tty_region_pane(
1215: struct tty *tty, const struct tty_ctx *ctx, u_int rupper, u_int rlower)
1.1 nicm 1216: {
1.113 nicm 1217: tty_region(tty, ctx->yoff + rupper, ctx->yoff + rlower);
1.39 nicm 1218: }
1219:
1.40 nicm 1220: /* Set region at absolute position. */
1.39 nicm 1221: void
1.40 nicm 1222: tty_region(struct tty *tty, u_int rupper, u_int rlower)
1.39 nicm 1223: {
1224: if (tty->rlower == rlower && tty->rupper == rupper)
1225: return;
1.1 nicm 1226: if (!tty_term_has(tty->term, TTYC_CSR))
1227: return;
1.39 nicm 1228:
1229: tty->rupper = rupper;
1230: tty->rlower = rlower;
1.55 nicm 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);
1.42 nicm 1240:
1.39 nicm 1241: tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower);
1.78 nicm 1242: tty_cursor(tty, 0, 0);
1.1 nicm 1243: }
1244:
1.42 nicm 1245: /* Move cursor inside pane. */
1.1 nicm 1246: void
1.41 nicm 1247: tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy)
1248: {
1.113 nicm 1249: tty_cursor(tty, ctx->xoff + cx, ctx->yoff + cy);
1.41 nicm 1250: }
1251:
1.42 nicm 1252: /* Move cursor to absolute position. */
1.41 nicm 1253: void
1254: tty_cursor(struct tty *tty, u_int cx, u_int cy)
1.1 nicm 1255: {
1.42 nicm 1256: struct tty_term *term = tty->term;
1257: u_int thisx, thisy;
1258: int change;
1.77 nicm 1259:
1.42 nicm 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:
1.43 nicm 1270: /* Very end of the line, just use absolute movement. */
1271: if (thisx > tty->sx - 1)
1272: goto absolute;
1273:
1.42 nicm 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. */
1.48 nicm 1281: if (cx == 0 && cy == thisy + 1 && thisy != tty->rlower) {
1.1 nicm 1282: tty_putc(tty, '\r');
1.42 nicm 1283: tty_putc(tty, '\n');
1284: goto out;
1285: }
1286:
1.45 nicm 1287: /* Moving column or row. */
1.42 nicm 1288: if (cy == thisy) {
1.45 nicm 1289: /*
1290: * Moving column only, row staying the same.
1291: */
1292:
1.42 nicm 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: */
1.87 nicm 1318: if ((u_int) abs(change) > cx && tty_term_has(term, TTYC_HPA)) {
1.42 nicm 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: }
1.45 nicm 1328: } else if (cx == thisx) {
1329: /*
1330: * Moving row only, column staying the same.
1331: */
1.42 nicm 1332:
1333: /* One above. */
1.77 nicm 1334: if (thisy != tty->rupper &&
1.42 nicm 1335: cy == thisy - 1 && tty_term_has(term, TTYC_CUU1)) {
1336: tty_putcode(tty, TTYC_CUU1);
1337: goto out;
1338: }
1339:
1340: /* One below. */
1.49 nicm 1341: if (thisy != tty->rlower &&
1.42 nicm 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: /*
1.77 nicm 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.
1.42 nicm 1353: */
1.87 nicm 1354: if ((u_int) abs(change) > cy ||
1.42 nicm 1355: (change < 0 && cy - change > tty->rlower) ||
1.44 nicm 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: }
1.42 nicm 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:
1.43 nicm 1370: absolute:
1.42 nicm 1371: /* Absolute movement. */
1372: tty_putcode2(tty, TTYC_CUP, cy, cx);
1373:
1374: out:
1375: tty->cx = cx;
1376: tty->cy = cy;
1.1 nicm 1377: }
1378:
1379: void
1.176 nicm 1380: tty_attributes(struct tty *tty, const struct grid_cell *gc,
1381: const struct window_pane *wp)
1.1 nicm 1382: {
1.63 nicm 1383: struct grid_cell *tc = &tty->cell, gc2;
1.85 nicm 1384: u_char changed;
1.61 nicm 1385:
1.85 nicm 1386: memcpy(&gc2, gc, sizeof gc2);
1.176 nicm 1387: tty_default_colours(&gc2, wp);
1.63 nicm 1388:
1.18 nicm 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)) {
1.85 nicm 1395: if (gc2.attr & GRID_ATTR_REVERSE) {
1396: if (gc2.fg != 7 && gc2.fg != 8)
1.64 nicm 1397: gc2.attr &= ~GRID_ATTR_REVERSE;
1.18 nicm 1398: } else {
1.85 nicm 1399: if (gc2.bg != 0 && gc2.bg != 8)
1.64 nicm 1400: gc2.attr |= GRID_ATTR_REVERSE;
1.18 nicm 1401: }
1402: }
1.1 nicm 1403:
1.85 nicm 1404: /* Fix up the colours if necessary. */
1405: tty_check_fg(tty, &gc2);
1406: tty_check_bg(tty, &gc2);
1407:
1.64 nicm 1408: /* If any bits are being cleared, reset everything. */
1.85 nicm 1409: if (tc->attr & ~gc2.attr)
1.64 nicm 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: */
1.85 nicm 1416: tty_colours(tty, &gc2);
1.64 nicm 1417:
1.1 nicm 1418: /* Filter out attribute bits already set. */
1.85 nicm 1419: changed = gc2.attr & ~tc->attr;
1420: tc->attr = gc2.attr;
1.1 nicm 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);
1.180 nicm 1427: if (changed & GRID_ATTR_ITALICS)
1428: tty_set_italics(tty);
1.1 nicm 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);
1.90 nicm 1441: if ((changed & GRID_ATTR_CHARSET) && tty_use_acs(tty))
1.1 nicm 1442: tty_putcode(tty, TTYC_SMACS);
1443: }
1444:
1.61 nicm 1445: void
1.85 nicm 1446: tty_colours(struct tty *tty, const struct grid_cell *gc)
1.1 nicm 1447: {
1.61 nicm 1448: struct grid_cell *tc = &tty->cell;
1.62 nicm 1449: u_char fg = gc->fg, bg = gc->bg, flags = gc->flags;
1450: int have_ax, fg_default, bg_default;
1.61 nicm 1451:
1452: /* No changes? Nothing is necessary. */
1.62 nicm 1453: if (fg == tc->fg && bg == tc->bg &&
1454: ((flags ^ tc->flags) & (GRID_FLAG_FG256|GRID_FLAG_BG256)) == 0)
1.63 nicm 1455: return;
1.1 nicm 1456:
1.61 nicm 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: */
1.62 nicm 1463: fg_default = (fg == 8 && !(flags & GRID_FLAG_FG256));
1464: bg_default = (bg == 8 && !(flags & GRID_FLAG_BG256));
1.61 nicm 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: */
1.174 nicm 1473: have_ax = tty_term_flag(tty->term, TTYC_AX);
1.61 nicm 1474: if (!have_ax && tty_term_has(tty->term, TTYC_OP))
1475: tty_reset(tty);
1476: else {
1477: if (fg_default &&
1.81 nicm 1478: (tc->fg != 8 || tc->flags & GRID_FLAG_FG256)) {
1.61 nicm 1479: if (have_ax)
1480: tty_puts(tty, "\033[39m");
1.81 nicm 1481: else if (tc->fg != 7 ||
1482: tc->flags & GRID_FLAG_FG256)
1.61 nicm 1483: tty_putcode1(tty, TTYC_SETAF, 7);
1484: tc->fg = 8;
1485: tc->flags &= ~GRID_FLAG_FG256;
1486: }
1487: if (bg_default &&
1.81 nicm 1488: (tc->bg != 8 || tc->flags & GRID_FLAG_BG256)) {
1.77 nicm 1489: if (have_ax)
1.61 nicm 1490: tty_puts(tty, "\033[49m");
1.81 nicm 1491: else if (tc->bg != 0 ||
1492: tc->flags & GRID_FLAG_BG256)
1.61 nicm 1493: tty_putcode1(tty, TTYC_SETAB, 0);
1494: tc->bg = 8;
1495: tc->flags &= ~GRID_FLAG_BG256;
1496: }
1497: }
1498: }
1.1 nicm 1499:
1.61 nicm 1500: /* Set the foreground colour. */
1501: if (!fg_default && (fg != tc->fg ||
1.62 nicm 1502: ((flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256))))
1.85 nicm 1503: tty_colours_fg(tty, gc);
1.1 nicm 1504:
1.61 nicm 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 ||
1.62 nicm 1510: ((flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256))))
1.73 nicm 1511: tty_colours_bg(tty, gc);
1.1 nicm 1512: }
1513:
1514: void
1.85 nicm 1515: tty_check_fg(struct tty *tty, struct grid_cell *gc)
1516: {
1517: u_int colours;
1518:
1.175 nicm 1519: colours = tty_term_number(tty->term, TTYC_COLORS);
1520:
1.85 nicm 1521: /* Is this a 256-colour colour? */
1522: if (gc->flags & GRID_FLAG_FG256) {
1523: /* And not a 256 colour mode? */
1.158 nicm 1524: if (!(tty->term->flags & TERM_256COLOURS) &&
1.85 nicm 1525: !(tty->term_flags & TERM_256COLOURS)) {
1526: gc->fg = colour_256to16(gc->fg);
1527: if (gc->fg & 8) {
1528: gc->fg &= 7;
1.175 nicm 1529: if (colours >= 16)
1530: gc->fg += 90;
1531: else
1532: gc->attr |= GRID_ATTR_BRIGHT;
1.85 nicm 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:
1.175 nicm 1552: colours = tty_term_number(tty->term, TTYC_COLORS);
1553:
1.85 nicm 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: */
1.158 nicm 1561: if (!(tty->term->flags & TERM_256COLOURS) &&
1.85 nicm 1562: !(tty->term_flags & TERM_256COLOURS)) {
1563: gc->bg = colour_256to16(gc->bg);
1.175 nicm 1564: if (gc->bg & 8) {
1.85 nicm 1565: gc->bg &= 7;
1.175 nicm 1566: if (colours >= 16)
1567: gc->fg += 90;
1568: }
1.85 nicm 1569: gc->flags &= ~GRID_FLAG_BG256;
1570: }
1571: return;
1572: }
1573:
1574: /* Is this an aixterm colour? */
1.175 nicm 1575: if (gc->bg >= 90 && gc->bg <= 97 && colours < 16)
1.85 nicm 1576: gc->bg -= 90;
1577: }
1578:
1579: void
1580: tty_colours_fg(struct tty *tty, const struct grid_cell *gc)
1.1 nicm 1581: {
1.61 nicm 1582: struct grid_cell *tc = &tty->cell;
1583: u_char fg = gc->fg;
1.79 nicm 1584: char s[32];
1.1 nicm 1585:
1.61 nicm 1586: /* Is this a 256-colour colour? */
1.1 nicm 1587: if (gc->flags & GRID_FLAG_FG256) {
1.158 nicm 1588: /* Try as 256 colours. */
1.1 nicm 1589: if (tty_try_256(tty, fg, "38") == 0)
1.61 nicm 1590: goto save_fg;
1.85 nicm 1591: /* Else already handled by tty_check_fg. */
1592: return;
1.1 nicm 1593: }
1594:
1.79 nicm 1595: /* Is this an aixterm bright colour? */
1596: if (fg >= 90 && fg <= 97) {
1.85 nicm 1597: xsnprintf(s, sizeof s, "\033[%dm", fg);
1598: tty_puts(tty, s);
1599: goto save_fg;
1.79 nicm 1600: }
1601:
1.61 nicm 1602: /* Otherwise set the foreground colour. */
1603: tty_putcode1(tty, TTYC_SETAF, fg);
1604:
1.77 nicm 1605: save_fg:
1.61 nicm 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;
1.1 nicm 1610: }
1611:
1612: void
1.73 nicm 1613: tty_colours_bg(struct tty *tty, const struct grid_cell *gc)
1.1 nicm 1614: {
1.61 nicm 1615: struct grid_cell *tc = &tty->cell;
1616: u_char bg = gc->bg;
1.79 nicm 1617: char s[32];
1.1 nicm 1618:
1.61 nicm 1619: /* Is this a 256-colour colour? */
1.1 nicm 1620: if (gc->flags & GRID_FLAG_BG256) {
1.158 nicm 1621: /* Try as 256 colours. */
1.1 nicm 1622: if (tty_try_256(tty, bg, "48") == 0)
1.61 nicm 1623: goto save_bg;
1.85 nicm 1624: /* Else already handled by tty_check_bg. */
1625: return;
1.79 nicm 1626: }
1627:
1628: /* Is this an aixterm bright colour? */
1.112 nicm 1629: if (bg >= 90 && bg <= 97) {
1.175 nicm 1630: xsnprintf(s, sizeof s, "\033[%dm", bg + 10);
1631: tty_puts(tty, s);
1632: goto save_bg;
1.1 nicm 1633: }
1634:
1.61 nicm 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:
1.165 nicm 1650: /*
1651: * If the terminfo entry has 256 colours, assume that setaf and setab
1652: * work correctly.
1653: */
1654: if (tty->term->flags & TERM_256COLOURS) {
1655: if (*type == '3')
1656: tty_putcode1(tty, TTYC_SETAF, colour);
1657: else
1658: tty_putcode1(tty, TTYC_SETAB, colour);
1659: return (0);
1660: }
1661:
1662: /*
1663: * If the user has specified -2 to the client, setaf and setab may not
1664: * work, so send the usual sequence.
1665: */
1666: if (tty->term_flags & TERM_256COLOURS) {
1667: xsnprintf(s, sizeof s, "\033[%s;5;%hhum", type, colour);
1668: tty_puts(tty, s);
1669: return (0);
1670: }
1.61 nicm 1671:
1.165 nicm 1672: return (-1);
1.176 nicm 1673: }
1674:
1675: void
1676: tty_default_colours(struct grid_cell *gc, const struct window_pane *wp)
1677: {
1678: const struct grid_cell *agc, *pgc, *wgc;
1679:
1680: if (wp == NULL)
1681: return;
1682:
1683: pgc = &wp->colgc;
1684: agc = options_get_style(&wp->window->options, "window-active-style");
1685: wgc = options_get_style(&wp->window->options, "window-style");
1686:
1687: if (gc->fg == 8 && !(gc->flags & GRID_FLAG_FG256)) {
1688: if (pgc->fg != 8 || (pgc->flags & GRID_FLAG_FG256)) {
1689: gc->fg = pgc->fg;
1690: gc->flags |= (pgc->flags & GRID_FLAG_FG256);
1691: } else if (wp == wp->window->active &&
1692: (agc->fg != 8 || (agc->flags & GRID_FLAG_FG256))) {
1693: gc->fg = agc->fg;
1694: gc->flags |= (agc->flags & GRID_FLAG_FG256);
1695: } else {
1696: gc->fg = wgc->fg;
1697: gc->flags |= (wgc->flags & GRID_FLAG_FG256);
1698: }
1699: }
1700:
1701: if (gc->bg == 8 && !(gc->flags & GRID_FLAG_BG256)) {
1702: if (pgc->bg != 8 || (pgc->flags & GRID_FLAG_BG256)) {
1703: gc->bg = pgc->bg;
1704: gc->flags |= (pgc->flags & GRID_FLAG_BG256);
1705: } else if (wp == wp->window->active &&
1706: (agc->bg != 8 || (agc->flags & GRID_FLAG_BG256))) {
1707: gc->bg = agc->bg;
1708: gc->flags |= (agc->flags & GRID_FLAG_BG256);
1709: } else {
1710: gc->bg = wgc->bg;
1711: gc->flags |= (wgc->flags & GRID_FLAG_BG256);
1712: }
1713: }
1.1 nicm 1714: }