Browse Source

Merge branch 'master' into fixes/reduce-excessive-layout-passes

pull/8305/head
Dan Walmsley 4 years ago
committed by GitHub
parent
commit
e39be15f42
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1490
      Avalonia.sln
  2. 1
      build/CoreLibraries.props
  3. 1
      nukebuild/Build.cs
  4. 1
      src/Avalonia.Base/Avalonia.Base.csproj
  5. 5
      src/Avalonia.Base/Platform/AssetLoader.cs
  6. 2
      src/Avalonia.Base/Platform/Internal/AssemblyDescriptor.cs
  7. 6
      src/Avalonia.Base/Platform/Internal/AssemblyDescriptorResolver.cs
  8. 2
      src/Avalonia.Base/Platform/Internal/AssetDescriptor.cs
  9. 2
      src/Avalonia.Base/Platform/Internal/Constants.cs
  10. 58
      src/Avalonia.Base/Platform/Internal/DynLoader.cs
  11. 2
      src/Avalonia.Base/Platform/Internal/SlicedStream.cs
  12. 155
      src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs
  13. 5
      src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs
  14. 58
      src/Avalonia.Base/Platform/StandardRuntimePlatform.cs
  15. 15
      src/Avalonia.Base/Platform/StandardRuntimePlatformServices.cs
  16. 14
      src/Avalonia.Base/Properties/AssemblyInfo.cs
  17. 2
      src/Avalonia.Controls/AppBuilder.cs
  18. 36
      src/Avalonia.Controls/AppBuilderBase.cs
  19. 24
      src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj
  20. 218
      src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs
  21. 1
      src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj
  22. 1
      src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs
  23. 16
      tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs
  24. 1
      tests/Avalonia.Benchmarks/Styling/ResourceBenchmarks.cs
  25. 1
      tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs
  26. 2
      tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs
  27. 24
      tests/Avalonia.PlatformSupport.UnitTests/Avalonia.PlatformSupport.UnitTests.csproj
  28. 2
      tests/Avalonia.RenderTests/TestBase.cs
  29. 1
      tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj
  30. 1
      tests/Avalonia.UnitTests/TestServices.cs
  31. 1
      tests/Avalonia.UnitTests/UnitTestApplication.cs

1490
Avalonia.sln

File diff suppressed because it is too large

1
build/CoreLibraries.props

@ -8,6 +8,5 @@
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup/Avalonia.Markup.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.MicroCom/Avalonia.MicroCom.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj" />
</ItemGroup>
</Project>

1
nukebuild/Build.cs

@ -221,7 +221,6 @@ partial class Build : NukeBuild
RunCoreTest("Avalonia.Markup.Xaml.UnitTests");
RunCoreTest("Avalonia.Skia.UnitTests");
RunCoreTest("Avalonia.ReactiveUI.UnitTests");
RunCoreTest("Avalonia.PlatformSupport.UnitTests");
});
Target RunRenderTests => _ => _

1
src/Avalonia.Base/Avalonia.Base.csproj

@ -28,7 +28,6 @@
<InternalsVisibleTo Include="Avalonia.Direct2D1.RenderTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.LeakTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Markup.Xaml.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.PlatformSupport, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Skia.RenderTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Skia.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.UnitTests, PublicKey=$(AvaloniaPublicKey)" />

5
src/Avalonia.PlatformSupport/AssetLoader.cs → src/Avalonia.Base/Platform/AssetLoader.cs

