mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-17 05:33:52 -04:00
commit
3f57cc9c01
5 changed files with 75 additions and 41 deletions
|
|
@ -45,6 +45,8 @@
|
||||||
`footclient` (https://codeberg.org/dnkl/foot/issues/337).
|
`footclient` (https://codeberg.org/dnkl/foot/issues/337).
|
||||||
* `-D,--working-directory=DIR` to both `foot` and `footclient`
|
* `-D,--working-directory=DIR` to both `foot` and `footclient`
|
||||||
(https://codeberg.org/dnkl/foot/issues/347)
|
(https://codeberg.org/dnkl/foot/issues/347)
|
||||||
|
* `DECSET 80` - sixel scrolling
|
||||||
|
(https://codeberg.org/dnkl/foot/issues/361).
|
||||||
* `DECSET 1070` - sixel private color palette
|
* `DECSET 1070` - sixel private color palette
|
||||||
(https://codeberg.org/dnkl/foot/issues/362).
|
(https://codeberg.org/dnkl/foot/issues/362).
|
||||||
* `DECSET 8452` - position cursor to the right of sixels
|
* `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;
|
term->reverse_wrap = enable;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 80:
|
||||||
|
term->sixel.scrolling = enable;
|
||||||
|
break;
|
||||||
|
|
||||||
case 1000:
|
case 1000:
|
||||||
if (enable)
|
if (enable)
|
||||||
term->mouse_tracking = MOUSE_CLICK;
|
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 12: *enabled = term->cursor_blink.decset; return true;
|
||||||
case 25: *enabled = !term->hide_cursor; return true;
|
case 25: *enabled = !term->hide_cursor; return true;
|
||||||
case 45: *enabled = term->reverse_wrap; 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 1000: *enabled = term->mouse_tracking == MOUSE_CLICK; return true;
|
||||||
case 1001: *enabled = false; return true;
|
case 1001: *enabled = false; return true;
|
||||||
case 1002: *enabled = term->mouse_tracking == MOUSE_DRAG; 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 25: term->xtsave.show_cursor = !term->hide_cursor; break;
|
||||||
case 45: term->xtsave.reverse_wrap = term->reverse_wrap; break;
|
case 45: term->xtsave.reverse_wrap = term->reverse_wrap; break;
|
||||||
case 47: term->xtsave.alt_screen = term->grid == &term->alt; 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 1000: term->xtsave.mouse_click = term->mouse_tracking == MOUSE_CLICK; break;
|
||||||
case 1001: break;
|
case 1001: break;
|
||||||
case 1002: term->xtsave.mouse_drag = term->mouse_tracking == MOUSE_DRAG; 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 25: enable = term->xtsave.show_cursor; break;
|
||||||
case 45: enable = term->xtsave.reverse_wrap; break;
|
case 45: enable = term->xtsave.reverse_wrap; break;
|
||||||
case 47: enable = term->xtsave.alt_screen; 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 1000: enable = term->xtsave.mouse_click; break;
|
||||||
case 1001: return;
|
case 1001: return;
|
||||||
case 1002: enable = term->xtsave.mouse_drag; break;
|
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);
|
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
|
* Furthermore, if the sixel reaches the bottom of the scrolling
|
||||||
* will emit a carriage-return (after several linefeeds), which
|
* region, the terminal content is scrolled.
|
||||||
* will reset the cursor column to 0. If we use _that_ column for
|
*
|
||||||
* the subsequent image parts, the image will look sheared.
|
* 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
|
/* We do not allow sixels to cross the scrollback wrap-around, as
|
||||||
* this makes intersection calculations much more complicated */
|
* this makes intersection calculations much more complicated */
|
||||||
while (pixel_rows_left > 0) {
|
while (pixel_rows_left > 0 && rows_avail > 0) {
|
||||||
const struct coord *cursor = &term->grid->cursor.point;
|
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 pixel_rows_avail = usable_rows * term->cell_height;
|
||||||
const int rows_avail = term->grid->num_rows - cur_row;
|
|
||||||
|
|
||||||
const int pixel_rows_avail = rows_avail * term->cell_height;
|
|
||||||
|
|
||||||
const int width = term->sixel.image.width;
|
const int width = term->sixel.image.width;
|
||||||
const int height = min(pixel_rows_left, pixel_rows_avail);
|
const int height = min(pixel_rows_left, pixel_rows_avail);
|
||||||
|
|
@ -755,12 +774,15 @@ sixel_unhook(struct terminal *term)
|
||||||
image.width, image.height,
|
image.width, image.height,
|
||||||
img_data, stride);
|
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++) {
|
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;
|
row->dirty = true;
|
||||||
|
|
||||||
/* Mark cells touched by the sixel as dirty */
|
|
||||||
for (int col = image.pos.col;
|
for (int col = image.pos.col;
|
||||||
col < min(image.pos.col + image.cols, term->cols);
|
col < min(image.pos.col + image.cols, term->cols);
|
||||||
col++)
|
col++)
|
||||||
|
|
@ -768,36 +790,37 @@ sixel_unhook(struct terminal *term)
|
||||||
row->cells[col].attrs.clean = 0;
|
row->cells[col].attrs.clean = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < image.rows - 1 || !term->sixel.cursor_right_of_graphics)
|
if (do_scroll) {
|
||||||
term_linefeed(term);
|
/*
|
||||||
|
* 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(
|
_sixel_overwrite_by_rectangle(
|
||||||
term, image.pos.row, image.pos.col, image.rows, image.cols);
|
term, image.pos.row, image.pos.col, image.rows, image.cols);
|
||||||
|
|
||||||
sixel_insert(term, image);
|
sixel_insert(term, image);
|
||||||
|
|
||||||
pixel_row_idx += height;
|
if (do_scroll)
|
||||||
pixel_rows_left -= height;
|
start_row = term->grid->cursor.point.row;
|
||||||
|
else
|
||||||
|
start_row -= image.rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
term->sixel.image.data = NULL;
|
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,
|
.upper_fd = delay_upper_fd,
|
||||||
},
|
},
|
||||||
.sixel = {
|
.sixel = {
|
||||||
|
.scrolling = true,
|
||||||
.use_private_palette = true,
|
.use_private_palette = true,
|
||||||
.palette_size = SIXEL_MAX_COLORS,
|
.palette_size = SIXEL_MAX_COLORS,
|
||||||
.max_width = SIXEL_MAX_WIDTH,
|
.max_width = SIXEL_MAX_WIDTH,
|
||||||
|
|
|
||||||
|
|
@ -360,6 +360,7 @@ struct terminal {
|
||||||
bool modify_escape_key:1;
|
bool modify_escape_key:1;
|
||||||
bool ime:1;
|
bool ime:1;
|
||||||
|
|
||||||
|
bool sixel_scrolling:1;
|
||||||
bool sixel_private_palette:1;
|
bool sixel_private_palette:1;
|
||||||
bool sixel_cursor_right_of_graphics:1;
|
bool sixel_cursor_right_of_graphics:1;
|
||||||
} xtsave;
|
} xtsave;
|
||||||
|
|
@ -533,14 +534,14 @@ struct terminal {
|
||||||
bool autosize;
|
bool autosize;
|
||||||
} image;
|
} 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 params[5]; /* Collected parameters, for RASTER, COLOR_SPEC */
|
||||||
unsigned param; /* Currently collecting parameter, for RASTER, COLOR_SPEC and REPEAT */
|
unsigned param; /* Currently collecting parameter, for RASTER, COLOR_SPEC and REPEAT */
|
||||||
unsigned param_idx; /* Parameters seen */
|
unsigned param_idx; /* Parameters seen */
|
||||||
|
|
||||||
bool cursor_right_of_graphics:1; /* Private mode 8452 */
|
|
||||||
|
|
||||||
/* Application configurable */
|
/* Application configurable */
|
||||||
unsigned palette_size; /* Number of colors in palette */
|
unsigned palette_size; /* Number of colors in palette */
|
||||||
unsigned max_width; /* Maximum image width, in pixels */
|
unsigned max_width; /* Maximum image width, in pixels */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue