From b2443aa2f98c1a1fa5d53d4e79a3e7fd221cc365 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 16 Apr 2020 13:35:24 +0000 Subject: [PATCH 1/3] Add support for the iTerm2 sychronized updates escape sequence which drastically reduces flickering. --- screen-redraw.c | 6 ++++++ screen-write.c | 11 ++++++++++- tmux.1 | 2 ++ tmux.h | 6 ++++++ tty-keys.c | 2 +- tty-term.c | 5 +++++ tty.c | 26 ++++++++++++++++++++++++++ 7 files changed, 56 insertions(+), 2 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index 211f7f79..c510fb68 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -435,6 +435,7 @@ screen_redraw_screen(struct client *c) flags = screen_redraw_update(c, c->flags); screen_redraw_set_context(c, &ctx); + tty_sync_start(&c->tty); if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) { if (ctx.pane_status != PANE_STATUS_OFF) @@ -448,7 +449,9 @@ screen_redraw_screen(struct client *c) screen_redraw_draw_status(&ctx); if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) c->overlay_draw(c, &ctx); + tty_reset(&c->tty); + tty_sync_end(&c->tty); } /* Redraw a single pane. */ @@ -461,9 +464,12 @@ screen_redraw_pane(struct client *c, struct window_pane *wp) return; screen_redraw_set_context(c, &ctx); + tty_sync_start(&c->tty); screen_redraw_draw_pane(&ctx, wp); + tty_reset(&c->tty); + tty_sync_end(&c->tty); } /* Draw a border cell. */ diff --git a/screen-write.c b/screen-write.c index b2f9e223..3e7fa66b 100644 --- a/screen-write.c +++ b/screen-write.c @@ -100,7 +100,8 @@ void screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp, struct screen *s) { - u_int y; + struct tty_ctx ttyctx; + u_int y; memset(ctx, 0, sizeof *ctx); @@ -129,18 +130,26 @@ screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp, screen_size_y(ctx->s)); } } + + screen_write_initctx(ctx, &ttyctx); + tty_write(tty_cmd_syncstart, &ttyctx); } /* Finish writing. */ void screen_write_stop(struct screen_write_ctx *ctx) { + struct tty_ctx ttyctx; + screen_write_collect_end(ctx); screen_write_collect_flush(ctx, 0); log_debug("%s: %u cells (%u written, %u skipped)", __func__, ctx->cells, ctx->written, ctx->skipped); + screen_write_initctx(ctx, &ttyctx); + tty_write(tty_cmd_syncend, &ttyctx); + free(ctx->item); free(ctx->list); /* flush will have emptied */ } diff --git a/tmux.1 b/tmux.1 index 81a5c613..fd022c9e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -5511,6 +5511,8 @@ $ printf '\e033[4 q' If .Em Se is not set, \&Ss with argument 0 will be used to reset the cursor style instead. +.It Em \&Sync +Show that the terminal supports synchronized updates. .It Em \&Tc Indicate that the terminal supports the .Ql direct colour diff --git a/tmux.h b/tmux.h index 98d78a63..87d38ef3 100644 --- a/tmux.h +++ b/tmux.h @@ -452,6 +452,7 @@ enum tty_code_code { TTYC_SMUL, TTYC_SMXX, TTYC_SS, + TTYC_SYNC, TTYC_TC, TTYC_TSL, TTYC_U8, @@ -1181,6 +1182,7 @@ struct tty_term { #define TERM_DECSLRM 0x4 #define TERM_DECFRA 0x8 #define TERM_RGBCOLOURS 0x10 +#define TERM_SYNC 0x20 int flags; LIST_ENTRY(tty_term) entry; @@ -1949,6 +1951,8 @@ void tty_set_title(struct tty *, const char *); void tty_update_mode(struct tty *, int, struct screen *); void tty_draw_line(struct tty *, struct window_pane *, struct screen *, u_int, u_int, u_int, u_int, u_int); +void tty_sync_start(struct tty *); +void tty_sync_end(struct tty *); int tty_open(struct tty *, char **); void tty_close(struct tty *); void tty_free(struct tty *); @@ -1976,6 +1980,8 @@ void tty_cmd_scrolldown(struct tty *, const struct tty_ctx *); void tty_cmd_reverseindex(struct tty *, const struct tty_ctx *); void tty_cmd_setselection(struct tty *, const struct tty_ctx *); void tty_cmd_rawstring(struct tty *, const struct tty_ctx *); +void tty_cmd_syncstart(struct tty *, const struct tty_ctx *); +void tty_cmd_syncend(struct tty *, const struct tty_ctx *); /* tty-term.c */ extern struct tty_terms tty_terms; diff --git a/tty-keys.c b/tty-keys.c index 064f2172..1fcc74b8 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1117,7 +1117,7 @@ tty_keys_device_status_report(struct tty *tty, const char *buf, size_t len, /* Set terminal flags. */ if (strncmp(tmp, "ITERM2 ", 7) == 0) - flags |= (TERM_DECSLRM|TERM_256COLOURS|TERM_RGBCOLOURS); + flags |= (TERM_DECSLRM|TERM_256COLOURS|TERM_RGBCOLOURS|TERM_SYNC); if (strncmp(tmp, "TMUX ", 5) == 0) flags |= (TERM_256COLOURS|TERM_RGBCOLOURS); log_debug("%s: received DSR %.*s", c->name, (int)*size, buf); diff --git a/tty-term.c b/tty-term.c index ef7d7905..d6faa6ff 100644 --- a/tty-term.c +++ b/tty-term.c @@ -260,6 +260,7 @@ static const struct tty_term_code_entry tty_term_codes[] = { [TTYC_SMUL] = { TTYCODE_STRING, "smul" }, [TTYC_SMXX] = { TTYCODE_STRING, "smxx" }, [TTYC_SS] = { TTYCODE_STRING, "Ss" }, + [TTYC_SYNC] = { TTYCODE_FLAG, "Sync" }, [TTYC_TC] = { TTYCODE_FLAG, "Tc" }, [TTYC_TSL] = { TTYCODE_STRING, "tsl" }, [TTYC_U8] = { TTYCODE_NUMBER, "U8" }, @@ -532,6 +533,10 @@ tty_term_find(char *name, int fd, char **cause) tty_term_has(term, TTYC_SETRGBB))) term->flags |= TERM_RGBCOLOURS; + /* Set flag if terminal has synchronized updates. */ + if (tty_term_flag(term, TTYC_SYNC)) + term->flags |= TERM_SYNC; + /* * Terminals without xenl (eat newline glitch) wrap at at $COLUMNS - 1 * rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1). diff --git a/tty.c b/tty.c index a7607cba..95c16fb8 100644 --- a/tty.c +++ b/tty.c @@ -1426,6 +1426,20 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s, tty_update_mode(tty, tty->mode, s); } +void +tty_sync_start(struct tty *tty) +{ + if ((tty->term->flags|tty->term_flags) & TERM_SYNC) + tty_puts(tty, "\033P=1s\033\\"); +} + +void +tty_sync_end(struct tty *tty) +{ + if ((tty->term->flags|tty->term_flags) & TERM_SYNC) + tty_puts(tty, "\033P=2s\033\\"); +} + static int tty_client_ready(struct client *c, struct window_pane *wp) { @@ -1919,6 +1933,18 @@ tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx) tty_invalidate(tty); } +void +tty_cmd_syncstart(struct tty *tty, __unused const struct tty_ctx *ctx) +{ + tty_sync_start(tty); +} + +void +tty_cmd_syncend(struct tty *tty, __unused const struct tty_ctx *ctx) +{ + tty_sync_end(tty); +} + static void tty_cell(struct tty *tty, const struct grid_cell *gc, struct window_pane *wp) { From 4744aa43af47815a9c4c110cceb3959b1662e54b Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 16 Apr 2020 14:03:51 +0000 Subject: [PATCH 2/3] Add a helper function to get the terminal flags. --- tmux.h | 1 + tty.c | 44 ++++++++++++++++++++++++++------------------ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/tmux.h b/tmux.h index 87d38ef3..dbf3244f 100644 --- a/tmux.h +++ b/tmux.h @@ -1957,6 +1957,7 @@ int tty_open(struct tty *, char **); void tty_close(struct tty *); void tty_free(struct tty *); void tty_set_flags(struct tty *, int); +int tty_get_flags(struct tty *); void tty_write(void (*)(struct tty *, const struct tty_ctx *), struct tty_ctx *); void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *); diff --git a/tty.c b/tty.c index 95c16fb8..a068c1a6 100644 --- a/tty.c +++ b/tty.c @@ -74,7 +74,7 @@ static void tty_default_attributes(struct tty *, struct window_pane *, u_int); #define tty_use_margin(tty) \ - ((tty->term->flags|tty->term_flags) & TERM_DECSLRM) + (tty_get_flags(tty) & TERM_DECSLRM) #define tty_pane_full_width(tty, ctx) \ ((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx) @@ -478,6 +478,14 @@ tty_set_flags(struct tty *tty, int flags) tty_puts(tty, "\033[?69h"); /* DECLRMM */ } +int +tty_get_flags(struct tty *tty) +{ + if (tty->term != NULL) + return (tty->term->flags|tty->term_flags); + return (tty->term_flags); +} + void tty_raw(struct tty *tty, const char *s) { @@ -575,7 +583,7 @@ tty_putc(struct tty *tty, u_char ch) { const char *acs; - if ((tty->term->flags & TERM_NOXENL) && + if ((tty_get_flags(tty) & TERM_NOXENL) && ch >= 0x20 && ch != 0x7f && tty->cy == tty->sy - 1 && tty->cx + 1 >= tty->sx) @@ -601,7 +609,7 @@ tty_putc(struct tty *tty, u_char ch) * where we think it should be after a line wrap - this * means it works on sensible terminals as well. */ - if (tty->term->flags & TERM_NOXENL) + if (tty_get_flags(tty) & TERM_NOXENL) tty_putcode2(tty, TTYC_CUP, tty->cy, tty->cx); } else tty->cx++; @@ -611,7 +619,7 @@ tty_putc(struct tty *tty, u_char ch) void tty_putn(struct tty *tty, const void *buf, size_t len, u_int width) { - if ((tty->term->flags & TERM_NOXENL) && + if ((tty_get_flags(tty) & TERM_NOXENL) && tty->cy == tty->sy - 1 && tty->cx + len >= tty->sx) len = tty->sx - tty->cx - 1; @@ -1167,7 +1175,7 @@ tty_clear_area(struct tty *tty, struct window_pane *wp, u_int py, u_int ny, * background colour isn't default (because it doesn't work * after SGR 0). */ - if (((tty->term->flags|tty->term_flags) & TERM_DECFRA) && + if ((tty_get_flags(tty) & TERM_DECFRA) && !COLOUR_DEFAULT(bg)) { xsnprintf(tmp, sizeof tmp, "\033[32;%u;%u;%u;%u$x", py + 1, px + 1, py + ny, px + nx); @@ -1429,14 +1437,14 @@ tty_draw_line(struct tty *tty, struct window_pane *wp, struct screen *s, void tty_sync_start(struct tty *tty) { - if ((tty->term->flags|tty->term_flags) & TERM_SYNC) + if (tty_get_flags(tty) & TERM_SYNC) tty_puts(tty, "\033P=1s\033\\"); } void tty_sync_end(struct tty *tty) { - if ((tty->term->flags|tty->term_flags) & TERM_SYNC) + if (tty_get_flags(tty) & TERM_SYNC) tty_puts(tty, "\033P=2s\033\\"); } @@ -1890,7 +1898,7 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx) ctx->xoff + ctx->ocx + ctx->num > ctx->ox + ctx->sx)) { if (!ctx->wrapped || !tty_pane_full_width(tty, ctx) || - (tty->term->flags & TERM_NOXENL) || + (tty_get_flags(tty) & TERM_NOXENL) || ctx->xoff + ctx->ocx != 0 || ctx->yoff + ctx->ocy != tty->cy + 1 || tty->cx < tty->sx || @@ -1951,7 +1959,7 @@ tty_cell(struct tty *tty, const struct grid_cell *gc, struct window_pane *wp) const struct grid_cell *gcp; /* Skip last character if terminal is stupid. */ - if ((tty->term->flags & TERM_NOXENL) && + if ((tty_get_flags(tty) & TERM_NOXENL) && tty->cy == tty->sy - 1 && tty->cx == tty->sx - 1) return; @@ -2110,7 +2118,7 @@ tty_cursor_pane_unless_wrap(struct tty *tty, const struct tty_ctx *ctx, { if (!ctx->wrapped || !tty_pane_full_width(tty, ctx) || - (tty->term->flags & TERM_NOXENL) || + (tty_get_flags(tty) & TERM_NOXENL) || ctx->xoff + cx != 0 || ctx->yoff + cy != tty->cy + 1 || tty->cx < tty->sx || @@ -2447,14 +2455,14 @@ tty_check_fg(struct tty *tty, struct window_pane *wp, struct grid_cell *gc) /* Is this a 24-bit colour? */ if (gc->fg & COLOUR_FLAG_RGB) { /* Not a 24-bit terminal? Translate to 256-colour palette. */ - if ((tty->term->flags|tty->term_flags) & TERM_RGBCOLOURS) + if (tty_get_flags(tty) & TERM_RGBCOLOURS) return; colour_split_rgb(gc->fg, &r, &g, &b); gc->fg = colour_find_rgb(r, g, b); } /* How many colours does this terminal have? */ - if ((tty->term->flags|tty->term_flags) & TERM_256COLOURS) + if (tty_get_flags(tty) & TERM_256COLOURS) colours = 256; else colours = tty_term_number(tty->term, TTYC_COLORS); @@ -2496,14 +2504,14 @@ tty_check_bg(struct tty *tty, struct window_pane *wp, struct grid_cell *gc) /* Is this a 24-bit colour? */ if (gc->bg & COLOUR_FLAG_RGB) { /* Not a 24-bit terminal? Translate to 256-colour palette. */ - if ((tty->term->flags|tty->term_flags) & TERM_RGBCOLOURS) + if (tty_get_flags(tty) & TERM_RGBCOLOURS) return; colour_split_rgb(gc->bg, &r, &g, &b); gc->bg = colour_find_rgb(r, g, b); } /* How many colours does this terminal have? */ - if ((tty->term->flags|tty->term_flags) & TERM_256COLOURS) + if (tty_get_flags(tty) & TERM_256COLOURS) colours = 256; else colours = tty_term_number(tty->term, TTYC_COLORS); @@ -2564,7 +2572,7 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc) /* Is this an aixterm bright colour? */ if (gc->fg >= 90 && gc->fg <= 97) { - if (tty->term_flags & TERM_256COLOURS) { + if (tty_get_flags(tty) & TERM_256COLOURS) { xsnprintf(s, sizeof s, "\033[%dm", gc->fg); tty_puts(tty, s); } else @@ -2596,7 +2604,7 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc) /* Is this an aixterm bright colour? */ if (gc->bg >= 90 && gc->bg <= 97) { - if (tty->term_flags & TERM_256COLOURS) { + if (tty_get_flags(tty) & TERM_256COLOURS) { xsnprintf(s, sizeof s, "\033[%dm", gc->bg + 10); tty_puts(tty, s); } else @@ -2652,7 +2660,7 @@ tty_try_colour(struct tty *tty, int colour, const char *type) * Also if RGB is set, setaf and setab do not support the 256 * colour palette so use the sequences directly there too. */ - if ((tty->term_flags & TERM_256COLOURS) || + if ((tty_get_flags(tty) & TERM_256COLOURS) || tty_term_has(tty->term, TTYC_RGB)) goto fallback_256; @@ -2660,7 +2668,7 @@ tty_try_colour(struct tty *tty, int colour, const char *type) * If the terminfo entry has 256 colours and setaf and setab * exist, assume that they work correctly. */ - if (tty->term->flags & TERM_256COLOURS) { + if (tty_get_flags(tty) & TERM_256COLOURS) { if (*type == '3') { if (!tty_term_has(tty->term, TTYC_SETAF)) goto fallback_256; From 5ec80bd249a37147207ec2ef420086336ccf78a8 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 16 Apr 2020 14:25:35 +0000 Subject: [PATCH 3/3] Move the UTF-8 flag to terminal flags. --- format.c | 2 +- server-client.c | 2 +- tmux.h | 3 ++- tty-acs.c | 2 +- tty.c | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/format.c b/format.c index fd3b45b9..f2387f7a 100644 --- a/format.c +++ b/format.c @@ -2569,7 +2569,7 @@ format_defaults_client(struct format_tree *ft, struct client *c) format_add(ft, "client_prefix", "%d", 1); format_add(ft, "client_key_table", "%s", c->keytable->name); - if (tty->flags & TTY_UTF8) + if (tty_get_flags(tty) & TERM_UTF8) format_add(ft, "client_utf8", "%d", 1); else format_add(ft, "client_utf8", "%d", 0); diff --git a/server-client.c b/server-client.c index 8042da9a..1b27ae20 100644 --- a/server-client.c +++ b/server-client.c @@ -2056,7 +2056,7 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg) c->fd = -1; } else { if (c->flags & CLIENT_UTF8) - c->tty.flags |= TTY_UTF8; + c->tty.term_flags |= TERM_UTF8; if (c->flags & CLIENT_256COLOURS) c->tty.term_flags |= TERM_256COLOURS; tty_resize(&c->tty); diff --git a/tmux.h b/tmux.h index dbf3244f..58840108 100644 --- a/tmux.h +++ b/tmux.h @@ -1183,6 +1183,7 @@ struct tty_term { #define TERM_DECFRA 0x8 #define TERM_RGBCOLOURS 0x10 #define TERM_SYNC 0x20 +#define TERM_UTF8 0x40 int flags; LIST_ENTRY(tty_term) entry; @@ -1235,7 +1236,7 @@ struct tty { #define TTY_NOCURSOR 0x1 #define TTY_FREEZE 0x2 #define TTY_TIMER 0x4 -#define TTY_UTF8 0x8 +/* 0x8 unused */ #define TTY_STARTED 0x10 #define TTY_OPENED 0x20 #define TTY_FOCUS 0x40 diff --git a/tty-acs.c b/tty-acs.c index 14634120..f5352d3e 100644 --- a/tty-acs.c +++ b/tty-acs.c @@ -99,7 +99,7 @@ tty_acs_needed(struct tty *tty) tty_term_number(tty->term, TTYC_U8) == 0) return (1); - if (tty->flags & TTY_UTF8) + if (tty_get_flags(tty) & TERM_UTF8) return (0); return (1); } diff --git a/tty.c b/tty.c index a068c1a6..239d1cde 100644 --- a/tty.c +++ b/tty.c @@ -1255,7 +1255,7 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc) return (gc); /* UTF-8 terminal and a UTF-8 character - fine. */ - if (tty->flags & TTY_UTF8) + if (tty_get_flags(tty) & TERM_UTF8) return (gc); /* Replace by the right number of underscores. */