diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index 44e1bb4696..ba616f071a 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -1,48 +1,78 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Build Schema", - "$ref": "#/definitions/build", "definitions": { - "build": { - "type": "object", + "Host": { + "type": "string", + "enum": [ + "AppVeyor", + "AzurePipelines", + "Bamboo", + "Bitbucket", + "Bitrise", + "GitHubActions", + "GitLab", + "Jenkins", + "Rider", + "SpaceAutomation", + "TeamCity", + "Terminal", + "TravisCI", + "VisualStudio", + "VSCode" + ] + }, + "ExecutableTarget": { + "type": "string", + "enum": [ + "BuildToNuGetCache", + "CiAzureLinux", + "CiAzureOSX", + "CiAzureWindows", + "Clean", + "Compile", + "CompileHtmlPreviewer", + "CompileNative", + "CreateIntermediateNugetPackages", + "CreateNugetPackages", + "DownloadApiBaselinePackages", + "GenerateCppHeaders", + "OutputApiDiff", + "OutputVersion", + "Package", + "RunCoreLibsTests", + "RunHtmlPreviewerTests", + "RunLeakTests", + "RunRenderTests", + "RunTests", + "RunToolsTests", + "ValidateApiDiff", + "VerifyXamlCompilation", + "ZipFiles" + ] + }, + "Verbosity": { + "type": "string", + "description": "", + "enum": [ + "Verbose", + "Normal", + "Minimal", + "Quiet" + ] + }, + "NukeBuild": { "properties": { - "api-baseline": { - "type": "string" - }, - "configuration": { - "type": "string" - }, "Continue": { "type": "boolean", "description": "Indicates to continue a previously failed build attempt" }, - "force-nuget-version": { - "type": "string" - }, "Help": { "type": "boolean", "description": "Shows the help text for this build assembly" }, "Host": { - "type": "string", "description": "Host for execution. Default is 'automatic'", - "enum": [ - "AppVeyor", - "AzurePipelines", - "Bamboo", - "Bitbucket", - "Bitrise", - "GitHubActions", - "GitLab", - "Jenkins", - "Rider", - "SpaceAutomation", - "TeamCity", - "Terminal", - "TravisCI", - "VisualStudio", - "VSCode" - ] + "$ref": "#/definitions/Host" }, "NoLogo": { "type": "boolean", @@ -71,89 +101,54 @@ "type": "array", "description": "List of targets to be skipped. Empty list skips all dependencies", "items": { - "type": "string", - "enum": [ - "BuildToNuGetCache", - "CiAzureLinux", - "CiAzureOSX", - "CiAzureWindows", - "Clean", - "Compile", - "CompileHtmlPreviewer", - "CompileNative", - "CreateIntermediateNugetPackages", - "CreateNugetPackages", - "GenerateCppHeaders", - "OutputApiDiff", - "OutputVersion", - "Package", - "RunCoreLibsTests", - "RunHtmlPreviewerTests", - "RunLeakTests", - "RunRenderTests", - "RunTests", - "RunToolsTests", - "ValidateApiDiff", - "VerifyXamlCompilation", - "ZipFiles" - ] + "$ref": "#/definitions/ExecutableTarget" } }, - "skip-previewer": { - "type": "boolean" - }, - "skip-tests": { - "type": "boolean" - }, "Target": { "type": "array", "description": "List of targets to be invoked. Default is '{default_target}'", "items": { - "type": "string", - "enum": [ - "BuildToNuGetCache", - "CiAzureLinux", - "CiAzureOSX", - "CiAzureWindows", - "Clean", - "Compile", - "CompileHtmlPreviewer", - "CompileNative", - "CreateIntermediateNugetPackages", - "CreateNugetPackages", - "GenerateCppHeaders", - "OutputApiDiff", - "OutputVersion", - "Package", - "RunCoreLibsTests", - "RunHtmlPreviewerTests", - "RunLeakTests", - "RunRenderTests", - "RunTests", - "RunToolsTests", - "ValidateApiDiff", - "VerifyXamlCompilation", - "ZipFiles" - ] + "$ref": "#/definitions/ExecutableTarget" } }, - "update-api-suppression": { - "type": "boolean" - }, "Verbosity": { - "type": "string", "description": "Logging verbosity during build execution. Default is 'Normal'", - "enum": [ - "Minimal", - "Normal", - "Quiet", - "Verbose" + "$ref": "#/definitions/Verbosity" + } + } + } + }, + "allOf": [ + { + "properties": { + "configuration": { + "type": "string" + }, + "force-api-baseline": { + "type": "string" + }, + "force-nuget-version": { + "type": "string" + }, + "skip-previewer": { + "type": "boolean" + }, + "skip-tests": { + "type": "boolean" + }, + "update-api-suppression": { + "type": [ + "boolean", + "null" ] }, "version-output-dir": { "type": "string" } } + }, + { + "$ref": "#/definitions/NukeBuild" } - } -} \ No newline at end of file + ] +} diff --git a/Avalonia.Desktop.slnf b/Avalonia.Desktop.slnf index 0cddbdf9fd..67ca3c2bf1 100644 --- a/Avalonia.Desktop.slnf +++ b/Avalonia.Desktop.slnf @@ -8,8 +8,8 @@ "samples\\ControlCatalog\\ControlCatalog.csproj", "samples\\GpuInterop\\GpuInterop.csproj", "samples\\IntegrationTestApp\\IntegrationTestApp.csproj", + "samples\\TextTestApp\\TextTestApp.csproj", "samples\\MiniMvvm\\MiniMvvm.csproj", - "samples\\ReactiveUIDemo\\ReactiveUIDemo.csproj", "samples\\RenderDemo\\RenderDemo.csproj", "samples\\SampleControls\\ControlSamples.csproj", "samples\\Sandbox\\Sandbox.csproj", @@ -31,7 +31,6 @@ "src\\Avalonia.Native\\Avalonia.Native.csproj", "src\\Avalonia.OpenGL\\Avalonia.OpenGL.csproj", "src\\Avalonia.Vulkan\\Avalonia.Vulkan.csproj", - "src\\Avalonia.ReactiveUI\\Avalonia.ReactiveUI.csproj", "src\\Avalonia.Remote.Protocol\\Avalonia.Remote.Protocol.csproj", "src\\Avalonia.Themes.Fluent\\Avalonia.Themes.Fluent.csproj", "src\\Avalonia.Themes.Simple\\Avalonia.Themes.Simple.csproj", @@ -64,7 +63,6 @@ "tests\\Avalonia.LeakTests\\Avalonia.LeakTests.csproj", "tests\\Avalonia.Markup.UnitTests\\Avalonia.Markup.UnitTests.csproj", "tests\\Avalonia.Markup.Xaml.UnitTests\\Avalonia.Markup.Xaml.UnitTests.csproj", - "tests\\Avalonia.ReactiveUI.UnitTests\\Avalonia.ReactiveUI.UnitTests.csproj", "tests\\Avalonia.RenderTests.WpfCompare\\Avalonia.RenderTests.WpfCompare.csproj", "tests\\Avalonia.Skia.RenderTests\\Avalonia.Skia.RenderTests.csproj", "tests\\Avalonia.Skia.UnitTests\\Avalonia.Skia.UnitTests.csproj", diff --git a/Avalonia.sln b/Avalonia.sln index 8ee6f65989..b7625ed1dd 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -9,8 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Windows", "Windows", "{B39A EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32", "src\Windows\Avalonia.Win32\Avalonia.Win32.csproj", "{811A76CF-1CF6-440F-963B-BBE31BD72A82}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1", "src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj", "{3E908F67-5543-4879-A1DC-08EACE79B3CD}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls", "src\Avalonia.Controls\Avalonia.Controls.csproj", "{D2221C82-4A25-4583-9B43-D791E3F6820C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Simple", "src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj", "{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}" @@ -23,10 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.UnitTests EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Base.UnitTests", "tests\Avalonia.Base.UnitTests\Avalonia.Base.UnitTests.csproj", "{2905FF23-53FB-45E6-AA49-6AF47A172056}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1.RenderTests", "tests\Avalonia.Direct2D1.RenderTests\Avalonia.Direct2D1.RenderTests.csproj", "{DABFD304-D6A4-4752-8123-C2CCF7AC7831}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1.UnitTests", "tests\Avalonia.Direct2D1.UnitTests\Avalonia.Direct2D1.UnitTests.csproj", "{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.Xaml.UnitTests", "tests\Avalonia.Markup.Xaml.UnitTests\Avalonia.Markup.Xaml.UnitTests.csproj", "{99135EAB-653D-47E4-A378-C96E1278CA44}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Markup", "Markup", "{8B6A8209-894F-4BA1-B880-965FD453982C}" @@ -38,15 +32,14 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DEF5-D50F-4975-8B72-124C9EB54066}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + src\Shared\CallerArgumentExpressionAttribute.cs = src\Shared\CallerArgumentExpressionAttribute.cs src\Shared\IsExternalInit.cs = src\Shared\IsExternalInit.cs src\Shared\ModuleInitializer.cs = src\Shared\ModuleInitializer.cs - src\Shared\NullableAttributes.cs = src\Shared\NullableAttributes.cs src\Shared\SourceGeneratorAttributes.cs = src\Shared\SourceGeneratorAttributes.cs src\Shared\StringCompatibilityExtensions.cs = src\Shared\StringCompatibilityExtensions.cs + src\Shared\StreamCompatibilityExtensions.cs = src\Shared\StreamCompatibilityExtensions.cs EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI", "src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup", "src\Markup\Avalonia.Markup\Avalonia.Markup.csproj", "{6417E941-21BC-467B-A771-0DE389353CE6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.UnitTests", "tests\Avalonia.Markup.UnitTests\Avalonia.Markup.UnitTests.csproj", "{8EF392D5-1416-45AA-9956-7CBBC3229E8A}" @@ -87,8 +80,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Android", "s EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia", "src\Skia\Avalonia.Skia\Avalonia.Skia.csproj", "{7D2D3083-71DD-4CC9-8907-39A0D86FB322}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.NetCore", "samples\ControlCatalog.NetCore\ControlCatalog.NetCore.csproj", "{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1-27F5-4255-9AFC-04ABFD11683A}" ProjectSection(SolutionItems) = preProject build\AvaloniaPublicKey.props = build\AvaloniaPublicKey.props @@ -107,12 +98,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1 build\NetCore.props = build\NetCore.props build\NetFX.props = build\NetFX.props build\NullableEnable.props = build\NullableEnable.props - build\ReactiveUI.props = build\ReactiveUI.props build\ReferenceCoreLibraries.props = build\ReferenceCoreLibraries.props build\Rx.props = build\Rx.props build\SampleApp.props = build\SampleApp.props build\SharedVersion.props = build\SharedVersion.props - build\SharpDX.props = build\SharpDX.props build\SkiaSharp.props = build\SkiaSharp.props build\SourceGenerators.props = build\SourceGenerators.props build\SourceLink.props = build\SourceLink.props @@ -121,6 +110,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1 build\UnitTests.NetFX.props = build\UnitTests.NetFX.props build\WarnAsErrors.props = build\WarnAsErrors.props build\XUnit.props = build\XUnit.props + build\AnalyzerProject.targets = build\AnalyzerProject.targets EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Targets", "Targets", "{4D6FAF79-58B4-482F-9122-0668C346364C}" @@ -169,8 +159,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.X11", "src\Avaloni EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlatformSanityChecks", "samples\PlatformSanityChecks\PlatformSanityChecks.csproj", "{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI.UnitTests", "tests\Avalonia.ReactiveUI.UnitTests\Avalonia.ReactiveUI.UnitTests.csproj", "{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Dialogs", "src\Avalonia.Dialogs\Avalonia.Dialogs.csproj", "{4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.FreeDesktop", "src\Avalonia.FreeDesktop\Avalonia.FreeDesktop.csproj", "{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}" @@ -191,6 +179,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MiniMvvm", "samples\MiniMvv EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTestApp", "samples\IntegrationTestApp\IntegrationTestApp.csproj", "{676D6BFD-029D-4E43-BFC7-3892265CE251}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TextTestApp", "samples\TextTestApp\TextTestApp.csproj", "{CE728F96-A593-462C-B8D4-1D5AFFDB5B4F}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.IntegrationTests.Appium", "tests\Avalonia.IntegrationTests.Appium\Avalonia.IntegrationTests.Appium.csproj", "{F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Browser", "Browser", "{86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}" @@ -213,14 +203,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SingleProjectSandbox", "sam EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Browser", "src\Browser\Avalonia.Browser\Avalonia.Browser.csproj", "{4A39637C-9338-4925-A4DB-D072E292EC78}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Browser.Blazor", "src\Browser\Avalonia.Browser.Blazor\Avalonia.Browser.Blazor.csproj", "{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Browser", "samples\ControlCatalog.Browser\ControlCatalog.Browser.csproj", "{15B93A4C-1B46-43F6-B534-7B25B6E99932}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Browser.Blazor", "samples\ControlCatalog.Browser.Blazor\ControlCatalog.Browser.Blazor.csproj", "{90B08091-9BBD-4362-B712-E9F2CC62B218}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUIDemo", "samples\ReactiveUIDemo\ReactiveUIDemo.csproj", "{75C47156-C5D8-44BC-A5A7-E8657C2248D6}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GpuInterop", "samples\GpuInterop\GpuInterop.csproj", "{C810060E-3809-4B74-A125-F11533AF9C1B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers", "src\tools\Avalonia.Analyzers\Avalonia.Analyzers.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}" @@ -266,16 +250,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.NUnit", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators.Tests", "tests\Avalonia.Generators.Tests\Avalonia.Generators.Tests.csproj", "{4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.NUnit.UnitTests", "tests\Avalonia.Headless.NUnit.UnitTests\Avalonia.Headless.NUnit.UnitTests.csproj", "{2999D79E-3C20-4A90-B651-CA7E0AC92D35}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.XUnit.UnitTests", "tests\Avalonia.Headless.XUnit.UnitTests\Avalonia.Headless.XUnit.UnitTests.csproj", "{F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tizen", "Tizen", "{D1300000-7217-4693-8B0F-57CBD5814302}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Tizen", "src\Tizen\Avalonia.Tizen\Avalonia.Tizen.csproj", "{DFFBDBF5-5DBE-47ED-9EAE-D40B75AC99E8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Tizen", "samples\ControlCatalog.Tizen\ControlCatalog.Tizen.csproj", "{A0B29221-2B6F-4B29-A4D5-2227811B5915}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Metal", "src\Avalonia.Metal\Avalonia.Metal.csproj", "{60B4ED1F-ECFA-453B-8A70-1788261C8355}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Build.Tasks.UnitTest", "tests\Avalonia.Build.Tasks.UnitTest\Avalonia.Build.Tasks.UnitTest.csproj", "{B0FD6A48-FBAB-4676-B36A-DE76B0922B12}" @@ -300,9 +274,17 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32.Automation", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XEmbedSample", "samples\XEmbedSample\XEmbedSample.csproj", "{255614F5-CB64-4ECA-A026-E0B1AF6A2EF4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.MacCatalyst", "samples\ControlCatalog.iOS\ControlCatalog.MacCatalyst.csproj", "{DE3C28DD-B602-4750-831D-345102A54CA0}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.MacCatalyst", "samples\ControlCatalog.MacCatalyst\ControlCatalog.MacCatalyst.csproj", "{DE3C28DD-B602-4750-831D-345102A54CA0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.tvOS", "samples\ControlCatalog.tvOS\ControlCatalog.tvOS.csproj", "{14342787-B4EF-4076-8C91-BA6C523DE8DF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.NUnit.PerAssembly.UnitTests", "tests\Avalonia.Headless.NUnit.PerAssembly.UnitTests\Avalonia.Headless.NUnit.PerAssembly.UnitTests.csproj", "{A175EFAE-476C-4DAA-87D5-742C18CFCC27}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.NUnit.PerTest.UnitTests", "tests\Avalonia.Headless.NUnit.PerTest.UnitTests\Avalonia.Headless.NUnit.PerTest.UnitTests.csproj", "{09EC467F-0F25-4E6F-A836-2BAEC8F6AB0C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.XUnit.PerAssembly.UnitTests", "tests\Avalonia.Headless.XUnit.PerAssembly.UnitTests\Avalonia.Headless.XUnit.PerAssembly.UnitTests.csproj", "{342D2657-2F84-493C-B74B-9D2CAE5D9DAB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.tvOS", "samples\ControlCatalog.iOS\ControlCatalog.tvOS.csproj", "{14342787-B4EF-4076-8C91-BA6C523DE8DF}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.XUnit.PerTest.UnitTests", "tests\Avalonia.Headless.XUnit.PerTest.UnitTests\Avalonia.Headless.XUnit.PerTest.UnitTests.csproj", "{26918642-829D-4FA2-B60A-BE8D83F4E063}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -318,10 +300,6 @@ Global {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.Build.0 = Debug|Any CPU {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.ActiveCfg = Release|Any CPU {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.Build.0 = Release|Any CPU {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.Build.0 = Debug|Any CPU {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -342,14 +320,6 @@ Global {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.Build.0 = Debug|Any CPU {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.ActiveCfg = Release|Any CPU {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|Any CPU.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.Build.0 = Release|Any CPU {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.Build.0 = Debug|Any CPU {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -358,10 +328,6 @@ Global {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.Build.0 = Debug|Any CPU {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.ActiveCfg = Release|Any CPU {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.Build.0 = Release|Any CPU {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|Any CPU.Build.0 = Debug|Any CPU {6417E941-21BC-467B-A771-0DE389353CE6}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -428,10 +394,6 @@ Global {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|Any CPU.Build.0 = Debug|Any CPU {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|Any CPU.ActiveCfg = Release|Any CPU {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|Any CPU.Build.0 = Release|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|Any CPU.Build.0 = Release|Any CPU {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|Any CPU.Build.0 = Debug|Any CPU {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -494,10 +456,6 @@ Global {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|Any CPU.Build.0 = Release|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|Any CPU.Build.0 = Release|Any CPU {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -538,6 +496,10 @@ Global {676D6BFD-029D-4E43-BFC7-3892265CE251}.Debug|Any CPU.Build.0 = Debug|Any CPU {676D6BFD-029D-4E43-BFC7-3892265CE251}.Release|Any CPU.ActiveCfg = Release|Any CPU {676D6BFD-029D-4E43-BFC7-3892265CE251}.Release|Any CPU.Build.0 = Release|Any CPU + {CE728F96-A593-462C-B8D4-1D5AFFDB5B4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE728F96-A593-462C-B8D4-1D5AFFDB5B4F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE728F96-A593-462C-B8D4-1D5AFFDB5B4F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE728F96-A593-462C-B8D4-1D5AFFDB5B4F}.Release|Any CPU.Build.0 = Release|Any CPU {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Debug|Any CPU.Build.0 = Debug|Any CPU {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -578,22 +540,10 @@ Global {4A39637C-9338-4925-A4DB-D072E292EC78}.Debug|Any CPU.Build.0 = Debug|Any CPU {4A39637C-9338-4925-A4DB-D072E292EC78}.Release|Any CPU.ActiveCfg = Release|Any CPU {4A39637C-9338-4925-A4DB-D072E292EC78}.Release|Any CPU.Build.0 = Release|Any CPU - {47F8530C-F19B-4B1A-B4D6-EB231522AE5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {47F8530C-F19B-4B1A-B4D6-EB231522AE5D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {47F8530C-F19B-4B1A-B4D6-EB231522AE5D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {47F8530C-F19B-4B1A-B4D6-EB231522AE5D}.Release|Any CPU.Build.0 = Release|Any CPU {15B93A4C-1B46-43F6-B534-7B25B6E99932}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {15B93A4C-1B46-43F6-B534-7B25B6E99932}.Debug|Any CPU.Build.0 = Debug|Any CPU {15B93A4C-1B46-43F6-B534-7B25B6E99932}.Release|Any CPU.ActiveCfg = Release|Any CPU {15B93A4C-1B46-43F6-B534-7B25B6E99932}.Release|Any CPU.Build.0 = Release|Any CPU - {90B08091-9BBD-4362-B712-E9F2CC62B218}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {90B08091-9BBD-4362-B712-E9F2CC62B218}.Debug|Any CPU.Build.0 = Debug|Any CPU - {90B08091-9BBD-4362-B712-E9F2CC62B218}.Release|Any CPU.ActiveCfg = Release|Any CPU - {90B08091-9BBD-4362-B712-E9F2CC62B218}.Release|Any CPU.Build.0 = Release|Any CPU - {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.Build.0 = Release|Any CPU {C810060E-3809-4B74-A125-F11533AF9C1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C810060E-3809-4B74-A125-F11533AF9C1B}.Debug|Any CPU.Build.0 = Debug|Any CPU {C810060E-3809-4B74-A125-F11533AF9C1B}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -650,24 +600,6 @@ Global {4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}.Debug|Any CPU.Build.0 = Debug|Any CPU {4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}.Release|Any CPU.ActiveCfg = Release|Any CPU {4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64}.Release|Any CPU.Build.0 = Release|Any CPU - {2999D79E-3C20-4A90-B651-CA7E0AC92D35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2999D79E-3C20-4A90-B651-CA7E0AC92D35}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2999D79E-3C20-4A90-B651-CA7E0AC92D35}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2999D79E-3C20-4A90-B651-CA7E0AC92D35}.Release|Any CPU.Build.0 = Release|Any CPU - {F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3}.Release|Any CPU.Build.0 = Release|Any CPU - {DFFBDBF5-5DBE-47ED-9EAE-D40B75AC99E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DFFBDBF5-5DBE-47ED-9EAE-D40B75AC99E8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DFFBDBF5-5DBE-47ED-9EAE-D40B75AC99E8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DFFBDBF5-5DBE-47ED-9EAE-D40B75AC99E8}.Release|Any CPU.Build.0 = Release|Any CPU - {A0B29221-2B6F-4B29-A4D5-2227811B5915}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A0B29221-2B6F-4B29-A4D5-2227811B5915}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A0B29221-2B6F-4B29-A4D5-2227811B5915}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {A0B29221-2B6F-4B29-A4D5-2227811B5915}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A0B29221-2B6F-4B29-A4D5-2227811B5915}.Release|Any CPU.Build.0 = Release|Any CPU - {A0B29221-2B6F-4B29-A4D5-2227811B5915}.Release|Any CPU.Deploy.0 = Release|Any CPU {60B4ED1F-ECFA-453B-8A70-1788261C8355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {60B4ED1F-ECFA-453B-8A70-1788261C8355}.Debug|Any CPU.Build.0 = Debug|Any CPU {60B4ED1F-ECFA-453B-8A70-1788261C8355}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -712,17 +644,30 @@ Global {14342787-B4EF-4076-8C91-BA6C523DE8DF}.Debug|Any CPU.Build.0 = Debug|Any CPU {14342787-B4EF-4076-8C91-BA6C523DE8DF}.Release|Any CPU.ActiveCfg = Release|Any CPU {14342787-B4EF-4076-8C91-BA6C523DE8DF}.Release|Any CPU.Build.0 = Release|Any CPU + {A175EFAE-476C-4DAA-87D5-742C18CFCC27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A175EFAE-476C-4DAA-87D5-742C18CFCC27}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A175EFAE-476C-4DAA-87D5-742C18CFCC27}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A175EFAE-476C-4DAA-87D5-742C18CFCC27}.Release|Any CPU.Build.0 = Release|Any CPU + {09EC467F-0F25-4E6F-A836-2BAEC8F6AB0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {09EC467F-0F25-4E6F-A836-2BAEC8F6AB0C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {09EC467F-0F25-4E6F-A836-2BAEC8F6AB0C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09EC467F-0F25-4E6F-A836-2BAEC8F6AB0C}.Release|Any CPU.Build.0 = Release|Any CPU + {342D2657-2F84-493C-B74B-9D2CAE5D9DAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {342D2657-2F84-493C-B74B-9D2CAE5D9DAB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {342D2657-2F84-493C-B74B-9D2CAE5D9DAB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {342D2657-2F84-493C-B74B-9D2CAE5D9DAB}.Release|Any CPU.Build.0 = Release|Any CPU + {26918642-829D-4FA2-B60A-BE8D83F4E063}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {26918642-829D-4FA2-B60A-BE8D83F4E063}.Debug|Any CPU.Build.0 = Debug|Any CPU + {26918642-829D-4FA2-B60A-BE8D83F4E063}.Release|Any CPU.ActiveCfg = Release|Any CPU + {26918642-829D-4FA2-B60A-BE8D83F4E063}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {811A76CF-1CF6-440F-963B-BBE31BD72A82} = {B39A8919-9F95-48FE-AD7B-76E08B509888} - {3E908F67-5543-4879-A1DC-08EACE79B3CD} = {B39A8919-9F95-48FE-AD7B-76E08B509888} {5CCB5571-7C30-4E7D-967D-0E2158EBD91F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {2905FF23-53FB-45E6-AA49-6AF47A172056} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {DABFD304-D6A4-4752-8123-C2CCF7AC7831} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {99135EAB-653D-47E4-A378-C96E1278CA44} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {3E53A01A-B331-47F3-B828-4A5717E77A24} = {8B6A8209-894F-4BA1-B880-965FD453982C} {6417E941-21BC-467B-A771-0DE389353CE6} = {8B6A8209-894F-4BA1-B880-965FD453982C} @@ -741,7 +686,6 @@ Global {F1FDC5B0-4654-416F-AE69-E3E9BBD87801} = {9B9E3891-2366-4253-A952-D08BCEB71098} {29132311-1848-4FD6-AE0C-4FF841151BD3} = {9B9E3891-2366-4253-A952-D08BCEB71098} {7D2D3083-71DD-4CC9-8907-39A0D86FB322} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3} = {9B9E3891-2366-4253-A952-D08BCEB71098} {854568D5-13D1-4B4F-B50D-534DC7EFD3C9} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B} {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E} = {B39A8919-9F95-48FE-AD7B-76E08B509888} {E1582370-37B3-403C-917F-8209551B1634} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} @@ -753,7 +697,6 @@ Global {3C471044-3640-45E3-B1B2-16D2FF8399EE} = {E870DCD7-F46A-498D-83FC-D0FD13E0A11C} {41B02319-965D-4945-8005-C1A3D1224165} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B} {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B} {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC} = {FF237916-7150-496B-89ED-6CA3292896E7} {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7} @@ -761,6 +704,7 @@ Global {11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098} {BC594FD5-4AF2-409E-A1E6-04123F54D7C5} = {9B9E3891-2366-4253-A952-D08BCEB71098} {676D6BFD-029D-4E43-BFC7-3892265CE251} = {9B9E3891-2366-4253-A952-D08BCEB71098} + {CE728F96-A593-462C-B8D4-1D5AFFDB5B4F} = {9B9E3891-2366-4253-A952-D08BCEB71098} {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {26A98DA1-D89D-4A95-8152-349F404DA2E2} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270} = {9B9E3891-2366-4253-A952-D08BCEB71098} @@ -770,10 +714,7 @@ Global {1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} {3B8519C1-2F51-4F12-A348-120AB91D4532} = {9B9E3891-2366-4253-A952-D08BCEB71098} {4A39637C-9338-4925-A4DB-D072E292EC78} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268} - {47F8530C-F19B-4B1A-B4D6-EB231522AE5D} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268} {15B93A4C-1B46-43F6-B534-7B25B6E99932} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {90B08091-9BBD-4362-B712-E9F2CC62B218} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {75C47156-C5D8-44BC-A5A7-E8657C2248D6} = {9B9E3891-2366-4253-A952-D08BCEB71098} {C810060E-3809-4B74-A125-F11533AF9C1B} = {9B9E3891-2366-4253-A952-D08BCEB71098} {C692FE73-43DB-49CE-87FC-F03ED61F25C9} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} {DDA28789-C21A-4654-86CE-D01E81F095C5} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} @@ -786,10 +727,6 @@ Global {F47F8316-4D4B-4026-8EF3-16B2CFDA8119} = {FF237916-7150-496B-89ED-6CA3292896E7} {ED976634-B118-43F8-8B26-0279C7A7044F} = {FF237916-7150-496B-89ED-6CA3292896E7} {4B8EBBEB-A1AD-49EC-8B69-B93ED15BFA64} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {2999D79E-3C20-4A90-B651-CA7E0AC92D35} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {F83FC908-A4E3-40DE-B4CF-A4BA1E92CDB3} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {DFFBDBF5-5DBE-47ED-9EAE-D40B75AC99E8} = {D1300000-7217-4693-8B0F-57CBD5814302} - {A0B29221-2B6F-4B29-A4D5-2227811B5915} = {9B9E3891-2366-4253-A952-D08BCEB71098} {B0FD6A48-FBAB-4676-B36A-DE76B0922B12} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {9D6AEF22-221F-4F4B-B335-A4BA510F002C} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {5BF0C3B8-E595-4940-AB30-2DA206C2F085} = {9D6AEF22-221F-4F4B-B335-A4BA510F002C} @@ -802,6 +739,10 @@ Global {255614F5-CB64-4ECA-A026-E0B1AF6A2EF4} = {9B9E3891-2366-4253-A952-D08BCEB71098} {DE3C28DD-B602-4750-831D-345102A54CA0} = {9B9E3891-2366-4253-A952-D08BCEB71098} {14342787-B4EF-4076-8C91-BA6C523DE8DF} = {9B9E3891-2366-4253-A952-D08BCEB71098} + {A175EFAE-476C-4DAA-87D5-742C18CFCC27} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {09EC467F-0F25-4E6F-A836-2BAEC8F6AB0C} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {342D2657-2F84-493C-B74B-9D2CAE5D9DAB} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {26918642-829D-4FA2-B60A-BE8D83F4E063} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d3ed95005d..8351fc2ea6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ A bug fix will ideally be accompanied by tests. There are a few types of tests: - Unit tests are for issues that aren't related to platform features. These tests are located in the `tests` directly, categorised by the assembly which they're testing. - Integration tests are for issues that are related to platform features (for example fixing a bug with Window resizing). These tests are located in the `tests/Avalonia.IntegrationTests.Appium` directory. Integration tests should be run on Windows and macOS. See the readme in that directory for more information -- Render tests are for issues with rendering. These tests are located in `tests/Avalonia.RenderTests` with separate project files for Skia and Direct2D. The Direct2D backend is currently mostly unmaintained so render tests that just run on Skia are acceptable +- Render tests are for issues with rendering. These tests are located in `tests/Avalonia.RenderTests` and are imported in the `Avalonia.Skia.RenderTests` project. It's not always feasible to accompany a bug fix with a test, but doing so will speed up the review process. @@ -88,4 +88,4 @@ Render tests should describe what the produced image is: ## Code of Conduct This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community. -For more information see the [Contributor Covenant Code of Conduct](https://dotnetfoundation.org/code-of-conduct) \ No newline at end of file +For more information see the [Contributor Covenant Code of Conduct](https://dotnetfoundation.org/code-of-conduct) diff --git a/Directory.Build.props b/Directory.Build.props index f124456eab..4498f87dab 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,11 +4,11 @@ $(MSBuildThisFileDirectory)build-intermediate/nuget - $(MSBuildThisFileDirectory)\src\tools\Avalonia.Designer.HostApp\bin\$(Configuration)\netstandard2.0\Avalonia.Designer.HostApp.dll + $(MSBuildThisFileDirectory)\src\tools\Avalonia.Designer.HostApp\bin\$(Configuration)\$(AvsCurrentTargetFramework)\Avalonia.Designer.HostApp.dll false False - 12 + 14.0 true true true diff --git a/NuGet.Config b/NuGet.Config index 2042fea360..99d827d465 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -3,7 +3,6 @@ - - + diff --git a/api/Avalonia.Android.nupkg.xml b/api/Avalonia.Android.nupkg.xml deleted file mode 100644 index deed9db4de..0000000000 --- a/api/Avalonia.Android.nupkg.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CP0001 - T:Avalonia.Android.AvaloniaMainActivity`1 - baseline/net8.0-android34.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0002 - M:Avalonia.Android.AndroidViewControlHandle.get_HandleDescriptor - baseline/net8.0-android34.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - - CP0007 - T:Avalonia.Android.AndroidViewControlHandle - baseline/net8.0-android34.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll - - \ No newline at end of file diff --git a/api/Avalonia.Browser.nupkg.xml b/api/Avalonia.Browser.nupkg.xml deleted file mode 100644 index 0fb414ed14..0000000000 --- a/api/Avalonia.Browser.nupkg.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CP0002 - M:Avalonia.Browser.JSObjectControlHandle.get_Handle - baseline/net8.0-browser1.0/Avalonia.Browser.dll - target/net8.0-browser1.0/Avalonia.Browser.dll - - - CP0002 - M:Avalonia.Browser.JSObjectControlHandle.get_HandleDescriptor - baseline/net8.0-browser1.0/Avalonia.Browser.dll - target/net8.0-browser1.0/Avalonia.Browser.dll - - - CP0007 - T:Avalonia.Browser.JSObjectControlHandle - baseline/net8.0-browser1.0/Avalonia.Browser.dll - target/net8.0-browser1.0/Avalonia.Browser.dll - - \ No newline at end of file diff --git a/api/Avalonia.FreeDesktop.nupkg.xml b/api/Avalonia.FreeDesktop.nupkg.xml deleted file mode 100644 index f5fcb60bc8..0000000000 --- a/api/Avalonia.FreeDesktop.nupkg.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - CP0001 - T:Tmds.DBus.SourceGenerator.PropertyChanges`1 - baseline/netstandard2.0/Avalonia.FreeDesktop.dll - target/netstandard2.0/Avalonia.FreeDesktop.dll - - \ No newline at end of file diff --git a/api/Avalonia.Skia.nupkg.xml b/api/Avalonia.Skia.nupkg.xml deleted file mode 100644 index b275cbff58..0000000000 --- a/api/Avalonia.Skia.nupkg.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - CP0002 - M:Avalonia.Skia.SkiaSharpExtensions.ToSKFilterQuality(Avalonia.Media.Imaging.BitmapInterpolationMode) - baseline/netstandard2.0/Avalonia.Skia.dll - target/netstandard2.0/Avalonia.Skia.dll - - - CP0006 - M:Avalonia.Skia.ISkiaGpuWithPlatformGraphicsContext.TryGetGrContext - baseline/netstandard2.0/Avalonia.Skia.dll - target/netstandard2.0/Avalonia.Skia.dll - - \ No newline at end of file diff --git a/api/Avalonia.Themes.Fluent.nupkg.xml b/api/Avalonia.Themes.Fluent.nupkg.xml deleted file mode 100644 index 717b64f81e..0000000000 --- a/api/Avalonia.Themes.Fluent.nupkg.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - CP0007 - T:Avalonia.Themes.Fluent.ColorPaletteResources - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - - CP0008 - T:Avalonia.Themes.Fluent.ColorPaletteResources - baseline/netstandard2.0/Avalonia.Themes.Fluent.dll - target/netstandard2.0/Avalonia.Themes.Fluent.dll - - \ No newline at end of file diff --git a/api/Avalonia.Win32.Interoperability.nupkg.xml b/api/Avalonia.Win32.Interoperability.nupkg.xml new file mode 100644 index 0000000000..3672bb9b99 --- /dev/null +++ b/api/Avalonia.Win32.Interoperability.nupkg.xml @@ -0,0 +1,40 @@ + + + + + CP0002 + M:Avalonia.Win32.Interoperability.WinFormsAvaloniaControlHost.PreFilterMessage(System.Windows.Forms.Message@) + baseline/Avalonia.Win32.Interoperability/lib/net461/Avalonia.Win32.Interoperability.dll + current/Avalonia.Win32.Interoperability/lib/net461/Avalonia.Win32.Interoperability.dll + + + CP0002 + M:Avalonia.Win32.Interoperability.WinFormsAvaloniaControlHost.PreFilterMessage(System.Windows.Forms.Message@) + baseline/Avalonia.Win32.Interoperability/lib/net6.0-windows7.0/Avalonia.Win32.Interoperability.dll + current/Avalonia.Win32.Interoperability/lib/net6.0-windows7.0/Avalonia.Win32.Interoperability.dll + + + CP0002 + M:Avalonia.Win32.Interoperability.WinFormsAvaloniaControlHost.PreFilterMessage(System.Windows.Forms.Message@) + baseline/Avalonia.Win32.Interoperability/lib/net8.0-windows7.0/Avalonia.Win32.Interoperability.dll + current/Avalonia.Win32.Interoperability/lib/net8.0-windows7.0/Avalonia.Win32.Interoperability.dll + + + CP0008 + T:Avalonia.Win32.Interoperability.WinFormsAvaloniaControlHost + baseline/Avalonia.Win32.Interoperability/lib/net461/Avalonia.Win32.Interoperability.dll + current/Avalonia.Win32.Interoperability/lib/net461/Avalonia.Win32.Interoperability.dll + + + CP0008 + T:Avalonia.Win32.Interoperability.WinFormsAvaloniaControlHost + baseline/Avalonia.Win32.Interoperability/lib/net6.0-windows7.0/Avalonia.Win32.Interoperability.dll + current/Avalonia.Win32.Interoperability/lib/net6.0-windows7.0/Avalonia.Win32.Interoperability.dll + + + CP0008 + T:Avalonia.Win32.Interoperability.WinFormsAvaloniaControlHost + baseline/Avalonia.Win32.Interoperability/lib/net8.0-windows7.0/Avalonia.Win32.Interoperability.dll + current/Avalonia.Win32.Interoperability/lib/net8.0-windows7.0/Avalonia.Win32.Interoperability.dll + + diff --git a/api/Avalonia.Win32.nupkg.xml b/api/Avalonia.Win32.nupkg.xml deleted file mode 100644 index 3ce897deda..0000000000 --- a/api/Avalonia.Win32.nupkg.xml +++ /dev/null @@ -1,214 +0,0 @@ - - - - - CP0001 - T:Avalonia.Win32.Interop.Automation.DockPosition - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IDockProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IExpandCollapseProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IGridItemProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IGridProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IInvokeProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IMultipleViewProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IRangeValueProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IRawElementProviderAdviseEvents - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IRawElementProviderFragment - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IRawElementProviderFragmentRoot - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IRawElementProviderSimple - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IRawElementProviderSimple2 - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IScrollItemProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IScrollProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.ISelectionItemProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.ISelectionProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.ISynchronizedInputProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.ITableItemProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.ITableProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.ITextProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.ITextRangeProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IToggleProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.ITransformProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IValueProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.IWindowProvider - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.NavigateDirection - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.ProviderOptions - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.RowOrColumnMajor - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.SupportedTextSelection - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.SynchronizedInputType - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.TextPatternRangeEndpoint - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.TextUnit - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.WindowInteractionState - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - - CP0001 - T:Avalonia.Win32.Interop.Automation.WindowVisualState - baseline/netstandard2.0/Avalonia.Win32.dll - target/netstandard2.0/Avalonia.Win32.dll - - \ No newline at end of file diff --git a/api/Avalonia.iOS.nupkg.xml b/api/Avalonia.iOS.nupkg.xml deleted file mode 100644 index 5f6e822d81..0000000000 --- a/api/Avalonia.iOS.nupkg.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - CP0002 - M:Avalonia.iOS.UIViewControlHandle.get_HandleDescriptor - baseline/net8.0-tvos17.0/Avalonia.iOS.dll - target/net8.0-tvos17.0/Avalonia.iOS.dll - - - CP0007 - T:Avalonia.iOS.UIViewControlHandle - baseline/net8.0-tvos17.0/Avalonia.iOS.dll - target/net8.0-tvos17.0/Avalonia.iOS.dll - - \ No newline at end of file diff --git a/api/Avalonia.nupkg.xml b/api/Avalonia.nupkg.xml index 8d64cb2a82..af46d2fb2e 100644 --- a/api/Avalonia.nupkg.xml +++ b/api/Avalonia.nupkg.xml @@ -1,268 +1,448 @@ - - + + CP0001 - T:Avalonia.Controls.PseudolassesExtensions - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + T:Avalonia.Media.Fonts.FontFamilyLoader + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll CP0001 - T:Avalonia.Data.Core.CastTypePropertyPathElement - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + T:Avalonia.Media.Fonts.FontFamilyLoader + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll CP0001 - T:Avalonia.Data.Core.ChildTraversalPropertyPathElement - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + T:Avalonia.Media.Fonts.FontFamilyLoader + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll CP0001 - T:Avalonia.Data.Core.EnsureTypePropertyPathElement - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + T:Avalonia.Media.Fonts.FontFamilyLoader + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll - CP0001 - T:Avalonia.Data.Core.IPropertyPathElement - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0002 + F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll - CP0001 - T:Avalonia.Data.Core.PropertyPath - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0002 + M:Avalonia.Media.Fonts.FontCollectionBase.Initialize(Avalonia.Platform.IFontManagerImpl) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll - CP0001 - T:Avalonia.Data.Core.PropertyPathBuilder - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0002 + M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll - CP0001 - T:Avalonia.Data.Core.PropertyPropertyPathElement - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0002 + M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll - CP0001 - T:Avalonia.Utilities.CharacterReader - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0002 + F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll - CP0001 - T:Avalonia.Utilities.IdentifierParser - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0002 + M:Avalonia.Media.Fonts.FontCollectionBase.Initialize(Avalonia.Platform.IFontManagerImpl) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll - CP0001 - T:Avalonia.Utilities.KeywordParser - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0002 + M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll - CP0001 - T:Avalonia.Utilities.StyleClassParser - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0002 + M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll CP0002 - M:Avalonia.Diagnostics.AppliedStyle.get_HasActivator - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + M:Avalonia.Dialogs.Internal.ManagedFileChooserFilterViewModel.#ctor(Avalonia.Platform.Storage.FilePickerFileType) + baseline/Avalonia/lib/net6.0/Avalonia.Dialogs.dll + current/Avalonia/lib/net6.0/Avalonia.Dialogs.dll CP0002 - M:Avalonia.Diagnostics.AppliedStyle.get_IsActive - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll CP0002 - M:Avalonia.Diagnostics.AppliedStyle.get_Style - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + M:Avalonia.Media.Fonts.FontCollectionBase.Initialize(Avalonia.Platform.IFontManagerImpl) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll CP0002 - M:Avalonia.Diagnostics.StyledElementExtensions.GetStyleDiagnostics(Avalonia.StyledElement) - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll CP0002 - M:Avalonia.Diagnostics.StyleDiagnostics.#ctor(System.Collections.Generic.IReadOnlyList{Avalonia.Diagnostics.AppliedStyle}) - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll CP0002 - M:Avalonia.Diagnostics.StyleDiagnostics.get_AppliedStyles - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + M:Avalonia.Dialogs.Internal.ManagedFileChooserFilterViewModel.#ctor(Avalonia.Platform.Storage.FilePickerFileType) + baseline/Avalonia/lib/net8.0/Avalonia.Dialogs.dll + current/Avalonia/lib/net8.0/Avalonia.Dialogs.dll CP0002 - M:Avalonia.Threading.DispatcherPriorityAwaitable.get_IsCompleted - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll CP0002 - M:Avalonia.Threading.DispatcherPriorityAwaitable.GetAwaiter - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + M:Avalonia.Media.Fonts.FontCollectionBase.Initialize(Avalonia.Platform.IFontManagerImpl) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll CP0002 - M:Avalonia.Threading.DispatcherPriorityAwaitable.GetResult - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll CP0002 - M:Avalonia.Threading.DispatcherPriorityAwaitable.OnCompleted(System.Action) - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll CP0002 - M:Avalonia.Threading.DispatcherPriorityAwaitable`1.GetAwaiter - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + M:Avalonia.Dialogs.Internal.ManagedFileChooserFilterViewModel.#ctor(Avalonia.Platform.Storage.FilePickerFileType) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Dialogs.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Dialogs.dll - CP0002 - M:Avalonia.Threading.DispatcherPriorityAwaitable`1.GetResult - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll - CP0002 - M:Avalonia.Controls.Primitives.IPopupHost.ConfigurePosition(Avalonia.Visual,Avalonia.Controls.PlacementMode,Avalonia.Point,Avalonia.Controls.Primitives.PopupPositioning.PopupAnchor,Avalonia.Controls.Primitives.PopupPositioning.PopupGravity,Avalonia.Controls.Primitives.PopupPositioning.PopupPositionerConstraintAdjustment,System.Nullable{Avalonia.Rect}) - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll + CP0006 + M:Avalonia.Input.Platform.IClipboard.SetDataAsync(Avalonia.Input.IAsyncDataTransfer) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll - CP0002 - M:Avalonia.Controls.Screens.#ctor(Avalonia.Platform.IScreenImpl) - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll + CP0006 + M:Avalonia.Input.Platform.IClipboard.TryGetDataAsync + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Input.Platform.IClipboard.TryGetInProcessDataAsync + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Input.Platform.IPlatformDragSource.DoDragDropAsync(Avalonia.Input.PointerEventArgs,Avalonia.Input.IDataTransfer,Avalonia.Input.DragDropEffects) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IPlatformRenderInterfaceImportedImage.SnapshotWithTimelineSemaphores(Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64,Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.Storage.IStorageProvider.SaveFilePickerWithResultAsync(Avalonia.Platform.Storage.FilePickerSaveOptions) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.OpenGL.IGlExternalSemaphore.SignalTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64) + baseline/Avalonia/lib/net6.0/Avalonia.OpenGL.dll + current/Avalonia/lib/net6.0/Avalonia.OpenGL.dll + + + CP0006 + M:Avalonia.OpenGL.IGlExternalSemaphore.WaitTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64) + baseline/Avalonia/lib/net6.0/Avalonia.OpenGL.dll + current/Avalonia/lib/net6.0/Avalonia.OpenGL.dll + + + CP0006 + P:Avalonia.OpenGL.IGlExternalImageTexture.TextureType + baseline/Avalonia/lib/net6.0/Avalonia.OpenGL.dll + current/Avalonia/lib/net6.0/Avalonia.OpenGL.dll + + + CP0006 + M:Avalonia.Input.Platform.IClipboard.SetDataAsync(Avalonia.Input.IAsyncDataTransfer) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Input.Platform.IClipboard.TryGetDataAsync + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Input.Platform.IClipboard.TryGetInProcessDataAsync + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Input.Platform.IPlatformDragSource.DoDragDropAsync(Avalonia.Input.PointerEventArgs,Avalonia.Input.IDataTransfer,Avalonia.Input.DragDropEffects) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IPlatformRenderInterfaceImportedImage.SnapshotWithTimelineSemaphores(Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64,Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.Storage.IStorageProvider.SaveFilePickerWithResultAsync(Avalonia.Platform.Storage.FilePickerSaveOptions) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll CP0006 - M:Avalonia.Input.Platform.IClipboard.FlushAsync - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + M:Avalonia.OpenGL.IGlExternalSemaphore.SignalTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64) + baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll + current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll CP0006 - M:Avalonia.Input.Platform.IClipboard.TryGetInProcessDataObjectAsync - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + M:Avalonia.OpenGL.IGlExternalSemaphore.WaitTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64) + baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll + current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll CP0006 - M:Avalonia.Platform.Storage.IStorageFolder.GetFileAsync(System.String) - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + P:Avalonia.OpenGL.IGlExternalImageTexture.TextureType + baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll + current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll CP0006 - M:Avalonia.Platform.Storage.IStorageFolder.GetFolderAsync(System.String) - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + M:Avalonia.Input.Platform.IClipboard.SetDataAsync(Avalonia.Input.IAsyncDataTransfer) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll CP0006 - M:Avalonia.Controls.Notifications.IManagedNotificationManager.Close(System.Object) - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll + M:Avalonia.Input.Platform.IClipboard.TryGetDataAsync + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll CP0006 - M:Avalonia.Controls.Notifications.INotificationManager.Close(Avalonia.Controls.Notifications.INotification) - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll + M:Avalonia.Input.Platform.IClipboard.TryGetInProcessDataAsync + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll CP0006 - M:Avalonia.Controls.Notifications.INotificationManager.CloseAll - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll + M:Avalonia.Input.Platform.IPlatformDragSource.DoDragDropAsync(Avalonia.Input.PointerEventArgs,Avalonia.Input.IDataTransfer,Avalonia.Input.DragDropEffects) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll CP0006 - M:Avalonia.Controls.Primitives.IPopupHost.ConfigurePosition(Avalonia.Controls.Primitives.PopupPositioning.PopupPositionRequest) - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll + M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll CP0006 - M:Avalonia.Controls.Primitives.IPopupHost.TakeFocus - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll + M:Avalonia.Platform.IPlatformRenderInterfaceImportedImage.SnapshotWithTimelineSemaphores(Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64,Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll CP0006 - P:Avalonia.Controls.Platform.IInsetsManager.DisplayEdgeToEdgePreference - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll + M:Avalonia.Platform.Storage.IStorageProvider.SaveFilePickerWithResultAsync(Avalonia.Platform.Storage.FilePickerSaveOptions) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll CP0006 - P:Avalonia.Controls.Platform.IInsetsManager.DisplaysEdgeToEdge - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll + M:Avalonia.OpenGL.IGlExternalSemaphore.SignalTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64) + baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll + current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll + + + CP0006 + M:Avalonia.OpenGL.IGlExternalSemaphore.WaitTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64) + baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll + current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll + + + CP0006 + P:Avalonia.OpenGL.IGlExternalImageTexture.TextureType + baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll + current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll + + + CP0012 + M:Avalonia.Media.Fonts.FontCollectionBase.get_Count + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll - CP0007 - T:Avalonia.Threading.DispatcherPriorityAwaitable - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0012 + M:Avalonia.Media.Fonts.FontCollectionBase.get_Item(System.Int32) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll - CP0007 - T:Avalonia.Threading.DispatcherPriorityAwaitable`1 - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0012 + M:Avalonia.Media.Fonts.FontCollectionBase.GetEnumerator + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll - CP0008 - T:Avalonia.Threading.DispatcherPriorityAwaitable - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0012 + P:Avalonia.Media.Fonts.FontCollectionBase.Count + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll - CP0008 - T:Avalonia.Threading.DispatcherPriorityAwaitable`1 - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0012 + P:Avalonia.Media.Fonts.FontCollectionBase.Item(System.Int32) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll - CP0009 - T:Avalonia.Diagnostics.StyleDiagnostics - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0012 + M:Avalonia.Media.Fonts.FontCollectionBase.get_Count + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll - CP0009 - T:Avalonia.Controls.Screens - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll + CP0012 + M:Avalonia.Media.Fonts.FontCollectionBase.get_Item(System.Int32) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0012 + M:Avalonia.Media.Fonts.FontCollectionBase.GetEnumerator + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0012 + P:Avalonia.Media.Fonts.FontCollectionBase.Count + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0012 + P:Avalonia.Media.Fonts.FontCollectionBase.Item(System.Int32) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0012 + M:Avalonia.Media.Fonts.FontCollectionBase.get_Count + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0012 + M:Avalonia.Media.Fonts.FontCollectionBase.get_Item(System.Int32) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0012 + M:Avalonia.Media.Fonts.FontCollectionBase.GetEnumerator + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0012 + P:Avalonia.Media.Fonts.FontCollectionBase.Count + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0012 + P:Avalonia.Media.Fonts.FontCollectionBase.Item(System.Int32) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0012 + M:Avalonia.Media.Fonts.FontCollectionBase.get_Count + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0012 + M:Avalonia.Media.Fonts.FontCollectionBase.get_Item(System.Int32) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0012 + M:Avalonia.Media.Fonts.FontCollectionBase.GetEnumerator + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0012 + P:Avalonia.Media.Fonts.FontCollectionBase.Count + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll CP0012 - M:Avalonia.Controls.Button.OnAccessKey(Avalonia.Interactivity.RoutedEventArgs) - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll + P:Avalonia.Media.Fonts.FontCollectionBase.Item(System.Int32) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll - \ No newline at end of file + diff --git a/azure-pipelines-integrationtests.yml b/azure-pipelines-integrationtests.yml index fa83e8bccd..89b6a3ac53 100644 --- a/azure-pipelines-integrationtests.yml +++ b/azure-pipelines-integrationtests.yml @@ -5,13 +5,13 @@ jobs: steps: - task: UseDotNet@2 - displayName: 'Use .NET 6.0 Runtime' + displayName: 'Use .NET 8.0 Runtime' inputs: packageType: runtime - version: 6.0.x + version: 8.0.x - task: UseDotNet@2 - displayName: 'Use .NET 8.0 SDK' + displayName: 'Use .NET 10.0 SDK' inputs: packageType: sdk useGlobalJson: true @@ -25,16 +25,16 @@ jobs: arch="arm64" fi git clean -ffdx - sudo xcode-select -s /Applications/Xcode.app/Contents/Developer pkill node pkill testmanagerd appium > appium.out & pkill IntegrationTestApp + sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer ./build.sh CompileNative rm -rf $(osascript -e "POSIX path of (path to application id \"net.avaloniaui.avalonia.integrationtestapp\")") pkill IntegrationTestApp ./samples/IntegrationTestApp/bundle.sh - open -n ./samples/IntegrationTestApp/bin/Debug/net8.0/osx-$arch/publish/IntegrationTestApp.app + open -n ./samples/IntegrationTestApp/bin/Debug/net10.0/osx-$arch/publish/IntegrationTestApp.app pkill IntegrationTestApp displayName: 'Build IntegrationTestApp' @@ -56,17 +56,17 @@ jobs: - job: Windows pool: - vmImage: 'windows-2022' + vmImage: 'windows-2025' steps: - task: UseDotNet@2 - displayName: 'Use .NET 6.0 Runtime' + displayName: 'Use .NET 8.0 Runtime' inputs: packageType: runtime - version: 6.0.x + version: 8.0.x - task: UseDotNet@2 - displayName: 'Use .NET 8.0 SDK' + displayName: 'Use .NET 10.0 SDK' inputs: packageType: sdk useGlobalJson: true diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d9a4c80fdf..06da4bcd2b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -2,12 +2,12 @@ jobs: - job: GetPRNumber pool: - vmImage: 'ubuntu-22.04' + vmImage: 'ubuntu-24.04' variables: SolutionDir: '$(Build.SourcesDirectory)' steps: - task: UseDotNet@2 - displayName: 'Use .NET 8.0 SDK' + displayName: 'Use .NET 10.0 SDK' inputs: packageType: sdk useGlobalJson: true @@ -23,16 +23,16 @@ jobs: - job: Linux pool: - vmImage: 'ubuntu-22.04' + vmImage: 'ubuntu-24.04' steps: - task: UseDotNet@2 - displayName: 'Use .NET 6.0 Runtime' + displayName: 'Use .NET 8.0 Runtime' inputs: packageType: runtime - version: 6.0.x + version: 8.0.x - task: UseDotNet@2 - displayName: 'Use .NET 8.0 SDK' + displayName: 'Use .NET 10.0 SDK' inputs: packageType: sdk useGlobalJson: true @@ -62,16 +62,16 @@ jobs: variables: SolutionDir: '$(Build.SourcesDirectory)' pool: - vmImage: 'macos-13' + vmImage: 'macos-15' steps: - task: UseDotNet@2 - displayName: 'Use .NET 6.0 Runtime' + displayName: 'Use .NET 8.0 Runtime' inputs: packageType: runtime - version: 6.0.x + version: 8.0.x - task: UseDotNet@2 - displayName: 'Use .NET 8.0 SDK' + displayName: 'Use .NET 10.0 SDK' inputs: packageType: sdk useGlobalJson: true @@ -95,11 +95,11 @@ jobs: inputs: actions: 'build' scheme: '' - sdk: 'macosx13.0' + sdk: 'macosx26.0' configuration: 'Release' xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace' xcodeVersion: 'specifyPath' # Options: 8, 9, default, specifyPath - xcodeDeveloperDir: '/Applications/Xcode_14.1.app/Contents/Developer' + xcodeDeveloperDir: '/Applications/Xcode_26.0.app/Contents/Developer' args: '-derivedDataPath ./' - task: CmdLine@2 @@ -134,18 +134,18 @@ jobs: - job: Windows pool: - vmImage: 'windows-2022' + vmImage: 'windows-2025' variables: SolutionDir: '$(Build.SourcesDirectory)' steps: - task: UseDotNet@2 - displayName: 'Use .NET 6.0 Runtime' + displayName: 'Use .NET 8.0 Runtime' inputs: packageType: runtime - version: 6.0.x + version: 8.0.x - task: UseDotNet@2 - displayName: 'Use .NET 8.0 SDK' + displayName: 'Use .NET 10.0 SDK' inputs: packageType: sdk useGlobalJson: true @@ -160,7 +160,7 @@ jobs: displayName: 'Install Nuke' inputs: script: | - dotnet tool install --global Nuke.GlobalTool --version 6.2.1 + dotnet tool install --global Nuke.GlobalTool --version 9.0.4 - task: CmdLine@2 displayName: 'Run Nuke' diff --git a/build/AnalyzerProject.targets b/build/AnalyzerProject.targets new file mode 100644 index 0000000000..f067ec0418 --- /dev/null +++ b/build/AnalyzerProject.targets @@ -0,0 +1,14 @@ + + + + true + true + + + + + + + + + diff --git a/build/Base.props b/build/Base.props index 0e667f105b..ab5853fcfa 100644 --- a/build/Base.props +++ b/build/Base.props @@ -1,12 +1,8 @@  - - - - - - - + - + + + diff --git a/build/DevSingleProject.targets b/build/DevSingleProject.targets index f6b9b54d02..6387123429 100644 --- a/build/DevSingleProject.targets +++ b/build/DevSingleProject.targets @@ -9,8 +9,6 @@ - - diff --git a/build/Moq.props b/build/Moq.props index 357f0c9a5f..fc659f7f5f 100644 --- a/build/Moq.props +++ b/build/Moq.props @@ -1,5 +1,5 @@  - + diff --git a/build/ReactiveUI.props b/build/ReactiveUI.props deleted file mode 100644 index 299a91953c..0000000000 --- a/build/ReactiveUI.props +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/build/SharedVersion.props b/build/SharedVersion.props index d18aa6447c..37d14a5647 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -3,7 +3,6 @@ Avalonia 12.0.999 - 11.1.0 Avalonia Team Copyright 2013-$([System.DateTime]::Now.ToString(`yyyy`)) © The AvaloniaUI Project https://avaloniaui.net/?utm_source=nuget&utm_medium=referral&utm_content=project_homepage_link diff --git a/build/SourceLink.props b/build/SourceLink.props index fb014e7e21..62ad50e78d 100644 --- a/build/SourceLink.props +++ b/build/SourceLink.props @@ -14,10 +14,6 @@ true - - - - diff --git a/build/TargetFrameworks.props b/build/TargetFrameworks.props index e48c9933f3..96541e7ecf 100644 --- a/build/TargetFrameworks.props +++ b/build/TargetFrameworks.props @@ -1,19 +1,17 @@ - net8.0 + net10.0 $(AvsCurrentTargetFramework)-windows $(AvsCurrentTargetFramework)-macos - $(AvsCurrentTargetFramework)-android34.0 - $(AvsCurrentTargetFramework)-maccatalyst17.0 - $(AvsCurrentTargetFramework)-ios17.0 - $(AvsCurrentTargetFramework)-tvos17.0 + $(AvsCurrentTargetFramework)-android36.0 + $(AvsCurrentTargetFramework)-maccatalyst26.0 + $(AvsCurrentTargetFramework)-ios26.0 + $(AvsCurrentTargetFramework)-tvos26.0 $(AvsCurrentTargetFramework)-browser - $(AvsCurrentTargetFramework)-tizen - 8.0.155 - net6.0 - net6.0-windows + net8.0 + net8.0-windows @@ -22,8 +20,7 @@ 13.0 13.0 13.1 - 6.5 - 21.0 + 24.0 10.15 diff --git a/build/UnitTests.NetCore.targets b/build/UnitTests.NetCore.targets index 42da8e4ab1..19b2253f4f 100644 --- a/build/UnitTests.NetCore.targets +++ b/build/UnitTests.NetCore.targets @@ -3,7 +3,4 @@ false true - - - - \ No newline at end of file + diff --git a/build/XUnit.props b/build/XUnit.props index b4e9708ecd..4b00869d5b 100644 --- a/build/XUnit.props +++ b/build/XUnit.props @@ -8,7 +8,7 @@ - + $(MSBuildThisFileDirectory)\avalonia.snk diff --git a/dirs.proj b/dirs.proj index 28a91c8b68..084fd30475 100644 --- a/dirs.proj +++ b/dirs.proj @@ -9,23 +9,17 @@ + + - - - - - - - - diff --git a/docs/api-compat.md b/docs/api-compat.md index 1aa4fbd422..17dc42b38c 100644 --- a/docs/api-compat.md +++ b/docs/api-compat.md @@ -29,4 +29,4 @@ API changes are validated against a **baseline version**—the reference point f ## Additional Resources -- [API Validation Tool Implementation](https://github.com/AvaloniaUI/Avalonia/pull/12072) - Pull request that introduced this feature \ No newline at end of file +- [API Validation Tool Implementation](https://github.com/AvaloniaUI/Avalonia/pull/12072) - Pull request that introduced this feature diff --git a/docs/build.md b/docs/build.md index 643c767736..2edf5a8178 100644 --- a/docs/build.md +++ b/docs/build.md @@ -71,6 +71,9 @@ And run tests: Or if you need to create nuget packages as well (it will compile and run tests automatically): `nuke --target Package --configuration Release` +Alternatively, you can run nuke build direclty without installing Nuke global tool: +`dotnet run --project nukebuild/_build.csproj -- --configuration Debug` + # Linux/macOS It's *not* possible to build the *whole* project on Linux/macOS. You can only build the subset targeting .NET Standard and .NET Core (which is, however, sufficient to get UI working on Linux/macOS). If you want to something that involves changing platform-specific APIs you'll need a Windows machine. @@ -97,25 +100,6 @@ On macOS it is necessary to build and manually install the respective native lib ./build.sh CompileNative ``` -# Building Avalonia into a local NuGet cache - -It is possible to build Avalonia locally and generate NuGet packages that can be used locally to test local changes. - -First, install Nuke's dotnet global tool like so: - -```bash -dotnet tool install Nuke.GlobalTool --global -``` - -Then you need to run: -```bash -nuke --target BuildToNuGetCache --configuration Release -``` - -This command will generate nuget packages and push them into a local NuGet automatically. -To use these packages use `9999.0.0-localbuild` package version. -Each time local changes are made to Avalonia, running this command again will replace old packages and reset cache for the same version. - ## Browser To build and run browser/wasm projects, it's necessary to install NodeJS. @@ -124,3 +108,7 @@ You can find latest LTS on https://nodejs.org/. ## Windows It is possible to run some .NET Framework samples and tests using .NET Framework SDK. You need to install at least 4.7 SDK. + +## Building Avalonia into a local NuGet cache + +See [Building Local NuGet Packages](nuget.md) diff --git a/docs/index.md b/docs/index.md index 6adc4fd450..c8355c0f74 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,6 +12,7 @@ This documentation covers Avalonia framework development. For user documentation - [Debugging the XAML Compiler](debug-xaml-compiler.md) - [Porting Code from 3rd Party Sources](porting-code-from-3rd-party-sources.md) +- [Building Local NuGet Packages](nuget.md) ## Releases diff --git a/docs/nuget.md b/docs/nuget.md new file mode 100644 index 0000000000..3ccb571bab --- /dev/null +++ b/docs/nuget.md @@ -0,0 +1,56 @@ +# Building Local NuGet Packages + +To build NuGet packages, one can use the `CreateNugetPackages` target: + +Windows + +``` +.\build.ps1 CreateNugetPackages +``` + +Linux/macOS + +``` +./build.sh CreateNugetPackages +``` + +Or if you have Nuke's [dotnet global tool](https://nuke.build/docs/getting-started/installation/) installed: + +``` +nuke CreateNugetPackages +``` + +The produced NuGet packages will be placed in the `artifacts\nuget` directory. + +> [!NOTE] +> The rest of this document will assume that you have the Nuke global tool installed, as the invocation is the same on all platforms. You can always replace `nuke` in the instructions below with the `build` script relvant to your platform. + +By default the packages will be built in debug configuration. To build in relase configuration add the `--configuration` parameter, e.g.: + +``` +nuke CreateNugetPackages --configuration Release +``` + +To configure the version of the built packages, add the `--force-nuget-version` parameter, e.g.: + +``` +nuke CreateNugetPackages --force-nuget-version 11.4.0 +``` + +## Building to the Local Cache + +Building packages with the `CreateNugetPackages` target has a few gotchas: + +- One needs to set up a local nuget feed to consume the packages +- When building on an operating system other than macOS, the Avalonia.Native package will not be built, resulting in a NuGet error when trying to use Avalonia.Desktop +- It's easy to introduce versioning problems + +For these reasons, it is possible to build Avalonia directly to your machine's NuGet cache using the `BuildToNuGetCache` target: + +```bash +nuke --target BuildToNuGetCache --configuration Release +``` + +This command will generate nuget packages and push them into your local NuGet cache (usually `~/.nuget/packages`) with a version of `9999.0.0-localbuild`. + +Each time local changes are made to Avalonia, running this command again will replace the old packages and reset the cache, meaning that the changes should be picked up automatically by msbuild. diff --git a/docs/porting-code-from-3rd-party-sources.md b/docs/porting-code-from-3rd-party-sources.md index 9aa72b8fce..249c215545 100644 --- a/docs/porting-code-from-3rd-party-sources.md +++ b/docs/porting-code-from-3rd-party-sources.md @@ -9,4 +9,4 @@ When porting code or adapting code from other projects with a MIT compatible lic // Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation. ``` -If the file is a port of a specific commit of file from a 3rd party source, then consider including a permalink to the source file. \ No newline at end of file +If the file is a port of a specific commit of file from a 3rd party source, then consider including a permalink to the source file. diff --git a/docs/release.md b/docs/release.md index 00c83cc47c..42f8927f42 100644 --- a/docs/release.md +++ b/docs/release.md @@ -16,8 +16,10 @@ This document describes the process for creating a new Avalonia release - Create a branch named e.g. `release/11.0.9` for the specific minor version - Update the version number in the file [SharedVersion.props](../build/SharedVersion.props), e.g. `11.0.9` -- Add a tag for this version, e.g. `git tag 11.0.9` -- Push the release branch and the tag. +- Commit the file. +- Add a tag for this version, e.g. `git tag 11.0.9`. +- Update the `release/latest` branch to point to the same commit. +- Push the release branches and the tag. - Wait for azure pipelines to finish the build. Nightly build with 11.0.9 version should be released soon after. - Using the nightly build run a due diligence test to make sure you're happy with the package. - On azure pipelines, on the release for your release branch `release/11.0.9` click on the badge for "Nuget Release" @@ -27,4 +29,4 @@ This document describes the process for creating a new Avalonia release - Replace changelog with one generated by avalonia-backport tool. Enable discussion for the specific release - Review the release information and publish. - Update the dotnet templates, visual studio templates. -- Announce on telegram (RU and EN), twitter, etc \ No newline at end of file +- Announce on telegram (RU and EN), twitter, etc diff --git a/external/XamlX b/external/XamlX index 83567b8a50..c32d3040e5 160000 --- a/external/XamlX +++ b/external/XamlX @@ -1 +1 @@ -Subproject commit 83567b8a50bbf612a0b1420a3dc6d8e8ebee2399 +Subproject commit c32d3040e536ae9768233ea5a445697632578bd0 diff --git a/global.json b/global.json index f496cffc50..60d847ac0c 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.411", + "version": "10.0.100", "rollForward": "latestFeature" }, "msbuild-sdks": { diff --git a/native/Avalonia.Native/inc/com.h b/native/Avalonia.Native/inc/com.h index 42a989e050..9a3f067dce 100644 --- a/native/Avalonia.Native/inc/com.h +++ b/native/Avalonia.Native/inc/com.h @@ -28,7 +28,8 @@ typedef DWORD ULONG; #define E_UNEXPECTED 0x8000FFFFL #define E_HANDLE 0x80070006L #define E_INVALIDARG 0x80070057L -#define COR_E_INVALIDOPERATION 0x80131509L +#define COR_E_INVALIDOPERATION 0x80131509L +#define COR_E_OBJECTDISPOSED 0x80131622L struct IUnknown { diff --git a/native/Avalonia.Native/inc/noarc.h b/native/Avalonia.Native/inc/noarc.h index c49d975ade..7d338bf05d 100644 --- a/native/Avalonia.Native/inc/noarc.h +++ b/native/Avalonia.Native/inc/noarc.h @@ -8,4 +8,7 @@ public: ~CppAutoreleasePool(); }; -#define START_ARP_CALL CppAutoreleasePool __autoreleasePool \ No newline at end of file +#define START_ARP_CALL CppAutoreleasePool __autoreleasePool +extern void ReleaseNSObject(void* obj); +extern void RetainNSObject(void* obj); +extern uint64_t GetRetainCountForNSObject(void* obj); diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj index 9a67ee0161..e82c150961 100644 --- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj +++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj @@ -31,6 +31,8 @@ 1A3E5EAE23E9FB1300EDE661 /* cgl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E5EAD23E9FB1300EDE661 /* cgl.mm */; }; 1A3E5EB023E9FE8300EDE661 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */; }; 1A465D10246AB61600C5858B /* dnd.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A465D0F246AB61600C5858B /* dnd.mm */; }; + 1AC7F1432DCA0C2E003A161B /* crapium.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1AC7F1422DCA0C2E003A161B /* crapium.mm */; }; + 1AE55B8C2DC1060E00FD0BB3 /* memhelp.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1AE55B8B2DC1060E00FD0BB3 /* memhelp.mm */; }; 1AFD334123E03C4F0042899B /* controlhost.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1AFD334023E03C4F0042899B /* controlhost.mm */; }; 37155CE4233C00EB0034DCE9 /* menu.h in Headers */ = {isa = PBXBuildFile; fileRef = 37155CE3233C00EB0034DCE9 /* menu.h */; }; 37A517B32159597E00FBA241 /* Screens.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37A517B22159597E00FBA241 /* Screens.mm */; }; @@ -63,6 +65,7 @@ EDF8CDCD2964CB01001EE34F /* PlatformSettings.mm in Sources */ = {isa = PBXBuildFile; fileRef = EDF8CDCC2964CB01001EE34F /* PlatformSettings.mm */; }; F10084842BFF1F9E0024303E /* TopLevelImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = F10084832BFF1F9E0024303E /* TopLevelImpl.h */; }; F10084862BFF1FB40024303E /* TopLevelImpl.mm in Sources */ = {isa = PBXBuildFile; fileRef = F10084852BFF1FB40024303E /* TopLevelImpl.mm */; }; + F931F8682E2D43A7004E081E /* clipboard.h in Headers */ = {isa = PBXBuildFile; fileRef = F931F8672E2D43A4004E081E /* clipboard.h */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -90,6 +93,9 @@ 1A3E5EAD23E9FB1300EDE661 /* cgl.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cgl.mm; sourceTree = ""; }; 1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 1A465D0F246AB61600C5858B /* dnd.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = dnd.mm; sourceTree = ""; }; + 1AC7F1422DCA0C2E003A161B /* crapium.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objcpp; path = crapium.mm; sourceTree = ""; }; + 1AC7F1442DCA0D6A003A161B /* crapium.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = crapium.h; sourceTree = ""; }; + 1AE55B8B2DC1060E00FD0BB3 /* memhelp.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = memhelp.mm; sourceTree = ""; }; 1AFD334023E03C4F0042899B /* controlhost.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = controlhost.mm; sourceTree = ""; }; 37155CE3233C00EB0034DCE9 /* menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = menu.h; sourceTree = ""; }; 379860FE214DA0C000CD0246 /* KeyTransform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyTransform.h; sourceTree = ""; }; @@ -130,6 +136,7 @@ EDF8CDCC2964CB01001EE34F /* PlatformSettings.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformSettings.mm; sourceTree = ""; }; F10084832BFF1F9E0024303E /* TopLevelImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TopLevelImpl.h; sourceTree = ""; }; F10084852BFF1FB40024303E /* TopLevelImpl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TopLevelImpl.mm; sourceTree = ""; }; + F931F8672E2D43A4004E081E /* clipboard.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = clipboard.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -169,6 +176,9 @@ AB7A61E62147C814003C5833 = { isa = PBXGroup; children = ( + 1AC7F1442DCA0D6A003A161B /* crapium.h */, + 1AC7F1422DCA0C2E003A161B /* crapium.mm */, + 1AE55B8B2DC1060E00FD0BB3 /* memhelp.mm */, F10084852BFF1FB40024303E /* TopLevelImpl.mm */, BC7C33832C066F1100945A48 /* AvnAccessibility.h */, BC7C33812C066DBF00945A48 /* AvnAutomationNode.h */, @@ -189,6 +199,7 @@ 1AFD334023E03C4F0042899B /* controlhost.mm */, 5BF943652167AD1D009CAE35 /* cursor.h */, 5B21A981216530F500CEE36E /* cursor.mm */, + F931F8672E2D43A4004E081E /* clipboard.h */, 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */, 1A465D0F246AB61600C5858B /* dnd.mm */, AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */, @@ -246,6 +257,7 @@ files = ( 37155CE4233C00EB0034DCE9 /* menu.h in Headers */, F10084842BFF1F9E0024303E /* TopLevelImpl.h in Headers */, + F931F8682E2D43A7004E081E /* clipboard.h in Headers */, BC11A5BE2608D58F0017BAD0 /* automation.h in Headers */, 183916173528EC2737DBE5E1 /* WindowBaseImpl.h in Headers */, 1839171DCC651B0638603AC4 /* INSWindowHolder.h in Headers */, @@ -329,6 +341,7 @@ 523484CA26EA688F00EA0C2C /* trayicon.mm in Sources */, AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */, 1A3E5EA823E9E83B00EDE661 /* rendertarget.mm in Sources */, + 1AE55B8C2DC1060E00FD0BB3 /* memhelp.mm in Sources */, 1A3E5EAE23E9FB1300EDE661 /* cgl.mm in Sources */, BC11A5BF2608D58F0017BAD0 /* automation.mm in Sources */, 37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */, @@ -349,6 +362,7 @@ ED754D262A97306B0078B4DF /* PlatformRenderTimer.mm in Sources */, 1839151F32D1BB1AB51A7BB6 /* AvnPanelWindow.mm in Sources */, 18391AC16726CBC45856233B /* AvnWindow.mm in Sources */, + 1AC7F1432DCA0C2E003A161B /* crapium.mm in Sources */, 18391D8CD1756DC858DC1A09 /* PopupImpl.mm in Sources */, EDF8CDCD2964CB01001EE34F /* PlatformSettings.mm in Sources */, 64B1EA48E308E574685AFB07 /* metal.mm in Sources */, @@ -471,6 +485,7 @@ DYLIB_CURRENT_VERSION = 1; EXECUTABLE_PREFIX = lib; HEADER_SEARCH_PATHS = ../../inc; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -482,6 +497,7 @@ DYLIB_CURRENT_VERSION = 1; EXECUTABLE_PREFIX = lib; HEADER_SEARCH_PATHS = ../../inc; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; diff --git a/native/Avalonia.Native/src/OSX/AvnView.h b/native/Avalonia.Native/src/OSX/AvnView.h index c80805a15c..030330c908 100644 --- a/native/Avalonia.Native/src/OSX/AvnView.h +++ b/native/Avalonia.Native/src/OSX/AvnView.h @@ -19,7 +19,6 @@ -(AvnPoint) translateLocalPoint:(AvnPoint)pt; -(void) onClosed; -(void) setModifiers:(NSEventModifierFlags)modifierFlags; --(void) resetPressedMouseButtons; -(AvnPlatformResizeReason) getResizeReason; -(void) setResizeReason:(AvnPlatformResizeReason)reason; diff --git a/native/Avalonia.Native/src/OSX/AvnView.mm b/native/Avalonia.Native/src/OSX/AvnView.mm index 4cc495f321..d4942afced 100644 --- a/native/Avalonia.Native/src/OSX/AvnView.mm +++ b/native/Avalonia.Native/src/OSX/AvnView.mm @@ -456,13 +456,12 @@ static void ConvertTilt(NSPoint tilt, float* xTilt, float* yTilt) switch(event.buttonNumber) { case 2: - case 3: [self mouseEvent:event withType:MiddleButtonDown]; break; - case 4: + case 3: [self mouseEvent:event withType:XButton1Down]; break; - case 5: + case 4: [self mouseEvent:event withType:XButton2Down]; break; @@ -487,13 +486,12 @@ static void ConvertTilt(NSPoint tilt, float* xTilt, float* yTilt) switch(event.buttonNumber) { case 2: - case 3: [self mouseEvent:event withType:MiddleButtonUp]; break; - case 4: + case 3: [self mouseEvent:event withType:XButton1Up]; break; - case 5: + case 4: [self mouseEvent:event withType:XButton2Up]; break; @@ -868,7 +866,7 @@ static void ConvertTilt(NSPoint tilt, float* xTilt, float* yTilt) return NSDragOperationNone; int reffects = (int)parent->TopLevelEvents ->DragEvent(type, point, modifiers, effects, - CreateClipboard([info draggingPasteboard], nil), + CreateClipboard([info draggingPasteboard]), GetAvnDataObjectHandleFromDraggingInfo(info)); NSDragOperation ret = static_cast(0); @@ -943,7 +941,7 @@ static void ConvertTilt(NSPoint tilt, float* xTilt, float* yTilt) auto window = (AvnWindow*)[self window]; auto peer = [window automationPeer]; - if (!peer->IsRootProvider()) + if (peer == nullptr || !peer->IsRootProvider()) return nil; auto clientPoint = [window convertPointFromScreen:point]; @@ -980,6 +978,10 @@ static void ConvertTilt(NSPoint tilt, float* xTilt, float* yTilt) // of the AvnView. auto window = (AvnWindow*)[self window]; auto peer = [window automationPeer]; + if (peer == nullptr) + { + return; + } auto childPeers = peer->GetChildren(); auto childCount = childPeers != nullptr ? childPeers->GetCount() : 0; diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm index 03daa2f296..6d49fc85e0 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -35,6 +35,7 @@ bool _canBecomeKeyWindow; bool _isExtended; bool _isTransitioningToFullScreen; + bool _isTitlebarSession; AvnMenu* _menu; IAvnAutomationPeer* _automationPeer; AvnAutomationNode* _automationNode; @@ -435,23 +436,28 @@ return; } - // If the window has been moved into a position where it's "zoomed" - // Then it should be set as Maximized. - if (window->WindowState() != Maximized && window->IsZoomed()) + // Don't adjust window state during fullscreen transitions + // as this can interfere with proper decoration restoration + if(!window->IsTransitioningWindowState()) { - window->SetWindowState(Maximized, false); - } - // We should only return the window state to normal if - // the internal window state is maximized, and macOS says - // the window is no longer zoomed (I.E, the user has moved it) - // Stage Manager will "move" the window when repositioning it - // So if the window was "maximized" before, it should stay maximized - else if(window->WindowState() == Maximized && !window->IsZoomed()) - { - // If we're moving the window while maximized, - // we need to let macOS handle if it should be resized - // And not handle it ourselves. - window->SetWindowState(Normal, false); + // If the window has been moved into a position where it's "zoomed" + // Then it should be set as Maximized. + if (window->WindowState() != Maximized && window->IsZoomed()) + { + window->SetWindowState(Maximized, false); + } + // We should only return the window state to normal if + // the internal window state is maximized, and macOS says + // the window is no longer zoomed (I.E, the user has moved it) + // Stage Manager will "move" the window when repositioning it + // So if the window was "maximized" before, it should stay maximized + else if(window->WindowState() == Maximized && !window->IsZoomed()) + { + // If we're moving the window while maximized, + // we need to let macOS handle if it should be resized + // And not handle it ourselves. + window->SetWindowState(Normal, false); + } } } @@ -501,68 +507,10 @@ return NO; } -- (void)forwardToAvnView:(NSEvent *)event -{ - auto parent = _parent.tryGetWithCast(); - if (!parent) { - return; - } - - switch(event.type) { - case NSEventTypeLeftMouseDown: - [parent->View mouseDown:event]; - break; - case NSEventTypeLeftMouseUp: - [parent->View mouseUp:event]; - break; - case NSEventTypeLeftMouseDragged: - [parent->View mouseDragged:event]; - break; - case NSEventTypeRightMouseDown: - [parent->View rightMouseDown:event]; - break; - case NSEventTypeRightMouseUp: - [parent->View rightMouseUp:event]; - break; - case NSEventTypeRightMouseDragged: - [parent->View rightMouseDragged:event]; - break; - case NSEventTypeOtherMouseDown: - [parent->View otherMouseDown:event]; - break; - case NSEventTypeOtherMouseUp: - [parent->View otherMouseUp:event]; - break; - case NSEventTypeOtherMouseDragged: - [parent->View otherMouseDragged:event]; - break; - case NSEventTypeMouseMoved: - [parent->View mouseMoved:event]; - break; - default: - break; - } -} - - (void)sendEvent:(NSEvent *_Nonnull)event { - // Event-tracking loop for thick titlebar mouse events - if (event.type == NSEventTypeLeftMouseDown && [self isPointInTitlebar:event.locationInWindow]) - { - NSEventMask mask = NSEventMaskLeftMouseDragged | NSEventMaskLeftMouseUp; - NSEvent *ev = event; - while (ev.type != NSEventTypeLeftMouseUp) - { - [self forwardToAvnView:ev]; - [super sendEvent:ev]; - ev = [NSApp nextEventMatchingMask:mask - untilDate:[NSDate distantFuture] - inMode:NSEventTrackingRunLoopMode - dequeue:YES]; - } - [self forwardToAvnView:ev]; - [super sendEvent:ev]; - return; + if (event.type == NSEventTypeLeftMouseDown) { + _isTitlebarSession = [self isPointInTitlebar:event.locationInWindow]; } [super sendEvent:event]; @@ -603,6 +551,37 @@ } break; + case NSEventTypeLeftMouseDragged: + case NSEventTypeMouseMoved: + case NSEventTypeLeftMouseUp: + { + // Usually NSToolbar events are passed natively to AvnView when the mouse is inside the control. + // When a drag operation started in NSToolbar leaves the control region, the view does not get any + // events. We will detect this scenario and pass events ourselves. + + if(!_isTitlebarSession || [self isPointInTitlebar:event.locationInWindow]) + break; + + AvnView* view = parent->View; + + if(!view) + break; + + if(event.type == NSEventTypeLeftMouseDragged) + { + [view mouseDragged:event]; + } + else if(event.type == NSEventTypeMouseMoved) + { + [view mouseMoved:event]; + } + else if(event.type == NSEventTypeLeftMouseUp) + { + [view mouseUp:event]; + } + } + break; + case NSEventTypeMouseEntered: { parent->UpdateCursor(); @@ -618,6 +597,10 @@ default: break; } + + if(event.type == NSEventTypeLeftMouseUp) { + _isTitlebarSession = NO; + } } } @@ -627,21 +610,30 @@ - (id _Nullable) accessibilityFocusedUIElement { - if (![self automationPeer]->IsRootProvider()) + auto automationPeer = [self automationPeer]; + if (automationPeer == nullptr || !automationPeer->IsRootProvider()) return nil; - auto focusedPeer = [self automationPeer]->RootProvider_GetFocus(); + + auto focusedPeer = automationPeer->RootProvider_GetFocus(); + if (focusedPeer == nullptr) + return nil; + return [AvnAccessibilityElement acquire:focusedPeer]; } - (NSString * _Nullable) accessibilityIdentifier { - return GetNSStringAndRelease([self automationPeer]->GetAutomationId()); + auto automationPeer = [self automationPeer]; + if (automationPeer == nullptr) + return nil; + + return GetNSStringAndRelease(automationPeer->GetAutomationId()); } - (IAvnAutomationPeer* _Nonnull) automationPeer { auto parent = _parent.tryGet(); - if (_automationPeer == nullptr) + if (parent && _automationPeer == nullptr) { _automationPeer = parent->BaseEvents->GetAutomationPeer(); _automationNode = new AvnAutomationNode(self); @@ -654,7 +646,8 @@ - (void)raiseChildrenChanged { auto parent = _parent.tryGet(); - [parent->View raiseAccessibilityChildrenChanged]; + if(parent) + [parent->View raiseAccessibilityChildrenChanged]; } - (void)raiseFocusChanged diff --git a/native/Avalonia.Native/src/OSX/KeyTransform.mm b/native/Avalonia.Native/src/OSX/KeyTransform.mm index ba3d809dd9..a6056cef91 100644 --- a/native/Avalonia.Native/src/OSX/KeyTransform.mm +++ b/native/Avalonia.Native/src/OSX/KeyTransform.mm @@ -33,7 +33,7 @@ const KeyInfo keyInfos[] = { 0x1A, AvnPhysicalKeyDigit7, AvnKeyD7, '7' }, { 0x1C, AvnPhysicalKeyDigit8, AvnKeyD8, '8' }, { 0x19, AvnPhysicalKeyDigit9, AvnKeyD9, '9' }, - { 0x18, AvnPhysicalKeyEqual, AvnKeyOemMinus, '-' }, + { 0x18, AvnPhysicalKeyEqual, AvnKeyOemPlus, '=' }, { 0x0A, AvnPhysicalKeyIntlBackslash, AvnKeyOem102, 0 }, { 0x5E, AvnPhysicalKeyIntlRo, AvnKeyOem102, 0 }, { 0x5D, AvnPhysicalKeyIntlYen, AvnKeyOem5, 0 }, diff --git a/native/Avalonia.Native/src/OSX/StorageProvider.mm b/native/Avalonia.Native/src/OSX/StorageProvider.mm index 92278a85e9..570281fdfd 100644 --- a/native/Avalonia.Native/src/OSX/StorageProvider.mm +++ b/native/Avalonia.Native/src/OSX/StorageProvider.mm @@ -320,12 +320,22 @@ public: } auto handler = ^(NSModalResponse result) { + int selectedIndex = -1; + if (panel.accessoryView != nil) + { + auto popup = [panel.accessoryView viewWithTag:kFileTypePopupTag]; + if ([popup isKindOfClass:[NSPopUpButton class]]) + { + selectedIndex = (int)[(NSPopUpButton*)popup indexOfSelectedItem]; + } + } + if(result == NSFileHandlingPanelOKButton) { auto url = [panel URL]; auto urls = [NSArray arrayWithObject:url]; auto uriStrings = CreateAvnStringArray(urls); - events->OnCompleted(uriStrings); + events->OnCompletedWithFilter(uriStrings, selectedIndex); [panel orderOut:panel]; @@ -338,7 +348,7 @@ public: return; } - events->OnCompleted(nullptr); + events->OnCompletedWithFilter(nullptr, selectedIndex); }; @@ -355,6 +365,35 @@ public: } } + virtual HRESULT TryResolveFileReferenceUri(IAvnString* fileUriStr, IAvnString** ret) override { + if (ret == nullptr) + return E_POINTER; + + if (fileUriStr == nullptr) + { + *ret = nullptr; + return S_OK; + } + + auto fileUri = [NSURL URLWithString:GetNSStringAndRelease(fileUriStr)]; + if (fileUri == nil) + { + *ret = nullptr; + return S_OK; + } + + auto filePathUri = [fileUri filePathURL]; + if (fileUri == nil) + { + *ret = nullptr; + return S_OK; + } + + *ret = CreateAvnString([filePathUri absoluteString]); + return S_OK; + } + + private: NSView* CreateAccessoryView() { // The label. Add attributes per-OS to match the labels that macOS uses. diff --git a/native/Avalonia.Native/src/OSX/TopLevelImpl.h b/native/Avalonia.Native/src/OSX/TopLevelImpl.h index dd494ab761..0be1439ec2 100644 --- a/native/Avalonia.Native/src/OSX/TopLevelImpl.h +++ b/native/Avalonia.Native/src/OSX/TopLevelImpl.h @@ -60,6 +60,14 @@ public: virtual HRESULT SetTransparencyMode(AvnWindowTransparencyMode mode) override; virtual HRESULT GetCurrentDisplayId (CGDirectDisplayID* ret) override; + + virtual HRESULT BeginDragAndDropOperation( + AvnDragDropEffects effects, + AvnPoint point, + IAvnClipboardDataSource* source, + IAvnDndResultCallback* callback, + void* sourceHandle) override; + protected: NSCursor *cursor; virtual void UpdateAppearance(); diff --git a/native/Avalonia.Native/src/OSX/TopLevelImpl.mm b/native/Avalonia.Native/src/OSX/TopLevelImpl.mm index 6200f096d3..bdfc1be62f 100644 --- a/native/Avalonia.Native/src/OSX/TopLevelImpl.mm +++ b/native/Avalonia.Native/src/OSX/TopLevelImpl.mm @@ -6,6 +6,8 @@ #include "TopLevelImpl.h" #include "AvnTextInputMethod.h" #include "AvnView.h" +#include "common.h" +#include "clipboard.h" TopLevelImpl::~TopLevelImpl() { View = nullptr; @@ -271,6 +273,66 @@ void TopLevelImpl::UpdateAppearance() { } +HRESULT TopLevelImpl::BeginDragAndDropOperation( + AvnDragDropEffects effects, + AvnPoint point, + IAvnClipboardDataSource* source, + IAvnDndResultCallback* callback, + void* sourceHandle) +{ + START_COM_CALL; + + if (View == NULL) + return E_FAIL; + + auto nsevent = [NSApp currentEvent]; + auto nseventType = [nsevent type]; + + // If current event isn't a mouse one (probably due to malfunctioning user app) + // attempt to forge a new one + if (!((nseventType >= NSEventTypeLeftMouseDown && nseventType <= NSEventTypeMouseExited) + || (nseventType >= NSEventTypeOtherMouseDown && nseventType <= NSEventTypeOtherMouseDragged))) { + // For TopLevelImpl, we don't have a Window so we use the View's window + auto window = [View window]; + if (window != nil) { + NSRect convertRect = [window convertRectToScreen:NSMakeRect(point.X, point.Y, 0.0, 0.0)]; + auto nspoint = NSMakePoint(convertRect.origin.x, convertRect.origin.y); + CGPoint cgpoint = NSPointToCGPoint(nspoint); + auto cgevent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, cgpoint, kCGMouseButtonLeft); + nsevent = [NSEvent eventWithCGEvent:cgevent]; + CFRelease(cgevent); + } + } + + auto itemCount = source->GetItemCount(); + auto draggingItems = [NSMutableArray arrayWithCapacity:itemCount]; + auto dragItemImage = [NSImage imageNamed:NSImageNameMultipleDocuments]; + NSRect dragItemRect = {(float) point.X, (float) point.Y, [dragItemImage size].width, [dragItemImage size].height}; + + for (auto i = 0; i < itemCount; ++i) + { + auto item = source->GetItem(i); + auto writeableItem = [[WriteableClipboardItem alloc] initWithItem:item source:source]; + auto draggingItem = [[NSDraggingItem alloc] initWithPasteboardWriter:writeableItem]; + [draggingItem setDraggingFrame:dragItemRect contents:dragItemImage]; + [draggingItems addObject:draggingItem]; + } + + int op = 0; + int ieffects = (int) effects; + if ((ieffects & (int) AvnDragDropEffects::Copy) != 0) + op |= NSDragOperationCopy; + if ((ieffects & (int) AvnDragDropEffects::Link) != 0) + op |= NSDragOperationLink; + if ((ieffects & (int) AvnDragDropEffects::Move) != 0) + op |= NSDragOperationMove; + + [View beginDraggingSessionWithItems:draggingItems + event:nsevent + source:CreateDraggingSource((NSDragOperation) op, callback, sourceHandle)]; + return S_OK; +} + void TopLevelImpl::SetClientSize(NSSize size){ [View setFrameSize:size]; } diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h index 0c3d410094..873a520d6d 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h @@ -69,10 +69,6 @@ public: virtual HRESULT SetFrameThemeVariant(AvnPlatformThemeVariant variant) override; - virtual HRESULT BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point, - IAvnClipboard *clipboard, IAvnDndResultCallback *cb, - void *sourceHandle) override; - virtual HRESULT SetTransparencyMode(AvnWindowTransparencyMode mode) override; virtual bool IsModal(); diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index 6553e8f460..551ea4c2e0 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -411,51 +411,6 @@ HRESULT WindowBaseImpl::SetFrameThemeVariant(AvnPlatformThemeVariant variant) { return S_OK; } -HRESULT WindowBaseImpl::BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point, IAvnClipboard *clipboard, IAvnDndResultCallback *cb, void *sourceHandle) { - START_COM_CALL; - - auto item = TryGetPasteboardItem(clipboard); - [item setString:@"" forType:GetAvnCustomDataType()]; - if (item == nil) - return E_INVALIDARG; - if (View == NULL) - return E_FAIL; - - auto nsevent = [NSApp currentEvent]; - auto nseventType = [nsevent type]; - - // If current event isn't a mouse one (probably due to malfunctioning user app) - // attempt to forge a new one - if (!((nseventType >= NSEventTypeLeftMouseDown && nseventType <= NSEventTypeMouseExited) - || (nseventType >= NSEventTypeOtherMouseDown && nseventType <= NSEventTypeOtherMouseDragged))) { - NSRect convertRect = [Window convertRectToScreen:NSMakeRect(point.X, point.Y, 0.0, 0.0)]; - auto nspoint = NSMakePoint(convertRect.origin.x, convertRect.origin.y); - CGPoint cgpoint = NSPointToCGPoint(nspoint); - auto cgevent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, cgpoint, kCGMouseButtonLeft); - nsevent = [NSEvent eventWithCGEvent:cgevent]; - CFRelease(cgevent); - } - - auto dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:item]; - - auto dragItemImage = [NSImage imageNamed:NSImageNameMultipleDocuments]; - NSRect dragItemRect = {(float) point.X, (float) point.Y, [dragItemImage size].width, [dragItemImage size].height}; - [dragItem setDraggingFrame:dragItemRect contents:dragItemImage]; - - int op = 0; - int ieffects = (int) effects; - if ((ieffects & (int) AvnDragDropEffects::Copy) != 0) - op |= NSDragOperationCopy; - if ((ieffects & (int) AvnDragDropEffects::Link) != 0) - op |= NSDragOperationLink; - if ((ieffects & (int) AvnDragDropEffects::Move) != 0) - op |= NSDragOperationMove; - [View resetPressedMouseButtons]; - [View beginDraggingSessionWithItems:@[dragItem] event:nsevent - source:CreateDraggingSource((NSDragOperation) op, cb, sourceHandle)]; - return S_OK; -} - bool WindowBaseImpl::IsModal() { return false; } diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.h b/native/Avalonia.Native/src/OSX/WindowImpl.h index 37699082ed..940699f09d 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowImpl.h @@ -45,6 +45,10 @@ BEGIN_INTERFACE_MAP() void DoZoom(); virtual HRESULT SetCanResize(bool value) override; + + virtual HRESULT SetCanMinimize(bool value) override; + + virtual HRESULT SetCanMaximize(bool value) override; virtual HRESULT SetDecorations(SystemDecorations value) override; @@ -82,8 +86,10 @@ BEGIN_INTERFACE_MAP() bool CanBecomeKeyWindow (); - bool CanZoom() override { return _isEnabled && _canResize; } - + bool CanZoom() override { return _isEnabled && _canMaximize; } + + bool IsTransitioningWindowState() { return _transitioningWindowState; } + protected: virtual NSWindowStyleMask CalculateStyleMask() override; virtual void UpdateAppearance() override; @@ -94,6 +100,8 @@ private: NSString *_lastTitle; bool _isEnabled; bool _canResize; + bool _canMinimize; + bool _canMaximize; bool _fullScreenActive; SystemDecorations _decorations; AvnWindowState _lastWindowState; diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index 341085ec08..5a57715b55 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -16,6 +16,8 @@ WindowImpl::WindowImpl(IAvnWindowEvents *events) : TopLevelImpl(events), WindowB _extendClientHints = AvnDefaultChrome; _fullScreenActive = false; _canResize = true; + _canMinimize = true; + _canMaximize = true; _decorations = SystemDecorationsFull; _transitioningWindowState = false; _inSetWindowState = false; @@ -191,7 +193,8 @@ bool WindowImpl::IsZoomed() { void WindowImpl::DoZoom() { if (_decorations == SystemDecorationsNone || _decorations == SystemDecorationsBorderOnly || - _canResize == false) { + _canResize == false || + _canMaximize == false) { [Window setFrame:[Window screen].visibleFrame display:true]; } else { [Window performZoom:Window]; @@ -208,6 +211,22 @@ HRESULT WindowImpl::SetCanResize(bool value) { } } +HRESULT WindowImpl::SetCanMinimize(bool value) { + START_COM_ARP_CALL; + + _canMinimize = value; + UpdateAppearance(); + return S_OK; +} + +HRESULT WindowImpl::SetCanMaximize(bool value) { + START_COM_ARP_CALL; + + _canMaximize = value; + UpdateAppearance(); + return S_OK; +} + HRESULT WindowImpl::SetDecorations(SystemDecorations value) { START_COM_CALL; @@ -583,7 +602,7 @@ NSWindowStyleMask WindowImpl::CalculateStyleMask() { break; } - if (!IsOwned()) { + if (_canMinimize && !IsOwned()) { s |= NSWindowStyleMaskMiniaturizable; } @@ -611,9 +630,9 @@ void WindowImpl::UpdateAppearance() { [closeButton setHidden:!hasTrafficLights]; [closeButton setEnabled:_isEnabled]; [miniaturizeButton setHidden:!hasTrafficLights]; - [miniaturizeButton setEnabled:_isEnabled]; + [miniaturizeButton setEnabled:_isEnabled && _canMinimize]; [zoomButton setHidden:!hasTrafficLights]; - [zoomButton setEnabled:CanZoom()]; + [zoomButton setEnabled:CanZoom() || (([Window styleMask] & NSWindowStyleMaskFullScreen) != 0 && _isEnabled)]; } extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events) diff --git a/native/Avalonia.Native/src/OSX/automation.mm b/native/Avalonia.Native/src/OSX/automation.mm index 1847a83160..fccb53b7aa 100644 --- a/native/Avalonia.Native/src/OSX/automation.mm +++ b/native/Avalonia.Native/src/OSX/automation.mm @@ -122,7 +122,7 @@ case AutomationSplitButton: return NSAccessibilityPopUpButtonRole; case AutomationWindow: return NSAccessibilityWindowRole; case AutomationPane: return NSAccessibilityGroupRole; - case AutomationHeader: return NSAccessibilityGroupRole; + case AutomationHeader: return @"AXHeading"; case AutomationHeaderItem: return NSAccessibilityButtonRole; case AutomationTable: return NSAccessibilityTableRole; case AutomationTitleBar: return NSAccessibilityGroupRole; @@ -133,6 +133,38 @@ } } +- (NSAccessibilitySubrole)accessibilitySubrole +{ + auto landmarkType = _peer->GetLandmarkType(); + switch (landmarkType) { + case LandmarkBanner: return @"AXLandmarkBanner"; + case LandmarkComplementary: return @"AXLandmarkComplementary"; + case LandmarkContentInfo: return @"AXLandmarkContentInfo"; + case LandmarkRegion: return @"AXLandmarkRegion"; + case LandmarkForm: return @"AXLandmarkForm"; + case LandmarkMain: return @"AXLandmarkMain"; + case LandmarkNavigation: return @"AXLandmarkNavigation"; + case LandmarkSearch: return @"AXLandmarkSearch"; + default: return NSAccessibilityUnknownSubrole; + } +} + +- (NSString *)accessibilityRoleDescription +{ + auto landmarkType = _peer->GetLandmarkType(); + switch (landmarkType) { + case LandmarkBanner: return @"banner"; + case LandmarkComplementary: return @"complementary"; + case LandmarkContentInfo: return @"content"; + case LandmarkRegion: return @"region"; + case LandmarkForm: return @"form"; + case LandmarkMain: return @"main"; + case LandmarkNavigation: return @"navigation"; + case LandmarkSearch: return @"search"; + } + return NSAccessibilityRoleDescription([self accessibilityRole], [self accessibilitySubrole]); +} + - (NSString *)accessibilityIdentifier { return GetNSStringAndRelease(_peer->GetAutomationId()); @@ -176,6 +208,10 @@ { return GetNSStringAndRelease(_peer->GetName()); } + else if (_peer->GetAutomationControlType() == AutomationHeader) + { + return [NSNumber numberWithInt:_peer->GetHeadingLevel()]; + } return [super accessibilityValue]; } diff --git a/native/Avalonia.Native/src/OSX/cgl.mm b/native/Avalonia.Native/src/OSX/cgl.mm index 085037978e..4fc4064df1 100644 --- a/native/Avalonia.Native/src/OSX/cgl.mm +++ b/native/Avalonia.Native/src/OSX/cgl.mm @@ -107,6 +107,61 @@ public: return Context; } + int texImageIOSurface2D(int target, int internal_format, + int width, int height, int format, int type, void* ioSurface, int plane) override + { + return CGLTexImageIOSurface2D(Context, target, internal_format, width, height, format, type, (IOSurfaceRef)ioSurface, plane); + } + + bool GetIOKitRegistryId(uint64_t *value) override { + if (@available(macOS 10.13, *)) + { + + GLint rendererId; + if(CGLGetParameter(Context, kCGLCPCurrentRendererID, &rendererId) != 0) + return false; + + GLint rendererCount = 0; + CGLRendererInfoObj rendererInfo; + + if(CGLQueryRendererInfo(0xFFFFFFFF, &rendererInfo, &rendererCount)) + return false; + + @try + { + for(auto i = 0; i < rendererCount; i++) + { + GLint thisRendererID; + + CGLDescribeRenderer(rendererInfo, i, kCGLRPRendererID, &thisRendererID); + if(thisRendererID == rendererId) + { + GLint gpuIDLow = 0; + GLint gpuIDHigh = 0; + + if(CGLDescribeRenderer(rendererInfo, 0, kCGLRPRegistryIDLow, &gpuIDLow)) + return false; + + if(CGLDescribeRenderer(rendererInfo, 0, kCGLRPRegistryIDHigh, &gpuIDHigh)) + return false; + + *value = ((uint64_t)gpuIDHigh << 32) | gpuIDLow; + return true; + } + } + return false; + + } + @finally + { + CGLDestroyRendererInfo(rendererInfo); + } + } + else + return false; + } + + ~AvnGlContext() { CGLReleaseContext(Context); diff --git a/native/Avalonia.Native/src/OSX/clipboard.h b/native/Avalonia.Native/src/OSX/clipboard.h new file mode 100644 index 0000000000..fd0ddbf117 --- /dev/null +++ b/native/Avalonia.Native/src/OSX/clipboard.h @@ -0,0 +1,7 @@ +#pragma once + +#include "common.h" + +@interface WriteableClipboardItem : NSObject +- (nonnull instancetype) initWithItem:(nonnull IAvnClipboardDataItem*)item source:(nonnull IAvnClipboardDataSource*)source; +@end diff --git a/native/Avalonia.Native/src/OSX/clipboard.mm b/native/Avalonia.Native/src/OSX/clipboard.mm index 68f0e7d87a..9786a64b27 100644 --- a/native/Avalonia.Native/src/OSX/clipboard.mm +++ b/native/Avalonia.Native/src/OSX/clipboard.mm @@ -1,206 +1,354 @@ +#import #include "common.h" +#include "clipboard.h" #include "AvnString.h" class Clipboard : public ComSingleObject { private: - NSPasteboard* _pb; - NSPasteboardItem* _item; + NSPasteboard* _pasteboard; public: FORWARD_IUNKNOWN() - Clipboard(NSPasteboard* pasteboard, NSPasteboardItem* item) + Clipboard(NSPasteboard* pasteboard) { - if(pasteboard == nil && item == nil) + if (pasteboard == nil) pasteboard = [NSPasteboard generalPasteboard]; - _pb = pasteboard; - _item = item; + _pasteboard = pasteboard; } - NSPasteboardItem* TryGetItem() + virtual HRESULT GetFormats(int64_t changeCount, IAvnStringArray** ret) override { - return _item; + START_COM_ARP_CALL; + + if (ret == nullptr) + return E_POINTER; + + if (changeCount != [_pasteboard changeCount]) + return COR_E_OBJECTDISPOSED; + + *ret = ConvertPasteboardTypes([_pasteboard types]); + return S_OK; } - - virtual HRESULT GetText (char* type, IAvnString**ppv) override + + virtual HRESULT GetItemCount(int64_t changeCount, int* ret) override { - START_COM_CALL; + START_COM_ARP_CALL; - @autoreleasepool + if (ret == nullptr) + return E_POINTER; + + if (changeCount != [_pasteboard changeCount]) + return COR_E_OBJECTDISPOSED; + + auto items = [_pasteboard pasteboardItems]; + *ret = items == nil ? 0 : (int)[items count]; + return S_OK; + } + + virtual HRESULT GetItemFormats(int index, int64_t changeCount, IAvnStringArray** ret) override + { + START_COM_ARP_CALL; + + if (ret == nullptr) + return E_POINTER; + + if (changeCount != [_pasteboard changeCount]) + return COR_E_OBJECTDISPOSED; + + auto item = [[_pasteboard pasteboardItems] objectAtIndex:index]; + + *ret = ConvertPasteboardTypes([item types]); + return S_OK; + } + + static IAvnStringArray* ConvertPasteboardTypes(NSArray *types) + { + if (types != nil) { - if(ppv == nullptr) + NSMutableArray *mutableTypes = [types mutableCopy]; + + // Add png if format list doesn't have PNG, + // but has any other image type that can be converter into PNG + if (![mutableTypes containsObject:NSPasteboardTypePNG]) { - return E_POINTER; + if ([mutableTypes containsObject:NSPasteboardTypeTIFF] + || [mutableTypes containsObject:@"public.jpeg"]) + { + [mutableTypes addObject: NSPasteboardTypePNG]; + } } - NSString* typeString = [NSString stringWithUTF8String:(const char*)type]; - NSString* string = _item == nil ? [_pb stringForType:typeString] : [_item stringForType:typeString]; - - *ppv = CreateAvnString(string); - - return S_OK; + + return CreateAvnStringArray(mutableTypes); } + + return nil; } - - virtual HRESULT SetStrings(char* type, IAvnStringArray*ppv) override + + virtual HRESULT GetItemValueAsString(int index, int64_t changeCount, const char* format, IAvnString** ret) override { - START_COM_CALL; + START_COM_ARP_CALL; - @autoreleasepool - { - NSArray* data = GetNSArrayOfStringsAndRelease(ppv); - NSString* typeString = [NSString stringWithUTF8String:(const char*)type]; - if(_item == nil) - [_pb setPropertyList: data forType: typeString]; - else - [_item setPropertyList: data forType:typeString]; - return S_OK; - } + if (ret == nullptr) + return E_POINTER; + + if (changeCount != [_pasteboard changeCount]) + return COR_E_OBJECTDISPOSED; + + auto item = [[_pasteboard pasteboardItems] objectAtIndex:index]; + auto value = [item stringForType:[NSString stringWithUTF8String:format]]; + *ret = value == nil ? nullptr : CreateAvnString(value); + return S_OK; } - virtual HRESULT GetStrings(char* type, IAvnStringArray**ppv) override + virtual HRESULT GetItemValueAsBytes(int index, int64_t changeCount, const char* format, IAvnString** ret) override { - START_COM_CALL; + START_COM_ARP_CALL; - @autoreleasepool + if (ret == nullptr) + return E_POINTER; + + if (changeCount != [_pasteboard changeCount]) + return COR_E_OBJECTDISPOSED; + + auto item = [[_pasteboard pasteboardItems] objectAtIndex:index]; + auto formatStr = [NSString stringWithUTF8String:format]; + + auto value = [item dataForType: formatStr]; + + // If PNG wasn't found, try to convert TIFF or JPEG to PNG + if (value == nil && [formatStr isEqualToString: NSPasteboardTypePNG]) { - *ppv= nil; - NSString* typeString = [NSString stringWithUTF8String:(const char*)type]; - NSObject* data = _item == nil ? [_pb propertyListForType: typeString] : [_item propertyListForType: typeString]; - if(data == nil) - return S_OK; - - if([data isKindOfClass: [NSString class]]) + NSData *imageData = nil; + + // Try TIFF first + imageData = [item dataForType:NSPasteboardTypeTIFF]; + + // If no TIFF, try JPEG + if (imageData == nil) { + imageData = [item dataForType:@"public.jpeg"]; + } + + if (imageData != nil) { - *ppv = CreateAvnStringArray((NSString*) data); - return S_OK; + auto image = [[NSImage alloc] initWithData:imageData]; + + NSBitmapImageRep *bitmapRep = nil; + for (NSImageRep *rep in image.representations) { + if ([rep isKindOfClass:[NSBitmapImageRep class]]) { + bitmapRep = (NSBitmapImageRep *)rep; + break; + } + } + + if (!bitmapRep) { + [image lockFocus]; + bitmapRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, image.size.width, image.size.height)]; + [image unlockFocus]; + } + + value = [bitmapRep representationUsingType:NSBitmapImageFileTypePNG properties:@{}]; } - - NSArray* arr = (NSArray*)data; - - for(int c = 0; c < [arr count]; c++) - if(![[arr objectAtIndex:c] isKindOfClass:[NSString class]]) - return E_INVALIDARG; - - *ppv = CreateAvnStringArray(arr); - return S_OK; } + + *ret = value == nil || [value length] == 0 + ? nullptr + : CreateByteArray((void*)[value bytes], (int)[value length]); + return S_OK; } - - virtual HRESULT SetText (char* type, char* utf8String) override + + virtual HRESULT Clear(int64_t* ret) override { - START_COM_CALL; + START_COM_ARP_CALL; - @autoreleasepool - { - auto string = [NSString stringWithUTF8String:(const char*)utf8String]; - auto typeString = [NSString stringWithUTF8String:(const char*)type]; - if(_item == nil) - [_pb setString: string forType: typeString]; - else - [_item setString: string forType:typeString]; + *ret = [_pasteboard clearContents]; + return S_OK; + } + + virtual HRESULT GetChangeCount(int64_t* ret) override + { + START_COM_ARP_CALL; - return S_OK; - } + *ret = [_pasteboard changeCount]; + return S_OK; } - virtual HRESULT SetBytes(char* type, void* bytes, int len) override + virtual HRESULT SetData(IAvnClipboardDataSource* source) override { - START_COM_CALL; + START_COM_ARP_CALL; - @autoreleasepool + auto count = source->GetItemCount(); + auto writeableItems = [NSMutableArray arrayWithCapacity:count]; + + for (auto i = 0; i < count; ++i) { - auto typeString = [NSString stringWithUTF8String:(const char*)type]; - auto data = [NSData dataWithBytes:bytes length:len]; - if(_item == nil) - [_pb setData:data forType:typeString]; - else - [_item setData:data forType:typeString]; - return S_OK; + auto item = source->GetItem(i); + auto writeableItem = [[WriteableClipboardItem alloc] initWithItem:item source:source]; + [writeableItems addObject:writeableItem]; } + + [_pasteboard writeObjects:writeableItems]; + return S_OK; } - - virtual HRESULT GetBytes(char* type, IAvnString**ppv) override + + virtual bool IsTextFormat(const char *format) override { - START_COM_CALL; + START_COM_ARP_CALL; + + auto formatString = [NSString stringWithUTF8String:format]; - @autoreleasepool + if (@available(macOS 11.0, *)) { - *ppv = nil; - auto typeString = [NSString stringWithUTF8String:(const char*)type]; - NSData*data; - @try - { - if(_item) - data = [_item dataForType:typeString]; - else - data = [_pb dataForType:typeString]; - if(data == nil) - return E_FAIL; - } - @catch(NSException* e) - { - return E_FAIL; - } - *ppv = CreateByteArray((void*)data.bytes, (int)data.length); - return S_OK; + auto type = [UTType typeWithIdentifier:formatString]; + return type != nil && [type conformsToType:UTTypeText]; + } + else + { + return UTTypeConformsTo((__bridge CFStringRef)formatString, kUTTypeText); } } +}; - virtual HRESULT Clear(int64_t* rv) override +extern IAvnClipboard* CreateClipboard(NSPasteboard* pb) +{ + return new Clipboard(pb); +} + + +@implementation WriteableClipboardItem +{ + IAvnClipboardDataItem* _item; + IAvnClipboardDataSource* _source; +} + +- (nonnull WriteableClipboardItem*) initWithItem:(nonnull IAvnClipboardDataItem*)item source:(nonnull IAvnClipboardDataSource*)source +{ + self = [super init]; + _item = item; + _source = source; + + // Each item references its source so it doesn't get disposed too early. + source->AddRef(); + + return self; +} + +NSString* TryConvertFormatToUti(NSString* format) +{ + if (@available(macOS 11.0, *)) { - START_COM_CALL; - - @autoreleasepool + auto type = [UTType typeWithIdentifier:format]; + if (type == nil) { - if(_item != nil) - { - _item = [NSPasteboardItem new]; - return 0; - } + if ([format containsString:@"/"]) + type = [UTType typeWithMIMEType:format]; else + type = [UTType exportedTypeWithIdentifier:format]; + + if (type == nil) { - *rv = [_pb clearContents]; - [_pb setString:@"" forType:NSPasteboardTypeString]; + // For now, we need to use the deprecated UTTypeCreatePreferredIdentifierForTag to create a dynamic UTI for arbitrary strings. + // This is only necessary because the old IDataObject can provide arbitrary types that aren't UTIs nor mime types. + // With the new DataFormat: + // - If the format is an application format, the managed side provides a UTI like net.avaloniaui.app.uti.xxx. + // - If the format is an OS format, the user has been warned that they MUST provide a name which is valid for the OS. + // TODO12: remove! + auto fromPasteboardType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassNSPboardType, (__bridge CFStringRef)format, nil); + if (fromPasteboardType != nil) + return (__bridge_transfer NSString*)fromPasteboardType; } - - return S_OK; } + + return type == nil ? nil : [type identifier]; } - - virtual HRESULT GetChangeCount(int64_t* rv) override + else { - START_COM_CALL; - if(_item == nil) - { - *rv = [_pb changeCount]; - return S_OK; - } - return E_NOTIMPL; + auto bridgedFormat = (__bridge CFStringRef)format; + if (UTTypeIsDeclared(bridgedFormat)) + return format; + + auto fromMimeType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, bridgedFormat, nil); + if (fromMimeType != nil) + return (__bridge_transfer NSString*)fromMimeType; + + auto fromPasteboardType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassNSPboardType, bridgedFormat, nil); + if (fromPasteboardType != nil) + return (__bridge_transfer NSString*)fromPasteboardType; + + return nil; } +} + +- (nonnull NSArray*) writableTypesForPasteboard:(nonnull NSPasteboard*)pasteboard +{ + auto formats = _item->ProvideFormats(); + if (formats == nullptr) + return [NSArray array]; - virtual HRESULT ObtainFormats(IAvnStringArray** ppv) override + auto count = formats->GetCount(); + if (count == 0) + return [NSArray array]; + + auto utis = [NSMutableArray arrayWithCapacity:count]; + IAvnString* format; + for (auto i = 0; i < count; ++i) { - START_COM_CALL; - - @autoreleasepool - { - *ppv = CreateAvnStringArray(_item == nil ? [_pb types] : [_item types]); - return S_OK; - } + if (formats->Get(i, &format) != S_OK) + continue; + + // Only UTIs must be returned from writableTypesForPasteboard or an exception will be thrown + auto formatString = GetNSStringAndRelease(format); + auto uti = TryConvertFormatToUti(formatString); + if (uti != nil) + [utis addObject:uti]; } -}; + formats->Release(); + + [utis addObject:GetAvnCustomDataType()]; + + return utis; +} -extern IAvnClipboard* CreateClipboard(NSPasteboard* pb, NSPasteboardItem* item) +- (NSPasteboardWritingOptions) writingOptionsForType:(NSPasteboardType)type pasteboard:(NSPasteboard*)pasteboard { - return new Clipboard(pb, item); + return [type isEqualToString:NSPasteboardTypeString] || [type isEqualToString:GetAvnCustomDataType()] + ? 0 + : NSPasteboardWritingPromised; } -extern NSPasteboardItem* TryGetPasteboardItem(IAvnClipboard*cb) +- (nullable id) pasteboardPropertyListForType:(nonnull NSPasteboardType)type { - auto clipboard = dynamic_cast(cb); - if(clipboard == nil) + if ([type isEqualToString:GetAvnCustomDataType()]) + return @""; + + ComPtr value(_item->GetValue([type UTF8String]), true); + if (value.getRaw() == nullptr) return nil; - return clipboard->TryGetItem(); + + if (value->IsString()) + return GetNSStringAndRelease(value->AsString()); + + auto length = value->GetByteLength(); + auto buffer = malloc(length); + value->CopyBytesTo(buffer); + return [NSData dataWithBytesNoCopy:buffer length:length]; +} + +- (void) dealloc +{ + if (_item != nullptr) + { + _item->Release(); + _item = nullptr; + } + + if (_source != nullptr) + { + _source->Release(); + _source = nullptr; + } } + +@end diff --git a/native/Avalonia.Native/src/OSX/common.h b/native/Avalonia.Native/src/OSX/common.h index 36c157704d..fae03984fd 100644 --- a/native/Avalonia.Native/src/OSX/common.h +++ b/native/Avalonia.Native/src/OSX/common.h @@ -16,8 +16,7 @@ extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events); extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events); extern IAvnStorageProvider* CreateStorageProvider(); extern IAvnScreens* CreateScreens(IAvnScreenEvents* cb); -extern IAvnClipboard* CreateClipboard(NSPasteboard*, NSPasteboardItem*); -extern NSPasteboardItem* TryGetPasteboardItem(IAvnClipboard*); +extern IAvnClipboard* CreateClipboard(NSPasteboard* pb); extern NSObject* CreateDraggingSource(NSDragOperation op, IAvnDndResultCallback* cb, void* handle); extern void* GetAvnDataObjectHandleFromDraggingInfo(NSObject* info); extern NSString* GetAvnCustomDataType(); @@ -34,6 +33,7 @@ extern IAvnPlatformBehaviorInhibition* CreatePlatformBehaviorInhibition(); extern IAvnNativeControlHost* CreateNativeControlHost(NSView* parent); extern IAvnPlatformSettings* CreatePlatformSettings(); extern IAvnPlatformRenderTimer* CreatePlatformRenderTimer(); +extern IAvnNativeObjectsMemoryManagement* CreateMemoryManagementHelper(); extern void SetAppMenu(IAvnMenu *menu); extern void SetServicesMenu (IAvnMenu* menu); extern IAvnMenu* GetAppMenu (); @@ -48,6 +48,7 @@ extern AvnPoint ToAvnPoint (NSPoint p); extern AvnPoint ConvertPointY (AvnPoint p); extern NSSize ToNSSize (AvnSize s); extern AvnSize FromNSSize (NSSize s); +extern IAvnMTLSharedEvent* ImportMTLSharedEvent(void* object); #ifdef DEBUG #define NSDebugLog(...) NSLog(__VA_ARGS__) #else diff --git a/native/Avalonia.Native/src/OSX/crapium.h b/native/Avalonia.Native/src/OSX/crapium.h new file mode 100644 index 0000000000..0b27b68c79 --- /dev/null +++ b/native/Avalonia.Native/src/OSX/crapium.h @@ -0,0 +1,9 @@ +// The only reason this file exists is Appium which limits our highest Xcode version to 15.2. Please, purge Appium from our codebase +#ifndef crapium_h +#define crapium_h +#import +@protocol MTLSharedEvent; + +API_AVAILABLE(macos(12)) +extern BOOL MtlSharedEventWaitUntilSignaledValueHack(id ev, uint64_t value, uint64_t milliseconds); +#endif /* crapium_h */ diff --git a/native/Avalonia.Native/src/OSX/crapium.mm b/native/Avalonia.Native/src/OSX/crapium.mm new file mode 100644 index 0000000000..962d7e2eda --- /dev/null +++ b/native/Avalonia.Native/src/OSX/crapium.mm @@ -0,0 +1,21 @@ +// The only reason this file exists is Appium which limits our highest Xcode version to 15.2. Please, purge Appium from our codebase +#import +#import "crapium.h" +@class MTLSharedEventHandle; +@protocol MTLSharedEvent; +@protocol MTLEvent; + +typedef void (^MTLSharedEventNotificationBlock)(id , uint64_t value); + +API_AVAILABLE(macos(10.14), ios(12.0)) +@protocol MTLSharedEvent +// Synchronously wait for the signaledValue to be greater than or equal to 'value', with a timeout +// specified in milliseconds. Returns YES if the value was signaled before the timeout, otherwise NO. +- (BOOL)waitUntilSignaledValue:(uint64_t)value timeoutMS:(uint64_t)milliseconds API_AVAILABLE(macos(12.0), ios(15.0)); +@end + +API_AVAILABLE(macos(12)) +extern BOOL MtlSharedEventWaitUntilSignaledValueHack(id ev, uint64_t value, uint64_t milliseconds) +{ + return [ev waitUntilSignaledValue:value timeoutMS:milliseconds]; +} diff --git a/native/Avalonia.Native/src/OSX/dnd.mm b/native/Avalonia.Native/src/OSX/dnd.mm index 531bdcccfd..aebe4afb88 100644 --- a/native/Avalonia.Native/src/OSX/dnd.mm +++ b/native/Avalonia.Native/src/OSX/dnd.mm @@ -14,9 +14,17 @@ extern AvnDragDropEffects ConvertDragDropEffects(NSDragOperation nsop) extern NSString* GetAvnCustomDataType() { - char buffer[256]; - sprintf(buffer, "net.avaloniaui.inproc.uti.n%in", getpid()); - return [NSString stringWithUTF8String:buffer]; + static NSString* result = nil; + + if (result == nil) + { + const size_t bufferSize = 256; + char buffer[bufferSize]; + snprintf(buffer, bufferSize, "net.avaloniaui.inproc.uti.n%in", getpid()); + result = [NSString stringWithUTF8String:buffer]; + } + + return result; } @interface AvnDndSource : NSObject diff --git a/native/Avalonia.Native/src/OSX/main.mm b/native/Avalonia.Native/src/OSX/main.mm index 0e3621517e..2a92eb3bcf 100644 --- a/native/Avalonia.Native/src/OSX/main.mm +++ b/native/Avalonia.Native/src/OSX/main.mm @@ -312,18 +312,7 @@ public: @autoreleasepool { - *ppv = ::CreateClipboard (nil, nil); - return S_OK; - } - } - - virtual HRESULT CreateDndClipboard(IAvnClipboard** ppv) override - { - START_COM_CALL; - - @autoreleasepool - { - *ppv = ::CreateClipboard (nil, [NSPasteboardItem new]); + *ppv = ::CreateClipboard(nil); return S_OK; } } @@ -478,6 +467,22 @@ public: return S_OK; } } + + virtual HRESULT ImportMTLSharedEvent(void* event, IAvnMTLSharedEvent** ppv) override + { + START_COM_CALL; + *ppv = ::ImportMTLSharedEvent(event); + return *ppv != nullptr ? S_OK : E_FAIL; + } + + HRESULT CreateMemoryManagementHelper(IAvnNativeObjectsMemoryManagement **ppv) override { + START_COM_CALL; + *ppv = ::CreateMemoryManagementHelper(); + return S_OK; + } + + + }; extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative() diff --git a/native/Avalonia.Native/src/OSX/memhelp.mm b/native/Avalonia.Native/src/OSX/memhelp.mm new file mode 100644 index 0000000000..1efee567b4 --- /dev/null +++ b/native/Avalonia.Native/src/OSX/memhelp.mm @@ -0,0 +1,40 @@ +#include "common.h" +class MemHelper : public ComSingleObject +{ + FORWARD_IUNKNOWN() + void RetainNSObject(void *object) override + { + ::RetainNSObject(object); + } + + void ReleaseNSObject(void *object) override + { + ::ReleaseNSObject(object); + } + + void RetainCFObject(void *object) override + { + CFRetain(object); + } + + void ReleaseCFObject(void *object) override + { + CFRelease(object); + } + + uint64_t GetRetainCountForNSObject(void *obj) override { + return ::GetRetainCountForNSObject(obj); + } + + int64_t GetRetainCountForCFObject(void *obj) override { + return CFGetRetainCount(obj); + } + + +}; + + +extern IAvnNativeObjectsMemoryManagement* CreateMemoryManagementHelper() +{ + return new MemHelper(); +} diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm index 1235979cb2..1adbe093bb 100644 --- a/native/Avalonia.Native/src/OSX/menu.mm +++ b/native/Avalonia.Native/src/OSX/menu.mm @@ -262,10 +262,10 @@ HRESULT AvnAppMenuItem::SetIcon(void *data, size_t length) NSSize originalSize = [image size]; NSSize size; - size.height = [[NSFont menuFontOfSize:0] pointSize] * 1.333333; + size.height = floor([[NSFont menuFontOfSize:0] pointSize] * 1.333333); auto scaleFactor = size.height / originalSize.height; - size.width = originalSize.width * scaleFactor; + size.width = floor(originalSize.width * scaleFactor); [image setSize: size]; [_native setImage:image]; diff --git a/native/Avalonia.Native/src/OSX/metal.mm b/native/Avalonia.Native/src/OSX/metal.mm index 5622f2040e..33aa2aeb53 100644 --- a/native/Avalonia.Native/src/OSX/metal.mm +++ b/native/Avalonia.Native/src/OSX/metal.mm @@ -3,6 +3,74 @@ #import #include "common.h" #include "rendertarget.h" +#import "crapium.h" + + +class API_AVAILABLE(macos(12.0)) AvnMTLSharedEvent : public ComSingleObject +{ + id _event; +public: + + AvnMTLSharedEvent(id ev) : _event(ev) + { + + } + + FORWARD_IUNKNOWN() + + id GetEvent() + { + return _event; + } + + void *GetNativeHandle() override { + return (__bridge void*)_event; + } + + bool Wait(uint64_t value, uint64_t timeoutMS) override { + return MtlSharedEventWaitUntilSignaledValueHack(_event, value, timeoutMS); + } + + void SetSignaledValue(uint64_t value) override { + _event.signaledValue = value; + } + + uint64_t GetSignaledValue() override { + return _event.signaledValue; + } +}; + + +class AvnMetalTexture : public ComSingleObject +{ + id _texture; +public: + FORWARD_IUNKNOWN() + AvnMetalTexture(id texture) : _texture(texture) + { + + } + void *GetNativeHandle() override + { + return (__bridge void*)_texture; + } + + int GetWidth() override + { + return (int)_texture.width; + } + + int GetHeight() override + { + return (int)_texture.height; + } + + int GetSampleCount() override + { + return (int)_texture.sampleCount; + } + +}; class AvnMetalDevice : public ComSingleObject { @@ -18,7 +86,86 @@ public: void *GetQueue() override { return (__bridge void*) queue; } - + + HRESULT ImportIOSurface(void *handle, AvnPixelFormat pixelFormat, IAvnMetalTexture **ppv) override { + auto surf = (IOSurfaceRef)handle; + auto width = IOSurfaceGetWidth(surf); + auto height = IOSurfaceGetHeight(surf); + + auto desc = [MTLTextureDescriptor new]; + if(pixelFormat == kAvnRgba8888) + desc.pixelFormat = MTLPixelFormatRGBA8Unorm; + else if(pixelFormat == kAvnBgra8888) + desc.pixelFormat = MTLPixelFormatBGRA8Unorm; + else + return E_INVALIDARG; + desc.textureType = MTLTextureType2D; + desc.width = width; + desc.height = height; + desc.depth = 1; + desc.mipmapLevelCount = 1; + desc.sampleCount = 1; + desc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget; + + auto texture = [device newTextureWithDescriptor:desc iosurface:surf plane:0]; + if(texture == nullptr) + return E_FAIL; + *ppv = new AvnMetalTexture(texture); + return S_OK; + + } + + HRESULT ImportSharedEvent(void *mtlSharedEventInstance, IAvnMTLSharedEvent**ppv) override { + if (@available(macOS 12.0, *)) { + auto external = (__bridge id)mtlSharedEventInstance; + auto handle = external.newSharedEventHandle; + auto imported = [device newSharedEventWithHandle: handle]; + *ppv = new AvnMTLSharedEvent(imported); + return S_OK; + } + else + { + return E_NOTIMPL; + } + } + + + HRESULT SignalOrWait(IAvnMTLSharedEvent *ev, uint64_t value, bool wait) + { + if (@available(macOS 12.0, *)) + { + auto e = dynamic_cast(ev); + if(e == nullptr) + return E_FAIL;; + auto buf = [queue commandBuffer]; + if(wait) + [buf encodeWaitForEvent:e->GetEvent() value:value]; + else + [buf encodeSignalEvent:e->GetEvent() value:value]; + [buf commit]; + return S_OK; + } + else + return E_FAIL; + } + + HRESULT SubmitWait(IAvnMTLSharedEvent *ev, uint64_t value) override { + return SignalOrWait(ev, value, true); + } + + HRESULT SubmitSignal(IAvnMTLSharedEvent *ev, uint64_t value) override { + return SignalOrWait(ev, value, false); + } + + bool GetIOKitRegistryId(uint64_t *value) override { + if (@available(macOS 10.13, *)) { + *value = [device registryID]; + return true; + } else { + return false; + } + } + AvnMetalDevice(id device, id queue) : device(device), queue(queue) { } @@ -160,3 +307,23 @@ extern IAvnMetalDisplay* GetMetalDisplay() { return _display; } + + +extern IAvnMTLSharedEvent* ImportMTLSharedEvent(void* object) +{ + if (@available(macOS 12.0, *)) { + if(object == nullptr) + return nil; + auto evId = (__bridge id)object; + + if(evId == nil) + return nil; + + + return new AvnMTLSharedEvent(evId); + } + else + { + return nil; + } +} diff --git a/native/Avalonia.Native/src/OSX/noarc.mm b/native/Avalonia.Native/src/OSX/noarc.mm index 82378ce84c..6a87fc78d0 100644 --- a/native/Avalonia.Native/src/OSX/noarc.mm +++ b/native/Avalonia.Native/src/OSX/noarc.mm @@ -1,5 +1,5 @@ #include "noarc.h" - +#include "avalonia-native.h" CppAutoreleasePool::CppAutoreleasePool() { _pool = [[NSAutoreleasePool alloc] init]; @@ -9,3 +9,17 @@ CppAutoreleasePool::~CppAutoreleasePool() { auto ptr = (NSAutoreleasePool*)_pool; [ptr release]; } + +extern void ReleaseNSObject(void* obj) +{ + [(NSObject*)obj release]; +} +extern void RetainNSObject(void* obj) +{ + [(NSObject*)obj retain]; +} + +extern uint64_t GetRetainCountForNSObject(void* obj) +{ + return [(NSObject*)obj retainCount]; +} diff --git a/native/Avalonia.Native/src/OSX/trayicon.mm b/native/Avalonia.Native/src/OSX/trayicon.mm index 917ff87694..3ac42b4f25 100644 --- a/native/Avalonia.Native/src/OSX/trayicon.mm +++ b/native/Avalonia.Native/src/OSX/trayicon.mm @@ -39,10 +39,10 @@ HRESULT AvnTrayIcon::SetIcon (void* data, size_t length) NSSize originalSize = [image size]; NSSize size; - size.height = [[NSFont menuFontOfSize:0] pointSize] * 1.333333; - + size.height = floor([[NSFont menuFontOfSize:0] pointSize] * 1.333333); + auto scaleFactor = size.height / originalSize.height; - size.width = originalSize.width * scaleFactor; + size.width = floor(originalSize.width * scaleFactor); [image setSize: size]; [image setTemplate: _isTemplateIcon]; diff --git a/nukebuild/ApiDiffHelper.cs b/nukebuild/ApiDiffHelper.cs index ac6be61ee3..4a51630557 100644 --- a/nukebuild/ApiDiffHelper.cs +++ b/nukebuild/ApiDiffHelper.cs @@ -1,313 +1,488 @@ +#nullable enable + using System; using System.Collections.Generic; -using System.Diagnostics; +using System.Collections.Immutable; using System.IO; using System.IO.Compression; using System.Linq; -using System.Net; -using System.Net.Http; +using System.Security.Cryptography; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; +using NuGet.Common; +using NuGet.Configuration; +using NuGet.Frameworks; +using NuGet.Packaging; +using NuGet.Protocol; +using NuGet.Protocol.Core.Types; +using NuGet.Versioning; +using Nuke.Common.IO; using Nuke.Common.Tooling; -using Serilog; using static Serilog.Log; public static class ApiDiffHelper { - static readonly HttpClient s_httpClient = new(); + const string NightlyFeedUri = "https://nuget-feed-nightly.avaloniaui.net/v3/index.json"; + const string MainPackageName = "Avalonia"; + const string FolderLib = "lib"; + + private static readonly Regex s_suppressionPathRegex = + new("<(Left|Right)>(.*?)", RegexOptions.Compiled); + + public static void ValidatePackage( + Tool apiCompatTool, + PackageDiffInfo packageDiff, + AbsolutePath rootAssembliesFolderPath, + AbsolutePath suppressionFilesFolderPath, + bool updateSuppressionFile) + { + Information("Validating API for package {Id}", packageDiff.PackageId); + + Directory.CreateDirectory(suppressionFilesFolderPath); + + var suppressionFilePath = suppressionFilesFolderPath / (packageDiff.PackageId + ".nupkg.xml"); + var replaceDirectorySeparators = Path.DirectorySeparatorChar == '\\'; + var allErrors = new List(); + + foreach (var framework in packageDiff.Frameworks) + { + var relativeBaselinePath = rootAssembliesFolderPath.GetRelativePathTo(framework.BaselineFolderPath); + var relativeCurrentPath = rootAssembliesFolderPath.GetRelativePathTo(framework.CurrentFolderPath); + var args = ""; + + if (suppressionFilePath.FileExists()) + { + args += $""" --suppression-file="{suppressionFilePath}" --permit-unnecessary-suppressions """; + + if (replaceDirectorySeparators) + ReplaceDirectorySeparators(suppressionFilePath, '/', '\\'); + } + + if (updateSuppressionFile) + args += $""" --suppression-output-file="{suppressionFilePath}" --generate-suppression-file --preserve-unnecessary-suppressions """; + + args += $""" -l="{relativeBaselinePath}" -r="{relativeCurrentPath}" """; + + var localErrors = GetErrors(apiCompatTool($"{args:nq}", rootAssembliesFolderPath, exitHandler: _ => { })); + + if (replaceDirectorySeparators) + ReplaceDirectorySeparators(suppressionFilePath, '\\', '/'); + + allErrors.AddRange(localErrors); + } + + ThrowOnErrors(allErrors, packageDiff.PackageId, "ValidateApiDiff"); + } - public static async Task GetDiff( - Tool apiDiffTool, string outputFolder, - string packagePath, string baselineVersion) + /// + /// The ApiCompat tool treats paths with '/' and '\' separators as different files. + /// Before running the tool, adjust the existing separators (using a dirty regex) to match the current platform. + /// After running the tool, change all separators back to '/'. + /// + static void ReplaceDirectorySeparators(AbsolutePath suppressionFilePath, char oldSeparator, char newSeparator) { - await using var baselineStream = await DownloadBaselinePackage(packagePath, baselineVersion); - if (baselineStream == null) + if (!File.Exists(suppressionFilePath)) return; - if (!Directory.Exists(outputFolder)) + var lines = File.ReadAllLines(suppressionFilePath); + + for (var i = 0; i < lines.Length; i++) { - Directory.CreateDirectory(outputFolder!); + var original = lines[i]; + + var replacement = s_suppressionPathRegex.Replace(original, match => + { + var path = match.Groups[2].Value.Replace(oldSeparator, newSeparator); + return $"<{match.Groups[1].Value}>{path}"; + }); + + lines[i] = replacement; } - using (var target = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.Read), ZipArchiveMode.Read)) - using (var baseline = new ZipArchive(baselineStream, ZipArchiveMode.Read)) - using (Helpers.UseTempDir(out var tempFolder)) - { - var targetDlls = GetDlls(target); - var baselineDlls = GetDlls(baseline); + File.WriteAllLines(suppressionFilePath, lines); + } - var pairs = new List<(string baseline, string target)>(); + public static void GenerateMarkdownDiff( + Tool apiDiffTool, + PackageDiffInfo packageDiff, + AbsolutePath rootOutputFolderPath, + string baselineDisplay, + string currentDisplay) + { + Information("Creating markdown diff for package {Id}", packageDiff.PackageId); - var packageId = GetPackageId(packagePath); + var packageOutputFolderPath = rootOutputFolderPath / packageDiff.PackageId; + Directory.CreateDirectory(packageOutputFolderPath); - // Don't use Path.Combine with these left and right tool parameters. - // Microsoft.DotNet.ApiCompat.Tool is stupid and treats '/' and '\' as different assemblies in suppression files. - // So, always use Unix '/' - foreach (var baselineDll in baselineDlls) - { - var baselineDllPath = await ExtractDll("baseline", baselineDll, tempFolder); + // Not specifying -eattrs incorrectly tries to load AttributesToExclude.txt, create an empty file instead. + // See https://github.com/dotnet/sdk/issues/49719 + var excludedAttributesFilePath = (AbsolutePath)Path.Join(Path.GetTempPath(), Guid.NewGuid().ToString()); + File.WriteAllBytes(excludedAttributesFilePath!, []); - var targetTfm = baselineDll.target; - var targetDll = targetDlls.FirstOrDefault(e => - e.target.StartsWith(targetTfm) && e.entry.Name == baselineDll.entry.Name); - if (targetDll is null) + try + { + var allErrors = new List(); + + // The API diff tool is unbelievably slow, process in parallel. + Parallel.ForEach( + packageDiff.Frameworks, + framework => { - if (s_tfmRedirects.FirstOrDefault(t => baselineDll.target.StartsWith(t.oldTfm) && (t.package is null || packageId == t.package)).newTfm is {} newTfm) + var frameworkOutputFolderPath = packageOutputFolderPath / framework.Framework.GetShortFolderName(); + var args = $""" -b="{framework.BaselineFolderPath}" -bfn="{baselineDisplay}" -a="{framework.CurrentFolderPath}" -afn="{currentDisplay}" -o="{frameworkOutputFolderPath}" -eattrs="{excludedAttributesFilePath}" """; + + var localErrors = GetErrors(apiDiffTool($"{args:nq}")); + + if (localErrors.Length > 0) { - targetTfm = newTfm; - targetDll = targetDlls.FirstOrDefault(e => - e.target.StartsWith(targetTfm) && e.entry.Name == baselineDll.entry.Name); + lock (allErrors) + allErrors.AddRange(localErrors); } - } + }); - if (targetDll?.entry is null) - { - throw new InvalidOperationException($"Some assemblies are missing in the new package {packageId}: {baselineDll.entry.Name} for {baselineDll.target}"); - } + ThrowOnErrors(allErrors, packageDiff.PackageId, "OutputApiDiff"); - var targetDllPath = await ExtractDll("target", targetDll, tempFolder); + MergeFrameworkMarkdownDiffFiles( + rootOutputFolderPath, + packageOutputFolderPath, + [..packageDiff.Frameworks.Select(info => info.Framework)]); - pairs.Add((baselineDllPath, targetDllPath)); - } + Directory.Delete(packageOutputFolderPath, true); + } + finally + { + File.Delete(excludedAttributesFilePath); + } + } - await Task.WhenAll(pairs.Select(p => Task.Run(() => + static void MergeFrameworkMarkdownDiffFiles( + AbsolutePath rootOutputFolderPath, + AbsolutePath packageOutputFolderPath, + ImmutableArray frameworks) + { + // At this point, the hierarchy looks like: + // markdown/ + // ├─ net8.0/ + // │ ├─ api_diff_Avalonia.md + // │ ├─ api_diff_Avalonia.Controls.md + // ├─ netstandard2.0/ + // │ ├─ api_diff_Avalonia.md + // │ ├─ api_diff_Avalonia.Controls.md + // + // We want one file per assembly: merge all files with the same name. + // However, it's very likely that the diff is the same for several frameworks: in this case, keep only one file. + + var assemblyGroups = frameworks + .SelectMany(GetFrameworkDiffFiles, (framework, filePath) => (framework, filePath)) + .GroupBy(x => x.filePath.Name) + .OrderBy(x => x.Key, StringComparer.OrdinalIgnoreCase); + + foreach (var assemblyGroup in assemblyGroups) + { + using var writer = File.CreateText(rootOutputFolderPath / assemblyGroup.Key.Replace("api_diff_", "")); + var addSeparator = false; + + foreach (var similarDiffGroup in assemblyGroup.GroupBy(x => HashFile(x.filePath), ByteArrayEqualityComparer.Instance)) { - var baselineApi = p.baseline + Random.Shared.Next() + ".api.cs"; - var targetApi = p.target + Random.Shared.Next() + ".api.cs"; - var resultDiff = p.target + ".api.diff.cs"; - - GenerateApiListing(apiDiffTool, p.baseline, baselineApi, tempFolder); - GenerateApiListing(apiDiffTool, p.target, targetApi, tempFolder); - - var args = $"""-c core.autocrlf=false diff --no-index --minimal """; - args += """--ignore-matching-lines="^\[assembly: System.Reflection.AssemblyVersionAttribute" """; - args += $""" --output {resultDiff} {baselineApi} {targetApi}"""; - - using (var gitProcess = new Process()) - { - gitProcess.StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - RedirectStandardError = false, - RedirectStandardOutput = false, - FileName = "git", - Arguments = args, - WorkingDirectory = tempFolder - }; - gitProcess.Start(); - gitProcess.WaitForExit(); - } + if (addSeparator) + writer.WriteLine(); - var resultFile = new FileInfo(Path.Combine(tempFolder, resultDiff)); - if (resultFile.Length > 0) - { - resultFile.CopyTo(Path.Combine(outputFolder, Path.GetFileName(resultDiff)), true); - } - }))); + using var reader = File.OpenText(similarDiffGroup.First().filePath); + var firstLine = reader.ReadLine(); + + writer.Write(firstLine); + writer.WriteLine(" (" + string.Join(", ", similarDiffGroup.Select(x => x.framework.GetShortFolderName())) + ")"); + + while (reader.ReadLine() is { } line) + writer.WriteLine(line); + + addSeparator = true; + } } - } - private static readonly (string package, string oldTfm, string newTfm)[] s_tfmRedirects = new[] - { - // We use StartsWith below comparing these tfm, as we ignore platform versions (like, net6.0-ios16.1). - ("Avalonia.Android", "net6.0-android", "net8.0-android"), - ("Avalonia.iOS", "net6.0-ios", "net8.0-ios"), - // Browser was changed from net7.0 to net8.0-browser. - ("Avalonia.Browser", "net7.0", "net8.0-browser"), - ("Avalonia.Browser.Blazor", "net7.0", "net8.0-browser"), - // Designer was moved from netcoreapp to netstandard. - ("Avalonia", "netcoreapp2.0", "netstandard2.0"), - ("Avalonia", "net461", "netstandard2.0") - }; - - public static async Task ValidatePackage( - Tool apiCompatTool, string packagePath, string baselineVersion, - string suppressionFilesFolder, bool updateSuppressionFile) - { - if (!Directory.Exists(suppressionFilesFolder)) + AbsolutePath[] GetFrameworkDiffFiles(NuGetFramework framework) { - Directory.CreateDirectory(suppressionFilesFolder!); + var frameworkFolderPath = packageOutputFolderPath / framework.GetShortFolderName(); + if (!frameworkFolderPath.DirectoryExists()) + return []; + + return Directory.GetFiles(frameworkFolderPath, "*.md") + .Where(filePath => Path.GetFileName(filePath) != "api_diff.md") + .Select(filePath => (AbsolutePath)filePath) + .ToArray(); } - await using var baselineStream = await DownloadBaselinePackage(packagePath, baselineVersion); - if (baselineStream == null) - return; + static byte[] HashFile(AbsolutePath filePath) + { + using var stream = File.OpenRead(filePath); + return SHA256.HashData(stream); + } + } + + public static void MergePackageMarkdownDiffFiles( + AbsolutePath rootOutputFolderPath, + string baselineDisplay, + string currentDisplay) + { + const string mergedFileName = "_diff.md"; - using (var target = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.Read), ZipArchiveMode.Read)) - using (var baseline = new ZipArchive(baselineStream, ZipArchiveMode.Read)) - using (Helpers.UseTempDir(out var tempFolder)) + var filePaths = Directory.EnumerateFiles(rootOutputFolderPath, "*.md") + .Where(filePath => Path.GetFileName(filePath) != mergedFileName) + .Order(StringComparer.OrdinalIgnoreCase) + .ToArray(); + + using var writer = File.CreateText(rootOutputFolderPath / mergedFileName); + + writer.WriteLine($"# API diff between {baselineDisplay} and {currentDisplay}"); + + if (filePaths.Length == 0) { - var targetDlls = GetDlls(target); - var baselineDlls = GetDlls(baseline); + writer.WriteLine(); + writer.WriteLine("No changes."); + return; + } - var left = new List(); - var right = new List(); + foreach (var filePath in filePaths) + { + writer.WriteLine(); - var packageId = GetPackageId(packagePath); - var suppressionFile = Path.Combine(suppressionFilesFolder, packageId + ".nupkg.xml"); + using var reader = File.OpenText(filePath); - // Don't use Path.Combine with these left and right tool parameters. - // Microsoft.DotNet.ApiCompat.Tool is stupid and treats '/' and '\' as different assemblies in suppression files. - // So, always use Unix '/' - foreach (var baselineDll in baselineDlls) + while (reader.ReadLine() is { } line) { - var baselineDllPath = await ExtractDll("baseline", baselineDll, tempFolder); + if (line.StartsWith('#')) + writer.Write('#'); - var targetTfm = baselineDll.target; - var targetDll = targetDlls.FirstOrDefault(e => - e.target.StartsWith(targetTfm) && e.entry.Name == baselineDll.entry.Name); - if (targetDll?.entry is null) - { - if (s_tfmRedirects.FirstOrDefault(t => baselineDll.target.StartsWith(t.oldTfm) && (t.package is null || packageId == t.package)).newTfm is {} newTfm) - { - targetTfm = newTfm; - targetDll = targetDlls.FirstOrDefault(e => - e.target.StartsWith(targetTfm) && e.entry.Name == baselineDll.entry.Name); - } - } - if (targetDll?.entry is null && targetDlls.Count == 1) - { - targetDll = targetDlls.First(); - Warning( - $"Some assemblies are missing in the new package {packageId}: {baselineDll.entry.Name} for {baselineDll.target}." + - $"Resolved: {targetDll.target} ({targetDll.entry.Name})"); - } + writer.WriteLine(line); + } + } + } - if (targetDll?.entry is null) - { - if (packageId == "Avalonia" - && baselineDll.target is "net461" or "netcoreapp2.0") - { - // In 11.1 we have removed net461 and netcoreapp2.0 targets from Avalonia package. - continue; - } - - var actualTargets = string.Join(", ", - targetDlls.Select(d => $"{d.target} ({d.entry.Name})")); - throw new InvalidOperationException( - $"Some assemblies are missing in the new package {packageId}: {baselineDll.entry.Name} for {baselineDll.target}." - + $"\r\nActual targets: {actualTargets}."); - } + static string[] GetErrors(IEnumerable outputs) + => outputs + .Where(output => output.Type == OutputType.Err) + .Select(output => output.Text) + .ToArray(); + + static void ThrowOnErrors(List errors, string packageId, string taskName) + { + if (errors.Count > 0) + { + throw new AggregateException( + $"{taskName} task has failed for \"{packageId}\" package", + errors.Select(error => new Exception(error))); + } + } + + public static async Task DownloadAndExtractPackagesAsync( + IEnumerable currentPackagePaths, + NuGetVersion currentVersion, + bool isReleaseBranch, + AbsolutePath outputFolderPath, + NuGetVersion? forcedBaselineVersion) + { + var downloadContext = await CreateNuGetDownloadContextAsync(); + var baselineVersion = forcedBaselineVersion ?? + await GetBaselineVersionAsync(downloadContext, currentVersion, isReleaseBranch); - var targetDllPath = await ExtractDll("target", targetDll, tempFolder); + Information("API baseline version is {Baseline} for current version {Current}", baselineVersion, currentVersion); - left.Add(baselineDllPath); - right.Add(targetDllPath); + var memoryStream = new MemoryStream(); + var packageDiffs = ImmutableArray.CreateBuilder(); + + foreach (var packagePath in currentPackagePaths) + { + string packageId; + AbsolutePath currentFolderPath; + AbsolutePath baselineFolderPath; + Dictionary currentFolderNames; + Dictionary baselineFolderNames; + + // Extract current package + using (var currentArchive = new ZipArchive(File.OpenRead(packagePath), ZipArchiveMode.Read, leaveOpen: false)) + { + using var packageReader = new PackageArchiveReader(currentArchive); + packageId = packageReader.NuspecReader.GetId(); + currentFolderPath = outputFolderPath / "current" / packageId; + currentFolderNames = ExtractDiffableAssembliesFromPackage(currentArchive, currentFolderPath); } - if (left.Any()) + // Download baseline package + memoryStream.Position = 0L; + memoryStream.SetLength(0L); + await DownloadBaselinePackageAsync(memoryStream, downloadContext, packageId, baselineVersion); + memoryStream.Position = 0L; + + // Extract baseline package + using (var baselineArchive = new ZipArchive(memoryStream, ZipArchiveMode.Read, leaveOpen: true)) { - var args = $""" -l={string.Join(',', left)} -r="{string.Join(',', right)}" """; - if (File.Exists(suppressionFile)) - { - args += $""" --suppression-file="{suppressionFile}" """; - } + baselineFolderPath = outputFolderPath / "baseline" / packageId; + baselineFolderNames = ExtractDiffableAssembliesFromPackage(baselineArchive, baselineFolderPath); + } - if (updateSuppressionFile) - { - args += $""" --suppression-output-file="{suppressionFile}" --generate-suppression-file=true """; - } + if (currentFolderNames.Count == 0 && baselineFolderNames.Count == 0) + continue; - var result = apiCompatTool(args, tempFolder) - .Where(t => t.Type == OutputType.Err).ToArray(); - if (result.Any()) - { - throw new AggregateException( - $"ApiDiffValidation task has failed for \"{Path.GetFileName(packagePath)}\" package", - result.Select(r => new Exception(r.Text))); - } + var frameworkDiffs = new List(); + + foreach (var (framework, currentFolderName) in currentFolderNames) + { + // Ignore new frameworks that didn't exist in the baseline package. Empty folders make the ApiDiff tool crash. + if (!baselineFolderNames.TryGetValue(framework, out var baselineFolderName)) + continue; + + frameworkDiffs.Add(new FrameworkDiffInfo( + framework, + baselineFolderPath / FolderLib / baselineFolderName, + currentFolderPath / FolderLib / currentFolderName)); } + + packageDiffs.Add(new PackageDiffInfo(packageId, [..frameworkDiffs])); } + + return new GlobalDiffInfo(baselineVersion, currentVersion, packageDiffs.DrainToImmutable()); } - record DllEntry(string target, ZipArchiveEntry entry); - - static IReadOnlyCollection GetDlls(ZipArchive archive) + static async Task CreateNuGetDownloadContextAsync() { - return archive.Entries - .Where(e => Path.GetExtension(e.FullName) == ".dll" - // Exclude analyzers and build task, as we don't care about breaking changes there - && !e.FullName.Contains("analyzers/") && !e.FullName.Contains("analyzers\\") - && !e.Name.Contains("Avalonia.Build.Tasks")) - .Select(e => ( - entry: e, - isRef: e.FullName.Contains("ref/") || e.FullName.Contains("ref\\"), - target: Path.GetDirectoryName(e.FullName)!.Split(new [] { '/', '\\' }).Last()) - ) - .GroupBy(e => (e.target, e.entry.Name)) - .Select(g => g.MaxBy(e => e.isRef)) - .Select(e => new DllEntry(e.target, e.entry)) - .ToArray(); + var packageSource = new PackageSource(NightlyFeedUri) { ProtocolVersion = 3 }; + var repository = Repository.Factory.GetCoreV3(packageSource); + var findPackageByIdResource = await repository.GetResourceAsync(); + return new NuGetDownloadContext(packageSource, findPackageByIdResource); } - static async Task DownloadBaselinePackage(string packagePath, string baselineVersion) + /// + /// Finds the baseline version to diff against. + /// On release branches, use the latest stable version. + /// On the main branch and on PRs, use the latest nightly version. + /// This method assumes all packages share the same version. + /// + static async Task GetBaselineVersionAsync( + NuGetDownloadContext context, + NuGetVersion currentVersion, + bool isReleaseBranch) { - if (baselineVersion is null) + var versions = await context.FindPackageByIdResource.GetAllVersionsAsync( + MainPackageName, + context.CacheContext, + NullLogger.Instance, + CancellationToken.None); + + versions = versions.Where(v => v < currentVersion); + + if (isReleaseBranch) + versions = versions.Where(v => !v.IsPrerelease); + + return versions.OrderDescending().FirstOrDefault() + ?? throw new InvalidOperationException( + $"Could not find a version less than {currentVersion} for package {MainPackageName} in source {context.PackageSource.Source}"); + } + + static async Task DownloadBaselinePackageAsync( + Stream destinationStream, + NuGetDownloadContext context, + string packageId, + NuGetVersion version) + { + Information("Downloading {Id} {Version} baseline package", packageId, version); + + var downloaded = await context.FindPackageByIdResource.CopyNupkgToStreamAsync( + packageId, + version, + destinationStream, + context.CacheContext, + NullLogger.Instance, + CancellationToken.None); + + if (!downloaded) { throw new InvalidOperationException( - "Build \"api-baseline\" parameter must be set when running Nuke CreatePackages"); + $"Could not download version {version} for package {packageId} in source {context.PackageSource.Source}"); } + } - /* - Gets package name from versions like: - Avalonia.0.10.0-preview1 - Avalonia.11.0.999-cibuild0037534-beta - Avalonia.11.0.0 - */ - var packageId = GetPackageId(packagePath); - Information("Downloading {0} {1} baseline package", packageId, baselineVersion); + static Dictionary ExtractDiffableAssembliesFromPackage( + ZipArchive packageArchive, + AbsolutePath destinationFolderPath) + { + var folderByFramework = new Dictionary(); - try + foreach (var entry in packageArchive.Entries) { - using var response = await s_httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, - $"https://www.nuget.org/api/v2/package/{packageId}/{baselineVersion}"), HttpCompletionOption.ResponseHeadersRead); - response.EnsureSuccessStatusCode(); - - await using var stream = await response.Content.ReadAsStreamAsync(); - var memoryStream = new MemoryStream(); - await stream.CopyToAsync(memoryStream); - memoryStream.Seek(0, SeekOrigin.Begin); - return memoryStream; - } - catch (HttpRequestException e) when (e.StatusCode == HttpStatusCode.NotFound) - { - return null; + if (TryGetFrameworkFolderName(entry.FullName) is not { } folderName) + continue; + + // Ignore platform versions: assume that e.g. net8.0-android34 and net8.0-android35 are the same for diff purposes. + var framework = WithoutPlatformVersion(NuGetFramework.ParseFolder(folderName)); + + if (folderByFramework.TryGetValue(framework, out var existingFolderName)) + { + if (existingFolderName != folderName) + { + throw new InvalidOperationException( + $"Found two similar frameworks with different platform versions: {existingFolderName} and {folderName}"); + } + } + else + folderByFramework.Add(framework, folderName); + + var targetFilePath = destinationFolderPath / entry.FullName; + Directory.CreateDirectory(targetFilePath.Parent); + entry.ExtractToFile(targetFilePath, overwrite: true); } - catch (Exception ex) + + return folderByFramework; + + static string? TryGetFrameworkFolderName(string entryPath) { - throw new InvalidOperationException($"Downloading baseline package for {packageId} {baselineVersion} failed.\r" + ex.Message, ex); + if (!entryPath.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) + return null; + + var segments = entryPath.Split('/'); + if (segments is not [FolderLib, var name, ..]) + return null; + + return name; } + + // e.g. net8.0-android34.0 to net8.0-android + static NuGetFramework WithoutPlatformVersion(NuGetFramework value) + => value.HasPlatform && value.PlatformVersion != FrameworkConstants.EmptyVersion ? + new NuGetFramework(value.Framework, value.Version, value.Platform, FrameworkConstants.EmptyVersion) : + value; } - static async Task ExtractDll(string basePath, DllEntry dllEntry, string targetFolder) + public sealed class GlobalDiffInfo( + NuGetVersion baselineVersion, + NuGetVersion currentVersion, + ImmutableArray packages) { - var dllPath = $"{basePath}/{dllEntry.target}/{dllEntry.entry.Name}"; - var dllRealPath = Path.Combine(targetFolder, dllPath); - Directory.CreateDirectory(Path.GetDirectoryName(dllRealPath)!); - await using (var dllFile = File.Create(dllRealPath)) - { - await dllEntry.entry.Open().CopyToAsync(dllFile); - } + public NuGetVersion BaselineVersion { get; } = baselineVersion; + public NuGetVersion CurrentVersion { get; } = currentVersion; + public ImmutableArray Packages { get; } = packages; + } - return dllPath; + public sealed class PackageDiffInfo(string packageId, ImmutableArray frameworks) + { + public string PackageId { get; } = packageId; + public ImmutableArray Frameworks { get; } = frameworks; } - static void GenerateApiListing(Tool apiDiffTool, string inputFile, string outputFile, string workingDif) + public sealed class FrameworkDiffInfo( + NuGetFramework framework, + AbsolutePath baselineFolderPath, + AbsolutePath currentFolderPath) { - var args = $""" --assembly={inputFile} --output-path={outputFile} --include-assembly-attributes=true"""; - var result = apiDiffTool(args, workingDif) - .Where(t => t.Type == OutputType.Err).ToArray(); - if (result.Any()) - { - throw new AggregateException($"GetApi tool failed task has failed", - result.Select(r => new Exception(r.Text))); - } + public NuGetFramework Framework { get; } = framework; + public AbsolutePath BaselineFolderPath { get; } = baselineFolderPath; + public AbsolutePath CurrentFolderPath { get; } = currentFolderPath; } - static string GetPackageId(string packagePath) + sealed class NuGetDownloadContext(PackageSource packageSource, FindPackageByIdResource findPackageByIdResource) { - return Regex.Replace( - Path.GetFileNameWithoutExtension(packagePath), - """(\.\d+\.\d+\.\d+(?:-.+)?)$""", ""); + public SourceCacheContext CacheContext { get; } = new(); + public PackageSource PackageSource { get; } = packageSource; + public FindPackageByIdResource FindPackageByIdResource { get; } = findPackageByIdResource; } } diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index c6942e430c..d3c2cb1d01 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -1,8 +1,10 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading.Tasks; using System.Xml.Linq; @@ -10,16 +12,15 @@ using Nuke.Common; using Nuke.Common.Tooling; using Nuke.Common.Tools.DotNet; using Nuke.Common.Tools.Npm; +using Nuke.Common.Utilities; using static Nuke.Common.EnvironmentInfo; -using static Nuke.Common.IO.FileSystemTasks; using static Nuke.Common.IO.PathConstruction; -using static Nuke.Common.Tools.MSBuild.MSBuildTasks; +using static Nuke.Common.Tools.DotMemoryUnit.DotMemoryUnitTasks; using static Nuke.Common.Tools.DotNet.DotNetTasks; -using static Nuke.Common.Tools.Xunit.XunitTasks; -using static Nuke.Common.Tools.VSWhere.VSWhereTasks; using static Serilog.Log; using MicroCom.CodeGenerator; using NuGet.Configuration; +using NuGet.Versioning; using Nuke.Common.CI.AzurePipelines; using Nuke.Common.IO; @@ -35,13 +36,17 @@ partial class Build : NukeBuild { BuildParameters Parameters { get; set; } - [PackageExecutable("Microsoft.DotNet.ApiCompat.Tool", "Microsoft.DotNet.ApiCompat.Tool.dll", Framework = "net6.0")] +#nullable enable + ApiDiffHelper.GlobalDiffInfo? GlobalDiff { get; set; } +#nullable restore + + [NuGetPackage("Microsoft.DotNet.ApiCompat.Tool", "Microsoft.DotNet.ApiCompat.Tool.dll", Framework = "net8.0")] Tool ApiCompatTool; - [PackageExecutable("Microsoft.DotNet.GenAPI.Tool", "Microsoft.DotNet.GenAPI.Tool.dll", Framework = "net8.0")] - Tool ApiGenTool; + [NuGetPackage("Microsoft.DotNet.ApiDiff.Tool", "Microsoft.DotNet.ApiDiff.Tool.dll", Framework = "net8.0")] + Tool ApiDiffTool; - [PackageExecutable("dotnet-ilrepack", "ILRepackTool.dll", Framework = "net8.0")] + [NuGetPackage("dotnet-ilrepack", "ILRepackTool.dll", Framework = "net8.0")] Tool IlRepackTool; protected override void OnBuildInitialized() @@ -91,7 +96,7 @@ partial class Build : NukeBuild c.AddProperty("JavaSdkDirectory", GetVariable("JAVA_HOME_11_X64")); c.AddProperty("PackageVersion", Parameters.Version) .SetConfiguration(Parameters.Configuration) - .SetVerbosity(DotNetVerbosity.Minimal); + .SetVerbosity(DotNetVerbosity.minimal); if (Parameters.IsPackingToLocalCache) c .AddProperty("ForcePackAvaloniaNative", "True") @@ -111,12 +116,23 @@ partial class Build : NukeBuild Target Clean => _ => _.Executes(() => { - Parameters.BuildDirs.ForEach(DeleteDirectory); - EnsureCleanDirectory(Parameters.ArtifactsDir); - EnsureCleanDirectory(Parameters.NugetIntermediateRoot); - EnsureCleanDirectory(Parameters.NugetRoot); - EnsureCleanDirectory(Parameters.ZipRoot); - EnsureCleanDirectory(Parameters.TestResultsRoot); + foreach (var buildDir in Parameters.BuildDirs) + { + Information("Deleting {Directory}", buildDir); + buildDir.DeleteDirectory(); + } + + CleanDirectory(Parameters.ArtifactsDir); + CleanDirectory(Parameters.NugetIntermediateRoot); + CleanDirectory(Parameters.NugetRoot); + CleanDirectory(Parameters.ZipRoot); + CleanDirectory(Parameters.TestResultsRoot); + + void CleanDirectory(AbsolutePath path) + { + Information("Cleaning {Path}", path); + path.CreateOrCleanDirectory(); + } }); Target CompileHtmlPreviewer => _ => _ @@ -128,7 +144,7 @@ partial class Build : NukeBuild NpmTasks.NpmInstall(c => c .SetProcessWorkingDirectory(webappDir) - .SetProcessArgumentConfigurator(a => a.Add("--silent"))); + .SetProcessAdditionalArguments("--silent")); NpmTasks.NpmRun(c => c .SetProcessWorkingDirectory(webappDir) .SetCommand("dist")); @@ -171,6 +187,31 @@ partial class Build : NukeBuild }); void RunCoreTest(string projectName) + { + RunCoreTest(projectName, (project, tfm) => + { + DotNetTest(c => ApplySetting(c, project,tfm)); + }); + } + + void RunCoreDotMemoryUnit(string projectName) + { + RunCoreTest(projectName, (project, tfm) => + { + var testSettings = ApplySetting(new DotNetTestSettings(), project, tfm); + var testToolPath = GetToolPathInternal(new DotNetTasks(), testSettings); + var testArgs = GetArguments(testSettings).JoinSpace(); + DotMemoryUnit($"{testToolPath} --propagate-exit-code -- {testArgs:nq}"); + }); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(GetToolPathInternal))] + extern static string GetToolPathInternal(ToolTasks tasks, ToolOptions options); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(GetArguments))] + extern static IEnumerable GetArguments(ToolOptions options); + } + + void RunCoreTest(string projectName, Action runTest) { Information($"Running tests from {projectName}"); var project = RootDirectory.GlobFiles(@$"**\{projectName}.csproj").FirstOrDefault() @@ -199,11 +240,11 @@ partial class Build : NukeBuild var tfm = fw; if (tfm == "$(AvsCurrentTargetFramework)") { - tfm = "net8.0"; + tfm = "net10.0"; } if (tfm == "$(AvsLegacyTargetFrameworks)") { - tfm = "net6.0"; + tfm = "net8.0"; } if (tfm.StartsWith("net4") @@ -216,17 +257,20 @@ partial class Build : NukeBuild Information($"Running for {projectName} ({tfm}) ..."); - DotNetTest(c => ApplySetting(c) - .SetProjectFile(project) - .SetFramework(tfm) - .EnableNoBuild() - .EnableNoRestore() - .When(Parameters.PublishTestResults, _ => _ - .SetLoggers("trx") - .SetResultsDirectory(Parameters.TestResultsRoot))); + runTest(project, tfm); } } + DotNetTestSettings ApplySetting(DotNetTestSettings settings, string project, string tfm) => + ApplySetting(settings) + .SetProjectFile(project) + .SetFramework(tfm) + .EnableNoBuild() + .EnableNoRestore() + .When(_ => Parameters.PublishTestResults, _ => _ + .SetLoggers("trx") + .SetResultsDirectory(Parameters.TestResultsRoot)); + Target RunHtmlPreviewerTests => _ => _ .DependsOn(CompileHtmlPreviewer) .OnlyWhenStatic(() => !(Parameters.SkipPreviewer || Parameters.SkipTests)) @@ -236,7 +280,7 @@ partial class Build : NukeBuild NpmTasks.NpmInstall(c => c .SetProcessWorkingDirectory(webappTestDir) - .SetProcessArgumentConfigurator(a => a.Add("--silent"))); + .SetProcessAdditionalArguments("--silent")); NpmTasks.NpmRun(c => c .SetProcessWorkingDirectory(webappTestDir) .SetCommand("test")); @@ -252,9 +296,10 @@ partial class Build : NukeBuild RunCoreTest("Avalonia.Markup.UnitTests"); RunCoreTest("Avalonia.Markup.Xaml.UnitTests"); RunCoreTest("Avalonia.Skia.UnitTests"); - RunCoreTest("Avalonia.ReactiveUI.UnitTests"); - RunCoreTest("Avalonia.Headless.NUnit.UnitTests"); - RunCoreTest("Avalonia.Headless.XUnit.UnitTests"); + RunCoreTest("Avalonia.Headless.NUnit.PerAssembly.UnitTests"); + RunCoreTest("Avalonia.Headless.NUnit.PerTest.UnitTests"); + RunCoreTest("Avalonia.Headless.XUnit.PerAssembly.UnitTests"); + RunCoreTest("Avalonia.Headless.XUnit.PerTest.UnitTests"); }); Target RunRenderTests => _ => _ @@ -263,8 +308,6 @@ partial class Build : NukeBuild .Executes(() => { RunCoreTest("Avalonia.Skia.RenderTests"); - if (Parameters.IsRunningOnWindows) - RunCoreTest("Avalonia.Direct2D1.RenderTests"); }); Target RunToolsTests => _ => _ @@ -284,7 +327,7 @@ partial class Build : NukeBuild { void DoMemoryTest() { - RunCoreTest("Avalonia.LeakTests"); + RunCoreDotMemoryUnit("Avalonia.LeakTests"); } ControlFlow.ExecuteWithRetry(DoMemoryTest, delay: TimeSpan.FromMilliseconds(3)); }); @@ -313,7 +356,7 @@ partial class Build : NukeBuild Parameters.Version + ".nupkg", IlRepackTool); var config = Numerge.MergeConfiguration.LoadFile(RootDirectory / "nukebuild" / "numerge.config"); - EnsureCleanDirectory(Parameters.NugetRoot); + Parameters.NugetRoot.CreateOrCleanDirectory(); if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config, new NumergeNukeLogger())) throw new Exception("Package merge failed"); @@ -321,33 +364,62 @@ partial class Build : NukeBuild Parameters.NugetRoot / $"Avalonia.{Parameters.Version}.nupkg", Parameters.NugetRoot / $"Avalonia.{Parameters.Version}.snupkg"); }); - - Target ValidateApiDiff => _ => _ + + Target DownloadApiBaselinePackages => _ => _ .DependsOn(CreateNugetPackages) .Executes(async () => { - await Task.WhenAll( - Directory.GetFiles(Parameters.NugetRoot, "*.nupkg").Select(nugetPackage => ApiDiffHelper.ValidatePackage( - ApiCompatTool, nugetPackage, Parameters.ApiValidationBaseline, - Parameters.ApiValidationSuppressionFiles, Parameters.UpdateApiValidationSuppression))); + GlobalDiff = await ApiDiffHelper.DownloadAndExtractPackagesAsync( + Directory.EnumerateFiles(Parameters.NugetRoot, "*.nupkg").Select(path => (AbsolutePath)path), + NuGetVersion.Parse(Parameters.Version), + Parameters.IsReleaseBranch, + Parameters.ArtifactsDir / "api-diff" / "assemblies", + Parameters.ForceApiValidationBaseline is { } forcedBaseline ? NuGetVersion.Parse(forcedBaseline) : null); + }); + + Target ValidateApiDiff => _ => _ + .DependsOn(DownloadApiBaselinePackages) + .Executes(() => + { + var globalDiff = GlobalDiff!; + + Parallel.ForEach( + globalDiff.Packages, + packageDiff => ApiDiffHelper.ValidatePackage( + ApiCompatTool, + packageDiff, + Parameters.ArtifactsDir / "api-diff" / "assemblies", + Parameters.ApiValidationSuppressionFiles, + Parameters.UpdateApiValidationSuppression)); }); Target OutputApiDiff => _ => _ - .DependsOn(CreateNugetPackages) - .Executes(async () => + .DependsOn(DownloadApiBaselinePackages) + .Executes(() => { - await Task.WhenAll( - Directory.GetFiles(Parameters.NugetRoot, "*.nupkg").Select(nugetPackage => ApiDiffHelper.GetDiff( - ApiGenTool, RootDirectory / "api" / "diff", - nugetPackage, Parameters.ApiValidationBaseline))); + var globalDiff = GlobalDiff!; + var outputFolderPath = Parameters.ArtifactsDir / "api-diff" / "markdown"; + var baselineDisplay = globalDiff.BaselineVersion.ToString(); + var currentDisplay = globalDiff.CurrentVersion.ToString(); + + Parallel.ForEach( + globalDiff.Packages, + packageDiff => ApiDiffHelper.GenerateMarkdownDiff( + ApiDiffTool, + packageDiff, + outputFolderPath, + baselineDisplay, + currentDisplay)); + + ApiDiffHelper.MergePackageMarkdownDiffFiles(outputFolderPath, baselineDisplay, currentDisplay); }); - + Target RunTests => _ => _ .DependsOn(RunCoreLibsTests) .DependsOn(RunRenderTests) .DependsOn(RunToolsTests) - .DependsOn(RunHtmlPreviewerTests) - .DependsOn(RunLeakTests); + .DependsOn(RunHtmlPreviewerTests); + //.DependsOn(RunLeakTests); // dotMemory Unit doesn't support modern .NET versions, see https://youtrack.jetbrains.com/issue/DMU-300/ Target Package => _ => _ .DependsOn(RunTests) @@ -418,7 +490,7 @@ partial class Build : NukeBuild var artifactsDirectory = buildTestsDirectory / "artifacts"; var nugetCacheDirectory = artifactsDirectory / "nuget-cache"; - DeleteDirectory(artifactsDirectory); + artifactsDirectory.DeleteDirectory(); BuildTestsAndVerify("Debug"); BuildTestsAndVerify("Release"); @@ -432,7 +504,7 @@ partial class Build : NukeBuild .SetProperty("NuGetPackageRoot", nugetCacheDirectory) .SetPackageDirectory(nugetCacheDirectory) .SetProjectFile(buildTestsDirectory / "BuildTests.sln") - .SetProcessArgumentConfigurator(arguments => arguments.Add("--nodeReuse:false"))); + .SetProcessAdditionalArguments("--nodeReuse:false")); // Standard compilation - should have compiled XAML VerifyBuildTestAssembly("bin", "BuildTests"); @@ -461,7 +533,7 @@ partial class Build : NukeBuild .SetPackageDirectory(nugetCacheDirectory) .SetNoBuild(noBuild) .SetProject(buildTestsDirectory / projectName / (projectName + ".csproj")) - .SetProcessArgumentConfigurator(arguments => arguments.Add("--nodeReuse:false"))); + .SetProcessAdditionalArguments("--nodeReuse:false")); void VerifyBuildTestAssembly(string folder, string projectName) => XamlCompilationVerifier.VerifyAssemblyCompiledXaml( diff --git a/nukebuild/BuildParameters.cs b/nukebuild/BuildParameters.cs index 41e075a64c..bfcfa46522 100644 --- a/nukebuild/BuildParameters.cs +++ b/nukebuild/BuildParameters.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using System.Collections.Generic; using System.Linq; @@ -7,30 +9,29 @@ using System.Xml.Linq; using Nuke.Common; using Nuke.Common.CI.AzurePipelines; using Nuke.Common.IO; -using static Nuke.Common.IO.PathConstruction; public partial class Build { [Parameter(Name = "configuration")] - public string Configuration { get; set; } + public string? Configuration { get; set; } [Parameter(Name = "skip-tests")] public bool SkipTests { get; set; } [Parameter(Name = "force-nuget-version")] - public string ForceNugetVersion { get; set; } + public string? ForceNugetVersion { get; set; } [Parameter(Name = "skip-previewer")] public bool SkipPreviewer { get; set; } - [Parameter(Name = "api-baseline")] - public string ApiValidationBaseline { get; set; } + [Parameter(Name = "force-api-baseline")] + public string? ForceApiValidationBaseline { get; set; } [Parameter(Name = "update-api-suppression")] public bool? UpdateApiValidationSuppression { get; set; } [Parameter(Name = "version-output-dir")] - public AbsolutePath VersionOutputDir { get; set; } + public AbsolutePath? VersionOutputDir { get; set; } public class BuildParameters { @@ -39,8 +40,8 @@ public partial class Build public bool SkipPreviewer {get;} public string MainRepo { get; } public string MasterBranch { get; } - public string RepositoryName { get; } - public string RepositoryBranch { get; } + public string? RepositoryName { get; } + public string? RepositoryBranch { get; } public string ReleaseConfiguration { get; } public Regex ReleaseBranchRegex { get; } public string MSBuildSolution { get; } @@ -66,14 +67,14 @@ public partial class Build public AbsolutePath ZipRoot { get; } public AbsolutePath TestResultsRoot { get; } public string DirSuffix { get; } - public List BuildDirs { get; } + public List BuildDirs { get; } public string FileZipSuffix { get; } public AbsolutePath ZipCoreArtifacts { get; } public AbsolutePath ZipNuGetArtifacts { get; } - public string ApiValidationBaseline { get; } + public string? ForceApiValidationBaseline { get; } public bool UpdateApiValidationSuppression { get; } public AbsolutePath ApiValidationSuppressionFiles { get; } - public AbsolutePath VersionOutputDir { get; } + public AbsolutePath? VersionOutputDir { get; } public BuildParameters(Build b, bool isPackingToLocalCache) { @@ -115,10 +116,9 @@ public partial class Build IsNuGetRelease = IsMainRepo && IsReleasable && IsReleaseBranch; // VERSION - var (propsVersion, propsApiCompatVersion) = GetVersion(); - Version = b.ForceNugetVersion ?? propsVersion; + Version = b.ForceNugetVersion ?? GetVersion(); - ApiValidationBaseline = b.ApiValidationBaseline ?? propsApiCompatVersion; + ForceApiValidationBaseline = b.ForceApiValidationBaseline; UpdateApiValidationSuppression = b.UpdateApiValidationSuppression ?? IsLocalBuild; if (IsRunningOnAzure) @@ -126,7 +126,9 @@ public partial class Build if (!IsNuGetRelease) { // Use AssemblyVersion with Build as version - Version += "-cibuild" + int.Parse(Environment.GetEnvironmentVariable("BUILD_BUILDID")).ToString("0000000") + "-alpha"; + var buildId = Environment.GetEnvironmentVariable("BUILD_BUILDID") ?? + throw new InvalidOperationException("Missing environment variable BUILD_BUILDID"); + Version += "-cibuild" + int.Parse(buildId).ToString("0000000") + "-alpha"; } PublishTestResults = true; @@ -144,10 +146,10 @@ public partial class Build NugetIntermediateRoot = RootDirectory / "build-intermediate" / "nuget"; ZipRoot = ArtifactsDir / "zip"; TestResultsRoot = ArtifactsDir / "test-results"; - BuildDirs = GlobDirectories(RootDirectory, "**/bin") - .Concat(GlobDirectories(RootDirectory, "**/obj")) - .Where(dir => !dir.Contains("nukebuild")) - .Concat(GlobDirectories(RootDirectory, "**/node_modules")) + BuildDirs = RootDirectory.GlobDirectories("**/bin") + .Concat(RootDirectory.GlobDirectories("**/obj")) + .Where(dir => !((string)dir).Contains("nukebuild")) + .Concat(RootDirectory.GlobDirectories("**/node_modules")) .ToList(); DirSuffix = Configuration; FileZipSuffix = Version + ".zip"; @@ -157,13 +159,10 @@ public partial class Build VersionOutputDir = b.VersionOutputDir; } - (string Version, string ApiCompatVersion) GetVersion() + string GetVersion() { var xdoc = XDocument.Load(RootDirectory / "build/SharedVersion.props"); - return ( - xdoc.Descendants().First(x => x.Name.LocalName == "Version").Value, - xdoc.Descendants().First(x => x.Name.LocalName == "ApiCompatVersion").Value - ); + return xdoc.Descendants().First(x => x.Name.LocalName == "Version").Value; } } diff --git a/nukebuild/BuildTasksPatcher.cs b/nukebuild/BuildTasksPatcher.cs index 6bb71f4320..874d663490 100644 --- a/nukebuild/BuildTasksPatcher.cs +++ b/nukebuild/BuildTasksPatcher.cs @@ -85,7 +85,7 @@ public class BuildTasksPatcher var cecilMdbAsm = GetAssemblyPath(typeof(Mono.Cecil.Mdb.MdbReaderProvider)); ilRepackTool.Invoke( - $"/internalize /out:\"{output}\" \"{temp}\" \"{cecilAsm}\" \"{cecilRocksAsm}\" \"{cecilPdbAsm}\" \"{cecilMdbAsm}\"", + $"/internalize /out:\"{output:nq}\" \"{temp:nq}\" \"{cecilAsm:nq}\" \"{cecilRocksAsm:nq}\" \"{cecilPdbAsm:nq}\" \"{cecilMdbAsm:nq}\"", tempDir); // 'hurr-durr assembly with the same name is already loaded' prevention diff --git a/nukebuild/ByteArrayEqualityComparer.cs b/nukebuild/ByteArrayEqualityComparer.cs new file mode 100644 index 0000000000..f49a8f830e --- /dev/null +++ b/nukebuild/ByteArrayEqualityComparer.cs @@ -0,0 +1,25 @@ +#nullable enable + +using System; +using System.Collections.Generic; + +public sealed class ByteArrayEqualityComparer : IEqualityComparer +{ + public static ByteArrayEqualityComparer Instance { get; } = new(); + + public bool Equals(byte[]? x, byte[]? y) { + if (ReferenceEquals(x, y)) + return true; + if (x is null || y is null) + return false; + + return x.AsSpan().SequenceEqual(y.AsSpan()); + } + + public int GetHashCode(byte[]? obj) + { + var hashCode = new HashCode(); + hashCode.AddBytes(obj.AsSpan()); + return hashCode.ToHashCode(); + } +} diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj index 2a74be30bf..5890e65259 100644 --- a/nukebuild/_build.csproj +++ b/nukebuild/_build.csproj @@ -9,25 +9,20 @@ $(AvsCurrentTargetFramework) true - - https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8-transport/nuget/v3/index.json + + https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet10-transport/nuget/v3/index.json - - + - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + diff --git a/packages/Avalonia/Avalonia.csproj b/packages/Avalonia/Avalonia.csproj index b954f02f47..1cd1245d3f 100644 --- a/packages/Avalonia/Avalonia.csproj +++ b/packages/Avalonia/Avalonia.csproj @@ -1,11 +1,11 @@  - $(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0 + $(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks) Avalonia - + @@ -27,13 +27,13 @@ - <_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/netstandard2.0/Avalonia.Designer.HostApp.dll"> - tools/netstandard2.0/designer + <_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/$(AvsCurrentTargetFramework)/Avalonia.Designer.HostApp.dll"> + tools/$(AvsCurrentTargetFramework)/designer false None - <_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/net461/Avalonia.Designer.HostApp.exe"> - tools/net461/designer + <_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/$(AvsLegacyTargetFrameworks)/Avalonia.Designer.HostApp.dll"> + tools/$(AvsLegacyTargetFrameworks)/designer false None diff --git a/packages/Avalonia/Avalonia.props b/packages/Avalonia/Avalonia.props index 57b7f9dc32..78656a1726 100644 --- a/packages/Avalonia/Avalonia.props +++ b/packages/Avalonia/Avalonia.props @@ -1,12 +1,11 @@ - $(MSBuildThisFileDirectory)\..\tools\netstandard2.0\designer\Avalonia.Designer.HostApp.dll - $(MSBuildThisFileDirectory)\..\tools\net461\designer\Avalonia.Designer.HostApp.exe + $(MSBuildThisFileDirectory)\..\tools\$(AvsCurrentTargetFramework)\designer\Avalonia.Designer.HostApp.dll $(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Avalonia.Build.Tasks.dll $(UsedAvaloniaProducts);AvaloniaUI true false - false + true true diff --git a/packages/Avalonia/AvaloniaPrivateApis.targets b/packages/Avalonia/AvaloniaPrivateApis.targets index 5f69187d92..47219535cc 100644 --- a/packages/Avalonia/AvaloniaPrivateApis.targets +++ b/packages/Avalonia/AvaloniaPrivateApis.targets @@ -13,7 +13,7 @@ - net6.0 + net8.0 netstandard2.0 diff --git a/packages/Avalonia/AvaloniaSingleProject.targets b/packages/Avalonia/AvaloniaSingleProject.targets index 17b456f145..25125b26e4 100644 --- a/packages/Avalonia/AvaloniaSingleProject.targets +++ b/packages/Avalonia/AvaloniaSingleProject.targets @@ -98,7 +98,7 @@ 13.0 10.15 13.1 - 21.0 + 24.0 6.5 @@ -278,7 +278,7 @@ Include="$(TizenSharedPrefix)\**\*" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);@(TizenTpkUserExcludeFiles)" /> - + diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj index 958725eed5..f60ba69395 100644 --- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj +++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj @@ -26,7 +26,7 @@ - + diff --git a/samples/ControlCatalog.Browser.Blazor/App.razor b/samples/ControlCatalog.Browser.Blazor/App.razor deleted file mode 100644 index b941644e29..0000000000 --- a/samples/ControlCatalog.Browser.Blazor/App.razor +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - -

