Using the undocumented SetWindowCompositionAttribute
API on Windows 10, it's possible to enable glass for a window. The glass is white or clear, as seen in this screenshot:
However, the Windows 10 Start menu and the notification center, which both also uses glass, both blend with the accent colour, like so:
How does it do it?
Investigations
The accent colour in the following examples is a light purple - here's a screenshot from the Settings app:
The AccentPolicy structure defined in this example code has accent state, flags and gradient color fields:
AccentPolicy = packed record
AccentState: Integer;
AccentFlags: Integer;
GradientColor: Integer;
AnimationId: Integer;
end;
and the state can have any of these values:
ACCENT_ENABLE_GRADIENT = 1;
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2;
ACCENT_ENABLE_BLURBEHIND = 3;
Note that the first two of these were found on this github gist.
The third works fine - that enables glass. Of the other two,
- ACCENT_ENABLE_GRADIENT results in a window that is completely gray, regardless of what is behind it. There is no transparency or glass effect, but the window colour being drawn is being drawn by the DWM, not by the app.
- ACCENT_ENABLE_TRANSPARENTGRADIENT results in a window that is painted completely with the accent colour, regardless of what is behind it. There is no transparency or glass effect, but the window colour being drawn is being drawn by the DWM, not by the app.
So this is getting close, and it seems to be what some of the popup windows like the volume control applet use.
The values can't be or-ed together, and the value of the GradientColor field has no effect except that it must be non-zero.
Drawing directly on a glass-enabled window results in very odd blending. Here it's filling the client area with red (0x000000FF in ABGR format):
and any non-zero alpha, eg 0xAA0000FF, results in no colour at all:
Neither match the look of the Start menu or notification area.
How do those windows do it?
Since GDI forms on Delphi don't support alpha channels (unless using alpha layered windows, which might not be suitable), commonly the black color will be taken as the transparent one, unless the component supports alpha channels.
tl;dr Just use your TTransparentCanvas class,
.Rectangle(0,0,Width+1,Height+1,222)
, using the color obtained with DwmGetColorizationColor that you could blend with a dark color.The following will use TImage component instead.
I'm going to use a TImage and TImage32 (Graphics32) to show the difference with alpha channels. This is a borderless form, because borders won't accept our colorization.
As you can see, the left one is using TImage1 and is affected by Aero Glass, and the right one is using TGraphics32, which allows to overlay with opaque colors (no translucent).
Now, we will be using a TImage1 with a translucent PNG that we can create with the following code:
We need to add another TImage component to our form and send it back so other components won't be below it.
And that's is how our form will look like the Start Menu.
Now, to get the accent color use DwmGetColorizationColor, which is already defined in
DwmAPI.pas
However, that color won't be dark enough as shown by the Start Menu.
So we need to blend the accent color with a dark color:
And this is the result blending clBlack with the Accent color by 50%:
There are other things that you might want to add, like for example detecting when the accent color changes and automatically update our app color too, for example:
To maintain consistency with Windows 10 start menu settings, you can read the registry to find out if the Taskbar/StartMenu is translucent (enabled) and the start menu is enabled to use the accent color or just a black background, to do so this keys will tell us:
This is the full code, you need TImage1, TImage2, for the colorization, the other ones are not optional.
Here is the source code and demo binary hope it helps.
I hope there is a better way, and if there is, please let us know.
BTW on C# and WPF it is easier, but those apps are very slow on cold start.
[Bonus Update] Alternatively on Windows 10 April 2018 Update or newer (might work on Fall Creators Update), you can use Acrylic blur behind instead, it can be used as follows:
But this might not work if WM_NCCALCSIZE is executed, i.e. will only work on
bsNone
border style or WM_NCALCSIZE avoided. Notice that colorizing is included, no need to paint manually.Just add transparent colored component to the form. I have selfwriten component like TPanel (on Delphi).
Here Alpha = 40%:
AccentPolicy.GradientColor
has effect when you play withAccentPolicy.AccentFlags
, I found these values:2
- fills window withAccentPolicy.GradientColor
- what you need4
- makes area to the right and bottom of the window blurred (weird)6
- combination of above: fills whole screen withAccentPolicy.GradientColor
and blurs area like4
To set
AccentPolicy.GradientColor
property, you'll need ActiveCaption and InactiveCaption system colours. I would try Rafael's suggestion to useGetImmersiveColor*
family of functions. Also there is a question for Vista/7.Note: I tried drawing with GDI+ and saw that
FillRectangle()
works incorrectly with Glass whenbrush.alpha==0xFF
(workarounds here). Inner rectangles havebrush.alpha==0xFE
on both screenshots because of this bug.Screenshots note:
GradientColor==0x80804000
, it doesn't have to be premultiplied, just a coincidence.