Modernize Your App: Are You Handling Windows Themes Correctly?

Modern versions of Microsoft Windows are arguably a lot more pleasing to look at.  Gone are the days of apps being gray slabs and chunky buttons.  When Microsoft adopted the Fluent UI interface along with it came a richer color palette, a cleaner, leaner look and fonts without the curls and twists of the Serif families. Sidling in with that beauty treatment were a number of other usability and user convenience facets of being a modern app for us to consider: high DPI, notifications and themes designed to cater for a “light” and “dark” mode.

High DPI in your apps

RAD Studio Delphi already handles the high DPI changes.  If you right click on your project in the IDE and select “properties” and then click on the “manifest” section you should see it say “per monitor v2”. Having this section ticked lets Windows know that your app (actually the VCL in your app) understands the high DPI – screen resolution pixels – and contains assets and API handling to work with it.  There is actually a substantial amount of work going on behind the scenes in the VCL runtime when the per monitor v2 setting is enabled, which it is by default, but for ordinary mortals like you and I we don’t get to worry about any of that; it just works.

If you compare a program compiled with an older version of a compiler which doesn’t understand per monitor v2 you should notice that things on higher resolution monitors can look a little fuzzy.  That’s because that manifest file setting is not there and the internal API calls are older ‘backwardly compatible’ ones which work using the lowest common denominator, resulting in the app not making the best use of modern display technology. It’s a bit like watching a 1970s movie on a 4K OLED TV – bearable, but it looks…dated.

What isn’t covered by the latest VCL?

The other major visible change ushered in by Windows 10 was the introduction of a “dark mode”. For years we’ve all really been running Windows with almost the only choice available – white backgrounds, gray buttons and some colors dotted around to relieve the glare. Then, Microsoft brought out a “dark mode”. This dark mode turns all the Windows assets, dark (it’s well named!) and this is a setting that your apps are expected to both understand and react to. Currently this is an area where the VCL has not quite covered.

Detecting dark mode

When your app launches it should try and detect whether Windows is currently expecting you to be “in dark mode” or “light mode”. This is currently handled by a set of API calls for which we do not currently have support in the VCL. Luckily, there’s a registry key we can check.

When our app detects that it should be “dark” then we should tell our Delphi app to load an appropriate ‘dark’ theme.  Conversely, if Windows indicates we are expecting ‘light mode’ then a similarly appropriate light-colored VCL theme should be loaded.

How to detect dark mode in your VCL apps the easy way

It wouldn’t be Delphi if there wasn’t an easy way to do all the hard work. So I wrote a little unit you can include in your VCL Delphi programs to easily detect Windows dark or light mode and to load the correct theme for you – and of course it’s free and open source.

Getting The Delphi Dark Mode Unit

Go to my GitHub repository here:

And clone it to your local machine.

Now in your application select “Add to Project” (shift + F11) and navigate to where you cloned the DelphiDarkMode unit.

You can read more about the DelphiDarkMode unit and Windows Dark Mode in general in my blog post from CodeRage here:

Using Delphi Dark Mode to automatically change your Delphi theme

The first thing you need to do is choose and apply two VCL themes to your app.

Go to the project, options dialog and pick “appearance”.

Now check on two themes, one for the “light mode” and one for the “dark mode”.  Note down the exact names of the themes because you will need them in a moment.

modernize your app - pick a theme

I chose “Windows10” and “Windows10 Dark”.  There are MANY gorgeous VCL themes to pick from and you can use the GetIt package manager to install and apply dozens of other professionally-designed custom themes as well as a staggering array from the superb Delphi Styles site found here

Now, in your program, add the following code:

Now try running your program.  You should find if Windows is set to dark mode then your app will use the “Windows10 Dark” theme and if Windows is in light mode then it will use the lighter “Windows10” theme.

You can replace those two themes with anything you like – the only caveat is that the theme must already be applied as a possible theme by putting a tick against its name in the appearance section.

Detecting when Windows changes to dark or light mode while the app is running

So, what happens if our app is already running and the user changes from light mode to dark mode or vice versa? Well, Windows broadcasts a WM_SETTINGSCHANGE message to all top-level Windows of running apps.  The ‘section’ parameter of this message is “ImmersiveColorSet”.  If we test for the arrival of the WM_SETTINGSCHANGE message and look for that parameter we know that the user has changed the Windows theme from light to dark or dark to light mode.

Adding code to detect a Windows dark or light mode change

Add the following code to your main form’s definition:

Now in the implementation section put:

Here it is in action in my sample app

Modernize your VCL app example of theme change


As is typical with RAD Studio Delphi there is more than one way to detect the Windows settings change message.

You can use the TApplicationEvents control.  Add code to the OnSettingsChange event handler like so:

Modernize your app with TApplicationEvents

And then add this code to the event

You can obviously create this control dynamically too.  Personally it’s easier for me to just trap the WMSettingChange message as I’ve shown in my example.

The whole code to detect Windows Dark Mode in VCL apps

More on themes

There’s a lot more to properly handling theme changes. For example there are settings for the theme ‘accent color’ which your app should probably detect and use where possible.  There are also settings for border colors and when the theme changes you should also manage older controls which are not ‘theme aware’ and therefore do not get repainted with the correct values when the VCL theme changes. Overall though, detecting dark and light mode is really the largest part of making your apps look more like the belong on Windows 10.

What about Dark Mode in Firemonkey?

Detecting Dark Mode cross platform is a little more complicated. On iOS Firemonkey already deals with this for you. Android, macOS and Linux are more tricky – especially Linux. The code shown in this article deals exclusively with Windows and it can be adapted to load FMX styles but messaging in Firemonkey apps is a little different in general anyway.