Browse Source

Merge remote-tracking branch 'origin/master' into remove-reactive-package

pull/9749/head
Max Katz 3 years ago
parent
commit
0a6a3e94e3
  1. 5
      samples/ControlCatalog/Pages/PlatformInfoPage.xaml.cs
  2. 4
      samples/ControlCatalog/ViewModels/PlatformInformationViewModel.cs
  3. 2
      src/Android/Avalonia.Android/AndroidPlatform.cs
  4. 2
      src/Android/Avalonia.Android/AvaloniaSplashActivity.cs
  5. 3
      src/Avalonia.Base/Avalonia.Base.csproj
  6. 26
      src/Avalonia.Base/Compatibility/OperatingSystem.cs
  7. 5
      src/Avalonia.Base/Logging/LogArea.cs
  8. 19
      src/Avalonia.Base/Platform/IRuntimePlatform.cs
  9. 44
      src/Avalonia.Base/Platform/StandardRuntimePlatform.cs
  10. 13
      src/Avalonia.Base/Platform/StandardRuntimePlatformServices.cs
  11. 239
      src/Avalonia.Controls/AppBuilder.cs
  12. 244
      src/Avalonia.Controls/AppBuilderBase.cs
  13. 5
      src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
  14. 6
      src/Avalonia.Controls/LoggingExtensions.cs
  15. 6
      src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs
  16. 32
      src/Avalonia.Desktop/AppBuilderDesktopExtensions.cs
  17. 7
      src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs
  18. 5
      src/Avalonia.Headless.Vnc/HeadlessVncPlatformExtensions.cs
  19. 3
      src/Avalonia.Headless/AvaloniaHeadlessPlatform.cs
  20. 3
      src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs
  21. 6
      src/Avalonia.OpenGL/Egl/EglInterface.cs
  22. 3
      src/Avalonia.ReactiveUI/AppBuilderExtensions.cs
  23. 2
      src/Avalonia.X11/X11Platform.cs
  24. 7
      src/Browser/Avalonia.Browser.Blazor/BlazorSingleViewLifetime.cs
  25. 7
      src/Browser/Avalonia.Browser/BrowserRuntimePlatform.cs
  26. 12
      src/Browser/Avalonia.Browser/BrowserSingleViewLifetime.cs
  27. 30
      src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs
  28. 1
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOptionMarkupExtensionTransformer.cs
  29. 4
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnFormFactorExtension.cs
  30. 43
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnPlatformExtension.cs
  31. 8
      src/Skia/Avalonia.Skia/Helpers/PixelFormatHelper.cs
  32. 3
      src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs
  33. 2
      src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
  34. 4
      src/Windows/Avalonia.Win32/Win32Platform.cs
  35. 2
      src/iOS/Avalonia.iOS/Platform.cs
  36. 2
      tests/Avalonia.Base.UnitTests/Media/Fonts/FontFamilyLoaderTests.cs
  37. 75
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/OnPlatformExtensionTests.cs
  38. 2
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/OptionsMarkupExtensionTests.cs
  39. 14
      tests/Avalonia.UnitTests/TestServices.cs

5
samples/ControlCatalog/Pages/PlatformInfoPage.xaml.cs

@ -1,5 +1,8 @@
using Avalonia.Controls;
using System;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Media.Immutable;
using ControlCatalog.ViewModels;
namespace ControlCatalog.Pages

4
samples/ControlCatalog/ViewModels/PlatformInformationViewModel.cs

