mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
commit
3f57cc9c01
5 changed files with 75 additions and 41 deletions
|
|
@ -45,6 +45,8 @@
|
|||
`footclient` (https://codeberg.org/dnkl/foot/issues/337).
|
||||
* `-D,--working-directory=DIR` to both `foot` and `footclient`
|
||||
(https://codeberg.org/dnkl/foot/issues/347)
|
||||
* `DECSET 80` - sixel scrolling
|
||||
(https://codeberg.org/dnkl/foot/issues/361).
|
||||
* `DECSET 1070` - sixel private color palette
|
||||
(https://codeberg.org/dnkl/foot/issues/362).
|
||||
* `DECSET 8452` - position cursor to the right of sixels
|
||||
|
|
|
|||
7
csi.c
7
csi.c
|
|
@ -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;
|
||||
|
|
|
|||
99
sixel.c
99
sixel.c
|
|
@ -701,24 +701,43 @@ sixel_unhook(struct terminal *term)
|
|||
const int stride = term->sixel.image.width * sizeof(uint32_t);
|
||||
|
||||
/*
|
||||
* Need to 'remember' current cursor column.
|
||||
* When sixel scrolling is enabled (the default), sixels behave
|
||||
* pretty much like normal output; the sixel starts at the current
|
||||
* cursor position and the cursor is moved to a point after the
|
||||
* sixel.
|
||||
*
|
||||
* If we split up the sixel (to avoid scrollback wrap-around), we
|
||||
* will emit a carriage-return (after several linefeeds), which
|
||||
* will reset the cursor column to 0. If we use _that_ column for
|
||||
* the subsequent image parts, the image will look sheared.
|
||||
* Furthermore, if the sixel reaches the bottom of the scrolling
|
||||
* region, the terminal content is scrolled.
|
||||
*
|
||||
* When scrolling is disabled, sixels always start at (0,0), the
|
||||
* cursor is not moved at all, and the terminal content never
|
||||
* scrolls.
|
||||
*/
|
||||
const int start_col = term->grid->cursor.point.col;
|
||||
|
||||
const bool do_scroll = term->sixel.scrolling;
|
||||
|
||||
/* Number of rows we're allowed to use.
|
||||
*
|
||||
* When scrolling is enabled, we always allow the entire sixel to
|
||||
* be emitted.
|
||||
*
|
||||
* When disabled, only the number of screen rows may be used. */
|
||||
int rows_avail = do_scroll
|
||||
? (term->sixel.image.height + term->cell_height - 1) / term->cell_height
|
||||
: term->scroll_region.end;
|
||||
|
||||
/* Initial sixel coordinates */
|
||||
int start_row = do_scroll ? term->grid->cursor.point.row : 0;
|
||||
const int start_col = do_scroll ? term->grid->cursor.point.col : 0;
|
||||
|
||||
/* We do not allow sixels to cross the scrollback wrap-around, as
|
||||
* this makes intersection calculations much more complicated */
|
||||
while (pixel_rows_left > 0) {
|
||||
const struct coord *cursor = &term->grid->cursor.point;
|
||||
while (pixel_rows_left > 0 && rows_avail > 0) {
|
||||
const int cur_row = (term->grid->offset + start_row) & (term->grid->num_rows - 1);
|
||||
const int rows_left_until_wrap_around = term->grid->num_rows - cur_row;
|
||||
const int usable_rows = min(rows_avail, rows_left_until_wrap_around);
|
||||
|
||||
const int cur_row = (term->grid->offset + cursor->row) & (term->grid->num_rows - 1);
|
||||
const int rows_avail = term->grid->num_rows - cur_row;
|
||||
|
||||
const int pixel_rows_avail = rows_avail * term->cell_height;
|
||||
const int pixel_rows_avail = usable_rows * term->cell_height;
|
||||
|
||||
const int width = term->sixel.image.width;
|
||||
const int height = min(pixel_rows_left, pixel_rows_avail);
|
||||
|
|
@ -755,12 +774,15 @@ sixel_unhook(struct terminal *term)
|
|||
image.width, image.height,
|
||||
img_data, stride);
|
||||
|
||||
/* Allocate space *first* (by emitting line-feeds), then insert */
|
||||
pixel_row_idx += height;
|
||||
pixel_rows_left -= height;
|
||||
rows_avail -= image.rows;
|
||||
|
||||
/* Dirty touched cells, and scroll terminal content if necessary */
|
||||
for (size_t i = 0; i < image.rows; i++) {
|
||||
struct row *row = term->grid->cur_row;
|
||||
struct row *row = term->grid->rows[cur_row + i];
|
||||
row->dirty = true;
|
||||
|
||||
/* Mark cells touched by the sixel as dirty */
|
||||
for (int col = image.pos.col;
|
||||
col < min(image.pos.col + image.cols, term->cols);
|
||||
col++)
|
||||
|
|
@ -768,36 +790,37 @@ sixel_unhook(struct terminal *term)
|
|||
row->cells[col].attrs.clean = 0;
|
||||
}
|
||||
|
||||
if (i < image.rows - 1 || !term->sixel.cursor_right_of_graphics)
|
||||
term_linefeed(term);
|
||||
if (do_scroll) {
|
||||
/*
|
||||
* Linefeed, *unless* we're on the very last row of
|
||||
* the final image (not just this chunk) and private
|
||||
* mode 8452 (leave cursor at the right of graphics)
|
||||
* is enabled.
|
||||
*/
|
||||
if (term->sixel.cursor_right_of_graphics &&
|
||||
rows_avail == 0 &&
|
||||
i >= image.rows - 1)
|
||||
{
|
||||
term_cursor_to(
|
||||
term,
|
||||
term->grid->cursor.point.row,
|
||||
min(image.pos.col + image.cols, term->cols - 1));
|
||||
} else {
|
||||
term_linefeed(term);
|
||||
term_carriage_return(term);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Position cursor
|
||||
*
|
||||
* Private mode 8452 controls where we leave the cursor after
|
||||
* emitting a sixel:
|
||||
*
|
||||
* When disabled (the default), the cursor is positioned on a
|
||||
* new line.
|
||||
*
|
||||
* When enabled, the cursor is positioned to the right of the
|
||||
* sixel.
|
||||
*/
|
||||
term_cursor_to(
|
||||
term,
|
||||
term->grid->cursor.point.row,
|
||||
(term->sixel.cursor_right_of_graphics
|
||||
? min(image.pos.col + image.cols, term->cols - 1)
|
||||
: 0));
|
||||
|
||||
_sixel_overwrite_by_rectangle(
|
||||
term, image.pos.row, image.pos.col, image.rows, image.cols);
|
||||
|
||||
sixel_insert(term, image);
|
||||
|
||||
pixel_row_idx += height;
|
||||
pixel_rows_left -= height;
|
||||
if (do_scroll)
|
||||
start_row = term->grid->cursor.point.row;
|
||||
else
|
||||
start_row -= image.rows;
|
||||
}
|
||||
|
||||
term->sixel.image.data = NULL;
|
||||
|
|
|
|||
|
|
@ -1178,6 +1178,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
|||
.upper_fd = delay_upper_fd,
|
||||
},
|
||||
.sixel = {
|
||||
.scrolling = true,
|
||||
.use_private_palette = true,
|
||||
.palette_size = SIXEL_MAX_COLORS,
|
||||
.max_width = SIXEL_MAX_WIDTH,
|
||||
|
|
|
|||
|
|
@ -360,6 +360,7 @@ struct terminal {
|
|||
bool modify_escape_key:1;
|
||||
bool ime:1;
|
||||
|
||||
bool sixel_scrolling:1;
|
||||
bool sixel_private_palette:1;
|
||||
bool sixel_cursor_right_of_graphics:1;
|
||||
} xtsave;
|
||||
|
|
@ -533,14 +534,14 @@ struct terminal {
|
|||
bool autosize;
|
||||
} image;
|
||||
|
||||
bool use_private_palette:1; /* Private mode 1070 */
|
||||
bool scrolling:1; /* Private mode 80 */
|
||||
bool use_private_palette:1; /* Private mode 1070 */
|
||||
bool cursor_right_of_graphics:1; /* Private mode 8452 */
|
||||
|
||||
unsigned params[5]; /* Collected parameters, for RASTER, COLOR_SPEC */
|
||||
unsigned param; /* Currently collecting parameter, for RASTER, COLOR_SPEC and REPEAT */
|
||||
unsigned param_idx; /* Parameters seen */
|
||||
|
||||
bool cursor_right_of_graphics:1; /* Private mode 8452 */
|
||||
|
||||
/* Application configurable */
|
||||
unsigned palette_size; /* Number of colors in palette */
|
||||
unsigned max_width; /* Maximum image width, in pixels */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue