diff --git a/src/Windows/Avalonia.Win32/Win32GlManager.cs b/src/Windows/Avalonia.Win32/Win32GlManager.cs
index e70ea52106..289c100d51 100644
--- a/src/Windows/Avalonia.Win32/Win32GlManager.cs
+++ b/src/Windows/Avalonia.Win32/Win32GlManager.cs
@@ -27,7 +27,7 @@ namespace Avalonia.Win32
if (egl != null &&
opts?.UseWindowsUIComposition == true)
{
- WinUICompositorConnection.TryCreateAndRegister(egl);
+ WinUICompositorConnection.TryCreateAndRegister(egl, opts.CompositionBackdropCornerRadius);
}
return egl;
diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs
index c011a458c3..9d56306c59 100644
--- a/src/Windows/Avalonia.Win32/Win32Platform.cs
+++ b/src/Windows/Avalonia.Win32/Win32Platform.cs
@@ -89,6 +89,12 @@ namespace Avalonia
/// This is recommended if you need to use AcrylicBlur or acrylic in your applications.
///
public bool UseWindowsUIComposition { get; set; } = true;
+
+ ///
+ /// When enabled, create rounded corner blur brushes
+ /// If set to zero the brushes will be created using default settings (sharp corners)
+ ///
+ public float CompositionBackdropCornerRadius { get; set; }
}
}
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs
index 4ae9c08410..1162cf9d70 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs
@@ -13,6 +13,8 @@ namespace Avalonia.Win32.WinRT.Composition
{
private EglContext _syncContext;
private readonly object _pumpLock;
+ private readonly IVisual _micaVisual;
+ private readonly ICompositionRoundedRectangleGeometry _roundedRectangleGeometry;
private readonly IVisual _blurVisual;
private ICompositionTarget _compositionTarget;
private IVisual _contentVisual;
@@ -28,11 +30,14 @@ namespace Avalonia.Win32.WinRT.Composition
object pumpLock,
ICompositionTarget compositionTarget,
ICompositionDrawingSurfaceInterop surfaceInterop,
- IVisual contentVisual, IVisual blurVisual)
+ IVisual contentVisual, IVisual blurVisual, IVisual micaVisual,
+ ICompositionRoundedRectangleGeometry roundedRectangleGeometry)
{
_compositor = compositor.CloneReference();
_syncContext = syncContext;
_pumpLock = pumpLock;
+ _micaVisual = micaVisual;
+ _roundedRectangleGeometry = roundedRectangleGeometry;
_blurVisual = blurVisual.CloneReference();
_compositionTarget = compositionTarget.CloneReference();
_contentVisual = contentVisual.CloneReference();
@@ -48,6 +53,7 @@ namespace Avalonia.Win32.WinRT.Composition
{
_surfaceInterop.Resize(new UnmanagedMethods.POINT { X = size.Width, Y = size.Height });
_contentVisual.SetSize(new Vector2(size.Width, size.Height));
+ _roundedRectangleGeometry?.SetSize(new Vector2(size.Width, size.Height));
_size = size;
}
}
@@ -57,7 +63,7 @@ namespace Avalonia.Win32.WinRT.Composition
{
if (!_syncContext.IsCurrent)
throw new InvalidOperationException();
-
+
var iid = IID_ID3D11Texture2D;
void* pTexture;
var off = _surfaceInterop.BeginDraw(null, &iid, &pTexture);
@@ -72,10 +78,13 @@ namespace Avalonia.Win32.WinRT.Composition
_surfaceInterop.EndDraw();
}
- public void SetBlur(bool enable)
+ public void SetBlur(BlurEffect blurEffect)
{
using (_syncContext.EnsureLocked())
- _blurVisual.SetIsVisible(enable ? 1 : 0);
+ {
+ _blurVisual.SetIsVisible(blurEffect == BlurEffect.Acrylic ? 1 : 0);
+ _micaVisual?.SetIsVisible(blurEffect == BlurEffect.Mica ? 1 : 0);
+ }
}
public IDisposable BeginTransaction()
@@ -83,7 +92,7 @@ namespace Avalonia.Win32.WinRT.Composition
Monitor.Enter(_pumpLock);
return Disposable.Create(() => Monitor.Exit(_pumpLock));
}
-
+
public void Dispose()
{
if (_syncContext == null)
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs
index bc8f5a606c..ebdbae06d7 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.InteropServices;
@@ -26,12 +27,15 @@ namespace Avalonia.Win32.WinRT.Composition
private EglPlatformOpenGlInterface _gl;
private ICompositorDesktopInterop _compositorDesktopInterop;
private ICompositionBrush _blurBrush;
+ private readonly ICompositionBrush _micaBrush;
private object _pumpLock = new object();
+ private readonly float _backdropCornerRadius;
- public WinUICompositorConnection(EglPlatformOpenGlInterface gl, object pumpLock)
+ public WinUICompositorConnection(EglPlatformOpenGlInterface gl, object pumpLock, float backdropCornerRadius)
{
_gl = gl;
_pumpLock = pumpLock;
+ _backdropCornerRadius = backdropCornerRadius;
_syncContext = _gl.PrimaryEglContext;
_angle = (AngleWin32EglDisplay)_gl.Display;
_compositor = NativeWinRTMethods.CreateInstance("Windows.UI.Composition.Compositor");
@@ -40,15 +44,15 @@ namespace Avalonia.Win32.WinRT.Composition
_compositorInterop = _compositor.QueryInterface();
_compositorDesktopInterop = _compositor.QueryInterface();
using var device = MicroComRuntime.CreateProxyFor(_angle.GetDirect3DDevice(), true);
-
+
_device = _compositorInterop.CreateGraphicsDevice(device);
- _blurBrush = CreateBlurBrush();
-
+ _blurBrush = CreateAcrylicBlurBackdropBrush();
+ _micaBrush = CreateMicaBackdropBrush();
}
public EglPlatformOpenGlInterface Egl => _gl;
- static bool TryCreateAndRegisterCore(EglPlatformOpenGlInterface angle)
+ static bool TryCreateAndRegisterCore(EglPlatformOpenGlInterface angle, float backdropCornerRadius)
{
var tcs = new TaskCompletionSource();
var pumpLock = new object();
@@ -63,22 +67,19 @@ namespace Avalonia.Win32.WinRT.Composition
dwSize = Marshal.SizeOf(),
threadType = NativeWinRTMethods.DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT
});
- connect = new WinUICompositorConnection(angle, pumpLock);
+ connect = new WinUICompositorConnection(angle, pumpLock, backdropCornerRadius);
AvaloniaLocator.CurrentMutable.BindToSelf(connect);
AvaloniaLocator.CurrentMutable.Bind().ToConstant(connect);
tcs.SetResult(true);
-
}
catch (Exception e)
{
tcs.SetException(e);
return;
}
+
connect.RunLoop();
- })
- {
- IsBackground = true
- };
+ }) { IsBackground = true };
th.SetApartmentState(ApartmentState.STA);
th.Start();
return tcs.Task.Result;
@@ -93,9 +94,9 @@ namespace Avalonia.Win32.WinRT.Composition
{
_parent = parent;
}
+
public void Dispose()
{
-
}
public void Invoke(IAsyncAction asyncInfo, AsyncStatus asyncStatus)
@@ -106,6 +107,7 @@ namespace Avalonia.Win32.WinRT.Composition
}
public MicroComShadow Shadow { get; set; }
+
public void OnReferencedFromNative()
{
}
@@ -114,12 +116,12 @@ namespace Avalonia.Win32.WinRT.Composition
{
}
}
-
+
private void RunLoop()
{
{
var st = Stopwatch.StartNew();
- using (var act = _compositor5.RequestCommitAsync())
+ using (var act = _compositor5.RequestCommitAsync())
act.SetCompleted(new RunLoopHandler(this));
while (true)
{
@@ -130,7 +132,8 @@ namespace Avalonia.Win32.WinRT.Composition
}
}
- public static void TryCreateAndRegister(EglPlatformOpenGlInterface angle)
+ public static void TryCreateAndRegister(EglPlatformOpenGlInterface angle,
+ float backdropCornerRadius)
{
const int majorRequired = 10;
const int buildRequired = 17134;
@@ -143,14 +146,12 @@ namespace Avalonia.Win32.WinRT.Composition
{
try
{
- TryCreateAndRegisterCore(angle);
- return;
+ TryCreateAndRegisterCore(angle, backdropCornerRadius);
}
catch (Exception e)
{
Logger.TryGet(LogEventLevel.Error, "WinUIComposition")
?.Log(null, "Unable to initialize WinUI compositor: {0}", e);
-
}
}
@@ -167,17 +168,19 @@ namespace Avalonia.Win32.WinRT.Composition
using var sc = _syncContext.EnsureLocked();
using var desktopTarget = _compositorDesktopInterop.CreateDesktopWindowTarget(hWnd, 0);
using var target = desktopTarget.QueryInterface();
-
- using var drawingSurface = _device.CreateDrawingSurface(new UnmanagedMethods.SIZE(), DirectXPixelFormat.B8G8R8A8UIntNormalized,
+
+ using var drawingSurface = _device.CreateDrawingSurface(new UnmanagedMethods.SIZE(),
+ DirectXPixelFormat.B8G8R8A8UIntNormalized,
DirectXAlphaMode.Premultiplied);
using var surface = drawingSurface.QueryInterface();
using var surfaceInterop = drawingSurface.QueryInterface();
-
+
using var surfaceBrush = _compositor.CreateSurfaceBrushWithSurface(surface);
using var brush = surfaceBrush.QueryInterface();
using var spriteVisual = _compositor.CreateSpriteVisual();
spriteVisual.SetBrush(brush);
+
using var visual = spriteVisual.QueryInterface();
using var visual2 = spriteVisual.QueryInterface();
using var container = _compositor.CreateContainerVisual();
@@ -185,47 +188,90 @@ namespace Avalonia.Win32.WinRT.Composition
using var containerVisual2 = container.QueryInterface();
containerVisual2.SetRelativeSizeAdjustment(new Vector2(1, 1));
using var containerChildren = container.Children;
-
+
target.SetRoot(containerVisual);
- using var blur = CreateBlurVisual();
-
+ using var blur = CreateBlurVisual(_blurBrush);
+ IVisual mica = null;
+ if (_micaBrush != null)
+ {
+ mica = CreateBlurVisual(_micaBrush);
+ containerChildren.InsertAtTop(mica);
+ }
+
+ var compositionRoundedRectangleGeometry = ClipVisual(blur, mica);
+
containerChildren.InsertAtTop(blur);
containerChildren.InsertAtTop(visual);
-
- return new WinUICompositedWindow(_syncContext, _compositor, _pumpLock, target, surfaceInterop, visual, blur);
+
+ return new WinUICompositedWindow(_syncContext, _compositor, _pumpLock, target, surfaceInterop, visual,
+ blur, mica, compositionRoundedRectangleGeometry);
}
+ private ICompositionBrush CreateMicaBackdropBrush()
+ {
+ if (Win32Platform.WindowsVersion.Build < 22000)
+ return null;
+
+ using var compositorWithBlurredWallpaperBackdropBrush =
+ _compositor.QueryInterface();
+ using var blurredWallpaperBackdropBrush =
+ compositorWithBlurredWallpaperBackdropBrush?.TryCreateBlurredWallpaperBackdropBrush();
+ using var micaBackdropBrush = blurredWallpaperBackdropBrush?.QueryInterface();
+ return micaBackdropBrush.CloneReference();
+ }
- private unsafe ICompositionBrush CreateBlurBrush()
+ private unsafe ICompositionBrush CreateAcrylicBlurBackdropBrush()
{
- using var backDropParameterFactory = NativeWinRTMethods.CreateActivationFactory(
- "Windows.UI.Composition.CompositionEffectSourceParameter");
+ using var backDropParameterFactory =
+ NativeWinRTMethods.CreateActivationFactory(
+ "Windows.UI.Composition.CompositionEffectSourceParameter");
using var backdropString = new HStringInterop("backdrop");
using var backDropParameter =
backDropParameterFactory.Create(backdropString.Handle);
using var backDropParameterAsSource = backDropParameter.QueryInterface();
var blurEffect = new WinUIGaussianBlurEffect(backDropParameterAsSource);
using var blurEffectFactory = _compositor.CreateEffectFactory(blurEffect);
+ using var compositionEffectBrush = blurEffectFactory.CreateBrush();
using var backdrop = _compositor2.CreateBackdropBrush();
using var backdropBrush = backdrop.QueryInterface();
-
-
+
var saturateEffect = new SaturationEffect(blurEffect);
using var satEffectFactory = _compositor.CreateEffectFactory(saturateEffect);
using var sat = satEffectFactory.CreateBrush();
- sat.SetSourceParameter(backdropString.Handle, backdropBrush);
- return sat.QueryInterface();
+ compositionEffectBrush.SetSourceParameter(backdropString.Handle, backdropBrush);
+ return compositionEffectBrush.QueryInterface();
+ }
+
+ private ICompositionRoundedRectangleGeometry ClipVisual(params IVisual[] containerVisuals)
+ {
+ if (_backdropCornerRadius == 0)
+ return null;
+ using var roundedRectangleGeometry = _compositor5.CreateRoundedRectangleGeometry();
+ roundedRectangleGeometry.SetCornerRadius(new Vector2(_backdropCornerRadius, _backdropCornerRadius));
+
+ using var compositor6 = _compositor.QueryInterface();
+ using var compositionGeometry = roundedRectangleGeometry
+ .QueryInterface();
+
+ using var geometricClipWithGeometry =
+ compositor6.CreateGeometricClipWithGeometry(compositionGeometry);
+ foreach (var visual in containerVisuals)
+ {
+ visual?.SetClip(geometricClipWithGeometry.QueryInterface());
+ }
+
+ return roundedRectangleGeometry.CloneReference();
}
-
- private unsafe IVisual CreateBlurVisual()
+
+ private unsafe IVisual CreateBlurVisual(ICompositionBrush compositionBrush)
{
using var spriteVisual = _compositor.CreateSpriteVisual();
using var visual = spriteVisual.QueryInterface();
using var visual2 = spriteVisual.QueryInterface();
-
-
- spriteVisual.SetBrush(_blurBrush);
+
+
+ spriteVisual.SetBrush(compositionBrush);
visual.SetIsVisible(0);
visual2.SetRelativeSizeAdjustment(new Vector2(1.0f, 1.0f));
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs
index f59d50860a..4ed882552b 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs
@@ -15,7 +15,7 @@ namespace Avalonia.Win32.WinRT.Composition
private EglPlatformOpenGlInterface _egl;
private readonly EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo _info;
private IRef _window;
- private bool _enableBlur;
+ private BlurEffect _blurEffect;
public WinUiCompositedWindowSurface(WinUICompositorConnection connection, IEglWindowGlPlatformSurfaceInfo info) : base()
{
@@ -31,7 +31,7 @@ namespace Avalonia.Win32.WinRT.Composition
if (_window?.Item == null)
{
_window = RefCountable.Create(_connection.CreateWindow(_info.Handle));
- _window.Item.SetBlur(_enableBlur);
+ _window.Item.SetBlur(_blurEffect);
}
return new CompositionRenderTarget(_egl, _window, _info);
@@ -100,10 +100,10 @@ namespace Avalonia.Win32.WinRT.Composition
}
}
- public void SetBlur(bool enable)
+ public void SetBlur(BlurEffect blurEffect)
{
- _enableBlur = enable;
- _window?.Item?.SetBlur(enable);
+ _blurEffect = blurEffect;
+ _window?.Item?.SetBlur(blurEffect);
}
public void Dispose()
diff --git a/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs b/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
index 81c0e3e185..ea5dcdeeba 100644
--- a/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
@@ -1,7 +1,14 @@
namespace Avalonia.Win32.WinRT
{
+ public enum BlurEffect
+ {
+ None,
+ Acrylic,
+ Mica
+ }
+
public interface IBlurHost
{
- void SetBlur(bool enable);
+ void SetBlur(BlurEffect enable);
}
}
diff --git a/src/Windows/Avalonia.Win32/WinRT/winrt.idl b/src/Windows/Avalonia.Win32/WinRT/winrt.idl
index 929377999c..18a9a26fca 100644
--- a/src/Windows/Avalonia.Win32/WinRT/winrt.idl
+++ b/src/Windows/Avalonia.Win32/WinRT/winrt.idl
@@ -358,6 +358,12 @@ interface ICompositor2 : IInspectable
[overload("CreateStepEasingFunction")] HRESULT CreateStepEasingFunctionWithStepCount([in] INT32 stepCount, [out] [retval] void** result);
}
+[uuid(0D8FB190-F122-5B8D-9FDD-543B0D8EB7F3)]
+interface ICompositorWithBlurredWallpaperBackdropBrush : IInspectable
+{
+ HRESULT TryCreateBlurredWallpaperBackdropBrush([out] [retval] ICompositionBackdropBrush** result);
+}
+
[uuid(08E05581-1AD1-4F97-9757-402D76E4233B)]
interface ISpriteVisual : IInspectable
{
@@ -520,6 +526,13 @@ enum CompositionCompositeMode
MinBlend,
}
+[contract(Windows.Foundation.UniversalApiContract, 2.0)]
+[exclusiveto(Windows.UI.Composition.CompositionClip)]
+[uuid(1CCD2A52-CFC7-4ACE-9983-146BB8EB6A3C)]
+interface ICompositionClip : IInspectable
+{
+}
+
[uuid(117E202D-A859-4C89-873B-C2AA566788E3)]
interface IVisual : IInspectable
{
@@ -531,8 +544,8 @@ interface IVisual : IInspectable
[propput] HRESULT BorderMode([in] CompositionBorderMode value);
[propget] HRESULT CenterPoint([out] [retval] Vector3* value);
[propput] HRESULT CenterPoint([in] Vector3 value);
- [propget] HRESULT Clip([out] [retval]void** value);
- [propput] HRESULT Clip([in] void* value);
+ [propget] HRESULT Clip([out] [retval] ICompositionClip** value);
+ [propput] HRESULT Clip([in] ICompositionClip* value);
[propget] HRESULT CompositeMode([out] [retval] CompositionCompositeMode* value);
[propput] HRESULT CompositeMode([in] CompositionCompositeMode value);
[propget] HRESULT IsVisible([out] [retval] boolean* value);
@@ -692,6 +705,99 @@ interface ICompositionScopedBatch : IInspectable
[eventremove] HRESULT RemoveCompleted([in] int token);
}
+[contract(Windows.Foundation.UniversalApiContract, 6.0)]
+[exclusiveto(Windows.UI.Composition.CompositionRoundedRectangleGeometry)]
+[uuid(8770C822-1D50-4B8B-B013-7C9A0E46935F)]
+interface ICompositionRoundedRectangleGeometry : IInspectable
+{
+ [propget] HRESULT CornerRadius([out] [retval] Vector2* value);
+ [propput] HRESULT CornerRadius([in] Vector2 value);
+ [propget] HRESULT Offset([out] [retval] Vector2* value);
+ [propput] HRESULT Offset([in] Vector2 value);
+ [propget] HRESULT Size([out] [retval] Vector2* value);
+ [propput] HRESULT Size([in] Vector2 value);
+}
+
+[contract(Windows.Foundation.UniversalApiContract, 6.0)]
+[exclusiveto(Windows.UI.Composition.CompositionGeometry)]
+[uuid(E985217C-6A17-4207-ABD8-5FD3DD612A9D)]
+interface ICompositionGeometry : IInspectable
+{
+ [propget] HRESULT TrimEnd([out] [retval] FLOAT* value);
+ [propput] HRESULT TrimEnd([in] FLOAT value);
+ [propget] HRESULT TrimOffset([out] [retval] FLOAT* value);
+ [propput] HRESULT TrimOffset([in] FLOAT value);
+ [propget] HRESULT TrimStart([out] [retval] FLOAT* value);
+ [propput] HRESULT TrimStart([in] FLOAT value);
+}
+
+[uuid(401B61BB-0007-4363-B1F3-6BCC003FB83E)]
+interface ICompositionSpriteShape : IInspectable
+{
+ [propget] HRESULT GetFillBrush([out] [retval] ICompositionBrush** value);
+ [propput] HRESULT SetFillBrush([in] ICompositionBrush* value);
+ [propget] HRESULT Geometry([out] [retval] ICompositionGeometry** value);
+ [propput] HRESULT Geometry([in] ICompositionGeometry* value);
+ [propget] HRESULT IsStrokeNonScaling([out] [retval] boolean* value);
+ [propput] HRESULT IsStrokeNonScaling([in] boolean value);
+ [propget] HRESULT StrokeBrush([out] [retval] ICompositionBrush** value);
+ [propput] HRESULT StrokeBrush([in] ICompositionBrush* value);
+ [propget] HRESULT StrokeDashArray();
+ [propget] HRESULT StrokeDashCap();
+ [propput] HRESULT StrokeDashCap();
+ [propget] HRESULT StrokeDashOffset();
+ [propput] HRESULT StrokeDashOffset();
+ [propget] HRESULT StrokeEndCap();
+ [propput] HRESULT StrokeEndCap();
+ [propget] HRESULT StrokeLineJoin();
+ [propput] HRESULT StrokeLineJoin();
+ [propget] HRESULT StrokeMiterLimit();
+ [propput] HRESULT StrokeMiterLimit();
+ [propget] HRESULT StrokeStartCap();
+ [propput] HRESULT StrokeStartCap();
+ [propget] HRESULT StrokeThickness();
+ [propput] HRESULT StrokeThickness();
+}
+
+[contract(Windows.Foundation.UniversalApiContract, 6.0)]
+[exclusiveto(Windows.UI.Composition.CompositionShape)]
+[uuid(B47CE2F7-9A88-42C4-9E87-2E500CA8688C)]
+interface ICompositionShape : IInspectable
+{
+ [propget] HRESULT CenterPoint([out] [retval] Vector2* value);
+ [propput] HRESULT CenterPoint([in] Vector2 value);
+}
+
+[uuid(42d4219a-be1b-5091-8f1e-90270840fc2d)]
+interface IVectorOfCompositionShape : IInspectable
+{
+ HRESULT GetAt();
+ [propget] HRESULT GetSize();
+ HRESULT GetView();
+ HRESULT IndexOf();
+ HRESULT SetAt();
+ HRESULT InsertAt();
+ HRESULT RemoveAt();
+ HRESULT Append([in] ICompositionShape* value);
+ HRESULT RemoveAtEnd();
+ HRESULT Clear();
+}
+
+[contract(Windows.Foundation.UniversalApiContract, 7.0)]
+[exclusiveto(Windows.UI.Composition.CompositionGeometricClip)]
+[uuid(C840B581-81C9-4444-A2C1-CCAECE3A50E5)]
+interface ICompositionGeometricClip : IInspectable
+{
+ [propget] HRESULT Geometry([out] [retval] ICompositionGeometry** value);
+ [propput] HRESULT Geometry([in] ICompositionGeometry* value);
+}
+
+[uuid(F2BD13C3-BA7E-4B0F-9126-FFB7536B8176)]
+interface IShapeVisual : IInspectable
+{
+ [propget] HRESULT Shapes([out] [retval] IUnknown** value);
+}
+
[uuid(48EA31AD-7FCD-4076-A79C-90CC4B852C9B)]
interface ICompositor5 : IInspectable
{
@@ -709,10 +815,19 @@ interface ICompositor5 : IInspectable
[overload("CreatePathGeometry")] HRESULT CreatePathGeometryWithPath([in] void* path, [out] [retval] void** result);
HRESULT CreatePathKeyFrameAnimation([out] [retval] void** result);
HRESULT CreateRectangleGeometry([out] [retval] void** result);
- HRESULT CreateRoundedRectangleGeometry([out] [retval] void** result);
- HRESULT CreateShapeVisual([out] [retval] void** result);
+ HRESULT CreateRoundedRectangleGeometry([out] [retval] ICompositionRoundedRectangleGeometry** result);
+ HRESULT CreateShapeVisual([out] [retval] IShapeVisual** result);
[overload("CreateSpriteShape")] HRESULT CreateSpriteShape([out] [retval] void** result);
[overload("CreateSpriteShape")] HRESULT CreateSpriteShapeWithGeometry([in] void* geometry, [out] [retval] void** result);
HRESULT CreateViewBox([out] [retval] void** result);
HRESULT RequestCommitAsync([out] [retval] IAsyncAction** operation);
}
+
+[contract(Windows.Foundation.UniversalApiContract, 7.0)]
+[exclusiveto(Windows.UI.Composition.Compositor)]
+[uuid(7A38B2BD-CEC8-4EEB-830F-D8D07AEDEBC3)]
+interface ICompositor6 : IInspectable
+{
+ [overload("CreateGeometricClip")] HRESULT CreateGeometricClip([out] [retval] ICompositionGeometricClip** result);
+ [overload("CreateGeometricClip")] HRESULT CreateGeometricClipWithGeometry([in] ICompositionGeometry* geometry, [out] [retval] ICompositionGeometricClip** result);
+}
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index 8fc25f8cfa..0a0f600520 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -82,7 +82,7 @@ namespace Avalonia.Win32
private Size _minSize;
private Size _maxSize;
private POINT _maxTrackSize;
- private WindowImpl _parent;
+ private WindowImpl _parent;
private ExtendClientAreaChromeHints _extendChromeHints = ExtendClientAreaChromeHints.Default;
private bool _isCloseRequested;
private bool _shown;
@@ -105,9 +105,7 @@ namespace Avalonia.Win32
_windowProperties = new WindowProperties
{
- ShowInTaskbar = false,
- IsResizable = true,
- Decorations = SystemDecorations.Full
+ ShowInTaskbar = false, IsResizable = true, Decorations = SystemDecorations.Full
};
_rendererLock = new ManagedDeferredRendererLock();
@@ -116,13 +114,13 @@ namespace Avalonia.Win32
var compositionConnector = AvaloniaLocator.Current.GetService();
_isUsingComposition = compositionConnector is { } &&
- glPlatform is EglPlatformOpenGlInterface egl &&
- egl.Display is AngleWin32EglDisplay angleDisplay &&
- angleDisplay.PlatformApi == AngleOptions.PlatformApi.DirectX11;
+ glPlatform is EglPlatformOpenGlInterface egl &&
+ egl.Display is AngleWin32EglDisplay angleDisplay &&
+ angleDisplay.PlatformApi == AngleOptions.PlatformApi.DirectX11;
CreateWindow();
_framebuffer = new FramebufferManager(_hwnd);
-
+
if (glPlatform != null)
{
if (_isUsingComposition)
@@ -168,7 +166,7 @@ namespace Avalonia.Win32
public Action PositionChanged { get; set; }
public Action WindowStateChanged { get; set; }
-
+
public Action LostFocus { get; set; }
public Action TransparencyLevelChanged { get; set; }
@@ -224,7 +222,8 @@ namespace Avalonia.Win32
return new Size(rcWindow.Width, rcWindow.Height) / RenderScaling;
}
- DwmGetWindowAttribute(_hwnd, (int)DwmWindowAttribute.DWMWA_EXTENDED_FRAME_BOUNDS, out var rect, Marshal.SizeOf(typeof(RECT)));
+ DwmGetWindowAttribute(_hwnd, (int)DwmWindowAttribute.DWMWA_EXTENDED_FRAME_BOUNDS, out var rect,
+ Marshal.SizeOf(typeof(RECT)));
return new Size(rect.Width, rect.Height) / RenderScaling;
}
}
@@ -233,7 +232,8 @@ namespace Avalonia.Win32
public IPlatformHandle Handle { get; private set; }
- public virtual Size MaxAutoSizeHint => new Size(_maxTrackSize.X / RenderScaling, _maxTrackSize.Y / RenderScaling);
+ public virtual Size MaxAutoSizeHint =>
+ new Size(_maxTrackSize.X / RenderScaling, _maxTrackSize.Y / RenderScaling);
public IMouseDevice MouseDevice => _mouseDevice;
@@ -241,7 +241,7 @@ namespace Avalonia.Win32
{
get
{
- if(_isFullScreenActive)
+ if (_isFullScreenActive)
{
return WindowState.FullScreen;
}
@@ -264,7 +264,7 @@ namespace Avalonia.Win32
ShowWindow(value, true);
}
- _showWindowState = value;
+ _showWindowState = value;
}
}
@@ -272,7 +272,7 @@ namespace Avalonia.Win32
protected IntPtr Hwnd => _hwnd;
- public void SetTransparencyLevelHint (WindowTransparencyLevel transparencyLevel)
+ public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
{
TransparencyLevel = EnableBlur(transparencyLevel);
}
@@ -312,12 +312,12 @@ namespace Avalonia.Win32
}
var blurInfo = new DWM_BLURBEHIND(false);
-
+
if (transparencyLevel == WindowTransparencyLevel.Blur)
{
blurInfo = new DWM_BLURBEHIND(true);
}
-
+
DwmEnableBlurBehindWindow(_hwnd, ref blurInfo);
if (transparencyLevel == WindowTransparencyLevel.Transparent)
@@ -373,13 +373,20 @@ namespace Avalonia.Win32
{
if (_isUsingComposition)
{
- _blurHost?.SetBlur(transparencyLevel >= WindowTransparencyLevel.Blur);
+ _blurHost?.SetBlur(transparencyLevel switch
+ {
+ WindowTransparencyLevel.Mica => BlurEffect.Mica,
+ WindowTransparencyLevel.AcrylicBlur => BlurEffect.Acrylic,
+ WindowTransparencyLevel.Blur => BlurEffect.Acrylic,
+ _ => BlurEffect.None
+ });
return transparencyLevel;
}
else
{
- bool canUseAcrylic = Win32Platform.WindowsVersion.Major > 10 || Win32Platform.WindowsVersion.Build >= 19628;
+ bool canUseAcrylic = Win32Platform.WindowsVersion.Major > 10 ||
+ Win32Platform.WindowsVersion.Build >= 19628;
var accent = new AccentPolicy();
var accentStructSize = Marshal.SizeOf(accent);
@@ -530,7 +537,7 @@ namespace Avalonia.Win32
{
BeforeCloseCleanup(true);
}
-
+
DestroyWindow(_hwnd);
_hwnd = IntPtr.Zero;
}
@@ -596,7 +603,7 @@ namespace Avalonia.Win32
public void SetParent(IWindowImpl parent)
{
_parent = (WindowImpl)parent;
-
+
var parentHwnd = _parent?._hwnd ?? IntPtr.Zero;
if (parentHwnd == IntPtr.Zero && !_windowProperties.ShowInTaskbar)
@@ -707,7 +714,7 @@ namespace Avalonia.Win32
_isUsingComposition ? (int)WindowStyles.WS_EX_NOREDIRECTIONBITMAP : 0,
atom,
null,
- (int)WindowStyles.WS_OVERLAPPEDWINDOW | (int) WindowStyles.WS_CLIPCHILDREN,
+ (int)WindowStyles.WS_OVERLAPPEDWINDOW | (int)WindowStyles.WS_CLIPCHILDREN,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
@@ -763,7 +770,7 @@ namespace Avalonia.Win32
}
if (ShCoreAvailable && Win32Platform.WindowsVersion > PlatformConstants.Windows8)
- {
+ {
var monitor = MonitorFromWindow(
_hwnd,
MONITOR.MONITOR_DEFAULTTONEAREST);
@@ -809,7 +816,9 @@ namespace Avalonia.Win32
// Set new window style and size.
SetStyle(current & ~(WindowStyles.WS_CAPTION | WindowStyles.WS_THICKFRAME), false);
- SetExtendedStyle(currentEx & ~(WindowStyles.WS_EX_DLGMODALFRAME | WindowStyles.WS_EX_WINDOWEDGE | WindowStyles.WS_EX_CLIENTEDGE | WindowStyles.WS_EX_STATICEDGE), false);
+ SetExtendedStyle(
+ currentEx & ~(WindowStyles.WS_EX_DLGMODALFRAME | WindowStyles.WS_EX_WINDOWEDGE |
+ WindowStyles.WS_EX_CLIENTEDGE | WindowStyles.WS_EX_STATICEDGE), false);
// On expand, if we're given a window_rect, grow to it, otherwise do
// not resize.
@@ -819,8 +828,9 @@ namespace Avalonia.Win32
var window_rect = monitor_info.rcMonitor.ToPixelRect();
SetWindowPos(_hwnd, IntPtr.Zero, window_rect.X, window_rect.Y,
- window_rect.Width, window_rect.Height,
- SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED);
+ window_rect.Width, window_rect.Height,
+ SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE |
+ SetWindowPosFlags.SWP_FRAMECHANGED);
_isFullScreenActive = true;
}
@@ -839,21 +849,22 @@ namespace Avalonia.Win32
var new_rect = _savedWindowInfo.WindowRect.ToPixelRect();
SetWindowPos(_hwnd, IntPtr.Zero, new_rect.X, new_rect.Y, new_rect.Width,
- new_rect.Height,
- SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_FRAMECHANGED);
+ new_rect.Height,
+ SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE |
+ SetWindowPosFlags.SWP_FRAMECHANGED);
UpdateWindowProperties(_windowProperties, true);
}
TaskBarList.MarkFullscreen(_hwnd, fullscreen);
-
+
ExtendClientArea();
}
private MARGINS UpdateExtendMargins()
{
RECT borderThickness = new RECT();
- RECT borderCaptionThickness = new RECT();
+ RECT borderCaptionThickness = new RECT();
AdjustWindowRectEx(ref borderCaptionThickness, (uint)(GetStyle()), false, 0);
AdjustWindowRectEx(ref borderThickness, (uint)(GetStyle() & ~WindowStyles.WS_CAPTION), false, 0);
@@ -862,7 +873,8 @@ namespace Avalonia.Win32
borderCaptionThickness.left *= -1;
borderCaptionThickness.top *= -1;
- bool wantsTitleBar = _extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.SystemChrome) || _extendTitleBarHint == -1;
+ bool wantsTitleBar = _extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.SystemChrome) ||
+ _extendTitleBarHint == -1;
if (!wantsTitleBar)
{
@@ -876,15 +888,22 @@ namespace Avalonia.Win32
if (_extendTitleBarHint != -1)
{
- borderCaptionThickness.top = (int)(_extendTitleBarHint * RenderScaling);
+ borderCaptionThickness.top = (int)(_extendTitleBarHint * RenderScaling);
}
- margins.cyTopHeight = _extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.SystemChrome) && !_extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.PreferSystemChrome) ? borderCaptionThickness.top : 1;
+ margins.cyTopHeight =
+ _extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.SystemChrome) &&
+ !_extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.PreferSystemChrome) ?
+ borderCaptionThickness.top :
+ 1;
if (WindowState == WindowState.Maximized)
{
- _extendedMargins = new Thickness(0, (borderCaptionThickness.top - borderThickness.top) / RenderScaling, 0, 0);
- _offScreenMargin = new Thickness(borderThickness.left / RenderScaling, borderThickness.top / RenderScaling, borderThickness.right / RenderScaling, borderThickness.bottom / RenderScaling);
+ _extendedMargins = new Thickness(0, (borderCaptionThickness.top - borderThickness.top) / RenderScaling,
+ 0, 0);
+ _offScreenMargin = new Thickness(borderThickness.left / RenderScaling,
+ borderThickness.top / RenderScaling, borderThickness.right / RenderScaling,
+ borderThickness.bottom / RenderScaling);
}
else
{
@@ -901,12 +920,13 @@ namespace Avalonia.Win32
{
return;
}
-
+
if (DwmIsCompositionEnabled(out bool compositionEnabled) < 0 || !compositionEnabled)
{
_isClientAreaExtended = false;
return;
}
+
GetClientRect(_hwnd, out var rcClient);
GetWindowRect(_hwnd, out var rcWindow);
@@ -929,12 +949,14 @@ namespace Avalonia.Win32
_offScreenMargin = new Thickness();
_extendedMargins = new Thickness();
-
- Resize(new Size(rcWindow.Width/ RenderScaling, rcWindow.Height / RenderScaling), PlatformResizeReason.Layout);
+
+ Resize(new Size(rcWindow.Width / RenderScaling, rcWindow.Height / RenderScaling),
+ PlatformResizeReason.Layout);
}
- if(!_isClientAreaExtended || (_extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.SystemChrome) &&
- !_extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.PreferSystemChrome)))
+ if (!_isClientAreaExtended || (_extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.SystemChrome) &&
+ !_extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints
+ .PreferSystemChrome)))
{
EnableCloseButton(_hwnd);
}
@@ -949,12 +971,12 @@ namespace Avalonia.Win32
private void ShowWindow(WindowState state, bool activate)
{
_shown = true;
-
+
if (_isClientAreaExtended)
{
ExtendClientArea();
}
-
+
ShowWindowCommand? command;
var newWindowProperties = _windowProperties;
@@ -972,7 +994,7 @@ namespace Avalonia.Win32
case WindowState.Normal:
newWindowProperties.IsFullScreen = false;
- command = IsWindowVisible(_hwnd) ? ShowWindowCommand.Restore :
+ command = IsWindowVisible(_hwnd) ? ShowWindowCommand.Restore :
activate ? ShowWindowCommand.Normal : ShowWindowCommand.ShowNoActivate;
break;
@@ -1002,7 +1024,7 @@ namespace Avalonia.Win32
SetFocus(_hwnd);
}
}
-
+
private void BeforeCloseCleanup(bool isDisposing)
{
// Based on https://github.com/dotnet/wpf/blob/master/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs#L4270-L4337
@@ -1020,7 +1042,7 @@ namespace Avalonia.Win32
// Our window closed callback will set enabled state to a correct value after child window gets destroyed.
_parent.SetEnabled(true);
}
-
+
// We also need to activate our parent window since again OS might try to activate a window behind if it is not set.
if (wasActive)
{
@@ -1047,7 +1069,7 @@ namespace Avalonia.Win32
SetWindowPos(_hwnd, WindowPosZOrder.HWND_NOTOPMOST, x, y, cx, cy, SetWindowPosFlags.SWP_SHOWWINDOW);
}
}
- }
+ }
private WindowStyles GetWindowStateStyles()
{
@@ -1200,10 +1222,7 @@ namespace Avalonia.Win32
var margins = new MARGINS
{
- cyBottomHeight = margin,
- cxRightWidth = margin,
- cxLeftWidth = margin,
- cyTopHeight = margin
+ cyBottomHeight = margin, cxRightWidth = margin, cxLeftWidth = margin, cyTopHeight = margin
};
DwmExtendFrameIntoClientArea(_hwnd, ref margins);
@@ -1224,7 +1243,7 @@ namespace Avalonia.Win32
SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE |
SetWindowPosFlags.SWP_FRAMECHANGED);
}
- }
+ }
}
private const int MF_BYCOMMAND = 0x0;
@@ -1238,12 +1257,13 @@ namespace Avalonia.Win32
void DisableCloseButton(IntPtr hwnd)
{
EnableMenuItem(GetSystemMenu(hwnd, false), SC_CLOSE,
- MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
+ MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
}
+
void EnableCloseButton(IntPtr hwnd)
{
EnableMenuItem(GetSystemMenu(hwnd, false), SC_CLOSE,
- MF_BYCOMMAND | MF_ENABLED);
+ MF_BYCOMMAND | MF_ENABLED);
}
#if USE_MANAGED_DRAG
@@ -1274,9 +1294,9 @@ namespace Avalonia.Win32
public void SetExtendClientAreaToDecorationsHint(bool hint)
{
_isClientAreaExtended = hint;
-
- ExtendClientArea();
- }
+
+ ExtendClientArea();
+ }
public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints)
{
@@ -1284,7 +1304,7 @@ namespace Avalonia.Win32
ExtendClientArea();
}
-
+
///
public void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight)
{
@@ -1298,9 +1318,11 @@ namespace Avalonia.Win32
///
public Action ExtendClientAreaToDecorationsChanged { get; set; }
-
+
///
- public bool NeedsManagedDecorations => _isClientAreaExtended && _extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.PreferSystemChrome);
+ public bool NeedsManagedDecorations => _isClientAreaExtended &&
+ _extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints
+ .PreferSystemChrome);
///
public Thickness ExtendedMargins => _extendedMargins;
@@ -1309,7 +1331,8 @@ namespace Avalonia.Win32
public Thickness OffScreenMargin => _offScreenMargin;
///
- public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 0.8, 0);
+ public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } =
+ new AcrylicPlatformCompensationLevels(1, 0.8, 0);
private ResizeReasonScope SetResizeReason(PlatformResizeReason reason)
{
@@ -1337,7 +1360,7 @@ namespace Avalonia.Win32
{
private readonly WindowImpl _owner;
private readonly PlatformResizeReason _restore;
-
+
public ResizeReasonScope(WindowImpl owner, PlatformResizeReason restore)
{
_owner = owner;