term: split cursor blink state into two

There are two different escape sequences that can be used to set the
cursor blink state: ‘CSI ? 12 h/l’ and ‘CSI Ps SP q’.

Up until now, they both modified the same internal state in foot. This
meant you could enable a blinking cursor with e.g. ‘CSI ? 12 h’ and
then disable it with ‘CSI 2 SP q’.

Since the ‘CSI ? 12’ escapes are used in the civis/cnorm/cvvis
terminfo entries, applications often ended up disabling the blink
state on exit (typically be emitting ‘cnorm’), requiring users to
manually re-enable blinking.

By splitting the internal state into two separate states, we can
improve the situation.

The cursor will blink if at least one of the two have been enabled.

The setting in foot.ini sets the default state of the ‘CSI Ps SP q’
escape.

This means if the user has enabled blinking in the configuration, the
cursor will blink regardless of civis/cnorm/cvvis. Which probably is
what the user wants.

If the user has NOT enabled blinking, civis/cnorm/cvvis act as
intended: cvvis blink, civis and cnorm do not.

If an application overrides the cursor blink/style with ‘CSI Ps SP q’,
that will override the user’s setting in foot.ini. But most likely
that too is intended (for example, the user may have configured the
application to use a different cursor style). And, a well written
application will emit the ‘Se’ terminfo sequence on exit, which in
foot is defined to ‘CSI SP q’, which will reset both the style and
blink state to the user configured style/state.

Closes #218
This commit is contained in:
Daniel Eklöf 2020-11-26 18:09:32 +01:00
parent 360cc8e6de
commit cb2f496269
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
3 changed files with 15 additions and 38 deletions

View file

@ -95,6 +95,10 @@ means foot can be PGO:d in e.g. sandboxed build scripts. See
* Graphical glitches/flashes when resizing the window while running a
fullscreen application, i.e. the 'alt' screen
(https://codeberg.org/dnkl/foot/issues/221).
* Cursor will now blink if **either** `CSI ? 12 h` or `CSI Ps SP q`
has been used to enable blinking. **cursor.blink** in `foot.ini`
controls the default state of `CSI Ps SP q`
(https://codeberg.org/dnkl/foot/issues/218).
### Deprecated

39
csi.c
View file

@ -390,10 +390,8 @@ decset_decrst(struct terminal *term, unsigned param, bool enable)
break;
case 12:
if (enable)
term_cursor_blink_enable(term);
else
term_cursor_blink_disable(term);
term->cursor_blink.decset = enable;
term_cursor_blink_update(term);
break;
case 25:
@ -556,12 +554,6 @@ decrst(struct terminal *term, unsigned param)
decset_decrst(term, param, false);
}
static bool
timespecs_equal(const struct timespec *a, const struct timespec *b)
{
return a->tv_sec == b->tv_sec && a->tv_nsec == b->tv_nsec;
}
static void
xtsave(struct terminal *term, unsigned param)
{
@ -573,20 +565,7 @@ xtsave(struct terminal *term, unsigned param)
case 6: term->xtsave.origin = term->origin; break;
case 7: term->xtsave.auto_margin = term->auto_margin; break;
case 9: /* term->xtsave.mouse_x10 = term->mouse_tracking == MOUSE_X10; */ break;
case 12: {
struct itimerspec current_value;
if (timerfd_gettime(term->cursor_blink.fd, &current_value) < 0)
LOG_WARN("xtsave: failed to read cursor blink timer: %s", strerror(errno));
else {
const struct timespec zero = {.tv_sec = 0, .tv_nsec = 0};
term->xtsave.cursor_blink =
!(timespecs_equal(&current_value.it_interval, &zero) &&
timespecs_equal(&current_value.it_value, &zero));
}
break;
}
case 12: term->xtsave.cursor_blink = term->cursor_blink.decset; break;
case 25: term->xtsave.show_cursor = !term->hide_cursor; break;
case 45: term->xtsave.reverse_wrap = term->reverse_wrap; break;
case 1000: term->xtsave.mouse_click = term->mouse_tracking == MOUSE_CLICK; break;
@ -1514,11 +1493,9 @@ csi_dispatch(struct terminal *term, uint8_t final)
int param = vt_param_get(term, 0, 0);
switch (param) {
case 0: /* blinking block, but we use it to reset to configured default */
if (term->default_cursor_blink)
term_cursor_blink_enable(term);
else
term_cursor_blink_disable(term);
term->cursor_style = term->conf->cursor.style;
term->cursor_blink.deccsusr = term->conf->cursor.blink;
term_cursor_blink_update(term);
break;
case 1: /* blinking block */
@ -1542,10 +1519,8 @@ csi_dispatch(struct terminal *term, uint8_t final)
}
if (param > 0 && param <= 6) {
if (param & 1)
term_cursor_blink_enable(term);
else
term_cursor_blink_disable(term);
term->cursor_blink.deccsusr = param & 1;
term_cursor_blink_update(term);
}
break;
}

View file

@ -338,11 +338,11 @@ struct terminal {
enum cursor_style cursor_style;
struct {
bool active;
enum { CURSOR_BLINK_ON, CURSOR_BLINK_OFF } state;
bool decset; /* Blink enabled via '\E[?12h' */
bool deccsusr; /* Blink enabled via '\E[X q' */
int fd;
enum { CURSOR_BLINK_ON, CURSOR_BLINK_OFF } state;
} cursor_blink;
bool default_cursor_blink;
struct {
uint32_t text;
uint32_t cursor;
@ -538,9 +538,7 @@ void term_cursor_left(struct terminal *term, int count);
void term_cursor_right(struct terminal *term, int count);
void term_cursor_up(struct terminal *term, int count);
void term_cursor_down(struct terminal *term, int count);
void term_cursor_blink_enable(struct terminal *term);
void term_cursor_blink_disable(struct terminal *term);
void term_cursor_blink_restart(struct terminal *term);
void term_cursor_blink_update(struct terminal *term);
void term_print(struct terminal *term, wchar_t wc, int width);