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>
31 void tty_read_callback(struct bufferevent
*, void *);
32 void tty_error_callback(struct bufferevent
*, short, void *);
34 int tty_try_256(struct tty
*, u_char
, const char *);
35 int tty_try_88(struct tty
*, u_char
, const char *);
37 void tty_colours(struct tty
*, const struct grid_cell
*);
38 void tty_check_fg(struct tty
*, struct grid_cell
*);
39 void tty_check_bg(struct tty
*, struct grid_cell
*);
40 void tty_colours_fg(struct tty
*, const struct grid_cell
*);
41 void tty_colours_bg(struct tty
*, const struct grid_cell
*);
43 void tty_redraw_region(struct tty
*, const struct tty_ctx
*);
44 void tty_emulate_repeat(
45 struct tty
*, enum tty_code_code
, enum tty_code_code
, u_int
);
46 void tty_cell(struct tty
*,
47 const struct grid_cell
*, const struct grid_utf8
*);
49 #define tty_use_acs(tty) \
50 (tty_term_has(tty->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8))
53 tty_init(struct tty
*tty
, int fd
, char *term
)
57 memset(tty
, 0, sizeof *tty
);
60 if (term
== NULL
|| *term
== '\0')
61 tty
->termname
= xstrdup("unknown");
63 tty
->termname
= xstrdup(term
);
66 if ((path
= ttyname(fd
)) == NULL
)
67 fatalx("ttyname failed");
68 tty
->path
= xstrdup(path
);
75 tty_resize(struct tty
*tty
)
80 if (ioctl(tty
->fd
, TIOCGWINSZ
, &ws
) != -1) {
91 if (sx
== tty
->sx
&& sy
== tty
->sy
)
99 tty
->rupper
= UINT_MAX
;
100 tty
->rlower
= UINT_MAX
;
103 * If the terminal has been started, reset the actual scroll region and
104 * cursor position, as this may not have happened.
106 if (tty
->flags
& TTY_STARTED
) {
107 tty_cursor(tty
, 0, 0);
108 tty_region(tty
, 0, tty
->sy
- 1);
115 tty_open(struct tty
*tty
, const char *overrides
, char **cause
)
120 if (debug_level
> 3) {
121 xsnprintf(out
, sizeof out
, "tmux-out-%ld.log", (long) getpid());
122 fd
= open(out
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644);
123 if (fd
!= -1 && fcntl(fd
, F_SETFD
, FD_CLOEXEC
) == -1)
124 fatal("fcntl failed");
128 tty
->term
= tty_term_find(tty
->termname
, tty
->fd
, overrides
, cause
);
129 if (tty
->term
== NULL
) {
133 tty
->flags
|= TTY_OPENED
;
135 tty
->flags
&= ~(TTY_NOCURSOR
|TTY_FREEZE
|TTY_ESCAPE
);
137 tty
->event
= bufferevent_new(
138 tty
->fd
, tty_read_callback
, NULL
, tty_error_callback
, tty
);
149 tty_read_callback(unused
struct bufferevent
*bufev
, void *data
)
151 struct tty
*tty
= data
;
153 while (tty_keys_next(tty
))
160 unused
struct bufferevent
*bufev
, unused
short what
, unused
void *data
)
165 tty_start_tty(struct tty
*tty
)
173 if ((mode
= fcntl(tty
->fd
, F_GETFL
)) == -1)
174 fatal("fcntl failed");
175 if (fcntl(tty
->fd
, F_SETFL
, mode
|O_NONBLOCK
) == -1)
176 fatal("fcntl failed");
178 bufferevent_enable(tty
->event
, EV_READ
|EV_WRITE
);
180 if (tcgetattr(tty
->fd
, &tty
->tio
) != 0)
181 fatal("tcgetattr failed");
182 memcpy(&tio
, &tty
->tio
, sizeof tio
);
183 tio
.c_iflag
&= ~(IXON
|IXOFF
|ICRNL
|INLCR
|IGNCR
|IMAXBEL
|ISTRIP
);
184 tio
.c_iflag
|= IGNBRK
;
185 tio
.c_oflag
&= ~(OPOST
|ONLCR
|OCRNL
|ONLRET
);
186 tio
.c_lflag
&= ~(IEXTEN
|ICANON
|ECHO
|ECHOE
|ECHONL
|ECHOCTL
|
187 ECHOPRT
|ECHOKE
|ECHOCTL
|ISIG
);
190 if (tcsetattr(tty
->fd
, TCSANOW
, &tio
) != 0)
191 fatal("tcsetattr failed");
192 tcflush(tty
->fd
, TCIOFLUSH
);
194 tty_putcode(tty
, TTYC_SMCUP
);
196 tty_putcode(tty
, TTYC_SGR0
);
197 memcpy(&tty
->cell
, &grid_default_cell
, sizeof tty
->cell
);
199 tty_putcode(tty
, TTYC_RMKX
);
200 if (tty_use_acs(tty
))
201 tty_putcode(tty
, TTYC_ENACS
);
202 tty_putcode(tty
, TTYC_CLEAR
);
204 tty_putcode(tty
, TTYC_CNORM
);
205 if (tty_term_has(tty
->term
, TTYC_KMOUS
))
206 tty_puts(tty
, "\033[?1000l");
211 tty
->rlower
= UINT_MAX
;
212 tty
->rupper
= UINT_MAX
;
214 tty
->mode
= MODE_CURSOR
;
216 tty
->flags
|= TTY_STARTED
;
220 tty_stop_tty(struct tty
*tty
)
225 if (!(tty
->flags
& TTY_STARTED
))
227 tty
->flags
&= ~TTY_STARTED
;
229 bufferevent_disable(tty
->event
, EV_READ
|EV_WRITE
);
232 * Be flexible about error handling and try not kill the server just
233 * because the fd is invalid. Things like ssh -t can easily leave us
236 if (ioctl(tty
->fd
, TIOCGWINSZ
, &ws
) == -1)
238 if (tcsetattr(tty
->fd
, TCSANOW
, &tty
->tio
) == -1)
241 tty_raw(tty
, tty_term_string2(tty
->term
, TTYC_CSR
, 0, ws
.ws_row
- 1));
242 if (tty_use_acs(tty
))
243 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_RMACS
));
244 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_SGR0
));
245 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_RMKX
));
246 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_CLEAR
));
248 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_CNORM
));
249 if (tty_term_has(tty
->term
, TTYC_KMOUS
))
250 tty_raw(tty
, "\033[?1000l");
252 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_RMCUP
));
254 if ((mode
= fcntl(tty
->fd
, F_GETFL
)) != -1)
255 fcntl(tty
->fd
, F_SETFL
, mode
& ~O_NONBLOCK
);
259 tty_close(struct tty
*tty
)
261 if (tty
->log_fd
!= -1) {
266 evtimer_del(&tty
->key_timer
);
269 if (tty
->flags
& TTY_OPENED
) {
270 bufferevent_free(tty
->event
);
272 tty_term_free(tty
->term
);
275 tty
->flags
&= ~TTY_OPENED
;
285 tty_free(struct tty
*tty
)
289 if (tty
->path
!= NULL
)
291 if (tty
->termname
!= NULL
)
292 xfree(tty
->termname
);
296 tty_raw(struct tty
*tty
, const char *s
)
298 write(tty
->fd
, s
, strlen(s
));
302 tty_putcode(struct tty
*tty
, enum tty_code_code code
)
304 tty_puts(tty
, tty_term_string(tty
->term
, code
));
308 tty_putcode1(struct tty
*tty
, enum tty_code_code code
, int a
)
312 tty_puts(tty
, tty_term_string1(tty
->term
, code
, a
));
316 tty_putcode2(struct tty
*tty
, enum tty_code_code code
, int a
, int b
)
320 tty_puts(tty
, tty_term_string2(tty
->term
, code
, a
, b
));
324 tty_puts(struct tty
*tty
, const char *s
)
328 bufferevent_write(tty
->event
, s
, strlen(s
));
330 if (tty
->log_fd
!= -1)
331 write(tty
->log_fd
, s
, strlen(s
));
335 tty_putc(struct tty
*tty
, u_char ch
)
340 if (tty
->cell
.attr
& GRID_ATTR_CHARSET
) {
341 acs
= tty_acs_get(tty
, ch
);
343 bufferevent_write(tty
->event
, acs
, strlen(acs
));
345 bufferevent_write(tty
->event
, &ch
, 1);
347 bufferevent_write(tty
->event
, &ch
, 1);
349 if (ch
>= 0x20 && ch
!= 0x7f) {
351 if (tty
->term
->flags
& TERM_EARLYWRAP
)
356 if (tty
->cy
!= tty
->rlower
)
362 if (tty
->log_fd
!= -1)
363 write(tty
->log_fd
, &ch
, 1);
367 tty_pututf8(struct tty
*tty
, const struct grid_utf8
*gu
)
371 size
= grid_utf8_size(gu
);
372 bufferevent_write(tty
->event
, gu
->data
, size
);
373 if (tty
->log_fd
!= -1)
374 write(tty
->log_fd
, gu
->data
, size
);
375 tty
->cx
+= gu
->width
;
379 tty_set_title(struct tty
*tty
, const char *title
)
381 if (strstr(tty
->termname
, "xterm") == NULL
&&
382 strstr(tty
->termname
, "rxvt") == NULL
&&
383 strcmp(tty
->termname
, "screen") != 0)
386 tty_puts(tty
, "\033]0;");
387 tty_puts(tty
, title
);
388 tty_putc(tty
, '\007');
392 tty_update_mode(struct tty
*tty
, int mode
)
396 if (tty
->flags
& TTY_NOCURSOR
)
397 mode
&= ~MODE_CURSOR
;
399 changed
= mode
^ tty
->mode
;
400 if (changed
& MODE_CURSOR
) {
401 if (mode
& MODE_CURSOR
)
402 tty_putcode(tty
, TTYC_CNORM
);
404 tty_putcode(tty
, TTYC_CIVIS
);
406 if (changed
& (MODE_MOUSE
|MODE_MOUSEMOTION
)) {
407 if (mode
& MODE_MOUSE
) {
408 if (mode
& MODE_MOUSEMOTION
)
409 tty_puts(tty
, "\033[?1003h");
411 tty_puts(tty
, "\033[?1000h");
413 if (mode
& MODE_MOUSEMOTION
)
414 tty_puts(tty
, "\033[?1003l");
416 tty_puts(tty
, "\033[?1000l");
419 if (changed
& MODE_KKEYPAD
) {
420 if (mode
& MODE_KKEYPAD
)
421 tty_putcode(tty
, TTYC_SMKX
);
423 tty_putcode(tty
, TTYC_RMKX
);
430 struct tty
*tty
, enum tty_code_code code
, enum tty_code_code code1
, u_int n
)
432 if (tty_term_has(tty
->term
, code
))
433 tty_putcode1(tty
, code
, n
);
436 tty_putcode(tty
, code1
);
441 * Redraw scroll region using data from screen (already updated). Used when
442 * CSR not supported, or window is a pane that doesn't take up the full
443 * width of the terminal.
446 tty_redraw_region(struct tty
*tty
, const struct tty_ctx
*ctx
)
448 struct window_pane
*wp
= ctx
->wp
;
449 struct screen
*s
= wp
->screen
;
453 * If region is >= 50% of the screen, just schedule a window redraw. In
454 * most cases, this is likely to be followed by some more scrolling -
455 * without this, the entire pane ends up being redrawn many times which
456 * can be much more data.
458 if (ctx
->orupper
- ctx
->orlower
>= screen_size_y(s
) / 2) {
459 wp
->flags
|= PANE_REDRAW
;
463 if (ctx
->ocy
< ctx
->orupper
|| ctx
->ocy
> ctx
->orlower
) {
464 for (i
= ctx
->ocy
; i
< screen_size_y(s
); i
++)
465 tty_draw_line(tty
, s
, i
, wp
->xoff
, wp
->yoff
);
467 for (i
= ctx
->orupper
; i
<= ctx
->orlower
; i
++)
468 tty_draw_line(tty
, s
, i
, wp
->xoff
, wp
->yoff
);
473 tty_draw_line(struct tty
*tty
, struct screen
*s
, u_int py
, u_int ox
, u_int oy
)
475 const struct grid_cell
*gc
;
476 struct grid_line
*gl
;
477 struct grid_cell tmpgc
;
478 const struct grid_utf8
*gu
;
481 tty_update_mode(tty
, tty
->mode
& ~MODE_CURSOR
);
483 sx
= screen_size_x(s
);
484 if (sx
> s
->grid
->linedata
[s
->grid
->hsize
+ py
].cellsize
)
485 sx
= s
->grid
->linedata
[s
->grid
->hsize
+ py
].cellsize
;
490 * Don't move the cursor to the start permission if it will wrap there
495 gl
= &s
->grid
->linedata
[s
->grid
->hsize
+ py
- 1];
496 if (oy
+ py
== 0 || gl
== NULL
|| !(gl
->flags
& GRID_LINE_WRAPPED
) ||
497 tty
->cx
< tty
->sx
|| ox
!= 0 ||
498 (oy
+ py
!= tty
->cy
+ 1 && tty
->cy
!= s
->rlower
+ oy
))
499 tty_cursor(tty
, ox
, oy
+ py
);
501 for (i
= 0; i
< sx
; i
++) {
502 gc
= grid_view_peek_cell(s
->grid
, i
, py
);
505 if (gc
->flags
& GRID_FLAG_UTF8
)
506 gu
= grid_view_peek_utf8(s
->grid
, i
, py
);
508 if (screen_check_selection(s
, i
, py
)) {
509 memcpy(&tmpgc
, &s
->sel
.cell
, sizeof tmpgc
);
510 tmpgc
.data
= gc
->data
;
511 tmpgc
.flags
= gc
->flags
&
512 ~(GRID_FLAG_FG256
|GRID_FLAG_BG256
);
513 tmpgc
.flags
|= s
->sel
.cell
.flags
&
514 (GRID_FLAG_FG256
|GRID_FLAG_BG256
);
515 tty_cell(tty
, &tmpgc
, gu
);
517 tty_cell(tty
, gc
, gu
);
521 tty_update_mode(tty
, tty
->mode
);
526 tty_cursor(tty
, ox
+ sx
, oy
+ py
);
527 if (screen_size_x(s
) >= tty
->sx
&& tty_term_has(tty
->term
, TTYC_EL
))
528 tty_putcode(tty
, TTYC_EL
);
530 for (i
= sx
; i
< screen_size_x(s
); i
++)
533 tty_update_mode(tty
, tty
->mode
);
537 tty_write(void (*cmdfn
)(
538 struct tty
*, const struct tty_ctx
*), const struct tty_ctx
*ctx
)
540 struct window_pane
*wp
= ctx
->wp
;
544 /* wp can be NULL if updating the screen but not the terminal. */
548 if (wp
->window
->flags
& WINDOW_REDRAW
|| wp
->flags
& PANE_REDRAW
)
550 if (wp
->window
->flags
& WINDOW_HIDDEN
|| !window_pane_visible(wp
))
553 for (i
= 0; i
< ARRAY_LENGTH(&clients
); i
++) {
554 c
= ARRAY_ITEM(&clients
, i
);
555 if (c
== NULL
|| c
->session
== NULL
)
557 if (c
->flags
& CLIENT_SUSPENDED
)
560 if (c
->session
->curw
->window
== wp
->window
) {
561 if (c
->tty
.term
== NULL
)
563 if (c
->tty
.flags
& (TTY_FREEZE
|TTY_BACKOFF
))
571 tty_cmd_insertcharacter(struct tty
*tty
, const struct tty_ctx
*ctx
)
573 struct window_pane
*wp
= ctx
->wp
;
574 struct screen
*s
= wp
->screen
;
577 if (wp
->xoff
!= 0 || screen_size_x(s
) < tty
->sx
) {
578 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, wp
->xoff
, wp
->yoff
);
584 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
586 if (tty_term_has(tty
->term
, TTYC_ICH
) ||
587 tty_term_has(tty
->term
, TTYC_ICH1
))
588 tty_emulate_repeat(tty
, TTYC_ICH
, TTYC_ICH1
, ctx
->num
);
589 else if (tty_term_has(tty
->term
, TTYC_SMIR
) &&
590 tty_term_has(tty
->term
, TTYC_RMIR
)) {
591 tty_putcode(tty
, TTYC_SMIR
);
592 for (i
= 0; i
< ctx
->num
; i
++)
594 tty_putcode(tty
, TTYC_RMIR
);
596 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, wp
->xoff
, wp
->yoff
);
600 tty_cmd_deletecharacter(struct tty
*tty
, const struct tty_ctx
*ctx
)
602 struct window_pane
*wp
= ctx
->wp
;
603 struct screen
*s
= wp
->screen
;
605 if (wp
->xoff
!= 0 || screen_size_x(s
) < tty
->sx
||
606 (!tty_term_has(tty
->term
, TTYC_DCH
) &&
607 !tty_term_has(tty
->term
, TTYC_DCH1
))) {
608 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, wp
->xoff
, wp
->yoff
);
614 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
616 if (tty_term_has(tty
->term
, TTYC_DCH
) ||
617 tty_term_has(tty
->term
, TTYC_DCH1
))
618 tty_emulate_repeat(tty
, TTYC_DCH
, TTYC_DCH1
, ctx
->num
);
622 tty_cmd_insertline(struct tty
*tty
, const struct tty_ctx
*ctx
)
624 struct window_pane
*wp
= ctx
->wp
;
625 struct screen
*s
= wp
->screen
;
627 if (wp
->xoff
!= 0 || screen_size_x(s
) < tty
->sx
||
628 !tty_term_has(tty
->term
, TTYC_CSR
) ||
629 !tty_term_has(tty
->term
, TTYC_IL1
)) {
630 tty_redraw_region(tty
, ctx
);
636 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
637 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
639 tty_emulate_repeat(tty
, TTYC_IL
, TTYC_IL1
, ctx
->num
);
643 tty_cmd_deleteline(struct tty
*tty
, const struct tty_ctx
*ctx
)
645 struct window_pane
*wp
= ctx
->wp
;
646 struct screen
*s
= wp
->screen
;
648 if (wp
->xoff
!= 0 || screen_size_x(s
) < tty
->sx
||
649 !tty_term_has(tty
->term
, TTYC_CSR
) ||
650 !tty_term_has(tty
->term
, TTYC_DL1
)) {
651 tty_redraw_region(tty
, ctx
);
657 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
658 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
660 tty_emulate_repeat(tty
, TTYC_DL
, TTYC_DL1
, ctx
->num
);
664 tty_cmd_clearline(struct tty
*tty
, const struct tty_ctx
*ctx
)
666 struct window_pane
*wp
= ctx
->wp
;
667 struct screen
*s
= wp
->screen
;
672 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
);
674 if (wp
->xoff
== 0 && screen_size_x(s
) >= tty
->sx
&&
675 tty_term_has(tty
->term
, TTYC_EL
)) {
676 tty_putcode(tty
, TTYC_EL
);
678 for (i
= 0; i
< screen_size_x(s
); i
++)
684 tty_cmd_clearendofline(struct tty
*tty
, const struct tty_ctx
*ctx
)
686 struct window_pane
*wp
= ctx
->wp
;
687 struct screen
*s
= wp
->screen
;
692 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
694 if (wp
->xoff
== 0 && screen_size_x(s
) >= tty
->sx
&&
695 tty_term_has(tty
->term
, TTYC_EL
))
696 tty_putcode(tty
, TTYC_EL
);
698 for (i
= ctx
->ocx
; i
< screen_size_x(s
); i
++)
704 tty_cmd_clearstartofline(struct tty
*tty
, const struct tty_ctx
*ctx
)
706 struct window_pane
*wp
= ctx
->wp
;
711 if (wp
->xoff
== 0 && tty_term_has(tty
->term
, TTYC_EL1
)) {
712 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
713 tty_putcode(tty
, TTYC_EL1
);
715 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
);
716 for (i
= 0; i
< ctx
->ocx
+ 1; i
++)
722 tty_cmd_reverseindex(struct tty
*tty
, const struct tty_ctx
*ctx
)
724 struct window_pane
*wp
= ctx
->wp
;
725 struct screen
*s
= wp
->screen
;
727 if (ctx
->ocy
!= ctx
->orupper
)
730 if (wp
->xoff
!= 0 || screen_size_x(s
) < tty
->sx
||
731 !tty_term_has(tty
->term
, TTYC_CSR
) ||
732 !tty_term_has(tty
->term
, TTYC_RI
)) {
733 tty_redraw_region(tty
, ctx
);
739 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
740 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->orupper
);
742 tty_putcode(tty
, TTYC_RI
);
746 tty_cmd_linefeed(struct tty
*tty
, const struct tty_ctx
*ctx
)
748 struct window_pane
*wp
= ctx
->wp
;
749 struct screen
*s
= wp
->screen
;
751 if (ctx
->ocy
!= ctx
->orlower
)
754 if (wp
->xoff
!= 0 || screen_size_x(s
) < tty
->sx
||
755 !tty_term_has(tty
->term
, TTYC_CSR
)) {
756 tty_redraw_region(tty
, ctx
);
761 * If this line wrapped naturally (ctx->num is nonzero), don't do
762 * anything - the cursor can just be moved to the last cell and wrap
765 if (ctx
->num
&& !(tty
->term
->flags
& TERM_EARLYWRAP
))
770 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
771 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
777 tty_cmd_clearendofscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
779 struct window_pane
*wp
= ctx
->wp
;
780 struct screen
*s
= wp
->screen
;
785 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
786 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
788 if (wp
->xoff
== 0 && screen_size_x(s
) >= tty
->sx
&&
789 tty_term_has(tty
->term
, TTYC_EL
)) {
790 tty_putcode(tty
, TTYC_EL
);
791 if (ctx
->ocy
!= screen_size_y(s
) - 1) {
792 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
+ 1);
793 for (i
= ctx
->ocy
+ 1; i
< screen_size_y(s
); i
++) {
794 tty_putcode(tty
, TTYC_EL
);
795 if (i
== screen_size_y(s
) - 1)
797 tty_emulate_repeat(tty
, TTYC_CUD
, TTYC_CUD1
, 1);
802 for (i
= ctx
->ocx
; i
< screen_size_x(s
); i
++)
804 for (j
= ctx
->ocy
+ 1; j
< screen_size_y(s
); j
++) {
805 tty_cursor_pane(tty
, ctx
, 0, j
);
806 for (i
= 0; i
< screen_size_x(s
); i
++)
813 tty_cmd_clearstartofscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
815 struct window_pane
*wp
= ctx
->wp
;
816 struct screen
*s
= wp
->screen
;
821 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
822 tty_cursor_pane(tty
, ctx
, 0, 0);
824 if (wp
->xoff
== 0 && screen_size_x(s
) >= tty
->sx
&&
825 tty_term_has(tty
->term
, TTYC_EL
)) {
826 for (i
= 0; i
< ctx
->ocy
; i
++) {
827 tty_putcode(tty
, TTYC_EL
);
828 tty_emulate_repeat(tty
, TTYC_CUD
, TTYC_CUD1
, 1);
832 for (j
= 0; j
< ctx
->ocy
; j
++) {
833 tty_cursor_pane(tty
, ctx
, 0, j
);
834 for (i
= 0; i
< screen_size_x(s
); i
++)
838 for (i
= 0; i
<= ctx
->ocx
; i
++)
843 tty_cmd_clearscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
845 struct window_pane
*wp
= ctx
->wp
;
846 struct screen
*s
= wp
->screen
;
851 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
852 tty_cursor_pane(tty
, ctx
, 0, 0);
854 if (wp
->xoff
== 0 && screen_size_x(s
) >= tty
->sx
&&
855 tty_term_has(tty
->term
, TTYC_EL
)) {
856 for (i
= 0; i
< screen_size_y(s
); i
++) {
857 tty_putcode(tty
, TTYC_EL
);
858 if (i
!= screen_size_y(s
) - 1) {
859 tty_emulate_repeat(tty
, TTYC_CUD
, TTYC_CUD1
, 1);
864 for (j
= 0; j
< screen_size_y(s
); j
++) {
865 tty_cursor_pane(tty
, ctx
, 0, j
);
866 for (i
= 0; i
< screen_size_x(s
); i
++)
873 tty_cmd_alignmenttest(struct tty
*tty
, const struct tty_ctx
*ctx
)
875 struct window_pane
*wp
= ctx
->wp
;
876 struct screen
*s
= wp
->screen
;
881 tty_region_pane(tty
, ctx
, 0, screen_size_y(s
) - 1);
883 for (j
= 0; j
< screen_size_y(s
); j
++) {
884 tty_cursor_pane(tty
, ctx
, 0, j
);
885 for (i
= 0; i
< screen_size_x(s
); i
++)
891 tty_cmd_cell(struct tty
*tty
, const struct tty_ctx
*ctx
)
893 struct window_pane
*wp
= ctx
->wp
;
894 struct screen
*s
= wp
->screen
;
897 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
899 /* Is the cursor in the very last position? */
900 if (ctx
->ocx
> wp
->sx
- ctx
->last_width
) {
901 if (wp
->xoff
!= 0 || wp
->sx
!= tty
->sx
) {
903 * The pane doesn't fill the entire line, the linefeed
904 * will already have happened, so just move the cursor.
906 tty_cursor_pane(tty
, ctx
, 0, ctx
->ocy
+ 1);
907 } else if (tty
->cx
< tty
->sx
) {
909 * The cursor isn't in the last position already, so
910 * move as far left as possinble and redraw the last
911 * cell to move into the last position.
913 cx
= screen_size_x(s
) - ctx
->last_width
;
914 tty_cursor_pane(tty
, ctx
, cx
, ctx
->ocy
);
915 tty_cell(tty
, &ctx
->last_cell
, &ctx
->last_utf8
);
918 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
920 tty_cell(tty
, ctx
->cell
, ctx
->utf8
);
924 tty_cmd_utf8character(struct tty
*tty
, const struct tty_ctx
*ctx
)
926 struct window_pane
*wp
= ctx
->wp
;
929 * Cannot rely on not being a partial character, so just redraw the
932 tty_draw_line(tty
, wp
->screen
, ctx
->ocy
, wp
->xoff
, wp
->yoff
);
937 struct tty
*tty
, const struct grid_cell
*gc
, const struct grid_utf8
*gu
)
941 /* Skip last character if terminal is stupid. */
942 if (tty
->term
->flags
& TERM_EARLYWRAP
&&
943 tty
->cy
== tty
->sy
- 1 && tty
->cx
== tty
->sx
- 1)
946 /* If this is a padding character, do nothing. */
947 if (gc
->flags
& GRID_FLAG_PADDING
)
950 /* Set the attributes. */
951 tty_attributes(tty
, gc
);
953 /* If not UTF-8, write directly. */
954 if (!(gc
->flags
& GRID_FLAG_UTF8
)) {
955 if (gc
->data
< 0x20 || gc
->data
== 0x7f)
957 tty_putc(tty
, gc
->data
);
961 /* If the terminal doesn't support UTF-8, write underscores. */
962 if (!(tty
->flags
& TTY_UTF8
)) {
963 for (i
= 0; i
< gu
->width
; i
++)
968 /* Otherwise, write UTF-8. */
969 tty_pututf8(tty
, gu
);
973 tty_reset(struct tty
*tty
)
975 struct grid_cell
*gc
= &tty
->cell
;
977 if (memcmp(gc
, &grid_default_cell
, sizeof *gc
) == 0)
980 if ((gc
->attr
& GRID_ATTR_CHARSET
) && tty_use_acs(tty
))
981 tty_putcode(tty
, TTYC_RMACS
);
982 tty_putcode(tty
, TTYC_SGR0
);
983 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
986 /* Set region inside pane. */
989 struct tty
*tty
, const struct tty_ctx
*ctx
, u_int rupper
, u_int rlower
)
991 struct window_pane
*wp
= ctx
->wp
;
993 tty_region(tty
, wp
->yoff
+ rupper
, wp
->yoff
+ rlower
);
996 /* Set region at absolute position. */
998 tty_region(struct tty
*tty
, u_int rupper
, u_int rlower
)
1000 if (tty
->rlower
== rlower
&& tty
->rupper
== rupper
)
1002 if (!tty_term_has(tty
->term
, TTYC_CSR
))
1005 tty
->rupper
= rupper
;
1006 tty
->rlower
= rlower
;
1009 * Some terminals (such as PuTTY) do not correctly reset the cursor to
1010 * 0,0 if it is beyond the last column (they do not reset their wrap
1011 * flag so further output causes a line feed). As a workaround, do an
1012 * explicit move to 0 first.
1014 if (tty
->cx
>= tty
->sx
)
1015 tty_cursor(tty
, 0, tty
->cy
);
1017 tty_putcode2(tty
, TTYC_CSR
, tty
->rupper
, tty
->rlower
);
1018 tty_cursor(tty
, 0, 0);
1021 /* Move cursor inside pane. */
1023 tty_cursor_pane(struct tty
*tty
, const struct tty_ctx
*ctx
, u_int cx
, u_int cy
)
1025 struct window_pane
*wp
= ctx
->wp
;
1027 tty_cursor(tty
, wp
->xoff
+ cx
, wp
->yoff
+ cy
);
1030 /* Move cursor to absolute position. */
1032 tty_cursor(struct tty
*tty
, u_int cx
, u_int cy
)
1034 struct tty_term
*term
= tty
->term
;
1038 if (cx
> tty
->sx
- 1)
1045 if (cx
== thisx
&& cy
== thisy
)
1048 /* Very end of the line, just use absolute movement. */
1049 if (thisx
> tty
->sx
- 1)
1052 /* Move to home position (0, 0). */
1053 if (cx
== 0 && cy
== 0 && tty_term_has(term
, TTYC_HOME
)) {
1054 tty_putcode(tty
, TTYC_HOME
);
1058 /* Zero on the next line. */
1059 if (cx
== 0 && cy
== thisy
+ 1 && thisy
!= tty
->rlower
) {
1060 tty_putc(tty
, '\r');
1061 tty_putc(tty
, '\n');
1065 /* Moving column or row. */
1068 * Moving column only, row staying the same.
1073 tty_putc(tty
, '\r');
1077 /* One to the left. */
1078 if (cx
== thisx
- 1 && tty_term_has(term
, TTYC_CUB1
)) {
1079 tty_putcode(tty
, TTYC_CUB1
);
1083 /* One to the right. */
1084 if (cx
== thisx
+ 1 && tty_term_has(term
, TTYC_CUF1
)) {
1085 tty_putcode(tty
, TTYC_CUF1
);
1089 /* Calculate difference. */
1090 change
= thisx
- cx
; /* +ve left, -ve right */
1093 * Use HPA if change is larger than absolute, otherwise move
1094 * the cursor with CUB/CUF.
1096 if ((u_int
) abs(change
) > cx
&& tty_term_has(term
, TTYC_HPA
)) {
1097 tty_putcode1(tty
, TTYC_HPA
, cx
);
1099 } else if (change
> 0 && tty_term_has(term
, TTYC_CUB
)) {
1100 tty_putcode1(tty
, TTYC_CUB
, change
);
1102 } else if (change
< 0 && tty_term_has(term
, TTYC_CUF
)) {
1103 tty_putcode1(tty
, TTYC_CUF
, -change
);
1106 } else if (cx
== thisx
) {
1108 * Moving row only, column staying the same.
1112 if (thisy
!= tty
->rupper
&&
1113 cy
== thisy
- 1 && tty_term_has(term
, TTYC_CUU1
)) {
1114 tty_putcode(tty
, TTYC_CUU1
);
1119 if (thisy
!= tty
->rlower
&&
1120 cy
== thisy
+ 1 && tty_term_has(term
, TTYC_CUD1
)) {
1121 tty_putcode(tty
, TTYC_CUD1
);
1125 /* Calculate difference. */
1126 change
= thisy
- cy
; /* +ve up, -ve down */
1129 * Try to use VPA if change is larger than absolute or if this
1130 * change would cross the scroll region, otherwise use CUU/CUD.
1132 if ((u_int
) abs(change
) > cy
||
1133 (change
< 0 && cy
- change
> tty
->rlower
) ||
1134 (change
> 0 && cy
- change
< tty
->rupper
)) {
1135 if (tty_term_has(term
, TTYC_VPA
)) {
1136 tty_putcode1(tty
, TTYC_VPA
, cy
);
1139 } else if (change
> 0 && tty_term_has(term
, TTYC_CUU
)) {
1140 tty_putcode1(tty
, TTYC_CUU
, change
);
1142 } else if (change
< 0 && tty_term_has(term
, TTYC_CUD
)) {
1143 tty_putcode1(tty
, TTYC_CUD
, -change
);
1149 /* Absolute movement. */
1150 tty_putcode2(tty
, TTYC_CUP
, cy
, cx
);
1158 tty_attributes(struct tty
*tty
, const struct grid_cell
*gc
)
1160 struct grid_cell
*tc
= &tty
->cell
, gc2
;
1163 memcpy(&gc2
, gc
, sizeof gc2
);
1166 * If no setab, try to use the reverse attribute as a best-effort for a
1167 * non-default background. This is a bit of a hack but it doesn't do
1168 * any serious harm and makes a couple of applications happier.
1170 if (!tty_term_has(tty
->term
, TTYC_SETAB
)) {
1171 if (gc2
.attr
& GRID_ATTR_REVERSE
) {
1172 if (gc2
.fg
!= 7 && gc2
.fg
!= 8)
1173 gc2
.attr
&= ~GRID_ATTR_REVERSE
;
1175 if (gc2
.bg
!= 0 && gc2
.bg
!= 8)
1176 gc2
.attr
|= GRID_ATTR_REVERSE
;
1180 /* Fix up the colours if necessary. */
1181 tty_check_fg(tty
, &gc2
);
1182 tty_check_bg(tty
, &gc2
);
1184 /* If any bits are being cleared, reset everything. */
1185 if (tc
->attr
& ~gc2
.attr
)
1189 * Set the colours. This may call tty_reset() (so it comes next) and
1190 * may add to (NOT remove) the desired attributes by changing new_attr.
1192 tty_colours(tty
, &gc2
);
1194 /* Filter out attribute bits already set. */
1195 changed
= gc2
.attr
& ~tc
->attr
;
1196 tc
->attr
= gc2
.attr
;
1198 /* Set the attributes. */
1199 if (changed
& GRID_ATTR_BRIGHT
)
1200 tty_putcode(tty
, TTYC_BOLD
);
1201 if (changed
& GRID_ATTR_DIM
)
1202 tty_putcode(tty
, TTYC_DIM
);
1203 if (changed
& GRID_ATTR_ITALICS
)
1204 tty_putcode(tty
, TTYC_SMSO
);
1205 if (changed
& GRID_ATTR_UNDERSCORE
)
1206 tty_putcode(tty
, TTYC_SMUL
);
1207 if (changed
& GRID_ATTR_BLINK
)
1208 tty_putcode(tty
, TTYC_BLINK
);
1209 if (changed
& GRID_ATTR_REVERSE
) {
1210 if (tty_term_has(tty
->term
, TTYC_REV
))
1211 tty_putcode(tty
, TTYC_REV
);
1212 else if (tty_term_has(tty
->term
, TTYC_SMSO
))
1213 tty_putcode(tty
, TTYC_SMSO
);
1215 if (changed
& GRID_ATTR_HIDDEN
)
1216 tty_putcode(tty
, TTYC_INVIS
);
1217 if ((changed
& GRID_ATTR_CHARSET
) && tty_use_acs(tty
))
1218 tty_putcode(tty
, TTYC_SMACS
);
1222 tty_colours(struct tty
*tty
, const struct grid_cell
*gc
)
1224 struct grid_cell
*tc
= &tty
->cell
;
1225 u_char fg
= gc
->fg
, bg
= gc
->bg
, flags
= gc
->flags
;
1226 int have_ax
, fg_default
, bg_default
;
1228 /* No changes? Nothing is necessary. */
1229 if (fg
== tc
->fg
&& bg
== tc
->bg
&&
1230 ((flags
^ tc
->flags
) & (GRID_FLAG_FG256
|GRID_FLAG_BG256
)) == 0)
1234 * Is either the default colour? This is handled specially because the
1235 * best solution might be to reset both colours to default, in which
1236 * case if only one is default need to fall onward to set the other
1239 fg_default
= (fg
== 8 && !(flags
& GRID_FLAG_FG256
));
1240 bg_default
= (bg
== 8 && !(flags
& GRID_FLAG_BG256
));
1241 if (fg_default
|| bg_default
) {
1243 * If don't have AX but do have op, send sgr0 (op can't
1244 * actually be used because it is sometimes the same as sgr0
1245 * and sometimes isn't). This resets both colours to default.
1247 * Otherwise, try to set the default colour only as needed.
1249 have_ax
= tty_term_has(tty
->term
, TTYC_AX
);
1250 if (!have_ax
&& tty_term_has(tty
->term
, TTYC_OP
))
1254 (tc
->fg
!= 8 || tc
->flags
& GRID_FLAG_FG256
)) {
1256 tty_puts(tty
, "\033[39m");
1257 else if (tc
->fg
!= 7 ||
1258 tc
->flags
& GRID_FLAG_FG256
)
1259 tty_putcode1(tty
, TTYC_SETAF
, 7);
1261 tc
->flags
&= ~GRID_FLAG_FG256
;
1264 (tc
->bg
!= 8 || tc
->flags
& GRID_FLAG_BG256
)) {
1266 tty_puts(tty
, "\033[49m");
1267 else if (tc
->bg
!= 0 ||
1268 tc
->flags
& GRID_FLAG_BG256
)
1269 tty_putcode1(tty
, TTYC_SETAB
, 0);
1271 tc
->flags
&= ~GRID_FLAG_BG256
;
1276 /* Set the foreground colour. */
1277 if (!fg_default
&& (fg
!= tc
->fg
||
1278 ((flags
& GRID_FLAG_FG256
) != (tc
->flags
& GRID_FLAG_FG256
))))
1279 tty_colours_fg(tty
, gc
);
1282 * Set the background colour. This must come after the foreground as
1283 * tty_colour_fg() can call tty_reset().
1285 if (!bg_default
&& (bg
!= tc
->bg
||
1286 ((flags
& GRID_FLAG_BG256
) != (tc
->flags
& GRID_FLAG_BG256
))))
1287 tty_colours_bg(tty
, gc
);
1291 tty_check_fg(struct tty
*tty
, struct grid_cell
*gc
)
1295 /* Is this a 256-colour colour? */
1296 if (gc
->flags
& GRID_FLAG_FG256
) {
1297 /* And not a 256 colour mode? */
1298 if (!(tty
->term
->flags
& TERM_88COLOURS
) &&
1299 !(tty
->term_flags
& TERM_88COLOURS
) &&
1300 !(tty
->term
->flags
& TERM_256COLOURS
) &&
1301 !(tty
->term_flags
& TERM_256COLOURS
)) {
1302 gc
->fg
= colour_256to16(gc
->fg
);
1305 gc
->attr
|= GRID_ATTR_BRIGHT
;
1307 gc
->attr
&= ~GRID_ATTR_BRIGHT
;
1308 gc
->flags
&= ~GRID_FLAG_FG256
;
1313 /* Is this an aixterm colour? */
1314 colours
= tty_term_number(tty
->term
, TTYC_COLORS
);
1315 if (gc
->fg
>= 90 && gc
->fg
<= 97 && colours
< 16) {
1317 gc
->attr
|= GRID_ATTR_BRIGHT
;
1322 tty_check_bg(struct tty
*tty
, struct grid_cell
*gc
)
1326 /* Is this a 256-colour colour? */
1327 if (gc
->flags
& GRID_FLAG_BG256
) {
1329 * And not a 256 colour mode? Translate to 16-colour
1330 * palette. Bold background doesn't exist portably, so just
1331 * discard the bold bit if set.
1333 if (!(tty
->term
->flags
& TERM_88COLOURS
) &&
1334 !(tty
->term_flags
& TERM_88COLOURS
) &&
1335 !(tty
->term
->flags
& TERM_256COLOURS
) &&
1336 !(tty
->term_flags
& TERM_256COLOURS
)) {
1337 gc
->bg
= colour_256to16(gc
->bg
);
1340 gc
->attr
&= ~GRID_ATTR_BRIGHT
;
1341 gc
->flags
&= ~GRID_FLAG_BG256
;
1346 /* Is this an aixterm colour? */
1347 colours
= tty_term_number(tty
->term
, TTYC_COLORS
);
1348 if (gc
->bg
>= 100 && gc
->bg
<= 107 && colours
< 16) {
1350 gc
->attr
|= GRID_ATTR_BRIGHT
;
1355 tty_colours_fg(struct tty
*tty
, const struct grid_cell
*gc
)
1357 struct grid_cell
*tc
= &tty
->cell
;
1361 /* Is this a 256-colour colour? */
1362 if (gc
->flags
& GRID_FLAG_FG256
) {
1363 /* Try as 256 colours or translating to 88. */
1364 if (tty_try_256(tty
, fg
, "38") == 0)
1366 if (tty_try_88(tty
, fg
, "38") == 0)
1368 /* Else already handled by tty_check_fg. */
1372 /* Is this an aixterm bright colour? */
1373 if (fg
>= 90 && fg
<= 97) {
1374 xsnprintf(s
, sizeof s
, "\033[%dm", fg
);
1379 /* Otherwise set the foreground colour. */
1380 tty_putcode1(tty
, TTYC_SETAF
, fg
);
1383 /* Save the new values in the terminal current cell. */
1385 tc
->flags
&= ~GRID_FLAG_FG256
;
1386 tc
->flags
|= gc
->flags
& GRID_FLAG_FG256
;
1390 tty_colours_bg(struct tty
*tty
, const struct grid_cell
*gc
)
1392 struct grid_cell
*tc
= &tty
->cell
;
1396 /* Is this a 256-colour colour? */
1397 if (gc
->flags
& GRID_FLAG_BG256
) {
1398 /* Try as 256 colours or translating to 88. */
1399 if (tty_try_256(tty
, bg
, "48") == 0)
1401 if (tty_try_88(tty
, bg
, "48") == 0)
1403 /* Else already handled by tty_check_bg. */
1407 /* Is this an aixterm bright colour? */
1408 if (bg
>= 100 && bg
<= 107) {
1409 /* 16 colour terminals or above only. */
1410 if (tty_term_number(tty
->term
, TTYC_COLORS
) >= 16) {
1411 xsnprintf(s
, sizeof s
, "\033[%dm", bg
);
1416 /* no such thing as a bold background */
1419 /* Otherwise set the background colour. */
1420 tty_putcode1(tty
, TTYC_SETAB
, bg
);
1423 /* Save the new values in the terminal current cell. */
1425 tc
->flags
&= ~GRID_FLAG_BG256
;
1426 tc
->flags
|= gc
->flags
& GRID_FLAG_BG256
;
1430 tty_try_256(struct tty
*tty
, u_char colour
, const char *type
)
1434 if (!(tty
->term
->flags
& TERM_256COLOURS
) &&
1435 !(tty
->term_flags
& TERM_256COLOURS
))
1438 xsnprintf(s
, sizeof s
, "\033[%s;5;%hhum", type
, colour
);
1444 tty_try_88(struct tty
*tty
, u_char colour
, const char *type
)
1448 if (!(tty
->term
->flags
& TERM_88COLOURS
) &&
1449 !(tty
->term_flags
& TERM_88COLOURS
))
1451 colour
= colour_256to88(colour
);
1453 xsnprintf(s
, sizeof s
, "\033[%s;5;%hhum", type
, colour
);