Browse Source

Merge branch 'master' into x11-mate-clipboard

pull/12002/head
Max Katz 3 years ago
committed by GitHub
parent
commit
8c5a73c2a6
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 26
      packages/Avalonia/AvaloniaBuildTasks.targets
  2. 4
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
  3. 2
      src/Avalonia.Native/NativePlatformSettings.cs
  4. 3
      src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs
  5. 104
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs
  6. 30
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs
  7. 9
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs
  8. 72
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs
  9. 3
      src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
  10. 23
      src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs
  11. 13
      src/Windows/Avalonia.Win32/WindowImpl.cs
  12. 16
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_SelectedValue.cs

26
packages/Avalonia/AvaloniaBuildTasks.targets

@ -144,4 +144,30 @@
<UpToDateCheckInput Include="@(AvaloniaResource)" />
<UpToDateCheckInput Include="@(AvaloniaXaml)" />
</ItemGroup>
<PropertyGroup>
<AvaloniaFilePreviewDependsOn Condition="'$(SkipBuild)'!='True'">Build</AvaloniaFilePreviewDependsOn>
</PropertyGroup>
<Target Name="AvaloniaFilePreview" DependsOnTargets="$(AvaloniaFilePreviewDependsOn)">
<PropertyGroup>
<APreviewerUrl>http://127.0.0.1:6001</APreviewerUrl>
<APreviewExecutable>$(OutputPath)/$(AssemblyName).dll</APreviewExecutable>
<APreviewFile Condition="$(APreviewFile) == ''">MainWindow.axaml</APreviewFile>
<APreviewAssembly Condition="$(APreviewAssembly) == ''">$(APreviewExecutable)</APreviewAssembly>
<APreviewerDepsJsonPath>$([System.IO.Path]::ChangeExtension('$(APreviewExecutable)', '.deps.json'))</APreviewerDepsJsonPath>
<APreviewerRuntimeConfigPath>$([System.IO.Path]::ChangeExtension('$(APreviewExecutable)', '.runtimeconfig.json'))</APreviewerRuntimeConfigPath>
<APreviewTransportUrl>$([System.IO.Path]::GetFullPath('$(APreviewFile)'))</APreviewTransportUrl>
</PropertyGroup>
<Message Importance="high" Text="Launching previewer for"/>
<Message Importance="high" Text="File (APreviewFile): $(APreviewTransportUrl)"/>
<Message Importance="high" Text="Containing assembly (APreviewAssembly): $(APreviewDefiningAssembly)"/>
<Message Importance="high" Text="Executable: $(APreviewExecutable)"/>
<Message Importance="high" Text="Url (APreviewerUrl): $(APreviewerUrl)"/>
<Exec Command="dotnet exec --runtimeconfig &quot;$(APreviewerRuntimeConfigPath)&quot; --depsfile &quot;$(APreviewerDepsJsonPath)&quot; &quot;$(AvaloniaPreviewerNetCoreToolPath)&quot; --method html --html-url $(APreviewerUrl) --transport $(APreviewTransportUrl) &quot;$(APreviewExecutable)&quot;"/>
</Target>
</Project>

4
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@ -1395,10 +1395,8 @@ namespace Avalonia.Controls.Primitives
public object Evaluate(object? dataContext)
{
dataContext = dataContext ?? throw new ArgumentNullException(nameof(dataContext));
// Only update the DataContext if necessary
if (!dataContext.Equals(DataContext))
if (!Equals(dataContext, DataContext))
DataContext = dataContext;
return GetValue(ValueProperty);

2
src/Avalonia.Native/NativePlatformSettings.cs

@ -23,7 +23,7 @@ internal class NativePlatformSettings : DefaultPlatformSettings
AvnPlatformThemeVariant.Dark => (PlatformThemeVariant.Dark, ColorContrastPreference.NoPreference),
AvnPlatformThemeVariant.Light => (PlatformThemeVariant.Light, ColorContrastPreference.NoPreference),
AvnPlatformThemeVariant.HighContrastDark => (PlatformThemeVariant.Dark, ColorContrastPreference.High),
AvnPlatformThemeVariant.HighContrastLight => (PlatformThemeVariant.Dark, ColorContrastPreference.High),
AvnPlatformThemeVariant.HighContrastLight => (PlatformThemeVariant.Light, ColorContrastPreference.High),
_ => throw new ArgumentOutOfRangeException()
};
var color = _platformSettings.AccentColor;

