Skip to content

Commit

Permalink
Merge pull request #12196 from adirh3/features/mica_light_dark
Browse files Browse the repository at this point in the history
Added support for Mica Light & Dark based on Win11
  • Loading branch information
maxkatz6 authored Jul 15, 2023
2 parents 76f4d94 + 7a0e0c4 commit 8852a6d
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 21 deletions.
3 changes: 3 additions & 0 deletions src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class D2DEffects
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);

Expand Down
104 changes: 104 additions & 0 deletions src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,110 @@ public override void OnUnreferencedFromNative()
_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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -25,7 +26,8 @@ public void Dispose()
{
_compositionRoundedRectangleGeometry?.Dispose();
_blur.Dispose();
_mica?.Dispose();
_micaLight?.Dispose();
_micaDark?.Dispose();
_visual.Dispose();
_surfaceBrush.Dispose();
_target.Dispose();
Expand All @@ -50,14 +52,20 @@ public WinUiCompositedWindow(EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInf
_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();
Expand All @@ -68,9 +76,6 @@ public WinUiCompositedWindow(EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInf
using var compositionBrush = _surfaceBrush.QueryInterface<ICompositionBrush>();
spriteVisual.SetBrush(compositionBrush);
_target.SetRoot(containerVisual);



}

public void SetSurface(ICompositionSurface surface) => _surfaceBrush.SetSurface(surface);
Expand All @@ -79,12 +84,13 @@ public void SetBlur(BlurEffect blurEffect)
{
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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ internal class WinUiCompositionShared : IDisposable
public ICompositor5 Compositor5 { get; }
public ICompositorDesktopInterop DesktopInterop { get; }
public ICompositionBrush BlurBrush { get; }
public ICompositionBrush? MicaBrush { get; }
public ICompositionBrush? MicaBrushLight { get; }
public ICompositionBrush? MicaBrushDark { get; }
public object SyncRoot { get; } = new();

public static readonly Version MinWinCompositionVersion = new(10, 0, 17134);
Expand All @@ -21,14 +22,16 @@ public WinUiCompositionShared(ICompositor compositor)
Compositor = compositor.CloneReference();
Compositor5 = compositor.QueryInterface<ICompositor5>();
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<ICompositorDesktopInterop>();
}

public void Dispose()
{
BlurBrush.Dispose();
MicaBrush?.Dispose();
MicaBrushLight?.Dispose();
MicaBrushDark?.Dispose();
DesktopInterop.Dispose();
Compositor.Dispose();
Compositor5.Dispose();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,77 @@
using System;
using System.Numerics;
using MicroCom.Runtime;

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<ICompositionEffectSourceParameterFactory>(
"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<ICompositionBrush>();

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<ICompositionBrush>();

using var compositorWithBlurredWallpaperBackdropBrush =
compositor.QueryInterface<ICompositorWithBlurredWallpaperBackdropBrush>();
using var blurredWallpaperBackdropBrush =
compositorWithBlurredWallpaperBackdropBrush?.TryCreateBlurredWallpaperBackdropBrush();
return blurredWallpaperBackdropBrush?.QueryInterface<ICompositionBrush>();
using var micaBackdropBrush = blurredWallpaperBackdropBrush?.QueryInterface<ICompositionBrush>();


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<ICompositionBrush>();
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<ICompositionBrush>();
return micaBackdropBrush1.CloneReference();
}

public static ICompositionBrush CreateAcrylicBlurBackdropBrush(ICompositor compositor)
Expand Down Expand Up @@ -97,4 +154,15 @@ public static ICompositionBrush CreateBackdropBrush(ICompositor compositor)
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<IGraphicsEffectSource>();
handle = backdropString.Handle;
return backDropParameterAsSource;
}
}
3 changes: 2 additions & 1 deletion src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ internal enum BlurEffect
{
None,
Acrylic,
Mica
MicaLight,
MicaDark
}

internal interface IBlurHost
Expand Down
23 changes: 21 additions & 2 deletions src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Avalonia.Win32.WinRT
Expand All @@ -16,7 +17,15 @@ public WinRTPropertyValue(uint u)
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; }
Expand Down Expand Up @@ -62,7 +71,17 @@ public WinRTPropertyValue(uint u)

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<float>());
Marshal.Copy(_singleArray, 0, allocCoTaskMem, _singleArray.Length);
float* s = (float*)allocCoTaskMem;

return s;
}

public unsafe double* GetDoubleArray(uint* __valueSize) => throw NotImplemented;

Expand Down
Loading

0 comments on commit 8852a6d

Please sign in to comment.