Add support for the DECSCNM Screen Mode #5294

Closed
opened 2026-01-31 00:09:54 +00:00 by claunia · 5 comments
Owner

Originally created by @j4james on GitHub (Nov 28, 2019).

Description of the new feature/enhancement

The DECSCNM (screen mode) escape sequence is a DEC private mode for switching the display between normal and reverse - often referred to as dark and light backgrounds on monochrome terminals. I doubt it's widely used in practice, but it's needed to pass some of the tests in the Vttest suite.

In the DEC STD 070 manual, the behaviour of the DECSCNM mode is described as follows:

Changing between normal and reverse screen mode will affect which attribute bits from display memory are used to render the text foreground and background color. It does not affect the current rendition, or how the current rendition is applied to the character attribute bits associated with each character in display memory.

I take that to mean that the background attributes of a cell will be used to render the text foreground and the foreground attributes will be used for the background. This seems to be how it's implemented in Konsole and the Linux virtual terminal, but there is quite a lot of variation in how other terminals interpret it. Without a clear consensus, though, I'd be inclined to follow the standard. As long as it passes Vttest, I don't think it really matters.

Proposed technical implementation details

Looking at the conhost side of things, I think this can be achieved with a new flag in the Settings class, and then updates to the LookupForegroundColor and LookupBackgroundColor methods, to switch the returned foreground and background colors when the flag is set. This seems to be enough to make the renderer draw everything with the correct colors, including underlines.

We'll also need a new private API in the ConGetSet interface, which can be called from the AdaptDispatch class to actually toggle the mode, and trigger a redraw of the display. And the HardReset implementation should probably be updated to reset the mode back to normal.

As for the Windows Terminal, my preliminary tests suggest it doesn't require anything special. Whatever is rendered on the conhost side seems to be passed through correctly via conpty as well.

Originally created by @j4james on GitHub (Nov 28, 2019). # Description of the new feature/enhancement The [`DECSCNM`](https://vt100.net/docs/vt510-rm/DECSCNM.html) (screen mode) escape sequence is a DEC private mode for switching the display between normal and reverse - often referred to as dark and light backgrounds on monochrome terminals. I doubt it's widely used in practice, but it's needed to pass some of the tests in the [Vttest](https://invisible-island.net/vttest/) suite. In the _DEC STD 070_ manual, the behaviour of the `DECSCNM` mode is described as follows: > Changing between normal and reverse screen mode will affect which attribute bits from display memory are used to render the text foreground and background color. It does not affect the current rendition, or how the current rendition is applied to the character attribute bits associated with each character in display memory. I take that to mean that the background attributes of a cell will be used to render the text foreground and the foreground attributes will be used for the background. This seems to be how it's implemented in Konsole and the Linux virtual terminal, but there is quite a lot of variation in how other terminals interpret it. Without a clear consensus, though, I'd be inclined to follow the standard. As long as it passes Vttest, I don't think it really matters. # Proposed technical implementation details Looking at the conhost side of things, I think this can be achieved with a new flag in the `Settings` class, and then updates to the `LookupForegroundColor` and `LookupBackgroundColor` methods, to switch the returned foreground and background colors when the flag is set. This seems to be enough to make the renderer draw everything with the correct colors, including underlines. We'll also need a new private API in the `ConGetSet` interface, which can be called from the `AdaptDispatch` class to actually toggle the mode, and trigger a redraw of the display. And the `HardReset` implementation should probably be updated to reset the mode back to normal. As for the Windows Terminal, my preliminary tests suggest it doesn't require anything special. Whatever is rendered on the conhost side seems to be passed through correctly via conpty as well.
Author
Owner

@egmontkob commented on GitHub (Nov 28, 2019):

I doubt it's widely used in practice

I think it's used by some apps to achieve a visual bell. Terminfo describes flash=\E[?5h$<100/>\E[?5l, the middle segment apparently encoding a delay. Accordingly, tput flash switches to global reverse mode for 0.1 seconds. I haven't seen any app (except for vttest) enabling this mode for a longer time, and they really shouldn't.

Probably the same question applies as for the per-character reverse mode (SGR 7): if combined with the "bright" attribute is it the foreground or the background to be brightened? I don't think it really matters. Probably the simplest is just to XOR the per-character "reverse" bit with this global flag, and have whatever comes out of that.

In my opinion emitting this sequence, even for the purpose of a visual bell, is a terrible practice. The timing is unreliable across a remote connection. The sudden switch between such different colors, especially if repeated a couple of times, could perhaps even trigger epileptic seizure in some people. I think apps should emit the regular BEL, and it should be a user setting of the terminal whether they want audible or visual bell (or both or none), whereas the visual can be implemented in more sophisticated ways, e.g. a smooth transition back and forth between normal and reverse video, or a(n animated) bell icon symbol showing up in the tab bar, etc.

I've also seen apps toggling this global reverse mode back and forth without a delay in between, expecting to achieve a visual bell effect – like, what?

You might also want to look at this bug in "screen": https://savannah.gnu.org/bugs/?52545, just to give you an idea how broken sometimes it is implemented in practice.

That being said, of course it's okay to support this feature in the terminal and blame the apps that actually use it. :)

