PowerToys
PowerToys copied to clipboard
Added flyout theme setting
Summary of the Pull Request
Adds the ability to toggle the flyout between dark and light mode. Closes #23831.
PR Checklist
- [x] Closes: #23831
- [x] Communication: I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected
- [x] Tests: Added/updated and all pass
- [x] Localization: All end user facing strings can be localized
TODO
- [x] PT currently needs to be restarted in order for the change to take place
- [x] Brief flash of white before dark mode takes effect
- [ ] Fix settings icon not changing color initially
Validation Steps Performed
- [x] Added unit test
- [x] Tested the feature locally
@BLM16 Thank you for the contribution.
Doesn't it make more sense to bind the fly out on the Settings ui theme setting we already have?
I thought about that, but there is windows theme and app theme, and I have them set differently. I feel the flout should be separate so people can have it on dark mode while still using a light app theme.
Default for my apps is light mode, yet I use windows' dark mode.
That is why I have separated them: the settings UI should behave like an app, the flout should behave like a native part of windows.
I could change it and add a fourth (becoming the default) option to match PT theme.
Because it takes no extra effort to make a setting for it, and I see use, I added it.
I could change it and add a fourth (becoming the default) option to match PT theme.
Because it takes no extra effort to make a setting for it, and I see use, I added it.
What about reading the setting in Registry and let the user switch between "PT Theme" and "OS Theme"?
What about reading the setting in Registry and let the user switch between "PT Theme" and "OS Theme"?
That is a good idea. Keep light and dark manual, change the windows default to use windows' OS (not app) theme and add the default option to use PT theme (which would default to the windows app theme anyways)?
What about reading the setting in Registry and let the user switch between "PT Theme" and "OS Theme"?
That is a good idea. Keep light and dark manual, change the windows default to use windows' OS (not app) theme and add the default option to use PT theme (which would default to the windows app theme anyways)?
Sounds a bit complex. Maybe two independent settings are better. I think the most important question is which common usage scenarios will be there.
Sounds a bit complex. Maybe two independent settings are better. I think the most important question is which common usage scenarios will be there.
I don't quite follow what you mean. What I was thinking was for the flyout theme setting. having the following options:
- Light
- Dark
- Windows theme (Default setting to make flyout feel native?)
- PowerToys theme (Default setting to keep PT consistent?)
I would also likely change the App theme dropdown option to say "Windows app theme" instead of "Windows default" because this is more clear which windows theme it is using (since app and os themes both exist).
Thoughts on which flyout theme should be the default?
Sounds a bit complex. Maybe two independent settings are better. I think the most important question is which common usage scenarios will be there.
I don't quite follow what you mean. What I was thinking was for the flyout theme setting. having the following options:
- Light
- Dark
- Windows theme (Default setting to make flyout feel native?)
- PowerToys theme (Default setting to keep PT consistent?)
Let's do it without PT theme. I think if a user want to have it the same he can set both to light or dark.
I would also likely change the App theme dropdown option to say "Windows app theme" instead of "Windows default" because this is more clear which windows theme it is using (since app and os themes both exist).
Sounds good.
Thoughts on which flyout theme should be the default?
Let's have the OS theme as default.
@BLM16 mind adding a screenshot of the added settings card to the original post so folks can see what's happening there :)?
Hi, thanks for the contribution! Seems to function well enough, but after having opened the flyout already once, changing the setting doesn't seem to take effect until PowerToys is restarted. Other than that and the question from Niels about "AcrylicBackgroundFillColorDefaultBrush" being needed, it looks good to me!
I commented on the restart still being required and it is part of the TODO for this PR. I need to get that sorted out first.
@BLM16 mind adding a screenshot of the added settings card to the original post so folks can see what's happening there :)?
Added in the PR description up top.
@BLM16 mind adding a screenshot of the added settings card to the original post so folks can see what's happening there :)?
Added in the PR description up top.
Having the same card twice couls be confusing. What about having an SettingsExpander instead?
You can move the Flyout SettingsCard into the SettingsExpander.Items and remove the icon (and description I guess)
What about having an SettingsExpander instead?
Updated. See the edited image up top.
At this point, the flyout theme change works as expected. There is still a very brief flash of white before the dark theme takes effect when opening the flyout that I cannot seem to figure out.
At this point, the flyout theme change works as expected. There is still a very brief flash of white before the dark theme takes effect when opening the flyout that I cannot seem to figure out.
Two questions:
- Could you do a before vs. after screenshot to see if there are no visual changes to the Acrylic?
- Are tooltips (hover over a module button to show the shortcut tooltip) rendered in the correct theme?
The FlyoutWindow has the right Acrylic recipe defined (AcrylicBackgroundFillColorBaseBrush
). If I understand correctly, this PR introduces another layer of Acrylic in the ShellPage).
Might be that the flashing happens because the acrylic of the window gets loaded first (and is not adjusted to the theme)?
Either way, I think there are two options
- Remove the Acrylic from the FlyoutWindow and use
AcrylicBackgroundFillColorBaseBrush
in the ShellPage (I'm not sure if this would work - because the window background might no longer be translucent?) - Remove the Acylic from the ShellPage and handle the theme changes on the window itself (preferred)
See: (https://github.com/microsoft/PowerToys/blob/eeca3014e7841263cdc36a5c83f57a7d57728aec/src/settings-ui/Settings.UI/FlyoutWindow.xaml#L21
2. Remove the Acylic from the ShellPage and handle the theme changes on the window itself (preferred)
What do you mean by this? Change the acrylic to be on the LaunchPage.xaml
? Which window are you referring to?
The reason the acrylic is currently applied to the ShellPage is because this combines with the LayerOnAcrylicFillColorDefaultBrush of the LaunchPage and AppsListPage to create a lighter color than the bottom bar. This is similar to the slight difference in color on the toolbar of the win11 action center.
https://github.com/microsoft/PowerToys/blob/f85fc98352f68a59e3e77d30cbde800e92167c82/src/settings-ui/Settings.UI/Flyout/LaunchPage.xaml#L29-L32
Hang on, sorry. I see what you are meaning. I will look into that shortly. Not sure how I missed that previously but it looks like I would have saved a bunch of trouble if I saw that.
@niels9001 The correct acrylic brush should be used now. Thanks for pointing that out! The brief flash is also now fixed when handling the theme change from the base window rather than the shell page. The WinUIEx base theme was temporarily overriding the shell page when it was changing states.
The "ShellPage" is still handling the theme change, however it is the main window controlling this. WinUIEx doesn't give the option to manually set the RequestedTheme
as far as I can tell, so it had to be implemented this way. At least the window is controlling the theme.
Could you do a before vs. after screenshot to see if there are no visual changes to the Acrylic?


Are tooltips (hover over a module button to show the shortcut tooltip) rendered in the correct theme?
Yes, all the tooltips are rendered in the correct theme for the modules and other buttons. Their acrylics render as expected.
Could you do a before vs. after screenshot to see if there are no visual changes to the Acrylic?
![]()
Are tooltips (hover over a module button to show the shortcut tooltip) rendered in the correct theme?
Yes, all the tooltips are rendered in the correct theme for the modules and other buttons. Their acrylics render as expected.
Hmm.. we're still setting the acrylic brush twice, right? Looks like Background="{ThemeResource AcrylicBackgroundFillColorBaseBrush}"
kills the Acrylic effect.
Without AcrylicBackgroundFillColorBaseBrush
(expected):
With AcrylicBackgroundFillColorBaseBrush
But, removing it causes this when switching from dark to light theme:
But works with AcrylicBackgroundFillColorBaseBrush
(albeit with no transparency in the acrylic)
@BLM16 Would it make sense to just restart PowerToys to update this setting.. that should work, right? Changing themes of UWP/WinUI has always been a pain :(.. Thoughts?
@BLM16 Btw, we ran into the same issue with adding Mica to the Settings page - when switching themes the backdrop is gone and things don't render correctly. So if we can figure it out here we can solve it for Settings as well 😊!
Would it make sense to just restart PowerToys to update this setting.. that should work, right? Changing themes of UWP/WinUI has always been a pain :(.. Thoughts?
I will look into this and a few other solutions to see what is best. Good catch on the acrylic.
I have fixed the acrylic not showing colors from behind. The acrylic should now work for both themes and everything appears to function as expected.
I just wanted to follow up on this and see if anything else is missing from this PR that is preventing it from getting merged. Any updates would be appreciated 🙂!
@niels9001 Could you take a look? Thanks
I can help with merge conflicts
@check-spelling-bot Report
:red_circle: Please review
See the :open_file_folder: files view, the :scroll:action log, or :memo: job summary for details.
Unrecognized words (32)
dcompi
dwmcorei
ETW
Filetime
flyouts
lnks
Microsofts
msvcp
nand
nanother
napp
productwxspath
reparented
ringbuffer
screenshots
SIDs
subkeys
tapp
tbutton
tdisplay
tlocation
tprimary
tweakme
tworking
vccorlib
vcomp
vcruntime
websites
WMI
workarounds
wpfdepsjsonpath
wuceffectsi
Previously acknowledged words that are now absent
AAD abi Acl activatable adio ADMINS AEAD amd anges Animatable AOT Applets apps Arity asdf Attribs Aut AUTHN AUTHZ azor BDB BGR bitmask bluetooth Bopomofo bstr btn Bto buf bytearray cdecl chdir CIELAB CIEXYZ Cloneable Cls clsid cmdline cmyk cnt CODENAME COLORREF COMDAT CSIDL Ctx CUI cvtsi cwd Datavalue DATAW Dbg declspec deref dllexport dns dsc edis edshift endregion ERRORLEVEL estructuredtext etstat etw exif fabricbot FDF feimage filetime Finalizers flyout FSCTL FTYPE GAC gcnew GETSTATE GETTEXT google graphql gui HACCEL Hashtable HBRUSH HHmmss HHOOK highlighter HKL HLOCAL HOMEPATH HPALETTE hread HRSRC hsl hsv IBase idx Iface IIO imeutil ingbuffer inheritdoc Inlines ipc isfinite keydown keyup langword Lcid len lhs linq lnk LOCALAPPDATA LOn LPBYTE LPCWSTR LPPOINT LPRECT LPSTR LPVOID LPWSTR lshift lzw MAJORVERSION Maximizable Mega microsoft millis MINORVERSION mkd MODECHANGE MOUSELEAVE MOUSEMOVE MOUSEWHEEL msbuild msvc Mul myfile mysql nameof NESW nint NONAME NONCONVERT notfound notmatch NOUPDATE nuint numpad OBJID odbc Oem oid OLEDB onstd OUTOFMEMORY paramref pdb pdbonly PDWORD pgsql PHANDLE pid pkey plugins posix precomp PROGRAMFILES PULONG pwsh qps qword RAWINPUT Rbp READWRITE RECTL rects Refreshable reinit Remapper reparent retval rfc rhs RLO RMENU Rpc rshift scancode SCOPEID screenshot setenv setlocal SFP Shl sid snd spam sre standalone stdcall Subdir subfolders subkey subresource TApp targetnametoken taskbar tasklist tcl tcp Templated testapp testcase textblock typedef TYPEKEY TYPELIB typeparam uby Udp uid UIs ULARGE unapply unassign Uncompress Uninitialize uninstalling Unk Unmap unmute unsubscribe USERDOMAIN userprofile Utc utf uuidof vec Versioning viewbox Vpn vtable weakme websearch webserver website whitespaces wikipedia wildcards Winsock wmi workaround workflows workspaces writefile WSAEADDRINUSE WSAEADDRNOTAVAIL WSAECONNRESET wss Wwan XAttribute XOffset YOffset ypescript ZIndex zipfile 🫥To accept these unrecognized words as correct and remove the previously acknowledged and now absent words, you could run the following commands
... in a clone of the [email protected]:BLM16/PowerToys.git repository
on the flyout-theme-setting
branch (:information_source: how do I use this?):
curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/v0.0.22/apply.pl' |
perl - 'https://github.com/microsoft/PowerToys/actions/runs/6898774693/attempts/1'
Available :books: dictionaries could cover words (expected and unrecognized) not in the :blue_book: dictionary
This includes both expected items (2349) from .github/actions/spell-check/expect.txt and unrecognized words (32)
Dictionary | Entries | Covers | Uniquely |
---|---|---|---|
cspell:cpp/src/lang-keywords.txt | 44 | 2 | 2 |
cspell:npm/dict/npm.txt | 302 | 2 | 1 |
cspell:r/src/r.txt | 543 | 2 | 1 |
cspell:cpp/src/compiler-clang-attributes.txt | 46 | 1 | 1 |
cspell:monkeyc/src/monkeyc_keywords.txt | 123 | 1 | 1 |
Consider adding them (in .github/workflows/spelling2.yml
) for uses: check-spelling/[email protected]
in its with
:
with:
extra_dictionaries:
cspell:cpp/src/lang-keywords.txt
cspell:npm/dict/npm.txt
cspell:r/src/r.txt
cspell:cpp/src/compiler-clang-attributes.txt
cspell:monkeyc/src/monkeyc_keywords.txt
To stop checking additional dictionaries, add (in .github/workflows/spelling2.yml
) for uses: check-spelling/[email protected]
in its with
:
check_extra_dictionaries: ''
Errors (3)
See the :open_file_folder: files view, the :scroll:action log, or :memo: job summary for details.
:x: Errors | Count |
---|---|
:x: forbidden-pattern | 1 |
:x: ignored-expect-variant | 1 |
:information_source: non-alpha-in-dictionary | 102 |
See :x: Event descriptions for more information.
If the flagged items are :exploding_head: false positives
If items relate to a ...
-
binary file (or some other file you wouldn't want to check at all).
Please add a file path to the
excludes.txt
file matching the containing file.File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.
^
refers to the file's path from the root of the repository, so^README\.md$
would exclude README.md (on whichever branch you're using). -
well-formed pattern.
If you can write a pattern that would match it, try adding it to the
patterns.txt
file.Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.
Note that patterns can't match multiline strings.
@check-spelling-bot Report
:red_circle: Please review
See the :open_file_folder: files view, the :scroll:action log, or :memo: job summary for details.
Unrecognized words (32)
dcompi
dwmcorei
ETW
Filetime
flyouts
lnks
Microsofts
msvcp
nand
nanother
napp
productwxspath
reparented
ringbuffer
screenshots
SIDs
subkeys
tapp
tbutton
tdisplay
tlocation
tprimary
tweakme
tworking
vccorlib
vcomp
vcruntime
websites
WMI
workarounds
wpfdepsjsonpath
wuceffectsi
Previously acknowledged words that are now absent
AAD abi Acl activatable adio ADMINS AEAD amd anges Animatable AOT Applets apps Arity asdf Attribs Aut AUTHN AUTHZ azor BDB BGR bitmask bluetooth Bopomofo bstr btn Bto buf bytearray cdecl chdir CIELAB CIEXYZ Cloneable Cls clsid cmdline cmyk cnt CODENAME COLORREF COMDAT CSIDL Ctx CUI cvtsi cwd Datavalue DATAW Dbg declspec deref dllexport dns dsc edis edshift endregion ERRORLEVEL estructuredtext etstat etw exif fabricbot FDF feimage filetime Finalizers flyout FSCTL FTYPE GAC gcnew GETSTATE GETTEXT google graphql gui HACCEL Hashtable HBRUSH HHmmss HHOOK highlighter HKL HLOCAL HOMEPATH HPALETTE hread HRSRC hsl hsv IBase idx Iface IIO imeutil ingbuffer inheritdoc Inlines ipc isfinite keydown keyup langword Lcid len lhs linq lnk LOCALAPPDATA LOn LPBYTE LPCWSTR LPPOINT LPRECT LPSTR LPVOID LPWSTR lshift lzw MAJORVERSION Maximizable Mega microsoft millis MINORVERSION mkd MODECHANGE MOUSELEAVE MOUSEMOVE MOUSEWHEEL msbuild msvc Mul myfile mysql nameof NESW nint NONAME NONCONVERT notfound notmatch NOUPDATE nuint numpad OBJID odbc Oem oid OLEDB onstd OUTOFMEMORY paramref pdb pdbonly PDWORD pgsql PHANDLE pid pkey plugins posix precomp PROGRAMFILES PULONG pwsh qps qword RAWINPUT Rbp READWRITE RECTL rects Refreshable reinit Remapper reparent retval rfc rhs RLO RMENU Rpc rshift scancode SCOPEID screenshot setenv setlocal SFP Shl sid snd spam sre standalone stdcall Subdir subfolders subkey subresource TApp targetnametoken taskbar tasklist tcl tcp Templated testapp testcase textblock typedef TYPEKEY TYPELIB typeparam uby Udp uid UIs ULARGE unapply unassign Uncompress Uninitialize uninstalling Unk Unmap unmute unsubscribe USERDOMAIN userprofile Utc utf uuidof vec Versioning viewbox Vpn vtable weakme websearch webserver website whitespaces wikipedia wildcards Winsock wmi workaround workflows workspaces writefile WSAEADDRINUSE WSAEADDRNOTAVAIL WSAECONNRESET wss Wwan XAttribute XOffset YOffset ypescript ZIndex zipfile 🫥To accept these unrecognized words as correct and remove the previously acknowledged and now absent words, you could run the following commands
... in a clone of the [email protected]:BLM16/PowerToys.git repository
on the flyout-theme-setting
branch (:information_source: how do I use this?):
curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/v0.0.22/apply.pl' |
perl - 'https://github.com/microsoft/PowerToys/actions/runs/6898855060/attempts/1'
Available :books: dictionaries could cover words (expected and unrecognized) not in the :blue_book: dictionary
This includes both expected items (2349) from .github/actions/spell-check/expect.txt and unrecognized words (32)
Dictionary | Entries | Covers | Uniquely |
---|---|---|---|
cspell:cpp/src/lang-keywords.txt | 44 | 2 | 2 |
cspell:npm/dict/npm.txt | 302 | 2 | 1 |
cspell:r/src/r.txt | 543 | 2 | 1 |
cspell:cpp/src/compiler-clang-attributes.txt | 46 | 1 | 1 |
cspell:monkeyc/src/monkeyc_keywords.txt | 123 | 1 | 1 |
Consider adding them (in .github/workflows/spelling2.yml
) for uses: check-spelling/[email protected]
in its with
:
with:
extra_dictionaries:
cspell:cpp/src/lang-keywords.txt
cspell:npm/dict/npm.txt
cspell:r/src/r.txt
cspell:cpp/src/compiler-clang-attributes.txt
cspell:monkeyc/src/monkeyc_keywords.txt
To stop checking additional dictionaries, add (in .github/workflows/spelling2.yml
) for uses: check-spelling/[email protected]
in its with
:
check_extra_dictionaries: ''
Errors (3)
See the :open_file_folder: files view, the :scroll:action log, or :memo: job summary for details.
:x: Errors | Count |
---|---|
:x: forbidden-pattern | 1 |
:x: ignored-expect-variant | 1 |
:information_source: non-alpha-in-dictionary | 102 |
See :x: Event descriptions for more information.
If the flagged items are :exploding_head: false positives
If items relate to a ...
-
binary file (or some other file you wouldn't want to check at all).
Please add a file path to the
excludes.txt
file matching the containing file.File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.
^
refers to the file's path from the root of the repository, so^README\.md$
would exclude README.md (on whichever branch you're using). -
well-formed pattern.
If you can write a pattern that would match it, try adding it to the
patterns.txt
file.Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.
Note that patterns can't match multiline strings.
Using VS I somehow messed up the rebase a while back and now many of these files diverge or have been "added" from main. I wonder if somehow I switched from a rebase to a merge halfway through? Is there a clean way to fix this outside of completely resetting this to main and adding the commits again?
Using VS I somehow messed up the rebase a while back and now many of these files diverge or have been "added" from main. I wonder if somehow I switched from a rebase to a merge halfway through? Is there a clean way to fix this outside of completely resetting this to main and adding the commits again?
Not sure. Might be easier to start from the clean current main and cherry-pick your commits one by one. Either that or merge current main here and resolve reported conflicts
@check-spelling-bot Report
:red_circle: Please review
See the :open_file_folder: files view, the :scroll:action log, or :memo: job summary for details.
Unrecognized words (1)
Clor
Previously acknowledged words that are now absent
CHT constexpr DEU hashcode HEB JPN LAlt Lambson langword nodiscard pcs qps roundf RUS RValue SVE tonos weakme wifi 🫥To accept these unrecognized words as correct and remove the previously acknowledged and now absent words, you could run the following commands
... in a clone of the [email protected]:BLM16/PowerToys.git repository
on the flyout-theme-setting
branch (:information_source: how do I use this?):
curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/v0.0.22/apply.pl' |
perl - 'https://github.com/microsoft/PowerToys/actions/runs/7191013611/attempts/1'
Available :books: dictionaries could cover words (expected and unrecognized) not in the :blue_book: dictionary
This includes both expected items (1857) from .github/actions/spell-check/expect.txt and unrecognized words (1)
Dictionary | Entries | Covers | Uniquely |
---|---|---|---|
cspell:r/src/r.txt | 543 | 1 | 1 |
cspell:cpp/src/people.txt | 23 | 1 | |
cspell:cpp/src/ecosystem.txt | 51 | 1 |
Consider adding them (in .github/workflows/spelling2.yml
) for uses: check-spelling/[email protected]
in its with
:
with:
extra_dictionaries:
cspell:r/src/r.txt
cspell:cpp/src/people.txt
cspell:cpp/src/ecosystem.txt
To stop checking additional dictionaries, add (in .github/workflows/spelling2.yml
) for uses: check-spelling/[email protected]
in its with
:
check_extra_dictionaries: ''
If the flagged items are :exploding_head: false positives
If items relate to a ...
-
binary file (or some other file you wouldn't want to check at all).
Please add a file path to the
excludes.txt
file matching the containing file.File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.
^
refers to the file's path from the root of the repository, so^README\.md$
would exclude README.md (on whichever branch you're using). -
well-formed pattern.
If you can write a pattern that would match it, try adding it to the
patterns.txt
file.Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.
Note that patterns can't match multiline strings.