4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
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>
35 static int tty_log_fd
= -1;
37 static void tty_set_italics(struct tty
*);
38 static int tty_try_colour(struct tty
*, int, const char *);
39 static void tty_force_cursor_colour(struct tty
*, int);
40 static void tty_cursor_pane(struct tty
*, const struct tty_ctx
*, u_int
,
42 static void tty_cursor_pane_unless_wrap(struct tty
*,
43 const struct tty_ctx
*, u_int
, u_int
);
44 static void tty_invalidate(struct tty
*);
45 static void tty_colours(struct tty
*, const struct grid_cell
*);
46 static void tty_check_fg(struct tty
*, struct colour_palette
*,
48 static void tty_check_bg(struct tty
*, struct colour_palette
*,
50 static void tty_check_us(struct tty
*, struct colour_palette
*,
52 static void tty_colours_fg(struct tty
*, const struct grid_cell
*);
53 static void tty_colours_bg(struct tty
*, const struct grid_cell
*);
54 static void tty_colours_us(struct tty
*, const struct grid_cell
*);
56 static void tty_region_pane(struct tty
*, const struct tty_ctx
*, u_int
,
58 static void tty_region(struct tty
*, u_int
, u_int
);
59 static void tty_margin_pane(struct tty
*, const struct tty_ctx
*);
60 static void tty_margin(struct tty
*, u_int
, u_int
);
61 static int tty_large_region(struct tty
*, const struct tty_ctx
*);
62 static int tty_fake_bce(const struct tty
*, const struct grid_cell
*,
64 static void tty_redraw_region(struct tty
*, const struct tty_ctx
*);
65 static void tty_emulate_repeat(struct tty
*, enum tty_code_code
,
66 enum tty_code_code
, u_int
);
67 static void tty_repeat_space(struct tty
*, u_int
);
68 static void tty_draw_pane(struct tty
*, const struct tty_ctx
*, u_int
);
69 static void tty_default_attributes(struct tty
*, const struct grid_cell
*,
70 struct colour_palette
*, u_int
, struct hyperlinks
*);
71 static int tty_check_overlay(struct tty
*, u_int
, u_int
);
72 static void tty_check_overlay_range(struct tty
*, u_int
, u_int
, u_int
,
73 struct overlay_ranges
*);
76 static void tty_write_one(void (*)(struct tty
*, const struct tty_ctx
*),
77 struct client
*, struct tty_ctx
*);
80 #define tty_use_margin(tty) \
81 (tty->term->flags & TERM_DECSLRM)
82 #define tty_full_width(tty, ctx) \
83 ((ctx)->xoff == 0 && (ctx)->sx >= (tty)->sx)
85 #define TTY_BLOCK_INTERVAL (100000 /* 100 milliseconds */)
86 #define TTY_BLOCK_START(tty) (1 + ((tty)->sx * (tty)->sy) * 8)
87 #define TTY_BLOCK_STOP(tty) (1 + ((tty)->sx * (tty)->sy) / 8)
89 #define TTY_QUERY_TIMEOUT 5
90 #define TTY_REQUEST_LIMIT 30
97 xsnprintf(name
, sizeof name
, "tmux-out-%ld.log", (long)getpid());
99 tty_log_fd
= open(name
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644);
100 if (tty_log_fd
!= -1 && fcntl(tty_log_fd
, F_SETFD
, FD_CLOEXEC
) == -1)
101 fatal("fcntl failed");
105 tty_init(struct tty
*tty
, struct client
*c
)
110 memset(tty
, 0, sizeof *tty
);
113 tty
->cstyle
= SCREEN_CURSOR_DEFAULT
;
115 tty
->fg
= tty
->bg
= -1;
117 if (tcgetattr(c
->fd
, &tty
->tio
) != 0)
123 tty_resize(struct tty
*tty
)
125 struct client
*c
= tty
->client
;
127 u_int sx
, sy
, xpixel
, ypixel
;
129 if (ioctl(c
->fd
, TIOCGWINSZ
, &ws
) != -1) {
135 xpixel
= ws
.ws_xpixel
/ sx
;
141 ypixel
= ws
.ws_ypixel
/ sy
;
148 log_debug("%s: %s now %ux%u (%ux%u)", __func__
, c
->name
, sx
, sy
,
150 tty_set_size(tty
, sx
, sy
, xpixel
, ypixel
);
155 tty_set_size(struct tty
*tty
, u_int sx
, u_int sy
, u_int xpixel
, u_int ypixel
)
159 tty
->xpixel
= xpixel
;
160 tty
->ypixel
= ypixel
;
164 tty_read_callback(__unused
int fd
, __unused
short events
, void *data
)
166 struct tty
*tty
= data
;
167 struct client
*c
= tty
->client
;
168 const char *name
= c
->name
;
169 size_t size
= EVBUFFER_LENGTH(tty
->in
);
172 nread
= evbuffer_read(tty
->in
, c
->fd
, -1);
173 if (nread
== 0 || nread
== -1) {
175 log_debug("%s: read closed", name
);
177 log_debug("%s: read error: %s", name
, strerror(errno
));
178 event_del(&tty
->event_in
);
179 server_client_lost(tty
->client
);
182 log_debug("%s: read %d bytes (already %zu)", name
, nread
, size
);
184 while (tty_keys_next(tty
))
189 tty_timer_callback(__unused
int fd
, __unused
short events
, void *data
)
191 struct tty
*tty
= data
;
192 struct client
*c
= tty
->client
;
193 struct timeval tv
= { .tv_usec
= TTY_BLOCK_INTERVAL
};
195 log_debug("%s: %zu discarded", c
->name
, tty
->discarded
);
197 c
->flags
|= CLIENT_ALLREDRAWFLAGS
;
198 c
->discarded
+= tty
->discarded
;
200 if (tty
->discarded
< TTY_BLOCK_STOP(tty
)) {
201 tty
->flags
&= ~TTY_BLOCK
;
206 evtimer_add(&tty
->timer
, &tv
);
210 tty_block_maybe(struct tty
*tty
)
212 struct client
*c
= tty
->client
;
213 size_t size
= EVBUFFER_LENGTH(tty
->out
);
214 struct timeval tv
= { .tv_usec
= TTY_BLOCK_INTERVAL
};
217 tty
->flags
&= ~TTY_NOBLOCK
;
218 else if (tty
->flags
& TTY_NOBLOCK
)
221 if (size
< TTY_BLOCK_START(tty
))
224 if (tty
->flags
& TTY_BLOCK
)
226 tty
->flags
|= TTY_BLOCK
;
228 log_debug("%s: can't keep up, %zu discarded", c
->name
, size
);
230 evbuffer_drain(tty
->out
, size
);
231 c
->discarded
+= size
;
234 evtimer_add(&tty
->timer
, &tv
);
239 tty_write_callback(__unused
int fd
, __unused
short events
, void *data
)
241 struct tty
*tty
= data
;
242 struct client
*c
= tty
->client
;
243 size_t size
= EVBUFFER_LENGTH(tty
->out
);
246 nwrite
= evbuffer_write(tty
->out
, c
->fd
);
249 log_debug("%s: wrote %d bytes (of %zu)", c
->name
, nwrite
, size
);
252 if ((size_t)nwrite
>= c
->redraw
)
256 log_debug("%s: waiting for redraw, %zu bytes left", c
->name
,
258 } else if (tty_block_maybe(tty
))
261 if (EVBUFFER_LENGTH(tty
->out
) != 0)
262 event_add(&tty
->event_out
, NULL
);
266 tty_open(struct tty
*tty
, char **cause
)
268 struct client
*c
= tty
->client
;
270 tty
->term
= tty_term_create(tty
, c
->term_name
, c
->term_caps
,
271 c
->term_ncaps
, &c
->term_features
, cause
);
272 if (tty
->term
== NULL
) {
276 tty
->flags
|= TTY_OPENED
;
278 tty
->flags
&= ~(TTY_NOCURSOR
|TTY_FREEZE
|TTY_BLOCK
|TTY_TIMER
);
280 event_set(&tty
->event_in
, c
->fd
, EV_PERSIST
|EV_READ
,
281 tty_read_callback
, tty
);
282 tty
->in
= evbuffer_new();
284 fatal("out of memory");
286 event_set(&tty
->event_out
, c
->fd
, EV_WRITE
, tty_write_callback
, tty
);
287 tty
->out
= evbuffer_new();
288 if (tty
->out
== NULL
)
289 fatal("out of memory");
291 evtimer_set(&tty
->timer
, tty_timer_callback
, tty
);
300 tty_start_timer_callback(__unused
int fd
, __unused
short events
, void *data
)
302 struct tty
*tty
= data
;
303 struct client
*c
= tty
->client
;
305 log_debug("%s: start timer fired", c
->name
);
306 if ((tty
->flags
& (TTY_HAVEDA
|TTY_HAVEDA2
|TTY_HAVEXDA
)) == 0)
307 tty_update_features(tty
);
308 tty
->flags
|= TTY_ALL_REQUEST_FLAGS
;
312 tty_start_tty(struct tty
*tty
)
314 struct client
*c
= tty
->client
;
316 struct timeval tv
= { .tv_sec
= TTY_QUERY_TIMEOUT
};
318 setblocking(c
->fd
, 0);
319 event_add(&tty
->event_in
, NULL
);
321 memcpy(&tio
, &tty
->tio
, sizeof tio
);
322 tio
.c_iflag
&= ~(IXON
|IXOFF
|ICRNL
|INLCR
|IGNCR
|IMAXBEL
|ISTRIP
);
323 tio
.c_iflag
|= IGNBRK
;
324 tio
.c_oflag
&= ~(OPOST
|ONLCR
|OCRNL
|ONLRET
);
325 tio
.c_lflag
&= ~(IEXTEN
|ICANON
|ECHO
|ECHOE
|ECHONL
|ECHOCTL
|ECHOPRT
|
329 if (tcsetattr(c
->fd
, TCSANOW
, &tio
) == 0)
330 tcflush(c
->fd
, TCOFLUSH
);
332 tty_putcode(tty
, TTYC_SMCUP
);
334 tty_putcode(tty
, TTYC_SMKX
);
335 tty_putcode(tty
, TTYC_CLEAR
);
337 if (tty_acs_needed(tty
)) {
338 log_debug("%s: using capabilities for ACS", c
->name
);
339 tty_putcode(tty
, TTYC_ENACS
);
341 log_debug("%s: using UTF-8 for ACS", c
->name
);
343 tty_putcode(tty
, TTYC_CNORM
);
344 if (tty_term_has(tty
->term
, TTYC_KMOUS
)) {
345 tty_puts(tty
, "\033[?1000l\033[?1002l\033[?1003l");
346 tty_puts(tty
, "\033[?1006l\033[?1005l");
348 if (tty_term_has(tty
->term
, TTYC_ENBP
))
349 tty_putcode(tty
, TTYC_ENBP
);
351 evtimer_set(&tty
->start_timer
, tty_start_timer_callback
, tty
);
352 evtimer_add(&tty
->start_timer
, &tv
);
354 tty
->flags
|= TTY_STARTED
;
357 if (tty
->ccolour
!= -1)
358 tty_force_cursor_colour(tty
, -1);
360 tty
->mouse_drag_flag
= 0;
361 tty
->mouse_drag_update
= NULL
;
362 tty
->mouse_drag_release
= NULL
;
366 tty_send_requests(struct tty
*tty
)
368 if (~tty
->flags
& TTY_STARTED
)
371 if (tty
->term
->flags
& TERM_VT100LIKE
) {
372 if (~tty
->term
->flags
& TTY_HAVEDA
)
373 tty_puts(tty
, "\033[c");
374 if (~tty
->flags
& TTY_HAVEDA2
)
375 tty_puts(tty
, "\033[>c");
376 if (~tty
->flags
& TTY_HAVEXDA
)
377 tty_puts(tty
, "\033[>q");
378 tty_puts(tty
, "\033]10;?\033\\");
379 tty_puts(tty
, "\033]11;?\033\\");
381 tty
->flags
|= TTY_ALL_REQUEST_FLAGS
;
382 tty
->last_requests
= time (NULL
);
386 tty_repeat_requests(struct tty
*tty
)
388 time_t t
= time (NULL
);
390 if (~tty
->flags
& TTY_STARTED
)
393 if (t
- tty
->last_requests
<= TTY_REQUEST_LIMIT
)
395 tty
->last_requests
= t
;
397 if (tty
->term
->flags
& TERM_VT100LIKE
) {
398 tty_puts(tty
, "\033]10;?\033\\");
399 tty_puts(tty
, "\033]11;?\033\\");
404 tty_stop_tty(struct tty
*tty
)
406 struct client
*c
= tty
->client
;
409 if (!(tty
->flags
& TTY_STARTED
))
411 tty
->flags
&= ~TTY_STARTED
;
413 evtimer_del(&tty
->start_timer
);
415 event_del(&tty
->timer
);
416 tty
->flags
&= ~TTY_BLOCK
;
418 event_del(&tty
->event_in
);
419 event_del(&tty
->event_out
);
422 * Be flexible about error handling and try not kill the server just
423 * because the fd is invalid. Things like ssh -t can easily leave us
426 if (ioctl(c
->fd
, TIOCGWINSZ
, &ws
) == -1)
428 if (tcsetattr(c
->fd
, TCSANOW
, &tty
->tio
) == -1)
431 tty_raw(tty
, tty_term_string_ii(tty
->term
, TTYC_CSR
, 0, ws
.ws_row
- 1));
432 if (tty_acs_needed(tty
))
433 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_RMACS
));
434 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_SGR0
));
435 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_RMKX
));
436 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_CLEAR
));
437 if (tty
->cstyle
!= SCREEN_CURSOR_DEFAULT
) {
438 if (tty_term_has(tty
->term
, TTYC_SE
))
439 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_SE
));
440 else if (tty_term_has(tty
->term
, TTYC_SS
))
441 tty_raw(tty
, tty_term_string_i(tty
->term
, TTYC_SS
, 0));
443 if (tty
->ccolour
!= -1)
444 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_CR
));
446 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_CNORM
));
447 if (tty_term_has(tty
->term
, TTYC_KMOUS
)) {
448 tty_raw(tty
, "\033[?1000l\033[?1002l\033[?1003l");
449 tty_raw(tty
, "\033[?1006l\033[?1005l");
451 if (tty_term_has(tty
->term
, TTYC_DSBP
))
452 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_DSBP
));
454 if (tty
->term
->flags
& TERM_VT100LIKE
)
455 tty_raw(tty
, "\033[?7727l");
456 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_DSFCS
));
457 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_DSEKS
));
459 if (tty_use_margin(tty
))
460 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_DSMG
));
461 tty_raw(tty
, tty_term_string(tty
->term
, TTYC_RMCUP
));
463 setblocking(c
->fd
, 1);
467 tty_close(struct tty
*tty
)
469 if (event_initialized(&tty
->key_timer
))
470 evtimer_del(&tty
->key_timer
);
473 if (tty
->flags
& TTY_OPENED
) {
474 evbuffer_free(tty
->in
);
475 event_del(&tty
->event_in
);
476 evbuffer_free(tty
->out
);
477 event_del(&tty
->event_out
);
479 tty_term_free(tty
->term
);
482 tty
->flags
&= ~TTY_OPENED
;
487 tty_free(struct tty
*tty
)
493 tty_update_features(struct tty
*tty
)
495 struct client
*c
= tty
->client
;
497 if (tty_apply_features(tty
->term
, c
->term_features
))
498 tty_term_apply_overrides(tty
->term
);
500 if (tty_use_margin(tty
))
501 tty_putcode(tty
, TTYC_ENMG
);
502 if (options_get_number(global_options
, "extended-keys"))
503 tty_puts(tty
, tty_term_string(tty
->term
, TTYC_ENEKS
));
504 if (options_get_number(global_options
, "focus-events"))
505 tty_puts(tty
, tty_term_string(tty
->term
, TTYC_ENFCS
));
506 if (tty
->term
->flags
& TERM_VT100LIKE
)
507 tty_puts(tty
, "\033[?7727h");
510 * Features might have changed since the first draw during attach. For
511 * example, this happens when DA responses are received.
513 server_redraw_client(c
);
519 tty_raw(struct tty
*tty
, const char *s
)
521 struct client
*c
= tty
->client
;
526 for (i
= 0; i
< 5; i
++) {
527 n
= write(c
->fd
, s
, slen
);
533 } else if (n
== -1 && errno
!= EAGAIN
)
540 tty_putcode(struct tty
*tty
, enum tty_code_code code
)
542 tty_puts(tty
, tty_term_string(tty
->term
, code
));
546 tty_putcode_i(struct tty
*tty
, enum tty_code_code code
, int a
)
550 tty_puts(tty
, tty_term_string_i(tty
->term
, code
, a
));
554 tty_putcode_ii(struct tty
*tty
, enum tty_code_code code
, int a
, int b
)
558 tty_puts(tty
, tty_term_string_ii(tty
->term
, code
, a
, b
));
562 tty_putcode_iii(struct tty
*tty
, enum tty_code_code code
, int a
, int b
, int c
)
564 if (a
< 0 || b
< 0 || c
< 0)
566 tty_puts(tty
, tty_term_string_iii(tty
->term
, code
, a
, b
, c
));
570 tty_putcode_s(struct tty
*tty
, enum tty_code_code code
, const char *a
)
573 tty_puts(tty
, tty_term_string_s(tty
->term
, code
, a
));
577 tty_putcode_ss(struct tty
*tty
, enum tty_code_code code
, const char *a
,
580 if (a
!= NULL
&& b
!= NULL
)
581 tty_puts(tty
, tty_term_string_ss(tty
->term
, code
, a
, b
));
585 tty_add(struct tty
*tty
, const char *buf
, size_t len
)
587 struct client
*c
= tty
->client
;
589 if (tty
->flags
& TTY_BLOCK
) {
590 tty
->discarded
+= len
;
594 evbuffer_add(tty
->out
, buf
, len
);
595 log_debug("%s: %.*s", c
->name
, (int)len
, buf
);
598 if (tty_log_fd
!= -1)
599 write(tty_log_fd
, buf
, len
);
600 if (tty
->flags
& TTY_STARTED
)
601 event_add(&tty
->event_out
, NULL
);
605 tty_puts(struct tty
*tty
, const char *s
)
608 tty_add(tty
, s
, strlen(s
));
612 tty_putc(struct tty
*tty
, u_char ch
)
616 if ((tty
->term
->flags
& TERM_NOAM
) &&
617 ch
>= 0x20 && ch
!= 0x7f &&
618 tty
->cy
== tty
->sy
- 1 &&
619 tty
->cx
+ 1 >= tty
->sx
)
622 if (tty
->cell
.attr
& GRID_ATTR_CHARSET
) {
623 acs
= tty_acs_get(tty
, ch
);
625 tty_add(tty
, acs
, strlen(acs
));
627 tty_add(tty
, &ch
, 1);
629 tty_add(tty
, &ch
, 1);
631 if (ch
>= 0x20 && ch
!= 0x7f) {
632 if (tty
->cx
>= tty
->sx
) {
634 if (tty
->cy
!= tty
->rlower
)
638 * On !am terminals, force the cursor position to where
639 * we think it should be after a line wrap - this means
640 * it works on sensible terminals as well.
642 if (tty
->term
->flags
& TERM_NOAM
)
643 tty_putcode_ii(tty
, TTYC_CUP
, tty
->cy
, tty
->cx
);
650 tty_putn(struct tty
*tty
, const void *buf
, size_t len
, u_int width
)
652 if ((tty
->term
->flags
& TERM_NOAM
) &&
653 tty
->cy
== tty
->sy
- 1 &&
654 tty
->cx
+ len
>= tty
->sx
)
655 len
= tty
->sx
- tty
->cx
- 1;
657 tty_add(tty
, buf
, len
);
658 if (tty
->cx
+ width
> tty
->sx
) {
659 tty
->cx
= (tty
->cx
+ width
) - tty
->sx
;
660 if (tty
->cx
<= tty
->sx
)
663 tty
->cx
= tty
->cy
= UINT_MAX
;
669 tty_set_italics(struct tty
*tty
)
673 if (tty_term_has(tty
->term
, TTYC_SITM
)) {
674 s
= options_get_string(global_options
, "default-terminal");
675 if (strcmp(s
, "screen") != 0 && strncmp(s
, "screen-", 7) != 0) {
676 tty_putcode(tty
, TTYC_SITM
);
680 tty_putcode(tty
, TTYC_SMSO
);
684 tty_set_title(struct tty
*tty
, const char *title
)
686 if (!tty_term_has(tty
->term
, TTYC_TSL
) ||
687 !tty_term_has(tty
->term
, TTYC_FSL
))
690 tty_putcode(tty
, TTYC_TSL
);
691 tty_puts(tty
, title
);
692 tty_putcode(tty
, TTYC_FSL
);
696 tty_set_path(struct tty
*tty
, const char *title
)
698 if (!tty_term_has(tty
->term
, TTYC_SWD
) ||
699 !tty_term_has(tty
->term
, TTYC_FSL
))
702 tty_putcode(tty
, TTYC_SWD
);
703 tty_puts(tty
, title
);
704 tty_putcode(tty
, TTYC_FSL
);
708 tty_force_cursor_colour(struct tty
*tty
, int c
)
714 c
= colour_force_rgb(c
);
715 if (c
== tty
->ccolour
)
718 tty_putcode(tty
, TTYC_CR
);
720 colour_split_rgb(c
, &r
, &g
, &b
);
721 xsnprintf(s
, sizeof s
, "rgb:%02hhx/%02hhx/%02hhx", r
, g
, b
);
722 tty_putcode_s(tty
, TTYC_CS
, s
);
728 tty_update_cursor(struct tty
*tty
, int mode
, struct screen
*s
)
730 enum screen_cursor_style cstyle
;
731 int ccolour
, changed
, cmode
= mode
;
733 /* Set cursor colour if changed. */
735 ccolour
= s
->ccolour
;
736 if (s
->ccolour
== -1)
737 ccolour
= s
->default_ccolour
;
738 tty_force_cursor_colour(tty
, ccolour
);
741 /* If cursor is off, set as invisible. */
742 if (~cmode
& MODE_CURSOR
) {
743 if (tty
->mode
& MODE_CURSOR
)
744 tty_putcode(tty
, TTYC_CIVIS
);
748 /* Check if blinking or very visible flag changed or style changed. */
750 cstyle
= tty
->cstyle
;
753 if (cstyle
== SCREEN_CURSOR_DEFAULT
) {
754 if (~cmode
& MODE_CURSOR_BLINKING_SET
) {
755 if (s
->default_mode
& MODE_CURSOR_BLINKING
)
756 cmode
|= MODE_CURSOR_BLINKING
;
758 cmode
&= ~MODE_CURSOR_BLINKING
;
760 cstyle
= s
->default_cstyle
;
764 /* If nothing changed, do nothing. */
765 changed
= cmode
^ tty
->mode
;
766 if ((changed
& CURSOR_MODES
) == 0 && cstyle
== tty
->cstyle
)
770 * Set cursor style. If an explicit style has been set with DECSCUSR,
771 * set it if supported, otherwise send cvvis for blinking styles.
773 * If no style, has been set (SCREEN_CURSOR_DEFAULT), then send cvvis
774 * if either the blinking or very visible flags are set.
776 tty_putcode(tty
, TTYC_CNORM
);
778 case SCREEN_CURSOR_DEFAULT
:
779 if (tty
->cstyle
!= SCREEN_CURSOR_DEFAULT
) {
780 if (tty_term_has(tty
->term
, TTYC_SE
))
781 tty_putcode(tty
, TTYC_SE
);
783 tty_putcode_i(tty
, TTYC_SS
, 0);
785 if (cmode
& (MODE_CURSOR_BLINKING
|MODE_CURSOR_VERY_VISIBLE
))
786 tty_putcode(tty
, TTYC_CVVIS
);
788 case SCREEN_CURSOR_BLOCK
:
789 if (tty_term_has(tty
->term
, TTYC_SS
)) {
790 if (cmode
& MODE_CURSOR_BLINKING
)
791 tty_putcode_i(tty
, TTYC_SS
, 1);
793 tty_putcode_i(tty
, TTYC_SS
, 2);
794 } else if (cmode
& MODE_CURSOR_BLINKING
)
795 tty_putcode(tty
, TTYC_CVVIS
);
797 case SCREEN_CURSOR_UNDERLINE
:
798 if (tty_term_has(tty
->term
, TTYC_SS
)) {
799 if (cmode
& MODE_CURSOR_BLINKING
)
800 tty_putcode_i(tty
, TTYC_SS
, 3);
802 tty_putcode_i(tty
, TTYC_SS
, 4);
803 } else if (cmode
& MODE_CURSOR_BLINKING
)
804 tty_putcode(tty
, TTYC_CVVIS
);
806 case SCREEN_CURSOR_BAR
:
807 if (tty_term_has(tty
->term
, TTYC_SS
)) {
808 if (cmode
& MODE_CURSOR_BLINKING
)
809 tty_putcode_i(tty
, TTYC_SS
, 5);
811 tty_putcode_i(tty
, TTYC_SS
, 6);
812 } else if (cmode
& MODE_CURSOR_BLINKING
)
813 tty_putcode(tty
, TTYC_CVVIS
);
816 tty
->cstyle
= cstyle
;
821 tty_update_mode(struct tty
*tty
, int mode
, struct screen
*s
)
823 struct tty_term
*term
= tty
->term
;
824 struct client
*c
= tty
->client
;
827 if (tty
->flags
& TTY_NOCURSOR
)
828 mode
&= ~MODE_CURSOR
;
830 if (tty_update_cursor(tty
, mode
, s
) & MODE_CURSOR_BLINKING
)
831 mode
|= MODE_CURSOR_BLINKING
;
833 mode
&= ~MODE_CURSOR_BLINKING
;
835 changed
= mode
^ tty
->mode
;
836 if (log_get_level() != 0 && changed
!= 0) {
837 log_debug("%s: current mode %s", c
->name
,
838 screen_mode_to_string(tty
->mode
));
839 log_debug("%s: setting mode %s", c
->name
,
840 screen_mode_to_string(mode
));
843 if ((changed
& ALL_MOUSE_MODES
) && tty_term_has(term
, TTYC_KMOUS
)) {
845 * If the mouse modes have changed, clear then all and apply
846 * again. There are differences in how terminals track the
849 tty_puts(tty
, "\033[?1006l\033[?1000l\033[?1002l\033[?1003l");
850 if (mode
& ALL_MOUSE_MODES
)
851 tty_puts(tty
, "\033[?1006h");
852 if (mode
& MODE_MOUSE_ALL
)
853 tty_puts(tty
, "\033[?1000h\033[?1002h\033[?1003h");
854 else if (mode
& MODE_MOUSE_BUTTON
)
855 tty_puts(tty
, "\033[?1000h\033[?1002h");
856 else if (mode
& MODE_MOUSE_STANDARD
)
857 tty_puts(tty
, "\033[?1000h");
863 tty_emulate_repeat(struct tty
*tty
, enum tty_code_code code
,
864 enum tty_code_code code1
, u_int n
)
866 if (tty_term_has(tty
->term
, code
))
867 tty_putcode_i(tty
, code
, n
);
870 tty_putcode(tty
, code1
);
875 tty_repeat_space(struct tty
*tty
, u_int n
)
880 memset(s
, ' ', sizeof s
);
882 while (n
> sizeof s
) {
883 tty_putn(tty
, s
, sizeof s
, sizeof s
);
887 tty_putn(tty
, s
, n
, n
);
890 /* Is this window bigger than the terminal? */
892 tty_window_bigger(struct tty
*tty
)
894 struct client
*c
= tty
->client
;
895 struct window
*w
= c
->session
->curw
->window
;
897 return (tty
->sx
< w
->sx
|| tty
->sy
- status_line_size(c
) < w
->sy
);
900 /* What offset should this window be drawn at? */
902 tty_window_offset(struct tty
*tty
, u_int
*ox
, u_int
*oy
, u_int
*sx
, u_int
*sy
)
912 /* What offset should this window be drawn at? */
914 tty_window_offset1(struct tty
*tty
, u_int
*ox
, u_int
*oy
, u_int
*sx
, u_int
*sy
)
916 struct client
*c
= tty
->client
;
917 struct window
*w
= c
->session
->curw
->window
;
918 struct window_pane
*wp
= server_client_get_pane(c
);
921 lines
= status_line_size(c
);
923 if (tty
->sx
>= w
->sx
&& tty
->sy
- lines
>= w
->sy
) {
929 c
->pan_window
= NULL
;
934 *sy
= tty
->sy
- lines
;
936 if (c
->pan_window
== w
) {
939 else if (c
->pan_ox
+ *sx
> w
->sx
)
940 c
->pan_ox
= w
->sx
- *sx
;
944 else if (c
->pan_oy
+ *sy
> w
->sy
)
945 c
->pan_oy
= w
->sy
- *sy
;
950 if (~wp
->screen
->mode
& MODE_CURSOR
) {
954 cx
= wp
->xoff
+ wp
->screen
->cx
;
955 cy
= wp
->yoff
+ wp
->screen
->cy
;
959 else if (cx
> w
->sx
- *sx
)
966 else if (cy
> w
->sy
- *sy
)
972 c
->pan_window
= NULL
;
976 /* Update stored offsets for a window and redraw if necessary. */
978 tty_update_window_offset(struct window
*w
)
982 TAILQ_FOREACH(c
, &clients
, entry
) {
983 if (c
->session
!= NULL
&&
984 c
->session
->curw
!= NULL
&&
985 c
->session
->curw
->window
== w
)
986 tty_update_client_offset(c
);
990 /* Update stored offsets for a client and redraw if necessary. */
992 tty_update_client_offset(struct client
*c
)
994 u_int ox
, oy
, sx
, sy
;
996 if (~c
->flags
& CLIENT_TERMINAL
)
999 c
->tty
.oflag
= tty_window_offset1(&c
->tty
, &ox
, &oy
, &sx
, &sy
);
1000 if (ox
== c
->tty
.oox
&&
1006 log_debug ("%s: %s offset has changed (%u,%u %ux%u -> %u,%u %ux%u)",
1007 __func__
, c
->name
, c
->tty
.oox
, c
->tty
.ooy
, c
->tty
.osx
, c
->tty
.osy
,
1015 c
->flags
|= (CLIENT_REDRAWWINDOW
|CLIENT_REDRAWSTATUS
);
1019 * Is the region large enough to be worth redrawing once later rather than
1020 * probably several times now? Currently yes if it is more than 50% of the
1024 tty_large_region(__unused
struct tty
*tty
, const struct tty_ctx
*ctx
)
1026 return (ctx
->orlower
- ctx
->orupper
>= ctx
->sy
/ 2);
1030 * Return if BCE is needed but the terminal doesn't have it - it'll need to be
1034 tty_fake_bce(const struct tty
*tty
, const struct grid_cell
*gc
, u_int bg
)
1036 if (tty_term_flag(tty
->term
, TTYC_BCE
))
1038 if (!COLOUR_DEFAULT(bg
) || !COLOUR_DEFAULT(gc
->bg
))
1044 * Redraw scroll region using data from screen (already updated). Used when
1045 * CSR not supported, or window is a pane that doesn't take up the full
1046 * width of the terminal.
1049 tty_redraw_region(struct tty
*tty
, const struct tty_ctx
*ctx
)
1051 struct client
*c
= tty
->client
;
1055 * If region is large, schedule a redraw. In most cases this is likely
1056 * to be followed by some more scrolling.
1058 if (tty_large_region(tty
, ctx
)) {
1059 log_debug("%s: %s large redraw", __func__
, c
->name
);
1060 ctx
->redraw_cb(ctx
);
1064 for (i
= ctx
->orupper
; i
<= ctx
->orlower
; i
++)
1065 tty_draw_pane(tty
, ctx
, i
);
1068 /* Is this position visible in the pane? */
1070 tty_is_visible(__unused
struct tty
*tty
, const struct tty_ctx
*ctx
, u_int px
,
1071 u_int py
, u_int nx
, u_int ny
)
1073 u_int xoff
= ctx
->rxoff
+ px
, yoff
= ctx
->ryoff
+ py
;
1078 if (xoff
+ nx
<= ctx
->wox
|| xoff
>= ctx
->wox
+ ctx
->wsx
||
1079 yoff
+ ny
<= ctx
->woy
|| yoff
>= ctx
->woy
+ ctx
->wsy
)
1084 /* Clamp line position to visible part of pane. */
1086 tty_clamp_line(struct tty
*tty
, const struct tty_ctx
*ctx
, u_int px
, u_int py
,
1087 u_int nx
, u_int
*i
, u_int
*x
, u_int
*rx
, u_int
*ry
)
1089 u_int xoff
= ctx
->rxoff
+ px
;
1091 if (!tty_is_visible(tty
, ctx
, px
, py
, nx
, 1))
1093 *ry
= ctx
->yoff
+ py
- ctx
->woy
;
1095 if (xoff
>= ctx
->wox
&& xoff
+ nx
<= ctx
->wox
+ ctx
->wsx
) {
1098 *x
= ctx
->xoff
+ px
- ctx
->wox
;
1100 } else if (xoff
< ctx
->wox
&& xoff
+ nx
> ctx
->wox
+ ctx
->wsx
) {
1101 /* Both left and right not visible. */
1105 } else if (xoff
< ctx
->wox
) {
1106 /* Left not visible. */
1107 *i
= ctx
->wox
- (ctx
->xoff
+ px
);
1111 /* Right not visible. */
1113 *x
= (ctx
->xoff
+ px
) - ctx
->wox
;
1114 *rx
= ctx
->wsx
- *x
;
1117 fatalx("%s: x too big, %u > %u", __func__
, *rx
, nx
);
1124 tty_clear_line(struct tty
*tty
, const struct grid_cell
*defaults
, u_int py
,
1125 u_int px
, u_int nx
, u_int bg
)
1127 struct client
*c
= tty
->client
;
1128 struct overlay_ranges r
;
1131 log_debug("%s: %s, %u at %u,%u", __func__
, c
->name
, nx
, px
, py
);
1133 /* Nothing to clear. */
1137 /* If genuine BCE is available, can try escape sequences. */
1138 if (c
->overlay_check
== NULL
&& !tty_fake_bce(tty
, defaults
, bg
)) {
1139 /* Off the end of the line, use EL if available. */
1140 if (px
+ nx
>= tty
->sx
&& tty_term_has(tty
->term
, TTYC_EL
)) {
1141 tty_cursor(tty
, px
, py
);
1142 tty_putcode(tty
, TTYC_EL
);
1146 /* At the start of the line. Use EL1. */
1147 if (px
== 0 && tty_term_has(tty
->term
, TTYC_EL1
)) {
1148 tty_cursor(tty
, px
+ nx
- 1, py
);
1149 tty_putcode(tty
, TTYC_EL1
);
1153 /* Section of line. Use ECH if possible. */
1154 if (tty_term_has(tty
->term
, TTYC_ECH
)) {
1155 tty_cursor(tty
, px
, py
);
1156 tty_putcode_i(tty
, TTYC_ECH
, nx
);
1162 * Couldn't use an escape sequence, use spaces. Clear only the visible
1163 * bit if there is an overlay.
1165 tty_check_overlay_range(tty
, px
, py
, nx
, &r
);
1166 for (i
= 0; i
< OVERLAY_MAX_RANGES
; i
++) {
1169 tty_cursor(tty
, r
.px
[i
], py
);
1170 tty_repeat_space(tty
, r
.nx
[i
]);
1174 /* Clear a line, adjusting to visible part of pane. */
1176 tty_clear_pane_line(struct tty
*tty
, const struct tty_ctx
*ctx
, u_int py
,
1177 u_int px
, u_int nx
, u_int bg
)
1179 struct client
*c
= tty
->client
;
1182 log_debug("%s: %s, %u at %u,%u", __func__
, c
->name
, nx
, px
, py
);
1184 if (tty_clamp_line(tty
, ctx
, px
, py
, nx
, &i
, &x
, &rx
, &ry
))
1185 tty_clear_line(tty
, &ctx
->defaults
, ry
, x
, rx
, bg
);
1188 /* Clamp area position to visible part of pane. */
1190 tty_clamp_area(struct tty
*tty
, const struct tty_ctx
*ctx
, u_int px
, u_int py
,
1191 u_int nx
, u_int ny
, u_int
*i
, u_int
*j
, u_int
*x
, u_int
*y
, u_int
*rx
,
1194 u_int xoff
= ctx
->rxoff
+ px
, yoff
= ctx
->ryoff
+ py
;
1196 if (!tty_is_visible(tty
, ctx
, px
, py
, nx
, ny
))
1199 if (xoff
>= ctx
->wox
&& xoff
+ nx
<= ctx
->wox
+ ctx
->wsx
) {
1202 *x
= ctx
->xoff
+ px
- ctx
->wox
;
1204 } else if (xoff
< ctx
->wox
&& xoff
+ nx
> ctx
->wox
+ ctx
->wsx
) {
1205 /* Both left and right not visible. */
1209 } else if (xoff
< ctx
->wox
) {
1210 /* Left not visible. */
1211 *i
= ctx
->wox
- (ctx
->xoff
+ px
);
1215 /* Right not visible. */
1217 *x
= (ctx
->xoff
+ px
) - ctx
->wox
;
1218 *rx
= ctx
->wsx
- *x
;
1221 fatalx("%s: x too big, %u > %u", __func__
, *rx
, nx
);
1223 if (yoff
>= ctx
->woy
&& yoff
+ ny
<= ctx
->woy
+ ctx
->wsy
) {
1226 *y
= ctx
->yoff
+ py
- ctx
->woy
;
1228 } else if (yoff
< ctx
->woy
&& yoff
+ ny
> ctx
->woy
+ ctx
->wsy
) {
1229 /* Both top and bottom not visible. */
1233 } else if (yoff
< ctx
->woy
) {
1234 /* Top not visible. */
1235 *j
= ctx
->woy
- (ctx
->yoff
+ py
);
1239 /* Bottom not visible. */
1241 *y
= (ctx
->yoff
+ py
) - ctx
->woy
;
1242 *ry
= ctx
->wsy
- *y
;
1245 fatalx("%s: y too big, %u > %u", __func__
, *ry
, ny
);
1250 /* Clear an area, adjusting to visible part of pane. */
1252 tty_clear_area(struct tty
*tty
, const struct grid_cell
*defaults
, u_int py
,
1253 u_int ny
, u_int px
, u_int nx
, u_int bg
)
1255 struct client
*c
= tty
->client
;
1259 log_debug("%s: %s, %u,%u at %u,%u", __func__
, c
->name
, nx
, ny
, px
, py
);
1261 /* Nothing to clear. */
1262 if (nx
== 0 || ny
== 0)
1265 /* If genuine BCE is available, can try escape sequences. */
1266 if (c
->overlay_check
== NULL
&& !tty_fake_bce(tty
, defaults
, bg
)) {
1267 /* Use ED if clearing off the bottom of the terminal. */
1269 px
+ nx
>= tty
->sx
&&
1270 py
+ ny
>= tty
->sy
&&
1271 tty_term_has(tty
->term
, TTYC_ED
)) {
1272 tty_cursor(tty
, 0, py
);
1273 tty_putcode(tty
, TTYC_ED
);
1278 * On VT420 compatible terminals we can use DECFRA if the
1279 * background colour isn't default (because it doesn't work
1282 if ((tty
->term
->flags
& TERM_DECFRA
) && !COLOUR_DEFAULT(bg
)) {
1283 xsnprintf(tmp
, sizeof tmp
, "\033[32;%u;%u;%u;%u$x",
1284 py
+ 1, px
+ 1, py
+ ny
, px
+ nx
);
1289 /* Full lines can be scrolled away to clear them. */
1291 px
+ nx
>= tty
->sx
&&
1293 tty_term_has(tty
->term
, TTYC_CSR
) &&
1294 tty_term_has(tty
->term
, TTYC_INDN
)) {
1295 tty_region(tty
, py
, py
+ ny
- 1);
1296 tty_margin_off(tty
);
1297 tty_putcode_i(tty
, TTYC_INDN
, ny
);
1302 * If margins are supported, can just scroll the area off to
1307 tty_term_has(tty
->term
, TTYC_CSR
) &&
1308 tty_use_margin(tty
) &&
1309 tty_term_has(tty
->term
, TTYC_INDN
)) {
1310 tty_region(tty
, py
, py
+ ny
- 1);
1311 tty_margin(tty
, px
, px
+ nx
- 1);
1312 tty_putcode_i(tty
, TTYC_INDN
, ny
);
1317 /* Couldn't use an escape sequence, loop over the lines. */
1318 for (yy
= py
; yy
< py
+ ny
; yy
++)
1319 tty_clear_line(tty
, defaults
, yy
, px
, nx
, bg
);
1322 /* Clear an area in a pane. */
1324 tty_clear_pane_area(struct tty
*tty
, const struct tty_ctx
*ctx
, u_int py
,
1325 u_int ny
, u_int px
, u_int nx
, u_int bg
)
1327 u_int i
, j
, x
, y
, rx
, ry
;
1329 if (tty_clamp_area(tty
, ctx
, px
, py
, nx
, ny
, &i
, &j
, &x
, &y
, &rx
, &ry
))
1330 tty_clear_area(tty
, &ctx
->defaults
, y
, ry
, x
, rx
, bg
);
1334 tty_draw_pane(struct tty
*tty
, const struct tty_ctx
*ctx
, u_int py
)
1336 struct screen
*s
= ctx
->s
;
1337 u_int nx
= ctx
->sx
, i
, x
, rx
, ry
;
1339 log_debug("%s: %s %u %d", __func__
, tty
->client
->name
, py
, ctx
->bigger
);
1342 tty_draw_line(tty
, s
, 0, py
, nx
, ctx
->xoff
, ctx
->yoff
+ py
,
1343 &ctx
->defaults
, ctx
->palette
);
1346 if (tty_clamp_line(tty
, ctx
, 0, py
, nx
, &i
, &x
, &rx
, &ry
)) {
1347 tty_draw_line(tty
, s
, i
, py
, rx
, x
, ry
, &ctx
->defaults
,
1352 static const struct grid_cell
*
1353 tty_check_codeset(struct tty
*tty
, const struct grid_cell
*gc
)
1355 static struct grid_cell
new;
1358 /* Characters less than 0x7f are always fine, no matter what. */
1359 if (gc
->data
.size
== 1 && *gc
->data
.data
< 0x7f)
1362 /* UTF-8 terminal and a UTF-8 character - fine. */
1363 if (tty
->client
->flags
& CLIENT_UTF8
)
1365 memcpy(&new, gc
, sizeof new);
1367 /* See if this can be mapped to an ACS character. */
1368 c
= tty_acs_reverse_get(tty
, gc
->data
.data
, gc
->data
.size
);
1370 utf8_set(&new.data
, c
);
1371 new.attr
|= GRID_ATTR_CHARSET
;
1375 /* Replace by the right number of underscores. */
1376 new.data
.size
= gc
->data
.width
;
1377 if (new.data
.size
> UTF8_SIZE
)
1378 new.data
.size
= UTF8_SIZE
;
1379 memset(new.data
.data
, '_', new.data
.size
);
1384 * Check if a single character is obstructed by the overlay and return a
1388 tty_check_overlay(struct tty
*tty
, u_int px
, u_int py
)
1390 struct overlay_ranges r
;
1393 * A unit width range will always return nx[2] == 0 from a check, even
1394 * with multiple overlays, so it's sufficient to check just the first
1397 tty_check_overlay_range(tty
, px
, py
, 1, &r
);
1398 if (r
.nx
[0] + r
.nx
[1] == 0)
1403 /* Return parts of the input range which are visible. */
1405 tty_check_overlay_range(struct tty
*tty
, u_int px
, u_int py
, u_int nx
,
1406 struct overlay_ranges
*r
)
1408 struct client
*c
= tty
->client
;
1410 if (c
->overlay_check
== NULL
) {
1420 c
->overlay_check(c
, c
->overlay_data
, px
, py
, nx
, r
);
1424 tty_draw_line(struct tty
*tty
, struct screen
*s
, u_int px
, u_int py
, u_int nx
,
1425 u_int atx
, u_int aty
, const struct grid_cell
*defaults
,
1426 struct colour_palette
*palette
)
1428 struct grid
*gd
= s
->grid
;
1429 struct grid_cell gc
, last
;
1430 const struct grid_cell
*gcp
;
1431 struct grid_line
*gl
;
1432 struct client
*c
= tty
->client
;
1433 struct overlay_ranges r
;
1434 u_int i
, j
, ux
, sx
, width
, hidden
, eux
, nxx
;
1436 int flags
, cleared
= 0, wrapped
= 0;
1440 log_debug("%s: px=%u py=%u nx=%u atx=%u aty=%u", __func__
,
1441 px
, py
, nx
, atx
, aty
);
1442 log_debug("%s: defaults: fg=%d, bg=%d", __func__
, defaults
->fg
,
1446 * py is the line in the screen to draw.
1447 * px is the start x and nx is the width to draw.
1448 * atx,aty is the line on the terminal to draw it.
1451 flags
= (tty
->flags
& TTY_NOCURSOR
);
1452 tty
->flags
|= TTY_NOCURSOR
;
1453 tty_update_mode(tty
, tty
->mode
, s
);
1455 tty_region_off(tty
);
1456 tty_margin_off(tty
);
1459 * Clamp the width to cellsize - note this is not cellused, because
1460 * there may be empty background cells after it (from BCE).
1462 sx
= screen_size_x(s
);
1465 cellsize
= grid_get_line(gd
, gd
->hsize
+ py
)->cellsize
;
1477 gl
= grid_get_line(gd
, gd
->hsize
+ py
- 1);
1479 (~gl
->flags
& GRID_LINE_WRAPPED
) ||
1481 tty
->cx
< tty
->sx
||
1486 tty_term_has(tty
->term
, TTYC_EL1
) &&
1487 !tty_fake_bce(tty
, defaults
, 8) &&
1488 c
->overlay_check
== NULL
) {
1489 tty_default_attributes(tty
, defaults
, palette
, 8,
1491 tty_cursor(tty
, nx
- 1, aty
);
1492 tty_putcode(tty
, TTYC_EL1
);
1496 log_debug("%s: wrapped line %u", __func__
, aty
);
1500 memcpy(&last
, &grid_default_cell
, sizeof last
);
1504 for (i
= 0; i
< sx
; i
++) {
1505 grid_view_get_cell(gd
, px
+ i
, py
, &gc
);
1506 gcp
= tty_check_codeset(tty
, &gc
);
1508 (!tty_check_overlay(tty
, atx
+ ux
+ width
, aty
) ||
1509 (gcp
->attr
& GRID_ATTR_CHARSET
) ||
1510 gcp
->flags
!= last
.flags
||
1511 gcp
->attr
!= last
.attr
||
1512 gcp
->fg
!= last
.fg
||
1513 gcp
->bg
!= last
.bg
||
1514 gcp
->us
!= last
.us
||
1515 gcp
->link
!= last
.link
||
1516 ux
+ width
+ gcp
->data
.width
> nx
||
1517 (sizeof buf
) - len
< gcp
->data
.size
)) {
1518 tty_attributes(tty
, &last
, defaults
, palette
,
1520 if (last
.flags
& GRID_FLAG_CLEARED
) {
1521 log_debug("%s: %zu cleared", __func__
, len
);
1522 tty_clear_line(tty
, defaults
, aty
, atx
+ ux
,
1525 if (!wrapped
|| atx
!= 0 || ux
!= 0)
1526 tty_cursor(tty
, atx
+ ux
, aty
);
1527 tty_putn(tty
, buf
, len
, width
);
1536 if (gcp
->flags
& GRID_FLAG_SELECTED
)
1537 screen_select_cell(s
, &last
, gcp
);
1539 memcpy(&last
, gcp
, sizeof last
);
1541 tty_check_overlay_range(tty
, atx
+ ux
, aty
, gcp
->data
.width
,
1544 for (j
= 0; j
< OVERLAY_MAX_RANGES
; j
++)
1546 hidden
= gcp
->data
.width
- hidden
;
1547 if (hidden
!= 0 && hidden
== gcp
->data
.width
) {
1548 if (~gcp
->flags
& GRID_FLAG_PADDING
)
1549 ux
+= gcp
->data
.width
;
1550 } else if (hidden
!= 0 || ux
+ gcp
->data
.width
> nx
) {
1551 if (~gcp
->flags
& GRID_FLAG_PADDING
) {
1552 tty_attributes(tty
, &last
, defaults
, palette
,
1554 for (j
= 0; j
< OVERLAY_MAX_RANGES
; j
++) {
1557 /* Effective width drawn so far. */
1558 eux
= r
.px
[j
] - atx
;
1560 tty_cursor(tty
, r
.px
[j
], aty
);
1564 tty_repeat_space(tty
, r
.nx
[j
]);
1569 } else if (gcp
->attr
& GRID_ATTR_CHARSET
) {
1570 tty_attributes(tty
, &last
, defaults
, palette
,
1572 tty_cursor(tty
, atx
+ ux
, aty
);
1573 for (j
= 0; j
< gcp
->data
.size
; j
++)
1574 tty_putc(tty
, gcp
->data
.data
[j
]);
1575 ux
+= gcp
->data
.width
;
1576 } else if (~gcp
->flags
& GRID_FLAG_PADDING
) {
1577 memcpy(buf
+ len
, gcp
->data
.data
, gcp
->data
.size
);
1578 len
+= gcp
->data
.size
;
1579 width
+= gcp
->data
.width
;
1582 if (len
!= 0 && ((~last
.flags
& GRID_FLAG_CLEARED
) || last
.bg
!= 8)) {
1583 tty_attributes(tty
, &last
, defaults
, palette
, s
->hyperlinks
);
1584 if (last
.flags
& GRID_FLAG_CLEARED
) {
1585 log_debug("%s: %zu cleared (end)", __func__
, len
);
1586 tty_clear_line(tty
, defaults
, aty
, atx
+ ux
, width
,
1589 if (!wrapped
|| atx
!= 0 || ux
!= 0)
1590 tty_cursor(tty
, atx
+ ux
, aty
);
1591 tty_putn(tty
, buf
, len
, width
);
1596 if (!cleared
&& ux
< nx
) {
1597 log_debug("%s: %u to end of line (%zu cleared)", __func__
,
1599 tty_default_attributes(tty
, defaults
, palette
, 8,
1601 tty_clear_line(tty
, defaults
, aty
, atx
+ ux
, nx
- ux
, 8);
1604 tty
->flags
= (tty
->flags
& ~TTY_NOCURSOR
) | flags
;
1605 tty_update_mode(tty
, tty
->mode
, s
);
1609 /* Update context for client. */
1611 tty_set_client_cb(struct tty_ctx
*ttyctx
, struct client
*c
)
1613 struct window_pane
*wp
= ttyctx
->arg
;
1615 if (c
->session
->curw
->window
!= wp
->window
)
1617 if (wp
->layout_cell
== NULL
)
1620 /* Set the properties relevant to the current client. */
1621 ttyctx
->bigger
= tty_window_offset(&c
->tty
, &ttyctx
->wox
, &ttyctx
->woy
,
1622 &ttyctx
->wsx
, &ttyctx
->wsy
);
1624 ttyctx
->yoff
= ttyctx
->ryoff
= wp
->yoff
;
1625 if (status_at_line(c
) == 0)
1626 ttyctx
->yoff
+= status_line_size(c
);
1632 tty_draw_images(struct client
*c
, struct window_pane
*wp
, struct screen
*s
)
1635 struct tty_ctx ttyctx
;
1637 TAILQ_FOREACH(im
, &s
->images
, entry
) {
1638 memset(&ttyctx
, 0, sizeof ttyctx
);
1640 /* Set the client independent properties. */
1641 ttyctx
.ocx
= im
->px
;
1642 ttyctx
.ocy
= im
->py
;
1644 ttyctx
.orlower
= s
->rlower
;
1645 ttyctx
.orupper
= s
->rupper
;
1647 ttyctx
.xoff
= ttyctx
.rxoff
= wp
->xoff
;
1653 ttyctx
.set_client_cb
= tty_set_client_cb
;
1654 ttyctx
.allow_invisible_panes
= 1;
1655 tty_write_one(tty_cmd_sixelimage
, c
, &ttyctx
);
1661 tty_sync_start(struct tty
*tty
)
1663 if (tty
->flags
& TTY_BLOCK
)
1665 if (tty
->flags
& TTY_SYNCING
)
1667 tty
->flags
|= TTY_SYNCING
;
1669 if (tty_term_has(tty
->term
, TTYC_SYNC
)) {
1670 log_debug("%s sync start", tty
->client
->name
);
1671 tty_putcode_i(tty
, TTYC_SYNC
, 1);
1676 tty_sync_end(struct tty
*tty
)
1678 if (tty
->flags
& TTY_BLOCK
)
1680 if (~tty
->flags
& TTY_SYNCING
)
1682 tty
->flags
&= ~TTY_SYNCING
;
1684 if (tty_term_has(tty
->term
, TTYC_SYNC
)) {
1685 log_debug("%s sync end", tty
->client
->name
);
1686 tty_putcode_i(tty
, TTYC_SYNC
, 2);
1691 tty_client_ready(const struct tty_ctx
*ctx
, struct client
*c
)
1693 if (c
->session
== NULL
|| c
->tty
.term
== NULL
)
1695 if (c
->flags
& CLIENT_SUSPENDED
)
1699 * If invisible panes are allowed (used for passthrough), don't care if
1700 * redrawing or frozen.
1702 if (ctx
->allow_invisible_panes
)
1705 if (c
->flags
& CLIENT_REDRAWWINDOW
)
1707 if (c
->tty
.flags
& TTY_FREEZE
)
1713 tty_write(void (*cmdfn
)(struct tty
*, const struct tty_ctx
*),
1714 struct tty_ctx
*ctx
)
1719 if (ctx
->set_client_cb
== NULL
)
1721 TAILQ_FOREACH(c
, &clients
, entry
) {
1722 if (tty_client_ready(ctx
, c
)) {
1723 state
= ctx
->set_client_cb(ctx
, c
);
1728 cmdfn(&c
->tty
, ctx
);
1734 /* Only write to the incoming tty instead of every client. */
1736 tty_write_one(void (*cmdfn
)(struct tty
*, const struct tty_ctx
*),
1737 struct client
*c
, struct tty_ctx
*ctx
)
1739 if (ctx
->set_client_cb
== NULL
)
1741 if ((ctx
->set_client_cb(ctx
, c
)) == 1)
1742 cmdfn(&c
->tty
, ctx
);
1747 tty_cmd_insertcharacter(struct tty
*tty
, const struct tty_ctx
*ctx
)
1749 struct client
*c
= tty
->client
;
1752 !tty_full_width(tty
, ctx
) ||
1753 tty_fake_bce(tty
, &ctx
->defaults
, ctx
->bg
) ||
1754 (!tty_term_has(tty
->term
, TTYC_ICH
) &&
1755 !tty_term_has(tty
->term
, TTYC_ICH1
)) ||
1756 c
->overlay_check
!= NULL
) {
1757 tty_draw_pane(tty
, ctx
, ctx
->ocy
);
1761 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
1762 ctx
->s
->hyperlinks
);
1764 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
1766 tty_emulate_repeat(tty
, TTYC_ICH
, TTYC_ICH1
, ctx
->num
);
1770 tty_cmd_deletecharacter(struct tty
*tty
, const struct tty_ctx
*ctx
)
1772 struct client
*c
= tty
->client
;
1775 !tty_full_width(tty
, ctx
) ||
1776 tty_fake_bce(tty
, &ctx
->defaults
, ctx
->bg
) ||
1777 (!tty_term_has(tty
->term
, TTYC_DCH
) &&
1778 !tty_term_has(tty
->term
, TTYC_DCH1
)) ||
1779 c
->overlay_check
!= NULL
) {
1780 tty_draw_pane(tty
, ctx
, ctx
->ocy
);
1784 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
1785 ctx
->s
->hyperlinks
);
1787 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
1789 tty_emulate_repeat(tty
, TTYC_DCH
, TTYC_DCH1
, ctx
->num
);
1793 tty_cmd_clearcharacter(struct tty
*tty
, const struct tty_ctx
*ctx
)
1795 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
1796 ctx
->s
->hyperlinks
);
1798 tty_clear_pane_line(tty
, ctx
, ctx
->ocy
, ctx
->ocx
, ctx
->num
, ctx
->bg
);
1802 tty_cmd_insertline(struct tty
*tty
, const struct tty_ctx
*ctx
)
1804 struct client
*c
= tty
->client
;
1807 !tty_full_width(tty
, ctx
) ||
1808 tty_fake_bce(tty
, &ctx
->defaults
, ctx
->bg
) ||
1809 !tty_term_has(tty
->term
, TTYC_CSR
) ||
1810 !tty_term_has(tty
->term
, TTYC_IL1
) ||
1813 c
->overlay_check
!= NULL
) {
1814 tty_redraw_region(tty
, ctx
);
1818 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
1819 ctx
->s
->hyperlinks
);
1821 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
1822 tty_margin_off(tty
);
1823 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
1825 tty_emulate_repeat(tty
, TTYC_IL
, TTYC_IL1
, ctx
->num
);
1826 tty
->cx
= tty
->cy
= UINT_MAX
;
1830 tty_cmd_deleteline(struct tty
*tty
, const struct tty_ctx
*ctx
)
1832 struct client
*c
= tty
->client
;
1835 !tty_full_width(tty
, ctx
) ||
1836 tty_fake_bce(tty
, &ctx
->defaults
, ctx
->bg
) ||
1837 !tty_term_has(tty
->term
, TTYC_CSR
) ||
1838 !tty_term_has(tty
->term
, TTYC_DL1
) ||
1841 c
->overlay_check
!= NULL
) {
1842 tty_redraw_region(tty
, ctx
);
1846 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
1847 ctx
->s
->hyperlinks
);
1849 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
1850 tty_margin_off(tty
);
1851 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
1853 tty_emulate_repeat(tty
, TTYC_DL
, TTYC_DL1
, ctx
->num
);
1854 tty
->cx
= tty
->cy
= UINT_MAX
;
1858 tty_cmd_clearline(struct tty
*tty
, const struct tty_ctx
*ctx
)
1860 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
1861 ctx
->s
->hyperlinks
);
1863 tty_clear_pane_line(tty
, ctx
, ctx
->ocy
, 0, ctx
->sx
, ctx
->bg
);
1867 tty_cmd_clearendofline(struct tty
*tty
, const struct tty_ctx
*ctx
)
1869 u_int nx
= ctx
->sx
- ctx
->ocx
;
1871 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
1872 ctx
->s
->hyperlinks
);
1874 tty_clear_pane_line(tty
, ctx
, ctx
->ocy
, ctx
->ocx
, nx
, ctx
->bg
);
1878 tty_cmd_clearstartofline(struct tty
*tty
, const struct tty_ctx
*ctx
)
1880 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
1881 ctx
->s
->hyperlinks
);
1883 tty_clear_pane_line(tty
, ctx
, ctx
->ocy
, 0, ctx
->ocx
+ 1, ctx
->bg
);
1887 tty_cmd_reverseindex(struct tty
*tty
, const struct tty_ctx
*ctx
)
1889 struct client
*c
= tty
->client
;
1891 if (ctx
->ocy
!= ctx
->orupper
)
1895 (!tty_full_width(tty
, ctx
) && !tty_use_margin(tty
)) ||
1896 tty_fake_bce(tty
, &ctx
->defaults
, 8) ||
1897 !tty_term_has(tty
->term
, TTYC_CSR
) ||
1898 (!tty_term_has(tty
->term
, TTYC_RI
) &&
1899 !tty_term_has(tty
->term
, TTYC_RIN
)) ||
1902 c
->overlay_check
!= NULL
) {
1903 tty_redraw_region(tty
, ctx
);
1907 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
1908 ctx
->s
->hyperlinks
);
1910 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
1911 tty_margin_pane(tty
, ctx
);
1912 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->orupper
);
1914 if (tty_term_has(tty
->term
, TTYC_RI
))
1915 tty_putcode(tty
, TTYC_RI
);
1917 tty_putcode_i(tty
, TTYC_RIN
, 1);
1921 tty_cmd_linefeed(struct tty
*tty
, const struct tty_ctx
*ctx
)
1923 struct client
*c
= tty
->client
;
1925 if (ctx
->ocy
!= ctx
->orlower
)
1929 (!tty_full_width(tty
, ctx
) && !tty_use_margin(tty
)) ||
1930 tty_fake_bce(tty
, &ctx
->defaults
, 8) ||
1931 !tty_term_has(tty
->term
, TTYC_CSR
) ||
1934 c
->overlay_check
!= NULL
) {
1935 tty_redraw_region(tty
, ctx
);
1939 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
1940 ctx
->s
->hyperlinks
);
1942 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
1943 tty_margin_pane(tty
, ctx
);
1946 * If we want to wrap a pane while using margins, the cursor needs to
1947 * be exactly on the right of the region. If the cursor is entirely off
1948 * the edge - move it back to the right. Some terminals are funny about
1949 * this and insert extra spaces, so only use the right if margins are
1952 if (ctx
->xoff
+ ctx
->ocx
> tty
->rright
) {
1953 if (!tty_use_margin(tty
))
1954 tty_cursor(tty
, 0, ctx
->yoff
+ ctx
->ocy
);
1956 tty_cursor(tty
, tty
->rright
, ctx
->yoff
+ ctx
->ocy
);
1958 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
1960 tty_putc(tty
, '\n');
1964 tty_cmd_scrollup(struct tty
*tty
, const struct tty_ctx
*ctx
)
1966 struct client
*c
= tty
->client
;
1970 (!tty_full_width(tty
, ctx
) && !tty_use_margin(tty
)) ||
1971 tty_fake_bce(tty
, &ctx
->defaults
, 8) ||
1972 !tty_term_has(tty
->term
, TTYC_CSR
) ||
1975 c
->overlay_check
!= NULL
) {
1976 tty_redraw_region(tty
, ctx
);
1980 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
1981 ctx
->s
->hyperlinks
);
1983 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
1984 tty_margin_pane(tty
, ctx
);
1986 if (ctx
->num
== 1 || !tty_term_has(tty
->term
, TTYC_INDN
)) {
1987 if (!tty_use_margin(tty
))
1988 tty_cursor(tty
, 0, tty
->rlower
);
1990 tty_cursor(tty
, tty
->rright
, tty
->rlower
);
1991 for (i
= 0; i
< ctx
->num
; i
++)
1992 tty_putc(tty
, '\n');
1994 if (tty
->cy
== UINT_MAX
)
1995 tty_cursor(tty
, 0, 0);
1997 tty_cursor(tty
, 0, tty
->cy
);
1998 tty_putcode_i(tty
, TTYC_INDN
, ctx
->num
);
2003 tty_cmd_scrolldown(struct tty
*tty
, const struct tty_ctx
*ctx
)
2006 struct client
*c
= tty
->client
;
2009 (!tty_full_width(tty
, ctx
) && !tty_use_margin(tty
)) ||
2010 tty_fake_bce(tty
, &ctx
->defaults
, 8) ||
2011 !tty_term_has(tty
->term
, TTYC_CSR
) ||
2012 (!tty_term_has(tty
->term
, TTYC_RI
) &&
2013 !tty_term_has(tty
->term
, TTYC_RIN
)) ||
2016 c
->overlay_check
!= NULL
) {
2017 tty_redraw_region(tty
, ctx
);
2021 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
2022 ctx
->s
->hyperlinks
);
2024 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
2025 tty_margin_pane(tty
, ctx
);
2026 tty_cursor_pane(tty
, ctx
, ctx
->ocx
, ctx
->orupper
);
2028 if (tty_term_has(tty
->term
, TTYC_RIN
))
2029 tty_putcode_i(tty
, TTYC_RIN
, ctx
->num
);
2031 for (i
= 0; i
< ctx
->num
; i
++)
2032 tty_putcode(tty
, TTYC_RI
);
2037 tty_cmd_clearendofscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
2039 u_int px
, py
, nx
, ny
;
2041 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
2042 ctx
->s
->hyperlinks
);
2044 tty_region_pane(tty
, ctx
, 0, ctx
->sy
- 1);
2045 tty_margin_off(tty
);
2050 ny
= ctx
->sy
- ctx
->ocy
- 1;
2052 tty_clear_pane_area(tty
, ctx
, py
, ny
, px
, nx
, ctx
->bg
);
2055 nx
= ctx
->sx
- ctx
->ocx
;
2058 tty_clear_pane_line(tty
, ctx
, py
, px
, nx
, ctx
->bg
);
2062 tty_cmd_clearstartofscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
2064 u_int px
, py
, nx
, ny
;
2066 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
2067 ctx
->s
->hyperlinks
);
2069 tty_region_pane(tty
, ctx
, 0, ctx
->sy
- 1);
2070 tty_margin_off(tty
);
2077 tty_clear_pane_area(tty
, ctx
, py
, ny
, px
, nx
, ctx
->bg
);
2083 tty_clear_pane_line(tty
, ctx
, py
, px
, nx
, ctx
->bg
);
2087 tty_cmd_clearscreen(struct tty
*tty
, const struct tty_ctx
*ctx
)
2089 u_int px
, py
, nx
, ny
;
2091 tty_default_attributes(tty
, &ctx
->defaults
, ctx
->palette
, ctx
->bg
,
2092 ctx
->s
->hyperlinks
);
2094 tty_region_pane(tty
, ctx
, 0, ctx
->sy
- 1);
2095 tty_margin_off(tty
);
2102 tty_clear_pane_area(tty
, ctx
, py
, ny
, px
, nx
, ctx
->bg
);
2106 tty_cmd_alignmenttest(struct tty
*tty
, const struct tty_ctx
*ctx
)
2111 ctx
->redraw_cb(ctx
);
2115 tty_attributes(tty
, &grid_default_cell
, &ctx
->defaults
, ctx
->palette
,
2116 ctx
->s
->hyperlinks
);
2118 tty_region_pane(tty
, ctx
, 0, ctx
->sy
- 1);
2119 tty_margin_off(tty
);
2121 for (j
= 0; j
< ctx
->sy
; j
++) {
2122 tty_cursor_pane(tty
, ctx
, 0, j
);
2123 for (i
= 0; i
< ctx
->sx
; i
++)
2129 tty_cmd_cell(struct tty
*tty
, const struct tty_ctx
*ctx
)
2131 const struct grid_cell
*gcp
= ctx
->cell
;
2132 struct screen
*s
= ctx
->s
;
2133 struct overlay_ranges r
;
2134 u_int px
, py
, i
, vis
= 0;
2136 px
= ctx
->xoff
+ ctx
->ocx
- ctx
->wox
;
2137 py
= ctx
->yoff
+ ctx
->ocy
- ctx
->woy
;
2138 if (!tty_is_visible(tty
, ctx
, ctx
->ocx
, ctx
->ocy
, 1, 1) ||
2139 (gcp
->data
.width
== 1 && !tty_check_overlay(tty
, px
, py
)))
2142 /* Handle partially obstructed wide characters. */
2143 if (gcp
->data
.width
> 1) {
2144 tty_check_overlay_range(tty
, px
, py
, gcp
->data
.width
, &r
);
2145 for (i
= 0; i
< OVERLAY_MAX_RANGES
; i
++)
2147 if (vis
< gcp
->data
.width
) {
2148 tty_draw_line(tty
, s
, s
->cx
, s
->cy
, gcp
->data
.width
,
2149 px
, py
, &ctx
->defaults
, ctx
->palette
);
2154 if (ctx
->xoff
+ ctx
->ocx
- ctx
->wox
> tty
->sx
- 1 &&
2155 ctx
->ocy
== ctx
->orlower
&&
2156 tty_full_width(tty
, ctx
))
2157 tty_region_pane(tty
, ctx
, ctx
->orupper
, ctx
->orlower
);
2159 tty_margin_off(tty
);
2160 tty_cursor_pane_unless_wrap(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
2162 tty_cell(tty
, ctx
->cell
, &ctx
->defaults
, ctx
->palette
,
2163 ctx
->s
->hyperlinks
);
2166 tty_invalidate(tty
);
2170 tty_cmd_cells(struct tty
*tty
, const struct tty_ctx
*ctx
)
2172 struct overlay_ranges r
;
2173 u_int i
, px
, py
, cx
;
2174 char *cp
= ctx
->ptr
;
2176 if (!tty_is_visible(tty
, ctx
, ctx
->ocx
, ctx
->ocy
, ctx
->num
, 1))
2180 (ctx
->xoff
+ ctx
->ocx
< ctx
->wox
||
2181 ctx
->xoff
+ ctx
->ocx
+ ctx
->num
> ctx
->wox
+ ctx
->wsx
)) {
2182 if (!ctx
->wrapped
||
2183 !tty_full_width(tty
, ctx
) ||
2184 (tty
->term
->flags
& TERM_NOAM
) ||
2185 ctx
->xoff
+ ctx
->ocx
!= 0 ||
2186 ctx
->yoff
+ ctx
->ocy
!= tty
->cy
+ 1 ||
2187 tty
->cx
< tty
->sx
||
2188 tty
->cy
== tty
->rlower
)
2189 tty_draw_pane(tty
, ctx
, ctx
->ocy
);
2191 ctx
->redraw_cb(ctx
);
2195 tty_margin_off(tty
);
2196 tty_cursor_pane_unless_wrap(tty
, ctx
, ctx
->ocx
, ctx
->ocy
);
2197 tty_attributes(tty
, ctx
->cell
, &ctx
->defaults
, ctx
->palette
, ctx
->s
->hyperlinks
);
2199 /* Get tty position from pane position for overlay check. */
2200 px
= ctx
->xoff
+ ctx
->ocx
- ctx
->wox
;
2201 py
= ctx
->yoff
+ ctx
->ocy
- ctx
->woy
;
2203 tty_check_overlay_range(tty
, px
, py
, ctx
->num
, &r
);
2204 for (i
= 0; i
< OVERLAY_MAX_RANGES
; i
++) {
2207 /* Convert back to pane position for printing. */
2208 cx
= r
.px
[i
] - ctx
->xoff
+ ctx
->wox
;
2209 tty_cursor_pane_unless_wrap(tty
, ctx
, cx
, ctx
->ocy
);
2210 tty_putn(tty
, cp
+ r
.px
[i
] - px
, r
.nx
[i
], r
.nx
[i
]);
2215 tty_cmd_setselection(struct tty
*tty
, const struct tty_ctx
*ctx
)
2217 tty_set_selection(tty
, ctx
->ptr2
, ctx
->ptr
, ctx
->num
);
2221 tty_set_selection(struct tty
*tty
, const char *flags
, const char *buf
,
2227 if (~tty
->flags
& TTY_STARTED
)
2229 if (!tty_term_has(tty
->term
, TTYC_MS
))
2232 size
= 4 * ((len
+ 2) / 3) + 1; /* storage for base64 */
2233 encoded
= xmalloc(size
);
2235 b64_ntop(buf
, len
, encoded
, size
);
2236 tty
->flags
|= TTY_NOBLOCK
;
2237 tty_putcode_ss(tty
, TTYC_MS
, flags
, encoded
);
2243 tty_cmd_rawstring(struct tty
*tty
, const struct tty_ctx
*ctx
)
2245 tty
->flags
|= TTY_NOBLOCK
;
2246 tty_add(tty
, ctx
->ptr
, ctx
->num
);
2247 tty_invalidate(tty
);
2252 tty_cmd_sixelimage(struct tty
*tty
, const struct tty_ctx
*ctx
)
2254 struct image
*im
= ctx
->ptr
;
2255 struct sixel_image
*si
= im
->data
;
2256 struct sixel_image
*new;
2259 u_int cx
= ctx
->ocx
, cy
= ctx
->ocy
, sx
, sy
;
2260 u_int i
, j
, x
, y
, rx
, ry
;
2263 if ((~tty
->term
->flags
& TERM_SIXEL
) &&
2264 !tty_term_has(tty
->term
, TTYC_SXL
))
2266 if (tty
->xpixel
== 0 || tty
->ypixel
== 0)
2269 sixel_size_in_cells(si
, &sx
, &sy
);
2270 log_debug("%s: image is %ux%u", __func__
, sx
, sy
);
2271 if (!tty_clamp_area(tty
, ctx
, cx
, cy
, sx
, sy
, &i
, &j
, &x
, &y
, &rx
, &ry
))
2273 log_debug("%s: clamping to %u,%u-%u,%u", __func__
, i
, j
, rx
, ry
);
2275 if (fallback
== 1) {
2276 data
= xstrdup(im
->fallback
);
2277 size
= strlen(data
);
2279 new = sixel_scale(si
, tty
->xpixel
, tty
->ypixel
, i
, j
, rx
, ry
, 0);
2283 data
= sixel_print(new, si
, &size
);
2286 log_debug("%s: %zu bytes: %s", __func__
, size
, data
);
2287 tty_region_off(tty
);
2288 tty_margin_off(tty
);
2289 tty_cursor(tty
, x
, y
);
2291 tty
->flags
|= TTY_NOBLOCK
;
2292 tty_add(tty
, data
, size
);
2293 tty_invalidate(tty
);
2303 tty_cmd_syncstart(struct tty
*tty
, const struct tty_ctx
*ctx
)
2305 if (ctx
->num
== 0x11) {
2307 * This is an overlay and a command that moves the cursor so
2308 * start synchronized updates.
2310 tty_sync_start(tty
);
2311 } else if (~ctx
->num
& 0x10) {
2313 * This is a pane. If there is an overlay, always start;
2314 * otherwise, only if requested.
2316 if (ctx
->num
|| tty
->client
->overlay_draw
!= NULL
)
2317 tty_sync_start(tty
);
2322 tty_cell(struct tty
*tty
, const struct grid_cell
*gc
,
2323 const struct grid_cell
*defaults
, struct colour_palette
*palette
,
2324 struct hyperlinks
*hl
)
2326 const struct grid_cell
*gcp
;
2328 /* Skip last character if terminal is stupid. */
2329 if ((tty
->term
->flags
& TERM_NOAM
) &&
2330 tty
->cy
== tty
->sy
- 1 &&
2331 tty
->cx
== tty
->sx
- 1)
2334 /* If this is a padding character, do nothing. */
2335 if (gc
->flags
& GRID_FLAG_PADDING
)
2338 /* Check the output codeset and apply attributes. */
2339 gcp
= tty_check_codeset(tty
, gc
);
2340 tty_attributes(tty
, gcp
, defaults
, palette
, hl
);
2342 /* If it is a single character, write with putc to handle ACS. */
2343 if (gcp
->data
.size
== 1) {
2344 tty_attributes(tty
, gcp
, defaults
, palette
, hl
);
2345 if (*gcp
->data
.data
< 0x20 || *gcp
->data
.data
== 0x7f)
2347 tty_putc(tty
, *gcp
->data
.data
);
2351 /* Write the data. */
2352 tty_putn(tty
, gcp
->data
.data
, gcp
->data
.size
, gcp
->data
.width
);
2356 tty_reset(struct tty
*tty
)
2358 struct grid_cell
*gc
= &tty
->cell
;
2360 if (!grid_cells_equal(gc
, &grid_default_cell
)) {
2362 tty_putcode_ss(tty
, TTYC_HLS
, "", "");
2363 if ((gc
->attr
& GRID_ATTR_CHARSET
) && tty_acs_needed(tty
))
2364 tty_putcode(tty
, TTYC_RMACS
);
2365 tty_putcode(tty
, TTYC_SGR0
);
2366 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
2368 memcpy(&tty
->last_cell
, &grid_default_cell
, sizeof tty
->last_cell
);
2372 tty_invalidate(struct tty
*tty
)
2374 memcpy(&tty
->cell
, &grid_default_cell
, sizeof tty
->cell
);
2375 memcpy(&tty
->last_cell
, &grid_default_cell
, sizeof tty
->last_cell
);
2377 tty
->cx
= tty
->cy
= UINT_MAX
;
2378 tty
->rupper
= tty
->rleft
= UINT_MAX
;
2379 tty
->rlower
= tty
->rright
= UINT_MAX
;
2381 if (tty
->flags
& TTY_STARTED
) {
2382 if (tty_use_margin(tty
))
2383 tty_putcode(tty
, TTYC_ENMG
);
2384 tty_putcode(tty
, TTYC_SGR0
);
2386 tty
->mode
= ALL_MODES
;
2387 tty_update_mode(tty
, MODE_CURSOR
, NULL
);
2389 tty_cursor(tty
, 0, 0);
2390 tty_region_off(tty
);
2391 tty_margin_off(tty
);
2393 tty
->mode
= MODE_CURSOR
;
2396 /* Turn off margin. */
2398 tty_region_off(struct tty
*tty
)
2400 tty_region(tty
, 0, tty
->sy
- 1);
2403 /* Set region inside pane. */
2405 tty_region_pane(struct tty
*tty
, const struct tty_ctx
*ctx
, u_int rupper
,
2408 tty_region(tty
, ctx
->yoff
+ rupper
- ctx
->woy
,
2409 ctx
->yoff
+ rlower
- ctx
->woy
);
2412 /* Set region at absolute position. */
2414 tty_region(struct tty
*tty
, u_int rupper
, u_int rlower
)
2416 if (tty
->rlower
== rlower
&& tty
->rupper
== rupper
)
2418 if (!tty_term_has(tty
->term
, TTYC_CSR
))
2421 tty
->rupper
= rupper
;
2422 tty
->rlower
= rlower
;
2425 * Some terminals (such as PuTTY) do not correctly reset the cursor to
2426 * 0,0 if it is beyond the last column (they do not reset their wrap
2427 * flag so further output causes a line feed). As a workaround, do an
2428 * explicit move to 0 first.
2430 if (tty
->cx
>= tty
->sx
) {
2431 if (tty
->cy
== UINT_MAX
)
2432 tty_cursor(tty
, 0, 0);
2434 tty_cursor(tty
, 0, tty
->cy
);
2437 tty_putcode_ii(tty
, TTYC_CSR
, tty
->rupper
, tty
->rlower
);
2438 tty
->cx
= tty
->cy
= UINT_MAX
;
2441 /* Turn off margin. */
2443 tty_margin_off(struct tty
*tty
)
2445 tty_margin(tty
, 0, tty
->sx
- 1);
2448 /* Set margin inside pane. */
2450 tty_margin_pane(struct tty
*tty
, const struct tty_ctx
*ctx
)
2452 tty_margin(tty
, ctx
->xoff
- ctx
->wox
,
2453 ctx
->xoff
+ ctx
->sx
- 1 - ctx
->wox
);
2456 /* Set margin at absolute position. */
2458 tty_margin(struct tty
*tty
, u_int rleft
, u_int rright
)
2460 if (!tty_use_margin(tty
))
2462 if (tty
->rleft
== rleft
&& tty
->rright
== rright
)
2465 tty_putcode_ii(tty
, TTYC_CSR
, tty
->rupper
, tty
->rlower
);
2468 tty
->rright
= rright
;
2470 if (rleft
== 0 && rright
== tty
->sx
- 1)
2471 tty_putcode(tty
, TTYC_CLMG
);
2473 tty_putcode_ii(tty
, TTYC_CMG
, rleft
, rright
);
2474 tty
->cx
= tty
->cy
= UINT_MAX
;
2478 * Move the cursor, unless it would wrap itself when the next character is
2482 tty_cursor_pane_unless_wrap(struct tty
*tty
, const struct tty_ctx
*ctx
,
2485 if (!ctx
->wrapped
||
2486 !tty_full_width(tty
, ctx
) ||
2487 (tty
->term
->flags
& TERM_NOAM
) ||
2488 ctx
->xoff
+ cx
!= 0 ||
2489 ctx
->yoff
+ cy
!= tty
->cy
+ 1 ||
2490 tty
->cx
< tty
->sx
||
2491 tty
->cy
== tty
->rlower
)
2492 tty_cursor_pane(tty
, ctx
, cx
, cy
);
2494 log_debug("%s: will wrap at %u,%u", __func__
, tty
->cx
, tty
->cy
);
2497 /* Move cursor inside pane. */
2499 tty_cursor_pane(struct tty
*tty
, const struct tty_ctx
*ctx
, u_int cx
, u_int cy
)
2501 tty_cursor(tty
, ctx
->xoff
+ cx
- ctx
->wox
, ctx
->yoff
+ cy
- ctx
->woy
);
2504 /* Move cursor to absolute position. */
2506 tty_cursor(struct tty
*tty
, u_int cx
, u_int cy
)
2508 struct tty_term
*term
= tty
->term
;
2512 if (tty
->flags
& TTY_BLOCK
)
2519 * If in the automargin space, and want to be there, do not move.
2520 * Otherwise, force the cursor to be in range (and complain).
2522 if (cx
== thisx
&& cy
== thisy
&& cx
== tty
->sx
)
2524 if (cx
> tty
->sx
- 1) {
2525 log_debug("%s: x too big %u > %u", __func__
, cx
, tty
->sx
- 1);
2530 if (cx
== thisx
&& cy
== thisy
)
2533 /* Currently at the very end of the line - use absolute movement. */
2534 if (thisx
> tty
->sx
- 1)
2537 /* Move to home position (0, 0). */
2538 if (cx
== 0 && cy
== 0 && tty_term_has(term
, TTYC_HOME
)) {
2539 tty_putcode(tty
, TTYC_HOME
);
2543 /* Zero on the next line. */
2544 if (cx
== 0 && cy
== thisy
+ 1 && thisy
!= tty
->rlower
&&
2545 (!tty_use_margin(tty
) || tty
->rleft
== 0)) {
2546 tty_putc(tty
, '\r');
2547 tty_putc(tty
, '\n');
2551 /* Moving column or row. */
2554 * Moving column only, row staying the same.
2558 if (cx
== 0 && (!tty_use_margin(tty
) || tty
->rleft
== 0)) {
2559 tty_putc(tty
, '\r');
2563 /* One to the left. */
2564 if (cx
== thisx
- 1 && tty_term_has(term
, TTYC_CUB1
)) {
2565 tty_putcode(tty
, TTYC_CUB1
);
2569 /* One to the right. */
2570 if (cx
== thisx
+ 1 && tty_term_has(term
, TTYC_CUF1
)) {
2571 tty_putcode(tty
, TTYC_CUF1
);
2575 /* Calculate difference. */
2576 change
= thisx
- cx
; /* +ve left, -ve right */
2579 * Use HPA if change is larger than absolute, otherwise move
2580 * the cursor with CUB/CUF.
2582 if ((u_int
) abs(change
) > cx
&& tty_term_has(term
, TTYC_HPA
)) {
2583 tty_putcode_i(tty
, TTYC_HPA
, cx
);
2585 } else if (change
> 0 &&
2586 tty_term_has(term
, TTYC_CUB
) &&
2587 !tty_use_margin(tty
)) {
2588 if (change
== 2 && tty_term_has(term
, TTYC_CUB1
)) {
2589 tty_putcode(tty
, TTYC_CUB1
);
2590 tty_putcode(tty
, TTYC_CUB1
);
2593 tty_putcode_i(tty
, TTYC_CUB
, change
);
2595 } else if (change
< 0 &&
2596 tty_term_has(term
, TTYC_CUF
) &&
2597 !tty_use_margin(tty
)) {
2598 tty_putcode_i(tty
, TTYC_CUF
, -change
);
2601 } else if (cx
== thisx
) {
2603 * Moving row only, column staying the same.
2607 if (thisy
!= tty
->rupper
&&
2608 cy
== thisy
- 1 && tty_term_has(term
, TTYC_CUU1
)) {
2609 tty_putcode(tty
, TTYC_CUU1
);
2614 if (thisy
!= tty
->rlower
&&
2615 cy
== thisy
+ 1 && tty_term_has(term
, TTYC_CUD1
)) {
2616 tty_putcode(tty
, TTYC_CUD1
);
2620 /* Calculate difference. */
2621 change
= thisy
- cy
; /* +ve up, -ve down */
2624 * Try to use VPA if change is larger than absolute or if this
2625 * change would cross the scroll region, otherwise use CUU/CUD.
2627 if ((u_int
) abs(change
) > cy
||
2628 (change
< 0 && cy
- change
> tty
->rlower
) ||
2629 (change
> 0 && cy
- change
< tty
->rupper
)) {
2630 if (tty_term_has(term
, TTYC_VPA
)) {
2631 tty_putcode_i(tty
, TTYC_VPA
, cy
);
2634 } else if (change
> 0 && tty_term_has(term
, TTYC_CUU
)) {
2635 tty_putcode_i(tty
, TTYC_CUU
, change
);
2637 } else if (change
< 0 && tty_term_has(term
, TTYC_CUD
)) {
2638 tty_putcode_i(tty
, TTYC_CUD
, -change
);
2644 /* Absolute movement. */
2645 tty_putcode_ii(tty
, TTYC_CUP
, cy
, cx
);
2653 tty_hyperlink(struct tty
*tty
, const struct grid_cell
*gc
,
2654 struct hyperlinks
*hl
)
2656 const char *uri
, *id
;
2658 if (gc
->link
== tty
->cell
.link
)
2660 tty
->cell
.link
= gc
->link
;
2665 if (gc
->link
== 0 || !hyperlinks_get(hl
, gc
->link
, &uri
, NULL
, &id
))
2666 tty_putcode_ss(tty
, TTYC_HLS
, "", "");
2668 tty_putcode_ss(tty
, TTYC_HLS
, id
, uri
);
2672 tty_attributes(struct tty
*tty
, const struct grid_cell
*gc
,
2673 const struct grid_cell
*defaults
, struct colour_palette
*palette
,
2674 struct hyperlinks
*hl
)
2676 struct grid_cell
*tc
= &tty
->cell
, gc2
;
2679 /* Copy cell and update default colours. */
2680 memcpy(&gc2
, gc
, sizeof gc2
);
2681 if (~gc
->flags
& GRID_FLAG_NOPALETTE
) {
2683 gc2
.fg
= defaults
->fg
;
2685 gc2
.bg
= defaults
->bg
;
2688 /* Ignore cell if it is the same as the last one. */
2689 if (gc2
.attr
== tty
->last_cell
.attr
&&
2690 gc2
.fg
== tty
->last_cell
.fg
&&
2691 gc2
.bg
== tty
->last_cell
.bg
&&
2692 gc2
.us
== tty
->last_cell
.us
&&
2693 gc2
.link
== tty
->last_cell
.link
)
2697 * If no setab, try to use the reverse attribute as a best-effort for a
2698 * non-default background. This is a bit of a hack but it doesn't do
2699 * any serious harm and makes a couple of applications happier.
2701 if (!tty_term_has(tty
->term
, TTYC_SETAB
)) {
2702 if (gc2
.attr
& GRID_ATTR_REVERSE
) {
2703 if (gc2
.fg
!= 7 && !COLOUR_DEFAULT(gc2
.fg
))
2704 gc2
.attr
&= ~GRID_ATTR_REVERSE
;
2706 if (gc2
.bg
!= 0 && !COLOUR_DEFAULT(gc2
.bg
))
2707 gc2
.attr
|= GRID_ATTR_REVERSE
;
2711 /* Fix up the colours if necessary. */
2712 tty_check_fg(tty
, palette
, &gc2
);
2713 tty_check_bg(tty
, palette
, &gc2
);
2714 tty_check_us(tty
, palette
, &gc2
);
2717 * If any bits are being cleared or the underline colour is now default,
2720 if ((tc
->attr
& ~gc2
.attr
) || (tc
->us
!= gc2
.us
&& gc2
.us
== 0))
2724 * Set the colours. This may call tty_reset() (so it comes next) and
2725 * may add to (NOT remove) the desired attributes.
2727 tty_colours(tty
, &gc2
);
2729 /* Filter out attribute bits already set. */
2730 changed
= gc2
.attr
& ~tc
->attr
;
2731 tc
->attr
= gc2
.attr
;
2733 /* Set the attributes. */
2734 if (changed
& GRID_ATTR_BRIGHT
)
2735 tty_putcode(tty
, TTYC_BOLD
);
2736 if (changed
& GRID_ATTR_DIM
)
2737 tty_putcode(tty
, TTYC_DIM
);
2738 if (changed
& GRID_ATTR_ITALICS
)
2739 tty_set_italics(tty
);
2740 if (changed
& GRID_ATTR_ALL_UNDERSCORE
) {
2741 if ((changed
& GRID_ATTR_UNDERSCORE
) ||
2742 !tty_term_has(tty
->term
, TTYC_SMULX
))
2743 tty_putcode(tty
, TTYC_SMUL
);
2744 else if (changed
& GRID_ATTR_UNDERSCORE_2
)
2745 tty_putcode_i(tty
, TTYC_SMULX
, 2);
2746 else if (changed
& GRID_ATTR_UNDERSCORE_3
)
2747 tty_putcode_i(tty
, TTYC_SMULX
, 3);
2748 else if (changed
& GRID_ATTR_UNDERSCORE_4
)
2749 tty_putcode_i(tty
, TTYC_SMULX
, 4);
2750 else if (changed
& GRID_ATTR_UNDERSCORE_5
)
2751 tty_putcode_i(tty
, TTYC_SMULX
, 5);
2753 if (changed
& GRID_ATTR_BLINK
)
2754 tty_putcode(tty
, TTYC_BLINK
);
2755 if (changed
& GRID_ATTR_REVERSE
) {
2756 if (tty_term_has(tty
->term
, TTYC_REV
))
2757 tty_putcode(tty
, TTYC_REV
);
2758 else if (tty_term_has(tty
->term
, TTYC_SMSO
))
2759 tty_putcode(tty
, TTYC_SMSO
);
2761 if (changed
& GRID_ATTR_HIDDEN
)
2762 tty_putcode(tty
, TTYC_INVIS
);
2763 if (changed
& GRID_ATTR_STRIKETHROUGH
)
2764 tty_putcode(tty
, TTYC_SMXX
);
2765 if (changed
& GRID_ATTR_OVERLINE
)
2766 tty_putcode(tty
, TTYC_SMOL
);
2767 if ((changed
& GRID_ATTR_CHARSET
) && tty_acs_needed(tty
))
2768 tty_putcode(tty
, TTYC_SMACS
);
2770 /* Set hyperlink if any. */
2771 tty_hyperlink(tty
, gc
, hl
);
2773 memcpy(&tty
->last_cell
, &gc2
, sizeof tty
->last_cell
);
2777 tty_colours(struct tty
*tty
, const struct grid_cell
*gc
)
2779 struct grid_cell
*tc
= &tty
->cell
;
2782 /* No changes? Nothing is necessary. */
2783 if (gc
->fg
== tc
->fg
&& gc
->bg
== tc
->bg
&& gc
->us
== tc
->us
)
2787 * Is either the default colour? This is handled specially because the
2788 * best solution might be to reset both colours to default, in which
2789 * case if only one is default need to fall onward to set the other
2792 if (COLOUR_DEFAULT(gc
->fg
) || COLOUR_DEFAULT(gc
->bg
)) {
2794 * If don't have AX but do have op, send sgr0 (op can't
2795 * actually be used because it is sometimes the same as sgr0
2796 * and sometimes isn't). This resets both colours to default.
2798 * Otherwise, try to set the default colour only as needed.
2800 have_ax
= tty_term_flag(tty
->term
, TTYC_AX
);
2801 if (!have_ax
&& tty_term_has(tty
->term
, TTYC_OP
))
2804 if (COLOUR_DEFAULT(gc
->fg
) && !COLOUR_DEFAULT(tc
->fg
)) {
2806 tty_puts(tty
, "\033[39m");
2807 else if (tc
->fg
!= 7)
2808 tty_putcode_i(tty
, TTYC_SETAF
, 7);
2811 if (COLOUR_DEFAULT(gc
->bg
) && !COLOUR_DEFAULT(tc
->bg
)) {
2813 tty_puts(tty
, "\033[49m");
2814 else if (tc
->bg
!= 0)
2815 tty_putcode_i(tty
, TTYC_SETAB
, 0);
2821 /* Set the foreground colour. */
2822 if (!COLOUR_DEFAULT(gc
->fg
) && gc
->fg
!= tc
->fg
)
2823 tty_colours_fg(tty
, gc
);
2826 * Set the background colour. This must come after the foreground as
2827 * tty_colour_fg() can call tty_reset().
2829 if (!COLOUR_DEFAULT(gc
->bg
) && gc
->bg
!= tc
->bg
)
2830 tty_colours_bg(tty
, gc
);
2832 /* Set the underscore colour. */
2833 if (gc
->us
!= tc
->us
)
2834 tty_colours_us(tty
, gc
);
2838 tty_check_fg(struct tty
*tty
, struct colour_palette
*palette
,
2839 struct grid_cell
*gc
)
2846 * Perform substitution if this pane has a palette. If the bright
2847 * attribute is set and Nobr is not present, use the bright entry in
2848 * the palette by changing to the aixterm colour
2850 if (~gc
->flags
& GRID_FLAG_NOPALETTE
) {
2853 gc
->attr
& GRID_ATTR_BRIGHT
&&
2854 !tty_term_has(tty
->term
, TTYC_NOBR
))
2856 if ((c
= colour_palette_get(palette
, c
)) != -1)
2860 /* Is this a 24-bit colour? */
2861 if (gc
->fg
& COLOUR_FLAG_RGB
) {
2862 /* Not a 24-bit terminal? Translate to 256-colour palette. */
2863 if (tty
->term
->flags
& TERM_RGBCOLOURS
)
2865 colour_split_rgb(gc
->fg
, &r
, &g
, &b
);
2866 gc
->fg
= colour_find_rgb(r
, g
, b
);
2869 /* How many colours does this terminal have? */
2870 if (tty
->term
->flags
& TERM_256COLOURS
)
2873 colours
= tty_term_number(tty
->term
, TTYC_COLORS
);
2875 /* Is this a 256-colour colour? */
2876 if (gc
->fg
& COLOUR_FLAG_256
) {
2877 /* And not a 256 colour mode? */
2878 if (colours
< 256) {
2879 gc
->fg
= colour_256to16(gc
->fg
);
2889 /* Is this an aixterm colour? */
2890 if (gc
->fg
>= 90 && gc
->fg
<= 97 && colours
< 16) {
2892 gc
->attr
|= GRID_ATTR_BRIGHT
;
2897 tty_check_bg(struct tty
*tty
, struct colour_palette
*palette
,
2898 struct grid_cell
*gc
)
2904 /* Perform substitution if this pane has a palette. */
2905 if (~gc
->flags
& GRID_FLAG_NOPALETTE
) {
2906 if ((c
= colour_palette_get(palette
, gc
->bg
)) != -1)
2910 /* Is this a 24-bit colour? */
2911 if (gc
->bg
& COLOUR_FLAG_RGB
) {
2912 /* Not a 24-bit terminal? Translate to 256-colour palette. */
2913 if (tty
->term
->flags
& TERM_RGBCOLOURS
)
2915 colour_split_rgb(gc
->bg
, &r
, &g
, &b
);
2916 gc
->bg
= colour_find_rgb(r
, g
, b
);
2919 /* How many colours does this terminal have? */
2920 if (tty
->term
->flags
& TERM_256COLOURS
)
2923 colours
= tty_term_number(tty
->term
, TTYC_COLORS
);
2925 /* Is this a 256-colour colour? */
2926 if (gc
->bg
& COLOUR_FLAG_256
) {
2928 * And not a 256 colour mode? Translate to 16-colour
2929 * palette. Bold background doesn't exist portably, so just
2930 * discard the bold bit if set.
2932 if (colours
< 256) {
2933 gc
->bg
= colour_256to16(gc
->bg
);
2943 /* Is this an aixterm colour? */
2944 if (gc
->bg
>= 90 && gc
->bg
<= 97 && colours
< 16)
2949 tty_check_us(__unused
struct tty
*tty
, struct colour_palette
*palette
,
2950 struct grid_cell
*gc
)
2954 /* Perform substitution if this pane has a palette. */
2955 if (~gc
->flags
& GRID_FLAG_NOPALETTE
) {
2956 if ((c
= colour_palette_get(palette
, gc
->us
)) != -1)
2960 /* Convert underscore colour if only RGB can be supported. */
2961 if (!tty_term_has(tty
->term
, TTYC_SETULC1
)) {
2962 if ((c
= colour_force_rgb (gc
->us
)) == -1)
2970 tty_colours_fg(struct tty
*tty
, const struct grid_cell
*gc
)
2972 struct grid_cell
*tc
= &tty
->cell
;
2975 /* Is this a 24-bit or 256-colour colour? */
2976 if (gc
->fg
& COLOUR_FLAG_RGB
|| gc
->fg
& COLOUR_FLAG_256
) {
2977 if (tty_try_colour(tty
, gc
->fg
, "38") == 0)
2979 /* Should not get here, already converted in tty_check_fg. */
2983 /* Is this an aixterm bright colour? */
2984 if (gc
->fg
>= 90 && gc
->fg
<= 97) {
2985 if (tty
->term
->flags
& TERM_256COLOURS
) {
2986 xsnprintf(s
, sizeof s
, "\033[%dm", gc
->fg
);
2989 tty_putcode_i(tty
, TTYC_SETAF
, gc
->fg
- 90 + 8);
2993 /* Otherwise set the foreground colour. */
2994 tty_putcode_i(tty
, TTYC_SETAF
, gc
->fg
);
2997 /* Save the new values in the terminal current cell. */
3002 tty_colours_bg(struct tty
*tty
, const struct grid_cell
*gc
)
3004 struct grid_cell
*tc
= &tty
->cell
;
3007 /* Is this a 24-bit or 256-colour colour? */
3008 if (gc
->bg
& COLOUR_FLAG_RGB
|| gc
->bg
& COLOUR_FLAG_256
) {
3009 if (tty_try_colour(tty
, gc
->bg
, "48") == 0)
3011 /* Should not get here, already converted in tty_check_bg. */
3015 /* Is this an aixterm bright colour? */
3016 if (gc
->bg
>= 90 && gc
->bg
<= 97) {
3017 if (tty
->term
->flags
& TERM_256COLOURS
) {
3018 xsnprintf(s
, sizeof s
, "\033[%dm", gc
->bg
+ 10);
3021 tty_putcode_i(tty
, TTYC_SETAB
, gc
->bg
- 90 + 8);
3025 /* Otherwise set the background colour. */
3026 tty_putcode_i(tty
, TTYC_SETAB
, gc
->bg
);
3029 /* Save the new values in the terminal current cell. */
3034 tty_colours_us(struct tty
*tty
, const struct grid_cell
*gc
)
3036 struct grid_cell
*tc
= &tty
->cell
;
3040 /* Clear underline colour. */
3041 if (COLOUR_DEFAULT(gc
->us
)) {
3042 tty_putcode(tty
, TTYC_OL
);
3047 * If this is not an RGB colour, use Setulc1 if it exists, otherwise
3050 if (~gc
->us
& COLOUR_FLAG_RGB
) {
3052 if ((~c
& COLOUR_FLAG_256
) && (c
>= 90 && c
<= 97))
3054 tty_putcode_i(tty
, TTYC_SETULC1
, c
& ~COLOUR_FLAG_256
);
3059 * Setulc and setal follows the ncurses(3) one argument "direct colour"
3060 * capability format. Calculate the colour value.
3062 colour_split_rgb(gc
->us
, &r
, &g
, &b
);
3063 c
= (65536 * r
) + (256 * g
) + b
;
3066 * Write the colour. Only use setal if the RGB flag is set because the
3067 * non-RGB version may be wrong.
3069 if (tty_term_has(tty
->term
, TTYC_SETULC
))
3070 tty_putcode_i(tty
, TTYC_SETULC
, c
);
3071 else if (tty_term_has(tty
->term
, TTYC_SETAL
) &&
3072 tty_term_has(tty
->term
, TTYC_RGB
))
3073 tty_putcode_i(tty
, TTYC_SETAL
, c
);
3076 /* Save the new values in the terminal current cell. */
3081 tty_try_colour(struct tty
*tty
, int colour
, const char *type
)
3085 if (colour
& COLOUR_FLAG_256
) {
3086 if (*type
== '3' && tty_term_has(tty
->term
, TTYC_SETAF
))
3087 tty_putcode_i(tty
, TTYC_SETAF
, colour
& 0xff);
3088 else if (tty_term_has(tty
->term
, TTYC_SETAB
))
3089 tty_putcode_i(tty
, TTYC_SETAB
, colour
& 0xff);
3093 if (colour
& COLOUR_FLAG_RGB
) {
3094 colour_split_rgb(colour
& 0xffffff, &r
, &g
, &b
);
3095 if (*type
== '3' && tty_term_has(tty
->term
, TTYC_SETRGBF
))
3096 tty_putcode_iii(tty
, TTYC_SETRGBF
, r
, g
, b
);
3097 else if (tty_term_has(tty
->term
, TTYC_SETRGBB
))
3098 tty_putcode_iii(tty
, TTYC_SETRGBB
, r
, g
, b
);
3106 tty_window_default_style(struct grid_cell
*gc
, struct window_pane
*wp
)
3108 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
3109 gc
->fg
= wp
->palette
.fg
;
3110 gc
->bg
= wp
->palette
.bg
;
3114 tty_default_colours(struct grid_cell
*gc
, struct window_pane
*wp
)
3116 struct options
*oo
= wp
->options
;
3117 struct format_tree
*ft
;
3119 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
3121 if (wp
->flags
& PANE_STYLECHANGED
) {
3122 log_debug("%%%u: style changed", wp
->id
);
3123 wp
->flags
&= ~PANE_STYLECHANGED
;
3125 ft
= format_create(NULL
, NULL
, FORMAT_PANE
|wp
->id
,
3127 format_defaults(ft
, NULL
, NULL
, NULL
, wp
);
3128 tty_window_default_style(&wp
->cached_active_gc
, wp
);
3129 style_add(&wp
->cached_active_gc
, oo
, "window-active-style", ft
);
3130 tty_window_default_style(&wp
->cached_gc
, wp
);
3131 style_add(&wp
->cached_gc
, oo
, "window-style", ft
);
3136 if (wp
== wp
->window
->active
&& wp
->cached_active_gc
.fg
!= 8)
3137 gc
->fg
= wp
->cached_active_gc
.fg
;
3139 gc
->fg
= wp
->cached_gc
.fg
;
3143 if (wp
== wp
->window
->active
&& wp
->cached_active_gc
.bg
!= 8)
3144 gc
->bg
= wp
->cached_active_gc
.bg
;
3146 gc
->bg
= wp
->cached_gc
.bg
;
3151 tty_default_attributes(struct tty
*tty
, const struct grid_cell
*defaults
,
3152 struct colour_palette
*palette
, u_int bg
, struct hyperlinks
*hl
)
3154 struct grid_cell gc
;
3156 memcpy(&gc
, &grid_default_cell
, sizeof gc
);
3158 tty_attributes(tty
, &gc
, defaults
, palette
, hl
);
3162 tty_clipboard_query_callback(__unused
int fd
, __unused
short events
, void *data
)
3164 struct tty
*tty
= data
;
3165 struct client
*c
= tty
->client
;
3167 c
->flags
&= ~CLIENT_CLIPBOARDBUFFER
;
3168 free(c
->clipboard_panes
);
3169 c
->clipboard_panes
= NULL
;
3170 c
->clipboard_npanes
= 0;
3172 tty
->flags
&= ~TTY_OSC52QUERY
;
3176 tty_clipboard_query(struct tty
*tty
)
3178 struct timeval tv
= { .tv_sec
= TTY_QUERY_TIMEOUT
};
3180 if ((~tty
->flags
& TTY_STARTED
) || (tty
->flags
& TTY_OSC52QUERY
))
3182 tty_putcode_ss(tty
, TTYC_MS
, "", "?");
3184 tty
->flags
|= TTY_OSC52QUERY
;
3185 evtimer_set(&tty
->clipboard_timer
, tty_clipboard_query_callback
, tty
);
3186 evtimer_add(&tty
->clipboard_timer
, &tv
);