mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-16 05:34:00 -04:00
commit
e5ed387426
7 changed files with 159 additions and 68 deletions
|
|
@ -63,10 +63,14 @@
|
||||||
* Support for high-res mouse wheel scroll events ([#1738][1738]).
|
* Support for high-res mouse wheel scroll events ([#1738][1738]).
|
||||||
* Styled and colored underlines ([#828][828]).
|
* Styled and colored underlines ([#828][828]).
|
||||||
* Support for SGR 21 (double underline).
|
* Support for SGR 21 (double underline).
|
||||||
|
* Support for `XTPUSHCOLORS`, `XTPOPCOLORS` and `XTREPORTCOLORS`,
|
||||||
|
i.e. color palette stack ([#856][856]).
|
||||||
|
|
||||||
[1707]: https://codeberg.org/dnkl/foot/issues/1707
|
[1707]: https://codeberg.org/dnkl/foot/issues/1707
|
||||||
[1738]: https://codeberg.org/dnkl/foot/issues/1738
|
[1738]: https://codeberg.org/dnkl/foot/issues/1738
|
||||||
[828]: https://codeberg.org/dnkl/foot/issues/828
|
[828]: https://codeberg.org/dnkl/foot/issues/828
|
||||||
|
[856]: https://codeberg.org/dnkl/foot/issues/856
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
||||||
77
csi.c
77
csi.c
|
|
@ -2048,6 +2048,83 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
break; /* private[0] == ‘$’ */
|
break; /* private[0] == ‘$’ */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case '#': {
|
||||||
|
switch (final) {
|
||||||
|
case 'P': { /* XTPUSHCOLORS */
|
||||||
|
int slot = vt_param_get(term, 0, 0);
|
||||||
|
|
||||||
|
/* Pm == 0, "push" (what xterm does is take take the
|
||||||
|
*current* slot + 1, even if that's in the middle of the
|
||||||
|
stack, and overwrites whatever is already in that
|
||||||
|
slot) */
|
||||||
|
if (slot == 0)
|
||||||
|
slot = term->color_stack.idx + 1;
|
||||||
|
|
||||||
|
if (term->color_stack.size < slot) {
|
||||||
|
const size_t new_size = slot;
|
||||||
|
term->color_stack.stack = xrealloc(
|
||||||
|
term->color_stack.stack,
|
||||||
|
new_size * sizeof(term->color_stack.stack[0]));
|
||||||
|
|
||||||
|
/* Initialize new slots (except the selected slot,
|
||||||
|
which is done below) */
|
||||||
|
xassert(new_size > 0);
|
||||||
|
for (size_t i = term->color_stack.size; i < new_size - 1; i++) {
|
||||||
|
memcpy(&term->color_stack.stack[i], &term->colors,
|
||||||
|
sizeof(term->colors));
|
||||||
|
}
|
||||||
|
term->color_stack.size = new_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
xassert(slot > 0);
|
||||||
|
xassert(slot <= term->color_stack.size);
|
||||||
|
term->color_stack.idx = slot;
|
||||||
|
memcpy(&term->color_stack.stack[slot - 1], &term->colors,
|
||||||
|
sizeof(term->colors));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'Q': { /* XTPOPCOLORS */
|
||||||
|
int slot = vt_param_get(term, 0, 0);
|
||||||
|
|
||||||
|
/* Pm == 0, "pop" (what xterm does is copy colors from the
|
||||||
|
*current* slot, *and* decrease the current slot index,
|
||||||
|
even if that's in the middle of the stack) */
|
||||||
|
if (slot == 0)
|
||||||
|
slot = term->color_stack.idx;
|
||||||
|
|
||||||
|
if (slot > 0 && slot <= term->color_stack.size) {
|
||||||
|
memcpy(&term->colors, &term->color_stack.stack[slot - 1],
|
||||||
|
sizeof(term->colors));
|
||||||
|
term->color_stack.idx = slot - 1;
|
||||||
|
|
||||||
|
/* TODO: we _could_ iterate all cells and only dirty
|
||||||
|
those that are affected by the palette change... */
|
||||||
|
term_damage_view(term);
|
||||||
|
term_damage_margins(term);
|
||||||
|
} else if (slot == 0) {
|
||||||
|
LOG_ERR("XTPOPCOLORS: cannot pop beyond the first element");
|
||||||
|
} else {
|
||||||
|
LOG_ERR(
|
||||||
|
"XTPOPCOLORS: invalid color slot: %d "
|
||||||
|
"(stack has %zu slots, current slot is %zu)",
|
||||||
|
vt_param_get(term, 0, 0),
|
||||||
|
term->color_stack.size, term->color_stack.idx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'R': { /* XTREPORTCOLORS */
|
||||||
|
char reply[64];
|
||||||
|
int n = xsnprintf(reply, sizeof(reply), "\033[?%zu;%zu#Q",
|
||||||
|
term->color_stack.idx, term->color_stack.size);
|
||||||
|
term_to_slave(term, reply, n);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break; /* private[0] == '#' */
|
||||||
|
}
|
||||||
|
|
||||||
case 0x243f: /* ?$ */
|
case 0x243f: /* ?$ */
|
||||||
switch (final) {
|
switch (final) {
|
||||||
case 'p': {
|
case 'p': {
|
||||||
|
|
|
||||||
|
|
@ -632,6 +632,19 @@ manipulation sequences. The generic format is:
|
||||||
: <unnamed>
|
: <unnamed>
|
||||||
: kitty
|
: kitty
|
||||||
: Update current Kitty keyboard flags, according to _mode_.
|
: Update current Kitty keyboard flags, according to _mode_.
|
||||||
|
| \\E[ # P
|
||||||
|
: XTPUSHCOLORS
|
||||||
|
: xterm
|
||||||
|
: Push current color palette onto stack
|
||||||
|
| \\E[ # Q
|
||||||
|
: XTPOPCOLORS
|
||||||
|
: xterm
|
||||||
|
: Pop color palette from stack
|
||||||
|
| \\E[ # R
|
||||||
|
: XTREPORTCOLORS
|
||||||
|
: xterm
|
||||||
|
: Report the current entry on the palette stack, and the number of
|
||||||
|
palettes stored on the stack.
|
||||||
|
|
||||||
|
|
||||||
# OSC
|
# OSC
|
||||||
|
|
|
||||||
74
osc.c
74
osc.c
|
|
@ -712,15 +712,25 @@ osc_dispatch(struct terminal *term)
|
||||||
osc_notify(term, string);
|
osc_notify(term, string);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 10:
|
case 10: /* fg */
|
||||||
case 11:
|
case 11: /* bg */
|
||||||
case 17:
|
case 12: /* cursor */
|
||||||
case 19: {
|
case 17: /* highlight (selection) fg */
|
||||||
|
case 19: { /* highlight (selection) bg */
|
||||||
/* Set default foreground/background/highlight-bg/highlight-fg color */
|
/* Set default foreground/background/highlight-bg/highlight-fg color */
|
||||||
|
|
||||||
/* Client queried for current value */
|
/* Client queried for current value */
|
||||||
if (string[0] == '?' && string[1] == '\0') {
|
if (string[0] == '?' && string[1] == '\0') {
|
||||||
uint32_t color = param == 10 ? term->colors.fg : term->colors.bg;
|
uint32_t color = param == 10
|
||||||
|
? term->colors.fg
|
||||||
|
: param == 11
|
||||||
|
? term->colors.bg
|
||||||
|
: param == 12
|
||||||
|
? term->colors.cursor_bg
|
||||||
|
: param == 17
|
||||||
|
? term->colors.selection_bg
|
||||||
|
: term->colors.selection_fg;
|
||||||
|
|
||||||
uint8_t r = (color >> 16) & 0xff;
|
uint8_t r = (color >> 16) & 0xff;
|
||||||
uint8_t g = (color >> 8) & 0xff;
|
uint8_t g = (color >> 8) & 0xff;
|
||||||
uint8_t b = (color >> 0) & 0xff;
|
uint8_t b = (color >> 0) & 0xff;
|
||||||
|
|
@ -754,6 +764,7 @@ osc_dispatch(struct terminal *term)
|
||||||
LOG_DBG("change color definition for %s to %06x",
|
LOG_DBG("change color definition for %s to %06x",
|
||||||
param == 10 ? "foreground" :
|
param == 10 ? "foreground" :
|
||||||
param == 11 ? "background" :
|
param == 11 ? "background" :
|
||||||
|
param == 12 ? "cursor" :
|
||||||
param == 17 ? "selection background" :
|
param == 17 ? "selection background" :
|
||||||
"selection foreground",
|
"selection foreground",
|
||||||
color);
|
color);
|
||||||
|
|
@ -761,6 +772,7 @@ osc_dispatch(struct terminal *term)
|
||||||
switch (param) {
|
switch (param) {
|
||||||
case 10:
|
case 10:
|
||||||
term->colors.fg = color;
|
term->colors.fg = color;
|
||||||
|
term_damage_view(term);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 11:
|
case 11:
|
||||||
|
|
@ -774,61 +786,31 @@ osc_dispatch(struct terminal *term)
|
||||||
term_font_subpixel_changed(term);
|
term_font_subpixel_changed(term);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
term_damage_view(term);
|
||||||
|
term_damage_margins(term);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 12:
|
||||||
|
term->colors.cursor_bg = 1u << 31 | color;
|
||||||
|
term_damage_cursor(term);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 17:
|
case 17:
|
||||||
term->colors.selection_bg = color;
|
term->colors.selection_bg = color;
|
||||||
term->colors.use_custom_selection = true;
|
term->colors.use_custom_selection = true;
|
||||||
|
term_damage_view(term);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 19:
|
case 19:
|
||||||
term->colors.selection_fg = color;
|
term->colors.selection_fg = color;
|
||||||
term->colors.use_custom_selection = true;
|
term->colors.use_custom_selection = true;
|
||||||
|
term_damage_view(term);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
term_damage_view(term);
|
|
||||||
term_damage_margins(term);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 12: /* Set cursor color */
|
|
||||||
|
|
||||||
/* Client queried for current value */
|
|
||||||
if (string[0] == '?' && string[1] == '\0') {
|
|
||||||
uint8_t r = (term->cursor_color.cursor >> 16) & 0xff;
|
|
||||||
uint8_t g = (term->cursor_color.cursor >> 8) & 0xff;
|
|
||||||
uint8_t b = (term->cursor_color.cursor >> 0) & 0xff;
|
|
||||||
const char *terminator = term->vt.osc.bel ? "\a" : "\033\\";
|
|
||||||
|
|
||||||
char reply[32];
|
|
||||||
size_t n = xsnprintf(
|
|
||||||
reply, sizeof(reply), "\033]12;rgb:%02x/%02x/%02x%s",
|
|
||||||
r, g, b, terminator);
|
|
||||||
|
|
||||||
term_to_slave(term, reply, n);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t color;
|
|
||||||
|
|
||||||
if (string[0] == '#' || string[0] == '['
|
|
||||||
? !parse_legacy_color(string, &color, NULL, NULL)
|
|
||||||
: !parse_rgb(string, &color, NULL, NULL))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DBG("change cursor color to %06x", color);
|
|
||||||
|
|
||||||
if (color == 0)
|
|
||||||
term->cursor_color.cursor = 0; /* Invert fg/bg */
|
|
||||||
else
|
|
||||||
term->cursor_color.cursor = 1u << 31 | color;
|
|
||||||
|
|
||||||
term_damage_cursor(term);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 22: /* Set mouse cursor */
|
case 22: /* Set mouse cursor */
|
||||||
term_set_user_mouse_cursor(term, string);
|
term_set_user_mouse_cursor(term, string);
|
||||||
break;
|
break;
|
||||||
|
|
@ -895,8 +877,8 @@ osc_dispatch(struct terminal *term)
|
||||||
|
|
||||||
case 112:
|
case 112:
|
||||||
LOG_DBG("resetting cursor color");
|
LOG_DBG("resetting cursor color");
|
||||||
term->cursor_color.text = term->conf->cursor.color.text;
|
term->colors.cursor_fg = term->conf->cursor.color.text;
|
||||||
term->cursor_color.cursor = term->conf->cursor.color.cursor;
|
term->colors.cursor_bg = term->conf->cursor.color.cursor;
|
||||||
term_damage_cursor(term);
|
term_damage_cursor(term);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
8
render.c
8
render.c
|
|
@ -557,13 +557,13 @@ cursor_colors_for_cell(const struct terminal *term, const struct cell *cell,
|
||||||
const pixman_color_t *fg, const pixman_color_t *bg,
|
const pixman_color_t *fg, const pixman_color_t *bg,
|
||||||
pixman_color_t *cursor_color, pixman_color_t *text_color)
|
pixman_color_t *cursor_color, pixman_color_t *text_color)
|
||||||
{
|
{
|
||||||
if (term->cursor_color.cursor >> 31)
|
if (term->colors.cursor_bg >> 31)
|
||||||
*cursor_color = color_hex_to_pixman(term->cursor_color.cursor);
|
*cursor_color = color_hex_to_pixman(term->colors.cursor_bg);
|
||||||
else
|
else
|
||||||
*cursor_color = *fg;
|
*cursor_color = *fg;
|
||||||
|
|
||||||
if (term->cursor_color.text >> 31)
|
if (term->colors.cursor_fg >> 31)
|
||||||
*text_color = color_hex_to_pixman(term->cursor_color.text);
|
*text_color = color_hex_to_pixman(term->colors.cursor_fg);
|
||||||
else {
|
else {
|
||||||
*text_color = *bg;
|
*text_color = *bg;
|
||||||
|
|
||||||
|
|
|
||||||
20
terminal.c
20
terminal.c
|
|
@ -1221,10 +1221,17 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
||||||
.fg = conf->colors.fg,
|
.fg = conf->colors.fg,
|
||||||
.bg = conf->colors.bg,
|
.bg = conf->colors.bg,
|
||||||
.alpha = conf->colors.alpha,
|
.alpha = conf->colors.alpha,
|
||||||
|
.cursor_fg = conf->cursor.color.text,
|
||||||
|
.cursor_bg = conf->cursor.color.cursor,
|
||||||
.selection_fg = conf->colors.selection_fg,
|
.selection_fg = conf->colors.selection_fg,
|
||||||
.selection_bg = conf->colors.selection_bg,
|
.selection_bg = conf->colors.selection_bg,
|
||||||
.use_custom_selection = conf->colors.use_custom.selection,
|
.use_custom_selection = conf->colors.use_custom.selection,
|
||||||
},
|
},
|
||||||
|
.color_stack = {
|
||||||
|
.stack = NULL,
|
||||||
|
.size = 0,
|
||||||
|
.idx = 0,
|
||||||
|
},
|
||||||
.origin = ORIGIN_ABSOLUTE,
|
.origin = ORIGIN_ABSOLUTE,
|
||||||
.cursor_style = conf->cursor.style,
|
.cursor_style = conf->cursor.style,
|
||||||
.cursor_blink = {
|
.cursor_blink = {
|
||||||
|
|
@ -1233,10 +1240,6 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
||||||
.state = CURSOR_BLINK_ON,
|
.state = CURSOR_BLINK_ON,
|
||||||
.fd = -1,
|
.fd = -1,
|
||||||
},
|
},
|
||||||
.cursor_color = {
|
|
||||||
.text = conf->cursor.color.text,
|
|
||||||
.cursor = conf->cursor.color.cursor,
|
|
||||||
},
|
|
||||||
.selection = {
|
.selection = {
|
||||||
.coords = {
|
.coords = {
|
||||||
.start = {-1, -1},
|
.start = {-1, -1},
|
||||||
|
|
@ -1825,6 +1828,7 @@ term_destroy(struct terminal *term)
|
||||||
free(term->foot_exe);
|
free(term->foot_exe);
|
||||||
free(term->cwd);
|
free(term->cwd);
|
||||||
free(term->mouse_user_cursor);
|
free(term->mouse_user_cursor);
|
||||||
|
free(term->color_stack.stack);
|
||||||
|
|
||||||
int ret = EXIT_SUCCESS;
|
int ret = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
|
@ -2035,11 +2039,17 @@ term_reset(struct terminal *term, bool hard)
|
||||||
term->colors.fg = term->conf->colors.fg;
|
term->colors.fg = term->conf->colors.fg;
|
||||||
term->colors.bg = term->conf->colors.bg;
|
term->colors.bg = term->conf->colors.bg;
|
||||||
term->colors.alpha = term->conf->colors.alpha;
|
term->colors.alpha = term->conf->colors.alpha;
|
||||||
|
term->colors.cursor_fg = term->conf->cursor.color.text;
|
||||||
|
term->colors.cursor_bg = term->conf->cursor.color.cursor;
|
||||||
term->colors.selection_fg = term->conf->colors.selection_fg;
|
term->colors.selection_fg = term->conf->colors.selection_fg;
|
||||||
term->colors.selection_bg = term->conf->colors.selection_bg;
|
term->colors.selection_bg = term->conf->colors.selection_bg;
|
||||||
term->colors.use_custom_selection = term->conf->colors.use_custom.selection;
|
term->colors.use_custom_selection = term->conf->colors.use_custom.selection;
|
||||||
memcpy(term->colors.table, term->conf->colors.table,
|
memcpy(term->colors.table, term->conf->colors.table,
|
||||||
sizeof(term->colors.table));
|
sizeof(term->colors.table));
|
||||||
|
free(term->color_stack.stack);
|
||||||
|
term->color_stack.stack = NULL;
|
||||||
|
term->color_stack.size = 0;
|
||||||
|
term->color_stack.idx = 0;
|
||||||
term->origin = ORIGIN_ABSOLUTE;
|
term->origin = ORIGIN_ABSOLUTE;
|
||||||
term->normal.cursor.lcf = false;
|
term->normal.cursor.lcf = false;
|
||||||
term->alt.cursor.lcf = false;
|
term->alt.cursor.lcf = false;
|
||||||
|
|
@ -2051,8 +2061,6 @@ term_reset(struct terminal *term, bool hard)
|
||||||
term->cursor_blink.decset = false;
|
term->cursor_blink.decset = false;
|
||||||
term->cursor_blink.deccsusr = term->conf->cursor.blink.enabled;
|
term->cursor_blink.deccsusr = term->conf->cursor.blink.enabled;
|
||||||
term_cursor_blink_update(term);
|
term_cursor_blink_update(term);
|
||||||
term->cursor_color.text = term->conf->cursor.color.text;
|
|
||||||
term->cursor_color.cursor = term->conf->cursor.color.cursor;
|
|
||||||
selection_cancel(term);
|
selection_cancel(term);
|
||||||
term->normal.offset = term->normal.view = 0;
|
term->normal.offset = term->normal.view = 0;
|
||||||
term->alt.offset = term->alt.view = 0;
|
term->alt.offset = term->alt.view = 0;
|
||||||
|
|
|
||||||
31
terminal.h
31
terminal.h
|
|
@ -393,6 +393,19 @@ struct url {
|
||||||
};
|
};
|
||||||
typedef tll(struct url) url_list_t;
|
typedef tll(struct url) url_list_t;
|
||||||
|
|
||||||
|
|
||||||
|
struct colors {
|
||||||
|
uint32_t fg;
|
||||||
|
uint32_t bg;
|
||||||
|
uint32_t table[256];
|
||||||
|
uint16_t alpha;
|
||||||
|
uint32_t cursor_fg; /* Text color */
|
||||||
|
uint32_t cursor_bg; /* cursor color */
|
||||||
|
uint32_t selection_fg;
|
||||||
|
uint32_t selection_bg;
|
||||||
|
bool use_custom_selection;
|
||||||
|
};
|
||||||
|
|
||||||
struct terminal {
|
struct terminal {
|
||||||
struct fdm *fdm;
|
struct fdm *fdm;
|
||||||
struct reaper *reaper;
|
struct reaper *reaper;
|
||||||
|
|
@ -563,15 +576,13 @@ struct terminal {
|
||||||
int cell_width; /* pixels per cell, x-wise */
|
int cell_width; /* pixels per cell, x-wise */
|
||||||
int cell_height; /* pixels per cell, y-wise */
|
int cell_height; /* pixels per cell, y-wise */
|
||||||
|
|
||||||
|
struct colors colors;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint32_t fg;
|
struct colors *stack;
|
||||||
uint32_t bg;
|
size_t idx;
|
||||||
uint32_t table[256];
|
size_t size;
|
||||||
uint16_t alpha;
|
} color_stack;
|
||||||
uint32_t selection_fg;
|
|
||||||
uint32_t selection_bg;
|
|
||||||
bool use_custom_selection;
|
|
||||||
} colors;
|
|
||||||
|
|
||||||
enum cursor_style cursor_style;
|
enum cursor_style cursor_style;
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -580,10 +591,6 @@ struct terminal {
|
||||||
int fd;
|
int fd;
|
||||||
enum { CURSOR_BLINK_ON, CURSOR_BLINK_OFF } state;
|
enum { CURSOR_BLINK_ON, CURSOR_BLINK_OFF } state;
|
||||||
} cursor_blink;
|
} cursor_blink;
|
||||||
struct {
|
|
||||||
uint32_t text;
|
|
||||||
uint32_t cursor;
|
|
||||||
} cursor_color;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
enum selection_kind kind;
|
enum selection_kind kind;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue