sixel: implement private mode 80 - sixel scrolling

When enabled (the default), sixels behave much like normal output; the
start where the cursor is, and the cursor moves with the
sixel. I.e. after emitting a sixel the cursor is left after the image;
either to the right, if private mode 8452 is enabled, or otherwise on
the next line. Terminal content is scrolled up if the sixel is larger
than the screen.

When disabled, sixels *always* start at (0,0), the cursor never moves,
and the terminal content never scrolls.

In other words, the ‘disabled’ mode is a much simpler mode.

All we need to do to support both modes is re-write the sixel-emitting
loop to:

* break early if we’re “out of rows”, i.e. we’ve reached the bottom of
  the screen.
* not linefeed, or move the cursor when scrolling is disabled

This patch also fixes a bug in the (new) implementation of private
mode 8452.

When emitting a sixel, we may break it up into smaller pieces, to
ensure a single sixel (as tracked internally) does not cross the
scrollback wrap-around.

The code that checked if we should do a linefeed or not, would skip
the linefeed on the last row of *each* such sixel piece. The correct
thing to do is to skip it only on the last row of the *last* piece.

I chose not to fix this bug in a separate patch since doing so would
have meant re-writing it again when implementing private mode 80.
This commit is contained in:
Daniel Eklöf 2021-02-26 09:28:03 +01:00
parent 792202bf29
commit 849427bf10
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
5 changed files with 75 additions and 41 deletions

7
csi.c
View file

@ -401,6 +401,10 @@ decset_decrst(struct terminal *term, unsigned param, bool enable)
term->reverse_wrap = enable;
break;
case 80:
term->sixel.scrolling = enable;
break;
case 1000:
if (enable)
term->mouse_tracking = MOUSE_CLICK;
@ -599,6 +603,7 @@ decrqm(const struct terminal *term, unsigned param, bool *enabled)
case 12: *enabled = term->cursor_blink.decset; return true;
case 25: *enabled = !term->hide_cursor; return true;
case 45: *enabled = term->reverse_wrap; return true;
case 80: *enabled = term->sixel.scrolling; return true;
case 1000: *enabled = term->mouse_tracking == MOUSE_CLICK; return true;
case 1001: *enabled = false; return true;
case 1002: *enabled = term->mouse_tracking == MOUSE_DRAG; return true;
@ -640,6 +645,7 @@ xtsave(struct terminal *term, unsigned param)
case 25: term->xtsave.show_cursor = !term->hide_cursor; break;
case 45: term->xtsave.reverse_wrap = term->reverse_wrap; break;
case 47: term->xtsave.alt_screen = term->grid == &term->alt; break;
case 80: term->xtsave.sixel_scrolling = term->sixel.scrolling; break;
case 1000: term->xtsave.mouse_click = term->mouse_tracking == MOUSE_CLICK; break;
case 1001: break;
case 1002: term->xtsave.mouse_drag = term->mouse_tracking == MOUSE_DRAG; break;
@ -680,6 +686,7 @@ xtrestore(struct terminal *term, unsigned param)
case 25: enable = term->xtsave.show_cursor; break;
case 45: enable = term->xtsave.reverse_wrap; break;
case 47: enable = term->xtsave.alt_screen; break;
case 80: enable = term->xtsave.sixel_scrolling; break;
case 1000: enable = term->xtsave.mouse_click; break;
case 1001: return;
case 1002: enable = term->xtsave.mouse_drag; break;