@ -3,11 +3,10 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Avalonia.Platform;
using Avalonia.PlatformSupport.Internal;
using Avalonia.Platform.Internal;
using Avalonia.Utilities;
namespace Avalonia.PlatformSupport
namespace Avalonia.Platform
{
/// <summary>
/// Loads assets compiled into the application binary.

2
src/Avalonia.PlatformSupport/Internal/AssemblyDescriptor.cs → src/Avalonia.Base/Platform/Internal/AssemblyDescriptor.cs

@ -4,7 +4,7 @@ using System.Linq;
using System.Reflection;
using Avalonia.Utilities;
namespace Avalonia.PlatformSupport.Internal;
namespace Avalonia.Platform.Internal;
internal interface IAssemblyDescriptor
{

6
src/Avalonia.PlatformSupport/Internal/AssemblyDescriptorResolver.cs → src/Avalonia.Base/Platform/Internal/AssemblyDescriptorResolver.cs

@ -2,8 +2,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Avalonia.PlatformSupport.Internal;
namespace Avalonia.Platform.Internal;
internal interface IAssemblyDescriptorResolver
{
@ -29,9 +30,8 @@ internal class AssemblyDescriptorResolver: IAssemblyDescriptorResolver
}
else
{
// iOS does not support loading assemblies dynamically!
#if NET6_0_OR_GREATER
if (OperatingSystem.IsIOS())
if (!RuntimeFeature.IsDynamicCodeSupported)
{
throw new InvalidOperationException(
$"Assembly {name} needs to be referenced and explicitly loaded before loading resources");

2
src/Avalonia.PlatformSupport/Internal/AssetDescriptor.cs → src/Avalonia.Base/Platform/Internal/AssetDescriptor.cs

@ -2,7 +2,7 @@
using System.IO;
using System.Reflection;
namespace Avalonia.PlatformSupport.Internal;
namespace Avalonia.Platform.Internal;
internal interface IAssetDescriptor
{

2
src/Avalonia.PlatformSupport/Internal/Constants.cs → src/Avalonia.Base/Platform/Internal/Constants.cs

@ -1,4 +1,4 @@
namespace Avalonia.PlatformSupport.Internal;
namespace Avalonia.Platform.Internal;
internal static class Constants
{

58
src/Avalonia.PlatformSupport/DynLoader.cs → src/Avalonia.Base/Platform/Internal/DynLoader.cs

@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
using Avalonia.Platform.Interop;
// ReSharper disable InconsistentNaming
namespace Avalonia.PlatformSupport
namespace Avalonia.Platform.Internal
{
class UnixLoader : IDynamicLibraryLoader
{
@ -26,25 +26,6 @@ namespace Avalonia.PlatformSupport
}
}
static class AndroidImports
{
[DllImport("libdl.so")]
private static extern IntPtr dlopen(string path, int flags);
[DllImport("libdl.so")]
private static extern IntPtr dlsym(IntPtr handle, string symbol);
[DllImport("libdl.so")]
private static extern IntPtr dlerror();
public static void Init()
{
DlOpen = dlopen;
DlSym = dlsym;
DlError = dlerror;
}
}
static class OsXImports
{
[DllImport("/usr/lib/libSystem.dylib")]
@ -77,10 +58,6 @@ namespace Avalonia.PlatformSupport
Marshal.FreeHGlobal(buffer);
if (unixName == "Darwin")
OsXImports.Init();
#if NET6_0_OR_GREATER
else if (OperatingSystem.IsAndroid())
AndroidImports.Init();
#endif
else
LinuxImports.Init();
}
@ -135,6 +112,39 @@ namespace Avalonia.PlatformSupport
return ptr;
}
}
#if NET6_0_OR_GREATER
internal class Net6Loader : IDynamicLibraryLoader
{
public IntPtr LoadLibrary(string dll)
{
try
{
return NativeLibrary.Load(dll);
}
catch (Exception ex)
{
throw new DynamicLibraryLoaderException("Error loading " + dll, ex);
}
}
public IntPtr GetProcAddress(IntPtr dll, string proc, bool optional)
{
try
{
if (optional)
{
return NativeLibrary.TryGetExport(dll, proc, out var address) ? address : default;
}
return NativeLibrary.GetExport(dll, proc);
}
catch (Exception ex)
{
throw new DynamicLibraryLoaderException("Error " + dll, ex);
}
}
}
#endif
internal class NotSupportedLoader : IDynamicLibraryLoader
{

2
src/Avalonia.PlatformSupport/Internal/SlicedStream.cs → src/Avalonia.Base/Platform/Internal/SlicedStream.cs

@ -1,7 +1,7 @@
using System;
using System.IO;
namespace Avalonia.PlatformSupport.Internal;
namespace Avalonia.Platform.Internal;
internal class SlicedStream : Stream
{

155
src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs

@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
namespace Avalonia.Platform.Internal;
internal class UnmanagedBlob : IUnmanagedBlob
{
private IntPtr _address;
private readonly object _lock = new object();
#if DEBUG
private static readonly List<string> Backtraces = new List<string>();
private static Thread? GCThread;
private readonly string _backtrace;
private static readonly object _btlock = new object();
class GCThreadDetector
{
~GCThreadDetector()
{
GCThread = Thread.CurrentThread;
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void Spawn() => new GCThreadDetector();
static UnmanagedBlob()
{
Spawn();
GC.WaitForPendingFinalizers();
}
#endif
public UnmanagedBlob(int size)
{
try
{
if (size <= 0)
throw new ArgumentException("Positive number required", nameof(size));
_address = Alloc(size);
GC.AddMemoryPressure(size);
Size = size;
}
catch
{
GC.SuppressFinalize(this);
throw;
}
#if DEBUG
_backtrace = Environment.StackTrace;
lock (_btlock)
Backtraces.Add(_backtrace);
#endif
}
void DoDispose()
{
lock (_lock)
{
if (!IsDisposed)
{
#if DEBUG
lock (_btlock)
Backtraces.Remove(_backtrace);
#endif
Free(_address, Size);
GC.RemoveMemoryPressure(Size);
IsDisposed = true;
_address = IntPtr.Zero;
Size = 0;
}
}
}
public void Dispose()
{
#if DEBUG
if (Thread.CurrentThread.ManagedThreadId == GCThread?.ManagedThreadId)
{
lock (_lock)
{
if (!IsDisposed)
{
Console.Error.WriteLine("Native blob disposal from finalizer thread\nBacktrace: "
+ Environment.StackTrace
+ "\n\nBlob created by " + _backtrace);
}
}
}
#endif
DoDispose();
GC.SuppressFinalize(this);
}
~UnmanagedBlob()
{
#if DEBUG
Console.Error.WriteLine("Undisposed native blob created by " + _backtrace);
#endif
DoDispose();
}
public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address;
public int Size { get; private set; }
public bool IsDisposed { get; private set; }
[DllImport("libc", SetLastError = true)]
private static extern IntPtr mmap(IntPtr addr, IntPtr length, int prot, int flags, int fd, IntPtr offset);
[DllImport("libc", SetLastError = true)]
private static extern int munmap(IntPtr addr, IntPtr length);
[DllImport("libc", SetLastError = true)]
private static extern long sysconf(int name);
private bool? _useMmap;
private bool UseMmap
=> _useMmap ?? ((_useMmap = RuntimeInformation.IsOSPlatform(OSPlatform.Linux)).Value);
// Could be replaced with https://github.com/dotnet/runtime/issues/40892 when it will be available.
private IntPtr Alloc(int size)
{
if (!UseMmap)
{
return Marshal.AllocHGlobal(size);
}
else
{
var rv = mmap(IntPtr.Zero, new IntPtr(size), 3, 0x22, -1, IntPtr.Zero);
if (rv.ToInt64() == -1 || (ulong)rv.ToInt64() == 0xffffffff)
{
var errno = Marshal.GetLastWin32Error();
throw new Exception("Unable to allocate memory: " + errno);
}
return rv;
}
}
private void Free(IntPtr ptr, int len)
{
if (!UseMmap)
{
Marshal.FreeHGlobal(ptr);
}
else
{
if (munmap(ptr, new IntPtr(len)) == -1)
{
var errno = Marshal.GetLastWin32Error();
throw new Exception("Unable to free memory: " + errno);
}
}
}
}

5
src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs

@ -16,5 +16,10 @@ namespace Avalonia.Platform.Interop
{
}
public DynamicLibraryLoaderException(string message, Exception innerException) : base(message, innerException)
{
}
}
}

58
src/Avalonia.Base/Platform/StandardRuntimePlatform.cs

@ -0,0 +1,58 @@
using System;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia.Platform.Internal;
namespace Avalonia.Platform
{
public class StandardRuntimePlatform : IRuntimePlatform
{
public IDisposable StartSystemTimer(TimeSpan interval, Action tick)
{
return new Timer(_ => tick(), null, interval, interval);
}
public IUnmanagedBlob AllocBlob(int size) => new UnmanagedBlob(size);
private static readonly Lazy<RuntimePlatformInfo> Info = new(() =>
{
OperatingSystemType os;
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
os = OperatingSystemType.OSX;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
os = OperatingSystemType.Linux;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
os = OperatingSystemType.WinNT;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("Android")))
os = OperatingSystemType.Android;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("iOS")))
os = OperatingSystemType.iOS;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("Browser")))
os = OperatingSystemType.Browser;
else
throw new Exception("Unknown OS platform " + RuntimeInformation.OSDescription);
// Source: https://github.com/dotnet/runtime/blob/main/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
var isCoreClr = Environment.Version.Major >= 5 || RuntimeInformation.FrameworkDescription.StartsWith(".NET Core", StringComparison.OrdinalIgnoreCase);
var isMonoRuntime = Type.GetType("Mono.Runtime") != null;
var isFramework = !isCoreClr && RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework", StringComparison.OrdinalIgnoreCase);
return new RuntimePlatformInfo
{
IsCoreClr = isCoreClr,
IsDotNetFramework = isFramework,
IsMono = isMonoRuntime,
IsDesktop = os is OperatingSystemType.Linux or OperatingSystemType.OSX or OperatingSystemType.WinNT,
IsMobile = os is OperatingSystemType.Android or OperatingSystemType.iOS,
IsUnix = os is OperatingSystemType.Linux or OperatingSystemType.OSX or OperatingSystemType.Android,
IsBrowser = os == OperatingSystemType.Browser,
OperatingSystem = os,
};
});
public virtual RuntimePlatformInfo GetRuntimeInfo() => Info.Value;
}
}

