mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-04 04:06:06 -05:00
csi: implement private mode 2031 (dark/light mode detection)
* Recognize 'CSI ? 996 n', and respond with - 'CSI ? 997 ; 1 n' if the primary theme is active - 'CSI ? 997 ; 2 n' if the alternative theme is actice * Implement private mode 2031, where changing the color theme (currently only possible via key bindings) causes the terminal to send the same CSI sequences as above. In this context, foot's primary theme is considered dark, and the alternative theme light (since the default theme is dark). Closes #2025
This commit is contained in:
parent
6bc91b5e28
commit
10e7f29149
6 changed files with 70 additions and 0 deletions
|
|
@ -71,6 +71,11 @@
|
||||||
`key-bindings.color-theme-toggle` key bindings. These can be used to
|
`key-bindings.color-theme-toggle` key bindings. These can be used to
|
||||||
switch between the primary and alternative color themes. They are
|
switch between the primary and alternative color themes. They are
|
||||||
not bound by default.
|
not bound by default.
|
||||||
|
* Support for private mode 2031 - [_Dark and Light Mode
|
||||||
|
Detection_](https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
|
||||||
|
([#2025][2025])
|
||||||
|
|
||||||
|
[2025]: https://codeberg.org/dnkl/foot/issues/2025
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
||||||
33
csi.c
33
csi.c
|
|
@ -563,6 +563,10 @@ decset_decrst(struct terminal *term, unsigned param, bool enable)
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 2031:
|
||||||
|
term->report_theme_changes = enable;
|
||||||
|
break;
|
||||||
|
|
||||||
case 2048:
|
case 2048:
|
||||||
if (enable)
|
if (enable)
|
||||||
term_enable_size_notifications(term);
|
term_enable_size_notifications(term);
|
||||||
|
|
@ -657,6 +661,7 @@ decrqm(const struct terminal *term, unsigned param)
|
||||||
case 2027: return term->conf->tweak.grapheme_width_method != GRAPHEME_WIDTH_DOUBLE
|
case 2027: return term->conf->tweak.grapheme_width_method != GRAPHEME_WIDTH_DOUBLE
|
||||||
? DECRPM_PERMANENTLY_RESET
|
? DECRPM_PERMANENTLY_RESET
|
||||||
: decrpm(term->grapheme_shaping);
|
: decrpm(term->grapheme_shaping);
|
||||||
|
case 2031: return decrpm(term->report_theme_changes);
|
||||||
case 2048: return decrpm(term->size_notifications);
|
case 2048: return decrpm(term->size_notifications);
|
||||||
case 8452: return decrpm(term->sixel.cursor_right_of_graphics);
|
case 8452: return decrpm(term->sixel.cursor_right_of_graphics);
|
||||||
case 737769: return decrpm(term_ime_is_enabled(term));
|
case 737769: return decrpm(term_ime_is_enabled(term));
|
||||||
|
|
@ -702,6 +707,7 @@ xtsave(struct terminal *term, unsigned param)
|
||||||
case 2004: term->xtsave.bracketed_paste = term->bracketed_paste; break;
|
case 2004: term->xtsave.bracketed_paste = term->bracketed_paste; break;
|
||||||
case 2026: term->xtsave.app_sync_updates = term->render.app_sync_updates.enabled; break;
|
case 2026: term->xtsave.app_sync_updates = term->render.app_sync_updates.enabled; break;
|
||||||
case 2027: term->xtsave.grapheme_shaping = term->grapheme_shaping; break;
|
case 2027: term->xtsave.grapheme_shaping = term->grapheme_shaping; break;
|
||||||
|
case 2031: term->xtsave.report_theme_changes = term->report_theme_changes; break;
|
||||||
case 2048: term->xtsave.size_notifications = term->size_notifications; break;
|
case 2048: term->xtsave.size_notifications = term->size_notifications; break;
|
||||||
case 8452: term->xtsave.sixel_cursor_right_of_graphics = term->sixel.cursor_right_of_graphics; break;
|
case 8452: term->xtsave.sixel_cursor_right_of_graphics = term->sixel.cursor_right_of_graphics; break;
|
||||||
case 737769: term->xtsave.ime = term_ime_is_enabled(term); break;
|
case 737769: term->xtsave.ime = term_ime_is_enabled(term); break;
|
||||||
|
|
@ -746,6 +752,7 @@ xtrestore(struct terminal *term, unsigned param)
|
||||||
case 2004: enable = term->xtsave.bracketed_paste; break;
|
case 2004: enable = term->xtsave.bracketed_paste; break;
|
||||||
case 2026: enable = term->xtsave.app_sync_updates; break;
|
case 2026: enable = term->xtsave.app_sync_updates; break;
|
||||||
case 2027: enable = term->xtsave.grapheme_shaping; break;
|
case 2027: enable = term->xtsave.grapheme_shaping; break;
|
||||||
|
case 2031: enable = term->xtsave.report_theme_changes; break;
|
||||||
case 2048: enable = term->xtsave.size_notifications; break;
|
case 2048: enable = term->xtsave.size_notifications; break;
|
||||||
case 8452: enable = term->xtsave.sixel_cursor_right_of_graphics; break;
|
case 8452: enable = term->xtsave.sixel_cursor_right_of_graphics; break;
|
||||||
case 737769: enable = term->xtsave.ime; break;
|
case 737769: enable = term->xtsave.ime; break;
|
||||||
|
|
@ -1539,6 +1546,32 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'n': {
|
||||||
|
const int param = vt_param_get(term, 0, 0);
|
||||||
|
|
||||||
|
switch (param) {
|
||||||
|
case 996: { /* Query current theme mode (see private mode 2031) */
|
||||||
|
/*
|
||||||
|
* 1 - dark mode
|
||||||
|
* 2 - light mode
|
||||||
|
*
|
||||||
|
* In foot, the themes aren't necessarily light/dark,
|
||||||
|
* but by convention, the primary theme is dark, and
|
||||||
|
* the alternative theme is light.
|
||||||
|
*/
|
||||||
|
char reply[16] = {0};
|
||||||
|
int chars = snprintf(
|
||||||
|
reply, sizeof(reply),
|
||||||
|
"\033[?997;%dn",
|
||||||
|
term->colors.active_theme == COLOR_THEME1 ? 1 : 2);
|
||||||
|
|
||||||
|
term_to_slave(term, reply, chars);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'p': {
|
case 'p': {
|
||||||
/*
|
/*
|
||||||
* Request status of ECMA-48/"ANSI" private mode (DECRQM
|
* Request status of ECMA-48/"ANSI" private mode (DECRQM
|
||||||
|
|
|
||||||
|
|
@ -337,6 +337,9 @@ that corresponds to one of the following modes:
|
||||||
| 2027
|
| 2027
|
||||||
: contour
|
: contour
|
||||||
: Grapheme cluster processing
|
: Grapheme cluster processing
|
||||||
|
| 2031
|
||||||
|
: contour
|
||||||
|
: Request color theme updates
|
||||||
| 2048
|
| 2048
|
||||||
: TODO
|
: TODO
|
||||||
: In-band window resize notifications
|
: In-band window resize notifications
|
||||||
|
|
@ -657,6 +660,13 @@ manipulation sequences. The generic format is:
|
||||||
: xterm
|
: xterm
|
||||||
: Report the current entry on the palette stack, and the number of
|
: Report the current entry on the palette stack, and the number of
|
||||||
palettes stored on the stack.
|
palettes stored on the stack.
|
||||||
|
| \\E[ ? 996 n
|
||||||
|
: Query the current (color) theme mode
|
||||||
|
: contour
|
||||||
|
: The current color theme mode (light or dark) is reported as *CSI ?
|
||||||
|
997 ; 1|2 n*, where *1* means dark and *2* light. By convention, the
|
||||||
|
primary theme in foot is considered dark, and the alternative theme
|
||||||
|
light.
|
||||||
|
|
||||||
|
|
||||||
# OSC
|
# OSC
|
||||||
|
|
|
||||||
|
|
@ -958,6 +958,10 @@ The colors are in RRGGBB format (i.e. plain old 6-digit hex values,
|
||||||
without prefix). That is, they do *not* have an alpha component. You
|
without prefix). That is, they do *not* have an alpha component. You
|
||||||
can configure the background transparency with the _alpha_ option.
|
can configure the background transparency with the _alpha_ option.
|
||||||
|
|
||||||
|
In the context of private mode 2031 (Dark and Light Mode detection),
|
||||||
|
the primary theme (i.e. the *colors* section) is considered to be the
|
||||||
|
dark theme (since the default theme is dark).
|
||||||
|
|
||||||
*cursor*
|
*cursor*
|
||||||
Two space separated RRGGBB values (i.e. plain old 6-digit hex
|
Two space separated RRGGBB values (i.e. plain old 6-digit hex
|
||||||
values, without prefix) specifying the foreground (text) and
|
values, without prefix) specifying the foreground (text) and
|
||||||
|
|
@ -1093,6 +1097,10 @@ Note that values are not inherited. That is, if you set a value in
|
||||||
*colors*, but not in *colors2*, the value from *colors* is not
|
*colors*, but not in *colors2*, the value from *colors* is not
|
||||||
inherited by *colors2*.
|
inherited by *colors2*.
|
||||||
|
|
||||||
|
In the context of private mode 2031 (Dark and Light Mode detection),
|
||||||
|
the primary theme (i.e. the *colors2* section) is considered to be the
|
||||||
|
light theme (since the default theme is dark).
|
||||||
|
|
||||||
# SECTION: csd
|
# SECTION: csd
|
||||||
|
|
||||||
This section controls the look of the _CSDs_ (Client Side
|
This section controls the look of the _CSDs_ (Client Side
|
||||||
|
|
|
||||||
12
input.c
12
input.c
|
|
@ -492,6 +492,9 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
wayl_win_alpha_changed(term->window);
|
wayl_win_alpha_changed(term->window);
|
||||||
term_font_subpixel_changed(term);
|
term_font_subpixel_changed(term);
|
||||||
|
|
||||||
|
if (term->report_theme_changes)
|
||||||
|
term_to_slave(term, "\033[?997;1n", 9);
|
||||||
|
|
||||||
term_damage_view(term);
|
term_damage_view(term);
|
||||||
term_damage_margins(term);
|
term_damage_margins(term);
|
||||||
render_refresh(term);
|
render_refresh(term);
|
||||||
|
|
@ -506,6 +509,9 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
wayl_win_alpha_changed(term->window);
|
wayl_win_alpha_changed(term->window);
|
||||||
term_font_subpixel_changed(term);
|
term_font_subpixel_changed(term);
|
||||||
|
|
||||||
|
if (term->report_theme_changes)
|
||||||
|
term_to_slave(term, "\033[?997;2n", 9);
|
||||||
|
|
||||||
term_damage_view(term);
|
term_damage_view(term);
|
||||||
term_damage_margins(term);
|
term_damage_margins(term);
|
||||||
render_refresh(term);
|
render_refresh(term);
|
||||||
|
|
@ -516,9 +522,15 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
if (term->colors.active_theme == COLOR_THEME1) {
|
if (term->colors.active_theme == COLOR_THEME1) {
|
||||||
term_theme_apply(term, &term->conf->colors2);
|
term_theme_apply(term, &term->conf->colors2);
|
||||||
term->colors.active_theme = COLOR_THEME2;
|
term->colors.active_theme = COLOR_THEME2;
|
||||||
|
|
||||||
|
if (term->report_theme_changes)
|
||||||
|
term_to_slave(term, "\033[?997;2n", 9);
|
||||||
} else {
|
} else {
|
||||||
term_theme_apply(term, &term->conf->colors);
|
term_theme_apply(term, &term->conf->colors);
|
||||||
term->colors.active_theme = COLOR_THEME1;
|
term->colors.active_theme = COLOR_THEME1;
|
||||||
|
|
||||||
|
if (term->report_theme_changes)
|
||||||
|
term_to_slave(term, "\033[?997;1n", 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
wayl_win_alpha_changed(term->window);
|
wayl_win_alpha_changed(term->window);
|
||||||
|
|
|
||||||
|
|
@ -518,6 +518,7 @@ struct terminal {
|
||||||
|
|
||||||
bool num_lock_modifier;
|
bool num_lock_modifier;
|
||||||
bool bell_action_enabled;
|
bool bell_action_enabled;
|
||||||
|
bool report_theme_changes;
|
||||||
|
|
||||||
/* Saved DECSET modes - we save the SET state */
|
/* Saved DECSET modes - we save the SET state */
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -548,6 +549,7 @@ struct terminal {
|
||||||
bool ime:1;
|
bool ime:1;
|
||||||
bool app_sync_updates:1;
|
bool app_sync_updates:1;
|
||||||
bool grapheme_shaping:1;
|
bool grapheme_shaping:1;
|
||||||
|
bool report_theme_changes:1;
|
||||||
|
|
||||||
bool size_notifications:1;
|
bool size_notifications:1;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue