Change cursor style handling so tmux understands which sequences contain
authornicm <nicm@openbsd.org>
Thu, 10 Jun 2021 07:36:47 +0000 (07:36 +0000)
committernicm <nicm@openbsd.org>
Thu, 10 Jun 2021 07:36:47 +0000 (07:36 +0000)
blinking and sets the flag appropriately, means that it works whether
cnorm disables blinking or not. GitHub issue 2682.

usr.bin/tmux/screen.c
usr.bin/tmux/tmux.h
usr.bin/tmux/tty.c

index cb8aa86..b578902 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: screen.c,v 1.71 2021/06/10 07:24:10 nicm Exp $ */
+/* $OpenBSD: screen.c,v 1.72 2021/06/10 07:36:47 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -81,7 +81,7 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
        s->titles = NULL;
        s->path = NULL;
 
-       s->cstyle = 0;
+       s->cstyle = SCREEN_CURSOR_DEFAULT;
        s->ccolour = xstrdup("");
        s->tabs = NULL;
        s->sel = NULL;
@@ -156,9 +156,35 @@ screen_reset_tabs(struct screen *s)
 void
 screen_set_cursor_style(struct screen *s, u_int style)
 {
-       if (style <= 6) {
-               s->cstyle = style;
+       switch (style)
+       {
+       case 0:
+               s->cstyle = SCREEN_CURSOR_DEFAULT;
+               break;
+       case 1:
+               s->cstyle = SCREEN_CURSOR_BLOCK;
+               s->mode |= MODE_BLINKING;
+               break;
+       case 2:
+               s->cstyle = SCREEN_CURSOR_BLOCK;
                s->mode &= ~MODE_BLINKING;
+               break;
+       case 3:
+               s->cstyle = SCREEN_CURSOR_UNDERLINE;
+               s->mode |= MODE_BLINKING;
+               break;
+       case 4:
+               s->cstyle = SCREEN_CURSOR_UNDERLINE;
+               s->mode &= ~MODE_BLINKING;
+               break;
+       case 5:
+               s->cstyle = SCREEN_CURSOR_BAR;
+               s->mode |= MODE_BLINKING;
+               break;
+       case 6:
+               s->cstyle = SCREEN_CURSOR_BAR;
+               s->mode &= ~MODE_BLINKING;
+               break;
        }
 }
 
index 21e522a..67f7d0e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1105 2021/06/10 07:33:41 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1106 2021/06/10 07:36:47 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -794,6 +794,14 @@ struct style {
        enum style_default_type default_type;
 };
 
+/* Cursor style. */
+enum screen_cursor_style {
+       SCREEN_CURSOR_DEFAULT,
+       SCREEN_CURSOR_BLOCK,
+       SCREEN_CURSOR_UNDERLINE,
+       SCREEN_CURSOR_BAR
+};
+
 /* Virtual screen. */
 struct screen_sel;
 struct screen_titles;
@@ -807,8 +815,8 @@ struct screen {
        u_int                            cx;      /* cursor x */
        u_int                            cy;      /* cursor y */
 
-       u_int                            cstyle;  /* cursor style */
-       char                            *ccolour; /* cursor colour string */
+       enum screen_cursor_style         cstyle;  /* cursor style */
+       char                            *ccolour; /* cursor colour */
 
        u_int                            rupper;  /* scroll region top */
        u_int                            rlower;  /* scroll region bottom */
@@ -1296,7 +1304,7 @@ struct tty {
 
        u_int            cx;
        u_int            cy;
-       u_int            cstyle;
+       enum screen_cursor_style cstyle;
        char            *ccolour;
 
        int              oflag;
index ba87484..58c4792 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty.c,v 1.390 2021/03/12 08:39:17 nicm Exp $ */
+/* $OpenBSD: tty.c,v 1.391 2021/06/10 07:36:47 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -98,7 +98,7 @@ tty_init(struct tty *tty, struct client *c)
        memset(tty, 0, sizeof *tty);
        tty->client = c;
 
-       tty->cstyle = 0;
+       tty->cstyle = SCREEN_CURSOR_DEFAULT;
        tty->ccolour = xstrdup("");
 
        if (tcgetattr(c->fd, &tty->tio) != 0)
@@ -392,10 +392,10 @@ tty_stop_tty(struct tty *tty)
        tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0));
        tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX));
        tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR));
-       if (tty_term_has(tty->term, TTYC_SS) && tty->cstyle != 0) {
+       if (tty->cstyle != SCREEN_CURSOR_DEFAULT) {
                if (tty_term_has(tty->term, TTYC_SE))
                        tty_raw(tty, tty_term_string(tty->term, TTYC_SE));
-               else
+               else if (tty_term_has(tty->term, TTYC_SS))
                        tty_raw(tty, tty_term_string1(tty->term, TTYC_SS, 0));
        }
        if (tty->mode & MODE_BRACKETPASTE)
@@ -657,11 +657,9 @@ tty_force_cursor_colour(struct tty *tty, const char *ccolour)
 void
 tty_update_mode(struct tty *tty, int mode, struct screen *s)
 {
-       struct client   *c = tty->client;
-       int              changed;
-
-       if (s != NULL && strcmp(s->ccolour, tty->ccolour) != 0)
-               tty_force_cursor_colour(tty, s->ccolour);
+       struct client           *c = tty->client;
+       int                      changed;
+       enum screen_cursor_style cstyle = tty->cstyle;
 
        if (tty->flags & TTY_NOCURSOR)
                mode &= ~MODE_CURSOR;
@@ -670,38 +668,83 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
        if (changed != 0)
                log_debug("%s: update mode %x to %x", c->name, tty->mode, mode);
 
-       /*
-        * The cursor blinking flag can be reset by setting the cursor style, so
-        * set the style first.
-        */
-       if (s != NULL && tty->cstyle != s->cstyle) {
-               if (tty_term_has(tty->term, TTYC_SS)) {
-                       if (s->cstyle == 0 && tty_term_has(tty->term, TTYC_SE))
-                               tty_putcode(tty, TTYC_SE);
-                       else
-                               tty_putcode1(tty, TTYC_SS, s->cstyle);
-               }
-               tty->cstyle = s->cstyle;
-               changed |= (MODE_CURSOR|MODE_BLINKING);
+       if (s != NULL) {
+               if (strcmp(s->ccolour, tty->ccolour) != 0)
+                       tty_force_cursor_colour(tty, s->ccolour);
+               cstyle = s->cstyle;
        }
-
-       /*
-        * Cursor invisible (RM ?25) overrides cursor blinking (SM ?12 or RM
-        * 34), and we need to be careful not send cnorm after cvvis since it
-        * can undo it.
-        */
-       if (changed & (MODE_CURSOR|MODE_BLINKING)) {
-               log_debug("%s: cursor %s, %sblinking", __func__,
-                   (mode & MODE_CURSOR) ? "on" : "off",
-                   (mode & MODE_BLINKING) ? "" : "not ");
-               if (~mode & MODE_CURSOR)
+       if (~mode & MODE_CURSOR) {
+               /* Cursor now off - set as invisible. */
+               if (changed & MODE_CURSOR)
                        tty_putcode(tty, TTYC_CIVIS);
-               else if (mode & MODE_BLINKING) {
-                       tty_putcode(tty, TTYC_CNORM);
-                       if (tty_term_has(tty->term, TTYC_CVVIS))
+       } else if ((changed & (MODE_CURSOR|MODE_BLINKING)) ||
+           cstyle != tty->cstyle) {
+               /*
+                * Cursor now on, blinking flag changed or style changed. Start
+                * by setting the cursor to normal.
+                */
+               tty_putcode(tty, TTYC_CNORM);
+               switch (cstyle) {
+               case SCREEN_CURSOR_DEFAULT:
+                       /*
+                        * If the old style wasn't default, then reset it to
+                        * default.
+                        */
+                       if (tty->cstyle != SCREEN_CURSOR_DEFAULT) {
+                               if (tty_term_has(tty->term, TTYC_SE))
+                                       tty_putcode(tty, TTYC_SE);
+                               else
+                                       tty_putcode1(tty, TTYC_SS, 0);
+                       }
+
+                       /* Set the cursor as very visible if necessary. */
+                       if (mode & MODE_BLINKING)
                                tty_putcode(tty, TTYC_CVVIS);
-               } else
-                       tty_putcode(tty, TTYC_CNORM);
+                       break;
+               case SCREEN_CURSOR_BLOCK:
+                       /*
+                        * Set style to either block blinking (1) or steady (2)
+                        * if supported, otherwise just check the blinking
+                        * flag.
+                        */
+                       if (tty_term_has(tty->term, TTYC_SS)) {
+                               if (mode & MODE_BLINKING)
+                                       tty_putcode1(tty, TTYC_SS, 1);
+                               else
+                                       tty_putcode1(tty, TTYC_SS, 2);
+                       } else if (mode & MODE_BLINKING)
+                               tty_putcode(tty, TTYC_CVVIS);
+                       break;
+               case SCREEN_CURSOR_UNDERLINE:
+                       /*
+                        * Set style to either underline blinking (3) or steady
+                        * (4) if supported, otherwise just check the blinking
+                        * flag.
+                        */
+                       if (tty_term_has(tty->term, TTYC_SS)) {
+                               if (mode & MODE_BLINKING)
+                                       tty_putcode1(tty, TTYC_SS, 3);
+                               else
+                                       tty_putcode1(tty, TTYC_SS, 4);
+                       } else if (mode & MODE_BLINKING)
+                               tty_putcode(tty, TTYC_CVVIS);
+                       break;
+               case SCREEN_CURSOR_BAR:
+                       /*
+                        * Set style to either bar blinking (5) or steady (6)
+                        * if supported, otherwise just check the blinking
+                        * flag.
+                        */
+                       if (tty_term_has(tty->term, TTYC_SS)) {
+                               if (mode & MODE_BLINKING)
+                                       tty_putcode1(tty, TTYC_SS, 5);
+                               else
+                                       tty_putcode1(tty, TTYC_SS, 6);
+                       } else if (mode & MODE_BLINKING)
+                               tty_putcode(tty, TTYC_CVVIS);
+                       break;
+               }
+               tty->cstyle = cstyle;
        }
 
        if ((changed & ALL_MOUSE_MODES) &&