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
, 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
, 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");
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");
297 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_RMCUP
));
299 setblocking(tty
->fd
, 1);
303 tty_close(struct tty
*tty
)
305 if (tty
->log_fd
!= -1) {
310 if (event_initialized(&tty
->key_timer
))
311 evtimer_del(&tty
->key_timer
);
314 if (tty
->flags
& TTY_OPENED
) {
315 bufferevent_free(tty
->event
);
317 tty_term_free(tty
->term
);
320 tty
->flags
&= ~TTY_OPENED
;
330 tty_free(struct tty
*tty
)
335 if (tty
->path
!= NULL
)
337 if (tty
->termname
!= NULL
)
342 tty_raw(struct tty
*tty
, const char *s
)
348 for (i
= 0; i
< 5; i
++) {
349 n
= write(tty
->fd
, s
, slen
);
355 } else if (n
== -1 && errno
!= EAGAIN
)
362 tty_putcode(struct tty
*tty
, enum tty_code_code code
)
364 tty_puts(tty
, tty_term_string(tty
->term
, code
));
368 tty_putcode1(struct tty
*tty
, enum tty_code_code code
, int a
)
372 tty_puts(tty
, tty_term_string1(tty
->term
, code
, a
));
376 tty_putcode2(struct tty
*tty
, enum tty_code_code code
, int a
, int b
)
380 tty_puts(tty
, tty_term_string2(tty
->term
, code
, a
, b
));
384 tty_putcode_ptr1(struct tty
*tty
, enum tty_code_code code
, const void *a
)
387 tty_puts(tty
, tty_term_ptr1(tty
->term
, code
, a
));
391 tty_putcode_ptr2(struct tty
*tty
, enum tty_code_code code
, const void *a
, const void *b
)
393 if (a
!= NULL
&& b
!= NULL
)
394 tty_puts(tty
, tty_term_ptr2(tty
->term
, code
, a
, b
));
398 tty_puts(struct tty
*tty
, const char *s
)
402 bufferevent_write(tty
->event
, s
, strlen(s
));
404 if (tty
->log_fd
!= -1)
405 write(tty
->log_fd
, s
, strlen(s
));
409 tty_putc(struct tty
*tty
, u_char ch
)
414 if (tty
->cell
.attr
& GRID_ATTR_CHARSET
) {
415 acs
= tty_acs_get(tty
, ch
);
417 bufferevent_write(tty
->event
, acs
, strlen(acs
));
419 bufferevent_write(tty
->event
, &ch
, 1);
421 bufferevent_write(tty
->event
, &ch
, 1);
423 if (ch
>= 0x20 && ch
!= 0x7f) {
425 if (tty
->term
->flags
& TERM_EARLYWRAP
)
430 if (tty
->cy
!= tty
->rlower
)
436 if (tty
->log_fd
!= -1)
437 write(tty
->log_fd
, &ch
, 1);
441 tty_putn(struct tty
*tty
, const void *buf
, size_t len
, u_int width
)
443 bufferevent_write(tty
->event
, buf
, len
);
444 if (tty
->log_fd
!= -1)
445 write(tty
->log_fd
, buf
, len
);
450 tty_set_title(struct tty
*tty
, const char *title
)
452 if (!tty_term_has(tty
->term
, TTYC_TSL
) ||
453 !tty_term_has(tty
->term
, TTYC_FSL
))
456 tty_putcode(tty
, TTYC_TSL
);
457 tty_puts(tty
, title
);
458 tty_putcode(tty
, TTYC_FSL
);
462 tty_force_cursor_colour(struct tty
*tty
, const char *ccolour
)
464 if (*ccolour
== '\0')
465 tty_putcode(tty
, TTYC_CR
);
467 tty_putcode_ptr1(tty
, TTYC_CS
, ccolour
);
469 tty
->ccolour
= xstrdup(ccolour
);
473 tty_update_mode(struct tty
*tty
, int mode
, struct screen
*s
)
477 if (strcmp(s
->ccolour
, tty
->ccolour
))
478 tty_force_cursor_colour(tty
, s
->ccolour
);
480 if (tty
->flags
& TTY_NOCURSOR
)
481 mode
&= ~MODE_CURSOR
;
483 changed
= mode
^ tty
->mode
;
484 if (changed
& MODE_CURSOR
) {
485 if (mode
& MODE_CURSOR
)
486 tty_putcode(tty
, TTYC_CNORM
);
488 tty_putcode(tty
, TTYC_CIVIS
);
490 if (tty
->cstyle
!= s
->cstyle
) {
491 if (tty_term_has(tty
->term
, TTYC_SS
)) {
492 if (s
->cstyle
== 0 &&
493 tty_term_has(tty
->term
, TTYC_SE
))
494 tty_putcode(tty
, TTYC_SE
);
496 tty_putcode1(tty
, TTYC_SS
, s
->cstyle
);
498 tty
->cstyle
= s
->cstyle
;
500 if (changed
& (ALL_MOUSE_MODES
|MODE_MOUSE_UTF8
)) {
501 if (mode
& ALL_MOUSE_MODES
) {
503 * Enable the UTF-8 (1005) extension if configured to.
504 * Enable the SGR (1006) extension unconditionally, as
505 * this is safe from misinterpretation. Do it in this
506 * order, because in some terminals it's the last one
507 * that takes effect and SGR is the preferred one.
509 if (mode
& MODE_MOUSE_UTF8
)
510 tty_puts(tty
, "\033[?1005h");
512 tty_puts(tty
, "\033[?1005l");
513 tty_puts(tty
, "\033[?1006h");
515 if (mode
& MODE_MOUSE_ANY
)
516 tty_puts(tty
, "\033[?1003h");
517 else if (mode
& MODE_MOUSE_BUTTON
)
518 tty_puts(tty
, "\033[?1002h");
519 else if (mode
& MODE_MOUSE_STANDARD
)
520 tty_puts(tty
, "\033[?1000h");
522 if (tty
->mode
& MODE_MOUSE_ANY
)
523 tty_puts(tty
, "\033[?1003l");
524 else if (tty
->mode
& MODE_MOUSE_BUTTON
)
525 tty_puts(tty
, "\033[?1002l");
526 else if (tty
->mode
& MODE_MOUSE_STANDARD
)
527 tty_puts(tty
, "\033[?1000l");
529 tty_puts(tty
, "\033[?1006l");
530 if (tty
->mode
& MODE_MOUSE_UTF8
)
531 tty_puts(tty
, "\033[?1005l");
534 if (changed
& MODE_KKEYPAD
) {
535 if (mode
& MODE_KKEYPAD
)
536 tty_putcode(tty
, TTYC_SMKX
);
538 tty_putcode(tty
, TTYC_RMKX
);
540 if (changed
& MODE_BRACKETPASTE
) {
541 if (mode
& MODE_BRACKETPASTE
)
542 tty_puts(tty
, "\033[?2004h");
544 tty_puts(tty
, "\033[?2004l");
551 struct tty
*tty
, enum tty_code_code code
, enum tty_code_code code1
, u_int n
)
553 if (tty_term_has(tty
->term
, code
))
554 tty_putcode1(tty
, code
, n
);
557 tty_putcode(tty
, code1
);
562 tty_repeat_space(struct tty
*tty
, u_int n
)
569 * Is the region large enough to be worth redrawing once later rather than
570 * probably several times now? Currently yes if it is more than 50% of the
574 tty_large_region(unused
struct tty
*tty
, const struct tty_ctx
*ctx
)
576 struct window_pane
*wp
= ctx
->wp
;
578 return (ctx
->orlower
- ctx
->orupper
>= screen_size_y(wp
->screen
) / 2);
582 * Redraw scroll region using data from screen (already updated). Used when
583 * CSR not supported, or window is a pane that doesn't take up the full
584 * width of the terminal.
587 tty_redraw_region(struct tty
*tty
, const struct tty_ctx
*ctx
)
589 struct window_pane
*wp
= ctx
->wp
;
590 struct screen
*s
= wp
->screen
;
594 * If region is large, schedule a window redraw. In most cases this is
595 * likely to be followed by some more scrolling.
597 if (tty_large_region(tty
, ctx
)) {
598 wp
->flags
|= PANE_REDRAW
;
602 if (ctx
->ocy
< ctx
->orupper
|| ctx
->ocy
> ctx
->orlower
) {
603 for (i
= ctx
->ocy
; i
< screen_size_y(s
); i
++)
604 tty_draw_line(tty
, s
, i
, ctx
->xoff
, ctx
->yoff
);
606 for (i
= ctx
->orupper
; i
<= ctx
->orlower
; i
++)
607 tty_draw_line(tty
, s
, i
, ctx
->xoff
, ctx
->yoff
);
612 tty_draw_line(struct tty
*tty
, struct screen
*s
, u_int py
, u_int ox
, u_int oy
)
614 const struct grid_cell
*gc
;
615 struct grid_line
*gl
;
616 struct grid_cell tmpgc
;
620 tty_update_mode(tty
, tty
->mode
& ~MODE_CURSOR
, s
);
622 sx
= screen_size_x(s
);
623 if (sx
> s
->grid
->linedata
[s
->grid
->hsize
+ py
].cellsize
)
624 sx
= s
->grid
->linedata
[s
->grid
->hsize
+ py
].cellsize
;
629 * Don't move the cursor to the start permission if it will wrap there
634 gl
= &s
->grid
->linedata
[s
->grid
->hsize
+ py
- 1];
635 if (oy
+ py
== 0 || gl
== NULL
|| !(gl
->flags
& GRID_LINE_WRAPPED
) ||
636 tty
->cx
< tty
->sx
|| ox
!= 0 ||
637 (oy
+ py
!= tty
->cy
+ 1 && tty
->cy
!= s
->rlower
+ oy
))
638 tty_cursor(tty
, ox
, oy
+ py
);
640 for (i
= 0; i
< sx
; i
++) {
641 gc
= grid_view_peek_cell(s
->grid
, i
, py
);
642 if (screen_check_selection(s
, i
, py
)) {
643 memcpy(&tmpgc
, &s
->sel
.cell
, sizeof tmpgc
);
644 grid_cell_get(gc
, &ud
);
645 grid_cell_set(&tmpgc
, &ud
);
646 tmpgc
.flags
= gc
->flags
&
647 ~(GRID_FLAG_FG256
|GRID_FLAG_BG256
);
648 tmpgc
.flags
|= s
->sel
.cell
.flags
&
649 (GRID_FLAG_FG256
|GRID_FLAG_BG256
);
650 tty_cell(tty
, &tmpgc
);
656 tty_update_mode(tty
, tty
->mode
, s
);
661 tty_cursor(tty
, ox
+ sx
, oy
+ py
);
662 if (sx
!= screen_size_x(s
) && ox
+ screen_size_x(s
) >= tty
->sx
&&
663 tty_term_has(tty
->term
, TTYC_EL
))
664 tty_putcode(tty
, TTYC_EL
);
666 tty_repeat_space(tty
, screen_size_x(s
) - sx
);
667 tty_update_mode(tty
, tty
->mode
, s
);
672 void (*cmdfn
)(struct tty
*, const struct tty_ctx
*), struct tty_ctx
*ctx
)
674 struct window_pane
*wp
= ctx
->wp
;
678 /* wp can be NULL if updating the screen but not the terminal. */
682 if (wp
->window
->flags
& WINDOW_REDRAW
|| wp
->flags
& PANE_REDRAW
)
684 if (!window_pane_visible(wp
) || wp
->flags
& PANE_DROP
)
687 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
688 c
= ARRAY_ITEM(&clients
, i
);
689 if (c
== NULL
|| c
->session
== NULL
|| c
->tty
.term
== NULL
)
691 if (c
->flags
& CLIENT_SUSPENDED
)
693 if (c
->tty
.flags
& TTY_FREEZE
)
695 if (c
->session
->curw
->window
!= wp
->window
)
698 ctx
->xoff
= wp
->xoff
;
699 ctx
->yoff
= wp
->yoff
;
700 if (status_at_line(c
) == 0)
708 tty_cmd_insertcharacter(struct tty
*tty
, const struct tty_ctx
*ctx
)
710 struct window_pane
*wp
= ctx
->wp
;
712 if (!tty_pane_full_width(tty
, ctx
)) {
713 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, ctx
->xoff
, ctx
->yoff
);
719 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
721 if (tty_term_has(tty
->term
, TTYC_ICH
) ||
722 tty_term_has(tty
->term
, TTYC_ICH1
))
723 tty_emulate_repeat(tty
, TTYC_ICH
, TTYC_ICH1
, ctx
->num
);
725 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, ctx
->xoff
, ctx
->yoff
);
729 tty_cmd_deletecharacter(struct tty
*tty
, const struct tty_ctx
*ctx
)
731 struct window_pane
*wp
= ctx
->wp
;
733 if (!tty_pane_full_width(tty
, ctx
) ||
734 (!tty_term_has(tty
->term
, TTYC_DCH
) &&
735 !tty_term_has(tty
->term
, TTYC_DCH1
))) {
736 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, ctx
->xoff
, ctx
->yoff
);
742 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
744 if (tty_term_has(tty
->term
, TTYC_DCH
) ||
745 tty_term_has(tty
->term
, TTYC_DCH1
))
746 tty_emulate_repeat(tty
, TTYC_DCH
, TTYC_DCH1
, ctx
->num
);
750 tty_cmd_clearcharacter(struct tty
*tty
, const struct tty_ctx
*ctx
)
756 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
758 if (tty_term_has(tty
->term
, TTYC_ECH
))
759 tty_putcode1(tty
, TTYC_ECH
, ctx
->num
);
761 for (i
= 0; i
< ctx
->num
; i
++)
767 tty_cmd_insertline(struct tty
*tty
, const struct tty_ctx
*ctx
)
769 if (!tty_pane_full_width(tty
, ctx
) ||
770 !tty_term_has(tty
->term
, TTYC_CSR
) ||
771 !tty_term_has(tty
->term
, TTYC_IL1
)) {
772 tty_redraw_region(tty
, ctx
);
778 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
779 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
781 tty_emulate_repeat(tty
, TTYC_IL
, TTYC_IL1
, ctx
->num
);
785 tty_cmd_deleteline(struct tty
*tty
, const struct tty_ctx
*ctx
)
787 if (!tty_pane_full_width(tty
, ctx
) ||
788 !tty_term_has(tty
->term
, TTYC_CSR
) ||
789 !tty_term_has(tty
->term
, TTYC_DL1
)) {
790 tty_redraw_region(tty
, ctx
);
796 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
797 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
799 tty_emulate_repeat(tty
, TTYC_DL
, TTYC_DL1
, ctx
->num
);
803 tty_cmd_clearline(struct tty
*tty
, const struct tty_ctx
*ctx
)
805 struct window_pane
*wp
= ctx
->wp
;
806 struct screen
*s
= wp
->screen
;
810 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
);
812 if (tty_pane_full_width(tty
, ctx
) && tty_term_has(tty
->term
, TTYC_EL
))
813 tty_putcode(tty
, TTYC_EL
);
815 tty_repeat_space(tty
, screen_size_x(s
));
819 tty_cmd_clearendofline(struct tty
*tty
, const struct tty_ctx
*ctx
)
821 struct window_pane
*wp
= ctx
->wp
;
822 struct screen
*s
= wp
->screen
;
826 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
828 if (tty_pane_full_width(tty
, ctx
) && tty_term_has(tty
->term
, TTYC_EL
))
829 tty_putcode(tty
, TTYC_EL
);
831 tty_repeat_space(tty
, screen_size_x(s
) - ctx
->ocx
);
835 tty_cmd_clearstartofline(struct tty
*tty
, const struct tty_ctx
*ctx
)
839 if (ctx
->xoff
== 0 && tty_term_has(tty
->term
, TTYC_EL1
)) {
840 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
841 tty_putcode(tty
, TTYC_EL1
);
843 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
);
844 tty_repeat_space(tty
, ctx
->ocx
+ 1);
849 tty_cmd_reverseindex(struct tty
*tty
, const struct tty_ctx
*ctx
)
851 if (ctx
->ocy
!= ctx
->orupper
)
854 if (!tty_pane_full_width(tty
, ctx
) ||
855 !tty_term_has(tty
->term
, TTYC_CSR
) ||
856 !tty_term_has(tty
->term
, TTYC_RI
)) {
857 tty_redraw_region(tty
, ctx
);
863 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
864 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->orupper
);
866 tty_putcode(tty
, TTYC_RI
);
870 tty_cmd_linefeed(struct tty
*tty
, const struct tty_ctx
*ctx
)
872 struct window_pane
*wp
= ctx
->wp
;
874 if (ctx
->ocy
!= ctx
->orlower
)
877 if (!tty_pane_full_width(tty
, ctx
) ||
878 !tty_term_has(tty
->term
, TTYC_CSR
)) {
879 if (tty_large_region(tty
, ctx
))
880 wp
->flags
|= PANE_REDRAW
;
882 tty_redraw_region(tty
, ctx
);
887 * If this line wrapped naturally (ctx->num is nonzero), don't do
888 * anything - the cursor can just be moved to the last cell and wrap
891 if (ctx
->num
&& !(tty
->term
->flags
& TERM_EARLYWRAP
))
896 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
897 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
903 tty_cmd_clearendofscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
905 struct window_pane
*wp
= ctx
->wp
;
906 struct screen
*s
= wp
->screen
;
911 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
912 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
914 if (tty_pane_full_width(tty
, ctx
) && tty_term_has(tty
->term
, TTYC_EL
)) {
915 tty_putcode(tty
, TTYC_EL
);
916 if (ctx
->ocy
!= screen_size_y(s
) - 1) {
917 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
+ 1);
918 for (i
= ctx
->ocy
+ 1; i
< screen_size_y(s
); i
++) {
919 tty_putcode(tty
, TTYC_EL
);
920 if (i
== screen_size_y(s
) - 1)
922 tty_emulate_repeat(tty
, TTYC_CUD
, TTYC_CUD1
, 1);
927 tty_repeat_space(tty
, screen_size_x(s
) - ctx
->ocx
);
928 for (j
= ctx
->ocy
+ 1; j
< screen_size_y(s
); j
++) {
929 tty_cursor_pane(tty
, ctx
, 0, j
);
930 tty_repeat_space(tty
, screen_size_x(s
));
936 tty_cmd_clearstartofscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
938 struct window_pane
*wp
= ctx
->wp
;
939 struct screen
*s
= wp
->screen
;
944 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
945 tty_cursor_pane(tty
, ctx
, 0, 0);
947 if (tty_pane_full_width(tty
, ctx
) && tty_term_has(tty
->term
, TTYC_EL
)) {
948 for (i
= 0; i
< ctx
->ocy
; i
++) {
949 tty_putcode(tty
, TTYC_EL
);
950 tty_emulate_repeat(tty
, TTYC_CUD
, TTYC_CUD1
, 1);
954 for (j
= 0; j
< ctx
->ocy
; j
++) {
955 tty_cursor_pane(tty
, ctx
, 0, j
);
956 tty_repeat_space(tty
, screen_size_x(s
));
959 tty_repeat_space(tty
, ctx
->ocx
+ 1);
963 tty_cmd_clearscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
965 struct window_pane
*wp
= ctx
->wp
;
966 struct screen
*s
= wp
->screen
;
971 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
972 tty_cursor_pane(tty
, ctx
, 0, 0);
974 if (tty_pane_full_width(tty
, ctx
) && tty_term_has(tty
->term
, TTYC_EL
)) {
975 for (i
= 0; i
< screen_size_y(s
); i
++) {
976 tty_putcode(tty
, TTYC_EL
);
977 if (i
!= screen_size_y(s
) - 1) {
978 tty_emulate_repeat(tty
, TTYC_CUD
, TTYC_CUD1
, 1);
983 for (j
= 0; j
< screen_size_y(s
); j
++) {
984 tty_cursor_pane(tty
, ctx
, 0, j
);
985 tty_repeat_space(tty
, screen_size_x(s
));
991 tty_cmd_alignmenttest(struct tty
*tty
, const struct tty_ctx
*ctx
)
993 struct window_pane
*wp
= ctx
->wp
;
994 struct screen
*s
= wp
->screen
;
999 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
1001 for (j
= 0; j
< screen_size_y(s
); j
++) {
1002 tty_cursor_pane(tty
, ctx
, 0, j
);
1003 for (i
= 0; i
< screen_size_x(s
); i
++)
1009 tty_cmd_cell(struct tty
*tty
, const struct tty_ctx
*ctx
)
1011 struct window_pane
*wp
= ctx
->wp
;
1012 struct screen
*s
= wp
->screen
;
1016 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
1018 /* Is the cursor in the very last position? */
1019 width
= grid_cell_width(ctx
->cell
);
1020 if (ctx
->ocx
> wp
->sx
- width
) {
1021 if (ctx
->xoff
!= 0 || wp
->sx
!= tty
->sx
) {
1023 * The pane doesn't fill the entire line, the linefeed
1024 * will already have happened, so just move the cursor.
1026 if (ctx
->ocy
!= wp
->yoff
+ wp
->screen
->rlower
)
1027 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
+ 1);
1029 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
);
1030 } else if (tty
->cx
< tty
->sx
) {
1032 * The cursor isn't in the last position already, so
1033 * move as far left as possible and redraw the last
1034 * cell to move into the last position.
1036 cx
= screen_size_x(s
) - grid_cell_width(&ctx
->last_cell
);
1037 tty_cursor_pane(tty
, ctx
, cx
, ctx
->ocy
);
1038 tty_cell(tty
, &ctx
->last_cell
);
1041 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
1043 tty_cell(tty
, ctx
->cell
);
1047 tty_cmd_utf8character(struct tty
*tty
, const struct tty_ctx
*ctx
)
1049 struct window_pane
*wp
= ctx
->wp
;
1052 * Cannot rely on not being a partial character, so just redraw the
1055 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, ctx
->xoff
, ctx
->yoff
);
1059 tty_cmd_setselection(struct tty
*tty
, const struct tty_ctx
*ctx
)
1064 if (!tty_term_has(tty
->term
, TTYC_MS
))
1067 off
= 4 * ((ctx
->num
+ 2) / 3) + 1; /* storage for base64 */
1070 b64_ntop(ctx
->ptr
, ctx
->num
, buf
, off
);
1071 tty_putcode_ptr2(tty
, TTYC_MS
, "", buf
);
1077 tty_cmd_rawstring(struct tty
*tty
, const struct tty_ctx
*ctx
)
1080 u_char
*str
= ctx
->ptr
;
1082 for (i
= 0; i
< ctx
->num
; i
++)
1083 tty_putc(tty
, str
[i
]);
1085 tty
->cx
= tty
->cy
= UINT_MAX
;
1086 tty
->rupper
= tty
->rlower
= UINT_MAX
;
1089 tty_cursor(tty
, 0, 0);
1093 tty_cell(struct tty
*tty
, const struct grid_cell
*gc
)
1095 struct utf8_data ud
;
1098 /* Skip last character if terminal is stupid. */
1099 if (tty
->term
->flags
& TERM_EARLYWRAP
&&
1100 tty
->cy
== tty
->sy
- 1 && tty
->cx
== tty
->sx
- 1)
1103 /* If this is a padding character, do nothing. */
1104 if (gc
->flags
& GRID_FLAG_PADDING
)
1107 /* Set the attributes. */
1108 tty_attributes(tty
, gc
);
1110 /* Get the cell and if ASCII write with putc to do ACS translation. */
1111 grid_cell_get(gc
, &ud
);
1113 if (*ud
.data
< 0x20 || *ud
.data
== 0x7f)
1115 tty_putc(tty
, *ud
.data
);
1119 /* If not UTF-8, write _. */
1120 if (!(tty
->flags
& TTY_UTF8
)) {
1121 for (i
= 0; i
< ud
.width
; i
++)
1126 /* Write the data. */
1127 tty_putn(tty
, ud
.data
, ud
.size
, ud
.width
);
1131 tty_reset(struct tty
*tty
)
1133 struct grid_cell
*gc
= &tty
->cell
;
1135 if (memcmp(gc
, &grid_default_cell
, sizeof *gc
) == 0)
1138 if ((gc
->attr
& GRID_ATTR_CHARSET
) && tty_use_acs(tty
))
1139 tty_putcode(tty
, TTYC_RMACS
);
1140 tty_putcode(tty
, TTYC_SGR0
);
1141 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
1144 /* Set region inside pane. */
1147 struct tty
*tty
, const struct tty_ctx
*ctx
, u_int rupper
, u_int rlower
)
1149 tty_region(tty
, ctx
->yoff
+ rupper
, ctx
->yoff
+ rlower
);
1152 /* Set region at absolute position. */
1154 tty_region(struct tty
*tty
, u_int rupper
, u_int rlower
)
1156 if (tty
->rlower
== rlower
&& tty
->rupper
== rupper
)
1158 if (!tty_term_has(tty
->term
, TTYC_CSR
))
1161 tty
->rupper
= rupper
;
1162 tty
->rlower
= rlower
;
1165 * Some terminals (such as PuTTY) do not correctly reset the cursor to
1166 * 0,0 if it is beyond the last column (they do not reset their wrap
1167 * flag so further output causes a line feed). As a workaround, do an
1168 * explicit move to 0 first.
1170 if (tty
->cx
>= tty
->sx
)
1171 tty_cursor(tty
, 0, tty
->cy
);
1173 tty_putcode2(tty
, TTYC_CSR
, tty
->rupper
, tty
->rlower
);
1174 tty_cursor(tty
, 0, 0);
1177 /* Move cursor inside pane. */
1179 tty_cursor_pane(struct tty
*tty
, const struct tty_ctx
*ctx
, u_int cx
, u_int cy
)
1181 tty_cursor(tty
, ctx
->xoff
+ cx
, ctx
->yoff
+ cy
);
1184 /* Move cursor to absolute position. */
1186 tty_cursor(struct tty
*tty
, u_int cx
, u_int cy
)
1188 struct tty_term
*term
= tty
->term
;
1192 if (cx
> tty
->sx
- 1)
1199 if (cx
== thisx
&& cy
== thisy
)
1202 /* Very end of the line, just use absolute movement. */
1203 if (thisx
> tty
->sx
- 1)
1206 /* Move to home position (0, 0). */
1207 if (cx
== 0 && cy
== 0 && tty_term_has(term
, TTYC_HOME
)) {
1208 tty_putcode(tty
, TTYC_HOME
);
1212 /* Zero on the next line. */
1213 if (cx
== 0 && cy
== thisy
+ 1 && thisy
!= tty
->rlower
) {
1214 tty_putc(tty
, '\r');
1215 tty_putc(tty
, '\n');
1219 /* Moving column or row. */
1222 * Moving column only, row staying the same.
1227 tty_putc(tty
, '\r');
1231 /* One to the left. */
1232 if (cx
== thisx
- 1 && tty_term_has(term
, TTYC_CUB1
)) {
1233 tty_putcode(tty
, TTYC_CUB1
);
1237 /* One to the right. */
1238 if (cx
== thisx
+ 1 && tty_term_has(term
, TTYC_CUF1
)) {
1239 tty_putcode(tty
, TTYC_CUF1
);
1243 /* Calculate difference. */
1244 change
= thisx
- cx
; /* +ve left, -ve right */
1247 * Use HPA if change is larger than absolute, otherwise move
1248 * the cursor with CUB/CUF.
1250 if ((u_int
) abs(change
) > cx
&& tty_term_has(term
, TTYC_HPA
)) {
1251 tty_putcode1(tty
, TTYC_HPA
, cx
);
1253 } else if (change
> 0 && tty_term_has(term
, TTYC_CUB
)) {
1254 tty_putcode1(tty
, TTYC_CUB
, change
);
1256 } else if (change
< 0 && tty_term_has(term
, TTYC_CUF
)) {
1257 tty_putcode1(tty
, TTYC_CUF
, -change
);
1260 } else if (cx
== thisx
) {
1262 * Moving row only, column staying the same.
1266 if (thisy
!= tty
->rupper
&&
1267 cy
== thisy
- 1 && tty_term_has(term
, TTYC_CUU1
)) {
1268 tty_putcode(tty
, TTYC_CUU1
);
1273 if (thisy
!= tty
->rlower
&&
1274 cy
== thisy
+ 1 && tty_term_has(term
, TTYC_CUD1
)) {
1275 tty_putcode(tty
, TTYC_CUD1
);
1279 /* Calculate difference. */
1280 change
= thisy
- cy
; /* +ve up, -ve down */
1283 * Try to use VPA if change is larger than absolute or if this
1284 * change would cross the scroll region, otherwise use CUU/CUD.
1286 if ((u_int
) abs(change
) > cy
||
1287 (change
< 0 && cy
- change
> tty
->rlower
) ||
1288 (change
> 0 && cy
- change
< tty
->rupper
)) {
1289 if (tty_term_has(term
, TTYC_VPA
)) {
1290 tty_putcode1(tty
, TTYC_VPA
, cy
);
1293 } else if (change
> 0 && tty_term_has(term
, TTYC_CUU
)) {
1294 tty_putcode1(tty
, TTYC_CUU
, change
);
1296 } else if (change
< 0 && tty_term_has(term
, TTYC_CUD
)) {
1297 tty_putcode1(tty
, TTYC_CUD
, -change
);
1303 /* Absolute movement. */
1304 tty_putcode2(tty
, TTYC_CUP
, cy
, cx
);
1312 tty_attributes(struct tty
*tty
, const struct grid_cell
*gc
)
1314 struct grid_cell
*tc
= &tty
->cell
, gc2
;
1317 memcpy(&gc2
, gc
, sizeof gc2
);
1320 * If no setab, try to use the reverse attribute as a best-effort for a
1321 * non-default background. This is a bit of a hack but it doesn't do
1322 * any serious harm and makes a couple of applications happier.
1324 if (!tty_term_has(tty
->term
, TTYC_SETAB
)) {
1325 if (gc2
.attr
& GRID_ATTR_REVERSE
) {
1326 if (gc2
.fg
!= 7 && gc2
.fg
!= 8)
1327 gc2
.attr
&= ~GRID_ATTR_REVERSE
;
1329 if (gc2
.bg
!= 0 && gc2
.bg
!= 8)
1330 gc2
.attr
|= GRID_ATTR_REVERSE
;
1334 /* Fix up the colours if necessary. */
1335 tty_check_fg(tty
, &gc2
);
1336 tty_check_bg(tty
, &gc2
);
1338 /* If any bits are being cleared, reset everything. */
1339 if (tc
->attr
& ~gc2
.attr
)
1343 * Set the colours. This may call tty_reset() (so it comes next) and
1344 * may add to (NOT remove) the desired attributes by changing new_attr.
1346 tty_colours(tty
, &gc2
);
1348 /* Filter out attribute bits already set. */
1349 changed
= gc2
.attr
& ~tc
->attr
;
1350 tc
->attr
= gc2
.attr
;
1352 /* Set the attributes. */
1353 if (changed
& GRID_ATTR_BRIGHT
)
1354 tty_putcode(tty
, TTYC_BOLD
);
1355 if (changed
& GRID_ATTR_DIM
)
1356 tty_putcode(tty
, TTYC_DIM
);
1357 if (changed
& GRID_ATTR_ITALICS
) {
1358 if (tty_term_has(tty
->term
, TTYC_SITM
))
1359 tty_putcode(tty
, TTYC_SITM
);
1361 tty_putcode(tty
, TTYC_SMSO
);
1363 if (changed
& GRID_ATTR_UNDERSCORE
)
1364 tty_putcode(tty
, TTYC_SMUL
);
1365 if (changed
& GRID_ATTR_BLINK
)
1366 tty_putcode(tty
, TTYC_BLINK
);
1367 if (changed
& GRID_ATTR_REVERSE
) {
1368 if (tty_term_has(tty
->term
, TTYC_REV
))
1369 tty_putcode(tty
, TTYC_REV
);
1370 else if (tty_term_has(tty
->term
, TTYC_SMSO
))
1371 tty_putcode(tty
, TTYC_SMSO
);
1373 if (changed
& GRID_ATTR_HIDDEN
)
1374 tty_putcode(tty
, TTYC_INVIS
);
1375 if ((changed
& GRID_ATTR_CHARSET
) && tty_use_acs(tty
))
1376 tty_putcode(tty
, TTYC_SMACS
);
1380 tty_colours(struct tty
*tty
, const struct grid_cell
*gc
)
1382 struct grid_cell
*tc
= &tty
->cell
;
1383 u_char fg
= gc
->fg
, bg
= gc
->bg
, flags
= gc
->flags
;
1384 int have_ax
, fg_default
, bg_default
;
1386 /* No changes? Nothing is necessary. */
1387 if (fg
== tc
->fg
&& bg
== tc
->bg
&&
1388 ((flags
^ tc
->flags
) & (GRID_FLAG_FG256
|GRID_FLAG_BG256
)) == 0)
1392 * Is either the default colour? This is handled specially because the
1393 * best solution might be to reset both colours to default, in which
1394 * case if only one is default need to fall onward to set the other
1397 fg_default
= (fg
== 8 && !(flags
& GRID_FLAG_FG256
));
1398 bg_default
= (bg
== 8 && !(flags
& GRID_FLAG_BG256
));
1399 if (fg_default
|| bg_default
) {
1401 * If don't have AX but do have op, send sgr0 (op can't
1402 * actually be used because it is sometimes the same as sgr0
1403 * and sometimes isn't). This resets both colours to default.
1405 * Otherwise, try to set the default colour only as needed.
1407 have_ax
= tty_term_has(tty
->term
, TTYC_AX
);
1408 if (!have_ax
&& tty_term_has(tty
->term
, TTYC_OP
))
1412 (tc
->fg
!= 8 || tc
->flags
& GRID_FLAG_FG256
)) {
1414 tty_puts(tty
, "\033[39m");
1415 else if (tc
->fg
!= 7 ||
1416 tc
->flags
& GRID_FLAG_FG256
)
1417 tty_putcode1(tty
, TTYC_SETAF
, 7);
1419 tc
->flags
&= ~GRID_FLAG_FG256
;
1422 (tc
->bg
!= 8 || tc
->flags
& GRID_FLAG_BG256
)) {
1424 tty_puts(tty
, "\033[49m");
1425 else if (tc
->bg
!= 0 ||
1426 tc
->flags
& GRID_FLAG_BG256
)
1427 tty_putcode1(tty
, TTYC_SETAB
, 0);
1429 tc
->flags
&= ~GRID_FLAG_BG256
;
1434 /* Set the foreground colour. */
1435 if (!fg_default
&& (fg
!= tc
->fg
||
1436 ((flags
& GRID_FLAG_FG256
) != (tc
->flags
& GRID_FLAG_FG256
))))
1437 tty_colours_fg(tty
, gc
);
1440 * Set the background colour. This must come after the foreground as
1441 * tty_colour_fg() can call tty_reset().
1443 if (!bg_default
&& (bg
!= tc
->bg
||
1444 ((flags
& GRID_FLAG_BG256
) != (tc
->flags
& GRID_FLAG_BG256
))))
1445 tty_colours_bg(tty
, gc
);
1449 tty_check_fg(struct tty
*tty
, struct grid_cell
*gc
)
1453 /* Is this a 256-colour colour? */
1454 if (gc
->flags
& GRID_FLAG_FG256
) {
1455 /* And not a 256 colour mode? */
1456 if (!(tty
->term
->flags
& TERM_256COLOURS
) &&
1457 !(tty
->term_flags
& TERM_256COLOURS
)) {
1458 gc
->fg
= colour_256to16(gc
->fg
);
1461 gc
->attr
|= GRID_ATTR_BRIGHT
;
1463 gc
->attr
&= ~GRID_ATTR_BRIGHT
;
1464 gc
->flags
&= ~GRID_FLAG_FG256
;
1469 /* Is this an aixterm colour? */
1470 colours
= tty_term_number(tty
->term
, TTYC_COLORS
);
1471 if (gc
->fg
>= 90 && gc
->fg
<= 97 && colours
< 16) {
1473 gc
->attr
|= GRID_ATTR_BRIGHT
;
1478 tty_check_bg(struct tty
*tty
, struct grid_cell
*gc
)
1482 /* Is this a 256-colour colour? */
1483 if (gc
->flags
& GRID_FLAG_BG256
) {
1485 * And not a 256 colour mode? Translate to 16-colour
1486 * palette. Bold background doesn't exist portably, so just
1487 * discard the bold bit if set.
1489 if (!(tty
->term
->flags
& TERM_256COLOURS
) &&
1490 !(tty
->term_flags
& TERM_256COLOURS
)) {
1491 gc
->bg
= colour_256to16(gc
->bg
);
1494 gc
->attr
&= ~GRID_ATTR_BRIGHT
;
1495 gc
->flags
&= ~GRID_FLAG_BG256
;
1500 /* Is this an aixterm colour? */
1501 colours
= tty_term_number(tty
->term
, TTYC_COLORS
);
1502 if (gc
->bg
>= 90 && gc
->bg
<= 97 && colours
< 16) {
1504 gc
->attr
|= GRID_ATTR_BRIGHT
;
1509 tty_colours_fg(struct tty
*tty
, const struct grid_cell
*gc
)
1511 struct grid_cell
*tc
= &tty
->cell
;
1515 /* Is this a 256-colour colour? */
1516 if (gc
->flags
& GRID_FLAG_FG256
) {
1517 /* Try as 256 colours. */
1518 if (tty_try_256(tty
, fg
, "38") == 0)
1520 /* Else already handled by tty_check_fg. */
1524 /* Is this an aixterm bright colour? */
1525 if (fg
>= 90 && fg
<= 97) {
1526 xsnprintf(s
, sizeof s
, "\033[%dm", fg
);
1531 /* Otherwise set the foreground colour. */
1532 tty_putcode1(tty
, TTYC_SETAF
, fg
);
1535 /* Save the new values in the terminal current cell. */
1537 tc
->flags
&= ~GRID_FLAG_FG256
;
1538 tc
->flags
|= gc
->flags
& GRID_FLAG_FG256
;
1542 tty_colours_bg(struct tty
*tty
, const struct grid_cell
*gc
)
1544 struct grid_cell
*tc
= &tty
->cell
;
1548 /* Is this a 256-colour colour? */
1549 if (gc
->flags
& GRID_FLAG_BG256
) {
1550 /* Try as 256 colours. */
1551 if (tty_try_256(tty
, bg
, "48") == 0)
1553 /* Else already handled by tty_check_bg. */
1557 /* Is this an aixterm bright colour? */
1558 if (bg
>= 90 && bg
<= 97) {
1559 /* 16 colour terminals or above only. */
1560 if (tty_term_number(tty
->term
, TTYC_COLORS
) >= 16) {
1561 xsnprintf(s
, sizeof s
, "\033[%dm", bg
+ 10);
1566 /* no such thing as a bold background */
1569 /* Otherwise set the background colour. */
1570 tty_putcode1(tty
, TTYC_SETAB
, bg
);
1573 /* Save the new values in the terminal current cell. */
1575 tc
->flags
&= ~GRID_FLAG_BG256
;
1576 tc
->flags
|= gc
->flags
& GRID_FLAG_BG256
;
1580 tty_try_256(struct tty
*tty
, u_char colour
, const char *type
)
1585 * If the terminfo entry has 256 colours, assume that setaf and setab
1588 if (tty
->term
->flags
& TERM_256COLOURS
) {
1590 tty_putcode1(tty
, TTYC_SETAF
, colour
);
1592 tty_putcode1(tty
, TTYC_SETAB
, colour
);
1597 * If the user has specified -2 to the client, setaf and setab may not
1598 * work, so send the usual sequence.
1600 if (tty
->term_flags
& TERM_256COLOURS
) {
1601 xsnprintf(s
, sizeof s
, "\033[%s;5;%hhum", type
, colour
);
1610 tty_bell(struct tty
*tty
)
1612 tty_putcode(tty
, TTYC_BEL
);