Skip to content

Add support for Windows Dark Mode#1217

Merged
goddessfreya merged 14 commits intorust-windowing:masterfrom
davidhewitt:windows_dark_mode
Dec 22, 2019
Merged

Add support for Windows Dark Mode#1217
goddessfreya merged 14 commits intorust-windowing:masterfrom
davidhewitt:windows_dark_mode

Conversation

@davidhewitt
Copy link
Copy Markdown
Contributor

I had a go at adding simple support for Windows 10's "Dark Mode". The moment the title bar will set to light / dark automatically according to system theme. I did not add an option for users of winit to disable this behaviour, as I felt it's likely desirable for most use cases. I can change that if you prefer otherwise!

Please advise on any documentation you'd like me to update.

The "window" example when Dark Mode is enabled:

image

  • Tested on all platforms changed
  • Compilation warnings were addressed
  • cargo fmt has been run on this branch
  • Added an entry to CHANGELOG.md if knowledge of this change could be valuable to users
  • Updated documentation to reflect any user-facing changes, including notes of platform-specific behavior
  • Created or updated an example program if it would help users understand this functionality
  • Updated feature matrix, if new features were added or implemented

Closes #1193

@davidhewitt
Copy link
Copy Markdown
Contributor Author

(I rebased onto master to fix the merge conflict)

@Osspial
Copy link
Copy Markdown
Contributor

Osspial commented Oct 9, 2019

For the most part, this seems good. Could you add a function to WindowExtWindows to allow users to retrieve whether dark mode is active or not? We should let users change their theme based on the OS option if they can.

EDIT: Ideally, we'd expose some sort of event that would notify users when the theme change has occurred, but we don't currently expose any mechanism for platform-specific messages and I don't know if this can be abstracted across multiple platforms. Neither of those are unsolvable problems, but I don't know if we want to solve them here.

@davidhewitt
Copy link
Copy Markdown
Contributor Author

Thanks for the review! I've added a field to WindowState to track the current state of dark mode.

Regarding the event, I was also wondering about such. I know MacOS also has a dark mode though know nothing about its integration in APIs. So the message might be relevant on at least two platforms.

@chrisduerr
Copy link
Copy Markdown
Contributor

I know MacOS also has a dark mode though know nothing about its integration in APIs

Dark mode on macOS is enabled by setting a property in the info.plist file. I'm not sure how you query for it as an application, but to support it there's no support necessary from winit (Alacritty already sets this property).

@davidhewitt
Copy link
Copy Markdown
Contributor Author

A quick google for macOS suggests we might be able to recieve a system broadcast for it on that platform too: https://stackoverflow.com/questions/39048894/how-to-detect-switch-between-macos-default-dark-mode-using-swift-3

So it might be appropriate to add a WindowEvent called SystemThemeChanged or DarkModeChanged - which might never get sent on some platforms (for now) but could be sent on (at least) Windows and macOS.

I don't have a mac so can't do the implementation for that platform. If you agree we should add a new WindowEvent I can do the Windows implementation as part of this PR and then open an issue for someone else to follow up with mac support.

@Osspial
Copy link
Copy Markdown
Contributor

Osspial commented Oct 16, 2019

@davidhewitt I'm fine with taking that approach.

@davidhewitt
Copy link
Copy Markdown
Contributor Author

Great - have now added an event DarkModeChanged and confirmed it fires during the window example.

@davidhewitt
Copy link
Copy Markdown
Contributor Author

Just a heads up; I recently updated my system to the latest Windows Insiders and it appears that this definition: const DWMWA_USE_IMMERSIVE_DARK_MODE: DWORD = 19; now needs to be 20 for the window example to run successfully on my system. I've no idea if this is an intended change or a bug or what.

The windows terminal source doesn't appear to have changed from 19 to 20, but that still works fine, which is puzzling. Might be worth holding off on merging this until I figure out what's going on.

Copy link
Copy Markdown
Contributor

@Osspial Osspial left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be good to merge once my comment below and your issue have been addressed. Sorry about taking so long to review this.

@davidhewitt
Copy link
Copy Markdown
Contributor Author

davidhewitt commented Nov 2, 2019

I've updated the to use a ThemeChanged event, and created a workaround for my problem. The best solution I could come up with is checking the Windows 10 build version and subsequently choosing the appropriate value for DWMA_USE_IMMERSIVE_DARK_MODE.

@goddessfreya goddessfreya added DS - win32 Affects the Win32/Windows backend C - waiting on maintainer A maintainer must review this code labels Nov 11, 2019
@goddessfreya
Copy link
Copy Markdown
Contributor

@Osspial This is, afaik, good for merge?

@Osspial
Copy link
Copy Markdown
Contributor

Osspial commented Nov 14, 2019

@davidhewitt Sorry it took so long to get back to you on this. I have no idea what's going on with dark mode on your system, since 8ba2055 completely broke this for me. There are two primary issues:

  • WIN10_BUILD_VERSION is defined as 4026549603 on my system, far outside the range defined in the source file.
  • Setting DWMWA_USE_IMMERSIVE_DARK_MODE to 20 causes the DwmSetWindowAttribute to fail. 19 works fine.

I'm inclined to remove the windows version check and publish this with DWMWA_USE_IMMERSIVE_DARK_MODE = 19.

@davidhewitt
Copy link
Copy Markdown
Contributor Author

I'm inclined to remove the windows version check and publish this with DWMWA_USE_IMMERSIVE_DARK_MODE = 19.

I would happily undo the version check! Strange about my system then. Are you on a stable windows 10 release or an insiders build?

@davidhewitt
Copy link
Copy Markdown
Contributor Author

davidhewitt commented Nov 14, 2019

Rebased on master.

