microsoft/vscode

[themes] setting for preferred light and dark color theme based on system dark mode setting (Windows/Mac)

malmaud opened this issue Β· 39 comments

Feature request: It would be cool if I could register in VSCode a preferred light workbench color theme and a separate preferred dark color them. Then VSCode could automatically switch to my chosen light or dark theme based on the system-wide Mojave dark appearance option.

Windows also has a dark mode now which we don't respect.

This issue is being closed to keep the number of issues in our inbox on a manageable level, we are closing issues that are not going to be addressed in the foreseeable future: We look at the number of votes the issue has received and the number of duplicate issues filed. More details here. If you disagree and feel that this issue is crucial: We are happy to listen and to reconsider.

If you wonder what we are up to, please see our roadmap and issue reporting guidelines.

Thanks for your understanding and happy coding!

This issue doesn't seem to be addressed nor duplicated.

It is about automatically switching colour theme based on macos mojave light mode vs dark mode.

So for instance, in Mojave Light Mode, I want to use:

	"workbench.colorTheme": "GitHub Plus",

However in Mojave Dark Mode, I want to use:

	"workbench.colorTheme": "Monokai"

Which when using this setting with flux, would mean that when the sun is up, my system, and vscode, and the vscode theme is using light mode, and when the sun is down, everything is using dark mode.

screen shot 2018-11-20 at 2 39 23 pm

I agree - I don't see what issue duplicates this and this issue has 7 votes now.

If anyone is interested in this I've made a small extension that does this for now, personally would love to see it built-in though πŸ‘

https://marketplace.visualstudio.com/items?itemName=LinusU.auto-dark-mode

thanks @LinusU for the extension, it detects changes to dark vs light almost instantly

I change my theme a lot depending on time of the day and it's annoying to not see VS Code respect that / having to switch VS Code manually. It's the only app I have that requires this.

Considering windows has Dark and Light mode now, and extension developers can manage it, I don't think this issue should be "out of scope." :/

Me either

macOS now supports automatic switching between dark theme and light theme depending on the time of day. This seems like the perfect time to start respecting the system theme.

@aeschli Hi Martin, I just found this discussion via Google and noticed that you're considering the feature. I'd just like to mention a use-case to keep in mind: Some people would love the ability to switch between a Light and Dark theme, but to not be tied to the system setting.

Anyway, here are extensions that may help:

And two more extensions that allow manually switching between Light and Dark themes:

And here is an extension which changes to predefined themes (can be more than two themes) at certain times of day:

And here is one that sets the theme based on sunset/sunrise (auto detected via world location, if you set it up completely), and it also supports changing based on system theme (on Mac only, not Windows), and it also adds a keybind to swap between to themes (doing so disables the automatic changing):

And lastly one that lets you cycle between all themes or a list of themes (such as a light and dark theme):

My dream solution would be to be able to swap between two themes with a Command Palette choice. Not at all tied to the system Dark setting. Just putting that interest out there, since it's better to keep such things in mind rather than to get a bunch of user requests for such a change later.

I also bet some other people will want some "time of day" based theme switching. Basically, the smartest design would be a generic framework for swapping between a Light and a Dark theme, and then various triggers as input for it: Manual Command Palette, or Time Based, or System Dark Theme Based.

PS: I'll personally go with the last extension on my list above. The "cyclic" theme switcher. It solves everything for me, and it's nice that it can cycle between a list of let's say 3 themes (so it isn't just a rigid Dark / Light choice). Good luck, everyone!

Thanks @VideoPlayerCode for the great summary of extensions out there.

With so many extensions to choose from and so many variants I think we can close the issue and leave this feature to extensions.

I disagree with that VSCode wouldn't provide this functionality out-of-the-box and I have to install an extension for this. I tried couple of extensions and some just don't work with my Mac...

Please support the extensions by filing issues if something is not working for you.
We need to share the work and want to have a rich extension eco-system.

Likewise disagree that this functionality should be delegated to extensions. It is now core functionality on system apps. MacOS HIG specifies that Dark Mode adaptation should be automatic. Overriding the system theme is optional.

