diff --git a/.editorconfig b/.editorconfig index 42c6f62e9c..7051372383 100644 --- a/.editorconfig +++ b/.editorconfig @@ -141,9 +141,6 @@ dotnet_analyzer_diagnostic.category-Performance.severity = none #error - Uncomme # CS0649: Field 'field' is never assigned to, and will always have its default value 'value' dotnet_diagnostic.CS0649.severity = error -# CS1591: Missing XML comment for publicly visible type or member -dotnet_diagnostic.CS1591.severity = suggestion - # CS0162: Remove unreachable code dotnet_diagnostic.CS0162.severity = error # CA1018: Mark attributes with AttributeUsageAttribute @@ -177,6 +174,8 @@ dotnet_diagnostic.CA1828.severity = warning dotnet_diagnostic.CA1829.severity = warning #CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters dotnet_diagnostic.CA1847.severity = warning +# CA1851: Possible multiple enumerations of IEnumerable collection +dotnet_diagnostic.CA1851.severity = warning #CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method dotnet_diagnostic.CA1854.severity = warning #CA2211:Non-constant fields should not be visible @@ -218,6 +217,8 @@ avalonia_xaml_diagnostic.AVLN2205.severity = error avalonia_xaml_diagnostic.AVLN2206.severity = info # TemplatePartWrongType avalonia_xaml_diagnostic.AVLN2207.severity = error +# ItemContainerInsideTemplate +avalonia_xaml_diagnostic.AVLN2208.severity = error # Obsolete avalonia_xaml_diagnostic.AVLN5001.severity = error diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index e70693d358..3fe56d6210 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -25,7 +25,10 @@ body: id: avalonia-version attributes: label: Avalonia version - placeholder: e.g. 11.0.9, 11.1.0 + description: | + Let us know which version you have tested. Please make sure to test latest stable version available. + If you could test [nightly builds](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed) in addition, this would be of great help. + placeholder: e.g. 11.2.0, 11.1.0 validations: required: true - type: dropdown diff --git a/.gitignore b/.gitignore index 32ada6ca2b..826b4d8a5a 100644 --- a/.gitignore +++ b/.gitignore @@ -45,8 +45,8 @@ x64/ *.vssscc .builds *.pidb -*.log *.scc +*.binlog # Visual C++ cache files ipch/ diff --git a/.gitmodules b/.gitmodules index 2d11fdfa9e..07f532607a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ -[submodule "nukebuild/Numerge"] - path = nukebuild/Numerge +[submodule "Numerge"] + path = external/Numerge url = https://github.com/kekekeks/Numerge.git -[submodule "src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github"] - path = src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github +[submodule "XamlX"] + path = external/XamlX url = https://github.com/kekekeks/XamlX.git diff --git a/.ncrunch/AppWithoutLifetime.v3.ncrunchproject b/.ncrunch/AppWithoutLifetime.v3.ncrunchproject index 3b82c33f1c..319cd523ce 100644 --- a/.ncrunch/AppWithoutLifetime.v3.ncrunchproject +++ b/.ncrunch/AppWithoutLifetime.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0 - True \ No newline at end of file diff --git a/.ncrunch/Avalonia.Analyzers.CSharp.v3.ncrunchproject b/.ncrunch/Avalonia.Analyzers.CSharp.v3.ncrunchproject new file mode 100644 index 0000000000..08b7dfa6ee --- /dev/null +++ b/.ncrunch/Avalonia.Analyzers.CSharp.v3.ncrunchproject @@ -0,0 +1,8 @@ + + + + TargetFramework = netstandard2.0 + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Analyzers.CodeFixes.CSharp.v3.ncrunchproject b/.ncrunch/Avalonia.Analyzers.CodeFixes.CSharp.v3.ncrunchproject new file mode 100644 index 0000000000..08b7dfa6ee --- /dev/null +++ b/.ncrunch/Avalonia.Analyzers.CodeFixes.CSharp.v3.ncrunchproject @@ -0,0 +1,8 @@ + + + + TargetFramework = netstandard2.0 + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Analyzers.VisualBasic.v3.ncrunchproject b/.ncrunch/Avalonia.Analyzers.VisualBasic.v3.ncrunchproject new file mode 100644 index 0000000000..08b7dfa6ee --- /dev/null +++ b/.ncrunch/Avalonia.Analyzers.VisualBasic.v3.ncrunchproject @@ -0,0 +1,8 @@ + + + + TargetFramework = netstandard2.0 + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Analyzers.v3.ncrunchproject b/.ncrunch/Avalonia.Analyzers.v3.ncrunchproject deleted file mode 100644 index a079eefacf..0000000000 --- a/.ncrunch/Avalonia.Analyzers.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - TargetFramework = netstandard2.0 - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Android.v3.ncrunchproject b/.ncrunch/Avalonia.Android.v3.ncrunchproject index 1335822600..a739b1286b 100644 --- a/.ncrunch/Avalonia.Android.v3.ncrunchproject +++ b/.ncrunch/Avalonia.Android.v3.ncrunchproject @@ -1,7 +1,7 @@  - TargetFramework = net8.0-android34.0 + TargetFramework = net10.0-android36.0 True diff --git a/.ncrunch/Avalonia.Base.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Base.UnitTests.v3.ncrunchproject index 1733492c89..0bcc569d05 100644 --- a/.ncrunch/Avalonia.Base.UnitTests.v3.ncrunchproject +++ b/.ncrunch/Avalonia.Base.UnitTests.v3.ncrunchproject @@ -1,7 +1,5 @@  - - TargetFramework = net8.0 - + False \ No newline at end of file diff --git a/.ncrunch/Avalonia.Base.v3.ncrunchproject b/.ncrunch/Avalonia.Base.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Base.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Benchmarks.v3.ncrunchproject b/.ncrunch/Avalonia.Benchmarks.v3.ncrunchproject deleted file mode 100644 index 3b82c33f1c..0000000000 --- a/.ncrunch/Avalonia.Benchmarks.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0 - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Browser.Blazor.v3.ncrunchproject b/.ncrunch/Avalonia.Browser.Blazor.v3.ncrunchproject deleted file mode 100644 index 7e6955b244..0000000000 --- a/.ncrunch/Avalonia.Browser.Blazor.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0-browser - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Browser.v3.ncrunchproject b/.ncrunch/Avalonia.Browser.v3.ncrunchproject deleted file mode 100644 index 7e6955b244..0000000000 --- a/.ncrunch/Avalonia.Browser.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0-browser - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Build.Tasks.UnitTest.v3.ncrunchproject b/.ncrunch/Avalonia.Build.Tasks.UnitTest.v3.ncrunchproject deleted file mode 100644 index f144353670..0000000000 --- a/.ncrunch/Avalonia.Build.Tasks.UnitTest.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net472 - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Build.Tasks.v3.ncrunchproject b/.ncrunch/Avalonia.Build.Tasks.v3.ncrunchproject index a079eefacf..08b7dfa6ee 100644 --- a/.ncrunch/Avalonia.Build.Tasks.v3.ncrunchproject +++ b/.ncrunch/Avalonia.Build.Tasks.v3.ncrunchproject @@ -3,5 +3,6 @@ TargetFramework = netstandard2.0 + False \ No newline at end of file diff --git a/.ncrunch/Avalonia.Controls.DataGrid.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Controls.DataGrid.UnitTests.v3.ncrunchproject deleted file mode 100644 index 1733492c89..0000000000 --- a/.ncrunch/Avalonia.Controls.DataGrid.UnitTests.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - TargetFramework = net8.0 - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Controls.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Controls.UnitTests.v3.ncrunchproject index 1733492c89..0bcc569d05 100644 --- a/.ncrunch/Avalonia.Controls.UnitTests.v3.ncrunchproject +++ b/.ncrunch/Avalonia.Controls.UnitTests.v3.ncrunchproject @@ -1,7 +1,5 @@  - - TargetFramework = net8.0 - + False \ No newline at end of file diff --git a/.ncrunch/Avalonia.Controls.v3.ncrunchproject b/.ncrunch/Avalonia.Controls.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Controls.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject b/.ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject deleted file mode 100644 index 3b82c33f1c..0000000000 --- a/.ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0 - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.DesignerSupport.TestApp.v3.ncrunchproject b/.ncrunch/Avalonia.DesignerSupport.TestApp.v3.ncrunchproject deleted file mode 100644 index 1733492c89..0000000000 --- a/.ncrunch/Avalonia.DesignerSupport.TestApp.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - TargetFramework = net8.0 - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.DesignerSupport.Tests.v3.ncrunchproject b/.ncrunch/Avalonia.DesignerSupport.Tests.v3.ncrunchproject deleted file mode 100644 index 3b82c33f1c..0000000000 --- a/.ncrunch/Avalonia.DesignerSupport.Tests.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0 - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.DesignerSupport.v3.ncrunchproject b/.ncrunch/Avalonia.DesignerSupport.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.DesignerSupport.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Desktop.v3.ncrunchproject b/.ncrunch/Avalonia.Desktop.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Desktop.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.AndroidTestApplication.v3.ncrunchproject b/.ncrunch/Avalonia.Diagnostics.net6.0.v3.ncrunchproject similarity index 100% rename from .ncrunch/Avalonia.AndroidTestApplication.v3.ncrunchproject rename to .ncrunch/Avalonia.Diagnostics.net6.0.v3.ncrunchproject diff --git a/.ncrunch/Avalonia.Desktop.net6.0.v3.ncrunchproject b/.ncrunch/Avalonia.Diagnostics.net8.0.v3.ncrunchproject similarity index 100% rename from .ncrunch/Avalonia.Desktop.net6.0.v3.ncrunchproject rename to .ncrunch/Avalonia.Diagnostics.net8.0.v3.ncrunchproject diff --git a/.ncrunch/Avalonia.Desktop.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.Diagnostics.netstandard2.0.v3.ncrunchproject similarity index 100% rename from .ncrunch/Avalonia.Desktop.netstandard2.0.v3.ncrunchproject rename to .ncrunch/Avalonia.Diagnostics.netstandard2.0.v3.ncrunchproject diff --git a/.ncrunch/Avalonia.Dialogs.v3.ncrunchproject b/.ncrunch/Avalonia.Dialogs.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Dialogs.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject b/.ncrunch/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject deleted file mode 100644 index 1733492c89..0000000000 --- a/.ncrunch/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - TargetFramework = net8.0 - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Direct2D1.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Direct2D1.UnitTests.v3.ncrunchproject deleted file mode 100644 index 1733492c89..0000000000 --- a/.ncrunch/Avalonia.Direct2D1.UnitTests.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - TargetFramework = net8.0 - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Fonts.Inter.v3.ncrunchproject b/.ncrunch/Avalonia.Fonts.Inter.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Fonts.Inter.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.FreeDesktop.v3.ncrunchproject b/.ncrunch/Avalonia.FreeDesktop.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.FreeDesktop.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Generators.Tests.v3.ncrunchproject b/.ncrunch/Avalonia.Generators.Tests.v3.ncrunchproject deleted file mode 100644 index 3b82c33f1c..0000000000 --- a/.ncrunch/Avalonia.Generators.Tests.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0 - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Generators.v3.ncrunchproject b/.ncrunch/Avalonia.Generators.v3.ncrunchproject index a079eefacf..08b7dfa6ee 100644 --- a/.ncrunch/Avalonia.Generators.v3.ncrunchproject +++ b/.ncrunch/Avalonia.Generators.v3.ncrunchproject @@ -3,5 +3,6 @@ TargetFramework = netstandard2.0 + False \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.NUnit.PerAssembly.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Headless.NUnit.PerAssembly.UnitTests.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Headless.NUnit.PerAssembly.UnitTests.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.NUnit.PerTest.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Headless.NUnit.PerTest.UnitTests.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Headless.NUnit.PerTest.UnitTests.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.NUnit.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Headless.NUnit.UnitTests.v3.ncrunchproject deleted file mode 100644 index 1733492c89..0000000000 --- a/.ncrunch/Avalonia.Headless.NUnit.UnitTests.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - TargetFramework = net8.0 - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.NUnit.v3.ncrunchproject b/.ncrunch/Avalonia.Headless.NUnit.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Headless.NUnit.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.Vnc.v3.ncrunchproject b/.ncrunch/Avalonia.Headless.Vnc.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Headless.Vnc.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.XUnit.PerAssembly.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Headless.XUnit.PerAssembly.UnitTests.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Headless.XUnit.PerAssembly.UnitTests.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.XUnit.PerTest.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Headless.XUnit.PerTest.UnitTests.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Headless.XUnit.PerTest.UnitTests.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.XUnit.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Headless.XUnit.UnitTests.v3.ncrunchproject deleted file mode 100644 index 1733492c89..0000000000 --- a/.ncrunch/Avalonia.Headless.XUnit.UnitTests.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - TargetFramework = net8.0 - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.XUnit.v3.ncrunchproject b/.ncrunch/Avalonia.Headless.XUnit.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Headless.XUnit.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.v3.ncrunchproject b/.ncrunch/Avalonia.Headless.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Headless.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.IntegrationTests.Appium.v3.ncrunchproject b/.ncrunch/Avalonia.IntegrationTests.Appium.v3.ncrunchproject deleted file mode 100644 index 3b82c33f1c..0000000000 --- a/.ncrunch/Avalonia.IntegrationTests.Appium.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0 - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.IntegrationTests.Win32.v3.ncrunchproject b/.ncrunch/Avalonia.IntegrationTests.Win32.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/Avalonia.IntegrationTests.Win32.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.LeakTests.v3.ncrunchproject b/.ncrunch/Avalonia.LeakTests.v3.ncrunchproject deleted file mode 100644 index 18f2aee75c..0000000000 --- a/.ncrunch/Avalonia.LeakTests.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - TargetFramework = net462 - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Markup.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Markup.UnitTests.v3.ncrunchproject index 1733492c89..0bcc569d05 100644 --- a/.ncrunch/Avalonia.Markup.UnitTests.v3.ncrunchproject +++ b/.ncrunch/Avalonia.Markup.UnitTests.v3.ncrunchproject @@ -1,7 +1,5 @@  - - TargetFramework = net8.0 - + False \ No newline at end of file diff --git a/.ncrunch/Avalonia.Markup.Xaml.Loader.v3.ncrunchproject b/.ncrunch/Avalonia.Markup.Xaml.Loader.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Markup.Xaml.Loader.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Markup.Xaml.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Markup.Xaml.UnitTests.v3.ncrunchproject index 1733492c89..0bcc569d05 100644 --- a/.ncrunch/Avalonia.Markup.Xaml.UnitTests.v3.ncrunchproject +++ b/.ncrunch/Avalonia.Markup.Xaml.UnitTests.v3.ncrunchproject @@ -1,7 +1,5 @@  - - TargetFramework = net8.0 - + False \ No newline at end of file diff --git a/.ncrunch/Avalonia.Markup.Xaml.v3.ncrunchproject b/.ncrunch/Avalonia.Markup.Xaml.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Markup.Xaml.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Markup.v3.ncrunchproject b/.ncrunch/Avalonia.Markup.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Markup.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Metal.v3.ncrunchproject b/.ncrunch/Avalonia.Metal.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Metal.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.MicroCom.v3.ncrunchproject b/.ncrunch/Avalonia.MicroCom.v3.ncrunchproject index a079eefacf..0bcc569d05 100644 --- a/.ncrunch/Avalonia.MicroCom.v3.ncrunchproject +++ b/.ncrunch/Avalonia.MicroCom.v3.ncrunchproject @@ -1,7 +1,5 @@  - - TargetFramework = netstandard2.0 - + False \ No newline at end of file diff --git a/.ncrunch/Avalonia.Native.net6.0.v3.ncrunchproject b/.ncrunch/Avalonia.Native.net6.0.v3.ncrunchproject deleted file mode 100644 index e8de009693..0000000000 --- a/.ncrunch/Avalonia.Native.net6.0.v3.ncrunchproject +++ /dev/null @@ -1,6 +0,0 @@ - - - True - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Native.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.Native.netstandard2.0.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/Avalonia.Native.netstandard2.0.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Native.v3.ncrunchproject b/.ncrunch/Avalonia.Native.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Native.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.OpenGL.v3.ncrunchproject b/.ncrunch/Avalonia.OpenGL.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.OpenGL.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.ReactiveUI.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.ReactiveUI.UnitTests.v3.ncrunchproject deleted file mode 100644 index 1733492c89..0000000000 --- a/.ncrunch/Avalonia.ReactiveUI.UnitTests.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - TargetFramework = net8.0 - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Remote.Protocol.v3.ncrunchproject b/.ncrunch/Avalonia.Remote.Protocol.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Remote.Protocol.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.RenderTests.WpfCompare.v3.ncrunchproject b/.ncrunch/Avalonia.RenderTests.WpfCompare.v3.ncrunchproject deleted file mode 100644 index 96fdff3555..0000000000 --- a/.ncrunch/Avalonia.RenderTests.WpfCompare.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - TargetFramework = net8.0-windows - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject b/.ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject index 1733492c89..0bcc569d05 100644 --- a/.ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject +++ b/.ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject @@ -1,7 +1,5 @@  - - TargetFramework = net8.0 - + False \ No newline at end of file diff --git a/.ncrunch/Avalonia.Skia.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Skia.UnitTests.v3.ncrunchproject index 1733492c89..0bcc569d05 100644 --- a/.ncrunch/Avalonia.Skia.UnitTests.v3.ncrunchproject +++ b/.ncrunch/Avalonia.Skia.UnitTests.v3.ncrunchproject @@ -1,7 +1,5 @@  - - TargetFramework = net8.0 - + False \ No newline at end of file diff --git a/.ncrunch/Avalonia.Skia.v3.ncrunchproject b/.ncrunch/Avalonia.Skia.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Skia.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Themes.Fluent.net6.0.v3.ncrunchproject b/.ncrunch/Avalonia.Themes.Fluent.net6.0.v3.ncrunchproject deleted file mode 100644 index 02eb0d211e..0000000000 --- a/.ncrunch/Avalonia.Themes.Fluent.net6.0.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - False - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Themes.Fluent.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.Themes.Fluent.netstandard2.0.v3.ncrunchproject deleted file mode 100644 index 02eb0d211e..0000000000 --- a/.ncrunch/Avalonia.Themes.Fluent.netstandard2.0.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - False - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Themes.Fluent.v3.ncrunchproject b/.ncrunch/Avalonia.Themes.Fluent.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Themes.Fluent.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Themes.Simple.net8.0.v3.ncrunchproject b/.ncrunch/Avalonia.Themes.Simple.net8.0.v3.ncrunchproject deleted file mode 100644 index bc1af9a143..0000000000 --- a/.ncrunch/Avalonia.Themes.Simple.net8.0.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - ..\Avalonia.Themes.Fluent\Strings\InvariantResources.xaml - - False - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject deleted file mode 100644 index bc1af9a143..0000000000 --- a/.ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - ..\Avalonia.Themes.Fluent\Strings\InvariantResources.xaml - - False - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Themes.Simple.v3.ncrunchproject b/.ncrunch/Avalonia.Themes.Simple.v3.ncrunchproject new file mode 100644 index 0000000000..cf2b7e5426 --- /dev/null +++ b/.ncrunch/Avalonia.Themes.Simple.v3.ncrunchproject @@ -0,0 +1,8 @@ + + + False + + ..\Avalonia.Themes.Fluent\Strings\InvariantResources.xaml + + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Tizen.v3.ncrunchproject b/.ncrunch/Avalonia.Tizen.v3.ncrunchproject deleted file mode 100644 index d2c880c578..0000000000 --- a/.ncrunch/Avalonia.Tizen.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0-tizen - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.UnitTests.v3.ncrunchproject index 7a4ea98049..0bcc569d05 100644 --- a/.ncrunch/Avalonia.UnitTests.v3.ncrunchproject +++ b/.ncrunch/Avalonia.UnitTests.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = netstandard2.0 - - False + False \ No newline at end of file diff --git a/.ncrunch/Avalonia.Vulkan.v3.ncrunchproject b/.ncrunch/Avalonia.Vulkan.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Vulkan.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Win32.Automation.v3.ncrunchproject b/.ncrunch/Avalonia.Win32.Automation.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Win32.Automation.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Win32.Interoperability.v3.ncrunchproject b/.ncrunch/Avalonia.Win32.Interoperability.v3.ncrunchproject deleted file mode 100644 index 96fdff3555..0000000000 --- a/.ncrunch/Avalonia.Win32.Interoperability.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - TargetFramework = net8.0-windows - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Win32.net6.0.v3.ncrunchproject b/.ncrunch/Avalonia.Win32.net6.0.v3.ncrunchproject deleted file mode 100644 index 95a483b433..0000000000 --- a/.ncrunch/Avalonia.Win32.net6.0.v3.ncrunchproject +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Win32.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.Win32.netstandard2.0.v3.ncrunchproject deleted file mode 100644 index 95a483b433..0000000000 --- a/.ncrunch/Avalonia.Win32.netstandard2.0.v3.ncrunchproject +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Win32.v3.ncrunchproject b/.ncrunch/Avalonia.Win32.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.Win32.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.X11.net6.0.v3.ncrunchproject b/.ncrunch/Avalonia.X11.net6.0.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/Avalonia.X11.net6.0.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.X11.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.X11.netstandard2.0.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/Avalonia.X11.netstandard2.0.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.X11.v3.ncrunchproject b/.ncrunch/Avalonia.X11.v3.ncrunchproject new file mode 100644 index 0000000000..0bcc569d05 --- /dev/null +++ b/.ncrunch/Avalonia.X11.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + False + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.iOS.v3.ncrunchproject b/.ncrunch/Avalonia.iOS.v3.ncrunchproject deleted file mode 100644 index 00c1cea8f4..0000000000 --- a/.ncrunch/Avalonia.iOS.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = netstandard2.0 - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.net461.v3.ncrunchproject b/.ncrunch/Avalonia.net461.v3.ncrunchproject deleted file mode 100644 index 4fdcd169ae..0000000000 --- a/.ncrunch/Avalonia.net461.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - DerivedFilesIncludedInWorkspace - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.net6.0.v3.ncrunchproject b/.ncrunch/Avalonia.net6.0.v3.ncrunchproject deleted file mode 100644 index 4fdcd169ae..0000000000 --- a/.ncrunch/Avalonia.net6.0.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - DerivedFilesIncludedInWorkspace - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.net8.0.v3.ncrunchproject b/.ncrunch/Avalonia.net8.0.v3.ncrunchproject deleted file mode 100644 index 4fdcd169ae..0000000000 --- a/.ncrunch/Avalonia.net8.0.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - DerivedFilesIncludedInWorkspace - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.netcoreapp2.0.v3.ncrunchproject b/.ncrunch/Avalonia.netcoreapp2.0.v3.ncrunchproject deleted file mode 100644 index 4fdcd169ae..0000000000 --- a/.ncrunch/Avalonia.netcoreapp2.0.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - DerivedFilesIncludedInWorkspace - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.netstandard2.0.v3.ncrunchproject deleted file mode 100644 index 4fdcd169ae..0000000000 --- a/.ncrunch/Avalonia.netstandard2.0.v3.ncrunchproject +++ /dev/null @@ -1,7 +0,0 @@ - - - - DerivedFilesIncludedInWorkspace - - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.v3.ncrunchproject b/.ncrunch/Avalonia.v3.ncrunchproject new file mode 100644 index 0000000000..b12ed97abf --- /dev/null +++ b/.ncrunch/Avalonia.v3.ncrunchproject @@ -0,0 +1,8 @@ + + + + DerivedFilesIncludedInWorkspace + + False + + \ No newline at end of file diff --git a/.ncrunch/BindingDemo.v3.ncrunchproject b/.ncrunch/BindingDemo.v3.ncrunchproject index 3b82c33f1c..319cd523ce 100644 --- a/.ncrunch/BindingDemo.v3.ncrunchproject +++ b/.ncrunch/BindingDemo.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0 - True \ No newline at end of file diff --git a/.ncrunch/ControlCatalog.Android.v3.ncrunchproject b/.ncrunch/ControlCatalog.Android.v3.ncrunchproject index 1335822600..319cd523ce 100644 --- a/.ncrunch/ControlCatalog.Android.v3.ncrunchproject +++ b/.ncrunch/ControlCatalog.Android.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0-android34.0 - True \ No newline at end of file diff --git a/.ncrunch/ControlCatalog.Browser.Blazor.v3.ncrunchproject b/.ncrunch/ControlCatalog.Browser.Blazor.v3.ncrunchproject deleted file mode 100644 index 7e6955b244..0000000000 --- a/.ncrunch/ControlCatalog.Browser.Blazor.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0-browser - - True - - \ No newline at end of file diff --git a/.ncrunch/ControlCatalog.Browser.v3.ncrunchproject b/.ncrunch/ControlCatalog.Browser.v3.ncrunchproject index 7e6955b244..319cd523ce 100644 --- a/.ncrunch/ControlCatalog.Browser.v3.ncrunchproject +++ b/.ncrunch/ControlCatalog.Browser.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0-browser - True \ No newline at end of file diff --git a/.ncrunch/ControlCatalog.Desktop.v3.ncrunchproject b/.ncrunch/ControlCatalog.Desktop.v3.ncrunchproject index ea3a821a00..319cd523ce 100644 --- a/.ncrunch/ControlCatalog.Desktop.v3.ncrunchproject +++ b/.ncrunch/ControlCatalog.Desktop.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net461 - True \ No newline at end of file diff --git a/.ncrunch/Avalonia.FreeDesktop.net6.0.v3.ncrunchproject b/.ncrunch/ControlCatalog.MacCatalyst.v3.ncrunchproject similarity index 100% rename from .ncrunch/Avalonia.FreeDesktop.net6.0.v3.ncrunchproject rename to .ncrunch/ControlCatalog.MacCatalyst.v3.ncrunchproject diff --git a/.ncrunch/ControlCatalog.NetCore.v3.ncrunchproject b/.ncrunch/ControlCatalog.NetCore.v3.ncrunchproject deleted file mode 100644 index 3b82c33f1c..0000000000 --- a/.ncrunch/ControlCatalog.NetCore.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0 - - True - - \ No newline at end of file diff --git a/.ncrunch/ControlCatalog.Tizen.v3.ncrunchproject b/.ncrunch/ControlCatalog.Tizen.v3.ncrunchproject deleted file mode 100644 index d2c880c578..0000000000 --- a/.ncrunch/ControlCatalog.Tizen.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0-tizen - - True - - \ No newline at end of file diff --git a/.ncrunch/ControlCatalog.iOS.v3.ncrunchproject b/.ncrunch/ControlCatalog.iOS.v3.ncrunchproject index 6ae5567f23..319cd523ce 100644 --- a/.ncrunch/ControlCatalog.iOS.v3.ncrunchproject +++ b/.ncrunch/ControlCatalog.iOS.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0-ios17.0 - True \ No newline at end of file diff --git a/.ncrunch/ControlCatalog.net8.0.v3.ncrunchproject b/.ncrunch/ControlCatalog.net8.0.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/ControlCatalog.net8.0.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/ControlCatalog.netstandard2.0.v3.ncrunchproject b/.ncrunch/ControlCatalog.netstandard2.0.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/ControlCatalog.netstandard2.0.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.FreeDesktop.netstandard2.0.v3.ncrunchproject b/.ncrunch/ControlCatalog.tvOS.v3.ncrunchproject similarity index 100% rename from .ncrunch/Avalonia.FreeDesktop.netstandard2.0.v3.ncrunchproject rename to .ncrunch/ControlCatalog.tvOS.v3.ncrunchproject diff --git a/.ncrunch/ControlSamples.v3.ncrunchproject b/.ncrunch/ControlSamples.v3.ncrunchproject index 00c1cea8f4..319cd523ce 100644 --- a/.ncrunch/ControlSamples.v3.ncrunchproject +++ b/.ncrunch/ControlSamples.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = netstandard2.0 - True \ No newline at end of file diff --git a/.ncrunch/DevAnalyzers.v3.ncrunchproject b/.ncrunch/DevAnalyzers.v3.ncrunchproject index a079eefacf..08b7dfa6ee 100644 --- a/.ncrunch/DevAnalyzers.v3.ncrunchproject +++ b/.ncrunch/DevAnalyzers.v3.ncrunchproject @@ -3,5 +3,6 @@ TargetFramework = netstandard2.0 + False \ No newline at end of file diff --git a/.ncrunch/DevGenerators.v3.ncrunchproject b/.ncrunch/DevGenerators.v3.ncrunchproject index a079eefacf..08b7dfa6ee 100644 --- a/.ncrunch/DevGenerators.v3.ncrunchproject +++ b/.ncrunch/DevGenerators.v3.ncrunchproject @@ -3,5 +3,6 @@ TargetFramework = netstandard2.0 + False \ No newline at end of file diff --git a/.ncrunch/Direct3DInteropSample.v3.ncrunchproject b/.ncrunch/Direct3DInteropSample.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/Direct3DInteropSample.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/Generators.Sandbox.v3.ncrunchproject b/.ncrunch/Generators.Sandbox.v3.ncrunchproject deleted file mode 100644 index 3b82c33f1c..0000000000 --- a/.ncrunch/Generators.Sandbox.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0 - - True - - \ No newline at end of file diff --git a/.ncrunch/GpuInterop.v3.ncrunchproject b/.ncrunch/GpuInterop.v3.ncrunchproject index 3b82c33f1c..319cd523ce 100644 --- a/.ncrunch/GpuInterop.v3.ncrunchproject +++ b/.ncrunch/GpuInterop.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0 - True \ No newline at end of file diff --git a/.ncrunch/IntegrationTestApp.v3.ncrunchproject b/.ncrunch/IntegrationTestApp.v3.ncrunchproject index 3b82c33f1c..319cd523ce 100644 --- a/.ncrunch/IntegrationTestApp.v3.ncrunchproject +++ b/.ncrunch/IntegrationTestApp.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0 - True \ No newline at end of file diff --git a/.ncrunch/MiniMvvm.v3.ncrunchproject b/.ncrunch/MiniMvvm.v3.ncrunchproject deleted file mode 100644 index 00c1cea8f4..0000000000 --- a/.ncrunch/MiniMvvm.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = netstandard2.0 - - True - - \ No newline at end of file diff --git a/.ncrunch/MobileSandbox.Android.v3.ncrunchproject b/.ncrunch/MobileSandbox.Android.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/MobileSandbox.Android.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/MobileSandbox.Browser.v3.ncrunchproject b/.ncrunch/MobileSandbox.Browser.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/MobileSandbox.Browser.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/MobileSandbox.Desktop.v3.ncrunchproject b/.ncrunch/MobileSandbox.Desktop.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/MobileSandbox.Desktop.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/MobileSandbox.iOS.v3.ncrunchproject b/.ncrunch/MobileSandbox.iOS.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/MobileSandbox.iOS.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/MobileSandbox.net6.0.v3.ncrunchproject b/.ncrunch/MobileSandbox.net6.0.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/MobileSandbox.net6.0.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/MobileSandbox.netstandard2.0.v3.ncrunchproject b/.ncrunch/MobileSandbox.netstandard2.0.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/MobileSandbox.netstandard2.0.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/MobileSandbox.v3.ncrunchproject b/.ncrunch/MobileSandbox.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/MobileSandbox.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/NativeEmbedSample.v3.ncrunchproject b/.ncrunch/NativeEmbedSample.v3.ncrunchproject deleted file mode 100644 index 319cd523ce..0000000000 --- a/.ncrunch/NativeEmbedSample.v3.ncrunchproject +++ /dev/null @@ -1,5 +0,0 @@ - - - True - - \ No newline at end of file diff --git a/.ncrunch/PInvoke.v3.ncrunchproject b/.ncrunch/PInvoke.v3.ncrunchproject index 00c1cea8f4..95a483b433 100644 --- a/.ncrunch/PInvoke.v3.ncrunchproject +++ b/.ncrunch/PInvoke.v3.ncrunchproject @@ -1,8 +1,3 @@  - - - TargetFramework = netstandard2.0 - - True - + \ No newline at end of file diff --git a/.ncrunch/PlatformSanityChecks.v3.ncrunchproject b/.ncrunch/PlatformSanityChecks.v3.ncrunchproject index 3b82c33f1c..319cd523ce 100644 --- a/.ncrunch/PlatformSanityChecks.v3.ncrunchproject +++ b/.ncrunch/PlatformSanityChecks.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0 - True \ No newline at end of file diff --git a/.ncrunch/Previewer.v3.ncrunchproject b/.ncrunch/Previewer.v3.ncrunchproject index 3b82c33f1c..319cd523ce 100644 --- a/.ncrunch/Previewer.v3.ncrunchproject +++ b/.ncrunch/Previewer.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0 - True \ No newline at end of file diff --git a/.ncrunch/ReactiveUIDemo.v3.ncrunchproject b/.ncrunch/ReactiveUIDemo.v3.ncrunchproject deleted file mode 100644 index 3b82c33f1c..0000000000 --- a/.ncrunch/ReactiveUIDemo.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0 - - True - - \ No newline at end of file diff --git a/.ncrunch/RemoteDemo.v3.ncrunchproject b/.ncrunch/RemoteDemo.v3.ncrunchproject index 3b82c33f1c..319cd523ce 100644 --- a/.ncrunch/RemoteDemo.v3.ncrunchproject +++ b/.ncrunch/RemoteDemo.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0 - True \ No newline at end of file diff --git a/.ncrunch/RenderDemo.v3.ncrunchproject b/.ncrunch/RenderDemo.v3.ncrunchproject index 3b82c33f1c..319cd523ce 100644 --- a/.ncrunch/RenderDemo.v3.ncrunchproject +++ b/.ncrunch/RenderDemo.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0 - True \ No newline at end of file diff --git a/.ncrunch/SafeAreaDemo.Android.v3.ncrunchproject b/.ncrunch/SafeAreaDemo.Android.v3.ncrunchproject index 1335822600..319cd523ce 100644 --- a/.ncrunch/SafeAreaDemo.Android.v3.ncrunchproject +++ b/.ncrunch/SafeAreaDemo.Android.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0-android34.0 - True \ No newline at end of file diff --git a/.ncrunch/SafeAreaDemo.Desktop.v3.ncrunchproject b/.ncrunch/SafeAreaDemo.Desktop.v3.ncrunchproject index 3b82c33f1c..319cd523ce 100644 --- a/.ncrunch/SafeAreaDemo.Desktop.v3.ncrunchproject +++ b/.ncrunch/SafeAreaDemo.Desktop.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0 - True \ No newline at end of file diff --git a/.ncrunch/SafeAreaDemo.iOS.v3.ncrunchproject b/.ncrunch/SafeAreaDemo.iOS.v3.ncrunchproject index 6ae5567f23..319cd523ce 100644 --- a/.ncrunch/SafeAreaDemo.iOS.v3.ncrunchproject +++ b/.ncrunch/SafeAreaDemo.iOS.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0-ios17.0 - True \ No newline at end of file diff --git a/.ncrunch/SafeAreaDemo.v3.ncrunchproject b/.ncrunch/SafeAreaDemo.v3.ncrunchproject index 3b82c33f1c..319cd523ce 100644 --- a/.ncrunch/SafeAreaDemo.v3.ncrunchproject +++ b/.ncrunch/SafeAreaDemo.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0 - True \ No newline at end of file diff --git a/.ncrunch/Sandbox.v3.ncrunchproject b/.ncrunch/Sandbox.v3.ncrunchproject index 3b82c33f1c..319cd523ce 100644 --- a/.ncrunch/Sandbox.v3.ncrunchproject +++ b/.ncrunch/Sandbox.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0 - True \ No newline at end of file diff --git a/.ncrunch/SingleProjectSandbox.v3.ncrunchproject b/.ncrunch/SingleProjectSandbox.v3.ncrunchproject deleted file mode 100644 index 3b82c33f1c..0000000000 --- a/.ncrunch/SingleProjectSandbox.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net8.0 - - True - - \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.NUnit.netstandard2.0.v3.ncrunchproject b/.ncrunch/TextTestApp.v3.ncrunchproject similarity index 100% rename from .ncrunch/Avalonia.Headless.NUnit.netstandard2.0.v3.ncrunchproject rename to .ncrunch/TextTestApp.v3.ncrunchproject diff --git a/.ncrunch/UnloadableAssemblyLoadContext.v3.ncrunchproject b/.ncrunch/UnloadableAssemblyLoadContext.v3.ncrunchproject deleted file mode 100644 index f074de260d..0000000000 --- a/.ncrunch/UnloadableAssemblyLoadContext.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net7.0 - - True - - \ No newline at end of file diff --git a/.ncrunch/UnloadableAssemblyLoadContextPlug.v3.ncrunchproject b/.ncrunch/UnloadableAssemblyLoadContextPlug.v3.ncrunchproject deleted file mode 100644 index f074de260d..0000000000 --- a/.ncrunch/UnloadableAssemblyLoadContextPlug.v3.ncrunchproject +++ /dev/null @@ -1,8 +0,0 @@ - - - - TargetFramework = net7.0 - - True - - \ No newline at end of file diff --git a/.ncrunch/VirtualizationDemo.v3.ncrunchproject b/.ncrunch/VirtualizationDemo.v3.ncrunchproject index 3b82c33f1c..319cd523ce 100644 --- a/.ncrunch/VirtualizationDemo.v3.ncrunchproject +++ b/.ncrunch/VirtualizationDemo.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0 - True \ No newline at end of file diff --git a/.ncrunch/WindowsInteropTest.v3.ncrunchproject b/.ncrunch/WindowsInteropTest.v3.ncrunchproject index 484445df0e..319cd523ce 100644 --- a/.ncrunch/WindowsInteropTest.v3.ncrunchproject +++ b/.ncrunch/WindowsInteropTest.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0-windows - True \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.XUnit.netstandard2.0.v3.ncrunchproject b/.ncrunch/XEmbedSample.v3.ncrunchproject similarity index 100% rename from .ncrunch/Avalonia.Headless.XUnit.netstandard2.0.v3.ncrunchproject rename to .ncrunch/XEmbedSample.v3.ncrunchproject diff --git a/.ncrunch/_build.v3.ncrunchproject b/.ncrunch/_build.v3.ncrunchproject index 3b82c33f1c..319cd523ce 100644 --- a/.ncrunch/_build.v3.ncrunchproject +++ b/.ncrunch/_build.v3.ncrunchproject @@ -1,8 +1,5 @@  - - TargetFramework = net8.0 - True \ No newline at end of file diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index f833ddd89a..e91aa1433c 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", + "CompileNative", + "CreateIntermediateNugetPackages", + "CreateNugetPackages", + "DownloadApiBaselinePackages", + "GenerateCppHeaders", + "InitDnx", + "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,87 +101,51 @@ "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", - "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", - "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-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 799e920441..ebf70fc8b7 100644 --- a/Avalonia.Desktop.slnf +++ b/Avalonia.Desktop.slnf @@ -1,24 +1,24 @@ -{ +{ "solution": { "path": "Avalonia.sln", "projects": [ "packages\\Avalonia\\Avalonia.csproj", "samples\\AppWithoutLifetime\\AppWithoutLifetime.csproj", - "samples\\ControlCatalog.NetCore\\ControlCatalog.NetCore.csproj", + "samples\\ControlCatalog.Desktop\\ControlCatalog.Desktop.csproj", "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", "samples\\UnloadableAssemblyLoadContext\\UnloadableAssemblyLoadContextPlug\\UnloadableAssemblyLoadContextPlug.csproj", "samples\\UnloadableAssemblyLoadContext\\UnloadableAssemblyLoadContext\\UnloadableAssemblyLoadContext.csproj", + "samples\\XEmbedSample\\XEmbedSample.csproj", "src\\Avalonia.Base\\Avalonia.Base.csproj", "src\\Avalonia.Build.Tasks\\Avalonia.Build.Tasks.csproj", "src\\Avalonia.Controls.ColorPicker\\Avalonia.Controls.ColorPicker.csproj", - "src\\Avalonia.Controls.DataGrid\\Avalonia.Controls.DataGrid.csproj", "src\\Avalonia.Controls\\Avalonia.Controls.csproj", "src\\Avalonia.DesignerSupport\\Avalonia.DesignerSupport.csproj", "src\\Avalonia.Desktop\\Avalonia.Desktop.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", @@ -43,28 +42,26 @@ "src\\Markup\\Avalonia.Markup.Xaml\\Avalonia.Markup.Xaml.csproj", "src\\Markup\\Avalonia.Markup\\Avalonia.Markup.csproj", "src\\Skia\\Avalonia.Skia\\Avalonia.Skia.csproj", - "src\\tools\\Avalonia.Analyzers\\Avalonia.Analyzers.csproj", + "src\\tools\\Avalonia.Analyzers.CodeFixes.CSharp\\Avalonia.Analyzers.CodeFixes.CSharp.csproj", + "src\\tools\\Avalonia.Analyzers.CSharp\\Avalonia.Analyzers.CSharp.csproj", + "src\\tools\\Avalonia.Analyzers.VisualBasic\\Avalonia.Analyzers.VisualBasic.csproj", "src\\tools\\Avalonia.Generators\\Avalonia.Generators.csproj", "src\\tools\\DevAnalyzers\\DevAnalyzers.csproj", "src\\tools\\DevGenerators\\DevGenerators.csproj", - "src\\Windows\\Avalonia.Direct2D1\\Avalonia.Direct2D1.csproj", + "src\\Windows\\Avalonia.Win32.Automation\\Avalonia.Win32.Automation.csproj", "src\\Windows\\Avalonia.Win32.Interoperability\\Avalonia.Win32.Interoperability.csproj", "src\\Windows\\Avalonia.Win32\\Avalonia.Win32.csproj", "tests\\Avalonia.Base.UnitTests\\Avalonia.Base.UnitTests.csproj", "tests\\Avalonia.Benchmarks\\Avalonia.Benchmarks.csproj", "tests\\Avalonia.Build.Tasks.UnitTest\\Avalonia.Build.Tasks.UnitTest.csproj", - "tests\\Avalonia.Controls.DataGrid.UnitTests\\Avalonia.Controls.DataGrid.UnitTests.csproj", "tests\\Avalonia.Controls.UnitTests\\Avalonia.Controls.UnitTests.csproj", "tests\\Avalonia.DesignerSupport.TestApp\\Avalonia.DesignerSupport.TestApp.csproj", "tests\\Avalonia.DesignerSupport.Tests\\Avalonia.DesignerSupport.Tests.csproj", - "tests\\Avalonia.Direct2D1.RenderTests\\Avalonia.Direct2D1.RenderTests.csproj", - "tests\\Avalonia.Direct2D1.UnitTests\\Avalonia.Direct2D1.UnitTests.csproj", "tests\\Avalonia.Generators.Tests\\Avalonia.Generators.Tests.csproj", "tests\\Avalonia.IntegrationTests.Appium\\Avalonia.IntegrationTests.Appium.csproj", "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", @@ -72,4 +69,4 @@ "tests\\TestFiles\\BuildTasks\\PInvoke\\PInvoke.csproj" ] } -} \ No newline at end of file +} diff --git a/Avalonia.sln b/Avalonia.sln index c995888350..1083462dcc 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -1,3 +1,4 @@ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 @@ -8,24 +9,16 @@ 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}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Diagnostics", "src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj", "{7062AE20-5DCC-4442-9645-8195BDECE63E}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.UnitTests", "tests\Avalonia.Controls.UnitTests\Avalonia.Controls.UnitTests.csproj", "{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}" 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}" @@ -37,15 +30,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\StreamCompatibilityExtensions.cs = src\Shared\StreamCompatibilityExtensions.cs src\Shared\StringCompatibilityExtensions.cs = src\Shared\StringCompatibilityExtensions.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}" @@ -86,10 +78,9 @@ 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\AnalyzerProject.targets = build\AnalyzerProject.targets build\AvaloniaPublicKey.props = build\AvaloniaPublicKey.props build\Base.props = build\Base.props build\Binding.props = build\Binding.props @@ -98,7 +89,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1 build\EmbedXaml.props = build\EmbedXaml.props build\HarfBuzzSharp.props = build\HarfBuzzSharp.props build\ImageSharp.props = build\ImageSharp.props - build\JetBrains.dotMemoryUnit.props = build\JetBrains.dotMemoryUnit.props build\Microsoft.CSharp.props = build\Microsoft.CSharp.props build\Microsoft.Reactive.Testing.props = build\Microsoft.Reactive.Testing.props build\Moq.props = build\Moq.props @@ -106,16 +96,13 @@ 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 - build\System.Memory.props = build\System.Memory.props build\TargetFrameworks.props = build\TargetFrameworks.props build\TrimmingEnable.props = build\TrimmingEnable.props build\UnitTests.NetFX.props = build\UnitTests.NetFX.props @@ -169,16 +156,10 @@ 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.Controls.DataGrid", "src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj", "{3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}" -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}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.DataGrid.UnitTests", "tests\Avalonia.Controls.DataGrid.UnitTests\Avalonia.Controls.DataGrid.UnitTests.csproj", "{351337F5-D66F-461B-A957-4EF60BDB4BA6}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Fluent", "src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj", "{C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless", "src\Headless\Avalonia.Headless\Avalonia.Headless.csproj", "{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}" @@ -195,6 +176,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}" @@ -217,17 +200,11 @@ 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}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers.CSharp", "src\tools\Avalonia.Analyzers.CSharp\Avalonia.Analyzers.CSharp.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{176582E8-46AF-416A-85C1-13A5C6744497}" ProjectSection(SolutionItems) = preProject @@ -244,7 +221,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution NOTICE.md = NOTICE.md NuGet.Config = NuGet.Config readme.md = readme.md - Settings.StyleCop = Settings.StyleCop EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators", "src\tools\Avalonia.Generators\Avalonia.Generators.csproj", "{DDA28789-C21A-4654-86CE-D01E81F095C5}" @@ -271,16 +247,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("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "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}" @@ -301,6 +267,32 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Vulkan", "src\Aval EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.RenderTests.WpfCompare", "tests\Avalonia.RenderTests.WpfCompare\Avalonia.RenderTests.WpfCompare.csproj", "{9AE1B827-21AC-4063-AB22-C8804B7F931E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32.Automation", "src\Windows\Avalonia.Win32.Automation\Avalonia.Win32.Automation.csproj", "{0097673D-DBCE-476E-82FE-E78A56E58AA2}" +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.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("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HarfBuzz", "HarfBuzz", "{7670D720-6E84-4AFC-8331-A5C399481905}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.HarfBuzz", "src\HarfBuzz\Avalonia.HarfBuzz\Avalonia.HarfBuzz.csproj", "{E2BFA463-6402-4EF8-8945-FD9A10A914D1}" +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}") = "Avalonia.Headless.XUnit.PerTest.UnitTests", "tests\Avalonia.Headless.XUnit.PerTest.UnitTests\Avalonia.Headless.XUnit.PerTest.UnitTests.csproj", "{26918642-829D-4FA2-B60A-BE8D83F4E063}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.IntegrationTests.Win32", "tests\Avalonia.IntegrationTests.Win32\Avalonia.IntegrationTests.Win32.csproj", "{11522B0D-BF31-42D5-8FC5-41E58F319AF9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Analyzers.CodeFixes.CSharp", "src\tools\Avalonia.Analyzers.CodeFixes.CSharp\Avalonia.Analyzers.CodeFixes.CSharp.csproj", "{FDFB9C25-552D-420B-9D4A-DB0BB6472239}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Analyzers.VisualBasic", "src\tools\Avalonia.Analyzers.VisualBasic\Avalonia.Analyzers.VisualBasic.csproj", "{A7644C3B-B843-44F1-9940-560D56CB0936}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -315,10 +307,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 @@ -327,10 +315,6 @@ Global {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|Any CPU.Build.0 = Debug|Any CPU {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.ActiveCfg = Release|Any CPU {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|Any CPU.Build.0 = Release|Any CPU {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.Build.0 = Debug|Any CPU {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -339,14 +323,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 @@ -355,10 +331,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 @@ -425,10 +397,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 @@ -491,14 +459,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 - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.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 @@ -507,10 +467,6 @@ Global {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|Any CPU.Build.0 = Release|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|Any CPU.Build.0 = Release|Any CPU {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Debug|Any CPU.Build.0 = Debug|Any CPU {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -543,6 +499,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 @@ -583,22 +543,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 @@ -655,24 +603,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 @@ -701,17 +631,62 @@ Global {9AE1B827-21AC-4063-AB22-C8804B7F931E}.Debug|Any CPU.Build.0 = Debug|Any CPU {9AE1B827-21AC-4063-AB22-C8804B7F931E}.Release|Any CPU.ActiveCfg = Release|Any CPU {9AE1B827-21AC-4063-AB22-C8804B7F931E}.Release|Any CPU.Build.0 = Release|Any CPU + {0097673D-DBCE-476E-82FE-E78A56E58AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0097673D-DBCE-476E-82FE-E78A56E58AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0097673D-DBCE-476E-82FE-E78A56E58AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0097673D-DBCE-476E-82FE-E78A56E58AA2}.Release|Any CPU.Build.0 = Release|Any CPU + {255614F5-CB64-4ECA-A026-E0B1AF6A2EF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {255614F5-CB64-4ECA-A026-E0B1AF6A2EF4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {255614F5-CB64-4ECA-A026-E0B1AF6A2EF4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {255614F5-CB64-4ECA-A026-E0B1AF6A2EF4}.Release|Any CPU.Build.0 = Release|Any CPU + {DE3C28DD-B602-4750-831D-345102A54CA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DE3C28DD-B602-4750-831D-345102A54CA0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DE3C28DD-B602-4750-831D-345102A54CA0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DE3C28DD-B602-4750-831D-345102A54CA0}.Release|Any CPU.Build.0 = Release|Any CPU + {14342787-B4EF-4076-8C91-BA6C523DE8DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {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 + {E2BFA463-6402-4EF8-8945-FD9A10A914D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2BFA463-6402-4EF8-8945-FD9A10A914D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2BFA463-6402-4EF8-8945-FD9A10A914D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2BFA463-6402-4EF8-8945-FD9A10A914D1}.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 + {11522B0D-BF31-42D5-8FC5-41E58F319AF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11522B0D-BF31-42D5-8FC5-41E58F319AF9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11522B0D-BF31-42D5-8FC5-41E58F319AF9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11522B0D-BF31-42D5-8FC5-41E58F319AF9}.Release|Any CPU.Build.0 = Release|Any CPU + {A7644C3B-B843-44F1-9940-560D56CB0936}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A7644C3B-B843-44F1-9940-560D56CB0936}.Release|Any CPU.Build.0 = Release|Any CPU + {A7644C3B-B843-44F1-9940-560D56CB0936}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {A7644C3B-B843-44F1-9940-560D56CB0936}.Debug|Any CPU.Build.0 = Release|Any CPU + {FDFB9C25-552D-420B-9D4A-DB0BB6472239}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FDFB9C25-552D-420B-9D4A-DB0BB6472239}.Release|Any CPU.Build.0 = Release|Any CPU + {FDFB9C25-552D-420B-9D4A-DB0BB6472239}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {FDFB9C25-552D-420B-9D4A-DB0BB6472239}.Debug|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} @@ -730,7 +705,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} @@ -742,15 +716,14 @@ 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} - {351337F5-D66F-461B-A957-4EF60BDB4BA6} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC} = {FF237916-7150-496B-89ED-6CA3292896E7} {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7} {909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C} {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} @@ -760,10 +733,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} @@ -776,10 +746,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} @@ -788,6 +754,18 @@ Global {D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0} = {9CCA131B-DE95-4D44-8788-C3CAE28574CD} {DA5F1FF9-4259-4C54-B443-85CFA226EE6A} = {9CCA131B-DE95-4D44-8788-C3CAE28574CD} {9AE1B827-21AC-4063-AB22-C8804B7F931E} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {0097673D-DBCE-476E-82FE-E78A56E58AA2} = {B39A8919-9F95-48FE-AD7B-76E08B509888} + {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} + {E2BFA463-6402-4EF8-8945-FD9A10A914D1} = {7670D720-6E84-4AFC-8331-A5C399481905} + {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} + {11522B0D-BF31-42D5-8FC5-41E58F319AF9} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {A7644C3B-B843-44F1-9940-560D56CB0936} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} + {FDFB9C25-552D-420B-9D4A-DB0BB6472239} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} diff --git a/Avalonia.sln.DotSettings b/Avalonia.sln.DotSettings index 061db72168..307393c9ab 100644 --- a/Avalonia.sln.DotSettings +++ b/Avalonia.sln.DotSettings @@ -22,6 +22,7 @@ <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /> + UI <Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="False" Prefix="I" Suffix="" Style="AaBb" /> diff --git a/Avalonia.v3.ncrunchsolution b/Avalonia.v3.ncrunchsolution index 95f316f8cf..4de91979d6 100644 --- a/Avalonia.v3.ncrunchsolution +++ b/Avalonia.v3.ncrunchsolution @@ -10,11 +10,11 @@ True RunApiCompat = false - TargetFrameworks = net8.0;netstandard2.0 + TargetFrameworks = net10.0 False .ncrunch True True - \ No newline at end of file + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index fde2931bf9..51c5c72372 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -25,6 +25,9 @@ community include: and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community +* Respecting that contributors and maintainers have invested significant effort in building this project +* Keeping discussions focused on improving Avalonia and its ecosystem +* When discussing alternatives, doing so with relevant technical context that advances the conversation Examples of unacceptable behavior include: @@ -36,6 +39,9 @@ Examples of unacceptable behavior include: address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting +* Repeated unsolicited promotion, recruitment, or calls to action for external projects, products, or services in Avalonia’s official channels, particularly when it derails technical discussion or continues after redirection +* Using Avalonia’s official channels to organise or coordinate work for unrelated projects rather than collaborating on Avalonia +* Posting promotional content primarily to drive traffic, sales, or contributors, rather than to contribute to the topic at hand ## Enforcement Responsibilities @@ -44,6 +50,8 @@ acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. +Avalonia’s official infrastructure exists to support Avalonia’s development and community. Constructive technical criticism and relevant comparisons are welcome. What is not welcome is repeated promotional activity, recruitment, or organising unrelated projects within Avalonia’s official channels. + Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation @@ -72,6 +80,13 @@ reporter of any incident. Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: +### Specific Guidance: Infrastructure Misuse and Promotion +**Community Impact:** A pattern of using Avalonia’s official channels primarily to promote external projects, products, or services, recruit contributors, or coordinate unrelated work, especially where it derails ongoing technical discussion or continues after a moderator request to stop. + +**Consequence:** Moderators will remove promotional content immediately to keep discussions focused. If the behaviour appears unintentional or isolated, moderators will follow up privately with guidance and redirect to appropriate venues (e.g., AvaloniaCommunity org, personal blogs). Repeated violations after guidance will result in a formal warning and, if continued, restriction from project platforms up to and including a permanent ban. + +*Note: This guidance addresses patterns of disruption and misuse of shared channels. It does not prohibit technical criticism, benchmarks, or mentioning alternatives when relevant and explained with technical context.* + ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed @@ -106,9 +121,7 @@ Violating these terms may lead to a permanent ban. ### 4. Permanent Ban -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. +**Community Impact:** Demonstrating a pattern of violation of community standards, including sustained inappropriate behaviour, harassment of an individual, aggression towards or disparagement of classes of individuals, or persistent misuse of project infrastructure after warnings. **Consequence**: A permanent ban from any sort of public interaction within the community. 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 117c0964d2..4498f87dab 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,10 +4,14 @@ $(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 + true diff --git a/Documentation/build.md b/Documentation/build.md deleted file mode 100644 index 065d2ee960..0000000000 --- a/Documentation/build.md +++ /dev/null @@ -1,126 +0,0 @@ -## Clone the Avalonia repository - -```bash -git clone https://github.com/AvaloniaUI/Avalonia.git -cd Avalonia -git submodule update --init -``` - -## Install the required version of the .NET Core SDK - -Go to https://dotnet.microsoft.com/en-us/download/visual-studio-sdks and install the latest version of the .NET SDK compatible with Avalonia UI. Make sure to download the SDK (not just the "runtime") package. The version compatible is indicated within the [global.json](https://github.com/AvaloniaUI/Avalonia/blob/master/global.json) file. Note that Avalonia UI does not always use the latest version and is hardcoded to use the last version known to be compatible (SDK releases may break the builds from time-to-time). - -### Installing necessary .NET Workloads - -.NET SDK requires developers to install workloads for each platform they are targeting. -Since Avalonia targets pretty much every supported .NET platform, you need to install these workloads as well. -Running it from the command line: -```bash -dotnet workload install android ios wasm-tools -``` - -macOS workloads are not required to build Avalonia. -Note: on Unix OS you need to run this command from sudo. -Tizen workload can be installed with PowerShell: -```powershell -(New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.ps1') | Invoke-Expression -``` -Or Bash: -```bash -curl -sSL https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.sh | sudo bash -``` - -## Build and Run Avalonia - -```bash -cd samples\ControlCatalog.NetCore -dotnet restore -dotnet run -``` - -## Opening in Visual Studio - -If you want to open Avalonia in Visual Studio you have two options: - -- Avalonia.sln: This contains the whole of Avalonia in including desktop, mobile and web. You must have a number of dotnet workloads installed in order to build everything in this solution -- Avalonia.Desktop.slnf: This solution filter opens only the parts of Avalonia required to run on desktop. This requires no extra workloads to be installed. - -Avalonia requires Visual Studio 2022 or newer. The free Visual Studio Community edition works fine. - -Build and run `ControlCatalog.NetCore` project to see the sample application. - -### Visual Studio Troubleshooting - - * **Error MSB4062 GenerateAvaloniaResourcesTask** - - Same as previous one, you need to manually build `Avalonia.Build.Tasks` project at least once. - - Alternatively, you can build the solution once with Nuke. - -## Building packages with Nuke - -Install Nuke -`dotnet tool install --global Nuke.GlobalTool --version 6.2.1` - -Build project: -`nuke --target Compile --configuration Release` - -And run tests: -`nuke --target RunTests --configuration Release` - -Or if you need to create nuget packages as well (it will compile and run tests automatically): -`nuke --target Package --configuration Release` - -# 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. - -MonoDevelop, Xamarin Studio and Visual Studio for Mac aren't capable of properly opening our solution. You can use Rider (at least 2017.2 EAP) or VS Code instead. They will fail to load most of platform specific projects, but you don't need them to run on .NET Core. - -## Additional requirements for macOS - -The build process needs [Xcode](https://developer.apple.com/xcode/) to build the native library. Following the install instructions at the [Xcode](https://developer.apple.com/xcode/) website to properly install. - -## Clone the Avalonia repository - -``` -git clone https://github.com/AvaloniaUI/Avalonia.git -cd Avalonia -git submodule update --init --recursive -``` - -## Build native libraries (macOS only) - -On macOS it is necessary to build and manually install the respective native libraries using [Xcode](https://developer.apple.com/xcode/). Execute the build script in the root project with the `CompileNative` task. It will build the headers, build the libraries, and place them in the appropriate place to allow .NET to find them at compilation and run time. - -```bash -./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. -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. diff --git a/NuGet.Config b/NuGet.Config index 2042fea360..93d7ba8778 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -3,7 +3,19 @@ - - + + + + + + + + + + + + + + diff --git a/api/Avalonia.Android.nupkg.xml b/api/Avalonia.Android.nupkg.xml index da33e03f2c..3c65a6fb9d 100644 --- a/api/Avalonia.Android.nupkg.xml +++ b/api/Avalonia.Android.nupkg.xml @@ -1,16 +1,16 @@ - - + + - CP0002 - M:Avalonia.Android.AndroidViewControlHandle.get_HandleDescriptor - baseline/net8.0-android34.0/Avalonia.Android.dll - target/net8.0-android34.0/Avalonia.Android.dll + CP0008 + T:Avalonia.Android.AvaloniaActivity + baseline/Avalonia.Android/lib/net10.0-android36.0/Avalonia.Android.dll + current/Avalonia.Android/lib/net10.0-android36.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 + CP0008 + T:Avalonia.Android.AvaloniaMainActivity + baseline/Avalonia.Android/lib/net10.0-android36.0/Avalonia.Android.dll + current/Avalonia.Android/lib/net10.0-android36.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 ed29e880a4..0000000000 --- a/api/Avalonia.Skia.nupkg.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - 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.Win32.Interoperability.nupkg.xml b/api/Avalonia.Win32.Interoperability.nupkg.xml new file mode 100644 index 0000000000..33fc2ac062 --- /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 + + \ 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 f9306abc56..cab4bf5580 100644 --- a/api/Avalonia.nupkg.xml +++ b/api/Avalonia.nupkg.xml @@ -1,88 +1,1312 @@  - + + + CP0001 + T:Avalonia.Media.IGlyphTypeface + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0001 + T:Avalonia.Media.IGlyphTypeface + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.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.Media.FontManager.TryGetGlyphTypeface(Avalonia.Media.Typeface,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll CP0002 - M:Avalonia.Diagnostics.AppliedStyle.get_IsActive - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + M:Avalonia.Media.FontMetrics.get_DesignEmHeight + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.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.TryAddGlyphTypeface(Avalonia.Media.IGlyphTypeface) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.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.FontCollectionBase.TryAddGlyphTypeface(System.IO.Stream,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.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.Media.Fonts.FontCollectionBase.TryAddGlyphTypeface(System.String,Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.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.Media.Fonts.FontCollectionBase.TryCreateSyntheticGlyphTypeface(Avalonia.Media.IGlyphTypeface,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + 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 + M:Avalonia.Media.Fonts.FontCollectionBase.TryGetGlyphTypeface(System.String,Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.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 + M:Avalonia.Media.Fonts.FontCollectionBase.TryGetGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.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 + CP0002 + M:Avalonia.Media.Fonts.FontCollectionBase.TryGetNearestMatch(System.Collections.Generic.IDictionary{Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface},Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.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 + CP0002 + M:Avalonia.Media.Fonts.FontCollectionBase.TryGetNearestMatch(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll - CP0006 - M:Avalonia.Controls.Notifications.INotificationManager.CloseAll - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll + CP0002 + M:Avalonia.Media.Fonts.IFontCollection.TryGetGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.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 + CP0002 + M:Avalonia.Media.GlyphMetrics.get_Height + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.GlyphMetrics.get_Width + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.GlyphRun.#ctor(Avalonia.Media.IGlyphTypeface,System.Double,System.ReadOnlyMemory{System.Char},System.Collections.Generic.IReadOnlyList{Avalonia.Media.TextFormatting.GlyphInfo},System.Nullable{Avalonia.Point},System.Int32) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.GlyphRun.#ctor(Avalonia.Media.IGlyphTypeface,System.Double,System.ReadOnlyMemory{System.Char},System.Collections.Generic.IReadOnlyList{System.UInt16},System.Nullable{Avalonia.Point},System.Int32) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.GlyphRun.get_GlyphTypeface + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyph(System.UInt32) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvances(System.ReadOnlySpan{System.UInt16}) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyphs(System.ReadOnlySpan{System.UInt32}) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.TryGetGlyph(System.UInt32,System.UInt16@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.TryGetTable(System.UInt32,System.Byte[]@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.TextFormatting.ShapedBuffer.#ctor(System.ReadOnlyMemory{System.Char},System.Int32,Avalonia.Media.IGlyphTypeface,System.Double,System.SByte) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.TextFormatting.ShapedBuffer.get_GlyphTypeface + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.TextFormatting.TextMetrics.#ctor(Avalonia.Media.IGlyphTypeface,System.Double) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.TextFormatting.TextShaperOptions.#ctor(Avalonia.Media.IGlyphTypeface,System.Collections.Generic.IReadOnlyList{Avalonia.Media.FontFeature},System.Double,System.SByte,System.Globalization.CultureInfo,System.Double,System.Double) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.TextFormatting.TextShaperOptions.#ctor(Avalonia.Media.IGlyphTypeface,System.Double,System.SByte,System.Globalization.CultureInfo,System.Double,System.Double) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.TextFormatting.TextShaperOptions.get_Typeface + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.Typeface.get_GlyphTypeface + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + 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.Platform.IGlyphRunImpl.get_GlyphTypeface + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Platform.IPlatformRenderInterface.CreateGlyphRun(Avalonia.Media.IGlyphTypeface,System.Double,System.Collections.Generic.IReadOnlyList{Avalonia.Media.TextFormatting.GlyphInfo},Avalonia.Point) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + F:Avalonia.Controls.Documents.TextElement.LetterSpacingProperty + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + F:Avalonia.Controls.Presenters.ContentPresenter.LetterSpacingProperty + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + F:Avalonia.Controls.Primitives.TemplatedControl.LetterSpacingProperty + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + F:Avalonia.Controls.TextBlock.LetterSpacingProperty + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Documents.TextElement.get_LetterSpacing + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Documents.TextElement.GetLetterSpacing(Avalonia.Controls.Control) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Documents.TextElement.set_LetterSpacing(System.Double) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Documents.TextElement.SetLetterSpacing(Avalonia.Controls.Control,System.Double) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Presenters.ContentPresenter.get_LetterSpacing + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Presenters.ContentPresenter.set_LetterSpacing(System.Double) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Primitives.TemplatedControl.get_LetterSpacing + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Primitives.TemplatedControl.set_LetterSpacing(System.Double) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Media.GlyphMetrics.get_Height + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.GlyphMetrics.get_Width + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.get_GlyphCount + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyph(System.UInt32) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvances(System.ReadOnlySpan{System.UInt16}) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyphs(System.ReadOnlySpan{System.UInt32}) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.TryGetGlyph(System.UInt32,System.UInt16@) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.TryGetTable(System.UInt32,System.Byte[]@) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.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.Platform.IGlyphRunImpl.get_GlyphTypeface + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.FontManager.TryGetGlyphTypeface(Avalonia.Media.Typeface,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.FontMetrics.get_DesignEmHeight + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.Fonts.FontCollectionBase.TryAddGlyphTypeface(Avalonia.Media.IGlyphTypeface) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.Fonts.FontCollectionBase.TryAddGlyphTypeface(System.IO.Stream,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.Fonts.FontCollectionBase.TryAddGlyphTypeface(System.String,Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.Fonts.FontCollectionBase.TryCreateSyntheticGlyphTypeface(Avalonia.Media.IGlyphTypeface,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.Fonts.FontCollectionBase.TryGetGlyphTypeface(System.String,Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.Fonts.FontCollectionBase.TryGetGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.Fonts.FontCollectionBase.TryGetNearestMatch(System.Collections.Generic.IDictionary{Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface},Avalonia.Media.Fonts.FontCollectionKey,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.Fonts.FontCollectionBase.TryGetNearestMatch(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.Fonts.IFontCollection.TryGetGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.GlyphMetrics.get_Height + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.GlyphMetrics.get_Width + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll - CP0009 - T:Avalonia.Diagnostics.StyleDiagnostics - baseline/netstandard2.0/Avalonia.Base.dll - target/netstandard2.0/Avalonia.Base.dll + CP0002 + M:Avalonia.Media.GlyphRun.#ctor(Avalonia.Media.IGlyphTypeface,System.Double,System.ReadOnlyMemory{System.Char},System.Collections.Generic.IReadOnlyList{Avalonia.Media.TextFormatting.GlyphInfo},System.Nullable{Avalonia.Point},System.Int32) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.GlyphRun.#ctor(Avalonia.Media.IGlyphTypeface,System.Double,System.ReadOnlyMemory{System.Char},System.Collections.Generic.IReadOnlyList{System.UInt16},System.Nullable{Avalonia.Point},System.Int32) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.GlyphRun.get_GlyphTypeface + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.get_GlyphCount + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyph(System.UInt32) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvances(System.ReadOnlySpan{System.UInt16}) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyphs(System.ReadOnlySpan{System.UInt32}) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.TryGetGlyph(System.UInt32,System.UInt16@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.TryGetTable(System.UInt32,System.Byte[]@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.TextFormatting.ShapedBuffer.#ctor(System.ReadOnlyMemory{System.Char},System.Int32,Avalonia.Media.IGlyphTypeface,System.Double,System.SByte) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.TextFormatting.ShapedBuffer.get_GlyphTypeface + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.TextFormatting.TextMetrics.#ctor(Avalonia.Media.IGlyphTypeface,System.Double) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.TextFormatting.TextShaperOptions.#ctor(Avalonia.Media.IGlyphTypeface,System.Collections.Generic.IReadOnlyList{Avalonia.Media.FontFeature},System.Double,System.SByte,System.Globalization.CultureInfo,System.Double,System.Double) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.TextFormatting.TextShaperOptions.#ctor(Avalonia.Media.IGlyphTypeface,System.Double,System.SByte,System.Globalization.CultureInfo,System.Double,System.Double) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.TextFormatting.TextShaperOptions.get_Typeface + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.Typeface.get_GlyphTypeface + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.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/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + 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 + + + CP0002 + M:Avalonia.Platform.IGlyphRunImpl.get_GlyphTypeface + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll - CP0009 - T:Avalonia.Controls.Screens - baseline/netstandard2.0/Avalonia.Controls.dll - target/netstandard2.0/Avalonia.Controls.dll + CP0002 + M:Avalonia.Platform.IPlatformRenderInterface.CreateGlyphRun(Avalonia.Media.IGlyphTypeface,System.Double,System.Collections.Generic.IReadOnlyList{Avalonia.Media.TextFormatting.GlyphInfo},Avalonia.Point) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + F:Avalonia.Controls.Documents.TextElement.LetterSpacingProperty + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + F:Avalonia.Controls.Presenters.ContentPresenter.LetterSpacingProperty + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + F:Avalonia.Controls.Primitives.TemplatedControl.LetterSpacingProperty + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + F:Avalonia.Controls.TextBlock.LetterSpacingProperty + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Documents.TextElement.get_LetterSpacing + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Documents.TextElement.GetLetterSpacing(Avalonia.Controls.Control) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Documents.TextElement.set_LetterSpacing(System.Double) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Documents.TextElement.SetLetterSpacing(Avalonia.Controls.Control,System.Double) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Presenters.ContentPresenter.get_LetterSpacing + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Presenters.ContentPresenter.set_LetterSpacing(System.Double) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Primitives.TemplatedControl.get_LetterSpacing + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Primitives.TemplatedControl.set_LetterSpacing(System.Double) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Media.GlyphMetrics.get_Height + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.GlyphMetrics.get_Width + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.get_GlyphCount + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyph(System.UInt32) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvances(System.ReadOnlySpan{System.UInt16}) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.GetGlyphs(System.ReadOnlySpan{System.UInt32}) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.TryGetGlyph(System.UInt32,System.UInt16@) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Media.IGlyphTypeface.TryGetTable(System.UInt32,System.Byte[]@) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/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/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Platform.IGlyphRunImpl.get_GlyphTypeface + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Media.Fonts.IFontCollection.TryCreateSyntheticGlyphTypeface(Avalonia.Media.GlyphTypeface,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.GlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Media.Fonts.IFontCollection.TryCreateSyntheticGlyphTypeface(Avalonia.Media.IGlyphTypeface,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Media.Fonts.IFontCollection.TryGetFamilyTypefaces(System.String,System.Collections.Generic.IReadOnlyList{Avalonia.Media.Typeface}@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Media.Fonts.IFontCollection.TryGetGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.GlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Media.Fonts.IFontCollection.TryGetNearestMatch(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.GlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Media.Fonts.IFontCollection.TryGetNearestMatch(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IPlatformTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IPlatformTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryGetFamilyTypefaces(System.String,System.Collections.Generic.IReadOnlyList{Avalonia.Media.Typeface}@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.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.IPlatformTypeface@) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IPlatformRenderInterface.CreateGlyphRun(Avalonia.Media.GlyphTypeface,System.Double,System.Collections.Generic.IReadOnlyList{Avalonia.Media.TextFormatting.GlyphInfo},Avalonia.Point) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.ITextShaperImpl.CreateTypeface(Avalonia.Media.GlyphTypeface) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.ITextShaperImpl.CreateTypeface(Avalonia.Media.IGlyphTypeface) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.CharacterToGlyphMap + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.FaceNames + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.FamilyNames + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.PlatformTypeface + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.SupportedFeatures + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.TextShaperTypeface + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.TypographicFamilyName + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.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 + + + 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.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IPlatformTypeface@) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IPlatformTypeface@) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryGetFamilyTypefaces(System.String,System.Collections.Generic.IReadOnlyList{Avalonia.Media.Typeface}@) + 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.Globalization.CultureInfo,Avalonia.Media.IPlatformTypeface@) + 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.ITextShaperImpl.CreateTypeface(Avalonia.Media.IGlyphTypeface) + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.CharacterToGlyphMap + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.FaceNames + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.FamilyNames + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.GlyphCount + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.PlatformTypeface + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.SupportedFeatures + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.TextShaperTypeface + baseline/Avalonia/lib/net6.0/Avalonia.Base.dll + current/Avalonia/lib/net6.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.TypographicFamilyName + 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.Media.Fonts.IFontCollection.TryCreateSyntheticGlyphTypeface(Avalonia.Media.GlyphTypeface,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.GlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Media.Fonts.IFontCollection.TryCreateSyntheticGlyphTypeface(Avalonia.Media.IGlyphTypeface,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Media.Fonts.IFontCollection.TryGetFamilyTypefaces(System.String,System.Collections.Generic.IReadOnlyList{Avalonia.Media.Typeface}@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Media.Fonts.IFontCollection.TryGetGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.GlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Media.Fonts.IFontCollection.TryGetNearestMatch(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.GlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Media.Fonts.IFontCollection.TryGetNearestMatch(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IGlyphTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IPlatformTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IPlatformTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryGetFamilyTypefaces(System.String,System.Collections.Generic.IReadOnlyList{Avalonia.Media.Typeface}@) + 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.Globalization.CultureInfo,Avalonia.Media.IPlatformTypeface@) + 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.IPlatformTypeface@) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IPlatformRenderInterface.CreateGlyphRun(Avalonia.Media.GlyphTypeface,System.Double,System.Collections.Generic.IReadOnlyList{Avalonia.Media.TextFormatting.GlyphInfo},Avalonia.Point) + 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.ITextShaperImpl.CreateTypeface(Avalonia.Media.GlyphTypeface) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.ITextShaperImpl.CreateTypeface(Avalonia.Media.IGlyphTypeface) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.CharacterToGlyphMap + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.FaceNames + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.FamilyNames + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.GlyphCount + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.PlatformTypeface + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.SupportedFeatures + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.TextShaperTypeface + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.TypographicFamilyName + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0006 + 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.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 + P:Avalonia.OpenGL.IGlExternalImageTexture.TextureType + baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll + current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll + + + CP0006 + 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.Input.Platform.IClipboard.TryGetDataAsync + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + 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.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.Media.IGlyphTypeface.GetGlyphAdvance(System.UInt16) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.IO.Stream,Avalonia.Media.FontSimulations,Avalonia.Media.IPlatformTypeface@) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryCreateGlyphTypeface(System.String,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,Avalonia.Media.IPlatformTypeface@) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryGetFamilyTypefaces(System.String,System.Collections.Generic.IReadOnlyList{Avalonia.Media.Typeface}@) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.IPlatformTypeface@) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + 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 + M:Avalonia.Platform.ITextShaperImpl.CreateTypeface(Avalonia.Media.IGlyphTypeface) + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.CharacterToGlyphMap + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.FaceNames + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.FamilyNames + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.GlyphCount + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.PlatformTypeface + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.SupportedFeatures + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.TextShaperTypeface + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + P:Avalonia.Media.IGlyphTypeface.TypographicFamilyName + baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll + + + CP0006 + 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 \ No newline at end of file diff --git a/azure-pipelines-integrationtests.yml b/azure-pipelines-integrationtests.yml index 2c3a2abc25..8a91e8fd68 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 @@ -24,16 +24,17 @@ jobs: if [[ $(uname -m) == 'arm64' ]]; then arch="arm64" fi - sudo xcode-select -s /Applications/Xcode.app/Contents/Developer + git clean -ffdx 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' @@ -42,7 +43,7 @@ jobs: inputs: command: 'test' projects: 'tests/Avalonia.IntegrationTests.Appium/Avalonia.IntegrationTests.Appium.csproj' - arguments: '-l "console;verbosity=detailed"' + arguments: '--no-progress' - script: | pkill IntegrationTestApp @@ -55,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 @@ -86,10 +87,17 @@ jobs: displayName: 'Build test project' inputs: command: 'build' - projects: 'tests\Avalonia.IntegrationTests.Appium\Avalonia.IntegrationTests.Appium.csproj' + projects: 'tests/Avalonia.IntegrationTests.Appium/Avalonia.IntegrationTests.Appium.csproj' + + - task: DotNetCoreCLI@2 + displayName: 'Run Win32 Integration Tests' + inputs: + command: 'run' + projects: 'tests/Avalonia.IntegrationTests.Win32/Avalonia.IntegrationTests.Win32.csproj' + arguments: '--no-progress' - task: VSTest@2 - displayName: 'Run Integration Tests' + displayName: 'Run Appium Integration Tests' inputs: testAssemblyVer2: '**\bin\**\Avalonia.IntegrationTests.Appium.dll' runSettingsFile: 'tests\Avalonia.IntegrationTests.Appium\record-video.runsettings' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f6e116a8fa..06da4bcd2b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -2,12 +2,12 @@ jobs: - job: GetPRNumber pool: - vmImage: 'ubuntu-20.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-20.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 @@ -43,13 +43,6 @@ jobs: script: | dotnet workload install android macos wasm-tools - - task: CmdLine@2 - displayName: 'Install Tizen Workload' - inputs: - targetType: 'inline' - script: | - curl -sSL https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.sh | sudo bash -s -- -d "/opt/hostedtoolcache/dotnet" - - task: CmdLine@2 displayName: 'Run Build' inputs: @@ -69,16 +62,16 @@ jobs: variables: SolutionDir: '$(Build.SourcesDirectory)' pool: - vmImage: 'macos-12' + 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 @@ -87,14 +80,7 @@ jobs: displayName: 'Install Workloads' inputs: script: | - dotnet workload install android ios macos wasm-tools - - - task: CmdLine@2 - displayName: 'Install Tizen Workload' - inputs: - targetType: 'inline' - script: | - curl -sSL https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.sh | sudo bash + dotnet workload install android ios maccatalyst macos wasm-tools - task: CmdLine@2 displayName: 'Generate avalonia-native' @@ -109,10 +95,11 @@ jobs: inputs: actions: 'build' scheme: '' - sdk: 'macosx12.3' + sdk: 'macosx26.0' configuration: 'Release' xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace' - xcodeVersion: '13' # Options: 8, 9, default, specifyPath + xcodeVersion: 'specifyPath' # Options: 8, 9, default, specifyPath + xcodeDeveloperDir: '/Applications/Xcode_26.0.app/Contents/Developer' args: '-derivedDataPath ./' - task: CmdLine@2 @@ -147,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 @@ -167,20 +154,13 @@ jobs: displayName: 'Install Workloads' inputs: script: | - dotnet workload install android ios tvos wasm-tools - - - task: PowerShell@2 - displayName: 'Install Tizen Workload' - inputs: - targetType: 'inline' - script: | - (New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.ps1') | Invoke-Expression + dotnet workload install android maccatalyst ios tvos wasm-tools - task: CmdLine@2 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..c1b96ebe04 --- /dev/null +++ b/build/AnalyzerProject.targets @@ -0,0 +1,13 @@ + + + + true + true + $(NoWarn);RS2008 + + + + + + + diff --git a/build/Base.props b/build/Base.props index 6b7ae5d677..ab5853fcfa 100644 --- a/build/Base.props +++ b/build/Base.props @@ -1,6 +1,8 @@  - - - + + + + + diff --git a/build/DevAnalyzers.props b/build/DevAnalyzers.props index fd416e3291..ae5e7a6c42 100644 --- a/build/DevAnalyzers.props +++ b/build/DevAnalyzers.props @@ -1,12 +1,20 @@ - - + + 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/ExternalConsumers.props b/build/ExternalConsumers.props index 96cf5cc608..79df2f6be4 100644 --- a/build/ExternalConsumers.props +++ b/build/ExternalConsumers.props @@ -30,5 +30,6 @@ + diff --git a/build/HarfBuzzSharp.props b/build/HarfBuzzSharp.props index cce53c1ed9..c7a3d753f2 100644 --- a/build/HarfBuzzSharp.props +++ b/build/HarfBuzzSharp.props @@ -1,7 +1,7 @@  - - - + + + diff --git a/build/ImageSharp.props b/build/ImageSharp.props index 74b9ab7e3c..cf401630b0 100644 --- a/build/ImageSharp.props +++ b/build/ImageSharp.props @@ -1,5 +1,5 @@ - + diff --git a/build/JetBrains.dotMemoryUnit.props b/build/JetBrains.dotMemoryUnit.props deleted file mode 100644 index 5d74d474cf..0000000000 --- a/build/JetBrains.dotMemoryUnit.props +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/build/Microsoft.Reactive.Testing.props b/build/Microsoft.Reactive.Testing.props index a0ba2163bb..c39c72df77 100644 --- a/build/Microsoft.Reactive.Testing.props +++ b/build/Microsoft.Reactive.Testing.props @@ -1,5 +1,5 @@  - + 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/Rx.props b/build/Rx.props index 73b18c6e0b..462428c286 100644 --- a/build/Rx.props +++ b/build/Rx.props @@ -1,5 +1,5 @@  - + diff --git a/build/SampleApp.props b/build/SampleApp.props index 8ecbe902ab..3f44553d2d 100644 --- a/build/SampleApp.props +++ b/build/SampleApp.props @@ -13,6 +13,10 @@ + + + + Avalonia - 11.2.999 - 11.1.0 + 12.0.999 Avalonia Team Copyright 2013-$([System.DateTime]::Now.ToString(`yyyy`)) © The AvaloniaUI Project - https://avaloniaui.net + https://avaloniaui.net/?utm_source=nuget&utm_medium=referral&utm_content=project_homepage_link https://github.com/AvaloniaUI/Avalonia/ true $(NoWarn);CS1591 diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props index a5789e1116..0dc94b3239 100644 --- a/build/SkiaSharp.props +++ b/build/SkiaSharp.props @@ -1,12 +1,7 @@  - - - - - - - - - + + + + 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/System.Memory.props b/build/System.Memory.props deleted file mode 100644 index 35a87a3a2f..0000000000 --- a/build/System.Memory.props +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/build/TargetFrameworks.props b/build/TargetFrameworks.props index 8c88b4cf4b..96541e7ecf 100644 --- a/build/TargetFrameworks.props +++ b/build/TargetFrameworks.props @@ -1,17 +1,17 @@ - net8.0 + net10.0 $(AvsCurrentTargetFramework)-windows $(AvsCurrentTargetFramework)-macos - $(AvsCurrentTargetFramework)-android34.0 - $(AvsCurrentTargetFramework)-ios17.0 - $(AvsCurrentTargetFramework)-tvos17.0 + $(AvsCurrentTargetFramework)-android36.0 + $(AvsCurrentTargetFramework)-maccatalyst26.0 + $(AvsCurrentTargetFramework)-ios26.0 + $(AvsCurrentTargetFramework)-tvos26.0 $(AvsCurrentTargetFramework)-browser - $(AvsCurrentTargetFramework)-tizen - net6.0 - net6.0-windows + net8.0 + net8.0-windows @@ -20,8 +20,7 @@ 13.0 13.0 13.1 - 6.5 - 21.0 + 24.0 10.15 diff --git a/build/TrimmingEnable.props b/build/TrimmingEnable.props index 1fa14cb022..34b3e232b6 100644 --- a/build/TrimmingEnable.props +++ b/build/TrimmingEnable.props @@ -19,4 +19,10 @@ $(WarningsAsErrors);IL3050;IL3051;IL3052;IL3053;IL3054;IL3055;IL3056 + + $(WarningsAsErrors);CA1420;CA1421 + + + + 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/WarnAsErrors.props b/build/WarnAsErrors.props index dd105f206e..eaab7bd00c 100644 --- a/build/WarnAsErrors.props +++ b/build/WarnAsErrors.props @@ -17,5 +17,7 @@ $(WarningsNotAsErrors);AVLN2205 $(WarningsNotAsErrors);AVLN2207 + + $(WarningsNotAsErrors);AVLN2208 diff --git a/build/XUnit.props b/build/XUnit.props index 8f991ae442..c2ccb1fa2c 100644 --- a/build/XUnit.props +++ b/build/XUnit.props @@ -1,14 +1,10 @@  - - - - - - - - - - + + + + + + $(MSBuildThisFileDirectory)\avalonia.snk diff --git a/dirs.proj b/dirs.proj index 5403847fab..084fd30475 100644 --- a/dirs.proj +++ b/dirs.proj @@ -4,29 +4,22 @@ - + - + + - - - - - - - - diff --git a/docs/api-compat.md b/docs/api-compat.md new file mode 100644 index 0000000000..17dc42b38c --- /dev/null +++ b/docs/api-compat.md @@ -0,0 +1,32 @@ +# API Compatibility + +Avalonia maintains strict **source and binary compatibility** within major versions. Automated API compatibility checks run on every CI build to enforce this policy—builds will fail if breaking changes are detected. + +## When Breaking Changes Are Permitted + +Breaking changes are only acceptable under these specific circumstances and **must be approved** by the Avalonia code team: + +- **Major version targeting**: When `master` branch is targeting a new major version +- **Accidental public APIs**: When code was unintentionally exposed as a public API and is unlikely to have external dependencies +- **Experimental features**: When the API is explicitly marked as unstable or experimental + +## Handling Approved Breaking Changes + +When a breaking change is approved, you can bypass CI validation using an API suppression file: + +1. **Generate suppression file**: Run `nuke --update-api-suppression true` +2. **Commit changes**: Commit the [updated suppression file](../api/) in a separate commit + +> **Note**: The suppression file should only be updated after the breaking change has been reviewed and approved. + +## Baseline Version Configuration + +API changes are validated against a **baseline version**—the reference point for compatibility checks. + +- **Default behavior**: Uses the current major version (e.g., for version 11.0.5, baseline is 11.0.0) +- **Custom baseline**: Override using the [`api-baseline`](https://github.com/AvaloniaUI/Avalonia/blob/56d94d64b9aa6f16200be39b3bcb17f03325b7f9/nukebuild/BuildParameters.cs#L27) parameter with `nuke` +- **Fallback**: When not specified, uses the version defined in [`SharedVersion.props`](https://github.com/AvaloniaUI/Avalonia/blob/56d94d64b9aa6f16200be39b3bcb17f03325b7f9/build/SharedVersion.props#L6) + +## Additional Resources + +- [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 new file mode 100644 index 0000000000..cef5ed3e10 --- /dev/null +++ b/docs/build.md @@ -0,0 +1,114 @@ +## Clone the Avalonia repository + +```bash +git clone https://github.com/AvaloniaUI/Avalonia.git +cd Avalonia +git submodule update --init +``` + +## Install the required version of the .NET Core SDK + +Go to https://dotnet.microsoft.com/en-us/download/visual-studio-sdks and install the latest version of the .NET SDK compatible with Avalonia UI. Make sure to download the SDK (not just the "runtime") package. The version compatible is indicated within the [global.json](https://github.com/AvaloniaUI/Avalonia/blob/master/global.json) file. Note that Avalonia UI does not always use the latest version and is hardcoded to use the last version known to be compatible (SDK releases may break the builds from time-to-time). + +### Installing necessary .NET Workloads + +.NET SDK requires developers to install workloads for each platform they are targeting. +Since Avalonia targets pretty much every supported .NET platform, you need to install these workloads as well. +Running it from the command line: +```bash +dotnet workload install android ios maccatalyst wasm-tools +``` + +macOS workloads are not required to build Avalonia. +Note: on Unix OS you need to run this command from sudo. +Tizen workload can be installed with PowerShell: +```powershell +(New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.ps1') | Invoke-Expression +``` +Or Bash: +```bash +curl -sSL https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.sh | sudo bash +``` + +## Build and Run Avalonia + +```bash +cd samples\ControlCatalog.Desktop +dotnet restore +dotnet run +``` + +## Opening in Visual Studio + +If you want to open Avalonia in Visual Studio you have two options: + +- Avalonia.sln: This contains the whole of Avalonia in including desktop, mobile and web. You must have a number of dotnet workloads installed in order to build everything in this solution +- Avalonia.Desktop.slnf: This solution filter opens only the parts of Avalonia required to run on desktop. This requires no extra workloads to be installed. + +Avalonia requires Visual Studio 2022 or newer. The free Visual Studio Community edition works fine. + +Build and run `ControlCatalog.Desktop` project to see the sample application. + +### Visual Studio Troubleshooting + + * **Error MSB4062 GenerateAvaloniaResourcesTask** + + Same as previous one, you need to manually build `Avalonia.Build.Tasks` project at least once. + + Alternatively, you can build the solution once with Nuke. + +## Building packages with Nuke + +Install Nuke +`dotnet tool install --global Nuke.GlobalTool --version 6.2.1` + +Build project: +`nuke --target Compile --configuration Release` + +And run tests: +`nuke --target RunTests --configuration Release` + +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. + +MonoDevelop, Xamarin Studio and Visual Studio for Mac aren't capable of properly opening our solution. You can use Rider (at least 2017.2 EAP) or VS Code instead. They will fail to load most of platform specific projects, but you don't need them to run on .NET Core. + +## Additional requirements for macOS + +The build process needs [Xcode](https://developer.apple.com/xcode/) to build the native library. Following the install instructions at the [Xcode](https://developer.apple.com/xcode/) website to properly install. + +## Clone the Avalonia repository + +``` +git clone https://github.com/AvaloniaUI/Avalonia.git +cd Avalonia +git submodule update --init --recursive +``` + +## Build native libraries (macOS only) + +On macOS it is necessary to build and manually install the respective native libraries using [Xcode](https://developer.apple.com/xcode/). Execute the build script in the root project with the `CompileNative` task. It will build the headers, build the libraries, and place them in the appropriate place to allow .NET to find them at compilation and run time. + +```bash +./build.sh CompileNative +``` + +## Browser + +To build and run browser/wasm projects, it's necessary to install NodeJS. +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/debug-xaml-compiler.md b/docs/debug-xaml-compiler.md new file mode 100644 index 0000000000..da260e6d0a --- /dev/null +++ b/docs/debug-xaml-compiler.md @@ -0,0 +1,15 @@ +# Debugging the XAML Compiler + +The Avalonia XAML compiler can be debugged by setting an MSBuild property which triggers a debugger launch during compilation. This allows you to step through the XAML compilation process and troubleshoot issues. + +To enable XAML compiler debugging, set the `AvaloniaXamlIlDebuggerLaunch` MSBuild property to `true` in your project file: + +```xml + + true + +``` + +When this property is enabled, the XAML compiler will call `Debugger.Launch()` on startup, which prompts you to attach a debugger to the compiler process. + +If you're working with the Sandbox project in the Avalonia repository, you can enable debugging by simply uncommenting the property line in the [project file](https://github.com/AvaloniaUI/Avalonia/blob/56d94d64b9aa6f16200be39b3bcb17f03325b7f9/samples/Sandbox/Sandbox.csproj#L8). diff --git a/docs/images/xcode-product-path.png b/docs/images/xcode-product-path.png new file mode 100644 index 0000000000..d254da9875 Binary files /dev/null and b/docs/images/xcode-product-path.png differ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000000..c8355c0f74 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,20 @@ +# Avalonia Developer Documentation + +This documentation covers Avalonia framework development. For user documentation on how to use Avalonia, visit https://docs.avaloniaui.net/. + +## Getting Started + +- [Building Avalonia](build.md) describes how to build Avalonia from source +- You should read the [Contributing guidelines](../CONTRIBUTING.md) before you start +- We have a [Code of Conduct](../CODE_OF_CONDUCT.md) + +## Development + +- [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 + +- [API Compatibility](api-compat.md) describes the API compatibility guarantees provided by Avalonia, and exceptions to these guarantees +- Our [Release Process](release.md) describes the process for creating a new Avalonia release diff --git a/docs/macos-native.md b/docs/macos-native.md new file mode 100644 index 0000000000..5c16742963 --- /dev/null +++ b/docs/macos-native.md @@ -0,0 +1,71 @@ +# macOS Native Code + +The macOS platform backend has a native component, written in objective-c and located in [`native/Avalonia.Native/src/OSX`](../native/Avalonia.Native/src/OSX/). To work on this code, open the [`Avalonia.Native.OSX.xcodeproj`](../native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj)project in Xcode. + +Changes to the native portion of the code can be recompiled in two ways: + +1. Using the [`build.sh`](build.md#build-native-libraries-macos-only) script: this has the downside that it will trigger a full recompile of Avalonia +2. Using `AvaloniaNativeLibraryPath` described below + +## Using `AvaloniaNativeLibraryPath ` + +When you make changes in Xcode and recompile using Cmd+B, the binary will be compiled to a location that can be seen under "Products": + +![How to find the product path in Xcode](images/xcode-product-path.png) + +To use this build in Avalonia, one can specifiy the path by using `AvaloniaNativePlatformOptions.AvaloniaNativeLibraryPath` in an application's AppBuilder: + +```csharp +public static AppBuilder BuildAvaloniaApp() => + AppBuilder.Configure() + .UsePlatformDetect() + .With(new AvaloniaNativePlatformOptions + { + AvaloniaNativeLibraryPath = "[Path to your dylib]", + }) +``` + +# Bundling Development Code + +In certain situations you need to run an Avalonia sample application as an app bundle. One of these situations is testing macOS Accessibility - Xcode's Accessibility Inspector fails to recognise the application otherwise. To facilitate this, the [`IntegrationTestApp`](../samples/IntegrationTestApp/) has a [`bundle.sh`](../samples/IntegrationTestApp/bundle.sh) script which can be run to create a bundle of that application. + +Alteratively, if you need to bundle another project, another solution is to change the sample's output path to resemble an app bundle. You can do this by modifying the output path in the csproj, e.g.: + +```xml +bin\$(Configuration)\$(Platform)\ControlCatalog.NetCore.app/Contents/MacOS +false +true +``` + +And in the Contents output directory place a valid `Info.plist` file. An example for ControlCatalog.NetCore is: + +```xml + + + + + CFBundleName + ControlCatalog.NetCore + CFBundleDisplayName + ControlCatalog.NetCore + CFBundleIdentifier + ControlCatalog.NetCore + CFBundleVersion + 0.10.999 + CFBundlePackageType + AAPL + CFBundleSignature + ???? + CFBundleExecutable + ControlCatalog.NetCore + CFBundleIconFile + ControlCatalog.NetCore.icns + CFBundleShortVersionString + 0.1 + NSPrincipalClass + NSApplication + NSHighResolutionCapable + + + +``` 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 new file mode 100644 index 0000000000..249c215545 --- /dev/null +++ b/docs/porting-code-from-3rd-party-sources.md @@ -0,0 +1,12 @@ +# Porting Code from 3rd Party Sources + +When porting code or adapting code from other projects with a MIT compatible license, the source file must contain appropriate license headers. For example when porting code from WPF the header should contain: + +``` +// This source file is adapted from the Windows Presentation Foundation project. +// (https://github.com/dotnet/wpf/) +// +// 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. diff --git a/docs/release.md b/docs/release.md new file mode 100644 index 0000000000..42f8927f42 --- /dev/null +++ b/docs/release.md @@ -0,0 +1,32 @@ +# Release Process + +This document describes the process for creating a new Avalonia release + +## Backports + +- Go through PRs with "backport-candidate-*" tags, make sure this list makes sense +- Checkout https://github.com/grokys/avalonia-backport tool from the source code, get github api token +- Checkout stable release branch, like `release/11.0` +- Run backport cherry-picking process to the stable release branch +- Test if everything builds and tests are passing +- Test nightly builds of Avalonia +- Run labeling process (automatically replace "backport-candidate" with "backported" tags) and generate changelog + +## 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` +- 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" +- Click deploy +- Make a release on Github releases +- Press "Auto-generate changelog", so GitHub will append information about new contributors +- 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 diff --git a/nukebuild/Numerge b/external/Numerge similarity index 100% rename from nukebuild/Numerge rename to external/Numerge diff --git a/external/XamlX b/external/XamlX new file mode 160000 index 0000000000..c32d3040e5 --- /dev/null +++ b/external/XamlX @@ -0,0 +1 @@ +Subproject commit c32d3040e536ae9768233ea5a445697632578bd0 diff --git a/global.json b/global.json index b423edba49..3773c7d736 100644 --- a/global.json +++ b/global.json @@ -1,8 +1,11 @@ { "sdk": { - "version": "8.0.204", + "version": "10.0.101", "rollForward": "latestFeature" }, + "test": { + "runner": "Microsoft.Testing.Platform" + }, "msbuild-sdks": { "Microsoft.Build.Traversal": "4.1.0" } diff --git a/native/Avalonia.Native/generate-headers.sh b/native/Avalonia.Native/generate-headers.sh new file mode 100755 index 0000000000..0c391ba211 --- /dev/null +++ b/native/Avalonia.Native/generate-headers.sh @@ -0,0 +1,6 @@ +#/bin/bash +set -e +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +cd $SCRIPT_DIR/../.. +dotnet run --project ./nukebuild/_build.csproj --target GenerateCppHeaders + 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/comimpl.h b/native/Avalonia.Native/inc/comimpl.h index fd9093bb41..e16adb1ec2 100644 --- a/native/Avalonia.Native/inc/comimpl.h +++ b/native/Avalonia.Native/inc/comimpl.h @@ -7,6 +7,7 @@ #define COMIMPL_H_INCLUDED #include +#include /** START_COM_CALL causes AddRef to be called at the beginning of a function. @@ -100,6 +101,13 @@ public: return _obj; } + template ComPtr dynamicCast() + { + if(_obj == nullptr) + return nullptr; + return dynamic_cast(_obj); + } + TInterface** getPPV() { return &_obj; @@ -130,10 +138,18 @@ public: } }; +class ComObjectWeakRefToken +{ +public: + bool Alive = true; +}; + + class ComObject : public virtual IUnknown { private: unsigned int _refCount; + std::shared_ptr _weakRefs; public: virtual ULONG AddRef() @@ -157,10 +173,22 @@ public: _refCount = 1; } + virtual ~ComObject() { + if(_weakRefs) + _weakRefs->Alive = false; } + std::shared_ptr __GetWeakRefToken() + { + if(_weakRefs == nullptr) + { + _weakRefs = std::make_shared(); + } + return _weakRefs; + } + virtual ::HRESULT STDMETHODCALLTYPE QueryInterfaceImpl(REFIID riid, void **ppvObject) = 0; @@ -188,6 +216,41 @@ protected: }; +template +class ComObjectWeakPtr +{ +private: + std::shared_ptr _token; + TClass* _rawPtr; +public: + ComPtr tryGet() + { + if(_rawPtr == nullptr) + return nullptr; + if(_token->Alive) + return _rawPtr; + return nullptr; + } + + template ComPtr tryGetWithCast() + { + return tryGet().template dynamicCast(); + } + + ComObjectWeakPtr(TClass* obj) + { + _rawPtr = obj; + if(obj) + _token = obj->__GetWeakRefToken(); + } + + ComObjectWeakPtr() + { + _rawPtr = nullptr; + _token = nullptr; + } +}; + #define FORWARD_IUNKNOWN() \ virtual ULONG Release() override \ { \ 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 75a5e98ed4..030330c908 100644 --- a/native/Avalonia.Native/src/OSX/AvnView.h +++ b/native/Avalonia.Native/src/OSX/AvnView.h @@ -18,6 +18,7 @@ -(NSEvent* _Nonnull) lastMouseDownEvent; -(AvnPoint) translateLocalPoint:(AvnPoint)pt; -(void) onClosed; +-(void) setModifiers:(NSEventModifierFlags)modifierFlags; -(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 8c38b1cf2d..0da6f43bf4 100644 --- a/native/Avalonia.Native/src/OSX/AvnView.mm +++ b/native/Avalonia.Native/src/OSX/AvnView.mm @@ -11,9 +11,8 @@ @implementation AvnView { - ComPtr _parent; + ComObjectWeakPtr _parent; NSTrackingArea* _area; - bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed; AvnInputModifiers _modifierState; NSEvent* _lastMouseDownEvent; AvnPixelSize _lastPixelSize; @@ -132,7 +131,8 @@ _area = nullptr; } - if (_parent == nullptr) + auto parent = _parent.tryGet(); + if (parent == nullptr) { return; } @@ -144,7 +144,7 @@ _area = [[NSTrackingArea alloc] initWithRect:rect options:options owner:self userInfo:nullptr]; [self addTrackingArea:_area]; - _parent->UpdateCursor(); + parent->UpdateCursor(); auto fsize = [self convertSizeToBacking: [self frame].size]; @@ -156,26 +156,28 @@ auto reason = [self inLiveResize] ? ResizeUser : _resizeReason; - _parent->TopLevelEvents->Resized(FromNSSize(newSize), reason); + parent->TopLevelEvents->Resized(FromNSSize(newSize), reason); } } - (void)updateLayer { AvnInsidePotentialDeadlock deadlock; - if (_parent == nullptr) + auto parent = _parent.tryGet(); + if (parent == nullptr) { return; } - _parent->TopLevelEvents->RunRenderPriorityJobs(); + parent->TopLevelEvents->RunRenderPriorityJobs(); - if (_parent == nullptr) + parent = _parent.tryGet(); + if (parent == nullptr) { return; } - _parent->TopLevelEvents->Paint(); + parent->TopLevelEvents->Paint(); } - (void)drawRect:(NSRect)dirtyRect @@ -196,9 +198,10 @@ _lastPixelSize.Height = (int)fsize.height; [self updateRenderTarget]; - if(_parent != nullptr) + auto parent = _parent.tryGet(); + if(parent != nullptr) { - _parent->TopLevelEvents->ScalingChanged([[self window] backingScaleFactor]); + parent->TopLevelEvents->ScalingChanged([[self window] backingScaleFactor]); } [super viewDidChangeBackingProperties]; @@ -206,7 +209,8 @@ - (bool) ignoreUserInput:(bool)trigerInputWhenDisabled { - if(_parent == nullptr) + auto parent = _parent.tryGet(); + if(parent == nullptr) { return TRUE; } @@ -221,7 +225,7 @@ { if(trigerInputWhenDisabled) { - WindowImpl* windowImpl = dynamic_cast(_parent.getRaw()); + auto windowImpl = _parent.tryGetWithCast(); if(windowImpl == nullptr){ return FALSE; @@ -236,6 +240,12 @@ return FALSE; } +static void ConvertTilt(NSPoint tilt, float* xTilt, float* yTilt) +{ + *xTilt = tilt.x * 90; + *yTilt = -tilt.y * 90; +} + - (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type { bool triggerInputWhenDisabled = type != Move && type != LeaveWindow; @@ -285,6 +295,57 @@ delta.Y = [event deltaY]; } + float pressure = 0.5f; + float xTilt = 0.0f; + float yTilt = 0.0f; + AvnPointerDeviceType pointerType = AvnPointerDeviceType::Mouse; + + switch (event.type) + { + case NSEventTypeLeftMouseDown: + case NSEventTypeLeftMouseDragged: + case NSEventTypeRightMouseDown: + case NSEventTypeRightMouseDragged: + case NSEventTypeOtherMouseDown: + case NSEventTypeOtherMouseDragged: + switch (event.subtype) + { + case NSEventSubtypeTabletPoint: + pointerType = AvnPointerDeviceType::Pen; + pressure = event.pressure; + ConvertTilt(event.tilt, &xTilt, &yTilt); + break; + case NSEventSubtypeTabletProximity: + pointerType = AvnPointerDeviceType::Pen; + pressure = 0.0f; + break; + default: + break; + } + break; + case NSEventTypeLeftMouseUp: + case NSEventTypeRightMouseUp: + case NSEventTypeOtherMouseUp: + case NSEventTypeMouseMoved: + switch (event.subtype) + { + case NSEventSubtypeTabletPoint: + pointerType = AvnPointerDeviceType::Pen; + pressure = 0.0f; + ConvertTilt(event.tilt, &xTilt, &yTilt); + break; + case NSEventSubtypeTabletProximity: + pointerType = AvnPointerDeviceType::Pen; + pressure = 0.0f; + break; + default: + break; + } + break; + default: + break; + } + uint64_t timestamp = static_cast([event timestamp] * 1000); auto modifiers = [self getModifiers:[event modifierFlags]]; @@ -298,25 +359,26 @@ ) ) { - WindowBaseImpl* windowBase = dynamic_cast(_parent.getRaw()); + auto windowBase = _parent.tryGetWithCast(); if(windowBase != nullptr){ - WindowBaseImpl* parent = windowBase->Parent; + auto parent = windowBase->Parent.tryGet(); if(parent != nullptr){ auto parentWindow = parent->Window; - [parentWindow makeFirstResponder:parent->View]; + if(parentWindow != nullptr) + [parentWindow makeFirstResponder:parent->View]; } } else{ [self becomeFirstResponder]; } } - - if(_parent != nullptr) + auto parent = _parent.tryGet(); + if(parent != nullptr) { - _parent->TopLevelEvents->RawMouseEvent(type, timestamp, modifiers, point, delta); + parent->TopLevelEvents->RawMouseEvent(type, pointerType, timestamp, modifiers, point, delta, pressure, xTilt, yTilt); } [super mouseMoved:event]; @@ -324,10 +386,58 @@ - (BOOL) resignFirstResponder { - _parent->TopLevelEvents->LostFocus(); + auto window = [self window]; + if (window != nullptr && window.keyWindow) + { + [self onLostFocus]; + } + return YES; } +- (void)viewWillMoveToWindow:(NSWindow *)newWindow +{ + auto oldWindow = [self window]; + if (oldWindow == newWindow) + { + // viewWillMoveToWindow can be called with the same window when the view hierarchy changes + return; + } + + if (oldWindow != nullptr) + { + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:@"NSWindowDidResignKeyNotification" + object: oldWindow]; + } + + if (newWindow != nullptr) + { + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(windowDidResignKey:) + name:@"NSWindowDidResignKeyNotification" + object: newWindow]; + } +} + +- (void)windowDidResignKey:(NSNotification*)notification +{ + auto window = [self window]; + if (window != nullptr && notification.object == window && [window firstResponder] == self) + { + [self onLostFocus]; + } +} + +- (void)onLostFocus +{ + auto parent = _parent.tryGet(); + if (parent) + parent->TopLevelEvents->LostFocus(); +} + - (void)mouseMoved:(NSEvent *)event { [self mouseEvent:event withType:Move]; @@ -335,7 +445,6 @@ - (void)mouseDown:(NSEvent *)event { - _isLeftPressed = true; _lastMouseDownEvent = event; [self mouseEvent:event withType:LeftButtonDown]; } @@ -347,16 +456,12 @@ switch(event.buttonNumber) { case 2: - case 3: - _isMiddlePressed = true; [self mouseEvent:event withType:MiddleButtonDown]; break; - case 4: - _isXButton1Pressed = true; + case 3: [self mouseEvent:event withType:XButton1Down]; break; - case 5: - _isXButton2Pressed = true; + case 4: [self mouseEvent:event withType:XButton2Down]; break; @@ -367,14 +472,12 @@ - (void)rightMouseDown:(NSEvent *)event { - _isRightPressed = true; _lastMouseDownEvent = event; [self mouseEvent:event withType:RightButtonDown]; } - (void)mouseUp:(NSEvent *)event { - _isLeftPressed = false; [self mouseEvent:event withType:LeftButtonUp]; } @@ -383,16 +486,12 @@ switch(event.buttonNumber) { case 2: - case 3: - _isMiddlePressed = false; [self mouseEvent:event withType:MiddleButtonUp]; break; - case 4: - _isXButton1Pressed = false; + case 3: [self mouseEvent:event withType:XButton1Up]; break; - case 5: - _isXButton2Pressed = false; + case 4: [self mouseEvent:event withType:XButton2Up]; break; @@ -403,7 +502,6 @@ - (void)rightMouseUp:(NSEvent *)event { - _isRightPressed = false; [self mouseEvent:event withType:RightButtonUp]; } @@ -463,7 +561,8 @@ - (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type { - if([self ignoreUserInput: false] || _parent == nullptr) + auto parent = _parent.tryGet(); + if([self ignoreUserInput: false] || parent == nullptr) { return; } @@ -477,7 +576,12 @@ auto timestamp = static_cast([event timestamp] * 1000); auto modifiers = [self getModifiers:[event modifierFlags]]; - _parent->TopLevelEvents->RawKeyEvent(type, timestamp, modifiers, key, physicalKey, keySymbolUtf8); + parent->TopLevelEvents->RawKeyEvent(type, timestamp, modifiers, key, physicalKey, keySymbolUtf8); +} + +- (void)setModifiers:(NSEventModifierFlags)modifierFlags +{ + _modifierState = [self getModifiers:modifierFlags]; } - (void)flagsChanged:(NSEvent *)event @@ -537,12 +641,14 @@ } - (bool) handleKeyDown: (NSTimeInterval) timestamp withKey:(AvnKey)key withPhysicalKey:(AvnPhysicalKey)physicalKey withModifiers:(AvnInputModifiers)modifiers withKeySymbol:(NSString*)keySymbol { - return _parent->TopLevelEvents->RawKeyEvent(KeyDown, timestamp, modifiers, key, physicalKey, [keySymbol UTF8String]); + auto parent = _parent.tryGet(); + return parent->TopLevelEvents->RawKeyEvent(KeyDown, timestamp, modifiers, key, physicalKey, [keySymbol UTF8String]); } - (void)keyDown:(NSEvent *)event { - if([self ignoreUserInput: false] || _parent == nullptr) + auto parent = _parent.tryGet(); + if([self ignoreUserInput: false] || parent == nullptr) { return; } @@ -559,7 +665,7 @@ auto modifiers = [self getModifiers:[event modifierFlags]]; //InputMethod is active - if(_parent->InputMethod->IsActive()){ + if(parent->InputMethod->IsActive()){ auto hasInputModifier = modifiers != AvnInputModifiersNone; //Handle keyDown first if an input modifier is present @@ -591,7 +697,7 @@ if(keySymbol != nullptr && key != AvnKeyEnter){ auto timestamp = static_cast([event timestamp] * 1000); - _parent->TopLevelEvents->RawTextInputEvent(timestamp, [keySymbol UTF8String]); + parent->TopLevelEvents->RawTextInputEvent(timestamp, [keySymbol UTF8String]); } } } @@ -624,15 +730,17 @@ if (mod & NSEventModifierFlagCommand) rv |= Windows; - if (_isLeftPressed) + NSUInteger pressedButtons = [NSEvent pressedMouseButtons]; + + if (pressedButtons & (1 << 0)) // Left mouse button rv |= LeftMouseButton; - if (_isMiddlePressed) - rv |= MiddleMouseButton; - if (_isRightPressed) + if (pressedButtons & (1 << 1)) // Right mouse button rv |= RightMouseButton; - if (_isXButton1Pressed) + if (pressedButtons & (1 << 2)) // Middle mouse button + rv |= MiddleMouseButton; + if (pressedButtons & (1 << 3)) // X1 button rv |= XButton1MouseButton; - if (_isXButton2Pressed) + if (pressedButtons & (1 << 4)) // X2 button rv |= XButton2MouseButton; return (AvnInputModifiers)rv; @@ -667,16 +775,18 @@ } _markedRange = NSMakeRange(_selectedRange.location, [markedText length]); - - if(_parent->InputMethod->IsActive()){ - _parent->InputMethod->Client->SetPreeditText((char*)[markedText UTF8String]); + auto parent = _parent.tryGet(); + + if(parent->InputMethod->IsActive()){ + parent->InputMethod->Client->SetPreeditText((char*)[markedText UTF8String]); } } - (void)unmarkText { - if(_parent->InputMethod->IsActive()){ - _parent->InputMethod->Client->SetPreeditText(nullptr); + auto parent = _parent.tryGet(); + if(parent->InputMethod->IsActive()){ + parent->InputMethod->Client->SetPreeditText(nullptr); } _markedRange = NSMakeRange(_selectedRange.location, 0); @@ -704,7 +814,8 @@ - (void)insertText:(id)string replacementRange:(NSRange)replacementRange { - if(_parent == nullptr){ + auto parent = _parent.tryGet(); + if(parent == nullptr){ return; } @@ -723,7 +834,7 @@ uint64_t timestamp = static_cast([NSDate timeIntervalSinceReferenceDate] * 1000); - _parent->TopLevelEvents->RawTextInputEvent(timestamp, [text UTF8String]); + parent->TopLevelEvents->RawTextInputEvent(timestamp, [text UTF8String]); } - (NSUInteger)characterIndexForPoint:(NSPoint)point @@ -733,7 +844,8 @@ - (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange { - if(!_parent->InputMethod->IsActive()){ + auto parent = _parent.tryGet(); + if(!parent->InputMethod->IsActive()){ return NSZeroRect; } @@ -742,16 +854,20 @@ - (NSDragOperation)triggerAvnDragEvent: (AvnDragEventType) type info: (id )info { - auto localPoint = [self convertPoint:[info draggingLocation] toView:self]; - auto avnPoint = ToAvnPoint(localPoint); - auto point = [self translateLocalPoint:avnPoint]; + NSPoint eventLocation = [info draggingLocation]; + auto viewLocation = [self convertPoint:NSMakePoint(0, 0) toView:nil]; + auto localPoint = NSMakePoint(eventLocation.x - viewLocation.x, viewLocation.y - eventLocation.y); + auto point = ToAvnPoint(localPoint); auto modifiers = [self getModifiers:[[NSApp currentEvent] modifierFlags]]; NSDragOperation nsop = [info draggingSourceOperationMask]; auto effects = ConvertDragDropEffects(nsop); - int reffects = (int)_parent->TopLevelEvents + auto parent = _parent.tryGet(); + if (!parent) + 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); @@ -826,7 +942,7 @@ auto window = (AvnWindow*)[self window]; auto peer = [window automationPeer]; - if (!peer->IsRootProvider()) + if (peer == nullptr || !peer->IsRootProvider()) return nil; auto clientPoint = [window convertPointFromScreen:point]; @@ -863,6 +979,10 @@ // 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 9b92dba523..6d49fc85e0 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -29,12 +29,13 @@ @implementation CLASS_NAME { - ComPtr _parent; + ComObjectWeakPtr _parent; bool _closed; bool _isEnabled; bool _canBecomeKeyWindow; bool _isExtended; bool _isTransitioningToFullScreen; + bool _isTitlebarSession; AvnMenu* _menu; IAvnAutomationPeer* _automationPeer; AvnAutomationNode* _automationNode; @@ -42,7 +43,8 @@ -(AvnView* _Nullable) view { - return _parent->View; + auto parent = _parent.tryGet(); + return parent ? parent->View : nullptr; } -(void) setIsExtended:(bool)value; @@ -52,7 +54,8 @@ -(bool) isDialog { - return _parent->IsModal(); + auto parent = _parent.tryGet(); + return parent ? parent->IsModal() : false; } -(double) getExtendedTitleBarHeight @@ -194,7 +197,7 @@ - (BOOL)windowShouldClose:(NSWindow *_Nonnull)sender { - auto window = dynamic_cast(_parent.getRaw()); + auto window = _parent.tryGet().dynamicCast(); if(window != nullptr) { @@ -212,14 +215,11 @@ - (void)windowWillClose:(NSNotification *_Nonnull)notification { _closed = true; - if(_parent) + auto parent = _parent.tryGetWithCast(); + if (parent) { - ComPtr parent = _parent; - _parent = NULL; - - auto window = dynamic_cast(parent.getRaw()); - - if(window != nullptr) + auto window = parent.dynamicCast(); + if (window) { window->SetParent(nullptr); } @@ -247,7 +247,7 @@ if(_canBecomeKeyWindow && !_closed) { // If the window has a child window being shown as a dialog then don't allow it to become the key window. - auto parent = dynamic_cast(_parent.getRaw()); + auto parent = _parent.tryGet().dynamicCast(); if(parent != nullptr) { @@ -286,9 +286,10 @@ { [self showWindowMenuWithAppMenu]; - if(_parent != nullptr) + auto parent = _parent.tryGet(); + if(parent != nullptr) { - _parent->BaseEvents->Activated(); + parent->BaseEvents->Activated(); } [super becomeKeyWindow]; @@ -296,16 +297,21 @@ - (void)windowDidBecomeKey:(NSNotification *_Nonnull)notification { - if (_parent == nullptr) + auto parent = _parent.tryGet(); + if (parent == nullptr) return; - - _parent->BringToFront(); + + if (parent->View != nullptr) + [parent->View setModifiers:NSEvent.modifierFlags]; + + parent->BringToFront(); dispatch_async(dispatch_get_main_queue(), ^{ @try { [self invalidateShadow]; - if (self->_parent != nullptr) - self->_parent->BringToFront(); + auto parent = self->_parent.tryGet(); + if (parent != nullptr) + parent->BringToFront(); } @finally{ } @@ -314,7 +320,7 @@ - (void)windowDidMiniaturize:(NSNotification *_Nonnull)notification { - auto parent = dynamic_cast(_parent.operator->()); + auto parent = _parent.tryGetWithCast(); if(parent != nullptr) { @@ -324,7 +330,7 @@ - (void)windowDidDeminiaturize:(NSNotification *_Nonnull)notification { - auto parent = dynamic_cast(_parent.operator->()); + auto parent = _parent.tryGetWithCast(); if(parent != nullptr) { @@ -334,7 +340,7 @@ - (void)windowDidResize:(NSNotification *_Nonnull)notification { - auto parent = dynamic_cast(_parent.operator->()); + auto parent = _parent.tryGetWithCast(); if(parent != nullptr) { @@ -344,7 +350,7 @@ - (void)windowWillExitFullScreen:(NSNotification *_Nonnull)notification { - auto parent = dynamic_cast(_parent.operator->()); + auto parent = _parent.tryGetWithCast(); if(parent != nullptr) { @@ -354,7 +360,7 @@ - (void)windowDidExitFullScreen:(NSNotification *_Nonnull)notification { - auto parent = dynamic_cast(_parent.operator->()); + auto parent = _parent.tryGetWithCast(); if(parent != nullptr) { @@ -378,7 +384,7 @@ - (void)windowWillEnterFullScreen:(NSNotification *_Nonnull)notification { _isTransitioningToFullScreen = true; - auto parent = dynamic_cast(_parent.operator->()); + auto parent = _parent.tryGetWithCast(); if(parent != nullptr) { @@ -389,7 +395,7 @@ - (void)windowDidEnterFullScreen:(NSNotification *_Nonnull)notification { _isTransitioningToFullScreen = false; - auto parent = dynamic_cast(_parent.operator->()); + auto parent = _parent.tryGetWithCast(); if(parent != nullptr) { @@ -400,13 +406,15 @@ - (BOOL)windowShouldZoom:(NSWindow *_Nonnull)window toFrame:(NSRect)newFrame { - return _parent->CanZoom(); + auto parent = _parent.tryGet(); + return parent ? parent->CanZoom() : false; } -(void)windowDidResignKey:(NSNotification* _Nonnull)notification { - if(_parent) - _parent->BaseEvents->Deactivated(); + auto parent = _parent.tryGet(); + if(parent) + parent->BaseEvents->Deactivated(); [self showAppMenuOnly]; @@ -417,25 +425,44 @@ { AvnPoint position; - if(_parent != nullptr) + auto parent = _parent.tryGet(); + if(parent != nullptr) { - auto cparent = dynamic_cast(_parent.getRaw()); - - if(cparent != nullptr) + auto window = parent.dynamicCast(); + if(window != nullptr) { - if(!cparent->IsShown()) + if(!window->IsShown()) { return; } - if(cparent->WindowState() == Maximized) + // Don't adjust window state during fullscreen transitions + // as this can interfere with proper decoration restoration + if(!window->IsTransitioningWindowState()) { - cparent->SetWindowState(Normal); + // 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); + } } } - _parent->GetPosition(&position); - _parent->BaseEvents->PositionChanged(position); + parent->GetPosition(&position); + parent->BaseEvents->PositionChanged(position); } } @@ -445,40 +472,119 @@ return pt; } +- (NSView*) findRootView:(NSView*)view +{ + while (true) { + auto parent = [view superview]; + if(parent == nil) + return view; + view = parent; + } +} + +- (BOOL)isPointInTitlebar:(NSPoint)windowPoint +{ + auto parent = _parent.tryGetWithCast(); + if (!parent || !_isExtended) { + return NO; + } + + AvnView* view = parent->View; + NSPoint viewPoint = [view convertPoint:windowPoint fromView:nil]; + double titlebarHeight = [self getExtendedTitleBarHeight]; + + // Check if click is in titlebar area (top portion of view) + if (viewPoint.y <= titlebarHeight) { + // Verify we're actually in a toolbar-related area + NSView* hitView = [[self findRootView:view] hitTest:windowPoint]; + if (hitView) { + NSString* hitViewClass = [hitView className]; + if ([hitViewClass containsString:@"Toolbar"] || [hitViewClass containsString:@"Titlebar"]) { + return YES; + } + } + } + return NO; +} + - (void)sendEvent:(NSEvent *_Nonnull)event { + if (event.type == NSEventTypeLeftMouseDown) { + _isTitlebarSession = [self isPointInTitlebar:event.locationInWindow]; + } + [super sendEvent:event]; + auto parent = _parent.tryGetWithCast(); /// This is to detect non-client clicks. This can only be done on Windows... not popups, hence the dynamic_cast. - if(_parent != nullptr && dynamic_cast(_parent.getRaw()) != nullptr) + if(parent) { switch(event.type) { case NSEventTypeLeftMouseDown: { - AvnView* view = _parent->View; + AvnView* view = parent->View; NSPoint windowPoint = [event locationInWindow]; NSPoint viewPoint = [view convertPoint:windowPoint fromView:nil]; - + + auto targetView = [[self findRootView:view] hitTest: windowPoint]; + if(targetView) + { + auto targetViewClass = [targetView className]; + if([targetViewClass containsString: @"_NSThemeWidget"]) + return; + } + if (!NSPointInRect(viewPoint, view.bounds)) { auto avnPoint = ToAvnPoint(windowPoint); auto point = [self translateLocalPoint:avnPoint]; AvnVector delta = { 0, 0 }; - _parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, static_cast([event timestamp] * 1000), AvnInputModifiersNone, point, delta); + parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, AvnPointerDeviceType::Mouse, static_cast([event timestamp] * 1000), AvnInputModifiersNone, point, delta, .5f, .0f, .0f); } if(!_isTransitioningToFullScreen) { - _parent->BringToFront(); + parent->BringToFront(); + } + } + 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(); + parent->UpdateCursor(); } break; @@ -491,6 +597,10 @@ default: break; } + + if(event.type == NSEventTypeLeftMouseUp) { + _isTitlebarSession = NO; + } } } @@ -500,22 +610,32 @@ - (id _Nullable) accessibilityFocusedUIElement { - if (![self automationPeer]->IsRootProvider()) + auto automationPeer = [self automationPeer]; + if (automationPeer == nullptr || !automationPeer->IsRootProvider()) + return nil; + + auto focusedPeer = automationPeer->RootProvider_GetFocus(); + if (focusedPeer == nullptr) return nil; - auto focusedPeer = [self automationPeer]->RootProvider_GetFocus(); + 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 { - if (_automationPeer == nullptr) + auto parent = _parent.tryGet(); + if (parent && _automationPeer == nullptr) { - _automationPeer = _parent->BaseEvents->GetAutomationPeer(); + _automationPeer = parent->BaseEvents->GetAutomationPeer(); _automationNode = new AvnAutomationNode(self); _automationPeer->SetNode(_automationNode); } @@ -525,7 +645,9 @@ - (void)raiseChildrenChanged { - [_parent->View raiseAccessibilityChildrenChanged]; + auto parent = _parent.tryGet(); + if(parent) + [parent->View raiseAccessibilityChildrenChanged]; } - (void)raiseFocusChanged diff --git a/native/Avalonia.Native/src/OSX/IWindowStateChanged.h b/native/Avalonia.Native/src/OSX/IWindowStateChanged.h index f0905da3ac..11478724bf 100644 --- a/native/Avalonia.Native/src/OSX/IWindowStateChanged.h +++ b/native/Avalonia.Native/src/OSX/IWindowStateChanged.h @@ -6,7 +6,7 @@ #ifndef AVALONIA_NATIVE_OSX_IWINDOWSTATECHANGED_H #define AVALONIA_NATIVE_OSX_IWINDOWSTATECHANGED_H -struct IWindowStateChanged +struct IWindowStateChanged: public IUnknown { virtual void WindowStateChanged () = 0; virtual void StartStateTransition () = 0; 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/PlatformRenderTimer.mm b/native/Avalonia.Native/src/OSX/PlatformRenderTimer.mm index 7f3bea0c18..282f2414f9 100644 --- a/native/Avalonia.Native/src/OSX/PlatformRenderTimer.mm +++ b/native/Avalonia.Native/src/OSX/PlatformRenderTimer.mm @@ -72,6 +72,7 @@ public: static CVReturn OnTick(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) { + START_ARP_CALL; PlatformRenderTimer *object = (PlatformRenderTimer *)displayLinkContext; object->_callback->Run(); return kCVReturnSuccess; diff --git a/native/Avalonia.Native/src/OSX/PopupImpl.mm b/native/Avalonia.Native/src/OSX/PopupImpl.mm index 40fe8ce88b..13131bf91e 100644 --- a/native/Avalonia.Native/src/OSX/PopupImpl.mm +++ b/native/Avalonia.Native/src/OSX/PopupImpl.mm @@ -42,6 +42,16 @@ public: return WindowBaseImpl::Show(activate, true); } + + virtual bool ShouldTakeFocusOnShow() override + { + auto parent = Parent.tryGet(); + // Don't steal the focus from another windows if our parent is inactive + if (parent != nullptr && parent->Window != nullptr && ![parent->Window isKeyWindow]) + return false; + + return WindowBaseImpl::ShouldTakeFocusOnShow(); + } }; diff --git a/native/Avalonia.Native/src/OSX/StorageProvider.mm b/native/Avalonia.Native/src/OSX/StorageProvider.mm index 0fd77c6789..570281fdfd 100644 --- a/native/Avalonia.Native/src/OSX/StorageProvider.mm +++ b/native/Avalonia.Native/src/OSX/StorageProvider.mm @@ -173,8 +173,7 @@ public: if(initialDirectory != nullptr) { auto directoryString = [NSString stringWithUTF8String:initialDirectory]; - panel.directoryURL = [NSURL fileURLWithPath:directoryString - isDirectory:true]; + panel.directoryURL = [NSURL URLWithString:directoryString]; } auto handler = ^(NSModalResponse result) { @@ -236,12 +235,6 @@ public: panel.title = [NSString stringWithUTF8String:title]; } - if(initialDirectory != nullptr) - { - auto directoryString = [NSString stringWithUTF8String:initialDirectory]; - panel.directoryURL = [NSURL fileURLWithPath:directoryString - isDirectory:true]; - } if(initialFile != nullptr) { @@ -250,6 +243,12 @@ public: SetAccessoryView(panel, filters, false); + if(initialDirectory != nullptr) + { + auto directoryString = [NSString stringWithUTF8String:initialDirectory]; + panel.directoryURL = [NSURL URLWithString:directoryString]; + } + auto handler = ^(NSModalResponse result) { if(result == NSFileHandlingPanelOKButton) { @@ -306,12 +305,6 @@ public: panel.title = [NSString stringWithUTF8String:title]; } - if(initialDirectory != nullptr) - { - auto directoryString = [NSString stringWithUTF8String:initialDirectory]; - panel.directoryURL = [NSURL fileURLWithPath:directoryString - isDirectory:true]; - } if(initialFile != nullptr) { @@ -320,13 +313,29 @@ public: SetAccessoryView(panel, filters, true); + if(initialDirectory != nullptr) + { + auto directoryString = [NSString stringWithUTF8String:initialDirectory]; + panel.directoryURL = [NSURL URLWithString:directoryString]; + } + 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]; @@ -339,7 +348,7 @@ public: return; } - events->OnCompleted(nullptr); + events->OnCompletedWithFilter(nullptr, selectedIndex); }; @@ -356,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 ab0a5fb6a1..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(); @@ -106,10 +102,9 @@ protected: AvnPoint lastPositionSet; bool _shown; std::list _children; - bool _isModal; public: - WindowBaseImpl* Parent; + ComObjectWeakPtr Parent = nullptr; NSWindow * Window; ComPtr BaseEvents; }; diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index afae6d6b5b..551ea4c2e0 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -106,6 +106,13 @@ HRESULT WindowBaseImpl::Show(bool activate, bool isDialog) { _shown = true; [Window setCollectionBehavior:collectionBehavior]; + + // Ensure that we call needsDisplay = YES so that AvnView.updateLayer is called after the + // window is shown: if the client is pumping messages during the window creation/show + // process, it's possible that updateLayer gets called after the window is created but + // before it's is shown. + [View.layer setNeedsDisplay]; + return S_OK; } } @@ -136,6 +143,19 @@ HRESULT WindowBaseImpl::Hide() { @autoreleasepool { if (Window != nullptr) { + + // If window is hidden without ending attached sheet first, it will stuck in "order out" state, + // and block any new sheets from being attached. + // Additionaly, we don't know if user would define any custom panels, so we only end/close file dialog sheets. + auto attachedSheet = Window.attachedSheet; + if (attachedSheet + && ([attachedSheet isKindOfClass: [NSOpenPanel class]] + || [attachedSheet isKindOfClass: [NSSavePanel class]])) + { + [Window endSheet:attachedSheet]; + [attachedSheet close]; + } + auto frame = [Window frame]; AvnPoint point; @@ -391,50 +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 beginDraggingSessionWithItems:@[dragItem] event:nsevent - source:CreateDraggingSource((NSDragOperation) op, cb, sourceHandle)]; - return S_OK; -} - bool WindowBaseImpl::IsModal() { return false; } @@ -482,18 +458,19 @@ HRESULT WindowBaseImpl::SetParent(IAvnWindowBase *parent) { START_COM_CALL; @autoreleasepool { - if(Parent != nullptr) + + auto oldParent = Parent.tryGet(); + + if(oldParent != nullptr) { - Parent->_children.remove(this); + oldParent->_children.remove(this); } auto cparent = dynamic_cast(parent); Parent = cparent; - - _isModal = Parent != nullptr; - - if(Parent != nullptr && Window != nullptr){ + + if(cparent != nullptr && Window != nullptr){ // If one tries to show a child window with a minimized parent window, then the parent window will be // restored but macOS isn't kind enough to *tell* us that, so the window will be left in a non-interactive // state. Detect this and explicitly restore the parent window ourselves to avoid this situation. diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.h b/native/Avalonia.Native/src/OSX/WindowImpl.h index b931e933db..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; @@ -71,6 +75,8 @@ BEGIN_INTERFACE_MAP() void ExitFullScreenMode (); virtual HRESULT SetWindowState (AvnWindowState state) override; + + virtual HRESULT SetWindowState (AvnWindowState state, bool shouldResize); virtual bool IsModal() override; @@ -80,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; @@ -92,6 +100,8 @@ private: NSString *_lastTitle; bool _isEnabled; bool _canResize; + bool _canMinimize; + bool _canMaximize; bool _fullScreenActive; SystemDecorations _decorations; AvnWindowState _lastWindowState; @@ -101,6 +111,7 @@ private: bool _transitioningWindowState; bool _isClientAreaExtended; AvnExtendClientAreaChromeHints _extendClientHints; + bool _isModal; }; #endif //AVALONIA_NATIVE_OSX_WINDOWIMPL_H diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index 42ac37ae8c..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; @@ -451,6 +470,10 @@ void WindowImpl::ExitFullScreenMode() { } HRESULT WindowImpl::SetWindowState(AvnWindowState state) { + return SetWindowState(state, true); +} + +HRESULT WindowImpl::SetWindowState(AvnWindowState state, bool shouldResize) { START_COM_CALL; @autoreleasepool { @@ -474,61 +497,63 @@ HRESULT WindowImpl::SetWindowState(AvnWindowState state) { if (_shown) { _actualWindowState = _lastWindowState; - switch (state) { - case Maximized: - if (currentState == FullScreen) { - ExitFullScreenMode(); - } + if (shouldResize) { + switch (state) { + case Maximized: + if (currentState == FullScreen) { + ExitFullScreenMode(); + } - lastPositionSet.X = 0; - lastPositionSet.Y = 0; + lastPositionSet.X = 0; + lastPositionSet.Y = 0; - if ([Window isMiniaturized]) { - [Window deminiaturize:Window]; - } + if ([Window isMiniaturized]) { + [Window deminiaturize:Window]; + } - if (!IsZoomed()) { - DoZoom(); - } - break; + if (!IsZoomed()) { + DoZoom(); + } + break; - case Minimized: - if (currentState == FullScreen) { - ExitFullScreenMode(); - } else { - [Window miniaturize:Window]; - } - break; + case Minimized: + if (currentState == FullScreen) { + ExitFullScreenMode(); + } else { + [Window miniaturize:Window]; + } + break; - case FullScreen: - if ([Window isMiniaturized]) { - [Window deminiaturize:Window]; - } + case FullScreen: + if ([Window isMiniaturized]) { + [Window deminiaturize:Window]; + } - EnterFullScreenMode(); - break; + EnterFullScreenMode(); + break; - case Normal: - if ([Window isMiniaturized]) { - [Window deminiaturize:Window]; - } + case Normal: + if ([Window isMiniaturized]) { + [Window deminiaturize:Window]; + } - if (currentState == FullScreen) { - ExitFullScreenMode(); - } + if (currentState == FullScreen) { + ExitFullScreenMode(); + } - if (IsZoomed()) { - if (_decorations == SystemDecorationsFull) { - DoZoom(); - } else { - [Window setFrame:_preZoomSize display:true]; - auto newFrame = [Window contentRectForFrameRect:[Window frame]].size; + if (IsZoomed()) { + if (_decorations == SystemDecorationsFull) { + DoZoom(); + } else { + [Window setFrame:_preZoomSize display:true]; + auto newFrame = [Window contentRectForFrameRect:[Window frame]].size; - [View setFrameSize:newFrame]; - } + [View setFrameSize:newFrame]; + } - } - break; + } + break; + } } WindowEvents->WindowStateChanged(_actualWindowState); @@ -546,7 +571,7 @@ bool WindowImpl::IsModal() { } bool WindowImpl::IsOwned() { - return Parent != nullptr; + return Parent.tryGet() != nullptr; } NSWindowStyleMask WindowImpl::CalculateStyleMask() { @@ -577,7 +602,7 @@ NSWindowStyleMask WindowImpl::CalculateStyleMask() { break; } - if (!IsOwned()) { + if (_canMinimize && !IsOwned()) { s |= NSWindowStyleMaskMiniaturizable; } @@ -605,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/app.mm b/native/Avalonia.Native/src/OSX/app.mm index d3d3d938e9..5dc994fb6b 100644 --- a/native/Avalonia.Native/src/OSX/app.mm +++ b/native/Avalonia.Native/src/OSX/app.mm @@ -30,8 +30,6 @@ ComPtr _events; break; } - [[NSApplication sharedApplication] setActivationPolicy: AvnDesiredActivationPolicy]; - [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"]; [[NSApplication sharedApplication] setHelpMenu: [[NSMenu new] initWithTitle:@""]]; @@ -59,6 +57,16 @@ ComPtr _events; _events->OnUnhide(); } +- (void) applicationDidBecomeActive:(NSNotification *) notification +{ + _events->OnActivate(); +} + +- (void) applicationDidResignActive:(NSNotification *) notification +{ + _events->OnDeactivate(); +} + - (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames { auto array = CreateAvnStringArray(filenames); diff --git a/native/Avalonia.Native/src/OSX/automation.mm b/native/Avalonia.Native/src/OSX/automation.mm index 7171de38f7..30e1f5ea00 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()); @@ -149,6 +181,11 @@ return [super accessibilityTitle]; } +- (NSString *)accessibilityHelp +{ + return GetNSStringAndRelease(_peer->GetHelpText()); +} + - (id)accessibilityValue { if (_peer->IsRangeValueProvider()) @@ -171,10 +208,30 @@ { return GetNSStringAndRelease(_peer->GetName()); } + else if (_peer->GetAutomationControlType() == AutomationHeader) + { + return [NSNumber numberWithInt:_peer->GetHeadingLevel()]; + } return [super accessibilityValue]; } +- (void)setAccessibilityValue:(id)newValue +{ + if (_peer->IsValueProvider()) + { + if (newValue == nil) + _peer->ValueProvider_SetValue(nil); + else if ([newValue isKindOfClass:[NSString class]]) + _peer->ValueProvider_SetValue([(NSString*)newValue UTF8String]); + } + else if (_peer->IsRangeValueProvider()) + { + if ([newValue isKindOfClass:[NSNumber class]]) + _peer->RangeValueProvider_SetValue([(NSNumber*)newValue doubleValue]); + } +} + - (id)accessibilityMinValue { if (_peer->IsRangeValueProvider()) 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 75c8f2a021..9786a64b27 100644 --- a/native/Avalonia.Native/src/OSX/clipboard.mm +++ b/native/Avalonia.Native/src/OSX/clipboard.mm @@ -1,192 +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 GetItemCount(int64_t changeCount, int* ret) override + { + START_COM_ARP_CALL; + + 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 GetText (char* type, IAvnString**ppv) override + + virtual HRESULT GetItemFormats(int index, int64_t changeCount, IAvnStringArray** ret) override { - START_COM_CALL; + START_COM_ARP_CALL; + + if (ret == nullptr) + return E_POINTER; - @autoreleasepool + 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; + + 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]; - @autoreleasepool + 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); } } +}; + + +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; +} - virtual HRESULT Clear() override +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]; + if ([format containsString:@"/"]) + type = [UTType typeWithMIMEType:format]; else + type = [UTType exportedTypeWithIdentifier:format]; + + if (type == nil) { - [_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 ObtainFormats(IAvnStringArray** ppv) override + else { - START_COM_CALL; + auto bridgedFormat = (__bridge CFStringRef)format; + if (UTTypeIsDeclared(bridgedFormat)) + return format; - @autoreleasepool - { - *ppv = CreateAvnStringArray(_item == nil ? [_pb types] : [_item types]); - return S_OK; - } + 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]; + + auto count = formats->GetCount(); + if (count == 0) + return [NSArray array]; + + auto utis = [NSMutableArray arrayWithCapacity:count]; + IAvnString* format; + for (auto i = 0; i < count; ++i) + { + 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 d1dbe9d186..2a92eb3bcf 100644 --- a/native/Avalonia.Native/src/OSX/main.mm +++ b/native/Avalonia.Native/src/OSX/main.mm @@ -129,14 +129,22 @@ public: } } - virtual HRESULT SetShowInDock(int show) override + virtual HRESULT SetShowInDock(int show) override { START_COM_CALL; @autoreleasepool { - AvnDesiredActivationPolicy = show - ? NSApplicationActivationPolicyRegular : NSApplicationActivationPolicyAccessory; + NSApplication* app = [NSApplication sharedApplication]; + NSApplicationActivationPolicy requestedPolicy = show + ? NSApplicationActivationPolicyRegular + : NSApplicationActivationPolicyAccessory; + + if ([app activationPolicy] != requestedPolicy) + { + [app setActivationPolicy:requestedPolicy]; + } + return S_OK; } } @@ -304,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; } } @@ -470,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..d16495969e 100644 --- a/nukebuild/ApiDiffHelper.cs +++ b/nukebuild/ApiDiffHelper.cs @@ -1,313 +1,577 @@ +#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, '/', '\\'); + } - public static async Task GetDiff( - Tool apiDiffTool, string outputFolder, - string packagePath, string baselineVersion) + 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"); + } + + /// + /// 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); + } + + public static void GenerateMarkdownDiff( + Tool apiDiffTool, + PackageDiffInfo packageDiff, + AbsolutePath rootOutputFolderPath, + string baselineDisplay, + string currentDisplay) + { + Information("Creating markdown diff for package {Id}", packageDiff.PackageId); - var pairs = new List<(string baseline, string target)>(); + var packageOutputFolderPath = rootOutputFolderPath / packageDiff.PackageId; + Directory.CreateDirectory(packageOutputFolderPath); - var packageId = GetPackageId(packagePath); + // 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!, []); - // 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); + try + { + var allErrors = new List(); - var targetTfm = baselineDll.target; - var targetDll = targetDlls.FirstOrDefault(e => - e.target.StartsWith(targetTfm) && e.entry.Name == baselineDll.entry.Name); - if (targetDll is null) + // 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; + } + } + + AbsolutePath[] GetFrameworkDiffFiles(NuGetFramework framework) + { + 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(); + } + + static byte[] HashFile(AbsolutePath filePath) + { + using var stream = File.OpenRead(filePath); + return SHA256.HashData(stream); } } - private static readonly (string package, string oldTfm, string newTfm)[] s_tfmRedirects = new[] + public static void MergePackageMarkdownDiffFiles( + AbsolutePath rootOutputFolderPath, + string baselineDisplay, + string currentDisplay) { - // 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)) + const string mergedFileName = "_diff.md"; + + 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) { - Directory.CreateDirectory(suppressionFilesFolder!); + writer.WriteLine(); + writer.WriteLine("No changes."); + return; } - await using var baselineStream = await DownloadBaselinePackage(packagePath, baselineVersion); - if (baselineStream == null) - return; + foreach (var filePath in filePaths) + { + writer.WriteLine(); + + using var reader = File.OpenText(filePath); + + while (reader.ReadLine() is { } line) + { + if (line.StartsWith('#')) + writer.Write('#'); - 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)) + writer.WriteLine(line); + } + } + } + + 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) { - var targetDlls = GetDlls(target); - var baselineDlls = GetDlls(baseline); + throw new AggregateException( + $"{taskName} task has failed for \"{packageId}\" package", + errors.Select(error => new Exception(error))); + } + } - var left = new List(); - var right = new List(); + 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); + + Information("API baseline version is {Baseline} for current version {Current}", baselineVersion, currentVersion); - var packageId = GetPackageId(packagePath); - var suppressionFile = Path.Combine(suppressionFilesFolder, packageId + ".nupkg.xml"); + var memoryStream = new MemoryStream(); + var packageDiffs = ImmutableArray.CreateBuilder(); - // 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) + 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)) { - var baselineDllPath = await ExtractDll("baseline", baselineDll, tempFolder); + using var packageReader = new PackageArchiveReader(currentArchive); + packageId = packageReader.NuspecReader.GetId(); - 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})"); - } + baselineFolderPath = outputFolderPath / "baseline" / packageId; + Directory.CreateDirectory(baselineFolderPath); - 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}."); - } + currentFolderPath = outputFolderPath / "current" / packageId; + Directory.CreateDirectory(currentFolderPath); + + currentFolderNames = ExtractDiffableAssembliesFromPackage(currentArchive, currentFolderPath); + } - var targetDllPath = await ExtractDll("target", targetDll, tempFolder); + var packageExists = await downloadContext.FindPackageByIdResource.DoesPackageExistAsync( + packageId, + baselineVersion, + downloadContext.CacheContext, + NullLogger.Instance, + CancellationToken.None); - left.Add(baselineDllPath); - right.Add(targetDllPath); + if (packageExists) + { + // 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); + baselineFolderNames = ExtractDiffableAssembliesFromPackage(baselineArchive, baselineFolderPath); } + else + { + Information("Baseline package {Id} {Version} does not exist. Assuming new package.", packageId, baselineVersion); + baselineFolderNames = []; + } + + if (currentFolderNames.Count == 0 && baselineFolderNames.Count == 0) + continue; - if (left.Any()) + var frameworkDiffs = new List(); + + // Match frameworks + foreach (var (framework, currentFolderName) in currentFolderNames) { - var args = $""" -l={string.Join(',', left)} -r="{string.Join(',', right)}" """; - if (File.Exists(suppressionFile)) - { - args += $""" --suppression-file="{suppressionFile}" """; - } + if (!baselineFolderNames.TryGetValue(framework, out var baselineFolderName)) + baselineFolderName = currentFolderName; - if (updateSuppressionFile) - { - args += $""" --suppression-output-file="{suppressionFile}" --generate-suppression-file=true """; - } + var frameworkDiff = new FrameworkDiffInfo( + framework, + baselineFolderPath / FolderLib / baselineFolderName, + currentFolderPath / FolderLib / currentFolderName); + + EnsureAssemblies(frameworkDiff); + + frameworkDiffs.Add(frameworkDiff); + } + + packageDiffs.Add(new PackageDiffInfo(packageId, [..frameworkDiffs])); + } - var result = apiCompatTool(args, tempFolder) - .Where(t => t.Type == OutputType.Err).ToArray(); - if (result.Any()) + return new GlobalDiffInfo(baselineVersion, currentVersion, packageDiffs.DrainToImmutable()); + + // Ensure that both sides of a framework diff have matching assemblies. + // For any missing, generate an empty assembly to diff against. + // (The API diff tool supports added and removed assemblies in theory but actually throws if one side doesn't have any.) + static void EnsureAssemblies(FrameworkDiffInfo frameworkDiff) + { + Directory.CreateDirectory(frameworkDiff.BaselineFolderPath); + Directory.CreateDirectory(frameworkDiff.CurrentFolderPath); + + var baselineFileNames = GetFileNames(frameworkDiff.BaselineFolderPath); + var currentFileNames = GetFileNames(frameworkDiff.CurrentFolderPath); + + GenerateMissingAssemblies(currentFileNames.Except(baselineFileNames), frameworkDiff.BaselineFolderPath); + GenerateMissingAssemblies(baselineFileNames.Except(currentFileNames), frameworkDiff.CurrentFolderPath); + + static string[] GetFileNames(string folderPath) + => Directory.EnumerateFiles(folderPath, "*.dll").Select(Path.GetFileName)!.ToArray(); + + void GenerateMissingAssemblies(IEnumerable missingFileNames, string folderPath) + { + foreach (var missingFileName in missingFileNames) { - throw new AggregateException( - $"ApiDiffValidation task has failed for \"{Path.GetFileName(packagePath)}\" package", - result.Select(r => new Exception(r.Text))); + GenerateEmptyAssembly( + Path.GetFileNameWithoutExtension(missingFileName), + frameworkDiff.Framework.GetShortFolderName(), + Path.Join(folderPath, missingFileName)); } } } } - 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); + } + + /// + /// 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) + { + 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 DownloadBaselinePackage(string packagePath, string baselineVersion) + static async Task DownloadBaselinePackageAsync( + Stream destinationStream, + NuGetDownloadContext context, + string packageId, + NuGetVersion version) { - if (baselineVersion is null) + 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) + static void GenerateEmptyAssembly(string name, string framework, string outputFilePath) { - 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)) + var projectContents = + $""" + + + {framework} + Release + None + + + """; + + var tempDirPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + var projectFilePath = Path.Join(tempDirPath, $"{name}.csproj"); + + Directory.CreateDirectory(tempDirPath); + + try { - await dllEntry.entry.Open().CopyToAsync(dllFile); + File.WriteAllText(projectFilePath, projectContents); + + using var process = ProcessTasks.StartProcess( + "dotnet", + $"build \"{projectFilePath}\" --output \"{tempDirPath}\"", + tempDirPath); + + process.AssertZeroExitCode(); + + File.Copy(Path.Join(tempDirPath, $"{name}.dll"), outputFilePath); } + finally + { + if (Directory.Exists(tempDirPath)) + Directory.Delete(tempDirPath, true); + } + } - return dllPath; + public sealed class GlobalDiffInfo( + NuGetVersion baselineVersion, + NuGetVersion currentVersion, + ImmutableArray packages) + { + public NuGetVersion BaselineVersion { get; } = baselineVersion; + public NuGetVersion CurrentVersion { get; } = currentVersion; + public ImmutableArray Packages { get; } = packages; } - static void GenerateApiListing(Tool apiDiffTool, string inputFile, string outputFile, string workingDif) + public sealed class PackageDiffInfo(string packageId, ImmutableArray frameworks) { - 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 string PackageId { get; } = packageId; + public ImmutableArray Frameworks { get; } = frameworks; + } + + public sealed class FrameworkDiffInfo( + NuGetFramework framework, + AbsolutePath baselineFolderPath, + AbsolutePath currentFolderPath) + { + 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 c71a0c1e39..41c5cbe0cf 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -9,17 +9,13 @@ using System.Xml.Linq; using Nuke.Common; using Nuke.Common.Tooling; using Nuke.Common.Tools.DotNet; -using Nuke.Common.Tools.Npm; 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.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; /* @@ -34,15 +30,19 @@ 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; - [PackageExecutable("dotnet-ilrepack", "ILRepackTool.dll", Framework = "net8.0")] + [NuGetPackage("Microsoft.DotNet.ApiDiff.Tool", "Microsoft.DotNet.ApiDiff.Tool.dll", Framework = "net8.0")] + Tool ApiDiffTool; + + [NuGetPackage("dotnet-ilrepack", "ILRepackTool.dll", Framework = "net8.0")] Tool IlRepackTool; - + protected override void OnBuildInitialized() { Parameters = new BuildParameters(this, ScheduledTargets.Contains(BuildToNuGetCache)); @@ -57,6 +57,7 @@ partial class Build : NukeBuild Information("Repository Name: " + Parameters.RepositoryName); Information("Repository Branch: " + Parameters.RepositoryBranch); } + Information("Configuration: " + Parameters.Configuration); Information("IsLocalBuild: " + Parameters.IsLocalBuild); Information("IsRunningOnUnix: " + Parameters.IsRunningOnUnix); @@ -73,12 +74,16 @@ partial class Build : NukeBuild void ExecWait(string preamble, string command, string args) { Console.WriteLine(preamble); - Process.Start(new ProcessStartInfo(command, args) {UseShellExecute = false}).WaitForExit(); + Process.Start(new ProcessStartInfo(command, args) { UseShellExecute = false }).WaitForExit(); } + ExecWait("dotnet version:", "dotnet", "--info"); ExecWait("dotnet workloads:", "dotnet", "workload list"); Information("Processor count: " + Environment.ProcessorCount); Information("Available RAM: " + GC.GetGCMemoryInfo().TotalAvailableMemoryBytes / 0x100000 + "MB"); + + if (Host is AzurePipelines azurePipelines) + azurePipelines.UpdateBuildNumber(Parameters.Version); } DotNetConfigHelper ApplySettingCore(DotNetConfigHelper c) @@ -87,7 +92,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") @@ -96,6 +101,7 @@ partial class Build : NukeBuild .AddProperty("SkipBuildingTests", "True"); return c; } + DotNetBuildSettings ApplySetting(DotNetBuildSettings c, Configure configurator = null) => ApplySettingCore(c).Build.Apply(configurator); @@ -105,30 +111,39 @@ partial class Build : NukeBuild DotNetTestSettings ApplySetting(DotNetTestSettings c, Configure configurator = null) => ApplySettingCore(c).Test.Apply(configurator); + DotNetRunSettings ApplySetting(DotNetRunSettings c, Configure configurator = null) => + ApplySettingCore(c).Run.Apply(configurator); + Target Clean => _ => _.Executes(() => { - Parameters.BuildDirs.ForEach(DeleteDirectory); - Parameters.BuildDirs.ForEach(EnsureCleanDirectory); - 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 => _ => _ - .DependsOn(Clean) - .OnlyWhenStatic(() => !Parameters.SkipPreviewer) + // Ensure that Bun.Official.Tool is downloaded at least once on CI to work around https://github.com/dotnet/sdk/issues/51831 + Target InitDnx => _ => _ .Executes(() => { - var webappDir = RootDirectory / "src" / "Avalonia.DesignerSupport" / "Remote" / "HtmlTransport" / "webapp"; - - NpmTasks.NpmInstall(c => c - .SetProcessWorkingDirectory(webappDir) - .SetProcessArgumentConfigurator(a => a.Add("--silent"))); - NpmTasks.NpmRun(c => c - .SetProcessWorkingDirectory(webappDir) - .SetCommand("dist")); + var process = ProcessTasks.StartProcess( + "dnx", + "Bun.Unofficial.Tool --yes -- install", + $"{RootDirectory}/src/Browser/Avalonia.Browser/webapp"); + process.AssertZeroExitCode(); }); Target CompileNative => _ => _ @@ -143,8 +158,7 @@ partial class Build : NukeBuild }); Target Compile => _ => _ - .DependsOn(Clean, CompileNative) - .DependsOn(CompileHtmlPreviewer) + .DependsOn(Clean, CompileNative, InitDnx) .Executes(() => { DotNetBuild(c => ApplySetting(c) @@ -168,6 +182,17 @@ partial class Build : NukeBuild }); void RunCoreTest(string projectName) + { + RunCoreTest(projectName, (project, tfm) => + { + // NOTE: Nuke DotNetTest doesn't support Microsoft.Testing.Platform yet. + // Issue: https://github.com/nuke-build/nuke/issues/1584. + // However, we can easily use DotNetRun instead since MTP projects are executables. + DotNetRun(c => ApplySetting(c, project, tfm)); + }); + } + + void RunCoreTest(string projectName, Action runTest) { Information($"Running tests from {projectName}"); var project = RootDirectory.GlobFiles(@$"**\{projectName}.csproj").FirstOrDefault() @@ -196,11 +221,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") @@ -213,30 +238,31 @@ 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); } } + DotNetRunSettings ApplySetting(DotNetRunSettings settings, string project, string tfm) => + ApplySetting(settings) + .SetProjectFile(project) + .SetFramework(tfm) + .EnableNoBuild() + .EnableNoRestore() + // Disable progress output (works like terminal logger which isn't so nice in CI). + // See https://github.com/microsoft/testfx/issues/7056 + .AddApplicationArguments("--no-progress") + .When(_ => Parameters.PublishTestResults, _ => _ + .AddApplicationArguments("--report-trx", "--results-directory", Parameters.TestResultsRoot)); + Target RunHtmlPreviewerTests => _ => _ - .DependsOn(CompileHtmlPreviewer) - .OnlyWhenStatic(() => !(Parameters.SkipPreviewer || Parameters.SkipTests)) + .OnlyWhenStatic(() => !(Parameters.SkipTests)) .Executes(() => { - var webappTestDir = RootDirectory / "tests" / "Avalonia.DesignerSupport.Tests" / "Remote" / "HtmlTransport" / "webapp"; - - NpmTasks.NpmInstall(c => c - .SetProcessWorkingDirectory(webappTestDir) - .SetProcessArgumentConfigurator(a => a.Add("--silent"))); - NpmTasks.NpmRun(c => c - .SetProcessWorkingDirectory(webappTestDir) - .SetCommand("test")); + var webappTest = RootDirectory / "tests" / "Avalonia.DesignerSupport.Tests"; + + DotNetMSBuild(o => o + .SetProcessWorkingDirectory(webappTest) + .SetTargets("BunRunTests")); }); Target RunCoreLibsTests => _ => _ @@ -246,13 +272,13 @@ partial class Build : NukeBuild { RunCoreTest("Avalonia.Base.UnitTests"); RunCoreTest("Avalonia.Controls.UnitTests"); - RunCoreTest("Avalonia.Controls.DataGrid.UnitTests"); 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 => _ => _ @@ -261,8 +287,6 @@ partial class Build : NukeBuild .Executes(() => { RunCoreTest("Avalonia.Skia.RenderTests"); - if (Parameters.IsRunningOnWindows) - RunCoreTest("Avalonia.Direct2D1.RenderTests"); }); Target RunToolsTests => _ => _ @@ -280,11 +304,7 @@ partial class Build : NukeBuild .DependsOn(Compile) .Executes(() => { - void DoMemoryTest() - { - RunCoreTest("Avalonia.LeakTests"); - } - ControlFlow.ExecuteWithRetry(DoMemoryTest, delay: TimeSpan.FromMilliseconds(3)); + RunCoreTest("Avalonia.LeakTests"); }); Target ZipFiles => _ => _ @@ -310,8 +330,8 @@ partial class Build : NukeBuild BuildTasksPatcher.PatchBuildTasksInPackage(Parameters.NugetIntermediateRoot / "Avalonia.Build.Tasks." + Parameters.Version + ".nupkg", IlRepackTool); - var config = Numerge.MergeConfiguration.LoadFile(RootDirectory / "nukebuild" / "numerge.config"); - EnsureCleanDirectory(Parameters.NugetRoot); + var config = Numerge.MergeConfiguration.LoadFile(RootDirectory / "nukebuild" / "numerge.json"); + Parameters.NugetRoot.CreateOrCleanDirectory(); if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config, new NumergeNukeLogger())) throw new Exception("Package merge failed"); @@ -319,27 +339,59 @@ 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))); + var apiDiffPath = Parameters.ArtifactsDir / "api-diff"; + apiDiffPath.DeleteDirectory(); + + GlobalDiff = await ApiDiffHelper.DownloadAndExtractPackagesAsync( + Directory.EnumerateFiles(Parameters.NugetRoot, "*.nupkg").Select(path => (AbsolutePath)path), + NuGetVersion.Parse(Parameters.Version), + Parameters.IsReleaseBranch, + apiDiffPath / "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) @@ -361,6 +413,7 @@ partial class Build : NukeBuild Target CiAzureWindows => _ => _ .DependsOn(Package) + .DependsOn(VerifyXamlCompilation) .DependsOn(ZipFiles); Target BuildToNuGetCache => _ => _ @@ -407,6 +460,67 @@ partial class Build : NukeBuild file.GenerateCppHeader()); }); + Target VerifyXamlCompilation => _ => _ + .DependsOn(CreateNugetPackages) + .Executes(() => + { + var buildTestsDirectory = RootDirectory / "tests" / "BuildTests"; + var artifactsDirectory = buildTestsDirectory / "artifacts"; + var nugetCacheDirectory = artifactsDirectory / "nuget-cache"; + + artifactsDirectory.DeleteDirectory(); + BuildTestsAndVerify("Debug"); + BuildTestsAndVerify("Release"); + + void BuildTestsAndVerify(string configuration) + { + var configName = configuration.ToLowerInvariant(); + + DotNetBuild(settings => settings + .SetConfiguration(configuration) + .SetProperty("AvaloniaVersion", Parameters.Version) + .SetProperty("NuGetPackageRoot", nugetCacheDirectory) + .SetPackageDirectory(nugetCacheDirectory) + .SetProjectFile(buildTestsDirectory / "BuildTests.sln") + .SetProcessAdditionalArguments("--nodeReuse:false")); + + // Standard compilation - should have compiled XAML + VerifyBuildTestAssembly("bin", "BuildTests"); + VerifyBuildTestAssembly("bin", "BuildTests.Android"); + VerifyBuildTestAssembly("bin", "BuildTests.Browser"); + VerifyBuildTestAssembly("bin", "BuildTests.Desktop"); + VerifyBuildTestAssembly("bin", "BuildTests.FSharp"); + VerifyBuildTestAssembly("bin", "BuildTests.iOS"); + VerifyBuildTestAssembly("bin", "BuildTests.WpfHybrid"); + + // Publish previously built project without rebuilding - should have compiled XAML + PublishBuildTestProject("BuildTests.Desktop", noBuild: true); + VerifyBuildTestAssembly("publish", "BuildTests.Desktop"); + + // Publish NativeAOT build, then run it - should not crash and have the expected output + PublishBuildTestProject("BuildTests.NativeAot"); + var exeExtension = OperatingSystem.IsWindows() ? ".exe" : null; + XamlCompilationVerifier.VerifyNativeAot( + GetBuildTestOutputPath("publish", "BuildTests.NativeAot", exeExtension)); + + void PublishBuildTestProject(string projectName, bool? noBuild = null) + => DotNetPublish(settings => settings + .SetConfiguration(configuration) + .SetProperty("AvaloniaVersion", Parameters.Version) + .SetProperty("NuGetPackageRoot", nugetCacheDirectory) + .SetPackageDirectory(nugetCacheDirectory) + .SetNoBuild(noBuild) + .SetProject(buildTestsDirectory / projectName / (projectName + ".csproj")) + .SetProcessAdditionalArguments("--nodeReuse:false")); + + void VerifyBuildTestAssembly(string folder, string projectName) + => XamlCompilationVerifier.VerifyAssemblyCompiledXaml( + GetBuildTestOutputPath(folder, projectName, ".dll")); + + AbsolutePath GetBuildTestOutputPath(string folder, string projectName, string extension) + => artifactsDirectory / folder / projectName / configName / (projectName + extension); + } + }); public static int Main() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) diff --git a/nukebuild/BuildParameters.cs b/nukebuild/BuildParameters.cs index 50f4f1c5da..4b55e1691e 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,40 +9,35 @@ 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; } - - [Parameter(Name = "skip-previewer")] - public bool SkipPreviewer { get; set; } + public string? ForceNugetVersion { 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 { public string Configuration { get; } public bool SkipTests { get; } - 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,21 +63,20 @@ 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) { // ARGUMENTS Configuration = b.Configuration ?? "Release"; SkipTests = b.SkipTests; - SkipPreviewer = b.SkipPreviewer; // CONFIGURATION MainRepo = "https://github.com/AvaloniaUI/Avalonia"; @@ -94,8 +90,7 @@ public partial class Build IsRunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX; IsRunningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - IsRunningOnAzure = Host is AzurePipelines || - Environment.GetEnvironmentVariable("LOGNAME") == "vsts"; + IsRunningOnAzure = Host is AzurePipelines; if (IsRunningOnAzure) { @@ -116,10 +111,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) @@ -127,7 +121,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; @@ -145,7 +141,11 @@ public partial class Build NugetIntermediateRoot = RootDirectory / "build-intermediate" / "nuget"; ZipRoot = ArtifactsDir / "zip"; TestResultsRoot = ArtifactsDir / "test-results"; - BuildDirs = GlobDirectories(RootDirectory, "**bin").Concat(GlobDirectories(RootDirectory, "**obj")).ToList(); + 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"; ZipCoreArtifacts = ZipRoot / ("Avalonia-" + FileZipSuffix); @@ -154,13 +154,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/DotNetConfigHelper.cs b/nukebuild/DotNetConfigHelper.cs index 9d43261616..b5315b3f5a 100644 --- a/nukebuild/DotNetConfigHelper.cs +++ b/nukebuild/DotNetConfigHelper.cs @@ -7,6 +7,7 @@ public class DotNetConfigHelper public DotNetBuildSettings Build; public DotNetPackSettings Pack; public DotNetTestSettings Test; + public DotNetRunSettings Run; public DotNetConfigHelper(DotNetBuildSettings s) { @@ -23,6 +24,11 @@ public class DotNetConfigHelper Test = s; } + public DotNetConfigHelper(DotNetRunSettings s) + { + Run = s; + } + public DotNetConfigHelper AddProperty(string key, bool value) => AddProperty(key, value.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()); public DotNetConfigHelper AddProperty(string key, string value) @@ -30,6 +36,7 @@ public class DotNetConfigHelper Build = Build?.AddProperty(key, value); Pack = Pack?.AddProperty(key, value); Test = Test?.AddProperty(key, value); + Run = Run?.AddProperty(key, value); return this; } @@ -39,6 +46,7 @@ public class DotNetConfigHelper Build = Build?.SetConfiguration(configuration); Pack = Pack?.SetConfiguration(configuration); Test = Test?.SetConfiguration(configuration); + Run = Run?.SetConfiguration(configuration); return this; } @@ -47,10 +55,12 @@ public class DotNetConfigHelper Build = Build?.SetVerbosity(verbosity); Pack = Pack?.SetVerbosity(verbosity); Test = Test?.SetVerbosity(verbosity); + Run = Run?.SetVerbosity(verbosity); return this; } public static implicit operator DotNetConfigHelper(DotNetBuildSettings s) => new DotNetConfigHelper(s); public static implicit operator DotNetConfigHelper(DotNetPackSettings s) => new DotNetConfigHelper(s); public static implicit operator DotNetConfigHelper(DotNetTestSettings s) => new DotNetConfigHelper(s); + public static implicit operator DotNetConfigHelper(DotNetRunSettings s) => new DotNetConfigHelper(s); } diff --git a/nukebuild/XamlCompilationVerifier.cs b/nukebuild/XamlCompilationVerifier.cs new file mode 100644 index 0000000000..ecf84f7f00 --- /dev/null +++ b/nukebuild/XamlCompilationVerifier.cs @@ -0,0 +1,56 @@ +using System; +using System.Linq; +using Mono.Cecil; +using Nuke.Common.Tooling; +using Serilog; + +internal static class XamlCompilationVerifier +{ + public static void VerifyAssemblyCompiledXaml(string assemblyPath) + { + const string avaloniaResourcesTypeName = "CompiledAvaloniaXaml.!AvaloniaResources"; + const string mainViewTypeName = "BuildTests.MainView"; + const string populateMethodName = "!XamlIlPopulate"; + + using var assembly = AssemblyDefinition.ReadAssembly(assemblyPath); + + if (assembly.MainModule.GetType(avaloniaResourcesTypeName) is null) + { + throw new InvalidOperationException( + $"Assembly {assemblyPath} is missing type {avaloniaResourcesTypeName}"); + } + + if (assembly.MainModule.GetType(mainViewTypeName) is not { } mainViewType) + { + throw new InvalidOperationException( + $"Assembly {assemblyPath} is missing type {mainViewTypeName}"); + } + + if (!mainViewType.Methods.Any(method => method.Name == populateMethodName)) + { + throw new InvalidOperationException( + $"Assembly {assemblyPath} is missing method {populateMethodName} on {mainViewTypeName}"); + } + + Log.Information($"Assembly {assemblyPath} correctly has compiled XAML"); + } + + public static void VerifyNativeAot(string programPath) + { + const string expectedOutput = "Hello from AOT"; + + using var process = ProcessTasks.StartProcess(programPath, string.Empty); + + process.WaitForExit(); + process.AssertZeroExitCode(); + + var output = process.Output.Select(o => o.Text).FirstOrDefault(); + if (output != expectedOutput) + { + throw new InvalidOperationException( + $"{programPath} returned text \"{output}\", expected \"{expectedOutput}\""); + } + + Log.Information($"Native program {programPath} correctly has compiled XAML"); + } +} diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj index a2c4f890da..075715346d 100644 --- a/nukebuild/_build.csproj +++ b/nukebuild/_build.csproj @@ -9,26 +9,18 @@ $(AvsCurrentTargetFramework) true - - https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8-transport/nuget/v3/index.json - - - + - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + + + @@ -36,8 +28,9 @@ - - + diff --git a/nukebuild/numerge.config b/nukebuild/numerge.config deleted file mode 100644 index 71b77bee93..0000000000 --- a/nukebuild/numerge.config +++ /dev/null @@ -1,28 +0,0 @@ -{ - "Packages": - [ - { - "Id": "Avalonia", - "MergeAll": true, - "Exclude": ["Avalonia.Remote.Protocol"], - "IncomingIncludeAssetsOverride": "", - "Merge": [ - { - "Id": "Avalonia.Build.Tasks", - "IgnoreMissingFrameworkBinaries": true, - "DoNotMergeDependencies": true - }, - { - "Id": "Avalonia.Generators", - "IgnoreMissingFrameworkBinaries": true, - "DoNotMergeDependencies": true - }, - { - "Id": "Avalonia.Analyzers", - "IgnoreMissingFrameworkBinaries": true, - "DoNotMergeDependencies": true - } - ] - } - ] -} diff --git a/nukebuild/numerge.json b/nukebuild/numerge.json new file mode 100644 index 0000000000..392348a044 --- /dev/null +++ b/nukebuild/numerge.json @@ -0,0 +1,50 @@ +{ + "Packages": + [ + { + "Id": "Avalonia", + "MergeAll": true, + "Exclude": ["Avalonia.Remote.Protocol"], + "IncomingIncludeAssetsOverride": "", + "Merge": [ + { + "Id": "Avalonia.Build.Tasks", + "IgnoreMissingFrameworkBinaries": true, + "DoNotMergeDependencies": true + }, + { + "Id": "Avalonia.Generators", + "IgnoreMissingFrameworkBinaries": true, + "DoNotMergeDependencies": true + }, + { + "Id": "Avalonia.Analyzers.CSharp", + "IgnoreMissingFrameworkBinaries": true, + "DoNotMergeDependencies": true + }, + { + "Id": "Avalonia.Analyzers.VisualBasic", + "IgnoreMissingFrameworkBinaries": true, + "DoNotMergeDependencies": true + }, + { + "Id": "Avalonia.Analyzers.CodeFixes.CSharp", + "IgnoreMissingFrameworkBinaries": true, + "DoNotMergeDependencies": true + } + ] + }, + { + "Id": "Avalonia.Win32", + "MergeAll": false, + "IncomingIncludeAssetsOverride": "", + "Merge": [ + { + "Id": "Avalonia.Win32.Automation", + "IgnoreMissingFrameworkBinaries": true, + "DoNotMergeDependencies": true + } + ] + } + ] +} diff --git a/packages/Avalonia/Avalonia.csproj b/packages/Avalonia/Avalonia.csproj index d25647b01c..e59e72f13b 100644 --- a/packages/Avalonia/Avalonia.csproj +++ b/packages/Avalonia/Avalonia.csproj @@ -1,22 +1,27 @@  - $(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0 + $(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks) Avalonia - + - - all - true - TargetFramework=netstandard2.0 - - + - + + @@ -30,13 +35,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/AvaloniaBuildTasks.targets b/packages/Avalonia/AvaloniaBuildTasks.targets index 9d68af031f..8fe77a095d 100644 --- a/packages/Avalonia/AvaloniaBuildTasks.targets +++ b/packages/Avalonia/AvaloniaBuildTasks.targets @@ -63,7 +63,7 @@ $(BuildAvaloniaResourcesDependsOn);AddAvaloniaResources;ResolveReferences;_GenerateAvaloniaResourcesDependencyCache - $(CompileAvaloniaXamlDependsOn);FindReferenceAssembliesForReferences;PrepareToCompileAvaloniaXaml + $(CompileAvaloniaXamlDependsOn);FindReferenceAssembliesForReferences @@ -107,34 +107,41 @@ - + + - false - false - false - <_AvaloniaHasCompiledXaml>true + $(TargetsTriggeredByCompilation);CompileAvaloniaXaml - - - <_DebugSymbolsIntermediatePath Update="*" AvaloniaCompileOutput="%(RelativeDir)Avalonia\%(Filename)%(Extension)"/> - - - - + + + + - + + + + + + false + false + false + + + + + <_DebugSymbolsIntermediatePath Update="*" AvaloniaCompileOutput="%(FullPath)"/> + + + @@ -160,54 +167,6 @@ AnalyzerConfigFiles="@(EditorConfigFiles)"/> - - - <_AvaloniaXamlCompiledAssembly Include="@(IntermediateAssembly->Metadata('AvaloniaCompileOutput'))"/> - - - - <_AvaloniaXamlCompiledRefAssembly Include="@(IntermediateRefAssembly->Metadata('AvaloniaCompileOutput'))"/> - - - - <_AvaloniaXamlCompiledSymbols Include="@(_DebugSymbolsIntermediatePath->Metadata('AvaloniaCompileOutput'))"/> - <_DebugSymbolsIntermediatePath Remove="@(_DebugSymbolsIntermediatePath)"/> - <_DebugSymbolsIntermediatePath Include="@(_AvaloniaXamlCompiledSymbols)"/> - - - - - - - - - - - - - - - - - - - - - - - - - Build @@ -246,7 +205,7 @@ Name="AvaloniaDeleteRefAssemblyBeforeOutputCopy" BeforeTargets="CopyFilesToOutputDirectory" Condition=" - '$(_AvaloniaHasCompiledXaml)' == 'true' and + '@(AvaloniaResource)@(AvaloniaXaml)' != '' and '$(TargetRefPath)' != '' and '$(ProduceReferenceAssembly)' == 'true' and ('$(CopyBuildOutputToOutputDirectory)' == '' or '$(CopyBuildOutputToOutputDirectory)' == 'true') and 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 793f0e36eb..25125b26e4 100644 --- a/packages/Avalonia/AvaloniaSingleProject.targets +++ b/packages/Avalonia/AvaloniaSingleProject.targets @@ -29,7 +29,7 @@ WinExe - true + true true @@ -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/readme.md b/readme.md index 53db867b46..08fd014798 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,5 @@ - -![Star Banner](https://github.com/AvaloniaUI/Avalonia/assets/552074/0f7f683f-2ddd-401f-ba28-3f703cc78ee0) -![Header](https://github.com/AvaloniaUI/Avalonia/assets/552074/d8388fc4-469e-47c5-926d-faf25233ad4e) - +[![Star_Banner@3x](https://github.com/user-attachments/assets/d55eb468-fa5c-499f-858e-54618beb6f92)](https://github.com/sponsors/AvaloniaUI) +[![Hero](https://github.com/user-attachments/assets/7436f0e7-8aea-4cff-886a-e2faef29ca37)](https://avaloniaui.net?utm_source=github&utm_medium=referral&utm_content=readme_link) [![Telegram](https://raw.githubusercontent.com/Patrolavia/telegram-badge/master/chat.svg)](https://t.me/Avalonia) [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) [![Backers on Open Collective](https://img.shields.io/opencollective/backers/Avalonia?logo=opencollective)](#backers) [![Sponsors on Open Collective](https://img.shields.io/opencollective/sponsors/Avalonia?logo=opencollective)](#sponsors) [![GitHub Sponsors](https://img.shields.io/github/sponsors/AvaloniaUI?logo=github)](https://github.com/sponsors/AvaloniaUI) ![License](https://img.shields.io/github/license/avaloniaui/avalonia.svg) @@ -10,14 +8,14 @@ ## 📖 About -[Avalonia](https://avaloniaui.net) is a cross-platform UI framework for dotnet, providing a flexible styling system and supporting a wide range of platforms such as Windows, macOS, Linux, iOS, Android and WebAssembly. Avalonia is mature and production ready and is used by companies, including [Schneider Electric](https://avaloniaui.net/showcase#se), [Unity](https://avaloniaui.net/showcase#unity), [JetBrains](https://avaloniaui.net/showcase#rider) and [GitHub](https://avaloniaui.net/showcase#github). +[Avalonia](https://avaloniaui.net?utm_source=github&utm_medium=referral&utm_content=readme_link) is a cross-platform UI framework for dotnet, providing a flexible styling system and supporting a wide range of platforms such as Windows, macOS, Linux, iOS, Android and WebAssembly. Avalonia is mature and production ready and is used by companies, including [Schneider Electric](https://avaloniaui.net/showcase#se), [Unity](https://avaloniaui.net/showcase#unity), [JetBrains](https://avaloniaui.net/showcase#rider) and [GitHub](https://avaloniaui.net/showcase#github). Considered by many to be the spiritual successor to WPF, Avalonia UI provides a familiar, modern development experience for XAML developers creating cross-platform applications. While Avalonia UI is [similar to WPF](https://docs.avaloniaui.net/docs/next/get-started/wpf/), it isn't a 1:1 copy, and you'll find plenty of improvements. -For those seeking a cross-platform WPF, we have created [Avalonia XPF](https://avaloniaui.net/xpf), enabling WPF applications to run on macOS and Linux with little to no code changes. Avalonia XPF is a commercial product and is licensed per-app, per-platform. +For those seeking a cross-platform WPF, we have created [Avalonia XPF]([https://avaloniaui.net/xpf](https://avaloniaui.net/xpf?utm_source=github&utm_medium=referral&utm_content=readme_link)), enabling WPF applications to run on macOS and Linux with little to no code changes. Avalonia XPF is a commercial product and is licensed per-app, per-platform. #### Blog -To see the latest announcements and read about the state of Avalonia, check out the [Avalonia UI Blog](https://www.avaloniaui.net/Blog/). +To see the latest announcements and read about the state of Avalonia, check out the [Avalonia UI Blog](https://www.avaloniaui.net/blog?utm_source=github&utm_medium=referral&utm_content=readme_link). #### Breaking Changes You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been. @@ -27,10 +25,10 @@ You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/ ## 🚀 Getting Started -See our [Get Started](https://avaloniaui.net/GettingStarted) guide to begin developing apps with Avalonia UI. +See our [Get Started](https://avaloniaui.net/gettingstarted?utm_source=github&utm_medium=referral&utm_content=readme_link) guide to begin developing apps with Avalonia UI. ### Visual Studio -The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starter guide see our [documentation](https://docs.avaloniaui.net/docs/getting-started). +The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaVS) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starter guide see our [documentation](https://docs.avaloniaui.net/docs/getting-started). ### JetBrains Rider [JetBrains Rider](https://www.jetbrains.com/rider/whatsnew/?mkt_tok=eyJpIjoiTURBNU1HSmhNV0kwTUdFMiIsInQiOiJtNnU2VEc1TlNLa1ZRVkROYmdZYVpYREJsaU1qdUhmS3dxSzRHczdYWHl0RVlTNDMwSFwvNUs3VENTNVM0bVcyNFdaRmVYZzVWTTF1N3VrQWNGTkJreEhlam1hMlB4UVVWcHBGM1dNOUxoXC95YnRQdGgyUXl1YmZCM3h3d3BVWWdBIn0%3D#avalonia-support) now has official support for Avalonia. @@ -47,9 +45,19 @@ Install-Package Avalonia.Desktop ``` ## Showcase -[![Showcase_Banner@3x](https://github.com/AvaloniaUI/Avalonia/assets/552074/8a0af0e9-e45e-442c-830d-4af3767d6469)](https://avaloniaui.net/showcase) +[![Showcase_Banner@3x](https://github.com/user-attachments/assets/42d21506-3d5a-4213-a4b4-7889a48acdc8)](https://avaloniaui.net/showcase?utm_source=github&utm_medium=referral&utm_content=readme_link) + +See what others have built with Avalonia UI on our [Showcase](https://avaloniaui.net/showcase?utm_source=github&utm_medium=referral&utm_content=readme_link). We welcome submissions! + +## Sponsors +Avalonia development is supported by the generous sponsorship of [Devolutions](https://devolutions.net/?utm_source=pr&utm_medium=partnership&utm_campaign=avalonia&utm_id=C086&member_status=responded). -See what others have built with Avalonia UI on our [Showcase](https://avaloniaui.net/Showcase). We welcome submissions! +devolutions-color-hr + + +## Community +Join our community hub to get early access to upcoming features, share your thoughts, and connect directly with the Avalonia team. +[![communityannouncement-banner 1](https://github.com/user-attachments/assets/21950b56-cd28-4574-9a0a-73bb17b89d31)](https://avaloniaui.community) ## Bleeding Edge Builds @@ -68,7 +76,7 @@ We have a [range of samples](https://github.com/AvaloniaUI/Avalonia.Samples) to ## Building and Using -See the [build instructions here](Documentation/build.md). +See the [build instructions here](docs/build.md). ## Contributing @@ -104,11 +112,10 @@ Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com ## Commercial Support -We have a range of [support plans available](https://avaloniaui.net/support) for those looking to partner with the creators of Avalonia, enabling access to the best support at every step of the development process. +We have a range of [support plans available](https://avaloniaui.net/support?utm_source=github&utm_medium=referral&utm_content=readme_link) for those looking to partner with the creators of Avalonia, enabling access to the best support at every step of the development process. *Please note that donations are not considered payment for commercial support agreements. Please contact us to discuss your needs first. [team@avaloniaui.net](mailto://team@avaloniaui.net)* -## Avalonia XPF +## Avalonia XPF - Our cross-platform WPF Unleash the full potential of your existing WPF apps with our cross-platform UI framework, enabling WPF apps to run on macOS and Linux without requiring expensive and risky rewrites. - -[![GH_Banner](https://user-images.githubusercontent.com/552074/218457976-92e76834-9e22-4e35-acfa-aa50281bc0f9.png)](https://avaloniaui.net/xpf) +[![GH_Banner](https://github.com/user-attachments/assets/a6176267-1187-45ff-b82b-fcc7048e54b7)](https://avaloniaui.net/xpf?utm_source=github&utm_medium=referral&utm_content=readme_ad) diff --git a/samples/AppWithoutLifetime/AppWithoutLifetime.csproj b/samples/AppWithoutLifetime/AppWithoutLifetime.csproj index 2e959798d0..edcad7d0af 100644 --- a/samples/AppWithoutLifetime/AppWithoutLifetime.csproj +++ b/samples/AppWithoutLifetime/AppWithoutLifetime.csproj @@ -2,14 +2,11 @@ WinExe $(AvsCurrentTargetFramework) - enable app.manifest - - diff --git a/samples/AppWithoutLifetime/MainWindow.axaml.cs b/samples/AppWithoutLifetime/MainWindow.axaml.cs index df3ed3cea0..a92bd31600 100644 --- a/samples/AppWithoutLifetime/MainWindow.axaml.cs +++ b/samples/AppWithoutLifetime/MainWindow.axaml.cs @@ -1,4 +1,3 @@ -using Avalonia; using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Markup.Xaml; @@ -17,13 +16,6 @@ public partial class MainWindow : Window AvaloniaXamlLoader.Load(this); } - /// - protected override void OnLoaded(RoutedEventArgs e) - { - this.AttachDevTools(); - base.OnLoaded(e); - } - public void Open(object sender, RoutedEventArgs e) { new Sub().Show(this); diff --git a/samples/AppWithoutLifetime/Program.cs b/samples/AppWithoutLifetime/Program.cs index 9404b9f01a..60ab32824e 100644 --- a/samples/AppWithoutLifetime/Program.cs +++ b/samples/AppWithoutLifetime/Program.cs @@ -24,5 +24,6 @@ class Program public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() + .WithDeveloperTools() .LogToTrace(); } diff --git a/samples/AppWithoutLifetime/Sub.axaml.cs b/samples/AppWithoutLifetime/Sub.axaml.cs index 3a7ce787bc..e0d07fb338 100644 --- a/samples/AppWithoutLifetime/Sub.axaml.cs +++ b/samples/AppWithoutLifetime/Sub.axaml.cs @@ -1,6 +1,4 @@ -using Avalonia; using Avalonia.Controls; -using Avalonia.Interactivity; using Avalonia.Markup.Xaml; namespace AppWithoutLifetime; @@ -16,11 +14,4 @@ public partial class Sub : Window { AvaloniaXamlLoader.Load(this); } - - /// - protected override void OnLoaded(RoutedEventArgs e) - { - this.AttachDevTools(); - base.OnLoaded(e); - } } diff --git a/samples/BindingDemo/App.xaml.cs b/samples/BindingDemo/App.xaml.cs index 8a5364c70b..e76f61ac63 100644 --- a/samples/BindingDemo/App.xaml.cs +++ b/samples/BindingDemo/App.xaml.cs @@ -24,6 +24,7 @@ namespace BindingDemo public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() + .WithDeveloperTools() .LogToTrace(); } } diff --git a/samples/BindingDemo/BindingDemo.csproj b/samples/BindingDemo/BindingDemo.csproj index faeb643d8a..b12e350814 100644 --- a/samples/BindingDemo/BindingDemo.csproj +++ b/samples/BindingDemo/BindingDemo.csproj @@ -2,9 +2,9 @@ Exe $(AvsCurrentTargetFramework) + - diff --git a/samples/BindingDemo/GenericMarkupExtension.cs b/samples/BindingDemo/GenericMarkupExtension.cs index aed0700cb8..be7d82e0d5 100644 --- a/samples/BindingDemo/GenericMarkupExtension.cs +++ b/samples/BindingDemo/GenericMarkupExtension.cs @@ -5,7 +5,7 @@ namespace BindingDemo; internal class GenericMarkupExtension : MarkupExtension { - public T Value { get; set; } + public T? Value { get; set; } public override object ProvideValue(IServiceProvider serviceProvider) { diff --git a/samples/BindingDemo/MainWindow.xaml b/samples/BindingDemo/MainWindow.xaml index f14ad59cd5..9d68c8da8a 100644 --- a/samples/BindingDemo/MainWindow.xaml +++ b/samples/BindingDemo/MainWindow.xaml @@ -3,6 +3,7 @@ x:Class="BindingDemo.MainWindow" xmlns:vm="using:BindingDemo.ViewModels" xmlns:local="using:BindingDemo" + xmlns:system="clr-namespace:System;assembly=System.Runtime" Title="AvaloniaUI Bindings Test" Width="800" Height="600" @@ -12,9 +13,6 @@ - - - @@ -32,7 +30,7 @@ - + @@ -54,9 +52,9 @@ + Text="{Binding Value, Source={StaticResource SharedItem}, Mode=TwoWay, DataType={x:Type vm:MainWindowViewModel+TestItem, x:TypeArguments=x:String}}"/> + Text="{Binding Value, Source={StaticResource SharedItem}, Mode=TwoWay, DataType={x:Type vm:MainWindowViewModel+TestItem, x:TypeArguments=x:String}}"/> @@ -70,8 +68,8 @@ - - + + @@ -84,7 +82,7 @@ - + @@ -126,7 +124,7 @@ - + diff --git a/samples/BindingDemo/MainWindow.xaml.cs b/samples/BindingDemo/MainWindow.xaml.cs index eaa57e1f5f..6a7c1e877d 100644 --- a/samples/BindingDemo/MainWindow.xaml.cs +++ b/samples/BindingDemo/MainWindow.xaml.cs @@ -1,5 +1,4 @@ using BindingDemo.ViewModels; -using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; @@ -9,9 +8,9 @@ namespace BindingDemo { public MainWindow() { + Resources["SharedItem"] = new MainWindowViewModel.TestItem() { Value = "shared" }; this.InitializeComponent(); this.DataContext = new MainWindowViewModel(); - this.AttachDevTools(); } private void InitializeComponent() diff --git a/samples/BindingDemo/TestItemView.xaml b/samples/BindingDemo/TestItemView.xaml index 6edade34b2..fcf3a80ceb 100644 --- a/samples/BindingDemo/TestItemView.xaml +++ b/samples/BindingDemo/TestItemView.xaml @@ -2,9 +2,9 @@ xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' xmlns:viewModels="using:BindingDemo.ViewModels" x:Class="BindingDemo.TestItemView" - x:DataType="viewModels:TestItem"> + x:DataType="{x:Type viewModels:MainWindowViewModel+TestItem, x:TypeArguments=x:String}"> - + diff --git a/samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs b/samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs index 391d1791d3..a51139f8ac 100644 --- a/samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs +++ b/samples/BindingDemo/ViewModels/DataAnnotationsErrorViewModel.cs @@ -6,7 +6,7 @@ namespace BindingDemo.ViewModels { [Phone] [MaxLength(10)] - public string PhoneNumber { get; set; } + public string? PhoneNumber { get; set; } [Range(0, 9)] public int LessThan10 { get; set; } diff --git a/samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs b/samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs index 9ae8d9558f..7273da38c8 100644 --- a/samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs +++ b/samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs @@ -9,7 +9,7 @@ namespace BindingDemo.ViewModels { private int _maximum = 10; private int _value; - private string _valueError; + private string? _valueError; public IndeiErrorViewModel() { @@ -34,16 +34,16 @@ namespace BindingDemo.ViewModels set { this.RaiseAndSetIfChanged(ref _value, value); } } - public event EventHandler ErrorsChanged; + public event EventHandler? ErrorsChanged; - public IEnumerable GetErrors(string propertyName) + public IEnumerable GetErrors(string? propertyName) { switch (propertyName) { case nameof(Value): return new[] { _valueError }; default: - return null; + return Array.Empty(); } } diff --git a/samples/BindingDemo/ViewModels/MainWindowViewModel.cs b/samples/BindingDemo/ViewModels/MainWindowViewModel.cs index 18a7a01a69..3fce67a6f6 100644 --- a/samples/BindingDemo/ViewModels/MainWindowViewModel.cs +++ b/samples/BindingDemo/ViewModels/MainWindowViewModel.cs @@ -16,21 +16,21 @@ namespace BindingDemo.ViewModels { private string _booleanString = "True"; private double _doubleValue = 5.0; - private string _stringValue = "Simple Binding"; + private string? _stringValue = "Simple Binding"; private bool _booleanFlag = false; - private string _currentTime; - private NestedCommandViewModel _nested; + private string? _currentTime; + private NestedCommandViewModel? _nested; public MainWindowViewModel() { - Items = new ObservableCollection( - Enumerable.Range(0, 20).Select(x => new TestItem + Items = new ObservableCollection>( + Enumerable.Range(0, 20).Select(x => new TestItem { - StringValue = "Item " + x, + Value = "Item " + x, Detail = "Item " + x + " details", })); - Selection = new SelectionModel { SingleSelect = false }; + Selection = new SelectionModel> { SingleSelect = false }; ShuffleItems = MiniCommand.Create(() => { @@ -58,8 +58,8 @@ namespace BindingDemo.ViewModels .Select(x => DateTimeOffset.Now); } - public ObservableCollection Items { get; } - public SelectionModel Selection { get; } + public ObservableCollection> Items { get; } + public SelectionModel> Selection { get; } public MiniCommand ShuffleItems { get; } public string BooleanString @@ -74,7 +74,7 @@ namespace BindingDemo.ViewModels set { this.RaiseAndSetIfChanged(ref _doubleValue, value); } } - public string StringValue + public string? StringValue { get { return _stringValue; } set { this.RaiseAndSetIfChanged(ref _stringValue, value); } @@ -86,7 +86,7 @@ namespace BindingDemo.ViewModels set { this.RaiseAndSetIfChanged(ref _booleanFlag, value); } } - public string CurrentTime + public string? CurrentTime { get { return _currentTime; } private set { this.RaiseAndSetIfChanged(ref _currentTime, value); } @@ -99,7 +99,7 @@ namespace BindingDemo.ViewModels public ExceptionErrorViewModel ExceptionDataValidation { get; } = new ExceptionErrorViewModel(); public IndeiErrorViewModel IndeiDataValidation { get; } = new IndeiErrorViewModel(); - public NestedCommandViewModel NestedModel + public NestedCommandViewModel? NestedModel { get { return _nested; } private set { this.RaiseAndSetIfChanged(ref _nested, value); } @@ -115,5 +115,24 @@ namespace BindingDemo.ViewModels { return BooleanFlag; } + + // Nested class, jsut so we can test it in XAML + public class TestItem : ViewModelBase + { + private T? _value; + private string? _detail; + + public T? Value + { + get { return _value; } + set { this.RaiseAndSetIfChanged(ref this._value, value); } + } + + public string? Detail + { + get { return _detail; } + set { this.RaiseAndSetIfChanged(ref this._detail, value); } + } + } } } diff --git a/samples/BindingDemo/ViewModels/TestItem.cs b/samples/BindingDemo/ViewModels/TestItem.cs index 2f49a3c99f..2e11f63e95 100644 --- a/samples/BindingDemo/ViewModels/TestItem.cs +++ b/samples/BindingDemo/ViewModels/TestItem.cs @@ -2,21 +2,5 @@ using MiniMvvm; namespace BindingDemo.ViewModels { - public class TestItem : ViewModelBase - { - private string _stringValue = "String Value"; - private string _detail; - public string StringValue - { - get { return _stringValue; } - set { this.RaiseAndSetIfChanged(ref this._stringValue, value); } - } - - public string Detail - { - get { return _detail; } - set { this.RaiseAndSetIfChanged(ref this._detail, value); } - } - } } diff --git a/samples/ControlCatalog.Android/Application.cs b/samples/ControlCatalog.Android/Application.cs new file mode 100644 index 0000000000..1bdb61e5e3 --- /dev/null +++ b/samples/ControlCatalog.Android/Application.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Android.App; +using Android.Runtime; +using Avalonia; +using Avalonia.Android; + +namespace ControlCatalog.Android +{ + [Application] + public class Application : AvaloniaAndroidApplication + { + protected Application(nint javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) + { + } + + + protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) + { + return base.CustomizeAppBuilder(builder) + .AfterSetup(_ => + { + Pages.EmbedSample.Implementation = new EmbedSampleAndroid(); + }); + } + } +} diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj index 958725eed5..b47172548e 100644 --- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj +++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj @@ -3,7 +3,6 @@ $(AvsCurrentAndroidTargetFramework) $(AvsMinSupportedAndroidVersion) Exe - enable com.Avalonia.ControlCatalog 1 1.0 @@ -26,7 +25,7 @@ - + diff --git a/samples/ControlCatalog.Android/MainActivity.cs b/samples/ControlCatalog.Android/MainActivity.cs index c54b616b17..b9f2d16168 100644 --- a/samples/ControlCatalog.Android/MainActivity.cs +++ b/samples/ControlCatalog.Android/MainActivity.cs @@ -1,7 +1,6 @@ using Android.App; using Android.Content.PM; using Android.OS; -using Avalonia; using Avalonia.Android; using static Android.Content.Intent; @@ -11,19 +10,11 @@ using static Android.Content.Intent; namespace ControlCatalog.Android { - [Activity(Name = "com.Avalonia.ControlCatalog.MainActivity", Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, Exported = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] + [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, Exported = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] // CategoryLeanbackLauncher is required for Android TV. - [IntentFilter(new [] { ActionView }, Categories = new [] { CategoryDefault, CategoryLeanbackLauncher })] - public class MainActivity : AvaloniaMainActivity + [IntentFilter(new[] { ActionView }, Categories = new[] { CategoryDefault, CategoryLeanbackLauncher })] + public class MainActivity : AvaloniaMainActivity { - protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) - { - return base.CustomizeAppBuilder(builder) - .AfterSetup(_ => - { - Pages.EmbedSample.Implementation = new EmbedSampleAndroid(); - }); - } } /// @@ -31,7 +22,7 @@ namespace ControlCatalog.Android /// `AvaloniaActivity` internally will redirect parameters to the Avalonia Application. /// [Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop, Exported = true, Theme = "@android:style/Theme.NoDisplay")] - [IntentFilter(new[] {ActionView}, Categories = new[] {CategoryDefault, CategoryBrowsable}, DataScheme = "avln")] + [IntentFilter(new[] { ActionView }, Categories = new[] { CategoryDefault, CategoryBrowsable }, DataScheme = "avln")] public class DataSchemeActivity : AvaloniaActivity { protected override void OnCreate(Bundle? savedInstanceState) diff --git a/samples/ControlCatalog.Android/Properties/AndroidManifest.xml b/samples/ControlCatalog.Android/Properties/AndroidManifest.xml index ec07a94b22..95529679ec 100644 --- a/samples/ControlCatalog.Android/Properties/AndroidManifest.xml +++ b/samples/ControlCatalog.Android/Properties/AndroidManifest.xml @@ -1,6 +1,6 @@  - + 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/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..c951862ad2 100644 --- a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj +++ b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj @@ -1,22 +1,40 @@  - Exe - net461 - x64 + WinExe + $(AvsCurrentTargetFramework) + true true - ../ControlCatalog.NetCore/app.manifest - - + + + + + + + + PreserveNewest + - + + + + + + + + + + en + app.manifest + + - + diff --git a/samples/ControlCatalog.Desktop/NativeControls/Gtk/EmbedSample.Gtk.cs b/samples/ControlCatalog.Desktop/NativeControls/Gtk/EmbedSample.Gtk.cs new file mode 100644 index 0000000000..523503cc38 --- /dev/null +++ b/samples/ControlCatalog.Desktop/NativeControls/Gtk/EmbedSample.Gtk.cs @@ -0,0 +1,34 @@ +using System.IO; +using System.Diagnostics; +using Avalonia.Platform; +using Avalonia.Controls.Platform; +using System; +using ControlCatalog.Pages; + +namespace ControlCatalog.Desktop; + +public class EmbedSampleGtk : INativeDemoControl +{ + private Process? _mplayer; + + public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault) + { + if (isSecond) + { + var chooser = GtkHelper.CreateGtkFileChooser(parent.Handle); + if (chooser != null) + return chooser; + } + + var control = createDefault(); + var nodes = Path.GetFullPath(Path.Combine(typeof(EmbedSample).Assembly.GetModules()[0].FullyQualifiedName, + "..", "NativeControls", "Gtk", "nodes.mp4")); + _mplayer = Process.Start(new ProcessStartInfo("mplayer", + $"-vo x11 -zoom -loop 0 -wid {control.Handle.ToInt64()} \"{nodes}\"") + { + UseShellExecute = false, + + }); + return control; + } +} diff --git a/samples/ControlCatalog.Desktop/NativeControls/Gtk/GtkHelper.cs b/samples/ControlCatalog.Desktop/NativeControls/Gtk/GtkHelper.cs new file mode 100644 index 0000000000..78d7a45154 --- /dev/null +++ b/samples/ControlCatalog.Desktop/NativeControls/Gtk/GtkHelper.cs @@ -0,0 +1,53 @@ +using System; +using System.Threading.Tasks; +using Avalonia.Controls.Platform; +using Avalonia.Platform.Interop; +using Avalonia.X11.Interop; +using Avalonia.X11.NativeDialogs; +using static Avalonia.X11.NativeDialogs.Gtk; +using static Avalonia.X11.Interop.Glib; + +namespace ControlCatalog.Desktop; + +internal class GtkHelper +{ + class FileChooser : INativeControlHostDestroyableControlHandle + { + private readonly IntPtr _widget; + + public FileChooser(IntPtr widget, IntPtr xid) + { + _widget = widget; + Handle = xid; + } + + public IntPtr Handle { get; } + public string HandleDescriptor => "XID"; + + public void Destroy() + { + RunOnGlibThread(() => + { + gtk_widget_destroy(_widget); + return 0; + }).Wait(); + } + } + + + public static INativeControlHostDestroyableControlHandle CreateGtkFileChooser(IntPtr parentXid) + { + return GtkInteropHelper.RunOnGlibThread(() => + { + using (var title = new Utf8Buffer("Embedded")) + { + var widget = gtk_file_chooser_dialog_new(title, IntPtr.Zero, GtkFileChooserAction.SelectFolder, + IntPtr.Zero); + gtk_widget_realize(widget); + var xid = gdk_x11_window_get_xid(gtk_widget_get_window(widget)); + gtk_window_present(widget); + return new FileChooser(widget, xid); + } + }).Result; + } +} 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.Desktop/NativeControls/Mac/EmbedSample.Mac.cs b/samples/ControlCatalog.Desktop/NativeControls/Mac/EmbedSample.Mac.cs new file mode 100644 index 0000000000..b761ce0972 --- /dev/null +++ b/samples/ControlCatalog.Desktop/NativeControls/Mac/EmbedSample.Mac.cs @@ -0,0 +1,29 @@ +using System; + +using Avalonia.Platform; +using Avalonia.Threading; + +using ControlCatalog.Pages; + +using MonoMac.Foundation; +using MonoMac.WebKit; + +namespace ControlCatalog.Desktop; + +public class EmbedSampleMac : INativeDemoControl +{ + public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault) + { + // Note: We are using MonoMac for example purposes + // It shouldn't be used in production apps + MacHelper.EnsureInitialized(); + + var webView = new WebView(); + Dispatcher.UIThread.Post(() => + { + webView.MainFrame.LoadRequest(new NSUrlRequest(new NSUrl( + isSecond ? "https://bing.com" : "https://google.com/"))); + }); + return new MacOSViewHandle(webView); + } +} diff --git a/samples/ControlCatalog.Desktop/NativeControls/Mac/MacHelper.cs b/samples/ControlCatalog.Desktop/NativeControls/Mac/MacHelper.cs new file mode 100644 index 0000000000..01325a5fa9 --- /dev/null +++ b/samples/ControlCatalog.Desktop/NativeControls/Mac/MacHelper.cs @@ -0,0 +1,38 @@ +using System; + +using Avalonia.Controls.Platform; +using MonoMac.AppKit; + +namespace ControlCatalog.Desktop; + +internal class MacHelper +{ + private static bool _isInitialized; + + public static void EnsureInitialized() + { + if (_isInitialized) + return; + _isInitialized = true; + NSApplication.Init(); + } +} + +internal class MacOSViewHandle : INativeControlHostDestroyableControlHandle +{ + private NSView? _view; + + public MacOSViewHandle(NSView view) + { + _view = view; + } + + public IntPtr Handle => _view?.Handle ?? IntPtr.Zero; + public string HandleDescriptor => "NSView"; + + public void Destroy() + { + _view?.Dispose(); + _view = null; + } +} diff --git a/samples/ControlCatalog.Desktop/NativeControls/Win/EmbedSample.Win.cs b/samples/ControlCatalog.Desktop/NativeControls/Win/EmbedSample.Win.cs new file mode 100644 index 0000000000..c529c093f6 --- /dev/null +++ b/samples/ControlCatalog.Desktop/NativeControls/Win/EmbedSample.Win.cs @@ -0,0 +1,45 @@ +using System; +using System.Text; + +using Avalonia.Controls.Platform; +using Avalonia.Platform; + +using ControlCatalog.Pages; + +namespace ControlCatalog.Desktop; + +public class EmbedSampleWin : INativeDemoControl +{ + private const string RichText = + @"{\rtf1\ansi\ansicpg1251\deff0\nouicompat\deflang1049{\fonttbl{\f0\fnil\fcharset0 Calibri;}} +{\colortbl ;\red255\green0\blue0;\red0\green77\blue187;\red0\green176\blue80;\red155\green0\blue211;\red247\green150\blue70;\red75\green172\blue198;} +{\*\generator Riched20 6.3.9600}\viewkind4\uc1 +\pard\sa200\sl276\slmult1\f0\fs22\lang9 I \i am\i0 a \cf1\b Rich Text \cf0\b0\fs24 control\cf2\fs28 !\cf3\fs32 !\cf4\fs36 !\cf1\fs40 !\cf5\fs44 !\cf6\fs48 !\cf0\fs44\par +}"; + + public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault) + { + WinApi.LoadLibrary("Msftedit.dll"); + var handle = WinApi.CreateWindowEx(0, "RICHEDIT50W", + @"Rich Edit", + 0x800000 | 0x10000000 | 0x40000000 | 0x800000 | 0x10000 | 0x0004, 0, 0, 1, 1, parent.Handle, + IntPtr.Zero, WinApi.GetModuleHandle(null), IntPtr.Zero); + var st = new WinApi.SETTEXTEX { Codepage = 65001, Flags = 0x00000008 }; + var text = RichText.Replace("", isSecond ? "\\qr " : ""); + var bytes = Encoding.UTF8.GetBytes(text); + WinApi.SendMessage(handle, 0x0400 + 97, ref st, bytes); + return new Win32WindowControlHandle(handle, "HWND"); + } +} + +internal class Win32WindowControlHandle : PlatformHandle, INativeControlHostDestroyableControlHandle +{ + public Win32WindowControlHandle(IntPtr handle, string descriptor) : base(handle, descriptor) + { + } + + public void Destroy() + { + _ = WinApi.DestroyWindow(Handle); + } +} diff --git a/samples/ControlCatalog.Desktop/NativeControls/Win/WinApi.cs b/samples/ControlCatalog.Desktop/NativeControls/Win/WinApi.cs new file mode 100644 index 0000000000..514f704b30 --- /dev/null +++ b/samples/ControlCatalog.Desktop/NativeControls/Win/WinApi.cs @@ -0,0 +1,73 @@ +using System; +using System.Runtime.InteropServices; + +namespace ControlCatalog.Desktop; + +internal unsafe class WinApi +{ + public enum CommonControls : uint + { + ICC_LISTVIEW_CLASSES = 0x00000001, // listview, header + ICC_TREEVIEW_CLASSES = 0x00000002, // treeview, tooltips + ICC_BAR_CLASSES = 0x00000004, // toolbar, statusbar, trackbar, tooltips + ICC_TAB_CLASSES = 0x00000008, // tab, tooltips + ICC_UPDOWN_CLASS = 0x00000010, // updown + ICC_PROGRESS_CLASS = 0x00000020, // progress + ICC_HOTKEY_CLASS = 0x00000040, // hotkey + ICC_ANIMATE_CLASS = 0x00000080, // animate + ICC_WIN95_CLASSES = 0x000000FF, + ICC_DATE_CLASSES = 0x00000100, // month picker, date picker, time picker, updown + ICC_USEREX_CLASSES = 0x00000200, // comboex + ICC_COOL_CLASSES = 0x00000400, // rebar (coolbar) control + ICC_INTERNET_CLASSES = 0x00000800, + ICC_PAGESCROLLER_CLASS = 0x00001000, // page scroller + ICC_NATIVEFNTCTL_CLASS = 0x00002000, // native font control + ICC_STANDARD_CLASSES = 0x00004000, + ICC_LINK_CLASS = 0x00008000 + } + + [StructLayout(LayoutKind.Sequential)] + public struct INITCOMMONCONTROLSEX + { + public int dwSize; + public uint dwICC; + } + + [DllImport("Comctl32.dll")] + public static extern void InitCommonControlsEx(ref INITCOMMONCONTROLSEX init); + + [DllImport("user32.dll", SetLastError = true)] + public static extern bool DestroyWindow(IntPtr hwnd); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "LoadLibraryW", ExactSpelling = true)] + public static extern IntPtr LoadLibrary(string lib); + + + [DllImport("kernel32.dll")] + public static extern IntPtr GetModuleHandle(string? lpModuleName); + + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr CreateWindowEx( + int dwExStyle, + string lpClassName, + string lpWindowName, + uint dwStyle, + int x, + int y, + int nWidth, + int nHeight, + IntPtr hWndParent, + IntPtr hMenu, + IntPtr hInstance, + IntPtr lpParam); + + [StructLayout(LayoutKind.Sequential)] + public struct SETTEXTEX + { + public uint Flags; + public uint Codepage; + } + + [DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "SendMessageW")] + public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, ref SETTEXTEX wParam, byte[] lParam); +} diff --git a/samples/ControlCatalog.Desktop/Program.cs b/samples/ControlCatalog.Desktop/Program.cs index 533ee8308a..c4c42a7311 100644 --- a/samples/ControlCatalog.Desktop/Program.cs +++ b/samples/ControlCatalog.Desktop/Program.cs @@ -1,38 +1,172 @@ 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.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() is "DatePicker" or "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() - .AfterSetup(builder => + .UsePlatformDetect() + .With(new X11PlatformOptions { - builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions() - { - StartupScreenIndex = 1, - }); + EnableMultiTouch = true, + UseDBusMenu = true, + EnableIme = true, + }) - EmbedSample.Implementation = new EmbedSampleWin(); + .With(new VulkanOptions + { + VulkanInstanceCreationOptions = new () + { + UseDebug = true + } + }) + .With(new CompositionOptions() + { + UseRegionDirtyRectClipping = true + }) + .UseSkia() + .WithInterFont() + .WithDeveloperTools() + .AfterSetup(builder => + { + 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.Desktop/Properties/launchSettings.json b/samples/ControlCatalog.Desktop/Properties/launchSettings.json new file mode 100644 index 0000000000..d57a2680e4 --- /dev/null +++ b/samples/ControlCatalog.Desktop/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "profiles": { + "ControlCatalog.Desktop": { + "commandName": "Project" + }, + "Dxgi": { + "commandName": "Project", + "commandLineArgs": "--dxgi" + }, + "VNC": { + "commandName": "Project", + "commandLineArgs": "--vnc" + } + } +} 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.MacCatalyst/ControlCatalog.MacCatalyst.csproj b/samples/ControlCatalog.MacCatalyst/ControlCatalog.MacCatalyst.csproj new file mode 100644 index 0000000000..954ed20d99 --- /dev/null +++ b/samples/ControlCatalog.MacCatalyst/ControlCatalog.MacCatalyst.csproj @@ -0,0 +1,22 @@ + + + + Exe + manual + $(AvsCurrentMacCatalystTargetFramework) + + 15.0 + 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.MacCatalyst/Info.plist b/samples/ControlCatalog.MacCatalyst/Info.plist new file mode 100644 index 0000000000..1a21cbbfed --- /dev/null +++ b/samples/ControlCatalog.MacCatalyst/Info.plist @@ -0,0 +1,42 @@ + + + + + CFBundleDisplayName + ControlCatalog.MacCatalyst + CFBundleIdentifier + Avalonia.ControlCatalog + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIDeviceFamily + + 6 + + UIRequiredDeviceCapabilities + + arm64 + + UILaunchStoryboardName + LaunchScreen + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + com.apple.security.files.user-selected.read-write + + + diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj deleted file mode 100644 index c87d9fdead..0000000000 --- a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj +++ /dev/null @@ -1,40 +0,0 @@ - - - - WinExe - $(AvsCurrentTargetFramework) - true - true - - - - - - - - - - PreserveNewest - - - - - - - - - - - - - - - - - en - app.manifest - - - - - diff --git a/samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs b/samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs deleted file mode 100644 index 81a5ba536f..0000000000 --- a/samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.IO; -using System.Diagnostics; -using Avalonia.Platform; -using Avalonia.Controls.Platform; -using System; -using ControlCatalog.Pages; - -namespace ControlCatalog.NetCore; - -public class EmbedSampleGtk : INativeDemoControl -{ - private Process _mplayer; - - public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault) - { - if (isSecond) - { - var chooser = GtkHelper.CreateGtkFileChooser(parent.Handle); - if (chooser != null) - return chooser; - } - - var control = createDefault(); - var nodes = Path.GetFullPath(Path.Combine(typeof(EmbedSample).Assembly.GetModules()[0].FullyQualifiedName, - "..", "NativeControls", "Gtk", "nodes.mp4")); - _mplayer = Process.Start(new ProcessStartInfo("mplayer", - $"-vo x11 -zoom -loop 0 -wid {control.Handle.ToInt64()} \"{nodes}\"") - { - UseShellExecute = false, - - }); - return control; - } -} diff --git a/samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs b/samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs deleted file mode 100644 index b1fef7c013..0000000000 --- a/samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Threading.Tasks; -using Avalonia.Controls.Platform; -using Avalonia.Platform.Interop; -using Avalonia.X11.Interop; -using Avalonia.X11.NativeDialogs; -using static Avalonia.X11.NativeDialogs.Gtk; -using static Avalonia.X11.NativeDialogs.Glib; - -namespace ControlCatalog.NetCore; - -internal class GtkHelper -{ - class FileChooser : INativeControlHostDestroyableControlHandle - { - private readonly IntPtr _widget; - - public FileChooser(IntPtr widget, IntPtr xid) - { - _widget = widget; - Handle = xid; - } - - public IntPtr Handle { get; } - public string HandleDescriptor => "XID"; - - public void Destroy() - { - RunOnGlibThread(() => - { - gtk_widget_destroy(_widget); - return 0; - }).Wait(); - } - } - - - public static INativeControlHostDestroyableControlHandle CreateGtkFileChooser(IntPtr parentXid) - { - return GtkInteropHelper.RunOnGlibThread(() => - { - using (var title = new Utf8Buffer("Embedded")) - { - var widget = gtk_file_chooser_dialog_new(title, IntPtr.Zero, GtkFileChooserAction.SelectFolder, - IntPtr.Zero); - gtk_widget_realize(widget); - var xid = gdk_x11_window_get_xid(gtk_widget_get_window(widget)); - gtk_window_present(widget); - return new FileChooser(widget, xid); - } - }).Result; - } -} diff --git a/samples/ControlCatalog.NetCore/NativeControls/Mac/EmbedSample.Mac.cs b/samples/ControlCatalog.NetCore/NativeControls/Mac/EmbedSample.Mac.cs deleted file mode 100644 index 7967c9c073..0000000000 --- a/samples/ControlCatalog.NetCore/NativeControls/Mac/EmbedSample.Mac.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; - -using Avalonia.Platform; -using Avalonia.Threading; - -using ControlCatalog.Pages; - -using MonoMac.Foundation; -using MonoMac.WebKit; - -namespace ControlCatalog.NetCore; - -public class EmbedSampleMac : INativeDemoControl -{ - public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault) - { - // Note: We are using MonoMac for example purposes - // It shouldn't be used in production apps - MacHelper.EnsureInitialized(); - - var webView = new WebView(); - Dispatcher.UIThread.Post(() => - { - webView.MainFrame.LoadRequest(new NSUrlRequest(new NSUrl( - isSecond ? "https://bing.com" : "https://google.com/"))); - }); - return new MacOSViewHandle(webView); - } -} diff --git a/samples/ControlCatalog.NetCore/NativeControls/Mac/MacHelper.cs b/samples/ControlCatalog.NetCore/NativeControls/Mac/MacHelper.cs deleted file mode 100644 index 5b3bc9abf1..0000000000 --- a/samples/ControlCatalog.NetCore/NativeControls/Mac/MacHelper.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; - -using Avalonia.Controls.Platform; -using MonoMac.AppKit; - -namespace ControlCatalog.NetCore; - -internal class MacHelper -{ - private static bool _isInitialized; - - public static void EnsureInitialized() - { - if (_isInitialized) - return; - _isInitialized = true; - NSApplication.Init(); - } -} - -internal class MacOSViewHandle : INativeControlHostDestroyableControlHandle -{ - private NSView _view; - - public MacOSViewHandle(NSView view) - { - _view = view; - } - - public IntPtr Handle => _view?.Handle ?? IntPtr.Zero; - public string HandleDescriptor => "NSView"; - - public void Destroy() - { - _view.Dispose(); - _view = null; - } -} diff --git a/samples/ControlCatalog.NetCore/NativeControls/Win/EmbedSample.Win.cs b/samples/ControlCatalog.NetCore/NativeControls/Win/EmbedSample.Win.cs deleted file mode 100644 index 77982db0ca..0000000000 --- a/samples/ControlCatalog.NetCore/NativeControls/Win/EmbedSample.Win.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Text; - -using Avalonia.Controls.Platform; -using Avalonia.Platform; - -using ControlCatalog.Pages; - -namespace ControlCatalog.NetCore; - -public class EmbedSampleWin : INativeDemoControl -{ - private const string RichText = - @"{\rtf1\ansi\ansicpg1251\deff0\nouicompat\deflang1049{\fonttbl{\f0\fnil\fcharset0 Calibri;}} -{\colortbl ;\red255\green0\blue0;\red0\green77\blue187;\red0\green176\blue80;\red155\green0\blue211;\red247\green150\blue70;\red75\green172\blue198;} -{\*\generator Riched20 6.3.9600}\viewkind4\uc1 -\pard\sa200\sl276\slmult1\f0\fs22\lang9 I \i am\i0 a \cf1\b Rich Text \cf0\b0\fs24 control\cf2\fs28 !\cf3\fs32 !\cf4\fs36 !\cf1\fs40 !\cf5\fs44 !\cf6\fs48 !\cf0\fs44\par -}"; - - public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault) - { - WinApi.LoadLibrary("Msftedit.dll"); - var handle = WinApi.CreateWindowEx(0, "RICHEDIT50W", - @"Rich Edit", - 0x800000 | 0x10000000 | 0x40000000 | 0x800000 | 0x10000 | 0x0004, 0, 0, 1, 1, parent.Handle, - IntPtr.Zero, WinApi.GetModuleHandle(null), IntPtr.Zero); - var st = new WinApi.SETTEXTEX { Codepage = 65001, Flags = 0x00000008 }; - var text = RichText.Replace("", isSecond ? "\\qr " : ""); - var bytes = Encoding.UTF8.GetBytes(text); - WinApi.SendMessage(handle, 0x0400 + 97, ref st, bytes); - return new Win32WindowControlHandle(handle, "HWND"); - } -} - -internal class Win32WindowControlHandle : PlatformHandle, INativeControlHostDestroyableControlHandle -{ - public Win32WindowControlHandle(IntPtr handle, string descriptor) : base(handle, descriptor) - { - } - - public void Destroy() - { - _ = WinApi.DestroyWindow(Handle); - } -} diff --git a/samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs b/samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs deleted file mode 100644 index bd0c1bf98e..0000000000 --- a/samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace ControlCatalog.NetCore; - -internal unsafe class WinApi -{ - public enum CommonControls : uint - { - ICC_LISTVIEW_CLASSES = 0x00000001, // listview, header - ICC_TREEVIEW_CLASSES = 0x00000002, // treeview, tooltips - ICC_BAR_CLASSES = 0x00000004, // toolbar, statusbar, trackbar, tooltips - ICC_TAB_CLASSES = 0x00000008, // tab, tooltips - ICC_UPDOWN_CLASS = 0x00000010, // updown - ICC_PROGRESS_CLASS = 0x00000020, // progress - ICC_HOTKEY_CLASS = 0x00000040, // hotkey - ICC_ANIMATE_CLASS = 0x00000080, // animate - ICC_WIN95_CLASSES = 0x000000FF, - ICC_DATE_CLASSES = 0x00000100, // month picker, date picker, time picker, updown - ICC_USEREX_CLASSES = 0x00000200, // comboex - ICC_COOL_CLASSES = 0x00000400, // rebar (coolbar) control - ICC_INTERNET_CLASSES = 0x00000800, - ICC_PAGESCROLLER_CLASS = 0x00001000, // page scroller - ICC_NATIVEFNTCTL_CLASS = 0x00002000, // native font control - ICC_STANDARD_CLASSES = 0x00004000, - ICC_LINK_CLASS = 0x00008000 - } - - [StructLayout(LayoutKind.Sequential)] - public struct INITCOMMONCONTROLSEX - { - public int dwSize; - public uint dwICC; - } - - [DllImport("Comctl32.dll")] - public static extern void InitCommonControlsEx(ref INITCOMMONCONTROLSEX init); - - [DllImport("user32.dll", SetLastError = true)] - public static extern bool DestroyWindow(IntPtr hwnd); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "LoadLibraryW", ExactSpelling = true)] - public static extern IntPtr LoadLibrary(string lib); - - - [DllImport("kernel32.dll")] - public static extern IntPtr GetModuleHandle(string lpModuleName); - - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr CreateWindowEx( - int dwExStyle, - string lpClassName, - string lpWindowName, - uint dwStyle, - int x, - int y, - int nWidth, - int nHeight, - IntPtr hWndParent, - IntPtr hMenu, - IntPtr hInstance, - IntPtr lpParam); - - [StructLayout(LayoutKind.Sequential)] - public struct SETTEXTEX - { - public uint Flags; - public uint Codepage; - } - - [DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "SendMessageW")] - public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, ref SETTEXTEX wParam, byte[] lParam); -} 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.NetCore/Properties/launchSettings.json b/samples/ControlCatalog.NetCore/Properties/launchSettings.json deleted file mode 100644 index 11feb94bb3..0000000000 --- a/samples/ControlCatalog.NetCore/Properties/launchSettings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "profiles": { - "ControlCatalog.NetCore": { - "commandName": "Project" - }, - "Dxgi": { - "commandName": "Project", - "commandLineArgs": "--dxgi" - }, - "VNC": { - "commandName": "Project", - "commandLineArgs": "--vnc" - } - } -} diff --git a/samples/ControlCatalog.Tizen/ControlCatalog.Tizen.csproj b/samples/ControlCatalog.Tizen/ControlCatalog.Tizen.csproj deleted file mode 100644 index 6b14083842..0000000000 --- a/samples/ControlCatalog.Tizen/ControlCatalog.Tizen.csproj +++ /dev/null @@ -1,20 +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 75c244711b..bab1dd4c9f 100644 --- a/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj +++ b/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj @@ -1,13 +1,15 @@  + Exe manual $(AvsCurrentIOSTargetFramework) - $(AvsMinSupportedIOSVersion) + - - + + + diff --git a/samples/ControlCatalog.iOS/Info.plist b/samples/ControlCatalog.iOS/Info.plist index b4c7c07eb6..a1aa23e506 100644 --- a/samples/ControlCatalog.iOS/Info.plist +++ b/samples/ControlCatalog.iOS/Info.plist @@ -16,7 +16,6 @@ 1 2 - 3 UIRequiredDeviceCapabilities @@ -38,5 +37,7 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + com.apple.security.files.user-selected.read-write + diff --git a/samples/ControlCatalog.tvOS/ControlCatalog.tvOS.csproj b/samples/ControlCatalog.tvOS/ControlCatalog.tvOS.csproj new file mode 100644 index 0000000000..5e191a59dd --- /dev/null +++ b/samples/ControlCatalog.tvOS/ControlCatalog.tvOS.csproj @@ -0,0 +1,24 @@ + + + + Exe + manual + $(AvsCurrentTvOSTargetFramework) + $(AvsMinSupportedTvOSVersion) + + tvossimulator-x64 + 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.tvOS/Info.plist b/samples/ControlCatalog.tvOS/Info.plist new file mode 100644 index 0000000000..779324b970 --- /dev/null +++ b/samples/ControlCatalog.tvOS/Info.plist @@ -0,0 +1,40 @@ + + + + + CFBundleDisplayName + ControlCatalog.tvOS + CFBundleIdentifier + Avalonia.ControlCatalog + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIDeviceFamily + + 3 + + UIRequiredDeviceCapabilities + + arm64 + + UILaunchStoryboardName + LaunchScreen + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/samples/ControlCatalog/App.xaml b/samples/ControlCatalog/App.xaml index 157009a5e3..022118d3ab 100644 --- a/samples/ControlCatalog/App.xaml +++ b/samples/ControlCatalog/App.xaml @@ -28,11 +28,8 @@ - - + - - diff --git a/samples/ControlCatalog/App.xaml.cs b/samples/ControlCatalog/App.xaml.cs index 2b55c5bad8..b08df1223d 100644 --- a/samples/ControlCatalog/App.xaml.cs +++ b/samples/ControlCatalog/App.xaml.cs @@ -18,7 +18,6 @@ namespace ControlCatalog private FluentTheme? _fluentTheme; private SimpleTheme? _simpleTheme; private IStyle? _colorPickerFluent, _colorPickerSimple; - private IStyle? _dataGridFluent, _dataGridSimple; public App() { @@ -35,8 +34,6 @@ namespace ControlCatalog _simpleTheme = (SimpleTheme)Resources["SimpleTheme"]!; _colorPickerFluent = (IStyle)Resources["ColorPickerFluent"]!; _colorPickerSimple = (IStyle)Resources["ColorPickerSimple"]!; - _dataGridFluent = (IStyle)Resources["DataGridFluent"]!; - _dataGridSimple = (IStyle)Resources["DataGridSimple"]!; SetCatalogThemes(CatalogTheme.Fluent); } @@ -47,6 +44,10 @@ namespace ControlCatalog { desktopLifetime.MainWindow = new MainWindow { DataContext = new MainWindowViewModel() }; } + else if(ApplicationLifetime is IActivityApplicationLifetime singleViewFactoryApplicationLifetime) + { + singleViewFactoryApplicationLifetime.MainViewFactory = () => new MainView { DataContext = new MainWindowViewModel() }; + } else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime) { singleViewLifetime.MainView = new MainView { DataContext = new MainWindowViewModel() }; @@ -83,13 +84,11 @@ namespace ControlCatalog { app._themeStylesContainer[0] = app._fluentTheme!; app._themeStylesContainer[1] = app._colorPickerFluent!; - app._themeStylesContainer[2] = app._dataGridFluent!; } else if (theme == CatalogTheme.Simple) { app._themeStylesContainer[0] = app._simpleTheme!; app._themeStylesContainer[1] = app._colorPickerSimple!; - app._themeStylesContainer[2] = app._dataGridSimple!; } if (shouldReopenWindow) @@ -102,6 +101,10 @@ namespace ControlCatalog newWindow.Show(); oldWindow?.Close(); } + else if (app.ApplicationLifetime is IActivityApplicationLifetime singleViewFactoryApplicationLifetime) + { + singleViewFactoryApplicationLifetime.MainViewFactory = () => new MainView { DataContext = new MainWindowViewModel() }; + } else if (app.ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime) { singleViewLifetime.MainView = new MainView(); diff --git a/samples/ControlCatalog/Assets/image1.jpg b/samples/ControlCatalog/Assets/image1.jpg new file mode 100644 index 0000000000..673cb38399 Binary files /dev/null and b/samples/ControlCatalog/Assets/image1.jpg differ diff --git a/samples/ControlCatalog/Assets/image2.jpg b/samples/ControlCatalog/Assets/image2.jpg new file mode 100644 index 0000000000..83d721c083 Binary files /dev/null and b/samples/ControlCatalog/Assets/image2.jpg differ diff --git a/samples/ControlCatalog/Assets/image3.jpg b/samples/ControlCatalog/Assets/image3.jpg new file mode 100644 index 0000000000..b14700656e Binary files /dev/null and b/samples/ControlCatalog/Assets/image3.jpg differ diff --git a/samples/ControlCatalog/Assets/image4.jpg b/samples/ControlCatalog/Assets/image4.jpg new file mode 100644 index 0000000000..e15787a2e7 Binary files /dev/null and b/samples/ControlCatalog/Assets/image4.jpg differ diff --git a/samples/ControlCatalog/Assets/image5.jpg b/samples/ControlCatalog/Assets/image5.jpg new file mode 100644 index 0000000000..b6077334ef Binary files /dev/null and b/samples/ControlCatalog/Assets/image5.jpg differ diff --git a/samples/ControlCatalog/Assets/image6.jpg b/samples/ControlCatalog/Assets/image6.jpg new file mode 100644 index 0000000000..ea5228d178 Binary files /dev/null and b/samples/ControlCatalog/Assets/image6.jpg differ diff --git a/samples/ControlCatalog/Assets/image7.jpg b/samples/ControlCatalog/Assets/image7.jpg new file mode 100644 index 0000000000..2f86ce4ae5 Binary files /dev/null and b/samples/ControlCatalog/Assets/image7.jpg differ diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj index edcbcbe988..c71e7a93ad 100644 --- a/samples/ControlCatalog/ControlCatalog.csproj +++ b/samples/ControlCatalog/ControlCatalog.csproj @@ -1,20 +1,28 @@  - netstandard2.0;$(AvsCurrentTargetFramework) + $(AvsCurrentTargetFramework) true - enable true %(Filename) - + Designer - + + + + + + + + + + @@ -26,7 +34,6 @@ - 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/AcceleratorPage.xaml.cs b/samples/ControlCatalog/Pages/AcceleratorPage.xaml.cs new file mode 100644 index 0000000000..e013d9aaac --- /dev/null +++ b/samples/ControlCatalog/Pages/AcceleratorPage.xaml.cs @@ -0,0 +1,12 @@ +using Avalonia.Controls; + +namespace ControlCatalog.Pages +{ + public partial class AcceleratorPage : UserControl + { + public AcceleratorPage() + { + InitializeComponent(); + } + } +} diff --git a/samples/ControlCatalog/Pages/AcrylicPage.xaml.cs b/samples/ControlCatalog/Pages/AcrylicPage.xaml.cs index 44e7c4b92b..9516655bb9 100644 --- a/samples/ControlCatalog/Pages/AcrylicPage.xaml.cs +++ b/samples/ControlCatalog/Pages/AcrylicPage.xaml.cs @@ -1,19 +1,12 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; +using Avalonia.Controls; namespace ControlCatalog.Pages { - public class AcrylicPage : UserControl + public partial class AcrylicPage : UserControl { public AcrylicPage() { - this.InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); + InitializeComponent(); } } } diff --git a/samples/ControlCatalog/Pages/AdornerLayerPage.xaml.cs b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml.cs index 0cf4a6633c..526b8a492b 100644 --- a/samples/ControlCatalog/Pages/AdornerLayerPage.xaml.cs +++ b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml.cs @@ -1,47 +1,33 @@ using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Interactivity; -using Avalonia.Markup.Xaml; namespace ControlCatalog.Pages { - public class AdornerLayerPage : UserControl + public partial class AdornerLayerPage : UserControl { private Control? _adorner; public AdornerLayerPage() { - this.InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); + InitializeComponent(); } private void RemoveAdorner_OnClick(object? sender, RoutedEventArgs e) { - var adornerButton = this.FindControl + + Disabled + + @@ -141,7 +145,7 @@ Padding="15"> - + diff --git a/samples/ControlCatalog/Pages/ButtonsPage.xaml.cs b/samples/ControlCatalog/Pages/ButtonsPage.xaml.cs index 2d63f1fee9..6dcee1ab7d 100644 --- a/samples/ControlCatalog/Pages/ButtonsPage.xaml.cs +++ b/samples/ControlCatalog/Pages/ButtonsPage.xaml.cs @@ -1,29 +1,21 @@ using Avalonia.Controls; -using Avalonia.Markup.Xaml; +using Avalonia.Interactivity; namespace ControlCatalog.Pages { - public class ButtonsPage : UserControl + public partial class ButtonsPage : UserControl { private int repeatButtonClickCount = 0; public ButtonsPage() { InitializeComponent(); - - this.Get("RepeatButton").Click += OnRepeatButtonClick; - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); } - public void OnRepeatButtonClick(object? sender, object args) + public void OnRepeatButtonClick(object? sender, RoutedEventArgs args) { repeatButtonClickCount++; - var textBlock = this.Get("RepeatButtonTextBlock"); - textBlock.Text = $"Repeat Button: {repeatButtonClickCount}"; + RepeatButtonTextBlock.Text = $"Repeat Button: {repeatButtonClickCount}"; } } } diff --git a/samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs b/samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs index 2cd6e547f6..73e1fe4bba 100644 --- a/samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs +++ b/samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs @@ -1,36 +1,23 @@ -using Avalonia.Controls; -using Avalonia.Markup.Xaml; using System; +using Avalonia.Controls; namespace ControlCatalog.Pages { - public class CalendarDatePickerPage : UserControl + public partial class CalendarDatePickerPage : UserControl { public CalendarDatePickerPage() { InitializeComponent(); - - var dp1 = this.Get("DatePicker1"); - var dp2 = this.Get("DatePicker2"); - var dp3 = this.Get("DatePicker3"); - var dp4 = this.Get("DatePicker4"); - var dp5 = this.Get("DatePicker5"); - dp1.SelectedDate = DateTime.Today; - dp2.SelectedDate = DateTime.Today.AddDays(10); - dp3.SelectedDate = DateTime.Today.AddDays(20); - dp5.SelectedDate = DateTime.Today; + DatePicker1.SelectedDate = DateTime.Today; + DatePicker2.SelectedDate = DateTime.Today.AddDays(10); + DatePicker3.SelectedDate = DateTime.Today.AddDays(20); + DatePicker5.SelectedDate = DateTime.Today; - dp4.TemplateApplied += (s, e) => + DatePicker4.TemplateApplied += (s, e) => { - dp4.BlackoutDates?.AddDatesInPast(); + DatePicker4.BlackoutDates?.AddDatesInPast(); }; - - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); } } } diff --git a/samples/ControlCatalog/Pages/CalendarPage.xaml b/samples/ControlCatalog/Pages/CalendarPage.xaml index cfae7140b0..e142c4da72 100644 --- a/samples/ControlCatalog/Pages/CalendarPage.xaml +++ b/samples/ControlCatalog/Pages/CalendarPage.xaml @@ -32,6 +32,11 @@ + + + + ("DisplayDatesCalendar"); - cal1.DisplayDateStart = today.AddDays(-25); - cal1.DisplayDateEnd = today.AddDays(25); + var today = DateTime.Today; + DisplayDatesCalendar.DisplayDateStart = today.AddDays(-25); + DisplayDatesCalendar.DisplayDateEnd = today.AddDays(25); - var cal2 = this.Get("BlackoutDatesCalendar"); - cal2.BlackoutDates.AddDatesInPast(); - cal2.BlackoutDates.Add(new CalendarDateRange(today.AddDays(6))); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); + BlackoutDatesCalendar.BlackoutDates.AddDatesInPast(); + BlackoutDatesCalendar.BlackoutDates.Add(new CalendarDateRange(today.AddDays(6))); } } } diff --git a/samples/ControlCatalog/Pages/CanvasPage.xaml.cs b/samples/ControlCatalog/Pages/CanvasPage.xaml.cs index f43d974c18..e52df597a9 100644 --- a/samples/ControlCatalog/Pages/CanvasPage.xaml.cs +++ b/samples/ControlCatalog/Pages/CanvasPage.xaml.cs @@ -1,18 +1,12 @@ using Avalonia.Controls; -using Avalonia.Markup.Xaml; namespace ControlCatalog.Pages { - public class CanvasPage : UserControl + public partial class CanvasPage : UserControl { public CanvasPage() { - this.InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); + InitializeComponent(); } } } diff --git a/samples/ControlCatalog/Pages/CarouselPage.xaml.cs b/samples/ControlCatalog/Pages/CarouselPage.xaml.cs index c6aab5c4d5..713da34051 100644 --- a/samples/ControlCatalog/Pages/CarouselPage.xaml.cs +++ b/samples/ControlCatalog/Pages/CarouselPage.xaml.cs @@ -1,53 +1,35 @@ using System; using Avalonia.Animation; using Avalonia.Controls; -using Avalonia.Markup.Xaml; namespace ControlCatalog.Pages { - public class CarouselPage : UserControl + public partial class CarouselPage : UserControl { - private Carousel _carousel; - private Button _left; - private Button _right; - private ComboBox _transition; - private ComboBox _orientation; - public CarouselPage() { - this.InitializeComponent(); - _carousel = this.Get("carousel"); - _left = this.Get - - -