From 4d866b544cc41ed882e31dc23868ddb450cf4b61 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Fri, 28 Jan 2022 20:51:04 -0500 Subject: [PATCH] Replace shared project with Avalonia.PlatformSupport --- Avalonia.sln | 41 +- .../Avalonia.Android/AndroidPlatform.cs | 5 +- src/Android/Avalonia.Android/AppBuilder.cs | 2 +- .../Avalonia.Android/Avalonia.Android.csproj | 4 +- src/Android/Avalonia.Android/RuntimeInfo.cs | 18 - .../Platform/IRuntimePlatform.cs | 5 +- .../ApiCompatBaseline.txt | 3 + src/Avalonia.DesktopRuntime/AppBuilder.cs | 2 +- .../Avalonia.DesktopRuntime.csproj | 2 +- src/Avalonia.DesktopRuntime/RuntimeInfo.cs | 40 -- .../AssetLoader.cs | 17 +- .../Avalonia.PlatformSupport.csproj | 18 + .../DynLoader.cs | 65 +- .../StandardRuntimePlatform.cs | 79 ++- .../StandardRuntimePlatformServices.cs | 31 + .../PlatformSupport/PlatformSupport.projitems | 17 - .../PlatformSupport/PlatformSupport.shproj | 11 - .../StandardRuntimePlatformServices.cs | 28 - src/Shared/RenderHelpers/QuadBezierHelper.cs | 13 - .../RenderHelpers/RenderHelpers.projitems | 14 - src/Shared/RenderHelpers/RenderHelpers.shproj | 13 - src/Shared/WindowResizeDragHelper.cs | 84 --- src/Skia/Avalonia.Skia/Avalonia.Skia.csproj | 3 +- .../Avalonia.Web.Blazor.csproj | 3 +- .../AvaloniaBlazorAppBuilder.cs | 5 +- .../BlazorRuntimePlatform.cs | 61 -- .../Avalonia.Direct2D1.csproj | 1 - src/iOS/Avalonia.iOS/Avalonia.iOS.csproj | 11 +- .../Avalonia.iOS/Boilerplate/AppBuilder.cs | 5 +- .../Boilerplate/RuntimePlatform.cs | 19 - src/iOS/Avalonia.iOS/Boilerplate/Shared.cs | 595 ------------------ .../Themes/FluentBenchmark.cs | 4 +- .../Themes/ThemeBenchmark.cs | 2 +- tests/Avalonia.RenderTests/TestBase.cs | 2 +- .../Avalonia.UnitTests.csproj | 2 +- tests/Avalonia.UnitTests/RuntimeInfo.cs | 16 - tests/Avalonia.UnitTests/TestServices.cs | 2 +- .../Avalonia.UnitTests/UnitTestApplication.cs | 2 +- 38 files changed, 212 insertions(+), 1033 deletions(-) delete mode 100644 src/Android/Avalonia.Android/RuntimeInfo.cs create mode 100644 src/Avalonia.DesktopRuntime/ApiCompatBaseline.txt delete mode 100644 src/Avalonia.DesktopRuntime/RuntimeInfo.cs rename src/{Shared/PlatformSupport => Avalonia.PlatformSupport}/AssetLoader.cs (97%) create mode 100644 src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj rename src/{Shared/PlatformSupport => Avalonia.PlatformSupport}/DynLoader.cs (77%) rename src/{Shared/PlatformSupport => Avalonia.PlatformSupport}/StandardRuntimePlatform.cs (66%) create mode 100644 src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs delete mode 100644 src/Shared/PlatformSupport/PlatformSupport.projitems delete mode 100644 src/Shared/PlatformSupport/PlatformSupport.shproj delete mode 100644 src/Shared/PlatformSupport/StandardRuntimePlatformServices.cs delete mode 100644 src/Shared/RenderHelpers/QuadBezierHelper.cs delete mode 100644 src/Shared/RenderHelpers/RenderHelpers.projitems delete mode 100644 src/Shared/RenderHelpers/RenderHelpers.shproj delete mode 100644 src/Shared/WindowResizeDragHelper.cs delete mode 100644 src/Web/Avalonia.Web.Blazor/BlazorRuntimePlatform.cs delete mode 100644 src/iOS/Avalonia.iOS/Boilerplate/RuntimePlatform.cs delete mode 100644 src/iOS/Avalonia.iOS/Boilerplate/Shared.cs delete mode 100644 tests/Avalonia.UnitTests/RuntimeInfo.cs diff --git a/Avalonia.sln b/Avalonia.sln index 4e7b4cc318..0354e20d4f 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -60,20 +60,17 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DEF5-D50F-4975-8B72-124C9EB54066}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + src\Shared\ModuleInitializer.cs = src\Shared\ModuleInitializer.cs EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI", "src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PlatformSupport", "src\Shared\PlatformSupport\PlatformSupport.shproj", "{E4D9629C-F168-4224-3F51-A5E482FFBC42}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup", "src\Markup\Avalonia.Markup\Avalonia.Markup.csproj", "{6417E941-21BC-467B-A771-0DE389353CE6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.UnitTests", "tests\Avalonia.Markup.UnitTests\Avalonia.Markup.UnitTests.csproj", "{8EF392D5-1416-45AA-9956-7CBBC3229E8A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BindingDemo", "samples\BindingDemo\BindingDemo.csproj", "{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RenderHelpers", "src\Shared\RenderHelpers\RenderHelpers.shproj", "{3C4C0CB4-0C0F-4450-A37B-148C84FF905F}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Skia", "Skia", "{3743B0F2-CC41-4F14-A8C8-267F579BF91E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Android", "Android", "{7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}" @@ -235,15 +232,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsInteropTest", "sampl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlSamples", "samples\SampleControls\ControlSamples.csproj", "{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.PlatformSupport", "src\Avalonia.PlatformSupport\Avalonia.PlatformSupport.csproj", "{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}" +EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13 - src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 5 - src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 5 - src\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 5 - src\Shared\PlatformSupport\PlatformSupport.projitems*{88060192-33d5-4932-b0f9-8bd2763e857d}*SharedItemsImports = 5 - src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU Ad-Hoc|iPhone = Ad-Hoc|iPhone @@ -2169,6 +2160,30 @@ Global {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhone.Build.0 = Release|Any CPU {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhone.Build.0 = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhone.Build.0 = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|Any CPU.Build.0 = Release|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhone.ActiveCfg = Release|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhone.Build.0 = Release|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2187,11 +2202,9 @@ Global {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {99135EAB-653D-47E4-A378-C96E1278CA44} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {3E53A01A-B331-47F3-B828-4A5717E77A24} = {8B6A8209-894F-4BA1-B880-965FD453982C} - {E4D9629C-F168-4224-3F51-A5E482FFBC42} = {A689DEF5-D50F-4975-8B72-124C9EB54066} {6417E941-21BC-467B-A771-0DE389353CE6} = {8B6A8209-894F-4BA1-B880-965FD453982C} {8EF392D5-1416-45AA-9956-7CBBC3229E8A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {3C4C0CB4-0C0F-4450-A37B-148C84FF905F} = {A689DEF5-D50F-4975-8B72-124C9EB54066} {7B92AF71-6287-4693-9DCB-BD5B6E927E23} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F} {FF69B927-C545-49AE-8E16-3D14D621AA12} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F} {4488AD85-1495-4809-9AA4-DDFE0A48527E} = {0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1} diff --git a/src/Android/Avalonia.Android/AndroidPlatform.cs b/src/Android/Avalonia.Android/AndroidPlatform.cs index 6a940a54f1..2d4f6a305f 100644 --- a/src/Android/Avalonia.Android/AndroidPlatform.cs +++ b/src/Android/Avalonia.Android/AndroidPlatform.cs @@ -10,7 +10,7 @@ using Avalonia.Input.Platform; using Avalonia.OpenGL.Egl; using Avalonia.Platform; using Avalonia.Rendering; -using Avalonia.Shared.PlatformSupport; +using Avalonia.PlatformSupport; using Avalonia.Skia; namespace Avalonia @@ -59,8 +59,7 @@ namespace Avalonia.Android .Bind().ToSingleton() .Bind().ToConstant(new ChoreographerTimer()) .Bind().ToConstant(new RenderLoop()) - .Bind().ToSingleton() - .Bind().ToConstant(new AssetLoader(appType.Assembly)); + .Bind().ToSingleton(); SkiaPlatform.Initialize(); diff --git a/src/Android/Avalonia.Android/AppBuilder.cs b/src/Android/Avalonia.Android/AppBuilder.cs index 805bb61655..04f1ff00d0 100644 --- a/src/Android/Avalonia.Android/AppBuilder.cs +++ b/src/Android/Avalonia.Android/AppBuilder.cs @@ -1,5 +1,5 @@ using Avalonia.Controls; -using Avalonia.Shared.PlatformSupport; +using Avalonia.PlatformSupport; namespace Avalonia { diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj index 8c6775733f..5c33dbcea6 100644 --- a/src/Android/Avalonia.Android/Avalonia.Android.csproj +++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj @@ -5,9 +5,11 @@ + + TargetFramework=netstandard2.0 + - diff --git a/src/Android/Avalonia.Android/RuntimeInfo.cs b/src/Android/Avalonia.Android/RuntimeInfo.cs deleted file mode 100644 index bb2466c357..0000000000 --- a/src/Android/Avalonia.Android/RuntimeInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Avalonia.Platform; - -namespace Avalonia.Shared.PlatformSupport -{ - internal partial class StandardRuntimePlatform - { - public RuntimePlatformInfo GetRuntimeInfo() => new RuntimePlatformInfo - { - IsCoreClr = false, - IsDesktop = false, - IsMobile = true, - IsDotNetFramework = false, - IsMono = true, - IsUnix = true, - OperatingSystem = OperatingSystemType.Android - }; - } -} \ No newline at end of file diff --git a/src/Avalonia.Base/Platform/IRuntimePlatform.cs b/src/Avalonia.Base/Platform/IRuntimePlatform.cs index a0d5d611b3..850757a1ee 100644 --- a/src/Avalonia.Base/Platform/IRuntimePlatform.cs +++ b/src/Avalonia.Base/Platform/IRuntimePlatform.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; namespace Avalonia.Platform { @@ -23,6 +22,7 @@ namespace Avalonia.Platform public OperatingSystemType OperatingSystem { get; set; } public bool IsDesktop { get; set; } public bool IsMobile { get; set; } + public bool IsBrowser { get; set; } public bool IsCoreClr { get; set; } public bool IsMono { get; set; } public bool IsDotNetFramework { get; set; } @@ -36,6 +36,7 @@ namespace Avalonia.Platform Linux, OSX, Android, - iOS + iOS, + Browser } } diff --git a/src/Avalonia.DesktopRuntime/ApiCompatBaseline.txt b/src/Avalonia.DesktopRuntime/ApiCompatBaseline.txt new file mode 100644 index 0000000000..0493db9ab3 --- /dev/null +++ b/src/Avalonia.DesktopRuntime/ApiCompatBaseline.txt @@ -0,0 +1,3 @@ +Compat issues with assembly Avalonia.DesktopRuntime: +TypesMustExist : Type 'Avalonia.Shared.PlatformSupport.AssetLoader' does not exist in the implementation but it does exist in the contract. +Total Issues: 1 diff --git a/src/Avalonia.DesktopRuntime/AppBuilder.cs b/src/Avalonia.DesktopRuntime/AppBuilder.cs index ff0d84a6e9..2946324c83 100644 --- a/src/Avalonia.DesktopRuntime/AppBuilder.cs +++ b/src/Avalonia.DesktopRuntime/AppBuilder.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Reflection; using Avalonia.Controls; using Avalonia.Platform; -using Avalonia.Shared.PlatformSupport; +using Avalonia.PlatformSupport; namespace Avalonia { diff --git a/src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj b/src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj index f2a0faeb22..25effae46e 100644 --- a/src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj +++ b/src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj @@ -8,6 +8,7 @@ + @@ -16,6 +17,5 @@ - diff --git a/src/Avalonia.DesktopRuntime/RuntimeInfo.cs b/src/Avalonia.DesktopRuntime/RuntimeInfo.cs deleted file mode 100644 index 82eaadb895..0000000000 --- a/src/Avalonia.DesktopRuntime/RuntimeInfo.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using Avalonia.Platform; - - -namespace Avalonia.Shared.PlatformSupport -{ - internal partial class StandardRuntimePlatform - { - private static readonly Lazy Info = new Lazy(() => - { - 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 - throw new Exception("Unknown OS platform " + RuntimeInformation.OSDescription); - - return new RuntimePlatformInfo - { -#if NETCOREAPP2_0 - IsCoreClr = true, -#elif NET461 - IsDotNetFramework = false, -#endif - IsDesktop = true, - IsMono = false, - IsMobile = false, - IsUnix = os != OperatingSystemType.WinNT, - OperatingSystem = os, - }; - }); - - - public RuntimePlatformInfo GetRuntimeInfo() => Info.Value; - } -} diff --git a/src/Shared/PlatformSupport/AssetLoader.cs b/src/Avalonia.PlatformSupport/AssetLoader.cs similarity index 97% rename from src/Shared/PlatformSupport/AssetLoader.cs rename to src/Avalonia.PlatformSupport/AssetLoader.cs index 43f9211889..7220694d7b 100644 --- a/src/Shared/PlatformSupport/AssetLoader.cs +++ b/src/Avalonia.PlatformSupport/AssetLoader.cs @@ -6,9 +6,7 @@ using System.Reflection; using Avalonia.Platform; using Avalonia.Utilities; -#nullable enable - -namespace Avalonia.Shared.PlatformSupport +namespace Avalonia.PlatformSupport { /// /// Loads assets compiled into the application binary. @@ -233,14 +231,15 @@ namespace Avalonia.Shared.PlatformSupport else { // iOS does not support loading assemblies dynamically! - // -#if __IOS__ - throw new InvalidOperationException( - $"Assembly {name} needs to be referenced and explicitly loaded before loading resources"); -#else +#if NET6_0_OR_GREATER + if (OperatingSystem.IsIOS()) + { + throw new InvalidOperationException( + $"Assembly {name} needs to be referenced and explicitly loaded before loading resources"); + } +#endif name = Uri.UnescapeDataString(name); AssemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(name)); -#endif } } diff --git a/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj b/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj new file mode 100644 index 0000000000..be73d87e2c --- /dev/null +++ b/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj @@ -0,0 +1,18 @@ + + + + net6.0;net461;netstandard2.0 + + + + + + + + + + + + + + diff --git a/src/Shared/PlatformSupport/DynLoader.cs b/src/Avalonia.PlatformSupport/DynLoader.cs similarity index 77% rename from src/Shared/PlatformSupport/DynLoader.cs rename to src/Avalonia.PlatformSupport/DynLoader.cs index 8fd4b1ad1e..ad76ac4724 100644 --- a/src/Shared/PlatformSupport/DynLoader.cs +++ b/src/Avalonia.PlatformSupport/DynLoader.cs @@ -1,35 +1,40 @@ using System; using System.Runtime.InteropServices; -using Avalonia.Platform; using Avalonia.Platform.Interop; -namespace Avalonia.Shared.PlatformSupport +// ReSharper disable InconsistentNaming +namespace Avalonia.PlatformSupport { -#if !__IOS__ class UnixLoader : IDynamicLibraryLoader { - // ReSharper disable InconsistentNaming static class LinuxImports { -#if __ANDROID__ - [DllImport("libdl.so")] -#else [DllImport("libdl.so.2")] -#endif private static extern IntPtr dlopen(string path, int flags); -#if __ANDROID__ - [DllImport("libdl.so")] -#else [DllImport("libdl.so.2")] -#endif private static extern IntPtr dlsym(IntPtr handle, string symbol); -#if __ANDROID__ - [DllImport("libdl.so")] -#else [DllImport("libdl.so.2")] -#endif + private static extern IntPtr dlerror(); + + public static void Init() + { + DlOpen = dlopen; + DlSym = dlsym; + DlError = dlerror; + } + } + + 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() @@ -42,8 +47,6 @@ namespace Avalonia.Shared.PlatformSupport static class OsXImports { - - [DllImport("/usr/lib/libSystem.dylib")] private static extern IntPtr dlopen(string path, int flags); @@ -72,32 +75,36 @@ namespace Avalonia.Shared.PlatformSupport uname(buffer); var unixName = Marshal.PtrToStringAnsi(buffer); Marshal.FreeHGlobal(buffer); - if(unixName == "Darwin") + if (unixName == "Darwin") OsXImports.Init(); +#if NET6_0_OR_GREATER + else if (OperatingSystem.IsAndroid()) + AndroidImports.Init(); +#endif else LinuxImports.Init(); } - private static Func DlOpen; - private static Func DlSym; - private static Func DlError; + private static Func? DlOpen; + private static Func? DlSym; + private static Func? DlError; // ReSharper restore InconsistentNaming - static string DlErrorString() => Marshal.PtrToStringAnsi(DlError()); + static string? DlErrorString() => Marshal.PtrToStringAnsi(DlError!.Invoke()); public IntPtr LoadLibrary(string dll) { - var handle = DlOpen(dll, 1); + var handle = DlOpen!.Invoke(dll, 1); if (handle == IntPtr.Zero) - throw new DynamicLibraryLoaderException(DlErrorString()); + throw new DynamicLibraryLoaderException(DlErrorString()!); return handle; } public IntPtr GetProcAddress(IntPtr dll, string proc, bool optional) { - var ptr = DlSym(dll, proc); + var ptr = DlSym!.Invoke(dll, proc); if (ptr == IntPtr.Zero && !optional) - throw new DynamicLibraryLoaderException(DlErrorString()); + throw new DynamicLibraryLoaderException(DlErrorString()!); return ptr; } } @@ -129,8 +136,7 @@ namespace Avalonia.Shared.PlatformSupport } } -#else - internal class IOSLoader : IDynamicLibraryLoader + internal class NotSupportedLoader : IDynamicLibraryLoader { IntPtr IDynamicLibraryLoader.LoadLibrary(string dll) { @@ -142,5 +148,4 @@ namespace Avalonia.Shared.PlatformSupport throw new PlatformNotSupportedException(); } } -#endif } diff --git a/src/Shared/PlatformSupport/StandardRuntimePlatform.cs b/src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs similarity index 66% rename from src/Shared/PlatformSupport/StandardRuntimePlatform.cs rename to src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs index 8521a50087..768966ba2d 100644 --- a/src/Shared/PlatformSupport/StandardRuntimePlatform.cs +++ b/src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs @@ -1,14 +1,13 @@ using System; using System.Collections.Generic; -using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using Avalonia.Platform; -namespace Avalonia.Shared.PlatformSupport +namespace Avalonia.PlatformSupport { - internal partial class StandardRuntimePlatform : IRuntimePlatform + public class StandardRuntimePlatform : IRuntimePlatform { public IDisposable StartSystemTimer(TimeSpan interval, Action tick) { @@ -16,15 +15,15 @@ namespace Avalonia.Shared.PlatformSupport } public IUnmanagedBlob AllocBlob(int size) => new UnmanagedBlob(this, size); - - class UnmanagedBlob : IUnmanagedBlob + + private class UnmanagedBlob : IUnmanagedBlob { private readonly StandardRuntimePlatform _plat; private IntPtr _address; private readonly object _lock = new object(); #if DEBUG private static readonly List Backtraces = new List(); - private static Thread GCThread; + private static Thread? GCThread; private readonly string _backtrace; private static readonly object _btlock = new object(); @@ -38,15 +37,14 @@ namespace Avalonia.Shared.PlatformSupport [MethodImpl(MethodImplOptions.NoInlining)] static void Spawn() => new GCThreadDetector(); - + static UnmanagedBlob() { Spawn(); GC.WaitForPendingFinalizers(); } - #endif - + public UnmanagedBlob(StandardRuntimePlatform plat, int size) { try @@ -117,14 +115,12 @@ namespace Avalonia.Shared.PlatformSupport DoDispose(); } - public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address; + 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 + +#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)] @@ -133,15 +129,15 @@ namespace Avalonia.Shared.PlatformSupport private static extern long sysconf(int name); private bool? _useMmap; - 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) + if (rv.ToInt64() == -1 || (ulong)rv.ToInt64() == 0xffffffff) { var errno = Marshal.GetLastWin32Error(); throw new Exception("Unable to allocate memory: " + errno); @@ -169,5 +165,54 @@ namespace Avalonia.Shared.PlatformSupport IntPtr Alloc(int size) => Marshal.AllocHGlobal(size); void Free(IntPtr ptr, int len) => Marshal.FreeHGlobal(ptr); #endif + + private static readonly Lazy Info = new Lazy(() => + { + 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 = false, +#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; } } diff --git a/src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs b/src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs new file mode 100644 index 0000000000..ae7478feb9 --- /dev/null +++ b/src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs @@ -0,0 +1,31 @@ +using System.Reflection; +using Avalonia.Platform; +using Avalonia.Platform.Interop; + +namespace Avalonia.PlatformSupport +{ + 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().ToConstant(standardPlatform) + .Bind().ToConstant(new AssetLoader(assembly)) + .Bind().ToConstant( + os switch + { + OperatingSystemType.WinNT => new Win32Loader(), + OperatingSystemType.OSX => new UnixLoader(), + OperatingSystemType.Linux => new UnixLoader(), + OperatingSystemType.Android => new UnixLoader(), + // iOS, WASM, ... + _ => (IDynamicLibraryLoader)new NotSupportedLoader() + } + ); + } + } +} diff --git a/src/Shared/PlatformSupport/PlatformSupport.projitems b/src/Shared/PlatformSupport/PlatformSupport.projitems deleted file mode 100644 index 34515a0912..0000000000 --- a/src/Shared/PlatformSupport/PlatformSupport.projitems +++ /dev/null @@ -1,17 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - {E4D9629C-F168-4224-8F51-F5E482FFEC42} - - - Avalonia.Shared.PlatformSupport - - - - - - - - \ No newline at end of file diff --git a/src/Shared/PlatformSupport/PlatformSupport.shproj b/src/Shared/PlatformSupport/PlatformSupport.shproj deleted file mode 100644 index 5b0e7dbb08..0000000000 --- a/src/Shared/PlatformSupport/PlatformSupport.shproj +++ /dev/null @@ -1,11 +0,0 @@ - - - - {E4D9629C-F168-4224-3F51-A5E482FFBC42} - - - - - - - \ No newline at end of file diff --git a/src/Shared/PlatformSupport/StandardRuntimePlatformServices.cs b/src/Shared/PlatformSupport/StandardRuntimePlatformServices.cs deleted file mode 100644 index 0dd7aea356..0000000000 --- a/src/Shared/PlatformSupport/StandardRuntimePlatformServices.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; -using Avalonia.Platform; -using Avalonia.Platform.Interop; - -namespace Avalonia.Shared.PlatformSupport -{ - static class StandardRuntimePlatformServices - { - public static void Register(Assembly assembly = null) - { - var standardPlatform = new StandardRuntimePlatform(); - AssetLoader.RegisterResUriParsers(); - AvaloniaLocator.CurrentMutable - .Bind().ToConstant(standardPlatform) - .Bind().ToConstant(new AssetLoader(assembly)) - .Bind().ToConstant( -#if __IOS__ - new IOSLoader() -#else - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) - ? (IDynamicLibraryLoader)new Win32Loader() - : new UnixLoader() -#endif - ); - } - } -} diff --git a/src/Shared/RenderHelpers/QuadBezierHelper.cs b/src/Shared/RenderHelpers/QuadBezierHelper.cs deleted file mode 100644 index 8439265e73..0000000000 --- a/src/Shared/RenderHelpers/QuadBezierHelper.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Avalonia.Platform; - -namespace Avalonia.RenderHelpers -{ - static class QuadBezierHelper - { - public static void QuadraticBezierTo(IStreamGeometryContextImpl context, Point current, Point controlPoint, Point endPoint) - { - //(s, (s + 2c)/ 3, (e + 2c)/ 3, e) - context.CubicBezierTo((current + 2*controlPoint)/3, (endPoint + 2*controlPoint)/3, endPoint); - } - } -} diff --git a/src/Shared/RenderHelpers/RenderHelpers.projitems b/src/Shared/RenderHelpers/RenderHelpers.projitems deleted file mode 100644 index 4c80ec50c4..0000000000 --- a/src/Shared/RenderHelpers/RenderHelpers.projitems +++ /dev/null @@ -1,14 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - 3c4c0cb4-0c0f-4450-a37b-148c84ff905f - - - Avalonia.RenderHelpers - - - - - \ No newline at end of file diff --git a/src/Shared/RenderHelpers/RenderHelpers.shproj b/src/Shared/RenderHelpers/RenderHelpers.shproj deleted file mode 100644 index ef561259f3..0000000000 --- a/src/Shared/RenderHelpers/RenderHelpers.shproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - 3c4c0cb4-0c0f-4450-a37b-148c84ff905f - 14.0 - - - - - - - - diff --git a/src/Shared/WindowResizeDragHelper.cs b/src/Shared/WindowResizeDragHelper.cs deleted file mode 100644 index e0e0936b69..0000000000 --- a/src/Shared/WindowResizeDragHelper.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using Avalonia.Controls; -using Avalonia.Input.Raw; -using Avalonia.Platform; - -namespace Avalonia -{ - internal class ManagedWindowResizeDragHelper - { - private readonly IWindowBaseImpl _window; - private readonly Action _captureMouse; - private readonly Action _resize; - private WindowEdge? _edge; - private Point _prevPoint; - - public ManagedWindowResizeDragHelper(IWindowBaseImpl window, Action captureMouse, Action resize = null) - { - _window = window; - _captureMouse = captureMouse; - _resize = resize; - } - - public void BeginResizeDrag(WindowEdge edge, Point currentMousePosition) - { - _captureMouse(true); - _prevPoint = currentMousePosition; - _edge = edge; - } - - public bool PreprocessInputEvent(ref RawInputEventArgs e) - { - if (_edge == null) - return false; - if (e is RawMouseEventArgs args) - { - if (args.Type == RawMouseEventType.LeftButtonUp) - { - _edge = null; - _captureMouse(false); - } - if (args.Type == RawMouseEventType.Move) - { - MoveWindow(args.Position); - return true; - } - - - _edge = null; - } - - return false; - } - - private void MoveWindow(Point position) - { - var diff = position - _prevPoint; - var edge = _edge.Value; - var rc = new Rect(_window.Position, _window.ClientSize); - if (edge == WindowEdge.East || edge == WindowEdge.NorthEast || edge == WindowEdge.SouthEast) - { - rc = rc.WithWidth(rc.Width + diff.X); - _prevPoint = _prevPoint.WithX(position.X); - } - if (edge == WindowEdge.West || edge == WindowEdge.NorthWest || edge == WindowEdge.SouthWest) - rc = rc.WithX(rc.X + diff.X).WithWidth(rc.Width - diff.X); - if (edge == WindowEdge.South || edge == WindowEdge.SouthWest || edge == WindowEdge.SouthEast) - { - rc = rc.WithHeight(rc.Height + diff.Y); - _prevPoint = _prevPoint.WithY(position.Y); - } - if (edge == WindowEdge.North || edge == WindowEdge.NorthWest || edge == WindowEdge.NorthEast) - rc = rc.WithY(rc.Y + diff.Y).WithHeight(rc.Height - diff.Y); - if (_resize != null) - _resize(rc); - else - { - if (_window.Position != rc.Position) - _window.Position = rc.Position; - if (_window.ClientSize != rc.Size) - _window.Resize(rc.Size); - } - } - } -} diff --git a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj index bc14494f6a..50ace8209c 100644 --- a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj +++ b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj @@ -16,6 +16,5 @@ - - + diff --git a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj b/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj index 94350b40cf..cc604a9753 100644 --- a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj +++ b/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj @@ -10,7 +10,6 @@ - @@ -51,7 +50,7 @@ - + diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs index 65c73b101a..9bf1fe6663 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs @@ -1,5 +1,6 @@ using Avalonia.Controls; using Avalonia.Platform; +using Avalonia.PlatformSupport; namespace Avalonia.Web.Blazor { @@ -10,7 +11,9 @@ namespace Avalonia.Web.Blazor { } - public AvaloniaBlazorAppBuilder() : base(BlazorRuntimePlatform.Instance, BlazorRuntimePlatform.RegisterServices) + public AvaloniaBlazorAppBuilder() + : base(new StandardRuntimePlatform(), + builder => StandardRuntimePlatformServices.Register(builder.ApplicationType.Assembly)) { UseWindowingSubsystem(BlazorWindowingPlatform.Register); } diff --git a/src/Web/Avalonia.Web.Blazor/BlazorRuntimePlatform.cs b/src/Web/Avalonia.Web.Blazor/BlazorRuntimePlatform.cs deleted file mode 100644 index 9a5bf6b151..0000000000 --- a/src/Web/Avalonia.Web.Blazor/BlazorRuntimePlatform.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Runtime.InteropServices; -using Avalonia.Platform; -using Avalonia.Shared.PlatformSupport; - -namespace Avalonia.Web.Blazor -{ - internal class BlazorRuntimePlatform : IRuntimePlatform - { - public static readonly IRuntimePlatform Instance = new BlazorRuntimePlatform(); - - public IDisposable StartSystemTimer(TimeSpan interval, Action tick) - { - return new Timer(_ => tick(), null, interval, interval); - } - - public RuntimePlatformInfo GetRuntimeInfo() - { - return new RuntimePlatformInfo - { - IsDesktop = false, - IsMobile = false, - IsMono = true, - IsUnix = false, - IsCoreClr = false, - IsDotNetFramework = false - }; - } - - private class BasicBlob : IUnmanagedBlob - { - public BasicBlob(int size) - { - Address = Marshal.AllocHGlobal(size); - Size = size; - } - public void Dispose() - { - if (Address != IntPtr.Zero) - Marshal.FreeHGlobal(Address); - Address = IntPtr.Zero; - } - - public IntPtr Address { get; private set; } - - public int Size { get; } - public bool IsDisposed => Address == IntPtr.Zero; - } - - public IUnmanagedBlob AllocBlob(int size) - { - return new BasicBlob(size); - } - - public static void RegisterServices(AvaloniaBlazorAppBuilder builder) - { - AssetLoader.RegisterResUriParsers(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(Instance); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(new AssetLoader()); - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj index bc529208ea..a1d8a60cb9 100644 --- a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj +++ b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj @@ -17,6 +17,5 @@ - diff --git a/src/iOS/Avalonia.iOS/Avalonia.iOS.csproj b/src/iOS/Avalonia.iOS/Avalonia.iOS.csproj index c219e08c8b..e9015d857c 100644 --- a/src/iOS/Avalonia.iOS/Avalonia.iOS.csproj +++ b/src/iOS/Avalonia.iOS/Avalonia.iOS.csproj @@ -4,19 +4,14 @@ true latest - - - Code - - - Code - - + + TargetFramework=netstandard2.0 + diff --git a/src/iOS/Avalonia.iOS/Boilerplate/AppBuilder.cs b/src/iOS/Avalonia.iOS/Boilerplate/AppBuilder.cs index 65143c939f..d5830510f6 100644 --- a/src/iOS/Avalonia.iOS/Boilerplate/AppBuilder.cs +++ b/src/iOS/Avalonia.iOS/Boilerplate/AppBuilder.cs @@ -1,6 +1,5 @@ using Avalonia.Controls; -using Avalonia.iOS; -using Avalonia.Shared.PlatformSupport; +using Avalonia.PlatformSupport; namespace Avalonia { @@ -12,4 +11,4 @@ namespace Avalonia this.UseSkia().UseWindowingSubsystem(iOS.Platform.Register); } } -} \ No newline at end of file +} diff --git a/src/iOS/Avalonia.iOS/Boilerplate/RuntimePlatform.cs b/src/iOS/Avalonia.iOS/Boilerplate/RuntimePlatform.cs deleted file mode 100644 index c5c4d66450..0000000000 --- a/src/iOS/Avalonia.iOS/Boilerplate/RuntimePlatform.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Avalonia.Platform; - -namespace Avalonia.Shared.PlatformSupport -{ - partial class StandardRuntimePlatform - { - public RuntimePlatformInfo GetRuntimeInfo() - { - return new RuntimePlatformInfo - { - IsDesktop = false, - IsMobile = true, - IsMono = true, - IsUnix = true, - OperatingSystem = OperatingSystemType.iOS - }; - } - } -} \ No newline at end of file diff --git a/src/iOS/Avalonia.iOS/Boilerplate/Shared.cs b/src/iOS/Avalonia.iOS/Boilerplate/Shared.cs deleted file mode 100644 index c6e6e01e64..0000000000 --- a/src/iOS/Avalonia.iOS/Boilerplate/Shared.cs +++ /dev/null @@ -1,595 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Threading; -using Avalonia.Platform; -using Avalonia.Platform.Interop; -using Avalonia.Utilities; - -namespace Avalonia.Shared.PlatformSupport -{ - static class StandardRuntimePlatformServices - { - public static void Register(Assembly assembly = null) - { - var standardPlatform = new StandardRuntimePlatform(); - AssetLoader.RegisterResUriParsers(); - AvaloniaLocator.CurrentMutable - .Bind().ToConstant(standardPlatform) - .Bind().ToConstant(new AssetLoader(assembly)) - .Bind().ToConstant( -#if __IOS__ - new IOSLoader() -#else - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) - ? (IDynamicLibraryLoader)new Win32Loader() - : new UnixLoader() -#endif - ); - } - } - - - internal partial 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); - - class UnmanagedBlob : IUnmanagedBlob - { - private readonly StandardRuntimePlatform _plat; - private IntPtr _address; - private readonly object _lock = new object(); -#if DEBUG - private static readonly List Backtraces = new List(); - 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) - { - if (size <= 0) - throw new ArgumentException("Positive number required", nameof(size)); - _plat = plat; - _address = plat.Alloc(size); - GC.AddMemoryPressure(size); - Size = size; -#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 - [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 - - - } - - internal class IOSLoader : IDynamicLibraryLoader - { - IntPtr IDynamicLibraryLoader.LoadLibrary(string dll) - { - throw new PlatformNotSupportedException(); - } - - IntPtr IDynamicLibraryLoader.GetProcAddress(IntPtr dll, string proc, bool optional) - { - throw new PlatformNotSupportedException(); - } - } - - public class AssetLoader : IAssetLoader - { - private const string AvaloniaResourceName = "!AvaloniaResources"; - private static readonly Dictionary AssemblyNameCache - = new Dictionary(); - - private AssemblyDescriptor _defaultResmAssembly; - - /// - /// Initializes a new instance of the class. - /// - /// - /// The default assembly from which to load resm: assets for which no assembly is specified. - /// - public AssetLoader(Assembly assembly = null) - { - if (assembly == null) - assembly = Assembly.GetEntryAssembly(); - if (assembly != null) - _defaultResmAssembly = new AssemblyDescriptor(assembly); - } - - /// - /// Sets the default assembly from which to load assets for which no assembly is specified. - /// - /// The default assembly. - public void SetDefaultAssembly(Assembly assembly) - { - _defaultResmAssembly = new AssemblyDescriptor(assembly); - } - - /// - /// Checks if an asset with the specified URI exists. - /// - /// The URI. - /// - /// A base URI to use if is relative. - /// - /// True if the asset could be found; otherwise false. - public bool Exists(Uri uri, Uri baseUri = null) - { - return GetAsset(uri, baseUri) != null; - } - - /// - /// Opens the asset with the requested URI. - /// - /// The URI. - /// - /// A base URI to use if is relative. - /// - /// A stream containing the asset contents. - /// - /// The asset could not be found. - /// - public Stream Open(Uri uri, Uri baseUri = null) => OpenAndGetAssembly(uri, baseUri).Item1; - - /// - /// Opens the asset with the requested URI and returns the asset stream and the - /// assembly containing the asset. - /// - /// The URI. - /// - /// A base URI to use if is relative. - /// - /// - /// The stream containing the resource contents together with the assembly. - /// - /// - /// The asset could not be found. - /// - public (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri baseUri = null) - { - var asset = GetAsset(uri, baseUri); - - if (asset == null) - { - throw new FileNotFoundException($"The resource {uri} could not be found."); - } - - return (asset.GetStream(), asset.Assembly); - } - - public Assembly GetAssembly(Uri uri, Uri baseUri) - { - if (!uri.IsAbsoluteUri && baseUri != null) - uri = new Uri(baseUri, uri); - return GetAssembly(uri).Assembly; - } - - /// - /// Gets all assets of a folder and subfolders that match specified uri. - /// - /// The URI. - /// Base URI that is used if is relative. - /// All matching assets as a tuple of the absolute path to the asset and the assembly containing the asset - public IEnumerable GetAssets(Uri uri, Uri baseUri) - { - if (uri.IsAbsoluteUri && uri.Scheme == "resm") - { - var assembly = GetAssembly(uri); - - return assembly?.Resources.Where(x => x.Key.Contains(uri.AbsolutePath)) - .Select(x =>new Uri($"resm:{x.Key}?assembly={assembly.Name}")) ?? - Enumerable.Empty(); - } - - uri = EnsureAbsolute(uri, baseUri); - if (uri.Scheme == "avares") - { - var (asm, path) = GetResAsmAndPath(uri); - if (asm == null) - { - throw new ArgumentException( - "No default assembly, entry assembly or explicit assembly specified; " + - "don't know where to look up for the resource, try specifying assembly explicitly."); - } - - if (asm?.AvaloniaResources == null) - return Enumerable.Empty(); - path = path.TrimEnd('/') + '/'; - return asm.AvaloniaResources.Where(r => r.Key.StartsWith(path)) - .Select(x => new Uri($"avares://{asm.Name}{x.Key}")); - } - - return Enumerable.Empty(); - } - - private Uri EnsureAbsolute(Uri uri, Uri baseUri) - { - if (uri.IsAbsoluteUri) - return uri; - if(baseUri == null) - throw new ArgumentException($"Relative uri {uri} without base url"); - if (!baseUri.IsAbsoluteUri) - throw new ArgumentException($"Base uri {baseUri} is relative"); - if (baseUri.Scheme == "resm") - throw new ArgumentException( - $"Relative uris for 'resm' scheme aren't supported; {baseUri} uses resm"); - return new Uri(baseUri, uri); - } - - private IAssetDescriptor GetAsset(Uri uri, Uri baseUri) - { - if (uri.IsAbsoluteUri && uri.Scheme == "resm") - { - var asm = GetAssembly(uri) ?? GetAssembly(baseUri) ?? _defaultResmAssembly; - - if (asm == null) - { - throw new ArgumentException( - "No default assembly, entry assembly or explicit assembly specified; " + - "don't know where to look up for the resource, try specifying assembly explicitly."); - } - - IAssetDescriptor rv; - - var resourceKey = uri.AbsolutePath; - asm.Resources.TryGetValue(resourceKey, out rv); - return rv; - } - - uri = EnsureAbsolute(uri, baseUri); - - if (uri.Scheme == "avares") - { - var (asm, path) = GetResAsmAndPath(uri); - if (asm.AvaloniaResources == null) - return null; - asm.AvaloniaResources.TryGetValue(path, out var desc); - return desc; - } - - throw new ArgumentException($"Unsupported url type: " + uri.Scheme, nameof(uri)); - } - - private (AssemblyDescriptor asm, string path) GetResAsmAndPath(Uri uri) - { - var asm = GetAssembly(uri.Authority); - return (asm, uri.AbsolutePath); - } - - private AssemblyDescriptor GetAssembly(Uri uri) - { - if (uri != null) - { - if (!uri.IsAbsoluteUri) - return null; - if (uri.Scheme == "avares") - return GetResAsmAndPath(uri).asm; - - if (uri.Scheme == "resm") - { - var qs = ParseQueryString(uri); - string assemblyName; - - if (qs.TryGetValue("assembly", out assemblyName)) - { - return GetAssembly(assemblyName); - } - } - } - - return null; - } - - private AssemblyDescriptor GetAssembly(string name) - { - if (name == null) - throw new ArgumentNullException(nameof(name)); - - AssemblyDescriptor rv; - if (!AssemblyNameCache.TryGetValue(name, out rv)) - { - var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); - var match = loadedAssemblies.FirstOrDefault(a => a.GetName().Name == name); - if (match != null) - { - AssemblyNameCache[name] = rv = new AssemblyDescriptor(match); - } - else - { - // iOS does not support loading assemblies dynamically! - // -#if __IOS__ - throw new InvalidOperationException( - $"Assembly {name} needs to be referenced and explicitly loaded before loading resources"); -#else - name = Uri.UnescapeDataString(name); - AssemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(name)); -#endif - } - } - - return rv; - } - - private Dictionary ParseQueryString(Uri uri) - { - return uri.Query.TrimStart('?') - .Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries) - .Select(p => p.Split('=')) - .ToDictionary(p => p[0], p => p[1]); - } - - private interface IAssetDescriptor - { - Stream GetStream(); - Assembly Assembly { get; } - } - - private class AssemblyResourceDescriptor : IAssetDescriptor - { - private readonly Assembly _asm; - private readonly string _name; - - public AssemblyResourceDescriptor(Assembly asm, string name) - { - _asm = asm; - _name = name; - } - - public Stream GetStream() - { - return _asm.GetManifestResourceStream(_name); - } - - public Assembly Assembly => _asm; - } - - private class AvaloniaResourceDescriptor : IAssetDescriptor - { - private readonly int _offset; - private readonly int _length; - public Assembly Assembly { get; } - - public AvaloniaResourceDescriptor(Assembly asm, int offset, int length) - { - _offset = offset; - _length = length; - Assembly = asm; - } - - public Stream GetStream() - { - return new SlicedStream(Assembly.GetManifestResourceStream(AvaloniaResourceName), _offset, _length); - } - } - - class SlicedStream : Stream - { - private readonly Stream _baseStream; - private readonly int _from; - - public SlicedStream(Stream baseStream, int from, int length) - { - Length = length; - _baseStream = baseStream; - _from = from; - _baseStream.Position = from; - } - public override void Flush() - { - } - - public override int Read(byte[] buffer, int offset, int count) - { - return _baseStream.Read(buffer, offset, (int)Math.Min(count, Length - Position)); - } - - public override long Seek(long offset, SeekOrigin origin) - { - if (origin == SeekOrigin.Begin) - Position = offset; - if (origin == SeekOrigin.End) - Position = _from + Length + offset; - if (origin == SeekOrigin.Current) - Position = Position + offset; - return Position; - } - - public override void SetLength(long value) => throw new NotSupportedException(); - - public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - - public override bool CanRead => true; - public override bool CanSeek => _baseStream.CanRead; - public override bool CanWrite => false; - public override long Length { get; } - public override long Position - { - get => _baseStream.Position - _from; - set => _baseStream.Position = value + _from; - } - - protected override void Dispose(bool disposing) - { - if (disposing) - _baseStream.Dispose(); - } - - public override void Close() => _baseStream.Close(); - } - - private class AssemblyDescriptor - { - public AssemblyDescriptor(Assembly assembly) - { - Assembly = assembly; - - if (assembly != null) - { - Resources = assembly.GetManifestResourceNames() - .ToDictionary(n => n, n => (IAssetDescriptor)new AssemblyResourceDescriptor(assembly, n)); - Name = assembly.GetName().Name; - using (var resources = assembly.GetManifestResourceStream(AvaloniaResourceName)) - { - if (resources != null) - { - Resources.Remove(AvaloniaResourceName); - - var indexLength = new BinaryReader(resources).ReadInt32(); - var index = AvaloniaResourcesIndexReaderWriter.Read(new SlicedStream(resources, 4, indexLength)); - var baseOffset = indexLength + 4; - AvaloniaResources = index.ToDictionary(r => "/" + r.Path.TrimStart('/'), r => (IAssetDescriptor) - new AvaloniaResourceDescriptor(assembly, baseOffset + r.Offset, r.Size)); - } - } - } - } - - public Assembly Assembly { get; } - public Dictionary Resources { get; } - public Dictionary AvaloniaResources { get; } - public string Name { get; } - } - - public static void RegisterResUriParsers() - { - if (!UriParser.IsKnownScheme("avares")) - UriParser.Register(new GenericUriParser( - GenericUriParserOptions.GenericAuthority | - GenericUriParserOptions.NoUserInfo | - GenericUriParserOptions.NoPort | - GenericUriParserOptions.NoQuery | - GenericUriParserOptions.NoFragment), "avares", -1); - } - } -} \ No newline at end of file diff --git a/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs b/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs index 363a4fabaf..6f04bb5206 100644 --- a/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs +++ b/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs @@ -1,9 +1,7 @@ using System; using Avalonia.Controls; -using Avalonia.Markup.Xaml; -using Avalonia.Markup.Xaml.Styling; using Avalonia.Platform; -using Avalonia.Shared.PlatformSupport; +using Avalonia.PlatformSupport; using Avalonia.Styling; using Avalonia.UnitTests; using BenchmarkDotNet.Attributes; diff --git a/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs b/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs index 79a11d0cea..81264f109c 100644 --- a/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs +++ b/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs @@ -2,7 +2,7 @@ using Avalonia.Controls; using Avalonia.Markup.Xaml.Styling; -using Avalonia.Shared.PlatformSupport; +using Avalonia.PlatformSupport; using Avalonia.Styling; using Avalonia.UnitTests; diff --git a/tests/Avalonia.RenderTests/TestBase.cs b/tests/Avalonia.RenderTests/TestBase.cs index a0fbf704cf..b70c721085 100644 --- a/tests/Avalonia.RenderTests/TestBase.cs +++ b/tests/Avalonia.RenderTests/TestBase.cs @@ -24,7 +24,7 @@ namespace Avalonia.Skia.RenderTests namespace Avalonia.Direct2D1.RenderTests #endif { - using Avalonia.Shared.PlatformSupport; + using Avalonia.PlatformSupport; public class TestBase { diff --git a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj index f5e502bca8..8b37fa1b41 100644 --- a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj +++ b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj @@ -13,6 +13,7 @@ + @@ -25,7 +26,6 @@ - diff --git a/tests/Avalonia.UnitTests/RuntimeInfo.cs b/tests/Avalonia.UnitTests/RuntimeInfo.cs deleted file mode 100644 index eb5781a725..0000000000 --- a/tests/Avalonia.UnitTests/RuntimeInfo.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Avalonia.Platform; -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Text; - -namespace Avalonia.Shared.PlatformSupport -{ - internal partial class StandardRuntimePlatform : IRuntimePlatform - { - public RuntimePlatformInfo GetRuntimeInfo() - { - return new RuntimePlatformInfo(); - } - } -} diff --git a/tests/Avalonia.UnitTests/TestServices.cs b/tests/Avalonia.UnitTests/TestServices.cs index da678fd74b..e5cea4823f 100644 --- a/tests/Avalonia.UnitTests/TestServices.cs +++ b/tests/Avalonia.UnitTests/TestServices.cs @@ -5,7 +5,7 @@ using Avalonia.Layout; using Avalonia.Markup.Xaml; using Avalonia.Media; using Avalonia.Platform; -using Avalonia.Shared.PlatformSupport; +using Avalonia.PlatformSupport; using Avalonia.Styling; using Avalonia.Themes.Default; using Avalonia.Rendering; diff --git a/tests/Avalonia.UnitTests/UnitTestApplication.cs b/tests/Avalonia.UnitTests/UnitTestApplication.cs index dc10754ea2..bb6e53d74f 100644 --- a/tests/Avalonia.UnitTests/UnitTestApplication.cs +++ b/tests/Avalonia.UnitTests/UnitTestApplication.cs @@ -10,7 +10,7 @@ using System.Reactive.Disposables; using System.Reactive.Concurrency; using Avalonia.Input.Platform; using Avalonia.Animation; -using Avalonia.Shared.PlatformSupport; +using Avalonia.PlatformSupport; namespace Avalonia.UnitTests {