Sorry, there's nothing at this address.

-
-
-
diff --git a/samples/ControlCatalog.Browser.Blazor/App.razor.cs b/samples/ControlCatalog.Browser.Blazor/App.razor.cs deleted file mode 100644 index c331625664..0000000000 --- a/samples/ControlCatalog.Browser.Blazor/App.razor.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Threading.Tasks; -using Avalonia; -using Avalonia.Browser.Blazor; - -namespace ControlCatalog.Browser.Blazor; - -public partial class App -{ -} diff --git a/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj b/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj deleted file mode 100644 index 2950028e68..0000000000 --- a/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj +++ /dev/null @@ -1,29 +0,0 @@ - - - $(AvsCurrentBrowserTargetFramework) - browser-wasm - enable - 16777216 - false - false - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/ControlCatalog.Browser.Blazor/Pages/Index.razor b/samples/ControlCatalog.Browser.Blazor/Pages/Index.razor deleted file mode 100644 index 7480e4c5e9..0000000000 --- a/samples/ControlCatalog.Browser.Blazor/Pages/Index.razor +++ /dev/null @@ -1,5 +0,0 @@ -@page "/" - -@using Avalonia.Browser.Blazor - - diff --git a/samples/ControlCatalog.Browser.Blazor/Program.cs b/samples/ControlCatalog.Browser.Blazor/Program.cs deleted file mode 100644 index e68e9b14d9..0000000000 --- a/samples/ControlCatalog.Browser.Blazor/Program.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Net.Http; -using System.Threading.Tasks; -using Avalonia; -using Avalonia.Browser.Blazor; -using Microsoft.AspNetCore.Components.WebAssembly.Hosting; -using Microsoft.Extensions.DependencyInjection; -using ControlCatalog.Browser.Blazor; - -public class Program -{ - public static async Task Main(string[] args) - { - var host = CreateHostBuilder(args).Build(); - await StartAvaloniaApp(); - await host.RunAsync(); - } - - public static async Task StartAvaloniaApp() - { - await AppBuilder.Configure() - .StartBlazorAppAsync(); - } - - public static WebAssemblyHostBuilder CreateHostBuilder(string[] args) - { - var builder = WebAssemblyHostBuilder.CreateDefault(args); - - builder.RootComponents.Add("#app"); - - builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); - - return builder; - } -} - - - - diff --git a/samples/ControlCatalog.Browser.Blazor/Properties/launchSettings.json b/samples/ControlCatalog.Browser.Blazor/Properties/launchSettings.json deleted file mode 100644 index ad2b1e30f6..0000000000 --- a/samples/ControlCatalog.Browser.Blazor/Properties/launchSettings.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:13961", - "sslPort": 44319 - } - }, - "profiles": { - "ControlCatalog.Web": { - "commandName": "Project", - "dotnetRunMessages": "true", - "launchBrowser": true, - "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", - "applicationUrl": "https://localhost:5001;http://localhost:5000", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - } - } -} diff --git a/samples/ControlCatalog.Browser.Blazor/Shared/MainLayout.razor b/samples/ControlCatalog.Browser.Blazor/Shared/MainLayout.razor deleted file mode 100644 index 63fb17716c..0000000000 --- a/samples/ControlCatalog.Browser.Blazor/Shared/MainLayout.razor +++ /dev/null @@ -1,7 +0,0 @@ -@inherits LayoutComponentBase - -
-
- @Body -
-
diff --git a/samples/ControlCatalog.Browser.Blazor/_Imports.razor b/samples/ControlCatalog.Browser.Blazor/_Imports.razor deleted file mode 100644 index dc4f778352..0000000000 --- a/samples/ControlCatalog.Browser.Blazor/_Imports.razor +++ /dev/null @@ -1,10 +0,0 @@ -@using System.Net.Http -@using System.Net.Http.Json -@using Microsoft.AspNetCore.Components.Forms -@using Microsoft.AspNetCore.Components.Routing -@using Microsoft.AspNetCore.Components.Web -@using Microsoft.AspNetCore.Components.Web.Virtualization -@using Microsoft.AspNetCore.Components.WebAssembly.Http -@using Microsoft.JSInterop -@using ControlCatalog.Browser.Blazor.Shared -@using SkiaSharp diff --git a/samples/ControlCatalog.Browser.Blazor/wwwroot/css/app.css b/samples/ControlCatalog.Browser.Blazor/wwwroot/css/app.css deleted file mode 100644 index 49ca14e162..0000000000 --- a/samples/ControlCatalog.Browser.Blazor/wwwroot/css/app.css +++ /dev/null @@ -1,56 +0,0 @@ -html, body { - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; - margin: 0; - height: 100vh; - overflow: hidden; - touch-action: none; -} - -a, .btn-link { - color: #0366d6; -} - -.btn-primary { - color: #fff; - background-color: #1b6ec2; - border-color: #1861ac; -} - -.content { - padding-top: 1.1rem; -} - -.valid.modified:not([type=checkbox]) { - outline: 1px solid #26b050; -} - -.invalid { - outline: 1px solid red; -} - -.validation-message { - color: red; -} - -#blazor-error-ui { - background: lightyellow; - bottom: 0; - box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); - display: none; - left: 0; - padding: 0.6rem 1.25rem 0.7rem 1.25rem; - position: fixed; - width: 100%; - z-index: 1000; -} - -#blazor-error-ui .dismiss { - cursor: pointer; - position: absolute; - right: 0.75rem; - top: 0.5rem; -} - -#app, .page { - height: 100%; -} diff --git a/samples/ControlCatalog.Browser.Blazor/wwwroot/favicon.ico b/samples/ControlCatalog.Browser.Blazor/wwwroot/favicon.ico deleted file mode 100644 index da8d49ff9b..0000000000 Binary files a/samples/ControlCatalog.Browser.Blazor/wwwroot/favicon.ico and /dev/null differ diff --git a/samples/ControlCatalog.Browser.Blazor/wwwroot/index.html b/samples/ControlCatalog.Browser.Blazor/wwwroot/index.html deleted file mode 100644 index cad9123836..0000000000 --- a/samples/ControlCatalog.Browser.Blazor/wwwroot/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - Avalonia Sample - - - - - -
Powered by Avalonia
- -
- An unhandled error has occurred. - Reload - 🗙 -
- - - diff --git a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj index 2c47effa38..9398987837 100644 --- a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj +++ b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj @@ -1,22 +1,41 @@  - Exe - net461 - x64 + WinExe + $(AvsCurrentTargetFramework) + true true - ../ControlCatalog.NetCore/app.manifest - - + + + + + + + + PreserveNewest + - + + + + + + + + + + + en + app.manifest + + - + diff --git a/samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs b/samples/ControlCatalog.Desktop/NativeControls/Gtk/EmbedSample.Gtk.cs similarity index 96% rename from samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs rename to samples/ControlCatalog.Desktop/NativeControls/Gtk/EmbedSample.Gtk.cs index 81a5ba536f..c42ac73b88 100644 --- a/samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs +++ b/samples/ControlCatalog.Desktop/NativeControls/Gtk/EmbedSample.Gtk.cs @@ -5,7 +5,7 @@ using Avalonia.Controls.Platform; using System; using ControlCatalog.Pages; -namespace ControlCatalog.NetCore; +namespace ControlCatalog.Desktop; public class EmbedSampleGtk : INativeDemoControl { diff --git a/samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs b/samples/ControlCatalog.Desktop/NativeControls/Gtk/GtkHelper.cs similarity index 97% rename from samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs rename to samples/ControlCatalog.Desktop/NativeControls/Gtk/GtkHelper.cs index 9d698716ee..78d7a45154 100644 --- a/samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs +++ b/samples/ControlCatalog.Desktop/NativeControls/Gtk/GtkHelper.cs @@ -7,7 +7,7 @@ using Avalonia.X11.NativeDialogs; using static Avalonia.X11.NativeDialogs.Gtk; using static Avalonia.X11.Interop.Glib; -namespace ControlCatalog.NetCore; +namespace ControlCatalog.Desktop; internal class GtkHelper { diff --git a/samples/ControlCatalog.NetCore/NativeControls/Gtk/nodes-license.md b/samples/ControlCatalog.Desktop/NativeControls/Gtk/nodes-license.md similarity index 100% rename from samples/ControlCatalog.NetCore/NativeControls/Gtk/nodes-license.md rename to samples/ControlCatalog.Desktop/NativeControls/Gtk/nodes-license.md diff --git a/samples/ControlCatalog.NetCore/NativeControls/Gtk/nodes.mp4 b/samples/ControlCatalog.Desktop/NativeControls/Gtk/nodes.mp4 similarity index 100% rename from samples/ControlCatalog.NetCore/NativeControls/Gtk/nodes.mp4 rename to samples/ControlCatalog.Desktop/NativeControls/Gtk/nodes.mp4 diff --git a/samples/ControlCatalog.NetCore/NativeControls/Mac/EmbedSample.Mac.cs b/samples/ControlCatalog.Desktop/NativeControls/Mac/EmbedSample.Mac.cs similarity index 95% rename from samples/ControlCatalog.NetCore/NativeControls/Mac/EmbedSample.Mac.cs rename to samples/ControlCatalog.Desktop/NativeControls/Mac/EmbedSample.Mac.cs index 7967c9c073..b761ce0972 100644 --- a/samples/ControlCatalog.NetCore/NativeControls/Mac/EmbedSample.Mac.cs +++ b/samples/ControlCatalog.Desktop/NativeControls/Mac/EmbedSample.Mac.cs @@ -8,7 +8,7 @@ using ControlCatalog.Pages; using MonoMac.Foundation; using MonoMac.WebKit; -namespace ControlCatalog.NetCore; +namespace ControlCatalog.Desktop; public class EmbedSampleMac : INativeDemoControl { diff --git a/samples/ControlCatalog.NetCore/NativeControls/Mac/MacHelper.cs b/samples/ControlCatalog.Desktop/NativeControls/Mac/MacHelper.cs similarity index 95% rename from samples/ControlCatalog.NetCore/NativeControls/Mac/MacHelper.cs rename to samples/ControlCatalog.Desktop/NativeControls/Mac/MacHelper.cs index 5b3bc9abf1..154878e4ff 100644 --- a/samples/ControlCatalog.NetCore/NativeControls/Mac/MacHelper.cs +++ b/samples/ControlCatalog.Desktop/NativeControls/Mac/MacHelper.cs @@ -3,7 +3,7 @@ using System; using Avalonia.Controls.Platform; using MonoMac.AppKit; -namespace ControlCatalog.NetCore; +namespace ControlCatalog.Desktop; internal class MacHelper { diff --git a/samples/ControlCatalog.NetCore/NativeControls/Win/EmbedSample.Win.cs b/samples/ControlCatalog.Desktop/NativeControls/Win/EmbedSample.Win.cs similarity index 98% rename from samples/ControlCatalog.NetCore/NativeControls/Win/EmbedSample.Win.cs rename to samples/ControlCatalog.Desktop/NativeControls/Win/EmbedSample.Win.cs index 77982db0ca..c529c093f6 100644 --- a/samples/ControlCatalog.NetCore/NativeControls/Win/EmbedSample.Win.cs +++ b/samples/ControlCatalog.Desktop/NativeControls/Win/EmbedSample.Win.cs @@ -6,7 +6,7 @@ using Avalonia.Platform; using ControlCatalog.Pages; -namespace ControlCatalog.NetCore; +namespace ControlCatalog.Desktop; public class EmbedSampleWin : INativeDemoControl { diff --git a/samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs b/samples/ControlCatalog.Desktop/NativeControls/Win/WinApi.cs similarity index 98% rename from samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs rename to samples/ControlCatalog.Desktop/NativeControls/Win/WinApi.cs index bd0c1bf98e..1bb3879ac3 100644 --- a/samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs +++ b/samples/ControlCatalog.Desktop/NativeControls/Win/WinApi.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace ControlCatalog.NetCore; +namespace ControlCatalog.Desktop; internal unsafe class WinApi { diff --git a/samples/ControlCatalog.Desktop/Program.cs b/samples/ControlCatalog.Desktop/Program.cs index 533ee8308a..707ead5f1d 100644 --- a/samples/ControlCatalog.Desktop/Program.cs +++ b/samples/ControlCatalog.Desktop/Program.cs @@ -1,38 +1,180 @@ using System; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Avalonia; -using Avalonia.Platform; -using ControlCatalog.NetCore; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Fonts.Inter; +using Avalonia.Headless; +using Avalonia.LinuxFramebuffer.Output; +using Avalonia.LogicalTree; +using Avalonia.Rendering.Composition; +using Avalonia.Threading; +using Avalonia.Vulkan; using ControlCatalog.Pages; -namespace ControlCatalog +namespace ControlCatalog.Desktop { - internal class Program + static class Program { + private static bool s_useFramebuffer; + [STAThread] - public static int Main(string[] args) - => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + static int Main(string[] args) + { + if (args.Contains("--fbdev")) + { + s_useFramebuffer = true; + } + + if (args.Contains("--wait-for-attach")) + { + Console.WriteLine("Attach debugger and use 'Set next statement'"); + while (true) + { + Thread.Sleep(100); + if (Debugger.IsAttached) + break; + } + } + + var builder = BuildAvaloniaApp(); + + double GetScaling() + { + var idx = Array.IndexOf(args, "--scaling"); + if (idx != 0 && args.Length > idx + 1 && + double.TryParse(args[idx + 1], NumberStyles.Any, CultureInfo.InvariantCulture, out var scaling)) + return scaling; + return 1; + } + if (s_useFramebuffer) + { + SilenceConsole(); + return builder.StartLinuxFbDev(args, new FbDevOutputOptions() + { + Scaling = GetScaling() + }); + } + else if (args.Contains("--vnc")) + { + return builder.StartWithHeadlessVncPlatform(null, 5901, args, ShutdownMode.OnMainWindowClose); + } + else if (args.Contains("--full-headless")) + { + return builder + .UseHeadless(new AvaloniaHeadlessPlatformOptions + { + UseHeadlessDrawing = true + }) + .AfterSetup(_ => + { + DispatcherTimer.RunOnce(async () => + { + var window = ((IClassicDesktopStyleApplicationLifetime)Application.Current.ApplicationLifetime) + .MainWindow; + var tc = window.GetLogicalDescendants().OfType().First(); + foreach (var page in tc.Items.Cast().ToList()) + { + if (page.Header.ToString() == "DatePicker" || page.Header.ToString() == "TreeView") + continue; + Console.WriteLine("Selecting " + page.Header); + tc.SelectedItem = page; + await Task.Delay(50); + } + Console.WriteLine("Selecting the first page"); + tc.SelectedItem = tc.Items.OfType().First(); + await Task.Delay(500); + Console.WriteLine("Clicked through all pages, triggering GC"); + for (var c = 0; c < 3; c++) + { + GC.Collect(2, GCCollectionMode.Forced); + await Task.Delay(50); + } + + void FormatMem(string metric, long bytes) + { + Console.WriteLine(metric + ": " + bytes / 1024 / 1024 + "MB"); + } + + FormatMem("GC allocated bytes", GC.GetTotalMemory(true)); + FormatMem("WorkingSet64", Process.GetCurrentProcess().WorkingSet64); + }, TimeSpan.FromSeconds(1)); + }) + .StartWithClassicDesktopLifetime(args); + } + else if (args.Contains("--drm")) + { + SilenceConsole(); + return builder.StartLinuxDrm(args, scaling: GetScaling()); + } + else if (args.Contains("--dxgi")) + { + builder.With(new Win32PlatformOptions() + { + CompositionMode = new [] { Win32CompositionMode.LowLatencyDxgiSwapChain } + }); + return builder.StartWithClassicDesktopLifetime(args); + } + else + return builder.StartWithClassicDesktopLifetime(args); + } /// /// This method is needed for IDE previewer infrastructure /// public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() - .LogToTrace() + .UsePlatformDetect() + .With(new X11PlatformOptions + { + EnableMultiTouch = true, + UseDBusMenu = true, + EnableIme = true, + }) + + .With(new VulkanOptions + { + VulkanInstanceCreationOptions = new () + { + UseDebug = true + } + }) + .With(new CompositionOptions() + { + UseRegionDirtyRectClipping = true + }) + .UseSkia() + .WithInterFont() .AfterSetup(builder => { - builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions() + if (!s_useFramebuffer) { - StartupScreenIndex = 1, - }); + builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions() + { + StartupScreenIndex = 1, + }); + } - EmbedSample.Implementation = new EmbedSampleWin(); + EmbedSample.Implementation = OperatingSystem.IsWindows() ? (INativeDemoControl)new EmbedSampleWin() + : OperatingSystem.IsMacOS() ? new EmbedSampleMac() + : OperatingSystem.IsLinux() ? new EmbedSampleGtk() + : null; }) - .UseWin32() - .UseSkia(); + .LogToTrace(); - private static void ConfigureAssetAssembly(AppBuilder builder) + static void SilenceConsole() { - AssetLoader.SetDefaultAssembly(typeof(App).Assembly); + new Thread(() => + { + Console.CursorVisible = false; + while (true) + Console.ReadKey(true); + }) + { IsBackground = true }.Start(); } } } diff --git a/samples/ControlCatalog.NetCore/Properties/launchSettings.json b/samples/ControlCatalog.Desktop/Properties/launchSettings.json similarity index 87% rename from samples/ControlCatalog.NetCore/Properties/launchSettings.json rename to samples/ControlCatalog.Desktop/Properties/launchSettings.json index 11feb94bb3..d57a2680e4 100644 --- a/samples/ControlCatalog.NetCore/Properties/launchSettings.json +++ b/samples/ControlCatalog.Desktop/Properties/launchSettings.json @@ -1,6 +1,6 @@ { "profiles": { - "ControlCatalog.NetCore": { + "ControlCatalog.Desktop": { "commandName": "Project" }, "Dxgi": { diff --git a/samples/ControlCatalog.NetCore/app.manifest b/samples/ControlCatalog.Desktop/app.manifest similarity index 100% rename from samples/ControlCatalog.NetCore/app.manifest rename to samples/ControlCatalog.Desktop/app.manifest diff --git a/samples/ControlCatalog.iOS/ControlCatalog.MacCatalyst.csproj b/samples/ControlCatalog.MacCatalyst/ControlCatalog.MacCatalyst.csproj similarity index 56% rename from samples/ControlCatalog.iOS/ControlCatalog.MacCatalyst.csproj rename to samples/ControlCatalog.MacCatalyst/ControlCatalog.MacCatalyst.csproj index f7cd8eebf4..954ed20d99 100644 --- a/samples/ControlCatalog.iOS/ControlCatalog.MacCatalyst.csproj +++ b/samples/ControlCatalog.MacCatalyst/ControlCatalog.MacCatalyst.csproj @@ -1,19 +1,22 @@  + Exe manual $(AvsCurrentMacCatalystTargetFramework) - 14.0 + 15.0 + true + - - - - Info.plist - + + - - true - + + + + + + diff --git a/samples/ControlCatalog.MacCatalyst/Entitlements.plist b/samples/ControlCatalog.MacCatalyst/Entitlements.plist new file mode 100644 index 0000000000..0c67376eba --- /dev/null +++ b/samples/ControlCatalog.MacCatalyst/Entitlements.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/samples/ControlCatalog.iOS/Info.Catalyst.plist b/samples/ControlCatalog.MacCatalyst/Info.plist similarity index 96% rename from samples/ControlCatalog.iOS/Info.Catalyst.plist rename to samples/ControlCatalog.MacCatalyst/Info.plist index ad5aecb10a..1a21cbbfed 100644 --- a/samples/ControlCatalog.iOS/Info.Catalyst.plist +++ b/samples/ControlCatalog.MacCatalyst/Info.plist @@ -3,7 +3,7 @@ CFBundleDisplayName - ControlCatalog.Catalyst + ControlCatalog.MacCatalyst CFBundleIdentifier Avalonia.ControlCatalog CFBundleShortVersionString diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj deleted file mode 100644 index 9398987837..0000000000 --- a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj +++ /dev/null @@ -1,41 +0,0 @@ - - - - WinExe - $(AvsCurrentTargetFramework) - true - true - - - - - - - - - - - PreserveNewest - - - - - - - - - - - - - - - - - en - app.manifest - - - - - diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs deleted file mode 100644 index 036dd13f7a..0000000000 --- a/samples/ControlCatalog.NetCore/Program.cs +++ /dev/null @@ -1,180 +0,0 @@ -using System; -using System.Diagnostics; -using System.Globalization; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Fonts.Inter; -using Avalonia.Headless; -using Avalonia.LinuxFramebuffer.Output; -using Avalonia.LogicalTree; -using Avalonia.Rendering.Composition; -using Avalonia.Threading; -using Avalonia.Vulkan; -using ControlCatalog.Pages; - -namespace ControlCatalog.NetCore -{ - static class Program - { - private static bool s_useFramebuffer; - - [STAThread] - static int Main(string[] args) - { - if (args.Contains("--fbdev")) - { - s_useFramebuffer = true; - } - - if (args.Contains("--wait-for-attach")) - { - Console.WriteLine("Attach debugger and use 'Set next statement'"); - while (true) - { - Thread.Sleep(100); - if (Debugger.IsAttached) - break; - } - } - - var builder = BuildAvaloniaApp(); - - double GetScaling() - { - var idx = Array.IndexOf(args, "--scaling"); - if (idx != 0 && args.Length > idx + 1 && - double.TryParse(args[idx + 1], NumberStyles.Any, CultureInfo.InvariantCulture, out var scaling)) - return scaling; - return 1; - } - if (s_useFramebuffer) - { - SilenceConsole(); - return builder.StartLinuxFbDev(args, new FbDevOutputOptions() - { - Scaling = GetScaling() - }); - } - else if (args.Contains("--vnc")) - { - return builder.StartWithHeadlessVncPlatform(null, 5901, args, ShutdownMode.OnMainWindowClose); - } - else if (args.Contains("--full-headless")) - { - return builder - .UseHeadless(new AvaloniaHeadlessPlatformOptions - { - UseHeadlessDrawing = true - }) - .AfterSetup(_ => - { - DispatcherTimer.RunOnce(async () => - { - var window = ((IClassicDesktopStyleApplicationLifetime)Application.Current.ApplicationLifetime) - .MainWindow; - var tc = window.GetLogicalDescendants().OfType().First(); - foreach (var page in tc.Items.Cast().ToList()) - { - if (page.Header.ToString() == "DatePicker" || page.Header.ToString() == "TreeView") - continue; - Console.WriteLine("Selecting " + page.Header); - tc.SelectedItem = page; - await Task.Delay(50); - } - Console.WriteLine("Selecting the first page"); - tc.SelectedItem = tc.Items.OfType().First(); - await Task.Delay(500); - Console.WriteLine("Clicked through all pages, triggering GC"); - for (var c = 0; c < 3; c++) - { - GC.Collect(2, GCCollectionMode.Forced); - await Task.Delay(50); - } - - void FormatMem(string metric, long bytes) - { - Console.WriteLine(metric + ": " + bytes / 1024 / 1024 + "MB"); - } - - FormatMem("GC allocated bytes", GC.GetTotalMemory(true)); - FormatMem("WorkingSet64", Process.GetCurrentProcess().WorkingSet64); - }, TimeSpan.FromSeconds(1)); - }) - .StartWithClassicDesktopLifetime(args); - } - else if (args.Contains("--drm")) - { - SilenceConsole(); - return builder.StartLinuxDrm(args, scaling: GetScaling()); - } - else if (args.Contains("--dxgi")) - { - builder.With(new Win32PlatformOptions() - { - CompositionMode = new [] { Win32CompositionMode.LowLatencyDxgiSwapChain } - }); - return builder.StartWithClassicDesktopLifetime(args); - } - else - return builder.StartWithClassicDesktopLifetime(args); - } - - /// - /// This method is needed for IDE previewer infrastructure - /// - public static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure() - .UsePlatformDetect() - .With(new X11PlatformOptions - { - EnableMultiTouch = true, - UseDBusMenu = true, - EnableIme = true, - }) - - .With(new VulkanOptions - { - VulkanInstanceCreationOptions = new () - { - UseDebug = true - } - }) - .With(new CompositionOptions() - { - UseRegionDirtyRectClipping = true - }) - .UseSkia() - .WithInterFont() - .AfterSetup(builder => - { - if (!s_useFramebuffer) - { - builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions() - { - StartupScreenIndex = 1, - }); - } - - EmbedSample.Implementation = OperatingSystem.IsWindows() ? (INativeDemoControl)new EmbedSampleWin() - : OperatingSystem.IsMacOS() ? new EmbedSampleMac() - : OperatingSystem.IsLinux() ? new EmbedSampleGtk() - : null; - }) - .LogToTrace(); - - static void SilenceConsole() - { - new Thread(() => - { - Console.CursorVisible = false; - while (true) - Console.ReadKey(true); - }) - { IsBackground = true }.Start(); - } - } -} diff --git a/samples/ControlCatalog.Tizen/ControlCatalog.Tizen.csproj b/samples/ControlCatalog.Tizen/ControlCatalog.Tizen.csproj deleted file mode 100644 index 4b12a096d4..0000000000 --- a/samples/ControlCatalog.Tizen/ControlCatalog.Tizen.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - $(AvsCurrentTizenTargetFramework) - Exe - - - - - - - - - - - - - - - - - - - - diff --git a/samples/ControlCatalog.Tizen/EmbedSampleNuiTizen.cs b/samples/ControlCatalog.Tizen/EmbedSampleNuiTizen.cs deleted file mode 100644 index 728ea58e3b..0000000000 --- a/samples/ControlCatalog.Tizen/EmbedSampleNuiTizen.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Avalonia.Platform; -using Avalonia.Tizen; -using ControlCatalog.Pages; -using Tizen.NUI.BaseComponents; -using Tizen.NUI.Components; -using Tizen.Pims.Contacts.ContactsViews; - -namespace ControlCatalog.Tizen; -public class EmbedSampleNuiTizen : INativeDemoControl -{ - public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault) - { - if (isSecond) - { - var webView = new WebView(); - webView.LoadUrl("https://avaloniaui.net/"); - return new NuiViewControlHandle(webView); - } - else - { - var clickCount = 0; - var button = new Button - { - Text = "Hello world" - }; - - button.Clicked += (sender, e) => - { - clickCount++; - button.Text = $"Click count {clickCount}"; - }; - - return new NuiViewControlHandle(button); - } - } -} diff --git a/samples/ControlCatalog.Tizen/Main.cs b/samples/ControlCatalog.Tizen/Main.cs deleted file mode 100644 index 2d611ef5a3..0000000000 --- a/samples/ControlCatalog.Tizen/Main.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using Avalonia; -using Avalonia.Tizen; -using ElmSharp; -using SkiaSharp; -using Tizen.Applications; - -namespace ControlCatalog.Tizen; - -class Program : NuiTizenApplication -{ - protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) => - base.CustomizeAppBuilder(builder).AfterSetup(_ => - { - Pages.EmbedSample.Implementation = new EmbedSampleNuiTizen(); - }); - - static void Main(string[] args) - { - var app = new Program(); - app.Run(args); - } -} diff --git a/samples/ControlCatalog.Tizen/shared/res/Avalonia.png b/samples/ControlCatalog.Tizen/shared/res/Avalonia.png deleted file mode 100644 index ea0bb4986f..0000000000 Binary files a/samples/ControlCatalog.Tizen/shared/res/Avalonia.png and /dev/null differ diff --git a/samples/ControlCatalog.Tizen/tizen-manifest.xml b/samples/ControlCatalog.Tizen/tizen-manifest.xml deleted file mode 100644 index 50101d37ff..0000000000 --- a/samples/ControlCatalog.Tizen/tizen-manifest.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - Avalonia.png - - - - - - http://tizen.org/privilege/appdir.shareddata - http://tizen.org/privilege/appmanager.launch - http://tizen.org/privilege/externalstorage - http://tizen.org/privilege/externalstorage.appdata - http://tizen.org/privilege/internet - http://tizen.org/privilege/network.get - - - - http://tizen.org/feature/opengles.surfaceless_context - http://tizen.org/feature/opengles.version.2_0 - diff --git a/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj b/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj index 1ab3df1b63..bab1dd4c9f 100644 --- a/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj +++ b/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj @@ -1,18 +1,15 @@  + Exe manual $(AvsCurrentIOSTargetFramework) $(AvsMinSupportedIOSVersion) + - - - - Info.plist - + + - - true - - \ No newline at end of file + + diff --git a/samples/ControlCatalog.iOS/Info.iOS.plist b/samples/ControlCatalog.iOS/Info.plist similarity index 100% rename from samples/ControlCatalog.iOS/Info.iOS.plist rename to samples/ControlCatalog.iOS/Info.plist diff --git a/samples/ControlCatalog.iOS/ControlCatalog.tvOS.csproj b/samples/ControlCatalog.tvOS/ControlCatalog.tvOS.csproj similarity index 70% rename from samples/ControlCatalog.iOS/ControlCatalog.tvOS.csproj rename to samples/ControlCatalog.tvOS/ControlCatalog.tvOS.csproj index 35e964abab..5e191a59dd 100644 --- a/samples/ControlCatalog.iOS/ControlCatalog.tvOS.csproj +++ b/samples/ControlCatalog.tvOS/ControlCatalog.tvOS.csproj @@ -1,4 +1,5 @@ + Exe manual @@ -7,15 +8,17 @@ tvossimulator-x64 + true + - - - - Info.plist - + + - - true - + + + + + + diff --git a/samples/ControlCatalog.tvOS/Entitlements.plist b/samples/ControlCatalog.tvOS/Entitlements.plist new file mode 100644 index 0000000000..0c67376eba --- /dev/null +++ b/samples/ControlCatalog.tvOS/Entitlements.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/samples/ControlCatalog.iOS/Info.tvOS.plist b/samples/ControlCatalog.tvOS/Info.plist similarity index 100% rename from samples/ControlCatalog.iOS/Info.tvOS.plist rename to samples/ControlCatalog.tvOS/Info.plist diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj index cff0bb4e92..81caa6b2e4 100644 --- a/samples/ControlCatalog/ControlCatalog.csproj +++ b/samples/ControlCatalog/ControlCatalog.csproj @@ -1,6 +1,6 @@  - netstandard2.0;$(AvsCurrentTargetFramework) + $(AvsCurrentTargetFramework) true enable true @@ -9,9 +9,9 @@ %(Filename) - + Designer - + diff --git a/samples/ControlCatalog/DecoratedWindow.xaml.cs b/samples/ControlCatalog/DecoratedWindow.xaml.cs index c97b157040..bb87d982ba 100644 --- a/samples/ControlCatalog/DecoratedWindow.xaml.cs +++ b/samples/ControlCatalog/DecoratedWindow.xaml.cs @@ -1,52 +1,45 @@ -using Avalonia; using Avalonia.Controls; -using Avalonia.Markup.Xaml; -using System; using Avalonia.Input; namespace ControlCatalog { - public class DecoratedWindow : Window + public partial class DecoratedWindow : Window { public DecoratedWindow() { - this.InitializeComponent(); - } - - void SetupSide(string name, StandardCursorType cursor, WindowEdge edge) - { - var ctl = this.Get(name); - ctl.Cursor = new Cursor(cursor); - ctl.PointerPressed += (i, e) => - { - BeginResizeDrag(edge, e); - }; - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - this.Get("TitleBar").PointerPressed += (i, e) => + InitializeComponent(); + TitleBar.PointerPressed += (i, e) => { BeginMoveDrag(e); }; - SetupSide("Left", StandardCursorType.LeftSide, WindowEdge.West); - SetupSide("Right", StandardCursorType.RightSide, WindowEdge.East); - SetupSide("Top", StandardCursorType.TopSide, WindowEdge.North); - SetupSide("Bottom", StandardCursorType.BottomSide, WindowEdge.South); - SetupSide("TopLeft", StandardCursorType.TopLeftCorner, WindowEdge.NorthWest); - SetupSide("TopRight", StandardCursorType.TopRightCorner, WindowEdge.NorthEast); - SetupSide("BottomLeft", StandardCursorType.BottomLeftCorner, WindowEdge.SouthWest); - SetupSide("BottomRight", StandardCursorType.BottomRightCorner, WindowEdge.SouthEast); - this.Get - - - + diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs index 5b7814fb5d..0e2ad7d2b9 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs @@ -21,22 +21,24 @@ using Avalonia.Platform.Storage.FileIO; namespace ControlCatalog.Pages { - public class DialogsPage : UserControl + public partial class DialogsPage : UserControl { public DialogsPage() { - this.InitializeComponent(); + InitializeComponent(); IStorageFolder? lastSelectedDirectory = null; IStorageItem? lastSelectedItem = null; bool ignoreTextChanged = false; - var results = this.Get("PickerLastResults"); - var resultsVisible = this.Get("PickerLastResultsVisible"); - var bookmarkContainer = this.Get("BookmarkContainer"); - var openedFileContent = this.Get("OpenedFileContent"); - var openMultiple = this.Get("OpenMultiple"); - var currentFolderBox = this.Get("CurrentFolderBox"); + var results = PickerLastResults; + var resultsVisible = PickerLastResultsVisible; + var bookmarkContainer = BookmarkContainer; + var openedFileContent = OpenedFileContent; + var openMultiple = OpenMultiple; + var currentFolderBox = CurrentFolderBox; + var useSuggestedFilter = UseSuggestedFilter; + var suggestedFilterSelector = SuggestedFilterSelector; currentFolderBox.TextChanged += async (sender, args) => { @@ -61,7 +63,7 @@ namespace ControlCatalog.Pages } catch (SecurityException) { - + } } } @@ -76,9 +78,9 @@ namespace ControlCatalog.Pages }).ToList() ?? new List(); } - List? GetFileTypes() + List? BuildFileTypes() { - var selectedItem = (this.Get("FilterSelector").SelectedItem as ComboBoxItem)?.Content + var selectedItem = (FilterSelector.SelectedItem as ComboBoxItem)?.Content ?? "None"; var binLogType = new FilePickerFileType("Binary Log") @@ -115,7 +117,65 @@ namespace ControlCatalog.Pages }; } - this.Get"; - var mfxt = this.Get("MenuFlyoutXamlText"); + var mfxt = this.MenuFlyoutXamlText; mfxt.Text = ""; - var afxt = this.Get("AttachedFlyoutXamlText"); + var afxt = this.AttachedFlyoutXamlText; afxt.Text = "\n" + " \n" + " \n" + @@ -63,7 +59,7 @@ namespace ControlCatalog.Pages "\n\n In DoubleTapped handler:\n" + "FlyoutBase.ShowAttachedFlyout(AttachedFlyoutPanel);"; - var sfxt = this.Get("SharedFlyoutXamlText"); + var sfxt = this.SharedFlyoutXamlText; sfxt.Text = "Declare a flyout in Resources:\n" + "\n" + " \n" + diff --git a/samples/ControlCatalog/Pages/GesturePage.cs b/samples/ControlCatalog/Pages/GesturePage.cs index 9164384eae..c480b512b4 100644 --- a/samples/ControlCatalog/Pages/GesturePage.cs +++ b/samples/ControlCatalog/Pages/GesturePage.cs @@ -1,75 +1,61 @@ using System; -using System.Numerics; using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.LogicalTree; -using Avalonia.Markup.Xaml; using Avalonia.Rendering.Composition; using Avalonia.Utilities; namespace ControlCatalog.Pages { - public class GesturePage : UserControl + public partial class GesturePage : UserControl { private bool _isInit; private double _currentScale; public GesturePage() { - this.InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); + InitializeComponent(); } protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); - if(_isInit) + if (_isInit) { return; } _isInit = true; - SetPullHandlers(this.Find("TopPullZone"), false); - SetPullHandlers(this.Find("BottomPullZone"), true); - SetPullHandlers(this.Find("RightPullZone"), true); - SetPullHandlers(this.Find("LeftPullZone"), false); + SetPullHandlers(TopPullZone, false); + SetPullHandlers(BottomPullZone, true); + SetPullHandlers(RightPullZone, true); + SetPullHandlers(LeftPullZone, false); - var image = this.Get("PinchImage"); + var image = PinchImage; SetPinchHandlers(image); - var reset = this.Get - - diff --git a/samples/IntegrationTestApp/Pages/WindowPage.axaml.cs b/samples/IntegrationTestApp/Pages/WindowPage.axaml.cs index 5549e537d3..b7f505a7b2 100644 --- a/samples/IntegrationTestApp/Pages/WindowPage.axaml.cs +++ b/samples/IntegrationTestApp/Pages/WindowPage.axaml.cs @@ -23,10 +23,13 @@ public partial class WindowPage : UserControl private void ShowWindow_Click(object? sender, RoutedEventArgs e) { var size = !string.IsNullOrWhiteSpace(ShowWindowSize.Text) ? Size.Parse(ShowWindowSize.Text) : (Size?)null; + var canResize = ShowWindowCanResize.IsChecked ?? false; var window = new ShowWindowTest { WindowStartupLocation = (WindowStartupLocation)ShowWindowLocation.SelectedIndex, - CanResize = ShowWindowCanResize.IsChecked ?? false, + CanResize = canResize, + CanMinimize = ShowWindowCanMinimize.IsChecked ?? false, + CanMaximize = canResize && (ShowWindowCanMaximize.IsChecked ?? false) }; if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime) diff --git a/samples/IntegrationTestApp/ShowWindowTest.axaml b/samples/IntegrationTestApp/ShowWindowTest.axaml index c43e00497f..272c61ed0c 100644 --- a/samples/IntegrationTestApp/ShowWindowTest.axaml +++ b/samples/IntegrationTestApp/ShowWindowTest.axaml @@ -15,7 +15,7 @@ - + @@ -62,13 +62,19 @@