From 57100376cc70739f53a1f8a4bacf192b8cdcd124 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 3 Nov 2021 13:37:17 +0000 Subject: [PATCH] Add a cursor-style option, from Alexis Hildebrandt in GitHub issue 2960. --- input.c | 4 +++- options-table.c | 12 +++++++++++ options.c | 8 ++++++++ screen.c | 34 ++++++++++++++++--------------- tmux.1 | 10 +++++++++ tmux.h | 5 ++++- tty.c | 54 ++++++++++++++++++++++++++++++++----------------- 7 files changed, 91 insertions(+), 36 deletions(-) diff --git a/input.c b/input.c index b2769e31..3626c4b2 100644 --- a/input.c +++ b/input.c @@ -1619,7 +1619,7 @@ input_csi_dispatch(struct input_ctx *ictx) case INPUT_CSI_DECSCUSR: n = input_get(ictx, 0, 0, 0); if (n != -1) - screen_set_cursor_style(s, n); + screen_set_cursor_style(n, &s->cstyle, &s->mode); break; case INPUT_CSI_XDA: n = input_get(ictx, 0, 0, 0); @@ -1685,6 +1685,7 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx) break; case 12: screen_write_mode_clear(sctx, MODE_CURSOR_BLINKING); + screen_write_mode_set(sctx, MODE_CURSOR_BLINKING_SET); break; case 25: /* TCEM */ screen_write_mode_clear(sctx, MODE_CURSOR); @@ -1774,6 +1775,7 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx) break; case 12: screen_write_mode_set(sctx, MODE_CURSOR_BLINKING); + screen_write_mode_set(sctx, MODE_CURSOR_BLINKING_SET); break; case 25: /* TCEM */ screen_write_mode_set(sctx, MODE_CURSOR); diff --git a/options-table.c b/options-table.c index d23f7d57..bad22bfb 100644 --- a/options-table.c +++ b/options-table.c @@ -57,6 +57,10 @@ static const char *options_table_bell_action_list[] = { static const char *options_table_visual_bell_list[] = { "off", "on", "both", NULL }; +static const char *options_table_cursor_style_list[] = { + "default", "blinking-block", "block", "blinking-underline", "underline", + "blinking-bar", "bar", NULL +}; static const char *options_table_pane_status_list[] = { "off", "top", "bottom", NULL }; @@ -243,6 +247,14 @@ const struct options_table_entry options_table[] = { .text = "Colour of the cursor." }, + { .name = "cursor-style", + .type = OPTIONS_TABLE_CHOICE, + .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, + .choices = options_table_cursor_style_list, + .default_num = 0, + .text = "Style of the cursor." + }, + { .name = "default-terminal", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SERVER, diff --git a/options.c b/options.c index 4da1c408..865ab01f 100644 --- a/options.c +++ b/options.c @@ -1122,6 +1122,14 @@ options_push_changes(const char *name) wp->screen->default_ccolour = c; } } + if (strcmp(name, "cursor-style") == 0) { + RB_FOREACH(wp, window_pane_tree, &all_window_panes) { + wp->screen->default_mode = 0; + screen_set_cursor_style(options_get_number(wp->options, + name), &wp->screen->default_cstyle, + &wp->screen->default_mode); + } + } if (strcmp(name, "key-table") == 0) { TAILQ_FOREACH(loop, &clients, entry) server_client_set_key_table(loop, NULL); diff --git a/screen.c b/screen.c index bc95705a..da108866 100644 --- a/screen.c +++ b/screen.c @@ -82,6 +82,8 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit) s->path = NULL; s->cstyle = SCREEN_CURSOR_DEFAULT; + s->default_cstyle = SCREEN_CURSOR_DEFAULT; + s->default_mode = 0; s->ccolour = -1; s->default_ccolour = -1; s->tabs = NULL; @@ -152,38 +154,38 @@ screen_reset_tabs(struct screen *s) bit_set(s->tabs, i); } -/* Set screen cursor style. */ +/* Set screen cursor style and mode. */ void -screen_set_cursor_style(struct screen *s, u_int style) +screen_set_cursor_style(u_int style, enum screen_cursor_style *cstyle, + int *mode) { - log_debug("%s: new %u, was %u", __func__, style, s->cstyle); switch (style) { case 0: - s->cstyle = SCREEN_CURSOR_DEFAULT; + *cstyle = SCREEN_CURSOR_DEFAULT; break; case 1: - s->cstyle = SCREEN_CURSOR_BLOCK; - s->mode |= MODE_CURSOR_BLINKING; + *cstyle = SCREEN_CURSOR_BLOCK; + *mode |= MODE_CURSOR_BLINKING; break; case 2: - s->cstyle = SCREEN_CURSOR_BLOCK; - s->mode &= ~MODE_CURSOR_BLINKING; + *cstyle = SCREEN_CURSOR_BLOCK; + *mode &= ~MODE_CURSOR_BLINKING; break; case 3: - s->cstyle = SCREEN_CURSOR_UNDERLINE; - s->mode |= MODE_CURSOR_BLINKING; + *cstyle = SCREEN_CURSOR_UNDERLINE; + *mode |= MODE_CURSOR_BLINKING; break; case 4: - s->cstyle = SCREEN_CURSOR_UNDERLINE; - s->mode &= ~MODE_CURSOR_BLINKING; + *cstyle = SCREEN_CURSOR_UNDERLINE; + *mode &= ~MODE_CURSOR_BLINKING; break; case 5: - s->cstyle = SCREEN_CURSOR_BAR; - s->mode |= MODE_CURSOR_BLINKING; + *cstyle = SCREEN_CURSOR_BAR; + *mode |= MODE_CURSOR_BLINKING; break; case 6: - s->cstyle = SCREEN_CURSOR_BAR; - s->mode &= ~MODE_CURSOR_BLINKING; + *cstyle = SCREEN_CURSOR_BAR; + *mode &= ~MODE_CURSOR_BLINKING; break; } } diff --git a/tmux.1 b/tmux.1 index eb2340e3..4131719c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4426,6 +4426,16 @@ Each entry in the array defines the colour uses when the colour with that index is requested. The index may be from zero to 255. .Pp +.It Ic cursor-style Ar style +Set the style of the cursor. Available styles are: +.Ic default , +.Ic blinking-block , +.Ic block , +.Ic blinking-underline , +.Ic underline , +.Ic blinking-bar , +.Ic bar . +.Pp .It Xo Ic remain-on-exit .Op Ic on | off | failed .Xc diff --git a/tmux.h b/tmux.h index 62c84cc7..07e649f2 100644 --- a/tmux.h +++ b/tmux.h @@ -530,6 +530,7 @@ enum tty_code_code { #define MODE_CRLF 0x4000 #define MODE_KEXTENDED 0x8000 #define MODE_CURSOR_VERY_VISIBLE 0x10000 +#define MODE_CURSOR_BLINKING_SET 0x20000 #define ALL_MODES 0xffffff #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL) @@ -779,6 +780,7 @@ struct screen { u_int cy; /* cursor y */ enum screen_cursor_style cstyle; /* cursor style */ + enum screen_cursor_style default_cstyle; int ccolour; /* cursor colour */ int default_ccolour; @@ -786,6 +788,7 @@ struct screen { u_int rlower; /* scroll region bottom */ int mode; + int default_mode; u_int saved_cx; u_int saved_cy; @@ -2793,7 +2796,7 @@ void screen_init(struct screen *, u_int, u_int, u_int); void screen_reinit(struct screen *); void screen_free(struct screen *); void screen_reset_tabs(struct screen *); -void screen_set_cursor_style(struct screen *, u_int); +void screen_set_cursor_style(u_int, enum screen_cursor_style *, int *); void screen_set_cursor_colour(struct screen *, int); int screen_set_title(struct screen *, const char *); void screen_set_path(struct screen *, const char *); diff --git a/tty.c b/tty.c index 38a7a752..70470a08 100644 --- a/tty.c +++ b/tty.c @@ -668,11 +668,11 @@ tty_force_cursor_colour(struct tty *tty, int c) tty->ccolour = c; } -static void -tty_update_cursor(struct tty *tty, int mode, int changed, struct screen *s) +static int +tty_update_cursor(struct tty *tty, int mode, struct screen *s) { enum screen_cursor_style cstyle; - int ccolour; + int ccolour, changed, cmode = mode; /* Set cursor colour if changed. */ if (s != NULL) { @@ -683,19 +683,32 @@ tty_update_cursor(struct tty *tty, int mode, int changed, struct screen *s) } /* If cursor is off, set as invisible. */ - if (~mode & MODE_CURSOR) { - if (changed & MODE_CURSOR) + if (~cmode & MODE_CURSOR) { + if (tty->mode & MODE_CURSOR) tty_putcode(tty, TTYC_CIVIS); - return; + return (cmode); } /* Check if blinking or very visible flag changed or style changed. */ if (s == NULL) cstyle = tty->cstyle; - else + else { cstyle = s->cstyle; + if (cstyle == SCREEN_CURSOR_DEFAULT) { + if (~cmode & MODE_CURSOR_BLINKING_SET) { + if (s->default_mode & MODE_CURSOR_BLINKING) + cmode |= MODE_CURSOR_BLINKING; + else + cmode &= ~MODE_CURSOR_BLINKING; + } + cstyle = s->default_cstyle; + } + } + + /* If nothing changed, do nothing. */ + changed = cmode ^ tty->mode; if ((changed & CURSOR_MODES) == 0 && cstyle == tty->cstyle) - return; + return (cmode); /* * Set cursor style. If an explicit style has been set with DECSCUSR, @@ -713,49 +726,56 @@ tty_update_cursor(struct tty *tty, int mode, int changed, struct screen *s) else tty_putcode1(tty, TTYC_SS, 0); } - if (mode & (MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE)) + if (cmode & (MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE)) tty_putcode(tty, TTYC_CVVIS); break; case SCREEN_CURSOR_BLOCK: if (tty_term_has(tty->term, TTYC_SS)) { - if (mode & MODE_CURSOR_BLINKING) + if (cmode & MODE_CURSOR_BLINKING) tty_putcode1(tty, TTYC_SS, 1); else tty_putcode1(tty, TTYC_SS, 2); - } else if (mode & MODE_CURSOR_BLINKING) + } else if (cmode & MODE_CURSOR_BLINKING) tty_putcode(tty, TTYC_CVVIS); break; case SCREEN_CURSOR_UNDERLINE: if (tty_term_has(tty->term, TTYC_SS)) { - if (mode & MODE_CURSOR_BLINKING) + if (cmode & MODE_CURSOR_BLINKING) tty_putcode1(tty, TTYC_SS, 3); else tty_putcode1(tty, TTYC_SS, 4); - } else if (mode & MODE_CURSOR_BLINKING) + } else if (cmode & MODE_CURSOR_BLINKING) tty_putcode(tty, TTYC_CVVIS); break; case SCREEN_CURSOR_BAR: if (tty_term_has(tty->term, TTYC_SS)) { - if (mode & MODE_CURSOR_BLINKING) + if (cmode & MODE_CURSOR_BLINKING) tty_putcode1(tty, TTYC_SS, 5); else tty_putcode1(tty, TTYC_SS, 6); - } else if (mode & MODE_CURSOR_BLINKING) + } else if (cmode & MODE_CURSOR_BLINKING) tty_putcode(tty, TTYC_CVVIS); break; } tty->cstyle = cstyle; + return (cmode); } void tty_update_mode(struct tty *tty, int mode, struct screen *s) { + struct tty_term *term = tty->term; struct client *c = tty->client; int changed; if (tty->flags & TTY_NOCURSOR) mode &= ~MODE_CURSOR; + if (tty_update_cursor(tty, mode, s) & MODE_CURSOR_BLINKING) + mode |= MODE_CURSOR_BLINKING; + else + mode &= ~MODE_CURSOR_BLINKING; + changed = mode ^ tty->mode; if (log_get_level() != 0 && changed != 0) { log_debug("%s: current mode %s", c->name, @@ -764,9 +784,7 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s) screen_mode_to_string(mode)); } - tty_update_cursor(tty, mode, changed, s); - if ((changed & ALL_MOUSE_MODES) && - tty_term_has(tty->term, TTYC_KMOUS)) { + if ((changed & ALL_MOUSE_MODES) && tty_term_has(term, TTYC_KMOUS)) { /* * If the mouse modes have changed, clear any that are set and * apply again. There are differences in how terminals track