From 160613b47408b988e1855c1cee3ae889831a9f9d Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Fri, 23 Feb 2024 17:38:44 -0500 Subject: [PATCH] feat: Add Skia generic builder --- build/ci/.azure-devops-skia-tests.yml | 78 ++++------ global.json | 16 +-- .../SamplesApp.Skia.Generic/Program.cs | 47 ++++++ .../Properties/launchSettings.json | 17 +++ .../SamplesApp.Skia.Generic.csproj | 98 +++++++++++++ .../app.manifest | 0 .../Program.cs | 41 ------ .../Properties/launchSettings.json | 9 -- .../SamplesApp.Skia.Linux.FrameBuffer.csproj | 55 ------- .../SamplesApp.Skia.MacOS/Program.cs | 31 ---- .../SamplesApp.Skia.MacOS.csproj | 69 --------- .../SamplesApp.Skia.MacOS/app.manifest | 25 ---- src/SamplesApp/SamplesApp.Skia.Wpf/App.xaml | 8 -- .../SamplesApp.Skia.Wpf/App.xaml.cs | 33 ----- .../Properties/launchSettings.json | 8 -- .../SamplesApp.Skia.Wpf.csproj | 102 ------------- src/SamplesApp/SamplesApp.Skia.X11/Program.cs | 19 --- .../Properties/launchSettings.json | 12 -- .../SamplesApp.Skia.X11.csproj | 59 -------- src/Uno.Foundation.Logging/AssemblyInfo.cs | 1 + src/Uno.UI-Skia-only.slnf | 7 +- .../Builder/FramebufferHostBuilder.cs | 17 +++ .../Builder/HostBuilder.cs | 16 +++ .../FramebufferHost.cs | 15 +- ...o.UI.Runtime.Skia.Linux.FrameBuffer.csproj | 1 + .../Builder/HostBuilder.cs | 16 +++ .../Builder/MacOSHostBuilder.cs | 17 +++ src/Uno.UI.Runtime.Skia.MacOS/MacSkiaHost.cs | 7 +- .../Builder/HostBuilder.cs | 31 ++++ .../Builder/IWindowsSkiaHostBuilder.cs | 10 ++ .../Builder/WpfHostBuilder.cs | 136 ++++++++++++++++++ .../Uno.UI.Runtime.Skia.Wpf.csproj | 13 +- src/Uno.UI.Runtime.Skia.Wpf/WpfHost.cs | 23 ++- .../Builder/HostBuilder.cs | 16 +++ .../Builder/X11HostBuilder.cs | 17 +++ .../Uno.UI.Runtime.Skia.X11.csproj | 1 + .../X11ApplicationHost.cs | 13 +- src/Uno.UI.Runtime.Skia/AssemblyInfo.cs | 8 ++ .../IPlatformHostBuilder.cs | 9 ++ src/Uno.UI.Runtime.Skia/ISkiaHostBuilder.cs | 13 ++ src/Uno.UI.Runtime.Skia/SkiaHost.cs | 6 +- src/Uno.UI.Runtime.Skia/SkiaHostBuilder.cs | 75 ++++++++++ .../SkiaHostBuilderExtensions.cs | 17 +++ .../Uno.UI.Runtime.Skia.csproj | 14 +- src/Uno.UI.sln | 4 +- src/Uno.UWP/AssemblyInfo.cs | 1 - 46 files changed, 673 insertions(+), 558 deletions(-) create mode 100644 src/SamplesApp/SamplesApp.Skia.Generic/Program.cs create mode 100644 src/SamplesApp/SamplesApp.Skia.Generic/Properties/launchSettings.json create mode 100644 src/SamplesApp/SamplesApp.Skia.Generic/SamplesApp.Skia.Generic.csproj rename src/SamplesApp/{SamplesApp.Skia.Wpf => SamplesApp.Skia.Generic}/app.manifest (100%) delete mode 100644 src/SamplesApp/SamplesApp.Skia.Linux.FrameBuffer/Program.cs delete mode 100644 src/SamplesApp/SamplesApp.Skia.Linux.FrameBuffer/Properties/launchSettings.json delete mode 100644 src/SamplesApp/SamplesApp.Skia.Linux.FrameBuffer/SamplesApp.Skia.Linux.FrameBuffer.csproj delete mode 100644 src/SamplesApp/SamplesApp.Skia.MacOS/Program.cs delete mode 100644 src/SamplesApp/SamplesApp.Skia.MacOS/SamplesApp.Skia.MacOS.csproj delete mode 100644 src/SamplesApp/SamplesApp.Skia.MacOS/app.manifest delete mode 100644 src/SamplesApp/SamplesApp.Skia.Wpf/App.xaml delete mode 100644 src/SamplesApp/SamplesApp.Skia.Wpf/App.xaml.cs delete mode 100644 src/SamplesApp/SamplesApp.Skia.Wpf/Properties/launchSettings.json delete mode 100644 src/SamplesApp/SamplesApp.Skia.Wpf/SamplesApp.Skia.Wpf.csproj delete mode 100644 src/SamplesApp/SamplesApp.Skia.X11/Program.cs delete mode 100644 src/SamplesApp/SamplesApp.Skia.X11/Properties/launchSettings.json delete mode 100644 src/SamplesApp/SamplesApp.Skia.X11/SamplesApp.Skia.X11.csproj create mode 100644 src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Builder/FramebufferHostBuilder.cs create mode 100644 src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Builder/HostBuilder.cs create mode 100644 src/Uno.UI.Runtime.Skia.MacOS/Builder/HostBuilder.cs create mode 100644 src/Uno.UI.Runtime.Skia.MacOS/Builder/MacOSHostBuilder.cs create mode 100644 src/Uno.UI.Runtime.Skia.Wpf/Builder/HostBuilder.cs create mode 100644 src/Uno.UI.Runtime.Skia.Wpf/Builder/IWindowsSkiaHostBuilder.cs create mode 100644 src/Uno.UI.Runtime.Skia.Wpf/Builder/WpfHostBuilder.cs create mode 100644 src/Uno.UI.Runtime.Skia.X11/Builder/HostBuilder.cs create mode 100644 src/Uno.UI.Runtime.Skia.X11/Builder/X11HostBuilder.cs create mode 100644 src/Uno.UI.Runtime.Skia/AssemblyInfo.cs create mode 100644 src/Uno.UI.Runtime.Skia/IPlatformHostBuilder.cs create mode 100644 src/Uno.UI.Runtime.Skia/ISkiaHostBuilder.cs create mode 100644 src/Uno.UI.Runtime.Skia/SkiaHostBuilder.cs create mode 100644 src/Uno.UI.Runtime.Skia/SkiaHostBuilderExtensions.cs diff --git a/build/ci/.azure-devops-skia-tests.yml b/build/ci/.azure-devops-skia-tests.yml index 713c9d7e6ef8..9671f6fe5df2 100644 --- a/build/ci/.azure-devops-skia-tests.yml +++ b/build/ci/.azure-devops-skia-tests.yml @@ -59,17 +59,6 @@ jobs: ArtifactName: skia-gtk-samples-app-$(XAML_FLAVOR_BUILD) ArtifactType: Container - - powershell: dotnet msbuild src/SamplesApp/SamplesApp.Skia.WPF/SamplesApp.Skia.WPF.csproj /r /m /p:Configuration=Release /detailedsummary /m /bl:$(build.artifactstagingdirectory)\build-wpf.binlog - displayName: Build WPF Head - - - task: PublishBuildArtifacts@1 - retryCountOnTaskFailure: 3 - condition: always() - inputs: - PathtoPublish: $(Build.SourcesDirectory)\src\SamplesApp\SamplesApp.Skia.WPF\bin\Release\net7.0-windows - ArtifactName: skia-wpf-samples-app-$(XAML_FLAVOR_BUILD) - ArtifactType: Container - - powershell: dotnet msbuild src/SamplesApp/UnoIslandsSamplesApp.Skia.WPF/UnoIslandsSamplesApp.Skia.Wpf.csproj /r /m /p:Configuration=Release /detailedsummary /m /bl:$(build.artifactstagingdirectory)\build-wpf-islands.binlog displayName: Build WPF Islands Head @@ -81,26 +70,15 @@ jobs: ArtifactName: uno-islands-skia-wpf-samples-app-$(XAML_FLAVOR_BUILD) ArtifactType: Container - - powershell: dotnet publish src/SamplesApp/SamplesApp.Skia.Linux.FrameBuffer/SamplesApp.Skia.Linux.FrameBuffer.csproj -c Release -f net7.0 /bl:$(build.artifactstagingdirectory)\build-framebuffer.binlog - displayName: Build Framebuffer Head + - powershell: dotnet publish src/SamplesApp/SamplesApp.Skia.Generic/SamplesApp.Skia.Generic.csproj -c Release -f net7.0 /bl:$(build.artifactstagingdirectory)\build-x11.binlog + displayName: Build Generic Skia Head - task: PublishBuildArtifacts@1 retryCountOnTaskFailure: 3 condition: always() inputs: - PathtoPublish: $(Build.SourcesDirectory)\src\SamplesApp\SamplesApp.Skia.Linux.FrameBuffer\bin\Release\net7.0 - ArtifactName: skia-framebuffer-samples-app-$(XAML_FLAVOR_BUILD) - ArtifactType: Container - - - powershell: dotnet publish src/SamplesApp/SamplesApp.Skia.X11/SamplesApp.Skia.X11.csproj -c Release -f net7.0 /bl:$(build.artifactstagingdirectory)\build-x11.binlog - displayName: Build X11 Head - - - task: PublishBuildArtifacts@1 - retryCountOnTaskFailure: 3 - condition: always() - inputs: - PathtoPublish: $(Build.SourcesDirectory)\src\SamplesApp\SamplesApp.Skia.X11\bin\Release\net7.0 - ArtifactName: skia-x11-samples-app-$(XAML_FLAVOR_BUILD) + PathtoPublish: $(Build.SourcesDirectory)\src\SamplesApp\SamplesApp.Skia.Generic\bin\Release\net7.0 + ArtifactName: skia-generic-samples-app-$(XAML_FLAVOR_BUILD) ArtifactType: Container - task: PublishBuildArtifacts@1 @@ -243,8 +221,8 @@ jobs: ## WPF ## -- job: Skia_Wpf_Screenshot_Tests - displayName: 'Run Skia WPF Snapshot Tests' +- job: Skia_Windows_Screenshot_Tests + displayName: 'Run Skia Windows Snapshot Tests' timeoutInMinutes: 60 pool: @@ -254,7 +232,7 @@ jobs: condition: and(succeeded(), eq(variables['UNO_UWP_BUILD'], 'false')) variables: - SamplesAppArtifactName: skia-wpf-samples-app-WinUI + SamplesAppArtifactName: skia-generic-samples-app-WinUI SamplesAppArtifactPath: $(build.sourcesdirectory)/build/$(SamplesAppArtifactName) UNO_UWP_BUILD: ${{ parameters.UNO_UWP_BUILD }} @@ -270,9 +248,9 @@ jobs: - script: | cd $(SamplesAppArtifactPath) - dotnet SamplesApp.Skia.Wpf.dll --auto-screenshots=$(build.artifactstagingdirectory)/screenshots/skia-wpf-screenshots + dotnet SamplesApp.Skia.Generic.dll --auto-screenshots=$(build.artifactstagingdirectory)/screenshots/skia-windows-screenshots - displayName: Run Skia WPF Snapshot Tests + displayName: Run Skia Windows Snapshot Tests - task: PublishBuildArtifacts@1 condition: always() @@ -282,8 +260,8 @@ jobs: ArtifactName: uitests-results ArtifactType: Container -- job: Skia_Wpf_Runtime_Tests_Build - displayName: 'Run Skia WPF Runtime Tests' +- job: Skia_Windows_Runtime_Tests_Build + displayName: 'Run Skia Windows Runtime Tests' timeoutInMinutes: 60 pool: @@ -292,7 +270,7 @@ jobs: dependsOn: Skia_Tests_Build variables: - SamplesAppArtifactName: skia-wpf-samples-app-$(XAML_FLAVOR_BUILD) + SamplesAppArtifactName: skia-generic-samples-app-$(XAML_FLAVOR_BUILD) SamplesAppArtifactPath: $(build.sourcesdirectory)/build/$(SamplesAppArtifactName) UNO_UWP_BUILD: ${{ parameters.UNO_UWP_BUILD }} @@ -308,16 +286,16 @@ jobs: - script: | cd $(SamplesAppArtifactPath) - dotnet SamplesApp.Skia.Wpf.dll --runtime-tests=$(build.sourcesdirectory)/build/skia-wpf-runtime-tests-results.xml + dotnet SamplesApp.Skia.Generic.dll --runtime-tests=$(build.sourcesdirectory)/build/skia-windows-runtime-tests-results.xml - displayName: Run Skia WPF $(XAML_FLAVOR_BUILD) Runtime Tests + displayName: Run Skia Windows $(XAML_FLAVOR_BUILD) Runtime Tests - task: PublishTestResults@2 condition: always() inputs: - testRunTitle: 'Skia WPF $(XAML_FLAVOR_BUILD) Runtime Tests' + testRunTitle: 'Skia Windows $(XAML_FLAVOR_BUILD) Runtime Tests' testResultsFormat: 'NUnit' - testResultsFiles: '$(build.sourcesdirectory)/build/skia-wpf-runtime-tests-results.xml' + testResultsFiles: '$(build.sourcesdirectory)/build/skia-windows-runtime-tests-results.xml' failTaskOnFailedTests: true - job: Uno_Islands_Skia_Wpf_Runtime_Tests_Build @@ -362,8 +340,8 @@ jobs: ## X11 ## -- job: Skia_X11_Screenshot_Tests - displayName: 'Run Skia X11 Snapshot Tests' +- job: Skia_Linux_Screenshot_Tests + displayName: 'Run Skia Linux Snapshot Tests' timeoutInMinutes: 60 pool: @@ -373,7 +351,7 @@ jobs: condition: and(succeeded(), eq(variables['UNO_UWP_BUILD'], 'false')) variables: - SamplesAppArtifactName: skia-x11-samples-app-WinUI + SamplesAppArtifactName: skia-linux-samples-app-WinUI SamplesAppArtifactPath: $(build.sourcesdirectory)/build/$(SamplesAppArtifactName) UNO_UWP_BUILD: ${{ parameters.UNO_UWP_BUILD }} XAML_FLAVOR_BUILD: ${{ parameters.XAML_FLAVOR_BUILD }} @@ -389,9 +367,9 @@ jobs: - script: | cd $(build.sourcesdirectory)/build/$(SamplesAppArtifactName) - xvfb-run --auto-servernum --server-args='-screen 0 1280x1024x24' sh -c '{ fluxbox & } ; dotnet SamplesApp.Skia.X11.dll --auto-screenshots=$(build.artifactstagingdirectory)/screenshots/skia-x11-screenshots' + xvfb-run --auto-servernum --server-args='-screen 0 1280x1024x24' sh -c '{ fluxbox & } ; dotnet SamplesApp.Skia.Generic.dll --auto-screenshots=$(build.artifactstagingdirectory)/screenshots/skia-linux-screenshots' - displayName: Run Skia X11 Snapshot Tests + displayName: Run Skia Linux Snapshot Tests - task: PublishBuildArtifacts@1 condition: always() @@ -401,8 +379,8 @@ jobs: ArtifactName: uitests-results ArtifactType: Container -- job: Skia_X11_Runtime_Tests_Build - displayName: 'Run Skia X11 Runtime Tests' +- job: Skia_Linux_Runtime_Tests_Build + displayName: 'Run Skia Linux Runtime Tests' timeoutInMinutes: 60 pool: @@ -411,7 +389,7 @@ jobs: dependsOn: Skia_Tests_Build variables: - SamplesAppArtifactName: skia-x11-samples-app-$(XAML_FLAVOR_BUILD) + SamplesAppArtifactName: skia-linux-samples-app-$(XAML_FLAVOR_BUILD) SamplesAppArtifactPath: $(build.sourcesdirectory)/build/$(SamplesAppArtifactName) UNO_UWP_BUILD: ${{ parameters.UNO_UWP_BUILD }} @@ -431,7 +409,7 @@ jobs: - script: | cd $(SamplesAppArtifactPath) - xvfb-run --auto-servernum --server-args='-screen 0 1280x1024x24' sh -c '{ fluxbox & } ; dotnet SamplesApp.Skia.X11.dll --runtime-tests=$(build.sourcesdirectory)/build/skia-x11-runtime-tests-results.xml' + xvfb-run --auto-servernum --server-args='-screen 0 1280x1024x24' sh -c '{ fluxbox & } ; dotnet SamplesApp.Skia.Generic.dll --runtime-tests=$(build.sourcesdirectory)/build/skia-linux-runtime-tests-results.xml' displayName: Run Skia $(XAML_FLAVOR_BUILD) Runtime Tests env: @@ -441,7 +419,7 @@ jobs: - task: PublishTestResults@2 condition: always() inputs: - testRunTitle: 'Skia X11 $(XAML_FLAVOR_BUILD) Runtime Tests' + testRunTitle: 'Skia Linux $(XAML_FLAVOR_BUILD) Runtime Tests' testResultsFormat: 'NUnit' - testResultsFiles: '$(build.sourcesdirectory)/build/skia-x11-runtime-tests-results.xml' - failTaskOnFailedTests: true \ No newline at end of file + testResultsFiles: '$(build.sourcesdirectory)/build/skia-linux-runtime-tests-results.xml' + failTaskOnFailedTests: true diff --git a/global.json b/global.json index 5e89ae19cbcd..57804b9a009e 100644 --- a/global.json +++ b/global.json @@ -1,12 +1,12 @@ { - "sdk": { - "version": "7.0.302", - "allowPrerelease": false, - "rollForward": "latestFeature" - }, - "tools": { - "dotnet": "7.0.302" - }, + //"sdk": { + // "version": "7.0.302", + // "allowPrerelease": false, + // "rollForward": "latestFeature" + //}, + //"tools": { + // "dotnet": "7.0.302" + //}, "msbuild-sdks": { "MSBuild.Sdk.Extras": "3.0.44", "Microsoft.Build.NoTargets": "3.7.56" diff --git a/src/SamplesApp/SamplesApp.Skia.Generic/Program.cs b/src/SamplesApp/SamplesApp.Skia.Generic/Program.cs new file mode 100644 index 000000000000..ffdd29edc600 --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.Generic/Program.cs @@ -0,0 +1,47 @@ +#nullable enable + +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Uno.UI.Runtime.Skia; + +namespace SkiaSharpExample +{ + class MainClass + { + static SamplesApp.App? _app; + + [STAThread] + public static void Main(string[] args) + { + SamplesApp.App.ConfigureLogging(); // Enable tracing of the host + + var host = SkiaHostBuilder.Create() + .App(() => _app = new SamplesApp.App()) + .AfterInit(() => + { + if (_app is not null && OperatingSystem.IsWindows()) + { + _app.MainWindowActivated += delegate + { + var windowContent = System.Windows.Application.Current.Windows[0].Content; + Assert.IsInstanceOfType(windowContent, typeof(System.Windows.UIElement)); + var windowContentAsUIElement = (System.Windows.UIElement)windowContent; + Assert.IsTrue(windowContentAsUIElement.IsFocused); + }; + } + }) + .UseX11() + .UseLinuxFrameBuffer() + .UseWindows(b => b + .WpfApplication(() => + { + // optional app creation + return new System.Windows.Application(); + })) + .UseMacOS() + .Build(); + + host.Run(); + } + } +} diff --git a/src/SamplesApp/SamplesApp.Skia.Generic/Properties/launchSettings.json b/src/SamplesApp/SamplesApp.Skia.Generic/Properties/launchSettings.json new file mode 100644 index 000000000000..873bc5c3fdc9 --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.Generic/Properties/launchSettings.json @@ -0,0 +1,17 @@ +{ + "profiles": { + "SamplesApp.Skia.Generic": { + "commandName": "Project", + "nativeDebugging": false, + "environmentVariables": { + //"COREHOST_TRACE": "1", + //"COREHOST_TRACE_VERBOSITY": "4" + // "DOTNET_ADDITIONAL_DEPS": "C:\\Program Files\\dotnet\\shared\\Microsoft.WindowsDesktop.App\\8.0.2\\Microsoft.WindowsDesktop.App.deps.json" + } + }, + "WSL": { + "commandName": "WSL2", + "distributionName": "" + } + } +} diff --git a/src/SamplesApp/SamplesApp.Skia.Generic/SamplesApp.Skia.Generic.csproj b/src/SamplesApp/SamplesApp.Skia.Generic/SamplesApp.Skia.Generic.csproj new file mode 100644 index 000000000000..ac5934436c1d --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.Generic/SamplesApp.Skia.Generic.csproj @@ -0,0 +1,98 @@ + + + $(NetSkiaPreviousAndCurrent) + Major + true + + + + + + Exe + + + true + + + Major + + app.manifest + + + + + + + + + + + + + + <_Parameter1>false + + + <_Parameter1>System.Windows.ResourceDictionaryLocation.None + <_Parameter1_IsLiteral>true + <_Parameter2>System.Windows.ResourceDictionaryLocation.SourceAssembly + <_Parameter2_IsLiteral>true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(MSBuildThisFileDirectory)..\..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow + + + + + + + + <_validationPath Include="Uno.Fonts.Fluent/Fonts/uno-fluentui-assets.ttf" /> + <_validationPath Include="Uno.UI.RuntimeTests/Assets/Fonts/uno-fluentui-assets-runtimetest01.ttf" /> + + + + + + + + + + + + + + <_RuntimeFrameworkToRemove Include="@(RuntimeFramework)" Condition="'%(Identity)'=='Microsoft.WindowsDesktop.App'" /> + + + + diff --git a/src/SamplesApp/SamplesApp.Skia.Wpf/app.manifest b/src/SamplesApp/SamplesApp.Skia.Generic/app.manifest similarity index 100% rename from src/SamplesApp/SamplesApp.Skia.Wpf/app.manifest rename to src/SamplesApp/SamplesApp.Skia.Generic/app.manifest diff --git a/src/SamplesApp/SamplesApp.Skia.Linux.FrameBuffer/Program.cs b/src/SamplesApp/SamplesApp.Skia.Linux.FrameBuffer/Program.cs deleted file mode 100644 index 3ceb8dd7fb02..000000000000 --- a/src/SamplesApp/SamplesApp.Skia.Linux.FrameBuffer/Program.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using SkiaSharp; -using Uno.Foundation.Extensibility; -using System.Threading; -using Uno.UI.Runtime.Skia.Linux.FrameBuffer; -using Microsoft.UI.Xaml; -using Windows.UI.Core; - -namespace SkiaSharpExample -{ - class MainClass - { - [STAThread] - public static void Main(string[] args) - { - try - { - SamplesApp.App.ConfigureLogging(); // Enable tracing of the host - - Console.CursorVisible = false; - var host = new FrameBufferHost(() => - { - CoreWindow.GetForCurrentThreadSafe().KeyDown += (s, e) => - { - if (e.VirtualKey == Windows.System.VirtualKey.F12) - { - Application.Current.Exit(); - } - }; - - return new SamplesApp.App(); - }); - host.Run(); - } - finally - { - Console.CursorVisible = true; - } - } - } -} diff --git a/src/SamplesApp/SamplesApp.Skia.Linux.FrameBuffer/Properties/launchSettings.json b/src/SamplesApp/SamplesApp.Skia.Linux.FrameBuffer/Properties/launchSettings.json deleted file mode 100644 index 076831efa636..000000000000 --- a/src/SamplesApp/SamplesApp.Skia.Linux.FrameBuffer/Properties/launchSettings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "profiles": { - "SamplesApp.Skia.Gtk": { - "commandName": "Project", - "commandLineArgs": "--_auto-screenshots=C:\\temp\\screenshots", - "nativeDebugging": false - } - } -} diff --git a/src/SamplesApp/SamplesApp.Skia.Linux.FrameBuffer/SamplesApp.Skia.Linux.FrameBuffer.csproj b/src/SamplesApp/SamplesApp.Skia.Linux.FrameBuffer/SamplesApp.Skia.Linux.FrameBuffer.csproj deleted file mode 100644 index 365ad1d060a7..000000000000 --- a/src/SamplesApp/SamplesApp.Skia.Linux.FrameBuffer/SamplesApp.Skia.Linux.FrameBuffer.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - $(NetSkiaPreviousAndCurrent) - Major - - - - - - Exe - - - true - - - - - - - - - - - - - - - - - - - - - - - - - $(MSBuildThisFileDirectory)..\..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow - - - - - - - - <_validationPath Include="Uno.Fonts.Fluent/Fonts/uno-fluentui-assets.ttf"/> - <_validationPath Include="Uno.UI.RuntimeTests/Assets/Fonts/uno-fluentui-assets-runtimetest01.ttf"/> - - - - - - diff --git a/src/SamplesApp/SamplesApp.Skia.MacOS/Program.cs b/src/SamplesApp/SamplesApp.Skia.MacOS/Program.cs deleted file mode 100644 index 448d2a967239..000000000000 --- a/src/SamplesApp/SamplesApp.Skia.MacOS/Program.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -// using Uno.Foundation.Extensibility; -// using Uno.Media.Playback; - -using Uno.UI.Runtime.Skia.MacOS; - -namespace SkiaSharpExample; - -public class MainClass -{ - [STAThread] - public static void Main() - { - SamplesApp.App.ConfigureLogging(); // Enable tracing of the host - - // ApiExtensibility.Register(typeof(IMediaPlayerExtension), o => new Uno.UI.Media.MediaPlayerExtension(o)); - // ApiExtensibility.Register(typeof(IMediaPlayerPresenterExtension), o => new Uno.UI.Media.MediaPlayerPresenterExtension(o)); - - AppDomain.CurrentDomain.UnhandledException += delegate (object sender, System.UnhandledExceptionEventArgs args) - { - Console.WriteLine($"UNHANDLED {(args.IsTerminating ? "FINAL" : "")} EXCEPTION {args.ExceptionObject}"); - }; - - var host = new MacSkiaHost(() => new SamplesApp.App()); -#if IS_CI - // macOS virtualization often mess up with Metal support, see https://github.com/actions/runner-images/issues/1779 - host.RenderSurfaceType = RenderSurfaceType.Software; -#endif - host.Run(); - } -} diff --git a/src/SamplesApp/SamplesApp.Skia.MacOS/SamplesApp.Skia.MacOS.csproj b/src/SamplesApp/SamplesApp.Skia.MacOS/SamplesApp.Skia.MacOS.csproj deleted file mode 100644 index d7b2a5ec727c..000000000000 --- a/src/SamplesApp/SamplesApp.Skia.MacOS/SamplesApp.Skia.MacOS.csproj +++ /dev/null @@ -1,69 +0,0 @@ - - - $(NetSkiaPreviousAndCurrent) - Major - app.manifest - - - - - - Exe - - - true - - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - $(MSBuildThisFileDirectory)..\..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow - - - - - - - - - - <_XcodeBuildArgs Condition="'$(Configuration)'=='Debug'">build-for-testing -scheme UnoNativeMac - - - - - - - - - - - - - diff --git a/src/SamplesApp/SamplesApp.Skia.MacOS/app.manifest b/src/SamplesApp/SamplesApp.Skia.MacOS/app.manifest deleted file mode 100644 index 3b7ed29dd546..000000000000 --- a/src/SamplesApp/SamplesApp.Skia.MacOS/app.manifest +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - true/PM - PerMonitorV2, PerMonitor - - - diff --git a/src/SamplesApp/SamplesApp.Skia.Wpf/App.xaml b/src/SamplesApp/SamplesApp.Skia.Wpf/App.xaml deleted file mode 100644 index 2629eee8358e..000000000000 --- a/src/SamplesApp/SamplesApp.Skia.Wpf/App.xaml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - diff --git a/src/SamplesApp/SamplesApp.Skia.Wpf/App.xaml.cs b/src/SamplesApp/SamplesApp.Skia.Wpf/App.xaml.cs deleted file mode 100644 index 5157ab29cc7b..000000000000 --- a/src/SamplesApp/SamplesApp.Skia.Wpf/App.xaml.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Windows; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Uno.UI.Runtime.Skia.Wpf; - -namespace SamplesApp.Wpf -{ - /// - /// Interaction logic for App.xaml - /// - public partial class App : System.Windows.Application - { - private SamplesApp.App _app; - - public App() - { - SamplesApp.App.ConfigureLogging(); - - var host = new WpfHost(Dispatcher, () => _app ??= new SamplesApp.App()); - - host.Run(); - - _app.MainWindowActivated += OnMainWindowActivated; - } - - private void OnMainWindowActivated(object sender, System.EventArgs e) - { - var windowContent = Application.Current.Windows[0].Content; - Assert.IsInstanceOfType(windowContent, typeof(System.Windows.UIElement)); - var windowContentAsUIElement = (System.Windows.UIElement)windowContent; - Assert.IsTrue(windowContentAsUIElement.IsFocused); - } - } -} diff --git a/src/SamplesApp/SamplesApp.Skia.Wpf/Properties/launchSettings.json b/src/SamplesApp/SamplesApp.Skia.Wpf/Properties/launchSettings.json deleted file mode 100644 index 8ea9b65db229..000000000000 --- a/src/SamplesApp/SamplesApp.Skia.Wpf/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "SamplesApp.Skia.Wpf": { - "commandName": "Project", - "commandLineArgs": "" - } - } -} diff --git a/src/SamplesApp/SamplesApp.Skia.Wpf/SamplesApp.Skia.Wpf.csproj b/src/SamplesApp/SamplesApp.Skia.Wpf/SamplesApp.Skia.Wpf.csproj deleted file mode 100644 index c5422750aa06..000000000000 --- a/src/SamplesApp/SamplesApp.Skia.Wpf/SamplesApp.Skia.Wpf.csproj +++ /dev/null @@ -1,102 +0,0 @@ - - - $(NetPreviousWpf) - $(TargetFrameworks);$(NetCurrentWpf) - - - - - - - Major - - - true - - - - - <_Parameter1>false - - - <_Parameter1>System.Windows.ResourceDictionaryLocation.None - <_Parameter1_IsLiteral>true - <_Parameter2>System.Windows.ResourceDictionaryLocation.SourceAssembly - <_Parameter2_IsLiteral>true - - - - - Exe - true - app.manifest - - - $(NoWarn);NU5104 - - - - - - - - - - - - - - - - - - - - - - {6ffac28c-aced-4ba1-954d-7e720b035928} - Uno.Xaml - unoxaml - - - {9f2268e0-49cc-43e6-a59f-5f5219349545} - Uno.Foundation.Skia - - - {dd7daec9-8f20-440a-81cd-8ed00dbc96d5} - Uno.UI.Runtime.Skia.Wpf - - - {2d066b5f-f67e-469c-abc6-5c3fcb8dda7a} - Uno.UI.Skia - - - {e2985032-e07e-4d8b-b716-8c96bb519ae3} - Uno.Skia - - - {1023dc8a-7fd7-41d1-9fd3-4142b2c76d00} - SamplesApp.Skia - - - - - - True - - - - - $(MSBuildThisFileDirectory)..\..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow - - - - - - - - - diff --git a/src/SamplesApp/SamplesApp.Skia.X11/Program.cs b/src/SamplesApp/SamplesApp.Skia.X11/Program.cs deleted file mode 100644 index f905f01b2d4f..000000000000 --- a/src/SamplesApp/SamplesApp.Skia.X11/Program.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using Uno.WinUI.Runtime.Skia.X11; - -namespace SkiaSharpExample -{ - class MainClass - { - [STAThread] - public static void Main(string[] args) - { - // WARNING: don't make any X11 calls until X11ApplicationHost is instantiated. - - SamplesApp.App.ConfigureLogging(); // Enable tracing of the host - - var host = new X11ApplicationHost(() => new SamplesApp.App()); - host.Run(); - } - } -} diff --git a/src/SamplesApp/SamplesApp.Skia.X11/Properties/launchSettings.json b/src/SamplesApp/SamplesApp.Skia.X11/Properties/launchSettings.json deleted file mode 100644 index d518d0f5a03e..000000000000 --- a/src/SamplesApp/SamplesApp.Skia.X11/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "SamplesApp.Skia.X11": { - "commandName": "Project", - "nativeDebugging": false - }, - "WSL": { - "commandName": "WSL2", - "distributionName": "" - } - } -} diff --git a/src/SamplesApp/SamplesApp.Skia.X11/SamplesApp.Skia.X11.csproj b/src/SamplesApp/SamplesApp.Skia.X11/SamplesApp.Skia.X11.csproj deleted file mode 100644 index d03df871b210..000000000000 --- a/src/SamplesApp/SamplesApp.Skia.X11/SamplesApp.Skia.X11.csproj +++ /dev/null @@ -1,59 +0,0 @@ - - - $(NetSkiaPreviousAndCurrent) - Major - true - - - - - - Exe - - - true - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - $(MSBuildThisFileDirectory)..\..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow - - - - - - - - <_validationPath Include="Uno.Fonts.Fluent/Fonts/uno-fluentui-assets.ttf"/> - <_validationPath Include="Uno.UI.RuntimeTests/Assets/Fonts/uno-fluentui-assets-runtimetest01.ttf"/> - - - - - - diff --git a/src/Uno.Foundation.Logging/AssemblyInfo.cs b/src/Uno.Foundation.Logging/AssemblyInfo.cs index 98df29340eb7..3e3b0f6d7d14 100644 --- a/src/Uno.Foundation.Logging/AssemblyInfo.cs +++ b/src/Uno.Foundation.Logging/AssemblyInfo.cs @@ -41,3 +41,4 @@ [assembly: InternalsVisibleTo("Uno.UI.Adapter.Microsoft.Extensions.Logging")] [assembly: InternalsVisibleTo("Uno.UI.Composition")] [assembly: InternalsVisibleTo("Uno.UI.Dispatching")] +[assembly: InternalsVisibleTo("Uno.UI.Runtime.Skia")] diff --git a/src/Uno.UI-Skia-only.slnf b/src/Uno.UI-Skia-only.slnf index 3ce5ab2ce53a..a570c5eb7492 100644 --- a/src/Uno.UI-Skia-only.slnf +++ b/src/Uno.UI-Skia-only.slnf @@ -9,10 +9,8 @@ "SamplesApp\\Benchmarks.Shared\\SamplesApp.Benchmarks.shproj", "SamplesApp\\SamplesApp.Shared\\SamplesApp.Shared.shproj", "SamplesApp\\SamplesApp.Skia.Gtk\\SamplesApp.Skia.Gtk.csproj", - "SamplesApp\\SamplesApp.Skia.Linux.FrameBuffer\\SamplesApp.Skia.Linux.FrameBuffer.csproj", "SamplesApp\\SamplesApp.Skia.MacOS\\SamplesApp.Skia.MacOS.csproj", - "SamplesApp\\SamplesApp.Skia.Wpf\\SamplesApp.Skia.Wpf.csproj", - "SamplesApp\\SamplesApp.Skia.X11\\SamplesApp.Skia.X11.csproj", + "SamplesApp\\SamplesApp.Skia.Generic\\SamplesApp.Skia.Generic.csproj", "SamplesApp\\SamplesApp.Skia\\SamplesApp.Skia.csproj", "SamplesApp\\SamplesApp.UITests.Generator\\Uno.Samples.UITest.Generator.csproj", "SamplesApp\\SamplesApp.UITests\\SamplesApp.UITests.csproj", @@ -48,6 +46,7 @@ "Uno.UI.Runtime.Skia.MacOS\\Uno.UI.Runtime.Skia.MacOS.csproj", "Uno.UI.Runtime.Skia.Wpf\\Uno.UI.Runtime.Skia.Wpf.csproj", "Uno.UI.Runtime.Skia.X11\\Uno.UI.Runtime.Skia.X11.csproj", + "Uno.UI.Runtime.Skia\\Uno.UI.Runtime.Skia.csproj", "Uno.UI.RuntimeTests\\Uno.UI.RuntimeTests.Skia.csproj", "Uno.UI.TestComparer\\Uno.UI.TestComparer.csproj", "Uno.UI.Toolkit\\Uno.UI.Toolkit.Skia.csproj", @@ -59,4 +58,4 @@ "Uno.UWP\\Uno.Skia.csproj" ] } -} \ No newline at end of file +} diff --git a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Builder/FramebufferHostBuilder.cs b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Builder/FramebufferHostBuilder.cs new file mode 100644 index 000000000000..2ce4eb1429ad --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Builder/FramebufferHostBuilder.cs @@ -0,0 +1,17 @@ +using System; +using Uno.UI.Runtime.Skia.Linux.FrameBuffer; + +namespace Uno.UI.Runtime.Skia; + +internal class FramebufferHostBuilder : IPlatformHostBuilder +{ + public FramebufferHostBuilder() + { + } + + public bool IsSupported + => OperatingSystem.IsLinux(); + + public SkiaHost Create(Func appBuilder) + => new FrameBufferHost(appBuilder); +} diff --git a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Builder/HostBuilder.cs b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Builder/HostBuilder.cs new file mode 100644 index 000000000000..960bf04745a5 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Builder/HostBuilder.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.WebUI; + +namespace Uno.UI.Runtime.Skia; + +public static class HostBuilder +{ + public static ISkiaHostBuilder UseLinuxFrameBuffer(this ISkiaHostBuilder builder) + { + builder.AddHostBuilder(() => new FramebufferHostBuilder()); + return builder; + } +} diff --git a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/FramebufferHost.cs b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/FramebufferHost.cs index e4046041310e..4579a46721be 100644 --- a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/FramebufferHost.cs +++ b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/FramebufferHost.cs @@ -17,7 +17,7 @@ namespace Uno.UI.Runtime.Skia.Linux.FrameBuffer { - public class FrameBufferHost : ISkiaApplicationHost, IXamlRootHost + public class FrameBufferHost : SkiaHost, ISkiaApplicationHost, IXamlRootHost, IDisposable { [ThreadStatic] private static bool _isDispatcherThread = false; @@ -52,12 +52,15 @@ public FrameBufferHost(Func appBuilder) /// This value can be overriden by the UNO_DISPLAY_SCALE_OVERRIDE environment variable public float? DisplayScale { get; set; } - public void Run() + protected override void Initialize() { StartConsoleInterception(); - _eventLoop.Schedule(Initialize); + _eventLoop.Schedule(InnerInitialize); + } + protected override void RunLoop() + { _terminationGate.WaitOne(); if (this.Log().IsEnabled(LogLevel.Debug)) @@ -89,7 +92,7 @@ private void StartConsoleInterception() _consoleInterceptionThread.Start(); } - private void Initialize() + private void InnerInitialize() { _isDispatcherThread = true; @@ -146,5 +149,9 @@ void CreateApp(ApplicationInitializationCallbackParams _) void IXamlRootHost.InvalidateRender() => _renderer?.InvalidateRender(); WUX.UIElement? IXamlRootHost.RootElement => FrameBufferWindowWrapper.Instance.Window?.RootElement; + + public void Dispose() + { + } } } diff --git a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Uno.UI.Runtime.Skia.Linux.FrameBuffer.csproj b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Uno.UI.Runtime.Skia.Linux.FrameBuffer.csproj index 86ab47ba252f..47a804f1870e 100644 --- a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Uno.UI.Runtime.Skia.Linux.FrameBuffer.csproj +++ b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Uno.UI.Runtime.Skia.Linux.FrameBuffer.csproj @@ -41,6 +41,7 @@ + diff --git a/src/Uno.UI.Runtime.Skia.MacOS/Builder/HostBuilder.cs b/src/Uno.UI.Runtime.Skia.MacOS/Builder/HostBuilder.cs new file mode 100644 index 000000000000..9e792d7f7b61 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.MacOS/Builder/HostBuilder.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.WebUI; + +namespace Uno.UI.Runtime.Skia; + +public static class HostBuilder +{ + public static ISkiaHostBuilder UseMacOS(this ISkiaHostBuilder builder) + { + builder.AddHostBuilder(() => new MacOSHostBuilder()); + return builder; + } +} diff --git a/src/Uno.UI.Runtime.Skia.MacOS/Builder/MacOSHostBuilder.cs b/src/Uno.UI.Runtime.Skia.MacOS/Builder/MacOSHostBuilder.cs new file mode 100644 index 000000000000..08098934373d --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.MacOS/Builder/MacOSHostBuilder.cs @@ -0,0 +1,17 @@ +using System; +using Uno.UI.Runtime.Skia.MacOS; + +namespace Uno.UI.Runtime.Skia; + +internal class MacOSHostBuilder : IPlatformHostBuilder +{ + public MacOSHostBuilder() + { + } + + public bool IsSupported + => OperatingSystem.IsMacOS(); + + public SkiaHost Create(Func appBuilder) + => new MacSkiaHost(appBuilder); +} diff --git a/src/Uno.UI.Runtime.Skia.MacOS/MacSkiaHost.cs b/src/Uno.UI.Runtime.Skia.MacOS/MacSkiaHost.cs index 703ba9b0540a..a1fc19df7ab4 100644 --- a/src/Uno.UI.Runtime.Skia.MacOS/MacSkiaHost.cs +++ b/src/Uno.UI.Runtime.Skia.MacOS/MacSkiaHost.cs @@ -5,7 +5,7 @@ namespace Uno.UI.Runtime.Skia.MacOS; -public class MacSkiaHost : ISkiaApplicationHost +public class MacSkiaHost : SkiaHost, ISkiaApplicationHost { private readonly Func _appBuilder; @@ -48,7 +48,7 @@ public MacSkiaHost(Func appBuilder) public RenderSurfaceType RenderSurfaceType { get; set; } - public void Run() + protected override void Initialize() { if (!InitializeMac()) { @@ -60,7 +60,10 @@ public void Run() } InitializeDispatcher(); + } + protected override void RunLoop() + { StartApp(); // `argc` and `argv` parameters are ignored by macOS diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Builder/HostBuilder.cs b/src/Uno.UI.Runtime.Skia.Wpf/Builder/HostBuilder.cs new file mode 100644 index 000000000000..7c142370843d --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Wpf/Builder/HostBuilder.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Navigation; +using Windows.UI.WebUI; + +namespace Uno.UI.Runtime.Skia; + +public static class HostBuilder +{ + public static ISkiaHostBuilder UseWindows(this ISkiaHostBuilder builder, Action windowsBuilder = null) + { + builder.AddHostBuilder(() => + { + var wpfBuilder = new WpfHostBuilder(); + windowsBuilder?.Invoke(wpfBuilder); + return wpfBuilder; + }); + + return builder; + } + + public static IWindowsSkiaHostBuilder WpfApplication(this IWindowsSkiaHostBuilder builder, Func action) + { + builder.WpfApplication = action; + + return builder; + } +} diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Builder/IWindowsSkiaHostBuilder.cs b/src/Uno.UI.Runtime.Skia.Wpf/Builder/IWindowsSkiaHostBuilder.cs new file mode 100644 index 000000000000..df6622a5a7d1 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Wpf/Builder/IWindowsSkiaHostBuilder.cs @@ -0,0 +1,10 @@ +#nullable enable + +using System; + +namespace Uno.UI.Runtime.Skia; + +public interface IWindowsSkiaHostBuilder +{ + internal Func? WpfApplication { get; set; } +} diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Builder/WpfHostBuilder.cs b/src/Uno.UI.Runtime.Skia.Wpf/Builder/WpfHostBuilder.cs new file mode 100644 index 000000000000..33bcb681f719 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Wpf/Builder/WpfHostBuilder.cs @@ -0,0 +1,136 @@ +#nullable enable + +using System; +using System.IO; +using System.Reflection; +using System.Reflection.Metadata; +using System.Runtime.InteropServices; +using System.Runtime.Loader; +using System.Windows; +using System.Windows.Media.Media3D; +using Uno.Foundation.Logging; +using Uno.UI.Runtime.Skia.Wpf; + +namespace Uno.UI.Runtime.Skia; + +internal class WpfHostBuilder : IPlatformHostBuilder, IWindowsSkiaHostBuilder +{ + private Func? _wpfApplication; + private string? _windowsDesktopFrameworkPath; + + public WpfHostBuilder() + { + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + RegisterAssemblyResolver(); + } + } + + private void RegisterAssemblyResolver() + { + AssemblyLoadContext.Default.Resolving += OnAssemblyResolving; + + if (Uri.TryCreate(typeof(object).Assembly.Location, UriKind.RelativeOrAbsolute, out var uri)) + { + // We expect that the path from System.Private.CoreLib.dll: + // + // file:///C:/Program Files/dotnet/shared/Microsoft.NETCore.App/8.0.2/System.Private.CoreLib.dll + // + // Will be the in a sibling folder from the Microsoft.WindowsDesktop.App using the same version. + // If the structure of the .NET installation changes, this code will need to be updated. + var version = Path.GetFileName(Path.GetDirectoryName(uri.LocalPath))!; + var dotnetShared = Path.Combine(Path.GetDirectoryName(uri.LocalPath)!, "..", ".."); + + _windowsDesktopFrameworkPath = Path.GetFullPath(Path.Combine( + dotnetShared, + "Microsoft.WindowsDesktop.App", + version)); + + if (!Directory.Exists(_windowsDesktopFrameworkPath)) + { + throw new InvalidOperationException($"Unable to find the Microsoft.WindowsDesktop.App framework. An Uno Platform update may be required (Expected path {_windowsDesktopFrameworkPath})"); + } + + // Explicitly load WindowsBase to avoid later incorrect loading issues with this message: + // + // System.IO.FileNotFoundException: Could not load file or assembly 'WindowsBase, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified. + // HRESULT 0x80070002 + // + AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.Combine(_windowsDesktopFrameworkPath, "WindowsBase.dll")); + + // Setup native images lookup in order for NativeLibrary.TryLoad to succeed + var registration = NativeMethods.AddDllDirectory(_windowsDesktopFrameworkPath); + + LoadNativeImage("PresentationNative_cor3.dll"); + LoadNativeImage("wpfgfx_cor3.dll"); + } + } + + private static void LoadNativeImage(string image) + { + if (!NativeLibrary.TryLoad( + image, + typeof(WpfHostBuilder).Assembly, + DllImportSearchPath.UserDirectories, + out _)) + { + throw new InvalidOperationException($"Failed to load native image. An Uno Platform update may be required. (Tried loading {image})"); + } + } + + private Assembly? OnAssemblyResolving(AssemblyLoadContext context, AssemblyName assemblyName) + { + if (_windowsDesktopFrameworkPath is not null) + { + var assemblyPath = Path.Combine(_windowsDesktopFrameworkPath, assemblyName.Name + ".dll"); + + if (File.Exists(assemblyPath)) + { + if (this.Log().IsEnabled(LogLevel.Trace)) + { + this.Log().Trace($"Resolving {assemblyName} with {assemblyPath}"); + } + + try + { + return context.LoadFromAssemblyPath(assemblyPath); + } + catch (Exception e) + { + if (this.Log().IsEnabled(LogLevel.Trace)) + { + // Only log loading errors in trace level, some are false positives. + this.Log().Error($"Failed to load {assemblyPath} for {assemblyName}", e); + } + } + } + else + { + if (this.Log().IsEnabled(LogLevel.Trace)) + { + this.Log().Trace($"Unable to find file {assemblyPath} for {assemblyName}"); + } + } + } + + return null; + } + + public bool IsSupported + => OperatingSystem.IsWindows(); + + Func? IWindowsSkiaHostBuilder.WpfApplication + { + get => _wpfApplication; + set => _wpfApplication = value; + } + + public SkiaHost Create(Func appBuilder) + => new WpfHost(appBuilder, _wpfApplication); + + private static class NativeMethods + { + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern int AddDllDirectory(string NewDirectory); + } +} diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Uno.UI.Runtime.Skia.Wpf.csproj b/src/Uno.UI.Runtime.Skia.Wpf/Uno.UI.Runtime.Skia.Wpf.csproj index ca4901010877..6f48508c5d95 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Uno.UI.Runtime.Skia.Wpf.csproj +++ b/src/Uno.UI.Runtime.Skia.Wpf/Uno.UI.Runtime.Skia.Wpf.csproj @@ -1,11 +1,11 @@  - $(NetPreviousWpf) - $(TargetFrameworks);$(NetCurrentWpf) + $(NetPrevious) + $(TargetFrameworks);$(NetCurrent) - + true @@ -19,12 +19,16 @@ Uno.WinUI.Runtime.Skia.Wpf true - true + $(NoWarn);NU5104 + + + + @@ -44,6 +48,7 @@ + diff --git a/src/Uno.UI.Runtime.Skia.Wpf/WpfHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/WpfHost.cs index 758672d09d03..3a2f9e705124 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/WpfHost.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/WpfHost.cs @@ -13,16 +13,18 @@ namespace Uno.UI.Runtime.Skia.Wpf; -public class WpfHost : IWpfApplicationHost +public class WpfHost : SkiaHost, IWpfApplicationHost { private readonly Dispatcher _dispatcher; private readonly Func _appBuilder; + private readonly WpfApplication? _wpfApp; [ThreadStatic] private static WpfHost? _current; private bool _ignorePixelScaling; - static WpfHost() => WpfExtensionsRegistrar.Register(); + static WpfHost() + => WpfExtensionsRegistrar.Register(); public WpfHost(Dispatcher dispatcher, Func appBuilder) { @@ -31,6 +33,15 @@ public WpfHost(Dispatcher dispatcher, Func appBuilder) _appBuilder = appBuilder; } + internal WpfHost(Func appBuilder, Func? wpfAppBuilder) + { + _wpfApp = wpfAppBuilder?.Invoke() ?? new WpfApplication(); + + _current = this; + _dispatcher = _wpfApp.Dispatcher; + _appBuilder = appBuilder; + } + internal static WpfHost? Current => _current; /// @@ -51,14 +62,18 @@ public bool IgnorePixelScaling } } } - - public void Run() + protected override void Initialize() { InitializeDispatcher(); + } + protected override void RunLoop() + { // App needs to be created after the native overlay layer is properly initialized // otherwise the initially focused input element would cause exception. StartApp(); + + _wpfApp?.Run(); } private void InitializeDispatcher() diff --git a/src/Uno.UI.Runtime.Skia.X11/Builder/HostBuilder.cs b/src/Uno.UI.Runtime.Skia.X11/Builder/HostBuilder.cs new file mode 100644 index 000000000000..14597a7f242f --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.X11/Builder/HostBuilder.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.WebUI; + +namespace Uno.UI.Runtime.Skia; + +public static class HostBuilder +{ + public static ISkiaHostBuilder UseX11(this ISkiaHostBuilder builder) + { + builder.AddHostBuilder(() => new X11HostBuilder()); + return builder; + } +} diff --git a/src/Uno.UI.Runtime.Skia.X11/Builder/X11HostBuilder.cs b/src/Uno.UI.Runtime.Skia.X11/Builder/X11HostBuilder.cs new file mode 100644 index 000000000000..316a08a28777 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.X11/Builder/X11HostBuilder.cs @@ -0,0 +1,17 @@ +using System; +using Uno.WinUI.Runtime.Skia.X11; + +namespace Uno.UI.Runtime.Skia; + +internal class X11HostBuilder : IPlatformHostBuilder +{ + public X11HostBuilder() + { + } + + public bool IsSupported + => OperatingSystem.IsLinux(); + + public SkiaHost Create(Func appBuilder) + => new X11ApplicationHost(appBuilder); +} diff --git a/src/Uno.UI.Runtime.Skia.X11/Uno.UI.Runtime.Skia.X11.csproj b/src/Uno.UI.Runtime.Skia.X11/Uno.UI.Runtime.Skia.X11.csproj index e94ad18fa818..6a1a549d383e 100644 --- a/src/Uno.UI.Runtime.Skia.X11/Uno.UI.Runtime.Skia.X11.csproj +++ b/src/Uno.UI.Runtime.Skia.X11/Uno.UI.Runtime.Skia.X11.csproj @@ -41,6 +41,7 @@ + diff --git a/src/Uno.UI.Runtime.Skia.X11/X11ApplicationHost.cs b/src/Uno.UI.Runtime.Skia.X11/X11ApplicationHost.cs index 33e7672c5b02..382277bc1b7f 100644 --- a/src/Uno.UI.Runtime.Skia.X11/X11ApplicationHost.cs +++ b/src/Uno.UI.Runtime.Skia.X11/X11ApplicationHost.cs @@ -13,10 +13,11 @@ using Uno.UI.Hosting; using Uno.UI.Runtime.Skia.Extensions.System; using Uno.UI.Xaml.Controls; +using Uno.UI.Runtime.Skia; namespace Uno.WinUI.Runtime.Skia.X11; -public class X11ApplicationHost : ISkiaApplicationHost +public class X11ApplicationHost : SkiaHost, ISkiaApplicationHost, IDisposable { [ThreadStatic] private static bool _isDispatcherThread; private readonly EventLoop _eventLoop; @@ -73,7 +74,7 @@ public X11ApplicationHost(Func appBuilder) CoreDispatcher.HasThreadAccessOverride = () => _isDispatcherThread; } - public void Run() + protected override void RunLoop() { _eventLoop.Schedule(StartApp); @@ -102,4 +103,12 @@ void CreateApp(ApplicationInitializationCallbackParams _) Application.StartWithArguments(CreateApp); } + + protected override void Initialize() + { + } + + public void Dispose() + { + } } diff --git a/src/Uno.UI.Runtime.Skia/AssemblyInfo.cs b/src/Uno.UI.Runtime.Skia/AssemblyInfo.cs new file mode 100644 index 000000000000..94f9cf03f669 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia/AssemblyInfo.cs @@ -0,0 +1,8 @@ +using System; +using System.IO; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Uno.UI.Runtime.Skia.Wpf")] +[assembly: InternalsVisibleTo("Uno.UI.Runtime.Skia.X11")] +[assembly: InternalsVisibleTo("Uno.UI.Runtime.Skia.Linux.FrameBuffer")] +[assembly: InternalsVisibleTo("Uno.UI.Runtime.Skia.MacOS")] diff --git a/src/Uno.UI.Runtime.Skia/IPlatformHostBuilder.cs b/src/Uno.UI.Runtime.Skia/IPlatformHostBuilder.cs new file mode 100644 index 000000000000..093434222db0 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia/IPlatformHostBuilder.cs @@ -0,0 +1,9 @@ +namespace Uno.UI.Runtime.Skia +{ + internal interface IPlatformHostBuilder + { + bool IsSupported { get; } + + SkiaHost Create(Func appBuilder); + } +} diff --git a/src/Uno.UI.Runtime.Skia/ISkiaHostBuilder.cs b/src/Uno.UI.Runtime.Skia/ISkiaHostBuilder.cs new file mode 100644 index 000000000000..214e0f88970e --- /dev/null +++ b/src/Uno.UI.Runtime.Skia/ISkiaHostBuilder.cs @@ -0,0 +1,13 @@ +using Microsoft.UI.Xaml; + +namespace Uno.UI.Runtime.Skia; + +public interface ISkiaHostBuilder +{ + internal Func? AppBuilder { get; set; } + internal Action? AfterInit { get; set; } + + internal void AddHostBuilder(Func hostBuilder); + + public SkiaHost Build(); +} diff --git a/src/Uno.UI.Runtime.Skia/SkiaHost.cs b/src/Uno.UI.Runtime.Skia/SkiaHost.cs index e7472ea1aa96..c30cc5865cec 100644 --- a/src/Uno.UI.Runtime.Skia/SkiaHost.cs +++ b/src/Uno.UI.Runtime.Skia/SkiaHost.cs @@ -1,10 +1,14 @@ -namespace Uno.Runtime.Skia; + +namespace Uno.UI.Runtime.Skia; public abstract class SkiaHost { + internal Action? AfterInit { get; set; } + public void Run() { Initialize(); + AfterInit?.Invoke(); RunLoop(); } diff --git a/src/Uno.UI.Runtime.Skia/SkiaHostBuilder.cs b/src/Uno.UI.Runtime.Skia/SkiaHostBuilder.cs new file mode 100644 index 000000000000..882e39754d4f --- /dev/null +++ b/src/Uno.UI.Runtime.Skia/SkiaHostBuilder.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.UI.Xaml; +using Uno.Foundation.Logging; + +namespace Uno.UI.Runtime.Skia +{ + public class SkiaHostBuilder : ISkiaHostBuilder + { + private List> _hostBuilders = new(); + private Func? _appBuilder; + private Action? _afterInit; + + private SkiaHostBuilder() { } + + Func? ISkiaHostBuilder.AppBuilder + { + get => _appBuilder; + set => _appBuilder = value; + } + + Action? ISkiaHostBuilder.AfterInit + { + get => _afterInit; + set => _afterInit = value; + } + + public static SkiaHostBuilder Create() + => new SkiaHostBuilder(); + + public SkiaHost Build() + { + if (_appBuilder is null) + { + throw new InvalidOperationException($"No app builder delegate was provided"); + } + + foreach (var hostBuilderFunc in _hostBuilders) + { + var hostBuilder = hostBuilderFunc(); + + if (hostBuilder.IsSupported) + { + if (this.Log().IsEnabled(LogLevel.Debug)) + { + this.Log().Debug($"Using host builder {hostBuilder.GetType()}"); + } + + var host = hostBuilder.Create(_appBuilder); + + host.AfterInit = _afterInit; + + return host; + } + else + { + if (this.Log().IsEnabled(LogLevel.Debug)) + { + this.Log().Debug($"Host builder {hostBuilder.GetType()} is not supported"); + } + } + } + + throw new InvalidOperationException($"No platform host could be selected"); + } + + void ISkiaHostBuilder.AddHostBuilder(Func platformHostBuilder) + { + _hostBuilders.Add(platformHostBuilder); + } + } +} diff --git a/src/Uno.UI.Runtime.Skia/SkiaHostBuilderExtensions.cs b/src/Uno.UI.Runtime.Skia/SkiaHostBuilderExtensions.cs new file mode 100644 index 000000000000..494acf76ad77 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia/SkiaHostBuilderExtensions.cs @@ -0,0 +1,17 @@ +namespace Uno.UI.Runtime.Skia +{ + public static class SkiaHostBuilderExtensions + { + public static ISkiaHostBuilder App(this ISkiaHostBuilder builder, Func appBuilder) + { + builder.AppBuilder = appBuilder; + return builder; + } + + public static ISkiaHostBuilder AfterInit(this ISkiaHostBuilder builder, Action action) + { + builder.AfterInit = action; + return builder; + } + } +} diff --git a/src/Uno.UI.Runtime.Skia/Uno.UI.Runtime.Skia.csproj b/src/Uno.UI.Runtime.Skia/Uno.UI.Runtime.Skia.csproj index e7b23691b3d2..06f52dd758d2 100644 --- a/src/Uno.UI.Runtime.Skia/Uno.UI.Runtime.Skia.csproj +++ b/src/Uno.UI.Runtime.Skia/Uno.UI.Runtime.Skia.csproj @@ -1,11 +1,17 @@ - + $(NetSkiaPreviousAndCurrent) - enable - enable - + enable + enable + + + + + + + diff --git a/src/Uno.UI.sln b/src/Uno.UI.sln index 4a6660c67cec..aae03412bc20 100644 --- a/src/Uno.UI.sln +++ b/src/Uno.UI.sln @@ -189,8 +189,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.RemoteControl.Refere EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.Runtime.Skia.Linux.FrameBuffer", "Uno.UI.Runtime.Skia.Linux.FrameBuffer\Uno.UI.Runtime.Skia.Linux.FrameBuffer.csproj", "{AA89E8AC-40EF-4911-99B5-55228188446A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SamplesApp.Skia.Linux.FrameBuffer", "SamplesApp\SamplesApp.Skia.Linux.FrameBuffer\SamplesApp.Skia.Linux.FrameBuffer.csproj", "{76EBBF09-F39F-48C2-BEE9-9DF5F8EC6A49}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.FluentTheme.v1.netcoremobile", "Uno.UI.FluentTheme.v1\Uno.UI.FluentTheme.v1.netcoremobile.csproj", "{34833538-6378-4592-B8DD-929C9F4B0E5C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.FluentTheme.v1.Reference", "Uno.UI.FluentTheme.v1\Uno.UI.FluentTheme.v1.Reference.csproj", "{04833538-6378-4592-B8DD-929C9F4B0E5C}" @@ -317,7 +315,7 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.Runtime.Skia", "Uno.UI.Runtime.Skia\Uno.UI.Runtime.Skia.csproj", "{A8C22BED-2589-48F1-B1D4-0B436A90FC3B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SamplesApp.Skia.MacOS", "SamplesApp\SamplesApp.Skia.MacOS\SamplesApp.Skia.MacOS.csproj", "{C60CE444-4959-4D84-B63F-D89599A8CCCA}" -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamplesApp.Skia.X11", "SamplesApp\SamplesApp.Skia.X11\SamplesApp.Skia.X11.csproj", "{93E6D033-52E2-4C2B-A715-A9FC1F609E3D}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamplesApp.Skia.Generic", "SamplesApp\SamplesApp.Skia.Generic\SamplesApp.Skia.Generic.csproj", "{93E6D033-52E2-4C2B-A715-A9FC1F609E3D}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Uno.UI.Runtime.Skia.X11", "Uno.UI.Runtime.Skia.X11\Uno.UI.Runtime.Skia.X11.csproj", "{37441DE3-088B-4B63-A1E2-E70E39BF4222}" EndProject diff --git a/src/Uno.UWP/AssemblyInfo.cs b/src/Uno.UWP/AssemblyInfo.cs index 8ff20e0c167b..cc804c467095 100644 --- a/src/Uno.UWP/AssemblyInfo.cs +++ b/src/Uno.UWP/AssemblyInfo.cs @@ -21,6 +21,5 @@ [assembly: InternalsVisibleTo("SamplesApp.macOS")] [assembly: InternalsVisibleTo("SamplesApp.Wasm")] [assembly: InternalsVisibleTo("SamplesApp.Skia")] -[assembly: InternalsVisibleTo("SamplesApp.Skia.Linux.FrameBuffer")] [assembly: InternalsVisibleTo("UnoIslandsSamplesApp.Skia")] [assembly: System.Reflection.AssemblyMetadata("IsTrimmable", "True")]