racket / gui

Other
63 stars 76 forks source link

Dark Mode under Windows #197

Open rfindler opened 4 years ago

rfindler commented 4 years ago

The OS-drawn controls aren't working properly when DrRacket is in dark mode.

This issue was created by culling the specific comments from https://github.com/racket/drracket/issues/235.

@jcolivo wrote

Hello Racket Team, I appreciate all the hard work on trying to improve the dark mode in DrRacket. Thank you.

Just hoping that you won't forget us Windows users. ;-) My issues are as pointed out in this thread: https://groups.google.com/forum/#!topic/racket-dev/xYjE9JCe9u0

If there is anything I can do to help (I'm not a programmer, but can certainly help with testing), please let me know.

Have a wonderful weekend!

@alex-hhh wrote

The registry key AppsUseLightTheme in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize, will be 1 or missing if applications use the "light" theme and will be 0 if the applications should use a dark theme.

I verified that AppsUseLightTheme changes to 0 if I select "dark" mode in my preferences on my Windows 10 machine. The key is missing if "Dark" mode was never selected on a machine.

white-on-black-panel-scheme? could just look for this key on Windows?

Source: https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application

@mflatt wrote:

More ideas for dark mode on Windows based on various undocumented flags and functions: mflatt/gui@fd38e76

Last time I looked at this, I concluded that system Win32 control classes like buttons or checkboxes (I forget which, but I think it was buttons) don't support dark mode.

@jcolivo wrote

I found the Windows Registry Key as @default-kramer mentioned above referencing the StackOverflow thread: https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application

If you want the "Choose your default app mode" setting, I'm pretty sure that I can find it in the Windows registry somewhere. (In fact, this looks like it: https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application) I can try to make a PR for mrlib if this is the desired behavior. I don't have any older versions of Windows handy, so it will likely support Win10 only.

On my system (64 bit Windows 10, latest version), I verified the location of the registry key: Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize

This is a screenshot of the key when light theme is chosen. Notice the ApsUseLightTheme value set at 0x00000001 (1) Light Theme On

This is a screenshot of the key when dark theme is chosen. Notice the ApsUseLightTheme value now set at 0x00000000 (0) Light Theme Off

Would this feature require Racket code to look for this specific registry key value, or would the code be written at a lower level?

alex-hhh commented 4 years ago

I switched my Windows machine to Dark mode, and only some of the applications changed to Dark mode. In particular, most of the Windows tools, such as control panel property boxes remained to the default "light" mode.

I suspect the registry setting and the windows message about the mode change is more an "advisory" setting. Applications built on .Net technologies will use it because the .Net libraries use it, but the Win32 controls don't. As such, if DrRacket (and the Racket GUI library) would like to implement Dark mode, it would either have to change to use the .Net GUI libraries, or do their own drawing of controls such as buttons, and consult the registry to determine if dark mode is enabled or not.

samusz commented 2 years ago

Dark mode in the preferences of DrRacket may be the easy route to go ?

rfindler commented 1 year ago

It looks like there has been some movement in the Windows API documentation related to dark mode. Here's an article from the end of 2022: Support Dark and Light themes in Win32 apps.

Currently the get-label-{background,foreground}-color functions are implemented using GetSysColor and the results do not seem to change when changing my Windows 10 VM into dark mode as described here.

The article above seems to suggest using UISettings.GetColorValue(UIColorType::Foreground) but I don't know how to make that call from our FFI. This seems to be the docs for UISettings.GetColorValue. Does anyone know how to call that function and get its value back into Racketdom?

DexterLagan commented 1 year ago

Would that be helpful? Ref: https://learn.microsoft.com/en-us/answers/questions/715081/how-to-detect-windows-dark-mode

It depends on Windows versions On recent OS (>= Windows 10 1903) :

    [DllImport("UXTheme.dll", SetLastError = true, EntryPoint = "#138")] 
    public static extern bool ShouldSystemUseDarkMode();

test :

    bool bRet = ShouldSystemUseDarkMode();
DexterLagan commented 1 year ago

Another uglier option: wrapping around PowerShell. I found this, but it doesn't work on my system. Maybe there's a way:

(New-Object Windows.UI.ViewManagement.UISettings).GetColorValue("background")

Ref: https://stackoverflow.com/questions/38734615/how-can-i-detect-windows-10-light-dark-mode

DexterLagan commented 1 year ago

Also, according to this, Visual Styles have to be enabled for GetThemeSysColor to work.

Ref: https://stackoverflow.com/questions/63159666/get-windows-10-theme-color-in-classic-c-winapi-win32-application

DexterLagan commented 1 year ago

Found the header file for the windows.ui.viewmanagement class for accessing UISettings, but for WinRT. Maybe these constants can help us with the FFI? Ref: https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/winrt/windows.ui.viewmanagement.h

DexterLagan commented 1 year ago

Here's a hack that uses an undocumented dark mode API introduced in Windows 10 1809: https://github.com/ysc3839/win32-darkmode I wouldn't use it, but it's a start?

DexterLagan commented 1 year ago

Another example in low(er) level C, using uxtheme.dll: https://github.com/ysc3839/VCMPBrowser/blob/darkmode/DarkMode.h

Cheers

LiberalArtist commented 2 months ago

I was reminded of this by a Discourse thread. I haven't thought about this in the last year, but I'll consolidate thoughts I had then into this issue.

In https://github.com/racket/gui/pull/293#issuecomment-1482080488 I wrote:

On Windows, the de facto way seems to be using RegNotifyChangeKeyValue to detect changes to the AppsUseLightTheme value of HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize (which may not exist).

In https://github.com/racket/gui/pull/293#issuecomment-1482100580 I wrote:

I've looked into windows (and there is an issue discussing it somewhere, I think) and the OS doesn't seem to provide a way to detect the theme.

That's my understanding, too, as far as detecting the theme. There's a Microsoft article recommending basically the same strategy white-on-black-panel-scheme? uses, but using a Windows-specific API. The registry key I mentioned is undocumented, but seems to be used by a number of projects, like Chromium, to detect changes to the theme.

racket-discourse-github-bot commented 2 months ago

This issue has been mentioned on Racket Discourse. There might be relevant details there:

https://racket.discourse.group/t/scope-and-purpose-of-racket-gui/2965/2