15
src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs → src/Avalonia.Base/Platform/StandardRuntimePlatformServices.cs

@ -1,30 +1,33 @@
using System.Reflection;
using Avalonia.Platform;
using Avalonia.Platform.Internal;
using Avalonia.Platform.Interop;
namespace Avalonia.PlatformSupport
namespace Avalonia.Platform
{
public static class StandardRuntimePlatformServices
{
public static void Register(Assembly? assembly = null)
{
var standardPlatform = new StandardRuntimePlatform();
var os = standardPlatform.GetRuntimeInfo().OperatingSystem;
AssetLoader.RegisterResUriParsers();
AvaloniaLocator.CurrentMutable
.Bind<IRuntimePlatform>().ToConstant(standardPlatform)
.Bind<IAssetLoader>().ToConstant(new AssetLoader(assembly))
.Bind<IDynamicLibraryLoader>().ToConstant(
os switch
#if NET6_0_OR_GREATER
new Net6Loader()
#else
standardPlatform.GetRuntimeInfo().OperatingSystem switch
{
OperatingSystemType.WinNT => new Win32Loader(),
OperatingSystemType.WinNT => (IDynamicLibraryLoader)new Win32Loader(),
OperatingSystemType.OSX => new UnixLoader(),
OperatingSystemType.Linux => new UnixLoader(),
OperatingSystemType.Android => new UnixLoader(),
// iOS, WASM, ...
_ => (IDynamicLibraryLoader)new NotSupportedLoader()
_ => new NotSupportedLoader()
}
#endif
);
}
}

14
src/Avalonia.Base/Properties/AssemblyInfo.cs

@ -17,3 +17,17 @@ using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media.Transformation")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Styling")]
[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Controls, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Controls.ColorPicker, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Controls.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.LeakTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Skia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Web.Blazor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

2
src/Avalonia.PlatformSupport/AppBuilder.cs → src/Avalonia.Controls/AppBuilder.cs

@ -1,5 +1,5 @@
using Avalonia.Controls;
using Avalonia.PlatformSupport;
using Avalonia.Platform;
namespace Avalonia
{

36
src/Avalonia.Controls/AppBuilderBase.cs

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using Avalonia.Controls.ApplicationLifetimes;
@ -120,38 +119,8 @@ namespace Avalonia.Controls
return Self;
}
/// <summary>
/// Starts the application with an instance of <typeparamref name="TMainWindow"/>.
/// </summary>
/// <typeparam name="TMainWindow">The window type.</typeparam>
/// <param name="dataContextProvider">A delegate that will be called to create a data context for the window (optional).</param>
[Obsolete("Use either lifetimes or AppMain overload. See see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details")]
public void Start<TMainWindow>(Func<object>? dataContextProvider = null)
where TMainWindow : Window, new()
{
AfterSetup(builder =>
{
var window = new TMainWindow();
if (dataContextProvider != null)
window.DataContext = dataContextProvider();
((IClassicDesktopStyleApplicationLifetime)builder.Instance!.ApplicationLifetime!)
.MainWindow = window;
});
// Copy-pasted because we can't call extension methods due to generic constraints
var lifetime = new ClassicDesktopStyleApplicationLifetime() {ShutdownMode = ShutdownMode.OnMainWindowClose};
SetupWithLifetime(lifetime);
lifetime.Start(Array.Empty<string>());
}
public delegate void AppMainDelegate(Application app, string[] args);
[Obsolete("Use either lifetimes or AppMain overload. See see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details", true)]
public void Start()
{
throw new NotSupportedException();
}
public void Start(AppMainDelegate main, string[] args)
{
Setup();
@ -234,6 +203,9 @@ namespace Avalonia.Controls
protected virtual bool CheckSetup => true;
/// <summary>
/// Searches and initiates modules included with <see cref="ExportAvaloniaModuleAttribute"/> attribute.
/// </summary>
private void SetupAvaloniaModules()
{
var moduleInitializers = from assembly in AppDomain.CurrentDomain.GetAssemblies()

24
src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj

@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net461;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Avalonia.Base/Avalonia.Base.csproj" />
<ProjectReference Include="../Avalonia.Controls/Avalonia.Controls.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" Condition="'$(TargetFramework)' == 'net461'" />
</ItemGroup>
<Import Project="..\..\build\NetCore.props" />
<Import Project="..\..\build\NetFX.props" />
<Import Project="..\..\build\NullableEnable.props" />
<ItemGroup>
<InternalsVisibleTo Include="$(AssemblyName).UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7" />
</ItemGroup>
</Project>

218
src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs

@ -1,218 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia.Platform;
namespace Avalonia.PlatformSupport
{
public class StandardRuntimePlatform : IRuntimePlatform
{
public IDisposable StartSystemTimer(TimeSpan interval, Action tick)
{
return new Timer(_ => tick(), null, interval, interval);
}
public IUnmanagedBlob AllocBlob(int size) => new UnmanagedBlob(this, size);
private class UnmanagedBlob : IUnmanagedBlob
{
private readonly StandardRuntimePlatform _plat;
private IntPtr _address;
private readonly object _lock = new object();
#if DEBUG
private static readonly List<string> Backtraces = new List<string>();
private static Thread? GCThread;
private readonly string _backtrace;
private static readonly object _btlock = new object();
class GCThreadDetector
{
~GCThreadDetector()
{
GCThread = Thread.CurrentThread;
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void Spawn() => new GCThreadDetector();
static UnmanagedBlob()
{
Spawn();
GC.WaitForPendingFinalizers();
}
#endif
public UnmanagedBlob(StandardRuntimePlatform plat, int size)
{
try
{
if (size <= 0)
throw new ArgumentException("Positive number required", nameof(size));
_plat = plat;
_address = plat.Alloc(size);
GC.AddMemoryPressure(size);
Size = size;
}
catch
{
GC.SuppressFinalize(this);
throw;
}
#if DEBUG
_backtrace = Environment.StackTrace;
lock (_btlock)
Backtraces.Add(_backtrace);
#endif
}
void DoDispose()
{
lock (_lock)
{
if (!IsDisposed)
{
#if DEBUG
lock (_btlock)
Backtraces.Remove(_backtrace);
#endif
_plat?.Free(_address, Size);
GC.RemoveMemoryPressure(Size);
IsDisposed = true;
_address = IntPtr.Zero;
Size = 0;
}
}
}
public void Dispose()
{
#if DEBUG
if (Thread.CurrentThread.ManagedThreadId == GCThread?.ManagedThreadId)
{
lock (_lock)
{
if (!IsDisposed)
{
Console.Error.WriteLine("Native blob disposal from finalizer thread\nBacktrace: "
+ Environment.StackTrace
+ "\n\nBlob created by " + _backtrace);
}
}
}
#endif
DoDispose();
GC.SuppressFinalize(this);
}
~UnmanagedBlob()
{
#if DEBUG
Console.Error.WriteLine("Undisposed native blob created by " + _backtrace);
#endif
DoDispose();
}
public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address;
public int Size { get; private set; }
public bool IsDisposed { get; private set; }
}
#if NET461 || NETCOREAPP2_0_OR_GREATER
[DllImport("libc", SetLastError = true)]
private static extern IntPtr mmap(IntPtr addr, IntPtr length, int prot, int flags, int fd, IntPtr offset);
[DllImport("libc", SetLastError = true)]
private static extern int munmap(IntPtr addr, IntPtr length);
[DllImport("libc", SetLastError = true)]
private static extern long sysconf(int name);
private bool? _useMmap;
private bool UseMmap
=> _useMmap ?? ((_useMmap = GetRuntimeInfo().OperatingSystem == OperatingSystemType.Linux)).Value;
IntPtr Alloc(int size)
{
if (UseMmap)
{
var rv = mmap(IntPtr.Zero, new IntPtr(size), 3, 0x22, -1, IntPtr.Zero);
if (rv.ToInt64() == -1 || (ulong)rv.ToInt64() == 0xffffffff)
{
var errno = Marshal.GetLastWin32Error();
throw new Exception("Unable to allocate memory: " + errno);
}
return rv;
}
else
return Marshal.AllocHGlobal(size);
}
void Free(IntPtr ptr, int len)
{
if (UseMmap)
{
if (munmap(ptr, new IntPtr(len)) == -1)
{
var errno = Marshal.GetLastWin32Error();
throw new Exception("Unable to free memory: " + errno);
}
}
else
Marshal.FreeHGlobal(ptr);
}
#else
IntPtr Alloc(int size) => Marshal.AllocHGlobal(size);
void Free(IntPtr ptr, int len) => Marshal.FreeHGlobal(ptr);
#endif
private static readonly Lazy<RuntimePlatformInfo> Info = new Lazy<RuntimePlatformInfo>(() =>
{
OperatingSystemType os;
#if NET5_0_OR_GREATER
if (OperatingSystem.IsWindows())
os = OperatingSystemType.WinNT;
else if (OperatingSystem.IsMacOS())
os = OperatingSystemType.OSX;
else if (OperatingSystem.IsLinux() || OperatingSystem.IsFreeBSD())
os = OperatingSystemType.Linux;
else if (OperatingSystem.IsAndroid())
os = OperatingSystemType.Android;
else if (OperatingSystem.IsIOS())
os = OperatingSystemType.iOS;
else if (OperatingSystem.IsBrowser())
os = OperatingSystemType.Browser;
else
throw new Exception("Unknown OS platform " + RuntimeInformation.OSDescription);
#else
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
os = OperatingSystemType.OSX;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
os = OperatingSystemType.Linux;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
os = OperatingSystemType.WinNT;
else
throw new Exception("Unknown OS platform " + RuntimeInformation.OSDescription);
#endif
return new RuntimePlatformInfo
{
#if NETCOREAPP
IsCoreClr = true,
#elif NETFRAMEWORK
IsDotNetFramework = true,
#endif
IsDesktop = os == OperatingSystemType.Linux || os == OperatingSystemType.OSX || os == OperatingSystemType.WinNT,
IsMono = os == OperatingSystemType.Android || os == OperatingSystemType.iOS || os == OperatingSystemType.Browser,
IsMobile = os == OperatingSystemType.Android || os == OperatingSystemType.iOS,
IsUnix = os == OperatingSystemType.Linux || os == OperatingSystemType.OSX || os == OperatingSystemType.Android,
IsBrowser = os == OperatingSystemType.Browser,
OperatingSystem = os,
};
});
public virtual RuntimePlatformInfo GetRuntimeInfo() => Info.Value;
}
}

1
src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj

@ -51,7 +51,6 @@
<ItemGroup>
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\..\Avalonia.PlatformSupport\Avalonia.PlatformSupport.csproj" />
<ProjectReference Include="..\..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
</ItemGroup>
</Project>

1
src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs

@ -1,6 +1,5 @@
using Avalonia.Controls;
using Avalonia.Platform;
using Avalonia.PlatformSupport;
namespace Avalonia.Web.Blazor
{

16
tests/Avalonia.PlatformSupport.UnitTests/AssetLoaderTests.cs → tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs

@ -1,12 +1,13 @@
using System;
using System.Reflection;
using Avalonia.PlatformSupport.Internal;
using Avalonia.Platform;
using Avalonia.Platform.Internal;
using Moq;
using Xunit;
namespace Avalonia.PlatformSupport.UnitTests;
namespace Avalonia.Base.UnitTests;
public class AssetLoaderTests
public class AssetLoaderTests : IDisposable
{
public class MockAssembly : Assembly {}
@ -14,7 +15,7 @@ public class AssetLoaderTests
private const string AssemblyNameWithNonAscii = "Какое-то-название";
static AssetLoaderTests()
public AssetLoaderTests()
{
var resolver = Mock.Of<IAssemblyDescriptorResolver>();
@ -38,7 +39,7 @@ public class AssetLoaderTests
Assert.Equal(AssemblyNameWithWhitespace, assemblyActual?.FullName);
}
[Fact]
[Fact(Skip = "RegisterResUriParsers breaks this test. See https://github.com/AvaloniaUI/Avalonia/issues/2555.")]
public void AssemblyName_With_Non_ASCII_Should_Load_Avares()
{
var uri = new Uri($"avares://{AssemblyNameWithNonAscii}/Assets/something");
@ -59,4 +60,9 @@ public class AssetLoaderTests
Mock.Get(descriptor).Setup(x => x.Assembly).Returns(assembly);
return descriptor;
}
public void Dispose()
{
AssetLoader.SetAssemblyDescriptorResolver(new AssemblyDescriptorResolver());
}
}

1
tests/Avalonia.Benchmarks/Styling/ResourceBenchmarks.cs

@ -1,7 +1,6 @@
using System;
using Avalonia.Controls;
using Avalonia.Platform;
using Avalonia.PlatformSupport;
using Avalonia.Styling;
using Avalonia.UnitTests;
using BenchmarkDotNet.Attributes;

1
tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs

@ -1,7 +1,6 @@
using System;
using Avalonia.Controls;
using Avalonia.Platform;
using Avalonia.PlatformSupport;
using Avalonia.Styling;
using Avalonia.UnitTests;
using BenchmarkDotNet.Attributes;

2
tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs

@ -2,7 +2,7 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.PlatformSupport;
using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.UnitTests;

24
tests/Avalonia.PlatformSupport.UnitTests/Avalonia.PlatformSupport.UnitTests.csproj

@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<OutputType>Library</OutputType>
<IsTestProject>true</IsTestProject>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<Import Project="..\..\build\UnitTests.NetCore.targets" />
<Import Project="..\..\build\UnitTests.NetFX.props" />
<Import Project="..\..\build\Moq.props" />
<Import Project="..\..\build\XUnit.props" />
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\Microsoft.Reactive.Testing.props" />
<Import Project="..\..\build\SharedVersion.props" />
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml.Loader\Avalonia.Markup.Xaml.Loader.csproj" />
<ProjectReference Include="..\Avalonia.UnitTests\Avalonia.UnitTests.csproj" />
</ItemGroup>
</Project>

2
tests/Avalonia.RenderTests/TestBase.cs

@ -25,8 +25,6 @@ namespace Avalonia.Skia.RenderTests
namespace Avalonia.Direct2D1.RenderTests
#endif
{
using Avalonia.PlatformSupport;
public class TestBase
{
#if AVALONIA_SKIA

1
tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj

@ -14,7 +14,6 @@
<EmbeddedResource Include="..\Avalonia.UnitTests\Assets\*.ttf" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.PlatformSupport\Avalonia.PlatformSupport.csproj" />
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />

1
tests/Avalonia.UnitTests/TestServices.cs

@ -5,7 +5,6 @@ using Avalonia.Layout;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.PlatformSupport;
using Avalonia.Styling;
using Avalonia.Themes.Default;
using Avalonia.Rendering;

1
tests/Avalonia.UnitTests/UnitTestApplication.cs

@ -10,7 +10,6 @@ using System.Reactive.Disposables;
using System.Reactive.Concurrency;
using Avalonia.Input.Platform;
using Avalonia.Animation;
using Avalonia.PlatformSupport;
namespace Avalonia.UnitTests
{

Loading…
Cancel
Save