4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
20 #include <sys/ioctl.h>
22 #include <netinet/in.h>
34 void tty_read_callback(struct bufferevent
*, void *);
35 void tty_error_callback(struct bufferevent
*, short, void *);
37 int tty_try_256(struct tty
*, u_char
, const char *);
39 void tty_colours(struct tty
*, const struct grid_cell
*);
40 void tty_check_fg(struct tty
*, struct grid_cell
*);
41 void tty_check_bg(struct tty
*, struct grid_cell
*);
42 void tty_colours_fg(struct tty
*, const struct grid_cell
*);
43 void tty_colours_bg(struct tty
*, const struct grid_cell
*);
45 int tty_large_region(struct tty
*, const struct tty_ctx
*);
46 void tty_redraw_region(struct tty
*, const struct tty_ctx
*);
47 void tty_emulate_repeat(
48 struct tty
*, enum tty_code_code
, enum tty_code_code
, u_int
);
49 void tty_repeat_space(struct tty
*, u_int
);
50 void tty_cell(struct tty
*, const struct grid_cell
*);
52 #define tty_use_acs(tty) \
53 (tty_term_has((tty)->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8))
55 #define tty_pane_full_width(tty, ctx) \
56 ((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx)
59 tty_init(struct tty
*tty
, struct client
*c
, int fd
, char *term
)
63 memset(tty
, 0, sizeof *tty
);
66 if (term
== NULL
|| *term
== '\0')
67 tty
->termname
= xstrdup("unknown");
69 tty
->termname
= xstrdup(term
);
73 if ((path
= ttyname(fd
)) == NULL
)
74 fatalx("ttyname failed");
75 tty
->path
= xstrdup(path
);
77 tty
->ccolour
= xstrdup("");
84 tty_resize(struct tty
*tty
)
89 if (ioctl(tty
->fd
, TIOCGWINSZ
, &ws
) != -1) {
100 if (!tty_set_size(tty
, sx
, sy
))
106 tty
->rupper
= UINT_MAX
;
107 tty
->rlower
= UINT_MAX
;
110 * If the terminal has been started, reset the actual scroll region and
111 * cursor position, as this may not have happened.
113 if (tty
->flags
& TTY_STARTED
) {
114 tty_cursor(tty
, 0, 0);
115 tty_region(tty
, 0, tty
->sy
- 1);
122 tty_set_size(struct tty
*tty
, u_int sx
, u_int sy
) {
123 if (sx
== tty
->sx
&& sy
== tty
->sy
)
131 tty_open(struct tty
*tty
, const char *overrides
, char **cause
)
136 if (debug_level
> 3) {
137 xsnprintf(out
, sizeof out
, "tmux-out-%ld.log", (long) getpid());
138 fd
= open(out
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644);
139 if (fd
!= -1 && fcntl(fd
, F_SETFD
, FD_CLOEXEC
) == -1)
140 fatal("fcntl failed");
144 tty
->term
= tty_term_find(tty
->termname
, tty
->fd
, overrides
, cause
);
145 if (tty
->term
== NULL
) {
149 tty
->flags
|= TTY_OPENED
;
151 tty
->flags
&= ~(TTY_NOCURSOR
|TTY_FREEZE
|TTY_TIMER
);
153 tty
->event
= bufferevent_new(
154 tty
->fd
, tty_read_callback
, NULL
, tty_error_callback
, tty
);
164 tty_read_callback(unused
struct bufferevent
*bufev
, void *data
)
166 struct tty
*tty
= data
;
168 while (tty_keys_next(tty
))
174 unused
struct bufferevent
*bufev
, unused
short what
, unused
void *data
)
179 tty_init_termios(int fd
, struct termios
*orig_tio
, struct bufferevent
*bufev
)
183 if (fd
== -1 || tcgetattr(fd
, orig_tio
) != 0)
189 bufferevent_enable(bufev
, EV_READ
|EV_WRITE
);
191 memcpy(&tio
, orig_tio
, sizeof tio
);
192 tio
.c_iflag
&= ~(IXON
|IXOFF
|ICRNL
|INLCR
|IGNCR
|IMAXBEL
|ISTRIP
);
193 tio
.c_iflag
|= IGNBRK
;
194 tio
.c_oflag
&= ~(OPOST
|ONLCR
|OCRNL
|ONLRET
);
195 tio
.c_lflag
&= ~(IEXTEN
|ICANON
|ECHO
|ECHOE
|ECHONL
|ECHOCTL
|
196 ECHOPRT
|ECHOKE
|ECHOCTL
|ISIG
);
199 if (tcsetattr(fd
, TCSANOW
, &tio
) == 0)
200 tcflush(fd
, TCIOFLUSH
);
204 tty_start_tty(struct tty
*tty
)
206 tty_init_termios(tty
->fd
, &tty
->tio
, tty
->event
);
208 tty_putcode(tty
, TTYC_SMCUP
);
210 tty_putcode(tty
, TTYC_SGR0
);
211 memcpy(&tty
->cell
, &grid_default_cell
, sizeof tty
->cell
);
213 tty_putcode(tty
, TTYC_RMKX
);
214 if (tty_use_acs(tty
))
215 tty_putcode(tty
, TTYC_ENACS
);
216 tty_putcode(tty
, TTYC_CLEAR
);
218 tty_putcode(tty
, TTYC_CNORM
);
219 if (tty_term_has(tty
->term
, TTYC_KMOUS
))
220 tty_puts(tty
, "\033[?1000l\033[?1006l\033[?1005l");
222 if (tty_term_has(tty
->term
, TTYC_XT
)) {
223 if (options_get_number(&global_options
, "focus-events")) {
224 tty
->flags
|= TTY_FOCUS
;
225 tty_puts(tty
, "\033[?1004h");
227 tty_puts(tty
, "\033[c\033[>4;1m\033[m");
233 tty
->rlower
= UINT_MAX
;
234 tty
->rupper
= UINT_MAX
;
236 tty
->mode
= MODE_CURSOR
;
238 tty
->flags
|= TTY_STARTED
;
240 tty_force_cursor_colour(tty
, "");
244 tty_set_class(struct tty
*tty
, u_int
class)
252 tty_stop_tty(struct tty
*tty
)
256 if (!(tty
->flags
& TTY_STARTED
))
258 tty
->flags
&= ~TTY_STARTED
;
260 bufferevent_disable(tty
->event
, EV_READ
|EV_WRITE
);
263 * Be flexible about error handling and try not kill the server just
264 * because the fd is invalid. Things like ssh -t can easily leave us
267 if (ioctl(tty
->fd
, TIOCGWINSZ
, &ws
) == -1)
269 if (tcsetattr(tty
->fd
, TCSANOW
, &tty
->tio
) == -1)
272 tty_raw(tty
, tty_term_string2(tty
->term
, TTYC_CSR
, 0, ws
.ws_row
- 1));
273 if (tty_use_acs(tty
))
274 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_RMACS
));
275 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_SGR0
));
276 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_RMKX
));
277 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_CLEAR
));
278 if (tty_term_has(tty
->term
, TTYC_SS
) && tty
->cstyle
!= 0) {
279 if (tty_term_has(tty
->term
, TTYC_SE
))
280 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_SE
));
282 tty_raw(tty
, tty_term_string1(tty
->term
, TTYC_SS
, 0));
284 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_CR
));
286 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_CNORM
));
287 if (tty_term_has(tty
->term
, TTYC_KMOUS
))
288 tty_raw(tty
, "\033[?1000l\033[?1006l\033[?1005l");
290 if (tty_term_has(tty
->term
, TTYC_XT
)) {
291 if (tty
->flags
& TTY_FOCUS
) {
292 tty
->flags
&= ~TTY_FOCUS
;
293 tty_puts(tty
, "\033[?1004l");
295 tty_raw(tty
, "\033[>4m\033[m");
298 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_RMCUP
));
300 setblocking(tty
->fd
, 1);
304 tty_close(struct tty
*tty
)
306 if (tty
->log_fd
!= -1) {
311 if (event_initialized(&tty
->key_timer
))
312 evtimer_del(&tty
->key_timer
);
315 if (tty
->flags
& TTY_OPENED
) {
316 bufferevent_free(tty
->event
);
318 tty_term_free(tty
->term
);
321 tty
->flags
&= ~TTY_OPENED
;
331 tty_free(struct tty
*tty
)
336 if (tty
->path
!= NULL
)
338 if (tty
->termname
!= NULL
)
343 tty_raw(struct tty
*tty
, const char *s
)
349 for (i
= 0; i
< 5; i
++) {
350 n
= write(tty
->fd
, s
, slen
);
356 } else if (n
== -1 && errno
!= EAGAIN
)
363 tty_putcode(struct tty
*tty
, enum tty_code_code code
)
365 tty_puts(tty
, tty_term_string(tty
->term
, code
));
369 tty_putcode1(struct tty
*tty
, enum tty_code_code code
, int a
)
373 tty_puts(tty
, tty_term_string1(tty
->term
, code
, a
));
377 tty_putcode2(struct tty
*tty
, enum tty_code_code code
, int a
, int b
)
381 tty_puts(tty
, tty_term_string2(tty
->term
, code
, a
, b
));
385 tty_putcode_ptr1(struct tty
*tty
, enum tty_code_code code
, const void *a
)
388 tty_puts(tty
, tty_term_ptr1(tty
->term
, code
, a
));
392 tty_putcode_ptr2(struct tty
*tty
, enum tty_code_code code
, const void *a
, const void *b
)
394 if (a
!= NULL
&& b
!= NULL
)
395 tty_puts(tty
, tty_term_ptr2(tty
->term
, code
, a
, b
));
399 tty_puts(struct tty
*tty
, const char *s
)
403 bufferevent_write(tty
->event
, s
, strlen(s
));
405 if (tty
->log_fd
!= -1)
406 write(tty
->log_fd
, s
, strlen(s
));
410 tty_putc(struct tty
*tty
, u_char ch
)
415 if (tty
->cell
.attr
& GRID_ATTR_CHARSET
) {
416 acs
= tty_acs_get(tty
, ch
);
418 bufferevent_write(tty
->event
, acs
, strlen(acs
));
420 bufferevent_write(tty
->event
, &ch
, 1);
422 bufferevent_write(tty
->event
, &ch
, 1);
424 if (ch
>= 0x20 && ch
!= 0x7f) {
426 if (tty
->term
->flags
& TERM_EARLYWRAP
)
431 if (tty
->cy
!= tty
->rlower
)
437 if (tty
->log_fd
!= -1)
438 write(tty
->log_fd
, &ch
, 1);
442 tty_putn(struct tty
*tty
, const void *buf
, size_t len
, u_int width
)
444 bufferevent_write(tty
->event
, buf
, len
);
445 if (tty
->log_fd
!= -1)
446 write(tty
->log_fd
, buf
, len
);
451 tty_set_title(struct tty
*tty
, const char *title
)
453 if (!tty_term_has(tty
->term
, TTYC_TSL
) ||
454 !tty_term_has(tty
->term
, TTYC_FSL
))
457 tty_putcode(tty
, TTYC_TSL
);
458 tty_puts(tty
, title
);
459 tty_putcode(tty
, TTYC_FSL
);
463 tty_force_cursor_colour(struct tty
*tty
, const char *ccolour
)
465 if (*ccolour
== '\0')
466 tty_putcode(tty
, TTYC_CR
);
468 tty_putcode_ptr1(tty
, TTYC_CS
, ccolour
);
470 tty
->ccolour
= xstrdup(ccolour
);
474 tty_update_mode(struct tty
*tty
, int mode
, struct screen
*s
)
478 if (strcmp(s
->ccolour
, tty
->ccolour
))
479 tty_force_cursor_colour(tty
, s
->ccolour
);
481 if (tty
->flags
& TTY_NOCURSOR
)
482 mode
&= ~MODE_CURSOR
;
484 changed
= mode
^ tty
->mode
;
485 if (changed
& MODE_CURSOR
) {
486 if (mode
& MODE_CURSOR
)
487 tty_putcode(tty
, TTYC_CNORM
);
489 tty_putcode(tty
, TTYC_CIVIS
);
491 if (tty
->cstyle
!= s
->cstyle
) {
492 if (tty_term_has(tty
->term
, TTYC_SS
)) {
493 if (s
->cstyle
== 0 &&
494 tty_term_has(tty
->term
, TTYC_SE
))
495 tty_putcode(tty
, TTYC_SE
);
497 tty_putcode1(tty
, TTYC_SS
, s
->cstyle
);
499 tty
->cstyle
= s
->cstyle
;
501 if (changed
& (ALL_MOUSE_MODES
|MODE_MOUSE_UTF8
)) {
502 if (mode
& ALL_MOUSE_MODES
) {
504 * Enable the UTF-8 (1005) extension if configured to.
505 * Enable the SGR (1006) extension unconditionally, as
506 * this is safe from misinterpretation. Do it in this
507 * order, because in some terminals it's the last one
508 * that takes effect and SGR is the preferred one.
510 if (mode
& MODE_MOUSE_UTF8
)
511 tty_puts(tty
, "\033[?1005h");
513 tty_puts(tty
, "\033[?1005l");
514 tty_puts(tty
, "\033[?1006h");
516 if (mode
& MODE_MOUSE_ANY
)
517 tty_puts(tty
, "\033[?1003h");
518 else if (mode
& MODE_MOUSE_BUTTON
)
519 tty_puts(tty
, "\033[?1002h");
520 else if (mode
& MODE_MOUSE_STANDARD
)
521 tty_puts(tty
, "\033[?1000h");
523 if (tty
->mode
& MODE_MOUSE_ANY
)
524 tty_puts(tty
, "\033[?1003l");
525 else if (tty
->mode
& MODE_MOUSE_BUTTON
)
526 tty_puts(tty
, "\033[?1002l");
527 else if (tty
->mode
& MODE_MOUSE_STANDARD
)
528 tty_puts(tty
, "\033[?1000l");
530 tty_puts(tty
, "\033[?1006l");
531 if (tty
->mode
& MODE_MOUSE_UTF8
)
532 tty_puts(tty
, "\033[?1005l");
535 if (changed
& MODE_KKEYPAD
) {
536 if (mode
& MODE_KKEYPAD
)
537 tty_putcode(tty
, TTYC_SMKX
);
539 tty_putcode(tty
, TTYC_RMKX
);
541 if (changed
& MODE_BRACKETPASTE
) {
542 if (mode
& MODE_BRACKETPASTE
)
543 tty_puts(tty
, "\033[?2004h");
545 tty_puts(tty
, "\033[?2004l");
552 struct tty
*tty
, enum tty_code_code code
, enum tty_code_code code1
, u_int n
)
554 if (tty_term_has(tty
->term
, code
))
555 tty_putcode1(tty
, code
, n
);
558 tty_putcode(tty
, code1
);
563 tty_repeat_space(struct tty
*tty
, u_int n
)
570 * Is the region large enough to be worth redrawing once later rather than
571 * probably several times now? Currently yes if it is more than 50% of the
575 tty_large_region(unused
struct tty
*tty
, const struct tty_ctx
*ctx
)
577 struct window_pane
*wp
= ctx
->wp
;
579 return (ctx
->orlower
- ctx
->orupper
>= screen_size_y(wp
->screen
) / 2);
583 * Redraw scroll region using data from screen (already updated). Used when
584 * CSR not supported, or window is a pane that doesn't take up the full
585 * width of the terminal.
588 tty_redraw_region(struct tty
*tty
, const struct tty_ctx
*ctx
)
590 struct window_pane
*wp
= ctx
->wp
;
591 struct screen
*s
= wp
->screen
;
595 * If region is large, schedule a window redraw. In most cases this is
596 * likely to be followed by some more scrolling.
598 if (tty_large_region(tty
, ctx
)) {
599 wp
->flags
|= PANE_REDRAW
;
603 if (ctx
->ocy
< ctx
->orupper
|| ctx
->ocy
> ctx
->orlower
) {
604 for (i
= ctx
->ocy
; i
< screen_size_y(s
); i
++)
605 tty_draw_line(tty
, s
, i
, ctx
->xoff
, ctx
->yoff
);
607 for (i
= ctx
->orupper
; i
<= ctx
->orlower
; i
++)
608 tty_draw_line(tty
, s
, i
, ctx
->xoff
, ctx
->yoff
);
613 tty_draw_line(struct tty
*tty
, struct screen
*s
, u_int py
, u_int ox
, u_int oy
)
615 const struct grid_cell
*gc
;
616 struct grid_line
*gl
;
617 struct grid_cell tmpgc
;
621 tty_update_mode(tty
, tty
->mode
& ~MODE_CURSOR
, s
);
623 sx
= screen_size_x(s
);
624 if (sx
> s
->grid
->linedata
[s
->grid
->hsize
+ py
].cellsize
)
625 sx
= s
->grid
->linedata
[s
->grid
->hsize
+ py
].cellsize
;
630 * Don't move the cursor to the start permission if it will wrap there
635 gl
= &s
->grid
->linedata
[s
->grid
->hsize
+ py
- 1];
636 if (oy
+ py
== 0 || gl
== NULL
|| !(gl
->flags
& GRID_LINE_WRAPPED
) ||
637 tty
->cx
< tty
->sx
|| ox
!= 0 ||
638 (oy
+ py
!= tty
->cy
+ 1 && tty
->cy
!= s
->rlower
+ oy
))
639 tty_cursor(tty
, ox
, oy
+ py
);
641 for (i
= 0; i
< sx
; i
++) {
642 gc
= grid_view_peek_cell(s
->grid
, i
, py
);
643 if (screen_check_selection(s
, i
, py
)) {
644 memcpy(&tmpgc
, &s
->sel
.cell
, sizeof tmpgc
);
645 grid_cell_get(gc
, &ud
);
646 grid_cell_set(&tmpgc
, &ud
);
647 tmpgc
.flags
= gc
->flags
&
648 ~(GRID_FLAG_FG256
|GRID_FLAG_BG256
);
649 tmpgc
.flags
|= s
->sel
.cell
.flags
&
650 (GRID_FLAG_FG256
|GRID_FLAG_BG256
);
651 tty_cell(tty
, &tmpgc
);
657 tty_update_mode(tty
, tty
->mode
, s
);
662 tty_cursor(tty
, ox
+ sx
, oy
+ py
);
663 if (sx
!= screen_size_x(s
) && ox
+ screen_size_x(s
) >= tty
->sx
&&
664 tty_term_has(tty
->term
, TTYC_EL
))
665 tty_putcode(tty
, TTYC_EL
);
667 tty_repeat_space(tty
, screen_size_x(s
) - sx
);
668 tty_update_mode(tty
, tty
->mode
, s
);
673 void (*cmdfn
)(struct tty
*, const struct tty_ctx
*), struct tty_ctx
*ctx
)
675 struct window_pane
*wp
= ctx
->wp
;
679 /* wp can be NULL if updating the screen but not the terminal. */
683 if (wp
->window
->flags
& WINDOW_REDRAW
|| wp
->flags
& PANE_REDRAW
)
685 if (!window_pane_visible(wp
) || wp
->flags
& PANE_DROP
)
688 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
689 c
= ARRAY_ITEM(&clients
, i
);
690 if (c
== NULL
|| c
->session
== NULL
|| c
->tty
.term
== NULL
)
692 if (c
->flags
& CLIENT_SUSPENDED
)
694 if (c
->tty
.flags
& TTY_FREEZE
)
696 if (c
->session
->curw
->window
!= wp
->window
)
699 ctx
->xoff
= wp
->xoff
;
700 ctx
->yoff
= wp
->yoff
;
701 if (status_at_line(c
) == 0)
709 tty_cmd_insertcharacter(struct tty
*tty
, const struct tty_ctx
*ctx
)
711 struct window_pane
*wp
= ctx
->wp
;
713 if (!tty_pane_full_width(tty
, ctx
)) {
714 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, ctx
->xoff
, ctx
->yoff
);
720 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
722 if (tty_term_has(tty
->term
, TTYC_ICH
) ||
723 tty_term_has(tty
->term
, TTYC_ICH1
))
724 tty_emulate_repeat(tty
, TTYC_ICH
, TTYC_ICH1
, ctx
->num
);
726 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, ctx
->xoff
, ctx
->yoff
);
730 tty_cmd_deletecharacter(struct tty
*tty
, const struct tty_ctx
*ctx
)
732 struct window_pane
*wp
= ctx
->wp
;
734 if (!tty_pane_full_width(tty
, ctx
) ||
735 (!tty_term_has(tty
->term
, TTYC_DCH
) &&
736 !tty_term_has(tty
->term
, TTYC_DCH1
))) {
737 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, ctx
->xoff
, ctx
->yoff
);
743 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
745 if (tty_term_has(tty
->term
, TTYC_DCH
) ||
746 tty_term_has(tty
->term
, TTYC_DCH1
))
747 tty_emulate_repeat(tty
, TTYC_DCH
, TTYC_DCH1
, ctx
->num
);
751 tty_cmd_clearcharacter(struct tty
*tty
, const struct tty_ctx
*ctx
)
757 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
759 if (tty_term_has(tty
->term
, TTYC_ECH
))
760 tty_putcode1(tty
, TTYC_ECH
, ctx
->num
);
762 for (i
= 0; i
< ctx
->num
; i
++)
768 tty_cmd_insertline(struct tty
*tty
, const struct tty_ctx
*ctx
)
770 if (!tty_pane_full_width(tty
, ctx
) ||
771 !tty_term_has(tty
->term
, TTYC_CSR
) ||
772 !tty_term_has(tty
->term
, TTYC_IL1
)) {
773 tty_redraw_region(tty
, ctx
);
779 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
780 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
782 tty_emulate_repeat(tty
, TTYC_IL
, TTYC_IL1
, ctx
->num
);
786 tty_cmd_deleteline(struct tty
*tty
, const struct tty_ctx
*ctx
)
788 if (!tty_pane_full_width(tty
, ctx
) ||
789 !tty_term_has(tty
->term
, TTYC_CSR
) ||
790 !tty_term_has(tty
->term
, TTYC_DL1
)) {
791 tty_redraw_region(tty
, ctx
);
797 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
798 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
800 tty_emulate_repeat(tty
, TTYC_DL
, TTYC_DL1
, ctx
->num
);
804 tty_cmd_clearline(struct tty
*tty
, const struct tty_ctx
*ctx
)
806 struct window_pane
*wp
= ctx
->wp
;
807 struct screen
*s
= wp
->screen
;
811 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
);
813 if (tty_pane_full_width(tty
, ctx
) && tty_term_has(tty
->term
, TTYC_EL
))
814 tty_putcode(tty
, TTYC_EL
);
816 tty_repeat_space(tty
, screen_size_x(s
));
820 tty_cmd_clearendofline(struct tty
*tty
, const struct tty_ctx
*ctx
)
822 struct window_pane
*wp
= ctx
->wp
;
823 struct screen
*s
= wp
->screen
;
827 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
829 if (tty_pane_full_width(tty
, ctx
) && tty_term_has(tty
->term
, TTYC_EL
))
830 tty_putcode(tty
, TTYC_EL
);
832 tty_repeat_space(tty
, screen_size_x(s
) - ctx
->ocx
);
836 tty_cmd_clearstartofline(struct tty
*tty
, const struct tty_ctx
*ctx
)
840 if (ctx
->xoff
== 0 && tty_term_has(tty
->term
, TTYC_EL1
)) {
841 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
842 tty_putcode(tty
, TTYC_EL1
);
844 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
);
845 tty_repeat_space(tty
, ctx
->ocx
+ 1);
850 tty_cmd_reverseindex(struct tty
*tty
, const struct tty_ctx
*ctx
)
852 if (ctx
->ocy
!= ctx
->orupper
)
855 if (!tty_pane_full_width(tty
, ctx
) ||
856 !tty_term_has(tty
->term
, TTYC_CSR
) ||
857 !tty_term_has(tty
->term
, TTYC_RI
)) {
858 tty_redraw_region(tty
, ctx
);
864 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
865 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->orupper
);
867 tty_putcode(tty
, TTYC_RI
);
871 tty_cmd_linefeed(struct tty
*tty
, const struct tty_ctx
*ctx
)
873 struct window_pane
*wp
= ctx
->wp
;
875 if (ctx
->ocy
!= ctx
->orlower
)
878 if (!tty_pane_full_width(tty
, ctx
) ||
879 !tty_term_has(tty
->term
, TTYC_CSR
)) {
880 if (tty_large_region(tty
, ctx
))
881 wp
->flags
|= PANE_REDRAW
;
883 tty_redraw_region(tty
, ctx
);
888 * If this line wrapped naturally (ctx->num is nonzero), don't do
889 * anything - the cursor can just be moved to the last cell and wrap
892 if (ctx
->num
&& !(tty
->term
->flags
& TERM_EARLYWRAP
))
897 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
898 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
904 tty_cmd_clearendofscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
906 struct window_pane
*wp
= ctx
->wp
;
907 struct screen
*s
= wp
->screen
;
912 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
913 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
915 if (tty_pane_full_width(tty
, ctx
) && tty_term_has(tty
->term
, TTYC_EL
)) {
916 tty_putcode(tty
, TTYC_EL
);
917 if (ctx
->ocy
!= screen_size_y(s
) - 1) {
918 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
+ 1);
919 for (i
= ctx
->ocy
+ 1; i
< screen_size_y(s
); i
++) {
920 tty_putcode(tty
, TTYC_EL
);
921 if (i
== screen_size_y(s
) - 1)
923 tty_emulate_repeat(tty
, TTYC_CUD
, TTYC_CUD1
, 1);
928 tty_repeat_space(tty
, screen_size_x(s
) - ctx
->ocx
);
929 for (j
= ctx
->ocy
+ 1; j
< screen_size_y(s
); j
++) {
930 tty_cursor_pane(tty
, ctx
, 0, j
);
931 tty_repeat_space(tty
, screen_size_x(s
));
937 tty_cmd_clearstartofscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
939 struct window_pane
*wp
= ctx
->wp
;
940 struct screen
*s
= wp
->screen
;
945 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
946 tty_cursor_pane(tty
, ctx
, 0, 0);
948 if (tty_pane_full_width(tty
, ctx
) && tty_term_has(tty
->term
, TTYC_EL
)) {
949 for (i
= 0; i
< ctx
->ocy
; i
++) {
950 tty_putcode(tty
, TTYC_EL
);
951 tty_emulate_repeat(tty
, TTYC_CUD
, TTYC_CUD1
, 1);
955 for (j
= 0; j
< ctx
->ocy
; j
++) {
956 tty_cursor_pane(tty
, ctx
, 0, j
);
957 tty_repeat_space(tty
, screen_size_x(s
));
960 tty_repeat_space(tty
, ctx
->ocx
+ 1);
964 tty_cmd_clearscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
966 struct window_pane
*wp
= ctx
->wp
;
967 struct screen
*s
= wp
->screen
;
972 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
973 tty_cursor_pane(tty
, ctx
, 0, 0);
975 if (tty_pane_full_width(tty
, ctx
) && tty_term_has(tty
->term
, TTYC_EL
)) {
976 for (i
= 0; i
< screen_size_y(s
); i
++) {
977 tty_putcode(tty
, TTYC_EL
);
978 if (i
!= screen_size_y(s
) - 1) {
979 tty_emulate_repeat(tty
, TTYC_CUD
, TTYC_CUD1
, 1);
984 for (j
= 0; j
< screen_size_y(s
); j
++) {
985 tty_cursor_pane(tty
, ctx
, 0, j
);
986 tty_repeat_space(tty
, screen_size_x(s
));
992 tty_cmd_alignmenttest(struct tty
*tty
, const struct tty_ctx
*ctx
)
994 struct window_pane
*wp
= ctx
->wp
;
995 struct screen
*s
= wp
->screen
;
1000 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
1002 for (j
= 0; j
< screen_size_y(s
); j
++) {
1003 tty_cursor_pane(tty
, ctx
, 0, j
);
1004 for (i
= 0; i
< screen_size_x(s
); i
++)
1010 tty_cmd_cell(struct tty
*tty
, const struct tty_ctx
*ctx
)
1012 struct window_pane
*wp
= ctx
->wp
;
1013 struct screen
*s
= wp
->screen
;
1017 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
1019 /* Is the cursor in the very last position? */
1020 width
= grid_cell_width(ctx
->cell
);
1021 if (ctx
->ocx
> wp
->sx
- width
) {
1022 if (ctx
->xoff
!= 0 || wp
->sx
!= tty
->sx
) {
1024 * The pane doesn't fill the entire line, the linefeed
1025 * will already have happened, so just move the cursor.
1027 if (ctx
->ocy
!= wp
->yoff
+ wp
->screen
->rlower
)
1028 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
+ 1);
1030 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
);
1031 } else if (tty
->cx
< tty
->sx
) {
1033 * The cursor isn't in the last position already, so
1034 * move as far left as possible and redraw the last
1035 * cell to move into the last position.
1037 cx
= screen_size_x(s
) - grid_cell_width(&ctx
->last_cell
);
1038 tty_cursor_pane(tty
, ctx
, cx
, ctx
->ocy
);
1039 tty_cell(tty
, &ctx
->last_cell
);
1042 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
1044 tty_cell(tty
, ctx
->cell
);
1048 tty_cmd_utf8character(struct tty
*tty
, const struct tty_ctx
*ctx
)
1050 struct window_pane
*wp
= ctx
->wp
;
1053 * Cannot rely on not being a partial character, so just redraw the
1056 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, ctx
->xoff
, ctx
->yoff
);
1060 tty_cmd_setselection(struct tty
*tty
, const struct tty_ctx
*ctx
)
1065 if (!tty_term_has(tty
->term
, TTYC_MS
))
1068 off
= 4 * ((ctx
->num
+ 2) / 3) + 1; /* storage for base64 */
1071 b64_ntop(ctx
->ptr
, ctx
->num
, buf
, off
);
1072 tty_putcode_ptr2(tty
, TTYC_MS
, "", buf
);
1078 tty_cmd_rawstring(struct tty
*tty
, const struct tty_ctx
*ctx
)
1081 u_char
*str
= ctx
->ptr
;
1083 for (i
= 0; i
< ctx
->num
; i
++)
1084 tty_putc(tty
, str
[i
]);
1086 tty
->cx
= tty
->cy
= UINT_MAX
;
1087 tty
->rupper
= tty
->rlower
= UINT_MAX
;
1090 tty_cursor(tty
, 0, 0);
1094 tty_cell(struct tty
*tty
, const struct grid_cell
*gc
)
1096 struct utf8_data ud
;
1099 /* Skip last character if terminal is stupid. */
1100 if (tty
->term
->flags
& TERM_EARLYWRAP
&&
1101 tty
->cy
== tty
->sy
- 1 && tty
->cx
== tty
->sx
- 1)
1104 /* If this is a padding character, do nothing. */
1105 if (gc
->flags
& GRID_FLAG_PADDING
)
1108 /* Set the attributes. */
1109 tty_attributes(tty
, gc
);
1111 /* Get the cell and if ASCII write with putc to do ACS translation. */
1112 grid_cell_get(gc
, &ud
);
1114 if (*ud
.data
< 0x20 || *ud
.data
== 0x7f)
1116 tty_putc(tty
, *ud
.data
);
1120 /* If not UTF-8, write _. */
1121 if (!(tty
->flags
& TTY_UTF8
)) {
1122 for (i
= 0; i
< ud
.width
; i
++)
1127 /* Write the data. */
1128 tty_putn(tty
, ud
.data
, ud
.size
, ud
.width
);
1132 tty_reset(struct tty
*tty
)
1134 struct grid_cell
*gc
= &tty
->cell
;
1136 if (memcmp(gc
, &grid_default_cell
, sizeof *gc
) == 0)
1139 if ((gc
->attr
& GRID_ATTR_CHARSET
) && tty_use_acs(tty
))
1140 tty_putcode(tty
, TTYC_RMACS
);
1141 tty_putcode(tty
, TTYC_SGR0
);
1142 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
1145 /* Set region inside pane. */
1148 struct tty
*tty
, const struct tty_ctx
*ctx
, u_int rupper
, u_int rlower
)
1150 tty_region(tty
, ctx
->yoff
+ rupper
, ctx
->yoff
+ rlower
);
1153 /* Set region at absolute position. */
1155 tty_region(struct tty
*tty
, u_int rupper
, u_int rlower
)
1157 if (tty
->rlower
== rlower
&& tty
->rupper
== rupper
)
1159 if (!tty_term_has(tty
->term
, TTYC_CSR
))
1162 tty
->rupper
= rupper
;
1163 tty
->rlower
= rlower
;
1166 * Some terminals (such as PuTTY) do not correctly reset the cursor to
1167 * 0,0 if it is beyond the last column (they do not reset their wrap
1168 * flag so further output causes a line feed). As a workaround, do an
1169 * explicit move to 0 first.
1171 if (tty
->cx
>= tty
->sx
)
1172 tty_cursor(tty
, 0, tty
->cy
);
1174 tty_putcode2(tty
, TTYC_CSR
, tty
->rupper
, tty
->rlower
);
1175 tty_cursor(tty
, 0, 0);
1178 /* Move cursor inside pane. */
1180 tty_cursor_pane(struct tty
*tty
, const struct tty_ctx
*ctx
, u_int cx
, u_int cy
)
1182 tty_cursor(tty
, ctx
->xoff
+ cx
, ctx
->yoff
+ cy
);
1185 /* Move cursor to absolute position. */
1187 tty_cursor(struct tty
*tty
, u_int cx
, u_int cy
)
1189 struct tty_term
*term
= tty
->term
;
1193 if (cx
> tty
->sx
- 1)
1200 if (cx
== thisx
&& cy
== thisy
)
1203 /* Very end of the line, just use absolute movement. */
1204 if (thisx
> tty
->sx
- 1)
1207 /* Move to home position (0, 0). */
1208 if (cx
== 0 && cy
== 0 && tty_term_has(term
, TTYC_HOME
)) {
1209 tty_putcode(tty
, TTYC_HOME
);
1213 /* Zero on the next line. */
1214 if (cx
== 0 && cy
== thisy
+ 1 && thisy
!= tty
->rlower
) {
1215 tty_putc(tty
, '\r');
1216 tty_putc(tty
, '\n');
1220 /* Moving column or row. */
1223 * Moving column only, row staying the same.
1228 tty_putc(tty
, '\r');
1232 /* One to the left. */
1233 if (cx
== thisx
- 1 && tty_term_has(term
, TTYC_CUB1
)) {
1234 tty_putcode(tty
, TTYC_CUB1
);
1238 /* One to the right. */
1239 if (cx
== thisx
+ 1 && tty_term_has(term
, TTYC_CUF1
)) {
1240 tty_putcode(tty
, TTYC_CUF1
);
1244 /* Calculate difference. */
1245 change
= thisx
- cx
; /* +ve left, -ve right */
1248 * Use HPA if change is larger than absolute, otherwise move
1249 * the cursor with CUB/CUF.
1251 if ((u_int
) abs(change
) > cx
&& tty_term_has(term
, TTYC_HPA
)) {
1252 tty_putcode1(tty
, TTYC_HPA
, cx
);
1254 } else if (change
> 0 && tty_term_has(term
, TTYC_CUB
)) {
1255 tty_putcode1(tty
, TTYC_CUB
, change
);
1257 } else if (change
< 0 && tty_term_has(term
, TTYC_CUF
)) {
1258 tty_putcode1(tty
, TTYC_CUF
, -change
);
1261 } else if (cx
== thisx
) {
1263 * Moving row only, column staying the same.
1267 if (thisy
!= tty
->rupper
&&
1268 cy
== thisy
- 1 && tty_term_has(term
, TTYC_CUU1
)) {
1269 tty_putcode(tty
, TTYC_CUU1
);
1274 if (thisy
!= tty
->rlower
&&
1275 cy
== thisy
+ 1 && tty_term_has(term
, TTYC_CUD1
)) {
1276 tty_putcode(tty
, TTYC_CUD1
);
1280 /* Calculate difference. */
1281 change
= thisy
- cy
; /* +ve up, -ve down */
1284 * Try to use VPA if change is larger than absolute or if this
1285 * change would cross the scroll region, otherwise use CUU/CUD.
1287 if ((u_int
) abs(change
) > cy
||
1288 (change
< 0 && cy
- change
> tty
->rlower
) ||
1289 (change
> 0 && cy
- change
< tty
->rupper
)) {
1290 if (tty_term_has(term
, TTYC_VPA
)) {
1291 tty_putcode1(tty
, TTYC_VPA
, cy
);
1294 } else if (change
> 0 && tty_term_has(term
, TTYC_CUU
)) {
1295 tty_putcode1(tty
, TTYC_CUU
, change
);
1297 } else if (change
< 0 && tty_term_has(term
, TTYC_CUD
)) {
1298 tty_putcode1(tty
, TTYC_CUD
, -change
);
1304 /* Absolute movement. */
1305 tty_putcode2(tty
, TTYC_CUP
, cy
, cx
);
1313 tty_attributes(struct tty
*tty
, const struct grid_cell
*gc
)
1315 struct grid_cell
*tc
= &tty
->cell
, gc2
;
1318 memcpy(&gc2
, gc
, sizeof gc2
);
1321 * If no setab, try to use the reverse attribute as a best-effort for a
1322 * non-default background. This is a bit of a hack but it doesn't do
1323 * any serious harm and makes a couple of applications happier.
1325 if (!tty_term_has(tty
->term
, TTYC_SETAB
)) {
1326 if (gc2
.attr
& GRID_ATTR_REVERSE
) {
1327 if (gc2
.fg
!= 7 && gc2
.fg
!= 8)
1328 gc2
.attr
&= ~GRID_ATTR_REVERSE
;
1330 if (gc2
.bg
!= 0 && gc2
.bg
!= 8)
1331 gc2
.attr
|= GRID_ATTR_REVERSE
;
1335 /* Fix up the colours if necessary. */
1336 tty_check_fg(tty
, &gc2
);
1337 tty_check_bg(tty
, &gc2
);
1339 /* If any bits are being cleared, reset everything. */
1340 if (tc
->attr
& ~gc2
.attr
)
1344 * Set the colours. This may call tty_reset() (so it comes next) and
1345 * may add to (NOT remove) the desired attributes by changing new_attr.
1347 tty_colours(tty
, &gc2
);
1349 /* Filter out attribute bits already set. */
1350 changed
= gc2
.attr
& ~tc
->attr
;
1351 tc
->attr
= gc2
.attr
;
1353 /* Set the attributes. */
1354 if (changed
& GRID_ATTR_BRIGHT
)
1355 tty_putcode(tty
, TTYC_BOLD
);
1356 if (changed
& GRID_ATTR_DIM
)
1357 tty_putcode(tty
, TTYC_DIM
);
1358 if (changed
& GRID_ATTR_ITALICS
)
1360 if (tty_term_has(tty
->term
, TTYC_SITM
))
1361 tty_putcode(tty
, TTYC_SITM
);
1363 tty_putcode(tty
, TTYC_SMSO
);
1365 if (changed
& GRID_ATTR_UNDERSCORE
)
1366 tty_putcode(tty
, TTYC_SMUL
);
1367 if (changed
& GRID_ATTR_BLINK
)
1368 tty_putcode(tty
, TTYC_BLINK
);
1369 if (changed
& GRID_ATTR_REVERSE
) {
1370 if (tty_term_has(tty
->term
, TTYC_REV
))
1371 tty_putcode(tty
, TTYC_REV
);
1372 else if (tty_term_has(tty
->term
, TTYC_SMSO
))
1373 tty_putcode(tty
, TTYC_SMSO
);
1375 if (changed
& GRID_ATTR_HIDDEN
)
1376 tty_putcode(tty
, TTYC_INVIS
);
1377 if ((changed
& GRID_ATTR_CHARSET
) && tty_use_acs(tty
))
1378 tty_putcode(tty
, TTYC_SMACS
);
1382 tty_colours(struct tty
*tty
, const struct grid_cell
*gc
)
1384 struct grid_cell
*tc
= &tty
->cell
;
1385 u_char fg
= gc
->fg
, bg
= gc
->bg
, flags
= gc
->flags
;
1386 int have_ax
, fg_default
, bg_default
;
1388 /* No changes? Nothing is necessary. */
1389 if (fg
== tc
->fg
&& bg
== tc
->bg
&&
1390 ((flags
^ tc
->flags
) & (GRID_FLAG_FG256
|GRID_FLAG_BG256
)) == 0)
1394 * Is either the default colour? This is handled specially because the
1395 * best solution might be to reset both colours to default, in which
1396 * case if only one is default need to fall onward to set the other
1399 fg_default
= (fg
== 8 && !(flags
& GRID_FLAG_FG256
));
1400 bg_default
= (bg
== 8 && !(flags
& GRID_FLAG_BG256
));
1401 if (fg_default
|| bg_default
) {
1403 * If don't have AX but do have op, send sgr0 (op can't
1404 * actually be used because it is sometimes the same as sgr0
1405 * and sometimes isn't). This resets both colours to default.
1407 * Otherwise, try to set the default colour only as needed.
1409 have_ax
= tty_term_has(tty
->term
, TTYC_AX
);
1410 if (!have_ax
&& tty_term_has(tty
->term
, TTYC_OP
))
1414 (tc
->fg
!= 8 || tc
->flags
& GRID_FLAG_FG256
)) {
1416 tty_puts(tty
, "\033[39m");
1417 else if (tc
->fg
!= 7 ||
1418 tc
->flags
& GRID_FLAG_FG256
)
1419 tty_putcode1(tty
, TTYC_SETAF
, 7);
1421 tc
->flags
&= ~GRID_FLAG_FG256
;
1424 (tc
->bg
!= 8 || tc
->flags
& GRID_FLAG_BG256
)) {
1426 tty_puts(tty
, "\033[49m");
1427 else if (tc
->bg
!= 0 ||
1428 tc
->flags
& GRID_FLAG_BG256
)
1429 tty_putcode1(tty
, TTYC_SETAB
, 0);
1431 tc
->flags
&= ~GRID_FLAG_BG256
;
1436 /* Set the foreground colour. */
1437 if (!fg_default
&& (fg
!= tc
->fg
||
1438 ((flags
& GRID_FLAG_FG256
) != (tc
->flags
& GRID_FLAG_FG256
))))
1439 tty_colours_fg(tty
, gc
);
1442 * Set the background colour. This must come after the foreground as
1443 * tty_colour_fg() can call tty_reset().
1445 if (!bg_default
&& (bg
!= tc
->bg
||
1446 ((flags
& GRID_FLAG_BG256
) != (tc
->flags
& GRID_FLAG_BG256
))))
1447 tty_colours_bg(tty
, gc
);
1451 tty_check_fg(struct tty
*tty
, struct grid_cell
*gc
)
1455 /* Is this a 256-colour colour? */
1456 if (gc
->flags
& GRID_FLAG_FG256
) {
1457 /* And not a 256 colour mode? */
1458 if (!(tty
->term
->flags
& TERM_256COLOURS
) &&
1459 !(tty
->term_flags
& TERM_256COLOURS
)) {
1460 gc
->fg
= colour_256to16(gc
->fg
);
1463 gc
->attr
|= GRID_ATTR_BRIGHT
;
1465 gc
->attr
&= ~GRID_ATTR_BRIGHT
;
1466 gc
->flags
&= ~GRID_FLAG_FG256
;
1471 /* Is this an aixterm colour? */
1472 colours
= tty_term_number(tty
->term
, TTYC_COLORS
);
1473 if (gc
->fg
>= 90 && gc
->fg
<= 97 && colours
< 16) {
1475 gc
->attr
|= GRID_ATTR_BRIGHT
;
1480 tty_check_bg(struct tty
*tty
, struct grid_cell
*gc
)
1484 /* Is this a 256-colour colour? */
1485 if (gc
->flags
& GRID_FLAG_BG256
) {
1487 * And not a 256 colour mode? Translate to 16-colour
1488 * palette. Bold background doesn't exist portably, so just
1489 * discard the bold bit if set.
1491 if (!(tty
->term
->flags
& TERM_256COLOURS
) &&
1492 !(tty
->term_flags
& TERM_256COLOURS
)) {
1493 gc
->bg
= colour_256to16(gc
->bg
);
1496 gc
->attr
&= ~GRID_ATTR_BRIGHT
;
1497 gc
->flags
&= ~GRID_FLAG_BG256
;
1502 /* Is this an aixterm colour? */
1503 colours
= tty_term_number(tty
->term
, TTYC_COLORS
);
1504 if (gc
->bg
>= 90 && gc
->bg
<= 97 && colours
< 16) {
1506 gc
->attr
|= GRID_ATTR_BRIGHT
;
1511 tty_colours_fg(struct tty
*tty
, const struct grid_cell
*gc
)
1513 struct grid_cell
*tc
= &tty
->cell
;
1517 /* Is this a 256-colour colour? */
1518 if (gc
->flags
& GRID_FLAG_FG256
) {
1519 /* Try as 256 colours. */
1520 if (tty_try_256(tty
, fg
, "38") == 0)
1522 /* Else already handled by tty_check_fg. */
1526 /* Is this an aixterm bright colour? */
1527 if (fg
>= 90 && fg
<= 97) {
1528 xsnprintf(s
, sizeof s
, "\033[%dm", fg
);
1533 /* Otherwise set the foreground colour. */
1534 tty_putcode1(tty
, TTYC_SETAF
, fg
);
1537 /* Save the new values in the terminal current cell. */
1539 tc
->flags
&= ~GRID_FLAG_FG256
;
1540 tc
->flags
|= gc
->flags
& GRID_FLAG_FG256
;
1544 tty_colours_bg(struct tty
*tty
, const struct grid_cell
*gc
)
1546 struct grid_cell
*tc
= &tty
->cell
;
1550 /* Is this a 256-colour colour? */
1551 if (gc
->flags
& GRID_FLAG_BG256
) {
1552 /* Try as 256 colours. */
1553 if (tty_try_256(tty
, bg
, "48") == 0)
1555 /* Else already handled by tty_check_bg. */
1559 /* Is this an aixterm bright colour? */
1560 if (bg
>= 90 && bg
<= 97) {
1561 /* 16 colour terminals or above only. */
1562 if (tty_term_number(tty
->term
, TTYC_COLORS
) >= 16) {
1563 xsnprintf(s
, sizeof s
, "\033[%dm", bg
+ 10);
1568 /* no such thing as a bold background */
1571 /* Otherwise set the background colour. */
1572 tty_putcode1(tty
, TTYC_SETAB
, bg
);
1575 /* Save the new values in the terminal current cell. */
1577 tc
->flags
&= ~GRID_FLAG_BG256
;
1578 tc
->flags
|= gc
->flags
& GRID_FLAG_BG256
;
1582 tty_try_256(struct tty
*tty
, u_char colour
, const char *type
)
1586 if (!(tty
->term
->flags
& TERM_256COLOURS
) &&
1587 !(tty
->term_flags
& TERM_256COLOURS
))
1590 xsnprintf(s
, sizeof s
, "\033[%s;5;%hhum", type
, colour
);
1596 tty_bell(struct tty
*tty
)
1598 tty_putcode(tty
, TTYC_BEL
);