feat(vt): add dark/light mode detection (DECSET 2031, CSI ? 996 n)#20335
feat(vt): add dark/light mode detection (DECSET 2031, CSI ? 996 n)#20335aymanbagabas wants to merge 1 commit into
Conversation
Implement the de-facto color-palette-update-notifications extension so applications can detect and follow the terminal's dark/light appearance: - CSI ? 996 n queries the current color mode; the terminal replies with CSI ? 997 ; 1 n (dark) or CSI ? 997 ; 2 n (light). - DECSET/DECRST 2031 enables/disables unsolicited reports, emitted when the terminal's color palette is updated by configuration (a profile/color-scheme change or an OS theme change) and only when the palette or the dark/light mode actually changed. The dark/light value is the resolved application/OS theme (the global theme setting's applicationTheme, resolving 'use Windows theme' via the OS appearance), surfaced as ICoreAppearance.DarkMode and pushed to the dispatcher on each appearance update. Adds adapter unit tests. See https://contour-terminal.org/vt-extensions/color-palette-update-notifications/ Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
fe570bc to
2ca26c7
Compare
This seems wrong to me. It should be reporting the user's preference for how they want their terminal colors to appear, which is not necessarily the same as their OS color preference. For example, if I change my color scheme from solarized dark to solarized light, then I expect the terminal to inform apps that I'm now using a light color scheme, irrespective of the OS dark/light state. Similarly, if I've explicitly configured the terminal to always use a dark color scheme, I don't want apps to suddenly switch to a light theme just because I enabled light mode in the OS. The OS dark/light mode is largely irrelevant, other than as a means to trigger a color scheme change in the terminal (and that is only when the user has explicitly configured it to do so). I also think this mode is supposed to trigger a notification for any color scheme change - not just ones that result in a dark/light transition. Some apps don't actually care whether the color scheme is dark or light - they just want to know that it's changed. They can then manually query the terminal for the new colors (e.g. with OSC 10/11), and update their theme to match. |
That's correct, it reports the user preference in WT and sends notifications on any color scheme changes. It uses the WT appearance |
|
Thank you @DHowett and @j4james. The dark/light mode state and terminal color scheme are separate concerns. Color schemes are flat palettes and don’t encode dark/light metadata. The spec only exposes theme state and does not imply anything about the active terminal colors (which apps can query via OSC 4/10/11/12). |
|
Having authored the spec for color schemes in Terminal, I am aware of what they are. FWIW, Terminal supports changing the color scheme in response to the system or application dark/light mode changing. That gives us positive signal that the user has a preference that the hosted application should change to fit their prevailing theme. However: the dark/light mode detection spec says
"has changed the terminal profile" suggests that the color scheme is important for the application's decisionmaking apropos this report. Fortunately, @christianparpart is a human we can ask about spec ambiguities. |

Summary of the Pull Request
Adds support for the de-facto "color palette update notifications" extension (a.k.a. dark/light mode detection), so applications running in the terminal can query and follow the terminal's dark/light appearance:
CSI ? 996 nqueries the current color mode. The terminal replies withCSI ? 997 ; 1 nfor dark andCSI ? 997 ; 2 nfor light.CSI ? 2031 h/CSI ? 2031 lenable/disable unsolicited reports. While enabled, the terminal emits the sameCSI ? 997 ; ... nreport whenever its color palette is updated because the user changed the profile/color scheme, or changed it indirectly by changing the OS theme and only when the palette or the dark/light mode actually changed.The reported dark/light value is the resolved application/OS theme (the global
themesetting'sapplicationTheme, resolving "use Windows theme" via the OS appearance), not a guess based on the background color.References and Relevant Issues
Detailed Description of the Pull Request / Additional comments
Shared VT adapter (
src/terminal/adapter):StatusType::ColorSchemeReport(DEC private DSR996) andModeParams::ColorThemeUpdates(DEC private mode2031).AdaptDispatchstores the current dark/light value used to answer the996query.ITermDispatch::ColorSchemeUpdated(isDark, paletteChanged)records the dark/light value and emits a997report when the mode or the palette changed and2031is enabled.TerminalCore (
src/cascadia/TerminalCore):Terminal::UpdateColorSchemenow reports whether the palette actually changed.Terminal::UpdateAppearanceresolves the dark/light value (ICoreAppearance.DarkMode) and forwards it plus the palette-changed flag to the dispatcher on every appearance update. Windows Terminal re-runs this on profile/color-scheme changes and on OS theme changes (WM_SETTINGCHANGE/ImmersiveColorSet-> settings reload).Under ConPTY the application's
2031/996sequences pass through to the hosting terminal viaWriteCharsVT; conhost does not respond to these (that is the terminal's job), and Windows Terminal -- which knows the theme -- answers and emits.Validation Steps Performed
AdapterTestcases covering the996reply (dark/light) and the2031unsolicited reports (dark/light mode change, palette change, and a no-op update). All passing.TerminalCore,TerminalControl, the settings adapter, and the adapter unit tests.PR Checklist