diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index 7ed2d67379..0a1621d02a 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -226,7 +226,8 @@
Transparent
Blur
AcrylicBlur
- Mica
+ MicaLight
+ MicaDark
- /// The window background is based on desktop wallpaper tint with a blur. This will only work on Windows 11
+ /// The window background is based on desktop wallpaper tint with a light blur. This will only work on Windows 11
///
- public static WindowTransparencyLevel Mica { get; } = new(nameof(Mica));
+ public static WindowTransparencyLevel MicaLight { get; } = new(nameof(MicaLight));
+
+ ///
+ /// The window background is based on desktop wallpaper tint with a dark blur. This will only work on Windows 11
+ ///
+ public static WindowTransparencyLevel MicaDark { get; } = new(nameof(MicaDark));
public override string ToString()
{
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs
index bef5a55b06..98e1077885 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs
@@ -28,6 +28,9 @@ namespace Avalonia.Win32.WinRT.Composition
public static readonly Guid CLSID_D2D1Border =
new Guid(0x2A2D49C0, 0x4ACF, 0x43C7, 0x8C, 0x6A, 0x7C, 0x4A, 0x27, 0x87, 0x4D, 0x27);
+ public static readonly Guid CLSID_D2D1Opacity =
+ new Guid("811d79a4-de28-4454-8094-c64685f8bd4c");
+
public static readonly Guid CLSID_D2D1Brightness =
new Guid(0x8CEA8D1E, 0x77B0, 0x4986, 0xB3, 0xB9, 0x2F, 0x0C, 0x0E, 0xAE, 0x78, 0x87);
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs
index 1a922b4acd..10dbcfcc6b 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs
@@ -52,6 +52,110 @@ namespace Avalonia.Win32.WinRT.Composition
_sources = null;
}
}
+
+ class BorderEffect : WinUIEffectBase
+ {
+ private readonly int _x;
+ private readonly int _y;
+ public override Guid EffectId => D2DEffects.CLSID_D2D1Border;
+ public override uint PropertyCount => 2;
+
+ public BorderEffect(int x, int y, params IGraphicsEffectSource[] _sources):base(_sources)
+ {
+ _x = x;
+ _y = y;
+ }
+
+ public override IPropertyValue? GetProperty(uint index)
+ {
+ if (index == 0)
+ return new WinRTPropertyValue((uint)_x);
+ if (index == 1)
+ return new WinRTPropertyValue((uint)_y);
+ return null;
+ }
+ }
+
+ class BlendEffect : WinUIEffectBase
+ {
+ private readonly int _mode;
+
+ public BlendEffect(int mode, params IGraphicsEffectSource[] _sources) : base(_sources)
+ {
+ _mode = mode;
+ }
+
+ public override Guid EffectId => D2DEffects.CLSID_D2D1Blend;
+ public override uint PropertyCount => 1;
+
+ public override IPropertyValue? GetProperty(uint index)
+ {
+ if (index == 0)
+ return new WinRTPropertyValue((uint)_mode);
+ return null;
+ }
+ }
+
+ class CompositeStepEffect : WinUIEffectBase
+ {
+ private readonly float _mode;
+
+ public CompositeStepEffect(int mode, params IGraphicsEffectSource[] _sources) : base(_sources)
+ {
+ _mode = mode;
+ }
+
+ public override Guid EffectId => D2DEffects.CLSID_D2D1Composite;
+ public override uint PropertyCount => 1;
+
+ public override IPropertyValue? GetProperty(uint index)
+ {
+ if (index == 0)
+ return new WinRTPropertyValue((uint)_mode);
+ return null;
+ }
+ }
+
+ class OpacityEffect : WinUIEffectBase
+ {
+ private readonly float _opacity;
+
+ public OpacityEffect(float opacity, params IGraphicsEffectSource[] _sources) : base(_sources)
+ {
+ _opacity = opacity;
+ }
+
+ public override Guid EffectId => D2DEffects.CLSID_D2D1Opacity;
+ public override uint PropertyCount => 1;
+
+ public override IPropertyValue? GetProperty(uint index)
+ {
+ if (index == 0)
+ return new WinRTPropertyValue(_opacity);
+ return null;
+ }
+ }
+
+ class ColorSourceEffect : WinUIEffectBase
+ {
+ private readonly float[] _color;
+
+ public ColorSourceEffect(float[] color)
+ {
+ _color = color;
+ }
+
+ public override Guid EffectId => D2DEffects.CLSID_D2D1Flood;
+ public override uint PropertyCount => 1;
+
+ public override IPropertyValue? GetProperty(uint index)
+ {
+ if (index == 0)
+ return new WinRTPropertyValue(_color);
+ return null;
+ }
+ }
+
internal class WinUIGaussianBlurEffect : WinUIEffectBase
{
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs
index 2f22ba99f9..d87c8d1361 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs
@@ -12,7 +12,8 @@ internal class WinUiCompositedWindow : IDisposable
public EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo WindowInfo { get; }
private readonly WinUiCompositionShared _shared;
private readonly ICompositionRoundedRectangleGeometry? _compositionRoundedRectangleGeometry;
- private readonly IVisual? _mica;
+ private readonly IVisual? _micaLight;
+ private readonly IVisual? _micaDark;
private readonly IVisual _blur;
private readonly IVisual _visual;
private PixelSize _size;
@@ -25,7 +26,8 @@ internal class WinUiCompositedWindow : IDisposable
{
_compositionRoundedRectangleGeometry?.Dispose();
_blur.Dispose();
- _mica?.Dispose();
+ _micaLight?.Dispose();
+ _micaDark?.Dispose();
_visual.Dispose();
_surfaceBrush.Dispose();
_target.Dispose();
@@ -50,14 +52,20 @@ internal class WinUiCompositedWindow : IDisposable
_target.SetRoot(containerVisual);
_blur = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.BlurBrush);
- if (shared.MicaBrush != null)
+ if (shared.MicaBrushLight != null)
{
- _mica = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.MicaBrush);
- containerChildren.InsertAtTop(_mica);
+ _micaLight = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.MicaBrushLight);
+ containerChildren.InsertAtTop(_micaLight);
+ }
+
+ if (shared.MicaBrushDark != null)
+ {
+ _micaDark = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.MicaBrushDark);
+ containerChildren.InsertAtTop(_micaDark);
}
_compositionRoundedRectangleGeometry =
- WinUiCompositionUtils.ClipVisual(shared.Compositor, backdropCornerRadius, _blur, _mica);
+ WinUiCompositionUtils.ClipVisual(shared.Compositor, backdropCornerRadius, _blur, _micaLight, _micaDark);
containerChildren.InsertAtTop(_blur);
using var spriteVisual = shared.Compositor.CreateSpriteVisual();
@@ -79,12 +87,13 @@ internal class WinUiCompositedWindow : IDisposable
{
lock (_shared.SyncRoot)
{
-
_blur.SetIsVisible(blurEffect == BlurEffect.Acrylic
- || blurEffect == BlurEffect.Mica && _mica == null ?
+ || (blurEffect == BlurEffect.MicaLight && _micaLight == null) ||
+ (blurEffect == BlurEffect.MicaDark && _micaDark == null) ?
1 :
0);
- _mica?.SetIsVisible(blurEffect == BlurEffect.Mica ? 1 : 0);
+ _micaLight?.SetIsVisible(blurEffect == BlurEffect.MicaLight ? 1 : 0);
+ _micaDark?.SetIsVisible(blurEffect == BlurEffect.MicaDark ? 1 : 0);
}
}
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs
index b3a328d097..5c7f490710 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs
@@ -9,6 +9,8 @@ internal class WinUiCompositionShared : IDisposable
public ICompositor5 Compositor5 { get; }
public ICompositorDesktopInterop DesktopInterop { get; }
public ICompositionBrush BlurBrush { get; }
+ public ICompositionBrush? MicaBrushLight { get; }
+ public ICompositionBrush? MicaBrushDark { get; }
public ICompositionBrush? MicaBrush { get; }
public object SyncRoot { get; } = new();
@@ -21,14 +23,16 @@ internal class WinUiCompositionShared : IDisposable
Compositor = compositor.CloneReference();
Compositor5 = compositor.QueryInterface();
BlurBrush = WinUiCompositionUtils.CreateAcrylicBlurBackdropBrush(compositor);
- MicaBrush = WinUiCompositionUtils.CreateMicaBackdropBrush(compositor);
+ MicaBrushLight = WinUiCompositionUtils.CreateMicaBackdropBrush(compositor, 242, 0.6f);
+ MicaBrushDark = WinUiCompositionUtils.CreateMicaBackdropBrush(compositor, 32, 0.8f);
DesktopInterop = compositor.QueryInterface();
}
public void Dispose()
{
BlurBrush.Dispose();
- MicaBrush?.Dispose();
+ MicaBrushLight?.Dispose();
+ MicaBrushDark?.Dispose();
DesktopInterop.Dispose();
Compositor.Dispose();
Compositor5.Dispose();
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs
index 7b970868df..1a130698ee 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs
@@ -1,3 +1,4 @@
+using System;
using System.Numerics;
using MicroCom.Runtime;
@@ -5,16 +6,75 @@ namespace Avalonia.Win32.WinRT.Composition;
internal static class WinUiCompositionUtils
{
- public static ICompositionBrush? CreateMicaBackdropBrush(ICompositor compositor)
+ public static ICompositionBrush? CreateMicaBackdropBrush(ICompositor compositor, float color, float opacity)
{
if (Win32Platform.WindowsVersion.Build < 22000)
return null;
+ using var backDropParameterFactory =
+ NativeWinRTMethods.CreateActivationFactory(
+ "Windows.UI.Composition.CompositionEffectSourceParameter");
+
+
+ var tint = new[] { color / 255f, color / 255f, color / 255f, 255f / 255f };
+
+ using var tintColorEffect = new ColorSourceEffect(tint);
+
+
+ using var tintOpacityEffect = new OpacityEffect(1.0f, tintColorEffect);
+ using var tintOpacityEffectFactory = compositor.CreateEffectFactory(tintOpacityEffect);
+ using var tintOpacityEffectBrushEffect = tintOpacityEffectFactory.CreateBrush();
+ using var tintOpacityEffectBrush = tintOpacityEffectBrushEffect.QueryInterface();
+
+ using var luminosityColorEffect = new ColorSourceEffect(tint);
+
+ using var luminosityOpacityEffect = new OpacityEffect(opacity, luminosityColorEffect);
+ using var luminosityOpacityEffectFactory = compositor.CreateEffectFactory(luminosityOpacityEffect);
+ using var luminosityOpacityEffectBrushEffect = luminosityOpacityEffectFactory.CreateBrush();
+ using var luminosityOpacityEffectBrush =
+ luminosityOpacityEffectBrushEffect.QueryInterface();
+
+
+ // using var backDropParameterAsSource = GetParameterSource("BlurredWallpaperBackdrop", backDropParameterFactory, out var backdropHandle);
+ // using var backdropCompositionBrsuh = backDropParameterAsSource.QueryInterface();
using var compositorWithBlurredWallpaperBackdropBrush =
compositor.QueryInterface();
using var blurredWallpaperBackdropBrush =
compositorWithBlurredWallpaperBackdropBrush?.TryCreateBlurredWallpaperBackdropBrush();
- return blurredWallpaperBackdropBrush?.QueryInterface();
+ using var micaBackdropBrush = blurredWallpaperBackdropBrush?.QueryInterface();
+
+
+ using var backgroundParameterAsSource =
+ GetParameterSource("Background", backDropParameterFactory, out var backgroundHandle);
+ using var foregroundParameterAsSource =
+ GetParameterSource("Foreground", backDropParameterFactory, out var foregroundHandle);
+
+ using var luminosityBlendEffect =
+ new BlendEffect(23, backgroundParameterAsSource, foregroundParameterAsSource);
+ using var luminosityBlendEffectFactory = compositor.CreateEffectFactory(luminosityBlendEffect);
+ using var luminosityBlendEffectBrush = luminosityBlendEffectFactory.CreateBrush();
+ using var luminosityBlendEffectBrush1 = luminosityBlendEffectBrush.QueryInterface();
+ luminosityBlendEffectBrush.SetSourceParameter(backgroundHandle, micaBackdropBrush);
+ luminosityBlendEffectBrush.SetSourceParameter(foregroundHandle, luminosityOpacityEffectBrush);
+
+
+ using var backgroundParameterAsSource1 =
+ GetParameterSource("Background", backDropParameterFactory, out var backgroundHandle1);
+ using var foregroundParameterAsSource1 =
+ GetParameterSource("Foreground", backDropParameterFactory, out var foregroundHandle1);
+
+ using var colorBlendEffect =
+ new BlendEffect(22, backgroundParameterAsSource1, foregroundParameterAsSource1);
+ using var colorBlendEffectFactory = compositor.CreateEffectFactory(colorBlendEffect);
+ using var colorBlendEffectBrush = colorBlendEffectFactory.CreateBrush();
+ colorBlendEffectBrush.SetSourceParameter(backgroundHandle1, luminosityBlendEffectBrush1);
+ colorBlendEffectBrush.SetSourceParameter(foregroundHandle1, tintOpacityEffectBrush);
+
+
+ // colorBlendEffectBrush.SetSourceParameter(backgroundHandle, micaBackdropBrush);
+
+ using var micaBackdropBrush1 = colorBlendEffectBrush.QueryInterface();
+ return micaBackdropBrush1.CloneReference();
}
public static ICompositionBrush CreateAcrylicBlurBackdropBrush(ICompositor compositor)
@@ -97,4 +157,15 @@ internal static class WinUiCompositionUtils
brush?.Dispose();
}
}
+
+ private static IGraphicsEffectSource GetParameterSource(string name,
+ ICompositionEffectSourceParameterFactory backDropParameterFactory, out IntPtr handle)
+ {
+ var backdropString = new HStringInterop(name);
+ var backDropParameter =
+ backDropParameterFactory.Create(backdropString.Handle);
+ var backDropParameterAsSource = backDropParameter.QueryInterface();
+ handle = backdropString.Handle;
+ return backDropParameterAsSource;
+ }
}
diff --git a/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs b/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
index a3918d9ae6..5f2e752af8 100644
--- a/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
@@ -4,7 +4,8 @@
{
None,
Acrylic,
- Mica
+ MicaLight,
+ MicaDark
}
internal interface IBlurHost
diff --git a/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs b/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs
index 684e7ff7b5..8874902d4e 100644
--- a/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs
@@ -1,4 +1,5 @@
using System;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Avalonia.Win32.WinRT
@@ -16,7 +17,15 @@ namespace Avalonia.Win32.WinRT
UInt32 = u;
Type = PropertyType.UInt32;
}
-
+
+ public WinRTPropertyValue(float[] uiColor)
+ {
+ Type = PropertyType.SingleArray;
+ _singleArray = uiColor;
+ }
+
+ private readonly float[]? _singleArray;
+
public PropertyType Type { get; }
public int IsNumericScalar { get; }
public byte UInt8 { get; }
@@ -62,7 +71,17 @@ namespace Avalonia.Win32.WinRT
public unsafe ulong* GetUInt64Array(uint* __valueSize) => throw NotImplemented;
- public unsafe float* GetSingleArray(uint* __valueSize) => throw NotImplemented;
+ public unsafe float* GetSingleArray(uint* __valueSize)
+ {
+ if (_singleArray == null)
+ throw NotImplemented;
+ *__valueSize = (uint)_singleArray.Length;
+ var allocCoTaskMem = Marshal.AllocCoTaskMem(_singleArray.Length * Unsafe.SizeOf());
+ Marshal.Copy(_singleArray, 0, allocCoTaskMem, _singleArray.Length);
+ float* s = (float*)allocCoTaskMem;
+
+ return s;
+ }
public unsafe double* GetDoubleArray(uint* __valueSize) => throw NotImplemented;
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index 057cdb2db0..2b16bbe275 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -374,8 +374,10 @@ namespace Avalonia.Win32
SetTransparencyBlur(windowsVersion);
else if (level == WindowTransparencyLevel.AcrylicBlur)
SetTransparencyAcrylicBlur(windowsVersion);
- else if (level == WindowTransparencyLevel.Mica)
- SetTransparencyMica(windowsVersion);
+ else if (level == WindowTransparencyLevel.MicaLight)
+ SetTransparencyMicaLight(windowsVersion);
+ else if (level == WindowTransparencyLevel.MicaDark)
+ SetTransparencyMicaDark(windowsVersion);
TransparencyLevel = level;
return;
@@ -418,7 +420,7 @@ namespace Avalonia.Win32
return windowsVersion >= WinUiCompositionShared.MinAcrylicVersion;
// Mica is supported on Windows >= 10.0.22000.
- if (level == WindowTransparencyLevel.Mica)
+ if (level == WindowTransparencyLevel.MicaLight || level == WindowTransparencyLevel.MicaDark)
return windowsVersion >= WinUiCompositionShared.MinHostBackdropVersion;
return false;
@@ -467,14 +469,24 @@ namespace Avalonia.Win32
_blurHost?.SetBlur(BlurEffect.Acrylic);
}
- private void SetTransparencyMica(Version windowsVersion)
+ private void SetTransparencyMicaLight(Version windowsVersion)
{
// Mica only supported with composition on Windows >= 10.0.22000.
if (!_isUsingComposition || windowsVersion < WinUiCompositionShared.MinHostBackdropVersion)
return;
SetUseHostBackdropBrush(false);
- _blurHost?.SetBlur(BlurEffect.Mica);
+ _blurHost?.SetBlur(BlurEffect.MicaLight);
+ }
+
+ private void SetTransparencyMicaDark(Version windowsVersion)
+ {
+ // Mica only supported with composition on Windows >= 10.0.22000.
+ if (!_isUsingComposition || windowsVersion < WinUiCompositionShared.MinHostBackdropVersion)
+ return;
+
+ SetUseHostBackdropBrush(false);
+ _blurHost?.SetBlur(BlurEffect.MicaDark);
}
private void SetAccentState(AccentState state)