@ -1,3 +1,5 @@
using System;
using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Platform;
using MiniMvvm;
@ -13,7 +15,7 @@ public class PlatformInformationViewModel : ViewModelBase
if (runtimeInfo is { } info)
{
if (info.IsBrowser)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER")))
{
if (info.IsDesktop)
{

2
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -15,7 +15,7 @@ namespace Avalonia
{
public static class AndroidApplicationExtensions
{
public static T UseAndroid<T>(this T builder) where T : AppBuilderBase<T>, new()
public static AppBuilder UseAndroid(this AppBuilder builder)
{
return builder
.UseWindowingSubsystem(() => AndroidPlatform.Initialize(), "Android")

2
src/Android/Avalonia.Android/AvaloniaSplashActivity.cs

@ -1,6 +1,6 @@
using Android.OS;
using AndroidX.AppCompat.App;
using AndroidX.Lifecycle;
using Avalonia.Controls;
namespace Avalonia.Android
{

3
src/Avalonia.Base/Avalonia.Base.csproj

@ -27,10 +27,13 @@
<ItemGroup Label="InternalsVisibleTo">
<InternalsVisibleTo Include="Avalonia.Base.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Desktop, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Benchmarks, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Controls, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Markup, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Markup.Xaml, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.OpenGL, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Skia, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Controls.ColorPicker, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Controls.DataGrid, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Headless, PublicKey=$(AvaloniaPublicKey)" />

26
src/Avalonia.Base/Compatibility/OperatingSystem.cs

@ -0,0 +1,26 @@
using System;
using System.Runtime.InteropServices;
namespace Avalonia.Compatibility
{
internal sealed class OperatingSystemEx
{
#if NET6_0_OR_GREATER
public static bool IsWindows() => OperatingSystem.IsWindows();
public static bool IsMacOS() => OperatingSystem.IsMacOS();
public static bool IsLinux() => OperatingSystem.IsLinux();
public static bool IsAndroid() => OperatingSystem.IsAndroid();
public static bool IsIOS() => OperatingSystem.IsIOS();
public static bool IsBrowser() => OperatingSystem.IsBrowser();
public static bool IsOSPlatform(string platform) => OperatingSystem.IsOSPlatform(platform);
#else
public static bool IsWindows() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public static bool IsMacOS() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
public static bool IsLinux() => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
public static bool IsAndroid() => IsOSPlatform("ANDROID");
public static bool IsIOS() => IsOSPlatform("IOS");
public static bool IsBrowser() => IsOSPlatform("BROWSER");
public static bool IsOSPlatform(string platform) => RuntimeInformation.IsOSPlatform(OSPlatform.Create(platform));
#endif
}
}

5
src/Avalonia.Base/Logging/LogArea.cs

@ -35,6 +35,11 @@ namespace Avalonia.Logging
/// </summary>
public const string Control = nameof(Control);
/// <summary>
/// The log event comes from Win32 Platform.
/// </summary>
public const string Platform = nameof(Platform);
/// <summary>
/// The log event comes from Win32 Platform.
/// </summary>

19
src/Avalonia.Base/Platform/IRuntimePlatform.cs

@ -23,29 +23,10 @@ namespace Avalonia.Platform
[Unstable]
public record struct RuntimePlatformInfo
{
public OperatingSystemType OperatingSystem { get; set; }
public FormFactorType FormFactor => IsDesktop ? FormFactorType.Desktop :
IsMobile ? FormFactorType.Mobile : FormFactorType.Unknown;
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; }
public bool IsUnix { get; set; }
}
[Unstable]
public enum OperatingSystemType
{
Unknown,
WinNT,
Linux,
OSX,
Android,
iOS,
Browser
}
[Unstable]

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

@ -1,6 +1,6 @@
using System;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia.Compatibility;
using Avalonia.Platform.Internal;
namespace Avalonia.Platform
@ -14,45 +14,13 @@ namespace Avalonia.Platform
public IUnmanagedBlob AllocBlob(int size) => new UnmanagedBlob(size);
private static readonly Lazy<RuntimePlatformInfo> Info = new(() =>
private static readonly RuntimePlatformInfo s_info = new()
{
OperatingSystemType os;
IsDesktop = OperatingSystemEx.IsWindows() || OperatingSystemEx.IsMacOS() || OperatingSystemEx.IsLinux(),
IsMobile = OperatingSystemEx.IsAndroid() || OperatingSystemEx.IsIOS()
};
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;
public virtual RuntimePlatformInfo GetRuntimeInfo() => s_info;
}
}

13
src/Avalonia.Base/Platform/StandardRuntimePlatformServices.cs

@ -1,4 +1,5 @@
using System.Reflection;
using Avalonia.Compatibility;
using Avalonia.Platform.Internal;
using Avalonia.Platform.Interop;
@ -18,15 +19,9 @@ namespace Avalonia.Platform
#if NET6_0_OR_GREATER
new Net6Loader()
#else
standardPlatform.GetRuntimeInfo().OperatingSystem switch
{
OperatingSystemType.WinNT => (IDynamicLibraryLoader)new Win32Loader(),
OperatingSystemType.OSX => new UnixLoader(),
OperatingSystemType.Linux => new UnixLoader(),
OperatingSystemType.Android => new UnixLoader(),
// iOS, WASM, ...
_ => new NotSupportedLoader()
}
OperatingSystemEx.IsWindows() ? (IDynamicLibraryLoader)new Win32Loader()
: OperatingSystemEx.IsMacOS() || OperatingSystemEx.IsLinux() || OperatingSystemEx.IsAndroid() ? new UnixLoader()
: new NotSupportedLoader()
#endif
);
}

239
src/Avalonia.Controls/AppBuilder.cs

@ -1,4 +1,8 @@
using Avalonia.Controls;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Linq;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform;
namespace Avalonia
@ -6,15 +10,244 @@ namespace Avalonia
/// <summary>
/// Initializes platform-specific services for an <see cref="Application"/>.
/// </summary>
public sealed class AppBuilder : AppBuilderBase<AppBuilder>
public class AppBuilder
{
private static bool s_setupWasAlreadyCalled;
private Action? _optionsInitializers;
private Func<Application>? _appFactory;
private IApplicationLifetime? _lifetime;
/// <summary>
/// Gets or sets the <see cref="IRuntimePlatform"/> instance.
/// </summary>
public IRuntimePlatform RuntimePlatform { get; set; }
/// <summary>
/// Gets or sets a method to call the initialize the runtime platform services (e. g. AssetLoader)
/// </summary>
public Action RuntimePlatformServicesInitializer { get; private set; }
/// <summary>
/// Gets the <see cref="Application"/> instance being initialized.
/// </summary>
public Application? Instance { get; private set; }
/// <summary>
/// Gets the type of the Instance (even if it's not created yet)
/// </summary>
public Type? ApplicationType { get; private set; }
/// <summary>
/// Gets or sets a method to call the initialize the windowing subsystem.
/// </summary>
public Action? WindowingSubsystemInitializer { get; private set; }
/// <summary>
/// Gets the name of the currently selected windowing subsystem.
/// </summary>
public string? WindowingSubsystemName { get; private set; }
/// <summary>
/// Gets or sets a method to call the initialize the windowing subsystem.
/// </summary>
public Action? RenderingSubsystemInitializer { get; private set; }
/// <summary>
/// Gets the name of the currently selected rendering subsystem.
/// </summary>
public string? RenderingSubsystemName { get; private set; }
/// <summary>
/// Gets or sets a method to call after the <see cref="Application"/> is setup.
/// </summary>
public Action<AppBuilder> AfterSetupCallback { get; private set; } = builder => { };
public Action<AppBuilder> AfterPlatformServicesSetupCallback { get; private set; } = builder => { };
/// <summary>
/// Initializes a new instance of the <see cref="AppBuilder"/> class.
/// </summary>
public AppBuilder()
: base(new StandardRuntimePlatform(),
: this(new StandardRuntimePlatform(),
builder => StandardRuntimePlatformServices.Register(builder.ApplicationType?.Assembly))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AppBuilder"/> class.
/// </summary>
protected AppBuilder(IRuntimePlatform platform, Action<AppBuilder> platformServices)
{
RuntimePlatform = platform;
RuntimePlatformServicesInitializer = () => platformServices(this);
}
/// <summary>
/// Begin configuring an <see cref="Application"/>.
/// </summary>
/// <typeparam name="TApp">The subclass of <see cref="Application"/> to configure.</typeparam>
/// <returns>An <see cref="AppBuilder"/> instance.</returns>
public static AppBuilder Configure<TApp>()
where TApp : Application, new()
{
return new AppBuilder()
{
ApplicationType = typeof(TApp),
// Needed for CoreRT compatibility
_appFactory = () => new TApp()
};
}
/// <summary>
/// Begin configuring an <see cref="Application"/>.
/// </summary>
/// <param name="appFactory">Factory function for <typeparamref name="TApp"/>.</param>
/// <typeparam name="TApp">The subclass of <see cref="Application"/> to configure.</typeparam>
/// <remarks><paramref name="appFactory"/> is useful for passing of dependencies to <typeparamref name="TApp"/>.</remarks>
/// <returns>An <see cref="AppBuilder"/> instance.</returns>
public static AppBuilder Configure<TApp>(Func<TApp> appFactory)
where TApp : Application
{
return new AppBuilder()
{
ApplicationType = typeof(TApp),
_appFactory = appFactory
};
}
protected AppBuilder Self => this;
public AppBuilder AfterSetup(Action<AppBuilder> callback)
{
AfterSetupCallback = (Action<AppBuilder>)Delegate.Combine(AfterSetupCallback, callback);
return Self;
}
public AppBuilder AfterPlatformServicesSetup(Action<AppBuilder> callback)
{
AfterPlatformServicesSetupCallback = (Action<AppBuilder>)Delegate.Combine(AfterPlatformServicesSetupCallback, callback);
return Self;
}
public delegate void AppMainDelegate(Application app, string[] args);
public void Start(AppMainDelegate main, string[] args)
{
Setup();
main(Instance!, args);
}
/// <summary>
/// Sets up the platform-specific services for the application, but does not run it.
/// </summary>
/// <returns></returns>
public AppBuilder SetupWithoutStarting()
{
Setup();
return Self;
}
/// <summary>
/// Sets up the platform-specific services for the application and initialized it with a particular lifetime, but does not run it.
/// </summary>
/// <param name="lifetime"></param>
/// <returns></returns>
public AppBuilder SetupWithLifetime(IApplicationLifetime lifetime)
{
_lifetime = lifetime;
Setup();
return Self;
}
/// <summary>
/// Specifies a windowing subsystem to use.
/// </summary>
/// <param name="initializer">The method to call to initialize the windowing subsystem.</param>
/// <param name="name">The name of the windowing subsystem.</param>
/// <returns>An <see cref="AppBuilder"/> instance.</returns>
public AppBuilder UseWindowingSubsystem(Action initializer, string name = "")
{
WindowingSubsystemInitializer = initializer;
WindowingSubsystemName = name;
return Self;
}
/// <summary>
/// Specifies a rendering subsystem to use.
/// </summary>
/// <param name="initializer">The method to call to initialize the rendering subsystem.</param>
/// <param name="name">The name of the rendering subsystem.</param>
/// <returns>An <see cref="AppBuilder"/> instance.</returns>
public AppBuilder UseRenderingSubsystem(Action initializer, string name = "")
{
RenderingSubsystemInitializer = initializer;
RenderingSubsystemName = name;
return Self;
}
/// <summary>
/// Configures platform-specific options
/// </summary>
public AppBuilder With<T>(T options)
{
_optionsInitializers += () => { AvaloniaLocator.CurrentMutable.Bind<T>().ToConstant(options); };
return Self;
}
/// <summary>
/// Configures platform-specific options
/// </summary>
public AppBuilder With<T>(Func<T> options)
{
_optionsInitializers += () => { AvaloniaLocator.CurrentMutable.Bind<T>().ToFunc(options); };
return Self;
}
/// <summary>
/// Sets up the platform-specific services for the <see cref="Application"/>.
/// </summary>
private void Setup()
{
if (RuntimePlatformServicesInitializer == null)
{
throw new InvalidOperationException("No runtime platform services configured.");
}
if (WindowingSubsystemInitializer == null)
{
throw new InvalidOperationException("No windowing system configured.");
}
if (RenderingSubsystemInitializer == null)
{
throw new InvalidOperationException("No rendering system configured.");
}
if (_appFactory == null)
{
throw new InvalidOperationException("No Application factory configured.");
}
if (s_setupWasAlreadyCalled)
{
throw new InvalidOperationException("Setup was already called on one of AppBuilder instances");
}
s_setupWasAlreadyCalled = true;
_optionsInitializers?.Invoke();
RuntimePlatformServicesInitializer();
RenderingSubsystemInitializer();
WindowingSubsystemInitializer();
AfterPlatformServicesSetupCallback(Self);
Instance = _appFactory();
Instance.ApplicationLifetime = _lifetime;
AvaloniaLocator.CurrentMutable.BindToSelf(Instance);
Instance.RegisterServices();
Instance.Initialize();
AfterSetupCallback(Self);
Instance.OnFrameworkInitializationCompleted();
}
}
}

244
src/Avalonia.Controls/AppBuilderBase.cs

@ -1,244 +0,0 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Linq;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform;
namespace Avalonia.Controls
{
/// <summary>
/// Base class for initializing platform-specific services for an <see cref="Application"/>.
/// </summary>
/// <typeparam name="TAppBuilder">The type of the AppBuilder class itself.</typeparam>
public abstract class AppBuilderBase<TAppBuilder> where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
{
private static bool s_setupWasAlreadyCalled;
private Action? _optionsInitializers;
private Func<Application>? _appFactory;
private IApplicationLifetime? _lifetime;
/// <summary>
/// Gets or sets the <see cref="IRuntimePlatform"/> instance.
/// </summary>
public IRuntimePlatform RuntimePlatform { get; set; }
/// <summary>
/// Gets or sets a method to call the initialize the runtime platform services (e. g. AssetLoader)
/// </summary>
public Action RuntimePlatformServicesInitializer { get; private set; }
/// <summary>
/// Gets the <see cref="Application"/> instance being initialized.
/// </summary>
public Application? Instance { get; private set; }
/// <summary>
/// Gets the type of the Instance (even if it's not created yet)
/// </summary>
public Type? ApplicationType { get; private set; }
/// <summary>
/// Gets or sets a method to call the initialize the windowing subsystem.
/// </summary>
public Action? WindowingSubsystemInitializer { get; private set; }
/// <summary>
/// Gets the name of the currently selected windowing subsystem.
/// </summary>
public string? WindowingSubsystemName { get; private set; }
/// <summary>
/// Gets or sets a method to call the initialize the windowing subsystem.
/// </summary>
public Action? RenderingSubsystemInitializer { get; private set; }
/// <summary>
/// Gets the name of the currently selected rendering subsystem.
/// </summary>
public string? RenderingSubsystemName { get; private set; }
/// <summary>
/// Gets or sets a method to call after the <see cref="Application"/> is setup.
/// </summary>
public Action<TAppBuilder> AfterSetupCallback { get; private set; } = builder => { };
public Action<TAppBuilder> AfterPlatformServicesSetupCallback { get; private set; } = builder => { };
protected AppBuilderBase(IRuntimePlatform platform, Action<TAppBuilder> platformServices)
{
RuntimePlatform = platform;
RuntimePlatformServicesInitializer = () => platformServices((TAppBuilder)this);
}
/// <summary>
/// Begin configuring an <see cref="Application"/>.
/// </summary>
/// <typeparam name="TApp">The subclass of <see cref="Application"/> to configure.</typeparam>
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public static TAppBuilder Configure<TApp>()
where TApp : Application, new()
{
return new TAppBuilder()
{
ApplicationType = typeof(TApp),
// Needed for CoreRT compatibility
_appFactory = () => new TApp()
};
}
/// <summary>
/// Begin configuring an <see cref="Application"/>.
/// </summary>
/// <param name="appFactory">Factory function for <typeparamref name="TApp"/>.</param>
/// <typeparam name="TApp">The subclass of <see cref="Application"/> to configure.</typeparam>
/// <remarks><paramref name="appFactory"/> is useful for passing of dependencies to <typeparamref name="TApp"/>.</remarks>
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public static TAppBuilder Configure<TApp>(Func<TApp> appFactory)
where TApp : Application
{
return new TAppBuilder()
{
ApplicationType = typeof(TApp),
_appFactory = appFactory
};
}
protected TAppBuilder Self => (TAppBuilder)this;
public TAppBuilder AfterSetup(Action<TAppBuilder> callback)
{
AfterSetupCallback = (Action<TAppBuilder>)Delegate.Combine(AfterSetupCallback, callback);
return Self;
}
public TAppBuilder AfterPlatformServicesSetup(Action<TAppBuilder> callback)
{
AfterPlatformServicesSetupCallback = (Action<TAppBuilder>)Delegate.Combine(AfterPlatformServicesSetupCallback, callback);
return Self;
}
public delegate void AppMainDelegate(Application app, string[] args);
public void Start(AppMainDelegate main, string[] args)
{
Setup();
main(Instance!, args);
}
/// <summary>
/// Sets up the platform-specific services for the application, but does not run it.
/// </summary>
/// <returns></returns>
public TAppBuilder SetupWithoutStarting()
{
Setup();
return Self;
}
/// <summary>
/// Sets up the platform-specific services for the application and initialized it with a particular lifetime, but does not run it.
/// </summary>
/// <param name="lifetime"></param>
/// <returns></returns>
public TAppBuilder SetupWithLifetime(IApplicationLifetime lifetime)
{
_lifetime = lifetime;
Setup();
return Self;
}
/// <summary>
/// Specifies a windowing subsystem to use.
/// </summary>
/// <param name="initializer">The method to call to initialize the windowing subsystem.</param>
/// <param name="name">The name of the windowing subsystem.</param>
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public TAppBuilder UseWindowingSubsystem(Action initializer, string name = "")
{
WindowingSubsystemInitializer = initializer;
WindowingSubsystemName = name;
return Self;
}
/// <summary>
/// Specifies a rendering subsystem to use.
/// </summary>
/// <param name="initializer">The method to call to initialize the rendering subsystem.</param>
/// <param name="name">The name of the rendering subsystem.</param>
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public TAppBuilder UseRenderingSubsystem(Action initializer, string name = "")
{
RenderingSubsystemInitializer = initializer;
RenderingSubsystemName = name;
return Self;
}
protected virtual bool CheckSetup => true;
/// <summary>
/// Configures platform-specific options
/// </summary>
public TAppBuilder With<T>(T options)
{
_optionsInitializers += () => { AvaloniaLocator.CurrentMutable.Bind<T>().ToConstant(options); };
return Self;
}
/// <summary>
/// Configures platform-specific options
/// </summary>
public TAppBuilder With<T>(Func<T> options)
{
_optionsInitializers += () => { AvaloniaLocator.CurrentMutable.Bind<T>().ToFunc(options); };
return Self;
}
/// <summary>
/// Sets up the platform-specific services for the <see cref="Application"/>.
/// </summary>
private void Setup()
{
if (RuntimePlatformServicesInitializer == null)
{
throw new InvalidOperationException("No runtime platform services configured.");
}
if (WindowingSubsystemInitializer == null)
{
throw new InvalidOperationException("No windowing system configured.");
}
if (RenderingSubsystemInitializer == null)
{
throw new InvalidOperationException("No rendering system configured.");
}
if (_appFactory == null)
{
throw new InvalidOperationException("No Application factory configured.");
}
if (s_setupWasAlreadyCalled && CheckSetup)
{
throw new InvalidOperationException("Setup was already called on one of AppBuilder instances");
}
s_setupWasAlreadyCalled = true;
_optionsInitializers?.Invoke();
RuntimePlatformServicesInitializer();
RenderingSubsystemInitializer();
WindowingSubsystemInitializer();
AfterPlatformServicesSetupCallback(Self);
Instance = _appFactory();
Instance.ApplicationLifetime = _lifetime;
AvaloniaLocator.CurrentMutable.BindToSelf(Instance);
Instance.RegisterServices();
Instance.Initialize();
AfterSetupCallback(Self);
Instance.OnFrameworkInitializationCompleted();
}
}
}

5
src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs

@ -200,9 +200,8 @@ namespace Avalonia
{
public static class ClassicDesktopStyleApplicationLifetimeExtensions
{
public static int StartWithClassicDesktopLifetime<T>(
this T builder, string[] args, ShutdownMode shutdownMode = ShutdownMode.OnLastWindowClose)
where T : AppBuilderBase<T>, new()
public static int StartWithClassicDesktopLifetime(
this AppBuilder builder, string[] args, ShutdownMode shutdownMode = ShutdownMode.OnLastWindowClose)
{
var lifetime = new ClassicDesktopStyleApplicationLifetime()
{

6
src/Avalonia.Controls/LoggingExtensions.cs

@ -8,16 +8,14 @@ namespace Avalonia
/// <summary>
/// Logs Avalonia events to the <see cref="System.Diagnostics.Trace"/> sink.
/// </summary>
/// <typeparam name="T">The application class type.</typeparam>
/// <param name="builder">The app builder instance.</param>
/// <param name="level">The minimum level to log.</param>
/// <param name="areas">The areas to log. Valid values are listed in <see cref="LogArea"/>.</param>
/// <returns>The app builder instance.</returns>
public static T LogToTrace<T>(
this T builder,
public static AppBuilder LogToTrace(
this AppBuilder builder,
LogEventLevel level = LogEventLevel.Warning,
params string[] areas)
where T : AppBuilderBase<T>, new()
{
Logger.Sink = new TraceLogSink(level, areas);
return builder;

6
src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs

@ -134,12 +134,12 @@ namespace Avalonia.DesignerSupport.Remote
IAvaloniaRemoteTransportConnection ConfigureApp(IAvaloniaRemoteTransportConnection transport, CommandLineArgs args, object obj);
}
class AppInitializer<T> : IAppInitializer where T : AppBuilderBase<T>, new()
class AppInitializer : IAppInitializer
{
public IAvaloniaRemoteTransportConnection ConfigureApp(IAvaloniaRemoteTransportConnection transport,
CommandLineArgs args, object obj)
{
var builder = (AppBuilderBase<T>)obj;
var builder = (AppBuilder)obj;
if (args.Method == Methods.AvaloniaRemote)
builder.UseWindowingSubsystem(() => PreviewerWindowingPlatform.Initialize(transport));
if (args.Method == Methods.Html)
@ -191,7 +191,7 @@ namespace Avalonia.DesignerSupport.Remote
Log($"Obtaining AppBuilder instance from {builderMethod.DeclaringType.FullName}.{builderMethod.Name}");
var appBuilder = builderMethod.Invoke(null, null);
Log($"Initializing application in design mode");
var initializer =(IAppInitializer)Activator.CreateInstance(typeof(AppInitializer<>).MakeGenericType(appBuilder.GetType()));
var initializer =(IAppInitializer)Activator.CreateInstance(typeof(AppInitializer));
transport = initializer.ConfigureApp(transport, args, appBuilder);
s_transport = transport;
transport.OnMessage += OnTransportMessage;

32
src/Avalonia.Desktop/AppBuilderDesktopExtensions.cs

@ -1,15 +1,13 @@
using Avalonia.Compatibility;
using Avalonia.Controls;
using Avalonia.Platform;
using Avalonia.Logging;
namespace Avalonia
{
public static class AppBuilderDesktopExtensions
{
public static TAppBuilder UsePlatformDetect<TAppBuilder>(this TAppBuilder builder)
where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
public static AppBuilder UsePlatformDetect(this AppBuilder builder)
{
var os = builder.RuntimePlatform.GetRuntimeInfo().OperatingSystem;
// We don't have the ability to load every assembly right now, so we are
// stuck with manual configuration here
// Helpers are extracted to separate methods to take the advantage of the fact
@ -17,37 +15,39 @@ namespace Avalonia
// Additionally, by having a hard reference to each assembly,
// we verify that the assemblies are in the final .deps.json file
// so .NET Core knows where to load the assemblies from,.
if (os == OperatingSystemType.WinNT)
if (OperatingSystemEx.IsWindows())
{
LoadWin32(builder);
LoadSkia(builder);
}
else if(os==OperatingSystemType.OSX)
else if(OperatingSystemEx.IsMacOS())
{
LoadAvaloniaNative(builder);
LoadSkia(builder);
}
else
else if (OperatingSystemEx.IsLinux())
{
LoadX11(builder);
LoadSkia(builder);
}
else
{
Logger.TryGet(LogEventLevel.Warning, LogArea.Platform)?.Log(builder,
"Avalonia.Desktop package was referenced on non-desktop platform or it isn't supported");
}
return builder;
}
static void LoadAvaloniaNative<TAppBuilder>(TAppBuilder builder)
where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
static void LoadAvaloniaNative(AppBuilder builder)
=> builder.UseAvaloniaNative();
static void LoadWin32<TAppBuilder>(TAppBuilder builder)
where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
static void LoadWin32(AppBuilder builder)
=> builder.UseWin32();
static void LoadX11<TAppBuilder>(TAppBuilder builder)
where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
static void LoadX11(AppBuilder builder)
=> builder.UseX11();
static void LoadSkia<TAppBuilder>(TAppBuilder builder)
where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
static void LoadSkia(AppBuilder builder)
=> builder.UseSkia();
}
}

7
src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs

@ -24,16 +24,15 @@ namespace Avalonia.Dialogs
}
}
public static TAppBuilder UseManagedSystemDialogs<TAppBuilder>(this TAppBuilder builder)
where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
public static AppBuilder UseManagedSystemDialogs(this AppBuilder builder)
{
builder.AfterSetup(_ =>
AvaloniaLocator.CurrentMutable.Bind<IStorageProviderFactory>().ToSingleton<ManagedStorageProviderFactory<Window>>());
return builder;
}
public static TAppBuilder UseManagedSystemDialogs<TAppBuilder, TWindow>(this TAppBuilder builder)
where TAppBuilder : AppBuilderBase<TAppBuilder>, new() where TWindow : Window, new()
public static AppBuilder UseManagedSystemDialogs<TWindow>(this AppBuilder builder)
where TWindow : Window, new()
{
builder.AfterSetup(_ =>
AvaloniaLocator.CurrentMutable.Bind<IStorageProviderFactory>().ToSingleton<ManagedStorageProviderFactory<TWindow>>());

5
src/Avalonia.Headless.Vnc/HeadlessVncPlatformExtensions.cs

@ -11,11 +11,10 @@ namespace Avalonia
{
public static class HeadlessVncPlatformExtensions
{
public static int StartWithHeadlessVncPlatform<T>(
this T builder,
public static int StartWithHeadlessVncPlatform(
this AppBuilder builder,
string host, int port,
string[] args, ShutdownMode shutdownMode = ShutdownMode.OnLastWindowClose)
where T : AppBuilderBase<T>, new()
{
var tcpServer = new TcpListener(host == null ? IPAddress.Loopback : IPAddress.Parse(host), port);
tcpServer.Start();

3
src/Avalonia.Headless/AvaloniaHeadlessPlatform.cs

@ -94,8 +94,7 @@ namespace Avalonia.Headless
public static class AvaloniaHeadlessPlatformExtensions
{
public static T UseHeadless<T>(this T builder, AvaloniaHeadlessPlatformOptions opts)
where T : AppBuilderBase<T>, new()
public static AppBuilder UseHeadless(this AppBuilder builder, AvaloniaHeadlessPlatformOptions opts)
{
if(opts.UseHeadlessDrawing)
builder.UseRenderingSubsystem(HeadlessPlatformRenderInterface.Initialize, "Headless");

3
src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs

@ -6,8 +6,7 @@ namespace Avalonia
{
public static class AvaloniaNativePlatformExtensions
{
public static T UseAvaloniaNative<T>(this T builder)
where T : AppBuilderBase<T>, new()
public static AppBuilder UseAvaloniaNative(this AppBuilder builder)
{
builder.UseWindowingSubsystem(() =>
{

6
src/Avalonia.OpenGL/Egl/EglInterface.cs

@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Compatibility;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
using Avalonia.SourceGenerator;
@ -24,10 +25,9 @@ namespace Avalonia.OpenGL.Egl
static Func<string, IntPtr> Load()
{
var os = AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem;
if(os == OperatingSystemType.Linux)
if(OperatingSystemEx.IsLinux())
return Load("libEGL.so.1");
if (os == OperatingSystemType.Android)
if (OperatingSystemEx.IsAndroid())
return Load("libEGL.so");
throw new PlatformNotSupportedException();

3
src/Avalonia.ReactiveUI/AppBuilderExtensions.cs

@ -12,8 +12,7 @@ namespace Avalonia.ReactiveUI
/// scheduler, an activation for view fetcher, a template binding hook. Remember
/// to call this method if you are using ReactiveUI in your application.
/// </summary>
public static TAppBuilder UseReactiveUI<TAppBuilder>(this TAppBuilder builder)
where TAppBuilder : AppBuilderBase<TAppBuilder>, new() =>
public static AppBuilder UseReactiveUI(this AppBuilder builder) =>
builder.AfterPlatformServicesSetup(_ => Locator.RegisterResolverCallbackChanged(() =>
{
if (Locator.CurrentMutable is null)

2
src/Avalonia.X11/X11Platform.cs

@ -303,7 +303,7 @@ namespace Avalonia
}
public static class AvaloniaX11PlatformExtensions
{
public static T UseX11<T>(this T builder) where T : AppBuilderBase<T>, new()
public static AppBuilder UseX11(this AppBuilder builder)
{
builder.UseWindowingSubsystem(() =>
new AvaloniaX11Platform().Initialize(AvaloniaLocator.Current.GetService<X11PlatformOptions>() ??

7
src/Browser/Avalonia.Browser.Blazor/BlazorSingleViewLifetime.cs

@ -8,14 +8,13 @@ namespace Avalonia.Browser.Blazor;
[SupportedOSPlatform("browser")]
public static class WebAppBuilder
{
public static T SetupWithSingleViewLifetime<T>(
this T builder)
where T : AppBuilderBase<T>, new()
public static AppBuilder SetupWithSingleViewLifetime(
this AppBuilder builder)
{
return builder.SetupWithLifetime(new BlazorSingleViewLifetime());
}
public static T UseBlazor<T>(this T builder) where T : AppBuilderBase<T>, new()
public static AppBuilder UseBlazor(this AppBuilder builder)
{
return builder
.UseBrowser()

7
src/Browser/Avalonia.Browser/BrowserRuntimePlatform.cs

@ -11,12 +11,11 @@ internal class BrowserRuntimePlatform : StandardRuntimePlatform
{
private static readonly Lazy<RuntimePlatformInfo> Info = new(() =>
{
var isMobile = AvaloniaModule.IsMobile();
var result = new RuntimePlatformInfo
{
IsCoreClr = true, // WASM browser is always CoreCLR
IsBrowser = true, // BrowserRuntimePlatform only runs on Browser.
OperatingSystem = OperatingSystemType.Browser,
IsMobile = AvaloniaModule.IsMobile()
IsMobile = isMobile,
IsDesktop = !isMobile
};
return result;

12
src/Browser/Avalonia.Browser/BrowserSingleViewLifetime.cs

@ -2,8 +2,6 @@
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using System.Runtime.Versioning;
using Avalonia.Browser.Skia;
using Avalonia.Platform;
namespace Avalonia.Browser;
@ -27,9 +25,8 @@ public class BrowserPlatformOptions
[SupportedOSPlatform("browser")]
public static class WebAppBuilder
{
public static T SetupBrowserApp<T>(
this T builder, string mainDivId)
where T : AppBuilderBase<T>, new()
public static AppBuilder SetupBrowserApp(
this AppBuilder builder, string mainDivId)
{
var lifetime = new BrowserSingleViewLifetime();
@ -42,9 +39,8 @@ public static class WebAppBuilder
.SetupWithLifetime(lifetime);
}
public static T UseBrowser<T>(
this T builder)
where T : AppBuilderBase<T>, new()
public static AppBuilder UseBrowser(
this AppBuilder builder)
{
return builder
.UseWindowingSubsystem(BrowserWindowingPlatform.Register)

30
src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs

@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using System.Threading;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Controls.Embedding;
@ -12,11 +13,9 @@ using Avalonia.LinuxFramebuffer.Input;
using Avalonia.LinuxFramebuffer.Input.EvDev;
using Avalonia.LinuxFramebuffer.Input.LibInput;
using Avalonia.LinuxFramebuffer.Output;
using Avalonia.OpenGL;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Avalonia.Threading;
#nullable enable
namespace Avalonia.LinuxFramebuffer
@ -60,7 +59,7 @@ namespace Avalonia.LinuxFramebuffer
}
internal static LinuxFramebufferLifetime Initialize<T>(T builder, IOutputBackend outputBackend, IInputBackend? inputBackend) where T : AppBuilderBase<T>, new()
internal static LinuxFramebufferLifetime Initialize(AppBuilder builder, IOutputBackend outputBackend, IInputBackend? inputBackend)
{
var platform = new LinuxFramebufferPlatform(outputBackend);
builder.UseSkia().UseWindowingSubsystem(platform.Initialize, "fbdev");
@ -140,20 +139,17 @@ namespace Avalonia.LinuxFramebuffer
public static class LinuxFramebufferPlatformExtensions
{
public static int StartLinuxFbDev<T>(this T builder, string[] args, string? fbdev = null, double scaling = 1, IInputBackend? inputBackend = default)
where T : AppBuilderBase<T>, new() =>
StartLinuxDirect(builder, args, new FbdevOutput(fileName: fbdev, format: null) { Scaling = scaling }, inputBackend);
public static int StartLinuxFbDev<T>(this T builder, string[] args, string fbdev, PixelFormat? format, double scaling, IInputBackend? inputBackend = default)
where T : AppBuilderBase<T>, new() =>
StartLinuxDirect(builder, args, new FbdevOutput(fileName: fbdev, format: format) { Scaling = scaling }, inputBackend);
public static int StartLinuxDrm<T>(this T builder, string[] args, string? card = null, double scaling = 1, IInputBackend? inputBackend = default)
where T : AppBuilderBase<T>, new() => StartLinuxDirect(builder, args, new DrmOutput(card) { Scaling = scaling }, inputBackend);
public static int StartLinuxDrm<T>(this T builder, string[] args, string? card = null, bool connectorsForceProbe = false, DrmOutputOptions? options = null, IInputBackend? inputBackend = default)
where T : AppBuilderBase<T>, new() => StartLinuxDirect(builder, args, new DrmOutput(card, connectorsForceProbe, options), inputBackend);
public static int StartLinuxDirect<T>(this T builder, string[] args, IOutputBackend outputBackend, IInputBackend? inputBackend = default)
where T : AppBuilderBase<T>, new()
public static int StartLinuxFbDev(this AppBuilder builder, string[] args, string? fbdev = null, double scaling = 1, IInputBackend? inputBackend = default)
=> StartLinuxDirect(builder, args, new FbdevOutput(fileName: fbdev, format: null) { Scaling = scaling }, inputBackend);
public static int StartLinuxFbDev(this AppBuilder builder, string[] args, string fbdev, PixelFormat? format, double scaling, IInputBackend? inputBackend = default)
=> StartLinuxDirect(builder, args, new FbdevOutput(fileName: fbdev, format: format) { Scaling = scaling }, inputBackend);
public static int StartLinuxDrm(this AppBuilder builder, string[] args, string? card = null, double scaling = 1, IInputBackend? inputBackend = default)
=> StartLinuxDirect(builder, args, new DrmOutput(card) { Scaling = scaling }, inputBackend);
public static int StartLinuxDrm(this AppBuilder builder, string[] args, string? card = null, bool connectorsForceProbe = false, DrmOutputOptions? options = null, IInputBackend? inputBackend = default)
=> StartLinuxDirect(builder, args, new DrmOutput(card, connectorsForceProbe, options), inputBackend);
public static int StartLinuxDirect(this AppBuilder builder, string[] args, IOutputBackend outputBackend, IInputBackend? inputBackend = default)
{
var lifetime = LinuxFramebufferPlatform.Initialize(builder, outputBackend, inputBackend);
builder.SetupWithLifetime(lifetime);

1
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOptionMarkupExtensionTransformer.cs

@ -366,6 +366,7 @@ internal class AvaloniaXamlIlOptionMarkupExtensionTransformer : IXamlAstTransfor
foreach (var branch in ExtensionNodeContainer.Branches)
{
var next = codeGen.DefineLabel();
codeGen.Emit(OpCodes.Nop);
if (branch.HasContext)
{
codeGen.Ldloc(context.ContextLocal);

4
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnFormFactorExtension.cs

@ -6,7 +6,7 @@ using Avalonia.Platform;
namespace Avalonia.Markup.Xaml.MarkupExtensions;
public class OnFormFactorExtension : OnFormFactorExtensionBase<object, On>
public sealed class OnFormFactorExtension : OnFormFactorExtensionBase<object, On>
{
public OnFormFactorExtension()
{
@ -24,7 +24,7 @@ public class OnFormFactorExtension : OnFormFactorExtensionBase<object, On>
}
}
public class OnFormFactorExtension<TReturn> : OnFormFactorExtensionBase<TReturn, On<TReturn>>
public sealed class OnFormFactorExtension<TReturn> : OnFormFactorExtensionBase<TReturn, On<TReturn>>
{
public OnFormFactorExtension()
{

43
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnPlatformExtension.cs

@ -1,11 +1,11 @@
#nullable enable
using System;
using Avalonia.Compatibility;
using Avalonia.Metadata;
using Avalonia.Platform;
namespace Avalonia.Markup.Xaml.MarkupExtensions;
public class OnPlatformExtension : OnPlatformExtensionBase<object, On>
public sealed class OnPlatformExtension : OnPlatformExtensionBase<object, On>
{
public OnPlatformExtension()
{
@ -17,13 +17,13 @@ public class OnPlatformExtension : OnPlatformExtensionBase<object, On>
Default = defaultValue;
}
public static bool ShouldProvideOption(IServiceProvider serviceProvider, OperatingSystemType option)
public static bool ShouldProvideOption(string option)
{
return serviceProvider.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem == option;
return ShouldProvideOptionInternal(option);
}
}
public class OnPlatformExtension<TReturn> : OnPlatformExtensionBase<TReturn, On<TReturn>>
public sealed class OnPlatformExtension<TReturn> : OnPlatformExtensionBase<TReturn, On<TReturn>>
{
public OnPlatformExtension()
{
@ -35,9 +35,9 @@ public class OnPlatformExtension<TReturn> : OnPlatformExtensionBase<TReturn, On<
Default = defaultValue;
}
public static bool ShouldProvideOption(IServiceProvider serviceProvider, OperatingSystemType option)
public static bool ShouldProvideOption(string option)
{
return serviceProvider.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem == option;
return ShouldProvideOptionInternal(option);
}
}
@ -47,27 +47,44 @@ public abstract class OnPlatformExtensionBase<TReturn, TOn> : IAddChild<TOn>
[MarkupExtensionDefaultOption]
public TReturn? Default { get; set; }
[MarkupExtensionOption(OperatingSystemType.WinNT)]
[MarkupExtensionOption("WINDOWS")]
public TReturn? Windows { get; set; }
[MarkupExtensionOption(OperatingSystemType.OSX)]
[MarkupExtensionOption("OSX")]
// ReSharper disable once InconsistentNaming
public TReturn? macOS { get; set; }
[MarkupExtensionOption(OperatingSystemType.Linux)]
[MarkupExtensionOption("LINUX")]
public TReturn? Linux { get; set; }
[MarkupExtensionOption(OperatingSystemType.Android)]
[MarkupExtensionOption("ANDROID")]
public TReturn? Android { get; set; }
[MarkupExtensionOption(OperatingSystemType.iOS)]
[MarkupExtensionOption("IOS")]
// ReSharper disable once InconsistentNaming
public TReturn? iOS { get; set; }
[MarkupExtensionOption(OperatingSystemType.Browser)]
[MarkupExtensionOption("BROWSER")]
public TReturn? Browser { get; set; }
// Required for the compiler, will be replaced with actual method compile time.
public object ProvideValue() { return this; }
void IAddChild<TOn>.AddChild(TOn child) {}
private protected static bool ShouldProvideOptionInternal(string option)
{
// Instead of using OperatingSystem.IsOSPlatform(string) we use specific "Is***" methods so whole method can be trimmed by the mono linked.
// Keep in mind it works only with const "option" parameter.
// IsOSPlatform might work better with trimming in the future, so it should be re-visited after .NET 8/9.
return option switch
{
"WINDOWS" => OperatingSystemEx.IsWindows(),
"OSX" => OperatingSystemEx.IsMacOS(),
"LINUX" => OperatingSystemEx.IsLinux(),
"ANDROID" => OperatingSystemEx.IsAndroid(),
"IOS" => OperatingSystemEx.IsIOS(),
"BROWSER" => OperatingSystemEx.IsBrowser(),
_ => OperatingSystemEx.IsOSPlatform(option)
};
}
}

8
src/Skia/Avalonia.Skia/Helpers/PixelFormatHelper.cs

@ -1,4 +1,5 @@
using Avalonia.Platform;
using Avalonia.Compatibility;
using Avalonia.Platform;
using SkiaSharp;
namespace Avalonia.Skia.Helpers
@ -18,10 +19,7 @@ namespace Avalonia.Skia.Helpers
var colorType = format?.ToSkColorType() ?? SKImageInfo.PlatformColorType;
// TODO: This looks like some leftover hack
var runtimePlatform = AvaloniaLocator.Current?.GetService<IRuntimePlatform>();
var runtime = runtimePlatform?.GetRuntimeInfo();
if (runtime?.IsDesktop == true && runtime.Value.OperatingSystem == OperatingSystemType.Linux)
if (OperatingSystemEx.IsLinux())
{
colorType = SKColorType.Bgra8888;
}

3
src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs

@ -12,10 +12,9 @@ namespace Avalonia
/// <summary>
/// Enable Skia renderer.
/// </summary>
/// <typeparam name="T">Builder type.</typeparam>
/// <param name="builder">Builder.</param>
/// <returns>Configure builder.</returns>
public static T UseSkia<T>(this T builder) where T : AppBuilderBase<T>, new()
public static AppBuilder UseSkia(this AppBuilder builder)
{
return builder.UseRenderingSubsystem(() => SkiaPlatform.Initialize(
AvaloniaLocator.Current.GetService<SkiaOptions>() ?? new SkiaOptions()),

2
src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs

@ -16,7 +16,7 @@ namespace Avalonia
{
public static class Direct2DApplicationExtensions
{
public static T UseDirect2D1<T>(this T builder) where T : AppBuilderBase<T>, new()
public static AppBuilder UseDirect2D1(this AppBuilder builder)
{
builder.UseRenderingSubsystem(Direct2D1.Direct2D1Platform.Initialize, "Direct2D1");
return builder;

4
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -26,9 +26,7 @@ namespace Avalonia
#nullable enable
public static class Win32ApplicationExtensions
{
public static T UseWin32<T>(
this T builder)
where T : AppBuilderBase<T>, new()
public static AppBuilder UseWin32(this AppBuilder builder)
{
return builder.UseWindowingSubsystem(
() => Win32.Win32Platform.Initialize(

2
src/iOS/Avalonia.iOS/Platform.cs

@ -12,7 +12,7 @@ namespace Avalonia
{
public static class IOSApplicationExtensions
{
public static T UseiOS<T>(this T builder) where T : AppBuilderBase<T>, new()
public static AppBuilder UseiOS(this AppBuilder builder)
{
return builder
.UseWindowingSubsystem(iOS.Platform.Register, "iOS")

2
tests/Avalonia.Base.UnitTests/Media/Fonts/FontFamilyLoaderTests.cs

@ -117,7 +117,7 @@ namespace Avalonia.Base.UnitTests.Media.Fonts
private static IDisposable StartWithResources(params (string, string)[] assets)
{
var assetLoader = new MockAssetLoader(assets);
var services = new TestServices(assetLoader: assetLoader, platform: new AppBuilder().RuntimePlatform);
var services = new TestServices(assetLoader: assetLoader, platform: new StandardRuntimePlatform());
return UnitTestApplication.Start(services);
}
}

75
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/OnPlatformExtensionTests.cs

@ -1,75 +0,0 @@
using Avalonia.Controls;
using Avalonia.Platform;
using Xunit;
namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;
public class OnPlatformExtensionTests : XamlTestBase
{
[Fact]
public void Should_Resolve_Default_Value()
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(OperatingSystemType.Unknown));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<TextBlock Text='{OnPlatform Default=""Hello World""}'/>
</UserControl>";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = (TextBlock)userControl.Content!;
Assert.Equal("Hello World", textBlock.Text);
}
}
[Theory]
[InlineData(OperatingSystemType.WinNT, "Im Windows")]
[InlineData(OperatingSystemType.OSX, "Im macOS")]
[InlineData(OperatingSystemType.Linux, "Im Linux")]
[InlineData(OperatingSystemType.Android, "Im Android")]
[InlineData(OperatingSystemType.iOS, "Im iOS")]
[InlineData(OperatingSystemType.Browser, "Im Browser")]
[InlineData(OperatingSystemType.Unknown, "Default value")]
public void Should_Resolve_Expected_Value_Per_Platform(OperatingSystemType currentPlatform, string expectedResult)
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(currentPlatform));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<TextBlock Text='{OnPlatform ""Default value"",
Windows=""Im Windows"", macOS=""Im macOS"",
Linux=""Im Linux"", Android=""Im Android"",
iOS=""Im iOS"", Browser=""Im Browser""}'/>
</UserControl>";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = (TextBlock)userControl.Content!;
Assert.Equal(expectedResult, textBlock.Text);
}
}
private class TestRuntimePlatform : StandardRuntimePlatform
{
private readonly OperatingSystemType _operatingSystemType;
public TestRuntimePlatform(OperatingSystemType operatingSystemType)
{
_operatingSystemType = operatingSystemType;
}
public override RuntimePlatformInfo GetRuntimeInfo()
{
return new RuntimePlatformInfo() { OperatingSystem = _operatingSystemType };
}
}
}

2
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/OptionsMarkupExtensionTests.cs

@ -434,7 +434,7 @@ public class OptionsMarkupExtensionTests : XamlTestBase
<TextBlock xmlns='https://github.com/avaloniaui'
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
Text='{local:OptionsMarkupExtensionNoServiceProvider OptionB=""Im Option 2""}' />";
Text='{local:OptionsMarkupExtensionNoServiceProvider OptionB=""Im Option 2"", OptionA=""Im Option 1""}' />";
var textBlock = (TextBlock)AvaloniaRuntimeXamlLoader.Load(xaml);

14
tests/Avalonia.UnitTests/TestServices.cs

@ -20,7 +20,7 @@ namespace Avalonia.UnitTests
{
public static readonly TestServices StyledWindow = new TestServices(
assetLoader: new AssetLoader(),
platform: new AppBuilder().RuntimePlatform,
platform: new StandardRuntimePlatform(),
renderInterface: new MockPlatformRenderInterface(),
standardCursorFactory: Mock.Of<ICursorFactory>(),
theme: () => CreateSimpleTheme(),
@ -165,16 +165,4 @@ namespace Avalonia.UnitTests
y => y.Open() == Mock.Of<IStreamGeometryContextImpl>()));
}
}
public class AppBuilder : AppBuilderBase<AppBuilder>
{
public AppBuilder()
: base(new StandardRuntimePlatform(),
builder => StandardRuntimePlatformServices.Register(builder.Instance?.GetType()
?.GetTypeInfo().Assembly))
{
}
protected override bool CheckSetup => false;
}
}

Loading…
Cancel
Save