@aeschli my extension is broken with the automatic switching on macOS Catalina, and it seems like the only way to get it to work again is to have the extension present some kind of UI. That is a system tray bar, a window or anything else visible to the user. (ref: LinusU/vscode-auto-dark-mode#11)

This of course would offer a very subpar experience. But if this was implemented directly in VS Code itself, it wouldn't be a problem since it already presents a window to the user.

I also very much agree with this:

MacOS HIG specifies that Dark Mode adaptation should be automatic. Overriding the system theme is optional.

@aeschli If we wanted to add this to core we could use window.matchMedia to listen for changes in prefers-color-scheme - this wouldn't be much code and would also work in web without needing any native node modules.

I use matchMedia in xterm.js to detect window DPR changes.

@aeschli You're welcome. The only thing I noticed today, when going through the "auto detect dark theme" code of the Windows theme, is that it uses some batch file and a registry read to detect the mode. It's kinda horrible. Likewise the Mac themes use some kinda hacks.

So I do agree that extensions should offer this feature, but VSCode kinda needs a built-in "Is Dark Mode Active on the system?" API/"on-change callback" to make the extensions cleaner and more robust. How about that? It's a smaller scope than originally asked for, and should be a lot easier to add to VSCode, and will help the extensions become robust.

PS: I use the "Theme Switcher" by JanBn as mentioned, and it's perfect. Bound Ctrl-Alt-T to "Next Theme (from separate list in config)" and that code now cycles between 3 or so themes for me. Just a tip for people who want that functionality. It was the least complicated extension to offer that feature, and the only one that offered more than 2 theme cycling. It was also really good for going through all installed themes (it has keybinds for that too) and comparing them quickly. Thanks to that, I was able to quickly compare all light themes and find the one with the best contrast/syntax highlighting!

Edit: Hmm... @Tyriar above mentioned that JavaScript has a cross-platform way of checking if the system is set to Light or Dark mode. I've never heard of that. Apparently the syntax is as follows:

window.matchMedia('(prefers-color-scheme: dark)').matches // this is true or false

Edit2: Works perfectly on Windows 10. I checked that property before and after setting Windows to dark theme, and it properly returned false first and true later. So there is zero need for any VS Code API/property change callback for this feature. I suspect that both Windows and Mac can get perfect support for detecting dark mode via that property. Thanks @Tyriar !

Edit3: You can also add INSTANTLY REACTING CALLBACKS! There is zero need for any VSCode changes! And ZERO need for any ugly setInterval or similar solutions to check the property constantly. Any extension maker can create an instantly-reacting extension via this code:

window.matchMedia('(prefers-color-scheme: dark)').addListener(function (isDark) {
    console.log("user wants dark theme: ", isDark.matches);
});

Edit4: I've now tested all code inside VSCode. Works perfectly. So, anyone who wants to make a Universal extension for instant theme-switching based on light/dark, simply needs to do two things: 1. At VSCode startup (extension loading), use the first syntax above to check which theme to load based on the current dark/light mode value, 2. Register a callback using the second syntax, which instantly changes between the light and dark themes based on the callback. Wanna be famous? Anyone can write this extension in like 20 lines of code. Just make an extension which defines two JSON properties for the theme choices, and reacts based on the rules above, along with a VSCode property-listener to detect if the user changes the JSON theme properties, and voila you're done.

Edit5: It has sadly been confirmed that only core VSCode is allowed to access the matchMedia or Electron (mentioned further down) APIs that can check dark mode. So at the very least, the dark mode check (and callback listener registration for efficiency) needs to be exposed to extensions.

Thanks @VideoPlayerCode for the great summary of extensions out there.

With so many extensions to choose from and so many variants I think we can close the issue and leave this feature to extensions.

Light and Dark mode adapting to system theme should really be a core feature. There's plenty of resources available for implementing this. Every browser already does. Forcing the user to install an extension for basic functionality is a bit much. Extensions eat resources and you shouldn't have to raise minimum requirements for simple functionality like this.

In regards to making it manual, I think consistency in an interface is important so a boolean setting to enable Change With System with a default of true is the best solution IMO.

@michaelchiche External extensions do not eat any resources that wouldn't already be taken by implementing the exact same JavaScript in VSCode's built-in extensions.

By the way look at #61519 (comment), with @Tyriar's help, I found a way to detect dark/light mode on both Mac and Windows. All "broken" extensions above can be fixed. No need for any hacks to detect dark mode anymore.

I've now taken @aeschli's advice and alerted extension creators about the better method. There's one more extension, by @LinusU. Since I know you read this thread, I'll tell you here. You can delete https://github.com/LinusU/node-dark-mode-listener/blob/master/index.js (ew, calling a 10 mb external Swift binary hehe) and start using the built-in, lightweight, instant-callback technique instead as mentioned above. Heck, your extension is already very small and therefore looks like the perfect candidate for creating the most minimalistic auto-dark/light mode switcher, which a lot of people here are asking for. Go for it! ;-)

@michaelchiche External extensions do not eat any resources that wouldn't already be taken by implementing the exact same JavaScript in VSCode's built-in extensions.

By the way look at #61519 (comment), with @Tyriar's help, I found a way to detect dark/light mode on both Mac and Windows. All "broken" extensions above can be fixed. No need for any hacks to detect dark mode anymore.

huh? I'm pretty sure extensions thread a whole new process and an extension involves installing an entire package. Why should VSCode be the only application to not support system dark/light modes? It makes much more sense to implement this as a core feature rather than rely on the community to keep extensions up to date. Electron has an API for this

@michaelgosling I think you want to link to this Electron API: nativeTheme

edit: after #83796, anyway.

@NilsEnevoldsen Thanks! I didn't read thoroughly enough to see that its deprecated now.

@michaelgosling You're right, I see now that each extension runs in a separate JS host, and communicates with the main host. Interesting... It's not a big deal though.

But you won me over with this comment: "Why should VSCode be the only application to not support system dark/light modes?"... True. Since APIs already exist in JavaScript for detecting the dark mode and getting a callback call whenever dark mode changes (I tested, they're supported in VSCode), and there even seems to be Electron APIs for the same thing... there really isn't much code that would need to be added to the VSCode core. Something like adding optional darkTheme, lightTheme and autoDarkTheme boolean JSON properties...

Those hosts add up quick, in my opinion. But it seems we’re in agreement, at the very least this should be a core feature when vscode moves to electron 7.

Ok, I reopen.Accessing the Electron or Dom API can only be done in the core.
If anyone wants to give it a try, I'm open for a PR.

@aeschli Could you give a hint where to start? I would take on this and enabling the Electron API, because I think it's a more consistence way for extension developers to use the VS Code API instead of using the DOM. Which would also give better abilities for tests, I guess.

There's a similar path when the OS reports that high contrast mode has been enabled:

Electron event in the main thread:

this.sendToAll('vscode:enterHighContrast');

Broadcasted to all renderers:

ipc.on('vscode:enterHighContrast', async () => {

We need a setting to let users set their prefered theme for light, dark and hc.
Also a setting that controls to enable/disable the auto theme switching.

If this can be done via browser event as @Tyriar describes, even better.

Ok, I reopen.Accessing the Electron or Dom API can only be done in the core.
If anyone wants to give it a try, I'm open for a PR.

Ouch. I see. Well at the very least, let's expose the Electron nativeTheme API (with both the function for checking and the ability to register callbacks) to extensions so that they can react to the correct theme. It would be needed regardless of whether switching is added to core. See: #61519 (comment)

If this can be done via browser event as @Tyriar describes, even better.

It can. As mentioned, I tried it in VSCode's built in Electron console. But why is that method preferable over Electron's API?

Also thank you @muuvmuuv for looking into this!

@VideoPlayerCode we don't want to rely on Electron APIs as then they won't work when VS Code is run in the browser and also Electron APIs could change and web APIs won't.

@Tyriar Woah, I didn't know vscode can run in the browser!

Well then it is fantastic that the web API exists! I hope extensions can get access to querying the various accessibility aspects. The Electron API gives hints: https://electronjs.org/docs/api/native-theme

DARK
INVERTED
HIGHCONTRAST

Those are the three types of accessibility themes available.

@aeschli already mentioned that vscode supports one of them and sends an event to all extensions.

So here is a stage 1 proposal:

  1. Support all three events via media match query.
  2. Broadcast the events to extensions when they happen.
  3. Add APIs to let extensions statically query the active mode at any time.

Stage 2: Theme switcher built into Vscode, based on the principles established in stage 1.

Makes sense, when I have more time I will look into this and try to expose the window API to extension authors.

I had time to look a bit deeper into the Core and this request. It seems like that the new Electron API has some deprecation (and Code needs too much time to update electron) regarding the method to get the preferred theme. So using the window match media makes the most sense. I'll try (first time contributing to Core) to set up a first proposal today. Since it wasn't clear enough to me what the high contrast thing does (and because it is windows only at this time) I'll leave it as is for now. Starting today with setting up the schema and logic. Stay tuned.
The new setting would be at workbench.colorThemeAutoSwitch: true/false, open for other suggestions. But this makes the most sense to me to keep the readability for users and to be visible in the search together with colorTheme.

Hey all!

Finished up something. Commit/PR will go out today. Would love to get some feedback. I'm pretty sure I have implemented it on the correct location but would like to get someone approved this first, before I continue cleaning it a little up.

For the moment I have not exposed the browser API with match media query rather have directly coded the theme switch into the core, which IMO makes more sense. I'm the Author of Sundial, which of course would make my extension a little useless but unless I created it just for the moment as soon as Code implements it by its own, I'm fine with that and still, Sundial provides some useful options besides the "auto theme switch".

Here is a little preview for VS Code in a browser (I haven't been able to run the native version yet):
https://imgur.com/a/o2DVjCW

@muuvmuuv That's excellent progress, thanks for working on this!

As for "high contrast", press Win+S to search, type "high contrast", and enable it. It's basically a Windows 3.1 theme. The dialogs become pitch black except for a pixel-arty window outline. ;-)

And as for the "inverted theme", I am not sure where to turn it on in Windows (doesn't seem like it's available), but it's definitely available on Macs, and it is literally the "inverted colors" effect. It just turns everything on-screen into their opposite colors. Everything gets an "alien glow" effect. Photos get totally weird. It used to be a smart solution before "Dark themes" existed in the world.

Your current solution supports dark theme switching, and doesn't expose any API to extensions. Seems fine, since dark themes are the most useful of the 3 types of accessibility themes.

If we ever expose APIs for querying/listening to theme events, then we should expose all three (dark mode, high-contrast mode, and inverted mode). What do people think? Are APIs important? It would allow extensions to take over the job of theme switching, via their own custom logic. Then again, not sure what extensions would wanna do with that...

And yes, using web media queries is better than the Electron API, as people mentioned above. It's more portable and works in the web browser version of VS Code.

Hope these answers help. Thanks a lot for your great work!