@Osspial I've changed the method used for querying the Windows 10 build version. Does this new method now return a build version within the expected range on your machine?

(I'm currently on Windows 10 insiders build 19018, and WIN10_BUILD_VERSION is coming out as 19018)

If this new method doesn't work on your box, then I'll remove the version checking and hard-code 19 again. Though it might be great if someone else on Windows 10 insiders can report their build number and also whether 19 or 20 is the correct definition of DWMWA_USE_IMMERSIVE_DARK_MODE for them.

I will also try downgrading my system to the Windows 10 November 2019 update (build number 18363, I believe), and check what the behavior is on there. My suspcision is that in that version 19 is still the correct ordinal. That'll give me an opportunity to then reinstall insiders and confirm that it's not just my system being bugged somehow.

So I think there's still a little bit of research to do before we can merge this :(

@chelmich
Copy link
Copy Markdown
Contributor

On my machine WIN10_BUILD_VERSION is reported as 18362. This matches what is displayed by winver. I can confirm that the dark theme works as intended, including changing the theme while a window is open.

@daxpedda
Copy link
Copy Markdown
Member

I had access to a machine with windows build 17763 on it, tried this out and it works as intended, WIN10_BUILD_VERSION was also reported correctly.

A tiny thing that I noticed: it doesn't change theme when the window isn't focused, but it will switch to the correct one as soon as it's focused again.

@davidhewitt
Copy link
Copy Markdown
Contributor Author

Thanks guys. Anyone else also on Windows 10 insiders builds greater than 18363? Looks like if there was an API change (if there is indeed one and it's not my system) it ocurred on a build later than that.

A tiny thing that I noticed: it doesn't change theme when the window isn't focused, but it will switch to the correct one as soon as it's focused again.

Interesting. Did you happen to notice at what time the ThemeChanged event is being fired in the window example? Is it when it switches into focus, or when you change the dark theme setting? (On my system the ThemeChanged event fires when I change the system setting, regardless of focus.)

@daxpedda
Copy link
Copy Markdown
Member

Did you happen to notice at what time the ThemeChanged event is being fired in the window example?

It fires as soon as I change the system setting, even though it will only actually switch theme when I focus the window again.

Same behaviour as on your system.

@davidhewitt
Copy link
Copy Markdown
Contributor Author

It fires as soon as I change the system setting, even though it will only actually switch theme when I focus the window again.

Cool. So we can probably make it switch theme sooner if we force Windows to redraw the title bar.

Past experiments I've had into trying to do that have never been very successful... anyone know a nice API to force the title bar to redraw? 😄

@daxpedda
Copy link
Copy Markdown
Member

Past experiments I've had into trying to do that have never been very successful... anyone know a nice API to force the title bar to redraw? 😄

I was playing around with this for a bit and as far as I could find, using SetWindowPos with SWP_FRAMECHANGED should fix this, but it doesn't. The only thing I could find is resizing the window to a new size, any size does it, just not the original one.

So the only workaround I could come up with, is if the window isn't focused, we want to resize the window by one pixel and than back again.

@davidhewitt
Copy link
Copy Markdown
Contributor Author

davidhewitt commented Nov 26, 2019

So the only workaround I could come up with, is if the window isn't focused, we want to resize the window by one pixel and than back again.

Yeah that's similar to the only thing I could find too. Feels rather hacky to me. Given that this focus issue only applies to an out-of-date Windows 10 build, my vote would probably be to not introduce such a workaround. :(

@daxpedda
Copy link
Copy Markdown
Member

Given that this focus issue only applies to an out-of-date Windows 10 build

I didn't know this issue is not present in newer builds? I will try on a newer build now and report back.

@davidhewitt
Copy link
Copy Markdown
Contributor Author

I didn't know this issue is not present in newer builds? I will try on a newer build now and report back.

I'm now doubting myself. Pretty sure on my system (most recent Windows Insiders build) the frame changes whether focussed or not. I'll check later.

@daxpedda
Copy link
Copy Markdown
Member

daxpedda commented Nov 26, 2019

Just tried it on the newest build, works as intended.

You were right, this only affects older versions of windows. I would consider this a bug on windows, not our problem.

@daxpedda
Copy link
Copy Markdown
Member

Out of curiosity, how are you testing so many Win10 versions so quickly? VMs?

Hahaha, that would be epic! 😄
My main windows machine is running LTSC, which is currently stuck at 17763, but my tablet is running 18362, so we just happen to be fortunate 😁.

Copy link
Copy Markdown
Member

@daxpedda daxpedda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, I'm not sure if we should stop using LoadLibraryExW here or start using it everywhere else in the codebase too.

@davidhewitt
Copy link
Copy Markdown
Contributor Author

Thanks; I switched to use get_function! and LoadLibraryA.

Copy link
Copy Markdown
Member

@daxpedda daxpedda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of tiny improvements.
Not sure if reducing the amount of as is actually desired.

@davidhewitt
Copy link
Copy Markdown
Contributor Author

Thanks again, have addressed all those suggestions.

@goddessfreya goddessfreya requested a review from Osspial December 5, 2019 09:32
@Arcitec
Copy link
Copy Markdown

Arcitec commented Dec 6, 2019

Looking really good now. Great work @davidhewitt

@Osspial
Copy link
Copy Markdown
Contributor

Osspial commented Dec 22, 2019

Sorry about the delay reviewing this. Once my nit is addressed this should be good to go. Thank you for researching and implementing this!

@davidhewitt
Copy link
Copy Markdown
Contributor Author

Nit fixed, and rebased - expecting the CI to be green and fingers crossed this is good to merge!

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

Labels

C - waiting on maintainer A maintainer must review this code DS - win32 Affects the Win32/Windows backend

Development

Successfully merging this pull request may close these issues.

Add support for Windows dark theme

7 participants