@egmontkob commented on GitHub (Nov 28, 2019): > I doubt it's widely used in practice I think it's used by some apps to achieve a visual bell. Terminfo describes `flash=\E[?5h$<100/>\E[?5l`, the middle segment apparently encoding a delay. Accordingly, `tput flash` switches to global reverse mode for 0.1 seconds. I haven't seen any app (except for vttest) enabling this mode for a longer time, and they really shouldn't. Probably the same question applies as for the per-character reverse mode (SGR 7): if combined with the "bright" attribute is it the foreground or the background to be brightened? I don't think it really matters. Probably the simplest is just to XOR the per-character "reverse" bit with this global flag, and have whatever comes out of that. In my opinion emitting this sequence, even for the purpose of a visual bell, is a terrible practice. The timing is unreliable across a remote connection. The sudden switch between such different colors, especially if repeated a couple of times, could perhaps even trigger epileptic seizure in some people. I think apps should emit the regular BEL, and it should be a user setting of the terminal whether they want audible or visual bell (or both or none), whereas the visual can be implemented in more sophisticated ways, e.g. a smooth transition back and forth between normal and reverse video, or a(n animated) bell icon symbol showing up in the tab bar, etc. I've also seen apps toggling this global reverse mode back and forth without a delay in between, expecting to achieve a visual bell effect – like, what? You might also want to look at this bug in "screen": https://savannah.gnu.org/bugs/?52545, just to give you an idea how broken sometimes it is implemented in practice. That being said, of course it's okay to support this feature in the terminal and blame the apps that actually use it. :)
Author
Owner

@j4james commented on GitHub (Nov 29, 2019):

I think it's used by some apps to achieve a visual bell.

I did not know that. Thank you! In fact I see we already have a bug report for visual bell support from way back (#72), which probably means this can be closed as a dup.

Probably the simplest is just to XOR the per-character "reverse" bit with this global flag.

Yep. Based on my reading of the spec that was my conclusion too. The way our code is structured it doesn't work out exactly like that, but the end result is the same.

In my opinion emitting this sequence, even for the purpose of a visual bell, is a terrible practice ... I think apps should emit the regular BEL, and it should be a user setting of the terminal whether they want audible or visual bell (or both or none), whereas the visual can be implemented in more sophisticated ways

Agreed. And I'm convinced we already have an issue with a suggestion along those lines although I can't find it right now.

I've also seen apps toggling this global reverse mode back and forth without a delay in between, expecting to achieve a visual bell effect – like, what?

Yeah, I was just testing the visible bell-style in bash that was mentioned in issue #72, and that's exactly what happened - my DECSCNM implementation had no visible effect. The vim visualbell option does at least work though.

@j4james commented on GitHub (Nov 29, 2019): > I think it's used by some apps to achieve a visual bell. I did not know that. Thank you! In fact I see we already have a bug report for visual bell support from way back (#72), which probably means this can be closed as a dup. > Probably the simplest is just to XOR the per-character "reverse" bit with this global flag. Yep. Based on my reading of the spec that was my conclusion too. The way our code is structured it doesn't work out exactly like that, but the end result is the same. > In my opinion emitting this sequence, even for the purpose of a visual bell, is a terrible practice ... I think apps should emit the regular BEL, and it should be a user setting of the terminal whether they want audible or visual bell (or both or none), whereas the visual can be implemented in more sophisticated ways Agreed. And I'm convinced we already have an issue with a suggestion along those lines although I can't find it right now. > I've also seen apps toggling this global reverse mode back and forth without a delay in between, expecting to achieve a visual bell effect – like, what? Yeah, I was just testing the visible bell-style in bash that was mentioned in issue #72, and that's exactly what happened - my `DECSCNM` implementation had no visible effect. The vim visualbell option does at least work though.
Author
Owner

@egmontkob commented on GitHub (Nov 29, 2019):

Haha, I totally did not remember that there was this #72 which I even commented on :-D

@egmontkob commented on GitHub (Nov 29, 2019): Haha, I totally did not remember that there was this #72 which I even commented on :-D
Author
Owner

@ghost commented on GitHub (Feb 13, 2020):

:tada:This issue was addressed in #3817, which has now been successfully released as Windows Terminal Preview v0.9.433.0.🎉

Handy links:

@ghost commented on GitHub (Feb 13, 2020): :tada:This issue was addressed in #3817, which has now been successfully released as `Windows Terminal Preview v0.9.433.0`.:tada: Handy links: * [Release Notes](https://github.com/microsoft/terminal/releases/tag/v0.9.433.0) * [Store Download](https://www.microsoft.com/store/apps/9n0dx20hk701?cid=storebadge&ocid=badge)
Author
Owner

@jdebp commented on GitHub (Feb 20, 2020):

The original purpose of the screen mode setting is laid out in the user guides, not in the programmers' references. The VT420 user guide, for example, explains that it is for "viewing comfort" and is to "improve readability". It's really a user preference, configurable in SETUP. It is one of the lockable user preferences, meaning that DECSCNM from a host might not do anything at all.

Note that terminal emulators do not do what real terminals did. XTerm has a long tradition of swapping "light" and "dark", and others have copied it, for starters. But then they don't even behave the same as one another when it comes to DECSCNM. Some swap foreground and background; some swap colour indexes 0 and 7; and some only reverse default-coloured text.

@jdebp commented on GitHub (Feb 20, 2020): The original purpose of the screen mode setting is laid out in the user guides, not in the programmers' references. The VT420 user guide, for example, explains that it is for "viewing comfort" and is to "improve readability". It's really a _user preference_, configurable in SETUP. It is one of the lockable user preferences, meaning that DECSCNM from a host might not do anything at all. Note that terminal emulators do not do what real terminals did. XTerm has a long tradition of swapping "light" and "dark", and others have copied it, for starters. But then they don't even behave the same as one another when it comes to DECSCNM. Some swap foreground and background; some swap colour indexes 0 and 7; and some only reverse default-coloured text.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#5294