3
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);

104
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
{

30
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();
@ -68,9 +76,6 @@ internal class WinUiCompositedWindow : IDisposable
using var compositionBrush = _surfaceBrush.QueryInterface<ICompositionBrush>();
spriteVisual.SetBrush(compositionBrush);
_target.SetRoot(containerVisual);
}
public void SetSurface(ICompositionSurface surface) => _surfaceBrush.SetSurface(surface);
@ -79,12 +84,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);
}
}

9
src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs

@ -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);
@ -21,14 +22,16 @@ internal class WinUiCompositionShared : IDisposable
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();

72
src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs

@ -1,3 +1,4 @@
using System;
using System.Numerics;
using MicroCom.Runtime;
@ -5,16 +6,72 @@ 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)
@ -97,4 +154,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<IGraphicsEffectSource>();
handle = backdropString.Handle;
return backDropParameterAsSource;
}
}

3
src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs

@ -4,7 +4,8 @@
{
None,
Acrylic,
Mica
MicaLight,
MicaDark
}
internal interface IBlurHost

23
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<float>());
Marshal.Copy(_singleArray, 0, allocCoTaskMem, _singleArray.Length);
float* s = (float*)allocCoTaskMem;
return s;
}
public unsafe double* GetDoubleArray(uint* __valueSize) => throw NotImplemented;

13
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -106,6 +106,7 @@ namespace Avalonia.Win32
private static POINTER_PEN_INFO[]? s_historyPenInfos;
private static POINTER_INFO[]? s_historyInfos;
private static MOUSEMOVEPOINT[]? s_mouseHistoryInfos;
private PlatformThemeVariant _currentThemeVariant;
public WindowImpl()
{
@ -474,7 +475,12 @@ namespace Avalonia.Win32
return;
SetUseHostBackdropBrush(false);
_blurHost?.SetBlur(BlurEffect.Mica);
_blurHost?.SetBlur(_currentThemeVariant switch
{
PlatformThemeVariant.Light => BlurEffect.MicaLight,
PlatformThemeVariant.Dark => BlurEffect.MicaDark,
_ => throw new ArgumentOutOfRangeException()
});
}
private void SetAccentState(AccentState state)
@ -778,6 +784,7 @@ namespace Avalonia.Win32
public unsafe void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
{
_currentThemeVariant = themeVariant;
if (Win32Platform.WindowsVersion.Build >= 22000)
{
var pvUseBackdropBrush = themeVariant == PlatformThemeVariant.Dark ? 1 : 0;
@ -786,6 +793,10 @@ namespace Avalonia.Win32
(int)DwmWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE,
&pvUseBackdropBrush,
sizeof(int));
if (TransparencyLevel == WindowTransparencyLevel.Mica)
{
SetTransparencyMica(Win32Platform.WindowsVersion);
}
}
}

16
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_SelectedValue.cs

@ -268,6 +268,22 @@ namespace Avalonia.Controls.UnitTests.Primitives
Assert.True(called);
}
[Fact]
public void Handles_Null_SelectedItem_When_SelectedValueBinding_Assigned()
{
// Issue #11220
var items = new object[] { null };
var sic = new SelectingItemsControl
{
ItemsSource = items,
SelectedIndex = 0,
SelectedValueBinding = new Binding("Name"),
Template = Template()
};
Assert.Null(sic.SelectedValue);
}
private static FuncControlTemplate Template()
{
return new FuncControlTemplate<SelectingItemsControl>((control, scope) =>

Loading…
Cancel
Save