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