Skip to content

feat(vt): add dark/light mode detection (DECSET 2031, CSI ? 996 n)#20335

Open
aymanbagabas wants to merge 1 commit into
microsoft:mainfrom
aymanbagabas:dev/ayman/dark-light-mode-detection
Open

feat(vt): add dark/light mode detection (DECSET 2031, CSI ? 996 n)#20335
aymanbagabas wants to merge 1 commit into
microsoft:mainfrom
aymanbagabas:dev/ayman/dark-light-mode-detection

Conversation

@aymanbagabas

@aymanbagabas aymanbagabas commented Jun 18, 2026

Copy link
Copy Markdown
Member

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 n queries the current color mode. The terminal replies with CSI ? 997 ; 1 n for dark and CSI ? 997 ; 2 n for light.
  • CSI ? 2031 h / CSI ? 2031 l enable/disable unsolicited reports. While enabled, the terminal emits the same CSI ? 997 ; ... n report 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 theme setting's applicationTheme, 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 DSR 996) and ModeParams::ColorThemeUpdates (DEC private mode 2031).
  • AdaptDispatch stores the current dark/light value used to answer the 996 query.
  • ITermDispatch::ColorSchemeUpdated(isDark, paletteChanged) records the dark/light value and emits a 997 report when the mode or the palette changed and 2031 is enabled.

TerminalCore (src/cascadia/TerminalCore):

  • Terminal::UpdateColorScheme now reports whether the palette actually changed.
  • Terminal::UpdateAppearance resolves 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/996 sequences pass through to the hosting terminal via WriteCharsVT; 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

  • New AdapterTest cases covering the 996 reply (dark/light) and the 2031 unsolicited reports (dark/light mode change, palette change, and a no-op update). All passing.
  • Built TerminalCore, TerminalControl, the settings adapter, and the adapter unit tests.

PR Checklist

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>
@aymanbagabas aymanbagabas force-pushed the dev/ayman/dark-light-mode-detection branch from fe570bc to 2ca26c7 Compare June 18, 2026 21:36
@j4james

j4james commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

The reported dark/light value is the resolved application/OS theme (the global theme setting's applicationTheme, resolving "use Windows theme" via the OS appearance), not a guess based on the background color.

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.

@aymanbagabas

Copy link
Copy Markdown
Member Author

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 Application Theme value to determine the dark/light state. When the value is set to Use Windows Theme, it reads the OS state instead. Any dark/light state or WT color scheme changes trigger a notification with the dark/light state.

@microsoft-github-policy-service microsoft-github-policy-service Bot added the Needs-Tag-Fix Doesn't match tag requirements label Jun 19, 2026
@DHowett

DHowett commented Jun 19, 2026

Copy link
Copy Markdown
Member

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. ...

That's correct, it reports the user preference in WT ...

I think James means "the prevailing color inside the terminal," rather than "the theme the user has selected for the terminal's UI".

Considering:

image

Even though the terminal chrome is Light (which this PR places in precedence order before the Windows theme, correctly), the prevailing theme inside the application-controlled region is dark.

I don't want apps to suddenly switch to a light theme just because I enabled light mode in the OS.

It would be reasonable to expand this to "just because I enabled light mode in the tab strip, command palette and title bar of Terminal" 🙂

@aymanbagabas

Copy link
Copy Markdown
Member Author

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).

@DHowett

DHowett commented Jun 19, 2026

Copy link
Copy Markdown
Member

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

But also TUIs like vim should be able to reflect dark/light mode changes as soon as the desktop has changed to light/dark mode or the user has changed the terminal profile.

"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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs-Tag-Fix Doesn't match tag requirements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement (Contour's) Color Palette Update Notification and report

3 participants