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 *);
38 int tty_try_88(struct tty
*, u_char
, const char *);
40 void tty_colours(struct tty
*, const struct grid_cell
*);
41 void tty_check_fg(struct tty
*, struct grid_cell
*);
42 void tty_check_bg(struct tty
*, struct grid_cell
*);
43 void tty_colours_fg(struct tty
*, const struct grid_cell
*);
44 void tty_colours_bg(struct tty
*, const struct grid_cell
*);
46 int tty_large_region(struct tty
*, const struct tty_ctx
*);
47 void tty_redraw_region(struct tty
*, const struct tty_ctx
*);
48 void tty_emulate_repeat(
49 struct tty
*, enum tty_code_code
, enum tty_code_code
, u_int
);
50 void tty_cell(struct tty
*,
51 const struct grid_cell
*, const struct grid_utf8
*);
53 #define tty_use_acs(tty) \
54 (tty_term_has(tty->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8))
57 tty_init(struct tty
*tty
, int fd
, char *term
)
61 memset(tty
, 0, sizeof *tty
);
64 if (term
== NULL
|| *term
== '\0')
65 tty
->termname
= xstrdup("unknown");
67 tty
->termname
= xstrdup(term
);
70 if ((path
= ttyname(fd
)) == NULL
)
71 fatalx("ttyname failed");
72 tty
->path
= xstrdup(path
);
74 tty
->ccolour
= xstrdup("");
81 tty_resize(struct tty
*tty
)
86 if (ioctl(tty
->fd
, TIOCGWINSZ
, &ws
) != -1) {
97 if (!tty_set_size(tty
, sx
, sy
))
103 tty
->rupper
= UINT_MAX
;
104 tty
->rlower
= UINT_MAX
;
107 * If the terminal has been started, reset the actual scroll region and
108 * cursor position, as this may not have happened.
110 if (tty
->flags
& TTY_STARTED
) {
111 tty_cursor(tty
, 0, 0);
112 tty_region(tty
, 0, tty
->sy
- 1);
119 tty_set_size(struct tty
*tty
, u_int sx
, u_int sy
) {
120 if (sx
== tty
->sx
&& sy
== tty
->sy
)
128 tty_open(struct tty
*tty
, const char *overrides
, char **cause
)
133 if (debug_level
> 3) {
134 xsnprintf(out
, sizeof out
, "tmux-out-%ld.log", (long) getpid());
135 fd
= open(out
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644);
136 if (fd
!= -1 && fcntl(fd
, F_SETFD
, FD_CLOEXEC
) == -1)
137 fatal("fcntl failed");
141 tty
->term
= tty_term_find(tty
->termname
, tty
->fd
, overrides
, cause
);
142 if (tty
->term
== NULL
) {
146 tty
->flags
|= TTY_OPENED
;
148 tty
->flags
&= ~(TTY_NOCURSOR
|TTY_FREEZE
|TTY_ESCAPE
);
150 tty
->event
= bufferevent_new(
151 tty
->fd
, tty_read_callback
, NULL
, tty_error_callback
, tty
);
162 tty_read_callback(unused
struct bufferevent
*bufev
, void *data
)
164 struct tty
*tty
= data
;
166 while (tty_keys_next(tty
))
173 unused
struct bufferevent
*bufev
, unused
short what
, unused
void *data
)
178 tty_init_termios(int fd
, struct termios
*orig_tio
, struct bufferevent
*bufev
)
182 if (fd
== -1 || tcgetattr(fd
, orig_tio
) != 0)
188 bufferevent_enable(bufev
, EV_READ
|EV_WRITE
);
190 memcpy(&tio
, orig_tio
, sizeof tio
);
191 tio
.c_iflag
&= ~(IXON
|IXOFF
|ICRNL
|INLCR
|IGNCR
|IMAXBEL
|ISTRIP
);
192 tio
.c_iflag
|= IGNBRK
;
193 tio
.c_oflag
&= ~(OPOST
|ONLCR
|OCRNL
|ONLRET
);
194 tio
.c_lflag
&= ~(IEXTEN
|ICANON
|ECHO
|ECHOE
|ECHONL
|ECHOCTL
|
195 ECHOPRT
|ECHOKE
|ECHOCTL
|ISIG
);
198 if (tcsetattr(fd
, TCSANOW
, &tio
) == 0)
199 tcflush(fd
, TCIOFLUSH
);
203 tty_start_tty(struct tty
*tty
)
205 tty_init_termios(tty
->fd
, &tty
->tio
, tty
->event
);
207 tty_putcode(tty
, TTYC_SMCUP
);
209 tty_putcode(tty
, TTYC_SGR0
);
210 memcpy(&tty
->cell
, &grid_default_cell
, sizeof tty
->cell
);
212 tty_putcode(tty
, TTYC_RMKX
);
213 if (tty_use_acs(tty
))
214 tty_putcode(tty
, TTYC_ENACS
);
215 tty_putcode(tty
, TTYC_CLEAR
);
217 tty_putcode(tty
, TTYC_CNORM
);
218 if (tty_term_has(tty
->term
, TTYC_KMOUS
))
219 tty_puts(tty
, "\033[?1000l");
221 if (tty_term_has(tty
->term
, TTYC_XT
))
222 tty_puts(tty
, "\033[>c");
227 tty
->rlower
= UINT_MAX
;
228 tty
->rupper
= UINT_MAX
;
230 tty
->mode
= MODE_CURSOR
;
232 tty
->flags
|= TTY_STARTED
;
234 tty_force_cursor_colour(tty
, "");
238 tty_set_version(struct tty
*tty
, u_int version
)
240 if (tty
->xterm_version
!= 0)
242 tty
->xterm_version
= version
;
244 if (tty
->xterm_version
> 270) {
245 tty_puts(tty
, "\033[65;1\"p");
247 tty_putcode(tty
, TTYC_RMACS
);
248 memcpy(&tty
->cell
, &grid_default_cell
, sizeof tty
->cell
);
253 tty
->rupper
= UINT_MAX
;
254 tty
->rlower
= UINT_MAX
;
259 tty_stop_tty(struct tty
*tty
)
263 if (!(tty
->flags
& TTY_STARTED
))
265 tty
->flags
&= ~TTY_STARTED
;
267 bufferevent_disable(tty
->event
, EV_READ
|EV_WRITE
);
270 * Be flexible about error handling and try not kill the server just
271 * because the fd is invalid. Things like ssh -t can easily leave us
274 if (ioctl(tty
->fd
, TIOCGWINSZ
, &ws
) == -1)
276 if (tcsetattr(tty
->fd
, TCSANOW
, &tty
->tio
) == -1)
279 setblocking(tty
->fd
, 1);
281 tty_raw(tty
, tty_term_string2(tty
->term
, TTYC_CSR
, 0, ws
.ws_row
- 1));
282 if (tty_use_acs(tty
))
283 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_RMACS
));
284 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_SGR0
));
285 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_RMKX
));
286 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_CLEAR
));
287 if (tty_term_has(tty
->term
, TTYC_CS1
) && tty
->cstyle
!= 0) {
288 if (tty_term_has(tty
->term
, TTYC_CSR1
))
289 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_CSR1
));
291 tty_raw(tty
, tty_term_string1(tty
->term
, TTYC_CS1
, 0));
293 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_CR
));
295 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_CNORM
));
296 if (tty_term_has(tty
->term
, TTYC_KMOUS
))
297 tty_raw(tty
, "\033[?1000l");
299 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_RMCUP
));
301 if (tty
->xterm_version
> 270)
302 tty_raw(tty
, "\033[61;1\"p");
306 tty_close(struct tty
*tty
)
308 if (tty
->log_fd
!= -1) {
313 if (event_initialized(&tty
->key_timer
))
314 evtimer_del(&tty
->key_timer
);
317 if (tty
->flags
& TTY_OPENED
) {
318 bufferevent_free(tty
->event
);
320 tty_term_free(tty
->term
);
323 tty
->flags
&= ~TTY_OPENED
;
333 tty_free(struct tty
*tty
)
338 if (tty
->path
!= NULL
)
340 if (tty
->termname
!= NULL
)
341 xfree(tty
->termname
);
345 tty_raw(struct tty
*tty
, const char *s
)
347 write(tty
->fd
, s
, strlen(s
));
351 tty_putcode(struct tty
*tty
, enum tty_code_code code
)
353 tty_puts(tty
, tty_term_string(tty
->term
, code
));
357 tty_putcode1(struct tty
*tty
, enum tty_code_code code
, int a
)
361 tty_puts(tty
, tty_term_string1(tty
->term
, code
, a
));
365 tty_putcode2(struct tty
*tty
, enum tty_code_code code
, int a
, int b
)
369 tty_puts(tty
, tty_term_string2(tty
->term
, code
, a
, b
));
373 tty_putcode_ptr1(struct tty
*tty
, enum tty_code_code code
, const void *a
)
376 tty_puts(tty
, tty_term_ptr1(tty
->term
, code
, a
));
380 tty_putcode_ptr2(struct tty
*tty
, enum tty_code_code code
, const void *a
, const void *b
)
382 if (a
!= NULL
&& b
!= NULL
)
383 tty_puts(tty
, tty_term_ptr2(tty
->term
, code
, a
, b
));
387 tty_puts(struct tty
*tty
, const char *s
)
391 bufferevent_write(tty
->event
, s
, strlen(s
));
393 if (tty
->log_fd
!= -1)
394 write(tty
->log_fd
, s
, strlen(s
));
398 tty_putc(struct tty
*tty
, u_char ch
)
403 if (tty
->cell
.attr
& GRID_ATTR_CHARSET
) {
404 acs
= tty_acs_get(tty
, ch
);
406 bufferevent_write(tty
->event
, acs
, strlen(acs
));
408 bufferevent_write(tty
->event
, &ch
, 1);
410 bufferevent_write(tty
->event
, &ch
, 1);
412 if (ch
>= 0x20 && ch
!= 0x7f) {
414 if (tty
->term
->flags
& TERM_EARLYWRAP
)
419 if (tty
->cy
!= tty
->rlower
)
425 if (tty
->log_fd
!= -1)
426 write(tty
->log_fd
, &ch
, 1);
430 tty_pututf8(struct tty
*tty
, const struct grid_utf8
*gu
)
434 size
= grid_utf8_size(gu
);
435 bufferevent_write(tty
->event
, gu
->data
, size
);
436 if (tty
->log_fd
!= -1)
437 write(tty
->log_fd
, gu
->data
, size
);
438 tty
->cx
+= gu
->width
;
442 tty_set_title(struct tty
*tty
, const char *title
)
444 if (!tty_term_has(tty
->term
, TTYC_TSL
) ||
445 !tty_term_has(tty
->term
, TTYC_FSL
))
448 tty_putcode(tty
, TTYC_TSL
);
449 tty_puts(tty
, title
);
450 tty_putcode(tty
, TTYC_FSL
);
454 tty_force_cursor_colour(struct tty
*tty
, const char *ccolour
)
456 if (*ccolour
== '\0')
457 tty_putcode(tty
, TTYC_CR
);
459 tty_putcode_ptr1(tty
, TTYC_CC
, ccolour
);
461 tty
->ccolour
= xstrdup(ccolour
);
465 tty_update_mode(struct tty
*tty
, int mode
, struct screen
*s
)
469 if (strcmp(s
->ccolour
, tty
->ccolour
))
470 tty_force_cursor_colour(tty
, s
->ccolour
);
472 if (tty
->flags
& TTY_NOCURSOR
)
473 mode
&= ~MODE_CURSOR
;
475 changed
= mode
^ tty
->mode
;
476 if (changed
& MODE_CURSOR
) {
477 if (mode
& MODE_CURSOR
)
478 tty_putcode(tty
, TTYC_CNORM
);
480 tty_putcode(tty
, TTYC_CIVIS
);
482 if (tty
->cstyle
!= s
->cstyle
) {
483 if (tty_term_has(tty
->term
, TTYC_CS1
)) {
484 if (s
->cstyle
== 0 &&
485 tty_term_has(tty
->term
, TTYC_CSR1
))
486 tty_putcode(tty
, TTYC_CSR1
);
488 tty_putcode1(tty
, TTYC_CS1
, s
->cstyle
);
490 tty
->cstyle
= s
->cstyle
;
492 if (changed
& ALL_MOUSE_MODES
) {
493 if (mode
& ALL_MOUSE_MODES
) {
494 if (mode
& MODE_MOUSE_UTF8
)
495 tty_puts(tty
, "\033[?1005h");
496 if (mode
& MODE_MOUSE_ANY
)
497 tty_puts(tty
, "\033[?1003h");
498 else if (mode
& MODE_MOUSE_BUTTON
)
499 tty_puts(tty
, "\033[?1002h");
500 else if (mode
& MODE_MOUSE_STANDARD
)
501 tty_puts(tty
, "\033[?1000h");
503 if (tty
->mode
& MODE_MOUSE_ANY
)
504 tty_puts(tty
, "\033[?1003l");
505 else if (tty
->mode
& MODE_MOUSE_BUTTON
)
506 tty_puts(tty
, "\033[?1002l");
507 else if (tty
->mode
& MODE_MOUSE_STANDARD
)
508 tty_puts(tty
, "\033[?1000l");
509 if (tty
->mode
& MODE_MOUSE_UTF8
)
510 tty_puts(tty
, "\033[?1005l");
513 if (changed
& MODE_KKEYPAD
) {
514 if (mode
& MODE_KKEYPAD
)
515 tty_putcode(tty
, TTYC_SMKX
);
517 tty_putcode(tty
, TTYC_RMKX
);
519 if (changed
& MODE_BRACKETPASTE
) {
520 if (mode
& MODE_BRACKETPASTE
)
521 tty_puts(tty
, "\033[?2004h");
523 tty_puts(tty
, "\033[?2004l");
530 struct tty
*tty
, enum tty_code_code code
, enum tty_code_code code1
, u_int n
)
532 if (tty_term_has(tty
->term
, code
))
533 tty_putcode1(tty
, code
, n
);
536 tty_putcode(tty
, code1
);
541 * Is the region large enough to be worth redrawing once later rather than
542 * probably several times now? Currently yes if it is more than 50% of the
546 tty_large_region(unused
struct tty
*tty
, const struct tty_ctx
*ctx
)
548 struct window_pane
*wp
= ctx
->wp
;
550 return (ctx
->orlower
- ctx
->orupper
>= screen_size_y(wp
->screen
) / 2);
554 * Redraw scroll region using data from screen (already updated). Used when
555 * CSR not supported, or window is a pane that doesn't take up the full
556 * width of the terminal.
559 tty_redraw_region(struct tty
*tty
, const struct tty_ctx
*ctx
)
561 struct window_pane
*wp
= ctx
->wp
;
562 struct screen
*s
= wp
->screen
;
566 * If region is large, schedule a window redraw. In most cases this is
567 * likely to be followed by some more scrolling.
569 if (tty_large_region(tty
, ctx
)) {
570 wp
->flags
|= PANE_REDRAW
;
574 if (ctx
->ocy
< ctx
->orupper
|| ctx
->ocy
> ctx
->orlower
) {
575 for (i
= ctx
->ocy
; i
< screen_size_y(s
); i
++)
576 tty_draw_line(tty
, s
, i
, ctx
->xoff
, ctx
->yoff
);
578 for (i
= ctx
->orupper
; i
<= ctx
->orlower
; i
++)
579 tty_draw_line(tty
, s
, i
, ctx
->xoff
, ctx
->yoff
);
584 tty_draw_line(struct tty
*tty
, struct screen
*s
, u_int py
, u_int ox
, u_int oy
)
586 const struct grid_cell
*gc
;
587 struct grid_line
*gl
;
588 struct grid_cell tmpgc
;
589 const struct grid_utf8
*gu
;
592 tty_update_mode(tty
, tty
->mode
& ~MODE_CURSOR
, s
);
594 sx
= screen_size_x(s
);
595 if (sx
> s
->grid
->linedata
[s
->grid
->hsize
+ py
].cellsize
)
596 sx
= s
->grid
->linedata
[s
->grid
->hsize
+ py
].cellsize
;
601 * Don't move the cursor to the start permission if it will wrap there
606 gl
= &s
->grid
->linedata
[s
->grid
->hsize
+ py
- 1];
607 if (oy
+ py
== 0 || gl
== NULL
|| !(gl
->flags
& GRID_LINE_WRAPPED
) ||
608 tty
->cx
< tty
->sx
|| ox
!= 0 ||
609 (oy
+ py
!= tty
->cy
+ 1 && tty
->cy
!= s
->rlower
+ oy
))
610 tty_cursor(tty
, ox
, oy
+ py
);
612 for (i
= 0; i
< sx
; i
++) {
613 gc
= grid_view_peek_cell(s
->grid
, i
, py
);
616 if (gc
->flags
& GRID_FLAG_UTF8
)
617 gu
= grid_view_peek_utf8(s
->grid
, i
, py
);
619 if (screen_check_selection(s
, i
, py
)) {
620 memcpy(&tmpgc
, &s
->sel
.cell
, sizeof tmpgc
);
621 tmpgc
.data
= gc
->data
;
622 tmpgc
.flags
= gc
->flags
&
623 ~(GRID_FLAG_FG256
|GRID_FLAG_BG256
);
624 tmpgc
.flags
|= s
->sel
.cell
.flags
&
625 (GRID_FLAG_FG256
|GRID_FLAG_BG256
);
626 tty_cell(tty
, &tmpgc
, gu
);
628 tty_cell(tty
, gc
, gu
);
632 tty_update_mode(tty
, tty
->mode
, s
);
637 tty_cursor(tty
, ox
+ sx
, oy
+ py
);
638 if (sx
!= screen_size_x(s
) && ox
+ screen_size_x(s
) >= tty
->sx
&&
639 tty_term_has(tty
->term
, TTYC_EL
))
640 tty_putcode(tty
, TTYC_EL
);
642 for (i
= sx
; i
< screen_size_x(s
); i
++)
645 tty_update_mode(tty
, tty
->mode
, s
);
650 void (*cmdfn
)(struct tty
*, const struct tty_ctx
*), struct tty_ctx
*ctx
)
652 struct window_pane
*wp
= ctx
->wp
;
658 /* wp can be NULL if updating the screen but not the terminal. */
662 if (wp
->window
->flags
& WINDOW_REDRAW
|| wp
->flags
& PANE_REDRAW
)
664 if (!window_pane_visible(wp
) || wp
->flags
& PANE_DROP
)
667 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
668 c
= ARRAY_ITEM(&clients
, i
);
669 if (c
== NULL
|| c
->session
== NULL
)
671 if (c
->flags
& CLIENT_SUSPENDED
)
675 if (s
->curw
->window
== wp
->window
) {
676 if (c
->tty
.term
== NULL
)
678 if (c
->tty
.flags
& TTY_FREEZE
)
682 ctx
->xoff
= wp
->xoff
;
683 ctx
->yoff
= wp
->yoff
;
684 if (status_at_line(c
) == 0)
693 tty_cmd_insertcharacter(struct tty
*tty
, const struct tty_ctx
*ctx
)
695 struct window_pane
*wp
= ctx
->wp
;
696 struct screen
*s
= wp
->screen
;
699 if (ctx
->xoff
!= 0 || screen_size_x(s
) < tty
->sx
) {
700 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, ctx
->xoff
, ctx
->yoff
);
706 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
708 if (tty_term_has(tty
->term
, TTYC_ICH
) ||
709 tty_term_has(tty
->term
, TTYC_ICH1
))
710 tty_emulate_repeat(tty
, TTYC_ICH
, TTYC_ICH1
, ctx
->num
);
711 else if (tty_term_has(tty
->term
, TTYC_SMIR
) &&
712 tty_term_has(tty
->term
, TTYC_RMIR
)) {
713 tty_putcode(tty
, TTYC_SMIR
);
714 for (i
= 0; i
< ctx
->num
; i
++)
716 tty_putcode(tty
, TTYC_RMIR
);
718 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, ctx
->xoff
, ctx
->yoff
);
722 tty_cmd_deletecharacter(struct tty
*tty
, const struct tty_ctx
*ctx
)
724 struct window_pane
*wp
= ctx
->wp
;
725 struct screen
*s
= wp
->screen
;
727 if (ctx
->xoff
!= 0 || screen_size_x(s
) < tty
->sx
||
728 (!tty_term_has(tty
->term
, TTYC_DCH
) &&
729 !tty_term_has(tty
->term
, TTYC_DCH1
))) {
730 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, ctx
->xoff
, ctx
->yoff
);
736 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
738 if (tty_term_has(tty
->term
, TTYC_DCH
) ||
739 tty_term_has(tty
->term
, TTYC_DCH1
))
740 tty_emulate_repeat(tty
, TTYC_DCH
, TTYC_DCH1
, ctx
->num
);
744 tty_cmd_insertline(struct tty
*tty
, const struct tty_ctx
*ctx
)
746 struct window_pane
*wp
= ctx
->wp
;
747 struct screen
*s
= wp
->screen
;
749 if (ctx
->xoff
!= 0 || screen_size_x(s
) < tty
->sx
||
750 !tty_term_has(tty
->term
, TTYC_CSR
) ||
751 !tty_term_has(tty
->term
, TTYC_IL1
)) {
752 tty_redraw_region(tty
, ctx
);
758 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
759 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
761 tty_emulate_repeat(tty
, TTYC_IL
, TTYC_IL1
, ctx
->num
);
765 tty_cmd_deleteline(struct tty
*tty
, const struct tty_ctx
*ctx
)
767 struct window_pane
*wp
= ctx
->wp
;
768 struct screen
*s
= wp
->screen
;
770 if (ctx
->xoff
!= 0 || screen_size_x(s
) < tty
->sx
||
771 !tty_term_has(tty
->term
, TTYC_CSR
) ||
772 !tty_term_has(tty
->term
, TTYC_DL1
)) {
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_DL
, TTYC_DL1
, ctx
->num
);
786 tty_cmd_clearline(struct tty
*tty
, const struct tty_ctx
*ctx
)
788 struct window_pane
*wp
= ctx
->wp
;
789 struct screen
*s
= wp
->screen
;
794 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
);
796 if (ctx
->xoff
== 0 && screen_size_x(s
) >= tty
->sx
&&
797 tty_term_has(tty
->term
, TTYC_EL
)) {
798 tty_putcode(tty
, TTYC_EL
);
800 for (i
= 0; i
< screen_size_x(s
); i
++)
806 tty_cmd_clearendofline(struct tty
*tty
, const struct tty_ctx
*ctx
)
808 struct window_pane
*wp
= ctx
->wp
;
809 struct screen
*s
= wp
->screen
;
814 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
816 if (ctx
->xoff
== 0 && screen_size_x(s
) >= tty
->sx
&&
817 tty_term_has(tty
->term
, TTYC_EL
))
818 tty_putcode(tty
, TTYC_EL
);
820 for (i
= ctx
->ocx
; i
< screen_size_x(s
); i
++)
826 tty_cmd_clearstartofline(struct tty
*tty
, const struct tty_ctx
*ctx
)
832 if (ctx
->xoff
== 0 && tty_term_has(tty
->term
, TTYC_EL1
)) {
833 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
834 tty_putcode(tty
, TTYC_EL1
);
836 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
);
837 for (i
= 0; i
< ctx
->ocx
+ 1; i
++)
843 tty_cmd_reverseindex(struct tty
*tty
, const struct tty_ctx
*ctx
)
845 struct window_pane
*wp
= ctx
->wp
;
846 struct screen
*s
= wp
->screen
;
848 if (ctx
->ocy
!= ctx
->orupper
)
851 if (ctx
->xoff
!= 0 || screen_size_x(s
) < tty
->sx
||
852 !tty_term_has(tty
->term
, TTYC_CSR
) ||
853 !tty_term_has(tty
->term
, TTYC_RI
)) {
854 tty_redraw_region(tty
, ctx
);
860 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
861 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->orupper
);
863 tty_putcode(tty
, TTYC_RI
);
867 tty_cmd_linefeed(struct tty
*tty
, const struct tty_ctx
*ctx
)
869 struct window_pane
*wp
= ctx
->wp
;
870 struct screen
*s
= wp
->screen
;
873 if (ctx
->ocy
!= ctx
->orlower
)
876 if (ctx
->xoff
!= 0 || screen_size_x(s
) < tty
->sx
||
877 !tty_term_has(tty
->term
, TTYC_CSR
)) {
878 if (tty_large_region(tty
, ctx
))
879 wp
->flags
|= PANE_REDRAW
;
880 else if (tty
->xterm_version
> 270) {
881 snprintf(tmp
, sizeof tmp
,
882 "\033[%u;%u;%u;%u;1;%u;%u;1$v",
883 ctx
->yoff
+ ctx
->orupper
+ 2,
885 ctx
->yoff
+ ctx
->orlower
+ 1,
886 ctx
->xoff
+ screen_size_x(s
),
887 ctx
->yoff
+ ctx
->orupper
+ 1,
890 tty_cmd_clearline(tty
, ctx
);
892 tty_redraw_region(tty
, ctx
);
897 * If this line wrapped naturally (ctx->num is nonzero), don't do
898 * anything - the cursor can just be moved to the last cell and wrap
901 if (ctx
->num
&& !(tty
->term
->flags
& TERM_EARLYWRAP
))
906 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
907 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
913 tty_cmd_clearendofscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
915 struct window_pane
*wp
= ctx
->wp
;
916 struct screen
*s
= wp
->screen
;
921 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
922 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
924 if (ctx
->xoff
== 0 && screen_size_x(s
) >= tty
->sx
&&
925 tty_term_has(tty
->term
, TTYC_EL
)) {
926 tty_putcode(tty
, TTYC_EL
);
927 if (ctx
->ocy
!= screen_size_y(s
) - 1) {
928 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
+ 1);
929 for (i
= ctx
->ocy
+ 1; i
< screen_size_y(s
); i
++) {
930 tty_putcode(tty
, TTYC_EL
);
931 if (i
== screen_size_y(s
) - 1)
933 tty_emulate_repeat(tty
, TTYC_CUD
, TTYC_CUD1
, 1);
938 for (i
= ctx
->ocx
; i
< screen_size_x(s
); i
++)
940 for (j
= ctx
->ocy
+ 1; j
< screen_size_y(s
); j
++) {
941 tty_cursor_pane(tty
, ctx
, 0, j
);
942 for (i
= 0; i
< screen_size_x(s
); i
++)
949 tty_cmd_clearstartofscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
951 struct window_pane
*wp
= ctx
->wp
;
952 struct screen
*s
= wp
->screen
;
957 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
958 tty_cursor_pane(tty
, ctx
, 0, 0);
960 if (ctx
->xoff
== 0 && screen_size_x(s
) >= tty
->sx
&&
961 tty_term_has(tty
->term
, TTYC_EL
)) {
962 for (i
= 0; i
< ctx
->ocy
; i
++) {
963 tty_putcode(tty
, TTYC_EL
);
964 tty_emulate_repeat(tty
, TTYC_CUD
, TTYC_CUD1
, 1);
968 for (j
= 0; j
< ctx
->ocy
; j
++) {
969 tty_cursor_pane(tty
, ctx
, 0, j
);
970 for (i
= 0; i
< screen_size_x(s
); i
++)
974 for (i
= 0; i
<= ctx
->ocx
; i
++)
979 tty_cmd_clearscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
981 struct window_pane
*wp
= ctx
->wp
;
982 struct screen
*s
= wp
->screen
;
987 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
988 tty_cursor_pane(tty
, ctx
, 0, 0);
990 if (ctx
->xoff
== 0 && screen_size_x(s
) >= tty
->sx
&&
991 tty_term_has(tty
->term
, TTYC_EL
)) {
992 for (i
= 0; i
< screen_size_y(s
); i
++) {
993 tty_putcode(tty
, TTYC_EL
);
994 if (i
!= screen_size_y(s
) - 1) {
995 tty_emulate_repeat(tty
, TTYC_CUD
, TTYC_CUD1
, 1);
1000 for (j
= 0; j
< screen_size_y(s
); j
++) {
1001 tty_cursor_pane(tty
, ctx
, 0, j
);
1002 for (i
= 0; i
< screen_size_x(s
); i
++)
1009 tty_cmd_alignmenttest(struct tty
*tty
, const struct tty_ctx
*ctx
)
1011 struct window_pane
*wp
= ctx
->wp
;
1012 struct screen
*s
= wp
->screen
;
1017 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
1019 for (j
= 0; j
< screen_size_y(s
); j
++) {
1020 tty_cursor_pane(tty
, ctx
, 0, j
);
1021 for (i
= 0; i
< screen_size_x(s
); i
++)
1027 tty_cmd_cell(struct tty
*tty
, const struct tty_ctx
*ctx
)
1029 struct window_pane
*wp
= ctx
->wp
;
1030 struct screen
*s
= wp
->screen
;
1033 const struct grid_cell
*gc
= ctx
->cell
;
1034 const struct grid_utf8
*gu
= ctx
->utf8
;
1036 if (gc
->flags
& GRID_FLAG_UTF8
)
1041 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
1043 /* Is the cursor in the very last position? */
1044 if (ctx
->ocx
> wp
->sx
- width
) {
1045 if (ctx
->xoff
!= 0 || wp
->sx
!= tty
->sx
) {
1047 * The pane doesn't fill the entire line, the linefeed
1048 * will already have happened, so just move the cursor.
1050 if (ctx
->ocy
!= wp
->yoff
+ wp
->screen
->rlower
)
1051 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
+ 1);
1053 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
);
1054 } else if (tty
->cx
< tty
->sx
) {
1056 * The cursor isn't in the last position already, so
1057 * move as far left as possible and redraw the last
1058 * cell to move into the last position.
1060 if (ctx
->last_cell
.flags
& GRID_FLAG_UTF8
)
1061 cx
= screen_size_x(s
) - ctx
->last_utf8
.width
;
1063 cx
= screen_size_x(s
) - 1;
1064 tty_cursor_pane(tty
, ctx
, cx
, ctx
->ocy
);
1065 tty_cell(tty
, &ctx
->last_cell
, &ctx
->last_utf8
);
1068 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
1070 tty_cell(tty
, ctx
->cell
, ctx
->utf8
);
1074 tty_cmd_utf8character(struct tty
*tty
, const struct tty_ctx
*ctx
)
1076 struct window_pane
*wp
= ctx
->wp
;
1079 * Cannot rely on not being a partial character, so just redraw the
1082 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, ctx
->xoff
, ctx
->yoff
);
1086 tty_cmd_setselection(struct tty
*tty
, const struct tty_ctx
*ctx
)
1091 if (!tty_term_has(tty
->term
, TTYC_MS
))
1094 off
= 4 * ((ctx
->num
+ 2) / 3) + 1; /* storage for base64 */
1097 b64_ntop(ctx
->ptr
, ctx
->num
, buf
, off
);
1098 tty_putcode_ptr2(tty
, TTYC_MS
, "", buf
);
1104 tty_cmd_rawstring(struct tty
*tty
, const struct tty_ctx
*ctx
)
1107 u_char
*str
= ctx
->ptr
;
1109 for (i
= 0; i
< ctx
->num
; i
++)
1110 tty_putc(tty
, str
[i
]);
1115 struct tty
*tty
, const struct grid_cell
*gc
, const struct grid_utf8
*gu
)
1119 /* Skip last character if terminal is stupid. */
1120 if (tty
->term
->flags
& TERM_EARLYWRAP
&&
1121 tty
->cy
== tty
->sy
- 1 && tty
->cx
== tty
->sx
- 1)
1124 /* If this is a padding character, do nothing. */
1125 if (gc
->flags
& GRID_FLAG_PADDING
)
1128 /* Set the attributes. */
1129 tty_attributes(tty
, gc
);
1131 /* If not UTF-8, write directly. */
1132 if (!(gc
->flags
& GRID_FLAG_UTF8
)) {
1133 if (gc
->data
< 0x20 || gc
->data
== 0x7f)
1135 tty_putc(tty
, gc
->data
);
1139 /* If the terminal doesn't support UTF-8, write underscores. */
1140 if (!(tty
->flags
& TTY_UTF8
)) {
1141 for (i
= 0; i
< gu
->width
; i
++)
1146 /* Otherwise, write UTF-8. */
1147 tty_pututf8(tty
, gu
);
1151 tty_reset(struct tty
*tty
)
1153 struct grid_cell
*gc
= &tty
->cell
;
1155 if (memcmp(gc
, &grid_default_cell
, sizeof *gc
) == 0)
1158 if ((gc
->attr
& GRID_ATTR_CHARSET
) && tty_use_acs(tty
))
1159 tty_putcode(tty
, TTYC_RMACS
);
1160 tty_putcode(tty
, TTYC_SGR0
);
1161 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
1164 /* Set region inside pane. */
1167 struct tty
*tty
, const struct tty_ctx
*ctx
, u_int rupper
, u_int rlower
)
1169 tty_region(tty
, ctx
->yoff
+ rupper
, ctx
->yoff
+ rlower
);
1172 /* Set region at absolute position. */
1174 tty_region(struct tty
*tty
, u_int rupper
, u_int rlower
)
1176 if (tty
->rlower
== rlower
&& tty
->rupper
== rupper
)
1178 if (!tty_term_has(tty
->term
, TTYC_CSR
))
1181 tty
->rupper
= rupper
;
1182 tty
->rlower
= rlower
;
1185 * Some terminals (such as PuTTY) do not correctly reset the cursor to
1186 * 0,0 if it is beyond the last column (they do not reset their wrap
1187 * flag so further output causes a line feed). As a workaround, do an
1188 * explicit move to 0 first.
1190 if (tty
->cx
>= tty
->sx
)
1191 tty_cursor(tty
, 0, tty
->cy
);
1193 tty_putcode2(tty
, TTYC_CSR
, tty
->rupper
, tty
->rlower
);
1194 tty_cursor(tty
, 0, 0);
1197 /* Move cursor inside pane. */
1199 tty_cursor_pane(struct tty
*tty
, const struct tty_ctx
*ctx
, u_int cx
, u_int cy
)
1201 tty_cursor(tty
, ctx
->xoff
+ cx
, ctx
->yoff
+ cy
);
1204 /* Move cursor to absolute position. */
1206 tty_cursor(struct tty
*tty
, u_int cx
, u_int cy
)
1208 struct tty_term
*term
= tty
->term
;
1212 if (cx
> tty
->sx
- 1)
1219 if (cx
== thisx
&& cy
== thisy
)
1222 /* Very end of the line, just use absolute movement. */
1223 if (thisx
> tty
->sx
- 1)
1226 /* Move to home position (0, 0). */
1227 if (cx
== 0 && cy
== 0 && tty_term_has(term
, TTYC_HOME
)) {
1228 tty_putcode(tty
, TTYC_HOME
);
1232 /* Zero on the next line. */
1233 if (cx
== 0 && cy
== thisy
+ 1 && thisy
!= tty
->rlower
) {
1234 tty_putc(tty
, '\r');
1235 tty_putc(tty
, '\n');
1239 /* Moving column or row. */
1242 * Moving column only, row staying the same.
1247 tty_putc(tty
, '\r');
1251 /* One to the left. */
1252 if (cx
== thisx
- 1 && tty_term_has(term
, TTYC_CUB1
)) {
1253 tty_putcode(tty
, TTYC_CUB1
);
1257 /* One to the right. */
1258 if (cx
== thisx
+ 1 && tty_term_has(term
, TTYC_CUF1
)) {
1259 tty_putcode(tty
, TTYC_CUF1
);
1263 /* Calculate difference. */
1264 change
= thisx
- cx
; /* +ve left, -ve right */
1267 * Use HPA if change is larger than absolute, otherwise move
1268 * the cursor with CUB/CUF.
1270 if ((u_int
) abs(change
) > cx
&& tty_term_has(term
, TTYC_HPA
)) {
1271 tty_putcode1(tty
, TTYC_HPA
, cx
);
1273 } else if (change
> 0 && tty_term_has(term
, TTYC_CUB
)) {
1274 tty_putcode1(tty
, TTYC_CUB
, change
);
1276 } else if (change
< 0 && tty_term_has(term
, TTYC_CUF
)) {
1277 tty_putcode1(tty
, TTYC_CUF
, -change
);
1280 } else if (cx
== thisx
) {
1282 * Moving row only, column staying the same.
1286 if (thisy
!= tty
->rupper
&&
1287 cy
== thisy
- 1 && tty_term_has(term
, TTYC_CUU1
)) {
1288 tty_putcode(tty
, TTYC_CUU1
);
1293 if (thisy
!= tty
->rlower
&&
1294 cy
== thisy
+ 1 && tty_term_has(term
, TTYC_CUD1
)) {
1295 tty_putcode(tty
, TTYC_CUD1
);
1299 /* Calculate difference. */
1300 change
= thisy
- cy
; /* +ve up, -ve down */
1303 * Try to use VPA if change is larger than absolute or if this
1304 * change would cross the scroll region, otherwise use CUU/CUD.
1306 if ((u_int
) abs(change
) > cy
||
1307 (change
< 0 && cy
- change
> tty
->rlower
) ||
1308 (change
> 0 && cy
- change
< tty
->rupper
)) {
1309 if (tty_term_has(term
, TTYC_VPA
)) {
1310 tty_putcode1(tty
, TTYC_VPA
, cy
);
1313 } else if (change
> 0 && tty_term_has(term
, TTYC_CUU
)) {
1314 tty_putcode1(tty
, TTYC_CUU
, change
);
1316 } else if (change
< 0 && tty_term_has(term
, TTYC_CUD
)) {
1317 tty_putcode1(tty
, TTYC_CUD
, -change
);
1323 /* Absolute movement. */
1324 tty_putcode2(tty
, TTYC_CUP
, cy
, cx
);
1332 tty_attributes(struct tty
*tty
, const struct grid_cell
*gc
)
1334 struct grid_cell
*tc
= &tty
->cell
, gc2
;
1337 memcpy(&gc2
, gc
, sizeof gc2
);
1340 * If no setab, try to use the reverse attribute as a best-effort for a
1341 * non-default background. This is a bit of a hack but it doesn't do
1342 * any serious harm and makes a couple of applications happier.
1344 if (!tty_term_has(tty
->term
, TTYC_SETAB
)) {
1345 if (gc2
.attr
& GRID_ATTR_REVERSE
) {
1346 if (gc2
.fg
!= 7 && gc2
.fg
!= 8)
1347 gc2
.attr
&= ~GRID_ATTR_REVERSE
;
1349 if (gc2
.bg
!= 0 && gc2
.bg
!= 8)
1350 gc2
.attr
|= GRID_ATTR_REVERSE
;
1354 /* Fix up the colours if necessary. */
1355 tty_check_fg(tty
, &gc2
);
1356 tty_check_bg(tty
, &gc2
);
1358 /* If any bits are being cleared, reset everything. */
1359 if (tc
->attr
& ~gc2
.attr
)
1363 * Set the colours. This may call tty_reset() (so it comes next) and
1364 * may add to (NOT remove) the desired attributes by changing new_attr.
1366 tty_colours(tty
, &gc2
);
1368 /* Filter out attribute bits already set. */
1369 changed
= gc2
.attr
& ~tc
->attr
;
1370 tc
->attr
= gc2
.attr
;
1372 /* Set the attributes. */
1373 if (changed
& GRID_ATTR_BRIGHT
)
1374 tty_putcode(tty
, TTYC_BOLD
);
1375 if (changed
& GRID_ATTR_DIM
)
1376 tty_putcode(tty
, TTYC_DIM
);
1377 if (changed
& GRID_ATTR_ITALICS
)
1379 if (tty_term_has(tty
->term
, TTYC_SITM
))
1380 tty_putcode(tty
, TTYC_SITM
);
1382 tty_putcode(tty
, TTYC_SMSO
);
1384 if (changed
& GRID_ATTR_UNDERSCORE
)
1385 tty_putcode(tty
, TTYC_SMUL
);
1386 if (changed
& GRID_ATTR_BLINK
)
1387 tty_putcode(tty
, TTYC_BLINK
);
1388 if (changed
& GRID_ATTR_REVERSE
) {
1389 if (tty_term_has(tty
->term
, TTYC_REV
))
1390 tty_putcode(tty
, TTYC_REV
);
1391 else if (tty_term_has(tty
->term
, TTYC_SMSO
))
1392 tty_putcode(tty
, TTYC_SMSO
);
1394 if (changed
& GRID_ATTR_HIDDEN
)
1395 tty_putcode(tty
, TTYC_INVIS
);
1396 if ((changed
& GRID_ATTR_CHARSET
) && tty_use_acs(tty
))
1397 tty_putcode(tty
, TTYC_SMACS
);
1401 tty_colours(struct tty
*tty
, const struct grid_cell
*gc
)
1403 struct grid_cell
*tc
= &tty
->cell
;
1404 u_char fg
= gc
->fg
, bg
= gc
->bg
, flags
= gc
->flags
;
1405 int have_ax
, fg_default
, bg_default
;
1407 /* No changes? Nothing is necessary. */
1408 if (fg
== tc
->fg
&& bg
== tc
->bg
&&
1409 ((flags
^ tc
->flags
) & (GRID_FLAG_FG256
|GRID_FLAG_BG256
)) == 0)
1413 * Is either the default colour? This is handled specially because the
1414 * best solution might be to reset both colours to default, in which
1415 * case if only one is default need to fall onward to set the other
1418 fg_default
= (fg
== 8 && !(flags
& GRID_FLAG_FG256
));
1419 bg_default
= (bg
== 8 && !(flags
& GRID_FLAG_BG256
));
1420 if (fg_default
|| bg_default
) {
1422 * If don't have AX but do have op, send sgr0 (op can't
1423 * actually be used because it is sometimes the same as sgr0
1424 * and sometimes isn't). This resets both colours to default.
1426 * Otherwise, try to set the default colour only as needed.
1428 have_ax
= tty_term_has(tty
->term
, TTYC_AX
);
1429 if (!have_ax
&& tty_term_has(tty
->term
, TTYC_OP
))
1433 (tc
->fg
!= 8 || tc
->flags
& GRID_FLAG_FG256
)) {
1435 tty_puts(tty
, "\033[39m");
1436 else if (tc
->fg
!= 7 ||
1437 tc
->flags
& GRID_FLAG_FG256
)
1438 tty_putcode1(tty
, TTYC_SETAF
, 7);
1440 tc
->flags
&= ~GRID_FLAG_FG256
;
1443 (tc
->bg
!= 8 || tc
->flags
& GRID_FLAG_BG256
)) {
1445 tty_puts(tty
, "\033[49m");
1446 else if (tc
->bg
!= 0 ||
1447 tc
->flags
& GRID_FLAG_BG256
)
1448 tty_putcode1(tty
, TTYC_SETAB
, 0);
1450 tc
->flags
&= ~GRID_FLAG_BG256
;
1455 /* Set the foreground colour. */
1456 if (!fg_default
&& (fg
!= tc
->fg
||
1457 ((flags
& GRID_FLAG_FG256
) != (tc
->flags
& GRID_FLAG_FG256
))))
1458 tty_colours_fg(tty
, gc
);
1461 * Set the background colour. This must come after the foreground as
1462 * tty_colour_fg() can call tty_reset().
1464 if (!bg_default
&& (bg
!= tc
->bg
||
1465 ((flags
& GRID_FLAG_BG256
) != (tc
->flags
& GRID_FLAG_BG256
))))
1466 tty_colours_bg(tty
, gc
);
1470 tty_check_fg(struct tty
*tty
, struct grid_cell
*gc
)
1474 /* Is this a 256-colour colour? */
1475 if (gc
->flags
& GRID_FLAG_FG256
) {
1476 /* And not a 256 colour mode? */
1477 if (!(tty
->term
->flags
& TERM_88COLOURS
) &&
1478 !(tty
->term_flags
& TERM_88COLOURS
) &&
1479 !(tty
->term
->flags
& TERM_256COLOURS
) &&
1480 !(tty
->term_flags
& TERM_256COLOURS
)) {
1481 gc
->fg
= colour_256to16(gc
->fg
);
1484 gc
->attr
|= GRID_ATTR_BRIGHT
;
1486 gc
->attr
&= ~GRID_ATTR_BRIGHT
;
1487 gc
->flags
&= ~GRID_FLAG_FG256
;
1492 /* Is this an aixterm colour? */
1493 colours
= tty_term_number(tty
->term
, TTYC_COLORS
);
1494 if (gc
->fg
>= 90 && gc
->fg
<= 97 && colours
< 16) {
1496 gc
->attr
|= GRID_ATTR_BRIGHT
;
1501 tty_check_bg(struct tty
*tty
, struct grid_cell
*gc
)
1505 /* Is this a 256-colour colour? */
1506 if (gc
->flags
& GRID_FLAG_BG256
) {
1508 * And not a 256 colour mode? Translate to 16-colour
1509 * palette. Bold background doesn't exist portably, so just
1510 * discard the bold bit if set.
1512 if (!(tty
->term
->flags
& TERM_88COLOURS
) &&
1513 !(tty
->term_flags
& TERM_88COLOURS
) &&
1514 !(tty
->term
->flags
& TERM_256COLOURS
) &&
1515 !(tty
->term_flags
& TERM_256COLOURS
)) {
1516 gc
->bg
= colour_256to16(gc
->bg
);
1519 gc
->attr
&= ~GRID_ATTR_BRIGHT
;
1520 gc
->flags
&= ~GRID_FLAG_BG256
;
1525 /* Is this an aixterm colour? */
1526 colours
= tty_term_number(tty
->term
, TTYC_COLORS
);
1527 if (gc
->bg
>= 90 && gc
->bg
<= 97 && colours
< 16) {
1529 gc
->attr
|= GRID_ATTR_BRIGHT
;
1534 tty_colours_fg(struct tty
*tty
, const struct grid_cell
*gc
)
1536 struct grid_cell
*tc
= &tty
->cell
;
1540 /* Is this a 256-colour colour? */
1541 if (gc
->flags
& GRID_FLAG_FG256
) {
1542 /* Try as 256 colours or translating to 88. */
1543 if (tty_try_256(tty
, fg
, "38") == 0)
1545 if (tty_try_88(tty
, fg
, "38") == 0)
1547 /* Else already handled by tty_check_fg. */
1551 /* Is this an aixterm bright colour? */
1552 if (fg
>= 90 && fg
<= 97) {
1553 xsnprintf(s
, sizeof s
, "\033[%dm", fg
);
1558 /* Otherwise set the foreground colour. */
1559 tty_putcode1(tty
, TTYC_SETAF
, fg
);
1562 /* Save the new values in the terminal current cell. */
1564 tc
->flags
&= ~GRID_FLAG_FG256
;
1565 tc
->flags
|= gc
->flags
& GRID_FLAG_FG256
;
1569 tty_colours_bg(struct tty
*tty
, const struct grid_cell
*gc
)
1571 struct grid_cell
*tc
= &tty
->cell
;
1575 /* Is this a 256-colour colour? */
1576 if (gc
->flags
& GRID_FLAG_BG256
) {
1577 /* Try as 256 colours or translating to 88. */
1578 if (tty_try_256(tty
, bg
, "48") == 0)
1580 if (tty_try_88(tty
, bg
, "48") == 0)
1582 /* Else already handled by tty_check_bg. */
1586 /* Is this an aixterm bright colour? */
1587 if (bg
>= 90 && bg
<= 97) {
1588 /* 16 colour terminals or above only. */
1589 if (tty_term_number(tty
->term
, TTYC_COLORS
) >= 16) {
1590 xsnprintf(s
, sizeof s
, "\033[%dm", bg
+ 10);
1595 /* no such thing as a bold background */
1598 /* Otherwise set the background colour. */
1599 tty_putcode1(tty
, TTYC_SETAB
, bg
);
1602 /* Save the new values in the terminal current cell. */
1604 tc
->flags
&= ~GRID_FLAG_BG256
;
1605 tc
->flags
|= gc
->flags
& GRID_FLAG_BG256
;
1609 tty_try_256(struct tty
*tty
, u_char colour
, const char *type
)
1613 if (!(tty
->term
->flags
& TERM_256COLOURS
) &&
1614 !(tty
->term_flags
& TERM_256COLOURS
))
1617 xsnprintf(s
, sizeof s
, "\033[%s;5;%hhum", type
, colour
);
1623 tty_try_88(struct tty
*tty
, u_char colour
, const char *type
)
1627 if (!(tty
->term
->flags
& TERM_88COLOURS
) &&
1628 !(tty
->term_flags
& TERM_88COLOURS
))
1630 colour
= colour_256to88(colour
);
1632 xsnprintf(s
, sizeof s
, "\033[%s;5;%hhum", type
, colour
);
1638 tty_bell(struct tty
*tty
)
1640 tty_putcode(tty
, TTYC_BEL
);